diff --git a/CREDITS b/CREDITS index 49dfefcb7575..17962bdd6dbd 100644 --- a/CREDITS +++ b/CREDITS @@ -3652,6 +3652,11 @@ S: Dag Hammerskjolds v. 3E S: S-226 64 LUND S: Sweden +N: Tilman Schmidt +E: tilman@imap.cc +D: Siemens Gigaset ISDN driver author and maintainer +D: ISDN CAPI subsystem contributions + N: Henning P. Schmiedehausen E: hps@tanstaafl.de D: added PCI support to the serial driver diff --git a/Documentation/.renames.txt b/Documentation/.renames.txt index a37d68471d50..43d44753ab93 100644 --- a/Documentation/.renames.txt +++ b/Documentation/.renames.txt @@ -783,11 +783,9 @@ namespaces/compatibility-list admin-guide/namespaces/compatibility-list namespaces/index admin-guide/namespaces/index namespaces/resource-control admin-guide/namespaces/resource-control networking/altera_tse networking/device_drivers/ethernet/altera/altera_tse -networking/baycom networking/device_drivers/hamradio/baycom networking/bpf_flow_dissector bpf/prog_flow_dissector networking/cxacru networking/device_drivers/atm/cxacru networking/defza networking/device_drivers/fddi/defza -networking/device_drivers/3com/3c509 networking/device_drivers/ethernet/3com/3c509 networking/device_drivers/3com/vortex networking/device_drivers/ethernet/3com/vortex networking/device_drivers/amazon/ena networking/device_drivers/ethernet/amazon/ena networking/device_drivers/aquantia/atlantic networking/device_drivers/ethernet/aquantia/atlantic @@ -822,7 +820,6 @@ networking/device_drivers/microsoft/netvsc networking/device_drivers/ethernet/mi networking/device_drivers/netronome/nfp networking/device_drivers/ethernet/netronome/nfp networking/device_drivers/pensando/ionic networking/device_drivers/ethernet/pensando/ionic networking/device_drivers/qualcomm/rmnet networking/device_drivers/cellular/qualcomm/rmnet -networking/device_drivers/smsc/smc9 networking/device_drivers/ethernet/smsc/smc9 networking/device_drivers/stmicro/stmmac networking/device_drivers/ethernet/stmicro/stmmac networking/device_drivers/ti/cpsw networking/device_drivers/ethernet/ti/cpsw networking/device_drivers/ti/cpsw_switchdev networking/device_drivers/ethernet/ti/cpsw_switchdev @@ -836,19 +833,16 @@ 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 networking/skfp networking/device_drivers/fddi/skfp -networking/z8530drv networking/device_drivers/hamradio/z8530drv nfc/index driver-api/nfc/index nfc/nfc-hci driver-api/nfc/nfc-hci nfc/nfc-pn544 driver-api/nfc/nfc-pn544 diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cf3807641d89..4d0f545fb3ec 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6,7 +6,6 @@ APPARMOR AppArmor support is enabled. ARM ARM architecture is enabled. ARM64 ARM64 architecture is enabled. - AX25 Appropriate AX.25 support is enabled. CLK Common clock infrastructure is enabled. CMA Contiguous Memory Area support is enabled. DRM Direct Rendering Management support is enabled. @@ -633,23 +632,6 @@ Kernel parameters 1 - Enable the BAU. unset - Disable the BAU. - baycom_epp= [HW,AX25] - Format: , - - baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem - Format: , - See header of drivers/net/hamradio/baycom_par.c. - - baycom_ser_fdx= [HW,AX25] - BayCom Serial Port AX.25 Modem (Full Duplex Mode) - Format: ,,[,] - See header of drivers/net/hamradio/baycom_ser_fdx.c. - - baycom_ser_hdx= [HW,AX25] - BayCom Serial Port AX.25 Modem (Half Duplex Mode) - Format: ,, - See header of drivers/net/hamradio/baycom_ser_hdx.c. - bdev_allow_write_mounted= Format: Control the ability to open a mounted block device diff --git a/Documentation/isdn/credits.rst b/Documentation/isdn/credits.rst deleted file mode 100644 index 319323f2091f..000000000000 --- a/Documentation/isdn/credits.rst +++ /dev/null @@ -1,73 +0,0 @@ -======= -Credits -======= - - -I want to thank all who contributed to this project and especially to: -(in alphabetical order) - -Thomas Bogendörfer (tsbogend@bigbug.franken.de) - Tester, lots of bugfixes and hints. - -Alan Cox (alan@lxorguk.ukuu.org.uk) - For help getting into standard-kernel. - -Henner Eisen (eis@baty.hanse.de) - For X.25 implementation. - -Volker Götz (volker@oops.franken.de) - For contribution of man-pages, the imontty-tool and a perfect - maintaining of the mailing-list at hub-wue. - -Matthias Hessler (hessler@isdn4linux.de) - For creating and maintaining the FAQ. - -Bernhard Hailer (Bernhard.Hailer@lrz.uni-muenchen.de) - For creating the FAQ, and the leafsite HOWTO. - -Michael 'Ghandi' Herold (michael@abadonna.franken.de) - For contribution of the vbox answering machine. - -Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - For his Sync-PPP-code. - -Karsten Keil (keil@isdn4linux.de) - For adding 1TR6-support to the Teles-driver. - For the HiSax-driver. - -Michael Knigge (knick@cove.han.de) - For contributing the imon-tool - -Andreas Kool (akool@Kool.f.EUnet.de) - For contribution of the isdnlog/isdnrep-tool - -Pedro Roque Marques (roque@di.fc.ul.pt) - For lot of new ideas and the pcbit driver. - -Eberhard Mönkeberg (emoenke@gwdg.de) - For testing and help to get into kernel. - -Thomas Neumann (tn@ruhr.de) - For help with Cisco-SLARP and keepalive - -Jan den Ouden (denouden@groovin.xs4all.nl) - For contribution of the original teles-driver - -Carsten Paeth (calle@calle.in-berlin.de) - For the AVM-B1-CAPI2.0 driver - -Thomas Pfeiffer (pfeiffer@pds.de) - For V.110, extended T.70 and Hylafax extensions in isdn_tty.c - -Max Riegel (riegel@max.franken.de) - For making the ICN hardware-documentation and test-equipment available. - -Armin Schindler (mac@melware.de) - For the eicon active card driver. - -Gerhard 'Fido' Schneider (fido@wuff.mayn.de) - For heavy-duty-beta-testing with his BBS ;) - -Thomas Uhl (uhl@think.de) - For distributing the cards. - For pushing me to work ;-) diff --git a/Documentation/isdn/index.rst b/Documentation/isdn/index.rst deleted file mode 100644 index d1125a16a746..000000000000 --- a/Documentation/isdn/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -==== -ISDN -==== - -.. toctree:: - :maxdepth: 2 - - interface_capi - - m_isdn - - credits diff --git a/Documentation/isdn/interface_capi.rst b/Documentation/isdn/interface_capi.rst deleted file mode 100644 index 4d63b34b35cf..000000000000 --- a/Documentation/isdn/interface_capi.rst +++ /dev/null @@ -1,336 +0,0 @@ -========================================= -Kernel CAPI Interface to Hardware Drivers -========================================= - -1. Overview -=========== - -From the CAPI 2.0 specification: -COMMON-ISDN-API (CAPI) is an application programming interface standard used -to access ISDN equipment connected to basic rate interfaces (BRI) and primary -rate interfaces (PRI). - -Kernel CAPI operates as a dispatching layer between CAPI applications and CAPI -hardware drivers. Hardware drivers register ISDN devices (controllers, in CAPI -lingo) with Kernel CAPI to indicate their readiness to provide their service -to CAPI applications. CAPI applications also register with Kernel CAPI, -requesting association with a CAPI device. Kernel CAPI then dispatches the -application registration to an available device, forwarding it to the -corresponding hardware driver. Kernel CAPI then forwards CAPI messages in both -directions between the application and the hardware driver. - -Format and semantics of CAPI messages are specified in the CAPI 2.0 standard. -This standard is freely available from https://www.capi.org. - - -2. Driver and Device Registration -================================= - -CAPI drivers must register each of the ISDN devices they control with Kernel -CAPI by calling the Kernel CAPI function attach_capi_ctr() with a pointer to a -struct capi_ctr before they can be used. This structure must be filled with -the names of the driver and controller, and a number of callback function -pointers which are subsequently used by Kernel CAPI for communicating with the -driver. The registration can be revoked by calling the function -detach_capi_ctr() with a pointer to the same struct capi_ctr. - -Before the device can be actually used, the driver must fill in the device -information fields 'manu', 'version', 'profile' and 'serial' in the capi_ctr -structure of the device, and signal its readiness by calling capi_ctr_ready(). -From then on, Kernel CAPI may call the registered callback functions for the -device. - -If the device becomes unusable for any reason (shutdown, disconnect ...), the -driver has to call capi_ctr_down(). This will prevent further calls to the -callback functions by Kernel CAPI. - - -3. Application Registration and Communication -============================================= - -Kernel CAPI forwards registration requests from applications (calls to CAPI -operation CAPI_REGISTER) to an appropriate hardware driver by calling its -register_appl() callback function. A unique Application ID (ApplID, u16) is -allocated by Kernel CAPI and passed to register_appl() along with the -parameter structure provided by the application. This is analogous to the -open() operation on regular files or character devices. - -After a successful return from register_appl(), CAPI messages from the -application may be passed to the driver for the device via calls to the -send_message() callback function. Conversely, the driver may call Kernel -CAPI's capi_ctr_handle_message() function to pass a received CAPI message to -Kernel CAPI for forwarding to an application, specifying its ApplID. - -Deregistration requests (CAPI operation CAPI_RELEASE) from applications are -forwarded as calls to the release_appl() callback function, passing the same -ApplID as with register_appl(). After return from release_appl(), no CAPI -messages for that application may be passed to or from the device anymore. - - -4. Data Structures -================== - -4.1 struct capi_driver ----------------------- - -This structure describes a Kernel CAPI driver itself. It is used in the -register_capi_driver() and unregister_capi_driver() functions, and contains -the following non-private fields, all to be set by the driver before calling -register_capi_driver(): - -``char name[32]`` - the name of the driver, as a zero-terminated ASCII string -``char revision[32]`` - the revision number of the driver, as a zero-terminated ASCII string - -4.2 struct capi_ctr -------------------- - -This structure describes an ISDN device (controller) handled by a Kernel CAPI -driver. After registration via the attach_capi_ctr() function it is passed to -all controller specific lower layer interface and callback functions to -identify the controller to operate on. - -It contains the following non-private fields: - -to be set by the driver before calling attach_capi_ctr(): -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -``struct module *owner`` - pointer to the driver module owning the device - -``void *driverdata`` - an opaque pointer to driver specific data, not touched by Kernel CAPI - -``char name[32]`` - the name of the controller, as a zero-terminated ASCII string - -``char *driver_name`` - the name of the driver, as a zero-terminated ASCII string - -``int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)`` - (optional) pointer to a callback function for sending firmware and - configuration data to the device - - The function may return before the operation has completed. - - Completion must be signalled by a call to capi_ctr_ready(). - - Return value: 0 on success, error code on error - Called in process context. - -``void (*reset_ctr)(struct capi_ctr *ctrlr)`` - (optional) pointer to a callback function for stopping the device, - releasing all registered applications - - The function may return before the operation has completed. - - Completion must be signalled by a call to capi_ctr_down(). - - Called in process context. - -``void (*register_appl)(struct capi_ctr *ctrlr, u16 applid, capi_register_params *rparam)`` - pointers to callback function for registration of - applications with the device - - Calls to these functions are serialized by Kernel CAPI so that only - one call to any of them is active at any time. - -``void (*release_appl)(struct capi_ctr *ctrlr, u16 applid)`` - pointers to callback functions deregistration of - applications with the device - - Calls to these functions are serialized by Kernel CAPI so that only - one call to any of them is active at any time. - -``u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb)`` - pointer to a callback function for sending a CAPI message to the - device - - Return value: CAPI error code - - If the method returns 0 (CAPI_NOERROR) the driver has taken ownership - of the skb and the caller may no longer access it. If it returns a - non-zero (error) value then ownership of the skb returns to the caller - who may reuse or free it. - - The return value should only be used to signal problems with respect - to accepting or queueing the message. Errors occurring during the - actual processing of the message should be signaled with an - appropriate reply message. - - May be called in process or interrupt context. - - Calls to this function are not serialized by Kernel CAPI, ie. it must - be prepared to be re-entered. - -``char *(*procinfo)(struct capi_ctr *ctrlr)`` - pointer to a callback function returning the entry for the device in - the CAPI controller info table, /proc/capi/controller - -Note: - Callback functions except send_message() are never called in interrupt - context. - -to be filled in before calling capi_ctr_ready(): -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -``u8 manu[CAPI_MANUFACTURER_LEN]`` - value to return for CAPI_GET_MANUFACTURER - -``capi_version version`` - value to return for CAPI_GET_VERSION - -``capi_profile profile`` - value to return for CAPI_GET_PROFILE - -``u8 serial[CAPI_SERIAL_LEN]`` - value to return for CAPI_GET_SERIAL - - -4.3 SKBs --------- - -CAPI messages are passed between Kernel CAPI and the driver via send_message() -and capi_ctr_handle_message(), stored in the data portion of a socket buffer -(skb). Each skb contains a single CAPI message coded according to the CAPI 2.0 -standard. - -For the data transfer messages, DATA_B3_REQ and DATA_B3_IND, the actual -payload data immediately follows the CAPI message itself within the same skb. -The Data and Data64 parameters are not used for processing. The Data64 -parameter may be omitted by setting the length field of the CAPI message to 22 -instead of 30. - - -4.4 The _cmsg Structure ------------------------ - -(declared in ) - -The _cmsg structure stores the contents of a CAPI 2.0 message in an easily -accessible form. It contains members for all possible CAPI 2.0 parameters, -including subparameters of the Additional Info and B Protocol structured -parameters, with the following exceptions: - -* second Calling party number (CONNECT_IND) - -* Data64 (DATA_B3_REQ and DATA_B3_IND) - -* Sending complete (subparameter of Additional Info, CONNECT_REQ and INFO_REQ) - -* Global Configuration (subparameter of B Protocol, CONNECT_REQ, CONNECT_RESP - and SELECT_B_PROTOCOL_REQ) - -Only those parameters appearing in the message type currently being processed -are actually used. Unused members should be set to zero. - -Members are named after the CAPI 2.0 standard names of the parameters they -represent. See for the exact spelling. Member data -types are: - -=========== ================================================================= -u8 for CAPI parameters of type 'byte' - -u16 for CAPI parameters of type 'word' - -u32 for CAPI parameters of type 'dword' - -_cstruct for CAPI parameters of type 'struct' - The member is a pointer to a buffer containing the parameter in - CAPI encoding (length + content). It may also be NULL, which will - be taken to represent an empty (zero length) parameter. - Subparameters are stored in encoded form within the content part. - -_cmstruct alternative representation for CAPI parameters of type 'struct' - (used only for the 'Additional Info' and 'B Protocol' parameters) - The representation is a single byte containing one of the values: - CAPI_DEFAULT: The parameter is empty/absent. - CAPI_COMPOSE: The parameter is present. - Subparameter values are stored individually in the corresponding - _cmsg structure members. -=========== ================================================================= - - -5. Lower Layer Interface Functions -================================== - -:: - - int attach_capi_ctr(struct capi_ctr *ctrlr) - int detach_capi_ctr(struct capi_ctr *ctrlr) - -register/unregister a device (controller) with Kernel CAPI - -:: - - void capi_ctr_ready(struct capi_ctr *ctrlr) - void capi_ctr_down(struct capi_ctr *ctrlr) - -signal controller ready/not ready - -:: - - void capi_ctr_handle_message(struct capi_ctr * ctrlr, u16 applid, - struct sk_buff *skb) - -pass a received CAPI message to Kernel CAPI -for forwarding to the specified application - - -6. Helper Functions and Macros -============================== - -Macros to extract/set element values from/in a CAPI message header -(from ): - -====================== ============================= ==================== -Get Macro Set Macro Element (Type) -====================== ============================= ==================== -CAPIMSG_LEN(m) CAPIMSG_SETLEN(m, len) Total Length (u16) -CAPIMSG_APPID(m) CAPIMSG_SETAPPID(m, applid) ApplID (u16) -CAPIMSG_COMMAND(m) CAPIMSG_SETCOMMAND(m,cmd) Command (u8) -CAPIMSG_SUBCOMMAND(m) CAPIMSG_SETSUBCOMMAND(m, cmd) Subcommand (u8) -CAPIMSG_CMD(m) - Command*256 - + Subcommand (u16) -CAPIMSG_MSGID(m) CAPIMSG_SETMSGID(m, msgid) Message Number (u16) - -CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr) Controller/PLCI/NCCI - (u32) -CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16) -====================== ============================= ==================== - - -Library functions for working with _cmsg structures -(from ): - -``char *capi_cmd2str(u8 Command, u8 Subcommand)`` - Returns the CAPI 2.0 message name corresponding to the given command - and subcommand values, as a static ASCII string. The return value may - be NULL if the command/subcommand is not one of those defined in the - CAPI 2.0 standard. - - -7. Debugging -============ - -The module kernelcapi has a module parameter showcapimsgs controlling some -debugging output produced by the module. It can only be set when the module is -loaded, via a parameter "showcapimsgs=" to the modprobe command, either on -the command line or in the configuration file. - -If the lowest bit of showcapimsgs is set, kernelcapi logs controller and -application up and down events. - -In addition, every registered CAPI controller has an associated traceflag -parameter controlling how CAPI messages sent from and to the controller are -logged. The traceflag parameter is initialized with the value of the -showcapimsgs parameter when the controller is registered, but can later be -changed via the MANUFACTURER_REQ command KCAPI_CMD_TRACE. - -If the value of traceflag is non-zero, CAPI messages are logged. -DATA_B3 messages are only logged if the value of traceflag is > 2. - -If the lowest bit of traceflag is set, only the command/subcommand and message -length are logged. Otherwise, kernelcapi logs a readable representation of -the entire message. diff --git a/Documentation/isdn/m_isdn.rst b/Documentation/isdn/m_isdn.rst deleted file mode 100644 index 5847a164287e..000000000000 --- a/Documentation/isdn/m_isdn.rst +++ /dev/null @@ -1,9 +0,0 @@ -============ -mISDN Driver -============ - -mISDN is a new modular ISDN driver, in the long term it should replace -the old I4L driver architecture for passive ISDN cards. -It was designed to allow a broad range of applications and interfaces -but only have the basic function in kernel, the interface to the user -space is based on sockets with a own address family AF_ISDN. diff --git a/Documentation/networking/6pack.rst b/Documentation/networking/6pack.rst deleted file mode 100644 index 66d5fd4fc821..000000000000 --- a/Documentation/networking/6pack.rst +++ /dev/null @@ -1,191 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -============== -6pack Protocol -============== - -This is the 6pack-mini-HOWTO, written by - -Andreas Könsgen DG3KQ - -:Internet: ajk@comnets.uni-bremen.de -:AMPR-net: dg3kq@db0pra.ampr.org -:AX.25: dg3kq@db0ach.#nrw.deu.eu - -Last update: April 7, 1998 - -1. What is 6pack, and what are the advantages to KISS? -====================================================== - -6pack is a transmission protocol for data exchange between the PC and -the TNC over a serial line. It can be used as an alternative to KISS. - -6pack has two major advantages: - -- The PC is given full control over the radio - channel. Special control data is exchanged between the PC and the TNC so - that the PC knows at any time if the TNC is receiving data, if a TNC - buffer underrun or overrun has occurred, if the PTT is - set and so on. This control data is processed at a higher priority than - normal data, so a data stream can be interrupted at any time to issue an - important event. This helps to improve the channel access and timing - algorithms as everything is computed in the PC. It would even be possible - to experiment with something completely different from the known CSMA and - DAMA channel access methods. - This kind of real-time control is especially important to supply several - TNCs that are connected between each other and the PC by a daisy chain - (however, this feature is not supported yet by the Linux 6pack driver). - -- Each packet transferred over the serial line is supplied with a checksum, - so it is easy to detect errors due to problems on the serial line. - Received packets that are corrupt are not passed on to the AX.25 layer. - Damaged packets that the TNC has received from the PC are not transmitted. - -More details about 6pack are described in the file 6pack.ps that is located -in the doc directory of the AX.25 utilities package. - -2. Who has developed the 6pack protocol? -======================================== - -The 6pack protocol has been developed by Ekki Plicht DF4OR, Henning Rech -DF9IC and Gunter Jost DK7WJ. A driver for 6pack, written by Gunter Jost and -Matthias Welwarsky DG2FEF, comes along with the PC version of FlexNet. -They have also written a firmware for TNCs to perform the 6pack -protocol (see section 4 below). - -3. Where can I get the latest version of 6pack for LinuX? -========================================================= - -At the moment, the 6pack stuff can obtained via anonymous ftp from -db0bm.automation.fh-aachen.de. In the directory /incoming/dg3kq, -there is a file named 6pack.tgz. - -4. Preparing the TNC for 6pack operation -======================================== - -To be able to use 6pack, a special firmware for the TNC is needed. The EPROM -of a newly bought TNC does not contain 6pack, so you will have to -program an EPROM yourself. The image file for 6pack EPROMs should be -available on any packet radio box where PC/FlexNet can be found. The name of -the file is 6pack.bin. This file is copyrighted and maintained by the FlexNet -team. It can be used under the terms of the license that comes along -with PC/FlexNet. Please do not ask me about the internals of this file as I -don't know anything about it. I used a textual description of the 6pack -protocol to program the Linux driver. - -TNCs contain a 64kByte EPROM, the lower half of which is used for -the firmware/KISS. The upper half is either empty or is sometimes -programmed with software called TAPR. In the latter case, the TNC -is supplied with a DIP switch so you can easily change between the -two systems. When programming a new EPROM, one of the systems is replaced -by 6pack. It is useful to replace TAPR, as this software is rarely used -nowadays. If your TNC is not equipped with the switch mentioned above, you -can build in one yourself that switches over the highest address pin -of the EPROM between HIGH and LOW level. After having inserted the new EPROM -and switched to 6pack, apply power to the TNC for a first test. The connect -and the status LED are lit for about a second if the firmware initialises -the TNC correctly. - -5. Building and installing the 6pack driver -=========================================== - -The driver has been tested with kernel version 2.1.90. Use with older -kernels may lead to a compilation error because the interface to a kernel -function has been changed in the 2.1.8x kernels. - -How to turn on 6pack support: ------------------------------ - -- In the linux kernel configuration program, select the code maturity level - options menu and turn on the prompting for development drivers. - -- Select the amateur radio support menu and turn on the serial port 6pack - driver. - -- Compile and install the kernel and the modules. - -To use the driver, the kissattach program delivered with the AX.25 utilities -has to be modified. - -- Do a cd to the directory that holds the kissattach sources. Edit the - kissattach.c file. At the top, insert the following lines:: - - #ifndef N_6PACK - #define N_6PACK (N_AX25+1) - #endif - - Then find the line: - - int disc = N_AX25; - - and replace N_AX25 by N_6PACK. - -- Recompile kissattach. Rename it to spattach to avoid confusions. - -Installing the driver: ----------------------- - -- Do an insmod 6pack. Look at your /var/log/messages file to check if the - module has printed its initialization message. - -- Do a spattach as you would launch kissattach when starting a KISS port. - Check if the kernel prints the message '6pack: TNC found'. - -- From here, everything should work as if you were setting up a KISS port. - The only difference is that the network device that represents - the 6pack port is called sp instead of sl or ax. So, sp0 would be the - first 6pack port. - -Although the driver has been tested on various platforms, I still declare it -ALPHA. BE CAREFUL! Sync your disks before insmoding the 6pack module -and spattaching. Watch out if your computer behaves strangely. Read section -6 of this file about known problems. - -Note that the connect and status LEDs of the TNC are controlled in a -different way than they are when the TNC is used with PC/FlexNet. When using -FlexNet, the connect LED is on if there is a connection; the status LED is -on if there is data in the buffer of the PC's AX.25 engine that has to be -transmitted. Under Linux, the 6pack layer is beyond the AX.25 layer, -so the 6pack driver doesn't know anything about connects or data that -has not yet been transmitted. Therefore the LEDs are controlled -as they are in KISS mode: The connect LED is turned on if data is transferred -from the PC to the TNC over the serial line, the status LED if data is -sent to the PC. - -6. Known problems -================= - -When testing the driver with 2.0.3x kernels and -operating with data rates on the radio channel of 9600 Baud or higher, -the driver may, on certain systems, sometimes print the message '6pack: -bad checksum', which is due to data loss if the other station sends two -or more subsequent packets. I have been told that this is due to a problem -with the serial driver of 2.0.3x kernels. I don't know yet if the problem -still exists with 2.1.x kernels, as I have heard that the serial driver -code has been changed with 2.1.x. - -When shutting down the sp interface with ifconfig, the kernel crashes if -there is still an AX.25 connection left over which an IP connection was -running, even if that IP connection is already closed. The problem does not -occur when there is a bare AX.25 connection still running. I don't know if -this is a problem of the 6pack driver or something else in the kernel. - -The driver has been tested as a module, not yet as a kernel-builtin driver. - -The 6pack protocol supports daisy-chaining of TNCs in a token ring, which is -connected to one serial port of the PC. This feature is not implemented -and at least at the moment I won't be able to do it because I do not have -the opportunity to build a TNC daisy-chain and test it. - -Some of the comments in the source code are inaccurate. They are left from -the SLIP/KISS driver, from which the 6pack driver has been derived. -I haven't modified or removed them yet -- sorry! The code itself needs -some cleaning and optimizing. This will be done in a later release. - -If you encounter a bug or if you have a question or suggestion concerning the -driver, feel free to mail me, using the addresses given at the beginning of -this file. - -Have fun! - -Andreas diff --git a/Documentation/networking/ax25.rst b/Documentation/networking/ax25.rst deleted file mode 100644 index 89c79dd6c6f9..000000000000 --- a/Documentation/networking/ax25.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -===== -AX.25 -===== - -To use the amateur radio protocols within Linux you will need to get a -suitable copy of the AX.25 Utilities. More detailed information about -AX.25, NET/ROM and ROSE, associated programs and utilities can be -found on https://linux-ax25.in-berlin.de. - -There is a mailing list for discussing Linux amateur radio matters -called linux-hams@vger.kernel.org. To subscribe to it, send a message to -linux-hams+subscribe@vger.kernel.org or use the web interface at -https://vger.kernel.org. The subject and body of the message are -ignored. You don't need to be subscribed to post but of course that -means you might miss an answer. diff --git a/Documentation/networking/caif/caif.rst b/Documentation/networking/caif/caif.rst deleted file mode 100644 index d922d419c513..000000000000 --- a/Documentation/networking/caif/caif.rst +++ /dev/null @@ -1,138 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. include:: - - -================ -Using Linux CAIF -================ - - -:Copyright: |copy| ST-Ericsson AB 2010 - -:Author: Sjur Brendeland/ sjur.brandeland@stericsson.com - -Start -===== - -If you have compiled CAIF for modules do:: - - $modprobe crc_ccitt - $modprobe caif - $modprobe caif_socket - $modprobe chnl_net - - -Preparing the setup with a STE modem -==================================== - -If you are working on integration of CAIF you should make sure -that the kernel is built with module support. - -There are some things that need to be tweaked to get the host TTY correctly -set up to talk to the modem. -Since the CAIF stack is running in the kernel and we want to use the existing -TTY, we are installing our physical serial driver as a line discipline above -the TTY device. - -To achieve this we need to install the N_CAIF ldisc from user space. -The benefit is that we can hook up to any TTY. - -The use of Start-of-frame-extension (STX) must also be set as -module parameter "ser_use_stx". - -Normally Frame Checksum is always used on UART, but this is also provided as a -module parameter "ser_use_fcs". - -:: - - $ modprobe caif_serial ser_ttyname=/dev/ttyS0 ser_use_stx=yes - $ ifconfig caif_ttyS0 up - -PLEASE NOTE: - There is a limitation in Android shell. - It only accepts one argument to insmod/modprobe! - -Trouble shooting -================ - -There are debugfs parameters provided for serial communication. -/sys/kernel/debug/caif_serial// - -* ser_state: Prints the bit-mask status where - - - 0x02 means SENDING, this is a transient state. - - 0x10 means FLOW_OFF_SENT, i.e. the previous frame has not been sent - and is blocking further send operation. Flow OFF has been propagated - to all CAIF Channels using this TTY. - -* tty_status: Prints the bit-mask tty status information - - - 0x01 - tty->warned is on. - - 0x04 - tty->packed is on. - - 0x08 - tty->flow.tco_stopped is on. - - 0x10 - tty->hw_stopped is on. - - 0x20 - tty->flow.stopped is on. - -* last_tx_msg: Binary blob Prints the last transmitted frame. - - This can be printed with:: - - $od --format=x1 /sys/kernel/debug/caif_serial//last_rx_msg. - - The first two tx messages sent look like this. Note: The initial - byte 02 is start of frame extension (STX) used for re-syncing - upon errors. - - - Enumeration:: - - 0000000 02 05 00 00 03 01 d2 02 - | | | | | | - STX(1) | | | | - Length(2)| | | - Control Channel(1) - Command:Enumeration(1) - Link-ID(1) - Checksum(2) - - - Channel Setup:: - - 0000000 02 07 00 00 00 21 a1 00 48 df - | | | | | | | | - STX(1) | | | | | | - Length(2)| | | | | - Control Channel(1) - Command:Channel Setup(1) - Channel Type(1) - Priority and Link-ID(1) - Endpoint(1) - Checksum(2) - -* last_rx_msg: Prints the last transmitted frame. - - The RX messages for LinkSetup look almost identical but they have the - bit 0x20 set in the command bit, and Channel Setup has added one byte - before Checksum containing Channel ID. - - NOTE: - Several CAIF Messages might be concatenated. The maximum debug - buffer size is 128 bytes. - -Error Scenarios -=============== - -- last_tx_msg contains channel setup message and last_rx_msg is empty -> - The host seems to be able to send over the UART, at least the CAIF ldisc get - notified that sending is completed. - -- last_tx_msg contains enumeration message and last_rx_msg is empty -> - The host is not able to send the message from UART, the tty has not been - able to complete the transmit operation. - -- if /sys/kernel/debug/caif_serial//tty_status is non-zero there - might be problems transmitting over UART. - - E.g. host and modem wiring is not correct you will typically see - tty_status = 0x10 (hw_stopped) and ser_state = 0x10 (FLOW_OFF_SENT). - - You will probably see the enumeration message in last_tx_message - and empty last_rx_message. diff --git a/Documentation/networking/caif/index.rst b/Documentation/networking/caif/index.rst deleted file mode 100644 index ec29b6f4bdb4..000000000000 --- a/Documentation/networking/caif/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -CAIF -==== - -Contents: - -.. toctree:: - :maxdepth: 2 - - linux_caif - caif diff --git a/Documentation/networking/caif/linux_caif.rst b/Documentation/networking/caif/linux_caif.rst deleted file mode 100644 index a0480862ab8c..000000000000 --- a/Documentation/networking/caif/linux_caif.rst +++ /dev/null @@ -1,195 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. include:: - -========== -Linux CAIF -========== - -Copyright |copy| ST-Ericsson AB 2010 - -:Author: Sjur Brendeland/ sjur.brandeland@stericsson.com -:License terms: GNU General Public License (GPL) version 2 - - -Introduction -============ - -CAIF is a MUX protocol used by ST-Ericsson cellular modems for -communication between Modem and host. The host processes can open virtual AT -channels, initiate GPRS Data connections, Video channels and Utility Channels. -The Utility Channels are general purpose pipes between modem and host. - -ST-Ericsson modems support a number of transports between modem -and host. Currently, UART and Loopback are available for Linux. - - -Architecture -============ - -The implementation of CAIF is divided into: - -* CAIF Socket Layer and GPRS IP Interface. -* CAIF Core Protocol Implementation -* CAIF Link Layer, implemented as NET devices. - -:: - - RTNL - ! - ! +------+ +------+ - ! +------+! +------+! - ! ! IP !! !Socket!! - +-------> !interf!+ ! API !+ <- CAIF Client APIs - ! +------+ +------! - ! ! ! - ! +-----------+ - ! ! - ! +------+ <- CAIF Core Protocol - ! ! CAIF ! - ! ! Core ! - ! +------+ - ! +----------!---------+ - ! ! ! ! - ! +------+ +-----+ +------+ - +--> ! HSI ! ! TTY ! ! USB ! <- Link Layer (Net Devices) - +------+ +-----+ +------+ - - - -Implementation -============== - - -CAIF Core Protocol Layer ------------------------- - -CAIF Core layer implements the CAIF protocol as defined by ST-Ericsson. -It implements the CAIF protocol stack in a layered approach, where -each layer described in the specification is implemented as a separate layer. -The architecture is inspired by the design patterns "Protocol Layer" and -"Protocol Packet". - -CAIF structure -^^^^^^^^^^^^^^ - -The Core CAIF implementation contains: - - - Simple implementation of CAIF. - - Layered architecture (a la Streams), each layer in the CAIF - specification is implemented in a separate c-file. - - Clients must call configuration function to add PHY layer. - - Clients must implement CAIF layer to consume/produce - CAIF payload with receive and transmit functions. - - Clients must call configuration function to add and connect the - Client layer. - - When receiving / transmitting CAIF Packets (cfpkt), ownership is passed - to the called function (except for framing layers' receive function) - -Layered Architecture -==================== - -The CAIF protocol can be divided into two parts: Support functions and Protocol -Implementation. The support functions include: - - - CFPKT CAIF Packet. Implementation of CAIF Protocol Packet. The - CAIF Packet has functions for creating, destroying and adding content - and for adding/extracting header and trailers to protocol packets. - -The CAIF Protocol implementation contains: - - - CFCNFG CAIF Configuration layer. Configures the CAIF Protocol - Stack and provides a Client interface for adding Link-Layer and - Driver interfaces on top of the CAIF Stack. - - - CFCTRL CAIF Control layer. Encodes and Decodes control messages - such as enumeration and channel setup. Also matches request and - response messages. - - - CFSERVL General CAIF Service Layer functionality; handles flow - control and remote shutdown requests. - - - CFVEI CAIF VEI layer. Handles CAIF AT Channels on VEI (Virtual - External Interface). This layer encodes/decodes VEI frames. - - - CFDGML CAIF Datagram layer. Handles CAIF Datagram layer (IP - traffic), encodes/decodes Datagram frames. - - - CFMUX CAIF Mux layer. Handles multiplexing between multiple - physical bearers and multiple channels such as VEI, Datagram, etc. - The MUX keeps track of the existing CAIF Channels and - Physical Instances and selects the appropriate instance based - on Channel-Id and Physical-ID. - - - CFFRML CAIF Framing layer. Handles Framing i.e. Frame length - and frame checksum. - - - CFSERL CAIF Serial layer. Handles concatenation/split of frames - into CAIF Frames with correct length. - -:: - - +---------+ - | Config | - | CFCNFG | - +---------+ - ! - +---------+ +---------+ +---------+ - | AT | | Control | | Datagram| - | CFVEIL | | CFCTRL | | CFDGML | - +---------+ +---------+ +---------+ - \_____________!______________/ - ! - +---------+ - | MUX | - | | - +---------+ - _____!_____ - / \ - +---------+ +---------+ - | CFFRML | | CFFRML | - | Framing | | Framing | - +---------+ +---------+ - ! ! - +---------+ +---------+ - | | | Serial | - | | | CFSERL | - +---------+ +---------+ - - -In this layered approach the following "rules" apply. - - - All layers embed the same structure "struct cflayer" - - A layer does not depend on any other layer's private data. - - Layers are stacked by setting the pointers:: - - layer->up , layer->dn - - - In order to send data upwards, each layer should do:: - - layer->up->receive(layer->up, packet); - - - In order to send data downwards, each layer should do:: - - layer->dn->transmit(layer->dn, packet); - - -CAIF Socket and IP interface -============================ - -The IP interface and CAIF socket API are implemented on top of the -CAIF Core protocol. The IP Interface and CAIF socket have an instance of -'struct cflayer', just like the CAIF Core protocol stack. -Net device and Socket implement the 'receive()' function defined by -'struct cflayer', just like the rest of the CAIF stack. In this way, transmit and -receive of packets is handled as by the rest of the layers: the 'dn->transmit()' -function is called in order to transmit data. - -Configuration of Link Layer ---------------------------- -The Link Layer is implemented as Linux network devices (struct net_device). -Payload handling and registration is done using standard Linux mechanisms. - -The CAIF Protocol relies on a loss-less link layer without implementing -retransmission. This implies that packet drops must not happen. -Therefore a flow-control mechanism is implemented where the physical -interface can initiate flow stop for all CAIF Channels. 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 @@ Contents: :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/Documentation/networking/device_drivers/ethernet/3com/3c509.rst b/Documentation/networking/device_drivers/ethernet/3com/3c509.rst deleted file mode 100644 index 47f706bacdd9..000000000000 --- a/Documentation/networking/device_drivers/ethernet/3com/3c509.rst +++ /dev/null @@ -1,249 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -============================================================================= -Linux and the 3Com EtherLink III Series Ethercards (driver v1.18c and higher) -============================================================================= - -This file contains the instructions and caveats for v1.18c and higher versions -of the 3c509 driver. You should not use the driver without reading this file. - -release 1.0 - -28 February 2002 - -Current maintainer (corrections to): - David Ruggiero - -Introduction -============ - -The following are notes and information on using the 3Com EtherLink III series -ethercards in Linux. These cards are commonly known by the most widely-used -card's 3Com model number, 3c509. They are all 10mb/s ISA-bus cards and shouldn't -be (but sometimes are) confused with the similarly-numbered PCI-bus "3c905" -(aka "Vortex" or "Boomerang") series. Kernel support for the 3c509 family is -provided by the module 3c509.c, which has code to support all of the following -models: - - - 3c509 (original ISA card) - - 3c509B (later revision of the ISA card; supports full-duplex) - - 3c589 (PCMCIA) - - 3c589B (later revision of the 3c589; supports full-duplex) - - 3c579 (EISA) - -Large portions of this documentation were heavily borrowed from the guide -written the original author of the 3c509 driver, Donald Becker. The master -copy of that document, which contains notes on older versions of the driver, -currently resides on Scyld web server: http://www.scyld.com/. - - -Special Driver Features -======================= - -Overriding card settings - -The driver allows boot- or load-time overriding of the card's detected IOADDR, -IRQ, and transceiver settings, although this capability shouldn't generally be -needed except to enable full-duplex mode (see below). An example of the syntax -for LILO parameters for doing this:: - - ether=10,0x310,3,0x3c509,eth0 - -This configures the first found 3c509 card for IRQ 10, base I/O 0x310, and -transceiver type 3 (10base2). The flag "0x3c509" must be set to avoid conflicts -with other card types when overriding the I/O address. When the driver is -loaded as a module, only the IRQ may be overridden. For example, -setting two cards to IRQ10 and IRQ11 is done by using the irq module -option:: - - options 3c509 irq=10,11 - - -Full-duplex mode -================ - -The v1.18c driver added support for the 3c509B's full-duplex capabilities. -In order to enable and successfully use full-duplex mode, three conditions -must be met: - -(a) You must have a Etherlink III card model whose hardware supports full- -duplex operations. Currently, the only members of the 3c509 family that are -positively known to support full-duplex are the 3c509B (ISA bus) and 3c589B -(PCMCIA) cards. Cards without the "B" model designation do *not* support -full-duplex mode; these include the original 3c509 (no "B"), the original -3c589, the 3c529 (MCA bus), and the 3c579 (EISA bus). - -(b) You must be using your card's 10baseT transceiver (i.e., the RJ-45 -connector), not its AUI (thick-net) or 10base2 (thin-net/coax) interfaces. -AUI and 10base2 network cabling is physically incapable of full-duplex -operation. - -(c) Most importantly, your 3c509B must be connected to a link partner that is -itself full-duplex capable. This is almost certainly one of two things: a full- -duplex-capable Ethernet switch (*not* a hub), or a full-duplex-capable NIC on -another system that's connected directly to the 3c509B via a crossover cable. - -Full-duplex mode can be enabled using 'ethtool'. - -.. warning:: - - Extremely important caution concerning full-duplex mode - - Understand that the 3c509B's hardware's full-duplex support is much more - limited than that provide by more modern network interface cards. Although - at the physical layer of the network it fully supports full-duplex operation, - the card was designed before the current Ethernet auto-negotiation (N-way) - spec was written. This means that the 3c509B family ***cannot and will not - auto-negotiate a full-duplex connection with its link partner under any - circumstances, no matter how it is initialized***. If the full-duplex mode - of the 3c509B is enabled, its link partner will very likely need to be - independently _forced_ into full-duplex mode as well; otherwise various nasty - failures will occur - at the very least, you'll see massive numbers of packet - collisions. This is one of very rare circumstances where disabling auto- - negotiation and forcing the duplex mode of a network interface card or switch - would ever be necessary or desirable. - - -Available Transceiver Types -=========================== - -For versions of the driver v1.18c and above, the available transceiver types are: - -== ========================================================================= -0 transceiver type from EEPROM config (normally 10baseT); force half-duplex -1 AUI (thick-net / DB15 connector) -2 (undefined) -3 10base2 (thin-net == coax / BNC connector) -4 10baseT (RJ-45 connector); force half-duplex mode -8 transceiver type and duplex mode taken from card's EEPROM config settings -12 10baseT (RJ-45 connector); force full-duplex mode -== ========================================================================= - -Prior to driver version 1.18c, only transceiver codes 0-4 were supported. Note -that the new transceiver codes 8 and 12 are the *only* ones that will enable -full-duplex mode, no matter what the card's detected EEPROM settings might be. -This insured that merely upgrading the driver from an earlier version would -never automatically enable full-duplex mode in an existing installation; -it must always be explicitly enabled via one of these code in order to be -activated. - -The transceiver type can be changed using 'ethtool'. - - -Interpretation of error messages and common problems ----------------------------------------------------- - -Error Messages -^^^^^^^^^^^^^^ - -eth0: Infinite loop in interrupt, status 2011. -These are "mostly harmless" message indicating that the driver had too much -work during that interrupt cycle. With a status of 0x2011 you are receiving -packets faster than they can be removed from the card. This should be rare -or impossible in normal operation. Possible causes of this error report are: - - - a "green" mode enabled that slows the processor down when there is no - keyboard activity. - - - some other device or device driver hogging the bus or disabling interrupts. - Check /proc/interrupts for excessive interrupt counts. The timer tick - interrupt should always be incrementing faster than the others. - -No received packets -^^^^^^^^^^^^^^^^^^^ - -If a 3c509, 3c562 or 3c589 can successfully transmit packets, but never -receives packets (as reported by /proc/net/dev or 'ifconfig') you likely -have an interrupt line problem. Check /proc/interrupts to verify that the -card is actually generating interrupts. If the interrupt count is not -increasing you likely have a physical conflict with two devices trying to -use the same ISA IRQ line. The common conflict is with a sound card on IRQ10 -or IRQ5, and the easiest solution is to move the 3c509 to a different -interrupt line. If the device is receiving packets but 'ping' doesn't work, -you have a routing problem. - -Tx Carrier Errors Reported in /proc/net/dev -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - -If an EtherLink III appears to transmit packets, but the "Tx carrier errors" -field in /proc/net/dev increments as quickly as the Tx packet count, you -likely have an unterminated network or the incorrect media transceiver selected. - -3c509B card is not detected on machines with an ISA PnP BIOS. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -While the updated driver works with most PnP BIOS programs, it does not work -with all. This can be fixed by disabling PnP support using the 3Com-supplied -setup program. - -3c509 card is not detected on overclocked machines -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Increase the delay time in id_read_eeprom() from the current value, 500, -to an absurdly high value, such as 5000. - - -Decoding Status and Error Messages ----------------------------------- - - -The bits in the main status register are: - -===== ====================================== -value description -===== ====================================== -0x01 Interrupt latch -0x02 Tx overrun, or Rx underrun -0x04 Tx complete -0x08 Tx FIFO room available -0x10 A complete Rx packet has arrived -0x20 A Rx packet has started to arrive -0x40 The driver has requested an interrupt -0x80 Statistics counter nearly full -===== ====================================== - -The bits in the transmit (Tx) status word are: - -===== ============================================ -value description -===== ============================================ -0x02 Out-of-window collision. -0x04 Status stack overflow (normally impossible). -0x08 16 collisions. -0x10 Tx underrun (not enough PCI bus bandwidth). -0x20 Tx jabber. -0x40 Tx interrupt requested. -0x80 Status is valid (this should always be set). -===== ============================================ - - -When a transmit error occurs the driver produces a status message such as:: - - eth0: Transmit error, Tx status register 82 - -The two values typically seen here are: - -0x82 -^^^^ - -Out of window collision. This typically occurs when some other Ethernet -host is incorrectly set to full duplex on a half duplex network. - -0x88 -^^^^ - -16 collisions. This typically occurs when the network is exceptionally busy -or when another host doesn't correctly back off after a collision. If this -error is mixed with 0x82 errors it is the result of a host incorrectly set -to full duplex (see above). - -Both of these errors are the result of network problems that should be -corrected. They do not represent driver malfunction. - - -Revision history (this file) -============================ - -28Feb02 v1.0 DR New; major portions based on Becker original 3c509 docs - diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst index 5f3f06111911..64621c21fd78 100644 --- a/Documentation/networking/device_drivers/ethernet/index.rst +++ b/Documentation/networking/device_drivers/ethernet/index.rst @@ -10,7 +10,6 @@ Contents: .. toctree:: :maxdepth: 2 - 3com/3c509 3com/vortex amazon/ena altera/altera_tse @@ -52,7 +51,6 @@ Contents: pensando/ionic pensando/ionic_rdma qualcomm/ppe/ppe - smsc/smc9 stmicro/stmmac ti/cpsw ti/cpsw_switchdev diff --git a/Documentation/networking/device_drivers/ethernet/smsc/smc9.rst b/Documentation/networking/device_drivers/ethernet/smsc/smc9.rst deleted file mode 100644 index e5eac896a631..000000000000 --- a/Documentation/networking/device_drivers/ethernet/smsc/smc9.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -================ -SMC 9xxxx Driver -================ - -Revision 0.12 - -3/5/96 - -Copyright 1996 Erik Stahlman - -Released under terms of the GNU General Public License. - -This file contains the instructions and caveats for my SMC9xxx driver. You -should not be using the driver without reading this file. - -Things to note about installation: - - 1. The driver should work on all kernels from 1.2.13 until 1.3.71. - (A kernel patch is supplied for 1.3.71 ) - - 2. If you include this into the kernel, you might need to change some - options, such as for forcing IRQ. - - - 3. To compile as a module, run 'make'. - Make will give you the appropriate options for various kernel support. - - 4. Loading the driver as a module:: - - use: insmod smc9194.o - optional parameters: - io=xxxx : your base address - irq=xx : your irq - ifport=x : 0 for whatever is default - 1 for twisted pair - 2 for AUI ( or BNC on some cards ) - -How to obtain the latest version? - -FTP: - ftp://fenris.campus.vt.edu/smc9/smc9-12.tar.gz - ftp://sfbox.vt.edu/filebox/F/fenris/smc9/smc9-12.tar.gz - - -Contacting me: - erik@mail.vt.edu diff --git a/Documentation/networking/device_drivers/hamradio/baycom.rst b/Documentation/networking/device_drivers/hamradio/baycom.rst deleted file mode 100644 index fe2d010f0e86..000000000000 --- a/Documentation/networking/device_drivers/hamradio/baycom.rst +++ /dev/null @@ -1,174 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -=============================== -Linux Drivers for Baycom Modems -=============================== - -Thomas M. Sailer, HB9JNX/AE4WA, - -The drivers for the baycom modems have been split into -separate drivers as they did not share any code, and the driver -and device names have changed. - -This document describes the Linux Kernel Drivers for simple Baycom style -amateur radio modems. - -The following drivers are available: -==================================== - -baycom_ser_fdx: - This driver supports the SER12 modems either full or half duplex. - Its baud rate may be changed via the ``baud`` module parameter, - therefore it supports just about every bit bang modem on a - serial port. Its devices are called bcsf0 through bcsf3. - This is the recommended driver for SER12 type modems, - however if you have a broken UART clone that does not have working - delta status bits, you may try baycom_ser_hdx. - -baycom_ser_hdx: - This is an alternative driver for SER12 type modems. - It only supports half duplex, and only 1200 baud. Its devices - are called bcsh0 through bcsh3. Use this driver only if baycom_ser_fdx - does not work with your UART. - -baycom_par: - This driver supports the par96 and picpar modems. - Its devices are called bcp0 through bcp3. - -baycom_epp: - This driver supports the EPP modem. - Its devices are called bce0 through bce3. - This driver is work-in-progress. - -The following modems are supported: - -======= ======================================================================== -ser12 This is a very simple 1200 baud AFSK modem. The modem consists only - of a modulator/demodulator chip, usually a TI TCM3105. The computer - is responsible for regenerating the receiver bit clock, as well as - for handling the HDLC protocol. The modem connects to a serial port, - hence the name. Since the serial port is not used as an async serial - port, the kernel driver for serial ports cannot be used, and this - driver only supports standard serial hardware (8250, 16450, 16550) - -par96 This is a modem for 9600 baud FSK compatible to the G3RUH standard. - The modem does all the filtering and regenerates the receiver clock. - Data is transferred from and to the PC via a shift register. - The shift register is filled with 16 bits and an interrupt is signalled. - The PC then empties the shift register in a burst. This modem connects - to the parallel port, hence the name. The modem leaves the - implementation of the HDLC protocol and the scrambler polynomial to - the PC. - -picpar This is a redesign of the par96 modem by Henning Rech, DF9IC. The modem - is protocol compatible to par96, but uses only three low power ICs - and can therefore be fed from the parallel port and does not require - an additional power supply. Furthermore, it incorporates a carrier - detect circuitry. - -EPP This is a high-speed modem adaptor that connects to an enhanced parallel - port. - - Its target audience is users working over a high speed hub (76.8kbit/s). - -eppfpga This is a redesign of the EPP adaptor. -======= ======================================================================== - -All of the above modems only support half duplex communications. However, -the driver supports the KISS (see below) fullduplex command. It then simply -starts to send as soon as there's a packet to transmit and does not care -about DCD, i.e. it starts to send even if there's someone else on the channel. -This command is required by some implementations of the DAMA channel -access protocol. - - -The Interface of the drivers -============================ - -Unlike previous drivers, these drivers are no longer character devices, -but they are now true kernel network interfaces. Installation is therefore -simple. Once installed, four interfaces named bc{sf,sh,p,e}[0-3] are available. -sethdlc from the ax25 utilities may be used to set driver states etc. -Users of userland AX.25 stacks may use the net2kiss utility (also available -in the ax25 utilities package) to convert packets of a network interface -to a KISS stream on a pseudo tty. There's also a patch available from -me for WAMPES which allows attaching a kernel network interface directly. - - -Configuring the driver -====================== - -Every time a driver is inserted into the kernel, it has to know which -modems it should access at which ports. This can be done with the setbaycom -utility. If you are only using one modem, you can also configure the -driver from the insmod command line (or by means of an option line in -``/etc/modprobe.d/*.conf``). - -Examples:: - - modprobe baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4 - sethdlc -i bcsf0 -p mode "ser12*" io 0x3f8 irq 4 - -Both lines configure the first port to drive a ser12 modem at the first -serial port (COM1 under DOS). The * in the mode parameter instructs the driver -to use the software DCD algorithm (see below):: - - insmod baycom_par mode="picpar" iobase=0x378 - sethdlc -i bcp0 -p mode "picpar" io 0x378 - -Both lines configure the first port to drive a picpar modem at the -first parallel port (LPT1 under DOS). (Note: picpar implies -hardware DCD, par96 implies software DCD). - -The channel access parameters can be set with sethdlc -a or kissparms. -Note that both utilities interpret the values slightly differently. - - -Hardware DCD versus Software DCD -================================ - -To avoid collisions on the air, the driver must know when the channel is -busy. This is the task of the DCD circuitry/software. The driver may either -utilise a software DCD algorithm (options=1) or use a DCD signal from -the hardware (options=0). - -======= ================================================================= -ser12 if software DCD is utilised, the radio's squelch should always be - open. It is highly recommended to use the software DCD algorithm, - as it is much faster than most hardware squelch circuitry. The - disadvantage is a slightly higher load on the system. - -par96 the software DCD algorithm for this type of modem is rather poor. - The modem simply does not provide enough information to implement - a reasonable DCD algorithm in software. Therefore, if your radio - feeds the DCD input of the PAR96 modem, the use of the hardware - DCD circuitry is recommended. - -picpar the picpar modem features a builtin DCD hardware, which is highly - recommended. -======= ================================================================= - - - -Compatibility with the rest of the Linux kernel -=============================================== - -The serial driver and the baycom serial drivers compete -for the same hardware resources. Of course only one driver can access a given -interface at a time. The serial driver grabs all interfaces it can find at -startup time. Therefore the baycom drivers subsequently won't be able to -access a serial port. You might therefore find it necessary to release -a port owned by the serial driver with 'setserial /dev/ttyS# uart none', where -# is the number of the interface. The baycom drivers do not reserve any -ports at startup, unless one is specified on the 'insmod' command line. Another -method to solve the problem is to compile all drivers as modules and -leave it to kmod to load the correct driver depending on the application. - -The parallel port drivers (baycom_par, baycom_epp) now use the parport subsystem -to arbitrate the ports between different client drivers. - -vy 73s de - -Tom Sailer, sailer@ife.ee.ethz.ch - -hb9jnx @ hb9w.ampr.org diff --git a/Documentation/networking/device_drivers/hamradio/index.rst b/Documentation/networking/device_drivers/hamradio/index.rst deleted file mode 100644 index 6af481c5b020..000000000000 --- a/Documentation/networking/device_drivers/hamradio/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) - -Amateur Radio Device Drivers -============================ - -Contents: - -.. toctree:: - :maxdepth: 2 - - baycom - z8530drv diff --git a/Documentation/networking/device_drivers/hamradio/z8530drv.rst b/Documentation/networking/device_drivers/hamradio/z8530drv.rst deleted file mode 100644 index d2942760f167..000000000000 --- a/Documentation/networking/device_drivers/hamradio/z8530drv.rst +++ /dev/null @@ -1,686 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. include:: - -========================================================= -SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 -========================================================= - - -This is a subset of the documentation. To use this driver you MUST have the -full package from: - -Internet: - - 1. ftp://ftp.ccac.rwth-aachen.de/pub/jr/z8530drv-utils_3.0-3.tar.gz - - 2. ftp://ftp.pspt.fi/pub/ham/linux/ax25/z8530drv-utils_3.0-3.tar.gz - -Please note that the information in this document may be hopelessly outdated. -A new version of the documentation, along with links to other important -Linux Kernel AX.25 documentation and programs, is available on -http://yaina.de/jreuter - -Copyright |copy| 1993,2000 by Joerg Reuter DL1BKE - -portions Copyright |copy| 1993 Guido ten Dolle PE1NNZ - -for the complete copyright notice see >> Copying.Z8530DRV << - -1. Initialization of the driver -=============================== - -To use the driver, 3 steps must be performed: - - 1. if compiled as module: loading the module - 2. Setup of hardware, MODEM and KISS parameters with sccinit - 3. Attach each channel to the Linux kernel AX.25 with "ifconfig" - -Unlike the versions below 2.4 this driver is a real network device -driver. If you want to run xNOS instead of our fine kernel AX.25 -use a 2.x version (available from above sites) or read the -AX.25-HOWTO on how to emulate a KISS TNC on network device drivers. - - -1.1 Loading the module -====================== - -(If you're going to compile the driver as a part of the kernel image, - skip this chapter and continue with 1.2) - -Before you can use a module, you'll have to load it with:: - - insmod scc.o - -please read 'man insmod' that comes with module-init-tools. - -You should include the insmod in one of the /etc/rc.d/rc.* files, -and don't forget to insert a call of sccinit after that. It -will read your /etc/z8530drv.conf. - -1.2. /etc/z8530drv.conf -======================= - -To setup all parameters you must run /sbin/sccinit from one -of your rc.*-files. This has to be done BEFORE you can -"ifconfig" an interface. Sccinit reads the file /etc/z8530drv.conf -and sets the hardware, MODEM and KISS parameters. A sample file is -delivered with this package. Change it to your needs. - -The file itself consists of two main sections. - -1.2.1 configuration of hardware parameters -========================================== - -The hardware setup section defines the following parameters for each -Z8530:: - - chip 1 - data_a 0x300 # data port A - ctrl_a 0x304 # control port A - data_b 0x301 # data port B - ctrl_b 0x305 # control port B - irq 5 # IRQ No. 5 - pclock 4915200 # clock - board BAYCOM # hardware type - escc no # enhanced SCC chip? (8580/85180/85280) - vector 0 # latch for interrupt vector - special no # address of special function register - option 0 # option to set via sfr - - -chip - - this is just a delimiter to make sccinit a bit simpler to - program. A parameter has no effect. - -data_a - - the address of the data port A of this Z8530 (needed) -ctrl_a - - the address of the control port A (needed) -data_b - - the address of the data port B (needed) -ctrl_b - - the address of the control port B (needed) - -irq - - the used IRQ for this chip. Different chips can use different - IRQs or the same. If they share an interrupt, it needs to be - specified within one chip-definition only. - -pclock - the clock at the PCLK pin of the Z8530 (option, 4915200 is - default), measured in Hertz - -board - - the "type" of the board: - - ======================= ======== - SCC type value - ======================= ======== - PA0HZP SCC card PA0HZP - EAGLE card EAGLE - PC100 card PC100 - PRIMUS-PC (DG9BL) card PRIMUS - BayCom (U)SCC card BAYCOM - ======================= ======== - -escc - - if you want support for ESCC chips (8580, 85180, 85280), set - this to "yes" (option, defaults to "no") - -vector - - address of the vector latch (aka "intack port") for PA0HZP - cards. There can be only one vector latch for all chips! - (option, defaults to 0) - -special - - address of the special function register on several cards. - (option, defaults to 0) - -option - The value you write into that register (option, default is 0) - -You can specify up to four chips (8 channels). If this is not enough, -just change:: - - #define MAXSCC 4 - -to a higher value. - -Example for the BAYCOM USCC: ----------------------------- - -:: - - chip 1 - data_a 0x300 # data port A - ctrl_a 0x304 # control port A - data_b 0x301 # data port B - ctrl_b 0x305 # control port B - irq 5 # IRQ No. 5 (#) - board BAYCOM # hardware type (*) - # - # SCC chip 2 - # - chip 2 - data_a 0x302 - ctrl_a 0x306 - data_b 0x303 - ctrl_b 0x307 - board BAYCOM - -An example for a PA0HZP card: ------------------------------ - -:: - - chip 1 - data_a 0x153 - data_b 0x151 - ctrl_a 0x152 - ctrl_b 0x150 - irq 9 - pclock 4915200 - board PA0HZP - vector 0x168 - escc no - # - # - # - chip 2 - data_a 0x157 - data_b 0x155 - ctrl_a 0x156 - ctrl_b 0x154 - irq 9 - pclock 4915200 - board PA0HZP - vector 0x168 - escc no - -A DRSI would should probably work with this: --------------------------------------------- -(actually: two DRSI cards...) - -:: - - chip 1 - data_a 0x303 - data_b 0x301 - ctrl_a 0x302 - ctrl_b 0x300 - irq 7 - pclock 4915200 - board DRSI - escc no - # - # - # - chip 2 - data_a 0x313 - data_b 0x311 - ctrl_a 0x312 - ctrl_b 0x310 - irq 7 - pclock 4915200 - board DRSI - escc no - -Note that you cannot use the on-board baudrate generator off DRSI -cards. Use "mode dpll" for clock source (see below). - -This is based on information provided by Mike Bilow (and verified -by Paul Helay) - -The utility "gencfg" --------------------- - -If you only know the parameters for the PE1CHL driver for DOS, -run gencfg. It will generate the correct port addresses (I hope). -Its parameters are exactly the same as the ones you use with -the "attach scc" command in net, except that the string "init" must -not appear. Example:: - - gencfg 2 0x150 4 2 0 1 0x168 9 4915200 - -will print a skeleton z8530drv.conf for the OptoSCC to stdout. - -:: - - gencfg 2 0x300 2 4 5 -4 0 7 4915200 0x10 - -does the same for the BAYCOM USCC card. In my opinion it is much easier -to edit scc_config.h... - - -1.2.2 channel configuration -=========================== - -The channel definition is divided into three sub sections for each -channel: - -An example for scc0:: - - # DEVICE - - device scc0 # the device for the following params - - # MODEM / BUFFERS - - speed 1200 # the default baudrate - clock dpll # clock source: - # dpll = normal half duplex operation - # external = MODEM provides own Rx/Tx clock - # divider = use full duplex divider if - # installed (1) - mode nrzi # HDLC encoding mode - # nrzi = 1k2 MODEM, G3RUH 9k6 MODEM - # nrz = DF9IC 9k6 MODEM - # - bufsize 384 # size of buffers. Note that this must include - # the AX.25 header, not only the data field! - # (optional, defaults to 384) - - # KISS (Layer 1) - - txdelay 36 # (see chapter 1.4) - persist 64 - slot 8 - tail 8 - fulldup 0 - wait 12 - min 3 - maxkey 7 - idle 3 - maxdef 120 - group 0 - txoff off - softdcd on - slip off - -The order WITHIN these sections is unimportant. The order OF these -sections IS important. The MODEM parameters are set with the first -recognized KISS parameter... - -Please note that you can initialize the board only once after boot -(or insmod). You can change all parameters but "mode" and "clock" -later with the Sccparam program or through KISS. Just to avoid -security holes... - -(1) this divider is usually mounted on the SCC-PBC (PA0HZP) or not - present at all (BayCom). It feeds back the output of the DPLL - (digital pll) as transmit clock. Using this mode without a divider - installed will normally result in keying the transceiver until - maxkey expires --- of course without sending anything (useful). - -2. Attachment of a channel by your AX.25 software -================================================= - -2.1 Kernel AX.25 -================ - -To set up an AX.25 device you can simply type:: - - ifconfig scc0 44.128.1.1 hw ax25 dl0tha-7 - -This will create a network interface with the IP number 44.128.20.107 -and the callsign "dl0tha". If you do not have any IP number (yet) you -can use any of the 44.128.0.0 network. Note that you do not need -axattach. The purpose of axattach (like slattach) is to create a KISS -network device linked to a TTY. Please read the documentation of the -ax25-utils and the AX.25-HOWTO to learn how to set the parameters of -the kernel AX.25. - -2.2 NOS, NET and TFKISS -======================= - -Since the TTY driver (aka KISS TNC emulation) is gone you need -to emulate the old behaviour. The cost of using these programs is -that you probably need to compile the kernel AX.25, regardless of whether -you actually use it or not. First setup your /etc/ax25/axports, -for example:: - - 9k6 dl0tha-9 9600 255 4 9600 baud port (scc3) - axlink dl0tha-15 38400 255 4 Link to NOS - -Now "ifconfig" the scc device:: - - ifconfig scc3 44.128.1.1 hw ax25 dl0tha-9 - -You can now axattach a pseudo-TTY:: - - axattach /dev/ptys0 axlink - -and start your NOS and attach /dev/ptys0 there. The problem is that -NOS is reachable only via digipeating through the kernel AX.25 -(disastrous on a DAMA controlled channel). To solve this problem, -configure "rxecho" to echo the incoming frames from "9k6" to "axlink" -and outgoing frames from "axlink" to "9k6" and start:: - - rxecho - -Or simply use "kissbridge" coming with z8530drv-utils:: - - ifconfig scc3 hw ax25 dl0tha-9 - kissbridge scc3 /dev/ptys0 - - -3. Adjustment and Display of parameters -======================================= - -3.1 Displaying SCC Parameters: -============================== - -Once a SCC channel has been attached, the parameter settings and -some statistic information can be shown using the param program:: - - dl1bke-u:~$ sccstat scc0 - - Parameters: - - speed : 1200 baud - txdelay : 36 - persist : 255 - slottime : 0 - txtail : 8 - fulldup : 1 - waittime : 12 - mintime : 3 sec - maxkeyup : 7 sec - idletime : 3 sec - maxdefer : 120 sec - group : 0x00 - txoff : off - softdcd : on - SLIP : off - - Status: - - HDLC Z8530 Interrupts Buffers - ----------------------------------------------------------------------- - Sent : 273 RxOver : 0 RxInts : 125074 Size : 384 - Received : 1095 TxUnder: 0 TxInts : 4684 NoSpace : 0 - RxErrors : 1591 ExInts : 11776 - TxErrors : 0 SpInts : 1503 - Tx State : idle - - -The status info shown is: - -============== ============================================================== -Sent number of frames transmitted -Received number of frames received -RxErrors number of receive errors (CRC, ABORT) -TxErrors number of discarded Tx frames (due to various reasons) -Tx State status of the Tx interrupt handler: idle/busy/active/tail (2) -RxOver number of receiver overruns -TxUnder number of transmitter underruns -RxInts number of receiver interrupts -TxInts number of transmitter interrupts -EpInts number of receiver special condition interrupts -SpInts number of external/status interrupts -Size maximum size of an AX.25 frame (*with* AX.25 headers!) -NoSpace number of times a buffer could not get allocated -============== ============================================================== - -An overrun is abnormal. If lots of these occur, the product of -baudrate and number of interfaces is too high for the processing -power of your computer. NoSpace errors are unlikely to be caused by the -driver or the kernel AX.25. - - -3.2 Setting Parameters -====================== - - -The setting of parameters of the emulated KISS TNC is done in the -same way in the SCC driver. You can change parameters by using -the kissparms program from the ax25-utils package or use the program -"sccparam":: - - sccparam - -You can change the following parameters: - -=========== ===== -param value -=========== ===== -speed 1200 -txdelay 36 -persist 255 -slottime 0 -txtail 8 -fulldup 1 -waittime 12 -mintime 3 -maxkeyup 7 -idletime 3 -maxdefer 120 -group 0x00 -txoff off -softdcd on -SLIP off -=========== ===== - - -The parameters have the following meaning: - -speed: - The baudrate on this channel in bits/sec - - Example: sccparam /dev/scc3 speed 9600 - -txdelay: - The delay (in units of 10 ms) after keying of the - transmitter, until the first byte is sent. This is usually - called "TXDELAY" in a TNC. When 0 is specified, the driver - will just wait until the CTS signal is asserted. This - assumes the presence of a timer or other circuitry in the - MODEM and/or transmitter, that asserts CTS when the - transmitter is ready for data. - A normal value of this parameter is 30-36. - - Example: sccparam /dev/scc0 txd 20 - -persist: - This is the probability that the transmitter will be keyed - when the channel is found to be free. It is a value from 0 - to 255, and the probability is (value+1)/256. The value - should be somewhere near 50-60, and should be lowered when - the channel is used more heavily. - - Example: sccparam /dev/scc2 persist 20 - -slottime: - This is the time between samples of the channel. It is - expressed in units of 10 ms. About 200-300 ms (value 20-30) - seems to be a good value. - - Example: sccparam /dev/scc0 slot 20 - -tail: - The time the transmitter will remain keyed after the last - byte of a packet has been transferred to the SCC. This is - necessary because the CRC and a flag still have to leave the - SCC before the transmitter is keyed down. The value depends - on the baudrate selected. A few character times should be - sufficient, e.g. 40ms at 1200 baud. (value 4) - The value of this parameter is in 10 ms units. - - Example: sccparam /dev/scc2 4 - -full: - The full-duplex mode switch. This can be one of the following - values: - - 0: The interface will operate in CSMA mode (the normal - half-duplex packet radio operation) - 1: Fullduplex mode, i.e. the transmitter will be keyed at - any time, without checking the received carrier. It - will be unkeyed when there are no packets to be sent. - 2: Like 1, but the transmitter will remain keyed, also - when there are no packets to be sent. Flags will be - sent in that case, until a timeout (parameter 10) - occurs. - - Example: sccparam /dev/scc0 fulldup off - -wait: - The initial waittime before any transmit attempt, after the - frame has been queue for transmit. This is the length of - the first slot in CSMA mode. In full duplex modes it is - set to 0 for maximum performance. - The value of this parameter is in 10 ms units. - - Example: sccparam /dev/scc1 wait 4 - -maxkey: - The maximal time the transmitter will be keyed to send - packets, in seconds. This can be useful on busy CSMA - channels, to avoid "getting a bad reputation" when you are - generating a lot of traffic. After the specified time has - elapsed, no new frame will be started. Instead, the trans- - mitter will be switched off for a specified time (parameter - min), and then the selected algorithm for keyup will be - started again. - The value 0 as well as "off" will disable this feature, - and allow infinite transmission time. - - Example: sccparam /dev/scc0 maxk 20 - -min: - This is the time the transmitter will be switched off when - the maximum transmission time is exceeded. - - Example: sccparam /dev/scc3 min 10 - -idle: - This parameter specifies the maximum idle time in full duplex - 2 mode, in seconds. When no frames have been sent for this - time, the transmitter will be keyed down. A value of 0 is - has same result as the fullduplex mode 1. This parameter - can be disabled. - - Example: sccparam /dev/scc2 idle off # transmit forever - -maxdefer - This is the maximum time (in seconds) to wait for a free channel - to send. When this timer expires the transmitter will be keyed - IMMEDIATELY. If you love to get trouble with other users you - should set this to a very low value ;-) - - Example: sccparam /dev/scc0 maxdefer 240 # 2 minutes - - -txoff: - When this parameter has the value 0, the transmission of packets - is enable. Otherwise it is disabled. - - Example: sccparam /dev/scc2 txoff on - -group: - It is possible to build special radio equipment to use more than - one frequency on the same band, e.g. using several receivers and - only one transmitter that can be switched between frequencies. - Also, you can connect several radios that are active on the same - band. In these cases, it is not possible, or not a good idea, to - transmit on more than one frequency. The SCC driver provides a - method to lock transmitters on different interfaces, using the - "param group " command. This will only work when - you are using CSMA mode (parameter full = 0). - - The number must be 0 if you want no group restrictions, and - can be computed as follows to create restricted groups: - is the sum of some OCTAL numbers: - - - === ======================================================= - 200 This transmitter will only be keyed when all other - transmitters in the group are off. - 100 This transmitter will only be keyed when the carrier - detect of all other interfaces in the group is off. - 0xx A byte that can be used to define different groups. - Interfaces are in the same group, when the logical AND - between their xx values is nonzero. - === ======================================================= - - Examples: - - When 2 interfaces use group 201, their transmitters will never be - keyed at the same time. - - When 2 interfaces use group 101, the transmitters will only key - when both channels are clear at the same time. When group 301, - the transmitters will not be keyed at the same time. - - Don't forget to convert the octal numbers into decimal before - you set the parameter. - - Example: (to be written) - -softdcd: - use a software dcd instead of the real one... Useful for a very - slow squelch. - - Example: sccparam /dev/scc0 soft on - - -4. Problems -=========== - -If you have tx-problems with your BayCom USCC card please check -the manufacturer of the 8530. SGS chips have a slightly -different timing. Try Zilog... A solution is to write to register 8 -instead to the data port, but this won't work with the ESCC chips. -*SIGH!* - -A very common problem is that the PTT locks until the maxkeyup timer -expires, although interrupts and clock source are correct. In most -cases compiling the driver with CONFIG_SCC_DELAY (set with -make config) solves the problems. For more hints read the (pseudo) FAQ -and the documentation coming with z8530drv-utils. - -I got reports that the driver has problems on some 386-based systems. -(i.e. Amstrad) Those systems have a bogus AT bus timing which will -lead to delayed answers on interrupts. You can recognize these -problems by looking at the output of Sccstat for the suspected -port. If it shows under- and overruns you own such a system. - -Delayed processing of received data: This depends on - -- the kernel version - -- kernel profiling compiled or not - -- a high interrupt load - -- a high load of the machine --- running X, Xmorph, XV and Povray, - while compiling the kernel... hmm ... even with 32 MB RAM ... ;-) - Or running a named for the whole .ampr.org domain on an 8 MB - box... - -- using information from rxecho or kissbridge. - -Kernel panics: please read /linux/README and find out if it -really occurred within the scc driver. - -If you cannot solve a problem, send me - -- a description of the problem, -- information on your hardware (computer system, scc board, modem) -- your kernel version -- the output of cat /proc/net/z8530 - -4. Thor RLC100 -============== - -Mysteriously this board seems not to work with the driver. Anyone -got it up-and-running? - - -Many thanks to Linus Torvalds and Alan Cox for including the driver -in the Linux standard distribution and their support. - -:: - - Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org - AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU - Internet: jreuter@yaina.de - WWW : http://yaina.de/jreuter diff --git a/Documentation/networking/device_drivers/index.rst b/Documentation/networking/device_drivers/index.rst index 1df51c9f7827..1f54f01d24be 100644 --- a/Documentation/networking/device_drivers/index.rst +++ b/Documentation/networking/device_drivers/index.rst @@ -13,6 +13,5 @@ Contents: cellular/index ethernet/index fddi/index - hamradio/index wifi/index wwan/index diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index c2406bd8ae0b..44a422ad3b05 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -17,7 +17,6 @@ Contents: diagnostic/index dsa/index devlink/index - caif/index ethtool-netlink ieee802154 iso15765-2 @@ -41,11 +40,9 @@ Contents: tls-handshake nfc 6lowpan - 6pack arcnet-hardware arcnet atm - ax25 bonding cdc_mbim dctcp diff --git a/Documentation/staging/magic-number.rst b/Documentation/staging/magic-number.rst index 79afddf0e692..670d3189a976 100644 --- a/Documentation/staging/magic-number.rst +++ b/Documentation/staging/magic-number.rst @@ -72,11 +72,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/uapi/l APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip/slip.h`` -BAYCOM_MAGIC 19730510 baycom_state ``drivers/net/hamradio/baycom_epp.c`` -HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` diff --git a/Documentation/subsystem-apis.rst b/Documentation/subsystem-apis.rst index ff4fe8c936c8..b1ad48bb4001 100644 --- a/Documentation/subsystem-apis.rst +++ b/Documentation/subsystem-apis.rst @@ -46,7 +46,6 @@ Networking interfaces networking/index netlabel/index infiniband/index - isdn/index mhi/index Storage interfaces diff --git a/Documentation/translations/it_IT/staging/magic-number.rst b/Documentation/translations/it_IT/staging/magic-number.rst index cd8f23571835..43dd6398300b 100644 --- a/Documentation/translations/it_IT/staging/magic-number.rst +++ b/Documentation/translations/it_IT/staging/magic-number.rst @@ -78,11 +78,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` diff --git a/Documentation/translations/sp_SP/process/magic-number.rst b/Documentation/translations/sp_SP/process/magic-number.rst index beb4b4c1de11..f5b4c3f2849f 100644 --- a/Documentation/translations/sp_SP/process/magic-number.rst +++ b/Documentation/translations/sp_SP/process/magic-number.rst @@ -77,11 +77,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` diff --git a/Documentation/translations/zh_CN/networking/index.rst b/Documentation/translations/zh_CN/networking/index.rst index c276c0993c51..333e9f6cafff 100644 --- a/Documentation/translations/zh_CN/networking/index.rst +++ b/Documentation/translations/zh_CN/networking/index.rst @@ -42,7 +42,6 @@ Todolist: * diagnostic/index * dsa/index * devlink/index -* caif/index * ethtool-netlink * ieee802154 * iso15765-2 diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 4ebc84cc0c54..05ee75cf4346 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -70,11 +70,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst index 5582df6d7ca7..bc7eb025dd1e 100644 --- a/Documentation/translations/zh_TW/process/magic-number.rst +++ b/Documentation/translations/zh_TW/process/magic-number.rst @@ -64,11 +64,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` diff --git a/MAINTAINERS b/MAINTAINERS index 090b52a5c341..473270d8e0e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -103,12 +103,6 @@ F: Documentation/networking/6lowpan.rst F: include/net/6lowpan.h F: net/6lowpan/ -6PACK NETWORK DRIVER FOR AX.25 -M: Andreas Koensgen -L: linux-hams@vger.kernel.org -S: Maintained -F: drivers/net/hamradio/6pack.c - 802.11 (including CFG80211/NL80211) M: Johannes Berg L: linux-wireless@vger.kernel.org @@ -144,7 +138,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git F: drivers/tty/serial/8250* F: include/linux/serial_8250.h -8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] +8390 NETWORK DRIVERS [NE2000, 3C503, etc.] L: netdev@vger.kernel.org S: Orphan / Obsolete F: drivers/net/ethernet/8390/ @@ -4158,10 +4152,12 @@ 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 @@ -4281,14 +4277,6 @@ S: Maintained F: Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml F: drivers/video/backlight/aw99706.c -AX.25 NETWORK LAYER -L: linux-hams@vger.kernel.org -S: Orphan -W: https://linux-ax25.in-berlin.de -F: include/net/ax25.h -F: include/uapi/linux/ax25.h -F: net/ax25/ - AXENTIA ARM DEVICES M: Peter Rosin L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -4430,13 +4418,6 @@ F: include/uapi/linux/batadv_packet.h F: include/uapi/linux/batman_adv.h F: net/batman-adv/ -BAYCOM/HDLCDRV DRIVERS FOR AX.25 -M: Thomas Sailer -L: linux-hams@vger.kernel.org -S: Maintained -W: http://www.baycom.org/~tom/ham/ham.html -F: drivers/net/hamradio/baycom* - BCACHE (BLOCK LAYER CACHE) M: Coly Li M: Kent Overstreet @@ -5675,15 +5656,6 @@ T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/cafe_ccic* F: drivers/media/platform/marvell/ -CAIF NETWORK LAYER -L: netdev@vger.kernel.org -S: Orphan -F: Documentation/networking/caif/ -F: drivers/net/caif/ -F: include/net/caif/ -F: include/uapi/linux/caif/ -F: net/caif/ - CAKE QDISC M: Toke Høiland-Jørgensen L: cake@lists.bufferbloat.net (moderated for non-subscribers) @@ -7030,20 +7002,6 @@ S: Maintained F: drivers/rtc/rtc-ds1685.c F: include/linux/rtc/ds1685.h -DAMA SLAVE for AX.25 -M: Joerg Reuter -L: linux-hams@vger.kernel.org -S: Maintained -W: http://yaina.de/jreuter/ -W: http://www.qsl.net/dl1bke/ -F: net/ax25/af_ax25.c -F: net/ax25/ax25_dev.c -F: net/ax25/ax25_ds_* -F: net/ax25/ax25_in.c -F: net/ax25/ax25_out.c -F: net/ax25/ax25_timer.c -F: net/ax25/sysctl_net_ax25.c - DASHARO ACPI PLATFORM DRIVER M: Michał Kopeć S: Maintained @@ -11523,11 +11481,6 @@ T: git https://github.com/Rust-for-Linux/linux.git timekeeping-next F: rust/kernel/time.rs F: rust/kernel/time/ -HIGH-SPEED SCC DRIVER FOR AX.25 -L: linux-hams@vger.kernel.org -S: Orphan -F: drivers/net/hamradio/scc.c - HIGHPOINT ROCKETRAID 3xxx RAID DRIVER M: HighPoint Linux Team S: Supported @@ -13677,25 +13630,6 @@ S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master F: drivers/infiniband/ulp/isert -ISDN/CMTP OVER BLUETOOTH -L: netdev@vger.kernel.org -S: Orphan -W: http://www.isdn4linux.de -F: Documentation/isdn/ -F: drivers/isdn/capi/ -F: include/linux/isdn/ -F: include/uapi/linux/isdn/ -F: net/bluetooth/cmtp/ - -ISDN/mISDN SUBSYSTEM -L: netdev@vger.kernel.org -S: Orphan -W: http://www.isdn4linux.de -F: drivers/isdn/Kconfig -F: drivers/isdn/Makefile -F: drivers/isdn/hardware/ -F: drivers/isdn/mISDN/ - ISL28022 HARDWARE MONITORING DRIVER M: Carsten Spieß L: linux-hwmon@vger.kernel.org @@ -18442,14 +18376,6 @@ F: net/bridge/br_netfilter*.c F: net/netfilter/ F: tools/testing/selftests/net/netfilter/ -NETROM NETWORK LAYER -L: linux-hams@vger.kernel.org -S: Orphan -W: https://linux-ax25.in-berlin.de -F: include/net/netrom.h -F: include/uapi/linux/netrom.h -F: net/netrom/ - NETRONIX EMBEDDED CONTROLLER M: Jonathan Neuschäfer S: Maintained @@ -23284,14 +23210,6 @@ F: include/linux/mfd/rohm-bd96802.h F: include/linux/mfd/rohm-generic.h F: include/linux/mfd/rohm-shared.h -ROSE NETWORK LAYER -L: linux-hams@vger.kernel.org -S: Orphan -W: https://linux-ax25.in-berlin.de -F: include/net/rose.h -F: include/uapi/linux/rose.h -F: net/rose/ - ROTATION DRIVER FOR ALLWINNER A83T M: Jernej Skrabec L: linux-media@vger.kernel.org @@ -29346,13 +29264,6 @@ F: lib/decompress_unxz.c F: lib/xz/ F: scripts/xz_wrap.sh -YAM DRIVER FOR AX.25 -M: Jean-Paul Roubelat -L: linux-hams@vger.kernel.org -S: Maintained -F: drivers/net/hamradio/yam* -F: include/linux/yam.h - YAMA SECURITY MODULE M: Kees Cook S: Supported @@ -29374,16 +29285,6 @@ S: Maintained F: Documentation/input/devices/yealink.rst F: drivers/input/misc/yealink.* -Z8530 DRIVER FOR AX.25 -M: Joerg Reuter -L: linux-hams@vger.kernel.org -S: Maintained -W: http://yaina.de/jreuter/ -W: http://www.qsl.net/dl1bke/ -F: Documentation/networking/device_drivers/hamradio/z8530drv.rst -F: drivers/net/hamradio/*scc.c -F: drivers/net/hamradio/z8530.h - ZD1211RW WIRELESS DRIVER L: linux-wireless@vger.kernel.org S: Orphan diff --git a/arch/alpha/configs/defconfig b/arch/alpha/configs/defconfig index 3280bd9e6578..29748bbd94f3 100644 --- a/arch/alpha/configs/defconfig +++ b/arch/alpha/configs/defconfig @@ -45,7 +45,6 @@ CONFIG_NET_TULIP=y CONFIG_DE2104X=m CONFIG_TULIP=y CONFIG_TULIP_MMIO=y -CONFIG_YELLOWFIN=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_RTC_CLASS=y diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 81199dddcde7..01d72580bcc5 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -52,9 +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 @@ -108,7 +105,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/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig index 4d720001c12e..8a5dcca743fc 100644 --- a/arch/arm/configs/neponset_defconfig +++ b/arch/arm/configs/neponset_defconfig @@ -40,7 +40,6 @@ CONFIG_BLK_DEV_SD=m CONFIG_NETDEVICES=y CONFIG_NET_VENDOR_SMC=y CONFIG_PCMCIA_PCNET=y -CONFIG_SMC9194=y CONFIG_SMC91X=y CONFIG_NET_PCMCIA=y # CONFIG_INPUT_MOUSE is not set diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index ba6ddaf82344..2fe25f5eb9a5 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -37,7 +37,6 @@ CONFIG_CFG80211=y CONFIG_CFG80211_DEBUGFS=y CONFIG_MAC80211=y CONFIG_MAC80211_LEDS=y -CONFIG_CAIF=y CONFIG_NFC=m CONFIG_NFC_HCI=m CONFIG_NFC_SHDLC=y diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index d10b3d4adbd1..acbab8dae53f 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -28,7 +28,6 @@ CONFIG_NETFILTER=y CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_FQ_CODEL=y -CONFIG_HAMRADIO=y CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_MTD=y diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 3b64e151e187..aa63ada62e28 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -84,16 +84,6 @@ CONFIG_IP_VS_FTP=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_VLAN_8021Q_GVRP=y -CONFIG_HAMRADIO=y -CONFIG_AX25=m -CONFIG_NETROM=m -CONFIG_ROSE=m -CONFIG_MKISS=m -CONFIG_6PACK=m -CONFIG_BPQETHER=m -CONFIG_BAYCOM_SER_FDX=m -CONFIG_BAYCOM_SER_HDX=m -CONFIG_YAM=m CONFIG_FW_LOADER=m CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m diff --git a/arch/mips/configs/db1xxx_defconfig b/arch/mips/configs/db1xxx_defconfig index 281dd7d0f805..49fe970c2860 100644 --- a/arch/mips/configs/db1xxx_defconfig +++ b/arch/mips/configs/db1xxx_defconfig @@ -105,7 +105,6 @@ CONFIG_PATA_PCMCIA=y CONFIG_PATA_PLATFORM=y CONFIG_NETDEVICES=y CONFIG_NLMON=y -CONFIG_PCMCIA_3C589=y CONFIG_MIPS_AU1X00_ENET=y CONFIG_SMC91X=y CONFIG_SMSC911X=y diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig index fdd28a89e336..ed1a8f80f96e 100644 --- a/arch/mips/configs/gpr_defconfig +++ b/arch/mips/configs/gpr_defconfig @@ -87,9 +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 @@ -104,7 +101,6 @@ CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m CONFIG_NET_SCH_PRIO=m CONFIG_NET_SCH_RED=m CONFIG_NET_SCH_SFQ=m @@ -130,17 +126,6 @@ CONFIG_NET_EMATCH_TEXT=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=y CONFIG_NET_PKTGEN=m -CONFIG_HAMRADIO=y -CONFIG_AX25=m -# CONFIG_AX25_DAMA_SLAVE is not set -CONFIG_NETROM=m -CONFIG_ROSE=m -CONFIG_MKISS=m -CONFIG_6PACK=m -CONFIG_BPQETHER=m -CONFIG_BAYCOM_SER_FDX=m -CONFIG_BAYCOM_SER_HDX=m -CONFIG_YAM=m CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_MTD=y @@ -167,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 4823dc01dcd0..3629afbe5d75 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -132,9 +132,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 @@ -149,7 +146,6 @@ CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m CONFIG_NET_SCH_PRIO=m CONFIG_NET_SCH_RED=m CONFIG_NET_SCH_SFQ=m @@ -175,17 +171,6 @@ CONFIG_NET_EMATCH_TEXT=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=y CONFIG_NET_PKTGEN=m -CONFIG_HAMRADIO=y -CONFIG_AX25=m -# CONFIG_AX25_DAMA_SLAVE is not set -CONFIG_NETROM=m -CONFIG_ROSE=m -CONFIG_MKISS=m -CONFIG_6PACK=m -CONFIG_BPQETHER=m -CONFIG_BAYCOM_SER_FDX=m -CONFIG_BAYCOM_SER_HDX=m -CONFIG_YAM=m CONFIG_BT=m CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y @@ -242,23 +227,11 @@ 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 CONFIG_TYPHOON=m CONFIG_ADAPTEC_STARFIRE=m CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m -CONFIG_PCMCIA_NMCLAN=m CONFIG_B44=m CONFIG_BNX2=m CONFIG_TIGON3=m @@ -272,7 +245,6 @@ CONFIG_ULI526X=m CONFIG_PCMCIA_XIRCOM=m CONFIG_DL2K=m CONFIG_SUNDANCE=m -CONFIG_PCMCIA_FMVJ18X=m CONFIG_E100=m CONFIG_E1000=m CONFIG_SKGE=m @@ -281,12 +253,9 @@ CONFIG_MYRI10GE=m CONFIG_FEALNX=m CONFIG_NATSEMI=m CONFIG_NS83820=m -CONFIG_PCMCIA_AXNET=m CONFIG_NE2K_PCI=m CONFIG_PCMCIA_PCNET=m CONFIG_FORCEDETH=m -CONFIG_HAMACHI=m -CONFIG_YELLOWFIN=m CONFIG_QLA3XXX=m CONFIG_8139CP=m CONFIG_8139TOO=m @@ -295,7 +264,6 @@ CONFIG_8139TOO_8129=y CONFIG_R8169=m CONFIG_SIS900=m CONFIG_SIS190=m -CONFIG_PCMCIA_SMC91C92=m CONFIG_EPIC100=m CONFIG_HAPPYMEAL=m CONFIG_SUNGEM=m diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig index 30d18b084cda..a88322fe3935 100644 --- a/arch/mips/configs/rb532_defconfig +++ b/arch/mips/configs/rb532_defconfig @@ -95,7 +95,6 @@ CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m CONFIG_NET_ACT_PEDIT=m -CONFIG_HAMRADIO=y CONFIG_MTD=y CONFIG_MTD_BLOCK=y CONFIG_MTD_BLOCK2MTD=y diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index b1e67ff0c4f0..ad9fbd0cbb38 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -147,13 +147,6 @@ CONFIG_NET_CLS_FW=m CONFIG_NET_CLS_U32=m CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m -CONFIG_HAMRADIO=y -CONFIG_AX25=m -CONFIG_NETROM=m -CONFIG_ROSE=m -CONFIG_MKISS=m -CONFIG_6PACK=m -CONFIG_BPQETHER=m CONFIG_CONNECTOR=m CONFIG_PARPORT=m CONFIG_PARPORT_PC=m diff --git a/arch/mips/configs/rt305x_defconfig b/arch/mips/configs/rt305x_defconfig index 8f9701efef19..c920976bedd0 100644 --- a/arch/mips/configs/rt305x_defconfig +++ b/arch/mips/configs/rt305x_defconfig @@ -64,7 +64,6 @@ CONFIG_BRIDGE=y # CONFIG_BRIDGE_IGMP_SNOOPING is not set CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y -CONFIG_HAMRADIO=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig index aae8497b6872..f1c53bbb72e9 100644 --- a/arch/mips/configs/xway_defconfig +++ b/arch/mips/configs/xway_defconfig @@ -66,7 +66,6 @@ CONFIG_BRIDGE=y # CONFIG_BRIDGE_IGMP_SNOOPING is not set CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y -CONFIG_HAMRADIO=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 7b04e2e787a7..ccabc6e17168 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -225,8 +225,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 @@ -238,7 +236,6 @@ CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m CONFIG_NET_SCH_PRIO=m CONFIG_NET_SCH_MULTIQ=m CONFIG_NET_SCH_RED=m @@ -396,21 +393,11 @@ 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 CONFIG_VORTEX=m CONFIG_TYPHOON=m CONFIG_ADAPTEC_STARFIRE=m CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m -CONFIG_PCMCIA_NMCLAN=m CONFIG_MACE=m CONFIG_BMAC=m CONFIG_ATL1=m @@ -433,7 +420,6 @@ CONFIG_DL2K=m CONFIG_SUNDANCE=m CONFIG_FEC_MPC52xx=m CONFIG_GIANFAR=m -CONFIG_PCMCIA_FMVJ18X=m CONFIG_E100=m CONFIG_E1000=m CONFIG_E1000E=m @@ -446,14 +432,10 @@ CONFIG_MYRI10GE=m CONFIG_FEALNX=m CONFIG_NATSEMI=m CONFIG_NS83820=m -CONFIG_PCMCIA_AXNET=m CONFIG_NE2000=m CONFIG_NE2K_PCI=m CONFIG_PCMCIA_PCNET=m -CONFIG_ULTRA=m CONFIG_FORCEDETH=m -CONFIG_HAMACHI=m -CONFIG_YELLOWFIN=m CONFIG_QLA3XXX=m CONFIG_NETXEN_NIC=m CONFIG_8139CP=m @@ -466,7 +448,6 @@ CONFIG_SC92031=m CONFIG_SIS900=m CONFIG_SIS190=m CONFIG_SFC=m -CONFIG_PCMCIA_SMC91C92=m CONFIG_EPIC100=m CONFIG_HAPPYMEAL=m CONFIG_SUNGEM=m diff --git a/drivers/Kconfig b/drivers/Kconfig index c0f1fb893ec0..f2bed2ddeb66 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -61,8 +61,6 @@ source "drivers/macintosh/Kconfig" source "drivers/net/Kconfig" -source "drivers/isdn/Kconfig" - # input before char - char/joystick depends on it. As does USB. source "drivers/input/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 53fbd2e0acdd..0841ea851847 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -124,7 +124,6 @@ obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_ACCESSIBILITY) += accessibility/ -obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_EDAC) += edac/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_PM_OPP) += opp/ 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/Kconfig b/drivers/atm/Kconfig index 63cdb46a3439..cb1dd7789ff1 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -15,306 +15,6 @@ menuconfig ATM_DRIVERS 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 diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index c9eade92019b..b95125a0bf12 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -1,32 +1,3 @@ # 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/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/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.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/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.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/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.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/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.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/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.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/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/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/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.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/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/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/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 - * - * - */ 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/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/drivers/isdn/Kconfig b/drivers/isdn/Kconfig deleted file mode 100644 index 6fd1b3f84a29..000000000000 --- a/drivers/isdn/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# ISDN device configuration -# - -menuconfig ISDN - bool "ISDN support" - depends on NET && NETDEVICES - help - ISDN ("Integrated Services Digital Network", called RNIS in France) - is a fully digital telephone service that can be used for voice and - data connections. If your computer is equipped with an ISDN - adapter you can use it to connect to your Internet service provider - (with SLIP or PPP) faster than via a conventional telephone modem - (though still much slower than with DSL) or to make and accept - voice calls (eg. turning your PC into a software answering machine - or PABX). - - Select this option if you want your kernel to support ISDN. - -if ISDN - -source "drivers/isdn/capi/Kconfig" - -source "drivers/isdn/mISDN/Kconfig" - -endif # ISDN diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile deleted file mode 100644 index d14334f4007e..000000000000 --- a/drivers/isdn/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the kernel ISDN subsystem and device drivers. - -# Object files in subdirectories - -obj-$(CONFIG_BT_CMTP) += capi/ -obj-$(CONFIG_MISDN) += mISDN/ -obj-$(CONFIG_ISDN) += hardware/ diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig deleted file mode 100644 index fdb43a632215..000000000000 --- a/drivers/isdn/capi/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config ISDN_CAPI - def_bool ISDN && BT - help - This provides CAPI (the Common ISDN Application Programming - Interface) Version 2.0, a standard making it easy for programs to - access ISDN hardware in a device independent way. (For details see - .) CAPI supports making and accepting voice - and data connections, controlling call options and protocols, - as well as ISDN supplementary services like call forwarding or - three-party conferences (if supported by the specific hardware - driver). - - This subsystem requires a hardware specific driver. - See CONFIG_BT_CMTP for the last remaining regular driver - in the kernel that uses the CAPI subsystem. - -config CAPI_TRACE - def_bool BT_CMTP - help - If you say Y here, the kernelcapi driver can make verbose traces - of CAPI messages. This feature can be enabled/disabled via IOCTL for - every controller (default disabled). - -config ISDN_CAPI_MIDDLEWARE - def_bool BT_CMTP && TTY - help - This option will enhance the capabilities of the /dev/capi20 - interface. It will provide a means of moving a data connection, - established via the usual /dev/capi20 interface to a special tty - device. If you want to use pppd with pppdcapiplugin to dial up to - your ISP, say Y here. diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile deleted file mode 100644 index 4fd3a4d7133f..000000000000 --- a/drivers/isdn/capi/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the CAPI subsystem used by BT_CMTP - -obj-$(CONFIG_BT_CMTP) += kernelcapi.o -kernelcapi-y := kcapi.o capiutil.o capi.o -kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c deleted file mode 100644 index aa28b1d32c4e..000000000000 --- a/drivers/isdn/capi/capi.c +++ /dev/null @@ -1,1435 +0,0 @@ -/* $Id: capi.c,v 1.1.2.7 2004/04/28 09:48:59 armin Exp $ - * - * CAPI 2.0 Interface for Linux - * - * Copyright 1996 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#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 -#include -#include -#include -#include - -#include "kcapi.h" - -MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer and /dev/capi20 interface"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* -------- driver information -------------------------------------- */ - -static DEFINE_MUTEX(capi_mutex); -static const struct class capi_class = { - .name = "capi", -}; -static int capi_major = 68; /* allocated */ - -module_param_named(major, capi_major, uint, 0); - -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -#define CAPINC_NR_PORTS 32 -#define CAPINC_MAX_PORTS 256 - -static int capi_ttyminors = CAPINC_NR_PORTS; - -module_param_named(ttyminors, capi_ttyminors, uint, 0); -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - -/* -------- defines ------------------------------------------------- */ - -#define CAPINC_MAX_RECVQUEUE 10 -#define CAPINC_MAX_SENDQUEUE 10 -#define CAPI_MAX_BLKSIZE 2048 - -/* -------- data structures ----------------------------------------- */ - -struct capidev; -struct capincci; -struct capiminor; - -struct ackqueue_entry { - struct list_head list; - u16 datahandle; -}; - -struct capiminor { - unsigned int minor; - - struct capi20_appl *ap; - u32 ncci; - atomic_t datahandle; - atomic_t msgid; - - struct tty_port port; - int ttyinstop; - int ttyoutstop; - - struct sk_buff_head inqueue; - - struct sk_buff_head outqueue; - int outbytes; - struct sk_buff *outskb; - spinlock_t outlock; - - /* transmit path */ - struct list_head ackqueue; - int nack; - spinlock_t ackqlock; -}; - -struct capincci { - struct list_head list; - u32 ncci; - struct capidev *cdev; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - struct capiminor *minorp; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -}; - -struct capidev { - struct list_head list; - struct capi20_appl ap; - u16 errcode; - unsigned userflags; - - struct sk_buff_head recvqueue; - wait_queue_head_t recvwait; - - struct list_head nccis; - - struct mutex lock; -}; - -/* -------- global variables ---------------------------------------- */ - -static DEFINE_MUTEX(capidev_list_lock); -static LIST_HEAD(capidev_list); - -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - -static DEFINE_SPINLOCK(capiminors_lock); -static struct capiminor **capiminors; - -static struct tty_driver *capinc_tty_driver; - -/* -------- datahandles --------------------------------------------- */ - -static int capiminor_add_ack(struct capiminor *mp, u16 datahandle) -{ - struct ackqueue_entry *n; - - n = kmalloc_obj(*n, GFP_ATOMIC); - if (unlikely(!n)) { - printk(KERN_ERR "capi: alloc datahandle failed\n"); - return -1; - } - n->datahandle = datahandle; - INIT_LIST_HEAD(&n->list); - spin_lock_bh(&mp->ackqlock); - list_add_tail(&n->list, &mp->ackqueue); - mp->nack++; - spin_unlock_bh(&mp->ackqlock); - return 0; -} - -static int capiminor_del_ack(struct capiminor *mp, u16 datahandle) -{ - struct ackqueue_entry *p, *tmp; - - spin_lock_bh(&mp->ackqlock); - list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { - if (p->datahandle == datahandle) { - list_del(&p->list); - mp->nack--; - spin_unlock_bh(&mp->ackqlock); - kfree(p); - return 0; - } - } - spin_unlock_bh(&mp->ackqlock); - return -1; -} - -static void capiminor_del_all_ack(struct capiminor *mp) -{ - struct ackqueue_entry *p, *tmp; - - list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { - list_del(&p->list); - kfree(p); - mp->nack--; - } -} - - -/* -------- struct capiminor ---------------------------------------- */ - -static void capiminor_destroy(struct tty_port *port) -{ - struct capiminor *mp = container_of(port, struct capiminor, port); - - kfree_skb(mp->outskb); - skb_queue_purge(&mp->inqueue); - skb_queue_purge(&mp->outqueue); - capiminor_del_all_ack(mp); - kfree(mp); -} - -static const struct tty_port_operations capiminor_port_ops = { - .destruct = capiminor_destroy, -}; - -static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) -{ - struct capiminor *mp; - struct device *dev; - unsigned int minor; - - mp = kzalloc_obj(*mp); - if (!mp) { - printk(KERN_ERR "capi: can't alloc capiminor\n"); - return NULL; - } - - mp->ap = ap; - mp->ncci = ncci; - INIT_LIST_HEAD(&mp->ackqueue); - spin_lock_init(&mp->ackqlock); - - skb_queue_head_init(&mp->inqueue); - skb_queue_head_init(&mp->outqueue); - spin_lock_init(&mp->outlock); - - tty_port_init(&mp->port); - mp->port.ops = &capiminor_port_ops; - - /* Allocate the least unused minor number. */ - spin_lock(&capiminors_lock); - for (minor = 0; minor < capi_ttyminors; minor++) - if (!capiminors[minor]) { - capiminors[minor] = mp; - break; - } - spin_unlock(&capiminors_lock); - - if (minor == capi_ttyminors) { - printk(KERN_NOTICE "capi: out of minors\n"); - goto err_out1; - } - - mp->minor = minor; - - dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor, - NULL); - if (IS_ERR(dev)) - goto err_out2; - - return mp; - -err_out2: - spin_lock(&capiminors_lock); - capiminors[minor] = NULL; - spin_unlock(&capiminors_lock); - -err_out1: - tty_port_put(&mp->port); - return NULL; -} - -static struct capiminor *capiminor_get(unsigned int minor) -{ - struct capiminor *mp; - - spin_lock(&capiminors_lock); - mp = capiminors[minor]; - if (mp) - tty_port_get(&mp->port); - spin_unlock(&capiminors_lock); - - return mp; -} - -static inline void capiminor_put(struct capiminor *mp) -{ - tty_port_put(&mp->port); -} - -static void capiminor_free(struct capiminor *mp) -{ - tty_unregister_device(capinc_tty_driver, mp->minor); - - spin_lock(&capiminors_lock); - capiminors[mp->minor] = NULL; - spin_unlock(&capiminors_lock); - - capiminor_put(mp); -} - -/* -------- struct capincci ----------------------------------------- */ - -static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) -{ - if (cdev->userflags & CAPIFLAG_HIGHJACKING) - np->minorp = capiminor_alloc(&cdev->ap, np->ncci); -} - -static void capincci_free_minor(struct capincci *np) -{ - struct capiminor *mp = np->minorp; - - if (mp) { - tty_port_tty_vhangup(&mp->port); - capiminor_free(mp); - } -} - -static inline unsigned int capincci_minor_opencount(struct capincci *np) -{ - struct capiminor *mp = np->minorp; - unsigned int count = 0; - struct tty_struct *tty; - - if (mp) { - tty = tty_port_tty_get(&mp->port); - if (tty) { - count = tty->count; - tty_kref_put(tty); - } - } - return count; -} - -#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ - -static inline void -capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { } -static inline void capincci_free_minor(struct capincci *np) { } - -#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ - -static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci) -{ - struct capincci *np; - - np = kzalloc_obj(*np); - if (!np) - return NULL; - np->ncci = ncci; - np->cdev = cdev; - - capincci_alloc_minor(cdev, np); - - list_add_tail(&np->list, &cdev->nccis); - - return np; -} - -static void capincci_free(struct capidev *cdev, u32 ncci) -{ - struct capincci *np, *tmp; - - list_for_each_entry_safe(np, tmp, &cdev->nccis, list) - if (ncci == 0xffffffff || np->ncci == ncci) { - capincci_free_minor(np); - list_del(&np->list); - kfree(np); - } -} - -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -static struct capincci *capincci_find(struct capidev *cdev, u32 ncci) -{ - struct capincci *np; - - list_for_each_entry(np, &cdev->nccis, list) - if (np->ncci == ncci) - return np; - return NULL; -} - -/* -------- handle data queue --------------------------------------- */ - -static struct sk_buff * -gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) -{ - struct sk_buff *nskb; - nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_KERNEL); - if (nskb) { - u16 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2); - unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN); - capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN); - capimsg_setu16(s, 2, mp->ap->applid); - capimsg_setu8 (s, 4, CAPI_DATA_B3); - capimsg_setu8 (s, 5, CAPI_RESP); - capimsg_setu16(s, 6, atomic_inc_return(&mp->msgid)); - capimsg_setu32(s, 8, mp->ncci); - capimsg_setu16(s, 12, datahandle); - } - return nskb; -} - -static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) -{ - unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data); - struct tty_struct *tty; - struct sk_buff *nskb; - u16 errcode, datahandle; - struct tty_ldisc *ld; - int ret = -1; - - tty = tty_port_tty_get(&mp->port); - if (!tty) { - pr_debug("capi: currently no receiver\n"); - return -1; - } - - ld = tty_ldisc_ref(tty); - if (!ld) { - /* fatal error, do not requeue */ - ret = 0; - kfree_skb(skb); - goto deref_tty; - } - - if (ld->ops->receive_buf == NULL) { - pr_debug("capi: ldisc has no receive_buf function\n"); - /* fatal error, do not requeue */ - goto free_skb; - } - if (mp->ttyinstop) { - pr_debug("capi: recv tty throttled\n"); - goto deref_ldisc; - } - - if (tty->receive_room < datalen) { - pr_debug("capi: no room in tty\n"); - goto deref_ldisc; - } - - nskb = gen_data_b3_resp_for(mp, skb); - if (!nskb) { - printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); - goto deref_ldisc; - } - - datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4); - - errcode = capi20_put_message(mp->ap, nskb); - - if (errcode == CAPI_NOERROR) { - skb_pull(skb, CAPIMSG_LEN(skb->data)); - pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n", - datahandle, skb->len); - ld->ops->receive_buf(tty, skb->data, NULL, skb->len); - } else { - printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", - errcode); - kfree_skb(nskb); - - if (errcode == CAPI_SENDQUEUEFULL) - goto deref_ldisc; - } - -free_skb: - ret = 0; - kfree_skb(skb); - -deref_ldisc: - tty_ldisc_deref(ld); - -deref_tty: - tty_kref_put(tty); - return ret; -} - -static void handle_minor_recv(struct capiminor *mp) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&mp->inqueue)) != NULL) - if (handle_recv_skb(mp, skb) < 0) { - skb_queue_head(&mp->inqueue, skb); - return; - } -} - -static void handle_minor_send(struct capiminor *mp) -{ - struct tty_struct *tty; - struct sk_buff *skb; - u16 len; - u16 errcode; - u16 datahandle; - - tty = tty_port_tty_get(&mp->port); - if (!tty) - return; - - if (mp->ttyoutstop) { - pr_debug("capi: send: tty stopped\n"); - tty_kref_put(tty); - return; - } - - while (1) { - spin_lock_bh(&mp->outlock); - skb = __skb_dequeue(&mp->outqueue); - if (!skb) { - spin_unlock_bh(&mp->outlock); - break; - } - len = (u16)skb->len; - mp->outbytes -= len; - spin_unlock_bh(&mp->outlock); - - datahandle = atomic_inc_return(&mp->datahandle); - skb_push(skb, CAPI_DATA_B3_REQ_LEN); - memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN); - capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN); - capimsg_setu16(skb->data, 2, mp->ap->applid); - capimsg_setu8 (skb->data, 4, CAPI_DATA_B3); - capimsg_setu8 (skb->data, 5, CAPI_REQ); - capimsg_setu16(skb->data, 6, atomic_inc_return(&mp->msgid)); - capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */ - capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */ - capimsg_setu16(skb->data, 16, len); /* Data length */ - capimsg_setu16(skb->data, 18, datahandle); - capimsg_setu16(skb->data, 20, 0); /* Flags */ - - if (capiminor_add_ack(mp, datahandle) < 0) { - skb_pull(skb, CAPI_DATA_B3_REQ_LEN); - - spin_lock_bh(&mp->outlock); - __skb_queue_head(&mp->outqueue, skb); - mp->outbytes += len; - spin_unlock_bh(&mp->outlock); - - break; - } - errcode = capi20_put_message(mp->ap, skb); - if (errcode == CAPI_NOERROR) { - pr_debug("capi: DATA_B3_REQ %u len=%u\n", - datahandle, len); - continue; - } - capiminor_del_ack(mp, datahandle); - - if (errcode == CAPI_SENDQUEUEFULL) { - skb_pull(skb, CAPI_DATA_B3_REQ_LEN); - - spin_lock_bh(&mp->outlock); - __skb_queue_head(&mp->outqueue, skb); - mp->outbytes += len; - spin_unlock_bh(&mp->outlock); - - break; - } - - /* ups, drop packet */ - printk(KERN_ERR "capi: put_message = %x\n", errcode); - kfree_skb(skb); - } - tty_kref_put(tty); -} - -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -/* -------- function called by lower level -------------------------- */ - -static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) -{ - struct capidev *cdev = ap->private; -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - struct capiminor *mp; - u16 datahandle; - struct capincci *np; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - - mutex_lock(&cdev->lock); - - if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { - u16 info = CAPIMSG_U16(skb->data, 12); // Info field - if ((info & 0xff00) == 0) - capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); - } - if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) - capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); - - if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { - skb_queue_tail(&cdev->recvqueue, skb); - wake_up_interruptible(&cdev->recvwait); - goto unlock_out; - } - -#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE - skb_queue_tail(&cdev->recvqueue, skb); - wake_up_interruptible(&cdev->recvwait); - -#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - - np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data)); - if (!np) { - printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); - skb_queue_tail(&cdev->recvqueue, skb); - wake_up_interruptible(&cdev->recvwait); - goto unlock_out; - } - - mp = np->minorp; - if (!mp) { - skb_queue_tail(&cdev->recvqueue, skb); - wake_up_interruptible(&cdev->recvwait); - goto unlock_out; - } - if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { - datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2); - pr_debug("capi_signal: DATA_B3_IND %u len=%d\n", - datahandle, skb->len-CAPIMSG_LEN(skb->data)); - skb_queue_tail(&mp->inqueue, skb); - - handle_minor_recv(mp); - - } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) { - - datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4); - pr_debug("capi_signal: DATA_B3_CONF %u 0x%x\n", - datahandle, - CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2)); - kfree_skb(skb); - capiminor_del_ack(mp, datahandle); - tty_port_tty_wakeup(&mp->port); - handle_minor_send(mp); - - } else { - /* ups, let capi application handle it :-) */ - skb_queue_tail(&cdev->recvqueue, skb); - wake_up_interruptible(&cdev->recvwait); - } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - -unlock_out: - mutex_unlock(&cdev->lock); -} - -/* -------- file_operations for capidev ----------------------------- */ - -static ssize_t -capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - struct capidev *cdev = file->private_data; - struct sk_buff *skb; - size_t copied; - int err; - - if (!cdev->ap.applid) - return -ENODEV; - - skb = skb_dequeue(&cdev->recvqueue); - if (!skb) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - err = wait_event_interruptible(cdev->recvwait, - (skb = skb_dequeue(&cdev->recvqueue))); - if (err) - return err; - } - if (skb->len > count) { - skb_queue_head(&cdev->recvqueue, skb); - return -EMSGSIZE; - } - if (copy_to_user(buf, skb->data, skb->len)) { - skb_queue_head(&cdev->recvqueue, skb); - return -EFAULT; - } - copied = skb->len; - - kfree_skb(skb); - - return copied; -} - -static ssize_t -capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - struct capidev *cdev = file->private_data; - struct sk_buff *skb; - u16 mlen; - - if (!cdev->ap.applid) - return -ENODEV; - - if (count < CAPIMSG_BASELEN) - return -EINVAL; - - skb = alloc_skb(count, GFP_USER); - if (!skb) - return -ENOMEM; - - if (copy_from_user(skb_put(skb, count), buf, count)) { - kfree_skb(skb); - return -EFAULT; - } - mlen = CAPIMSG_LEN(skb->data); - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { - if (count < CAPI_DATA_B3_REQ_LEN || - (size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) { - kfree_skb(skb); - return -EINVAL; - } - } else { - if (mlen != count) { - kfree_skb(skb); - return -EINVAL; - } - } - CAPIMSG_SETAPPID(skb->data, cdev->ap.applid); - - if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) { - if (count < CAPI_DISCONNECT_B3_RESP_LEN) { - kfree_skb(skb); - return -EINVAL; - } - mutex_lock(&cdev->lock); - capincci_free(cdev, CAPIMSG_NCCI(skb->data)); - mutex_unlock(&cdev->lock); - } - - cdev->errcode = capi20_put_message(&cdev->ap, skb); - - if (cdev->errcode) { - kfree_skb(skb); - return -EIO; - } - return count; -} - -static __poll_t -capi_poll(struct file *file, poll_table *wait) -{ - struct capidev *cdev = file->private_data; - __poll_t mask = 0; - - if (!cdev->ap.applid) - return EPOLLERR; - - poll_wait(file, &(cdev->recvwait), wait); - mask = EPOLLOUT | EPOLLWRNORM; - if (!skb_queue_empty_lockless(&cdev->recvqueue)) - mask |= EPOLLIN | EPOLLRDNORM; - return mask; -} - -static int -capi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct capidev *cdev = file->private_data; - capi_ioctl_struct data; - int retval = -EINVAL; - void __user *argp = (void __user *)arg; - - switch (cmd) { - case CAPI_REGISTER: - mutex_lock(&cdev->lock); - - if (cdev->ap.applid) { - retval = -EEXIST; - goto register_out; - } - if (copy_from_user(&cdev->ap.rparam, argp, - sizeof(struct capi_register_params))) { - retval = -EFAULT; - goto register_out; - } - cdev->ap.private = cdev; - cdev->ap.recv_message = capi_recv_message; - cdev->errcode = capi20_register(&cdev->ap); - retval = (int)cdev->ap.applid; - if (cdev->errcode) { - cdev->ap.applid = 0; - retval = -EIO; - } - -register_out: - mutex_unlock(&cdev->lock); - return retval; - - case CAPI_GET_VERSION: - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; - cdev->errcode = capi20_get_version(data.contr, &data.version); - if (cdev->errcode) - return -EIO; - if (copy_to_user(argp, &data.version, - sizeof(data.version))) - return -EFAULT; - return 0; - - case CAPI_GET_SERIAL: - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; - cdev->errcode = capi20_get_serial(data.contr, data.serial); - if (cdev->errcode) - return -EIO; - if (copy_to_user(argp, data.serial, - sizeof(data.serial))) - return -EFAULT; - return 0; - - case CAPI_GET_PROFILE: - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; - - if (data.contr == 0) { - cdev->errcode = capi20_get_profile(data.contr, &data.profile); - if (cdev->errcode) - return -EIO; - - retval = copy_to_user(argp, - &data.profile.ncontroller, - sizeof(data.profile.ncontroller)); - - } else { - cdev->errcode = capi20_get_profile(data.contr, &data.profile); - if (cdev->errcode) - return -EIO; - - retval = copy_to_user(argp, &data.profile, - sizeof(data.profile)); - } - if (retval) - return -EFAULT; - return 0; - - case CAPI_GET_MANUFACTURER: - if (copy_from_user(&data.contr, argp, - sizeof(data.contr))) - return -EFAULT; - cdev->errcode = capi20_get_manufacturer(data.contr, data.manufacturer); - if (cdev->errcode) - return -EIO; - - if (copy_to_user(argp, data.manufacturer, - sizeof(data.manufacturer))) - return -EFAULT; - - return 0; - - case CAPI_GET_ERRCODE: - data.errcode = cdev->errcode; - cdev->errcode = CAPI_NOERROR; - if (arg) { - if (copy_to_user(argp, &data.errcode, - sizeof(data.errcode))) - return -EFAULT; - } - return data.errcode; - - case CAPI_INSTALLED: - if (capi20_isinstalled() == CAPI_NOERROR) - return 0; - return -ENXIO; - - case CAPI_MANUFACTURER_CMD: { - struct capi_manufacturer_cmd mcmd; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&mcmd, argp, sizeof(mcmd))) - return -EFAULT; - return capi20_manufacturer(mcmd.cmd, mcmd.data); - } - case CAPI_SET_FLAGS: - case CAPI_CLR_FLAGS: { - unsigned userflags; - - if (copy_from_user(&userflags, argp, sizeof(userflags))) - return -EFAULT; - - mutex_lock(&cdev->lock); - if (cmd == CAPI_SET_FLAGS) - cdev->userflags |= userflags; - else - cdev->userflags &= ~userflags; - mutex_unlock(&cdev->lock); - return 0; - } - case CAPI_GET_FLAGS: - if (copy_to_user(argp, &cdev->userflags, - sizeof(cdev->userflags))) - return -EFAULT; - return 0; - -#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE - case CAPI_NCCI_OPENCOUNT: - return 0; - -#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - case CAPI_NCCI_OPENCOUNT: { - struct capincci *nccip; - unsigned ncci; - int count = 0; - - if (copy_from_user(&ncci, argp, sizeof(ncci))) - return -EFAULT; - - mutex_lock(&cdev->lock); - nccip = capincci_find(cdev, (u32)ncci); - if (nccip) - count = capincci_minor_opencount(nccip); - mutex_unlock(&cdev->lock); - return count; - } - - case CAPI_NCCI_GETUNIT: { - struct capincci *nccip; - struct capiminor *mp; - unsigned ncci; - int unit = -ESRCH; - - if (copy_from_user(&ncci, argp, sizeof(ncci))) - return -EFAULT; - - mutex_lock(&cdev->lock); - nccip = capincci_find(cdev, (u32)ncci); - if (nccip) { - mp = nccip->minorp; - if (mp) - unit = mp->minor; - } - mutex_unlock(&cdev->lock); - return unit; - } -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - - default: - return -EINVAL; - } -} - -static long -capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&capi_mutex); - ret = capi_ioctl(file, cmd, arg); - mutex_unlock(&capi_mutex); - - return ret; -} - -#ifdef CONFIG_COMPAT -static long -capi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - - if (cmd == CAPI_MANUFACTURER_CMD) { - struct { - compat_ulong_t cmd; - compat_uptr_t data; - } mcmd32; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&mcmd32, compat_ptr(arg), sizeof(mcmd32))) - return -EFAULT; - - mutex_lock(&capi_mutex); - ret = capi20_manufacturer(mcmd32.cmd, compat_ptr(mcmd32.data)); - mutex_unlock(&capi_mutex); - - return ret; - } - - return capi_unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); -} -#endif - -static int capi_open(struct inode *inode, struct file *file) -{ - struct capidev *cdev; - - cdev = kzalloc_obj(*cdev); - if (!cdev) - return -ENOMEM; - - mutex_init(&cdev->lock); - skb_queue_head_init(&cdev->recvqueue); - init_waitqueue_head(&cdev->recvwait); - INIT_LIST_HEAD(&cdev->nccis); - file->private_data = cdev; - - mutex_lock(&capidev_list_lock); - list_add_tail(&cdev->list, &capidev_list); - mutex_unlock(&capidev_list_lock); - - return stream_open(inode, file); -} - -static int capi_release(struct inode *inode, struct file *file) -{ - struct capidev *cdev = file->private_data; - - mutex_lock(&capidev_list_lock); - list_del(&cdev->list); - mutex_unlock(&capidev_list_lock); - - if (cdev->ap.applid) - capi20_release(&cdev->ap); - skb_queue_purge(&cdev->recvqueue); - capincci_free(cdev, 0xffffffff); - - kfree(cdev); - return 0; -} - -static const struct file_operations capi_fops = -{ - .owner = THIS_MODULE, - .read = capi_read, - .write = capi_write, - .poll = capi_poll, - .unlocked_ioctl = capi_unlocked_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = capi_compat_ioctl, -#endif - .open = capi_open, - .release = capi_release, -}; - -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -/* -------- tty_operations for capincci ----------------------------- */ - -static int -capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - struct capiminor *mp = capiminor_get(tty->index); - int ret = tty_standard_install(driver, tty); - - if (ret == 0) - tty->driver_data = mp; - else - capiminor_put(mp); - return ret; -} - -static void capinc_tty_cleanup(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - tty->driver_data = NULL; - capiminor_put(mp); -} - -static int capinc_tty_open(struct tty_struct *tty, struct file *filp) -{ - struct capiminor *mp = tty->driver_data; - int err; - - err = tty_port_open(&mp->port, tty, filp); - if (err) - return err; - - handle_minor_recv(mp); - return 0; -} - -static void capinc_tty_close(struct tty_struct *tty, struct file *filp) -{ - struct capiminor *mp = tty->driver_data; - - tty_port_close(&mp->port, tty, filp); -} - -static ssize_t capinc_tty_write(struct tty_struct *tty, const u8 *buf, - size_t count) -{ - struct capiminor *mp = tty->driver_data; - struct sk_buff *skb; - - pr_debug("capinc_tty_write(count=%zu)\n", count); - - spin_lock_bh(&mp->outlock); - skb = mp->outskb; - if (skb) { - mp->outskb = NULL; - __skb_queue_tail(&mp->outqueue, skb); - mp->outbytes += skb->len; - } - - skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + count, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n"); - spin_unlock_bh(&mp->outlock); - return -ENOMEM; - } - - skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); - skb_put_data(skb, buf, count); - - __skb_queue_tail(&mp->outqueue, skb); - mp->outbytes += skb->len; - spin_unlock_bh(&mp->outlock); - - handle_minor_send(mp); - - return count; -} - -static int capinc_tty_put_char(struct tty_struct *tty, u8 ch) -{ - struct capiminor *mp = tty->driver_data; - bool invoke_send = false; - struct sk_buff *skb; - int ret = 1; - - pr_debug("capinc_put_char(%u)\n", ch); - - spin_lock_bh(&mp->outlock); - skb = mp->outskb; - if (skb) { - if (skb_tailroom(skb) > 0) { - skb_put_u8(skb, ch); - goto unlock_out; - } - mp->outskb = NULL; - __skb_queue_tail(&mp->outqueue, skb); - mp->outbytes += skb->len; - invoke_send = true; - } - - skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + CAPI_MAX_BLKSIZE, GFP_ATOMIC); - if (skb) { - skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); - skb_put_u8(skb, ch); - mp->outskb = skb; - } else { - printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); - ret = 0; - } - -unlock_out: - spin_unlock_bh(&mp->outlock); - - if (invoke_send) - handle_minor_send(mp); - - return ret; -} - -static void capinc_tty_flush_chars(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - struct sk_buff *skb; - - spin_lock_bh(&mp->outlock); - skb = mp->outskb; - if (skb) { - mp->outskb = NULL; - __skb_queue_tail(&mp->outqueue, skb); - mp->outbytes += skb->len; - spin_unlock_bh(&mp->outlock); - - handle_minor_send(mp); - } else - spin_unlock_bh(&mp->outlock); - - handle_minor_recv(mp); -} - -static unsigned int capinc_tty_write_room(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - unsigned int room; - - room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue); - room *= CAPI_MAX_BLKSIZE; - pr_debug("capinc_tty_write_room = %u\n", room); - return room; -} - -static unsigned int capinc_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - - pr_debug("capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", - mp->outbytes, mp->nack, - skb_queue_len(&mp->outqueue), - skb_queue_len(&mp->inqueue)); - return mp->outbytes; -} - -static void capinc_tty_throttle(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - mp->ttyinstop = 1; -} - -static void capinc_tty_unthrottle(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - - mp->ttyinstop = 0; - handle_minor_recv(mp); -} - -static void capinc_tty_stop(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - - mp->ttyoutstop = 1; -} - -static void capinc_tty_start(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - - mp->ttyoutstop = 0; - handle_minor_send(mp); -} - -static void capinc_tty_hangup(struct tty_struct *tty) -{ - struct capiminor *mp = tty->driver_data; - - tty_port_hangup(&mp->port); -} - -static void capinc_tty_send_xchar(struct tty_struct *tty, u8 ch) -{ - pr_debug("capinc_tty_send_xchar(%u)\n", ch); -} - -static const struct tty_operations capinc_ops = { - .open = capinc_tty_open, - .close = capinc_tty_close, - .write = capinc_tty_write, - .put_char = capinc_tty_put_char, - .flush_chars = capinc_tty_flush_chars, - .write_room = capinc_tty_write_room, - .chars_in_buffer = capinc_tty_chars_in_buffer, - .throttle = capinc_tty_throttle, - .unthrottle = capinc_tty_unthrottle, - .stop = capinc_tty_stop, - .start = capinc_tty_start, - .hangup = capinc_tty_hangup, - .send_xchar = capinc_tty_send_xchar, - .install = capinc_tty_install, - .cleanup = capinc_tty_cleanup, -}; - -static int __init capinc_tty_init(void) -{ - struct tty_driver *drv; - int err; - - if (capi_ttyminors > CAPINC_MAX_PORTS) - capi_ttyminors = CAPINC_MAX_PORTS; - if (capi_ttyminors <= 0) - capi_ttyminors = CAPINC_NR_PORTS; - - capiminors = kzalloc_objs(struct capiminor *, capi_ttyminors); - if (!capiminors) - return -ENOMEM; - - drv = tty_alloc_driver(capi_ttyminors, TTY_DRIVER_REAL_RAW | - TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV); - if (IS_ERR(drv)) { - kfree(capiminors); - return PTR_ERR(drv); - } - drv->driver_name = "capi_nc"; - drv->name = "capi!"; - drv->major = 0; - drv->minor_start = 0; - drv->type = TTY_DRIVER_TYPE_SERIAL; - drv->subtype = SERIAL_TYPE_NORMAL; - drv->init_termios = tty_std_termios; - drv->init_termios.c_iflag = ICRNL; - drv->init_termios.c_oflag = OPOST | ONLCR; - drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - drv->init_termios.c_lflag = 0; - tty_set_operations(drv, &capinc_ops); - - err = tty_register_driver(drv); - if (err) { - tty_driver_kref_put(drv); - kfree(capiminors); - printk(KERN_ERR "Couldn't register capi_nc driver\n"); - return err; - } - capinc_tty_driver = drv; - return 0; -} - -static void __exit capinc_tty_exit(void) -{ - tty_unregister_driver(capinc_tty_driver); - tty_driver_kref_put(capinc_tty_driver); - kfree(capiminors); -} - -#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ - -static inline int capinc_tty_init(void) -{ - return 0; -} - -static inline void capinc_tty_exit(void) { } - -#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ - -/* -------- /proc functions ----------------------------------------- */ - -/* - * /proc/capi/capi20: - * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt - */ -static int __maybe_unused capi20_proc_show(struct seq_file *m, void *v) -{ - struct capidev *cdev; - struct list_head *l; - - mutex_lock(&capidev_list_lock); - list_for_each(l, &capidev_list) { - cdev = list_entry(l, struct capidev, list); - seq_printf(m, "0 %d %lu %lu %lu %lu\n", - cdev->ap.applid, - cdev->ap.nrecvctlpkt, - cdev->ap.nrecvdatapkt, - cdev->ap.nsentctlpkt, - cdev->ap.nsentdatapkt); - } - mutex_unlock(&capidev_list_lock); - return 0; -} - -/* - * /proc/capi/capi20ncci: - * applid ncci - */ -static int __maybe_unused capi20ncci_proc_show(struct seq_file *m, void *v) -{ - struct capidev *cdev; - struct capincci *np; - - mutex_lock(&capidev_list_lock); - list_for_each_entry(cdev, &capidev_list, list) { - mutex_lock(&cdev->lock); - list_for_each_entry(np, &cdev->nccis, list) - seq_printf(m, "%d 0x%x\n", cdev->ap.applid, np->ncci); - mutex_unlock(&cdev->lock); - } - mutex_unlock(&capidev_list_lock); - return 0; -} - -static void __init proc_init(void) -{ - proc_create_single("capi/capi20", 0, NULL, capi20_proc_show); - proc_create_single("capi/capi20ncci", 0, NULL, capi20ncci_proc_show); -} - -static void __exit proc_exit(void) -{ - remove_proc_entry("capi/capi20", NULL); - remove_proc_entry("capi/capi20ncci", NULL); -} - -/* -------- init function and module interface ---------------------- */ - - -static int __init capi_init(void) -{ - const char *compileinfo; - int major_ret; - int ret; - - ret = kcapi_init(); - if (ret) - return ret; - - major_ret = register_chrdev(capi_major, "capi20", &capi_fops); - if (major_ret < 0) { - printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); - kcapi_exit(); - return major_ret; - } - - ret = class_register(&capi_class); - if (ret) { - unregister_chrdev(capi_major, "capi20"); - kcapi_exit(); - return ret; - } - - device_create(&capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi20"); - - if (capinc_tty_init() < 0) { - device_destroy(&capi_class, MKDEV(capi_major, 0)); - class_unregister(&capi_class); - unregister_chrdev(capi_major, "capi20"); - kcapi_exit(); - return -ENOMEM; - } - - proc_init(); - -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - compileinfo = " (middleware)"; -#else - compileinfo = " (no middleware)"; -#endif - printk(KERN_NOTICE "CAPI 2.0 started up with major %d%s\n", - capi_major, compileinfo); - - return 0; -} - -static void __exit capi_exit(void) -{ - proc_exit(); - - device_destroy(&capi_class, MKDEV(capi_major, 0)); - class_unregister(&capi_class); - unregister_chrdev(capi_major, "capi20"); - - capinc_tty_exit(); - - kcapi_exit(); -} - -module_init(capi_init); -module_exit(capi_exit); diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c deleted file mode 100644 index eec9b36343b7..000000000000 --- a/drivers/isdn/capi/capiutil.c +++ /dev/null @@ -1,677 +0,0 @@ -/* $Id: capiutil.c,v 1.13.6.4 2001/09/23 22:24:33 kai Exp $ - * - * CAPI 2.0 convert capi message to capi message struct - * - * From CAPI 2.0 Development Kit AVM 1995 (msg.c) - * Rewritten for Linux 1996 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kcapi.h" - -/* from CAPI2.0 DDK AVM Berlin GmbH */ - -typedef struct { - int typ; - size_t off; -} _cdef; - -#define _CBYTE 1 -#define _CWORD 2 -#define _CDWORD 3 -#define _CSTRUCT 4 -#define _CMSTRUCT 5 -#define _CEND 6 - -static _cdef cdef[] = -{ - /*00 */ - {_CEND}, - /*01 */ - {_CEND}, - /*02 */ - {_CEND}, - /*03 */ - {_CDWORD, offsetof(_cmsg, adr.adrController)}, - /*04 */ - {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)}, - /*05 */ - {_CSTRUCT, offsetof(_cmsg, B1configuration)}, - /*06 */ - {_CWORD, offsetof(_cmsg, B1protocol)}, - /*07 */ - {_CSTRUCT, offsetof(_cmsg, B2configuration)}, - /*08 */ - {_CWORD, offsetof(_cmsg, B2protocol)}, - /*09 */ - {_CSTRUCT, offsetof(_cmsg, B3configuration)}, - /*0a */ - {_CWORD, offsetof(_cmsg, B3protocol)}, - /*0b */ - {_CSTRUCT, offsetof(_cmsg, BC)}, - /*0c */ - {_CSTRUCT, offsetof(_cmsg, BChannelinformation)}, - /*0d */ - {_CMSTRUCT, offsetof(_cmsg, BProtocol)}, - /*0e */ - {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)}, - /*0f */ - {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)}, - /*10 */ - {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)}, - /*11 */ - {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)}, - /*12 */ - {_CDWORD, offsetof(_cmsg, CIPmask)}, - /*13 */ - {_CDWORD, offsetof(_cmsg, CIPmask2)}, - /*14 */ - {_CWORD, offsetof(_cmsg, CIPValue)}, - /*15 */ - {_CDWORD, offsetof(_cmsg, Class)}, - /*16 */ - {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)}, - /*17 */ - {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)}, - /*18 */ - {_CDWORD, offsetof(_cmsg, Data)}, - /*19 */ - {_CWORD, offsetof(_cmsg, DataHandle)}, - /*1a */ - {_CWORD, offsetof(_cmsg, DataLength)}, - /*1b */ - {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)}, - /*1c */ - {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)}, - /*1d */ - {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)}, - /*1e */ - {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)}, - /*1f */ - {_CWORD, offsetof(_cmsg, FacilitySelector)}, - /*20 */ - {_CWORD, offsetof(_cmsg, Flags)}, - /*21 */ - {_CDWORD, offsetof(_cmsg, Function)}, - /*22 */ - {_CSTRUCT, offsetof(_cmsg, HLC)}, - /*23 */ - {_CWORD, offsetof(_cmsg, Info)}, - /*24 */ - {_CSTRUCT, offsetof(_cmsg, InfoElement)}, - /*25 */ - {_CDWORD, offsetof(_cmsg, InfoMask)}, - /*26 */ - {_CWORD, offsetof(_cmsg, InfoNumber)}, - /*27 */ - {_CSTRUCT, offsetof(_cmsg, Keypadfacility)}, - /*28 */ - {_CSTRUCT, offsetof(_cmsg, LLC)}, - /*29 */ - {_CSTRUCT, offsetof(_cmsg, ManuData)}, - /*2a */ - {_CDWORD, offsetof(_cmsg, ManuID)}, - /*2b */ - {_CSTRUCT, offsetof(_cmsg, NCPI)}, - /*2c */ - {_CWORD, offsetof(_cmsg, Reason)}, - /*2d */ - {_CWORD, offsetof(_cmsg, Reason_B3)}, - /*2e */ - {_CWORD, offsetof(_cmsg, Reject)}, - /*2f */ - {_CSTRUCT, offsetof(_cmsg, Useruserdata)} -}; - -static unsigned char *cpars[] = -{ - /* ALERT_REQ */ [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", - /* CONNECT_REQ */ [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", - /* DISCONNECT_REQ */ [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", - /* LISTEN_REQ */ [0x05] = "\x03\x25\x12\x13\x10\x11\x01", - /* INFO_REQ */ [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01", - /* FACILITY_REQ */ [0x09] = "\x03\x1f\x1e\x01", - /* SELECT_B_PROTOCOL_REQ */ [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01", - /* CONNECT_B3_REQ */ [0x0b] = "\x03\x2b\x01", - /* DISCONNECT_B3_REQ */ [0x0d] = "\x03\x2b\x01", - /* DATA_B3_REQ */ [0x0f] = "\x03\x18\x1a\x19\x20\x01", - /* RESET_B3_REQ */ [0x10] = "\x03\x2b\x01", - /* ALERT_CONF */ [0x13] = "\x03\x23\x01", - /* CONNECT_CONF */ [0x14] = "\x03\x23\x01", - /* DISCONNECT_CONF */ [0x16] = "\x03\x23\x01", - /* LISTEN_CONF */ [0x17] = "\x03\x23\x01", - /* MANUFACTURER_REQ */ [0x18] = "\x03\x2a\x15\x21\x29\x01", - /* INFO_CONF */ [0x1a] = "\x03\x23\x01", - /* FACILITY_CONF */ [0x1b] = "\x03\x23\x1f\x1b\x01", - /* SELECT_B_PROTOCOL_CONF */ [0x1c] = "\x03\x23\x01", - /* CONNECT_B3_CONF */ [0x1d] = "\x03\x23\x01", - /* DISCONNECT_B3_CONF */ [0x1f] = "\x03\x23\x01", - /* DATA_B3_CONF */ [0x21] = "\x03\x19\x23\x01", - /* RESET_B3_CONF */ [0x22] = "\x03\x23\x01", - /* CONNECT_IND */ [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", - /* CONNECT_ACTIVE_IND */ [0x27] = "\x03\x16\x17\x28\x01", - /* DISCONNECT_IND */ [0x28] = "\x03\x2c\x01", - /* MANUFACTURER_CONF */ [0x2a] = "\x03\x2a\x15\x21\x29\x01", - /* INFO_IND */ [0x2c] = "\x03\x26\x24\x01", - /* FACILITY_IND */ [0x2d] = "\x03\x1f\x1d\x01", - /* CONNECT_B3_IND */ [0x2f] = "\x03\x2b\x01", - /* CONNECT_B3_ACTIVE_IND */ [0x30] = "\x03\x2b\x01", - /* DISCONNECT_B3_IND */ [0x31] = "\x03\x2d\x2b\x01", - /* DATA_B3_IND */ [0x33] = "\x03\x18\x1a\x19\x20\x01", - /* RESET_B3_IND */ [0x34] = "\x03\x2b\x01", - /* CONNECT_B3_T90_ACTIVE_IND */ [0x35] = "\x03\x2b\x01", - /* CONNECT_RESP */ [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01", - /* CONNECT_ACTIVE_RESP */ [0x39] = "\x03\x01", - /* DISCONNECT_RESP */ [0x3a] = "\x03\x01", - /* MANUFACTURER_IND */ [0x3c] = "\x03\x2a\x15\x21\x29\x01", - /* INFO_RESP */ [0x3e] = "\x03\x01", - /* FACILITY_RESP */ [0x3f] = "\x03\x1f\x01", - /* CONNECT_B3_RESP */ [0x41] = "\x03\x2e\x2b\x01", - /* CONNECT_B3_ACTIVE_RESP */ [0x42] = "\x03\x01", - /* DISCONNECT_B3_RESP */ [0x43] = "\x03\x01", - /* DATA_B3_RESP */ [0x45] = "\x03\x19\x01", - /* RESET_B3_RESP */ [0x46] = "\x03\x01", - /* CONNECT_B3_T90_ACTIVE_RESP */ [0x47] = "\x03\x01", - /* MANUFACTURER_RESP */ [0x4e] = "\x03\x2a\x15\x21\x29\x01", -}; - -/*-------------------------------------------------------*/ - -#define byteTLcpy(x, y) *(u8 *)(x) = *(u8 *)(y); -#define wordTLcpy(x, y) *(u16 *)(x) = *(u16 *)(y); -#define dwordTLcpy(x, y) memcpy(x, y, 4); -#define structTLcpy(x, y, l) memcpy(x, y, l) -#define structTLcpyovl(x, y, l) memmove(x, y, l) - -#define byteTRcpy(x, y) *(u8 *)(y) = *(u8 *)(x); -#define wordTRcpy(x, y) *(u16 *)(y) = *(u16 *)(x); -#define dwordTRcpy(x, y) memcpy(y, x, 4); -#define structTRcpy(x, y, l) memcpy(y, x, l) -#define structTRcpyovl(x, y, l) memmove(y, x, l) - -/*-------------------------------------------------------*/ -static unsigned command_2_index(u8 c, u8 sc) -{ - if (c & 0x80) - c = 0x9 + (c & 0x0f); - else if (c == 0x41) - c = 0x9 + 0x1; - if (c > 0x18) - c = 0x00; - return (sc & 3) * (0x9 + 0x9) + c; -} - -/** - * capi_cmd2par() - find parameter string for CAPI 2.0 command/subcommand - * @cmd: command number - * @subcmd: subcommand number - * - * Return value: static string, NULL if command/subcommand unknown - */ - -static unsigned char *capi_cmd2par(u8 cmd, u8 subcmd) -{ - return cpars[command_2_index(cmd, subcmd)]; -} - -/*-------------------------------------------------------*/ -#define TYP (cdef[cmsg->par[cmsg->p]].typ) -#define OFF (((u8 *)cmsg) + cdef[cmsg->par[cmsg->p]].off) - -static void jumpcstruct(_cmsg *cmsg) -{ - unsigned layer; - for (cmsg->p++, layer = 1; layer;) { - /* $$$$$ assert (cmsg->p); */ - cmsg->p++; - switch (TYP) { - case _CMSTRUCT: - layer++; - break; - case _CEND: - layer--; - break; - } - } -} - -/*-------------------------------------------------------*/ - -static char *mnames[] = -{ - [0x01] = "ALERT_REQ", - [0x02] = "CONNECT_REQ", - [0x04] = "DISCONNECT_REQ", - [0x05] = "LISTEN_REQ", - [0x08] = "INFO_REQ", - [0x09] = "FACILITY_REQ", - [0x0a] = "SELECT_B_PROTOCOL_REQ", - [0x0b] = "CONNECT_B3_REQ", - [0x0d] = "DISCONNECT_B3_REQ", - [0x0f] = "DATA_B3_REQ", - [0x10] = "RESET_B3_REQ", - [0x13] = "ALERT_CONF", - [0x14] = "CONNECT_CONF", - [0x16] = "DISCONNECT_CONF", - [0x17] = "LISTEN_CONF", - [0x18] = "MANUFACTURER_REQ", - [0x1a] = "INFO_CONF", - [0x1b] = "FACILITY_CONF", - [0x1c] = "SELECT_B_PROTOCOL_CONF", - [0x1d] = "CONNECT_B3_CONF", - [0x1f] = "DISCONNECT_B3_CONF", - [0x21] = "DATA_B3_CONF", - [0x22] = "RESET_B3_CONF", - [0x26] = "CONNECT_IND", - [0x27] = "CONNECT_ACTIVE_IND", - [0x28] = "DISCONNECT_IND", - [0x2a] = "MANUFACTURER_CONF", - [0x2c] = "INFO_IND", - [0x2d] = "FACILITY_IND", - [0x2f] = "CONNECT_B3_IND", - [0x30] = "CONNECT_B3_ACTIVE_IND", - [0x31] = "DISCONNECT_B3_IND", - [0x33] = "DATA_B3_IND", - [0x34] = "RESET_B3_IND", - [0x35] = "CONNECT_B3_T90_ACTIVE_IND", - [0x38] = "CONNECT_RESP", - [0x39] = "CONNECT_ACTIVE_RESP", - [0x3a] = "DISCONNECT_RESP", - [0x3c] = "MANUFACTURER_IND", - [0x3e] = "INFO_RESP", - [0x3f] = "FACILITY_RESP", - [0x41] = "CONNECT_B3_RESP", - [0x42] = "CONNECT_B3_ACTIVE_RESP", - [0x43] = "DISCONNECT_B3_RESP", - [0x45] = "DATA_B3_RESP", - [0x46] = "RESET_B3_RESP", - [0x47] = "CONNECT_B3_T90_ACTIVE_RESP", - [0x4e] = "MANUFACTURER_RESP" -}; - -/** - * capi_cmd2str() - convert CAPI 2.0 command/subcommand number to name - * @cmd: command number - * @subcmd: subcommand number - * - * Return value: static string - */ - -char *capi_cmd2str(u8 cmd, u8 subcmd) -{ - char *result; - - result = mnames[command_2_index(cmd, subcmd)]; - if (result == NULL) - result = "INVALID_COMMAND"; - return result; -} - - -/*-------------------------------------------------------*/ - -#ifdef CONFIG_CAPI_TRACE - -/*-------------------------------------------------------*/ - -static char *pnames[] = -{ - /*00 */ NULL, - /*01 */ NULL, - /*02 */ NULL, - /*03 */ "Controller/PLCI/NCCI", - /*04 */ "AdditionalInfo", - /*05 */ "B1configuration", - /*06 */ "B1protocol", - /*07 */ "B2configuration", - /*08 */ "B2protocol", - /*09 */ "B3configuration", - /*0a */ "B3protocol", - /*0b */ "BC", - /*0c */ "BChannelinformation", - /*0d */ "BProtocol", - /*0e */ "CalledPartyNumber", - /*0f */ "CalledPartySubaddress", - /*10 */ "CallingPartyNumber", - /*11 */ "CallingPartySubaddress", - /*12 */ "CIPmask", - /*13 */ "CIPmask2", - /*14 */ "CIPValue", - /*15 */ "Class", - /*16 */ "ConnectedNumber", - /*17 */ "ConnectedSubaddress", - /*18 */ "Data32", - /*19 */ "DataHandle", - /*1a */ "DataLength", - /*1b */ "FacilityConfirmationParameter", - /*1c */ "Facilitydataarray", - /*1d */ "FacilityIndicationParameter", - /*1e */ "FacilityRequestParameter", - /*1f */ "FacilitySelector", - /*20 */ "Flags", - /*21 */ "Function", - /*22 */ "HLC", - /*23 */ "Info", - /*24 */ "InfoElement", - /*25 */ "InfoMask", - /*26 */ "InfoNumber", - /*27 */ "Keypadfacility", - /*28 */ "LLC", - /*29 */ "ManuData", - /*2a */ "ManuID", - /*2b */ "NCPI", - /*2c */ "Reason", - /*2d */ "Reason_B3", - /*2e */ "Reject", - /*2f */ "Useruserdata" -}; - -#include - -/*-------------------------------------------------------*/ -static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt, ...) -{ - va_list f; - size_t n, r; - - if (!cdb) - return NULL; - va_start(f, fmt); - r = cdb->size - cdb->pos; - n = vsnprintf(cdb->p, r, fmt, f); - va_end(f); - if (n >= r) { - /* truncated, need bigger buffer */ - size_t ns = 2 * cdb->size; - u_char *nb; - - while ((ns - cdb->pos) <= n) - ns *= 2; - nb = kmalloc(ns, GFP_ATOMIC); - if (!nb) { - cdebbuf_free(cdb); - return NULL; - } - memcpy(nb, cdb->buf, cdb->pos); - kfree(cdb->buf); - nb[cdb->pos] = 0; - cdb->buf = nb; - cdb->p = cdb->buf + cdb->pos; - cdb->size = ns; - va_start(f, fmt); - r = cdb->size - cdb->pos; - n = vsnprintf(cdb->p, r, fmt, f); - va_end(f); - } - cdb->p += n; - cdb->pos += n; - return cdb; -} - -static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 *m, unsigned len) -{ - unsigned hex = 0; - - if (!cdb) - return NULL; - for (; len; len--, m++) - if (isalnum(*m) || *m == ' ') { - if (hex) - cdb = bufprint(cdb, ">"); - cdb = bufprint(cdb, "%c", *m); - hex = 0; - } else { - if (!hex) - cdb = bufprint(cdb, "<%02x", *m); - else - cdb = bufprint(cdb, " %02x", *m); - hex = 1; - } - if (hex) - cdb = bufprint(cdb, ">"); - return cdb; -} - -static _cdebbuf *printstruct(_cdebbuf *cdb, u8 *m) -{ - unsigned len; - - if (m[0] != 0xff) { - len = m[0]; - m += 1; - } else { - len = ((u16 *) (m + 1))[0]; - m += 3; - } - cdb = printstructlen(cdb, m, len); - return cdb; -} - -/*-------------------------------------------------------*/ -#define NAME (pnames[cmsg->par[cmsg->p]]) - -static _cdebbuf *protocol_message_2_pars(_cdebbuf *cdb, _cmsg *cmsg, int level) -{ - if (!cmsg->par) - return NULL; /* invalid command/subcommand */ - - for (; TYP != _CEND; cmsg->p++) { - int slen = 29 + 3 - level; - int i; - - if (!cdb) - return NULL; - cdb = bufprint(cdb, " "); - for (i = 0; i < level - 1; i++) - cdb = bufprint(cdb, " "); - - switch (TYP) { - case _CBYTE: - cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l)); - cmsg->l++; - break; - case _CWORD: - cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l)); - cmsg->l += 2; - break; - case _CDWORD: - cdb = bufprint(cdb, "%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l)); - cmsg->l += 4; - break; - case _CSTRUCT: - cdb = bufprint(cdb, "%-*s = ", slen, NAME); - if (cmsg->m[cmsg->l] == '\0') - cdb = bufprint(cdb, "default"); - else - cdb = printstruct(cdb, cmsg->m + cmsg->l); - cdb = bufprint(cdb, "\n"); - if (cmsg->m[cmsg->l] != 0xff) - cmsg->l += 1 + cmsg->m[cmsg->l]; - else - cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1); - - break; - - case _CMSTRUCT: -/*----- Metastruktur 0 -----*/ - if (cmsg->m[cmsg->l] == '\0') { - cdb = bufprint(cdb, "%-*s = default\n", slen, NAME); - cmsg->l++; - jumpcstruct(cmsg); - } else { - char *name = NAME; - unsigned _l = cmsg->l; - cdb = bufprint(cdb, "%-*s\n", slen, name); - cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1; - cmsg->p++; - cdb = protocol_message_2_pars(cdb, cmsg, level + 1); - } - break; - } - } - return cdb; -} -/*-------------------------------------------------------*/ - -static _cdebbuf *g_debbuf; -static u_long g_debbuf_lock; -static _cmsg *g_cmsg; - -static _cdebbuf *cdebbuf_alloc(void) -{ - _cdebbuf *cdb; - - if (likely(!test_and_set_bit(1, &g_debbuf_lock))) { - cdb = g_debbuf; - goto init; - } else - cdb = kmalloc_obj(_cdebbuf, GFP_ATOMIC); - if (!cdb) - return NULL; - cdb->buf = kmalloc(CDEBUG_SIZE, GFP_ATOMIC); - if (!cdb->buf) { - kfree(cdb); - return NULL; - } - cdb->size = CDEBUG_SIZE; -init: - cdb->buf[0] = 0; - cdb->p = cdb->buf; - cdb->pos = 0; - return cdb; -} - -/** - * cdebbuf_free() - free CAPI debug buffer - * @cdb: buffer to free - */ - -void cdebbuf_free(_cdebbuf *cdb) -{ - if (likely(cdb == g_debbuf)) { - test_and_clear_bit(1, &g_debbuf_lock); - return; - } - if (likely(cdb)) - kfree(cdb->buf); - kfree(cdb); -} - - -/** - * capi_message2str() - format CAPI 2.0 message for printing - * @msg: CAPI 2.0 message - * - * Allocates a CAPI debug buffer and fills it with a printable representation - * of the CAPI 2.0 message in @msg. - * Return value: allocated debug buffer, NULL on error - * The returned buffer should be freed by a call to cdebbuf_free() after use. - */ - -_cdebbuf *capi_message2str(u8 *msg) -{ - _cdebbuf *cdb; - _cmsg *cmsg; - - cdb = cdebbuf_alloc(); - if (unlikely(!cdb)) - return NULL; - if (likely(cdb == g_debbuf)) - cmsg = g_cmsg; - else - cmsg = kmalloc_obj(_cmsg, GFP_ATOMIC); - if (unlikely(!cmsg)) { - cdebbuf_free(cdb); - return NULL; - } - cmsg->m = msg; - cmsg->l = 8; - cmsg->p = 0; - byteTRcpy(cmsg->m + 4, &cmsg->Command); - byteTRcpy(cmsg->m + 5, &cmsg->Subcommand); - cmsg->par = capi_cmd2par(cmsg->Command, cmsg->Subcommand); - - cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - ((unsigned short *) msg)[1], - ((unsigned short *) msg)[3], - ((unsigned short *) msg)[0]); - - cdb = protocol_message_2_pars(cdb, cmsg, 1); - if (unlikely(cmsg != g_cmsg)) - kfree(cmsg); - return cdb; -} - -int __init cdebug_init(void) -{ - g_cmsg = kmalloc_obj(_cmsg); - if (!g_cmsg) - return -ENOMEM; - g_debbuf = kmalloc_obj(_cdebbuf); - if (!g_debbuf) { - kfree(g_cmsg); - return -ENOMEM; - } - g_debbuf->buf = kmalloc(CDEBUG_GSIZE, GFP_KERNEL); - if (!g_debbuf->buf) { - kfree(g_cmsg); - kfree(g_debbuf); - return -ENOMEM; - } - g_debbuf->size = CDEBUG_GSIZE; - g_debbuf->buf[0] = 0; - g_debbuf->p = g_debbuf->buf; - g_debbuf->pos = 0; - return 0; -} - -void cdebug_exit(void) -{ - if (g_debbuf) - kfree(g_debbuf->buf); - kfree(g_debbuf); - kfree(g_cmsg); -} - -#else /* !CONFIG_CAPI_TRACE */ - -static _cdebbuf g_debbuf = {"CONFIG_CAPI_TRACE not enabled", NULL, 0, 0}; - -_cdebbuf *capi_message2str(u8 *msg) -{ - return &g_debbuf; -} - -_cdebbuf *capi_cmsg2str(_cmsg *cmsg) -{ - return &g_debbuf; -} - -void cdebbuf_free(_cdebbuf *cdb) -{ -} - -int __init cdebug_init(void) -{ - return 0; -} - -void cdebug_exit(void) -{ -} - -#endif diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c deleted file mode 100644 index f9fa17d68095..000000000000 --- a/drivers/isdn/capi/kcapi.c +++ /dev/null @@ -1,933 +0,0 @@ -/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $ - * - * Kernel CAPI 2.0 Module - * - * Copyright 1999 by Carsten Paeth - * Copyright 2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include "kcapi.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int showcapimsgs; -static struct workqueue_struct *kcapi_wq; - -module_param(showcapimsgs, uint, 0); - -/* ------------------------------------------------------------- */ - -struct capictr_event { - struct work_struct work; - unsigned int type; - u32 controller; -}; - -/* ------------------------------------------------------------- */ - -static const struct capi_version driver_version = {2, 0, 1, 1 << 4}; -static char driver_serial[CAPI_SERIAL_LEN] = "0004711"; -static char capi_manufakturer[64] = "AVM Berlin"; - -#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) - -struct capi_ctr *capi_controller[CAPI_MAXCONTR]; -DEFINE_MUTEX(capi_controller_lock); - -struct capi20_appl *capi_applications[CAPI_MAXAPPL]; - -static int ncontrollers; - -/* -------- controller ref counting -------------------------------------- */ - -static inline struct capi_ctr * -capi_ctr_get(struct capi_ctr *ctr) -{ - if (!try_module_get(ctr->owner)) - return NULL; - return ctr; -} - -static inline void -capi_ctr_put(struct capi_ctr *ctr) -{ - module_put(ctr->owner); -} - -/* ------------------------------------------------------------- */ - -static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr) -{ - if (contr < 1 || contr - 1 >= CAPI_MAXCONTR) - return NULL; - - return capi_controller[contr - 1]; -} - -static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid) -{ - lockdep_assert_held(&capi_controller_lock); - - if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) - return NULL; - - return capi_applications[applid - 1]; -} - -static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) -{ - if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) - return NULL; - - return rcu_dereference(capi_applications[applid - 1]); -} - -/* -------- util functions ------------------------------------ */ - -static inline int capi_cmd_valid(u8 cmd) -{ - switch (cmd) { - case CAPI_ALERT: - case CAPI_CONNECT: - case CAPI_CONNECT_ACTIVE: - case CAPI_CONNECT_B3_ACTIVE: - case CAPI_CONNECT_B3: - case CAPI_CONNECT_B3_T90_ACTIVE: - case CAPI_DATA_B3: - case CAPI_DISCONNECT_B3: - case CAPI_DISCONNECT: - case CAPI_FACILITY: - case CAPI_INFO: - case CAPI_LISTEN: - case CAPI_MANUFACTURER: - case CAPI_RESET_B3: - case CAPI_SELECT_B_PROTOCOL: - return 1; - } - return 0; -} - -static inline int capi_subcmd_valid(u8 subcmd) -{ - switch (subcmd) { - case CAPI_REQ: - case CAPI_CONF: - case CAPI_IND: - case CAPI_RESP: - return 1; - } - return 0; -} - -/* ------------------------------------------------------------ */ - -static void -register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam) -{ - ctr = capi_ctr_get(ctr); - - if (ctr) - ctr->register_appl(ctr, applid, rparam); - else - printk(KERN_WARNING "%s: cannot get controller resources\n", - __func__); -} - - -static void release_appl(struct capi_ctr *ctr, u16 applid) -{ - DBG("applid %#x", applid); - - ctr->release_appl(ctr, applid); - capi_ctr_put(ctr); -} - -static void notify_up(u32 contr) -{ - struct capi20_appl *ap; - struct capi_ctr *ctr; - u16 applid; - - mutex_lock(&capi_controller_lock); - - if (showcapimsgs & 1) - printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); - - ctr = get_capi_ctr_by_nr(contr); - if (ctr) { - if (ctr->state == CAPI_CTR_RUNNING) - goto unlock_out; - - ctr->state = CAPI_CTR_RUNNING; - - for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { - ap = __get_capi_appl_by_nr(applid); - if (ap) - register_appl(ctr, applid, &ap->rparam); - } - } else - printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); - -unlock_out: - mutex_unlock(&capi_controller_lock); -} - -static void ctr_down(struct capi_ctr *ctr, int new_state) -{ - struct capi20_appl *ap; - u16 applid; - - if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED) - return; - - ctr->state = new_state; - - memset(ctr->manu, 0, sizeof(ctr->manu)); - memset(&ctr->version, 0, sizeof(ctr->version)); - memset(&ctr->profile, 0, sizeof(ctr->profile)); - memset(ctr->serial, 0, sizeof(ctr->serial)); - - for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { - ap = __get_capi_appl_by_nr(applid); - if (ap) - capi_ctr_put(ctr); - } -} - -static void notify_down(u32 contr) -{ - struct capi_ctr *ctr; - - mutex_lock(&capi_controller_lock); - - if (showcapimsgs & 1) - printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr); - - ctr = get_capi_ctr_by_nr(contr); - if (ctr) - ctr_down(ctr, CAPI_CTR_DETECTED); - else - printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); - - mutex_unlock(&capi_controller_lock); -} - -static void do_notify_work(struct work_struct *work) -{ - struct capictr_event *event = - container_of(work, struct capictr_event, work); - - switch (event->type) { - case CAPICTR_UP: - notify_up(event->controller); - break; - case CAPICTR_DOWN: - notify_down(event->controller); - break; - } - - kfree(event); -} - -static int notify_push(unsigned int event_type, u32 controller) -{ - struct capictr_event *event = kmalloc_obj(*event, GFP_ATOMIC); - - if (!event) - return -ENOMEM; - - INIT_WORK(&event->work, do_notify_work); - event->type = event_type; - event->controller = controller; - - queue_work(kcapi_wq, &event->work); - return 0; -} - -/* -------- Receiver ------------------------------------------ */ - -static void recv_handler(struct work_struct *work) -{ - struct sk_buff *skb; - struct capi20_appl *ap = - container_of(work, struct capi20_appl, recv_work); - - if ((!ap) || (ap->release_in_progress)) - return; - - mutex_lock(&ap->recv_mtx); - while ((skb = skb_dequeue(&ap->recv_queue))) { - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) - ap->nrecvdatapkt++; - else - ap->nrecvctlpkt++; - - ap->recv_message(ap, skb); - } - mutex_unlock(&ap->recv_mtx); -} - -/** - * capi_ctr_handle_message() - handle incoming CAPI message - * @ctr: controller descriptor structure. - * @appl: application ID. - * @skb: message. - * - * Called by hardware driver to pass a CAPI message to the application. - */ - -void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, - struct sk_buff *skb) -{ - struct capi20_appl *ap; - int showctl = 0; - u8 cmd, subcmd; - _cdebbuf *cdb; - - if (ctr->state != CAPI_CTR_RUNNING) { - cdb = capi_message2str(skb->data); - if (cdb) { - printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s", - ctr->cnr, cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n", - ctr->cnr); - goto error; - } - - cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); - if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) { - ctr->nrecvdatapkt++; - if (ctr->traceflag > 2) - showctl |= 2; - } else { - ctr->nrecvctlpkt++; - if (ctr->traceflag) - showctl |= 2; - } - showctl |= (ctr->traceflag & 1); - if (showctl & 2) { - if (showctl & 1) { - printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n", - ctr->cnr, CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), - CAPIMSG_LEN(skb->data)); - } else { - cdb = capi_message2str(skb->data); - if (cdb) { - printk(KERN_DEBUG "kcapi: got [%03d] %s\n", - ctr->cnr, cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n", - ctr->cnr, CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), - CAPIMSG_LEN(skb->data)); - } - - } - - rcu_read_lock(); - ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); - if (!ap) { - rcu_read_unlock(); - cdb = capi_message2str(skb->data); - if (cdb) { - printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", - CAPIMSG_APPID(skb->data), cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n", - CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd)); - goto error; - } - skb_queue_tail(&ap->recv_queue, skb); - queue_work(kcapi_wq, &ap->recv_work); - rcu_read_unlock(); - - return; - -error: - kfree_skb(skb); -} - -EXPORT_SYMBOL(capi_ctr_handle_message); - -/** - * capi_ctr_ready() - signal CAPI controller ready - * @ctr: controller descriptor structure. - * - * Called by hardware driver to signal that the controller is up and running. - */ - -void capi_ctr_ready(struct capi_ctr *ctr) -{ - printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n", - ctr->cnr, ctr->name); - - notify_push(CAPICTR_UP, ctr->cnr); -} - -EXPORT_SYMBOL(capi_ctr_ready); - -/** - * capi_ctr_down() - signal CAPI controller not ready - * @ctr: controller descriptor structure. - * - * Called by hardware driver to signal that the controller is down and - * unavailable for use. - */ - -void capi_ctr_down(struct capi_ctr *ctr) -{ - printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr); - - notify_push(CAPICTR_DOWN, ctr->cnr); -} - -EXPORT_SYMBOL(capi_ctr_down); - -/* ------------------------------------------------------------- */ - -/** - * attach_capi_ctr() - register CAPI controller - * @ctr: controller descriptor structure. - * - * Called by hardware driver to register a controller with the CAPI subsystem. - * Return value: 0 on success, error code < 0 on error - */ - -int attach_capi_ctr(struct capi_ctr *ctr) -{ - int i; - - mutex_lock(&capi_controller_lock); - - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (!capi_controller[i]) - break; - } - if (i == CAPI_MAXCONTR) { - mutex_unlock(&capi_controller_lock); - printk(KERN_ERR "kcapi: out of controller slots\n"); - return -EBUSY; - } - capi_controller[i] = ctr; - - ctr->nrecvctlpkt = 0; - ctr->nrecvdatapkt = 0; - ctr->nsentctlpkt = 0; - ctr->nsentdatapkt = 0; - ctr->cnr = i + 1; - ctr->state = CAPI_CTR_DETECTED; - ctr->blocked = 0; - ctr->traceflag = showcapimsgs; - - sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr); - ctr->procent = proc_create_single_data(ctr->procfn, 0, NULL, - ctr->proc_show, ctr); - - ncontrollers++; - - mutex_unlock(&capi_controller_lock); - - printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n", - ctr->cnr, ctr->name); - return 0; -} - -EXPORT_SYMBOL(attach_capi_ctr); - -/** - * detach_capi_ctr() - unregister CAPI controller - * @ctr: controller descriptor structure. - * - * Called by hardware driver to remove the registration of a controller - * with the CAPI subsystem. - * Return value: 0 on success, error code < 0 on error - */ - -int detach_capi_ctr(struct capi_ctr *ctr) -{ - int err = 0; - - mutex_lock(&capi_controller_lock); - - ctr_down(ctr, CAPI_CTR_DETACHED); - - if (ctr->cnr < 1 || ctr->cnr - 1 >= CAPI_MAXCONTR) { - err = -EINVAL; - goto unlock_out; - } - - if (capi_controller[ctr->cnr - 1] != ctr) { - err = -EINVAL; - goto unlock_out; - } - capi_controller[ctr->cnr - 1] = NULL; - ncontrollers--; - - if (ctr->procent) - remove_proc_entry(ctr->procfn, NULL); - - printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n", - ctr->cnr, ctr->name); - -unlock_out: - mutex_unlock(&capi_controller_lock); - - return err; -} - -EXPORT_SYMBOL(detach_capi_ctr); - -/* ------------------------------------------------------------- */ -/* -------- CAPI2.0 Interface ---------------------------------- */ -/* ------------------------------------------------------------- */ - -/** - * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED - * - * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller - * is ready for use, CAPI_REGNOTINSTALLED otherwise) - */ - -u16 capi20_isinstalled(void) -{ - u16 ret = CAPI_REGNOTINSTALLED; - int i; - - mutex_lock(&capi_controller_lock); - - for (i = 0; i < CAPI_MAXCONTR; i++) - if (capi_controller[i] && - capi_controller[i]->state == CAPI_CTR_RUNNING) { - ret = CAPI_NOERROR; - break; - } - - mutex_unlock(&capi_controller_lock); - - return ret; -} - -/** - * capi20_register() - CAPI 2.0 operation CAPI_REGISTER - * @ap: CAPI application descriptor structure. - * - * Register an application's presence with CAPI. - * A unique application ID is assigned and stored in @ap->applid. - * After this function returns successfully, the message receive - * callback function @ap->recv_message() may be called at any time - * until capi20_release() has been called for the same @ap. - * Return value: CAPI result code - */ - -u16 capi20_register(struct capi20_appl *ap) -{ - int i; - u16 applid; - - DBG(""); - - if (ap->rparam.datablklen < 128) - return CAPI_LOGBLKSIZETOSMALL; - - ap->nrecvctlpkt = 0; - ap->nrecvdatapkt = 0; - ap->nsentctlpkt = 0; - ap->nsentdatapkt = 0; - mutex_init(&ap->recv_mtx); - skb_queue_head_init(&ap->recv_queue); - INIT_WORK(&ap->recv_work, recv_handler); - ap->release_in_progress = 0; - - mutex_lock(&capi_controller_lock); - - for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { - if (capi_applications[applid - 1] == NULL) - break; - } - if (applid > CAPI_MAXAPPL) { - mutex_unlock(&capi_controller_lock); - return CAPI_TOOMANYAPPLS; - } - - ap->applid = applid; - capi_applications[applid - 1] = ap; - - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (!capi_controller[i] || - capi_controller[i]->state != CAPI_CTR_RUNNING) - continue; - register_appl(capi_controller[i], applid, &ap->rparam); - } - - mutex_unlock(&capi_controller_lock); - - if (showcapimsgs & 1) { - printk(KERN_DEBUG "kcapi: appl %d up\n", applid); - } - - return CAPI_NOERROR; -} - -/** - * capi20_release() - CAPI 2.0 operation CAPI_RELEASE - * @ap: CAPI application descriptor structure. - * - * Terminate an application's registration with CAPI. - * After this function returns successfully, the message receive - * callback function @ap->recv_message() will no longer be called. - * Return value: CAPI result code - */ - -u16 capi20_release(struct capi20_appl *ap) -{ - int i; - - DBG("applid %#x", ap->applid); - - mutex_lock(&capi_controller_lock); - - ap->release_in_progress = 1; - capi_applications[ap->applid - 1] = NULL; - - synchronize_rcu(); - - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (!capi_controller[i] || - capi_controller[i]->state != CAPI_CTR_RUNNING) - continue; - release_appl(capi_controller[i], ap->applid); - } - - mutex_unlock(&capi_controller_lock); - - flush_workqueue(kcapi_wq); - skb_queue_purge(&ap->recv_queue); - - if (showcapimsgs & 1) { - printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid); - } - - return CAPI_NOERROR; -} - -/** - * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE - * @ap: CAPI application descriptor structure. - * @skb: CAPI message. - * - * Transfer a single message to CAPI. - * Return value: CAPI result code - */ - -u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb) -{ - struct capi_ctr *ctr; - int showctl = 0; - u8 cmd, subcmd; - - DBG("applid %#x", ap->applid); - - if (ncontrollers == 0) - return CAPI_REGNOTINSTALLED; - if ((ap->applid == 0) || ap->release_in_progress) - return CAPI_ILLAPPNR; - if (skb->len < 12 - || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) - || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) - return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; - - /* - * The controller reference is protected by the existence of the - * application passed to us. We assume that the caller properly - * synchronizes this service with capi20_release. - */ - ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data)); - if (!ctr || ctr->state != CAPI_CTR_RUNNING) - return CAPI_REGNOTINSTALLED; - if (ctr->blocked) - return CAPI_SENDQUEUEFULL; - - cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); - - if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { - ctr->nsentdatapkt++; - ap->nsentdatapkt++; - if (ctr->traceflag > 2) - showctl |= 2; - } else { - ctr->nsentctlpkt++; - ap->nsentctlpkt++; - if (ctr->traceflag) - showctl |= 2; - } - showctl |= (ctr->traceflag & 1); - if (showctl & 2) { - if (showctl & 1) { - printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n", - CAPIMSG_CONTROLLER(skb->data), - CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), - CAPIMSG_LEN(skb->data)); - } else { - _cdebbuf *cdb = capi_message2str(skb->data); - if (cdb) { - printk(KERN_DEBUG "kcapi: put [%03d] %s\n", - CAPIMSG_CONTROLLER(skb->data), - cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n", - CAPIMSG_CONTROLLER(skb->data), - CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), - CAPIMSG_LEN(skb->data)); - } - } - return ctr->send_message(ctr, skb); -} - -/** - * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER - * @contr: controller number. - * @buf: result buffer (64 bytes). - * - * Retrieve information about the manufacturer of the specified ISDN controller - * or (for @contr == 0) the driver itself. - * Return value: CAPI result code - */ - -u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN]) -{ - struct capi_ctr *ctr; - u16 ret; - - if (contr == 0) { - strscpy_pad(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); - return CAPI_NOERROR; - } - - mutex_lock(&capi_controller_lock); - - ctr = get_capi_ctr_by_nr(contr); - if (ctr && ctr->state == CAPI_CTR_RUNNING) { - strscpy_pad(buf, ctr->manu, CAPI_MANUFACTURER_LEN); - ret = CAPI_NOERROR; - } else - ret = CAPI_REGNOTINSTALLED; - - mutex_unlock(&capi_controller_lock); - return ret; -} - -/** - * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION - * @contr: controller number. - * @verp: result structure. - * - * Retrieve version information for the specified ISDN controller - * or (for @contr == 0) the driver itself. - * Return value: CAPI result code - */ - -u16 capi20_get_version(u32 contr, struct capi_version *verp) -{ - struct capi_ctr *ctr; - u16 ret; - - if (contr == 0) { - *verp = driver_version; - return CAPI_NOERROR; - } - - mutex_lock(&capi_controller_lock); - - ctr = get_capi_ctr_by_nr(contr); - if (ctr && ctr->state == CAPI_CTR_RUNNING) { - memcpy(verp, &ctr->version, sizeof(capi_version)); - ret = CAPI_NOERROR; - } else - ret = CAPI_REGNOTINSTALLED; - - mutex_unlock(&capi_controller_lock); - return ret; -} - -/** - * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER - * @contr: controller number. - * @serial: result buffer (8 bytes). - * - * Retrieve the serial number of the specified ISDN controller - * or (for @contr == 0) the driver itself. - * Return value: CAPI result code - */ - -u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN]) -{ - struct capi_ctr *ctr; - u16 ret; - - if (contr == 0) { - strscpy(serial, driver_serial, CAPI_SERIAL_LEN); - return CAPI_NOERROR; - } - - mutex_lock(&capi_controller_lock); - - ctr = get_capi_ctr_by_nr(contr); - if (ctr && ctr->state == CAPI_CTR_RUNNING) { - strscpy(serial, ctr->serial, CAPI_SERIAL_LEN); - ret = CAPI_NOERROR; - } else - ret = CAPI_REGNOTINSTALLED; - - mutex_unlock(&capi_controller_lock); - return ret; -} - -/** - * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE - * @contr: controller number. - * @profp: result structure. - * - * Retrieve capability information for the specified ISDN controller - * or (for @contr == 0) the number of installed controllers. - * Return value: CAPI result code - */ - -u16 capi20_get_profile(u32 contr, struct capi_profile *profp) -{ - struct capi_ctr *ctr; - u16 ret; - - if (contr == 0) { - profp->ncontroller = ncontrollers; - return CAPI_NOERROR; - } - - mutex_lock(&capi_controller_lock); - - ctr = get_capi_ctr_by_nr(contr); - if (ctr && ctr->state == CAPI_CTR_RUNNING) { - memcpy(profp, &ctr->profile, sizeof(struct capi_profile)); - ret = CAPI_NOERROR; - } else - ret = CAPI_REGNOTINSTALLED; - - mutex_unlock(&capi_controller_lock); - return ret; -} - -/** - * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER - * @cmd: command. - * @data: parameter. - * - * Perform manufacturer specific command. - * Return value: CAPI result code - */ - -int capi20_manufacturer(unsigned long cmd, void __user *data) -{ - struct capi_ctr *ctr; - int retval; - - switch (cmd) { - case KCAPI_CMD_TRACE: - { - kcapi_flagdef fdef; - - if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef))) - return -EFAULT; - - mutex_lock(&capi_controller_lock); - - ctr = get_capi_ctr_by_nr(fdef.contr); - if (ctr) { - ctr->traceflag = fdef.flag; - printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n", - ctr->cnr, ctr->traceflag); - retval = 0; - } else - retval = -ESRCH; - - mutex_unlock(&capi_controller_lock); - - return retval; - } - - default: - printk(KERN_ERR "kcapi: manufacturer command %lu unknown.\n", - cmd); - break; - - } - return -EINVAL; -} - -/* ------------------------------------------------------------- */ -/* -------- Init & Cleanup ------------------------------------- */ -/* ------------------------------------------------------------- */ - -/* - * init / exit functions - */ - -int __init kcapi_init(void) -{ - int err; - - kcapi_wq = alloc_workqueue("kcapi", WQ_PERCPU, 0); - if (!kcapi_wq) - return -ENOMEM; - - err = cdebug_init(); - if (err) { - destroy_workqueue(kcapi_wq); - return err; - } - - if (IS_ENABLED(CONFIG_PROC_FS)) - kcapi_proc_init(); - - return 0; -} - -void kcapi_exit(void) -{ - if (IS_ENABLED(CONFIG_PROC_FS)) - kcapi_proc_exit(); - - cdebug_exit(); - destroy_workqueue(kcapi_wq); -} diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h deleted file mode 100644 index 479623e1db2a..000000000000 --- a/drivers/isdn/capi/kcapi.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Kernel CAPI 2.0 Module - * - * Copyright 1999 by Carsten Paeth - * Copyright 2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include -#include -#include -#include - -#ifdef KCAPI_DEBUG -#define DBG(format, arg...) do { \ - printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ - } while (0) -#else -#define DBG(format, arg...) /* */ -#endif - -enum { - CAPI_CTR_DETACHED = 0, - CAPI_CTR_DETECTED = 1, - CAPI_CTR_LOADING = 2, - CAPI_CTR_RUNNING = 3, -}; - -extern struct capi_ctr *capi_controller[CAPI_MAXCONTR]; -extern struct mutex capi_controller_lock; - -extern struct capi20_appl *capi_applications[CAPI_MAXAPPL]; - -void kcapi_proc_init(void); -void kcapi_proc_exit(void); - -struct capi20_appl { - u16 applid; - capi_register_params rparam; - void (*recv_message)(struct capi20_appl *ap, struct sk_buff *skb); - void *private; - - /* internal to kernelcapi.o */ - unsigned long nrecvctlpkt; - unsigned long nrecvdatapkt; - unsigned long nsentctlpkt; - unsigned long nsentdatapkt; - struct mutex recv_mtx; - struct sk_buff_head recv_queue; - struct work_struct recv_work; - int release_in_progress; -}; - -u16 capi20_isinstalled(void); -u16 capi20_register(struct capi20_appl *ap); -u16 capi20_release(struct capi20_appl *ap); -u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb); -u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN]); -u16 capi20_get_version(u32 contr, struct capi_version *verp); -u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN]); -u16 capi20_get_profile(u32 contr, struct capi_profile *profp); -int capi20_manufacturer(unsigned long cmd, void __user *data); - -#define CAPICTR_UP 0 -#define CAPICTR_DOWN 1 - -int kcapi_init(void); -void kcapi_exit(void); - -/*----- basic-type definitions -----*/ - -typedef __u8 *_cstruct; - -typedef enum { - CAPI_COMPOSE, - CAPI_DEFAULT -} _cmstruct; - -/* - The _cmsg structure contains all possible CAPI 2.0 parameter. - All parameters are stored here first. The function CAPI_CMSG_2_MESSAGE - assembles the parameter and builds CAPI2.0 conform messages. - CAPI_MESSAGE_2_CMSG disassembles CAPI 2.0 messages and stores the - parameter in the _cmsg structure - */ - -typedef struct { - /* Header */ - __u16 ApplId; - __u8 Command; - __u8 Subcommand; - __u16 Messagenumber; - - /* Parameter */ - union { - __u32 adrController; - __u32 adrPLCI; - __u32 adrNCCI; - } adr; - - _cmstruct AdditionalInfo; - _cstruct B1configuration; - __u16 B1protocol; - _cstruct B2configuration; - __u16 B2protocol; - _cstruct B3configuration; - __u16 B3protocol; - _cstruct BC; - _cstruct BChannelinformation; - _cmstruct BProtocol; - _cstruct CalledPartyNumber; - _cstruct CalledPartySubaddress; - _cstruct CallingPartyNumber; - _cstruct CallingPartySubaddress; - __u32 CIPmask; - __u32 CIPmask2; - __u16 CIPValue; - __u32 Class; - _cstruct ConnectedNumber; - _cstruct ConnectedSubaddress; - __u32 Data; - __u16 DataHandle; - __u16 DataLength; - _cstruct FacilityConfirmationParameter; - _cstruct Facilitydataarray; - _cstruct FacilityIndicationParameter; - _cstruct FacilityRequestParameter; - __u16 FacilitySelector; - __u16 Flags; - __u32 Function; - _cstruct HLC; - __u16 Info; - _cstruct InfoElement; - __u32 InfoMask; - __u16 InfoNumber; - _cstruct Keypadfacility; - _cstruct LLC; - _cstruct ManuData; - __u32 ManuID; - _cstruct NCPI; - __u16 Reason; - __u16 Reason_B3; - __u16 Reject; - _cstruct Useruserdata; - - /* intern */ - unsigned l, p; - unsigned char *par; - __u8 *m; - - /* buffer to construct message */ - __u8 buf[180]; - -} _cmsg; - -/*-----------------------------------------------------------------------*/ - -/* - * Debugging / Tracing functions - */ - -char *capi_cmd2str(__u8 cmd, __u8 subcmd); - -typedef struct { - u_char *buf; - u_char *p; - size_t size; - size_t pos; -} _cdebbuf; - -#define CDEBUG_SIZE 1024 -#define CDEBUG_GSIZE 4096 - -void cdebbuf_free(_cdebbuf *cdb); -int cdebug_init(void); -void cdebug_exit(void); - -_cdebbuf *capi_message2str(__u8 *msg); diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c deleted file mode 100644 index 77e951206809..000000000000 --- a/drivers/isdn/capi/kcapi_proc.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Kernel CAPI 2.0 Module - /proc/capi handling - * - * Copyright 1999 by Carsten Paeth - * Copyright 2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include "kcapi.h" -#include -#include -#include -#include - -static char *state2str(unsigned short state) -{ - switch (state) { - case CAPI_CTR_DETECTED: return "detected"; - case CAPI_CTR_LOADING: return "loading"; - case CAPI_CTR_RUNNING: return "running"; - default: return "???"; - } -} - -// /proc/capi -// =========================================================================== - -// /proc/capi/controller: -// cnr driver cardstate name driverinfo -// /proc/capi/contrstats: -// cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt -// --------------------------------------------------------------------------- - -static void *controller_start(struct seq_file *seq, loff_t *pos) - __acquires(capi_controller_lock) -{ - mutex_lock(&capi_controller_lock); - - if (*pos < CAPI_MAXCONTR) - return &capi_controller[*pos]; - - return NULL; -} - -static void *controller_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - if (*pos < CAPI_MAXCONTR) - return &capi_controller[*pos]; - - return NULL; -} - -static void controller_stop(struct seq_file *seq, void *v) - __releases(capi_controller_lock) -{ - mutex_unlock(&capi_controller_lock); -} - -static int controller_show(struct seq_file *seq, void *v) -{ - struct capi_ctr *ctr = *(struct capi_ctr **) v; - - if (!ctr) - return 0; - - seq_printf(seq, "%d %-10s %-8s %-16s %s\n", - ctr->cnr, ctr->driver_name, - state2str(ctr->state), - ctr->name, - ctr->procinfo ? ctr->procinfo(ctr) : ""); - - return 0; -} - -static int contrstats_show(struct seq_file *seq, void *v) -{ - struct capi_ctr *ctr = *(struct capi_ctr **) v; - - if (!ctr) - return 0; - - seq_printf(seq, "%d %lu %lu %lu %lu\n", - ctr->cnr, - ctr->nrecvctlpkt, - ctr->nrecvdatapkt, - ctr->nsentctlpkt, - ctr->nsentdatapkt); - - return 0; -} - -static const struct seq_operations seq_controller_ops = { - .start = controller_start, - .next = controller_next, - .stop = controller_stop, - .show = controller_show, -}; - -static const struct seq_operations seq_contrstats_ops = { - .start = controller_start, - .next = controller_next, - .stop = controller_stop, - .show = contrstats_show, -}; - -// /proc/capi/applications: -// applid l3cnt dblkcnt dblklen #ncci recvqueuelen -// /proc/capi/applstats: -// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt -// --------------------------------------------------------------------------- - -static void *applications_start(struct seq_file *seq, loff_t *pos) - __acquires(capi_controller_lock) -{ - mutex_lock(&capi_controller_lock); - - if (*pos < CAPI_MAXAPPL) - return &capi_applications[*pos]; - - return NULL; -} - -static void * -applications_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - if (*pos < CAPI_MAXAPPL) - return &capi_applications[*pos]; - - return NULL; -} - -static void applications_stop(struct seq_file *seq, void *v) - __releases(capi_controller_lock) -{ - mutex_unlock(&capi_controller_lock); -} - -static int -applications_show(struct seq_file *seq, void *v) -{ - struct capi20_appl *ap = *(struct capi20_appl **) v; - - if (!ap) - return 0; - - seq_printf(seq, "%u %d %d %d\n", - ap->applid, - ap->rparam.level3cnt, - ap->rparam.datablkcnt, - ap->rparam.datablklen); - - return 0; -} - -static int -applstats_show(struct seq_file *seq, void *v) -{ - struct capi20_appl *ap = *(struct capi20_appl **) v; - - if (!ap) - return 0; - - seq_printf(seq, "%u %lu %lu %lu %lu\n", - ap->applid, - ap->nrecvctlpkt, - ap->nrecvdatapkt, - ap->nsentctlpkt, - ap->nsentdatapkt); - - return 0; -} - -static const struct seq_operations seq_applications_ops = { - .start = applications_start, - .next = applications_next, - .stop = applications_stop, - .show = applications_show, -}; - -static const struct seq_operations seq_applstats_ops = { - .start = applications_start, - .next = applications_next, - .stop = applications_stop, - .show = applstats_show, -}; - -// --------------------------------------------------------------------------- - -/* /proc/capi/drivers is always empty */ -static ssize_t empty_read(struct file *file, char __user *buf, - size_t size, loff_t *off) -{ - return 0; -} - -static const struct proc_ops empty_proc_ops = { - .proc_read = empty_read, - .proc_lseek = default_llseek, -}; - -// --------------------------------------------------------------------------- - -void __init -kcapi_proc_init(void) -{ - proc_mkdir("capi", NULL); - proc_mkdir("capi/controllers", NULL); - proc_create_seq("capi/controller", 0, NULL, &seq_controller_ops); - proc_create_seq("capi/contrstats", 0, NULL, &seq_contrstats_ops); - proc_create_seq("capi/applications", 0, NULL, &seq_applications_ops); - proc_create_seq("capi/applstats", 0, NULL, &seq_applstats_ops); - proc_create("capi/driver", 0, NULL, &empty_proc_ops); -} - -void -kcapi_proc_exit(void) -{ - remove_proc_entry("capi/driver", NULL); - remove_proc_entry("capi/controller", NULL); - remove_proc_entry("capi/contrstats", NULL); - remove_proc_entry("capi/applications", NULL); - remove_proc_entry("capi/applstats", NULL); - remove_proc_entry("capi/controllers", NULL); - remove_proc_entry("capi", NULL); -} diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile deleted file mode 100644 index 96f9eb2e46ba..000000000000 --- a/drivers/isdn/hardware/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile for the CAPI hardware drivers - -# Object files in subdirectories - -obj-$(CONFIG_MISDN) += mISDN/ diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig deleted file mode 100644 index a35bff8a93f5..000000000000 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ /dev/null @@ -1,98 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Hardware for mISDN -# -comment "mISDN hardware drivers" - -config MISDN_HFCPCI - tristate "Support for HFC PCI cards" - depends on MISDN - depends on PCI - help - Enable support for cards with Cologne Chip AG's - HFC PCI chip. - -config MISDN_HFCMULTI - tristate "Support for HFC multiport cards (HFC-4S/8S/E1)" - depends on (PCI || CPM1) && HAS_IOPORT - depends on MISDN - help - Enable support for cards with Cologne Chip AG's HFC multiport - chip. There are three types of chips that are quite similar, - but the interface is different: - * HFC-4S (4 S/T interfaces on one chip) - * HFC-8S (8 S/T interfaces on one chip) - * HFC-E1 (E1 interface for 2Mbit ISDN) - -config MISDN_HFCMULTI_8xx - bool "Support for XHFC embedded board in HFC multiport driver" - depends on MISDN - depends on MISDN_HFCMULTI - depends on CPM1 - default CPM1 - help - Enable support for the XHFC embedded solution from Speech Design. - -config MISDN_HFCUSB - tristate "Support for HFC-S USB based TAs" - depends on USB - help - Enable support for USB ISDN TAs with Cologne Chip AG's - HFC-S USB ISDN Controller - -config MISDN_AVMFRITZ - tristate "Support for AVM FRITZ!CARD PCI" - depends on MISDN - depends on PCI && HAS_IOPORT - select MISDN_IPAC - help - Enable support for AVMs FRITZ!CARD PCI cards - -config MISDN_SPEEDFAX - tristate "Support for Sedlbauer Speedfax+" - depends on MISDN - depends on PCI && HAS_IOPORT - select MISDN_IPAC - select MISDN_ISAR - help - Enable support for Sedlbauer Speedfax+. - -config MISDN_INFINEON - tristate "Support for cards with Infineon chipset" - depends on MISDN - depends on PCI && HAS_IOPORT - select MISDN_IPAC - help - Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX - chip from Infineon (former manufacturer Siemens). - -config MISDN_W6692 - tristate "Support for cards with Winbond 6692" - depends on MISDN - depends on PCI && HAS_IOPORT - help - Enable support for Winbond 6692 PCI chip based cards. - -config MISDN_NETJET - tristate "Support for NETJet cards" - depends on MISDN - depends on PCI && HAS_IOPORT - depends on TTY - select MISDN_IPAC - select MISDN_HDLC - help - Enable support for Traverse Technologies NETJet PCI cards. - -config MISDN_HDLC - tristate - select CRC_CCITT - select BITREVERSE - -config MISDN_IPAC - tristate - depends on MISDN - -config MISDN_ISAR - tristate - depends on MISDN - diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile deleted file mode 100644 index 3f50f8c4753f..000000000000 --- a/drivers/isdn/hardware/mISDN/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the modular ISDN hardware drivers -# -# - -obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o -obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o -obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o -obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o -obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o -obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o -obj-$(CONFIG_MISDN_W6692) += w6692.o -obj-$(CONFIG_MISDN_NETJET) += netjet.o -# chip modules -obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o -obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o - -obj-$(CONFIG_MISDN_HDLC) += isdnhdlc.o diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c deleted file mode 100644 index 55e0b9efa194..000000000000 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ /dev/null @@ -1,1164 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards - * Thanks to AVM, Berlin for informations - * - * Author Karsten Keil - * - * Copyright 2009 by Karsten Keil - */ -#include -#include -#include -#include -#include -#include -#include -#include "ipac.h" - - -#define AVMFRITZ_REV "2.3" - -static int AVM_cnt; -static int debug; - -enum { - AVM_FRITZ_PCI, - AVM_FRITZ_PCIV2, -}; - -#define HDLC_FIFO 0x0 -#define HDLC_STATUS 0x4 -#define CHIP_WINDOW 0x10 - -#define CHIP_INDEX 0x4 -#define AVM_HDLC_1 0x00 -#define AVM_HDLC_2 0x01 -#define AVM_ISAC_FIFO 0x02 -#define AVM_ISAC_REG_LOW 0x04 -#define AVM_ISAC_REG_HIGH 0x06 - -#define AVM_STATUS0_IRQ_ISAC 0x01 -#define AVM_STATUS0_IRQ_HDLC 0x02 -#define AVM_STATUS0_IRQ_TIMER 0x04 -#define AVM_STATUS0_IRQ_MASK 0x07 - -#define AVM_STATUS0_RESET 0x01 -#define AVM_STATUS0_DIS_TIMER 0x02 -#define AVM_STATUS0_RES_TIMER 0x04 -#define AVM_STATUS0_ENA_IRQ 0x08 -#define AVM_STATUS0_TESTBIT 0x10 - -#define AVM_STATUS1_INT_SEL 0x0f -#define AVM_STATUS1_ENA_IOM 0x80 - -#define HDLC_MODE_ITF_FLG 0x01 -#define HDLC_MODE_TRANS 0x02 -#define HDLC_MODE_CCR_7 0x04 -#define HDLC_MODE_CCR_16 0x08 -#define HDLC_FIFO_SIZE_128 0x20 -#define HDLC_MODE_TESTLOOP 0x80 - -#define HDLC_INT_XPR 0x80 -#define HDLC_INT_XDU 0x40 -#define HDLC_INT_RPR 0x20 -#define HDLC_INT_MASK 0xE0 - -#define HDLC_STAT_RME 0x01 -#define HDLC_STAT_RDO 0x10 -#define HDLC_STAT_CRCVFRRAB 0x0E -#define HDLC_STAT_CRCVFR 0x06 -#define HDLC_STAT_RML_MASK_V1 0x3f00 -#define HDLC_STAT_RML_MASK_V2 0x7f00 - -#define HDLC_CMD_XRS 0x80 -#define HDLC_CMD_XME 0x01 -#define HDLC_CMD_RRS 0x20 -#define HDLC_CMD_XML_MASK 0x3f00 - -#define HDLC_FIFO_SIZE_V1 32 -#define HDLC_FIFO_SIZE_V2 128 - -/* Fritz PCI v2.0 */ - -#define AVM_HDLC_FIFO_1 0x10 -#define AVM_HDLC_FIFO_2 0x18 - -#define AVM_HDLC_STATUS_1 0x14 -#define AVM_HDLC_STATUS_2 0x1c - -#define AVM_ISACX_INDEX 0x04 -#define AVM_ISACX_DATA 0x08 - -/* data struct */ -#define LOG_SIZE 63 - -struct hdlc_stat_reg { -#ifdef __BIG_ENDIAN - u8 fill; - u8 mode; - u8 xml; - u8 cmd; -#else - u8 cmd; - u8 xml; - u8 mode; - u8 fill; -#endif -} __attribute__((packed)); - -struct hdlc_hw { - union { - u32 ctrl; - struct hdlc_stat_reg sr; - } ctrl; - u32 stat; -}; - -struct fritzcard { - struct list_head list; - struct pci_dev *pdev; - char name[MISDN_MAX_IDLEN]; - u8 type; - u8 ctrlreg; - u16 irq; - u32 irqcnt; - u32 addr; - spinlock_t lock; /* hw lock */ - struct isac_hw isac; - struct hdlc_hw hdlc[2]; - struct bchannel bch[2]; - char log[LOG_SIZE + 1]; -}; - -static LIST_HEAD(Cards); -static DEFINE_RWLOCK(card_lock); /* protect Cards */ - -static void -_set_debug(struct fritzcard *card) -{ - card->isac.dch.debug = debug; - card->bch[0].debug = debug; - card->bch[1].debug = debug; -} - -static int -set_debug(const char *val, const struct kernel_param *kp) -{ - int ret; - struct fritzcard *card; - - ret = param_set_uint(val, kp); - if (!ret) { - read_lock(&card_lock); - list_for_each_entry(card, &Cards, list) - _set_debug(card); - read_unlock(&card_lock); - } - return ret; -} - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("mISDN driver for AVM FRITZ!CARD PCI ISDN cards"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(AVMFRITZ_REV); -module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "avmfritz debug mask"); - -/* Interface functions */ - -static u8 -ReadISAC_V1(void *p, u8 offset) -{ - struct fritzcard *fc = p; - u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - - outb(idx, fc->addr + CHIP_INDEX); - return inb(fc->addr + CHIP_WINDOW + (offset & 0xf)); -} - -static void -WriteISAC_V1(void *p, u8 offset, u8 value) -{ - struct fritzcard *fc = p; - u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - - outb(idx, fc->addr + CHIP_INDEX); - outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf)); -} - -static void -ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size) -{ - struct fritzcard *fc = p; - - outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); - insb(fc->addr + CHIP_WINDOW, data, size); -} - -static void -WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size) -{ - struct fritzcard *fc = p; - - outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); - outsb(fc->addr + CHIP_WINDOW, data, size); -} - -static u8 -ReadISAC_V2(void *p, u8 offset) -{ - struct fritzcard *fc = p; - - outl(offset, fc->addr + AVM_ISACX_INDEX); - return 0xff & inl(fc->addr + AVM_ISACX_DATA); -} - -static void -WriteISAC_V2(void *p, u8 offset, u8 value) -{ - struct fritzcard *fc = p; - - outl(offset, fc->addr + AVM_ISACX_INDEX); - outl(value, fc->addr + AVM_ISACX_DATA); -} - -static void -ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size) -{ - struct fritzcard *fc = p; - int i; - - outl(off, fc->addr + AVM_ISACX_INDEX); - for (i = 0; i < size; i++) - data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA); -} - -static void -WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size) -{ - struct fritzcard *fc = p; - int i; - - outl(off, fc->addr + AVM_ISACX_INDEX); - for (i = 0; i < size; i++) - outl(data[i], fc->addr + AVM_ISACX_DATA); -} - -static struct bchannel * -Sel_BCS(struct fritzcard *fc, u32 channel) -{ - if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && - (fc->bch[0].nr & channel)) - return &fc->bch[0]; - else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && - (fc->bch[1].nr & channel)) - return &fc->bch[1]; - else - return NULL; -} - -static inline void -__write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { - u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1; - - outl(idx, fc->addr + CHIP_INDEX); - outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS); -} - -static inline void -__write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { - outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 : - AVM_HDLC_STATUS_1)); -} - -static void -write_ctrl(struct bchannel *bch, int which) { - struct fritzcard *fc = bch->hw; - struct hdlc_hw *hdlc; - - hdlc = &fc->hdlc[(bch->nr - 1) & 1]; - pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr, - which, hdlc->ctrl.ctrl); - switch (fc->type) { - case AVM_FRITZ_PCIV2: - __write_ctrl_pciv2(fc, hdlc, bch->nr); - break; - case AVM_FRITZ_PCI: - __write_ctrl_pci(fc, hdlc, bch->nr); - break; - } -} - - -static inline u32 -__read_status_pci(u_long addr, u32 channel) -{ - outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX); - return inl(addr + CHIP_WINDOW + HDLC_STATUS); -} - -static inline u32 -__read_status_pciv2(u_long addr, u32 channel) -{ - return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 : - AVM_HDLC_STATUS_1)); -} - - -static u32 -read_status(struct fritzcard *fc, u32 channel) -{ - switch (fc->type) { - case AVM_FRITZ_PCIV2: - return __read_status_pciv2(fc->addr, channel); - case AVM_FRITZ_PCI: - return __read_status_pci(fc->addr, channel); - } - /* dummy */ - return 0; -} - -static void -enable_hwirq(struct fritzcard *fc) -{ - fc->ctrlreg |= AVM_STATUS0_ENA_IRQ; - outb(fc->ctrlreg, fc->addr + 2); -} - -static void -disable_hwirq(struct fritzcard *fc) -{ - fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ; - outb(fc->ctrlreg, fc->addr + 2); -} - -static int -modehdlc(struct bchannel *bch, int protocol) -{ - struct fritzcard *fc = bch->hw; - struct hdlc_hw *hdlc; - u8 mode; - - hdlc = &fc->hdlc[(bch->nr - 1) & 1]; - pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name, - '@' + bch->nr, bch->state, protocol, bch->nr); - hdlc->ctrl.ctrl = 0; - mode = (fc->type == AVM_FRITZ_PCIV2) ? HDLC_FIFO_SIZE_128 : 0; - - switch (protocol) { - case -1: /* used for init */ - bch->state = -1; - fallthrough; - case ISDN_P_NONE: - if (bch->state == ISDN_P_NONE) - break; - hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS; - write_ctrl(bch, 5); - bch->state = ISDN_P_NONE; - test_and_clear_bit(FLG_HDLC, &bch->Flags); - test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); - break; - case ISDN_P_B_RAW: - bch->state = protocol; - hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS; - write_ctrl(bch, 5); - hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; - write_ctrl(bch, 1); - hdlc->ctrl.sr.cmd = 0; - test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); - break; - case ISDN_P_B_HDLC: - bch->state = protocol; - hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - hdlc->ctrl.sr.mode = mode | HDLC_MODE_ITF_FLG; - write_ctrl(bch, 5); - hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; - write_ctrl(bch, 1); - hdlc->ctrl.sr.cmd = 0; - test_and_set_bit(FLG_HDLC, &bch->Flags); - break; - default: - pr_info("%s: protocol not known %x\n", fc->name, protocol); - return -ENOPROTOOPT; - } - return 0; -} - -static void -hdlc_empty_fifo(struct bchannel *bch, int count) -{ - u32 *ptr; - u8 *p; - u32 val, addr; - int cnt; - struct fritzcard *fc = bch->hw; - - pr_debug("%s: %s %d\n", fc->name, __func__, count); - if (test_bit(FLG_RX_OFF, &bch->Flags)) { - p = NULL; - bch->dropcnt += count; - } else { - cnt = bchannel_get_rxbuf(bch, count); - if (cnt < 0) { - pr_warn("%s.B%d: No bufferspace for %d bytes\n", - fc->name, bch->nr, count); - return; - } - p = skb_put(bch->rx_skb, count); - } - ptr = (u32 *)p; - if (fc->type == AVM_FRITZ_PCIV2) - addr = fc->addr + (bch->nr == 2 ? - AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); - else { - addr = fc->addr + CHIP_WINDOW; - outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); - } - cnt = 0; - while (cnt < count) { - val = le32_to_cpu(inl(addr)); - if (p) { - put_unaligned(val, ptr); - ptr++; - } - cnt += 4; - } - if (p && (debug & DEBUG_HW_BFIFO)) { - snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", - bch->nr, fc->name, count); - print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); - } -} - -static void -hdlc_fill_fifo(struct bchannel *bch) -{ - struct fritzcard *fc = bch->hw; - struct hdlc_hw *hdlc; - int count, fs, cnt = 0, idx; - bool fillempty = false; - u8 *p; - u32 *ptr, val, addr; - - idx = (bch->nr - 1) & 1; - hdlc = &fc->hdlc[idx]; - fs = (fc->type == AVM_FRITZ_PCIV2) ? - HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1; - if (!bch->tx_skb) { - if (!test_bit(FLG_TX_EMPTY, &bch->Flags)) - return; - count = fs; - p = bch->fill; - fillempty = true; - } else { - count = bch->tx_skb->len - bch->tx_idx; - if (count <= 0) - return; - p = bch->tx_skb->data + bch->tx_idx; - } - hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; - if (count > fs) { - count = fs; - } else { - if (test_bit(FLG_HDLC, &bch->Flags)) - hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; - } - ptr = (u32 *)p; - if (!fillempty) { - pr_debug("%s.B%d: %d/%d/%d", fc->name, bch->nr, count, - bch->tx_idx, bch->tx_skb->len); - bch->tx_idx += count; - } else { - pr_debug("%s.B%d: fillempty %d\n", fc->name, bch->nr, count); - } - hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count); - if (fc->type == AVM_FRITZ_PCIV2) { - __write_ctrl_pciv2(fc, hdlc, bch->nr); - addr = fc->addr + (bch->nr == 2 ? - AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); - } else { - __write_ctrl_pci(fc, hdlc, bch->nr); - addr = fc->addr + CHIP_WINDOW; - } - if (fillempty) { - while (cnt < count) { - /* all bytes the same - no worry about endian */ - outl(*ptr, addr); - cnt += 4; - } - } else { - while (cnt < count) { - val = get_unaligned(ptr); - outl(cpu_to_le32(val), addr); - ptr++; - cnt += 4; - } - } - if ((debug & DEBUG_HW_BFIFO) && !fillempty) { - snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", - bch->nr, fc->name, count); - print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); - } -} - -static void -HDLC_irq_xpr(struct bchannel *bch) -{ - if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) { - hdlc_fill_fifo(bch); - } else { - dev_kfree_skb(bch->tx_skb); - if (get_next_bframe(bch)) { - hdlc_fill_fifo(bch); - test_and_clear_bit(FLG_TX_EMPTY, &bch->Flags); - } else if (test_bit(FLG_TX_EMPTY, &bch->Flags)) { - hdlc_fill_fifo(bch); - } - } -} - -static void -HDLC_irq(struct bchannel *bch, u32 stat) -{ - struct fritzcard *fc = bch->hw; - int len, fs; - u32 rmlMask; - struct hdlc_hw *hdlc; - - hdlc = &fc->hdlc[(bch->nr - 1) & 1]; - pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat); - if (fc->type == AVM_FRITZ_PCIV2) { - rmlMask = HDLC_STAT_RML_MASK_V2; - fs = HDLC_FIFO_SIZE_V2; - } else { - rmlMask = HDLC_STAT_RML_MASK_V1; - fs = HDLC_FIFO_SIZE_V1; - } - if (stat & HDLC_INT_RPR) { - if (stat & HDLC_STAT_RDO) { - pr_warn("%s: ch%d stat %x RDO\n", - fc->name, bch->nr, stat); - hdlc->ctrl.sr.xml = 0; - hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS; - write_ctrl(bch, 1); - hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS; - write_ctrl(bch, 1); - if (bch->rx_skb) - skb_trim(bch->rx_skb, 0); - } else { - len = (stat & rmlMask) >> 8; - if (!len) - len = fs; - hdlc_empty_fifo(bch, len); - if (!bch->rx_skb) - goto handle_tx; - if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { - recv_Bchannel(bch, 0, false); - } else if (stat & HDLC_STAT_RME) { - if ((stat & HDLC_STAT_CRCVFRRAB) == - HDLC_STAT_CRCVFR) { - recv_Bchannel(bch, 0, false); - } else { - pr_warn("%s: got invalid frame\n", - fc->name); - skb_trim(bch->rx_skb, 0); - } - } - } - } -handle_tx: - if (stat & HDLC_INT_XDU) { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame on HDLC - * in transparent mode we send the next data - */ - pr_warn("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr, - stat, bch->tx_skb ? "tx_skb" : "no tx_skb"); - if (bch->tx_skb && bch->tx_skb->len) { - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - bch->tx_idx = 0; - } else if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { - test_and_set_bit(FLG_TX_EMPTY, &bch->Flags); - } - hdlc->ctrl.sr.xml = 0; - hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; - write_ctrl(bch, 1); - hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS; - HDLC_irq_xpr(bch); - return; - } else if (stat & HDLC_INT_XPR) - HDLC_irq_xpr(bch); -} - -static inline void -HDLC_irq_main(struct fritzcard *fc) -{ - u32 stat; - struct bchannel *bch; - - stat = read_status(fc, 1); - if (stat & HDLC_INT_MASK) { - bch = Sel_BCS(fc, 1); - if (bch) - HDLC_irq(bch, stat); - else - pr_debug("%s: spurious ch1 IRQ\n", fc->name); - } - stat = read_status(fc, 2); - if (stat & HDLC_INT_MASK) { - bch = Sel_BCS(fc, 2); - if (bch) - HDLC_irq(bch, stat); - else - pr_debug("%s: spurious ch2 IRQ\n", fc->name); - } -} - -static irqreturn_t -avm_fritz_interrupt(int intno, void *dev_id) -{ - struct fritzcard *fc = dev_id; - u8 val; - u8 sval; - - spin_lock(&fc->lock); - sval = inb(fc->addr + 2); - pr_debug("%s: irq stat0 %x\n", fc->name, sval); - if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { - /* shared IRQ from other HW */ - spin_unlock(&fc->lock); - return IRQ_NONE; - } - fc->irqcnt++; - - if (!(sval & AVM_STATUS0_IRQ_ISAC)) { - val = ReadISAC_V1(fc, ISAC_ISTA); - mISDNisac_irq(&fc->isac, val); - } - if (!(sval & AVM_STATUS0_IRQ_HDLC)) - HDLC_irq_main(fc); - spin_unlock(&fc->lock); - return IRQ_HANDLED; -} - -static irqreturn_t -avm_fritzv2_interrupt(int intno, void *dev_id) -{ - struct fritzcard *fc = dev_id; - u8 val; - u8 sval; - - spin_lock(&fc->lock); - sval = inb(fc->addr + 2); - pr_debug("%s: irq stat0 %x\n", fc->name, sval); - if (!(sval & AVM_STATUS0_IRQ_MASK)) { - /* shared IRQ from other HW */ - spin_unlock(&fc->lock); - return IRQ_NONE; - } - fc->irqcnt++; - - if (sval & AVM_STATUS0_IRQ_HDLC) - HDLC_irq_main(fc); - if (sval & AVM_STATUS0_IRQ_ISAC) { - val = ReadISAC_V2(fc, ISACX_ISTA); - mISDNisac_irq(&fc->isac, val); - } - if (sval & AVM_STATUS0_IRQ_TIMER) { - pr_debug("%s: timer irq\n", fc->name); - outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2); - udelay(1); - outb(fc->ctrlreg, fc->addr + 2); - } - spin_unlock(&fc->lock); - return IRQ_HANDLED; -} - -static int -avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct fritzcard *fc = bch->hw; - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(&fc->lock, flags); - ret = bchannel_senddata(bch, skb); - if (ret > 0) { /* direct TX */ - hdlc_fill_fifo(bch); - ret = 0; - } - spin_unlock_irqrestore(&fc->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - spin_lock_irqsave(&fc->lock, flags); - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) - ret = modehdlc(bch, ch->protocol); - else - ret = 0; - spin_unlock_irqrestore(&fc->lock, flags); - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - break; - case PH_DEACTIVATE_REQ: - spin_lock_irqsave(&fc->lock, flags); - mISDN_clear_bchannel(bch); - modehdlc(bch, ISDN_P_NONE); - spin_unlock_irqrestore(&fc->lock, flags); - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - ret = 0; - break; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static void -inithdlc(struct fritzcard *fc) -{ - modehdlc(&fc->bch[0], -1); - modehdlc(&fc->bch[1], -1); -} - -static void -clear_pending_hdlc_ints(struct fritzcard *fc) -{ - u32 val; - - val = read_status(fc, 1); - pr_debug("%s: HDLC 1 STA %x\n", fc->name, val); - val = read_status(fc, 2); - pr_debug("%s: HDLC 2 STA %x\n", fc->name, val); -} - -static void -reset_avm(struct fritzcard *fc) -{ - switch (fc->type) { - case AVM_FRITZ_PCI: - fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER; - break; - case AVM_FRITZ_PCIV2: - fc->ctrlreg = AVM_STATUS0_RESET; - break; - } - if (debug & DEBUG_HW) - pr_notice("%s: reset\n", fc->name); - disable_hwirq(fc); - mdelay(5); - switch (fc->type) { - case AVM_FRITZ_PCI: - fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER; - disable_hwirq(fc); - outb(AVM_STATUS1_ENA_IOM, fc->addr + 3); - break; - case AVM_FRITZ_PCIV2: - fc->ctrlreg = 0; - disable_hwirq(fc); - break; - } - mdelay(1); - if (debug & DEBUG_HW) - pr_notice("%s: S0/S1 %x/%x\n", fc->name, - inb(fc->addr + 2), inb(fc->addr + 3)); -} - -static int -init_card(struct fritzcard *fc) -{ - int ret, cnt = 3; - u_long flags; - - reset_avm(fc); /* disable IRQ */ - if (fc->type == AVM_FRITZ_PCIV2) - ret = request_irq(fc->irq, avm_fritzv2_interrupt, - IRQF_SHARED, fc->name, fc); - else - ret = request_irq(fc->irq, avm_fritz_interrupt, - IRQF_SHARED, fc->name, fc); - if (ret) { - pr_info("%s: couldn't get interrupt %d\n", - fc->name, fc->irq); - return ret; - } - while (cnt--) { - spin_lock_irqsave(&fc->lock, flags); - ret = fc->isac.init(&fc->isac); - if (ret) { - spin_unlock_irqrestore(&fc->lock, flags); - pr_info("%s: ISAC init failed with %d\n", - fc->name, ret); - break; - } - clear_pending_hdlc_ints(fc); - inithdlc(fc); - enable_hwirq(fc); - /* RESET Receiver and Transmitter */ - if (fc->type == AVM_FRITZ_PCIV2) { - WriteISAC_V2(fc, ISACX_MASK, 0); - WriteISAC_V2(fc, ISACX_CMDRD, 0x41); - } else { - WriteISAC_V1(fc, ISAC_MASK, 0); - WriteISAC_V1(fc, ISAC_CMDR, 0x41); - } - spin_unlock_irqrestore(&fc->lock, flags); - /* Timeout 10ms */ - msleep_interruptible(10); - if (debug & DEBUG_HW) - pr_notice("%s: IRQ %d count %d\n", fc->name, - fc->irq, fc->irqcnt); - if (!fc->irqcnt) { - pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", - fc->name, fc->irq, 3 - cnt); - reset_avm(fc); - } else - return 0; - } - free_irq(fc->irq, fc); - return -EIO; -} - -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - return mISDN_ctrl_bchannel(bch, cq); -} - -static int -avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct fritzcard *fc = bch->hw; - int ret = -EINVAL; - u_long flags; - - pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - cancel_work_sync(&bch->workq); - spin_lock_irqsave(&fc->lock, flags); - mISDN_clear_bchannel(bch); - modehdlc(bch, ISDN_P_NONE); - spin_unlock_irqrestore(&fc->lock, flags); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(THIS_MODULE); - ret = 0; - break; - case CONTROL_CHANNEL: - ret = channel_bctrl(bch, arg); - break; - default: - pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd); - } - return ret; -} - -static int -channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; - break; - case MISDN_CTRL_LOOP: - /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ - if (cq->channel < 0 || cq->channel > 3) { - ret = -EINVAL; - break; - } - ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel); - break; - case MISDN_CTRL_L1_TIMER3: - ret = fc->isac.ctrl(&fc->isac, HW_TIMER3_VALUE, cq->p1); - break; - default: - pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -open_bchannel(struct fritzcard *fc, struct channel_req *rq) -{ - struct bchannel *bch; - - if (rq->adr.channel == 0 || rq->adr.channel > 2) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - bch = &fc->bch[rq->adr.channel - 1]; - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; - return 0; -} - -/* - * device control function - */ -static int -avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct fritzcard *fc = dch->hw; - struct channel_req *rq; - int err = 0; - - pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - if (rq->protocol == ISDN_P_TE_S0) - err = fc->isac.open(&fc->isac, rq); - else - err = open_bchannel(fc, rq); - if (err) - break; - if (!try_module_get(THIS_MODULE)) - pr_info("%s: cannot get module\n", fc->name); - break; - case CLOSE_CHANNEL: - pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id, - __builtin_return_address(0)); - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - err = channel_ctrl(fc, arg); - break; - default: - pr_debug("%s: %s unknown command %x\n", - fc->name, __func__, cmd); - return -EINVAL; - } - return err; -} - -static int -setup_fritz(struct fritzcard *fc) -{ - u32 val, ver; - - if (!request_region(fc->addr, 32, fc->name)) { - pr_info("%s: AVM config port %x-%x already in use\n", - fc->name, fc->addr, fc->addr + 31); - return -EIO; - } - switch (fc->type) { - case AVM_FRITZ_PCI: - val = inl(fc->addr); - outl(AVM_HDLC_1, fc->addr + CHIP_INDEX); - ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24; - if (debug & DEBUG_HW) { - pr_notice("%s: PCI stat %#x\n", fc->name, val); - pr_notice("%s: PCI Class %X Rev %d\n", fc->name, - val & 0xff, (val >> 8) & 0xff); - pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); - } - ASSIGN_FUNC(V1, ISAC, fc->isac); - fc->isac.type = IPAC_TYPE_ISAC; - break; - case AVM_FRITZ_PCIV2: - val = inl(fc->addr); - ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24; - if (debug & DEBUG_HW) { - pr_notice("%s: PCI V2 stat %#x\n", fc->name, val); - pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name, - val & 0xff, (val >> 8) & 0xff); - pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); - } - ASSIGN_FUNC(V2, ISAC, fc->isac); - fc->isac.type = IPAC_TYPE_ISACX; - break; - default: - release_region(fc->addr, 32); - pr_info("%s: AVM unknown type %d\n", fc->name, fc->type); - return -ENODEV; - } - pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name, - (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" : - "AVM Fritz!CARD PCIv2", fc->irq, fc->addr); - return 0; -} - -static void -release_card(struct fritzcard *card) -{ - u_long flags; - - disable_hwirq(card); - spin_lock_irqsave(&card->lock, flags); - modehdlc(&card->bch[0], ISDN_P_NONE); - modehdlc(&card->bch[1], ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - card->isac.release(&card->isac); - free_irq(card->irq, card); - mISDN_freebchannel(&card->bch[1]); - mISDN_freebchannel(&card->bch[0]); - mISDN_unregister_device(&card->isac.dch.dev); - release_region(card->addr, 32); - pci_disable_device(card->pdev); - pci_set_drvdata(card->pdev, NULL); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - kfree(card); - AVM_cnt--; -} - -static int -setup_instance(struct fritzcard *card) -{ - int i, err; - unsigned short minsize; - u_long flags; - - snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); - write_lock_irqsave(&card_lock, flags); - list_add_tail(&card->list, &Cards); - write_unlock_irqrestore(&card_lock, flags); - - _set_debug(card); - card->isac.name = card->name; - spin_lock_init(&card->lock); - card->isac.hwlock = &card->lock; - mISDNisac_init(&card->isac, card); - - card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - card->isac.dch.dev.D.ctrl = avm_dctrl; - for (i = 0; i < 2; i++) { - card->bch[i].nr = i + 1; - set_channelmap(i + 1, card->isac.dch.dev.channelmap); - if (AVM_FRITZ_PCIV2 == card->type) - minsize = HDLC_FIFO_SIZE_V2; - else - minsize = HDLC_FIFO_SIZE_V1; - mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, minsize); - card->bch[i].hw = card; - card->bch[i].ch.send = avm_l2l1B; - card->bch[i].ch.ctrl = avm_bctrl; - card->bch[i].ch.nr = i + 1; - list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels); - } - err = setup_fritz(card); - if (err) - goto error; - err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, - card->name); - if (err) - goto error_reg; - err = init_card(card); - if (!err) { - AVM_cnt++; - pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt); - return 0; - } - mISDN_unregister_device(&card->isac.dch.dev); -error_reg: - release_region(card->addr, 32); -error: - card->isac.release(&card->isac); - mISDN_freebchannel(&card->bch[1]); - mISDN_freebchannel(&card->bch[0]); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - kfree(card); - return err; -} - -static int -fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - struct fritzcard *card; - - card = kzalloc_obj(struct fritzcard); - if (!card) { - pr_info("No kmem for fritzcard\n"); - return err; - } - if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) - card->type = AVM_FRITZ_PCIV2; - else - card->type = AVM_FRITZ_PCI; - card->pdev = pdev; - err = pci_enable_device(pdev); - if (err) { - kfree(card); - return err; - } - - pr_notice("mISDN: found adapter %s at %s\n", - (char *) ent->driver_data, pci_name(pdev)); - - card->addr = pci_resource_start(pdev, 1); - card->irq = pdev->irq; - pci_set_drvdata(pdev, card); - err = setup_instance(card); - if (err) - pci_set_drvdata(pdev, NULL); - return err; -} - -static void -fritz_remove_pci(struct pci_dev *pdev) -{ - struct fritzcard *card = pci_get_drvdata(pdev); - - if (card) - release_card(card); - else - if (debug) - pr_info("%s: drvdata already removed\n", __func__); -} - -static const struct pci_device_id fcpci_ids[] = { - { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, (unsigned long) "Fritz!Card PCI"}, - { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, (unsigned long) "Fritz!Card PCI v2" }, - { } -}; -MODULE_DEVICE_TABLE(pci, fcpci_ids); - -static struct pci_driver fcpci_driver = { - .name = "fcpci", - .probe = fritzpci_probe, - .remove = fritz_remove_pci, - .id_table = fcpci_ids, -}; - -static int __init AVM_init(void) -{ - int err; - - pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV); - err = pci_register_driver(&fcpci_driver); - return err; -} - -static void __exit AVM_cleanup(void) -{ - pci_unregister_driver(&fcpci_driver); -} - -module_init(AVM_init); -module_exit(AVM_cleanup); diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h deleted file mode 100644 index 5acf826d913c..000000000000 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ /dev/null @@ -1,1236 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * see notice in hfc_multi.c - */ - -#define DEBUG_HFCMULTI_FIFO 0x00010000 -#define DEBUG_HFCMULTI_CRC 0x00020000 -#define DEBUG_HFCMULTI_INIT 0x00040000 -#define DEBUG_HFCMULTI_PLXSD 0x00080000 -#define DEBUG_HFCMULTI_MODE 0x00100000 -#define DEBUG_HFCMULTI_MSG 0x00200000 -#define DEBUG_HFCMULTI_STATE 0x00400000 -#define DEBUG_HFCMULTI_FILL 0x00800000 -#define DEBUG_HFCMULTI_SYNC 0x01000000 -#define DEBUG_HFCMULTI_DTMF 0x02000000 -#define DEBUG_HFCMULTI_LOCK 0x80000000 - -#define PCI_ENA_REGIO 0x01 -#define PCI_ENA_MEMIO 0x02 - -#define XHFC_IRQ 4 /* SIU_IRQ2 */ -#define XHFC_MEMBASE 0xFE000000 -#define XHFC_MEMSIZE 0x00001000 -#define XHFC_OFFSET 0x00001000 -#define PA_XHFC_A0 0x0020 /* PA10 */ -#define PB_XHFC_IRQ1 0x00000100 /* PB23 */ -#define PB_XHFC_IRQ2 0x00000200 /* PB22 */ -#define PB_XHFC_IRQ3 0x00000400 /* PB21 */ -#define PB_XHFC_IRQ4 0x00000800 /* PB20 */ - -/* - * NOTE: some registers are assigned multiple times due to different modes - * also registers are assigned differen for HFC-4s/8s and HFC-E1 - */ - -/* - #define MAX_FRAME_SIZE 2048 -*/ - -struct hfc_chan { - struct dchannel *dch; /* link if channel is a D-channel */ - struct bchannel *bch; /* link if channel is a B-channel */ - int port; /* the interface port this */ - /* channel is associated with */ - int nt_timer; /* -1 if off, 0 if elapsed, >0 if running */ - int los, ais, slip_tx, slip_rx, rdi; /* current alarms */ - int jitter; - u_long cfg; /* port configuration */ - int sync; /* sync state (used by E1) */ - u_int protocol; /* current protocol */ - int slot_tx; /* current pcm slot */ - int bank_tx; /* current pcm bank */ - int slot_rx; - int bank_rx; - int conf; /* conference setting of TX slot */ - int txpending; /* if there is currently data in */ - /* the FIFO 0=no, 1=yes, 2=splloop */ - int Zfill; /* rx-fifo level on last hfcmulti_tx */ - int rx_off; /* set to turn fifo receive off */ - int coeff_count; /* curren coeff block */ - s32 *coeff; /* memory pointer to 8 coeff blocks */ -}; - - -struct hfcm_hw { - u_char r_ctrl; - u_char r_irq_ctrl; - u_char r_cirm; - u_char r_ram_sz; - u_char r_pcm_md0; - u_char r_irqmsk_misc; - u_char r_dtmf; - u_char r_st_sync; - u_char r_sci_msk; - u_char r_tx0, r_tx1; - u_char a_st_ctrl0[8]; - u_char r_bert_wd_md; - timer_t timer; -}; - - -/* for each stack these flags are used (cfg) */ -#define HFC_CFG_NONCAP_TX 1 /* S/T TX interface has less capacity */ -#define HFC_CFG_DIS_ECHANNEL 2 /* disable E-channel processing */ -#define HFC_CFG_REG_ECHANNEL 3 /* register E-channel */ -#define HFC_CFG_OPTICAL 4 /* the E1 interface is optical */ -#define HFC_CFG_REPORT_LOS 5 /* the card should report loss of signal */ -#define HFC_CFG_REPORT_AIS 6 /* the card should report alarm ind. sign. */ -#define HFC_CFG_REPORT_SLIP 7 /* the card should report bit slips */ -#define HFC_CFG_REPORT_RDI 8 /* the card should report remote alarm */ -#define HFC_CFG_DTMF 9 /* enable DTMF-detection */ -#define HFC_CFG_CRC4 10 /* disable CRC-4 Multiframe mode, */ -/* use double frame instead. */ - -#define HFC_TYPE_E1 1 /* controller is HFC-E1 */ -#define HFC_TYPE_4S 4 /* controller is HFC-4S */ -#define HFC_TYPE_8S 8 /* controller is HFC-8S */ -#define HFC_TYPE_XHFC 5 /* controller is XHFC */ - -#define HFC_CHIP_EXRAM_128 0 /* external ram 128k */ -#define HFC_CHIP_EXRAM_512 1 /* external ram 256k */ -#define HFC_CHIP_REVISION0 2 /* old fifo handling */ -#define HFC_CHIP_PCM_SLAVE 3 /* PCM is slave */ -#define HFC_CHIP_PCM_MASTER 4 /* PCM is master */ -#define HFC_CHIP_RX_SYNC 5 /* disable pll sync for pcm */ -#define HFC_CHIP_DTMF 6 /* DTMF decoding is enabled */ -#define HFC_CHIP_CONF 7 /* conference handling is enabled */ -#define HFC_CHIP_ULAW 8 /* ULAW mode */ -#define HFC_CHIP_CLOCK2 9 /* double clock mode */ -#define HFC_CHIP_E1CLOCK_GET 10 /* always get clock from E1 interface */ -#define HFC_CHIP_E1CLOCK_PUT 11 /* always put clock from E1 interface */ -#define HFC_CHIP_WATCHDOG 12 /* whether we should send signals */ -/* to the watchdog */ -#define HFC_CHIP_B410P 13 /* whether we have a b410p with echocan in */ -/* hw */ -#define HFC_CHIP_PLXSD 14 /* whether we have a Speech-Design PLX */ -#define HFC_CHIP_EMBSD 15 /* whether we have a SD Embedded board */ - -#define HFC_IO_MODE_PCIMEM 0x00 /* normal memory mapped IO */ -#define HFC_IO_MODE_REGIO 0x01 /* PCI io access */ -#define HFC_IO_MODE_PLXSD 0x02 /* access HFC via PLX9030 */ -#define HFC_IO_MODE_EMBSD 0x03 /* direct access */ - -/* table entry in the PCI devices list */ -struct hm_map { - char *vendor_name; - char *card_name; - int type; - int ports; - int clock2; - int leds; - int opticalsupport; - int dip_type; - int io_mode; - int irq; -}; - -struct hfc_multi { - struct list_head list; - struct hm_map *mtyp; - int id; - int pcm; /* id of pcm bus */ - int ctype; /* controller type */ - int ports; - - u_int irq; /* irq used by card */ - u_int irqcnt; - struct pci_dev *pci_dev; - int io_mode; /* selects mode */ -#ifdef HFC_REGISTER_DEBUG - void (*HFC_outb)(struct hfc_multi *hc, u_char reg, - u_char val, const char *function, int line); - void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg, - u_char val, const char *function, int line); - u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg, - const char *function, int line); - u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg, - const char *function, int line); - u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg, - const char *function, int line); - u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg, - const char *function, int line); - void (*HFC_wait)(struct hfc_multi *hc, - const char *function, int line); - void (*HFC_wait_nodebug)(struct hfc_multi *hc, - const char *function, int line); -#else - void (*HFC_outb)(struct hfc_multi *hc, u_char reg, - u_char val); - void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg, - u_char val); - u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg); - u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg); - u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg); - u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg); - void (*HFC_wait)(struct hfc_multi *hc); - void (*HFC_wait_nodebug)(struct hfc_multi *hc); -#endif - void (*read_fifo)(struct hfc_multi *hc, u_char *data, - int len); - void (*write_fifo)(struct hfc_multi *hc, u_char *data, - int len); - u_long pci_origmembase, plx_origmembase; - void __iomem *pci_membase; /* PCI memory */ - void __iomem *plx_membase; /* PLX memory */ - u_long xhfc_origmembase; - u_char *xhfc_membase; - u_long *xhfc_memaddr, *xhfc_memdata; -#ifdef CONFIG_MISDN_HFCMULTI_8xx - struct immap *immap; -#endif - u_long pb_irqmsk; /* Portbit mask to check the IRQ line */ - u_long pci_iobase; /* PCI IO */ - struct hfcm_hw hw; /* remember data of write-only-registers */ - - u_long chip; /* chip configuration */ - int masterclk; /* port that provides master clock -1=off */ - unsigned char silence;/* silence byte */ - unsigned char silence_data[128];/* silence block */ - int dtmf; /* flag that dtmf is currently in process */ - int Flen; /* F-buffer size */ - int Zlen; /* Z-buffer size (must be int for calculation)*/ - int max_trans; /* maximum transparent fifo fill */ - int Zmin; /* Z-buffer offset */ - int DTMFbase; /* base address of DTMF coefficients */ - - u_int slots; /* number of PCM slots */ - u_int leds; /* type of leds */ - u_long ledstate; /* save last state of leds */ - int opticalsupport; /* has the e1 board */ - /* an optical Interface */ - - u_int bmask[32]; /* bitmask of bchannels for port */ - u_char dnum[32]; /* array of used dchannel numbers for port */ - u_char created[32]; /* what port is created */ - u_int activity_tx; /* if there is data TX / RX */ - u_int activity_rx; /* bitmask according to port number */ - /* (will be cleared after */ - /* showing led-states) */ - u_int flash[8]; /* counter for flashing 8 leds on activity */ - - u_long wdcount; /* every 500 ms we need to */ - /* send the watchdog a signal */ - u_char wdbyte; /* watchdog toggle byte */ - int e1_state; /* keep track of last state */ - int e1_getclock; /* if sync is retrieved from interface */ - int syncronized; /* keep track of existing sync interface */ - int e1_resync; /* resync jobs */ - - spinlock_t lock; /* the lock */ - - struct mISDNclock *iclock; /* isdn clock support */ - int iclock_on; - - /* - * the channel index is counted from 0, regardless where the channel - * is located on the hfc-channel. - * the bch->channel is equvalent to the hfc-channel - */ - struct hfc_chan chan[32]; - signed char slot_owner[256]; /* owner channel of slot */ -}; - -/* PLX GPIOs */ -#define PLX_GPIO4_DIR_BIT 13 -#define PLX_GPIO4_BIT 14 -#define PLX_GPIO5_DIR_BIT 16 -#define PLX_GPIO5_BIT 17 -#define PLX_GPIO6_DIR_BIT 19 -#define PLX_GPIO6_BIT 20 -#define PLX_GPIO7_DIR_BIT 22 -#define PLX_GPIO7_BIT 23 -#define PLX_GPIO8_DIR_BIT 25 -#define PLX_GPIO8_BIT 26 - -#define PLX_GPIO4 (1 << PLX_GPIO4_BIT) -#define PLX_GPIO5 (1 << PLX_GPIO5_BIT) -#define PLX_GPIO6 (1 << PLX_GPIO6_BIT) -#define PLX_GPIO7 (1 << PLX_GPIO7_BIT) -#define PLX_GPIO8 (1 << PLX_GPIO8_BIT) - -#define PLX_GPIO4_DIR (1 << PLX_GPIO4_DIR_BIT) -#define PLX_GPIO5_DIR (1 << PLX_GPIO5_DIR_BIT) -#define PLX_GPIO6_DIR (1 << PLX_GPIO6_DIR_BIT) -#define PLX_GPIO7_DIR (1 << PLX_GPIO7_DIR_BIT) -#define PLX_GPIO8_DIR (1 << PLX_GPIO8_DIR_BIT) - -#define PLX_TERM_ON PLX_GPIO7 -#define PLX_SLAVE_EN_N PLX_GPIO5 -#define PLX_MASTER_EN PLX_GPIO6 -#define PLX_SYNC_O_EN PLX_GPIO4 -#define PLX_DSP_RES_N PLX_GPIO8 -/* GPIO4..8 Enable & Set to OUT, SLAVE_EN_N = 1 */ -#define PLX_GPIOC_INIT (PLX_GPIO4_DIR | PLX_GPIO5_DIR | PLX_GPIO6_DIR \ - | PLX_GPIO7_DIR | PLX_GPIO8_DIR | PLX_SLAVE_EN_N) - -/* PLX Interrupt Control/STATUS */ -#define PLX_INTCSR_LINTI1_ENABLE 0x01 -#define PLX_INTCSR_LINTI1_STATUS 0x04 -#define PLX_INTCSR_LINTI2_ENABLE 0x08 -#define PLX_INTCSR_LINTI2_STATUS 0x20 -#define PLX_INTCSR_PCIINT_ENABLE 0x40 - -/* PLX Registers */ -#define PLX_INTCSR 0x4c -#define PLX_CNTRL 0x50 -#define PLX_GPIOC 0x54 - - -/* - * REGISTER SETTING FOR HFC-4S/8S AND HFC-E1 - */ - -/* write only registers */ -#define R_CIRM 0x00 -#define R_CTRL 0x01 -#define R_BRG_PCM_CFG 0x02 -#define R_RAM_ADDR0 0x08 -#define R_RAM_ADDR1 0x09 -#define R_RAM_ADDR2 0x0A -#define R_FIRST_FIFO 0x0B -#define R_RAM_SZ 0x0C -#define R_FIFO_MD 0x0D -#define R_INC_RES_FIFO 0x0E -#define R_FSM_IDX 0x0F -#define R_FIFO 0x0F -#define R_SLOT 0x10 -#define R_IRQMSK_MISC 0x11 -#define R_SCI_MSK 0x12 -#define R_IRQ_CTRL 0x13 -#define R_PCM_MD0 0x14 -#define R_PCM_MD1 0x15 -#define R_PCM_MD2 0x15 -#define R_SH0H 0x15 -#define R_SH1H 0x15 -#define R_SH0L 0x15 -#define R_SH1L 0x15 -#define R_SL_SEL0 0x15 -#define R_SL_SEL1 0x15 -#define R_SL_SEL2 0x15 -#define R_SL_SEL3 0x15 -#define R_SL_SEL4 0x15 -#define R_SL_SEL5 0x15 -#define R_SL_SEL6 0x15 -#define R_SL_SEL7 0x15 -#define R_ST_SEL 0x16 -#define R_ST_SYNC 0x17 -#define R_CONF_EN 0x18 -#define R_TI_WD 0x1A -#define R_BERT_WD_MD 0x1B -#define R_DTMF 0x1C -#define R_DTMF_N 0x1D -#define R_E1_WR_STA 0x20 -#define R_E1_RD_STA 0x20 -#define R_LOS0 0x22 -#define R_LOS1 0x23 -#define R_RX0 0x24 -#define R_RX_FR0 0x25 -#define R_RX_FR1 0x26 -#define R_TX0 0x28 -#define R_TX1 0x29 -#define R_TX_FR0 0x2C - -#define R_TX_FR1 0x2D -#define R_TX_FR2 0x2E -#define R_JATT_ATT 0x2F /* undocumented */ -#define A_ST_RD_STATE 0x30 -#define A_ST_WR_STATE 0x30 -#define R_RX_OFF 0x30 -#define A_ST_CTRL0 0x31 -#define R_SYNC_OUT 0x31 -#define A_ST_CTRL1 0x32 -#define A_ST_CTRL2 0x33 -#define A_ST_SQ_WR 0x34 -#define R_TX_OFF 0x34 -#define R_SYNC_CTRL 0x35 -#define A_ST_CLK_DLY 0x37 -#define R_PWM0 0x38 -#define R_PWM1 0x39 -#define A_ST_B1_TX 0x3C -#define A_ST_B2_TX 0x3D -#define A_ST_D_TX 0x3E -#define R_GPIO_OUT0 0x40 -#define R_GPIO_OUT1 0x41 -#define R_GPIO_EN0 0x42 -#define R_GPIO_EN1 0x43 -#define R_GPIO_SEL 0x44 -#define R_BRG_CTRL 0x45 -#define R_PWM_MD 0x46 -#define R_BRG_MD 0x47 -#define R_BRG_TIM0 0x48 -#define R_BRG_TIM1 0x49 -#define R_BRG_TIM2 0x4A -#define R_BRG_TIM3 0x4B -#define R_BRG_TIM_SEL01 0x4C -#define R_BRG_TIM_SEL23 0x4D -#define R_BRG_TIM_SEL45 0x4E -#define R_BRG_TIM_SEL67 0x4F -#define A_SL_CFG 0xD0 -#define A_CONF 0xD1 -#define A_CH_MSK 0xF4 -#define A_CON_HDLC 0xFA -#define A_SUBCH_CFG 0xFB -#define A_CHANNEL 0xFC -#define A_FIFO_SEQ 0xFD -#define A_IRQ_MSK 0xFF - -/* read only registers */ -#define A_Z12 0x04 -#define A_Z1L 0x04 -#define A_Z1 0x04 -#define A_Z1H 0x05 -#define A_Z2L 0x06 -#define A_Z2 0x06 -#define A_Z2H 0x07 -#define A_F1 0x0C -#define A_F12 0x0C -#define A_F2 0x0D -#define R_IRQ_OVIEW 0x10 -#define R_IRQ_MISC 0x11 -#define R_IRQ_STATECH 0x12 -#define R_CONF_OFLOW 0x14 -#define R_RAM_USE 0x15 -#define R_CHIP_ID 0x16 -#define R_BERT_STA 0x17 -#define R_F0_CNTL 0x18 -#define R_F0_CNTH 0x19 -#define R_BERT_EC 0x1A -#define R_BERT_ECL 0x1A -#define R_BERT_ECH 0x1B -#define R_STATUS 0x1C -#define R_CHIP_RV 0x1F -#define R_STATE 0x20 -#define R_SYNC_STA 0x24 -#define R_RX_SL0_0 0x25 -#define R_RX_SL0_1 0x26 -#define R_RX_SL0_2 0x27 -#define R_JATT_DIR 0x2b /* undocumented */ -#define R_SLIP 0x2c -#define A_ST_RD_STA 0x30 -#define R_FAS_EC 0x30 -#define R_FAS_ECL 0x30 -#define R_FAS_ECH 0x31 -#define R_VIO_EC 0x32 -#define R_VIO_ECL 0x32 -#define R_VIO_ECH 0x33 -#define A_ST_SQ_RD 0x34 -#define R_CRC_EC 0x34 -#define R_CRC_ECL 0x34 -#define R_CRC_ECH 0x35 -#define R_E_EC 0x36 -#define R_E_ECL 0x36 -#define R_E_ECH 0x37 -#define R_SA6_SA13_EC 0x38 -#define R_SA6_SA13_ECL 0x38 -#define R_SA6_SA13_ECH 0x39 -#define R_SA6_SA23_EC 0x3A -#define R_SA6_SA23_ECL 0x3A -#define R_SA6_SA23_ECH 0x3B -#define A_ST_B1_RX 0x3C -#define A_ST_B2_RX 0x3D -#define A_ST_D_RX 0x3E -#define A_ST_E_RX 0x3F -#define R_GPIO_IN0 0x40 -#define R_GPIO_IN1 0x41 -#define R_GPI_IN0 0x44 -#define R_GPI_IN1 0x45 -#define R_GPI_IN2 0x46 -#define R_GPI_IN3 0x47 -#define R_INT_DATA 0x88 -#define R_IRQ_FIFO_BL0 0xC8 -#define R_IRQ_FIFO_BL1 0xC9 -#define R_IRQ_FIFO_BL2 0xCA -#define R_IRQ_FIFO_BL3 0xCB -#define R_IRQ_FIFO_BL4 0xCC -#define R_IRQ_FIFO_BL5 0xCD -#define R_IRQ_FIFO_BL6 0xCE -#define R_IRQ_FIFO_BL7 0xCF - -/* read and write registers */ -#define A_FIFO_DATA0 0x80 -#define A_FIFO_DATA1 0x80 -#define A_FIFO_DATA2 0x80 -#define A_FIFO_DATA0_NOINC 0x84 -#define A_FIFO_DATA1_NOINC 0x84 -#define A_FIFO_DATA2_NOINC 0x84 -#define R_RAM_DATA 0xC0 - - -/* - * BIT SETTING FOR HFC-4S/8S AND HFC-E1 - */ - -/* chapter 2: universal bus interface */ -/* R_CIRM */ -#define V_IRQ_SEL 0x01 -#define V_SRES 0x08 -#define V_HFCRES 0x10 -#define V_PCMRES 0x20 -#define V_STRES 0x40 -#define V_ETRES 0x40 -#define V_RLD_EPR 0x80 -/* R_CTRL */ -#define V_FIFO_LPRIO 0x02 -#define V_SLOW_RD 0x04 -#define V_EXT_RAM 0x08 -#define V_CLK_OFF 0x20 -#define V_ST_CLK 0x40 -/* R_RAM_ADDR0 */ -#define V_RAM_ADDR2 0x01 -#define V_ADDR_RES 0x40 -#define V_ADDR_INC 0x80 -/* R_RAM_SZ */ -#define V_RAM_SZ 0x01 -#define V_PWM0_16KHZ 0x10 -#define V_PWM1_16KHZ 0x20 -#define V_FZ_MD 0x80 -/* R_CHIP_ID */ -#define V_PNP_IRQ 0x01 -#define V_CHIP_ID 0x10 - -/* chapter 3: data flow */ -/* R_FIRST_FIFO */ -#define V_FIRST_FIRO_DIR 0x01 -#define V_FIRST_FIFO_NUM 0x02 -/* R_FIFO_MD */ -#define V_FIFO_MD 0x01 -#define V_CSM_MD 0x04 -#define V_FSM_MD 0x08 -#define V_FIFO_SZ 0x10 -/* R_FIFO */ -#define V_FIFO_DIR 0x01 -#define V_FIFO_NUM 0x02 -#define V_REV 0x80 -/* R_SLOT */ -#define V_SL_DIR 0x01 -#define V_SL_NUM 0x02 -/* A_SL_CFG */ -#define V_CH_DIR 0x01 -#define V_CH_SEL 0x02 -#define V_ROUTING 0x40 -/* A_CON_HDLC */ -#define V_IFF 0x01 -#define V_HDLC_TRP 0x02 -#define V_TRP_IRQ 0x04 -#define V_DATA_FLOW 0x20 -/* A_SUBCH_CFG */ -#define V_BIT_CNT 0x01 -#define V_START_BIT 0x08 -#define V_LOOP_FIFO 0x40 -#define V_INV_DATA 0x80 -/* A_CHANNEL */ -#define V_CH_DIR0 0x01 -#define V_CH_NUM0 0x02 -/* A_FIFO_SEQ */ -#define V_NEXT_FIFO_DIR 0x01 -#define V_NEXT_FIFO_NUM 0x02 -#define V_SEQ_END 0x40 - -/* chapter 4: FIFO handling and HDLC controller */ -/* R_INC_RES_FIFO */ -#define V_INC_F 0x01 -#define V_RES_F 0x02 -#define V_RES_LOST 0x04 - -/* chapter 5: S/T interface */ -/* R_SCI_MSK */ -#define V_SCI_MSK_ST0 0x01 -#define V_SCI_MSK_ST1 0x02 -#define V_SCI_MSK_ST2 0x04 -#define V_SCI_MSK_ST3 0x08 -#define V_SCI_MSK_ST4 0x10 -#define V_SCI_MSK_ST5 0x20 -#define V_SCI_MSK_ST6 0x40 -#define V_SCI_MSK_ST7 0x80 -/* R_ST_SEL */ -#define V_ST_SEL 0x01 -#define V_MULT_ST 0x08 -/* R_ST_SYNC */ -#define V_SYNC_SEL 0x01 -#define V_AUTO_SYNC 0x08 -/* A_ST_WR_STA */ -#define V_ST_SET_STA 0x01 -#define V_ST_LD_STA 0x10 -#define V_ST_ACT 0x20 -#define V_SET_G2_G3 0x80 -/* A_ST_CTRL0 */ -#define V_B1_EN 0x01 -#define V_B2_EN 0x02 -#define V_ST_MD 0x04 -#define V_D_PRIO 0x08 -#define V_SQ_EN 0x10 -#define V_96KHZ 0x20 -#define V_TX_LI 0x40 -#define V_ST_STOP 0x80 -/* A_ST_CTRL1 */ -#define V_G2_G3_EN 0x01 -#define V_D_HI 0x04 -#define V_E_IGNO 0x08 -#define V_E_LO 0x10 -#define V_B12_SWAP 0x80 -/* A_ST_CTRL2 */ -#define V_B1_RX_EN 0x01 -#define V_B2_RX_EN 0x02 -#define V_ST_TRIS 0x40 -/* A_ST_CLK_DLY */ -#define V_ST_CK_DLY 0x01 -#define V_ST_SMPL 0x10 -/* A_ST_D_TX */ -#define V_ST_D_TX 0x40 -/* R_IRQ_STATECH */ -#define V_SCI_ST0 0x01 -#define V_SCI_ST1 0x02 -#define V_SCI_ST2 0x04 -#define V_SCI_ST3 0x08 -#define V_SCI_ST4 0x10 -#define V_SCI_ST5 0x20 -#define V_SCI_ST6 0x40 -#define V_SCI_ST7 0x80 -/* A_ST_RD_STA */ -#define V_ST_STA 0x01 -#define V_FR_SYNC_ST 0x10 -#define V_TI2_EXP 0x20 -#define V_INFO0 0x40 -#define V_G2_G3 0x80 -/* A_ST_SQ_RD */ -#define V_ST_SQ 0x01 -#define V_MF_RX_RDY 0x10 -#define V_MF_TX_RDY 0x80 -/* A_ST_D_RX */ -#define V_ST_D_RX 0x40 -/* A_ST_E_RX */ -#define V_ST_E_RX 0x40 - -/* chapter 5: E1 interface */ -/* R_E1_WR_STA */ -/* R_E1_RD_STA */ -#define V_E1_SET_STA 0x01 -#define V_E1_LD_STA 0x10 -/* R_RX0 */ -#define V_RX_CODE 0x01 -#define V_RX_FBAUD 0x04 -#define V_RX_CMI 0x08 -#define V_RX_INV_CMI 0x10 -#define V_RX_INV_CLK 0x20 -#define V_RX_INV_DATA 0x40 -#define V_AIS_ITU 0x80 -/* R_RX_FR0 */ -#define V_NO_INSYNC 0x01 -#define V_AUTO_RESYNC 0x02 -#define V_AUTO_RECO 0x04 -#define V_SWORD_COND 0x08 -#define V_SYNC_LOSS 0x10 -#define V_XCRC_SYNC 0x20 -#define V_MF_RESYNC 0x40 -#define V_RESYNC 0x80 -/* R_RX_FR1 */ -#define V_RX_MF 0x01 -#define V_RX_MF_SYNC 0x02 -#define V_RX_SL0_RAM 0x04 -#define V_ERR_SIM 0x20 -#define V_RES_NMF 0x40 -/* R_TX0 */ -#define V_TX_CODE 0x01 -#define V_TX_FBAUD 0x04 -#define V_TX_CMI_CODE 0x08 -#define V_TX_INV_CMI_CODE 0x10 -#define V_TX_INV_CLK 0x20 -#define V_TX_INV_DATA 0x40 -#define V_OUT_EN 0x80 -/* R_TX1 */ -#define V_INV_CLK 0x01 -#define V_EXCHG_DATA_LI 0x02 -#define V_AIS_OUT 0x04 -#define V_ATX 0x20 -#define V_NTRI 0x40 -#define V_AUTO_ERR_RES 0x80 -/* R_TX_FR0 */ -#define V_TRP_FAS 0x01 -#define V_TRP_NFAS 0x02 -#define V_TRP_RAL 0x04 -#define V_TRP_SA 0x08 -/* R_TX_FR1 */ -#define V_TX_FAS 0x01 -#define V_TX_NFAS 0x02 -#define V_TX_RAL 0x04 -#define V_TX_SA 0x08 -/* R_TX_FR2 */ -#define V_TX_MF 0x01 -#define V_TRP_SL0 0x02 -#define V_TX_SL0_RAM 0x04 -#define V_TX_E 0x10 -#define V_NEG_E 0x20 -#define V_XS12_ON 0x40 -#define V_XS15_ON 0x80 -/* R_RX_OFF */ -#define V_RX_SZ 0x01 -#define V_RX_INIT 0x04 -/* R_SYNC_OUT */ -#define V_SYNC_E1_RX 0x01 -#define V_IPATS0 0x20 -#define V_IPATS1 0x40 -#define V_IPATS2 0x80 -/* R_TX_OFF */ -#define V_TX_SZ 0x01 -#define V_TX_INIT 0x04 -/* R_SYNC_CTRL */ -#define V_EXT_CLK_SYNC 0x01 -#define V_SYNC_OFFS 0x02 -#define V_PCM_SYNC 0x04 -#define V_NEG_CLK 0x08 -#define V_HCLK 0x10 -/* - #define V_JATT_AUTO_DEL 0x20 - #define V_JATT_AUTO 0x40 -*/ -#define V_JATT_OFF 0x80 -/* R_STATE */ -#define V_E1_STA 0x01 -#define V_ALT_FR_RX 0x40 -#define V_ALT_FR_TX 0x80 -/* R_SYNC_STA */ -#define V_RX_STA 0x01 -#define V_FR_SYNC_E1 0x04 -#define V_SIG_LOS 0x08 -#define V_MFA_STA 0x10 -#define V_AIS 0x40 -#define V_NO_MF_SYNC 0x80 -/* R_RX_SL0_0 */ -#define V_SI_FAS 0x01 -#define V_SI_NFAS 0x02 -#define V_A 0x04 -#define V_CRC_OK 0x08 -#define V_TX_E1 0x10 -#define V_TX_E2 0x20 -#define V_RX_E1 0x40 -#define V_RX_E2 0x80 -/* R_SLIP */ -#define V_SLIP_RX 0x01 -#define V_FOSLIP_RX 0x08 -#define V_SLIP_TX 0x10 -#define V_FOSLIP_TX 0x80 - -/* chapter 6: PCM interface */ -/* R_PCM_MD0 */ -#define V_PCM_MD 0x01 -#define V_C4_POL 0x02 -#define V_F0_NEG 0x04 -#define V_F0_LEN 0x08 -#define V_PCM_ADDR 0x10 -/* R_SL_SEL0 */ -#define V_SL_SEL0 0x01 -#define V_SH_SEL0 0x80 -/* R_SL_SEL1 */ -#define V_SL_SEL1 0x01 -#define V_SH_SEL1 0x80 -/* R_SL_SEL2 */ -#define V_SL_SEL2 0x01 -#define V_SH_SEL2 0x80 -/* R_SL_SEL3 */ -#define V_SL_SEL3 0x01 -#define V_SH_SEL3 0x80 -/* R_SL_SEL4 */ -#define V_SL_SEL4 0x01 -#define V_SH_SEL4 0x80 -/* R_SL_SEL5 */ -#define V_SL_SEL5 0x01 -#define V_SH_SEL5 0x80 -/* R_SL_SEL6 */ -#define V_SL_SEL6 0x01 -#define V_SH_SEL6 0x80 -/* R_SL_SEL7 */ -#define V_SL_SEL7 0x01 -#define V_SH_SEL7 0x80 -/* R_PCM_MD1 */ -#define V_ODEC_CON 0x01 -#define V_PLL_ADJ 0x04 -#define V_PCM_DR 0x10 -#define V_PCM_LOOP 0x40 -/* R_PCM_MD2 */ -#define V_SYNC_PLL 0x02 -#define V_SYNC_SRC 0x04 -#define V_SYNC_OUT 0x08 -#define V_ICR_FR_TIME 0x40 -#define V_EN_PLL 0x80 - -/* chapter 7: pulse width modulation */ -/* R_PWM_MD */ -#define V_EXT_IRQ_EN 0x08 -#define V_PWM0_MD 0x10 -#define V_PWM1_MD 0x40 - -/* chapter 8: multiparty audio conferences */ -/* R_CONF_EN */ -#define V_CONF_EN 0x01 -#define V_ULAW 0x80 -/* A_CONF */ -#define V_CONF_NUM 0x01 -#define V_NOISE_SUPPR 0x08 -#define V_ATT_LEV 0x20 -#define V_CONF_SL 0x80 -/* R_CONF_OFLOW */ -#define V_CONF_OFLOW0 0x01 -#define V_CONF_OFLOW1 0x02 -#define V_CONF_OFLOW2 0x04 -#define V_CONF_OFLOW3 0x08 -#define V_CONF_OFLOW4 0x10 -#define V_CONF_OFLOW5 0x20 -#define V_CONF_OFLOW6 0x40 -#define V_CONF_OFLOW7 0x80 - -/* chapter 9: DTMF contoller */ -/* R_DTMF0 */ -#define V_DTMF_EN 0x01 -#define V_HARM_SEL 0x02 -#define V_DTMF_RX_CH 0x04 -#define V_DTMF_STOP 0x08 -#define V_CHBL_SEL 0x10 -#define V_RST_DTMF 0x40 -#define V_ULAW_SEL 0x80 - -/* chapter 10: BERT */ -/* R_BERT_WD_MD */ -#define V_PAT_SEQ 0x01 -#define V_BERT_ERR 0x08 -#define V_AUTO_WD_RES 0x20 -#define V_WD_RES 0x80 -/* R_BERT_STA */ -#define V_BERT_SYNC_SRC 0x01 -#define V_BERT_SYNC 0x10 -#define V_BERT_INV_DATA 0x20 - -/* chapter 11: auxiliary interface */ -/* R_BRG_PCM_CFG */ -#define V_BRG_EN 0x01 -#define V_BRG_MD 0x02 -#define V_PCM_CLK 0x20 -#define V_ADDR_WRDLY 0x40 -/* R_BRG_CTRL */ -#define V_BRG_CS 0x01 -#define V_BRG_ADDR 0x08 -#define V_BRG_CS_SRC 0x80 -/* R_BRG_MD */ -#define V_BRG_MD0 0x01 -#define V_BRG_MD1 0x02 -#define V_BRG_MD2 0x04 -#define V_BRG_MD3 0x08 -#define V_BRG_MD4 0x10 -#define V_BRG_MD5 0x20 -#define V_BRG_MD6 0x40 -#define V_BRG_MD7 0x80 -/* R_BRG_TIM0 */ -#define V_BRG_TIM0_IDLE 0x01 -#define V_BRG_TIM0_CLK 0x10 -/* R_BRG_TIM1 */ -#define V_BRG_TIM1_IDLE 0x01 -#define V_BRG_TIM1_CLK 0x10 -/* R_BRG_TIM2 */ -#define V_BRG_TIM2_IDLE 0x01 -#define V_BRG_TIM2_CLK 0x10 -/* R_BRG_TIM3 */ -#define V_BRG_TIM3_IDLE 0x01 -#define V_BRG_TIM3_CLK 0x10 -/* R_BRG_TIM_SEL01 */ -#define V_BRG_WR_SEL0 0x01 -#define V_BRG_RD_SEL0 0x04 -#define V_BRG_WR_SEL1 0x10 -#define V_BRG_RD_SEL1 0x40 -/* R_BRG_TIM_SEL23 */ -#define V_BRG_WR_SEL2 0x01 -#define V_BRG_RD_SEL2 0x04 -#define V_BRG_WR_SEL3 0x10 -#define V_BRG_RD_SEL3 0x40 -/* R_BRG_TIM_SEL45 */ -#define V_BRG_WR_SEL4 0x01 -#define V_BRG_RD_SEL4 0x04 -#define V_BRG_WR_SEL5 0x10 -#define V_BRG_RD_SEL5 0x40 -/* R_BRG_TIM_SEL67 */ -#define V_BRG_WR_SEL6 0x01 -#define V_BRG_RD_SEL6 0x04 -#define V_BRG_WR_SEL7 0x10 -#define V_BRG_RD_SEL7 0x40 - -/* chapter 12: clock, reset, interrupt, timer and watchdog */ -/* R_IRQMSK_MISC */ -#define V_STA_IRQMSK 0x01 -#define V_TI_IRQMSK 0x02 -#define V_PROC_IRQMSK 0x04 -#define V_DTMF_IRQMSK 0x08 -#define V_IRQ1S_MSK 0x10 -#define V_SA6_IRQMSK 0x20 -#define V_RX_EOMF_MSK 0x40 -#define V_TX_EOMF_MSK 0x80 -/* R_IRQ_CTRL */ -#define V_FIFO_IRQ 0x01 -#define V_GLOB_IRQ_EN 0x08 -#define V_IRQ_POL 0x10 -/* R_TI_WD */ -#define V_EV_TS 0x01 -#define V_WD_TS 0x10 -/* A_IRQ_MSK */ -#define V_IRQ 0x01 -#define V_BERT_EN 0x02 -#define V_MIX_IRQ 0x04 -/* R_IRQ_OVIEW */ -#define V_IRQ_FIFO_BL0 0x01 -#define V_IRQ_FIFO_BL1 0x02 -#define V_IRQ_FIFO_BL2 0x04 -#define V_IRQ_FIFO_BL3 0x08 -#define V_IRQ_FIFO_BL4 0x10 -#define V_IRQ_FIFO_BL5 0x20 -#define V_IRQ_FIFO_BL6 0x40 -#define V_IRQ_FIFO_BL7 0x80 -/* R_IRQ_MISC */ -#define V_STA_IRQ 0x01 -#define V_TI_IRQ 0x02 -#define V_IRQ_PROC 0x04 -#define V_DTMF_IRQ 0x08 -#define V_IRQ1S 0x10 -#define V_SA6_IRQ 0x20 -#define V_RX_EOMF 0x40 -#define V_TX_EOMF 0x80 -/* R_STATUS */ -#define V_BUSY 0x01 -#define V_PROC 0x02 -#define V_DTMF_STA 0x04 -#define V_LOST_STA 0x08 -#define V_SYNC_IN 0x10 -#define V_EXT_IRQSTA 0x20 -#define V_MISC_IRQSTA 0x40 -#define V_FR_IRQSTA 0x80 -/* R_IRQ_FIFO_BL0 */ -#define V_IRQ_FIFO0_TX 0x01 -#define V_IRQ_FIFO0_RX 0x02 -#define V_IRQ_FIFO1_TX 0x04 -#define V_IRQ_FIFO1_RX 0x08 -#define V_IRQ_FIFO2_TX 0x10 -#define V_IRQ_FIFO2_RX 0x20 -#define V_IRQ_FIFO3_TX 0x40 -#define V_IRQ_FIFO3_RX 0x80 -/* R_IRQ_FIFO_BL1 */ -#define V_IRQ_FIFO4_TX 0x01 -#define V_IRQ_FIFO4_RX 0x02 -#define V_IRQ_FIFO5_TX 0x04 -#define V_IRQ_FIFO5_RX 0x08 -#define V_IRQ_FIFO6_TX 0x10 -#define V_IRQ_FIFO6_RX 0x20 -#define V_IRQ_FIFO7_TX 0x40 -#define V_IRQ_FIFO7_RX 0x80 -/* R_IRQ_FIFO_BL2 */ -#define V_IRQ_FIFO8_TX 0x01 -#define V_IRQ_FIFO8_RX 0x02 -#define V_IRQ_FIFO9_TX 0x04 -#define V_IRQ_FIFO9_RX 0x08 -#define V_IRQ_FIFO10_TX 0x10 -#define V_IRQ_FIFO10_RX 0x20 -#define V_IRQ_FIFO11_TX 0x40 -#define V_IRQ_FIFO11_RX 0x80 -/* R_IRQ_FIFO_BL3 */ -#define V_IRQ_FIFO12_TX 0x01 -#define V_IRQ_FIFO12_RX 0x02 -#define V_IRQ_FIFO13_TX 0x04 -#define V_IRQ_FIFO13_RX 0x08 -#define V_IRQ_FIFO14_TX 0x10 -#define V_IRQ_FIFO14_RX 0x20 -#define V_IRQ_FIFO15_TX 0x40 -#define V_IRQ_FIFO15_RX 0x80 -/* R_IRQ_FIFO_BL4 */ -#define V_IRQ_FIFO16_TX 0x01 -#define V_IRQ_FIFO16_RX 0x02 -#define V_IRQ_FIFO17_TX 0x04 -#define V_IRQ_FIFO17_RX 0x08 -#define V_IRQ_FIFO18_TX 0x10 -#define V_IRQ_FIFO18_RX 0x20 -#define V_IRQ_FIFO19_TX 0x40 -#define V_IRQ_FIFO19_RX 0x80 -/* R_IRQ_FIFO_BL5 */ -#define V_IRQ_FIFO20_TX 0x01 -#define V_IRQ_FIFO20_RX 0x02 -#define V_IRQ_FIFO21_TX 0x04 -#define V_IRQ_FIFO21_RX 0x08 -#define V_IRQ_FIFO22_TX 0x10 -#define V_IRQ_FIFO22_RX 0x20 -#define V_IRQ_FIFO23_TX 0x40 -#define V_IRQ_FIFO23_RX 0x80 -/* R_IRQ_FIFO_BL6 */ -#define V_IRQ_FIFO24_TX 0x01 -#define V_IRQ_FIFO24_RX 0x02 -#define V_IRQ_FIFO25_TX 0x04 -#define V_IRQ_FIFO25_RX 0x08 -#define V_IRQ_FIFO26_TX 0x10 -#define V_IRQ_FIFO26_RX 0x20 -#define V_IRQ_FIFO27_TX 0x40 -#define V_IRQ_FIFO27_RX 0x80 -/* R_IRQ_FIFO_BL7 */ -#define V_IRQ_FIFO28_TX 0x01 -#define V_IRQ_FIFO28_RX 0x02 -#define V_IRQ_FIFO29_TX 0x04 -#define V_IRQ_FIFO29_RX 0x08 -#define V_IRQ_FIFO30_TX 0x10 -#define V_IRQ_FIFO30_RX 0x20 -#define V_IRQ_FIFO31_TX 0x40 -#define V_IRQ_FIFO31_RX 0x80 - -/* chapter 13: general purpose I/O pins (GPIO) and input pins (GPI) */ -/* R_GPIO_OUT0 */ -#define V_GPIO_OUT0 0x01 -#define V_GPIO_OUT1 0x02 -#define V_GPIO_OUT2 0x04 -#define V_GPIO_OUT3 0x08 -#define V_GPIO_OUT4 0x10 -#define V_GPIO_OUT5 0x20 -#define V_GPIO_OUT6 0x40 -#define V_GPIO_OUT7 0x80 -/* R_GPIO_OUT1 */ -#define V_GPIO_OUT8 0x01 -#define V_GPIO_OUT9 0x02 -#define V_GPIO_OUT10 0x04 -#define V_GPIO_OUT11 0x08 -#define V_GPIO_OUT12 0x10 -#define V_GPIO_OUT13 0x20 -#define V_GPIO_OUT14 0x40 -#define V_GPIO_OUT15 0x80 -/* R_GPIO_EN0 */ -#define V_GPIO_EN0 0x01 -#define V_GPIO_EN1 0x02 -#define V_GPIO_EN2 0x04 -#define V_GPIO_EN3 0x08 -#define V_GPIO_EN4 0x10 -#define V_GPIO_EN5 0x20 -#define V_GPIO_EN6 0x40 -#define V_GPIO_EN7 0x80 -/* R_GPIO_EN1 */ -#define V_GPIO_EN8 0x01 -#define V_GPIO_EN9 0x02 -#define V_GPIO_EN10 0x04 -#define V_GPIO_EN11 0x08 -#define V_GPIO_EN12 0x10 -#define V_GPIO_EN13 0x20 -#define V_GPIO_EN14 0x40 -#define V_GPIO_EN15 0x80 -/* R_GPIO_SEL */ -#define V_GPIO_SEL0 0x01 -#define V_GPIO_SEL1 0x02 -#define V_GPIO_SEL2 0x04 -#define V_GPIO_SEL3 0x08 -#define V_GPIO_SEL4 0x10 -#define V_GPIO_SEL5 0x20 -#define V_GPIO_SEL6 0x40 -#define V_GPIO_SEL7 0x80 -/* R_GPIO_IN0 */ -#define V_GPIO_IN0 0x01 -#define V_GPIO_IN1 0x02 -#define V_GPIO_IN2 0x04 -#define V_GPIO_IN3 0x08 -#define V_GPIO_IN4 0x10 -#define V_GPIO_IN5 0x20 -#define V_GPIO_IN6 0x40 -#define V_GPIO_IN7 0x80 -/* R_GPIO_IN1 */ -#define V_GPIO_IN8 0x01 -#define V_GPIO_IN9 0x02 -#define V_GPIO_IN10 0x04 -#define V_GPIO_IN11 0x08 -#define V_GPIO_IN12 0x10 -#define V_GPIO_IN13 0x20 -#define V_GPIO_IN14 0x40 -#define V_GPIO_IN15 0x80 -/* R_GPI_IN0 */ -#define V_GPI_IN0 0x01 -#define V_GPI_IN1 0x02 -#define V_GPI_IN2 0x04 -#define V_GPI_IN3 0x08 -#define V_GPI_IN4 0x10 -#define V_GPI_IN5 0x20 -#define V_GPI_IN6 0x40 -#define V_GPI_IN7 0x80 -/* R_GPI_IN1 */ -#define V_GPI_IN8 0x01 -#define V_GPI_IN9 0x02 -#define V_GPI_IN10 0x04 -#define V_GPI_IN11 0x08 -#define V_GPI_IN12 0x10 -#define V_GPI_IN13 0x20 -#define V_GPI_IN14 0x40 -#define V_GPI_IN15 0x80 -/* R_GPI_IN2 */ -#define V_GPI_IN16 0x01 -#define V_GPI_IN17 0x02 -#define V_GPI_IN18 0x04 -#define V_GPI_IN19 0x08 -#define V_GPI_IN20 0x10 -#define V_GPI_IN21 0x20 -#define V_GPI_IN22 0x40 -#define V_GPI_IN23 0x80 -/* R_GPI_IN3 */ -#define V_GPI_IN24 0x01 -#define V_GPI_IN25 0x02 -#define V_GPI_IN26 0x04 -#define V_GPI_IN27 0x08 -#define V_GPI_IN28 0x10 -#define V_GPI_IN29 0x20 -#define V_GPI_IN30 0x40 -#define V_GPI_IN31 0x80 - -/* map of all registers, used for debugging */ - -#ifdef HFC_REGISTER_DEBUG -struct hfc_register_names { - char *name; - u_char reg; -} hfc_register_names[] = { - /* write registers */ - {"R_CIRM", 0x00}, - {"R_CTRL", 0x01}, - {"R_BRG_PCM_CFG ", 0x02}, - {"R_RAM_ADDR0", 0x08}, - {"R_RAM_ADDR1", 0x09}, - {"R_RAM_ADDR2", 0x0A}, - {"R_FIRST_FIFO", 0x0B}, - {"R_RAM_SZ", 0x0C}, - {"R_FIFO_MD", 0x0D}, - {"R_INC_RES_FIFO", 0x0E}, - {"R_FIFO / R_FSM_IDX", 0x0F}, - {"R_SLOT", 0x10}, - {"R_IRQMSK_MISC", 0x11}, - {"R_SCI_MSK", 0x12}, - {"R_IRQ_CTRL", 0x13}, - {"R_PCM_MD0", 0x14}, - {"R_0x15", 0x15}, - {"R_ST_SEL", 0x16}, - {"R_ST_SYNC", 0x17}, - {"R_CONF_EN", 0x18}, - {"R_TI_WD", 0x1A}, - {"R_BERT_WD_MD", 0x1B}, - {"R_DTMF", 0x1C}, - {"R_DTMF_N", 0x1D}, - {"R_E1_XX_STA", 0x20}, - {"R_LOS0", 0x22}, - {"R_LOS1", 0x23}, - {"R_RX0", 0x24}, - {"R_RX_FR0", 0x25}, - {"R_RX_FR1", 0x26}, - {"R_TX0", 0x28}, - {"R_TX1", 0x29}, - {"R_TX_FR0", 0x2C}, - {"R_TX_FR1", 0x2D}, - {"R_TX_FR2", 0x2E}, - {"R_JATT_ATT", 0x2F}, - {"A_ST_xx_STA/R_RX_OFF", 0x30}, - {"A_ST_CTRL0/R_SYNC_OUT", 0x31}, - {"A_ST_CTRL1", 0x32}, - {"A_ST_CTRL2", 0x33}, - {"A_ST_SQ_WR", 0x34}, - {"R_TX_OFF", 0x34}, - {"R_SYNC_CTRL", 0x35}, - {"A_ST_CLK_DLY", 0x37}, - {"R_PWM0", 0x38}, - {"R_PWM1", 0x39}, - {"A_ST_B1_TX", 0x3C}, - {"A_ST_B2_TX", 0x3D}, - {"A_ST_D_TX", 0x3E}, - {"R_GPIO_OUT0", 0x40}, - {"R_GPIO_OUT1", 0x41}, - {"R_GPIO_EN0", 0x42}, - {"R_GPIO_EN1", 0x43}, - {"R_GPIO_SEL", 0x44}, - {"R_BRG_CTRL", 0x45}, - {"R_PWM_MD", 0x46}, - {"R_BRG_MD", 0x47}, - {"R_BRG_TIM0", 0x48}, - {"R_BRG_TIM1", 0x49}, - {"R_BRG_TIM2", 0x4A}, - {"R_BRG_TIM3", 0x4B}, - {"R_BRG_TIM_SEL01", 0x4C}, - {"R_BRG_TIM_SEL23", 0x4D}, - {"R_BRG_TIM_SEL45", 0x4E}, - {"R_BRG_TIM_SEL67", 0x4F}, - {"A_FIFO_DATA0-2", 0x80}, - {"A_FIFO_DATA0-2_NOINC", 0x84}, - {"R_RAM_DATA", 0xC0}, - {"A_SL_CFG", 0xD0}, - {"A_CONF", 0xD1}, - {"A_CH_MSK", 0xF4}, - {"A_CON_HDLC", 0xFA}, - {"A_SUBCH_CFG", 0xFB}, - {"A_CHANNEL", 0xFC}, - {"A_FIFO_SEQ", 0xFD}, - {"A_IRQ_MSK", 0xFF}, - {NULL, 0}, - - /* read registers */ - {"A_Z1", 0x04}, - {"A_Z1H", 0x05}, - {"A_Z2", 0x06}, - {"A_Z2H", 0x07}, - {"A_F1", 0x0C}, - {"A_F2", 0x0D}, - {"R_IRQ_OVIEW", 0x10}, - {"R_IRQ_MISC", 0x11}, - {"R_IRQ_STATECH", 0x12}, - {"R_CONF_OFLOW", 0x14}, - {"R_RAM_USE", 0x15}, - {"R_CHIP_ID", 0x16}, - {"R_BERT_STA", 0x17}, - {"R_F0_CNTL", 0x18}, - {"R_F0_CNTH", 0x19}, - {"R_BERT_ECL", 0x1A}, - {"R_BERT_ECH", 0x1B}, - {"R_STATUS", 0x1C}, - {"R_CHIP_RV", 0x1F}, - {"R_STATE", 0x20}, - {"R_SYNC_STA", 0x24}, - {"R_RX_SL0_0", 0x25}, - {"R_RX_SL0_1", 0x26}, - {"R_RX_SL0_2", 0x27}, - {"R_JATT_DIR", 0x2b}, - {"R_SLIP", 0x2c}, - {"A_ST_RD_STA", 0x30}, - {"R_FAS_ECL", 0x30}, - {"R_FAS_ECH", 0x31}, - {"R_VIO_ECL", 0x32}, - {"R_VIO_ECH", 0x33}, - {"R_CRC_ECL / A_ST_SQ_RD", 0x34}, - {"R_CRC_ECH", 0x35}, - {"R_E_ECL", 0x36}, - {"R_E_ECH", 0x37}, - {"R_SA6_SA13_ECL", 0x38}, - {"R_SA6_SA13_ECH", 0x39}, - {"R_SA6_SA23_ECL", 0x3A}, - {"R_SA6_SA23_ECH", 0x3B}, - {"A_ST_B1_RX", 0x3C}, - {"A_ST_B2_RX", 0x3D}, - {"A_ST_D_RX", 0x3E}, - {"A_ST_E_RX", 0x3F}, - {"R_GPIO_IN0", 0x40}, - {"R_GPIO_IN1", 0x41}, - {"R_GPI_IN0", 0x44}, - {"R_GPI_IN1", 0x45}, - {"R_GPI_IN2", 0x46}, - {"R_GPI_IN3", 0x47}, - {"A_FIFO_DATA0-2", 0x80}, - {"A_FIFO_DATA0-2_NOINC", 0x84}, - {"R_INT_DATA", 0x88}, - {"R_RAM_DATA", 0xC0}, - {"R_IRQ_FIFO_BL0", 0xC8}, - {"R_IRQ_FIFO_BL1", 0xC9}, - {"R_IRQ_FIFO_BL2", 0xCA}, - {"R_IRQ_FIFO_BL3", 0xCB}, - {"R_IRQ_FIFO_BL4", 0xCC}, - {"R_IRQ_FIFO_BL5", 0xCD}, - {"R_IRQ_FIFO_BL6", 0xCE}, - {"R_IRQ_FIFO_BL7", 0xCF}, -}; -#endif /* HFC_REGISTER_DEBUG */ diff --git a/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h deleted file mode 100644 index 448ded8f9d24..000000000000 --- a/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h +++ /dev/null @@ -1,167 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * For License see notice in hfc_multi.c - * - * special IO and init functions for the embedded XHFC board - * from Speech Design - * - */ - -#include - -/* Change this to the value used by your board */ -#ifndef IMAP_ADDR -#define IMAP_ADDR 0xFFF00000 -#endif - -static void -#ifdef HFC_REGISTER_DEBUG -HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val, - const char *function, int line) -#else - HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val) -#endif -{ - hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; - writeb(reg, hc->xhfc_memaddr); - hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); - writeb(val, hc->xhfc_memdata); -} -static u_char -#ifdef HFC_REGISTER_DEBUG -HFC_inb_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line) -#else - HFC_inb_embsd(struct hfc_multi *hc, u_char reg) -#endif -{ - hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; - writeb(reg, hc->xhfc_memaddr); - hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); - return readb(hc->xhfc_memdata); -} -static u_short -#ifdef HFC_REGISTER_DEBUG -HFC_inw_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line) -#else - HFC_inw_embsd(struct hfc_multi *hc, u_char reg) -#endif -{ - hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; - writeb(reg, hc->xhfc_memaddr); - hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); - return readb(hc->xhfc_memdata); -} -static void -#ifdef HFC_REGISTER_DEBUG -HFC_wait_embsd(struct hfc_multi *hc, const char *function, int line) -#else - HFC_wait_embsd(struct hfc_multi *hc) -#endif -{ - hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; - writeb(R_STATUS, hc->xhfc_memaddr); - hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); - while (readb(hc->xhfc_memdata) & V_BUSY) - cpu_relax(); -} - -/* write fifo data (EMBSD) */ -void -write_fifo_embsd(struct hfc_multi *hc, u_char *data, int len) -{ - hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; - *hc->xhfc_memaddr = A_FIFO_DATA0; - hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); - while (len) { - *hc->xhfc_memdata = *data; - data++; - len--; - } -} - -/* read fifo data (EMBSD) */ -void -read_fifo_embsd(struct hfc_multi *hc, u_char *data, int len) -{ - hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; - *hc->xhfc_memaddr = A_FIFO_DATA0; - hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); - while (len) { - *data = (u_char)(*hc->xhfc_memdata); - data++; - len--; - } -} - -static int -setup_embedded(struct hfc_multi *hc, struct hm_map *m) -{ - printk(KERN_INFO - "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", - m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); - - hc->pci_dev = NULL; - if (m->clock2) - test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); - - hc->leds = m->leds; - hc->ledstate = 0xAFFEAFFE; - hc->opticalsupport = m->opticalsupport; - - hc->pci_iobase = 0; - hc->pci_membase = 0; - hc->xhfc_membase = NULL; - hc->xhfc_memaddr = NULL; - hc->xhfc_memdata = NULL; - - /* set memory access methods */ - if (m->io_mode) /* use mode from card config */ - hc->io_mode = m->io_mode; - switch (hc->io_mode) { - case HFC_IO_MODE_EMBSD: - test_and_set_bit(HFC_CHIP_EMBSD, &hc->chip); - hc->slots = 128; /* required */ - hc->HFC_outb = HFC_outb_embsd; - hc->HFC_inb = HFC_inb_embsd; - hc->HFC_inw = HFC_inw_embsd; - hc->HFC_wait = HFC_wait_embsd; - hc->read_fifo = read_fifo_embsd; - hc->write_fifo = write_fifo_embsd; - hc->xhfc_origmembase = XHFC_MEMBASE + XHFC_OFFSET * hc->id; - hc->xhfc_membase = (u_char *)ioremap(hc->xhfc_origmembase, - XHFC_MEMSIZE); - if (!hc->xhfc_membase) { - printk(KERN_WARNING - "HFC-multi: failed to remap xhfc address space. " - "(internal error)\n"); - return -EIO; - } - hc->xhfc_memaddr = (u_long *)(hc->xhfc_membase + 4); - hc->xhfc_memdata = (u_long *)(hc->xhfc_membase); - printk(KERN_INFO - "HFC-multi: xhfc_membase:%#lx xhfc_origmembase:%#lx " - "xhfc_memaddr:%#lx xhfc_memdata:%#lx\n", - (u_long)hc->xhfc_membase, hc->xhfc_origmembase, - (u_long)hc->xhfc_memaddr, (u_long)hc->xhfc_memdata); - break; - default: - printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); - return -EIO; - } - - /* Prepare the MPC8XX PortA 10 as output (address/data selector) */ - hc->immap = (struct immap *)(IMAP_ADDR); - hc->immap->im_ioport.iop_papar &= ~(PA_XHFC_A0); - hc->immap->im_ioport.iop_paodr &= ~(PA_XHFC_A0); - hc->immap->im_ioport.iop_padir |= PA_XHFC_A0; - - /* Prepare the MPC8xx PortB __X__ as input (ISDN__X__IRQ) */ - hc->pb_irqmsk = (PB_XHFC_IRQ1 << hc->id); - hc->immap->im_cpm.cp_pbpar &= ~(hc->pb_irqmsk); - hc->immap->im_cpm.cp_pbodr &= ~(hc->pb_irqmsk); - hc->immap->im_cpm.cp_pbdir &= ~(hc->pb_irqmsk); - - /* At this point the needed config is done */ - /* fifos are still not enabled */ - return 0; -} diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h deleted file mode 100644 index a0e4806c11fa..000000000000 --- a/drivers/isdn/hardware/mISDN/hfc_pci.h +++ /dev/null @@ -1,214 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * specific defines for CCD's HFC 2BDS0 PCI chips - * - * Author Werner Cornelius (werner@isdn4linux.de) - * - * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) - */ - -/* - * thresholds for transparent B-channel mode - * change mask and threshold simultaneously - */ -#define HFCPCI_BTRANS_THRESHOLD 128 -#define HFCPCI_FILLEMPTY 64 -#define HFCPCI_BTRANS_THRESMASK 0x00 - -/* defines for PCI config */ -#define PCI_ENA_MEMIO 0x02 -#define PCI_ENA_MASTER 0x04 - -/* GCI/IOM bus monitor registers */ -#define HCFPCI_C_I 0x08 -#define HFCPCI_TRxR 0x0C -#define HFCPCI_MON1_D 0x28 -#define HFCPCI_MON2_D 0x2C - -/* GCI/IOM bus timeslot registers */ -#define HFCPCI_B1_SSL 0x80 -#define HFCPCI_B2_SSL 0x84 -#define HFCPCI_AUX1_SSL 0x88 -#define HFCPCI_AUX2_SSL 0x8C -#define HFCPCI_B1_RSL 0x90 -#define HFCPCI_B2_RSL 0x94 -#define HFCPCI_AUX1_RSL 0x98 -#define HFCPCI_AUX2_RSL 0x9C - -/* GCI/IOM bus data registers */ -#define HFCPCI_B1_D 0xA0 -#define HFCPCI_B2_D 0xA4 -#define HFCPCI_AUX1_D 0xA8 -#define HFCPCI_AUX2_D 0xAC - -/* GCI/IOM bus configuration registers */ -#define HFCPCI_MST_EMOD 0xB4 -#define HFCPCI_MST_MODE 0xB8 -#define HFCPCI_CONNECT 0xBC - - -/* Interrupt and status registers */ -#define HFCPCI_FIFO_EN 0x44 -#define HFCPCI_TRM 0x48 -#define HFCPCI_B_MODE 0x4C -#define HFCPCI_CHIP_ID 0x58 -#define HFCPCI_CIRM 0x60 -#define HFCPCI_CTMT 0x64 -#define HFCPCI_INT_M1 0x68 -#define HFCPCI_INT_M2 0x6C -#define HFCPCI_INT_S1 0x78 -#define HFCPCI_INT_S2 0x7C -#define HFCPCI_STATUS 0x70 - -/* S/T section registers */ -#define HFCPCI_STATES 0xC0 -#define HFCPCI_SCTRL 0xC4 -#define HFCPCI_SCTRL_E 0xC8 -#define HFCPCI_SCTRL_R 0xCC -#define HFCPCI_SQ 0xD0 -#define HFCPCI_CLKDEL 0xDC -#define HFCPCI_B1_REC 0xF0 -#define HFCPCI_B1_SEND 0xF0 -#define HFCPCI_B2_REC 0xF4 -#define HFCPCI_B2_SEND 0xF4 -#define HFCPCI_D_REC 0xF8 -#define HFCPCI_D_SEND 0xF8 -#define HFCPCI_E_REC 0xFC - - -/* bits in status register (READ) */ -#define HFCPCI_PCI_PROC 0x02 -#define HFCPCI_NBUSY 0x04 -#define HFCPCI_TIMER_ELAP 0x10 -#define HFCPCI_STATINT 0x20 -#define HFCPCI_FRAMEINT 0x40 -#define HFCPCI_ANYINT 0x80 - -/* bits in CTMT (Write) */ -#define HFCPCI_CLTIMER 0x80 -#define HFCPCI_TIM3_125 0x04 -#define HFCPCI_TIM25 0x10 -#define HFCPCI_TIM50 0x14 -#define HFCPCI_TIM400 0x18 -#define HFCPCI_TIM800 0x1C -#define HFCPCI_AUTO_TIMER 0x20 -#define HFCPCI_TRANSB2 0x02 -#define HFCPCI_TRANSB1 0x01 - -/* bits in CIRM (Write) */ -#define HFCPCI_AUX_MSK 0x07 -#define HFCPCI_RESET 0x08 -#define HFCPCI_B1_REV 0x40 -#define HFCPCI_B2_REV 0x80 - -/* bits in INT_M1 and INT_S1 */ -#define HFCPCI_INTS_B1TRANS 0x01 -#define HFCPCI_INTS_B2TRANS 0x02 -#define HFCPCI_INTS_DTRANS 0x04 -#define HFCPCI_INTS_B1REC 0x08 -#define HFCPCI_INTS_B2REC 0x10 -#define HFCPCI_INTS_DREC 0x20 -#define HFCPCI_INTS_L1STATE 0x40 -#define HFCPCI_INTS_TIMER 0x80 - -/* bits in INT_M2 */ -#define HFCPCI_PROC_TRANS 0x01 -#define HFCPCI_GCI_I_CHG 0x02 -#define HFCPCI_GCI_MON_REC 0x04 -#define HFCPCI_IRQ_ENABLE 0x08 -#define HFCPCI_PMESEL 0x80 - -/* bits in STATES */ -#define HFCPCI_STATE_MSK 0x0F -#define HFCPCI_LOAD_STATE 0x10 -#define HFCPCI_ACTIVATE 0x20 -#define HFCPCI_DO_ACTION 0x40 -#define HFCPCI_NT_G2_G3 0x80 - -/* bits in HFCD_MST_MODE */ -#define HFCPCI_MASTER 0x01 -#define HFCPCI_SLAVE 0x00 -#define HFCPCI_F0IO_POSITIV 0x02 -#define HFCPCI_F0_NEGATIV 0x04 -#define HFCPCI_F0_2C4 0x08 -/* remaining bits are for codecs control */ - -/* bits in HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_MODE_TE 0x00 -#define SCTRL_MODE_NT 0x04 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* bits in SCTRL_E */ -#define HFCPCI_AUTO_AWAKE 0x01 -#define HFCPCI_DBIT_1 0x04 -#define HFCPCI_IGNORE_COL 0x08 -#define HFCPCI_CHG_B1_B2 0x80 - -/* bits in FIFO_EN register */ -#define HFCPCI_FIFOEN_B1 0x03 -#define HFCPCI_FIFOEN_B2 0x0C -#define HFCPCI_FIFOEN_DTX 0x10 -#define HFCPCI_FIFOEN_B1TX 0x01 -#define HFCPCI_FIFOEN_B1RX 0x02 -#define HFCPCI_FIFOEN_B2TX 0x04 -#define HFCPCI_FIFOEN_B2RX 0x08 - - -/* definitions of fifo memory area */ -#define MAX_D_FRAMES 15 -#define MAX_B_FRAMES 31 -#define B_SUB_VAL 0x200 -#define B_FIFO_SIZE (0x2000 - B_SUB_VAL) -#define D_FIFO_SIZE 512 -#define D_FREG_MASK 0xF - -struct zt { - __le16 z1; /* Z1 pointer 16 Bit */ - __le16 z2; /* Z2 pointer 16 Bit */ -}; - -struct dfifo { - u_char data[D_FIFO_SIZE]; /* FIFO data space */ - u_char fill1[0x20A0 - D_FIFO_SIZE]; /* reserved, do not use */ - u_char f1, f2; /* f pointers */ - u_char fill2[0x20C0 - 0x20A2]; /* reserved, do not use */ - /* mask index with D_FREG_MASK for access */ - struct zt za[MAX_D_FRAMES + 1]; - u_char fill3[0x4000 - 0x2100]; /* align 16K */ -}; - -struct bzfifo { - struct zt za[MAX_B_FRAMES + 1]; /* only range 0x0..0x1F allowed */ - u_char f1, f2; /* f pointers */ - u_char fill[0x2100 - 0x2082]; /* alignment */ -}; - - -union fifo_area { - struct { - struct dfifo d_tx; /* D-send channel */ - struct dfifo d_rx; /* D-receive channel */ - } d_chan; - struct { - u_char fill1[0x200]; - u_char txdat_b1[B_FIFO_SIZE]; - struct bzfifo txbz_b1; - struct bzfifo txbz_b2; - u_char txdat_b2[B_FIFO_SIZE]; - u_char fill2[D_FIFO_SIZE]; - u_char rxdat_b1[B_FIFO_SIZE]; - struct bzfifo rxbz_b1; - struct bzfifo rxbz_b2; - u_char rxdat_b2[B_FIFO_SIZE]; - } b_chans; - u_char fill[32768]; -}; - -#define Write_hfc(a, b, c) (writeb(c, (a->hw.pci_io) + b)) -#define Read_hfc(a, b) (readb((a->hw.pci_io) + b)) diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c deleted file mode 100644 index b3d28976b33a..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ /dev/null @@ -1,5540 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * hfcmulti.c low level driver for hfc-4s/hfc-8s/hfc-e1 based cards - * - * Author Andreas Eversberg (jolly@eversberg.eu) - * ported to mqueue mechanism: - * Peter Sprenger (sprengermoving-bytes.de) - * - * inspired by existing hfc-pci driver: - * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) - * Copyright 2008 by Karsten Keil (kkeil@suse.de) - * Copyright 2008 by Andreas Eversberg (jolly@eversberg.eu) - * - * Thanks to Cologne Chip AG for this great controller! - */ - -/* - * module parameters: - * type: - * By default (0), the card is automatically detected. - * Or use the following combinations: - * Bit 0-7 = 0x00001 = HFC-E1 (1 port) - * or Bit 0-7 = 0x00004 = HFC-4S (4 ports) - * or Bit 0-7 = 0x00008 = HFC-8S (8 ports) - * Bit 8 = 0x00100 = uLaw (instead of aLaw) - * Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware - * Bit 10 = spare - * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwise auto) - * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwise auto) - * Bit 13 = spare - * Bit 14 = 0x04000 = Use external ram (128K) - * Bit 15 = 0x08000 = Use external ram (512K) - * Bit 16 = 0x10000 = Use 64 timeslots instead of 32 - * or Bit 17 = 0x20000 = Use 128 timeslots instead of anything else - * Bit 18 = spare - * Bit 19 = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog) - * (all other bits are reserved and shall be 0) - * example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM - * bus (PCM master) - * - * port: (optional or required for all ports on all installed cards) - * HFC-4S/HFC-8S only bits: - * Bit 0 = 0x001 = Use master clock for this S/T interface - * (only once per chip). - * Bit 1 = 0x002 = transmitter line setup (non capacitive mode) - * Don't use this unless you know what you are doing! - * Bit 2 = 0x004 = Disable E-channel. (No E-channel processing) - * example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock - * received from port 1 - * - * HFC-E1 only bits: - * Bit 0 = 0x0001 = interface: 0=copper, 1=optical - * Bit 1 = 0x0002 = reserved (later for 32 B-channels transparent mode) - * Bit 2 = 0x0004 = Report LOS - * Bit 3 = 0x0008 = Report AIS - * Bit 4 = 0x0010 = Report SLIP - * Bit 5 = 0x0020 = Report RDI - * Bit 8 = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame - * mode instead. - * Bit 9 = 0x0200 = Force get clock from interface, even in NT mode. - * or Bit 10 = 0x0400 = Force put clock to interface, even in TE mode. - * Bit 11 = 0x0800 = Use direct RX clock for PCM sync rather than PLL. - * (E1 only) - * Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0 - * for default. - * (all other bits are reserved and shall be 0) - * - * debug: - * NOTE: only one debug value must be given for all cards - * enable debugging (see hfc_multi.h for debug options) - * - * poll: - * NOTE: only one poll value must be given for all cards - * Give the number of samples for each fifo process. - * By default 128 is used. Decrease to reduce delay, increase to - * reduce cpu load. If unsure, don't mess with it! - * Valid is 8, 16, 32, 64, 128, 256. - * - * pcm: - * NOTE: only one pcm value must be given for every card. - * The PCM bus id tells the mISDNdsp module about the connected PCM bus. - * By default (0), the PCM bus id is 100 for the card that is PCM master. - * If multiple cards are PCM master (because they are not interconnected), - * each card with PCM master will have increasing PCM id. - * All PCM buses with the same ID are expected to be connected and have - * common time slots slots. - * Only one chip of the PCM bus must be master, the others slave. - * -1 means no support of PCM bus not even. - * Omit this value, if all cards are interconnected or none is connected. - * If unsure, don't give this parameter. - * - * dmask and bmask: - * NOTE: One dmask value must be given for every HFC-E1 card. - * If omitted, the E1 card has D-channel on time slot 16, which is default. - * dmask is a 32 bit mask. The bit must be set for an alternate time slot. - * If multiple bits are set, multiple virtual card fragments are created. - * For each bit set, a bmask value must be given. Each bit on the bmask - * value stands for a B-channel. The bmask may not overlap with dmask or - * with other bmask values for that card. - * Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000 - * This will create one fragment with D-channel on slot 1 with - * B-channels on slots 2..15, and a second fragment with D-channel - * on slot 17 with B-channels on slot 18..31. Slot 16 is unused. - * If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will - * not function. - * Example: dmask=0x00000001 bmask=0xfffffffe - * This will create a port with all 31 usable timeslots as - * B-channels. - * If no bits are set on bmask, no B-channel is created for that fragment. - * Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask) - * This will create 31 ports with one D-channel only. - * If you don't know how to use it, you don't need it! - * - * iomode: - * NOTE: only one mode value must be given for every card. - * -> See hfc_multi.h for HFC_IO_MODE_* values - * By default, the IO mode is pci memory IO (MEMIO). - * Some cards require specific IO mode, so it cannot be changed. - * It may be useful to set IO mode to register io (REGIO) to solve - * PCI bridge problems. - * If unsure, don't give this parameter. - * - * clockdelay_nt: - * NOTE: only one clockdelay_nt value must be given once for all cards. - * Give the value of the clock control register (A_ST_CLK_DLY) - * of the S/T interfaces in NT mode. - * This register is needed for the TBR3 certification, so don't change it. - * - * clockdelay_te: - * NOTE: only one clockdelay_te value must be given once - * Give the value of the clock control register (A_ST_CLK_DLY) - * of the S/T interfaces in TE mode. - * This register is needed for the TBR3 certification, so don't change it. - * - * clock: - * NOTE: only one clock value must be given once - * Selects interface with clock source for mISDN and applications. - * Set to card number starting with 1. Set to -1 to disable. - * By default, the first card is used as clock source. - * - * hwid: - * NOTE: only one hwid value must be given once - * Enable special embedded devices with XHFC controllers. - */ - -/* - * debug register access (never use this, it will flood your system log) - * #define HFC_REGISTER_DEBUG - */ - -#define HFC_MULTI_VERSION "2.03" - -#include -#include -#include -#include -#include -#include -#include - -/* - #define IRQCOUNT_DEBUG - #define IRQ_DEBUG -*/ - -#include "hfc_multi.h" -#ifdef ECHOPREP -#include "gaintab.h" -#endif - -#define MAX_CARDS 8 -#define MAX_PORTS (8 * MAX_CARDS) -#define MAX_FRAGS (32 * MAX_CARDS) - -static LIST_HEAD(HFClist); -static DEFINE_SPINLOCK(HFClock); /* global hfc list lock */ - -static void ph_state_change(struct dchannel *); - -static struct hfc_multi *syncmaster; -static int plxsd_master; /* if we have a master card (yet) */ -static DEFINE_SPINLOCK(plx_lock); /* may not acquire other lock inside */ - -#define TYP_E1 1 -#define TYP_4S 4 -#define TYP_8S 8 - -static int poll_timer = 6; /* default = 128 samples = 16ms */ -/* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */ -static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; -#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ -#define CLKDEL_NT 0x6c /* CLKDEL in NT mode - (0x60 MUST be included!) */ - -#define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */ -#define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */ -#define DIP_E1 0x3 /* DIP Switches for Beronet E1 cards */ - -/* - * module stuff - */ - -static uint type[MAX_CARDS]; -static int pcm[MAX_CARDS]; -static uint dmask[MAX_CARDS]; -static uint bmask[MAX_FRAGS]; -static uint iomode[MAX_CARDS]; -static uint port[MAX_PORTS]; -static uint debug; -static uint poll; -static int clock; -static uint timer; -static uint clockdelay_te = CLKDEL_TE; -static uint clockdelay_nt = CLKDEL_NT; -#define HWID_NONE 0 -#define HWID_MINIP4 1 -#define HWID_MINIP8 2 -#define HWID_MINIP16 3 -static uint hwid = HWID_NONE; - -static int HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99; - -MODULE_AUTHOR("Andreas Eversberg"); -MODULE_DESCRIPTION("mISDN driver for hfc-4s/hfc-8s/hfc-e1 based cards"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(HFC_MULTI_VERSION); -module_param(debug, uint, S_IRUGO | S_IWUSR); -module_param(poll, uint, S_IRUGO | S_IWUSR); -module_param(clock, int, S_IRUGO | S_IWUSR); -module_param(timer, uint, S_IRUGO | S_IWUSR); -module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); -module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); -module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); -module_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(bmask, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); -module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ - -#ifdef HFC_REGISTER_DEBUG -#define HFC_outb(hc, reg, val) \ - (hc->HFC_outb(hc, reg, val, __func__, __LINE__)) -#define HFC_outb_nodebug(hc, reg, val) \ - (hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__)) -#define HFC_inb(hc, reg) \ - (hc->HFC_inb(hc, reg, __func__, __LINE__)) -#define HFC_inb_nodebug(hc, reg) \ - (hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__)) -#define HFC_inw(hc, reg) \ - (hc->HFC_inw(hc, reg, __func__, __LINE__)) -#define HFC_inw_nodebug(hc, reg) \ - (hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__)) -#define HFC_wait(hc) \ - (hc->HFC_wait(hc, __func__, __LINE__)) -#define HFC_wait_nodebug(hc) \ - (hc->HFC_wait_nodebug(hc, __func__, __LINE__)) -#else -#define HFC_outb(hc, reg, val) (hc->HFC_outb(hc, reg, val)) -#define HFC_outb_nodebug(hc, reg, val) (hc->HFC_outb_nodebug(hc, reg, val)) -#define HFC_inb(hc, reg) (hc->HFC_inb(hc, reg)) -#define HFC_inb_nodebug(hc, reg) (hc->HFC_inb_nodebug(hc, reg)) -#define HFC_inw(hc, reg) (hc->HFC_inw(hc, reg)) -#define HFC_inw_nodebug(hc, reg) (hc->HFC_inw_nodebug(hc, reg)) -#define HFC_wait(hc) (hc->HFC_wait(hc)) -#define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc)) -#endif - -#ifdef CONFIG_MISDN_HFCMULTI_8xx -#include "hfc_multi_8xx.h" -#endif - -/* HFC_IO_MODE_PCIMEM */ -static void -#ifdef HFC_REGISTER_DEBUG -HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, - const char *function, int line) -#else - HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) -#endif -{ - writeb(val, hc->pci_membase + reg); -} -static u_char -#ifdef HFC_REGISTER_DEBUG -HFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) -#else - HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) -#endif -{ - return readb(hc->pci_membase + reg); -} -static u_short -#ifdef HFC_REGISTER_DEBUG -HFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) -#else - HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) -#endif -{ - return readw(hc->pci_membase + reg); -} -static void -#ifdef HFC_REGISTER_DEBUG -HFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) -#else - HFC_wait_pcimem(struct hfc_multi *hc) -#endif -{ - while (readb(hc->pci_membase + R_STATUS) & V_BUSY) - cpu_relax(); -} - -/* HFC_IO_MODE_REGIO */ -static void -#ifdef HFC_REGISTER_DEBUG -HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, - const char *function, int line) -#else - HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) -#endif -{ - outb(reg, hc->pci_iobase + 4); - outb(val, hc->pci_iobase); -} -static u_char -#ifdef HFC_REGISTER_DEBUG -HFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) -#else - HFC_inb_regio(struct hfc_multi *hc, u_char reg) -#endif -{ - outb(reg, hc->pci_iobase + 4); - return inb(hc->pci_iobase); -} -static u_short -#ifdef HFC_REGISTER_DEBUG -HFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) -#else - HFC_inw_regio(struct hfc_multi *hc, u_char reg) -#endif -{ - outb(reg, hc->pci_iobase + 4); - return inw(hc->pci_iobase); -} -static void -#ifdef HFC_REGISTER_DEBUG -HFC_wait_regio(struct hfc_multi *hc, const char *function, int line) -#else - HFC_wait_regio(struct hfc_multi *hc) -#endif -{ - outb(R_STATUS, hc->pci_iobase + 4); - while (inb(hc->pci_iobase) & V_BUSY) - cpu_relax(); -} - -#ifdef HFC_REGISTER_DEBUG -static void -HFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, - const char *function, int line) -{ - char regname[256] = "", bits[9] = "xxxxxxxx"; - int i; - - i = -1; - while (hfc_register_names[++i].name) { - if (hfc_register_names[i].reg == reg) - strcat(regname, hfc_register_names[i].name); - } - if (regname[0] == '\0') - strcpy(regname, "register"); - - bits[7] = '0' + (!!(val & 1)); - bits[6] = '0' + (!!(val & 2)); - bits[5] = '0' + (!!(val & 4)); - bits[4] = '0' + (!!(val & 8)); - bits[3] = '0' + (!!(val & 16)); - bits[2] = '0' + (!!(val & 32)); - bits[1] = '0' + (!!(val & 64)); - bits[0] = '0' + (!!(val & 128)); - printk(KERN_DEBUG - "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", - hc->id, reg, regname, val, bits, function, line); - HFC_outb_nodebug(hc, reg, val); -} -static u_char -HFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) -{ - char regname[256] = "", bits[9] = "xxxxxxxx"; - u_char val = HFC_inb_nodebug(hc, reg); - int i; - - i = 0; - while (hfc_register_names[i++].name) - ; - while (hfc_register_names[++i].name) { - if (hfc_register_names[i].reg == reg) - strcat(regname, hfc_register_names[i].name); - } - if (regname[0] == '\0') - strcpy(regname, "register"); - - bits[7] = '0' + (!!(val & 1)); - bits[6] = '0' + (!!(val & 2)); - bits[5] = '0' + (!!(val & 4)); - bits[4] = '0' + (!!(val & 8)); - bits[3] = '0' + (!!(val & 16)); - bits[2] = '0' + (!!(val & 32)); - bits[1] = '0' + (!!(val & 64)); - bits[0] = '0' + (!!(val & 128)); - printk(KERN_DEBUG - "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", - hc->id, reg, regname, val, bits, function, line); - return val; -} -static u_short -HFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) -{ - char regname[256] = ""; - u_short val = HFC_inw_nodebug(hc, reg); - int i; - - i = 0; - while (hfc_register_names[i++].name) - ; - while (hfc_register_names[++i].name) { - if (hfc_register_names[i].reg == reg) - strcat(regname, hfc_register_names[i].name); - } - if (regname[0] == '\0') - strcpy(regname, "register"); - - printk(KERN_DEBUG - "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n", - hc->id, reg, regname, val, function, line); - return val; -} -static void -HFC_wait_debug(struct hfc_multi *hc, const char *function, int line) -{ - printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n", - hc->id, function, line); - HFC_wait_nodebug(hc); -} -#endif - -/* write fifo data (REGIO) */ -static void -write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) -{ - outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); - while (len >> 2) { - outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase); - data += 4; - len -= 4; - } - while (len >> 1) { - outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase); - data += 2; - len -= 2; - } - while (len) { - outb(*data, hc->pci_iobase); - data++; - len--; - } -} -/* write fifo data (PCIMEM) */ -static void -write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) -{ - while (len >> 2) { - writel(cpu_to_le32(*(u32 *)data), - hc->pci_membase + A_FIFO_DATA0); - data += 4; - len -= 4; - } - while (len >> 1) { - writew(cpu_to_le16(*(u16 *)data), - hc->pci_membase + A_FIFO_DATA0); - data += 2; - len -= 2; - } - while (len) { - writeb(*data, hc->pci_membase + A_FIFO_DATA0); - data++; - len--; - } -} - -/* read fifo data (REGIO) */ -static void -read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) -{ - outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); - while (len >> 2) { - *(u32 *)data = le32_to_cpu(inl(hc->pci_iobase)); - data += 4; - len -= 4; - } - while (len >> 1) { - *(u16 *)data = le16_to_cpu(inw(hc->pci_iobase)); - data += 2; - len -= 2; - } - while (len) { - *data = inb(hc->pci_iobase); - data++; - len--; - } -} - -/* read fifo data (PCIMEM) */ -static void -read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) -{ - while (len >> 2) { - *(u32 *)data = - le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0)); - data += 4; - len -= 4; - } - while (len >> 1) { - *(u16 *)data = - le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0)); - data += 2; - len -= 2; - } - while (len) { - *data = readb(hc->pci_membase + A_FIFO_DATA0); - data++; - len--; - } -} - -static void -enable_hwirq(struct hfc_multi *hc) -{ - hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN; - HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); -} - -static void -disable_hwirq(struct hfc_multi *hc) -{ - hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN); - HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); -} - -#define NUM_EC 2 -#define MAX_TDM_CHAN 32 - - -static inline void -enablepcibridge(struct hfc_multi *c) -{ - HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */ -} - -static inline void -disablepcibridge(struct hfc_multi *c) -{ - HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */ -} - -static inline unsigned char -readpcibridge(struct hfc_multi *hc, unsigned char address) -{ - unsigned short cipv; - unsigned char data; - - if (!hc->pci_iobase) - return 0; - - /* slow down a PCI read access by 1 PCI clock cycle */ - HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/ - - if (address == 0) - cipv = 0x4000; - else - cipv = 0x5800; - - /* select local bridge port address by writing to CIP port */ - /* data = HFC_inb(c, cipv); * was _io before */ - outw(cipv, hc->pci_iobase + 4); - data = inb(hc->pci_iobase); - - /* restore R_CTRL for normal PCI read cycle speed */ - HFC_outb(hc, R_CTRL, 0x0); /* was _io before */ - - return data; -} - -static inline void -writepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data) -{ - unsigned short cipv; - unsigned int datav; - - if (!hc->pci_iobase) - return; - - if (address == 0) - cipv = 0x4000; - else - cipv = 0x5800; - - /* select local bridge port address by writing to CIP port */ - outw(cipv, hc->pci_iobase + 4); - /* define a 32 bit dword with 4 identical bytes for write sequence */ - datav = data | ((__u32) data << 8) | ((__u32) data << 16) | - ((__u32) data << 24); - - /* - * write this 32 bit dword to the bridge data port - * this will initiate a write sequence of up to 4 writes to the same - * address on the local bus interface the number of write accesses - * is undefined but >=1 and depends on the next PCI transaction - * during write sequence on the local bus - */ - outl(datav, hc->pci_iobase); -} - -static inline void -cpld_set_reg(struct hfc_multi *hc, unsigned char reg) -{ - /* Do data pin read low byte */ - HFC_outb(hc, R_GPIO_OUT1, reg); -} - -static inline void -cpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val) -{ - cpld_set_reg(hc, reg); - - enablepcibridge(hc); - writepcibridge(hc, 1, val); - disablepcibridge(hc); - - return; -} - -static inline void -vpm_write_address(struct hfc_multi *hc, unsigned short addr) -{ - cpld_write_reg(hc, 0, 0xff & addr); - cpld_write_reg(hc, 1, 0x01 & (addr >> 8)); -} - -static inline unsigned char -vpm_in(struct hfc_multi *c, int which, unsigned short addr) -{ - unsigned char res; - - vpm_write_address(c, addr); - - if (!which) - cpld_set_reg(c, 2); - else - cpld_set_reg(c, 3); - - enablepcibridge(c); - res = readpcibridge(c, 1); - disablepcibridge(c); - - cpld_set_reg(c, 0); - - return res; -} - -static inline void -vpm_out(struct hfc_multi *c, int which, unsigned short addr, - unsigned char data) -{ - vpm_write_address(c, addr); - - enablepcibridge(c); - - if (!which) - cpld_set_reg(c, 2); - else - cpld_set_reg(c, 3); - - writepcibridge(c, 1, data); - - cpld_set_reg(c, 0); - - disablepcibridge(c); - - { - unsigned char regin; - regin = vpm_in(c, which, addr); - if (regin != data) - printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back " - "0x%x\n", data, addr, regin); - } - -} - - -static void -vpm_init(struct hfc_multi *wc) -{ - unsigned char reg; - unsigned int mask; - unsigned int i, x, y; - unsigned int ver; - - for (x = 0; x < NUM_EC; x++) { - /* Setup GPIO's */ - if (!x) { - ver = vpm_in(wc, x, 0x1a0); - printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver); - } - - for (y = 0; y < 4; y++) { - vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */ - vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */ - vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */ - } - - /* Setup TDM path - sets fsync and tdm_clk as inputs */ - reg = vpm_in(wc, x, 0x1a3); /* misc_con */ - vpm_out(wc, x, 0x1a3, reg & ~2); - - /* Setup Echo length (256 taps) */ - vpm_out(wc, x, 0x022, 1); - vpm_out(wc, x, 0x023, 0xff); - - /* Setup timeslots */ - vpm_out(wc, x, 0x02f, 0x00); - mask = 0x02020202 << (x * 4); - - /* Setup the tdm channel masks for all chips */ - for (i = 0; i < 4; i++) - vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff); - - /* Setup convergence rate */ - printk(KERN_DEBUG "VPM: A-law mode\n"); - reg = 0x00 | 0x10 | 0x01; - vpm_out(wc, x, 0x20, reg); - printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg); - /*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */ - - vpm_out(wc, x, 0x24, 0x02); - reg = vpm_in(wc, x, 0x24); - printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg); - - /* Initialize echo cans */ - for (i = 0; i < MAX_TDM_CHAN; i++) { - if (mask & (0x00000001 << i)) - vpm_out(wc, x, i, 0x00); - } - - /* - * ARM arch at least disallows a udelay of - * more than 2ms... it gives a fake "__bad_udelay" - * reference at link-time. - * long delays in kernel code are pretty sucky anyway - * for now work around it using 5 x 2ms instead of 1 x 10ms - */ - - udelay(2000); - udelay(2000); - udelay(2000); - udelay(2000); - udelay(2000); - - /* Put in bypass mode */ - for (i = 0; i < MAX_TDM_CHAN; i++) { - if (mask & (0x00000001 << i)) - vpm_out(wc, x, i, 0x01); - } - - /* Enable bypass */ - for (i = 0; i < MAX_TDM_CHAN; i++) { - if (mask & (0x00000001 << i)) - vpm_out(wc, x, 0x78 + i, 0x01); - } - - } -} - -#ifdef UNUSED -static void -vpm_check(struct hfc_multi *hctmp) -{ - unsigned char gpi2; - - gpi2 = HFC_inb(hctmp, R_GPI_IN2); - - if ((gpi2 & 0x3) != 0x3) - printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); -} -#endif /* UNUSED */ - - -/* - * Interface to enable/disable the HW Echocan - * - * these functions are called within a spin_lock_irqsave on - * the channel instance lock, so we are not disturbed by irqs - * - * we can later easily change the interface to make other - * things configurable, for now we configure the taps - * - */ - -static void -vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) -{ - unsigned int timeslot; - unsigned int unit; - struct bchannel *bch = hc->chan[ch].bch; -#ifdef TXADJ - int txadj = -4; - struct sk_buff *skb; -#endif - if (hc->chan[ch].protocol != ISDN_P_B_RAW) - return; - - if (!bch) - return; - -#ifdef TXADJ - skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, - sizeof(int), &txadj, GFP_ATOMIC); - if (skb) - recv_Bchannel_skb(bch, skb); -#endif - - timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1; - unit = ch % 4; - - printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n", - taps, timeslot); - - vpm_out(hc, unit, timeslot, 0x7e); -} - -static void -vpm_echocan_off(struct hfc_multi *hc, int ch) -{ - unsigned int timeslot; - unsigned int unit; - struct bchannel *bch = hc->chan[ch].bch; -#ifdef TXADJ - int txadj = 0; - struct sk_buff *skb; -#endif - - if (hc->chan[ch].protocol != ISDN_P_B_RAW) - return; - - if (!bch) - return; - -#ifdef TXADJ - skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, - sizeof(int), &txadj, GFP_ATOMIC); - if (skb) - recv_Bchannel_skb(bch, skb); -#endif - - timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1; - unit = ch % 4; - - printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n", - timeslot); - /* FILLME */ - vpm_out(hc, unit, timeslot, 0x01); -} - - -/* - * Speech Design resync feature - * NOTE: This is called sometimes outside interrupt handler. - * We must lock irqsave, so no other interrupt (other card) will occur! - * Also multiple interrupts may nest, so must lock each access (lists, card)! - */ -static inline void -hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) -{ - struct hfc_multi *hc, *next, *pcmmaster = NULL; - void __iomem *plx_acc_32; - u_int pv; - u_long flags; - - spin_lock_irqsave(&HFClock, flags); - spin_lock(&plx_lock); /* must be locked inside other locks */ - - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n", - __func__, syncmaster); - - /* select new master */ - if (newmaster) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "using provided controller\n"); - } else { - list_for_each_entry_safe(hc, next, &HFClist, list) { - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - if (hc->syncronized) { - newmaster = hc; - break; - } - } - } - } - - /* Disable sync of all cards */ - list_for_each_entry_safe(hc, next, &HFClist, list) { - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - pv = readl(plx_acc_32); - pv &= ~PLX_SYNC_O_EN; - writel(pv, plx_acc_32); - if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { - pcmmaster = hc; - if (hc->ctype == HFC_TYPE_E1) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG - "Schedule SYNC_I\n"); - hc->e1_resync |= 1; /* get SYNC_I */ - } - } - } - } - - if (newmaster) { - hc = newmaster; - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "id=%d (0x%p) = synchronized with " - "interface.\n", hc->id, hc); - /* Enable new sync master */ - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - pv = readl(plx_acc_32); - pv |= PLX_SYNC_O_EN; - writel(pv, plx_acc_32); - /* switch to jatt PLL, if not disabled by RX_SYNC */ - if (hc->ctype == HFC_TYPE_E1 - && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "Schedule jatt PLL\n"); - hc->e1_resync |= 2; /* switch to jatt */ - } - } else { - if (pcmmaster) { - hc = pcmmaster; - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG - "id=%d (0x%p) = PCM master synchronized " - "with QUARTZ\n", hc->id, hc); - if (hc->ctype == HFC_TYPE_E1) { - /* Use the crystal clock for the PCM - master card */ - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG - "Schedule QUARTZ for HFC-E1\n"); - hc->e1_resync |= 4; /* switch quartz */ - } else { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG - "QUARTZ is automatically " - "enabled by HFC-%dS\n", hc->ctype); - } - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - pv = readl(plx_acc_32); - pv |= PLX_SYNC_O_EN; - writel(pv, plx_acc_32); - } else - if (!rm) - printk(KERN_ERR "%s no pcm master, this MUST " - "not happen!\n", __func__); - } - syncmaster = newmaster; - - spin_unlock(&plx_lock); - spin_unlock_irqrestore(&HFClock, flags); -} - -/* This must be called AND hc must be locked irqsave!!! */ -static inline void -plxsd_checksync(struct hfc_multi *hc, int rm) -{ - if (hc->syncronized) { - if (syncmaster == NULL) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "%s: GOT sync on card %d" - " (id=%d)\n", __func__, hc->id + 1, - hc->id); - hfcmulti_resync(hc, hc, rm); - } - } else { - if (syncmaster == hc) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "%s: LOST sync on card %d" - " (id=%d)\n", __func__, hc->id + 1, - hc->id); - hfcmulti_resync(hc, NULL, rm); - } - } -} - - -/* - * free hardware resources used by driver - */ -static void -release_io_hfcmulti(struct hfc_multi *hc) -{ - void __iomem *plx_acc_32; - u_int pv; - u_long plx_flags; - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: entered\n", __func__); - - /* soft reset also masks all interrupts */ - hc->hw.r_cirm |= V_SRES; - HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(1000); - hc->hw.r_cirm &= ~V_SRES; - HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(1000); /* instead of 'wait' that may cause locking */ - - /* release Speech Design card, if PLX was initialized */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "%s: release PLXSD card %d\n", - __func__, hc->id + 1); - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - writel(PLX_GPIOC_INIT, plx_acc_32); - pv = readl(plx_acc_32); - /* Termination off */ - pv &= ~PLX_TERM_ON; - /* Disconnect the PCM */ - pv |= PLX_SLAVE_EN_N; - pv &= ~PLX_MASTER_EN; - pv &= ~PLX_SYNC_O_EN; - /* Put the DSP in Reset */ - pv &= ~PLX_DSP_RES_N; - writel(pv, plx_acc_32); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n", - __func__, pv); - spin_unlock_irqrestore(&plx_lock, plx_flags); - } - - /* disable memory mapped ports / io ports */ - test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ - if (hc->pci_dev) - pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); - if (hc->pci_membase) - iounmap(hc->pci_membase); - if (hc->plx_membase) - iounmap(hc->plx_membase); - if (hc->pci_iobase) - release_region(hc->pci_iobase, 8); - if (hc->xhfc_membase) - iounmap((void *)hc->xhfc_membase); - - if (hc->pci_dev) { - pci_disable_device(hc->pci_dev); - pci_set_drvdata(hc->pci_dev, NULL); - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: done\n", __func__); -} - -/* - * function called to reset the HFC chip. A complete software reset of chip - * and fifos is done. All configuration of the chip is done. - */ - -static int -init_chip(struct hfc_multi *hc) -{ - u_long flags, val, val2 = 0, rev; - int i, err = 0; - u_char r_conf_en, rval; - void __iomem *plx_acc_32; - u_int pv; - u_long plx_flags, hfc_flags; - int plx_count; - struct hfc_multi *pos, *next, *plx_last_hc; - - spin_lock_irqsave(&hc->lock, flags); - /* reset all registers */ - memset(&hc->hw, 0, sizeof(struct hfcm_hw)); - - /* revision check */ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: entered\n", __func__); - val = HFC_inb(hc, R_CHIP_ID); - if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe && - (val >> 1) != 0x31) { - printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); - err = -EIO; - goto out; - } - rev = HFC_inb(hc, R_CHIP_RV); - printk(KERN_INFO - "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", - val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ? - " (old FIFO handling)" : ""); - if (hc->ctype != HFC_TYPE_XHFC && rev == 0) { - test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); - printk(KERN_WARNING - "HFC_multi: NOTE: Your chip is revision 0, " - "ask Cologne Chip for update. Newer chips " - "have a better FIFO handling. Old chips " - "still work but may have slightly lower " - "HDLC transmit performance.\n"); - } - if (rev > 1) { - printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't " - "consider chip revision = %ld. The chip / " - "bridge may not work.\n", rev); - } - - /* set s-ram size */ - hc->Flen = 0x10; - hc->Zmin = 0x80; - hc->Zlen = 384; - hc->DTMFbase = 0x1000; - if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: changing to 128K external RAM\n", - __func__); - hc->hw.r_ctrl |= V_EXT_RAM; - hc->hw.r_ram_sz = 1; - hc->Flen = 0x20; - hc->Zmin = 0xc0; - hc->Zlen = 1856; - hc->DTMFbase = 0x2000; - } - if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: changing to 512K external RAM\n", - __func__); - hc->hw.r_ctrl |= V_EXT_RAM; - hc->hw.r_ram_sz = 2; - hc->Flen = 0x20; - hc->Zmin = 0xc0; - hc->Zlen = 8000; - hc->DTMFbase = 0x2000; - } - if (hc->ctype == HFC_TYPE_XHFC) { - hc->Flen = 0x8; - hc->Zmin = 0x0; - hc->Zlen = 64; - hc->DTMFbase = 0x0; - } - hc->max_trans = poll << 1; - if (hc->max_trans > hc->Zlen) - hc->max_trans = hc->Zlen; - - /* Speech Design PLX bridge */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", - __func__, hc->id + 1); - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - writel(PLX_GPIOC_INIT, plx_acc_32); - pv = readl(plx_acc_32); - /* The first and the last cards are terminating the PCM bus */ - pv |= PLX_TERM_ON; /* hc is currently the last */ - /* Disconnect the PCM */ - pv |= PLX_SLAVE_EN_N; - pv &= ~PLX_MASTER_EN; - pv &= ~PLX_SYNC_O_EN; - /* Put the DSP in Reset */ - pv &= ~PLX_DSP_RES_N; - writel(pv, plx_acc_32); - spin_unlock_irqrestore(&plx_lock, plx_flags); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n", - __func__, pv); - /* - * If we are the 3rd PLXSD card or higher, we must turn - * termination of last PLXSD card off. - */ - spin_lock_irqsave(&HFClock, hfc_flags); - plx_count = 0; - plx_last_hc = NULL; - list_for_each_entry_safe(pos, next, &HFClist, list) { - if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) { - plx_count++; - if (pos != hc) - plx_last_hc = pos; - } - } - if (plx_count >= 3) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "%s: card %d is between, so " - "we disable termination\n", - __func__, plx_last_hc->id + 1); - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC; - pv = readl(plx_acc_32); - pv &= ~PLX_TERM_ON; - writel(pv, plx_acc_32); - spin_unlock_irqrestore(&plx_lock, plx_flags); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: term off: PLX_GPIO=%x\n", - __func__, pv); - } - spin_unlock_irqrestore(&HFClock, hfc_flags); - hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ - } - - if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) - hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ - - /* we only want the real Z2 read-pointer for revision > 0 */ - if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) - hc->hw.r_ram_sz |= V_FZ_MD; - - /* select pcm mode */ - if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: setting PCM into slave mode\n", - __func__); - } else - if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: setting PCM into master mode\n", - __func__); - hc->hw.r_pcm_md0 |= V_PCM_MD; - } else { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: performing PCM auto detect\n", - __func__); - } - - /* soft reset */ - HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); - if (hc->ctype == HFC_TYPE_XHFC) - HFC_outb(hc, 0x0C /* R_FIFO_THRES */, - 0x11 /* 16 Bytes TX/RX */); - else - HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); - HFC_outb(hc, R_FIFO_MD, 0); - if (hc->ctype == HFC_TYPE_XHFC) - hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES; - else - hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES - | V_RLD_EPR; - HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(100); - hc->hw.r_cirm = 0; - HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(100); - if (hc->ctype != HFC_TYPE_XHFC) - HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); - - /* Speech Design PLX bridge pcm and sync mode */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - pv = readl(plx_acc_32); - /* Connect PCM */ - if (hc->hw.r_pcm_md0 & V_PCM_MD) { - pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; - pv |= PLX_SYNC_O_EN; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n", - __func__, pv); - } else { - pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); - pv &= ~PLX_SYNC_O_EN; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n", - __func__, pv); - } - writel(pv, plx_acc_32); - spin_unlock_irqrestore(&plx_lock, plx_flags); - } - - /* PCM setup */ - HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90); - if (hc->slots == 32) - HFC_outb(hc, R_PCM_MD1, 0x00); - if (hc->slots == 64) - HFC_outb(hc, R_PCM_MD1, 0x10); - if (hc->slots == 128) - HFC_outb(hc, R_PCM_MD1, 0x20); - HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) - HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ - else if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) - HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */ - else - HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ - HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); - for (i = 0; i < 256; i++) { - HFC_outb_nodebug(hc, R_SLOT, i); - HFC_outb_nodebug(hc, A_SL_CFG, 0); - if (hc->ctype != HFC_TYPE_XHFC) - HFC_outb_nodebug(hc, A_CONF, 0); - hc->slot_owner[i] = -1; - } - - /* set clock speed */ - if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: setting double clock\n", __func__); - HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); - } - - if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) - HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */); - - /* B410P GPIO */ - if (test_bit(HFC_CHIP_B410P, &hc->chip)) { - printk(KERN_NOTICE "Setting GPIOs\n"); - HFC_outb(hc, R_GPIO_SEL, 0x30); - HFC_outb(hc, R_GPIO_EN1, 0x3); - udelay(1000); - printk(KERN_NOTICE "calling vpm_init\n"); - vpm_init(hc); - } - - /* check if R_F0_CNT counts (8 kHz frame count) */ - val = HFC_inb(hc, R_F0_CNTL); - val += HFC_inb(hc, R_F0_CNTH) << 8; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "HFC_multi F0_CNT %ld after reset\n", val); - spin_unlock_irqrestore(&hc->lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((HZ / 100) ? : 1); /* Timeout minimum 10ms */ - spin_lock_irqsave(&hc->lock, flags); - val2 = HFC_inb(hc, R_F0_CNTL); - val2 += HFC_inb(hc, R_F0_CNTH) << 8; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "HFC_multi F0_CNT %ld after 10 ms (1st try)\n", - val2); - if (val2 >= val + 8) { /* 1 ms */ - /* it counts, so we keep the pcm mode */ - if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) - printk(KERN_INFO "controller is PCM bus MASTER\n"); - else - if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) - printk(KERN_INFO "controller is PCM bus SLAVE\n"); - else { - test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); - printk(KERN_INFO "controller is PCM bus SLAVE " - "(auto detected)\n"); - } - } else { - /* does not count */ - if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { - controller_fail: - printk(KERN_ERR "HFC_multi ERROR, getting no 125us " - "pulse. Seems that controller fails.\n"); - err = -EIO; - goto out; - } - if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { - printk(KERN_INFO "controller is PCM bus SLAVE " - "(ignoring missing PCM clock)\n"); - } else { - /* only one pcm master */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip) - && plxsd_master) { - printk(KERN_ERR "HFC_multi ERROR, no clock " - "on another Speech Design card found. " - "Please be sure to connect PCM cable.\n"); - err = -EIO; - goto out; - } - /* retry with master clock */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - pv = readl(plx_acc_32); - pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; - pv |= PLX_SYNC_O_EN; - writel(pv, plx_acc_32); - spin_unlock_irqrestore(&plx_lock, plx_flags); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: master: " - "PLX_GPIO=%x\n", __func__, pv); - } - hc->hw.r_pcm_md0 |= V_PCM_MD; - HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); - spin_unlock_irqrestore(&hc->lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((HZ / 100) ?: 1); /* Timeout min. 10ms */ - spin_lock_irqsave(&hc->lock, flags); - val2 = HFC_inb(hc, R_F0_CNTL); - val2 += HFC_inb(hc, R_F0_CNTH) << 8; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "HFC_multi F0_CNT %ld after " - "10 ms (2nd try)\n", val2); - if (val2 >= val + 8) { /* 1 ms */ - test_and_set_bit(HFC_CHIP_PCM_MASTER, - &hc->chip); - printk(KERN_INFO "controller is PCM bus MASTER " - "(auto detected)\n"); - } else - goto controller_fail; - } - } - - /* Release the DSP Reset */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) - plxsd_master = 1; - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = hc->plx_membase + PLX_GPIOC; - pv = readl(plx_acc_32); - pv |= PLX_DSP_RES_N; - writel(pv, plx_acc_32); - spin_unlock_irqrestore(&plx_lock, plx_flags); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n", - __func__, pv); - } - - /* pcm id */ - if (hc->pcm) - printk(KERN_INFO "controller has given PCM BUS ID %d\n", - hc->pcm); - else { - if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) - || test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - PCM_cnt++; /* SD has proprietary bridging */ - } - hc->pcm = PCM_cnt; - printk(KERN_INFO "controller has PCM BUS ID %d " - "(auto selected)\n", hc->pcm); - } - - /* set up timer */ - HFC_outb(hc, R_TI_WD, poll_timer); - hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; - - /* set E1 state machine IRQ */ - if (hc->ctype == HFC_TYPE_E1) - hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; - - /* set DTMF detection */ - if (test_bit(HFC_CHIP_DTMF, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: enabling DTMF detection " - "for all B-channel\n", __func__); - hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP; - if (test_bit(HFC_CHIP_ULAW, &hc->chip)) - hc->hw.r_dtmf |= V_ULAW_SEL; - HFC_outb(hc, R_DTMF_N, 102 - 1); - hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK; - } - - /* conference engine */ - if (test_bit(HFC_CHIP_ULAW, &hc->chip)) - r_conf_en = V_CONF_EN | V_ULAW; - else - r_conf_en = V_CONF_EN; - if (hc->ctype != HFC_TYPE_XHFC) - HFC_outb(hc, R_CONF_EN, r_conf_en); - - /* setting leds */ - switch (hc->leds) { - case 1: /* HFC-E1 OEM */ - if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) - HFC_outb(hc, R_GPIO_SEL, 0x32); - else - HFC_outb(hc, R_GPIO_SEL, 0x30); - - HFC_outb(hc, R_GPIO_EN1, 0x0f); - HFC_outb(hc, R_GPIO_OUT1, 0x00); - - HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); - break; - - case 2: /* HFC-4S OEM */ - case 3: - HFC_outb(hc, R_GPIO_SEL, 0xf0); - HFC_outb(hc, R_GPIO_EN1, 0xff); - HFC_outb(hc, R_GPIO_OUT1, 0x00); - break; - } - - if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) { - hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */ - HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); - } - - /* set master clock */ - if (hc->masterclk >= 0) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: setting ST master clock " - "to port %d (0..%d)\n", - __func__, hc->masterclk, hc->ports - 1); - hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC); - HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); - } - - - - /* setting misc irq */ - HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", - hc->hw.r_irqmsk_misc); - - /* RAM access test */ - HFC_outb(hc, R_RAM_ADDR0, 0); - HFC_outb(hc, R_RAM_ADDR1, 0); - HFC_outb(hc, R_RAM_ADDR2, 0); - for (i = 0; i < 256; i++) { - HFC_outb_nodebug(hc, R_RAM_ADDR0, i); - HFC_outb_nodebug(hc, R_RAM_DATA, ((i * 3) & 0xff)); - } - for (i = 0; i < 256; i++) { - HFC_outb_nodebug(hc, R_RAM_ADDR0, i); - HFC_inb_nodebug(hc, R_RAM_DATA); - rval = HFC_inb_nodebug(hc, R_INT_DATA); - if (rval != ((i * 3) & 0xff)) { - printk(KERN_DEBUG - "addr:%x val:%x should:%x\n", i, rval, - (i * 3) & 0xff); - err++; - } - } - if (err) { - printk(KERN_DEBUG "aborting - %d RAM access errors\n", err); - err = -EIO; - goto out; - } - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: done\n", __func__); -out: - spin_unlock_irqrestore(&hc->lock, flags); - return err; -} - - -/* - * control the watchdog - */ -static void -hfcmulti_watchdog(struct hfc_multi *hc) -{ - hc->wdcount++; - - if (hc->wdcount > 10) { - hc->wdcount = 0; - hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ? - V_GPIO_OUT3 : V_GPIO_OUT2; - - /* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */ - HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); - HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte); - } -} - - - -/* - * output leds - */ -static void -hfcmulti_leds(struct hfc_multi *hc) -{ - unsigned long lled; - unsigned long leddw; - int i, state, active, leds; - struct dchannel *dch; - int led[4]; - - switch (hc->leds) { - case 1: /* HFC-E1 OEM */ - /* 2 red steady: LOS - * 1 red steady: L1 not active - * 2 green steady: L1 active - * 1st green flashing: activity on TX - * 2nd green flashing: activity on RX - */ - led[0] = 0; - led[1] = 0; - led[2] = 0; - led[3] = 0; - dch = hc->chan[hc->dnum[0]].dch; - if (dch) { - if (hc->chan[hc->dnum[0]].los) - led[1] = 1; - if (hc->e1_state != 1) { - led[0] = 1; - hc->flash[2] = 0; - hc->flash[3] = 0; - } else { - led[2] = 1; - led[3] = 1; - if (!hc->flash[2] && hc->activity_tx) - hc->flash[2] = poll; - if (!hc->flash[3] && hc->activity_rx) - hc->flash[3] = poll; - if (hc->flash[2] && hc->flash[2] < 1024) - led[2] = 0; - if (hc->flash[3] && hc->flash[3] < 1024) - led[3] = 0; - if (hc->flash[2] >= 2048) - hc->flash[2] = 0; - if (hc->flash[3] >= 2048) - hc->flash[3] = 0; - if (hc->flash[2]) - hc->flash[2] += poll; - if (hc->flash[3]) - hc->flash[3] += poll; - } - } - leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; - /* leds are inverted */ - if (leds != (int)hc->ledstate) { - HFC_outb_nodebug(hc, R_GPIO_OUT1, leds); - hc->ledstate = leds; - } - break; - - case 2: /* HFC-4S OEM */ - /* red steady: PH_DEACTIVATE - * green steady: PH_ACTIVATE - * green flashing: activity on TX - */ - for (i = 0; i < 4; i++) { - state = 0; - active = -1; - dch = hc->chan[(i << 2) | 2].dch; - if (dch) { - state = dch->state; - if (dch->dev.D.protocol == ISDN_P_NT_S0) - active = 3; - else - active = 7; - } - if (state) { - if (state == active) { - led[i] = 1; /* led green */ - hc->activity_tx |= hc->activity_rx; - if (!hc->flash[i] && - (hc->activity_tx & (1 << i))) - hc->flash[i] = poll; - if (hc->flash[i] && hc->flash[i] < 1024) - led[i] = 0; /* led off */ - if (hc->flash[i] >= 2048) - hc->flash[i] = 0; - if (hc->flash[i]) - hc->flash[i] += poll; - } else { - led[i] = 2; /* led red */ - hc->flash[i] = 0; - } - } else - led[i] = 0; /* led off */ - } - if (test_bit(HFC_CHIP_B410P, &hc->chip)) { - leds = 0; - for (i = 0; i < 4; i++) { - if (led[i] == 1) { - /*green*/ - leds |= (0x2 << (i * 2)); - } else if (led[i] == 2) { - /*red*/ - leds |= (0x1 << (i * 2)); - } - } - if (leds != (int)hc->ledstate) { - vpm_out(hc, 0, 0x1a8 + 3, leds); - hc->ledstate = leds; - } - } else { - leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) | - ((led[0] > 0) << 2) | ((led[2] > 0) << 3) | - ((led[3] & 1) << 4) | ((led[1] & 1) << 5) | - ((led[0] & 1) << 6) | ((led[2] & 1) << 7); - if (leds != (int)hc->ledstate) { - HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F); - HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4); - hc->ledstate = leds; - } - } - break; - - case 3: /* HFC 1S/2S Beronet */ - /* red steady: PH_DEACTIVATE - * green steady: PH_ACTIVATE - * green flashing: activity on TX - */ - for (i = 0; i < 2; i++) { - state = 0; - active = -1; - dch = hc->chan[(i << 2) | 2].dch; - if (dch) { - state = dch->state; - if (dch->dev.D.protocol == ISDN_P_NT_S0) - active = 3; - else - active = 7; - } - if (state) { - if (state == active) { - led[i] = 1; /* led green */ - hc->activity_tx |= hc->activity_rx; - if (!hc->flash[i] && - (hc->activity_tx & (1 << i))) - hc->flash[i] = poll; - if (hc->flash[i] < 1024) - led[i] = 0; /* led off */ - if (hc->flash[i] >= 2048) - hc->flash[i] = 0; - if (hc->flash[i]) - hc->flash[i] += poll; - } else { - led[i] = 2; /* led red */ - hc->flash[i] = 0; - } - } else - led[i] = 0; /* led off */ - } - leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2) - | ((led[1]&1) << 3); - if (leds != (int)hc->ledstate) { - HFC_outb_nodebug(hc, R_GPIO_EN1, - ((led[0] > 0) << 2) | ((led[1] > 0) << 3)); - HFC_outb_nodebug(hc, R_GPIO_OUT1, - ((led[0] & 1) << 2) | ((led[1] & 1) << 3)); - hc->ledstate = leds; - } - break; - case 8: /* HFC 8S+ Beronet */ - /* off: PH_DEACTIVATE - * steady: PH_ACTIVATE - * flashing: activity on TX - */ - lled = 0xff; /* leds off */ - for (i = 0; i < 8; i++) { - state = 0; - active = -1; - dch = hc->chan[(i << 2) | 2].dch; - if (dch) { - state = dch->state; - if (dch->dev.D.protocol == ISDN_P_NT_S0) - active = 3; - else - active = 7; - } - if (state) { - if (state == active) { - lled &= ~(1 << i); /* led on */ - hc->activity_tx |= hc->activity_rx; - if (!hc->flash[i] && - (hc->activity_tx & (1 << i))) - hc->flash[i] = poll; - if (hc->flash[i] < 1024) - lled |= 1 << i; /* led off */ - if (hc->flash[i] >= 2048) - hc->flash[i] = 0; - if (hc->flash[i]) - hc->flash[i] += poll; - } else - hc->flash[i] = 0; - } - } - leddw = lled << 24 | lled << 16 | lled << 8 | lled; - if (leddw != hc->ledstate) { - /* HFC_outb(hc, R_BRG_PCM_CFG, 1); - HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */ - /* was _io before */ - HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); - outw(0x4000, hc->pci_iobase + 4); - outl(leddw, hc->pci_iobase); - HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK); - hc->ledstate = leddw; - } - break; - } - hc->activity_tx = 0; - hc->activity_rx = 0; -} -/* - * read dtmf coefficients - */ - -static void -hfcmulti_dtmf(struct hfc_multi *hc) -{ - s32 *coeff; - u_int mantissa; - int co, ch; - struct bchannel *bch = NULL; - u8 exponent; - int dtmf = 0; - int addr; - u16 w_float; - struct sk_buff *skb; - struct mISDNhead *hh; - - if (debug & DEBUG_HFCMULTI_DTMF) - printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__); - for (ch = 0; ch <= 31; ch++) { - /* only process enabled B-channels */ - bch = hc->chan[ch].bch; - if (!bch) - continue; - if (!hc->created[hc->chan[ch].port]) - continue; - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - continue; - if (debug & DEBUG_HFCMULTI_DTMF) - printk(KERN_DEBUG "%s: dtmf channel %d:", - __func__, ch); - coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]); - dtmf = 1; - for (co = 0; co < 8; co++) { - /* read W(n-1) coefficient */ - addr = hc->DTMFbase + ((co << 7) | (ch << 2)); - HFC_outb_nodebug(hc, R_RAM_ADDR0, addr); - HFC_outb_nodebug(hc, R_RAM_ADDR1, addr >> 8); - HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr >> 16) - | V_ADDR_INC); - w_float = HFC_inb_nodebug(hc, R_RAM_DATA); - w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); - if (debug & DEBUG_HFCMULTI_DTMF) - printk(" %04x", w_float); - - /* decode float (see chip doc) */ - mantissa = w_float & 0x0fff; - if (w_float & 0x8000) - mantissa |= 0xfffff000; - exponent = (w_float >> 12) & 0x7; - if (exponent) { - mantissa ^= 0x1000; - mantissa <<= (exponent - 1); - } - - /* store coefficient */ - coeff[co << 1] = mantissa; - - /* read W(n) coefficient */ - w_float = HFC_inb_nodebug(hc, R_RAM_DATA); - w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); - if (debug & DEBUG_HFCMULTI_DTMF) - printk(" %04x", w_float); - - /* decode float (see chip doc) */ - mantissa = w_float & 0x0fff; - if (w_float & 0x8000) - mantissa |= 0xfffff000; - exponent = (w_float >> 12) & 0x7; - if (exponent) { - mantissa ^= 0x1000; - mantissa <<= (exponent - 1); - } - - /* store coefficient */ - coeff[(co << 1) | 1] = mantissa; - } - if (debug & DEBUG_HFCMULTI_DTMF) - printk(" DTMF ready %08x %08x %08x %08x " - "%08x %08x %08x %08x\n", - coeff[0], coeff[1], coeff[2], coeff[3], - coeff[4], coeff[5], coeff[6], coeff[7]); - hc->chan[ch].coeff_count++; - if (hc->chan[ch].coeff_count == 8) { - hc->chan[ch].coeff_count = 0; - skb = mI_alloc_skb(512, GFP_ATOMIC); - if (!skb) { - printk(KERN_DEBUG "%s: No memory for skb\n", - __func__); - continue; - } - hh = mISDN_HEAD_P(skb); - hh->prim = PH_CONTROL_IND; - hh->id = DTMF_HFC_COEF; - skb_put_data(skb, hc->chan[ch].coeff, 512); - recv_Bchannel_skb(bch, skb); - } - } - - /* restart DTMF processing */ - hc->dtmf = dtmf; - if (dtmf) - HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); -} - - -/* - * fill fifo as much as possible - */ - -static void -hfcmulti_tx(struct hfc_multi *hc, int ch) -{ - int i, ii, temp, tmp_len, len = 0; - int Zspace, z1, z2; /* must be int for calculation */ - int Fspace, f1, f2; - u_char *d; - int *txpending, slot_tx; - struct bchannel *bch; - struct dchannel *dch; - struct sk_buff **sp = NULL; - int *idxp; - - bch = hc->chan[ch].bch; - dch = hc->chan[ch].dch; - if ((!dch) && (!bch)) - return; - - txpending = &hc->chan[ch].txpending; - slot_tx = hc->chan[ch].slot_tx; - if (dch) { - if (!test_bit(FLG_ACTIVE, &dch->Flags)) - return; - sp = &dch->tx_skb; - idxp = &dch->tx_idx; - } else { - if (!test_bit(FLG_ACTIVE, &bch->Flags)) - return; - sp = &bch->tx_skb; - idxp = &bch->tx_idx; - } - if (*sp) - len = (*sp)->len; - - if ((!len) && *txpending != 1) - return; /* no data */ - - if (test_bit(HFC_CHIP_B410P, &hc->chip) && - (hc->chan[ch].protocol == ISDN_P_B_RAW) && - (hc->chan[ch].slot_rx < 0) && - (hc->chan[ch].slot_tx < 0)) - HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1)); - else - HFC_outb_nodebug(hc, R_FIFO, ch << 1); - HFC_wait_nodebug(hc); - - if (*txpending == 2) { - /* reset fifo */ - HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait_nodebug(hc); - HFC_outb(hc, A_SUBCH_CFG, 0); - *txpending = 1; - } -next_frame: - if (dch || test_bit(FLG_HDLC, &bch->Flags)) { - f1 = HFC_inb_nodebug(hc, A_F1); - f2 = HFC_inb_nodebug(hc, A_F2); - while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG - "%s(card %d): reread f2 because %d!=%d\n", - __func__, hc->id + 1, temp, f2); - f2 = temp; /* repeat until F2 is equal */ - } - Fspace = f2 - f1 - 1; - if (Fspace < 0) - Fspace += hc->Flen; - /* - * Old FIFO handling doesn't give us the current Z2 read - * pointer, so we cannot send the next frame before the fifo - * is empty. It makes no difference except for a slightly - * lower performance. - */ - if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) { - if (f1 != f2) - Fspace = 0; - else - Fspace = 1; - } - /* one frame only for ST D-channels, to allow resending */ - if (hc->ctype != HFC_TYPE_E1 && dch) { - if (f1 != f2) - Fspace = 0; - } - /* F-counter full condition */ - if (Fspace == 0) - return; - } - z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; - z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; - while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG "%s(card %d): reread z2 because " - "%d!=%d\n", __func__, hc->id + 1, temp, z2); - z2 = temp; /* repeat unti Z2 is equal */ - } - hc->chan[ch].Zfill = z1 - z2; - if (hc->chan[ch].Zfill < 0) - hc->chan[ch].Zfill += hc->Zlen; - Zspace = z2 - z1; - if (Zspace <= 0) - Zspace += hc->Zlen; - Zspace -= 4; /* keep not too full, so pointers will not overrun */ - /* fill transparent data only to maximum transparent load (minus 4) */ - if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) - Zspace = Zspace - hc->Zlen + hc->max_trans; - if (Zspace <= 0) /* no space of 4 bytes */ - return; - - /* if no data */ - if (!len) { - if (z1 == z2) { /* empty */ - /* if done with FIFO audio data during PCM connection */ - if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && - *txpending && slot_tx >= 0) { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG - "%s: reconnecting PCM due to no " - "more FIFO data: channel %d " - "slot_tx %d\n", - __func__, ch, slot_tx); - /* connect slot */ - if (hc->ctype == HFC_TYPE_XHFC) - HFC_outb(hc, A_CON_HDLC, 0xc0 - | 0x07 << 2 | V_HDLC_TRP | V_IFF); - /* Enable FIFO, no interrupt */ - else - HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | - V_HDLC_TRP | V_IFF); - HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1); - HFC_wait_nodebug(hc); - if (hc->ctype == HFC_TYPE_XHFC) - HFC_outb(hc, A_CON_HDLC, 0xc0 - | 0x07 << 2 | V_HDLC_TRP | V_IFF); - /* Enable FIFO, no interrupt */ - else - HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | - V_HDLC_TRP | V_IFF); - HFC_outb_nodebug(hc, R_FIFO, ch << 1); - HFC_wait_nodebug(hc); - } - *txpending = 0; - } - return; /* no data */ - } - - /* "fill fifo if empty" feature */ - if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags) - && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) { - if (debug & DEBUG_HFCMULTI_FILL) - printk(KERN_DEBUG "%s: buffer empty, so we have " - "underrun\n", __func__); - /* fill buffer, to prevent future underrun */ - hc->write_fifo(hc, hc->silence_data, poll >> 1); - Zspace -= (poll >> 1); - } - - /* if audio data and connected slot */ - if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) - && slot_tx >= 0) { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: disconnecting PCM due to " - "FIFO data: channel %d slot_tx %d\n", - __func__, ch, slot_tx); - /* disconnect slot */ - if (hc->ctype == HFC_TYPE_XHFC) - HFC_outb(hc, A_CON_HDLC, 0x80 - | 0x07 << 2 | V_HDLC_TRP | V_IFF); - /* Enable FIFO, no interrupt */ - else - HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | - V_HDLC_TRP | V_IFF); - HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1); - HFC_wait_nodebug(hc); - if (hc->ctype == HFC_TYPE_XHFC) - HFC_outb(hc, A_CON_HDLC, 0x80 - | 0x07 << 2 | V_HDLC_TRP | V_IFF); - /* Enable FIFO, no interrupt */ - else - HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | - V_HDLC_TRP | V_IFF); - HFC_outb_nodebug(hc, R_FIFO, ch << 1); - HFC_wait_nodebug(hc); - } - *txpending = 1; - - /* show activity */ - if (dch) - hc->activity_tx |= 1 << hc->chan[ch].port; - - /* fill fifo to what we have left */ - ii = len; - if (dch || test_bit(FLG_HDLC, &bch->Flags)) - temp = 1; - else - temp = 0; - i = *idxp; - d = (*sp)->data + i; - if (ii - i > Zspace) - ii = Zspace + i; - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " - "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", - __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, - temp ? "HDLC" : "TRANS"); - - /* Have to prep the audio data */ - hc->write_fifo(hc, d, ii - i); - hc->chan[ch].Zfill += ii - i; - *idxp = ii; - - /* if not all data has been written */ - if (ii != len) { - /* NOTE: fifo is started by the calling function */ - return; - } - - /* if all data has been written, terminate frame */ - if (dch || test_bit(FLG_HDLC, &bch->Flags)) { - /* increment f-counter */ - HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); - HFC_wait_nodebug(hc); - } - - tmp_len = (*sp)->len; - dev_kfree_skb(*sp); - /* check for next frame */ - if (bch && get_next_bframe(bch)) { - len = tmp_len; - goto next_frame; - } - if (dch && get_next_dframe(dch)) { - len = tmp_len; - goto next_frame; - } - - /* - * now we have no more data, so in case of transparent, - * we set the last byte in fifo to 'silence' in case we will get - * no more data at all. this prevents sending an undefined value. - */ - if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); -} - - -/* NOTE: only called if E1 card is in active state */ -static void -hfcmulti_rx(struct hfc_multi *hc, int ch) -{ - int temp; - int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ - int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ - int again = 0; - struct bchannel *bch; - struct dchannel *dch = NULL; - struct sk_buff *skb, **sp = NULL; - int maxlen; - - bch = hc->chan[ch].bch; - if (bch) { - if (!test_bit(FLG_ACTIVE, &bch->Flags)) - return; - } else if (hc->chan[ch].dch) { - dch = hc->chan[ch].dch; - if (!test_bit(FLG_ACTIVE, &dch->Flags)) - return; - } else { - return; - } -next_frame: - /* on first AND before getting next valid frame, R_FIFO must be written - to. */ - if (test_bit(HFC_CHIP_B410P, &hc->chip) && - (hc->chan[ch].protocol == ISDN_P_B_RAW) && - (hc->chan[ch].slot_rx < 0) && - (hc->chan[ch].slot_tx < 0)) - HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1) | 1); - else - HFC_outb_nodebug(hc, R_FIFO, (ch << 1) | 1); - HFC_wait_nodebug(hc); - - /* ignore if rx is off BUT change fifo (above) to start pending TX */ - if (hc->chan[ch].rx_off) { - if (bch) - bch->dropcnt += poll; /* not exact but fair enough */ - return; - } - - if (dch || test_bit(FLG_HDLC, &bch->Flags)) { - f1 = HFC_inb_nodebug(hc, A_F1); - while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG - "%s(card %d): reread f1 because %d!=%d\n", - __func__, hc->id + 1, temp, f1); - f1 = temp; /* repeat until F1 is equal */ - } - f2 = HFC_inb_nodebug(hc, A_F2); - } - z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; - while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG "%s(card %d): reread z2 because " - "%d!=%d\n", __func__, hc->id + 1, temp, z2); - z1 = temp; /* repeat until Z1 is equal */ - } - z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; - Zsize = z1 - z2; - if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2) - /* complete hdlc frame */ - Zsize++; - if (Zsize < 0) - Zsize += hc->Zlen; - /* if buffer is empty */ - if (Zsize <= 0) - return; - - if (bch) { - maxlen = bchannel_get_rxbuf(bch, Zsize); - if (maxlen < 0) { - pr_warn("card%d.B%d: No bufferspace for %d bytes\n", - hc->id + 1, bch->nr, Zsize); - return; - } - sp = &bch->rx_skb; - maxlen = bch->maxlen; - } else { /* Dchannel */ - sp = &dch->rx_skb; - maxlen = dch->maxlen + 3; - if (*sp == NULL) { - *sp = mI_alloc_skb(maxlen, GFP_ATOMIC); - if (*sp == NULL) { - pr_warn("card%d: No mem for dch rx_skb\n", - hc->id + 1); - return; - } - } - } - /* show activity */ - if (dch) - hc->activity_rx |= 1 << hc->chan[ch].port; - - /* empty fifo with what we have */ - if (dch || test_bit(FLG_HDLC, &bch->Flags)) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d " - "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) " - "got=%d (again %d)\n", __func__, hc->id + 1, ch, - Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", - f1, f2, Zsize + (*sp)->len, again); - /* HDLC */ - if ((Zsize + (*sp)->len) > maxlen) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG - "%s(card %d): hdlc-frame too large.\n", - __func__, hc->id + 1); - skb_trim(*sp, 0); - HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait_nodebug(hc); - return; - } - - hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); - - if (f1 != f2) { - /* increment Z2,F2-counter */ - HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); - HFC_wait_nodebug(hc); - /* check size */ - if ((*sp)->len < 4) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG - "%s(card %d): Frame below minimum " - "size\n", __func__, hc->id + 1); - skb_trim(*sp, 0); - goto next_frame; - } - /* there is at least one complete frame, check crc */ - if ((*sp)->data[(*sp)->len - 1]) { - if (debug & DEBUG_HFCMULTI_CRC) - printk(KERN_DEBUG - "%s: CRC-error\n", __func__); - skb_trim(*sp, 0); - goto next_frame; - } - skb_trim(*sp, (*sp)->len - 3); - if ((*sp)->len < MISDN_COPY_SIZE) { - skb = *sp; - *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); - if (*sp) { - skb_put_data(*sp, skb->data, skb->len); - skb_trim(skb, 0); - } else { - printk(KERN_DEBUG "%s: No mem\n", - __func__); - *sp = skb; - skb = NULL; - } - } else { - skb = NULL; - } - if (debug & DEBUG_HFCMULTI_FIFO) { - printk(KERN_DEBUG "%s(card %d):", - __func__, hc->id + 1); - temp = 0; - while (temp < (*sp)->len) - printk(" %02x", (*sp)->data[temp++]); - printk("\n"); - } - if (dch) - recv_Dchannel(dch); - else - recv_Bchannel(bch, MISDN_ID_ANY, false); - *sp = skb; - again++; - goto next_frame; - } - /* there is an incomplete frame */ - } else { - /* transparent */ - hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG - "%s(card %d): fifo(%d) reading %d bytes " - "(z1=%04x, z2=%04x) TRANS\n", - __func__, hc->id + 1, ch, Zsize, z1, z2); - /* only bch is transparent */ - recv_Bchannel(bch, hc->chan[ch].Zfill, false); - } -} - - -/* - * Interrupt handler - */ -static void -signal_state_up(struct dchannel *dch, int info, char *msg) -{ - struct sk_buff *skb; - int id, data = info; - - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: %s\n", __func__, msg); - - id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */ - - skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data, - GFP_ATOMIC); - if (!skb) - return; - recv_Dchannel_skb(dch, skb); -} - -static inline void -handle_timer_irq(struct hfc_multi *hc) -{ - int ch, temp; - struct dchannel *dch; - u_long flags; - - /* process queued resync jobs */ - if (hc->e1_resync) { - /* lock, so e1_resync gets not changed */ - spin_lock_irqsave(&HFClock, flags); - if (hc->e1_resync & 1) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "Enable SYNC_I\n"); - HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC); - /* disable JATT, if RX_SYNC is set */ - if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) - HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); - } - if (hc->e1_resync & 2) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "Enable jatt PLL\n"); - HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); - } - if (hc->e1_resync & 4) { - if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG - "Enable QUARTZ for HFC-E1\n"); - /* set jatt to quartz */ - HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC - | V_JATT_OFF); - /* switch to JATT, in case it is not already */ - HFC_outb(hc, R_SYNC_OUT, 0); - } - hc->e1_resync = 0; - spin_unlock_irqrestore(&HFClock, flags); - } - - if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) - for (ch = 0; ch <= 31; ch++) { - if (hc->created[hc->chan[ch].port]) { - hfcmulti_tx(hc, ch); - /* fifo is started when switching to rx-fifo */ - hfcmulti_rx(hc, ch); - if (hc->chan[ch].dch && - hc->chan[ch].nt_timer > -1) { - dch = hc->chan[ch].dch; - if (!(--hc->chan[ch].nt_timer)) { - schedule_event(dch, - FLG_PHCHANGE); - if (debug & - DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG - "%s: nt_timer at " - "state %x\n", - __func__, - dch->state); - } - } - } - } - if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { - dch = hc->chan[hc->dnum[0]].dch; - /* LOS */ - temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; - hc->chan[hc->dnum[0]].los = temp; - if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { - if (!temp && hc->chan[hc->dnum[0]].los) - signal_state_up(dch, L1_SIGNAL_LOS_ON, - "LOS detected"); - if (temp && !hc->chan[hc->dnum[0]].los) - signal_state_up(dch, L1_SIGNAL_LOS_OFF, - "LOS gone"); - } - if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) { - /* AIS */ - temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; - if (!temp && hc->chan[hc->dnum[0]].ais) - signal_state_up(dch, L1_SIGNAL_AIS_ON, - "AIS detected"); - if (temp && !hc->chan[hc->dnum[0]].ais) - signal_state_up(dch, L1_SIGNAL_AIS_OFF, - "AIS gone"); - hc->chan[hc->dnum[0]].ais = temp; - } - if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) { - /* SLIP */ - temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; - if (!temp && hc->chan[hc->dnum[0]].slip_rx) - signal_state_up(dch, L1_SIGNAL_SLIP_RX, - " bit SLIP detected RX"); - hc->chan[hc->dnum[0]].slip_rx = temp; - temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; - if (!temp && hc->chan[hc->dnum[0]].slip_tx) - signal_state_up(dch, L1_SIGNAL_SLIP_TX, - " bit SLIP detected TX"); - hc->chan[hc->dnum[0]].slip_tx = temp; - } - if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) { - /* RDI */ - temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; - if (!temp && hc->chan[hc->dnum[0]].rdi) - signal_state_up(dch, L1_SIGNAL_RDI_ON, - "RDI detected"); - if (temp && !hc->chan[hc->dnum[0]].rdi) - signal_state_up(dch, L1_SIGNAL_RDI_OFF, - "RDI gone"); - hc->chan[hc->dnum[0]].rdi = temp; - } - temp = HFC_inb_nodebug(hc, R_JATT_DIR); - switch (hc->chan[hc->dnum[0]].sync) { - case 0: - if ((temp & 0x60) == 0x60) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG - "%s: (id=%d) E1 now " - "in clock sync\n", - __func__, hc->id); - HFC_outb(hc, R_RX_OFF, - hc->chan[hc->dnum[0]].jitter | V_RX_INIT); - HFC_outb(hc, R_TX_OFF, - hc->chan[hc->dnum[0]].jitter | V_RX_INIT); - hc->chan[hc->dnum[0]].sync = 1; - goto check_framesync; - } - break; - case 1: - if ((temp & 0x60) != 0x60) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG - "%s: (id=%d) E1 " - "lost clock sync\n", - __func__, hc->id); - hc->chan[hc->dnum[0]].sync = 0; - break; - } - check_framesync: - temp = HFC_inb_nodebug(hc, R_SYNC_STA); - if (temp == 0x27) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG - "%s: (id=%d) E1 " - "now in frame sync\n", - __func__, hc->id); - hc->chan[hc->dnum[0]].sync = 2; - } - break; - case 2: - if ((temp & 0x60) != 0x60) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG - "%s: (id=%d) E1 lost " - "clock & frame sync\n", - __func__, hc->id); - hc->chan[hc->dnum[0]].sync = 0; - break; - } - temp = HFC_inb_nodebug(hc, R_SYNC_STA); - if (temp != 0x27) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG - "%s: (id=%d) E1 " - "lost frame sync\n", - __func__, hc->id); - hc->chan[hc->dnum[0]].sync = 1; - } - break; - } - } - - if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) - hfcmulti_watchdog(hc); - - if (hc->leds) - hfcmulti_leds(hc); -} - -static void -ph_state_irq(struct hfc_multi *hc, u_char r_irq_statech) -{ - struct dchannel *dch; - int ch; - int active; - u_char st_status, temp; - - /* state machine */ - for (ch = 0; ch <= 31; ch++) { - if (hc->chan[ch].dch) { - dch = hc->chan[ch].dch; - if (r_irq_statech & 1) { - HFC_outb_nodebug(hc, R_ST_SEL, - hc->chan[ch].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - /* undocumented: status changes during read */ - st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE); - while (st_status != (temp = - HFC_inb_nodebug(hc, A_ST_RD_STATE))) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: reread " - "STATE because %d!=%d\n", - __func__, temp, - st_status); - st_status = temp; /* repeat */ - } - - /* Speech Design TE-sync indication */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && - dch->dev.D.protocol == ISDN_P_TE_S0) { - if (st_status & V_FR_SYNC_ST) - hc->syncronized |= - (1 << hc->chan[ch].port); - else - hc->syncronized &= - ~(1 << hc->chan[ch].port); - } - dch->state = st_status & 0x0f; - if (dch->dev.D.protocol == ISDN_P_NT_S0) - active = 3; - else - active = 7; - if (dch->state == active) { - HFC_outb_nodebug(hc, R_FIFO, - (ch << 1) | 1); - HFC_wait_nodebug(hc); - HFC_outb_nodebug(hc, - R_INC_RES_FIFO, V_RES_F); - HFC_wait_nodebug(hc); - dch->tx_idx = 0; - } - schedule_event(dch, FLG_PHCHANGE); - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG - "%s: S/T newstate %x port %d\n", - __func__, dch->state, - hc->chan[ch].port); - } - r_irq_statech >>= 1; - } - } - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) - plxsd_checksync(hc, 0); -} - -static void -fifo_irq(struct hfc_multi *hc, int block) -{ - int ch, j; - struct dchannel *dch; - struct bchannel *bch; - u_char r_irq_fifo_bl; - - r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block); - j = 0; - while (j < 8) { - ch = (block << 2) + (j >> 1); - dch = hc->chan[ch].dch; - bch = hc->chan[ch].bch; - if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) { - j += 2; - continue; - } - if (dch && (r_irq_fifo_bl & (1 << j)) && - test_bit(FLG_ACTIVE, &dch->Flags)) { - hfcmulti_tx(hc, ch); - /* start fifo */ - HFC_outb_nodebug(hc, R_FIFO, 0); - HFC_wait_nodebug(hc); - } - if (bch && (r_irq_fifo_bl & (1 << j)) && - test_bit(FLG_ACTIVE, &bch->Flags)) { - hfcmulti_tx(hc, ch); - /* start fifo */ - HFC_outb_nodebug(hc, R_FIFO, 0); - HFC_wait_nodebug(hc); - } - j++; - if (dch && (r_irq_fifo_bl & (1 << j)) && - test_bit(FLG_ACTIVE, &dch->Flags)) { - hfcmulti_rx(hc, ch); - } - if (bch && (r_irq_fifo_bl & (1 << j)) && - test_bit(FLG_ACTIVE, &bch->Flags)) { - hfcmulti_rx(hc, ch); - } - j++; - } -} - -#ifdef IRQ_DEBUG -int irqsem; -#endif -static irqreturn_t -hfcmulti_interrupt(int intno, void *dev_id) -{ -#ifdef IRQCOUNT_DEBUG - static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, - iq5 = 0, iq6 = 0, iqcnt = 0; -#endif - struct hfc_multi *hc = dev_id; - struct dchannel *dch; - u_char r_irq_statech, status, r_irq_misc, r_irq_oview; - int i; - void __iomem *plx_acc; - u_short wval; - u_char e1_syncsta, temp, temp2; - u_long flags; - - if (!hc) { - printk(KERN_ERR "HFC-multi: Spurious interrupt!\n"); - return IRQ_NONE; - } - - spin_lock(&hc->lock); - -#ifdef IRQ_DEBUG - if (irqsem) - printk(KERN_ERR "irq for card %d during irq from " - "card %d, this is no bug.\n", hc->id + 1, irqsem); - irqsem = hc->id + 1; -#endif -#ifdef CONFIG_MISDN_HFCMULTI_8xx - if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk) - goto irq_notforus; -#endif - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - spin_lock_irqsave(&plx_lock, flags); - plx_acc = hc->plx_membase + PLX_INTCSR; - wval = readw(plx_acc); - spin_unlock_irqrestore(&plx_lock, flags); - if (!(wval & PLX_INTCSR_LINTI1_STATUS)) - goto irq_notforus; - } - - status = HFC_inb_nodebug(hc, R_STATUS); - r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH); -#ifdef IRQCOUNT_DEBUG - if (r_irq_statech) - iq1++; - if (status & V_DTMF_STA) - iq2++; - if (status & V_LOST_STA) - iq3++; - if (status & V_EXT_IRQSTA) - iq4++; - if (status & V_MISC_IRQSTA) - iq5++; - if (status & V_FR_IRQSTA) - iq6++; - if (iqcnt++ > 5000) { - printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n", - iq1, iq2, iq3, iq4, iq5, iq6); - iqcnt = 0; - } -#endif - - if (!r_irq_statech && - !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | - V_MISC_IRQSTA | V_FR_IRQSTA))) { - /* irq is not for us */ - goto irq_notforus; - } - hc->irqcnt++; - if (r_irq_statech) { - if (hc->ctype != HFC_TYPE_E1) - ph_state_irq(hc, r_irq_statech); - } - if (status & V_LOST_STA) { - /* LOST IRQ */ - HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */ - } - if (status & V_MISC_IRQSTA) { - /* misc IRQ */ - r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); - r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ - if (r_irq_misc & V_STA_IRQ) { - if (hc->ctype == HFC_TYPE_E1) { - /* state machine */ - dch = hc->chan[hc->dnum[0]].dch; - e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); - if (test_bit(HFC_CHIP_PLXSD, &hc->chip) - && hc->e1_getclock) { - if (e1_syncsta & V_FR_SYNC_E1) - hc->syncronized = 1; - else - hc->syncronized = 0; - } - /* undocumented: status changes during read */ - temp = HFC_inb_nodebug(hc, R_E1_RD_STA); - while (temp != (temp2 = - HFC_inb_nodebug(hc, R_E1_RD_STA))) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: reread " - "STATE because %d!=%d\n", - __func__, temp, temp2); - temp = temp2; /* repeat */ - } - /* broadcast state change to all fragments */ - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG - "%s: E1 (id=%d) newstate %x\n", - __func__, hc->id, temp & 0x7); - for (i = 0; i < hc->ports; i++) { - dch = hc->chan[hc->dnum[i]].dch; - dch->state = temp & 0x7; - schedule_event(dch, FLG_PHCHANGE); - } - - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) - plxsd_checksync(hc, 0); - } - } - if (r_irq_misc & V_TI_IRQ) { - if (hc->iclock_on) - mISDN_clock_update(hc->iclock, poll, NULL); - handle_timer_irq(hc); - } - - if (r_irq_misc & V_DTMF_IRQ) - hfcmulti_dtmf(hc); - - if (r_irq_misc & V_IRQ_PROC) { - static int irq_proc_cnt; - if (!irq_proc_cnt++) - printk(KERN_DEBUG "%s: got V_IRQ_PROC -" - " this should not happen\n", __func__); - } - - } - if (status & V_FR_IRQSTA) { - /* FIFO IRQ */ - r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW); - for (i = 0; i < 8; i++) { - if (r_irq_oview & (1 << i)) - fifo_irq(hc, i); - } - } - -#ifdef IRQ_DEBUG - irqsem = 0; -#endif - spin_unlock(&hc->lock); - return IRQ_HANDLED; - -irq_notforus: -#ifdef IRQ_DEBUG - irqsem = 0; -#endif - spin_unlock(&hc->lock); - return IRQ_NONE; -} - - -/* - * timer callback for D-chan busy resolution. Currently no function - */ - -static void -hfcmulti_dbusy_timer(struct timer_list *t) -{ -} - - -/* - * activate/deactivate hardware for selected channels and mode - * - * configure B-channel with the given protocol - * ch eqals to the HFC-channel (0-31) - * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 - * for S/T, 1-31 for E1) - * the hdlc interrupts will be set/unset - */ -static int -mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, - int bank_tx, int slot_rx, int bank_rx) -{ - int flow_tx = 0, flow_rx = 0, routing = 0; - int oslot_tx, oslot_rx; - int conf; - - if (ch < 0 || ch > 31) - return -EINVAL; - oslot_tx = hc->chan[ch].slot_tx; - oslot_rx = hc->chan[ch].slot_rx; - conf = hc->chan[ch].conf; - - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG - "%s: card %d channel %d protocol %x slot old=%d new=%d " - "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n", - __func__, hc->id, ch, protocol, oslot_tx, slot_tx, - bank_tx, oslot_rx, slot_rx, bank_rx); - - if (oslot_tx >= 0 && slot_tx != oslot_tx) { - /* remove from slot */ - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: remove from slot %d (TX)\n", - __func__, oslot_tx); - if (hc->slot_owner[oslot_tx << 1] == ch) { - HFC_outb(hc, R_SLOT, oslot_tx << 1); - HFC_outb(hc, A_SL_CFG, 0); - if (hc->ctype != HFC_TYPE_XHFC) - HFC_outb(hc, A_CONF, 0); - hc->slot_owner[oslot_tx << 1] = -1; - } else { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG - "%s: we are not owner of this tx slot " - "anymore, channel %d is.\n", - __func__, hc->slot_owner[oslot_tx << 1]); - } - } - - if (oslot_rx >= 0 && slot_rx != oslot_rx) { - /* remove from slot */ - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG - "%s: remove from slot %d (RX)\n", - __func__, oslot_rx); - if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) { - HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR); - HFC_outb(hc, A_SL_CFG, 0); - hc->slot_owner[(oslot_rx << 1) | 1] = -1; - } else { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG - "%s: we are not owner of this rx slot " - "anymore, channel %d is.\n", - __func__, - hc->slot_owner[(oslot_rx << 1) | 1]); - } - } - - if (slot_tx < 0) { - flow_tx = 0x80; /* FIFO->ST */ - /* disable pcm slot */ - hc->chan[ch].slot_tx = -1; - hc->chan[ch].bank_tx = 0; - } else { - /* set pcm slot */ - if (hc->chan[ch].txpending) - flow_tx = 0x80; /* FIFO->ST */ - else - flow_tx = 0xc0; /* PCM->ST */ - /* put on slot */ - routing = bank_tx ? 0xc0 : 0x80; - if (conf >= 0 || bank_tx > 1) - routing = 0x40; /* loop */ - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: put channel %d to slot %d bank" - " %d flow %02x routing %02x conf %d (TX)\n", - __func__, ch, slot_tx, bank_tx, - flow_tx, routing, conf); - HFC_outb(hc, R_SLOT, slot_tx << 1); - HFC_outb(hc, A_SL_CFG, (ch << 1) | routing); - if (hc->ctype != HFC_TYPE_XHFC) - HFC_outb(hc, A_CONF, - (conf < 0) ? 0 : (conf | V_CONF_SL)); - hc->slot_owner[slot_tx << 1] = ch; - hc->chan[ch].slot_tx = slot_tx; - hc->chan[ch].bank_tx = bank_tx; - } - if (slot_rx < 0) { - /* disable pcm slot */ - flow_rx = 0x80; /* ST->FIFO */ - hc->chan[ch].slot_rx = -1; - hc->chan[ch].bank_rx = 0; - } else { - /* set pcm slot */ - if (hc->chan[ch].txpending) - flow_rx = 0x80; /* ST->FIFO */ - else - flow_rx = 0xc0; /* ST->(FIFO,PCM) */ - /* put on slot */ - routing = bank_rx ? 0x80 : 0xc0; /* reversed */ - if (conf >= 0 || bank_rx > 1) - routing = 0x40; /* loop */ - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: put channel %d to slot %d bank" - " %d flow %02x routing %02x conf %d (RX)\n", - __func__, ch, slot_rx, bank_rx, - flow_rx, routing, conf); - HFC_outb(hc, R_SLOT, (slot_rx << 1) | V_SL_DIR); - HFC_outb(hc, A_SL_CFG, (ch << 1) | V_CH_DIR | routing); - hc->slot_owner[(slot_rx << 1) | 1] = ch; - hc->chan[ch].slot_rx = slot_rx; - hc->chan[ch].bank_rx = bank_rx; - } - - switch (protocol) { - case (ISDN_P_NONE): - /* disable TX fifo */ - HFC_outb(hc, R_FIFO, ch << 1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - /* disable RX fifo */ - HFC_outb(hc, R_FIFO, (ch << 1) | 1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) { - hc->hw.a_st_ctrl0[hc->chan[ch].port] &= - ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN; - HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_CTRL0, - hc->hw.a_st_ctrl0[hc->chan[ch].port]); - } - if (hc->chan[ch].bch) { - test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); - test_and_clear_bit(FLG_TRANSPARENT, - &hc->chan[ch].bch->Flags); - } - break; - case (ISDN_P_B_RAW): /* B-channel */ - - if (test_bit(HFC_CHIP_B410P, &hc->chip) && - (hc->chan[ch].slot_rx < 0) && - (hc->chan[ch].slot_tx < 0)) { - - printk(KERN_DEBUG - "Setting B-channel %d to echo cancelable " - "state on PCM slot %d\n", ch, - ((ch / 4) * 8) + ((ch % 4) * 4) + 1); - printk(KERN_DEBUG - "Enabling pass through for channel\n"); - vpm_out(hc, ch, ((ch / 4) * 8) + - ((ch % 4) * 4) + 1, 0x01); - /* rx path */ - /* S/T -> PCM */ - HFC_outb(hc, R_FIFO, (ch << 1)); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); - HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + - ((ch % 4) * 4) + 1) << 1); - HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1)); - - /* PCM -> FIFO */ - HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - if (hc->chan[ch].protocol != protocol) { - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - } - HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + - ((ch % 4) * 4) + 1) << 1) | 1); - HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); - - /* tx path */ - /* PCM -> S/T */ - HFC_outb(hc, R_FIFO, (ch << 1) | 1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); - HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + - ((ch % 4) * 4)) << 1) | 1); - HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1); - - /* FIFO -> PCM */ - HFC_outb(hc, R_FIFO, 0x20 | (ch << 1)); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - if (hc->chan[ch].protocol != protocol) { - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - } - /* tx silence */ - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); - HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + - ((ch % 4) * 4)) << 1); - HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); - } else { - /* enable TX fifo */ - HFC_outb(hc, R_FIFO, ch << 1); - HFC_wait(hc); - if (hc->ctype == HFC_TYPE_XHFC) - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 | - V_HDLC_TRP | V_IFF); - /* Enable FIFO, no interrupt */ - else - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | - V_HDLC_TRP | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - if (hc->chan[ch].protocol != protocol) { - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - } - /* tx silence */ - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); - /* enable RX fifo */ - HFC_outb(hc, R_FIFO, (ch << 1) | 1); - HFC_wait(hc); - if (hc->ctype == HFC_TYPE_XHFC) - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 | - V_HDLC_TRP); - /* Enable FIFO, no interrupt*/ - else - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | - V_HDLC_TRP); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - if (hc->chan[ch].protocol != protocol) { - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - } - } - if (hc->ctype != HFC_TYPE_E1) { - hc->hw.a_st_ctrl0[hc->chan[ch].port] |= - ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; - HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_CTRL0, - hc->hw.a_st_ctrl0[hc->chan[ch].port]); - } - if (hc->chan[ch].bch) - test_and_set_bit(FLG_TRANSPARENT, - &hc->chan[ch].bch->Flags); - break; - case (ISDN_P_B_HDLC): /* B-channel */ - case (ISDN_P_TE_S0): /* D-channel */ - case (ISDN_P_NT_S0): - case (ISDN_P_TE_E1): - case (ISDN_P_NT_E1): - /* enable TX fifo */ - HFC_outb(hc, R_FIFO, ch << 1); - HFC_wait(hc); - if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) { - /* E1 or B-channel */ - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); - HFC_outb(hc, A_SUBCH_CFG, 0); - } else { - /* D-Channel without HDLC fill flags */ - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 2); - } - HFC_outb(hc, A_IRQ_MSK, V_IRQ); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - /* enable RX fifo */ - HFC_outb(hc, R_FIFO, (ch << 1) | 1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); - if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) - HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ - else - HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ - HFC_outb(hc, A_IRQ_MSK, V_IRQ); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - if (hc->chan[ch].bch) { - test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); - if (hc->ctype != HFC_TYPE_E1) { - hc->hw.a_st_ctrl0[hc->chan[ch].port] |= - ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; - HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_CTRL0, - hc->hw.a_st_ctrl0[hc->chan[ch].port]); - } - } - break; - default: - printk(KERN_DEBUG "%s: protocol not known %x\n", - __func__, protocol); - hc->chan[ch].protocol = ISDN_P_NONE; - return -ENOPROTOOPT; - } - hc->chan[ch].protocol = protocol; - return 0; -} - - -/* - * connect/disconnect PCM - */ - -static void -hfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx, - int slot_rx, int bank_rx) -{ - if (slot_tx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) { - /* disable PCM */ - mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0); - return; - } - - /* enable pcm */ - mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, - slot_rx, bank_rx); -} - -/* - * set/disable conference - */ - -static void -hfcmulti_conf(struct hfc_multi *hc, int ch, int num) -{ - if (num >= 0 && num <= 7) - hc->chan[ch].conf = num; - else - hc->chan[ch].conf = -1; - mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, - hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, - hc->chan[ch].bank_rx); -} - - -/* - * set/disable sample loop - */ - -/* NOTE: this function is experimental and therefore disabled */ - -/* - * Layer 1 callback function - */ -static int -hfcm_l1callback(struct dchannel *dch, u_int cmd) -{ - struct hfc_multi *hc = dch->hw; - struct sk_buff_head free_queue; - u_long flags; - - switch (cmd) { - case INFO3_P8: - case INFO3_P10: - break; - case HW_RESET_REQ: - /* start activation */ - spin_lock_irqsave(&hc->lock, flags); - if (hc->ctype == HFC_TYPE_E1) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: HW_RESET_REQ no BRI\n", - __func__); - } else { - HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */ - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, A_ST_WR_STATE, 3); - HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT * 3)); - /* activate */ - } - spin_unlock_irqrestore(&hc->lock, flags); - l1_event(dch->l1, HW_POWERUP_IND); - break; - case HW_DEACT_REQ: - __skb_queue_head_init(&free_queue); - /* start deactivation */ - spin_lock_irqsave(&hc->lock, flags); - if (hc->ctype == HFC_TYPE_E1) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: HW_DEACT_REQ no BRI\n", - __func__); - } else { - HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); - /* deactivate */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - hc->syncronized &= - ~(1 << hc->chan[dch->slot].port); - plxsd_checksync(hc, 0); - } - } - skb_queue_splice_init(&dch->squeue, &free_queue); - if (dch->tx_skb) { - __skb_queue_tail(&free_queue, dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - __skb_queue_tail(&free_queue, dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) - timer_delete(&dch->timer); - spin_unlock_irqrestore(&hc->lock, flags); - __skb_queue_purge(&free_queue); - break; - case HW_POWERUP_REQ: - spin_lock_irqsave(&hc->lock, flags); - if (hc->ctype == HFC_TYPE_E1) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: HW_POWERUP_REQ no BRI\n", - __func__); - } else { - HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */ - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */ - } - spin_unlock_irqrestore(&hc->lock, flags); - break; - case PH_ACTIVATE_IND: - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - case PH_DEACTIVATE_IND: - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - default: - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: unknown command %x\n", - __func__, cmd); - return -1; - } - return 0; -} - -/* - * Layer2 -> Layer 1 Transfer - */ - -static int -handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct hfc_multi *hc = dch->hw; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret = -EINVAL; - unsigned int id; - u_long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - if (skb->len < 1) - break; - spin_lock_irqsave(&hc->lock, flags); - ret = dchannel_senddata(dch, skb); - if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ - hfcmulti_tx(hc, dch->slot); - ret = 0; - /* start fifo */ - HFC_outb(hc, R_FIFO, 0); - HFC_wait(hc); - spin_unlock_irqrestore(&hc->lock, flags); - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&hc->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - if (dch->dev.D.protocol != ISDN_P_TE_S0) { - spin_lock_irqsave(&hc->lock, flags); - ret = 0; - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: PH_ACTIVATE port %d (0..%d)\n", - __func__, hc->chan[dch->slot].port, - hc->ports - 1); - /* start activation */ - if (hc->ctype == HFC_TYPE_E1) { - ph_state_change(dch); - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG - "%s: E1 report state %x \n", - __func__, dch->state); - } else { - HFC_outb(hc, R_ST_SEL, - hc->chan[dch->slot].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); - /* G1 */ - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, A_ST_WR_STATE, 1); - HFC_outb(hc, A_ST_WR_STATE, 1 | - (V_ST_ACT * 3)); /* activate */ - dch->state = 1; - } - spin_unlock_irqrestore(&hc->lock, flags); - } else - ret = l1_event(dch->l1, hh->prim); - break; - case PH_DEACTIVATE_REQ: - test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); - if (dch->dev.D.protocol != ISDN_P_TE_S0) { - struct sk_buff_head free_queue; - - __skb_queue_head_init(&free_queue); - spin_lock_irqsave(&hc->lock, flags); - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: PH_DEACTIVATE port %d (0..%d)\n", - __func__, hc->chan[dch->slot].port, - hc->ports - 1); - /* start deactivation */ - if (hc->ctype == HFC_TYPE_E1) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: PH_DEACTIVATE no BRI\n", - __func__); - } else { - HFC_outb(hc, R_ST_SEL, - hc->chan[dch->slot].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); - /* deactivate */ - dch->state = 1; - } - skb_queue_splice_init(&dch->squeue, &free_queue); - if (dch->tx_skb) { - __skb_queue_tail(&free_queue, dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - __skb_queue_tail(&free_queue, dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) - timer_delete(&dch->timer); -#ifdef FIXME - if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) - dchannel_sched_event(&hc->dch, D_CLEARBUSY); -#endif - ret = 0; - spin_unlock_irqrestore(&hc->lock, flags); - __skb_queue_purge(&free_queue); - } else - ret = l1_event(dch->l1, hh->prim); - break; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static void -deactivate_bchannel(struct bchannel *bch) -{ - struct hfc_multi *hc = bch->hw; - u_long flags; - - spin_lock_irqsave(&hc->lock, flags); - mISDN_clear_bchannel(bch); - hc->chan[bch->slot].coeff_count = 0; - hc->chan[bch->slot].rx_off = 0; - hc->chan[bch->slot].conf = -1; - mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); - spin_unlock_irqrestore(&hc->lock, flags); -} - -static int -handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct hfc_multi *hc = bch->hw; - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - if (!skb->len) - break; - spin_lock_irqsave(&hc->lock, flags); - ret = bchannel_senddata(bch, skb); - if (ret > 0) { /* direct TX */ - hfcmulti_tx(hc, bch->slot); - ret = 0; - /* start fifo */ - HFC_outb_nodebug(hc, R_FIFO, 0); - HFC_wait_nodebug(hc); - } - spin_unlock_irqrestore(&hc->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", - __func__, bch->slot); - spin_lock_irqsave(&hc->lock, flags); - /* activate B-channel if not already activated */ - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { - hc->chan[bch->slot].txpending = 0; - ret = mode_hfcmulti(hc, bch->slot, - ch->protocol, - hc->chan[bch->slot].slot_tx, - hc->chan[bch->slot].bank_tx, - hc->chan[bch->slot].slot_rx, - hc->chan[bch->slot].bank_rx); - if (!ret) { - if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf - && test_bit(HFC_CHIP_DTMF, &hc->chip)) { - /* start decoder */ - hc->dtmf = 1; - if (debug & DEBUG_HFCMULTI_DTMF) - printk(KERN_DEBUG - "%s: start dtmf decoder\n", - __func__); - HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | - V_RST_DTMF); - } - } - } else - ret = 0; - spin_unlock_irqrestore(&hc->lock, flags); - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, - GFP_KERNEL); - break; - case PH_CONTROL_REQ: - spin_lock_irqsave(&hc->lock, flags); - switch (hh->id) { - case HFC_SPL_LOOP_ON: /* set sample loop */ - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: HFC_SPL_LOOP_ON (len = %d)\n", - __func__, skb->len); - ret = 0; - break; - case HFC_SPL_LOOP_OFF: /* set silence */ - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n", - __func__); - ret = 0; - break; - default: - printk(KERN_ERR - "%s: unknown PH_CONTROL_REQ info %x\n", - __func__, hh->id); - ret = -EINVAL; - } - spin_unlock_irqrestore(&hc->lock, flags); - break; - case PH_DEACTIVATE_REQ: - deactivate_bchannel(bch); /* locked there */ - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, - GFP_KERNEL); - ret = 0; - break; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -/* - * bchannel control function - */ -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - struct dsp_features *features = - (struct dsp_features *)(*((u_long *)&cq->p1)); - struct hfc_multi *hc = bch->hw; - int slot_tx; - int bank_tx; - int slot_rx; - int bank_rx; - int num; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - ret = mISDN_ctrl_bchannel(bch, cq); - cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP; - break; - case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ - ret = mISDN_ctrl_bchannel(bch, cq); - hc->chan[bch->slot].rx_off = !!cq->p1; - if (!hc->chan[bch->slot].rx_off) { - /* reset fifo on rx on */ - HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1); - HFC_wait_nodebug(hc); - HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait_nodebug(hc); - } - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", - __func__, bch->nr, hc->chan[bch->slot].rx_off); - break; - case MISDN_CTRL_FILL_EMPTY: - ret = mISDN_ctrl_bchannel(bch, cq); - hc->silence = bch->fill[0]; - memset(hc->silence_data, hc->silence, sizeof(hc->silence_data)); - break; - case MISDN_CTRL_HW_FEATURES: /* fill features structure */ - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_FEATURE request\n", - __func__); - /* create confirm */ - features->hfc_id = hc->id; - if (test_bit(HFC_CHIP_DTMF, &hc->chip)) - features->hfc_dtmf = 1; - if (test_bit(HFC_CHIP_CONF, &hc->chip)) - features->hfc_conf = 1; - features->hfc_loops = 0; - if (test_bit(HFC_CHIP_B410P, &hc->chip)) { - features->hfc_echocanhw = 1; - } else { - features->pcm_id = hc->pcm; - features->pcm_slots = hc->slots; - features->pcm_banks = 2; - } - break; - case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */ - slot_tx = cq->p1 & 0xff; - bank_tx = cq->p1 >> 8; - slot_rx = cq->p2 & 0xff; - bank_rx = cq->p2 >> 8; - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: HFC_PCM_CONN slot %d bank %d (TX) " - "slot %d bank %d (RX)\n", - __func__, slot_tx, bank_tx, - slot_rx, bank_rx); - if (slot_tx < hc->slots && bank_tx <= 2 && - slot_rx < hc->slots && bank_rx <= 2) - hfcmulti_pcm(hc, bch->slot, - slot_tx, bank_tx, slot_rx, bank_rx); - else { - printk(KERN_WARNING - "%s: HFC_PCM_CONN slot %d bank %d (TX) " - "slot %d bank %d (RX) out of range\n", - __func__, slot_tx, bank_tx, - slot_rx, bank_rx); - ret = -EINVAL; - } - break; - case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */ - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HFC_PCM_DISC\n", - __func__); - hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0); - break; - case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */ - num = cq->p1 & 0xff; - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n", - __func__, num); - if (num <= 7) - hfcmulti_conf(hc, bch->slot, num); - else { - printk(KERN_WARNING - "%s: HW_CONF_JOIN conf %d out of range\n", - __func__, num); - ret = -EINVAL; - } - break; - case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */ - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__); - hfcmulti_conf(hc, bch->slot, -1); - break; - case MISDN_CTRL_HFC_ECHOCAN_ON: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__); - if (test_bit(HFC_CHIP_B410P, &hc->chip)) - vpm_echocan_on(hc, bch->slot, cq->p1); - else - ret = -EINVAL; - break; - - case MISDN_CTRL_HFC_ECHOCAN_OFF: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n", - __func__); - if (test_bit(HFC_CHIP_B410P, &hc->chip)) - vpm_echocan_off(hc, bch->slot); - else - ret = -EINVAL; - break; - default: - ret = mISDN_ctrl_bchannel(bch, cq); - break; - } - return ret; -} - -static int -hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct hfc_multi *hc = bch->hw; - int err = -EINVAL; - u_long flags; - - if (bch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: cmd:%x %p\n", - __func__, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - deactivate_bchannel(bch); /* locked there */ - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(THIS_MODULE); - err = 0; - break; - case CONTROL_CHANNEL: - spin_lock_irqsave(&hc->lock, flags); - err = channel_bctrl(bch, arg); - spin_unlock_irqrestore(&hc->lock, flags); - break; - default: - printk(KERN_WARNING "%s: unknown prim(%x)\n", - __func__, cmd); - } - return err; -} - -/* - * handle D-channel events - * - * handle state change event - */ -static void -ph_state_change(struct dchannel *dch) -{ - struct hfc_multi *hc; - int ch, i; - - if (!dch) { - printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__); - return; - } - hc = dch->hw; - ch = dch->slot; - - if (hc->ctype == HFC_TYPE_E1) { - if (dch->dev.D.protocol == ISDN_P_TE_E1) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG - "%s: E1 TE (id=%d) newstate %x\n", - __func__, hc->id, dch->state); - } else { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG - "%s: E1 NT (id=%d) newstate %x\n", - __func__, hc->id, dch->state); - } - switch (dch->state) { - case (1): - if (hc->e1_state != 1) { - for (i = 1; i <= 31; i++) { - /* reset fifos on e1 activation */ - HFC_outb_nodebug(hc, R_FIFO, - (i << 1) | 1); - HFC_wait_nodebug(hc); - HFC_outb_nodebug(hc, R_INC_RES_FIFO, - V_RES_F); - HFC_wait_nodebug(hc); - } - } - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - break; - - default: - if (hc->e1_state != 1) - return; - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - } - hc->e1_state = dch->state; - } else { - if (dch->dev.D.protocol == ISDN_P_TE_S0) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG - "%s: S/T TE newstate %x\n", - __func__, dch->state); - switch (dch->state) { - case (0): - l1_event(dch->l1, HW_RESET_IND); - break; - case (3): - l1_event(dch->l1, HW_DEACT_IND); - break; - case (5): - case (8): - l1_event(dch->l1, ANYSIGNAL); - break; - case (6): - l1_event(dch->l1, INFO2); - break; - case (7): - l1_event(dch->l1, INFO4_P8); - break; - } - } else { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: S/T NT newstate %x\n", - __func__, dch->state); - switch (dch->state) { - case (2): - if (hc->chan[ch].nt_timer == 0) { - hc->chan[ch].nt_timer = -1; - HFC_outb(hc, R_ST_SEL, - hc->chan[ch].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - HFC_outb(hc, A_ST_WR_STATE, 4 | - V_ST_LD_STA); /* G4 */ - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, A_ST_WR_STATE, 4); - dch->state = 4; - } else { - /* one extra count for the next event */ - hc->chan[ch].nt_timer = - nt_t1_count[poll_timer] + 1; - HFC_outb(hc, R_ST_SEL, - hc->chan[ch].port); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - /* allow G2 -> G3 transition */ - HFC_outb(hc, A_ST_WR_STATE, 2 | - V_SET_G2_G3); - } - break; - case (1): - hc->chan[ch].nt_timer = -1; - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - break; - case (4): - hc->chan[ch].nt_timer = -1; - break; - case (3): - hc->chan[ch].nt_timer = -1; - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - break; - } - } - } -} - -/* - * called for card mode init message - */ - -static void -hfcmulti_initmode(struct dchannel *dch) -{ - struct hfc_multi *hc = dch->hw; - u_char a_st_wr_state, r_e1_wr_sta; - int i, pt; - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: entered\n", __func__); - - i = dch->slot; - pt = hc->chan[i].port; - if (hc->ctype == HFC_TYPE_E1) { - /* E1 */ - hc->chan[hc->dnum[pt]].slot_tx = -1; - hc->chan[hc->dnum[pt]].slot_rx = -1; - hc->chan[hc->dnum[pt]].conf = -1; - if (hc->dnum[pt]) { - mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol, - -1, 0, -1, 0); - timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0); - } - for (i = 1; i <= 31; i++) { - if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ - continue; - hc->chan[i].slot_tx = -1; - hc->chan[i].slot_rx = -1; - hc->chan[i].conf = -1; - mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); - } - } - if (hc->ctype == HFC_TYPE_E1 && pt == 0) { - /* E1, port 0 */ - dch = hc->chan[hc->dnum[0]].dch; - if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { - HFC_outb(hc, R_LOS0, 255); /* 2 ms */ - HFC_outb(hc, R_LOS1, 255); /* 512 ms */ - } - if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) { - HFC_outb(hc, R_RX0, 0); - hc->hw.r_tx0 = 0 | V_OUT_EN; - } else { - HFC_outb(hc, R_RX0, 1); - hc->hw.r_tx0 = 1 | V_OUT_EN; - } - hc->hw.r_tx1 = V_ATX | V_NTRI; - HFC_outb(hc, R_TX0, hc->hw.r_tx0); - HFC_outb(hc, R_TX1, hc->hw.r_tx1); - HFC_outb(hc, R_TX_FR0, 0x00); - HFC_outb(hc, R_TX_FR1, 0xf8); - - if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) - HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); - - HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); - - if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) - HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); - - if (dch->dev.D.protocol == ISDN_P_NT_E1) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: E1 port is NT-mode\n", - __func__); - r_e1_wr_sta = 0; /* G0 */ - hc->e1_getclock = 0; - } else { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: E1 port is TE-mode\n", - __func__); - r_e1_wr_sta = 0; /* F0 */ - hc->e1_getclock = 1; - } - if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) - HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); - else - HFC_outb(hc, R_SYNC_OUT, 0); - if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip)) - hc->e1_getclock = 1; - if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip)) - hc->e1_getclock = 0; - if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { - /* SLAVE (clock master) */ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: E1 port is clock master " - "(clock from PCM)\n", __func__); - HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC); - } else { - if (hc->e1_getclock) { - /* MASTER (clock slave) */ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: E1 port is clock slave " - "(clock to PCM)\n", __func__); - HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); - } else { - /* MASTER (clock master) */ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: E1 port is " - "clock master " - "(clock from QUARTZ)\n", - __func__); - HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | - V_PCM_SYNC | V_JATT_OFF); - HFC_outb(hc, R_SYNC_OUT, 0); - } - } - HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */ - HFC_outb(hc, R_PWM_MD, V_PWM0_MD); - HFC_outb(hc, R_PWM0, 0x50); - HFC_outb(hc, R_PWM1, 0xff); - /* state machine setup */ - HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA); - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta); - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - hc->syncronized = 0; - plxsd_checksync(hc, 0); - } - } - if (hc->ctype != HFC_TYPE_E1) { - /* ST */ - hc->chan[i].slot_tx = -1; - hc->chan[i].slot_rx = -1; - hc->chan[i].conf = -1; - mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); - timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0); - hc->chan[i - 2].slot_tx = -1; - hc->chan[i - 2].slot_rx = -1; - hc->chan[i - 2].conf = -1; - mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0); - hc->chan[i - 1].slot_tx = -1; - hc->chan[i - 1].slot_rx = -1; - hc->chan[i - 1].conf = -1; - mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); - /* select interface */ - HFC_outb(hc, R_ST_SEL, pt); - /* undocumented: delay after R_ST_SEL */ - udelay(1); - if (dch->dev.D.protocol == ISDN_P_NT_S0) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: ST port %d is NT-mode\n", - __func__, pt); - /* clock delay */ - HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt); - a_st_wr_state = 1; /* G1 */ - hc->hw.a_st_ctrl0[pt] = V_ST_MD; - } else { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: ST port %d is TE-mode\n", - __func__, pt); - /* clock delay */ - HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te); - a_st_wr_state = 2; /* F2 */ - hc->hw.a_st_ctrl0[pt] = 0; - } - if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) - hc->hw.a_st_ctrl0[pt] |= V_TX_LI; - if (hc->ctype == HFC_TYPE_XHFC) { - hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */; - HFC_outb(hc, 0x35 /* A_ST_CTRL3 */, - 0x7c << 1 /* V_ST_PULSE */); - } - /* line setup */ - HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]); - /* disable E-channel */ - if ((dch->dev.D.protocol == ISDN_P_NT_S0) || - test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg)) - HFC_outb(hc, A_ST_CTRL1, V_E_IGNO); - else - HFC_outb(hc, A_ST_CTRL1, 0); - /* enable B-channel receive */ - HFC_outb(hc, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN); - /* state machine setup */ - HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA); - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state); - hc->hw.r_sci_msk |= 1 << pt; - /* state machine interrupts */ - HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk); - /* unset sync on port */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - hc->syncronized &= - ~(1 << hc->chan[dch->slot].port); - plxsd_checksync(hc, 0); - } - } - if (debug & DEBUG_HFCMULTI_INIT) - printk("%s: done\n", __func__); -} - - -static int -open_dchannel(struct hfc_multi *hc, struct dchannel *dch, - struct channel_req *rq) -{ - int err = 0; - u_long flags; - - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, - dch->dev.id, __builtin_return_address(0)); - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - if ((dch->dev.D.protocol != ISDN_P_NONE) && - (dch->dev.D.protocol != rq->protocol)) { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: change protocol %x to %x\n", - __func__, dch->dev.D.protocol, rq->protocol); - } - if ((dch->dev.D.protocol == ISDN_P_TE_S0) && - (rq->protocol != ISDN_P_TE_S0)) - l1_event(dch->l1, CLOSE_CHANNEL); - if (dch->dev.D.protocol != rq->protocol) { - if (rq->protocol == ISDN_P_TE_S0) { - err = create_l1(dch, hfcm_l1callback); - if (err) - return err; - } - dch->dev.D.protocol = rq->protocol; - spin_lock_irqsave(&hc->lock, flags); - hfcmulti_initmode(dch); - spin_unlock_irqrestore(&hc->lock, flags); - } - if (test_bit(FLG_ACTIVE, &dch->Flags)) - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - rq->ch = &dch->dev.D; - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s:cannot get module\n", __func__); - return 0; -} - -static int -open_bchannel(struct hfc_multi *hc, struct dchannel *dch, - struct channel_req *rq) -{ - struct bchannel *bch; - int ch; - - if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - if (hc->ctype == HFC_TYPE_E1) - ch = rq->adr.channel; - else - ch = (rq->adr.channel - 1) + (dch->slot - 2); - bch = hc->chan[ch].bch; - if (!bch) { - printk(KERN_ERR "%s:internal error ch %d has no bch\n", - __func__, ch); - return -EINVAL; - } - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - bch->ch.protocol = rq->protocol; - hc->chan[ch].rx_off = 0; - rq->ch = &bch->ch; - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s:cannot get module\n", __func__); - return 0; -} - -/* - * device control function - */ -static int -channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) -{ - struct hfc_multi *hc = dch->hw; - int ret = 0; - int wd_mode, wd_cnt; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3; - break; - case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ - wd_cnt = cq->p1 & 0xf; - wd_mode = !!(cq->p1 >> 4); - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s" - ", counter 0x%x\n", __func__, - wd_mode ? "AUTO" : "MANUAL", wd_cnt); - /* set the watchdog timer */ - HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4)); - hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0); - if (hc->ctype == HFC_TYPE_XHFC) - hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */; - /* init the watchdog register and reset the counter */ - HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - /* enable the watchdog output for Speech-Design */ - HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7); - HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15); - HFC_outb(hc, R_GPIO_OUT1, 0); - HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15); - } - break; - case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */ - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n", - __func__); - HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); - break; - case MISDN_CTRL_L1_TIMER3: - ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); - break; - default: - printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct hfc_multi *hc = dch->hw; - struct channel_req *rq; - int err = 0; - u_long flags; - - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: cmd:%x %p\n", - __func__, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - switch (rq->protocol) { - case ISDN_P_TE_S0: - case ISDN_P_NT_S0: - if (hc->ctype == HFC_TYPE_E1) { - err = -EINVAL; - break; - } - err = open_dchannel(hc, dch, rq); /* locked there */ - break; - case ISDN_P_TE_E1: - case ISDN_P_NT_E1: - if (hc->ctype != HFC_TYPE_E1) { - err = -EINVAL; - break; - } - err = open_dchannel(hc, dch, rq); /* locked there */ - break; - default: - spin_lock_irqsave(&hc->lock, flags); - err = open_bchannel(hc, dch, rq); - spin_unlock_irqrestore(&hc->lock, flags); - } - break; - case CLOSE_CHANNEL: - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: dev(%d) close from %p\n", - __func__, dch->dev.id, - __builtin_return_address(0)); - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - spin_lock_irqsave(&hc->lock, flags); - err = channel_dctrl(dch, arg); - spin_unlock_irqrestore(&hc->lock, flags); - break; - default: - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: unknown command %x\n", - __func__, cmd); - err = -EINVAL; - } - return err; -} - -static int -clockctl(void *priv, int enable) -{ - struct hfc_multi *hc = priv; - - hc->iclock_on = enable; - return 0; -} - -/* - * initialize the card - */ - -/* - * start timer irq, wait some time and check if we have interrupts. - * if not, reset chip and try again. - */ -static int -init_card(struct hfc_multi *hc) -{ - int err = -EIO; - u_long flags; - void __iomem *plx_acc; - u_long plx_flags; - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: entered\n", __func__); - - spin_lock_irqsave(&hc->lock, flags); - /* set interrupts but leave global interrupt disabled */ - hc->hw.r_irq_ctrl = V_FIFO_IRQ; - disable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - - if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED, - "HFC-multi", hc)) { - printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", - hc->irq); - hc->irq = 0; - return -EIO; - } - - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc = hc->plx_membase + PLX_INTCSR; - writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), - plx_acc); /* enable PCI & LINT1 irq */ - spin_unlock_irqrestore(&plx_lock, plx_flags); - } - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: IRQ %d count %d\n", - __func__, hc->irq, hc->irqcnt); - err = init_chip(hc); - if (err) - goto error; - /* - * Finally enable IRQ output - * this is only allowed, if an IRQ routine is already - * established for this HFC, so don't do that earlier - */ - spin_lock_irqsave(&hc->lock, flags); - enable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - /* printk(KERN_DEBUG "no master irq set!!!\n"); */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((100 * HZ) / 1000); /* Timeout 100ms */ - /* turn IRQ off until chip is completely initialized */ - spin_lock_irqsave(&hc->lock, flags); - disable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: IRQ %d count %d\n", - __func__, hc->irq, hc->irqcnt); - if (hc->irqcnt) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: done\n", __func__); - - return 0; - } - if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { - printk(KERN_INFO "ignoring missing interrupts\n"); - return 0; - } - - printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n", - hc->irq); - - err = -EIO; - -error: - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc = hc->plx_membase + PLX_INTCSR; - writew(0x00, plx_acc); /*disable IRQs*/ - spin_unlock_irqrestore(&plx_lock, plx_flags); - } - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); - if (hc->irq) { - free_irq(hc->irq, hc); - hc->irq = 0; - } - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err); - return err; -} - -/* - * find pci device and set it up - */ - -static int -setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct hm_map *m = (struct hm_map *)ent->driver_data; - - printk(KERN_INFO - "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", - m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); - - hc->pci_dev = pdev; - if (m->clock2) - test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); - - if (ent->vendor == PCI_VENDOR_ID_DIGIUM && - ent->device == PCI_DEVICE_ID_DIGIUM_HFC4S) { - test_and_set_bit(HFC_CHIP_B410P, &hc->chip); - test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); - test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); - hc->slots = 32; - } - - if (hc->pci_dev->irq <= 0) { - printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n"); - return -EIO; - } - if (pci_enable_device(hc->pci_dev)) { - printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n"); - return -EIO; - } - hc->leds = m->leds; - hc->ledstate = 0xAFFEAFFE; - hc->opticalsupport = m->opticalsupport; - - hc->pci_iobase = 0; - hc->pci_membase = NULL; - hc->plx_membase = NULL; - - /* set memory access methods */ - if (m->io_mode) /* use mode from card config */ - hc->io_mode = m->io_mode; - switch (hc->io_mode) { - case HFC_IO_MODE_PLXSD: - test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); - hc->slots = 128; /* required */ - hc->HFC_outb = HFC_outb_pcimem; - hc->HFC_inb = HFC_inb_pcimem; - hc->HFC_inw = HFC_inw_pcimem; - hc->HFC_wait = HFC_wait_pcimem; - hc->read_fifo = read_fifo_pcimem; - hc->write_fifo = write_fifo_pcimem; - hc->plx_origmembase = hc->pci_dev->resource[0].start; - /* MEMBASE 1 is PLX PCI Bridge */ - - if (!hc->plx_origmembase) { - printk(KERN_WARNING - "HFC-multi: No IO-Memory for PCI PLX bridge found\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - - hc->plx_membase = ioremap(hc->plx_origmembase, 0x80); - if (!hc->plx_membase) { - printk(KERN_WARNING - "HFC-multi: failed to remap plx address space. " - "(internal error)\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - printk(KERN_INFO - "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n", - (u_long)hc->plx_membase, hc->plx_origmembase); - - hc->pci_origmembase = hc->pci_dev->resource[2].start; - /* MEMBASE 1 is PLX PCI Bridge */ - if (!hc->pci_origmembase) { - printk(KERN_WARNING - "HFC-multi: No IO-Memory for PCI card found\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - - hc->pci_membase = ioremap(hc->pci_origmembase, 0x400); - if (!hc->pci_membase) { - printk(KERN_WARNING "HFC-multi: failed to remap io " - "address space. (internal error)\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - - printk(KERN_INFO - "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d " - "leds-type %d\n", - hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, - hc->pci_dev->irq, HZ, hc->leds); - pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); - break; - case HFC_IO_MODE_PCIMEM: - hc->HFC_outb = HFC_outb_pcimem; - hc->HFC_inb = HFC_inb_pcimem; - hc->HFC_inw = HFC_inw_pcimem; - hc->HFC_wait = HFC_wait_pcimem; - hc->read_fifo = read_fifo_pcimem; - hc->write_fifo = write_fifo_pcimem; - hc->pci_origmembase = hc->pci_dev->resource[1].start; - if (!hc->pci_origmembase) { - printk(KERN_WARNING - "HFC-multi: No IO-Memory for PCI card found\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - - hc->pci_membase = ioremap(hc->pci_origmembase, 256); - if (!hc->pci_membase) { - printk(KERN_WARNING - "HFC-multi: failed to remap io address space. " - "(internal error)\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ " - "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, - hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); - pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); - break; - case HFC_IO_MODE_REGIO: - hc->HFC_outb = HFC_outb_regio; - hc->HFC_inb = HFC_inb_regio; - hc->HFC_inw = HFC_inw_regio; - hc->HFC_wait = HFC_wait_regio; - hc->read_fifo = read_fifo_regio; - hc->write_fifo = write_fifo_regio; - hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; - if (!hc->pci_iobase) { - printk(KERN_WARNING - "HFC-multi: No IO for PCI card found\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - - if (!request_region(hc->pci_iobase, 8, "hfcmulti")) { - printk(KERN_WARNING "HFC-multi: failed to request " - "address space at 0x%08lx (internal error)\n", - hc->pci_iobase); - pci_disable_device(hc->pci_dev); - return -EIO; - } - - printk(KERN_INFO - "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n", - m->vendor_name, m->card_name, (u_int) hc->pci_iobase, - hc->pci_dev->irq, HZ, hc->leds); - pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO); - break; - default: - printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - - pci_set_drvdata(hc->pci_dev, hc); - - /* At this point the needed PCI config is done */ - /* fifos are still not enabled */ - return 0; -} - - -/* - * remove port - */ - -static void -release_port(struct hfc_multi *hc, struct dchannel *dch) -{ - int pt, ci, i = 0; - u_long flags; - struct bchannel *pb; - - ci = dch->slot; - pt = hc->chan[ci].port; - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: entered for port %d\n", - __func__, pt + 1); - - if (pt >= hc->ports) { - printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", - __func__, pt + 1); - return; - } - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: releasing port=%d\n", - __func__, pt + 1); - - if (dch->dev.D.protocol == ISDN_P_TE_S0) - l1_event(dch->l1, CLOSE_CHANNEL); - - hc->chan[ci].dch = NULL; - - if (hc->created[pt]) { - hc->created[pt] = 0; - mISDN_unregister_device(&dch->dev); - } - - spin_lock_irqsave(&hc->lock, flags); - - if (dch->timer.function) { - timer_delete(&dch->timer); - dch->timer.function = NULL; - } - - if (hc->ctype == HFC_TYPE_E1) { /* E1 */ - /* remove sync */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - hc->syncronized = 0; - plxsd_checksync(hc, 1); - } - /* free channels */ - for (i = 0; i <= 31; i++) { - if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ - continue; - if (hc->chan[i].bch) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: free port %d channel %d\n", - __func__, hc->chan[i].port + 1, i); - pb = hc->chan[i].bch; - hc->chan[i].bch = NULL; - spin_unlock_irqrestore(&hc->lock, flags); - mISDN_freebchannel(pb); - kfree(pb); - kfree(hc->chan[i].coeff); - spin_lock_irqsave(&hc->lock, flags); - } - } - } else { - /* remove sync */ - if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - hc->syncronized &= - ~(1 << hc->chan[ci].port); - plxsd_checksync(hc, 1); - } - /* free channels */ - if (hc->chan[ci - 2].bch) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: free port %d channel %d\n", - __func__, hc->chan[ci - 2].port + 1, - ci - 2); - pb = hc->chan[ci - 2].bch; - hc->chan[ci - 2].bch = NULL; - spin_unlock_irqrestore(&hc->lock, flags); - mISDN_freebchannel(pb); - kfree(pb); - kfree(hc->chan[ci - 2].coeff); - spin_lock_irqsave(&hc->lock, flags); - } - if (hc->chan[ci - 1].bch) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: free port %d channel %d\n", - __func__, hc->chan[ci - 1].port + 1, - ci - 1); - pb = hc->chan[ci - 1].bch; - hc->chan[ci - 1].bch = NULL; - spin_unlock_irqrestore(&hc->lock, flags); - mISDN_freebchannel(pb); - kfree(pb); - kfree(hc->chan[ci - 1].coeff); - spin_lock_irqsave(&hc->lock, flags); - } - } - - spin_unlock_irqrestore(&hc->lock, flags); - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__, - pt+1, ci); - mISDN_freedchannel(dch); - kfree(dch); - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: done!\n", __func__); -} - -static void -release_card(struct hfc_multi *hc) -{ - u_long flags; - int ch; - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: release card (%d) entered\n", - __func__, hc->id); - - /* unregister clock source */ - if (hc->iclock) - mISDN_unregister_clock(hc->iclock); - - /* disable and free irq */ - spin_lock_irqsave(&hc->lock, flags); - disable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - udelay(1000); - if (hc->irq) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n", - __func__, hc->irq, hc); - free_irq(hc->irq, hc); - hc->irq = 0; - - } - - /* disable D-channels & B-channels */ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: disable all channels (d and b)\n", - __func__); - for (ch = 0; ch <= 31; ch++) { - if (hc->chan[ch].dch) - release_port(hc, hc->chan[ch].dch); - } - - /* dimm leds */ - if (hc->leds) - hfcmulti_leds(hc); - - /* release hardware */ - release_io_hfcmulti(hc); - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: remove instance from list\n", - __func__); - list_del(&hc->list); - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: delete instance\n", __func__); - if (hc == syncmaster) - syncmaster = NULL; - kfree(hc); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: card successfully removed\n", - __func__); -} - -static void -init_e1_port_hw(struct hfc_multi *hc, struct hm_map *m) -{ - /* set optical line type */ - if (port[Port_cnt] & 0x001) { - if (!m->opticalsupport) { - printk(KERN_INFO - "This board has no optical " - "support\n"); - } else { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: PORT set optical " - "interface: card(%d) " - "port(%d)\n", - __func__, - HFC_cnt + 1, 1); - test_and_set_bit(HFC_CFG_OPTICAL, - &hc->chan[hc->dnum[0]].cfg); - } - } - /* set LOS report */ - if (port[Port_cnt] & 0x004) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PORT set " - "LOS report: card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CFG_REPORT_LOS, - &hc->chan[hc->dnum[0]].cfg); - } - /* set AIS report */ - if (port[Port_cnt] & 0x008) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PORT set " - "AIS report: card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CFG_REPORT_AIS, - &hc->chan[hc->dnum[0]].cfg); - } - /* set SLIP report */ - if (port[Port_cnt] & 0x010) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: PORT set SLIP report: " - "card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CFG_REPORT_SLIP, - &hc->chan[hc->dnum[0]].cfg); - } - /* set RDI report */ - if (port[Port_cnt] & 0x020) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: PORT set RDI report: " - "card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CFG_REPORT_RDI, - &hc->chan[hc->dnum[0]].cfg); - } - /* set CRC-4 Mode */ - if (!(port[Port_cnt] & 0x100)) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PORT turn on CRC4 report:" - " card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CFG_CRC4, - &hc->chan[hc->dnum[0]].cfg); - } else { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PORT turn off CRC4" - " report: card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - } - /* set forced clock */ - if (port[Port_cnt] & 0x0200) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PORT force getting clock from " - "E1: card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip); - } else - if (port[Port_cnt] & 0x0400) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PORT force putting clock to " - "E1: card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip); - } - /* set JATT PLL */ - if (port[Port_cnt] & 0x0800) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PORT disable JATT PLL on " - "E1: card(%d) port(%d)\n", - __func__, HFC_cnt + 1, 1); - test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); - } - /* set elastic jitter buffer */ - if (port[Port_cnt] & 0x3000) { - hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: PORT set elastic " - "buffer to %d: card(%d) port(%d)\n", - __func__, hc->chan[hc->dnum[0]].jitter, - HFC_cnt + 1, 1); - } else - hc->chan[hc->dnum[0]].jitter = 2; /* default */ -} - -static int -init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt) -{ - struct dchannel *dch; - struct bchannel *bch; - int ch, ret = 0; - char name[MISDN_MAX_IDLEN]; - int bcount = 0; - - dch = kzalloc_obj(struct dchannel); - if (!dch) - return -ENOMEM; - dch->debug = debug; - mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); - dch->hw = hc; - dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); - dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - dch->dev.D.send = handle_dmsg; - dch->dev.D.ctrl = hfcm_dctrl; - dch->slot = hc->dnum[pt]; - hc->chan[hc->dnum[pt]].dch = dch; - hc->chan[hc->dnum[pt]].port = pt; - hc->chan[hc->dnum[pt]].nt_timer = -1; - for (ch = 1; ch <= 31; ch++) { - if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */ - continue; - bch = kzalloc_obj(struct bchannel); - if (!bch) { - printk(KERN_ERR "%s: no memory for bchannel\n", - __func__); - ret = -ENOMEM; - goto free_chan; - } - hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); - if (!hc->chan[ch].coeff) { - printk(KERN_ERR "%s: no memory for coeffs\n", - __func__); - ret = -ENOMEM; - kfree(bch); - goto free_chan; - } - bch->nr = ch; - bch->slot = ch; - bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); - bch->hw = hc; - bch->ch.send = handle_bmsg; - bch->ch.ctrl = hfcm_bctrl; - bch->ch.nr = ch; - list_add(&bch->ch.list, &dch->dev.bchannels); - hc->chan[ch].bch = bch; - hc->chan[ch].port = pt; - set_channelmap(bch->nr, dch->dev.channelmap); - bcount++; - } - dch->dev.nrbchan = bcount; - if (pt == 0) - init_e1_port_hw(hc, m); - if (hc->ports > 1) - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d", - HFC_cnt + 1, pt+1); - else - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); - ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); - if (ret) - goto free_chan; - hc->created[pt] = 1; - return ret; -free_chan: - release_port(hc, dch); - return ret; -} - -static int -init_multi_port(struct hfc_multi *hc, int pt) -{ - struct dchannel *dch; - struct bchannel *bch; - int ch, i, ret = 0; - char name[MISDN_MAX_IDLEN]; - - dch = kzalloc_obj(struct dchannel); - if (!dch) - return -ENOMEM; - dch->debug = debug; - mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); - dch->hw = hc; - dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); - dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - dch->dev.D.send = handle_dmsg; - dch->dev.D.ctrl = hfcm_dctrl; - dch->dev.nrbchan = 2; - i = pt << 2; - dch->slot = i + 2; - hc->chan[i + 2].dch = dch; - hc->chan[i + 2].port = pt; - hc->chan[i + 2].nt_timer = -1; - for (ch = 0; ch < dch->dev.nrbchan; ch++) { - bch = kzalloc_obj(struct bchannel); - if (!bch) { - printk(KERN_ERR "%s: no memory for bchannel\n", - __func__); - ret = -ENOMEM; - goto free_chan; - } - hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL); - if (!hc->chan[i + ch].coeff) { - printk(KERN_ERR "%s: no memory for coeffs\n", - __func__); - ret = -ENOMEM; - kfree(bch); - goto free_chan; - } - bch->nr = ch + 1; - bch->slot = i + ch; - bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); - bch->hw = hc; - bch->ch.send = handle_bmsg; - bch->ch.ctrl = hfcm_bctrl; - bch->ch.nr = ch + 1; - list_add(&bch->ch.list, &dch->dev.bchannels); - hc->chan[i + ch].bch = bch; - hc->chan[i + ch].port = pt; - set_channelmap(bch->nr, dch->dev.channelmap); - } - /* set master clock */ - if (port[Port_cnt] & 0x001) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: PROTOCOL set master clock: " - "card(%d) port(%d)\n", - __func__, HFC_cnt + 1, pt + 1); - if (dch->dev.D.protocol != ISDN_P_TE_S0) { - printk(KERN_ERR "Error: Master clock " - "for port(%d) of card(%d) is only" - " possible with TE-mode\n", - pt + 1, HFC_cnt + 1); - ret = -EINVAL; - goto free_chan; - } - if (hc->masterclk >= 0) { - printk(KERN_ERR "Error: Master clock " - "for port(%d) of card(%d) already " - "defined for port(%d)\n", - pt + 1, HFC_cnt + 1, hc->masterclk + 1); - ret = -EINVAL; - goto free_chan; - } - hc->masterclk = pt; - } - /* set transmitter line to non capacitive */ - if (port[Port_cnt] & 0x002) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: PROTOCOL set non capacitive " - "transmitter: card(%d) port(%d)\n", - __func__, HFC_cnt + 1, pt + 1); - test_and_set_bit(HFC_CFG_NONCAP_TX, - &hc->chan[i + 2].cfg); - } - /* disable E-channel */ - if (port[Port_cnt] & 0x004) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: PROTOCOL disable E-channel: " - "card(%d) port(%d)\n", - __func__, HFC_cnt + 1, pt + 1); - test_and_set_bit(HFC_CFG_DIS_ECHANNEL, - &hc->chan[i + 2].cfg); - } - if (hc->ctype == HFC_TYPE_XHFC) { - snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d", - HFC_cnt + 1, pt + 1); - ret = mISDN_register_device(&dch->dev, NULL, name); - } else { - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", - hc->ctype, HFC_cnt + 1, pt + 1); - ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); - } - if (ret) - goto free_chan; - hc->created[pt] = 1; - return ret; -free_chan: - release_port(hc, dch); - return ret; -} - -static int -hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int ret_err = 0; - int pt; - struct hfc_multi *hc; - u_long flags; - u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ - int i, ch; - u_int maskcheck; - - if (HFC_cnt >= MAX_CARDS) { - printk(KERN_ERR "too many cards (max=%d).\n", - MAX_CARDS); - return -EINVAL; - } - if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) { - printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but " - "type[%d] %d was supplied as module parameter\n", - m->vendor_name, m->card_name, m->type, HFC_cnt, - type[HFC_cnt] & 0xff); - printk(KERN_WARNING "HFC-MULTI: Load module without parameters " - "first, to see cards and their types."); - return -EINVAL; - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n", - __func__, m->vendor_name, m->card_name, m->type, - type[HFC_cnt]); - - /* allocate card+fifo structure */ - hc = kzalloc_obj(struct hfc_multi); - if (!hc) { - printk(KERN_ERR "No kmem for HFC-Multi card\n"); - return -ENOMEM; - } - spin_lock_init(&hc->lock); - hc->mtyp = m; - hc->ctype = m->type; - hc->ports = m->ports; - hc->id = HFC_cnt; - hc->pcm = pcm[HFC_cnt]; - hc->io_mode = iomode[HFC_cnt]; - if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) { - /* fragment card */ - pt = 0; - maskcheck = 0; - for (ch = 0; ch <= 31; ch++) { - if (!((1 << ch) & dmask[E1_cnt])) - continue; - hc->dnum[pt] = ch; - hc->bmask[pt] = bmask[bmask_cnt++]; - if ((maskcheck & hc->bmask[pt]) - || (dmask[E1_cnt] & hc->bmask[pt])) { - printk(KERN_INFO - "HFC-E1 #%d has overlapping B-channels on fragment #%d\n", - E1_cnt + 1, pt); - kfree(hc); - return -EINVAL; - } - maskcheck |= hc->bmask[pt]; - printk(KERN_INFO - "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n", - E1_cnt + 1, ch, hc->bmask[pt]); - pt++; - } - hc->ports = pt; - } - if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) { - /* default card layout */ - hc->dnum[0] = 16; - hc->bmask[0] = 0xfffefffe; - hc->ports = 1; - } - - /* set chip specific features */ - hc->masterclk = -1; - if (type[HFC_cnt] & 0x100) { - test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); - hc->silence = 0xff; /* ulaw silence */ - } else - hc->silence = 0x2a; /* alaw silence */ - if ((poll >> 1) > sizeof(hc->silence_data)) { - printk(KERN_ERR "HFCMULTI error: silence_data too small, " - "please fix\n"); - kfree(hc); - return -EINVAL; - } - for (i = 0; i < (poll >> 1); i++) - hc->silence_data[i] = hc->silence; - - if (hc->ctype != HFC_TYPE_XHFC) { - if (!(type[HFC_cnt] & 0x200)) - test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); - test_and_set_bit(HFC_CHIP_CONF, &hc->chip); - } - - if (type[HFC_cnt] & 0x800) - test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); - if (type[HFC_cnt] & 0x1000) { - test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); - test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); - } - if (type[HFC_cnt] & 0x4000) - test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); - if (type[HFC_cnt] & 0x8000) - test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); - hc->slots = 32; - if (type[HFC_cnt] & 0x10000) - hc->slots = 64; - if (type[HFC_cnt] & 0x20000) - hc->slots = 128; - if (type[HFC_cnt] & 0x80000) { - test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip); - hc->wdcount = 0; - hc->wdbyte = V_GPIO_OUT2; - printk(KERN_NOTICE "Watchdog enabled\n"); - } - - if (pdev && ent) - /* setup pci, hc->slots may change due to PLXSD */ - ret_err = setup_pci(hc, pdev, ent); - else -#ifdef CONFIG_MISDN_HFCMULTI_8xx - ret_err = setup_embedded(hc, m); -#else - { - printk(KERN_WARNING "Embedded IO Mode not selected\n"); - ret_err = -EIO; - } -#endif - if (ret_err) { - if (hc == syncmaster) - syncmaster = NULL; - kfree(hc); - return ret_err; - } - - hc->HFC_outb_nodebug = hc->HFC_outb; - hc->HFC_inb_nodebug = hc->HFC_inb; - hc->HFC_inw_nodebug = hc->HFC_inw; - hc->HFC_wait_nodebug = hc->HFC_wait; -#ifdef HFC_REGISTER_DEBUG - hc->HFC_outb = HFC_outb_debug; - hc->HFC_inb = HFC_inb_debug; - hc->HFC_inw = HFC_inw_debug; - hc->HFC_wait = HFC_wait_debug; -#endif - /* create channels */ - for (pt = 0; pt < hc->ports; pt++) { - if (Port_cnt >= MAX_PORTS) { - printk(KERN_ERR "too many ports (max=%d).\n", - MAX_PORTS); - ret_err = -EINVAL; - goto free_card; - } - if (hc->ctype == HFC_TYPE_E1) - ret_err = init_e1_port(hc, m, pt); - else - ret_err = init_multi_port(hc, pt); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG - "%s: Registering D-channel, card(%d) port(%d) " - "result %d\n", - __func__, HFC_cnt + 1, pt + 1, ret_err); - - if (ret_err) { - while (pt) { /* release already registered ports */ - pt--; - if (hc->ctype == HFC_TYPE_E1) - release_port(hc, - hc->chan[hc->dnum[pt]].dch); - else - release_port(hc, - hc->chan[(pt << 2) + 2].dch); - } - goto free_card; - } - if (hc->ctype != HFC_TYPE_E1) - Port_cnt++; /* for each S0 port */ - } - if (hc->ctype == HFC_TYPE_E1) { - Port_cnt++; /* for each E1 port */ - E1_cnt++; - } - - /* disp switches */ - switch (m->dip_type) { - case DIP_4S: - /* - * Get DIP setting for beroNet 1S/2S/4S cards - * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + - * GPI 19/23 (R_GPI_IN2)) - */ - dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) | - ((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) | - (~HFC_inb(hc, R_GPI_IN2) & 0x08); - - /* Port mode (TE/NT) jumpers */ - pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4) & 0xf); - - if (test_bit(HFC_CHIP_B410P, &hc->chip)) - pmj = ~pmj & 0xf; - - printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n", - m->vendor_name, m->card_name, dips, pmj); - break; - case DIP_8S: - /* - * Get DIP Setting for beroNet 8S0+ cards - * Enable PCI auxbridge function - */ - HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); - /* prepare access to auxport */ - outw(0x4000, hc->pci_iobase + 4); - /* - * some dummy reads are required to - * read valid DIP switch data - */ - dips = inb(hc->pci_iobase); - dips = inb(hc->pci_iobase); - dips = inb(hc->pci_iobase); - dips = ~inb(hc->pci_iobase) & 0x3F; - outw(0x0, hc->pci_iobase + 4); - /* disable PCI auxbridge function */ - HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); - printk(KERN_INFO "%s: %s DIPs(0x%x)\n", - m->vendor_name, m->card_name, dips); - break; - case DIP_E1: - /* - * get DIP Setting for beroNet E1 cards - * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0) - */ - dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0) >> 4; - printk(KERN_INFO "%s: %s DIPs(0x%x)\n", - m->vendor_name, m->card_name, dips); - break; - } - - /* add to list */ - spin_lock_irqsave(&HFClock, flags); - list_add_tail(&hc->list, &HFClist); - spin_unlock_irqrestore(&HFClock, flags); - - /* use as clock source */ - if (clock == HFC_cnt + 1) - hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); - - /* initialize hardware */ - hc->irq = (m->irq) ? : hc->pci_dev->irq; - ret_err = init_card(hc); - if (ret_err) { - printk(KERN_ERR "init card returns %d\n", ret_err); - release_card(hc); - return ret_err; - } - - /* start IRQ and return */ - spin_lock_irqsave(&hc->lock, flags); - enable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - return 0; - -free_card: - release_io_hfcmulti(hc); - if (hc == syncmaster) - syncmaster = NULL; - kfree(hc); - return ret_err; -} - -static void hfc_remove_pci(struct pci_dev *pdev) -{ - struct hfc_multi *card = pci_get_drvdata(pdev); - u_long flags; - - if (debug) - printk(KERN_INFO "removing hfc_multi card vendor:%x " - "device:%x subvendor:%x subdevice:%x\n", - pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); - - if (card) { - spin_lock_irqsave(&HFClock, flags); - release_card(card); - spin_unlock_irqrestore(&HFClock, flags); - } else { - if (debug) - printk(KERN_DEBUG "%s: drvdata already removed\n", - __func__); - } -} - -#define VENDOR_CCD "Cologne Chip AG" -#define VENDOR_BN "beroNet GmbH" -#define VENDOR_DIG "Digium Inc." -#define VENDOR_JH "Junghanns.NET GmbH" -#define VENDOR_PRIM "PrimuX" - -static const struct hm_map hfcm_map[] = { - /*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0}, - /*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, - /*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, - /*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, - /*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0}, - /*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0}, - /*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, - /*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0}, - /*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0}, - /*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0}, - /*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0}, - /*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0}, - - /*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0}, - /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, - HFC_IO_MODE_REGIO, 0}, - /*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0}, - /*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0}, - - /*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0}, - /*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, - /*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, - - /*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, - /*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0}, - /*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, - /*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, - - /*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0}, - /*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0}, - /*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0}, - - /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, - HFC_IO_MODE_PLXSD, 0}, - /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, - HFC_IO_MODE_PLXSD, 0}, - /*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0}, - /*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0}, - /*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0}, - /*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0, - HFC_IO_MODE_EMBSD, XHFC_IRQ}, - /*32*/ {VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0}, - /*33*/ {VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, - /*34*/ {VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, -}; - -#undef H -#define H(x) ((unsigned long)&hfcm_map[x]) -static const struct pci_device_id hfmultipci_ids[] = { - - /* Cards with HFC-4S Chip */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */ - { PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, - PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)}, - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)}, - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - 0xb761, 0, 0, H(33)}, /* BN2S PCIe */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, - 0xb762, 0, 0, H(34)}, /* BN4S PCIe */ - - /* Cards with HFC-8S Chip */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S */ - - - /* Cards with HFC-E1 Chip */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */ - - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */ - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */ - - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ - - { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */ - - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 }, - {0, } -}; -#undef H - -MODULE_DEVICE_TABLE(pci, hfmultipci_ids); - -static int -hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct hm_map *m = (struct hm_map *)ent->driver_data; - int ret; - - if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && ( - ent->device == PCI_DEVICE_ID_CCD_HFC4S || - ent->device == PCI_DEVICE_ID_CCD_HFC8S || - ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { - printk(KERN_ERR - "Unknown HFC multiport controller (vendor:%04x device:%04x " - "subvendor:%04x subdevice:%04x)\n", pdev->vendor, - pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device); - printk(KERN_ERR - "Please contact the driver maintainer for support.\n"); - return -ENODEV; - } - ret = hfcmulti_init(m, pdev, ent); - if (ret) - return ret; - HFC_cnt++; - printk(KERN_INFO "%d devices registered\n", HFC_cnt); - return 0; -} - -static struct pci_driver hfcmultipci_driver = { - .name = "hfc_multi", - .probe = hfcmulti_probe, - .remove = hfc_remove_pci, - .id_table = hfmultipci_ids, -}; - -static void __exit -HFCmulti_cleanup(void) -{ - struct hfc_multi *card, *next; - - /* get rid of all devices of this driver */ - list_for_each_entry_safe(card, next, &HFClist, list) - release_card(card); - pci_unregister_driver(&hfcmultipci_driver); -} - -static int __init -HFCmulti_init(void) -{ - int err; - int i, xhfc = 0; - struct hm_map m; - - printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); - -#ifdef IRQ_DEBUG - printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__); -#endif - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: init entered\n", __func__); - - switch (poll) { - case 0: - poll_timer = 6; - poll = 128; - break; - case 8: - poll_timer = 2; - break; - case 16: - poll_timer = 3; - break; - case 32: - poll_timer = 4; - break; - case 64: - poll_timer = 5; - break; - case 128: - poll_timer = 6; - break; - case 256: - poll_timer = 7; - break; - default: - printk(KERN_ERR - "%s: Wrong poll value (%d).\n", __func__, poll); - err = -EINVAL; - return err; - - } - - if (!clock) - clock = 1; - - /* Register the embedded devices. - * This should be done before the PCI cards registration */ - switch (hwid) { - case HWID_MINIP4: - xhfc = 1; - m = hfcm_map[31]; - break; - case HWID_MINIP8: - xhfc = 2; - m = hfcm_map[31]; - break; - case HWID_MINIP16: - xhfc = 4; - m = hfcm_map[31]; - break; - default: - xhfc = 0; - } - - for (i = 0; i < xhfc; ++i) { - err = hfcmulti_init(&m, NULL, NULL); - if (err) { - printk(KERN_ERR "error registering embedded driver: " - "%x\n", err); - return err; - } - HFC_cnt++; - printk(KERN_INFO "%d devices registered\n", HFC_cnt); - } - - /* Register the PCI cards */ - err = pci_register_driver(&hfcmultipci_driver); - if (err < 0) { - printk(KERN_ERR "error registering pci driver: %x\n", err); - return err; - } - - return 0; -} - - -module_init(HFCmulti_init); -module_exit(HFCmulti_cleanup); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c deleted file mode 100644 index 554a1c640321..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ /dev/null @@ -1,2360 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * hfcpci.c low level driver for CCD's hfc-pci based cards - * - * Author Werner Cornelius (werner@isdn4linux.de) - * based on existing driver for CCD hfc ISA cards - * type approval valid for HFC-S PCI A based card - * - * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) - * Copyright 2008 by Karsten Keil - * - * Module options: - * - * debug: - * NOTE: only one poll value must be given for all cards - * See hfc_pci.h for debug flags. - * - * poll: - * NOTE: only one poll value must be given for all cards - * Give the number of samples for each fifo process. - * By default 128 is used. Decrease to reduce delay, increase to - * reduce cpu load. If unsure, don't mess with it! - * A value of 128 will use controller's interrupt. Other values will - * use kernel timer, because the controller will not allow lower values - * than 128. - * Also note that the value depends on the kernel timer frequency. - * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible. - * If the kernel uses 100 Hz, steps of 80 samples are possible. - * If the kernel uses 300 Hz, steps of about 26 samples are possible. - */ - -#include -#include -#include -#include -#include -#include - -#include "hfc_pci.h" - -static void hfcpci_softirq(struct timer_list *unused); -static const char *hfcpci_revision = "2.0"; - -static int HFC_cnt; -static uint debug; -static uint poll, tics; -static DEFINE_TIMER(hfc_tl, hfcpci_softirq); -static unsigned long hfc_jiffies; - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("mISDN driver for CCD's hfc-pci based cards"); -MODULE_LICENSE("GPL"); -module_param(debug, uint, S_IRUGO | S_IWUSR); -module_param(poll, uint, S_IRUGO | S_IWUSR); - -enum { - HFC_CCD_2BD0, - HFC_CCD_B000, - HFC_CCD_B006, - HFC_CCD_B007, - HFC_CCD_B008, - HFC_CCD_B009, - HFC_CCD_B00A, - HFC_CCD_B00B, - HFC_CCD_B00C, - HFC_CCD_B100, - HFC_CCD_B700, - HFC_CCD_B701, - HFC_ASUS_0675, - HFC_BERKOM_A1T, - HFC_BERKOM_TCONCEPT, - HFC_ANIGMA_MC145575, - HFC_ZOLTRIX_2BD0, - HFC_DIGI_DF_M_IOM2_E, - HFC_DIGI_DF_M_E, - HFC_DIGI_DF_M_IOM2_A, - HFC_DIGI_DF_M_A, - HFC_ABOCOM_2BD1, - HFC_SITECOM_DC105V2, -}; - -struct hfcPCI_hw { - unsigned char cirm; - unsigned char ctmt; - unsigned char clkdel; - unsigned char states; - unsigned char conn; - unsigned char mst_m; - unsigned char int_m1; - unsigned char int_m2; - unsigned char sctrl; - unsigned char sctrl_r; - unsigned char sctrl_e; - unsigned char trm; - unsigned char fifo_en; - unsigned char bswapped; - unsigned char protocol; - int nt_timer; - unsigned char __iomem *pci_io; /* start of PCI IO memory */ - dma_addr_t dmahandle; - void *fifos; /* FIFO memory */ - int last_bfifo_cnt[2]; - /* marker saving last b-fifo frame count */ - struct timer_list timer; -}; - -#define HFC_CFG_MASTER 1 -#define HFC_CFG_SLAVE 2 -#define HFC_CFG_PCM 3 -#define HFC_CFG_2HFC 4 -#define HFC_CFG_SLAVEHFC 5 -#define HFC_CFG_NEG_F0 6 -#define HFC_CFG_SW_DD_DU 7 - -#define FLG_HFC_TIMER_T1 16 -#define FLG_HFC_TIMER_T3 17 - -#define NT_T1_COUNT 1120 /* number of 3.125ms interrupts (3.5s) */ -#define NT_T3_COUNT 31 /* number of 3.125ms interrupts (97 ms) */ -#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ -#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ - - -struct hfc_pci { - u_char subtype; - u_char chanlimit; - u_char initdone; - u_long cfg; - u_int irq; - u_int irqcnt; - struct pci_dev *pdev; - struct hfcPCI_hw hw; - spinlock_t lock; /* card lock */ - struct dchannel dch; - struct bchannel bch[2]; -}; - -/* Interface functions */ -static void -enable_hwirq(struct hfc_pci *hc) -{ - hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE; - Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); -} - -static void -disable_hwirq(struct hfc_pci *hc) -{ - hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE); - Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); -} - -/* - * free hardware resources used by driver - */ -static void -release_io_hfcpci(struct hfc_pci *hc) -{ - /* disable memory mapped ports + busmaster */ - pci_write_config_word(hc->pdev, PCI_COMMAND, 0); - timer_delete(&hc->hw.timer); - dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos, - hc->hw.dmahandle); - iounmap(hc->hw.pci_io); -} - -/* - * set mode (NT or TE) - */ -static void -hfcpci_setmode(struct hfc_pci *hc) -{ - if (hc->hw.protocol == ISDN_P_NT_S0) { - hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */ - hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */ - hc->hw.states = 1; /* G1 */ - } else { - hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */ - hc->hw.sctrl &= ~SCTRL_MODE_NT; /* TE-MODE */ - hc->hw.states = 2; /* F2 */ - } - Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states); - udelay(10); - Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */ - Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); -} - -/* - * function called to reset the HFC PCI chip. A complete software reset of chip - * and fifos is done. - */ -static void -reset_hfcpci(struct hfc_pci *hc) -{ - u_char val; - int cnt = 0; - - printk(KERN_DEBUG "reset_hfcpci: entered\n"); - val = Read_hfc(hc, HFCPCI_CHIP_ID); - printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val); - /* enable memory mapped ports, disable busmaster */ - pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); - disable_hwirq(hc); - /* enable memory ports + busmaster */ - pci_write_config_word(hc->pdev, PCI_COMMAND, - PCI_ENA_MEMIO + PCI_ENA_MASTER); - val = Read_hfc(hc, HFCPCI_STATUS); - printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val); - hc->hw.cirm = HFCPCI_RESET; /* Reset On */ - Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); - set_current_state(TASK_UNINTERRUPTIBLE); - mdelay(10); /* Timeout 10ms */ - hc->hw.cirm = 0; /* Reset Off */ - Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); - val = Read_hfc(hc, HFCPCI_STATUS); - printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val); - while (cnt < 50000) { /* max 50000 us */ - udelay(5); - cnt += 5; - val = Read_hfc(hc, HFCPCI_STATUS); - if (!(val & 2)) - break; - } - printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt); - - hc->hw.fifo_en = 0x30; /* only D fifos enabled */ - - hc->hw.bswapped = 0; /* no exchange */ - hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; - hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ - hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ - hc->hw.sctrl_r = 0; - hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */ - hc->hw.mst_m = 0; - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */ - if (test_bit(HFC_CFG_NEG_F0, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_F0_NEGATIV; - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); - Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); - Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); - - hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | - HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - - /* Clear already pending ints */ - val = Read_hfc(hc, HFCPCI_INT_S1); - - /* set NT/TE mode */ - hfcpci_setmode(hc); - - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); - - /* - * Init GCI/IOM2 in master mode - * Slots 0 and 1 are set for B-chan 1 and 2 - * D- and monitor/CI channel are not enabled - * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC - * STIO2 is used as data input, B1+B2 from IOM->ST - * ST B-channel send disabled -> continuous 1s - * The IOM slots are always enabled - */ - if (test_bit(HFC_CFG_PCM, &hc->cfg)) { - /* set data flow directions: connect B1,B2: HFC to/from PCM */ - hc->hw.conn = 0x09; - } else { - hc->hw.conn = 0x36; /* set data flow directions */ - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { - Write_hfc(hc, HFCPCI_B1_SSL, 0xC0); - Write_hfc(hc, HFCPCI_B2_SSL, 0xC1); - Write_hfc(hc, HFCPCI_B1_RSL, 0xC0); - Write_hfc(hc, HFCPCI_B2_RSL, 0xC1); - } else { - Write_hfc(hc, HFCPCI_B1_SSL, 0x80); - Write_hfc(hc, HFCPCI_B2_SSL, 0x81); - Write_hfc(hc, HFCPCI_B1_RSL, 0x80); - Write_hfc(hc, HFCPCI_B2_RSL, 0x81); - } - } - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - val = Read_hfc(hc, HFCPCI_INT_S2); -} - -/* - * Timer function called when kernel timer expires - */ -static void -hfcpci_Timer(struct timer_list *t) -{ - struct hfc_pci *hc = timer_container_of(hc, t, hw.timer); - hc->hw.timer.expires = jiffies + 75; - /* WD RESET */ -/* - * WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80); - * add_timer(&hc->hw.timer); - */ -} - - -/* - * select a b-channel entry matching and active - */ -static struct bchannel * -Sel_BCS(struct hfc_pci *hc, int channel) -{ - if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) && - (hc->bch[0].nr & channel)) - return &hc->bch[0]; - else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) && - (hc->bch[1].nr & channel)) - return &hc->bch[1]; - else - return NULL; -} - -/* - * clear the desired B-channel rx fifo - */ -static void -hfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo) -{ - u_char fifo_state; - struct bzfifo *bzr; - - if (fifo) { - bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; - fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX; - } else { - bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; - fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX; - } - if (fifo_state) - hc->hw.fifo_en ^= fifo_state; - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); - hc->hw.last_bfifo_cnt[fifo] = 0; - bzr->f1 = MAX_B_FRAMES; - bzr->f2 = bzr->f1; /* init F pointers to remain constant */ - bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); - bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16( - le16_to_cpu(bzr->za[MAX_B_FRAMES].z1)); - if (fifo_state) - hc->hw.fifo_en |= fifo_state; - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); -} - -/* - * clear the desired B-channel tx fifo - */ -static void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo) -{ - u_char fifo_state; - struct bzfifo *bzt; - - if (fifo) { - bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; - fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX; - } else { - bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; - fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX; - } - if (fifo_state) - hc->hw.fifo_en ^= fifo_state; - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); - if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) " - "z1(%x) z2(%x) state(%x)\n", - fifo, bzt->f1, bzt->f2, - le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), - le16_to_cpu(bzt->za[MAX_B_FRAMES].z2), - fifo_state); - bzt->f2 = MAX_B_FRAMES; - bzt->f1 = bzt->f2; /* init F pointers to remain constant */ - bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); - bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 2); - if (fifo_state) - hc->hw.fifo_en |= fifo_state; - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); - if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG - "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n", - fifo, bzt->f1, bzt->f2, - le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), - le16_to_cpu(bzt->za[MAX_B_FRAMES].z2)); -} - -/* - * read a complete B-frame out of the buffer - */ -static void -hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, - u_char *bdata, int count) -{ - u_char *ptr, *ptr1, new_f2; - int maxlen, new_z2; - struct zt *zp; - - if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) - printk(KERN_DEBUG "hfcpci_empty_fifo\n"); - zp = &bz->za[bz->f2]; /* point to Z-Regs */ - new_z2 = le16_to_cpu(zp->z2) + count; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; - if ((count > MAX_DATA_SIZE + 3) || (count < 4) || - (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { - if (bch->debug & DEBUG_HW) - printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet " - "invalid length %d or crc\n", count); -#ifdef ERROR_STATISTIC - bch->err_inv++; -#endif - bz->za[new_f2].z2 = cpu_to_le16(new_z2); - bz->f2 = new_f2; /* next buffer */ - } else { - bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC); - if (!bch->rx_skb) { - printk(KERN_WARNING "HFCPCI: receive out of memory\n"); - return; - } - count -= 3; - ptr = skb_put(bch->rx_skb, count); - - if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = count; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - - le16_to_cpu(zp->z2); /* maximum */ - - ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); - /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - count -= maxlen; - - if (count) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, count); /* rest */ - } - bz->za[new_f2].z2 = cpu_to_le16(new_z2); - bz->f2 = new_f2; /* next buffer */ - recv_Bchannel(bch, MISDN_ID_ANY, false); - } -} - -/* - * D-channel receive procedure - */ -static int -receive_dmsg(struct hfc_pci *hc) -{ - struct dchannel *dch = &hc->dch; - int maxlen; - int rcnt, total; - int count = 5; - u_char *ptr, *ptr1; - struct dfifo *df; - struct zt *zp; - - df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx; - while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { - zp = &df->za[df->f2 & D_FREG_MASK]; - rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); - if (rcnt < 0) - rcnt += D_FIFO_SIZE; - rcnt++; - if (dch->debug & DEBUG_HW_DCHANNEL) - printk(KERN_DEBUG - "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n", - df->f1, df->f2, - le16_to_cpu(zp->z1), - le16_to_cpu(zp->z2), - rcnt); - - if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || - (df->data[le16_to_cpu(zp->z1)])) { - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG - "empty_fifo hfcpci packet inv. len " - "%d or crc %d\n", - rcnt, - df->data[le16_to_cpu(zp->z1)]); -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | - (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = - cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & - (D_FIFO_SIZE - 1)); - } else { - dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC); - if (!dch->rx_skb) { - printk(KERN_WARNING - "HFC-PCI: D receive out of memory\n"); - break; - } - total = rcnt; - rcnt -= 3; - ptr = skb_put(dch->rx_skb, rcnt); - - if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE) - maxlen = rcnt; /* complete transfer */ - else - maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2); - /* maximum */ - - ptr1 = df->data + le16_to_cpu(zp->z2); - /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - rcnt -= maxlen; - - if (rcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = df->data; /* start of buffer */ - memcpy(ptr, ptr1, rcnt); /* rest */ - } - df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | - (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16(( - le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1)); - recv_Dchannel(dch); - } - } - return 1; -} - -/* - * check for transparent receive data and read max one 'poll' size if avail - */ -static void -hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, - struct bzfifo *txbz, u_char *bdata) -{ - __le16 *z1r, *z2r, *z1t, *z2t; - int new_z2, fcnt_rx, fcnt_tx, maxlen; - u_char *ptr, *ptr1; - - z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ - z2r = z1r + 1; - z1t = &txbz->za[MAX_B_FRAMES].z1; - z2t = z1t + 1; - - fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); - if (!fcnt_rx) - return; /* no data avail */ - - if (fcnt_rx <= 0) - fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */ - new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - - fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); - if (fcnt_tx <= 0) - fcnt_tx += B_FIFO_SIZE; - /* fcnt_tx contains available bytes in tx-fifo */ - fcnt_tx = B_FIFO_SIZE - fcnt_tx; - /* remaining bytes to send (bytes in tx-fifo) */ - - if (test_bit(FLG_RX_OFF, &bch->Flags)) { - bch->dropcnt += fcnt_rx; - *z2r = cpu_to_le16(new_z2); - return; - } - maxlen = bchannel_get_rxbuf(bch, fcnt_rx); - if (maxlen < 0) { - pr_warn("B%d: No bufferspace for %d bytes\n", bch->nr, fcnt_rx); - } else { - ptr = skb_put(bch->rx_skb, fcnt_rx); - if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = fcnt_rx; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); - /* maximum */ - - ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); - /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - fcnt_rx -= maxlen; - - if (fcnt_rx) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, fcnt_rx); /* rest */ - } - recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */ - } - *z2r = cpu_to_le16(new_z2); /* new position */ -} - -/* - * B-channel main receive routine - */ -static void -main_rec_hfcpci(struct bchannel *bch) -{ - struct hfc_pci *hc = bch->hw; - int rcnt, real_fifo; - int receive = 0, count = 5; - struct bzfifo *txbz, *rxbz; - u_char *bdata; - struct zt *zp; - - if ((bch->nr & 2) && (!hc->hw.bswapped)) { - rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; - txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; - bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; - real_fifo = 1; - } else { - rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; - txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; - bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1; - real_fifo = 0; - } -Begin: - count--; - if (rxbz->f1 != rxbz->f2) { - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", - bch->nr, rxbz->f1, rxbz->f2); - zp = &rxbz->za[rxbz->f2]; - - rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); - if (rcnt < 0) - rcnt += B_FIFO_SIZE; - rcnt++; - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG - "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", - bch->nr, le16_to_cpu(zp->z1), - le16_to_cpu(zp->z2), rcnt); - hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt); - rcnt = rxbz->f1 - rxbz->f2; - if (rcnt < 0) - rcnt += MAX_B_FRAMES + 1; - if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { - rcnt = 0; - hfcpci_clear_fifo_rx(hc, real_fifo); - } - hc->hw.last_bfifo_cnt[real_fifo] = rcnt; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { - hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata); - return; - } else - receive = 0; - if (count && receive) - goto Begin; - -} - -/* - * D-channel send routine - */ -static void -hfcpci_fill_dfifo(struct hfc_pci *hc) -{ - struct dchannel *dch = &hc->dch; - int fcnt; - int count, new_z1, maxlen; - struct dfifo *df; - u_char *src, *dst, new_f1; - - if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO)) - printk(KERN_DEBUG "%s\n", __func__); - - if (!dch->tx_skb) - return; - count = dch->tx_skb->len - dch->tx_idx; - if (count <= 0) - return; - df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx; - - if (dch->debug & DEBUG_HW_DFIFO) - printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__, - df->f1, df->f2, - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1)); - fcnt = df->f1 - df->f2; /* frame count actually buffered */ - if (fcnt < 0) - fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ - if (fcnt > (MAX_D_FRAMES - 1)) { - if (dch->debug & DEBUG_HW_DCHANNEL) - printk(KERN_DEBUG - "hfcpci_fill_Dfifo more as 14 frames\n"); -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - return; - } - /* now determine free bytes in FIFO buffer */ - maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) - - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1; - if (maxlen <= 0) - maxlen += D_FIFO_SIZE; /* count now contains available bytes */ - - if (dch->debug & DEBUG_HW_DCHANNEL) - printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n", - count, maxlen); - if (count > maxlen) { - if (dch->debug & DEBUG_HW_DCHANNEL) - printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n"); - return; - } - new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & - (D_FIFO_SIZE - 1); - new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); - src = dch->tx_skb->data + dch->tx_idx; /* source pointer */ - dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); - maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); - /* end fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = df->data; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); - /* for next buffer */ - df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); - /* new pos actual buffer */ - df->f1 = new_f1; /* next frame */ - dch->tx_idx = dch->tx_skb->len; -} - -/* - * B-channel send routine - */ -static void -hfcpci_fill_fifo(struct bchannel *bch) -{ - struct hfc_pci *hc = bch->hw; - int maxlen, fcnt; - int count, new_z1; - struct bzfifo *bz; - u_char *bdata; - u_char new_f1, *src, *dst; - __le16 *z1t, *z2t; - - if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) - printk(KERN_DEBUG "%s\n", __func__); - if ((!bch->tx_skb) || bch->tx_skb->len == 0) { - if (!test_bit(FLG_FILLEMPTY, &bch->Flags) && - !test_bit(FLG_TRANSPARENT, &bch->Flags)) - return; - count = HFCPCI_FILLEMPTY; - } else { - count = bch->tx_skb->len - bch->tx_idx; - } - if ((bch->nr & 2) && (!hc->hw.bswapped)) { - bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; - bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2; - } else { - bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; - bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1; - } - - if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { - z1t = &bz->za[MAX_B_FRAMES].z1; - z2t = z1t + 1; - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) " - "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count, - le16_to_cpu(*z1t), le16_to_cpu(*z2t)); - fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); - if (fcnt <= 0) - fcnt += B_FIFO_SIZE; - if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { - /* fcnt contains available bytes in fifo */ - if (count > fcnt) - count = fcnt; - new_z1 = le16_to_cpu(*z1t) + count; - /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); - /* end of fifo */ - if (bch->debug & DEBUG_HW_BFIFO) - printk(KERN_DEBUG "hfcpci_FFt fillempty " - "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n", - fcnt, maxlen, new_z1, dst); - if (maxlen > count) - maxlen = count; /* limit size */ - memset(dst, bch->fill[0], maxlen); /* first copy */ - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - memset(dst, bch->fill[0], count); - } - *z1t = cpu_to_le16(new_z1); /* now send data */ - return; - } - /* fcnt contains available bytes in fifo */ - fcnt = B_FIFO_SIZE - fcnt; - /* remaining bytes to send (bytes in fifo) */ - - next_t_frame: - count = bch->tx_skb->len - bch->tx_idx; - /* maximum fill shall be poll*2 */ - if (count > (poll << 1) - fcnt) - count = (poll << 1) - fcnt; - if (count <= 0) - return; - /* data is suitable for fifo */ - new_z1 = le16_to_cpu(*z1t) + count; - /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - src = bch->tx_skb->data + bch->tx_idx; - /* source pointer */ - dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); - /* end of fifo */ - if (bch->debug & DEBUG_HW_BFIFO) - printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) " - "maxl(%d) nz1(%x) dst(%p)\n", - fcnt, maxlen, new_z1, dst); - fcnt += count; - bch->tx_idx += count; - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - *z1t = cpu_to_le16(new_z1); /* now send data */ - if (bch->tx_idx < bch->tx_skb->len) - return; - dev_kfree_skb_any(bch->tx_skb); - if (get_next_bframe(bch)) - goto next_t_frame; - return; - } - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG - "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n", - __func__, bch->nr, bz->f1, bz->f2, - bz->za[bz->f1].z1); - fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ - if (fcnt < 0) - fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ - if (fcnt > (MAX_B_FRAMES - 1)) { - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG - "hfcpci_fill_Bfifo more as 14 frames\n"); - return; - } - /* now determine free bytes in FIFO buffer */ - maxlen = le16_to_cpu(bz->za[bz->f2].z2) - - le16_to_cpu(bz->za[bz->f1].z1) - 1; - if (maxlen <= 0) - maxlen += B_FIFO_SIZE; /* count now contains available bytes */ - - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n", - bch->nr, count, maxlen); - - if (maxlen < count) { - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n"); - return; - } - new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count; - /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - - new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); - src = bch->tx_skb->data + bch->tx_idx; /* source pointer */ - dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1); - /* end fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ - bz->f1 = new_f1; /* next frame */ - dev_kfree_skb_any(bch->tx_skb); - get_next_bframe(bch); -} - - - -/* - * handle L1 state changes TE - */ - -static void -ph_state_te(struct dchannel *dch) -{ - if (dch->debug) - printk(KERN_DEBUG "%s: TE newstate %x\n", - __func__, dch->state); - switch (dch->state) { - case 0: - l1_event(dch->l1, HW_RESET_IND); - break; - case 3: - l1_event(dch->l1, HW_DEACT_IND); - break; - case 5: - case 8: - l1_event(dch->l1, ANYSIGNAL); - break; - case 6: - l1_event(dch->l1, INFO2); - break; - case 7: - l1_event(dch->l1, INFO4_P8); - break; - } -} - -/* - * handle L1 state changes NT - */ - -static void -handle_nt_timer3(struct dchannel *dch) { - struct hfc_pci *hc = dch->hw; - - test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - hc->hw.nt_timer = 0; - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); -} - -static void -ph_state_nt(struct dchannel *dch) -{ - struct hfc_pci *hc = dch->hw; - - if (dch->debug) - printk(KERN_DEBUG "%s: NT newstate %x\n", - __func__, dch->state); - switch (dch->state) { - case 2: - if (hc->hw.nt_timer < 0) { - hc->hw.nt_timer = 0; - test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); - test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - /* Clear already pending ints */ - (void) Read_hfc(hc, HFCPCI_INT_S1); - Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); - udelay(10); - Write_hfc(hc, HFCPCI_STATES, 4); - dch->state = 4; - } else if (hc->hw.nt_timer == 0) { - hc->hw.int_m1 |= HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - hc->hw.nt_timer = NT_T1_COUNT; - hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; - hc->hw.ctmt |= HFCPCI_TIM3_125; - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | - HFCPCI_CLTIMER); - test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); - test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags); - /* allow G2 -> G3 transition */ - Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); - } else { - Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); - } - break; - case 1: - hc->hw.nt_timer = 0; - test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); - test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - hc->hw.mst_m &= ~HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); - _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - break; - case 4: - hc->hw.nt_timer = 0; - test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); - test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - break; - case 3: - if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) { - if (!test_and_clear_bit(FLG_L2_ACTIVATED, - &dch->Flags)) { - handle_nt_timer3(dch); - break; - } - test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); - hc->hw.int_m1 |= HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - hc->hw.nt_timer = NT_T3_COUNT; - hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; - hc->hw.ctmt |= HFCPCI_TIM3_125; - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | - HFCPCI_CLTIMER); - } - break; - } -} - -static void -ph_state(struct dchannel *dch) -{ - struct hfc_pci *hc = dch->hw; - - if (hc->hw.protocol == ISDN_P_NT_S0) { - if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) && - hc->hw.nt_timer < 0) - handle_nt_timer3(dch); - else - ph_state_nt(dch); - } else - ph_state_te(dch); -} - -/* - * Layer 1 callback function - */ -static int -hfc_l1callback(struct dchannel *dch, u_int cmd) -{ - struct hfc_pci *hc = dch->hw; - - switch (cmd) { - case INFO3_P8: - case INFO3_P10: - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - break; - case HW_RESET_REQ: - Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); - /* HFC ST 3 */ - udelay(6); - Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */ - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | - HFCPCI_DO_ACTION); - l1_event(dch->l1, HW_POWERUP_IND); - break; - case HW_DEACT_REQ: - hc->hw.mst_m &= ~HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - skb_queue_purge(&dch->squeue); - if (dch->tx_skb) { - dev_kfree_skb(dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - dev_kfree_skb(dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) - timer_delete(&dch->timer); - break; - case HW_POWERUP_REQ: - Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION); - break; - case PH_ACTIVATE_IND: - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - case PH_DEACTIVATE_IND: - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - default: - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: unknown command %x\n", - __func__, cmd); - return -1; - } - return 0; -} - -/* - * Interrupt handler - */ -static inline void -tx_birq(struct bchannel *bch) -{ - if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) - hfcpci_fill_fifo(bch); - else { - dev_kfree_skb_any(bch->tx_skb); - if (get_next_bframe(bch)) - hfcpci_fill_fifo(bch); - } -} - -static inline void -tx_dirq(struct dchannel *dch) -{ - if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) - hfcpci_fill_dfifo(dch->hw); - else { - dev_kfree_skb(dch->tx_skb); - if (get_next_dframe(dch)) - hfcpci_fill_dfifo(dch->hw); - } -} - -static irqreturn_t -hfcpci_int(int intno, void *dev_id) -{ - struct hfc_pci *hc = dev_id; - u_char exval; - struct bchannel *bch; - u_char val, stat; - - spin_lock(&hc->lock); - if (!(hc->hw.int_m2 & 0x08)) { - spin_unlock(&hc->lock); - return IRQ_NONE; /* not initialised */ - } - stat = Read_hfc(hc, HFCPCI_STATUS); - if (HFCPCI_ANYINT & stat) { - val = Read_hfc(hc, HFCPCI_INT_S1); - if (hc->dch.debug & DEBUG_HW_DCHANNEL) - printk(KERN_DEBUG - "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val); - } else { - /* shared */ - spin_unlock(&hc->lock); - return IRQ_NONE; - } - hc->irqcnt++; - - if (hc->dch.debug & DEBUG_HW_DCHANNEL) - printk(KERN_DEBUG "HFC-PCI irq %x\n", val); - val &= hc->hw.int_m1; - if (val & 0x40) { /* state machine irq */ - exval = Read_hfc(hc, HFCPCI_STATES) & 0xf; - if (hc->dch.debug & DEBUG_HW_DCHANNEL) - printk(KERN_DEBUG "ph_state chg %d->%d\n", - hc->dch.state, exval); - hc->dch.state = exval; - schedule_event(&hc->dch, FLG_PHCHANGE); - val &= ~0x40; - } - if (val & 0x80) { /* timer irq */ - if (hc->hw.protocol == ISDN_P_NT_S0) { - if ((--hc->hw.nt_timer) < 0) - schedule_event(&hc->dch, FLG_PHCHANGE); - } - val &= ~0x80; - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); - } - if (val & 0x08) { /* B1 rx */ - bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); - if (bch) - main_rec_hfcpci(bch); - else if (hc->dch.debug) - printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n"); - } - if (val & 0x10) { /* B2 rx */ - bch = Sel_BCS(hc, 2); - if (bch) - main_rec_hfcpci(bch); - else if (hc->dch.debug) - printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n"); - } - if (val & 0x01) { /* B1 tx */ - bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); - if (bch) - tx_birq(bch); - else if (hc->dch.debug) - printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n"); - } - if (val & 0x02) { /* B2 tx */ - bch = Sel_BCS(hc, 2); - if (bch) - tx_birq(bch); - else if (hc->dch.debug) - printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n"); - } - if (val & 0x20) /* D rx */ - receive_dmsg(hc); - if (val & 0x04) { /* D tx */ - if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) - timer_delete(&hc->dch.timer); - tx_dirq(&hc->dch); - } - spin_unlock(&hc->lock); - return IRQ_HANDLED; -} - -/* - * timer callback for D-chan busy resolution. Currently no function - */ -static void -hfcpci_dbusy_timer(struct timer_list *t) -{ -} - -/* - * activate/deactivate hardware for selected channels and mode - */ -static int -mode_hfcpci(struct bchannel *bch, int bc, int protocol) -{ - struct hfc_pci *hc = bch->hw; - int fifo2; - u_char rx_slot = 0, tx_slot = 0, pcm_mode; - - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG - "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n", - bch->state, protocol, bch->nr, bc); - - fifo2 = bc; - pcm_mode = (bc >> 24) & 0xff; - if (pcm_mode) { /* PCM SLOT USE */ - if (!test_bit(HFC_CFG_PCM, &hc->cfg)) - printk(KERN_WARNING - "%s: pcm channel id without HFC_CFG_PCM\n", - __func__); - rx_slot = (bc >> 8) & 0xff; - tx_slot = (bc >> 16) & 0xff; - bc = bc & 0xff; - } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE)) - printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", - __func__); - if (hc->chanlimit > 1) { - hc->hw.bswapped = 0; /* B1 and B2 normal mode */ - hc->hw.sctrl_e &= ~0x80; - } else { - if (bc & 2) { - if (protocol != ISDN_P_NONE) { - hc->hw.bswapped = 1; /* B1 and B2 exchanged */ - hc->hw.sctrl_e |= 0x80; - } else { - hc->hw.bswapped = 0; /* B1 and B2 normal mode */ - hc->hw.sctrl_e &= ~0x80; - } - fifo2 = 1; - } else { - hc->hw.bswapped = 0; /* B1 and B2 normal mode */ - hc->hw.sctrl_e &= ~0x80; - } - } - switch (protocol) { - case (-1): /* used for init */ - bch->state = -1; - bch->nr = bc; - fallthrough; - case (ISDN_P_NONE): - if (bch->state == ISDN_P_NONE) - return 0; - if (bc & 2) { - hc->hw.sctrl &= ~SCTRL_B2_ENA; - hc->hw.sctrl_r &= ~SCTRL_B2_ENA; - } else { - hc->hw.sctrl &= ~SCTRL_B1_ENA; - hc->hw.sctrl_r &= ~SCTRL_B1_ENA; - } - if (fifo2 & 2) { - hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2; - hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS | - HFCPCI_INTS_B2REC); - } else { - hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1; - hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS | - HFCPCI_INTS_B1REC); - } -#ifdef REVERSE_BITORDER - if (bch->nr & 2) - hc->hw.cirm &= 0x7f; - else - hc->hw.cirm &= 0xbf; -#endif - bch->state = ISDN_P_NONE; - bch->nr = bc; - test_and_clear_bit(FLG_HDLC, &bch->Flags); - test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); - break; - case (ISDN_P_B_RAW): - bch->state = protocol; - bch->nr = bc; - hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); - hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); - if (bc & 2) { - hc->hw.sctrl |= SCTRL_B2_ENA; - hc->hw.sctrl_r |= SCTRL_B2_ENA; -#ifdef REVERSE_BITORDER - hc->hw.cirm |= 0x80; -#endif - } else { - hc->hw.sctrl |= SCTRL_B1_ENA; - hc->hw.sctrl_r |= SCTRL_B1_ENA; -#ifdef REVERSE_BITORDER - hc->hw.cirm |= 0x40; -#endif - } - if (fifo2 & 2) { - hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; - if (!tics) - hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | - HFCPCI_INTS_B2REC); - hc->hw.ctmt |= 2; - hc->hw.conn &= ~0x18; - } else { - hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; - if (!tics) - hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | - HFCPCI_INTS_B1REC); - hc->hw.ctmt |= 1; - hc->hw.conn &= ~0x03; - } - test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); - break; - case (ISDN_P_B_HDLC): - bch->state = protocol; - bch->nr = bc; - hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); - hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); - if (bc & 2) { - hc->hw.sctrl |= SCTRL_B2_ENA; - hc->hw.sctrl_r |= SCTRL_B2_ENA; - } else { - hc->hw.sctrl |= SCTRL_B1_ENA; - hc->hw.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2 & 2) { - hc->hw.last_bfifo_cnt[1] = 0; - hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; - hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | - HFCPCI_INTS_B2REC); - hc->hw.ctmt &= ~2; - hc->hw.conn &= ~0x18; - } else { - hc->hw.last_bfifo_cnt[0] = 0; - hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; - hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | - HFCPCI_INTS_B1REC); - hc->hw.ctmt &= ~1; - hc->hw.conn &= ~0x03; - } - test_and_set_bit(FLG_HDLC, &bch->Flags); - break; - default: - printk(KERN_DEBUG "prot not known %x\n", protocol); - return -ENOPROTOOPT; - } - if (test_bit(HFC_CFG_PCM, &hc->cfg)) { - if ((protocol == ISDN_P_NONE) || - (protocol == -1)) { /* init case */ - rx_slot = 0; - tx_slot = 0; - } else { - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { - rx_slot |= 0xC0; - tx_slot |= 0xC0; - } else { - rx_slot |= 0x80; - tx_slot |= 0x80; - } - } - if (bc & 2) { - hc->hw.conn &= 0xc7; - hc->hw.conn |= 0x08; - printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n", - __func__, tx_slot); - printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n", - __func__, rx_slot); - Write_hfc(hc, HFCPCI_B2_SSL, tx_slot); - Write_hfc(hc, HFCPCI_B2_RSL, rx_slot); - } else { - hc->hw.conn &= 0xf8; - hc->hw.conn |= 0x01; - printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n", - __func__, tx_slot); - printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n", - __func__, rx_slot); - Write_hfc(hc, HFCPCI_B1_SSL, tx_slot); - Write_hfc(hc, HFCPCI_B1_RSL, rx_slot); - } - } - Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); - Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); - Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); -#ifdef REVERSE_BITORDER - Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); -#endif - return 0; -} - -static int -set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) -{ - struct hfc_pci *hc = bch->hw; - - if (bch->debug & DEBUG_HW_BCHANNEL) - printk(KERN_DEBUG - "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n", - bch->state, protocol, bch->nr, chan); - if (bch->nr != chan) { - printk(KERN_DEBUG - "HFCPCI rxtest wrong channel parameter %x/%x\n", - bch->nr, chan); - return -EINVAL; - } - switch (protocol) { - case (ISDN_P_B_RAW): - bch->state = protocol; - hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); - if (chan & 2) { - hc->hw.sctrl_r |= SCTRL_B2_ENA; - hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; - if (!tics) - hc->hw.int_m1 |= HFCPCI_INTS_B2REC; - hc->hw.ctmt |= 2; - hc->hw.conn &= ~0x18; -#ifdef REVERSE_BITORDER - hc->hw.cirm |= 0x80; -#endif - } else { - hc->hw.sctrl_r |= SCTRL_B1_ENA; - hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; - if (!tics) - hc->hw.int_m1 |= HFCPCI_INTS_B1REC; - hc->hw.ctmt |= 1; - hc->hw.conn &= ~0x03; -#ifdef REVERSE_BITORDER - hc->hw.cirm |= 0x40; -#endif - } - break; - case (ISDN_P_B_HDLC): - bch->state = protocol; - hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); - if (chan & 2) { - hc->hw.sctrl_r |= SCTRL_B2_ENA; - hc->hw.last_bfifo_cnt[1] = 0; - hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; - hc->hw.int_m1 |= HFCPCI_INTS_B2REC; - hc->hw.ctmt &= ~2; - hc->hw.conn &= ~0x18; - } else { - hc->hw.sctrl_r |= SCTRL_B1_ENA; - hc->hw.last_bfifo_cnt[0] = 0; - hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; - hc->hw.int_m1 |= HFCPCI_INTS_B1REC; - hc->hw.ctmt &= ~1; - hc->hw.conn &= ~0x03; - } - break; - default: - printk(KERN_DEBUG "prot not known %x\n", protocol); - return -ENOPROTOOPT; - } - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); - Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); -#ifdef REVERSE_BITORDER - Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); -#endif - return 0; -} - -static void -deactivate_bchannel(struct bchannel *bch) -{ - struct hfc_pci *hc = bch->hw; - u_long flags; - - spin_lock_irqsave(&hc->lock, flags); - mISDN_clear_bchannel(bch); - mode_hfcpci(bch, bch->nr, ISDN_P_NONE); - spin_unlock_irqrestore(&hc->lock, flags); -} - -/* - * Layer 1 B-channel hardware access - */ -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - return mISDN_ctrl_bchannel(bch, cq); -} -static int -hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct hfc_pci *hc = bch->hw; - int ret = -EINVAL; - u_long flags; - - if (bch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); - switch (cmd) { - case HW_TESTRX_RAW: - spin_lock_irqsave(&hc->lock, flags); - ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg); - spin_unlock_irqrestore(&hc->lock, flags); - break; - case HW_TESTRX_HDLC: - spin_lock_irqsave(&hc->lock, flags); - ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg); - spin_unlock_irqrestore(&hc->lock, flags); - break; - case HW_TESTRX_OFF: - spin_lock_irqsave(&hc->lock, flags); - mode_hfcpci(bch, bch->nr, ISDN_P_NONE); - spin_unlock_irqrestore(&hc->lock, flags); - ret = 0; - break; - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - deactivate_bchannel(bch); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(THIS_MODULE); - ret = 0; - break; - case CONTROL_CHANNEL: - ret = channel_bctrl(bch, arg); - break; - default: - printk(KERN_WARNING "%s: unknown prim(%x)\n", - __func__, cmd); - } - return ret; -} - -/* - * Layer2 -> Layer 1 Dchannel data - */ -static int -hfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct hfc_pci *hc = dch->hw; - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned int id; - u_long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(&hc->lock, flags); - ret = dchannel_senddata(dch, skb); - if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ - hfcpci_fill_dfifo(dch->hw); - ret = 0; - spin_unlock_irqrestore(&hc->lock, flags); - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&hc->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - spin_lock_irqsave(&hc->lock, flags); - if (hc->hw.protocol == ISDN_P_NT_S0) { - ret = 0; - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - if (test_bit(FLG_ACTIVE, &dch->Flags)) { - spin_unlock_irqrestore(&hc->lock, flags); - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - break; - } - test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | - HFCPCI_DO_ACTION | 1); - } else - ret = l1_event(dch->l1, hh->prim); - spin_unlock_irqrestore(&hc->lock, flags); - break; - case PH_DEACTIVATE_REQ: - test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); - spin_lock_irqsave(&hc->lock, flags); - if (hc->hw.protocol == ISDN_P_NT_S0) { - struct sk_buff_head free_queue; - - __skb_queue_head_init(&free_queue); - /* prepare deactivation */ - Write_hfc(hc, HFCPCI_STATES, 0x40); - skb_queue_splice_init(&dch->squeue, &free_queue); - if (dch->tx_skb) { - __skb_queue_tail(&free_queue, dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - __skb_queue_tail(&free_queue, dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) - timer_delete(&dch->timer); -#ifdef FIXME - if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) - dchannel_sched_event(&hc->dch, D_CLEARBUSY); -#endif - hc->hw.mst_m &= ~HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - ret = 0; - spin_unlock_irqrestore(&hc->lock, flags); - __skb_queue_purge(&free_queue); - } else { - ret = l1_event(dch->l1, hh->prim); - spin_unlock_irqrestore(&hc->lock, flags); - } - break; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -/* - * Layer2 -> Layer 1 Bchannel data - */ -static int -hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct hfc_pci *hc = bch->hw; - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(&hc->lock, flags); - ret = bchannel_senddata(bch, skb); - if (ret > 0) { /* direct TX */ - hfcpci_fill_fifo(bch); - ret = 0; - } - spin_unlock_irqrestore(&hc->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - spin_lock_irqsave(&hc->lock, flags); - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) - ret = mode_hfcpci(bch, bch->nr, ch->protocol); - else - ret = 0; - spin_unlock_irqrestore(&hc->lock, flags); - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - break; - case PH_DEACTIVATE_REQ: - deactivate_bchannel(bch); - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - ret = 0; - break; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -/* - * called for card init message - */ - -static void -inithfcpci(struct hfc_pci *hc) -{ - printk(KERN_DEBUG "inithfcpci: entered\n"); - timer_setup(&hc->dch.timer, hfcpci_dbusy_timer, 0); - hc->chanlimit = 2; - mode_hfcpci(&hc->bch[0], 1, -1); - mode_hfcpci(&hc->bch[1], 2, -1); -} - - -static int -init_card(struct hfc_pci *hc) -{ - int cnt = 3; - u_long flags; - - printk(KERN_DEBUG "init_card: entered\n"); - - - spin_lock_irqsave(&hc->lock, flags); - disable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) { - printk(KERN_WARNING - "mISDN: couldn't get interrupt %d\n", hc->irq); - return -EIO; - } - spin_lock_irqsave(&hc->lock, flags); - reset_hfcpci(hc); - while (cnt) { - inithfcpci(hc); - /* - * Finally enable IRQ output - * this is only allowed, if an IRQ routine is already - * established for this HFC, so don't do that earlier - */ - enable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - /* Timeout 80ms */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((80 * HZ) / 1000); - printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", - hc->irq, hc->irqcnt); - /* now switch timer interrupt off */ - spin_lock_irqsave(&hc->lock, flags); - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - /* reinit mode reg */ - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - if (!hc->irqcnt) { - printk(KERN_WARNING - "HFC PCI: IRQ(%d) getting no interrupts " - "during init %d\n", hc->irq, 4 - cnt); - if (cnt == 1) - break; - else { - reset_hfcpci(hc); - cnt--; - } - } else { - spin_unlock_irqrestore(&hc->lock, flags); - hc->initdone = 1; - return 0; - } - } - disable_hwirq(hc); - spin_unlock_irqrestore(&hc->lock, flags); - free_irq(hc->irq, hc); - return -EIO; -} - -static int -channel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - u_char slot; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | - MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3; - break; - case MISDN_CTRL_LOOP: - /* channel 0 disabled loop */ - if (cq->channel < 0 || cq->channel > 2) { - ret = -EINVAL; - break; - } - if (cq->channel & 1) { - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) - slot = 0xC0; - else - slot = 0x80; - printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", - __func__, slot); - Write_hfc(hc, HFCPCI_B1_SSL, slot); - Write_hfc(hc, HFCPCI_B1_RSL, slot); - hc->hw.conn = (hc->hw.conn & ~7) | 6; - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - } - if (cq->channel & 2) { - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) - slot = 0xC1; - else - slot = 0x81; - printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", - __func__, slot); - Write_hfc(hc, HFCPCI_B2_SSL, slot); - Write_hfc(hc, HFCPCI_B2_RSL, slot); - hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30; - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - } - if (cq->channel & 3) - hc->hw.trm |= 0x80; /* enable IOM-loop */ - else { - hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - hc->hw.trm &= 0x7f; /* disable IOM-loop */ - } - Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); - break; - case MISDN_CTRL_CONNECT: - if (cq->channel == cq->p1) { - ret = -EINVAL; - break; - } - if (cq->channel < 1 || cq->channel > 2 || - cq->p1 < 1 || cq->p1 > 2) { - ret = -EINVAL; - break; - } - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) - slot = 0xC0; - else - slot = 0x80; - printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", - __func__, slot); - Write_hfc(hc, HFCPCI_B1_SSL, slot); - Write_hfc(hc, HFCPCI_B2_RSL, slot); - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) - slot = 0xC1; - else - slot = 0x81; - printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", - __func__, slot); - Write_hfc(hc, HFCPCI_B2_SSL, slot); - Write_hfc(hc, HFCPCI_B1_RSL, slot); - hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36; - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - hc->hw.trm |= 0x80; - Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); - break; - case MISDN_CTRL_DISCONNECT: - hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - hc->hw.trm &= 0x7f; /* disable IOM-loop */ - break; - case MISDN_CTRL_L1_TIMER3: - ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); - break; - default: - printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, - struct channel_req *rq) -{ - int err = 0; - - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, - hc->dch.dev.id, __builtin_return_address(0)); - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - if (rq->adr.channel == 1) { - /* TODO: E-Channel */ - return -EINVAL; - } - if (!hc->initdone) { - if (rq->protocol == ISDN_P_TE_S0) { - err = create_l1(&hc->dch, hfc_l1callback); - if (err) - return err; - } - hc->hw.protocol = rq->protocol; - ch->protocol = rq->protocol; - err = init_card(hc); - if (err) - return err; - } else { - if (rq->protocol != ch->protocol) { - if (hc->hw.protocol == ISDN_P_TE_S0) - l1_event(hc->dch.l1, CLOSE_CHANNEL); - if (rq->protocol == ISDN_P_TE_S0) { - err = create_l1(&hc->dch, hfc_l1callback); - if (err) - return err; - } - hc->hw.protocol = rq->protocol; - ch->protocol = rq->protocol; - hfcpci_setmode(hc); - } - } - - if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) || - ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) { - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - } - rq->ch = ch; - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s:cannot get module\n", __func__); - return 0; -} - -static int -open_bchannel(struct hfc_pci *hc, struct channel_req *rq) -{ - struct bchannel *bch; - - if (rq->adr.channel == 0 || rq->adr.channel > 2) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - bch = &hc->bch[rq->adr.channel - 1]; - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; /* TODO: E-channel */ - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s:cannot get module\n", __func__); - return 0; -} - -/* - * device control function - */ -static int -hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct hfc_pci *hc = dch->hw; - struct channel_req *rq; - int err = 0; - - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: cmd:%x %p\n", - __func__, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - if ((rq->protocol == ISDN_P_TE_S0) || - (rq->protocol == ISDN_P_NT_S0)) - err = open_dchannel(hc, ch, rq); - else - err = open_bchannel(hc, rq); - break; - case CLOSE_CHANNEL: - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: dev(%d) close from %p\n", - __func__, hc->dch.dev.id, - __builtin_return_address(0)); - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - err = channel_ctrl(hc, arg); - break; - default: - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: unknown command %x\n", - __func__, cmd); - return -EINVAL; - } - return err; -} - -static int -setup_hw(struct hfc_pci *hc) -{ - void *buffer; - - printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision); - hc->hw.cirm = 0; - hc->dch.state = 0; - pci_set_master(hc->pdev); - if (!hc->irq) { - printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); - return -EINVAL; - } - hc->hw.pci_io = - (char __iomem *)(unsigned long)hc->pdev->resource[1].start; - - if (!hc->hw.pci_io) { - printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); - return -ENOMEM; - } - /* Allocate memory for FIFOS */ - /* the memory needs to be on a 32k boundary within the first 4G */ - if (dma_set_mask(&hc->pdev->dev, 0xFFFF8000)) { - printk(KERN_WARNING - "HFC-PCI: No usable DMA configuration!\n"); - return -EIO; - } - buffer = dma_alloc_coherent(&hc->pdev->dev, 0x8000, &hc->hw.dmahandle, - GFP_KERNEL); - /* We silently assume the address is okay if nonzero */ - if (!buffer) { - printk(KERN_WARNING - "HFC-PCI: Error allocating memory for FIFO!\n"); - return -ENOMEM; - } - hc->hw.fifos = buffer; - pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle); - hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256); - if (unlikely(!hc->hw.pci_io)) { - printk(KERN_WARNING - "HFC-PCI: Error in ioremap for PCI!\n"); - dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos, - hc->hw.dmahandle); - return -ENOMEM; - } - - printk(KERN_INFO - "HFC-PCI: defined at mem %#lx fifo %p(%pad) IRQ %d HZ %d\n", - (u_long) hc->hw.pci_io, hc->hw.fifos, - &hc->hw.dmahandle, hc->irq, HZ); - - /* enable memory mapped ports, disable busmaster */ - pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); - hc->hw.int_m2 = 0; - disable_hwirq(hc); - hc->hw.int_m1 = 0; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - /* At this point the needed PCI config is done */ - /* fifos are still not enabled */ - timer_setup(&hc->hw.timer, hfcpci_Timer, 0); - /* default PCM master */ - test_and_set_bit(HFC_CFG_MASTER, &hc->cfg); - return 0; -} - -static void -release_card(struct hfc_pci *hc) { - u_long flags; - - spin_lock_irqsave(&hc->lock, flags); - hc->hw.int_m2 = 0; /* interrupt output off ! */ - disable_hwirq(hc); - mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE); - mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE); - if (hc->dch.timer.function != NULL) { - timer_delete(&hc->dch.timer); - hc->dch.timer.function = NULL; - } - spin_unlock_irqrestore(&hc->lock, flags); - if (hc->hw.protocol == ISDN_P_TE_S0) - l1_event(hc->dch.l1, CLOSE_CHANNEL); - if (hc->initdone) - free_irq(hc->irq, hc); - release_io_hfcpci(hc); /* must release after free_irq! */ - mISDN_unregister_device(&hc->dch.dev); - mISDN_freebchannel(&hc->bch[1]); - mISDN_freebchannel(&hc->bch[0]); - mISDN_freedchannel(&hc->dch); - pci_set_drvdata(hc->pdev, NULL); - kfree(hc); -} - -static int -setup_card(struct hfc_pci *card) -{ - int err = -EINVAL; - u_int i; - char name[MISDN_MAX_IDLEN]; - - card->dch.debug = debug; - spin_lock_init(&card->lock); - mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); - card->dch.hw = card; - card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); - card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - card->dch.dev.D.send = hfcpci_l2l1D; - card->dch.dev.D.ctrl = hfc_dctrl; - card->dch.dev.nrbchan = 2; - for (i = 0; i < 2; i++) { - card->bch[i].nr = i + 1; - set_channelmap(i + 1, card->dch.dev.channelmap); - card->bch[i].debug = debug; - mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1); - card->bch[i].hw = card; - card->bch[i].ch.send = hfcpci_l2l1B; - card->bch[i].ch.ctrl = hfc_bctrl; - card->bch[i].ch.nr = i + 1; - list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels); - } - err = setup_hw(card); - if (err) - goto error; - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); - err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name); - if (err) - goto error; - HFC_cnt++; - printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); - return 0; -error: - mISDN_freebchannel(&card->bch[1]); - mISDN_freebchannel(&card->bch[0]); - mISDN_freedchannel(&card->dch); - kfree(card); - return err; -} - -/* private data in the PCI devices list */ -struct _hfc_map { - u_int subtype; - u_int flag; - char *name; -}; - -static const struct _hfc_map hfc_map[] = -{ - {HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"}, - {HFC_CCD_B000, 0, "Billion B000"}, - {HFC_CCD_B006, 0, "Billion B006"}, - {HFC_CCD_B007, 0, "Billion B007"}, - {HFC_CCD_B008, 0, "Billion B008"}, - {HFC_CCD_B009, 0, "Billion B009"}, - {HFC_CCD_B00A, 0, "Billion B00A"}, - {HFC_CCD_B00B, 0, "Billion B00B"}, - {HFC_CCD_B00C, 0, "Billion B00C"}, - {HFC_CCD_B100, 0, "Seyeon B100"}, - {HFC_CCD_B700, 0, "Primux II S0 B700"}, - {HFC_CCD_B701, 0, "Primux II S0 NT B701"}, - {HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"}, - {HFC_ASUS_0675, 0, "Asuscom/Askey 675"}, - {HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"}, - {HFC_BERKOM_A1T, 0, "German telekom A1T"}, - {HFC_ANIGMA_MC145575, 0, "Motorola MC145575"}, - {HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"}, - {HFC_DIGI_DF_M_IOM2_E, 0, - "Digi International DataFire Micro V IOM2 (Europe)"}, - {HFC_DIGI_DF_M_E, 0, - "Digi International DataFire Micro V (Europe)"}, - {HFC_DIGI_DF_M_IOM2_A, 0, - "Digi International DataFire Micro V IOM2 (North America)"}, - {HFC_DIGI_DF_M_A, 0, - "Digi International DataFire Micro V (North America)"}, - {HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"}, - {}, -}; - -static const struct pci_device_id hfc_ids[] = -{ - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0), - (unsigned long) &hfc_map[0] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000), - (unsigned long) &hfc_map[1] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006), - (unsigned long) &hfc_map[2] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007), - (unsigned long) &hfc_map[3] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008), - (unsigned long) &hfc_map[4] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009), - (unsigned long) &hfc_map[5] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A), - (unsigned long) &hfc_map[6] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B), - (unsigned long) &hfc_map[7] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C), - (unsigned long) &hfc_map[8] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100), - (unsigned long) &hfc_map[9] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700), - (unsigned long) &hfc_map[10] }, - { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701), - (unsigned long) &hfc_map[11] }, - { PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1), - (unsigned long) &hfc_map[12] }, - { PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675), - (unsigned long) &hfc_map[13] }, - { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT), - (unsigned long) &hfc_map[14] }, - { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T), - (unsigned long) &hfc_map[15] }, - { PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575), - (unsigned long) &hfc_map[16] }, - { PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0), - (unsigned long) &hfc_map[17] }, - { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E), - (unsigned long) &hfc_map[18] }, - { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E), - (unsigned long) &hfc_map[19] }, - { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A), - (unsigned long) &hfc_map[20] }, - { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A), - (unsigned long) &hfc_map[21] }, - { PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2), - (unsigned long) &hfc_map[22] }, - {}, -}; - -static int -hfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - struct hfc_pci *card; - struct _hfc_map *m = (struct _hfc_map *)ent->driver_data; - - card = kzalloc_obj(struct hfc_pci); - if (!card) { - printk(KERN_ERR "No kmem for HFC card\n"); - return err; - } - card->pdev = pdev; - card->subtype = m->subtype; - err = pci_enable_device(pdev); - if (err) { - kfree(card); - return err; - } - - printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n", - m->name, pci_name(pdev)); - - card->irq = pdev->irq; - pci_set_drvdata(pdev, card); - err = setup_card(card); - if (err) - pci_set_drvdata(pdev, NULL); - return err; -} - -static void -hfc_remove_pci(struct pci_dev *pdev) -{ - struct hfc_pci *card = pci_get_drvdata(pdev); - - if (card) - release_card(card); - else - if (debug) - printk(KERN_DEBUG "%s: drvdata already removed\n", - __func__); -} - - -static struct pci_driver hfc_driver = { - .name = "hfcpci", - .probe = hfc_probe, - .remove = hfc_remove_pci, - .id_table = hfc_ids, -}; - -static int -_hfcpci_softirq(struct device *dev, void *unused) -{ - struct hfc_pci *hc = dev_get_drvdata(dev); - struct bchannel *bch; - if (hc == NULL) - return 0; - - if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { - spin_lock_irq(&hc->lock); - bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); - if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ - main_rec_hfcpci(bch); - tx_birq(bch); - } - bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); - if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ - main_rec_hfcpci(bch); - tx_birq(bch); - } - spin_unlock_irq(&hc->lock); - } - return 0; -} - -static void -hfcpci_softirq(struct timer_list *unused) -{ - WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, NULL, - _hfcpci_softirq) != 0); - - /* if next event would be in the past ... */ - if ((s32)(hfc_jiffies + tics - jiffies) <= 0) - hfc_jiffies = jiffies + 1; - else - hfc_jiffies += tics; - mod_timer(&hfc_tl, hfc_jiffies); -} - -static int __init -HFC_init(void) -{ - int err; - - if (!poll) - poll = HFCPCI_BTRANS_THRESHOLD; - - if (poll != HFCPCI_BTRANS_THRESHOLD) { - tics = (poll * HZ) / 8000; - if (tics < 1) - tics = 1; - poll = (tics * 8000) / HZ; - if (poll > 256 || poll < 8) { - printk(KERN_ERR "%s: Wrong poll value %d not in range " - "of 8..256.\n", __func__, poll); - err = -EINVAL; - return err; - } - } - if (poll != HFCPCI_BTRANS_THRESHOLD) { - printk(KERN_INFO "%s: Using alternative poll value of %d\n", - __func__, poll); - hfc_jiffies = jiffies + tics; - mod_timer(&hfc_tl, hfc_jiffies); - } else - tics = 0; /* indicate the use of controller's timer */ - - err = pci_register_driver(&hfc_driver); - if (err) { - if (timer_pending(&hfc_tl)) - timer_delete(&hfc_tl); - } - - return err; -} - -static void __exit -HFC_cleanup(void) -{ - timer_delete_sync(&hfc_tl); - - pci_unregister_driver(&hfc_driver); -} - -module_init(HFC_init); -module_exit(HFC_cleanup); - -MODULE_DEVICE_TABLE(pci, hfc_ids); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c deleted file mode 100644 index 227babe83879..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ /dev/null @@ -1,2157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* hfcsusb.c - * mISDN driver for Colognechip HFC-S USB chip - * - * Copyright 2001 by Peter Sprenger (sprenger@moving-bytes.de) - * Copyright 2008 by Martin Bachem (info@bachem-it.com) - * - * module params - * debug=, default=0, with n=0xHHHHGGGG - * H - l1 driver flags described in hfcsusb.h - * G - common mISDN debug flags described at mISDNhw.h - * - * poll=, default 128 - * n : burst size of PH_DATA_IND at transparent rx data - * - * Revision: 0.3.3 (socket), 2008-11-05 - */ - -#include -#include -#include -#include -#include -#include "hfcsusb.h" - -static unsigned int debug; -static int poll = DEFAULT_TRANSP_BURST_SZ; - -static LIST_HEAD(HFClist); -static DEFINE_RWLOCK(HFClock); - - -MODULE_AUTHOR("Martin Bachem"); -MODULE_DESCRIPTION("mISDN driver for Colognechip HFC-S USB chip"); -MODULE_LICENSE("GPL"); -module_param(debug, uint, S_IRUGO | S_IWUSR); -module_param(poll, int, 0); - -static int hfcsusb_cnt; - -/* some function prototypes */ -static void hfcsusb_ph_command(struct hfcsusb *hw, u_char command); -static void release_hw(struct hfcsusb *hw); -static void reset_hfcsusb(struct hfcsusb *hw); -static void setPortMode(struct hfcsusb *hw); -static void hfcsusb_start_endpoint(struct hfcsusb *hw, int channel); -static void hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel); -static int hfcsusb_setup_bch(struct bchannel *bch, int protocol); -static void deactivate_bchannel(struct bchannel *bch); -static int hfcsusb_ph_info(struct hfcsusb *hw); - -/* start next background transfer for control channel */ -static void -ctrl_start_transfer(struct hfcsusb *hw) -{ - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); - - if (hw->ctrl_cnt) { - hw->ctrl_urb->pipe = hw->ctrl_out_pipe; - hw->ctrl_urb->setup_packet = (u_char *)&hw->ctrl_write; - hw->ctrl_urb->transfer_buffer = NULL; - hw->ctrl_urb->transfer_buffer_length = 0; - hw->ctrl_write.wIndex = - cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].hfcs_reg); - hw->ctrl_write.wValue = - cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].reg_val); - - usb_submit_urb(hw->ctrl_urb, GFP_ATOMIC); - } -} - -/* - * queue a control transfer request to write HFC-S USB - * chip register using CTRL resuest queue - */ -static int write_reg(struct hfcsusb *hw, __u8 reg, __u8 val) -{ - struct ctrl_buf *buf; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s reg(0x%02x) val(0x%02x)\n", - hw->name, __func__, reg, val); - - spin_lock(&hw->ctrl_lock); - if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE) { - spin_unlock(&hw->ctrl_lock); - return 1; - } - buf = &hw->ctrl_buff[hw->ctrl_in_idx]; - buf->hfcs_reg = reg; - buf->reg_val = val; - if (++hw->ctrl_in_idx >= HFC_CTRL_BUFSIZE) - hw->ctrl_in_idx = 0; - if (++hw->ctrl_cnt == 1) - ctrl_start_transfer(hw); - spin_unlock(&hw->ctrl_lock); - - return 0; -} - -/* control completion routine handling background control cmds */ -static void -ctrl_complete(struct urb *urb) -{ - struct hfcsusb *hw = (struct hfcsusb *) urb->context; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); - - urb->dev = hw->dev; - if (hw->ctrl_cnt) { - hw->ctrl_cnt--; /* decrement actual count */ - if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE) - hw->ctrl_out_idx = 0; /* pointer wrap */ - - ctrl_start_transfer(hw); /* start next transfer */ - } -} - -/* handle LED bits */ -static void -set_led_bit(struct hfcsusb *hw, signed short led_bits, int set_on) -{ - if (set_on) { - if (led_bits < 0) - hw->led_state &= ~abs(led_bits); - else - hw->led_state |= led_bits; - } else { - if (led_bits < 0) - hw->led_state |= abs(led_bits); - else - hw->led_state &= ~led_bits; - } -} - -/* handle LED requests */ -static void -handle_led(struct hfcsusb *hw, int event) -{ - struct hfcsusb_vdata *driver_info = (struct hfcsusb_vdata *) - hfcsusb_idtab[hw->vend_idx].driver_info; - __u8 tmpled; - - if (driver_info->led_scheme == LED_OFF) - return; - tmpled = hw->led_state; - - switch (event) { - case LED_POWER_ON: - set_led_bit(hw, driver_info->led_bits[0], 1); - set_led_bit(hw, driver_info->led_bits[1], 0); - set_led_bit(hw, driver_info->led_bits[2], 0); - set_led_bit(hw, driver_info->led_bits[3], 0); - break; - case LED_POWER_OFF: - set_led_bit(hw, driver_info->led_bits[0], 0); - set_led_bit(hw, driver_info->led_bits[1], 0); - set_led_bit(hw, driver_info->led_bits[2], 0); - set_led_bit(hw, driver_info->led_bits[3], 0); - break; - case LED_S0_ON: - set_led_bit(hw, driver_info->led_bits[1], 1); - break; - case LED_S0_OFF: - set_led_bit(hw, driver_info->led_bits[1], 0); - break; - case LED_B1_ON: - set_led_bit(hw, driver_info->led_bits[2], 1); - break; - case LED_B1_OFF: - set_led_bit(hw, driver_info->led_bits[2], 0); - break; - case LED_B2_ON: - set_led_bit(hw, driver_info->led_bits[3], 1); - break; - case LED_B2_OFF: - set_led_bit(hw, driver_info->led_bits[3], 0); - break; - } - - if (hw->led_state != tmpled) { - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s reg(0x%02x) val(x%02x)\n", - hw->name, __func__, - HFCUSB_P_DATA, hw->led_state); - - write_reg(hw, HFCUSB_P_DATA, hw->led_state); - } -} - -/* - * Layer2 -> Layer 1 Bchannel data - */ -static int -hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct hfcsusb *hw = bch->hw; - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - u_long flags; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(&hw->lock, flags); - ret = bchannel_senddata(bch, skb); - spin_unlock_irqrestore(&hw->lock, flags); - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n", - hw->name, __func__, ret); - if (ret > 0) - ret = 0; - return ret; - case PH_ACTIVATE_REQ: - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { - hfcsusb_start_endpoint(hw, bch->nr - 1); - ret = hfcsusb_setup_bch(bch, ch->protocol); - } else - ret = 0; - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - break; - case PH_DEACTIVATE_REQ: - deactivate_bchannel(bch); - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - ret = 0; - break; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -/* - * send full D/B channel status information - * as MPH_INFORMATION_IND - */ -static int -hfcsusb_ph_info(struct hfcsusb *hw) -{ - struct ph_info *phi; - struct dchannel *dch = &hw->dch; - int i; - - phi = kzalloc_flex(*phi, bch, dch->dev.nrbchan, GFP_ATOMIC); - if (!phi) - return -ENOMEM; - - phi->dch.ch.protocol = hw->protocol; - phi->dch.ch.Flags = dch->Flags; - phi->dch.state = dch->state; - phi->dch.num_bch = dch->dev.nrbchan; - for (i = 0; i < dch->dev.nrbchan; i++) { - phi->bch[i].protocol = hw->bch[i].ch.protocol; - phi->bch[i].Flags = hw->bch[i].Flags; - } - _queue_data(&dch->dev.D, MPH_INFORMATION_IND, MISDN_ID_ANY, - struct_size(phi, bch, dch->dev.nrbchan), phi, GFP_ATOMIC); - kfree(phi); - - return 0; -} - -/* - * Layer2 -> Layer 1 Dchannel data - */ -static int -hfcusb_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct mISDNhead *hh = mISDN_HEAD_P(skb); - struct hfcsusb *hw = dch->hw; - int ret = -EINVAL; - u_long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s: PH_DATA_REQ\n", - hw->name, __func__); - - spin_lock_irqsave(&hw->lock, flags); - ret = dchannel_senddata(dch, skb); - spin_unlock_irqrestore(&hw->lock, flags); - if (ret > 0) { - ret = 0; - queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL); - } - break; - - case PH_ACTIVATE_REQ: - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s: PH_ACTIVATE_REQ %s\n", - hw->name, __func__, - (hw->protocol == ISDN_P_NT_S0) ? "NT" : "TE"); - - if (hw->protocol == ISDN_P_NT_S0) { - ret = 0; - if (test_bit(FLG_ACTIVE, &dch->Flags)) { - _queue_data(&dch->dev.D, - PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_ATOMIC); - } else { - hfcsusb_ph_command(hw, - HFC_L1_ACTIVATE_NT); - test_and_set_bit(FLG_L2_ACTIVATED, - &dch->Flags); - } - } else { - hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_TE); - ret = l1_event(dch->l1, hh->prim); - } - break; - - case PH_DEACTIVATE_REQ: - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s: PH_DEACTIVATE_REQ\n", - hw->name, __func__); - test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); - - if (hw->protocol == ISDN_P_NT_S0) { - struct sk_buff_head free_queue; - - __skb_queue_head_init(&free_queue); - hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT); - spin_lock_irqsave(&hw->lock, flags); - skb_queue_splice_init(&dch->squeue, &free_queue); - if (dch->tx_skb) { - __skb_queue_tail(&free_queue, dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - __skb_queue_tail(&free_queue, dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - spin_unlock_irqrestore(&hw->lock, flags); - __skb_queue_purge(&free_queue); -#ifdef FIXME - if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) - dchannel_sched_event(&hc->dch, D_CLEARBUSY); -#endif - ret = 0; - } else - ret = l1_event(dch->l1, hh->prim); - break; - case MPH_INFORMATION_REQ: - ret = hfcsusb_ph_info(hw); - break; - } - - return ret; -} - -/* - * Layer 1 callback function - */ -static int -hfc_l1callback(struct dchannel *dch, u_int cmd) -{ - struct hfcsusb *hw = dch->hw; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s cmd 0x%x\n", - hw->name, __func__, cmd); - - switch (cmd) { - case INFO3_P8: - case INFO3_P10: - case HW_RESET_REQ: - case HW_POWERUP_REQ: - break; - - case HW_DEACT_REQ: - skb_queue_purge(&dch->squeue); - if (dch->tx_skb) { - dev_kfree_skb(dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - dev_kfree_skb(dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - break; - case PH_ACTIVATE_IND: - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - case PH_DEACTIVATE_IND: - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - default: - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: unknown cmd %x\n", - hw->name, __func__, cmd); - return -1; - } - return hfcsusb_ph_info(hw); -} - -static int -open_dchannel(struct hfcsusb *hw, struct mISDNchannel *ch, - struct channel_req *rq) -{ - int err = 0; - - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: %s: dev(%d) open addr(%i) from %p\n", - hw->name, __func__, hw->dch.dev.id, rq->adr.channel, - __builtin_return_address(0)); - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - - test_and_clear_bit(FLG_ACTIVE, &hw->dch.Flags); - test_and_clear_bit(FLG_ACTIVE, &hw->ech.Flags); - hfcsusb_start_endpoint(hw, HFC_CHAN_D); - - /* E-Channel logging */ - if (rq->adr.channel == 1) { - if (hw->fifos[HFCUSB_PCM_RX].pipe) { - hfcsusb_start_endpoint(hw, HFC_CHAN_E); - set_bit(FLG_ACTIVE, &hw->ech.Flags); - _queue_data(&hw->ech.dev.D, PH_ACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - } else - return -EINVAL; - } - - if (!hw->initdone) { - hw->protocol = rq->protocol; - if (rq->protocol == ISDN_P_TE_S0) { - err = create_l1(&hw->dch, hfc_l1callback); - if (err) - return err; - } - setPortMode(hw); - ch->protocol = rq->protocol; - hw->initdone = 1; - } else { - if (rq->protocol != ch->protocol) - return -EPROTONOSUPPORT; - } - - if (((ch->protocol == ISDN_P_NT_S0) && (hw->dch.state == 3)) || - ((ch->protocol == ISDN_P_TE_S0) && (hw->dch.state == 7))) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - rq->ch = ch; - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s: %s: cannot get module\n", - hw->name, __func__); - return 0; -} - -static int -open_bchannel(struct hfcsusb *hw, struct channel_req *rq) -{ - struct bchannel *bch; - - if (rq->adr.channel == 0 || rq->adr.channel > 2) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s B%i\n", - hw->name, __func__, rq->adr.channel); - - bch = &hw->bch[rq->adr.channel - 1]; - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; - - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s: %s:cannot get module\n", - hw->name, __func__); - return 0; -} - -static int -channel_ctrl(struct hfcsusb *hw, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s op(0x%x) channel(0x%x)\n", - hw->name, __func__, (cq->op), (cq->channel)); - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | - MISDN_CTRL_DISCONNECT; - break; - default: - printk(KERN_WARNING "%s: %s: unknown Op %x\n", - hw->name, __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -/* - * device control function - */ -static int -hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct hfcsusb *hw = dch->hw; - struct channel_req *rq; - int err = 0; - - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: cmd:%x %p\n", - hw->name, __func__, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - if ((rq->protocol == ISDN_P_TE_S0) || - (rq->protocol == ISDN_P_NT_S0)) - err = open_dchannel(hw, ch, rq); - else - err = open_bchannel(hw, rq); - if (!err) - hw->open++; - break; - case CLOSE_CHANNEL: - hw->open--; - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG - "%s: %s: dev(%d) close from %p (open %d)\n", - hw->name, __func__, hw->dch.dev.id, - __builtin_return_address(0), hw->open); - if (!hw->open) { - hfcsusb_stop_endpoint(hw, HFC_CHAN_D); - if (hw->fifos[HFCUSB_PCM_RX].pipe) - hfcsusb_stop_endpoint(hw, HFC_CHAN_E); - handle_led(hw, LED_POWER_ON); - } - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - err = channel_ctrl(hw, arg); - break; - default: - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: unknown command %x\n", - hw->name, __func__, cmd); - return -EINVAL; - } - return err; -} - -/* - * S0 TE state change event handler - */ -static void -ph_state_te(struct dchannel *dch) -{ - struct hfcsusb *hw = dch->hw; - - if (debug & DEBUG_HW) { - if (dch->state <= HFC_MAX_TE_LAYER1_STATE) - printk(KERN_DEBUG "%s: %s: %s\n", hw->name, __func__, - HFC_TE_LAYER1_STATES[dch->state]); - else - printk(KERN_DEBUG "%s: %s: TE F%d\n", - hw->name, __func__, dch->state); - } - - switch (dch->state) { - case 0: - l1_event(dch->l1, HW_RESET_IND); - break; - case 3: - l1_event(dch->l1, HW_DEACT_IND); - break; - case 5: - case 8: - l1_event(dch->l1, ANYSIGNAL); - break; - case 6: - l1_event(dch->l1, INFO2); - break; - case 7: - l1_event(dch->l1, INFO4_P8); - break; - } - if (dch->state == 7) - handle_led(hw, LED_S0_ON); - else - handle_led(hw, LED_S0_OFF); -} - -/* - * S0 NT state change event handler - */ -static void -ph_state_nt(struct dchannel *dch) -{ - struct hfcsusb *hw = dch->hw; - - if (debug & DEBUG_HW) { - if (dch->state <= HFC_MAX_NT_LAYER1_STATE) - printk(KERN_DEBUG "%s: %s: %s\n", - hw->name, __func__, - HFC_NT_LAYER1_STATES[dch->state]); - - else - printk(KERN_INFO DRIVER_NAME "%s: %s: NT G%d\n", - hw->name, __func__, dch->state); - } - - switch (dch->state) { - case (1): - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); - hw->nt_timer = 0; - hw->timers &= ~NT_ACTIVATION_TIMER; - handle_led(hw, LED_S0_OFF); - break; - - case (2): - if (hw->nt_timer < 0) { - hw->nt_timer = 0; - hw->timers &= ~NT_ACTIVATION_TIMER; - hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT); - } else { - hw->timers |= NT_ACTIVATION_TIMER; - hw->nt_timer = NT_T1_COUNT; - /* allow G2 -> G3 transition */ - write_reg(hw, HFCUSB_STATES, 2 | HFCUSB_NT_G2_G3); - } - break; - case (3): - hw->nt_timer = 0; - hw->timers &= ~NT_ACTIVATION_TIMER; - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - handle_led(hw, LED_S0_ON); - break; - case (4): - hw->nt_timer = 0; - hw->timers &= ~NT_ACTIVATION_TIMER; - break; - default: - break; - } - hfcsusb_ph_info(hw); -} - -static void -ph_state(struct dchannel *dch) -{ - struct hfcsusb *hw = dch->hw; - - if (hw->protocol == ISDN_P_NT_S0) - ph_state_nt(dch); - else if (hw->protocol == ISDN_P_TE_S0) - ph_state_te(dch); -} - -/* - * disable/enable BChannel for desired protocol - */ -static int -hfcsusb_setup_bch(struct bchannel *bch, int protocol) -{ - struct hfcsusb *hw = bch->hw; - __u8 conhdlc, sctrl, sctrl_r; - - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: protocol %x-->%x B%d\n", - hw->name, __func__, bch->state, protocol, - bch->nr); - - /* setup val for CON_HDLC */ - conhdlc = 0; - if (protocol > ISDN_P_NONE) - conhdlc = 8; /* enable FIFO */ - - switch (protocol) { - case (-1): /* used for init */ - bch->state = -1; - fallthrough; - case (ISDN_P_NONE): - if (bch->state == ISDN_P_NONE) - return 0; /* already in idle state */ - bch->state = ISDN_P_NONE; - clear_bit(FLG_HDLC, &bch->Flags); - clear_bit(FLG_TRANSPARENT, &bch->Flags); - break; - case (ISDN_P_B_RAW): - conhdlc |= 2; - bch->state = protocol; - set_bit(FLG_TRANSPARENT, &bch->Flags); - break; - case (ISDN_P_B_HDLC): - bch->state = protocol; - set_bit(FLG_HDLC, &bch->Flags); - break; - default: - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: prot not known %x\n", - hw->name, __func__, protocol); - return -ENOPROTOOPT; - } - - if (protocol >= ISDN_P_NONE) { - write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 0 : 2); - write_reg(hw, HFCUSB_CON_HDLC, conhdlc); - write_reg(hw, HFCUSB_INC_RES_F, 2); - write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 1 : 3); - write_reg(hw, HFCUSB_CON_HDLC, conhdlc); - write_reg(hw, HFCUSB_INC_RES_F, 2); - - sctrl = 0x40 + ((hw->protocol == ISDN_P_TE_S0) ? 0x00 : 0x04); - sctrl_r = 0x0; - if (test_bit(FLG_ACTIVE, &hw->bch[0].Flags)) { - sctrl |= 1; - sctrl_r |= 1; - } - if (test_bit(FLG_ACTIVE, &hw->bch[1].Flags)) { - sctrl |= 2; - sctrl_r |= 2; - } - write_reg(hw, HFCUSB_SCTRL, sctrl); - write_reg(hw, HFCUSB_SCTRL_R, sctrl_r); - - if (protocol > ISDN_P_NONE) - handle_led(hw, (bch->nr == 1) ? LED_B1_ON : LED_B2_ON); - else - handle_led(hw, (bch->nr == 1) ? LED_B1_OFF : - LED_B2_OFF); - } - return hfcsusb_ph_info(hw); -} - -static void -hfcsusb_ph_command(struct hfcsusb *hw, u_char command) -{ - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: %x\n", - hw->name, __func__, command); - - switch (command) { - case HFC_L1_ACTIVATE_TE: - /* force sending sending INFO1 */ - write_reg(hw, HFCUSB_STATES, 0x14); - /* start l1 activation */ - write_reg(hw, HFCUSB_STATES, 0x04); - break; - - case HFC_L1_FORCE_DEACTIVATE_TE: - write_reg(hw, HFCUSB_STATES, 0x10); - write_reg(hw, HFCUSB_STATES, 0x03); - break; - - case HFC_L1_ACTIVATE_NT: - if (hw->dch.state == 3) - _queue_data(&hw->dch.dev.D, PH_ACTIVATE_IND, - MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); - else - write_reg(hw, HFCUSB_STATES, HFCUSB_ACTIVATE | - HFCUSB_DO_ACTION | HFCUSB_NT_G2_G3); - break; - - case HFC_L1_DEACTIVATE_NT: - write_reg(hw, HFCUSB_STATES, - HFCUSB_DO_ACTION); - break; - } -} - -/* - * Layer 1 B-channel hardware access - */ -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - return mISDN_ctrl_bchannel(bch, cq); -} - -/* collect data from incoming interrupt or isochron USB data */ -static void -hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, - int finish) -{ - struct hfcsusb *hw = fifo->hw; - struct sk_buff *rx_skb = NULL; - int maxlen = 0; - int fifon = fifo->fifonum; - int i; - int hdlc = 0; - unsigned long flags; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s: fifo(%i) len(%i) " - "dch(%p) bch(%p) ech(%p)\n", - hw->name, __func__, fifon, len, - fifo->dch, fifo->bch, fifo->ech); - - if (!len) - return; - - if ((!!fifo->dch + !!fifo->bch + !!fifo->ech) != 1) { - printk(KERN_DEBUG "%s: %s: undefined channel\n", - hw->name, __func__); - return; - } - - spin_lock_irqsave(&hw->lock, flags); - if (fifo->dch) { - rx_skb = fifo->dch->rx_skb; - maxlen = fifo->dch->maxlen; - hdlc = 1; - } - if (fifo->bch) { - if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) { - fifo->bch->dropcnt += len; - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - maxlen = bchannel_get_rxbuf(fifo->bch, len); - rx_skb = fifo->bch->rx_skb; - if (maxlen < 0) { - if (rx_skb) - skb_trim(rx_skb, 0); - pr_warn("%s.B%d: No bufferspace for %d bytes\n", - hw->name, fifo->bch->nr, len); - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - maxlen = fifo->bch->maxlen; - hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); - } - if (fifo->ech) { - rx_skb = fifo->ech->rx_skb; - maxlen = fifo->ech->maxlen; - hdlc = 1; - } - - if (fifo->dch || fifo->ech) { - if (!rx_skb) { - rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); - if (rx_skb) { - if (fifo->dch) - fifo->dch->rx_skb = rx_skb; - if (fifo->ech) - fifo->ech->rx_skb = rx_skb; - skb_trim(rx_skb, 0); - } else { - printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", - hw->name, __func__); - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - } - /* D/E-Channel SKB range check */ - if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { - printk(KERN_DEBUG "%s: %s: sbk mem exceeded " - "for fifo(%d) HFCUSB_D_RX\n", - hw->name, __func__, fifon); - skb_trim(rx_skb, 0); - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - } - - skb_put_data(rx_skb, data, len); - - if (hdlc) { - /* we have a complete hdlc packet */ - if (finish) { - if ((rx_skb->len > 3) && - (!(rx_skb->data[rx_skb->len - 1]))) { - if (debug & DBG_HFC_FIFO_VERBOSE) { - printk(KERN_DEBUG "%s: %s: fifon(%i)" - " new RX len(%i): ", - hw->name, __func__, fifon, - rx_skb->len); - i = 0; - while (i < rx_skb->len) - printk("%02x ", - rx_skb->data[i++]); - printk("\n"); - } - - /* remove CRC & status */ - skb_trim(rx_skb, rx_skb->len - 3); - - if (fifo->dch) - recv_Dchannel(fifo->dch); - if (fifo->bch) - recv_Bchannel(fifo->bch, MISDN_ID_ANY, - 0); - if (fifo->ech) - recv_Echannel(fifo->ech, - &hw->dch); - } else { - if (debug & DBG_HFC_FIFO_VERBOSE) { - printk(KERN_DEBUG - "%s: CRC or minlen ERROR fifon(%i) " - "RX len(%i): ", - hw->name, fifon, rx_skb->len); - i = 0; - while (i < rx_skb->len) - printk("%02x ", - rx_skb->data[i++]); - printk("\n"); - } - skb_trim(rx_skb, 0); - } - } - } else { - /* deliver transparent data to layer2 */ - recv_Bchannel(fifo->bch, MISDN_ID_ANY, false); - } - spin_unlock_irqrestore(&hw->lock, flags); -} - -static void -fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, - void *buf, int num_packets, int packet_size, int interval, - usb_complete_t complete, void *context) -{ - int k; - - usb_fill_bulk_urb(urb, dev, pipe, buf, packet_size * num_packets, - complete, context); - - urb->number_of_packets = num_packets; - urb->transfer_flags = URB_ISO_ASAP; - urb->actual_length = 0; - urb->interval = interval; - - for (k = 0; k < num_packets; k++) { - urb->iso_frame_desc[k].offset = packet_size * k; - urb->iso_frame_desc[k].length = packet_size; - urb->iso_frame_desc[k].actual_length = 0; - } -} - -/* receive completion routine for all ISO tx fifos */ -static void -rx_iso_complete(struct urb *urb) -{ - struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context; - struct usb_fifo *fifo = context_iso_urb->owner_fifo; - struct hfcsusb *hw = fifo->hw; - int k, len, errcode, offset, num_isoc_packets, fifon, maxlen, - status, iso_status, i; - __u8 *buf; - static __u8 eof[8]; - __u8 s0_state; - unsigned long flags; - - fifon = fifo->fifonum; - status = urb->status; - - spin_lock_irqsave(&hw->lock, flags); - if (fifo->stop_gracefull) { - fifo->stop_gracefull = 0; - fifo->active = 0; - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - spin_unlock_irqrestore(&hw->lock, flags); - - /* - * ISO transfer only partially completed, - * look at individual frame status for details - */ - if (status == -EXDEV) { - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: with -EXDEV " - "urb->status %d, fifonum %d\n", - hw->name, __func__, status, fifon); - - /* clear status, so go on with ISO transfers */ - status = 0; - } - - s0_state = 0; - if (fifo->active && !status) { - num_isoc_packets = iso_packets[fifon]; - maxlen = fifo->usb_packet_maxlen; - - for (k = 0; k < num_isoc_packets; ++k) { - len = urb->iso_frame_desc[k].actual_length; - offset = urb->iso_frame_desc[k].offset; - buf = context_iso_urb->buffer + offset; - iso_status = urb->iso_frame_desc[k].status; - - if (iso_status && (debug & DBG_HFC_FIFO_VERBOSE)) { - printk(KERN_DEBUG "%s: %s: " - "ISO packet %i, status: %i\n", - hw->name, __func__, k, iso_status); - } - - /* USB data log for every D ISO in */ - if ((fifon == HFCUSB_D_RX) && - (debug & DBG_HFC_USB_VERBOSE)) { - printk(KERN_DEBUG - "%s: %s: %d (%d/%d) len(%d) ", - hw->name, __func__, urb->start_frame, - k, num_isoc_packets - 1, - len); - for (i = 0; i < len; i++) - printk("%x ", buf[i]); - printk("\n"); - } - - if (!iso_status) { - if (fifo->last_urblen != maxlen) { - /* - * save fifo fill-level threshold bits - * to use them later in TX ISO URB - * completions - */ - hw->threshold_mask = buf[1]; - - if (fifon == HFCUSB_D_RX) - s0_state = (buf[0] >> 4); - - eof[fifon] = buf[0] & 1; - if (len > 2) - hfcsusb_rx_frame(fifo, buf + 2, - len - 2, (len < maxlen) - ? eof[fifon] : 0); - } else - hfcsusb_rx_frame(fifo, buf, len, - (len < maxlen) ? - eof[fifon] : 0); - fifo->last_urblen = len; - } - } - - /* signal S0 layer1 state change */ - if ((s0_state) && (hw->initdone) && - (s0_state != hw->dch.state)) { - hw->dch.state = s0_state; - schedule_event(&hw->dch, FLG_PHCHANGE); - } - - fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe, - context_iso_urb->buffer, num_isoc_packets, - fifo->usb_packet_maxlen, fifo->intervall, - (usb_complete_t)rx_iso_complete, urb->context); - errcode = usb_submit_urb(urb, GFP_ATOMIC); - if (errcode < 0) { - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: error submitting " - "ISO URB: %d\n", - hw->name, __func__, errcode); - } - } else { - if (status && (debug & DBG_HFC_URB_INFO)) - printk(KERN_DEBUG "%s: %s: rx_iso_complete : " - "urb->status %d, fifonum %d\n", - hw->name, __func__, status, fifon); - } -} - -/* receive completion routine for all interrupt rx fifos */ -static void -rx_int_complete(struct urb *urb) -{ - int len, status, i; - __u8 *buf, maxlen, fifon; - struct usb_fifo *fifo = (struct usb_fifo *) urb->context; - struct hfcsusb *hw = fifo->hw; - static __u8 eof[8]; - unsigned long flags; - - spin_lock_irqsave(&hw->lock, flags); - if (fifo->stop_gracefull) { - fifo->stop_gracefull = 0; - fifo->active = 0; - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - spin_unlock_irqrestore(&hw->lock, flags); - - fifon = fifo->fifonum; - if ((!fifo->active) || (urb->status)) { - if (debug & DBG_HFC_URB_ERROR) - printk(KERN_DEBUG - "%s: %s: RX-Fifo %i is going down (%i)\n", - hw->name, __func__, fifon, urb->status); - - fifo->urb->interval = 0; /* cancel automatic rescheduling */ - return; - } - len = urb->actual_length; - buf = fifo->buffer; - maxlen = fifo->usb_packet_maxlen; - - /* USB data log for every D INT in */ - if ((fifon == HFCUSB_D_RX) && (debug & DBG_HFC_USB_VERBOSE)) { - printk(KERN_DEBUG "%s: %s: D RX INT len(%d) ", - hw->name, __func__, len); - for (i = 0; i < len; i++) - printk("%02x ", buf[i]); - printk("\n"); - } - - if (fifo->last_urblen != fifo->usb_packet_maxlen) { - /* the threshold mask is in the 2nd status byte */ - hw->threshold_mask = buf[1]; - - /* signal S0 layer1 state change */ - if (hw->initdone && ((buf[0] >> 4) != hw->dch.state)) { - hw->dch.state = (buf[0] >> 4); - schedule_event(&hw->dch, FLG_PHCHANGE); - } - - eof[fifon] = buf[0] & 1; - /* if we have more than the 2 status bytes -> collect data */ - if (len > 2) - hfcsusb_rx_frame(fifo, buf + 2, - urb->actual_length - 2, - (len < maxlen) ? eof[fifon] : 0); - } else { - hfcsusb_rx_frame(fifo, buf, urb->actual_length, - (len < maxlen) ? eof[fifon] : 0); - } - fifo->last_urblen = urb->actual_length; - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: error resubmitting USB\n", - hw->name, __func__); - } -} - -/* transmit completion routine for all ISO tx fifos */ -static void -tx_iso_complete(struct urb *urb) -{ - struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context; - struct usb_fifo *fifo = context_iso_urb->owner_fifo; - struct hfcsusb *hw = fifo->hw; - struct sk_buff *tx_skb; - int k, tx_offset, num_isoc_packets, sink, remain, current_len, - errcode, hdlc, i; - int *tx_idx; - int frame_complete, fifon, status, fillempty = 0; - __u8 threshbit, *p; - unsigned long flags; - - spin_lock_irqsave(&hw->lock, flags); - if (fifo->stop_gracefull) { - fifo->stop_gracefull = 0; - fifo->active = 0; - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - - if (fifo->dch) { - tx_skb = fifo->dch->tx_skb; - tx_idx = &fifo->dch->tx_idx; - hdlc = 1; - } else if (fifo->bch) { - tx_skb = fifo->bch->tx_skb; - tx_idx = &fifo->bch->tx_idx; - hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); - if (!tx_skb && !hdlc && - test_bit(FLG_FILLEMPTY, &fifo->bch->Flags)) - fillempty = 1; - } else { - printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n", - hw->name, __func__); - spin_unlock_irqrestore(&hw->lock, flags); - return; - } - - fifon = fifo->fifonum; - status = urb->status; - - tx_offset = 0; - - /* - * ISO transfer only partially completed, - * look at individual frame status for details - */ - if (status == -EXDEV) { - if (debug & DBG_HFC_URB_ERROR) - printk(KERN_DEBUG "%s: %s: " - "-EXDEV (%i) fifon (%d)\n", - hw->name, __func__, status, fifon); - - /* clear status, so go on with ISO transfers */ - status = 0; - } - - if (fifo->active && !status) { - /* is FifoFull-threshold set for our channel? */ - threshbit = (hw->threshold_mask & (1 << fifon)); - num_isoc_packets = iso_packets[fifon]; - - /* predict dataflow to avoid fifo overflow */ - if (fifon >= HFCUSB_D_TX) - sink = (threshbit) ? SINK_DMIN : SINK_DMAX; - else - sink = (threshbit) ? SINK_MIN : SINK_MAX; - fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe, - context_iso_urb->buffer, num_isoc_packets, - fifo->usb_packet_maxlen, fifo->intervall, - (usb_complete_t)tx_iso_complete, urb->context); - memset(context_iso_urb->buffer, 0, - sizeof(context_iso_urb->buffer)); - frame_complete = 0; - - for (k = 0; k < num_isoc_packets; ++k) { - /* analyze tx success of previous ISO packets */ - if (debug & DBG_HFC_URB_ERROR) { - errcode = urb->iso_frame_desc[k].status; - if (errcode) { - printk(KERN_DEBUG "%s: %s: " - "ISO packet %i, status: %i\n", - hw->name, __func__, k, errcode); - } - } - - /* Generate next ISO Packets */ - if (tx_skb) - remain = tx_skb->len - *tx_idx; - else if (fillempty) - remain = 15; /* > not complete */ - else - remain = 0; - - if (remain > 0) { - fifo->bit_line -= sink; - current_len = (0 - fifo->bit_line) / 8; - if (current_len > 14) - current_len = 14; - if (current_len < 0) - current_len = 0; - if (remain < current_len) - current_len = remain; - - /* how much bit do we put on the line? */ - fifo->bit_line += current_len * 8; - - context_iso_urb->buffer[tx_offset] = 0; - if (current_len == remain) { - if (hdlc) { - /* signal frame completion */ - context_iso_urb-> - buffer[tx_offset] = 1; - /* add 2 byte flags and 16bit - * CRC at end of ISDN frame */ - fifo->bit_line += 32; - } - frame_complete = 1; - } - - /* copy tx data to iso-urb buffer */ - p = context_iso_urb->buffer + tx_offset + 1; - if (fillempty) { - memset(p, fifo->bch->fill[0], - current_len); - } else { - memcpy(p, (tx_skb->data + *tx_idx), - current_len); - *tx_idx += current_len; - } - urb->iso_frame_desc[k].offset = tx_offset; - urb->iso_frame_desc[k].length = current_len + 1; - - /* USB data log for every D ISO out */ - if ((fifon == HFCUSB_D_RX) && !fillempty && - (debug & DBG_HFC_USB_VERBOSE)) { - printk(KERN_DEBUG - "%s: %s (%d/%d) offs(%d) len(%d) ", - hw->name, __func__, - k, num_isoc_packets - 1, - urb->iso_frame_desc[k].offset, - urb->iso_frame_desc[k].length); - - for (i = urb->iso_frame_desc[k].offset; - i < (urb->iso_frame_desc[k].offset - + urb->iso_frame_desc[k].length); - i++) - printk("%x ", - context_iso_urb->buffer[i]); - - printk(" skb->len(%i) tx-idx(%d)\n", - tx_skb->len, *tx_idx); - } - - tx_offset += (current_len + 1); - } else { - urb->iso_frame_desc[k].offset = tx_offset++; - urb->iso_frame_desc[k].length = 1; - /* we lower data margin every msec */ - fifo->bit_line -= sink; - if (fifo->bit_line < BITLINE_INF) - fifo->bit_line = BITLINE_INF; - } - - if (frame_complete) { - frame_complete = 0; - - if (debug & DBG_HFC_FIFO_VERBOSE) { - printk(KERN_DEBUG "%s: %s: " - "fifon(%i) new TX len(%i): ", - hw->name, __func__, - fifon, tx_skb->len); - i = 0; - while (i < tx_skb->len) - printk("%02x ", - tx_skb->data[i++]); - printk("\n"); - } - - dev_consume_skb_irq(tx_skb); - tx_skb = NULL; - if (fifo->dch && get_next_dframe(fifo->dch)) - tx_skb = fifo->dch->tx_skb; - else if (fifo->bch && - get_next_bframe(fifo->bch)) - tx_skb = fifo->bch->tx_skb; - } - } - errcode = usb_submit_urb(urb, GFP_ATOMIC); - if (errcode < 0) { - if (debug & DEBUG_HW) - printk(KERN_DEBUG - "%s: %s: error submitting ISO URB: %d \n", - hw->name, __func__, errcode); - } - - /* - * abuse DChannel tx iso completion to trigger NT mode state - * changes tx_iso_complete is assumed to be called every - * fifo->intervall (ms) - */ - if ((fifon == HFCUSB_D_TX) && (hw->protocol == ISDN_P_NT_S0) - && (hw->timers & NT_ACTIVATION_TIMER)) { - if ((--hw->nt_timer) < 0) - schedule_event(&hw->dch, FLG_PHCHANGE); - } - - } else { - if (status && (debug & DBG_HFC_URB_ERROR)) - printk(KERN_DEBUG "%s: %s: urb->status %s (%i)" - "fifonum=%d\n", - hw->name, __func__, - symbolic(urb_errlist, status), status, fifon); - } - spin_unlock_irqrestore(&hw->lock, flags); -} - -/* - * allocs urbs and start isoc transfer with two pending urbs to avoid - * gaps in the transfer chain - */ -static int -start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb, - usb_complete_t complete, int packet_size) -{ - struct hfcsusb *hw = fifo->hw; - int i, k, errcode; - - if (debug) - printk(KERN_DEBUG "%s: %s: fifo %i\n", - hw->name, __func__, fifo->fifonum); - - /* allocate Memory for Iso out Urbs */ - for (i = 0; i < 2; i++) { - if (!(fifo->iso[i].urb)) { - fifo->iso[i].urb = - usb_alloc_urb(num_packets_per_urb, GFP_KERNEL); - if (!(fifo->iso[i].urb)) { - printk(KERN_DEBUG - "%s: %s: alloc urb for fifo %i failed", - hw->name, __func__, fifo->fifonum); - continue; - } - fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; - fifo->iso[i].indx = i; - - /* Init the first iso */ - if (ISO_BUFFER_SIZE >= - (fifo->usb_packet_maxlen * - num_packets_per_urb)) { - fill_isoc_urb(fifo->iso[i].urb, - fifo->hw->dev, fifo->pipe, - fifo->iso[i].buffer, - num_packets_per_urb, - fifo->usb_packet_maxlen, - fifo->intervall, complete, - &fifo->iso[i]); - memset(fifo->iso[i].buffer, 0, - sizeof(fifo->iso[i].buffer)); - - for (k = 0; k < num_packets_per_urb; k++) { - fifo->iso[i].urb-> - iso_frame_desc[k].offset = - k * packet_size; - fifo->iso[i].urb-> - iso_frame_desc[k].length = - packet_size; - } - } else { - printk(KERN_DEBUG - "%s: %s: ISO Buffer size to small!\n", - hw->name, __func__); - } - } - fifo->bit_line = BITLINE_INF; - - errcode = usb_submit_urb(fifo->iso[i].urb, GFP_KERNEL); - fifo->active = (errcode >= 0) ? 1 : 0; - fifo->stop_gracefull = 0; - if (errcode < 0) { - printk(KERN_DEBUG "%s: %s: %s URB nr:%d\n", - hw->name, __func__, - symbolic(urb_errlist, errcode), i); - } - } - return fifo->active; -} - -static void -stop_iso_gracefull(struct usb_fifo *fifo) -{ - struct hfcsusb *hw = fifo->hw; - int i, timeout; - u_long flags; - - for (i = 0; i < 2; i++) { - spin_lock_irqsave(&hw->lock, flags); - if (debug) - printk(KERN_DEBUG "%s: %s for fifo %i.%i\n", - hw->name, __func__, fifo->fifonum, i); - fifo->stop_gracefull = 1; - spin_unlock_irqrestore(&hw->lock, flags); - } - - for (i = 0; i < 2; i++) { - timeout = 3; - while (fifo->stop_gracefull && timeout--) - schedule_timeout_interruptible((HZ / 1000) * 16); - if (debug && fifo->stop_gracefull) - printk(KERN_DEBUG "%s: ERROR %s for fifo %i.%i\n", - hw->name, __func__, fifo->fifonum, i); - } -} - -static void -stop_int_gracefull(struct usb_fifo *fifo) -{ - struct hfcsusb *hw = fifo->hw; - int timeout; - u_long flags; - - spin_lock_irqsave(&hw->lock, flags); - if (debug) - printk(KERN_DEBUG "%s: %s for fifo %i\n", - hw->name, __func__, fifo->fifonum); - fifo->stop_gracefull = 1; - spin_unlock_irqrestore(&hw->lock, flags); - - timeout = 3; - while (fifo->stop_gracefull && timeout--) - schedule_timeout_interruptible((HZ / 1000) * 3); - if (debug && fifo->stop_gracefull) - printk(KERN_DEBUG "%s: ERROR %s for fifo %i\n", - hw->name, __func__, fifo->fifonum); -} - -/* start the interrupt transfer for the given fifo */ -static void -start_int_fifo(struct usb_fifo *fifo) -{ - struct hfcsusb *hw = fifo->hw; - int errcode; - - if (debug) - printk(KERN_DEBUG "%s: %s: INT IN fifo:%d\n", - hw->name, __func__, fifo->fifonum); - - if (!fifo->urb) { - fifo->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!fifo->urb) - return; - } - usb_fill_int_urb(fifo->urb, fifo->hw->dev, fifo->pipe, - fifo->buffer, fifo->usb_packet_maxlen, - (usb_complete_t)rx_int_complete, fifo, fifo->intervall); - fifo->active = 1; - fifo->stop_gracefull = 0; - errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); - if (errcode) { - printk(KERN_DEBUG "%s: %s: submit URB: status:%i\n", - hw->name, __func__, errcode); - fifo->active = 0; - } -} - -static void -setPortMode(struct hfcsusb *hw) -{ - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s %s\n", hw->name, __func__, - (hw->protocol == ISDN_P_TE_S0) ? "TE" : "NT"); - - if (hw->protocol == ISDN_P_TE_S0) { - write_reg(hw, HFCUSB_SCTRL, 0x40); - write_reg(hw, HFCUSB_SCTRL_E, 0x00); - write_reg(hw, HFCUSB_CLKDEL, CLKDEL_TE); - write_reg(hw, HFCUSB_STATES, 3 | 0x10); - write_reg(hw, HFCUSB_STATES, 3); - } else { - write_reg(hw, HFCUSB_SCTRL, 0x44); - write_reg(hw, HFCUSB_SCTRL_E, 0x09); - write_reg(hw, HFCUSB_CLKDEL, CLKDEL_NT); - write_reg(hw, HFCUSB_STATES, 1 | 0x10); - write_reg(hw, HFCUSB_STATES, 1); - } -} - -static void -reset_hfcsusb(struct hfcsusb *hw) -{ - struct usb_fifo *fifo; - int i; - - if (debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); - - /* do Chip reset */ - write_reg(hw, HFCUSB_CIRM, 8); - - /* aux = output, reset off */ - write_reg(hw, HFCUSB_CIRM, 0x10); - - /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */ - write_reg(hw, HFCUSB_USB_SIZE, (hw->packet_size / 8) | - ((hw->packet_size / 8) << 4)); - - /* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */ - write_reg(hw, HFCUSB_USB_SIZE_I, hw->iso_packet_size); - - /* enable PCM/GCI master mode */ - write_reg(hw, HFCUSB_MST_MODE1, 0); /* set default values */ - write_reg(hw, HFCUSB_MST_MODE0, 1); /* enable master mode */ - - /* init the fifos */ - write_reg(hw, HFCUSB_F_THRES, - (HFCUSB_TX_THRESHOLD / 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4)); - - fifo = hw->fifos; - for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { - write_reg(hw, HFCUSB_FIFO, i); /* select the desired fifo */ - fifo[i].max_size = - (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; - fifo[i].last_urblen = 0; - - /* set 2 bit for D- & E-channel */ - write_reg(hw, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); - - /* enable all fifos */ - if (i == HFCUSB_D_TX) - write_reg(hw, HFCUSB_CON_HDLC, - (hw->protocol == ISDN_P_NT_S0) ? 0x08 : 0x09); - else - write_reg(hw, HFCUSB_CON_HDLC, 0x08); - write_reg(hw, HFCUSB_INC_RES_F, 2); /* reset the fifo */ - } - - write_reg(hw, HFCUSB_SCTRL_R, 0); /* disable both B receivers */ - handle_led(hw, LED_POWER_ON); -} - -/* start USB data pipes dependand on device's endpoint configuration */ -static void -hfcsusb_start_endpoint(struct hfcsusb *hw, int channel) -{ - /* quick check if endpoint already running */ - if ((channel == HFC_CHAN_D) && (hw->fifos[HFCUSB_D_RX].active)) - return; - if ((channel == HFC_CHAN_B1) && (hw->fifos[HFCUSB_B1_RX].active)) - return; - if ((channel == HFC_CHAN_B2) && (hw->fifos[HFCUSB_B2_RX].active)) - return; - if ((channel == HFC_CHAN_E) && (hw->fifos[HFCUSB_PCM_RX].active)) - return; - - /* start rx endpoints using USB INT IN method */ - if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO) - start_int_fifo(hw->fifos + channel * 2 + 1); - - /* start rx endpoints using USB ISO IN method */ - if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) { - switch (channel) { - case HFC_CHAN_D: - start_isoc_chain(hw->fifos + HFCUSB_D_RX, - ISOC_PACKETS_D, - (usb_complete_t)rx_iso_complete, - 16); - break; - case HFC_CHAN_E: - start_isoc_chain(hw->fifos + HFCUSB_PCM_RX, - ISOC_PACKETS_D, - (usb_complete_t)rx_iso_complete, - 16); - break; - case HFC_CHAN_B1: - start_isoc_chain(hw->fifos + HFCUSB_B1_RX, - ISOC_PACKETS_B, - (usb_complete_t)rx_iso_complete, - 16); - break; - case HFC_CHAN_B2: - start_isoc_chain(hw->fifos + HFCUSB_B2_RX, - ISOC_PACKETS_B, - (usb_complete_t)rx_iso_complete, - 16); - break; - } - } - - /* start tx endpoints using USB ISO OUT method */ - switch (channel) { - case HFC_CHAN_D: - start_isoc_chain(hw->fifos + HFCUSB_D_TX, - ISOC_PACKETS_B, - (usb_complete_t)tx_iso_complete, 1); - break; - case HFC_CHAN_B1: - start_isoc_chain(hw->fifos + HFCUSB_B1_TX, - ISOC_PACKETS_D, - (usb_complete_t)tx_iso_complete, 1); - break; - case HFC_CHAN_B2: - start_isoc_chain(hw->fifos + HFCUSB_B2_TX, - ISOC_PACKETS_B, - (usb_complete_t)tx_iso_complete, 1); - break; - } -} - -/* stop USB data pipes dependand on device's endpoint configuration */ -static void -hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel) -{ - /* quick check if endpoint currently running */ - if ((channel == HFC_CHAN_D) && (!hw->fifos[HFCUSB_D_RX].active)) - return; - if ((channel == HFC_CHAN_B1) && (!hw->fifos[HFCUSB_B1_RX].active)) - return; - if ((channel == HFC_CHAN_B2) && (!hw->fifos[HFCUSB_B2_RX].active)) - return; - if ((channel == HFC_CHAN_E) && (!hw->fifos[HFCUSB_PCM_RX].active)) - return; - - /* rx endpoints using USB INT IN method */ - if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO) - stop_int_gracefull(hw->fifos + channel * 2 + 1); - - /* rx endpoints using USB ISO IN method */ - if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) - stop_iso_gracefull(hw->fifos + channel * 2 + 1); - - /* tx endpoints using USB ISO OUT method */ - if (channel != HFC_CHAN_E) - stop_iso_gracefull(hw->fifos + channel * 2); -} - - -/* Hardware Initialization */ -static int -setup_hfcsusb(struct hfcsusb *hw) -{ - void *dmabuf = kmalloc_obj(u_char); - u_char b; - int ret; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); - - if (!dmabuf) - return -ENOMEM; - - ret = read_reg_atomic(hw, HFCUSB_CHIP_ID, dmabuf); - - memcpy(&b, dmabuf, sizeof(u_char)); - kfree(dmabuf); - - /* check the chip id */ - if (ret != 1) { - printk(KERN_DEBUG "%s: %s: cannot read chip id\n", - hw->name, __func__); - return 1; - } - if (b != HFCUSB_CHIPID) { - printk(KERN_DEBUG "%s: %s: Invalid chip id 0x%02x\n", - hw->name, __func__, b); - return 1; - } - - /* first set the needed config, interface and alternate */ - (void) usb_set_interface(hw->dev, hw->if_used, hw->alt_used); - - hw->led_state = 0; - - /* init the background machinery for control requests */ - hw->ctrl_read.bRequestType = 0xc0; - hw->ctrl_read.bRequest = 1; - hw->ctrl_read.wLength = cpu_to_le16(1); - hw->ctrl_write.bRequestType = 0x40; - hw->ctrl_write.bRequest = 0; - hw->ctrl_write.wLength = 0; - usb_fill_control_urb(hw->ctrl_urb, hw->dev, hw->ctrl_out_pipe, - (u_char *)&hw->ctrl_write, NULL, 0, - (usb_complete_t)ctrl_complete, hw); - - reset_hfcsusb(hw); - return 0; -} - -static void -release_hw(struct hfcsusb *hw) -{ - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); - - /* - * stop all endpoints gracefully - * TODO: mISDN_core should generate CLOSE_CHANNEL - * signals after calling mISDN_unregister_device() - */ - hfcsusb_stop_endpoint(hw, HFC_CHAN_D); - hfcsusb_stop_endpoint(hw, HFC_CHAN_B1); - hfcsusb_stop_endpoint(hw, HFC_CHAN_B2); - if (hw->fifos[HFCUSB_PCM_RX].pipe) - hfcsusb_stop_endpoint(hw, HFC_CHAN_E); - if (hw->protocol == ISDN_P_TE_S0) - l1_event(hw->dch.l1, CLOSE_CHANNEL); - - mISDN_unregister_device(&hw->dch.dev); - mISDN_freebchannel(&hw->bch[1]); - mISDN_freebchannel(&hw->bch[0]); - mISDN_freedchannel(&hw->dch); - - if (hw->ctrl_urb) { - usb_kill_urb(hw->ctrl_urb); - usb_free_urb(hw->ctrl_urb); - hw->ctrl_urb = NULL; - } - - if (hw->intf) - usb_set_intfdata(hw->intf, NULL); - list_del(&hw->list); - kfree(hw); - hw = NULL; -} - -static void -deactivate_bchannel(struct bchannel *bch) -{ - struct hfcsusb *hw = bch->hw; - u_long flags; - - if (bch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: %s: bch->nr(%i)\n", - hw->name, __func__, bch->nr); - - spin_lock_irqsave(&hw->lock, flags); - mISDN_clear_bchannel(bch); - spin_unlock_irqrestore(&hw->lock, flags); - hfcsusb_setup_bch(bch, ISDN_P_NONE); - hfcsusb_stop_endpoint(hw, bch->nr - 1); -} - -/* - * Layer 1 B-channel hardware access - */ -static int -hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - int ret = -EINVAL; - - if (bch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); - - switch (cmd) { - case HW_TESTRX_RAW: - case HW_TESTRX_HDLC: - case HW_TESTRX_OFF: - ret = -EINVAL; - break; - - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - deactivate_bchannel(bch); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(THIS_MODULE); - ret = 0; - break; - case CONTROL_CHANNEL: - ret = channel_bctrl(bch, arg); - break; - default: - printk(KERN_WARNING "%s: unknown prim(%x)\n", - __func__, cmd); - } - return ret; -} - -static int -setup_instance(struct hfcsusb *hw, struct device *parent) -{ - u_long flags; - int err, i; - - if (debug & DBG_HFC_CALL_TRACE) - printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); - - spin_lock_init(&hw->ctrl_lock); - spin_lock_init(&hw->lock); - - mISDN_initdchannel(&hw->dch, MAX_DFRAME_LEN_L1, ph_state); - hw->dch.debug = debug & 0xFFFF; - hw->dch.hw = hw; - hw->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); - hw->dch.dev.D.send = hfcusb_l2l1D; - hw->dch.dev.D.ctrl = hfc_dctrl; - - /* enable E-Channel logging */ - if (hw->fifos[HFCUSB_PCM_RX].pipe) - mISDN_initdchannel(&hw->ech, MAX_DFRAME_LEN_L1, NULL); - - hw->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - hw->dch.dev.nrbchan = 2; - for (i = 0; i < 2; i++) { - hw->bch[i].nr = i + 1; - set_channelmap(i + 1, hw->dch.dev.channelmap); - hw->bch[i].debug = debug; - mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, poll >> 1); - hw->bch[i].hw = hw; - hw->bch[i].ch.send = hfcusb_l2l1B; - hw->bch[i].ch.ctrl = hfc_bctrl; - hw->bch[i].ch.nr = i + 1; - list_add(&hw->bch[i].ch.list, &hw->dch.dev.bchannels); - } - - hw->fifos[HFCUSB_B1_TX].bch = &hw->bch[0]; - hw->fifos[HFCUSB_B1_RX].bch = &hw->bch[0]; - hw->fifos[HFCUSB_B2_TX].bch = &hw->bch[1]; - hw->fifos[HFCUSB_B2_RX].bch = &hw->bch[1]; - hw->fifos[HFCUSB_D_TX].dch = &hw->dch; - hw->fifos[HFCUSB_D_RX].dch = &hw->dch; - hw->fifos[HFCUSB_PCM_RX].ech = &hw->ech; - hw->fifos[HFCUSB_PCM_TX].ech = &hw->ech; - - err = setup_hfcsusb(hw); - if (err) - goto out; - - snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s.%d", DRIVER_NAME, - hfcsusb_cnt + 1); - printk(KERN_INFO "%s: registered as '%s'\n", - DRIVER_NAME, hw->name); - - err = mISDN_register_device(&hw->dch.dev, parent, hw->name); - if (err) - goto out; - - hfcsusb_cnt++; - write_lock_irqsave(&HFClock, flags); - list_add_tail(&hw->list, &HFClist); - write_unlock_irqrestore(&HFClock, flags); - return 0; - -out: - mISDN_freebchannel(&hw->bch[1]); - mISDN_freebchannel(&hw->bch[0]); - mISDN_freedchannel(&hw->dch); - return err; -} - -static int -hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - int err; - struct hfcsusb *hw; - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_host_interface *iface = intf->cur_altsetting; - struct usb_host_interface *iface_used = NULL; - struct usb_host_endpoint *ep; - struct hfcsusb_vdata *driver_info; - int ifnum = iface->desc.bInterfaceNumber, i, idx, alt_idx, - probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, - ep_addr, cmptbl[16], small_match, iso_packet_size, packet_size, - alt_used = 0; - - vend_idx = 0xffff; - for (i = 0; hfcsusb_idtab[i].idVendor; i++) { - if ((le16_to_cpu(dev->descriptor.idVendor) - == hfcsusb_idtab[i].idVendor) && - (le16_to_cpu(dev->descriptor.idProduct) - == hfcsusb_idtab[i].idProduct)) { - vend_idx = i; - continue; - } - } - - printk(KERN_DEBUG - "%s: interface(%d) actalt(%d) minor(%d) vend_idx(%d)\n", - __func__, ifnum, iface->desc.bAlternateSetting, - intf->minor, vend_idx); - - if (vend_idx == 0xffff) { - printk(KERN_WARNING - "%s: no valid vendor found in USB descriptor\n", - __func__); - return -EIO; - } - /* if vendor and product ID is OK, start probing alternate settings */ - alt_idx = 0; - small_match = -1; - - /* default settings */ - iso_packet_size = 16; - packet_size = 64; - - while (alt_idx < intf->num_altsetting) { - iface = intf->altsetting + alt_idx; - probe_alt_setting = iface->desc.bAlternateSetting; - cfg_used = 0; - - while (validconf[cfg_used][0]) { - cfg_found = 1; - vcf = validconf[cfg_used]; - ep = iface->endpoint; - memcpy(cmptbl, vcf, 16 * sizeof(int)); - - /* check for all endpoints in this alternate setting */ - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - ep_addr = ep->desc.bEndpointAddress; - - /* get endpoint base */ - idx = ((ep_addr & 0x7f) - 1) * 2; - if (idx > 15) - return -EIO; - - if (ep_addr & 0x80) - idx++; - attr = ep->desc.bmAttributes; - - if (cmptbl[idx] != EP_NOP) { - if (cmptbl[idx] == EP_NUL) - cfg_found = 0; - if (attr == USB_ENDPOINT_XFER_INT - && cmptbl[idx] == EP_INT) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_BULK - && cmptbl[idx] == EP_BLK) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_ISOC - && cmptbl[idx] == EP_ISO) - cmptbl[idx] = EP_NUL; - - if (attr == USB_ENDPOINT_XFER_INT && - ep->desc.bInterval < vcf[17]) { - cfg_found = 0; - } - } - ep++; - } - - for (i = 0; i < 16; i++) - if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL) - cfg_found = 0; - - if (cfg_found) { - if (small_match < cfg_used) { - small_match = cfg_used; - alt_used = probe_alt_setting; - iface_used = iface; - } - } - cfg_used++; - } - alt_idx++; - } /* (alt_idx < intf->num_altsetting) */ - - /* not found a valid USB Ta Endpoint config */ - if (small_match == -1) - return -EIO; - - iface = iface_used; - hw = kzalloc_obj(struct hfcsusb); - if (!hw) - return -ENOMEM; /* got no mem */ - snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s", DRIVER_NAME); - - ep = iface->endpoint; - vcf = validconf[small_match]; - - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - struct usb_fifo *f; - - ep_addr = ep->desc.bEndpointAddress; - /* get endpoint base */ - idx = ((ep_addr & 0x7f) - 1) * 2; - if (ep_addr & 0x80) - idx++; - f = &hw->fifos[idx & 7]; - - /* init Endpoints */ - if (vcf[idx] == EP_NOP || vcf[idx] == EP_NUL) { - ep++; - continue; - } - switch (ep->desc.bmAttributes) { - case USB_ENDPOINT_XFER_INT: - f->pipe = usb_rcvintpipe(dev, - ep->desc.bEndpointAddress); - f->usb_transfer_mode = USB_INT; - packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); - break; - case USB_ENDPOINT_XFER_BULK: - if (ep_addr & 0x80) - f->pipe = usb_rcvbulkpipe(dev, - ep->desc.bEndpointAddress); - else - f->pipe = usb_sndbulkpipe(dev, - ep->desc.bEndpointAddress); - f->usb_transfer_mode = USB_BULK; - packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); - break; - case USB_ENDPOINT_XFER_ISOC: - if (ep_addr & 0x80) - f->pipe = usb_rcvisocpipe(dev, - ep->desc.bEndpointAddress); - else - f->pipe = usb_sndisocpipe(dev, - ep->desc.bEndpointAddress); - f->usb_transfer_mode = USB_ISOC; - iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); - break; - default: - f->pipe = 0; - } - - if (f->pipe) { - f->fifonum = idx & 7; - f->hw = hw; - f->usb_packet_maxlen = - le16_to_cpu(ep->desc.wMaxPacketSize); - f->intervall = ep->desc.bInterval; - } - ep++; - } - hw->dev = dev; /* save device */ - hw->if_used = ifnum; /* save used interface */ - hw->alt_used = alt_used; /* and alternate config */ - hw->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ - hw->cfg_used = vcf[16]; /* store used config */ - hw->vend_idx = vend_idx; /* store found vendor */ - hw->packet_size = packet_size; - hw->iso_packet_size = iso_packet_size; - - /* create the control pipes needed for register access */ - hw->ctrl_in_pipe = usb_rcvctrlpipe(hw->dev, 0); - hw->ctrl_out_pipe = usb_sndctrlpipe(hw->dev, 0); - - driver_info = (struct hfcsusb_vdata *) - hfcsusb_idtab[vend_idx].driver_info; - - hw->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!hw->ctrl_urb) { - pr_warn("%s: No memory for control urb\n", - driver_info->vend_name); - err = -ENOMEM; - goto err_free_hw; - } - - pr_info("%s: %s: detected \"%s\" (%s, if=%d alt=%d)\n", - hw->name, __func__, driver_info->vend_name, - conf_str[small_match], ifnum, alt_used); - - if (setup_instance(hw, dev->dev.parent)) { - err = -EIO; - goto err_free_urb; - } - - hw->intf = intf; - usb_set_intfdata(hw->intf, hw); - return 0; - -err_free_urb: - usb_free_urb(hw->ctrl_urb); -err_free_hw: - kfree(hw); - return err; -} - -/* function called when an active device is removed */ -static void -hfcsusb_disconnect(struct usb_interface *intf) -{ - struct hfcsusb *hw = usb_get_intfdata(intf); - struct hfcsusb *next; - int cnt = 0; - - printk(KERN_INFO "%s: device disconnected\n", hw->name); - - handle_led(hw, LED_POWER_OFF); - release_hw(hw); - - list_for_each_entry_safe(hw, next, &HFClist, list) - cnt++; - if (!cnt) - hfcsusb_cnt = 0; - - usb_set_intfdata(intf, NULL); -} - -static struct usb_driver hfcsusb_drv = { - .name = DRIVER_NAME, - .id_table = hfcsusb_idtab, - .probe = hfcsusb_probe, - .disconnect = hfcsusb_disconnect, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(hfcsusb_drv); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h deleted file mode 100644 index 7e2bc5068019..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcsusb.h +++ /dev/null @@ -1,425 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * hfcsusb.h, HFC-S USB mISDN driver - */ - -#ifndef __HFCSUSB_H__ -#define __HFCSUSB_H__ - - -#define DRIVER_NAME "HFC-S_USB" - -#define DBG_HFC_CALL_TRACE 0x00010000 -#define DBG_HFC_FIFO_VERBOSE 0x00020000 -#define DBG_HFC_USB_VERBOSE 0x00100000 -#define DBG_HFC_URB_INFO 0x00200000 -#define DBG_HFC_URB_ERROR 0x00400000 - -#define DEFAULT_TRANSP_BURST_SZ 128 - -#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */ -#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ -#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ - -/* hfcsusb Layer1 commands */ -#define HFC_L1_ACTIVATE_TE 1 -#define HFC_L1_ACTIVATE_NT 2 -#define HFC_L1_DEACTIVATE_NT 3 -#define HFC_L1_FORCE_DEACTIVATE_TE 4 - -/* cmd FLAGS in HFCUSB_STATES register */ -#define HFCUSB_LOAD_STATE 0x10 -#define HFCUSB_ACTIVATE 0x20 -#define HFCUSB_DO_ACTION 0x40 -#define HFCUSB_NT_G2_G3 0x80 - -/* timers */ -#define NT_ACTIVATION_TIMER 0x01 /* enables NT mode activation Timer */ -#define NT_T1_COUNT 10 - -#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */ - -#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */ -#define HFCUSB_TX_THRESHOLD 96 /* threshold for fifo report bit tx */ - -#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */ -#define HFCUSB_CIRM 0x00 /* cirm register index */ -#define HFCUSB_USB_SIZE 0x07 /* int length register */ -#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */ -#define HFCUSB_F_CROSS 0x0b /* bit order register */ -#define HFCUSB_CLKDEL 0x37 /* bit delay register */ -#define HFCUSB_CON_HDLC 0xfa /* channel connect register */ -#define HFCUSB_HDLC_PAR 0xfb -#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */ -#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */ -#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */ -#define HFCUSB_F_THRES 0x0c /* threshold register */ -#define HFCUSB_FIFO 0x0f /* fifo select register */ -#define HFCUSB_F_USAGE 0x1a /* fifo usage register */ -#define HFCUSB_MST_MODE0 0x14 -#define HFCUSB_MST_MODE1 0x15 -#define HFCUSB_P_DATA 0x1f -#define HFCUSB_INC_RES_F 0x0e -#define HFCUSB_B1_SSL 0x20 -#define HFCUSB_B2_SSL 0x21 -#define HFCUSB_B1_RSL 0x24 -#define HFCUSB_B2_RSL 0x25 -#define HFCUSB_STATES 0x30 - - -#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */ - -/* fifo registers */ -#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */ -#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */ -#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */ -#define HFCUSB_B2_TX 2 -#define HFCUSB_B2_RX 3 -#define HFCUSB_D_TX 4 -#define HFCUSB_D_RX 5 -#define HFCUSB_PCM_TX 6 -#define HFCUSB_PCM_RX 7 - - -#define USB_INT 0 -#define USB_BULK 1 -#define USB_ISOC 2 - -#define ISOC_PACKETS_D 8 -#define ISOC_PACKETS_B 8 -#define ISO_BUFFER_SIZE 128 - -/* defines how much ISO packets are handled in one URB */ -static int iso_packets[8] = -{ ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, - ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D -}; - - -/* Fifo flow Control for TX ISO */ -#define SINK_MAX 68 -#define SINK_MIN 48 -#define SINK_DMIN 12 -#define SINK_DMAX 18 -#define BITLINE_INF (-96 * 8) - -/* HFC-S USB register access by Control-URSs */ -#define write_reg_atomic(a, b, c) \ - usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), \ - 0, 0, HFC_CTRL_TIMEOUT) -#define read_reg_atomic(a, b, c) \ - usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), \ - 1, HFC_CTRL_TIMEOUT) -#define HFC_CTRL_BUFSIZE 64 - -struct ctrl_buf { - __u8 hfcs_reg; /* register number */ - __u8 reg_val; /* value to be written (or read) */ -}; - -/* - * URB error codes - * Used to represent a list of values and their respective symbolic names - */ -struct hfcusb_symbolic_list { - const int num; - const char *name; -}; - -static struct hfcusb_symbolic_list urb_errlist[] = { - {-ENOMEM, "No memory for allocation of internal structures"}, - {-ENOSPC, "The host controller's bandwidth is already consumed"}, - {-ENOENT, "URB was canceled by unlink_urb"}, - {-EXDEV, "ISO transfer only partially completed"}, - {-EAGAIN, "Too match scheduled for the future"}, - {-ENXIO, "URB already queued"}, - {-EFBIG, "Too much ISO frames requested"}, - {-ENOSR, "Buffer error (overrun)"}, - {-EPIPE, "Specified endpoint is stalled (device not responding)"}, - {-EOVERFLOW, "Babble (bad cable?)"}, - {-EPROTO, "Bit-stuff error (bad cable?)"}, - {-EILSEQ, "CRC/Timeout"}, - {-ETIMEDOUT, "NAK (device does not respond)"}, - {-ESHUTDOWN, "Device unplugged"}, - {-1, NULL} -}; - -static inline const char * -symbolic(struct hfcusb_symbolic_list list[], const int num) -{ - int i; - for (i = 0; list[i].name != NULL; i++) - if (list[i].num == num) - return list[i].name; - return ""; -} - -/* USB descriptor need to contain one of the following EndPoint combination: */ -#define CNF_4INT3ISO 1 /* 4 INT IN, 3 ISO OUT */ -#define CNF_3INT3ISO 2 /* 3 INT IN, 3 ISO OUT */ -#define CNF_4ISO3ISO 3 /* 4 ISO IN, 3 ISO OUT */ -#define CNF_3ISO3ISO 4 /* 3 ISO IN, 3 ISO OUT */ - -#define EP_NUL 1 /* Endpoint at this position not allowed */ -#define EP_NOP 2 /* all type of endpoints allowed at this position */ -#define EP_ISO 3 /* Isochron endpoint mandatory at this position */ -#define EP_BLK 4 /* Bulk endpoint mandatory at this position */ -#define EP_INT 5 /* Interrupt endpoint mandatory at this position */ - -#define HFC_CHAN_B1 0 -#define HFC_CHAN_B2 1 -#define HFC_CHAN_D 2 -#define HFC_CHAN_E 3 - - -/* - * List of all supported endpoint configuration sets, used to find the - * best matching endpoint configuration within a device's USB descriptor. - * We need at least 3 RX endpoints, and 3 TX endpoints, either - * INT-in and ISO-out, or ISO-in and ISO-out) - * with 4 RX endpoints even E-Channel logging is possible - */ -static int -validconf[][19] = { - /* INT in, ISO out config */ - {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT, - EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, - CNF_4INT3ISO, 2, 1}, - {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL, - EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, - CNF_3INT3ISO, 2, 0}, - /* ISO in, ISO out config */ - {EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, - EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO, - CNF_4ISO3ISO, 2, 1}, - {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, - EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL, - CNF_3ISO3ISO, 2, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* EOL element */ -}; - -/* string description of chosen config */ -static char *conf_str[] = { - "4 Interrupt IN + 3 Isochron OUT", - "3 Interrupt IN + 3 Isochron OUT", - "4 Isochron IN + 3 Isochron OUT", - "3 Isochron IN + 3 Isochron OUT" -}; - - -#define LED_OFF 0 /* no LED support */ -#define LED_SCHEME1 1 /* LED standard scheme */ -#define LED_SCHEME2 2 /* not used yet... */ - -#define LED_POWER_ON 1 -#define LED_POWER_OFF 2 -#define LED_S0_ON 3 -#define LED_S0_OFF 4 -#define LED_B1_ON 5 -#define LED_B1_OFF 6 -#define LED_B1_DATA 7 -#define LED_B2_ON 8 -#define LED_B2_OFF 9 -#define LED_B2_DATA 10 - -#define LED_NORMAL 0 /* LEDs are normal */ -#define LED_INVERTED 1 /* LEDs are inverted */ - -/* time in ms to perform a Flashing LED when B-Channel has traffic */ -#define LED_TIME 250 - - - -struct hfcsusb; -struct usb_fifo; - -/* structure defining input+output fifos (interrupt/bulk mode) */ -struct iso_urb { - struct urb *urb; - __u8 buffer[ISO_BUFFER_SIZE]; /* buffer rx/tx USB URB data */ - struct usb_fifo *owner_fifo; /* pointer to owner fifo */ - __u8 indx; /* Fifos's ISO double buffer 0 or 1 ? */ -#ifdef ISO_FRAME_START_DEBUG - int start_frames[ISO_FRAME_START_RING_COUNT]; - __u8 iso_frm_strt_pos; /* index in start_frame[] */ -#endif -}; - -struct usb_fifo { - int fifonum; /* fifo index attached to this structure */ - int active; /* fifo is currently active */ - struct hfcsusb *hw; /* pointer to main structure */ - int pipe; /* address of endpoint */ - __u8 usb_packet_maxlen; /* maximum length for usb transfer */ - unsigned int max_size; /* maximum size of receive/send packet */ - __u8 intervall; /* interrupt interval */ - struct urb *urb; /* transfer structure for usb routines */ - __u8 buffer[128]; /* buffer USB INT OUT URB data */ - int bit_line; /* how much bits are in the fifo? */ - - __u8 usb_transfer_mode; /* switched between ISO and INT */ - struct iso_urb iso[2]; /* two urbs to have one always - one pending */ - - struct dchannel *dch; /* link to hfcsusb_t->dch */ - struct bchannel *bch; /* link to hfcsusb_t->bch */ - struct dchannel *ech; /* link to hfcsusb_t->ech, TODO: E-CHANNEL */ - int last_urblen; /* remember length of last packet */ - __u8 stop_gracefull; /* stops URB retransmission */ -}; - -struct hfcsusb { - struct list_head list; - struct dchannel dch; - struct bchannel bch[2]; - struct dchannel ech; /* TODO : wait for struct echannel ;) */ - - struct usb_device *dev; /* our device */ - struct usb_interface *intf; /* used interface */ - int if_used; /* used interface number */ - int alt_used; /* used alternate config */ - int cfg_used; /* configuration index used */ - int vend_idx; /* index in hfcsusb_idtab */ - int packet_size; - int iso_packet_size; - struct usb_fifo fifos[HFCUSB_NUM_FIFOS]; - - /* control pipe background handling */ - struct ctrl_buf ctrl_buff[HFC_CTRL_BUFSIZE]; - int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; - struct urb *ctrl_urb; - struct usb_ctrlrequest ctrl_write; - struct usb_ctrlrequest ctrl_read; - int ctrl_paksize; - int ctrl_in_pipe, ctrl_out_pipe; - spinlock_t ctrl_lock; /* lock for ctrl */ - spinlock_t lock; - - __u8 threshold_mask; - __u8 led_state; - - __u8 protocol; - int nt_timer; - int open; - __u8 timers; - __u8 initdone; - char name[MISDN_MAX_IDLEN]; -}; - -/* private vendor specific data */ -struct hfcsusb_vdata { - __u8 led_scheme; /* led display scheme */ - signed short led_bits[8]; /* array of 8 possible LED bitmask */ - char *vend_name; /* device name */ -}; - - -#define HFC_MAX_TE_LAYER1_STATE 8 -#define HFC_MAX_NT_LAYER1_STATE 4 - -static const char *HFC_TE_LAYER1_STATES[HFC_MAX_TE_LAYER1_STATE + 1] = { - "TE F0 - Reset", - "TE F1 - Reset", - "TE F2 - Sensing", - "TE F3 - Deactivated", - "TE F4 - Awaiting signal", - "TE F5 - Identifying input", - "TE F6 - Synchronized", - "TE F7 - Activated", - "TE F8 - Lost framing", -}; - -static const char *HFC_NT_LAYER1_STATES[HFC_MAX_NT_LAYER1_STATE + 1] = { - "NT G0 - Reset", - "NT G1 - Deactive", - "NT G2 - Pending activation", - "NT G3 - Active", - "NT G4 - Pending deactivation", -}; - -/* supported devices */ -static const struct usb_device_id hfcsusb_idtab[] = { - { - USB_DEVICE(0x0959, 0x2bd0), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_OFF, {4, 0, 2, 1}, - "ISDN USB TA (Cologne Chip HFC-S USB based)"}), - }, - { - USB_DEVICE(0x0675, 0x1688), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {1, 2, 0, 0}, - "DrayTek miniVigor 128 USB ISDN TA"}), - }, - { - USB_DEVICE(0x07b0, 0x0007), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Billion tiny USB ISDN TA 128"}), - }, - { - USB_DEVICE(0x0742, 0x2008), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "Stollmann USB TA"}), - }, - { - USB_DEVICE(0x0742, 0x2009), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "Aceex USB ISDN TA"}), - }, - { - USB_DEVICE(0x0742, 0x200A), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "OEM USB ISDN TA"}), - }, - { - USB_DEVICE(0x08e3, 0x0301), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {2, 0, 1, 4}, - "Olitec USB RNIS"}), - }, - { - USB_DEVICE(0x07fa, 0x0846), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Bewan Modem RNIS USB"}), - }, - { - USB_DEVICE(0x07fa, 0x0847), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Djinn Numeris USB"}), - }, - { - USB_DEVICE(0x07b0, 0x0006), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Twister ISDN TA"}), - }, - { - USB_DEVICE(0x071d, 0x1005), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {0x02, 0, 0x01, 0x04}, - "Eicon DIVA USB 4.0"}), - }, - { - USB_DEVICE(0x0586, 0x0102), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {0x88, -64, -32, -16}, - "ZyXEL OMNI.NET USB II"}), - }, - { - USB_DEVICE(0x1ae7, 0x0525), - .driver_info = (unsigned long) &((struct hfcsusb_vdata) - {LED_SCHEME1, {0x88, -64, -32, -16}, - "X-Tensions USB ISDN TA XC-525"}), - }, - { } -}; - -MODULE_DEVICE_TABLE(usb, hfcsusb_idtab); - -#endif /* __HFCSUSB_H__ */ diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h deleted file mode 100644 index c81f7aba4b57..000000000000 --- a/drivers/isdn/hardware/mISDN/iohelper.h +++ /dev/null @@ -1,96 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * iohelper.h - * helper for define functions to access ISDN hardware - * supported are memory mapped IO - * indirect port IO (one port for address, one for data) - * - * Author Karsten Keil - * - * Copyright 2009 by Karsten Keil - */ - -#ifndef _IOHELPER_H -#define _IOHELPER_H - -typedef u8 (read_reg_func)(void *hwp, u8 offset); -typedef void (write_reg_func)(void *hwp, u8 offset, u8 value); -typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size); - -struct _ioport { - u32 port; - u32 ale; -}; - -#define IOFUNC_IO(name, hws, ap) \ - static u8 Read##name##_IO(void *p, u8 off) { \ - struct hws *hw = p; \ - return inb(hw->ap.port + off); \ - } \ - static void Write##name##_IO(void *p, u8 off, u8 val) { \ - struct hws *hw = p; \ - outb(val, hw->ap.port + off); \ - } \ - static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) { \ - struct hws *hw = p; \ - insb(hw->ap.port + off, dp, size); \ - } \ - static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) { \ - struct hws *hw = p; \ - outsb(hw->ap.port + off, dp, size); \ - } - -#define IOFUNC_IND(name, hws, ap) \ - static u8 Read##name##_IND(void *p, u8 off) { \ - struct hws *hw = p; \ - outb(off, hw->ap.ale); \ - return inb(hw->ap.port); \ - } \ - static void Write##name##_IND(void *p, u8 off, u8 val) { \ - struct hws *hw = p; \ - outb(off, hw->ap.ale); \ - outb(val, hw->ap.port); \ - } \ - static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) { \ - struct hws *hw = p; \ - outb(off, hw->ap.ale); \ - insb(hw->ap.port, dp, size); \ - } \ - static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) { \ - struct hws *hw = p; \ - outb(off, hw->ap.ale); \ - outsb(hw->ap.port, dp, size); \ - } - -#define IOFUNC_MEMIO(name, hws, typ, adr) \ - static u8 Read##name##_MIO(void *p, u8 off) { \ - struct hws *hw = p; \ - return readb(((typ *)hw->adr) + off); \ - } \ - static void Write##name##_MIO(void *p, u8 off, u8 val) { \ - struct hws *hw = p; \ - writeb(val, ((typ *)hw->adr) + off); \ - } \ - static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) { \ - struct hws *hw = p; \ - while (size--) \ - *dp++ = readb(((typ *)hw->adr) + off); \ - } \ - static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) { \ - struct hws *hw = p; \ - while (size--) \ - writeb(*dp++, ((typ *)hw->adr) + off); \ - } - -#define ASSIGN_FUNC(typ, name, dest) do { \ - dest.read_reg = &Read##name##_##typ; \ - dest.write_reg = &Write##name##_##typ; \ - dest.read_fifo = &ReadFiFo##name##_##typ; \ - dest.write_fifo = &WriteFiFo##name##_##typ; \ - } while (0) -#define ASSIGN_FUNC_IPAC(typ, target) do { \ - ASSIGN_FUNC(typ, ISAC, target.isac); \ - ASSIGN_FUNC(typ, IPAC, target); \ - } while (0) - -#endif diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h deleted file mode 100644 index 2f0c4978a7a5..000000000000 --- a/drivers/isdn/hardware/mISDN/ipac.h +++ /dev/null @@ -1,393 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * - * ipac.h Defines for the Infineon (former Siemens) ISDN - * chip series - * - * Author Karsten Keil - * - * Copyright 2009 by Karsten Keil - */ - -#include "iohelper.h" - -struct isac_hw { - struct dchannel dch; - u32 type; - u32 off; /* offset to isac regs */ - char *name; - spinlock_t *hwlock; /* lock HW access */ - read_reg_func *read_reg; - write_reg_func *write_reg; - fifo_func *read_fifo; - fifo_func *write_fifo; - int (*monitor)(void *, u32, u8 *, int); - void (*release)(struct isac_hw *); - int (*init)(struct isac_hw *); - int (*ctrl)(struct isac_hw *, u32, u_long); - int (*open)(struct isac_hw *, struct channel_req *); - u8 *mon_tx; - u8 *mon_rx; - int mon_txp; - int mon_txc; - int mon_rxp; - struct arcofi_msg *arcofi_list; - struct timer_list arcofitimer; - wait_queue_head_t arcofi_wait; - u8 arcofi_bc; - u8 arcofi_state; - u8 mocr; - u8 adf2; - u8 state; -}; - -struct ipac_hw; - -struct hscx_hw { - struct bchannel bch; - struct ipac_hw *ip; - u8 fifo_size; - u8 off; /* offset to ICA or ICB */ - u8 slot; - char log[64]; -}; - -struct ipac_hw { - struct isac_hw isac; - struct hscx_hw hscx[2]; - char *name; - void *hw; - spinlock_t *hwlock; /* lock HW access */ - struct module *owner; - u32 type; - read_reg_func *read_reg; - write_reg_func *write_reg; - fifo_func *read_fifo; - fifo_func *write_fifo; - void (*release)(struct ipac_hw *); - int (*init)(struct ipac_hw *); - int (*ctrl)(struct ipac_hw *, u32, u_long); - u8 conf; -}; - -#define IPAC_TYPE_ISAC 0x0010 -#define IPAC_TYPE_IPAC 0x0020 -#define IPAC_TYPE_ISACX 0x0040 -#define IPAC_TYPE_IPACX 0x0080 -#define IPAC_TYPE_HSCX 0x0100 - -#define ISAC_USE_ARCOFI 0x1000 - -/* Monitor functions */ -#define MONITOR_RX_0 0x1000 -#define MONITOR_RX_1 0x1001 -#define MONITOR_TX_0 0x2000 -#define MONITOR_TX_1 0x2001 - -/* All registers original Siemens Spec */ -/* IPAC/ISAC registers */ -#define ISAC_ISTA 0x20 -#define ISAC_MASK 0x20 -#define ISAC_CMDR 0x21 -#define ISAC_STAR 0x21 -#define ISAC_MODE 0x22 -#define ISAC_TIMR 0x23 -#define ISAC_EXIR 0x24 -#define ISAC_RBCL 0x25 -#define ISAC_RSTA 0x27 -#define ISAC_RBCH 0x2A -#define ISAC_SPCR 0x30 -#define ISAC_CIR0 0x31 -#define ISAC_CIX0 0x31 -#define ISAC_MOR0 0x32 -#define ISAC_MOX0 0x32 -#define ISAC_CIR1 0x33 -#define ISAC_CIX1 0x33 -#define ISAC_MOR1 0x34 -#define ISAC_MOX1 0x34 -#define ISAC_STCR 0x37 -#define ISAC_ADF1 0x38 -#define ISAC_ADF2 0x39 -#define ISAC_MOCR 0x3a -#define ISAC_MOSR 0x3a -#define ISAC_SQRR 0x3b -#define ISAC_SQXR 0x3b - -#define ISAC_RBCH_XAC 0x80 - -#define IPAC_D_TIN2 0x01 - -/* IPAC/HSCX */ -#define IPAC_ISTAB 0x20 /* RD */ -#define IPAC_MASKB 0x20 /* WR */ -#define IPAC_STARB 0x21 /* RD */ -#define IPAC_CMDRB 0x21 /* WR */ -#define IPAC_MODEB 0x22 /* R/W */ -#define IPAC_EXIRB 0x24 /* RD */ -#define IPAC_RBCLB 0x25 /* RD */ -#define IPAC_RAH1 0x26 /* WR */ -#define IPAC_RAH2 0x27 /* WR */ -#define IPAC_RSTAB 0x27 /* RD */ -#define IPAC_RAL1 0x28 /* R/W */ -#define IPAC_RAL2 0x29 /* WR */ -#define IPAC_RHCRB 0x29 /* RD */ -#define IPAC_XBCL 0x2A /* WR */ -#define IPAC_CCR2 0x2C /* R/W */ -#define IPAC_RBCHB 0x2D /* RD */ -#define IPAC_XBCH 0x2D /* WR */ -#define HSCX_VSTR 0x2E /* RD */ -#define IPAC_RLCR 0x2E /* WR */ -#define IPAC_CCR1 0x2F /* R/W */ -#define IPAC_TSAX 0x30 /* WR */ -#define IPAC_TSAR 0x31 /* WR */ -#define IPAC_XCCR 0x32 /* WR */ -#define IPAC_RCCR 0x33 /* WR */ - -/* IPAC_ISTAB/IPAC_MASKB bits */ -#define IPAC_B_XPR 0x10 -#define IPAC_B_RPF 0x40 -#define IPAC_B_RME 0x80 -#define IPAC_B_ON 0x2F - -/* IPAC_EXIRB bits */ -#define IPAC_B_RFS 0x04 -#define IPAC_B_RFO 0x10 -#define IPAC_B_XDU 0x40 -#define IPAC_B_XMR 0x80 - -/* IPAC special registers */ -#define IPAC_CONF 0xC0 /* R/W */ -#define IPAC_ISTA 0xC1 /* RD */ -#define IPAC_MASK 0xC1 /* WR */ -#define IPAC_ID 0xC2 /* RD */ -#define IPAC_ACFG 0xC3 /* R/W */ -#define IPAC_AOE 0xC4 /* R/W */ -#define IPAC_ARX 0xC5 /* RD */ -#define IPAC_ATX 0xC5 /* WR */ -#define IPAC_PITA1 0xC6 /* R/W */ -#define IPAC_PITA2 0xC7 /* R/W */ -#define IPAC_POTA1 0xC8 /* R/W */ -#define IPAC_POTA2 0xC9 /* R/W */ -#define IPAC_PCFG 0xCA /* R/W */ -#define IPAC_SCFG 0xCB /* R/W */ -#define IPAC_TIMR2 0xCC /* R/W */ - -/* IPAC_ISTA/_MASK bits */ -#define IPAC__EXB 0x01 -#define IPAC__ICB 0x02 -#define IPAC__EXA 0x04 -#define IPAC__ICA 0x08 -#define IPAC__EXD 0x10 -#define IPAC__ICD 0x20 -#define IPAC__INT0 0x40 -#define IPAC__INT1 0x80 -#define IPAC__ON 0xC0 - -/* HSCX ISTA/MASK bits */ -#define HSCX__EXB 0x01 -#define HSCX__EXA 0x02 -#define HSCX__ICA 0x04 - -/* ISAC/ISACX/IPAC/IPACX L1 commands */ -#define ISAC_CMD_TIM 0x0 -#define ISAC_CMD_RS 0x1 -#define ISAC_CMD_SCZ 0x4 -#define ISAC_CMD_SSZ 0x2 -#define ISAC_CMD_AR8 0x8 -#define ISAC_CMD_AR10 0x9 -#define ISAC_CMD_ARL 0xA -#define ISAC_CMD_DUI 0xF - -/* ISAC/ISACX/IPAC/IPACX L1 indications */ -#define ISAC_IND_DR 0x0 -#define ISAC_IND_RS 0x1 -#define ISAC_IND_SD 0x2 -#define ISAC_IND_DIS 0x3 -#define ISAC_IND_RSY 0x4 -#define ISAC_IND_DR6 0x5 -#define ISAC_IND_EI 0x6 -#define ISAC_IND_PU 0x7 -#define ISAC_IND_ARD 0x8 -#define ISAC_IND_TI 0xA -#define ISAC_IND_ATI 0xB -#define ISAC_IND_AI8 0xC -#define ISAC_IND_AI10 0xD -#define ISAC_IND_DID 0xF - -/* the new ISACX / IPACX */ -/* D-channel registers */ -#define ISACX_RFIFOD 0x00 /* RD */ -#define ISACX_XFIFOD 0x00 /* WR */ -#define ISACX_ISTAD 0x20 /* RD */ -#define ISACX_MASKD 0x20 /* WR */ -#define ISACX_STARD 0x21 /* RD */ -#define ISACX_CMDRD 0x21 /* WR */ -#define ISACX_MODED 0x22 /* R/W */ -#define ISACX_EXMD1 0x23 /* R/W */ -#define ISACX_TIMR1 0x24 /* R/W */ -#define ISACX_SAP1 0x25 /* WR */ -#define ISACX_SAP2 0x26 /* WR */ -#define ISACX_RBCLD 0x26 /* RD */ -#define ISACX_RBCHD 0x27 /* RD */ -#define ISACX_TEI1 0x27 /* WR */ -#define ISACX_TEI2 0x28 /* WR */ -#define ISACX_RSTAD 0x28 /* RD */ -#define ISACX_TMD 0x29 /* R/W */ -#define ISACX_CIR0 0x2E /* RD */ -#define ISACX_CIX0 0x2E /* WR */ -#define ISACX_CIR1 0x2F /* RD */ -#define ISACX_CIX1 0x2F /* WR */ - -/* Transceiver registers */ -#define ISACX_TR_CONF0 0x30 /* R/W */ -#define ISACX_TR_CONF1 0x31 /* R/W */ -#define ISACX_TR_CONF2 0x32 /* R/W */ -#define ISACX_TR_STA 0x33 /* RD */ -#define ISACX_TR_CMD 0x34 /* R/W */ -#define ISACX_SQRR1 0x35 /* RD */ -#define ISACX_SQXR1 0x35 /* WR */ -#define ISACX_SQRR2 0x36 /* RD */ -#define ISACX_SQXR2 0x36 /* WR */ -#define ISACX_SQRR3 0x37 /* RD */ -#define ISACX_SQXR3 0x37 /* WR */ -#define ISACX_ISTATR 0x38 /* RD */ -#define ISACX_MASKTR 0x39 /* R/W */ -#define ISACX_TR_MODE 0x3A /* R/W */ -#define ISACX_ACFG1 0x3C /* R/W */ -#define ISACX_ACFG2 0x3D /* R/W */ -#define ISACX_AOE 0x3E /* R/W */ -#define ISACX_ARX 0x3F /* RD */ -#define ISACX_ATX 0x3F /* WR */ - -/* IOM: Timeslot, DPS, CDA */ -#define ISACX_CDA10 0x40 /* R/W */ -#define ISACX_CDA11 0x41 /* R/W */ -#define ISACX_CDA20 0x42 /* R/W */ -#define ISACX_CDA21 0x43 /* R/W */ -#define ISACX_CDA_TSDP10 0x44 /* R/W */ -#define ISACX_CDA_TSDP11 0x45 /* R/W */ -#define ISACX_CDA_TSDP20 0x46 /* R/W */ -#define ISACX_CDA_TSDP21 0x47 /* R/W */ -#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */ -#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */ -#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */ -#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */ -#define ISACX_TR_TSDP_BC1 0x4C /* R/W */ -#define ISACX_TR_TSDP_BC2 0x4D /* R/W */ -#define ISACX_CDA1_CR 0x4E /* R/W */ -#define ISACX_CDA2_CR 0x4F /* R/W */ - -/* IOM: Contol, Sync transfer, Monitor */ -#define ISACX_TR_CR 0x50 /* R/W */ -#define ISACX_TRC_CR 0x50 /* R/W */ -#define ISACX_BCHA_CR 0x51 /* R/W */ -#define ISACX_BCHB_CR 0x52 /* R/W */ -#define ISACX_DCI_CR 0x53 /* R/W */ -#define ISACX_DCIC_CR 0x53 /* R/W */ -#define ISACX_MON_CR 0x54 /* R/W */ -#define ISACX_SDS1_CR 0x55 /* R/W */ -#define ISACX_SDS2_CR 0x56 /* R/W */ -#define ISACX_IOM_CR 0x57 /* R/W */ -#define ISACX_STI 0x58 /* RD */ -#define ISACX_ASTI 0x58 /* WR */ -#define ISACX_MSTI 0x59 /* R/W */ -#define ISACX_SDS_CONF 0x5A /* R/W */ -#define ISACX_MCDA 0x5B /* RD */ -#define ISACX_MOR 0x5C /* RD */ -#define ISACX_MOX 0x5C /* WR */ -#define ISACX_MOSR 0x5D /* RD */ -#define ISACX_MOCR 0x5E /* R/W */ -#define ISACX_MSTA 0x5F /* RD */ -#define ISACX_MCONF 0x5F /* WR */ - -/* Interrupt and general registers */ -#define ISACX_ISTA 0x60 /* RD */ -#define ISACX_MASK 0x60 /* WR */ -#define ISACX_AUXI 0x61 /* RD */ -#define ISACX_AUXM 0x61 /* WR */ -#define ISACX_MODE1 0x62 /* R/W */ -#define ISACX_MODE2 0x63 /* R/W */ -#define ISACX_ID 0x64 /* RD */ -#define ISACX_SRES 0x64 /* WR */ -#define ISACX_TIMR2 0x65 /* R/W */ - -/* Register Bits */ -/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */ -#define ISACX_D_XDU 0x04 -#define ISACX_D_XMR 0x08 -#define ISACX_D_XPR 0x10 -#define ISACX_D_RFO 0x20 -#define ISACX_D_RPF 0x40 -#define ISACX_D_RME 0x80 - -/* ISACX/IPACX _ISTA (R) and _MASK (W) */ -#define ISACX__ICD 0x01 -#define ISACX__MOS 0x02 -#define ISACX__TRAN 0x04 -#define ISACX__AUX 0x08 -#define ISACX__CIC 0x10 -#define ISACX__ST 0x20 -#define IPACX__ON 0x2C -#define IPACX__ICB 0x40 -#define IPACX__ICA 0x80 - -/* ISACX/IPACX _CMDRD (W) */ -#define ISACX_CMDRD_XRES 0x01 -#define ISACX_CMDRD_XME 0x02 -#define ISACX_CMDRD_XTF 0x08 -#define ISACX_CMDRD_STI 0x10 -#define ISACX_CMDRD_RRES 0x40 -#define ISACX_CMDRD_RMC 0x80 - -/* ISACX/IPACX _RSTAD (R) */ -#define ISACX_RSTAD_TA 0x01 -#define ISACX_RSTAD_CR 0x02 -#define ISACX_RSTAD_SA0 0x04 -#define ISACX_RSTAD_SA1 0x08 -#define ISACX_RSTAD_RAB 0x10 -#define ISACX_RSTAD_CRC 0x20 -#define ISACX_RSTAD_RDO 0x40 -#define ISACX_RSTAD_VFR 0x80 - -/* ISACX/IPACX _CIR0 (R) */ -#define ISACX_CIR0_BAS 0x01 -#define ISACX_CIR0_SG 0x08 -#define ISACX_CIR0_CIC1 0x08 -#define ISACX_CIR0_CIC0 0x08 - -/* B-channel registers */ -#define IPACX_OFF_ICA 0x70 -#define IPACX_OFF_ICB 0x80 - -/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */ - -#define IPACX_ISTAB 0x00 /* RD */ -#define IPACX_MASKB 0x00 /* WR */ -#define IPACX_STARB 0x01 /* RD */ -#define IPACX_CMDRB 0x01 /* WR */ -#define IPACX_MODEB 0x02 /* R/W */ -#define IPACX_EXMB 0x03 /* R/W */ -#define IPACX_RAH1 0x05 /* WR */ -#define IPACX_RAH2 0x06 /* WR */ -#define IPACX_RBCLB 0x06 /* RD */ -#define IPACX_RBCHB 0x07 /* RD */ -#define IPACX_RAL1 0x07 /* WR */ -#define IPACX_RAL2 0x08 /* WR */ -#define IPACX_RSTAB 0x08 /* RD */ -#define IPACX_TMB 0x09 /* R/W */ -#define IPACX_RFIFOB 0x0A /* RD */ -#define IPACX_XFIFOB 0x0A /* WR */ - -/* IPACX_ISTAB / IPACX_MASKB bits */ -#define IPACX_B_XDU 0x04 -#define IPACX_B_XPR 0x10 -#define IPACX_B_RFO 0x20 -#define IPACX_B_RPF 0x40 -#define IPACX_B_RME 0x80 - -#define IPACX_B_ON 0x0B - -extern int mISDNisac_init(struct isac_hw *, void *); -extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8); -extern u32 mISDNipac_init(struct ipac_hw *, void *); -extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int); diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h deleted file mode 100644 index 36a9fa564b17..000000000000 --- a/drivers/isdn/hardware/mISDN/isar.h +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * - * isar.h ISAR (Siemens PSB 7110) specific defines - * - * Author Karsten Keil (keil@isdn4linux.de) - * - * Copyright 2009 by Karsten Keil - */ - -#include "iohelper.h" - -struct isar_hw; - -struct isar_ch { - struct bchannel bch; - struct isar_hw *is; - struct timer_list ftimer; - u8 nr; - u8 dpath; - u8 mml; - u8 state; - u8 cmd; - u8 mod; - u8 newcmd; - u8 newmod; - u8 try_mod; - u8 conmsg[16]; -}; - -struct isar_hw { - struct isar_ch ch[2]; - void *hw; - spinlock_t *hwlock; /* lock HW access */ - char *name; - struct module *owner; - read_reg_func *read_reg; - write_reg_func *write_reg; - fifo_func *read_fifo; - fifo_func *write_fifo; - int (*ctrl)(void *, u32, u_long); - void (*release)(struct isar_hw *); - int (*init)(struct isar_hw *); - int (*open)(struct isar_hw *, struct channel_req *); - int (*firmware)(struct isar_hw *, const u8 *, int); - unsigned long Flags; - int version; - u8 bstat; - u8 iis; - u8 cmsb; - u8 clsb; - u8 buf[256]; - u8 log[256]; -}; - -#define ISAR_IRQMSK 0x04 -#define ISAR_IRQSTA 0x04 -#define ISAR_IRQBIT 0x75 -#define ISAR_CTRL_H 0x61 -#define ISAR_CTRL_L 0x60 -#define ISAR_IIS 0x58 -#define ISAR_IIA 0x58 -#define ISAR_HIS 0x50 -#define ISAR_HIA 0x50 -#define ISAR_MBOX 0x4c -#define ISAR_WADR 0x4a -#define ISAR_RADR 0x48 - -#define ISAR_HIS_VNR 0x14 -#define ISAR_HIS_DKEY 0x02 -#define ISAR_HIS_FIRM 0x1e -#define ISAR_HIS_STDSP 0x08 -#define ISAR_HIS_DIAG 0x05 -#define ISAR_HIS_P0CFG 0x3c -#define ISAR_HIS_P12CFG 0x24 -#define ISAR_HIS_SARTCFG 0x25 -#define ISAR_HIS_PUMPCFG 0x26 -#define ISAR_HIS_PUMPCTRL 0x2a -#define ISAR_HIS_IOM2CFG 0x27 -#define ISAR_HIS_IOM2REQ 0x07 -#define ISAR_HIS_IOM2CTRL 0x2b -#define ISAR_HIS_BSTREQ 0x0c -#define ISAR_HIS_PSTREQ 0x0e -#define ISAR_HIS_SDATA 0x20 -#define ISAR_HIS_DPS1 0x40 -#define ISAR_HIS_DPS2 0x80 -#define SET_DPS(x) ((x << 6) & 0xc0) - -#define ISAR_IIS_MSCMSD 0x3f -#define ISAR_IIS_VNR 0x15 -#define ISAR_IIS_DKEY 0x03 -#define ISAR_IIS_FIRM 0x1f -#define ISAR_IIS_STDSP 0x09 -#define ISAR_IIS_DIAG 0x25 -#define ISAR_IIS_GSTEV 0x00 -#define ISAR_IIS_BSTEV 0x28 -#define ISAR_IIS_BSTRSP 0x2c -#define ISAR_IIS_PSTRSP 0x2e -#define ISAR_IIS_PSTEV 0x2a -#define ISAR_IIS_IOM2RSP 0x27 -#define ISAR_IIS_RDATA 0x20 -#define ISAR_IIS_INVMSG 0x3f - -#define ISAR_CTRL_SWVER 0x10 -#define ISAR_CTRL_STST 0x40 - -#define ISAR_MSG_HWVER 0x20 - -#define ISAR_DP1_USE 1 -#define ISAR_DP2_USE 2 -#define ISAR_RATE_REQ 3 - -#define PMOD_DISABLE 0 -#define PMOD_FAX 1 -#define PMOD_DATAMODEM 2 -#define PMOD_HALFDUPLEX 3 -#define PMOD_V110 4 -#define PMOD_DTMF 5 -#define PMOD_DTMF_TRANS 6 -#define PMOD_BYPASS 7 - -#define PCTRL_ORIG 0x80 -#define PV32P2_V23R 0x40 -#define PV32P2_V22A 0x20 -#define PV32P2_V22B 0x10 -#define PV32P2_V22C 0x08 -#define PV32P2_V21 0x02 -#define PV32P2_BEL 0x01 - -/* LSB MSB in ISAR doc wrong !!! Arghhh */ -#define PV32P3_AMOD 0x80 -#define PV32P3_V32B 0x02 -#define PV32P3_V23B 0x01 -#define PV32P4_48 0x11 -#define PV32P5_48 0x05 -#define PV32P4_UT48 0x11 -#define PV32P5_UT48 0x0d -#define PV32P4_96 0x11 -#define PV32P5_96 0x03 -#define PV32P4_UT96 0x11 -#define PV32P5_UT96 0x0f -#define PV32P4_B96 0x91 -#define PV32P5_B96 0x0b -#define PV32P4_UTB96 0xd1 -#define PV32P5_UTB96 0x0f -#define PV32P4_120 0xb1 -#define PV32P5_120 0x09 -#define PV32P4_UT120 0xf1 -#define PV32P5_UT120 0x0f -#define PV32P4_144 0x99 -#define PV32P5_144 0x09 -#define PV32P4_UT144 0xf9 -#define PV32P5_UT144 0x0f -#define PV32P6_CTN 0x01 -#define PV32P6_ATN 0x02 - -#define PFAXP2_CTN 0x01 -#define PFAXP2_ATN 0x04 - -#define PSEV_10MS_TIMER 0x02 -#define PSEV_CON_ON 0x18 -#define PSEV_CON_OFF 0x19 -#define PSEV_V24_OFF 0x20 -#define PSEV_CTS_ON 0x21 -#define PSEV_CTS_OFF 0x22 -#define PSEV_DCD_ON 0x23 -#define PSEV_DCD_OFF 0x24 -#define PSEV_DSR_ON 0x25 -#define PSEV_DSR_OFF 0x26 -#define PSEV_REM_RET 0xcc -#define PSEV_REM_REN 0xcd -#define PSEV_GSTN_CLR 0xd4 - -#define PSEV_RSP_READY 0xbc -#define PSEV_LINE_TX_H 0xb3 -#define PSEV_LINE_TX_B 0xb2 -#define PSEV_LINE_RX_H 0xb1 -#define PSEV_LINE_RX_B 0xb0 -#define PSEV_RSP_CONN 0xb5 -#define PSEV_RSP_DISC 0xb7 -#define PSEV_RSP_FCERR 0xb9 -#define PSEV_RSP_SILDET 0xbe -#define PSEV_RSP_SILOFF 0xab -#define PSEV_FLAGS_DET 0xba - -#define PCTRL_CMD_TDTMF 0x5a - -#define PCTRL_CMD_FTH 0xa7 -#define PCTRL_CMD_FRH 0xa5 -#define PCTRL_CMD_FTM 0xa8 -#define PCTRL_CMD_FRM 0xa6 -#define PCTRL_CMD_SILON 0xac -#define PCTRL_CMD_CONT 0xa2 -#define PCTRL_CMD_ESC 0xa4 -#define PCTRL_CMD_SILOFF 0xab -#define PCTRL_CMD_HALT 0xa9 - -#define PCTRL_LOC_RET 0xcf -#define PCTRL_LOC_REN 0xce - -#define SMODE_DISABLE 0 -#define SMODE_V14 2 -#define SMODE_HDLC 3 -#define SMODE_BINARY 4 -#define SMODE_FSK_V14 5 - -#define SCTRL_HDMC_BOTH 0x00 -#define SCTRL_HDMC_DTX 0x80 -#define SCTRL_HDMC_DRX 0x40 -#define S_P1_OVSP 0x40 -#define S_P1_SNP 0x20 -#define S_P1_EOP 0x10 -#define S_P1_EDP 0x08 -#define S_P1_NSB 0x04 -#define S_P1_CHS_8 0x03 -#define S_P1_CHS_7 0x02 -#define S_P1_CHS_6 0x01 -#define S_P1_CHS_5 0x00 - -#define S_P2_BFT_DEF 0x10 - -#define IOM_CTRL_ENA 0x80 -#define IOM_CTRL_NOPCM 0x00 -#define IOM_CTRL_ALAW 0x02 -#define IOM_CTRL_ULAW 0x04 -#define IOM_CTRL_RCV 0x01 - -#define IOM_P1_TXD 0x10 - -#define HDLC_FED 0x40 -#define HDLC_FSD 0x20 -#define HDLC_FST 0x20 -#define HDLC_ERROR 0x1c -#define HDLC_ERR_FAD 0x10 -#define HDLC_ERR_RER 0x08 -#define HDLC_ERR_CER 0x04 -#define SART_NMD 0x01 - -#define BSTAT_RDM0 0x1 -#define BSTAT_RDM1 0x2 -#define BSTAT_RDM2 0x4 -#define BSTAT_RDM3 0x8 -#define BSTEV_TBO 0x1f -#define BSTEV_RBO 0x2f - -/* FAX State Machine */ -#define STFAX_NULL 0 -#define STFAX_READY 1 -#define STFAX_LINE 2 -#define STFAX_CONT 3 -#define STFAX_ACTIV 4 -#define STFAX_ESCAPE 5 -#define STFAX_SILDET 6 - -extern u32 mISDNisar_init(struct isar_hw *, void *); -extern void mISDNisar_irq(struct isar_hw *); diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.c b/drivers/isdn/hardware/mISDN/isdnhdlc.c deleted file mode 100644 index 985367e6711d..000000000000 --- a/drivers/isdn/hardware/mISDN/isdnhdlc.c +++ /dev/null @@ -1,617 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * isdnhdlc.c -- General purpose ISDN HDLC decoder. - * - * Copyright (C) - * 2009 Karsten Keil - * 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - */ - -#include -#include -#include -#include -#include "isdnhdlc.h" - -/*-------------------------------------------------------------------*/ - -MODULE_AUTHOR("Wolfgang Mües , " - "Frode Isaksen , " - "Kai Germaschewski "); -MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); -MODULE_LICENSE("GPL"); - -/*-------------------------------------------------------------------*/ - -enum { - HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, - HDLC_GET_DATA, HDLC_FAST_FLAG -}; - -enum { - HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, - HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, - HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE -}; - -void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) -{ - memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); - hdlc->state = HDLC_GET_DATA; - if (features & HDLC_56KBIT) - hdlc->do_adapt56 = 1; - if (features & HDLC_BITREVERSE) - hdlc->do_bitreverse = 1; -} -EXPORT_SYMBOL(isdnhdlc_out_init); - -void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) -{ - memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); - if (features & HDLC_DCHANNEL) { - hdlc->dchannel = 1; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - hdlc->dchannel = 0; - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->ffvalue = 0x7e; - } - hdlc->cbin = 0x7e; - if (features & HDLC_56KBIT) { - hdlc->do_adapt56 = 1; - hdlc->state = HDLC_SENDFLAG_B0; - } else - hdlc->data_bits = 8; - if (features & HDLC_BITREVERSE) - hdlc->do_bitreverse = 1; -} -EXPORT_SYMBOL(isdnhdlc_rcv_init); - -static int -check_frame(struct isdnhdlc_vars *hdlc) -{ - int status; - - if (hdlc->dstpos < 2) /* too small - framing error */ - status = -HDLC_FRAMING_ERROR; - else if (hdlc->crc != 0xf0b8) /* crc error */ - status = -HDLC_CRC_ERROR; - else { - /* remove CRC */ - hdlc->dstpos -= 2; - /* good frame */ - status = hdlc->dstpos; - } - return status; -} - -/* - isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. - - The source buffer is scanned for valid HDLC frames looking for - flags (01111110) to indicate the start of a frame. If the start of - the frame is found, the bit stuffing is removed (0 after 5 1's). - When a new flag is found, the complete frame has been received - and the CRC is checked. - If a valid frame is found, the function returns the frame length - excluding the CRC with the bit HDLC_END_OF_FRAME set. - If the beginning of a valid frame is found, the function returns - the length. - If a framing error is found (too many 1s and not a flag) the function - returns the length with the bit HDLC_FRAMING_ERROR set. - If a CRC error is found the function returns the length with the - bit HDLC_CRC_ERROR set. - If the frame length exceeds the destination buffer size, the function - returns the length with the bit HDLC_LENGTH_ERROR set. - - src - source buffer - slen - source buffer length - count - number of bytes removed (decoded) from the source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of decoded bytes in the destination buffer and status - flag. -*/ -int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, - int *count, u8 *dst, int dsize) -{ - int status = 0; - - static const unsigned char fast_flag[] = { - 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f - }; - - static const unsigned char fast_flag_value[] = { - 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f - }; - - static const unsigned char fast_abort[] = { - 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff - }; - -#define handle_fast_flag(h) \ - do { \ - if (h->cbin == fast_flag[h->bit_shift]) { \ - h->ffvalue = fast_flag_value[h->bit_shift]; \ - h->state = HDLC_FAST_FLAG; \ - h->ffbit_shift = h->bit_shift; \ - h->bit_shift = 1; \ - } else { \ - h->state = HDLC_GET_DATA; \ - h->data_received = 0; \ - } \ - } while (0) - -#define handle_abort(h) \ - do { \ - h->shift_reg = fast_abort[h->ffbit_shift - 1]; \ - h->hdlc_bits1 = h->ffbit_shift - 2; \ - if (h->hdlc_bits1 < 0) \ - h->hdlc_bits1 = 0; \ - h->data_bits = h->ffbit_shift - 1; \ - h->state = HDLC_GET_DATA; \ - h->data_received = 0; \ - } while (0) - - *count = slen; - - while (slen > 0) { - if (hdlc->bit_shift == 0) { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - hdlc->cbin = bitrev8(*src++); - else - hdlc->cbin = *src++; - slen--; - hdlc->bit_shift = 8; - if (hdlc->do_adapt56) - hdlc->bit_shift--; - } - - switch (hdlc->state) { - case STOPPED: - return 0; - case HDLC_FAST_IDLE: - if (hdlc->cbin == 0xff) { - hdlc->bit_shift = 0; - break; - } - hdlc->state = HDLC_GET_FLAG_B0; - hdlc->hdlc_bits1 = 0; - hdlc->bit_shift = 8; - break; - case HDLC_GET_FLAG_B0: - if (!(hdlc->cbin & 0x80)) { - hdlc->state = HDLC_GETFLAG_B1A6; - hdlc->hdlc_bits1 = 0; - } else { - if ((!hdlc->do_adapt56) && - (++hdlc->hdlc_bits1 >= 8) && - (hdlc->bit_shift == 1)) - hdlc->state = HDLC_FAST_IDLE; - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_GETFLAG_B1A6: - if (hdlc->cbin & 0x80) { - hdlc->hdlc_bits1++; - if (hdlc->hdlc_bits1 == 6) - hdlc->state = HDLC_GETFLAG_B7; - } else - hdlc->hdlc_bits1 = 0; - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_GETFLAG_B7: - if (hdlc->cbin & 0x80) { - hdlc->state = HDLC_GET_FLAG_B0; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->data_received = 0; - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_GET_DATA: - if (hdlc->cbin & 0x80) { - hdlc->hdlc_bits1++; - switch (hdlc->hdlc_bits1) { - case 6: - break; - case 7: - if (hdlc->data_received) - /* bad frame */ - status = -HDLC_FRAMING_ERROR; - if (!hdlc->do_adapt56) { - if (hdlc->cbin == fast_abort - [hdlc->bit_shift + 1]) { - hdlc->state = - HDLC_FAST_IDLE; - hdlc->bit_shift = 1; - break; - } - } else - hdlc->state = HDLC_GET_FLAG_B0; - break; - default: - hdlc->shift_reg >>= 1; - hdlc->shift_reg |= 0x80; - hdlc->data_bits++; - break; - } - } else { - switch (hdlc->hdlc_bits1) { - case 5: - break; - case 6: - if (hdlc->data_received) - status = check_frame(hdlc); - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->data_bits = 0; - if (!hdlc->do_adapt56) - handle_fast_flag(hdlc); - else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - break; - default: - hdlc->shift_reg >>= 1; - hdlc->data_bits++; - break; - } - hdlc->hdlc_bits1 = 0; - } - if (status) { - hdlc->dstpos = 0; - *count -= slen; - hdlc->cbin <<= 1; - hdlc->bit_shift--; - return status; - } - if (hdlc->data_bits == 8) { - hdlc->data_bits = 0; - hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, - hdlc->shift_reg); - - /* good byte received */ - if (hdlc->dstpos < dsize) - dst[hdlc->dstpos++] = hdlc->shift_reg; - else { - /* frame too long */ - status = -HDLC_LENGTH_ERROR; - hdlc->dstpos = 0; - } - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_FAST_FLAG: - if (hdlc->cbin == hdlc->ffvalue) { - hdlc->bit_shift = 0; - break; - } else { - if (hdlc->cbin == 0xff) { - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift = 0; - } else if (hdlc->ffbit_shift == 8) { - hdlc->state = HDLC_GETFLAG_B7; - break; - } else - handle_abort(hdlc); - } - break; - default: - break; - } - } - *count -= slen; - return 0; -} -EXPORT_SYMBOL(isdnhdlc_decode); -/* - isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. - - The bit stream starts with a beginning flag (01111110). After - that each byte is added to the bit stream with bit stuffing added - (0 after 5 1's). - When the last byte has been removed from the source buffer, the - CRC (2 bytes is added) and the frame terminates with the ending flag. - For the dchannel, the idle character (all 1's) is also added at the end. - If this function is called with empty source buffer (slen=0), flags or - idle character will be generated. - - src - source buffer - slen - source buffer length - count - number of bytes removed (encoded) from source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of encoded bytes in the destination buffer -*/ -int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, - int *count, u8 *dst, int dsize) -{ - static const unsigned char xfast_flag_value[] = { - 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e - }; - - int len = 0; - - *count = slen; - - /* special handling for one byte frames */ - if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) - hdlc->state = HDLC_SENDFLAG_ONE; - while (dsize > 0) { - if (hdlc->bit_shift == 0) { - if (slen && !hdlc->do_closing) { - hdlc->shift_reg = *src++; - slen--; - if (slen == 0) - /* closing sequence, CRC + flag(s) */ - hdlc->do_closing = 1; - hdlc->bit_shift = 8; - } else { - if (hdlc->state == HDLC_SEND_DATA) { - if (hdlc->data_received) { - hdlc->state = HDLC_SEND_CRC1; - hdlc->crc ^= 0xffff; - hdlc->bit_shift = 8; - hdlc->shift_reg = - hdlc->crc & 0xff; - } else if (!hdlc->do_adapt56) - hdlc->state = - HDLC_SEND_FAST_FLAG; - else - hdlc->state = - HDLC_SENDFLAG_B0; - } - - } - } - - switch (hdlc->state) { - case STOPPED: - while (dsize--) - *dst++ = 0xff; - return dsize; - case HDLC_SEND_FAST_FLAG: - hdlc->do_closing = 0; - if (slen == 0) { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - *dst++ = bitrev8(hdlc->ffvalue); - else - *dst++ = hdlc->ffvalue; - len++; - dsize--; - break; - } - fallthrough; - case HDLC_SENDFLAG_ONE: - if (hdlc->bit_shift == 8) { - hdlc->cbin = hdlc->ffvalue >> - (8 - hdlc->data_bits); - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SENDFLAG_B0: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->hdlc_bits1 = 0; - hdlc->state = HDLC_SENDFLAG_B1A6; - break; - case HDLC_SENDFLAG_B1A6: - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->cbin++; - if (++hdlc->hdlc_bits1 == 6) - hdlc->state = HDLC_SENDFLAG_B7; - break; - case HDLC_SENDFLAG_B7: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (slen == 0) { - hdlc->state = HDLC_SENDFLAG_B0; - break; - } - if (hdlc->bit_shift == 8) { - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SEND_FIRST_FLAG: - hdlc->data_received = 1; - if (hdlc->data_bits == 8) { - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - break; - } - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->shift_reg & 0x01) - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if (hdlc->bit_shift == 0) { - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - } - break; - case HDLC_SEND_DATA: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->bit_shift == 8) - hdlc->crc = crc_ccitt_byte(hdlc->crc, - hdlc->shift_reg); - if (hdlc->shift_reg & 0x01) { - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - break; - case HDLC_SEND_CRC1: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->shift_reg & 0x01) { - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if (hdlc->bit_shift == 0) { - hdlc->shift_reg = (hdlc->crc >> 8); - hdlc->state = HDLC_SEND_CRC2; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CRC2: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->shift_reg & 0x01) { - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if (hdlc->bit_shift == 0) { - hdlc->shift_reg = 0x7e; - hdlc->state = HDLC_SEND_CLOSING_FLAG; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CLOSING_FLAG: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->shift_reg & 0x01) - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if (hdlc->bit_shift == 0) { - hdlc->ffvalue = - xfast_flag_value[hdlc->data_bits]; - if (hdlc->dchannel) { - hdlc->ffvalue = 0x7e; - hdlc->state = HDLC_SEND_IDLE1; - hdlc->bit_shift = 8-hdlc->data_bits; - if (hdlc->bit_shift == 0) - hdlc->state = - HDLC_SEND_FAST_IDLE; - } else { - if (!hdlc->do_adapt56) { - hdlc->state = - HDLC_SEND_FAST_FLAG; - hdlc->data_received = 0; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - hdlc->data_received = 0; - } - /* Finished this frame, send flags */ - if (dsize > 1) - dsize = 1; - } - } - break; - case HDLC_SEND_IDLE1: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - hdlc->bit_shift--; - if (hdlc->bit_shift == 0) { - hdlc->state = HDLC_SEND_FAST_IDLE; - hdlc->bit_shift = 0; - } - break; - case HDLC_SEND_FAST_IDLE: - hdlc->do_closing = 0; - hdlc->cbin = 0xff; - hdlc->data_bits = 8; - if (hdlc->bit_shift == 8) { - hdlc->cbin = 0x7e; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - *dst++ = bitrev8(hdlc->cbin); - else - *dst++ = hdlc->cbin; - hdlc->bit_shift = 0; - hdlc->data_bits = 0; - len++; - dsize = 0; - } - break; - default: - break; - } - if (hdlc->do_adapt56) { - if (hdlc->data_bits == 7) { - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - } - } - if (hdlc->data_bits == 8) { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - *dst++ = bitrev8(hdlc->cbin); - else - *dst++ = hdlc->cbin; - hdlc->data_bits = 0; - len++; - dsize--; - } - } - *count -= slen; - - return len; -} -EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.h b/drivers/isdn/hardware/mISDN/isdnhdlc.h deleted file mode 100644 index fe2c1279c139..000000000000 --- a/drivers/isdn/hardware/mISDN/isdnhdlc.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * hdlc.h -- General purpose ISDN HDLC decoder. - * - * Implementation of a HDLC decoder/encoder in software. - * Necessary because some ISDN devices don't have HDLC - * controllers. - * - * Copyright (C) - * 2009 Karsten Keil - * 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - */ - -#ifndef __ISDNHDLC_H__ -#define __ISDNHDLC_H__ - -struct isdnhdlc_vars { - int bit_shift; - int hdlc_bits1; - int data_bits; - int ffbit_shift; /* encoding only */ - int state; - int dstpos; - - u16 crc; - - u8 cbin; - u8 shift_reg; - u8 ffvalue; - - /* set if transferring data */ - u32 data_received:1; - /* set if D channel (send idle instead of flags) */ - u32 dchannel:1; - /* set if 56K adaptation */ - u32 do_adapt56:1; - /* set if in closing phase (need to send CRC + flag) */ - u32 do_closing:1; - /* set if data is bitreverse */ - u32 do_bitreverse:1; -}; - -/* Feature Flags */ -#define HDLC_56KBIT 0x01 -#define HDLC_DCHANNEL 0x02 -#define HDLC_BITREVERSE 0x04 - -/* - The return value from isdnhdlc_decode is - the frame length, 0 if no complete frame was decoded, - or a negative error number -*/ -#define HDLC_FRAMING_ERROR 1 -#define HDLC_CRC_ERROR 2 -#define HDLC_LENGTH_ERROR 3 - -extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features); - -extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, - int slen, int *count, u8 *dst, int dsize); - -extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features); - -extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, - u16 slen, int *count, u8 *dst, int dsize); - -#endif /* __ISDNHDLC_H__ */ diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c deleted file mode 100644 index aaa639ad5526..000000000000 --- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c +++ /dev/null @@ -1,1168 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * mISDNinfineon.c - * Support for cards based on following Infineon ISDN chipsets - * - ISAC + HSCX - * - IPAC and IPAC-X - * - ISAC-SX + HSCX - * - * Supported cards: - * - Dialogic Diva 2.0 - * - Dialogic Diva 2.0U - * - Dialogic Diva 2.01 - * - Dialogic Diva 2.02 - * - Sedlbauer Speedwin - * - HST Saphir3 - * - Develo (former ELSA) Microlink PCI (Quickstep 1000) - * - Develo (former ELSA) Quickstep 3000 - * - Berkom Scitel BRIX Quadro - * - Dr.Neuhaus (Sagem) Niccy - * - * Author Karsten Keil - * - * Copyright 2009 by Karsten Keil - */ - -#include -#include -#include -#include -#include -#include -#include "ipac.h" - -#define INFINEON_REV "1.0" - -static int inf_cnt; -static u32 debug; -static u32 irqloops = 4; - -enum inf_types { - INF_NONE, - INF_DIVA20, - INF_DIVA20U, - INF_DIVA201, - INF_DIVA202, - INF_SPEEDWIN, - INF_SAPHIR3, - INF_QS1000, - INF_QS3000, - INF_NICCY, - INF_SCT_1, - INF_SCT_2, - INF_SCT_3, - INF_SCT_4, - INF_GAZEL_R685, - INF_GAZEL_R753 -}; - -enum addr_mode { - AM_NONE = 0, - AM_IO, - AM_MEMIO, - AM_IND_IO, -}; - -struct inf_cinfo { - enum inf_types typ; - const char *full; - const char *name; - enum addr_mode cfg_mode; - enum addr_mode addr_mode; - u8 cfg_bar; - u8 addr_bar; - void *irqfunc; -}; - -struct _ioaddr { - enum addr_mode mode; - union { - void __iomem *p; - struct _ioport io; - } a; -}; - -struct _iohandle { - enum addr_mode mode; - resource_size_t size; - resource_size_t start; - void __iomem *p; -}; - -struct inf_hw { - struct list_head list; - struct pci_dev *pdev; - const struct inf_cinfo *ci; - char name[MISDN_MAX_IDLEN]; - u32 irq; - u32 irqcnt; - struct _iohandle cfg; - struct _iohandle addr; - struct _ioaddr isac; - struct _ioaddr hscx; - spinlock_t lock; /* HW access lock */ - struct ipac_hw ipac; - struct inf_hw *sc[3]; /* slave cards */ -}; - - -#define PCI_SUBVENDOR_HST_SAPHIR3 0x52 -#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 -#define PCI_SUB_ID_SEDLBAUER 0x01 - -static struct pci_device_id infineon_ids[] = { - { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 }, - { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U }, - { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 }, - { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 }, - { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, - PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0, - INF_SPEEDWIN }, - { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, - PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 }, - { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 }, - { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 }, - { PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0, - INF_SCT_1 }, - { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 }, - { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 }, - { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 }, - { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 }, - { } -}; -MODULE_DEVICE_TABLE(pci, infineon_ids); - -/* PCI interface specific defines */ -/* Diva 2.0/2.0U */ -#define DIVA_HSCX_PORT 0x00 -#define DIVA_HSCX_ALE 0x04 -#define DIVA_ISAC_PORT 0x08 -#define DIVA_ISAC_ALE 0x0C -#define DIVA_PCI_CTRL 0x10 - -/* DIVA_PCI_CTRL bits */ -#define DIVA_IRQ_BIT 0x01 -#define DIVA_RESET_BIT 0x08 -#define DIVA_EEPROM_CLK 0x40 -#define DIVA_LED_A 0x10 -#define DIVA_LED_B 0x20 -#define DIVA_IRQ_CLR 0x80 - -/* Diva 2.01/2.02 */ -/* Siemens PITA */ -#define PITA_ICR_REG 0x00 -#define PITA_INT0_STATUS 0x02 - -#define PITA_MISC_REG 0x1c -#define PITA_PARA_SOFTRESET 0x01000000 -#define PITA_SER_SOFTRESET 0x02000000 -#define PITA_PARA_MPX_MODE 0x04000000 -#define PITA_INT0_ENABLE 0x00020000 - -/* TIGER 100 Registers */ -#define TIGER_RESET_ADDR 0x00 -#define TIGER_EXTERN_RESET 0x01 -#define TIGER_AUX_CTRL 0x02 -#define TIGER_AUX_DATA 0x03 -#define TIGER_AUX_IRQMASK 0x05 -#define TIGER_AUX_STATUS 0x07 - -/* Tiger AUX BITs */ -#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */ -#define TIGER_IRQ_BIT 0x02 - -#define TIGER_IPAC_ALE 0xC0 -#define TIGER_IPAC_PORT 0xC8 - -/* ELSA (now Develo) PCI cards */ -#define ELSA_IRQ_ADDR 0x4c -#define ELSA_IRQ_MASK 0x04 -#define QS1000_IRQ_OFF 0x01 -#define QS3000_IRQ_OFF 0x03 -#define QS1000_IRQ_ON 0x41 -#define QS3000_IRQ_ON 0x43 - -/* Dr Neuhaus/Sagem Niccy */ -#define NICCY_ISAC_PORT 0x00 -#define NICCY_HSCX_PORT 0x01 -#define NICCY_ISAC_ALE 0x02 -#define NICCY_HSCX_ALE 0x03 - -#define NICCY_IRQ_CTRL_REG 0x38 -#define NICCY_IRQ_ENABLE 0x001f00 -#define NICCY_IRQ_DISABLE 0xff0000 -#define NICCY_IRQ_BIT 0x800000 - - -/* Scitel PLX */ -#define SCT_PLX_IRQ_ADDR 0x4c -#define SCT_PLX_RESET_ADDR 0x50 -#define SCT_PLX_IRQ_ENABLE 0x41 -#define SCT_PLX_RESET_BIT 0x04 - -/* Gazel */ -#define GAZEL_IPAC_DATA_PORT 0x04 -/* Gazel PLX */ -#define GAZEL_CNTRL 0x50 -#define GAZEL_RESET 0x04 -#define GAZEL_RESET_9050 0x40000000 -#define GAZEL_INCSR 0x4C -#define GAZEL_ISAC_EN 0x08 -#define GAZEL_INT_ISAC 0x20 -#define GAZEL_HSCX_EN 0x01 -#define GAZEL_INT_HSCX 0x04 -#define GAZEL_PCI_EN 0x40 -#define GAZEL_IPAC_EN 0x03 - - -static LIST_HEAD(Cards); -static DEFINE_RWLOCK(card_lock); /* protect Cards */ - -static void -_set_debug(struct inf_hw *card) -{ - card->ipac.isac.dch.debug = debug; - card->ipac.hscx[0].bch.debug = debug; - card->ipac.hscx[1].bch.debug = debug; -} - -static int -set_debug(const char *val, const struct kernel_param *kp) -{ - int ret; - struct inf_hw *card; - - ret = param_set_uint(val, kp); - if (!ret) { - read_lock(&card_lock); - list_for_each_entry(card, &Cards, list) - _set_debug(card); - read_unlock(&card_lock); - } - return ret; -} - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("mISDN driver for cards based on Infineon ISDN chipsets"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(INFINEON_REV); -module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "infineon debug mask"); -module_param(irqloops, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)"); - -/* Interface functions */ - -IOFUNC_IO(ISAC, inf_hw, isac.a.io) -IOFUNC_IO(IPAC, inf_hw, hscx.a.io) -IOFUNC_IND(ISAC, inf_hw, isac.a.io) -IOFUNC_IND(IPAC, inf_hw, hscx.a.io) -IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p) -IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p) - -static irqreturn_t -diva_irq(int intno, void *dev_id) -{ - struct inf_hw *hw = dev_id; - u8 val; - - spin_lock(&hw->lock); - val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL); - if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */ - spin_unlock(&hw->lock); - return IRQ_NONE; /* shared */ - } - hw->irqcnt++; - mISDNipac_irq(&hw->ipac, irqloops); - spin_unlock(&hw->lock); - return IRQ_HANDLED; -} - -static irqreturn_t -diva20x_irq(int intno, void *dev_id) -{ - struct inf_hw *hw = dev_id; - u8 val; - - spin_lock(&hw->lock); - val = readb(hw->cfg.p); - if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */ - spin_unlock(&hw->lock); - return IRQ_NONE; /* shared */ - } - hw->irqcnt++; - mISDNipac_irq(&hw->ipac, irqloops); - writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */ - spin_unlock(&hw->lock); - return IRQ_HANDLED; -} - -static irqreturn_t -tiger_irq(int intno, void *dev_id) -{ - struct inf_hw *hw = dev_id; - u8 val; - - spin_lock(&hw->lock); - val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS); - if (val & TIGER_IRQ_BIT) { /* for us or shared ? */ - spin_unlock(&hw->lock); - return IRQ_NONE; /* shared */ - } - hw->irqcnt++; - mISDNipac_irq(&hw->ipac, irqloops); - spin_unlock(&hw->lock); - return IRQ_HANDLED; -} - -static irqreturn_t -elsa_irq(int intno, void *dev_id) -{ - struct inf_hw *hw = dev_id; - u8 val; - - spin_lock(&hw->lock); - val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR); - if (!(val & ELSA_IRQ_MASK)) { - spin_unlock(&hw->lock); - return IRQ_NONE; /* shared */ - } - hw->irqcnt++; - mISDNipac_irq(&hw->ipac, irqloops); - spin_unlock(&hw->lock); - return IRQ_HANDLED; -} - -static irqreturn_t -niccy_irq(int intno, void *dev_id) -{ - struct inf_hw *hw = dev_id; - u32 val; - - spin_lock(&hw->lock); - val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); - if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */ - spin_unlock(&hw->lock); - return IRQ_NONE; /* shared */ - } - outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); - hw->irqcnt++; - mISDNipac_irq(&hw->ipac, irqloops); - spin_unlock(&hw->lock); - return IRQ_HANDLED; -} - -static irqreturn_t -gazel_irq(int intno, void *dev_id) -{ - struct inf_hw *hw = dev_id; - irqreturn_t ret; - - spin_lock(&hw->lock); - ret = mISDNipac_irq(&hw->ipac, irqloops); - spin_unlock(&hw->lock); - return ret; -} - -static irqreturn_t -ipac_irq(int intno, void *dev_id) -{ - struct inf_hw *hw = dev_id; - u8 val; - - spin_lock(&hw->lock); - val = hw->ipac.read_reg(hw, IPAC_ISTA); - if (!(val & 0x3f)) { - spin_unlock(&hw->lock); - return IRQ_NONE; /* shared */ - } - hw->irqcnt++; - mISDNipac_irq(&hw->ipac, irqloops); - spin_unlock(&hw->lock); - return IRQ_HANDLED; -} - -static void -enable_hwirq(struct inf_hw *hw) -{ - u16 w; - u32 val; - - switch (hw->ci->typ) { - case INF_DIVA201: - case INF_DIVA202: - writel(PITA_INT0_ENABLE, hw->cfg.p); - break; - case INF_SPEEDWIN: - case INF_SAPHIR3: - outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); - break; - case INF_QS1000: - outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); - break; - case INF_QS3000: - outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); - break; - case INF_NICCY: - val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); - val |= NICCY_IRQ_ENABLE; - outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); - break; - case INF_SCT_1: - w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); - w |= SCT_PLX_IRQ_ENABLE; - outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); - break; - case INF_GAZEL_R685: - outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN, - (u32)hw->cfg.start + GAZEL_INCSR); - break; - case INF_GAZEL_R753: - outb(GAZEL_IPAC_EN + GAZEL_PCI_EN, - (u32)hw->cfg.start + GAZEL_INCSR); - break; - default: - break; - } -} - -static void -disable_hwirq(struct inf_hw *hw) -{ - u16 w; - u32 val; - - switch (hw->ci->typ) { - case INF_DIVA201: - case INF_DIVA202: - writel(0, hw->cfg.p); - break; - case INF_SPEEDWIN: - case INF_SAPHIR3: - outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); - break; - case INF_QS1000: - outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); - break; - case INF_QS3000: - outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); - break; - case INF_NICCY: - val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); - val &= NICCY_IRQ_DISABLE; - outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); - break; - case INF_SCT_1: - w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); - w &= (~SCT_PLX_IRQ_ENABLE); - outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); - break; - case INF_GAZEL_R685: - case INF_GAZEL_R753: - outb(0, (u32)hw->cfg.start + GAZEL_INCSR); - break; - default: - break; - } -} - -static void -ipac_chip_reset(struct inf_hw *hw) -{ - hw->ipac.write_reg(hw, IPAC_POTA2, 0x20); - mdelay(5); - hw->ipac.write_reg(hw, IPAC_POTA2, 0x00); - mdelay(5); - hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf); - hw->ipac.write_reg(hw, IPAC_MASK, 0xc0); -} - -static void -reset_inf(struct inf_hw *hw) -{ - u16 w; - u32 val; - - if (debug & DEBUG_HW) - pr_notice("%s: resetting card\n", hw->name); - switch (hw->ci->typ) { - case INF_DIVA20: - case INF_DIVA20U: - outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL); - mdelay(10); - outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL); - mdelay(10); - /* Workaround PCI9060 */ - outb(9, (u32)hw->cfg.start + 0x69); - outb(DIVA_RESET_BIT | DIVA_LED_A, - (u32)hw->cfg.start + DIVA_PCI_CTRL); - break; - case INF_DIVA201: - writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, - hw->cfg.p + PITA_MISC_REG); - mdelay(1); - writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG); - mdelay(10); - break; - case INF_DIVA202: - writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, - hw->cfg.p + PITA_MISC_REG); - mdelay(1); - writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET, - hw->cfg.p + PITA_MISC_REG); - mdelay(10); - break; - case INF_SPEEDWIN: - case INF_SAPHIR3: - ipac_chip_reset(hw); - hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); - hw->ipac.write_reg(hw, IPAC_AOE, 0x00); - hw->ipac.write_reg(hw, IPAC_PCFG, 0x12); - break; - case INF_QS1000: - case INF_QS3000: - ipac_chip_reset(hw); - hw->ipac.write_reg(hw, IPAC_ACFG, 0x00); - hw->ipac.write_reg(hw, IPAC_AOE, 0x3c); - hw->ipac.write_reg(hw, IPAC_ATX, 0xff); - break; - case INF_NICCY: - break; - case INF_SCT_1: - w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); - w &= (~SCT_PLX_RESET_BIT); - outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); - mdelay(10); - w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); - w |= SCT_PLX_RESET_BIT; - outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); - mdelay(10); - break; - case INF_GAZEL_R685: - val = inl((u32)hw->cfg.start + GAZEL_CNTRL); - val |= (GAZEL_RESET_9050 + GAZEL_RESET); - outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); - val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); - mdelay(4); - outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); - mdelay(10); - hw->ipac.isac.adf2 = 0x87; - hw->ipac.hscx[0].slot = 0x1f; - hw->ipac.hscx[1].slot = 0x23; - break; - case INF_GAZEL_R753: - val = inl((u32)hw->cfg.start + GAZEL_CNTRL); - val |= (GAZEL_RESET_9050 + GAZEL_RESET); - outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); - val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); - mdelay(4); - outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); - mdelay(10); - ipac_chip_reset(hw); - hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); - hw->ipac.write_reg(hw, IPAC_AOE, 0x00); - hw->ipac.conf = 0x01; /* IOM off */ - break; - default: - return; - } - enable_hwirq(hw); -} - -static int -inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg) -{ - int ret = 0; - - switch (cmd) { - case HW_RESET_REQ: - reset_inf(hw); - break; - default: - pr_info("%s: %s unknown command %x %lx\n", - hw->name, __func__, cmd, arg); - ret = -EINVAL; - break; - } - return ret; -} - -static int -init_irq(struct inf_hw *hw) -{ - int ret, cnt = 3; - u_long flags; - - if (!hw->ci->irqfunc) - return -EINVAL; - ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw); - if (ret) { - pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq); - return ret; - } - while (cnt--) { - spin_lock_irqsave(&hw->lock, flags); - reset_inf(hw); - ret = hw->ipac.init(&hw->ipac); - if (ret) { - spin_unlock_irqrestore(&hw->lock, flags); - pr_info("%s: ISAC init failed with %d\n", - hw->name, ret); - break; - } - spin_unlock_irqrestore(&hw->lock, flags); - msleep_interruptible(10); - if (debug & DEBUG_HW) - pr_notice("%s: IRQ %d count %d\n", hw->name, - hw->irq, hw->irqcnt); - if (!hw->irqcnt) { - pr_info("%s: IRQ(%d) got no requests during init %d\n", - hw->name, hw->irq, 3 - cnt); - } else - return 0; - } - free_irq(hw->irq, hw); - return -EIO; -} - -static void -release_io(struct inf_hw *hw) -{ - if (hw->cfg.mode) { - if (hw->cfg.mode == AM_MEMIO) { - release_mem_region(hw->cfg.start, hw->cfg.size); - if (hw->cfg.p) - iounmap(hw->cfg.p); - } else - release_region(hw->cfg.start, hw->cfg.size); - hw->cfg.mode = AM_NONE; - } - if (hw->addr.mode) { - if (hw->addr.mode == AM_MEMIO) { - release_mem_region(hw->addr.start, hw->addr.size); - if (hw->addr.p) - iounmap(hw->addr.p); - } else - release_region(hw->addr.start, hw->addr.size); - hw->addr.mode = AM_NONE; - } -} - -static int -setup_io(struct inf_hw *hw) -{ - int err = 0; - - if (hw->ci->cfg_mode) { - hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar); - hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar); - if (hw->ci->cfg_mode == AM_MEMIO) { - if (!request_mem_region(hw->cfg.start, hw->cfg.size, - hw->name)) - err = -EBUSY; - } else { - if (!request_region(hw->cfg.start, hw->cfg.size, - hw->name)) - err = -EBUSY; - } - if (err) { - pr_info("mISDN: %s config port %lx (%lu bytes)" - "already in use\n", hw->name, - (ulong)hw->cfg.start, (ulong)hw->cfg.size); - return err; - } - hw->cfg.mode = hw->ci->cfg_mode; - if (hw->ci->cfg_mode == AM_MEMIO) { - hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size); - if (!hw->cfg.p) - return -ENOMEM; - } - if (debug & DEBUG_HW) - pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n", - hw->name, (ulong)hw->cfg.start, - (ulong)hw->cfg.size, hw->ci->cfg_mode); - - } - if (hw->ci->addr_mode) { - hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar); - hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar); - if (hw->ci->addr_mode == AM_MEMIO) { - if (!request_mem_region(hw->addr.start, hw->addr.size, - hw->name)) - err = -EBUSY; - } else { - if (!request_region(hw->addr.start, hw->addr.size, - hw->name)) - err = -EBUSY; - } - if (err) { - pr_info("mISDN: %s address port %lx (%lu bytes)" - "already in use\n", hw->name, - (ulong)hw->addr.start, (ulong)hw->addr.size); - return err; - } - hw->addr.mode = hw->ci->addr_mode; - if (hw->ci->addr_mode == AM_MEMIO) { - hw->addr.p = ioremap(hw->addr.start, hw->addr.size); - if (!hw->addr.p) - return -ENOMEM; - } - if (debug & DEBUG_HW) - pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n", - hw->name, (ulong)hw->addr.start, - (ulong)hw->addr.size, hw->ci->addr_mode); - - } - - switch (hw->ci->typ) { - case INF_DIVA20: - case INF_DIVA20U: - hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; - hw->isac.mode = hw->cfg.mode; - hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE; - hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT; - hw->hscx.mode = hw->cfg.mode; - hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE; - hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT; - break; - case INF_DIVA201: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.mode = hw->addr.mode; - hw->isac.a.p = hw->addr.p; - hw->hscx.mode = hw->addr.mode; - hw->hscx.a.p = hw->addr.p; - break; - case INF_DIVA202: - hw->ipac.type = IPAC_TYPE_IPACX; - hw->isac.mode = hw->addr.mode; - hw->isac.a.p = hw->addr.p; - hw->hscx.mode = hw->addr.mode; - hw->hscx.a.p = hw->addr.p; - break; - case INF_SPEEDWIN: - case INF_SAPHIR3: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.mode = hw->cfg.mode; - hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; - hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; - hw->hscx.mode = hw->cfg.mode; - hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; - hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; - outb(0xff, (ulong)hw->cfg.start); - mdelay(1); - outb(0x00, (ulong)hw->cfg.start); - mdelay(1); - outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL); - break; - case INF_QS1000: - case INF_QS3000: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.a.io.ale = (u32)hw->addr.start; - hw->isac.a.io.port = (u32)hw->addr.start + 1; - hw->isac.mode = hw->addr.mode; - hw->hscx.a.io.ale = (u32)hw->addr.start; - hw->hscx.a.io.port = (u32)hw->addr.start + 1; - hw->hscx.mode = hw->addr.mode; - break; - case INF_NICCY: - hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; - hw->isac.mode = hw->addr.mode; - hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE; - hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT; - hw->hscx.mode = hw->addr.mode; - hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE; - hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT; - break; - case INF_SCT_1: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.a.io.ale = (u32)hw->addr.start; - hw->isac.a.io.port = hw->isac.a.io.ale + 4; - hw->isac.mode = hw->addr.mode; - hw->hscx.a.io.ale = hw->isac.a.io.ale; - hw->hscx.a.io.port = hw->isac.a.io.port; - hw->hscx.mode = hw->addr.mode; - break; - case INF_SCT_2: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.a.io.ale = (u32)hw->addr.start + 0x08; - hw->isac.a.io.port = hw->isac.a.io.ale + 4; - hw->isac.mode = hw->addr.mode; - hw->hscx.a.io.ale = hw->isac.a.io.ale; - hw->hscx.a.io.port = hw->isac.a.io.port; - hw->hscx.mode = hw->addr.mode; - break; - case INF_SCT_3: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.a.io.ale = (u32)hw->addr.start + 0x10; - hw->isac.a.io.port = hw->isac.a.io.ale + 4; - hw->isac.mode = hw->addr.mode; - hw->hscx.a.io.ale = hw->isac.a.io.ale; - hw->hscx.a.io.port = hw->isac.a.io.port; - hw->hscx.mode = hw->addr.mode; - break; - case INF_SCT_4: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.a.io.ale = (u32)hw->addr.start + 0x20; - hw->isac.a.io.port = hw->isac.a.io.ale + 4; - hw->isac.mode = hw->addr.mode; - hw->hscx.a.io.ale = hw->isac.a.io.ale; - hw->hscx.a.io.port = hw->isac.a.io.port; - hw->hscx.mode = hw->addr.mode; - break; - case INF_GAZEL_R685: - hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; - hw->ipac.isac.off = 0x80; - hw->isac.mode = hw->addr.mode; - hw->isac.a.io.port = (u32)hw->addr.start; - hw->hscx.mode = hw->addr.mode; - hw->hscx.a.io.port = hw->isac.a.io.port; - break; - case INF_GAZEL_R753: - hw->ipac.type = IPAC_TYPE_IPAC; - hw->ipac.isac.off = 0x80; - hw->isac.mode = hw->addr.mode; - hw->isac.a.io.ale = (u32)hw->addr.start; - hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT; - hw->hscx.mode = hw->addr.mode; - hw->hscx.a.io.ale = hw->isac.a.io.ale; - hw->hscx.a.io.port = hw->isac.a.io.port; - break; - default: - return -EINVAL; - } - switch (hw->isac.mode) { - case AM_MEMIO: - ASSIGN_FUNC_IPAC(MIO, hw->ipac); - break; - case AM_IND_IO: - ASSIGN_FUNC_IPAC(IND, hw->ipac); - break; - case AM_IO: - ASSIGN_FUNC_IPAC(IO, hw->ipac); - break; - default: - return -EINVAL; - } - return 0; -} - -static void -release_card(struct inf_hw *card) { - ulong flags; - int i; - - spin_lock_irqsave(&card->lock, flags); - disable_hwirq(card); - spin_unlock_irqrestore(&card->lock, flags); - card->ipac.isac.release(&card->ipac.isac); - free_irq(card->irq, card); - mISDN_unregister_device(&card->ipac.isac.dch.dev); - release_io(card); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - switch (card->ci->typ) { - case INF_SCT_2: - case INF_SCT_3: - case INF_SCT_4: - break; - case INF_SCT_1: - for (i = 0; i < 3; i++) { - if (card->sc[i]) - release_card(card->sc[i]); - card->sc[i] = NULL; - } - fallthrough; - default: - pci_disable_device(card->pdev); - pci_set_drvdata(card->pdev, NULL); - break; - } - kfree(card); - inf_cnt--; -} - -static int -setup_instance(struct inf_hw *card) -{ - int err; - ulong flags; - - snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name, - inf_cnt + 1); - write_lock_irqsave(&card_lock, flags); - list_add_tail(&card->list, &Cards); - write_unlock_irqrestore(&card_lock, flags); - - _set_debug(card); - card->ipac.isac.name = card->name; - card->ipac.name = card->name; - card->ipac.owner = THIS_MODULE; - spin_lock_init(&card->lock); - card->ipac.isac.hwlock = &card->lock; - card->ipac.hwlock = &card->lock; - card->ipac.ctrl = (void *)&inf_ctrl; - - err = setup_io(card); - if (err) - goto error_setup; - - card->ipac.isac.dch.dev.Bprotocols = - mISDNipac_init(&card->ipac, card); - - if (card->ipac.isac.dch.dev.Bprotocols == 0) - goto error_setup; - - err = mISDN_register_device(&card->ipac.isac.dch.dev, - &card->pdev->dev, card->name); - if (err) - goto error; - - err = init_irq(card); - if (!err) { - inf_cnt++; - pr_notice("Infineon %d cards installed\n", inf_cnt); - return 0; - } - mISDN_unregister_device(&card->ipac.isac.dch.dev); -error: - card->ipac.release(&card->ipac); -error_setup: - release_io(card); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - return err; -} - -static const struct inf_cinfo inf_card_info[] = { - { - INF_DIVA20, - "Dialogic Diva 2.0", - "diva20", - AM_IND_IO, AM_NONE, 2, 0, - &diva_irq - }, - { - INF_DIVA20U, - "Dialogic Diva 2.0U", - "diva20U", - AM_IND_IO, AM_NONE, 2, 0, - &diva_irq - }, - { - INF_DIVA201, - "Dialogic Diva 2.01", - "diva201", - AM_MEMIO, AM_MEMIO, 0, 1, - &diva20x_irq - }, - { - INF_DIVA202, - "Dialogic Diva 2.02", - "diva202", - AM_MEMIO, AM_MEMIO, 0, 1, - &diva20x_irq - }, - { - INF_SPEEDWIN, - "Sedlbauer SpeedWin PCI", - "speedwin", - AM_IND_IO, AM_NONE, 0, 0, - &tiger_irq - }, - { - INF_SAPHIR3, - "HST Saphir 3", - "saphir", - AM_IND_IO, AM_NONE, 0, 0, - &tiger_irq - }, - { - INF_QS1000, - "Develo Microlink PCI", - "qs1000", - AM_IO, AM_IND_IO, 1, 3, - &elsa_irq - }, - { - INF_QS3000, - "Develo QuickStep 3000", - "qs3000", - AM_IO, AM_IND_IO, 1, 3, - &elsa_irq - }, - { - INF_NICCY, - "Sagem NICCY", - "niccy", - AM_IO, AM_IND_IO, 0, 1, - &niccy_irq - }, - { - INF_SCT_1, - "SciTel Quadro", - "p1_scitel", - AM_IO, AM_IND_IO, 1, 5, - &ipac_irq - }, - { - INF_SCT_2, - "SciTel Quadro", - "p2_scitel", - AM_NONE, AM_IND_IO, 0, 4, - &ipac_irq - }, - { - INF_SCT_3, - "SciTel Quadro", - "p3_scitel", - AM_NONE, AM_IND_IO, 0, 3, - &ipac_irq - }, - { - INF_SCT_4, - "SciTel Quadro", - "p4_scitel", - AM_NONE, AM_IND_IO, 0, 2, - &ipac_irq - }, - { - INF_GAZEL_R685, - "Gazel R685", - "gazel685", - AM_IO, AM_IO, 1, 2, - &gazel_irq - }, - { - INF_GAZEL_R753, - "Gazel R753", - "gazel753", - AM_IO, AM_IND_IO, 1, 2, - &ipac_irq - }, - { - INF_NONE, - } -}; - -static const struct inf_cinfo * -get_card_info(enum inf_types typ) -{ - const struct inf_cinfo *ci = inf_card_info; - - while (ci->typ != INF_NONE) { - if (ci->typ == typ) - return ci; - ci++; - } - return NULL; -} - -static int -inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - struct inf_hw *card; - - card = kzalloc_obj(struct inf_hw); - if (!card) { - pr_info("No memory for Infineon ISDN card\n"); - return err; - } - card->pdev = pdev; - err = pci_enable_device(pdev); - if (err) { - kfree(card); - return err; - } - card->ci = get_card_info(ent->driver_data); - if (!card->ci) { - pr_info("mISDN: do not have information about adapter at %s\n", - pci_name(pdev)); - kfree(card); - pci_disable_device(pdev); - return -EINVAL; - } else - pr_notice("mISDN: found adapter %s at %s\n", - card->ci->full, pci_name(pdev)); - - card->irq = pdev->irq; - pci_set_drvdata(pdev, card); - err = setup_instance(card); - if (err) { - pci_disable_device(pdev); - kfree(card); - pci_set_drvdata(pdev, NULL); - } else if (ent->driver_data == INF_SCT_1) { - int i; - struct inf_hw *sc; - - for (i = 1; i < 4; i++) { - sc = kzalloc_obj(struct inf_hw); - if (!sc) { - release_card(card); - pci_disable_device(pdev); - return -ENOMEM; - } - sc->irq = card->irq; - sc->pdev = card->pdev; - sc->ci = card->ci + i; - err = setup_instance(sc); - if (err) { - pci_disable_device(pdev); - kfree(sc); - release_card(card); - break; - } else - card->sc[i - 1] = sc; - } - } - return err; -} - -static void -inf_remove(struct pci_dev *pdev) -{ - struct inf_hw *card = pci_get_drvdata(pdev); - - if (card) - release_card(card); - else - pr_debug("%s: drvdata already removed\n", __func__); -} - -static struct pci_driver infineon_driver = { - .name = "ISDN Infineon pci", - .probe = inf_probe, - .remove = inf_remove, - .id_table = infineon_ids, -}; - -static int __init -infineon_init(void) -{ - int err; - - pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV); - err = pci_register_driver(&infineon_driver); - return err; -} - -static void __exit -infineon_cleanup(void) -{ - pci_unregister_driver(&infineon_driver); -} - -module_init(infineon_init); -module_exit(infineon_cleanup); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c deleted file mode 100644 index a34ea6058960..000000000000 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ /dev/null @@ -1,1636 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * isac.c ISAC specific routines - * - * Author Karsten Keil - * - * Copyright 2009 by Karsten Keil - */ - -#include -#include -#include -#include -#include "ipac.h" - - -#define DBUSY_TIMER_VALUE 80 -#define ARCOFI_USE 1 - -#define ISAC_REV "2.0" - -MODULE_AUTHOR("Karsten Keil"); -MODULE_VERSION(ISAC_REV); -MODULE_DESCRIPTION("mISDN driver for ISAC specific functions"); -MODULE_LICENSE("GPL v2"); - -#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off)) -#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v)) -#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o)) -#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v)) -#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o)) -#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v)) - -static inline void -ph_command(struct isac_hw *isac, u8 command) -{ - pr_debug("%s: ph_command %x\n", isac->name, command); - if (isac->type & IPAC_TYPE_ISACX) - WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE); - else - WriteISAC(isac, ISAC_CIX0, (command << 2) | 3); -} - -static void -isac_ph_state_change(struct isac_hw *isac) -{ - switch (isac->state) { - case (ISAC_IND_RS): - case (ISAC_IND_EI): - ph_command(isac, ISAC_CMD_DUI); - } - schedule_event(&isac->dch, FLG_PHCHANGE); -} - -static void -isac_ph_state_bh(struct dchannel *dch) -{ - struct isac_hw *isac = container_of(dch, struct isac_hw, dch); - - switch (isac->state) { - case ISAC_IND_RS: - case ISAC_IND_EI: - dch->state = 0; - l1_event(dch->l1, HW_RESET_IND); - break; - case ISAC_IND_DID: - dch->state = 3; - l1_event(dch->l1, HW_DEACT_CNF); - break; - case ISAC_IND_DR: - case ISAC_IND_DR6: - dch->state = 3; - l1_event(dch->l1, HW_DEACT_IND); - break; - case ISAC_IND_PU: - dch->state = 4; - l1_event(dch->l1, HW_POWERUP_IND); - break; - case ISAC_IND_RSY: - if (dch->state <= 5) { - dch->state = 5; - l1_event(dch->l1, ANYSIGNAL); - } else { - dch->state = 8; - l1_event(dch->l1, LOSTFRAMING); - } - break; - case ISAC_IND_ARD: - dch->state = 6; - l1_event(dch->l1, INFO2); - break; - case ISAC_IND_AI8: - dch->state = 7; - l1_event(dch->l1, INFO4_P8); - break; - case ISAC_IND_AI10: - dch->state = 7; - l1_event(dch->l1, INFO4_P10); - break; - } - pr_debug("%s: TE newstate %x\n", isac->name, dch->state); -} - -static void -isac_empty_fifo(struct isac_hw *isac, int count) -{ - u8 *ptr; - - pr_debug("%s: %s %d\n", isac->name, __func__, count); - - if (!isac->dch.rx_skb) { - isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC); - if (!isac->dch.rx_skb) { - pr_info("%s: D receive out of memory\n", isac->name); - WriteISAC(isac, ISAC_CMDR, 0x80); - return; - } - } - if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) { - pr_debug("%s: %s overrun %d\n", isac->name, __func__, - isac->dch.rx_skb->len + count); - WriteISAC(isac, ISAC_CMDR, 0x80); - return; - } - ptr = skb_put(isac->dch.rx_skb, count); - isac->read_fifo(isac->dch.hw, isac->off, ptr, count); - WriteISAC(isac, ISAC_CMDR, 0x80); - if (isac->dch.debug & DEBUG_HW_DFIFO) { - char pfx[MISDN_MAX_IDLEN + 16]; - - snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ", - isac->name, count); - print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); - } -} - -static void -isac_fill_fifo(struct isac_hw *isac) -{ - int count, more; - u8 *ptr; - - if (!isac->dch.tx_skb) - return; - count = isac->dch.tx_skb->len - isac->dch.tx_idx; - if (count <= 0) - return; - - more = 0; - if (count > 32) { - more = !0; - count = 32; - } - pr_debug("%s: %s %d\n", isac->name, __func__, count); - ptr = isac->dch.tx_skb->data + isac->dch.tx_idx; - isac->dch.tx_idx += count; - isac->write_fifo(isac->dch.hw, isac->off, ptr, count); - WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa); - if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { - pr_debug("%s: %s dbusytimer running\n", isac->name, __func__); - timer_delete(&isac->dch.timer); - } - isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); - add_timer(&isac->dch.timer); - if (isac->dch.debug & DEBUG_HW_DFIFO) { - char pfx[MISDN_MAX_IDLEN + 16]; - - snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ", - isac->name, count); - print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); - } -} - -static void -isac_rme_irq(struct isac_hw *isac) -{ - u8 val, count; - - val = ReadISAC(isac, ISAC_RSTA); - if ((val & 0x70) != 0x20) { - if (val & 0x40) { - pr_debug("%s: ISAC RDO\n", isac->name); -#ifdef ERROR_STATISTIC - isac->dch.err_rx++; -#endif - } - if (!(val & 0x20)) { - pr_debug("%s: ISAC CRC error\n", isac->name); -#ifdef ERROR_STATISTIC - isac->dch.err_crc++; -#endif - } - WriteISAC(isac, ISAC_CMDR, 0x80); - dev_kfree_skb(isac->dch.rx_skb); - isac->dch.rx_skb = NULL; - } else { - count = ReadISAC(isac, ISAC_RBCL) & 0x1f; - if (count == 0) - count = 32; - isac_empty_fifo(isac, count); - recv_Dchannel(&isac->dch); - } -} - -static void -isac_xpr_irq(struct isac_hw *isac) -{ - if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) - timer_delete(&isac->dch.timer); - if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) { - isac_fill_fifo(isac); - } else { - dev_kfree_skb(isac->dch.tx_skb); - if (get_next_dframe(&isac->dch)) - isac_fill_fifo(isac); - } -} - -static void -isac_retransmit(struct isac_hw *isac) -{ - if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) - timer_delete(&isac->dch.timer); - if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) { - /* Restart frame */ - isac->dch.tx_idx = 0; - isac_fill_fifo(isac); - } else if (isac->dch.tx_skb) { /* should not happen */ - pr_info("%s: tx_skb exist but not busy\n", isac->name); - test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags); - isac->dch.tx_idx = 0; - isac_fill_fifo(isac); - } else { - pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name); - if (get_next_dframe(&isac->dch)) - isac_fill_fifo(isac); - } -} - -static void -isac_mos_irq(struct isac_hw *isac) -{ - u8 val; - int ret; - - val = ReadISAC(isac, ISAC_MOSR); - pr_debug("%s: ISAC MOSR %02x\n", isac->name, val); -#if ARCOFI_USE - if (val & 0x08) { - if (!isac->mon_rx) { - isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); - if (!isac->mon_rx) { - pr_info("%s: ISAC MON RX out of memory!\n", - isac->name); - isac->mocr &= 0xf0; - isac->mocr |= 0x0a; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - goto afterMONR0; - } else - isac->mon_rxp = 0; - } - if (isac->mon_rxp >= MAX_MON_FRAME) { - isac->mocr &= 0xf0; - isac->mocr |= 0x0a; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - isac->mon_rxp = 0; - pr_debug("%s: ISAC MON RX overflow!\n", isac->name); - goto afterMONR0; - } - isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0); - pr_debug("%s: ISAC MOR0 %02x\n", isac->name, - isac->mon_rx[isac->mon_rxp - 1]); - if (isac->mon_rxp == 1) { - isac->mocr |= 0x04; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - } - } -afterMONR0: - if (val & 0x80) { - if (!isac->mon_rx) { - isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); - if (!isac->mon_rx) { - pr_info("%s: ISAC MON RX out of memory!\n", - isac->name); - isac->mocr &= 0x0f; - isac->mocr |= 0xa0; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - goto afterMONR1; - } else - isac->mon_rxp = 0; - } - if (isac->mon_rxp >= MAX_MON_FRAME) { - isac->mocr &= 0x0f; - isac->mocr |= 0xa0; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - isac->mon_rxp = 0; - pr_debug("%s: ISAC MON RX overflow!\n", isac->name); - goto afterMONR1; - } - isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1); - pr_debug("%s: ISAC MOR1 %02x\n", isac->name, - isac->mon_rx[isac->mon_rxp - 1]); - isac->mocr |= 0x40; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - } -afterMONR1: - if (val & 0x04) { - isac->mocr &= 0xf0; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - isac->mocr |= 0x0a; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - if (isac->monitor) { - ret = isac->monitor(isac->dch.hw, MONITOR_RX_0, - isac->mon_rx, isac->mon_rxp); - if (ret) - kfree(isac->mon_rx); - } else { - pr_info("%s: MONITOR 0 received %d but no user\n", - isac->name, isac->mon_rxp); - kfree(isac->mon_rx); - } - isac->mon_rx = NULL; - isac->mon_rxp = 0; - } - if (val & 0x40) { - isac->mocr &= 0x0f; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - isac->mocr |= 0xa0; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - if (isac->monitor) { - ret = isac->monitor(isac->dch.hw, MONITOR_RX_1, - isac->mon_rx, isac->mon_rxp); - if (ret) - kfree(isac->mon_rx); - } else { - pr_info("%s: MONITOR 1 received %d but no user\n", - isac->name, isac->mon_rxp); - kfree(isac->mon_rx); - } - isac->mon_rx = NULL; - isac->mon_rxp = 0; - } - if (val & 0x02) { - if ((!isac->mon_tx) || (isac->mon_txc && - (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) { - isac->mocr &= 0xf0; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - isac->mocr |= 0x0a; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { - if (isac->monitor) - isac->monitor(isac->dch.hw, - MONITOR_TX_0, NULL, 0); - } - kfree(isac->mon_tx); - isac->mon_tx = NULL; - isac->mon_txc = 0; - isac->mon_txp = 0; - goto AfterMOX0; - } - if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { - if (isac->monitor) - isac->monitor(isac->dch.hw, - MONITOR_TX_0, NULL, 0); - kfree(isac->mon_tx); - isac->mon_tx = NULL; - isac->mon_txc = 0; - isac->mon_txp = 0; - goto AfterMOX0; - } - WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]); - pr_debug("%s: ISAC %02x -> MOX0\n", isac->name, - isac->mon_tx[isac->mon_txp - 1]); - } -AfterMOX0: - if (val & 0x20) { - if ((!isac->mon_tx) || (isac->mon_txc && - (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) { - isac->mocr &= 0x0f; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - isac->mocr |= 0xa0; - WriteISAC(isac, ISAC_MOCR, isac->mocr); - if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { - if (isac->monitor) - isac->monitor(isac->dch.hw, - MONITOR_TX_1, NULL, 0); - } - kfree(isac->mon_tx); - isac->mon_tx = NULL; - isac->mon_txc = 0; - isac->mon_txp = 0; - goto AfterMOX1; - } - if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { - if (isac->monitor) - isac->monitor(isac->dch.hw, - MONITOR_TX_1, NULL, 0); - kfree(isac->mon_tx); - isac->mon_tx = NULL; - isac->mon_txc = 0; - isac->mon_txp = 0; - goto AfterMOX1; - } - WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]); - pr_debug("%s: ISAC %02x -> MOX1\n", isac->name, - isac->mon_tx[isac->mon_txp - 1]); - } -AfterMOX1: - val = 0; /* dummy to avoid warning */ -#endif -} - -static void -isac_cisq_irq(struct isac_hw *isac) { - u8 val; - - val = ReadISAC(isac, ISAC_CIR0); - pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val); - if (val & 2) { - pr_debug("%s: ph_state change %x->%x\n", isac->name, - isac->state, (val >> 2) & 0xf); - isac->state = (val >> 2) & 0xf; - isac_ph_state_change(isac); - } - if (val & 1) { - val = ReadISAC(isac, ISAC_CIR1); - pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val); - } -} - -static void -isacsx_cic_irq(struct isac_hw *isac) -{ - u8 val; - - val = ReadISAC(isac, ISACX_CIR0); - pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); - if (val & ISACX_CIR0_CIC0) { - pr_debug("%s: ph_state change %x->%x\n", isac->name, - isac->state, val >> 4); - isac->state = val >> 4; - isac_ph_state_change(isac); - } -} - -static void -isacsx_rme_irq(struct isac_hw *isac) -{ - int count; - u8 val; - - val = ReadISAC(isac, ISACX_RSTAD); - if ((val & (ISACX_RSTAD_VFR | - ISACX_RSTAD_RDO | - ISACX_RSTAD_CRC | - ISACX_RSTAD_RAB)) - != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) { - pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val); -#ifdef ERROR_STATISTIC - if (val & ISACX_RSTAD_CRC) - isac->dch.err_rx++; - else - isac->dch.err_crc++; -#endif - WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); - dev_kfree_skb(isac->dch.rx_skb); - isac->dch.rx_skb = NULL; - } else { - count = ReadISAC(isac, ISACX_RBCLD) & 0x1f; - if (count == 0) - count = 32; - isac_empty_fifo(isac, count); - if (isac->dch.rx_skb) { - skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1); - pr_debug("%s: dchannel received %d\n", isac->name, - isac->dch.rx_skb->len); - recv_Dchannel(&isac->dch); - } - } -} - -irqreturn_t -mISDNisac_irq(struct isac_hw *isac, u8 val) -{ - if (unlikely(!val)) - return IRQ_NONE; - pr_debug("%s: ISAC interrupt %02x\n", isac->name, val); - if (isac->type & IPAC_TYPE_ISACX) { - if (val & ISACX__CIC) - isacsx_cic_irq(isac); - if (val & ISACX__ICD) { - val = ReadISAC(isac, ISACX_ISTAD); - pr_debug("%s: ISTAD %02x\n", isac->name, val); - if (val & ISACX_D_XDU) { - pr_debug("%s: ISAC XDU\n", isac->name); -#ifdef ERROR_STATISTIC - isac->dch.err_tx++; -#endif - isac_retransmit(isac); - } - if (val & ISACX_D_XMR) { - pr_debug("%s: ISAC XMR\n", isac->name); -#ifdef ERROR_STATISTIC - isac->dch.err_tx++; -#endif - isac_retransmit(isac); - } - if (val & ISACX_D_XPR) - isac_xpr_irq(isac); - if (val & ISACX_D_RFO) { - pr_debug("%s: ISAC RFO\n", isac->name); - WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); - } - if (val & ISACX_D_RME) - isacsx_rme_irq(isac); - if (val & ISACX_D_RPF) - isac_empty_fifo(isac, 0x20); - } - } else { - if (val & 0x80) /* RME */ - isac_rme_irq(isac); - if (val & 0x40) /* RPF */ - isac_empty_fifo(isac, 32); - if (val & 0x10) /* XPR */ - isac_xpr_irq(isac); - if (val & 0x04) /* CISQ */ - isac_cisq_irq(isac); - if (val & 0x20) /* RSC - never */ - pr_debug("%s: ISAC RSC interrupt\n", isac->name); - if (val & 0x02) /* SIN - never */ - pr_debug("%s: ISAC SIN interrupt\n", isac->name); - if (val & 0x01) { /* EXI */ - val = ReadISAC(isac, ISAC_EXIR); - pr_debug("%s: ISAC EXIR %02x\n", isac->name, val); - if (val & 0x80) /* XMR */ - pr_debug("%s: ISAC XMR\n", isac->name); - if (val & 0x40) { /* XDU */ - pr_debug("%s: ISAC XDU\n", isac->name); -#ifdef ERROR_STATISTIC - isac->dch.err_tx++; -#endif - isac_retransmit(isac); - } - if (val & 0x04) /* MOS */ - isac_mos_irq(isac); - } - } - return IRQ_HANDLED; -} -EXPORT_SYMBOL(mISDNisac_irq); - -static int -isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct isac_hw *isac = container_of(dch, struct isac_hw, dch); - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - u32 id; - u_long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(isac->hwlock, flags); - ret = dchannel_senddata(dch, skb); - if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ - isac_fill_fifo(isac); - ret = 0; - spin_unlock_irqrestore(isac->hwlock, flags); - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(isac->hwlock, flags); - return ret; - case PH_ACTIVATE_REQ: - ret = l1_event(dch->l1, hh->prim); - break; - case PH_DEACTIVATE_REQ: - test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); - ret = l1_event(dch->l1, hh->prim); - break; - } - - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -isac_ctrl(struct isac_hw *isac, u32 cmd, unsigned long para) -{ - u8 tl = 0; - unsigned long flags; - int ret = 0; - - switch (cmd) { - case HW_TESTLOOP: - spin_lock_irqsave(isac->hwlock, flags); - if (!(isac->type & IPAC_TYPE_ISACX)) { - /* TODO: implement for IPAC_TYPE_ISACX */ - if (para & 1) /* B1 */ - tl |= 0x0c; - else if (para & 2) /* B2 */ - tl |= 0x3; - /* we only support IOM2 mode */ - WriteISAC(isac, ISAC_SPCR, tl); - if (tl) - WriteISAC(isac, ISAC_ADF1, 0x8); - else - WriteISAC(isac, ISAC_ADF1, 0x0); - } - spin_unlock_irqrestore(isac->hwlock, flags); - break; - case HW_TIMER3_VALUE: - ret = l1_event(isac->dch.l1, HW_TIMER3_VALUE | (para & 0xff)); - break; - default: - pr_debug("%s: %s unknown command %x %lx\n", isac->name, - __func__, cmd, para); - ret = -1; - } - return ret; -} - -static int -isac_l1cmd(struct dchannel *dch, u32 cmd) -{ - struct isac_hw *isac = container_of(dch, struct isac_hw, dch); - u_long flags; - - pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state); - switch (cmd) { - case INFO3_P8: - spin_lock_irqsave(isac->hwlock, flags); - ph_command(isac, ISAC_CMD_AR8); - spin_unlock_irqrestore(isac->hwlock, flags); - break; - case INFO3_P10: - spin_lock_irqsave(isac->hwlock, flags); - ph_command(isac, ISAC_CMD_AR10); - spin_unlock_irqrestore(isac->hwlock, flags); - break; - case HW_RESET_REQ: - spin_lock_irqsave(isac->hwlock, flags); - if ((isac->state == ISAC_IND_EI) || - (isac->state == ISAC_IND_DR) || - (isac->state == ISAC_IND_DR6) || - (isac->state == ISAC_IND_RS)) - ph_command(isac, ISAC_CMD_TIM); - else - ph_command(isac, ISAC_CMD_RS); - spin_unlock_irqrestore(isac->hwlock, flags); - break; - case HW_DEACT_REQ: - skb_queue_purge(&dch->squeue); - if (dch->tx_skb) { - dev_kfree_skb(dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - dev_kfree_skb(dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) - timer_delete(&dch->timer); - break; - case HW_POWERUP_REQ: - spin_lock_irqsave(isac->hwlock, flags); - ph_command(isac, ISAC_CMD_TIM); - spin_unlock_irqrestore(isac->hwlock, flags); - break; - case PH_ACTIVATE_IND: - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - case PH_DEACTIVATE_IND: - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - default: - pr_debug("%s: %s unknown command %x\n", isac->name, - __func__, cmd); - return -1; - } - return 0; -} - -static void -isac_release(struct isac_hw *isac) -{ - if (isac->type & IPAC_TYPE_ISACX) - WriteISAC(isac, ISACX_MASK, 0xff); - else if (isac->type != 0) - WriteISAC(isac, ISAC_MASK, 0xff); - if (isac->dch.timer.function != NULL) { - timer_delete(&isac->dch.timer); - isac->dch.timer.function = NULL; - } - kfree(isac->mon_rx); - isac->mon_rx = NULL; - kfree(isac->mon_tx); - isac->mon_tx = NULL; - if (isac->dch.l1) - l1_event(isac->dch.l1, CLOSE_CHANNEL); - mISDN_freedchannel(&isac->dch); -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct isac_hw *isac = timer_container_of(isac, t, dch.timer); - int rbch, star; - u_long flags; - - if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { - spin_lock_irqsave(isac->hwlock, flags); - rbch = ReadISAC(isac, ISAC_RBCH); - star = ReadISAC(isac, ISAC_STAR); - pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", - isac->name, rbch, star); - if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */ - test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags); - else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags); - if (isac->dch.tx_idx) - isac->dch.tx_idx = 0; - else - pr_info("%s: ISAC D-Channel Busy no tx_idx\n", - isac->name); - /* Transmitter reset */ - WriteISAC(isac, ISAC_CMDR, 0x01); - } - spin_unlock_irqrestore(isac->hwlock, flags); - } -} - -static int -open_dchannel_caller(struct isac_hw *isac, struct channel_req *rq, void *caller) -{ - pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__, - isac->dch.dev.id, caller); - if (rq->protocol != ISDN_P_TE_S0) - return -EINVAL; - if (rq->adr.channel == 1) - /* E-Channel not supported */ - return -EINVAL; - rq->ch = &isac->dch.dev.D; - rq->ch->protocol = rq->protocol; - if (isac->dch.state == 7) - _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - return 0; -} - -static int -open_dchannel(struct isac_hw *isac, struct channel_req *rq) -{ - return open_dchannel_caller(isac, rq, __builtin_return_address(0)); -} - -static const char *ISACVer[] = -{"2086/2186 V1.1", "2085 B1", "2085 B2", - "2085 V2.3"}; - -static int -isac_init(struct isac_hw *isac) -{ - u8 val; - int err = 0; - - if (!isac->dch.l1) { - err = create_l1(&isac->dch, isac_l1cmd); - if (err) - return err; - } - isac->mon_tx = NULL; - isac->mon_rx = NULL; - timer_setup(&isac->dch.timer, dbusy_timer_handler, 0); - isac->mocr = 0xaa; - if (isac->type & IPAC_TYPE_ISACX) { - /* Disable all IRQ */ - WriteISAC(isac, ISACX_MASK, 0xff); - val = ReadISAC(isac, ISACX_STARD); - pr_debug("%s: ISACX STARD %x\n", isac->name, val); - val = ReadISAC(isac, ISACX_ISTAD); - pr_debug("%s: ISACX ISTAD %x\n", isac->name, val); - val = ReadISAC(isac, ISACX_ISTA); - pr_debug("%s: ISACX ISTA %x\n", isac->name, val); - /* clear LDD */ - WriteISAC(isac, ISACX_TR_CONF0, 0x00); - /* enable transmitter */ - WriteISAC(isac, ISACX_TR_CONF2, 0x00); - /* transparent mode 0, RAC, stop/go */ - WriteISAC(isac, ISACX_MODED, 0xc9); - /* all HDLC IRQ unmasked */ - val = ReadISAC(isac, ISACX_ID); - if (isac->dch.debug & DEBUG_HW) - pr_notice("%s: ISACX Design ID %x\n", - isac->name, val & 0x3f); - val = ReadISAC(isac, ISACX_CIR0); - pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); - isac->state = val >> 4; - isac_ph_state_change(isac); - ph_command(isac, ISAC_CMD_RS); - WriteISAC(isac, ISACX_MASK, IPACX__ON); - WriteISAC(isac, ISACX_MASKD, 0x00); - } else { /* old isac */ - WriteISAC(isac, ISAC_MASK, 0xff); - val = ReadISAC(isac, ISAC_STAR); - pr_debug("%s: ISAC STAR %x\n", isac->name, val); - val = ReadISAC(isac, ISAC_MODE); - pr_debug("%s: ISAC MODE %x\n", isac->name, val); - val = ReadISAC(isac, ISAC_ADF2); - pr_debug("%s: ISAC ADF2 %x\n", isac->name, val); - val = ReadISAC(isac, ISAC_ISTA); - pr_debug("%s: ISAC ISTA %x\n", isac->name, val); - if (val & 0x01) { - val = ReadISAC(isac, ISAC_EXIR); - pr_debug("%s: ISAC EXIR %x\n", isac->name, val); - } - val = ReadISAC(isac, ISAC_RBCH); - if (isac->dch.debug & DEBUG_HW) - pr_notice("%s: ISAC version (%x): %s\n", isac->name, - val, ISACVer[(val >> 5) & 3]); - isac->type |= ((val >> 5) & 3); - if (!isac->adf2) - isac->adf2 = 0x80; - if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */ - pr_info("%s: only support IOM2 mode but adf2=%02x\n", - isac->name, isac->adf2); - isac_release(isac); - return -EINVAL; - } - WriteISAC(isac, ISAC_ADF2, isac->adf2); - WriteISAC(isac, ISAC_SQXR, 0x2f); - WriteISAC(isac, ISAC_SPCR, 0x00); - WriteISAC(isac, ISAC_STCR, 0x70); - WriteISAC(isac, ISAC_MODE, 0xc9); - WriteISAC(isac, ISAC_TIMR, 0x00); - WriteISAC(isac, ISAC_ADF1, 0x00); - val = ReadISAC(isac, ISAC_CIR0); - pr_debug("%s: ISAC CIR0 %x\n", isac->name, val); - isac->state = (val >> 2) & 0xf; - isac_ph_state_change(isac); - ph_command(isac, ISAC_CMD_RS); - WriteISAC(isac, ISAC_MASK, 0); - } - return err; -} - -int -mISDNisac_init(struct isac_hw *isac, void *hw) -{ - mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh); - isac->dch.hw = hw; - isac->dch.dev.D.send = isac_l1hw; - isac->init = isac_init; - isac->release = isac_release; - isac->ctrl = isac_ctrl; - isac->open = open_dchannel; - isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); - isac->dch.dev.nrbchan = 2; - return 0; -} -EXPORT_SYMBOL(mISDNisac_init); - -static void -waitforCEC(struct hscx_hw *hx) -{ - u8 starb, to = 50; - - while (to) { - starb = ReadHSCX(hx, IPAC_STARB); - if (!(starb & 0x04)) - break; - udelay(1); - to--; - } - if (to < 50) - pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr, - 50 - to); - if (!to) - pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr); -} - - -static void -waitforXFW(struct hscx_hw *hx) -{ - u8 starb, to = 50; - - while (to) { - starb = ReadHSCX(hx, IPAC_STARB); - if ((starb & 0x44) == 0x40) - break; - udelay(1); - to--; - } - if (to < 50) - pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr, - 50 - to); - if (!to) - pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr); -} - -static void -hscx_cmdr(struct hscx_hw *hx, u8 cmd) -{ - if (hx->ip->type & IPAC_TYPE_IPACX) - WriteHSCX(hx, IPACX_CMDRB, cmd); - else { - waitforCEC(hx); - WriteHSCX(hx, IPAC_CMDRB, cmd); - } -} - -static void -hscx_empty_fifo(struct hscx_hw *hscx, u8 count) -{ - u8 *p; - int maxlen; - - pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); - if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) { - hscx->bch.dropcnt += count; - hscx_cmdr(hscx, 0x80); /* RMC */ - return; - } - maxlen = bchannel_get_rxbuf(&hscx->bch, count); - if (maxlen < 0) { - hscx_cmdr(hscx, 0x80); /* RMC */ - if (hscx->bch.rx_skb) - skb_trim(hscx->bch.rx_skb, 0); - pr_warn("%s.B%d: No bufferspace for %d bytes\n", - hscx->ip->name, hscx->bch.nr, count); - return; - } - p = skb_put(hscx->bch.rx_skb, count); - - if (hscx->ip->type & IPAC_TYPE_IPACX) - hscx->ip->read_fifo(hscx->ip->hw, - hscx->off + IPACX_RFIFOB, p, count); - else - hscx->ip->read_fifo(hscx->ip->hw, - hscx->off, p, count); - - hscx_cmdr(hscx, 0x80); /* RMC */ - - if (hscx->bch.debug & DEBUG_HW_BFIFO) { - snprintf(hscx->log, 64, "B%1d-recv %s %d ", - hscx->bch.nr, hscx->ip->name, count); - print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); - } -} - -static void -hscx_fill_fifo(struct hscx_hw *hscx) -{ - int count, more; - u8 *p; - - if (!hscx->bch.tx_skb) { - if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags)) - return; - count = hscx->fifo_size; - more = 1; - p = hscx->log; - memset(p, hscx->bch.fill[0], count); - } else { - count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; - if (count <= 0) - return; - p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; - - more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; - if (count > hscx->fifo_size) { - count = hscx->fifo_size; - more = 1; - } - pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, - count, hscx->bch.tx_idx, hscx->bch.tx_skb->len); - hscx->bch.tx_idx += count; - } - if (hscx->ip->type & IPAC_TYPE_IPACX) - hscx->ip->write_fifo(hscx->ip->hw, - hscx->off + IPACX_XFIFOB, p, count); - else { - waitforXFW(hscx); - hscx->ip->write_fifo(hscx->ip->hw, - hscx->off, p, count); - } - hscx_cmdr(hscx, more ? 0x08 : 0x0a); - - if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) { - snprintf(hscx->log, 64, "B%1d-send %s %d ", - hscx->bch.nr, hscx->ip->name, count); - print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); - } -} - -static void -hscx_xpr(struct hscx_hw *hx) -{ - if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) { - hscx_fill_fifo(hx); - } else { - dev_kfree_skb(hx->bch.tx_skb); - if (get_next_bframe(&hx->bch)) { - hscx_fill_fifo(hx); - test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags); - } else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) { - hscx_fill_fifo(hx); - } - } -} - -static void -ipac_rme(struct hscx_hw *hx) -{ - int count; - u8 rstab; - - if (hx->ip->type & IPAC_TYPE_IPACX) - rstab = ReadHSCX(hx, IPACX_RSTAB); - else - rstab = ReadHSCX(hx, IPAC_RSTAB); - pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab); - if ((rstab & 0xf0) != 0xa0) { - /* !(VFR && !RDO && CRC && !RAB) */ - if (!(rstab & 0x80)) { - if (hx->bch.debug & DEBUG_HW_BCHANNEL) - pr_notice("%s: B%1d invalid frame\n", - hx->ip->name, hx->bch.nr); - } - if (rstab & 0x40) { - if (hx->bch.debug & DEBUG_HW_BCHANNEL) - pr_notice("%s: B%1d RDO proto=%x\n", - hx->ip->name, hx->bch.nr, - hx->bch.state); - } - if (!(rstab & 0x20)) { - if (hx->bch.debug & DEBUG_HW_BCHANNEL) - pr_notice("%s: B%1d CRC error\n", - hx->ip->name, hx->bch.nr); - } - hscx_cmdr(hx, 0x80); /* Do RMC */ - return; - } - if (hx->ip->type & IPAC_TYPE_IPACX) - count = ReadHSCX(hx, IPACX_RBCLB); - else - count = ReadHSCX(hx, IPAC_RBCLB); - count &= (hx->fifo_size - 1); - if (count == 0) - count = hx->fifo_size; - hscx_empty_fifo(hx, count); - if (!hx->bch.rx_skb) - return; - if (hx->bch.rx_skb->len < 2) { - pr_debug("%s: B%1d frame too short %d\n", - hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len); - skb_trim(hx->bch.rx_skb, 0); - } else { - skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1); - recv_Bchannel(&hx->bch, 0, false); - } -} - -static void -ipac_irq(struct hscx_hw *hx, u8 ista) -{ - u8 istab, m, exirb = 0; - - if (hx->ip->type & IPAC_TYPE_IPACX) - istab = ReadHSCX(hx, IPACX_ISTAB); - else if (hx->ip->type & IPAC_TYPE_IPAC) { - istab = ReadHSCX(hx, IPAC_ISTAB); - m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB; - if (m & ista) { - exirb = ReadHSCX(hx, IPAC_EXIRB); - pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, - hx->bch.nr, exirb); - } - } else if (hx->bch.nr & 2) { /* HSCX B */ - if (ista & (HSCX__EXA | HSCX__ICA)) - ipac_irq(&hx->ip->hscx[0], ista); - if (ista & HSCX__EXB) { - exirb = ReadHSCX(hx, IPAC_EXIRB); - pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, - hx->bch.nr, exirb); - } - istab = ista & 0xF8; - } else { /* HSCX A */ - istab = ReadHSCX(hx, IPAC_ISTAB); - if (ista & HSCX__EXA) { - exirb = ReadHSCX(hx, IPAC_EXIRB); - pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, - hx->bch.nr, exirb); - } - istab = istab & 0xF8; - } - if (exirb & IPAC_B_XDU) - istab |= IPACX_B_XDU; - if (exirb & IPAC_B_RFO) - istab |= IPACX_B_RFO; - pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab); - - if (!test_bit(FLG_ACTIVE, &hx->bch.Flags)) - return; - - if (istab & IPACX_B_RME) - ipac_rme(hx); - - if (istab & IPACX_B_RPF) { - hscx_empty_fifo(hx, hx->fifo_size); - if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) - recv_Bchannel(&hx->bch, 0, false); - } - - if (istab & IPACX_B_RFO) { - pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr); - hscx_cmdr(hx, 0x40); /* RRES */ - } - - if (istab & IPACX_B_XPR) - hscx_xpr(hx); - - if (istab & IPACX_B_XDU) { - if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { - if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags)) - test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags); - hscx_xpr(hx); - return; - } - pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name, - hx->bch.nr, hx->bch.tx_idx); - hx->bch.tx_idx = 0; - hscx_cmdr(hx, 0x01); /* XRES */ - } -} - -irqreturn_t -mISDNipac_irq(struct ipac_hw *ipac, int maxloop) -{ - int cnt = maxloop + 1; - u8 ista, istad; - struct isac_hw *isac = &ipac->isac; - - if (ipac->type & IPAC_TYPE_IPACX) { - ista = ReadIPAC(ipac, ISACX_ISTA); - while (ista && --cnt) { - pr_debug("%s: ISTA %02x\n", ipac->name, ista); - if (ista & IPACX__ICA) - ipac_irq(&ipac->hscx[0], ista); - if (ista & IPACX__ICB) - ipac_irq(&ipac->hscx[1], ista); - if (ista & (ISACX__ICD | ISACX__CIC)) - mISDNisac_irq(&ipac->isac, ista); - ista = ReadIPAC(ipac, ISACX_ISTA); - } - } else if (ipac->type & IPAC_TYPE_IPAC) { - ista = ReadIPAC(ipac, IPAC_ISTA); - while (ista && --cnt) { - pr_debug("%s: ISTA %02x\n", ipac->name, ista); - if (ista & (IPAC__ICD | IPAC__EXD)) { - istad = ReadISAC(isac, ISAC_ISTA); - pr_debug("%s: ISTAD %02x\n", ipac->name, istad); - if (istad & IPAC_D_TIN2) - pr_debug("%s TIN2 irq\n", ipac->name); - if (ista & IPAC__EXD) - istad |= 1; /* ISAC EXI */ - mISDNisac_irq(isac, istad); - } - if (ista & (IPAC__ICA | IPAC__EXA)) - ipac_irq(&ipac->hscx[0], ista); - if (ista & (IPAC__ICB | IPAC__EXB)) - ipac_irq(&ipac->hscx[1], ista); - ista = ReadIPAC(ipac, IPAC_ISTA); - } - } else if (ipac->type & IPAC_TYPE_HSCX) { - while (--cnt) { - ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off); - pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista); - if (ista) - ipac_irq(&ipac->hscx[1], ista); - istad = ReadISAC(isac, ISAC_ISTA); - pr_debug("%s: ISTAD %02x\n", ipac->name, istad); - if (istad) - mISDNisac_irq(isac, istad); - if (0 == (ista | istad)) - break; - } - } - if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */ - return IRQ_NONE; - if (cnt < maxloop) - pr_debug("%s: %d irqloops cpu%d\n", ipac->name, - maxloop - cnt, smp_processor_id()); - if (maxloop && !cnt) - pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name, - maxloop, smp_processor_id()); - return IRQ_HANDLED; -} -EXPORT_SYMBOL(mISDNipac_irq); - -static int -hscx_mode(struct hscx_hw *hscx, u32 bprotocol) -{ - pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name, - '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr); - if (hscx->ip->type & IPAC_TYPE_IPACX) { - if (hscx->bch.nr & 1) { /* B1 and ICA */ - WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80); - WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88); - } else { /* B2 and ICB */ - WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81); - WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88); - } - switch (bprotocol) { - case ISDN_P_NONE: /* init */ - WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */ - WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */ - WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */ - hscx_cmdr(hscx, 0x41); - test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); - test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); - break; - case ISDN_P_B_RAW: - WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */ - WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */ - hscx_cmdr(hscx, 0x41); - WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); - test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); - break; - case ISDN_P_B_HDLC: - WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */ - WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */ - hscx_cmdr(hscx, 0x41); - WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); - test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); - break; - default: - pr_info("%s: protocol not known %x\n", hscx->ip->name, - bprotocol); - return -ENOPROTOOPT; - } - } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */ - WriteHSCX(hscx, IPAC_CCR1, 0x82); - WriteHSCX(hscx, IPAC_CCR2, 0x30); - WriteHSCX(hscx, IPAC_XCCR, 0x07); - WriteHSCX(hscx, IPAC_RCCR, 0x07); - WriteHSCX(hscx, IPAC_TSAX, hscx->slot); - WriteHSCX(hscx, IPAC_TSAR, hscx->slot); - switch (bprotocol) { - case ISDN_P_NONE: - WriteHSCX(hscx, IPAC_TSAX, 0x1F); - WriteHSCX(hscx, IPAC_TSAR, 0x1F); - WriteHSCX(hscx, IPAC_MODEB, 0x84); - WriteHSCX(hscx, IPAC_CCR1, 0x82); - WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ - test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); - test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); - break; - case ISDN_P_B_RAW: - WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ - WriteHSCX(hscx, IPAC_CCR1, 0x82); - hscx_cmdr(hscx, 0x41); - WriteHSCX(hscx, IPAC_MASKB, 0); - test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); - break; - case ISDN_P_B_HDLC: - WriteHSCX(hscx, IPAC_MODEB, 0x8c); - WriteHSCX(hscx, IPAC_CCR1, 0x8a); - hscx_cmdr(hscx, 0x41); - WriteHSCX(hscx, IPAC_MASKB, 0); - test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); - break; - default: - pr_info("%s: protocol not known %x\n", hscx->ip->name, - bprotocol); - return -ENOPROTOOPT; - } - } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */ - WriteHSCX(hscx, IPAC_CCR1, 0x85); - WriteHSCX(hscx, IPAC_CCR2, 0x30); - WriteHSCX(hscx, IPAC_XCCR, 0x07); - WriteHSCX(hscx, IPAC_RCCR, 0x07); - WriteHSCX(hscx, IPAC_TSAX, hscx->slot); - WriteHSCX(hscx, IPAC_TSAR, hscx->slot); - switch (bprotocol) { - case ISDN_P_NONE: - WriteHSCX(hscx, IPAC_TSAX, 0x1F); - WriteHSCX(hscx, IPAC_TSAR, 0x1F); - WriteHSCX(hscx, IPAC_MODEB, 0x84); - WriteHSCX(hscx, IPAC_CCR1, 0x85); - WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ - test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); - test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); - break; - case ISDN_P_B_RAW: - WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ - WriteHSCX(hscx, IPAC_CCR1, 0x85); - hscx_cmdr(hscx, 0x41); - WriteHSCX(hscx, IPAC_MASKB, 0); - test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); - break; - case ISDN_P_B_HDLC: - WriteHSCX(hscx, IPAC_MODEB, 0x8c); - WriteHSCX(hscx, IPAC_CCR1, 0x8d); - hscx_cmdr(hscx, 0x41); - WriteHSCX(hscx, IPAC_MASKB, 0); - test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); - break; - default: - pr_info("%s: protocol not known %x\n", hscx->ip->name, - bprotocol); - return -ENOPROTOOPT; - } - } else - return -EINVAL; - hscx->bch.state = bprotocol; - return 0; -} - -static int -hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(hx->ip->hwlock, flags); - ret = bchannel_senddata(bch, skb); - if (ret > 0) { /* direct TX */ - ret = 0; - hscx_fill_fifo(hx); - } - spin_unlock_irqrestore(hx->ip->hwlock, flags); - return ret; - case PH_ACTIVATE_REQ: - spin_lock_irqsave(hx->ip->hwlock, flags); - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) - ret = hscx_mode(hx, ch->protocol); - else - ret = 0; - spin_unlock_irqrestore(hx->ip->hwlock, flags); - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - break; - case PH_DEACTIVATE_REQ: - spin_lock_irqsave(hx->ip->hwlock, flags); - mISDN_clear_bchannel(bch); - hscx_mode(hx, ISDN_P_NONE); - spin_unlock_irqrestore(hx->ip->hwlock, flags); - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - ret = 0; - break; - default: - pr_info("%s: %s unknown prim(%x,%x)\n", - hx->ip->name, __func__, hh->prim, hh->id); - ret = -EINVAL; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - return mISDN_ctrl_bchannel(bch, cq); -} - -static int -hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); - int ret = -EINVAL; - u_long flags; - - pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - cancel_work_sync(&bch->workq); - spin_lock_irqsave(hx->ip->hwlock, flags); - mISDN_clear_bchannel(bch); - hscx_mode(hx, ISDN_P_NONE); - spin_unlock_irqrestore(hx->ip->hwlock, flags); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(hx->ip->owner); - ret = 0; - break; - case CONTROL_CHANNEL: - ret = channel_bctrl(bch, arg); - break; - default: - pr_info("%s: %s unknown prim(%x)\n", - hx->ip->name, __func__, cmd); - } - return ret; -} - -static void -free_ipac(struct ipac_hw *ipac) -{ - isac_release(&ipac->isac); -} - -static const char *HSCXVer[] = -{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", - "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; - - - -static void -hscx_init(struct hscx_hw *hx) -{ - u8 val; - - WriteHSCX(hx, IPAC_RAH2, 0xFF); - WriteHSCX(hx, IPAC_XBCH, 0x00); - WriteHSCX(hx, IPAC_RLCR, 0x00); - - if (hx->ip->type & IPAC_TYPE_HSCX) { - WriteHSCX(hx, IPAC_CCR1, 0x85); - val = ReadHSCX(hx, HSCX_VSTR); - pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val); - if (hx->bch.debug & DEBUG_HW) - pr_notice("%s: HSCX version %s\n", hx->ip->name, - HSCXVer[val & 0x0f]); - } else - WriteHSCX(hx, IPAC_CCR1, 0x82); - WriteHSCX(hx, IPAC_CCR2, 0x30); - WriteHSCX(hx, IPAC_XCCR, 0x07); - WriteHSCX(hx, IPAC_RCCR, 0x07); -} - -static int -ipac_init(struct ipac_hw *ipac) -{ - u8 val; - - if (ipac->type & IPAC_TYPE_HSCX) { - hscx_init(&ipac->hscx[0]); - hscx_init(&ipac->hscx[1]); - val = ReadIPAC(ipac, IPAC_ID); - } else if (ipac->type & IPAC_TYPE_IPAC) { - hscx_init(&ipac->hscx[0]); - hscx_init(&ipac->hscx[1]); - WriteIPAC(ipac, IPAC_MASK, IPAC__ON); - val = ReadIPAC(ipac, IPAC_CONF); - /* conf is default 0, but can be overwritten by card setup */ - pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name, - val, ipac->conf); - WriteIPAC(ipac, IPAC_CONF, ipac->conf); - val = ReadIPAC(ipac, IPAC_ID); - if (ipac->hscx[0].bch.debug & DEBUG_HW) - pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val); - } - /* nothing special for IPACX to do here */ - return isac_init(&ipac->isac); -} - -static int -open_bchannel(struct ipac_hw *ipac, struct channel_req *rq) -{ - struct bchannel *bch; - - if (rq->adr.channel == 0 || rq->adr.channel > 2) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - bch = &ipac->hscx[rq->adr.channel - 1].bch; - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; - return 0; -} - -static int -channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; - break; - case MISDN_CTRL_LOOP: - /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ - if (cq->channel < 0 || cq->channel > 3) { - ret = -EINVAL; - break; - } - ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel); - break; - case MISDN_CTRL_L1_TIMER3: - ret = ipac->isac.ctrl(&ipac->isac, HW_TIMER3_VALUE, cq->p1); - break; - default: - pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct isac_hw *isac = container_of(dch, struct isac_hw, dch); - struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac); - struct channel_req *rq; - int err = 0; - - pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - if (rq->protocol == ISDN_P_TE_S0) - err = open_dchannel_caller(isac, rq, __builtin_return_address(0)); - else - err = open_bchannel(ipac, rq); - if (err) - break; - if (!try_module_get(ipac->owner)) - pr_info("%s: cannot get module\n", ipac->name); - break; - case CLOSE_CHANNEL: - pr_debug("%s: dev(%d) close from %p\n", ipac->name, - dch->dev.id, __builtin_return_address(0)); - module_put(ipac->owner); - break; - case CONTROL_CHANNEL: - err = channel_ctrl(ipac, arg); - break; - default: - pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd); - return -EINVAL; - } - return err; -} - -u32 -mISDNipac_init(struct ipac_hw *ipac, void *hw) -{ - u32 ret; - u8 i; - - ipac->hw = hw; - if (ipac->isac.dch.debug & DEBUG_HW) - pr_notice("%s: ipac type %x\n", ipac->name, ipac->type); - if (ipac->type & IPAC_TYPE_HSCX) { - ipac->isac.type = IPAC_TYPE_ISAC; - ipac->hscx[0].off = 0; - ipac->hscx[1].off = 0x40; - ipac->hscx[0].fifo_size = 32; - ipac->hscx[1].fifo_size = 32; - } else if (ipac->type & IPAC_TYPE_IPAC) { - ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC; - ipac->hscx[0].off = 0; - ipac->hscx[1].off = 0x40; - ipac->hscx[0].fifo_size = 64; - ipac->hscx[1].fifo_size = 64; - } else if (ipac->type & IPAC_TYPE_IPACX) { - ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX; - ipac->hscx[0].off = IPACX_OFF_ICA; - ipac->hscx[1].off = IPACX_OFF_ICB; - ipac->hscx[0].fifo_size = 64; - ipac->hscx[1].fifo_size = 64; - } else - return 0; - - mISDNisac_init(&ipac->isac, hw); - - ipac->isac.dch.dev.D.ctrl = ipac_dctrl; - - for (i = 0; i < 2; i++) { - ipac->hscx[i].bch.nr = i + 1; - set_channelmap(i + 1, ipac->isac.dch.dev.channelmap); - list_add(&ipac->hscx[i].bch.ch.list, - &ipac->isac.dch.dev.bchannels); - mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM, - ipac->hscx[i].fifo_size); - ipac->hscx[i].bch.ch.nr = i + 1; - ipac->hscx[i].bch.ch.send = &hscx_l2l1; - ipac->hscx[i].bch.ch.ctrl = hscx_bctrl; - ipac->hscx[i].bch.hw = hw; - ipac->hscx[i].ip = ipac; - /* default values for IOM time slots - * can be overwritten by card */ - ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03; - } - - ipac->init = ipac_init; - ipac->release = free_ipac; - - ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - return ret; -} -EXPORT_SYMBOL(mISDNipac_init); - -static int __init -isac_mod_init(void) -{ - pr_notice("mISDNipac module version %s\n", ISAC_REV); - return 0; -} - -static void __exit -isac_mod_cleanup(void) -{ - pr_notice("mISDNipac module unloaded\n"); -} -module_init(isac_mod_init); -module_exit(isac_mod_cleanup); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c deleted file mode 100644 index dace91ba412b..000000000000 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ /dev/null @@ -1,1694 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * mISDNisar.c ISAR (Siemens PSB 7110) specific functions - * - * Author Karsten Keil (keil@isdn4linux.de) - * - * Copyright 2009 by Karsten Keil - */ - -/* define this to enable static debug messages, if you kernel supports - * dynamic debugging, you should use debugfs for this - */ -/* #define DEBUG */ - -#include -#include -#include -#include -#include -#include "isar.h" - -#define ISAR_REV "2.1" - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("mISDN driver for ISAR (Siemens PSB 7110) specific functions"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(ISAR_REV); - -#define DEBUG_HW_FIRMWARE_FIFO 0x10000 - -static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, - 122, 145, 146}; -#define FAXMODCNT 13 - -static void isar_setup(struct isar_hw *); - -static inline int -waitforHIA(struct isar_hw *isar, int timeout) -{ - int t = timeout; - u8 val = isar->read_reg(isar->hw, ISAR_HIA); - - while ((val & 1) && t) { - udelay(1); - t--; - val = isar->read_reg(isar->hw, ISAR_HIA); - } - pr_debug("%s: HIA after %dus\n", isar->name, timeout - t); - return timeout; -} - -/* - * send msg to ISAR mailbox - * if msg is NULL use isar->buf - */ -static int -send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg) -{ - if (!waitforHIA(isar, 1000)) - return 0; - pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len); - isar->write_reg(isar->hw, ISAR_CTRL_H, creg); - isar->write_reg(isar->hw, ISAR_CTRL_L, len); - isar->write_reg(isar->hw, ISAR_WADR, 0); - if (!msg) - msg = isar->buf; - if (msg && len) { - isar->write_fifo(isar->hw, ISAR_MBOX, msg, len); - if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { - int l = 0; - - while (l < (int)len) { - hex_dump_to_buffer(msg + l, len - l, 32, 1, - isar->log, 256, 1); - pr_debug("%s: %s %02x: %s\n", isar->name, - __func__, l, isar->log); - l += 32; - } - } - } - isar->write_reg(isar->hw, ISAR_HIS, his); - waitforHIA(isar, 1000); - return 1; -} - -/* - * receive message from ISAR mailbox - * if msg is NULL use isar->buf - */ -static void -rcv_mbox(struct isar_hw *isar, u8 *msg) -{ - if (!msg) - msg = isar->buf; - isar->write_reg(isar->hw, ISAR_RADR, 0); - if (msg && isar->clsb) { - isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb); - if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { - int l = 0; - - while (l < (int)isar->clsb) { - hex_dump_to_buffer(msg + l, isar->clsb - l, 32, - 1, isar->log, 256, 1); - pr_debug("%s: %s %02x: %s\n", isar->name, - __func__, l, isar->log); - l += 32; - } - } - } - isar->write_reg(isar->hw, ISAR_IIA, 0); -} - -static inline void -get_irq_infos(struct isar_hw *isar) -{ - isar->iis = isar->read_reg(isar->hw, ISAR_IIS); - isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H); - isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L); - pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name, - isar->iis, isar->cmsb, isar->clsb); -} - -/* - * poll answer message from ISAR mailbox - * should be used only with ISAR IRQs disabled before DSP was started - * - */ -static int -poll_mbox(struct isar_hw *isar, int maxdelay) -{ - int t = maxdelay; - u8 irq; - - irq = isar->read_reg(isar->hw, ISAR_IRQBIT); - while (t && !(irq & ISAR_IRQSTA)) { - udelay(1); - t--; - } - if (t) { - get_irq_infos(isar); - rcv_mbox(isar, NULL); - } - pr_debug("%s: pulled %d bytes after %d us\n", - isar->name, isar->clsb, maxdelay - t); - return t; -} - -static int -ISARVersion(struct isar_hw *isar) -{ - int ver; - - /* disable ISAR IRQ */ - isar->write_reg(isar->hw, ISAR_IRQBIT, 0); - isar->buf[0] = ISAR_MSG_HWVER; - isar->buf[1] = 0; - isar->buf[2] = 1; - if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL)) - return -1; - if (!poll_mbox(isar, 1000)) - return -2; - if (isar->iis == ISAR_IIS_VNR) { - if (isar->clsb == 1) { - ver = isar->buf[0] & 0xf; - return ver; - } - return -3; - } - return -4; -} - -static int -load_firmware(struct isar_hw *isar, const u8 *buf, int size) -{ - u32 saved_debug = isar->ch[0].bch.debug; - int ret, cnt; - u8 nom, noc; - u16 left, val, *sp = (u16 *)buf; - u8 *mp; - u_long flags; - - struct { - u16 sadr; - u16 len; - u16 d_key; - } blk_head; - - if (1 != isar->version) { - pr_err("%s: ISAR wrong version %d firmware download aborted\n", - isar->name, isar->version); - return -EINVAL; - } - if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO)) - isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO; - pr_debug("%s: load firmware %d words (%d bytes)\n", - isar->name, size / 2, size); - cnt = 0; - size /= 2; - /* disable ISAR IRQ */ - spin_lock_irqsave(isar->hwlock, flags); - isar->write_reg(isar->hw, ISAR_IRQBIT, 0); - spin_unlock_irqrestore(isar->hwlock, flags); - while (cnt < size) { - blk_head.sadr = le16_to_cpu(*sp++); - blk_head.len = le16_to_cpu(*sp++); - blk_head.d_key = le16_to_cpu(*sp++); - cnt += 3; - pr_debug("ISAR firmware block (%#x,%d,%#x)\n", - blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); - left = blk_head.len; - if (cnt + left > size) { - pr_info("%s: firmware error have %d need %d words\n", - isar->name, size, cnt + left); - ret = -EINVAL; - goto reterrflg; - } - spin_lock_irqsave(isar->hwlock, flags); - if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff, - 0, NULL)) { - pr_info("ISAR send_mbox dkey failed\n"); - ret = -ETIME; - goto reterror; - } - if (!poll_mbox(isar, 1000)) { - pr_warn("ISAR poll_mbox dkey failed\n"); - ret = -ETIME; - goto reterror; - } - spin_unlock_irqrestore(isar->hwlock, flags); - if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) { - pr_info("ISAR wrong dkey response (%x,%x,%x)\n", - isar->iis, isar->cmsb, isar->clsb); - ret = 1; - goto reterrflg; - } - while (left > 0) { - if (left > 126) - noc = 126; - else - noc = left; - nom = (2 * noc) + 3; - mp = isar->buf; - /* the ISAR is big endian */ - *mp++ = blk_head.sadr >> 8; - *mp++ = blk_head.sadr & 0xFF; - left -= noc; - cnt += noc; - *mp++ = noc; - pr_debug("%s: load %3d words at %04x\n", isar->name, - noc, blk_head.sadr); - blk_head.sadr += noc; - while (noc) { - val = le16_to_cpu(*sp++); - *mp++ = val >> 8; - *mp++ = val & 0xFF; - noc--; - } - spin_lock_irqsave(isar->hwlock, flags); - if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) { - pr_info("ISAR send_mbox prog failed\n"); - ret = -ETIME; - goto reterror; - } - if (!poll_mbox(isar, 1000)) { - pr_info("ISAR poll_mbox prog failed\n"); - ret = -ETIME; - goto reterror; - } - spin_unlock_irqrestore(isar->hwlock, flags); - if ((isar->iis != ISAR_IIS_FIRM) || - isar->cmsb || isar->clsb) { - pr_info("ISAR wrong prog response (%x,%x,%x)\n", - isar->iis, isar->cmsb, isar->clsb); - ret = -EIO; - goto reterrflg; - } - } - pr_debug("%s: ISAR firmware block %d words loaded\n", - isar->name, blk_head.len); - } - isar->ch[0].bch.debug = saved_debug; - /* 10ms delay */ - cnt = 10; - while (cnt--) - mdelay(1); - isar->buf[0] = 0xff; - isar->buf[1] = 0xfe; - isar->bstat = 0; - spin_lock_irqsave(isar->hwlock, flags); - if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) { - pr_info("ISAR send_mbox start dsp failed\n"); - ret = -ETIME; - goto reterror; - } - if (!poll_mbox(isar, 1000)) { - pr_info("ISAR poll_mbox start dsp failed\n"); - ret = -ETIME; - goto reterror; - } - if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) { - pr_info("ISAR wrong start dsp response (%x,%x,%x)\n", - isar->iis, isar->cmsb, isar->clsb); - ret = -EIO; - goto reterror; - } else - pr_debug("%s: ISAR start dsp success\n", isar->name); - - /* NORMAL mode entered */ - /* Enable IRQs of ISAR */ - isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA); - spin_unlock_irqrestore(isar->hwlock, flags); - cnt = 1000; /* max 1s */ - while ((!isar->bstat) && cnt) { - mdelay(1); - cnt--; - } - if (!cnt) { - pr_info("ISAR no general status event received\n"); - ret = -ETIME; - goto reterrflg; - } else - pr_debug("%s: ISAR general status event %x\n", - isar->name, isar->bstat); - /* 10ms delay */ - cnt = 10; - while (cnt--) - mdelay(1); - isar->iis = 0; - spin_lock_irqsave(isar->hwlock, flags); - if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { - pr_info("ISAR send_mbox self tst failed\n"); - ret = -ETIME; - goto reterror; - } - spin_unlock_irqrestore(isar->hwlock, flags); - cnt = 10000; /* max 100 ms */ - while ((isar->iis != ISAR_IIS_DIAG) && cnt) { - udelay(10); - cnt--; - } - mdelay(1); - if (!cnt) { - pr_info("ISAR no self tst response\n"); - ret = -ETIME; - goto reterrflg; - } - if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1) - && (isar->buf[0] == 0)) - pr_debug("%s: ISAR selftest OK\n", isar->name); - else { - pr_info("ISAR selftest not OK %x/%x/%x\n", - isar->cmsb, isar->clsb, isar->buf[0]); - ret = -EIO; - goto reterrflg; - } - spin_lock_irqsave(isar->hwlock, flags); - isar->iis = 0; - if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { - pr_info("ISAR RQST SVN failed\n"); - ret = -ETIME; - goto reterror; - } - spin_unlock_irqrestore(isar->hwlock, flags); - cnt = 30000; /* max 300 ms */ - while ((isar->iis != ISAR_IIS_DIAG) && cnt) { - udelay(10); - cnt--; - } - mdelay(1); - if (!cnt) { - pr_info("ISAR no SVN response\n"); - ret = -ETIME; - goto reterrflg; - } else { - if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) { - pr_notice("%s: ISAR software version %#x\n", - isar->name, isar->buf[0]); - } else { - pr_info("%s: ISAR wrong swver response (%x,%x)" - " cnt(%d)\n", isar->name, isar->cmsb, - isar->clsb, cnt); - ret = -EIO; - goto reterrflg; - } - } - spin_lock_irqsave(isar->hwlock, flags); - isar_setup(isar); - spin_unlock_irqrestore(isar->hwlock, flags); - ret = 0; -reterrflg: - spin_lock_irqsave(isar->hwlock, flags); -reterror: - isar->ch[0].bch.debug = saved_debug; - if (ret) - /* disable ISAR IRQ */ - isar->write_reg(isar->hw, ISAR_IRQBIT, 0); - spin_unlock_irqrestore(isar->hwlock, flags); - return ret; -} - -static inline void -deliver_status(struct isar_ch *ch, int status) -{ - pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status); - _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC); -} - -static inline void -isar_rcv_frame(struct isar_ch *ch) -{ - u8 *ptr; - int maxlen; - - if (!ch->is->clsb) { - pr_debug("%s; ISAR zero len frame\n", ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - return; - } - if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) { - ch->bch.dropcnt += ch->is->clsb; - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - return; - } - switch (ch->bch.state) { - case ISDN_P_NONE: - pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", - ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - case ISDN_P_B_RAW: - case ISDN_P_B_L2DTMF: - case ISDN_P_B_MODEM_ASYNC: - maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); - if (maxlen < 0) { - pr_warn("%s.B%d: No bufferspace for %d bytes\n", - ch->is->name, ch->bch.nr, ch->is->clsb); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } - rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); - recv_Bchannel(&ch->bch, 0, false); - break; - case ISDN_P_B_HDLC: - maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); - if (maxlen < 0) { - pr_warn("%s.B%d: No bufferspace for %d bytes\n", - ch->is->name, ch->bch.nr, ch->is->clsb); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } - if (ch->is->cmsb & HDLC_ERROR) { - pr_debug("%s: ISAR frame error %x len %d\n", - ch->is->name, ch->is->cmsb, ch->is->clsb); -#ifdef ERROR_STATISTIC - if (ch->is->cmsb & HDLC_ERR_RER) - ch->bch.err_inv++; - if (ch->is->cmsb & HDLC_ERR_CER) - ch->bch.err_crc++; -#endif - skb_trim(ch->bch.rx_skb, 0); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } - if (ch->is->cmsb & HDLC_FSD) - skb_trim(ch->bch.rx_skb, 0); - ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); - rcv_mbox(ch->is, ptr); - if (ch->is->cmsb & HDLC_FED) { - if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ - pr_debug("%s: ISAR frame too short %d\n", - ch->is->name, ch->bch.rx_skb->len); - skb_trim(ch->bch.rx_skb, 0); - break; - } - skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); - recv_Bchannel(&ch->bch, 0, false); - } - break; - case ISDN_P_B_T30_FAX: - if (ch->state != STFAX_ACTIV) { - pr_debug("%s: isar_rcv_frame: not ACTIV\n", - ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - if (ch->bch.rx_skb) - skb_trim(ch->bch.rx_skb, 0); - break; - } - if (!ch->bch.rx_skb) { - ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, - GFP_ATOMIC); - if (unlikely(!ch->bch.rx_skb)) { - pr_info("%s: B receive out of memory\n", - __func__); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } - } - if (ch->cmd == PCTRL_CMD_FRM) { - rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); - pr_debug("%s: isar_rcv_frame: %d\n", - ch->is->name, ch->bch.rx_skb->len); - if (ch->is->cmsb & SART_NMD) { /* ABORT */ - pr_debug("%s: isar_rcv_frame: no more data\n", - ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - send_mbox(ch->is, SET_DPS(ch->dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, - 0, NULL); - ch->state = STFAX_ESCAPE; - /* set_skb_flag(skb, DF_NOMOREDATA); */ - } - recv_Bchannel(&ch->bch, 0, false); - if (ch->is->cmsb & SART_NMD) - deliver_status(ch, HW_MOD_NOCARR); - break; - } - if (ch->cmd != PCTRL_CMD_FRH) { - pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", - ch->is->name, ch->cmd); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - if (ch->bch.rx_skb) - skb_trim(ch->bch.rx_skb, 0); - break; - } - /* PCTRL_CMD_FRH */ - if ((ch->bch.rx_skb->len + ch->is->clsb) > - (ch->bch.maxlen + 2)) { - pr_info("%s: %s incoming packet too large\n", - ch->is->name, __func__); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - skb_trim(ch->bch.rx_skb, 0); - break; - } else if (ch->is->cmsb & HDLC_ERROR) { - pr_info("%s: ISAR frame error %x len %d\n", - ch->is->name, ch->is->cmsb, ch->is->clsb); - skb_trim(ch->bch.rx_skb, 0); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } - if (ch->is->cmsb & HDLC_FSD) - skb_trim(ch->bch.rx_skb, 0); - ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); - rcv_mbox(ch->is, ptr); - if (ch->is->cmsb & HDLC_FED) { - if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ - pr_info("%s: ISAR frame too short %d\n", - ch->is->name, ch->bch.rx_skb->len); - skb_trim(ch->bch.rx_skb, 0); - break; - } - skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); - recv_Bchannel(&ch->bch, 0, false); - } - if (ch->is->cmsb & SART_NMD) { /* ABORT */ - pr_debug("%s: isar_rcv_frame: no more data\n", - ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - if (ch->bch.rx_skb) - skb_trim(ch->bch.rx_skb, 0); - send_mbox(ch->is, SET_DPS(ch->dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); - ch->state = STFAX_ESCAPE; - deliver_status(ch, HW_MOD_NOCARR); - } - break; - default: - pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } -} - -static void -isar_fill_fifo(struct isar_ch *ch) -{ - int count; - u8 msb; - u8 *ptr; - - pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr, - ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx); - if (!(ch->is->bstat & - (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) - return; - if (!ch->bch.tx_skb) { - if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) || - (ch->bch.state != ISDN_P_B_RAW)) - return; - count = ch->mml; - /* use the card buffer */ - memset(ch->is->buf, ch->bch.fill[0], count); - send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, - 0, count, ch->is->buf); - return; - } - count = ch->bch.tx_skb->len - ch->bch.tx_idx; - if (count <= 0) - return; - if (count > ch->mml) { - msb = 0; - count = ch->mml; - } else { - msb = HDLC_FED; - } - ptr = ch->bch.tx_skb->data + ch->bch.tx_idx; - if (!ch->bch.tx_idx) { - pr_debug("%s: frame start\n", ch->is->name); - if ((ch->bch.state == ISDN_P_B_T30_FAX) && - (ch->cmd == PCTRL_CMD_FTH)) { - if (count > 1) { - if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) { - /* last frame */ - test_and_set_bit(FLG_LASTDATA, - &ch->bch.Flags); - pr_debug("%s: set LASTDATA\n", - ch->is->name); - if (msb == HDLC_FED) - test_and_set_bit(FLG_DLEETX, - &ch->bch.Flags); - } - } - } - msb |= HDLC_FST; - } - ch->bch.tx_idx += count; - switch (ch->bch.state) { - case ISDN_P_NONE: - pr_info("%s: wrong protocol 0\n", __func__); - break; - case ISDN_P_B_RAW: - case ISDN_P_B_L2DTMF: - case ISDN_P_B_MODEM_ASYNC: - send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, - 0, count, ptr); - break; - case ISDN_P_B_HDLC: - send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, - msb, count, ptr); - break; - case ISDN_P_B_T30_FAX: - if (ch->state != STFAX_ACTIV) - pr_debug("%s: not ACTIV\n", ch->is->name); - else if (ch->cmd == PCTRL_CMD_FTH) - send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, - msb, count, ptr); - else if (ch->cmd == PCTRL_CMD_FTM) - send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, - 0, count, ptr); - else - pr_debug("%s: not FTH/FTM\n", ch->is->name); - break; - default: - pr_info("%s: protocol(%x) error\n", - __func__, ch->bch.state); - break; - } -} - -static inline struct isar_ch * -sel_bch_isar(struct isar_hw *isar, u8 dpath) -{ - struct isar_ch *base = &isar->ch[0]; - - if ((!dpath) || (dpath > 2)) - return NULL; - if (base->dpath == dpath) - return base; - base++; - if (base->dpath == dpath) - return base; - return NULL; -} - -static void -send_next(struct isar_ch *ch) -{ - pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__, - ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, - ch->bch.tx_idx); - if (ch->bch.state == ISDN_P_B_T30_FAX) { - if (ch->cmd == PCTRL_CMD_FTH) { - if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { - pr_debug("set NMD_DATA\n"); - test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); - } - } else if (ch->cmd == PCTRL_CMD_FTM) { - if (test_bit(FLG_DLEETX, &ch->bch.Flags)) { - test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags); - test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); - } - } - } - dev_kfree_skb(ch->bch.tx_skb); - if (get_next_bframe(&ch->bch)) { - isar_fill_fifo(ch); - test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags); - } else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) { - isar_fill_fifo(ch); - } else { - if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { - if (test_and_clear_bit(FLG_LASTDATA, - &ch->bch.Flags)) { - if (test_and_clear_bit(FLG_NMD_DATA, - &ch->bch.Flags)) { - u8 zd = 0; - send_mbox(ch->is, SET_DPS(ch->dpath) | - ISAR_HIS_SDATA, 0x01, 1, &zd); - } - test_and_set_bit(FLG_LL_OK, &ch->bch.Flags); - } else { - deliver_status(ch, HW_MOD_CONNECT); - } - } else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) { - test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags); - } - } -} - -static void -check_send(struct isar_hw *isar, u8 rdm) -{ - struct isar_ch *ch; - - pr_debug("%s: rdm %x\n", isar->name, rdm); - if (rdm & BSTAT_RDM1) { - ch = sel_bch_isar(isar, 1); - if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { - if (ch->bch.tx_skb && (ch->bch.tx_skb->len > - ch->bch.tx_idx)) - isar_fill_fifo(ch); - else - send_next(ch); - } - } - if (rdm & BSTAT_RDM2) { - ch = sel_bch_isar(isar, 2); - if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { - if (ch->bch.tx_skb && (ch->bch.tx_skb->len > - ch->bch.tx_idx)) - isar_fill_fifo(ch); - else - send_next(ch); - } - } -} - -static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", - "300", "600", "1200", "2400", "4800", "7200", - "9600nt", "9600t", "12000", "14400", "WRONG"}; -static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", - "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; - -static void -isar_pump_status_rsp(struct isar_ch *ch) { - u8 ril = ch->is->buf[0]; - u8 rim; - - if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags)) - return; - if (ril > 14) { - pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril); - ril = 15; - } - switch (ch->is->buf[1]) { - case 0: - rim = 0; - break; - case 0x20: - rim = 2; - break; - case 0x40: - rim = 3; - break; - case 0x41: - rim = 4; - break; - case 0x51: - rim = 5; - break; - case 0x61: - rim = 6; - break; - case 0x71: - rim = 7; - break; - case 0x82: - rim = 8; - break; - case 0x92: - rim = 9; - break; - case 0xa2: - rim = 10; - break; - default: - rim = 1; - break; - } - sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]); - pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg); -} - -static void -isar_pump_statev_modem(struct isar_ch *ch, u8 devt) { - u8 dps = SET_DPS(ch->dpath); - - switch (devt) { - case PSEV_10MS_TIMER: - pr_debug("%s: pump stev TIMER\n", ch->is->name); - break; - case PSEV_CON_ON: - pr_debug("%s: pump stev CONNECT\n", ch->is->name); - deliver_status(ch, HW_MOD_CONNECT); - break; - case PSEV_CON_OFF: - pr_debug("%s: pump stev NO CONNECT\n", ch->is->name); - send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - deliver_status(ch, HW_MOD_NOCARR); - break; - case PSEV_V24_OFF: - pr_debug("%s: pump stev V24 OFF\n", ch->is->name); - break; - case PSEV_CTS_ON: - pr_debug("%s: pump stev CTS ON\n", ch->is->name); - break; - case PSEV_CTS_OFF: - pr_debug("%s pump stev CTS OFF\n", ch->is->name); - break; - case PSEV_DCD_ON: - pr_debug("%s: pump stev CARRIER ON\n", ch->is->name); - test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); - send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - break; - case PSEV_DCD_OFF: - pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name); - break; - case PSEV_DSR_ON: - pr_debug("%s: pump stev DSR ON\n", ch->is->name); - break; - case PSEV_DSR_OFF: - pr_debug("%s: pump stev DSR_OFF\n", ch->is->name); - break; - case PSEV_REM_RET: - pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name); - break; - case PSEV_REM_REN: - pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name); - break; - case PSEV_GSTN_CLR: - pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name); - break; - default: - pr_info("u%s: unknown pump stev %x\n", ch->is->name, devt); - break; - } -} - -static void -isar_pump_statev_fax(struct isar_ch *ch, u8 devt) { - u8 dps = SET_DPS(ch->dpath); - u8 p1; - - switch (devt) { - case PSEV_10MS_TIMER: - pr_debug("%s: pump stev TIMER\n", ch->is->name); - break; - case PSEV_RSP_READY: - pr_debug("%s: pump stev RSP_READY\n", ch->is->name); - ch->state = STFAX_READY; - deliver_status(ch, HW_MOD_READY); -#ifdef AUTOCON - if (test_bit(BC_FLG_ORIG, &ch->bch.Flags)) - isar_pump_cmd(bch, HW_MOD_FRH, 3); - else - isar_pump_cmd(bch, HW_MOD_FTH, 3); -#endif - break; - case PSEV_LINE_TX_H: - if (ch->state == STFAX_LINE) { - pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name); - ch->state = STFAX_CONT; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - PCTRL_CMD_CONT, 0, NULL); - } else { - pr_debug("%s: pump stev LINE_TX_H wrong st %x\n", - ch->is->name, ch->state); - } - break; - case PSEV_LINE_RX_H: - if (ch->state == STFAX_LINE) { - pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name); - ch->state = STFAX_CONT; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - PCTRL_CMD_CONT, 0, NULL); - } else { - pr_debug("%s: pump stev LINE_RX_H wrong st %x\n", - ch->is->name, ch->state); - } - break; - case PSEV_LINE_TX_B: - if (ch->state == STFAX_LINE) { - pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name); - ch->state = STFAX_CONT; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - PCTRL_CMD_CONT, 0, NULL); - } else { - pr_debug("%s: pump stev LINE_TX_B wrong st %x\n", - ch->is->name, ch->state); - } - break; - case PSEV_LINE_RX_B: - if (ch->state == STFAX_LINE) { - pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name); - ch->state = STFAX_CONT; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - PCTRL_CMD_CONT, 0, NULL); - } else { - pr_debug("%s: pump stev LINE_RX_B wrong st %x\n", - ch->is->name, ch->state); - } - break; - case PSEV_RSP_CONN: - if (ch->state == STFAX_CONT) { - pr_debug("%s: pump stev RSP_CONN\n", ch->is->name); - ch->state = STFAX_ACTIV; - test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); - send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - if (ch->cmd == PCTRL_CMD_FTH) { - int delay = (ch->mod == 3) ? 1000 : 200; - /* 1s (200 ms) Flags before data */ - if (test_and_set_bit(FLG_FTI_RUN, - &ch->bch.Flags)) - timer_delete(&ch->ftimer); - ch->ftimer.expires = - jiffies + ((delay * HZ) / 1000); - test_and_set_bit(FLG_LL_CONN, - &ch->bch.Flags); - add_timer(&ch->ftimer); - } else { - deliver_status(ch, HW_MOD_CONNECT); - } - } else { - pr_debug("%s: pump stev RSP_CONN wrong st %x\n", - ch->is->name, ch->state); - } - break; - case PSEV_FLAGS_DET: - pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name); - break; - case PSEV_RSP_DISC: - pr_debug("%s: pump stev RSP_DISC state(%d)\n", - ch->is->name, ch->state); - if (ch->state == STFAX_ESCAPE) { - p1 = 5; - switch (ch->newcmd) { - case 0: - ch->state = STFAX_READY; - break; - case PCTRL_CMD_FTM: - p1 = 2; - fallthrough; - case PCTRL_CMD_FTH: - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - PCTRL_CMD_SILON, 1, &p1); - ch->state = STFAX_SILDET; - break; - case PCTRL_CMD_FRH: - case PCTRL_CMD_FRM: - ch->mod = ch->newmod; - p1 = ch->newmod; - ch->newmod = 0; - ch->cmd = ch->newcmd; - ch->newcmd = 0; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - ch->cmd, 1, &p1); - ch->state = STFAX_LINE; - ch->try_mod = 3; - break; - default: - pr_debug("%s: RSP_DISC unknown newcmd %x\n", - ch->is->name, ch->newcmd); - break; - } - } else if (ch->state == STFAX_ACTIV) { - if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags)) - deliver_status(ch, HW_MOD_OK); - else if (ch->cmd == PCTRL_CMD_FRM) - deliver_status(ch, HW_MOD_NOCARR); - else - deliver_status(ch, HW_MOD_FCERROR); - ch->state = STFAX_READY; - } else if (ch->state != STFAX_SILDET) { - /* ignore in STFAX_SILDET */ - ch->state = STFAX_READY; - deliver_status(ch, HW_MOD_FCERROR); - } - break; - case PSEV_RSP_SILDET: - pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name); - if (ch->state == STFAX_SILDET) { - ch->mod = ch->newmod; - p1 = ch->newmod; - ch->newmod = 0; - ch->cmd = ch->newcmd; - ch->newcmd = 0; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - ch->cmd, 1, &p1); - ch->state = STFAX_LINE; - ch->try_mod = 3; - } - break; - case PSEV_RSP_SILOFF: - pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name); - break; - case PSEV_RSP_FCERR: - if (ch->state == STFAX_LINE) { - pr_debug("%s: pump stev RSP_FCERR try %d\n", - ch->is->name, ch->try_mod); - if (ch->try_mod--) { - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, - ch->cmd, 1, &ch->mod); - break; - } - } - pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name); - ch->state = STFAX_ESCAPE; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, - 0, NULL); - deliver_status(ch, HW_MOD_FCERROR); - break; - default: - break; - } -} - -void -mISDNisar_irq(struct isar_hw *isar) -{ - struct isar_ch *ch; - - get_irq_infos(isar); - switch (isar->iis & ISAR_IIS_MSCMSD) { - case ISAR_IIS_RDATA: - ch = sel_bch_isar(isar, isar->iis >> 6); - if (ch) - isar_rcv_frame(ch); - else { - pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n", - isar->name, isar->iis, isar->cmsb, - isar->clsb); - isar->write_reg(isar->hw, ISAR_IIA, 0); - } - break; - case ISAR_IIS_GSTEV: - isar->write_reg(isar->hw, ISAR_IIA, 0); - isar->bstat |= isar->cmsb; - check_send(isar, isar->cmsb); - break; - case ISAR_IIS_BSTEV: -#ifdef ERROR_STATISTIC - ch = sel_bch_isar(isar, isar->iis >> 6); - if (ch) { - if (isar->cmsb == BSTEV_TBO) - ch->bch.err_tx++; - if (isar->cmsb == BSTEV_RBO) - ch->bch.err_rdo++; - } -#endif - pr_debug("%s: Buffer STEV dpath%d msb(%x)\n", - isar->name, isar->iis >> 6, isar->cmsb); - isar->write_reg(isar->hw, ISAR_IIA, 0); - break; - case ISAR_IIS_PSTEV: - ch = sel_bch_isar(isar, isar->iis >> 6); - if (ch) { - rcv_mbox(isar, NULL); - if (ch->bch.state == ISDN_P_B_MODEM_ASYNC) - isar_pump_statev_modem(ch, isar->cmsb); - else if (ch->bch.state == ISDN_P_B_T30_FAX) - isar_pump_statev_fax(ch, isar->cmsb); - else if (ch->bch.state == ISDN_P_B_RAW) { - int tt; - tt = isar->cmsb | 0x30; - if (tt == 0x3e) - tt = '*'; - else if (tt == 0x3f) - tt = '#'; - else if (tt > '9') - tt += 7; - tt |= DTMF_TONE_VAL; - _queue_data(&ch->bch.ch, PH_CONTROL_IND, - MISDN_ID_ANY, sizeof(tt), &tt, - GFP_ATOMIC); - } else - pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n", - isar->name, ch->bch.state, - isar->cmsb); - } else { - pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n", - isar->name, isar->iis, isar->cmsb, - isar->clsb); - isar->write_reg(isar->hw, ISAR_IIA, 0); - } - break; - case ISAR_IIS_PSTRSP: - ch = sel_bch_isar(isar, isar->iis >> 6); - if (ch) { - rcv_mbox(isar, NULL); - isar_pump_status_rsp(ch); - } else { - pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n", - isar->name, isar->iis, isar->cmsb, - isar->clsb); - isar->write_reg(isar->hw, ISAR_IIA, 0); - } - break; - case ISAR_IIS_DIAG: - case ISAR_IIS_BSTRSP: - case ISAR_IIS_IOM2RSP: - rcv_mbox(isar, NULL); - break; - case ISAR_IIS_INVMSG: - rcv_mbox(isar, NULL); - pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb); - break; - default: - rcv_mbox(isar, NULL); - pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n", - isar->name, isar->iis, isar->cmsb, isar->clsb); - break; - } -} -EXPORT_SYMBOL(mISDNisar_irq); - -static void -ftimer_handler(struct timer_list *t) -{ - struct isar_ch *ch = timer_container_of(ch, t, ftimer); - - pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); - test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); - if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags)) - deliver_status(ch, HW_MOD_CONNECT); -} - -static void -setup_pump(struct isar_ch *ch) { - u8 dps = SET_DPS(ch->dpath); - u8 ctrl, param[6]; - - switch (ch->bch.state) { - case ISDN_P_NONE: - case ISDN_P_B_RAW: - case ISDN_P_B_HDLC: - send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); - break; - case ISDN_P_B_L2DTMF: - if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) { - param[0] = 5; /* TOA 5 db */ - send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, - PMOD_DTMF_TRANS, 1, param); - } else { - param[0] = 40; /* REL -46 dbm */ - send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, - PMOD_DTMF, 1, param); - } - fallthrough; - case ISDN_P_B_MODEM_ASYNC: - ctrl = PMOD_DATAMODEM; - if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { - ctrl |= PCTRL_ORIG; - param[5] = PV32P6_CTN; - } else { - param[5] = PV32P6_ATN; - } - param[0] = 6; /* 6 db */ - param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | - PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; - param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; - param[3] = PV32P4_UT144; - param[4] = PV32P5_UT144; - send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); - break; - case ISDN_P_B_T30_FAX: - ctrl = PMOD_FAX; - if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { - ctrl |= PCTRL_ORIG; - param[1] = PFAXP2_CTN; - } else { - param[1] = PFAXP2_ATN; - } - param[0] = 6; /* 6 db */ - send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); - ch->state = STFAX_NULL; - ch->newcmd = 0; - ch->newmod = 0; - test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags); - break; - } - udelay(1000); - send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - udelay(1000); -} - -static void -setup_sart(struct isar_ch *ch) { - u8 dps = SET_DPS(ch->dpath); - u8 ctrl, param[2] = {0, 0}; - - switch (ch->bch.state) { - case ISDN_P_NONE: - send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, - 0, NULL); - break; - case ISDN_P_B_RAW: - case ISDN_P_B_L2DTMF: - send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, - 2, param); - break; - case ISDN_P_B_HDLC: - case ISDN_P_B_T30_FAX: - send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, - 1, param); - break; - case ISDN_P_B_MODEM_ASYNC: - ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; - param[0] = S_P1_CHS_8; - param[1] = S_P2_BFT_DEF; - send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); - break; - } - udelay(1000); - send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); - udelay(1000); -} - -static void -setup_iom2(struct isar_ch *ch) { - u8 dps = SET_DPS(ch->dpath); - u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; - - if (ch->bch.nr == 2) { - msg[1] = 1; - msg[3] = 1; - } - switch (ch->bch.state) { - case ISDN_P_NONE: - cmsb = 0; - /* dummy slot */ - msg[1] = ch->dpath + 2; - msg[3] = ch->dpath + 2; - break; - case ISDN_P_B_RAW: - case ISDN_P_B_HDLC: - break; - case ISDN_P_B_MODEM_ASYNC: - case ISDN_P_B_T30_FAX: - cmsb |= IOM_CTRL_RCV; - fallthrough; - case ISDN_P_B_L2DTMF: - if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) - cmsb |= IOM_CTRL_RCV; - cmsb |= IOM_CTRL_ALAW; - break; - } - send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); - udelay(1000); - send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); - udelay(1000); -} - -static int -modeisar(struct isar_ch *ch, u32 bprotocol) -{ - /* Here we are selecting the best datapath for requested protocol */ - if (ch->bch.state == ISDN_P_NONE) { /* New Setup */ - switch (bprotocol) { - case ISDN_P_NONE: /* init */ - if (!ch->dpath) - /* no init for dpath 0 */ - return 0; - test_and_clear_bit(FLG_HDLC, &ch->bch.Flags); - test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags); - break; - case ISDN_P_B_RAW: - case ISDN_P_B_HDLC: - /* best is datapath 2 */ - if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags)) - ch->dpath = 2; - else if (!test_and_set_bit(ISAR_DP1_USE, - &ch->is->Flags)) - ch->dpath = 1; - else { - pr_info("modeisar both paths in use\n"); - return -EBUSY; - } - if (bprotocol == ISDN_P_B_HDLC) - test_and_set_bit(FLG_HDLC, &ch->bch.Flags); - else - test_and_set_bit(FLG_TRANSPARENT, - &ch->bch.Flags); - break; - case ISDN_P_B_MODEM_ASYNC: - case ISDN_P_B_T30_FAX: - case ISDN_P_B_L2DTMF: - /* only datapath 1 */ - if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags)) - ch->dpath = 1; - else { - pr_info("%s: ISAR modeisar analog functions" - "only with DP1\n", ch->is->name); - return -EBUSY; - } - break; - default: - pr_info("%s: protocol not known %x\n", ch->is->name, - bprotocol); - return -ENOPROTOOPT; - } - } - pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name, - ch->bch.nr, ch->dpath, ch->bch.state, bprotocol); - ch->bch.state = bprotocol; - setup_pump(ch); - setup_iom2(ch); - setup_sart(ch); - if (ch->bch.state == ISDN_P_NONE) { - /* Clear resources */ - if (ch->dpath == 1) - test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags); - else if (ch->dpath == 2) - test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags); - ch->dpath = 0; - ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr); - } else - ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr); - return 0; -} - -static void -isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para) -{ - u8 dps = SET_DPS(ch->dpath); - u8 ctrl = 0, nom = 0, p1 = 0; - - pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n", - ch->is->name, cmd, para, ch->bch.state); - switch (cmd) { - case HW_MOD_FTM: - if (ch->state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FTM; - nom = 1; - ch->state = STFAX_LINE; - ch->cmd = ctrl; - ch->mod = para; - ch->newmod = 0; - ch->newcmd = 0; - ch->try_mod = 3; - } else if ((ch->state == STFAX_ACTIV) && - (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para)) - deliver_status(ch, HW_MOD_CONNECT); - else { - ch->newmod = para; - ch->newcmd = PCTRL_CMD_FTM; - nom = 0; - ctrl = PCTRL_CMD_ESC; - ch->state = STFAX_ESCAPE; - } - break; - case HW_MOD_FTH: - if (ch->state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FTH; - nom = 1; - ch->state = STFAX_LINE; - ch->cmd = ctrl; - ch->mod = para; - ch->newmod = 0; - ch->newcmd = 0; - ch->try_mod = 3; - } else if ((ch->state == STFAX_ACTIV) && - (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para)) - deliver_status(ch, HW_MOD_CONNECT); - else { - ch->newmod = para; - ch->newcmd = PCTRL_CMD_FTH; - nom = 0; - ctrl = PCTRL_CMD_ESC; - ch->state = STFAX_ESCAPE; - } - break; - case HW_MOD_FRM: - if (ch->state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FRM; - nom = 1; - ch->state = STFAX_LINE; - ch->cmd = ctrl; - ch->mod = para; - ch->newmod = 0; - ch->newcmd = 0; - ch->try_mod = 3; - } else if ((ch->state == STFAX_ACTIV) && - (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para)) - deliver_status(ch, HW_MOD_CONNECT); - else { - ch->newmod = para; - ch->newcmd = PCTRL_CMD_FRM; - nom = 0; - ctrl = PCTRL_CMD_ESC; - ch->state = STFAX_ESCAPE; - } - break; - case HW_MOD_FRH: - if (ch->state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FRH; - nom = 1; - ch->state = STFAX_LINE; - ch->cmd = ctrl; - ch->mod = para; - ch->newmod = 0; - ch->newcmd = 0; - ch->try_mod = 3; - } else if ((ch->state == STFAX_ACTIV) && - (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para)) - deliver_status(ch, HW_MOD_CONNECT); - else { - ch->newmod = para; - ch->newcmd = PCTRL_CMD_FRH; - nom = 0; - ctrl = PCTRL_CMD_ESC; - ch->state = STFAX_ESCAPE; - } - break; - case PCTRL_CMD_TDTMF: - p1 = para; - nom = 1; - ctrl = PCTRL_CMD_TDTMF; - break; - } - if (ctrl) - send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); -} - -static void -isar_setup(struct isar_hw *isar) -{ - u8 msg; - int i; - - /* Dpath 1, 2 */ - msg = 61; - for (i = 0; i < 2; i++) { - /* Buffer Config */ - send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | - ISAR_HIS_P12CFG, 4, 1, &msg); - isar->ch[i].mml = msg; - isar->ch[i].bch.state = 0; - isar->ch[i].dpath = i + 1; - modeisar(&isar->ch[i], ISDN_P_NONE); - } -} - -static int -isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct isar_ch *ich = container_of(bch, struct isar_ch, bch); - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - u32 id, *val; - u_long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(ich->is->hwlock, flags); - ret = bchannel_senddata(bch, skb); - if (ret > 0) { /* direct TX */ - ret = 0; - isar_fill_fifo(ich); - } - spin_unlock_irqrestore(ich->is->hwlock, flags); - return ret; - case PH_ACTIVATE_REQ: - spin_lock_irqsave(ich->is->hwlock, flags); - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) - ret = modeisar(ich, ch->protocol); - else - ret = 0; - spin_unlock_irqrestore(ich->is->hwlock, flags); - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - break; - case PH_DEACTIVATE_REQ: - spin_lock_irqsave(ich->is->hwlock, flags); - mISDN_clear_bchannel(bch); - modeisar(ich, ISDN_P_NONE); - spin_unlock_irqrestore(ich->is->hwlock, flags); - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - ret = 0; - break; - case PH_CONTROL_REQ: - val = (u32 *)skb->data; - pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name, - hh->id, *val); - if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) == - DTMF_TONE_VAL)) { - if (bch->state == ISDN_P_B_L2DTMF) { - char tt = *val & DTMF_TONE_MASK; - - if (tt == '*') - tt = 0x1e; - else if (tt == '#') - tt = 0x1f; - else if (tt > '9') - tt -= 7; - tt &= 0x1f; - spin_lock_irqsave(ich->is->hwlock, flags); - isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt); - spin_unlock_irqrestore(ich->is->hwlock, flags); - } else { - pr_info("%s: DTMF send wrong protocol %x\n", - __func__, bch->state); - return -EINVAL; - } - } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) || - (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) { - for (id = 0; id < FAXMODCNT; id++) - if (faxmodulation[id] == *val) - break; - if ((FAXMODCNT > id) && - test_bit(FLG_INITIALIZED, &bch->Flags)) { - pr_debug("%s: isar: new mod\n", ich->is->name); - isar_pump_cmd(ich, hh->id, *val); - ret = 0; - } else { - pr_info("%s: wrong modulation\n", - ich->is->name); - ret = -EINVAL; - } - } else if (hh->id == HW_MOD_LASTDATA) - test_and_set_bit(FLG_DLEETX, &bch->Flags); - else { - pr_info("%s: unknown PH_CONTROL_REQ %x\n", - ich->is->name, hh->id); - ret = -EINVAL; - } - fallthrough; - default: - pr_info("%s: %s unknown prim(%x,%x)\n", - ich->is->name, __func__, hh->prim, hh->id); - ret = -EINVAL; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - return mISDN_ctrl_bchannel(bch, cq); -} - -static int -isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct isar_ch *ich = container_of(bch, struct isar_ch, bch); - int ret = -EINVAL; - u_long flags; - - pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - cancel_work_sync(&bch->workq); - spin_lock_irqsave(ich->is->hwlock, flags); - mISDN_clear_bchannel(bch); - modeisar(ich, ISDN_P_NONE); - spin_unlock_irqrestore(ich->is->hwlock, flags); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(ich->is->owner); - ret = 0; - break; - case CONTROL_CHANNEL: - ret = channel_bctrl(bch, arg); - break; - default: - pr_info("%s: %s unknown prim(%x)\n", - ich->is->name, __func__, cmd); - } - return ret; -} - -static void -free_isar(struct isar_hw *isar) -{ - modeisar(&isar->ch[0], ISDN_P_NONE); - modeisar(&isar->ch[1], ISDN_P_NONE); - timer_delete(&isar->ch[0].ftimer); - timer_delete(&isar->ch[1].ftimer); - test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); - test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); -} - -static int -init_isar(struct isar_hw *isar) -{ - int cnt = 3; - - while (cnt--) { - isar->version = ISARVersion(isar); - if (isar->ch[0].bch.debug & DEBUG_HW) - pr_notice("%s: Testing version %d (%d time)\n", - isar->name, isar->version, 3 - cnt); - if (isar->version == 1) - break; - isar->ctrl(isar->hw, HW_RESET_REQ, 0); - } - if (isar->version != 1) - return -EINVAL; - timer_setup(&isar->ch[0].ftimer, ftimer_handler, 0); - test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); - timer_setup(&isar->ch[1].ftimer, ftimer_handler, 0); - test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); - return 0; -} - -static int -isar_open(struct isar_hw *isar, struct channel_req *rq) -{ - struct bchannel *bch; - - if (rq->adr.channel == 0 || rq->adr.channel > 2) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - bch = &isar->ch[rq->adr.channel - 1].bch; - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; - return 0; -} - -u32 -mISDNisar_init(struct isar_hw *isar, void *hw) -{ - u32 ret, i; - - isar->hw = hw; - for (i = 0; i < 2; i++) { - isar->ch[i].bch.nr = i + 1; - mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, 32); - isar->ch[i].bch.ch.nr = i + 1; - isar->ch[i].bch.ch.send = &isar_l2l1; - isar->ch[i].bch.ch.ctrl = isar_bctrl; - isar->ch[i].bch.hw = hw; - isar->ch[i].is = isar; - } - - isar->init = &init_isar; - isar->release = &free_isar; - isar->firmware = &load_firmware; - isar->open = &isar_open; - - ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK)); - - return ret; -} -EXPORT_SYMBOL(mISDNisar_init); - -static int __init isar_mod_init(void) -{ - pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV); - return 0; -} - -static void __exit isar_mod_cleanup(void) -{ - pr_notice("mISDN: ISAR module unloaded\n"); -} -module_init(isar_mod_init); -module_exit(isar_mod_cleanup); diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c deleted file mode 100644 index 8d740d8eacec..000000000000 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ /dev/null @@ -1,1154 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * NETJet mISDN driver - * - * Author Karsten Keil - * - * Copyright 2009 by Karsten Keil - */ - -#include -#include -#include -#include -#include -#include -#include "ipac.h" -#include "iohelper.h" -#include "netjet.h" -#include "isdnhdlc.h" - -#define NETJET_REV "2.0" - -enum nj_types { - NETJET_S_TJ300, - NETJET_S_TJ320, - ENTERNOW__TJ320, -}; - -struct tiger_dma { - size_t size; - u32 *start; - int idx; - u32 dmastart; - u32 dmairq; - u32 dmaend; - u32 dmacur; -}; - -struct tiger_hw; - -struct tiger_ch { - struct bchannel bch; - struct tiger_hw *nj; - int idx; - int free; - int lastrx; - u16 rxstate; - u16 txstate; - struct isdnhdlc_vars hsend; - struct isdnhdlc_vars hrecv; - u8 *hsbuf; - u8 *hrbuf; -}; - -#define TX_INIT 0x0001 -#define TX_IDLE 0x0002 -#define TX_RUN 0x0004 -#define TX_UNDERRUN 0x0100 -#define RX_OVERRUN 0x0100 - -#define LOG_SIZE 64 - -struct tiger_hw { - struct list_head list; - struct pci_dev *pdev; - char name[MISDN_MAX_IDLEN]; - enum nj_types typ; - int irq; - u32 irqcnt; - u32 base; - size_t base_s; - dma_addr_t dma; - void *dma_p; - spinlock_t lock; /* lock HW */ - struct isac_hw isac; - struct tiger_dma send; - struct tiger_dma recv; - struct tiger_ch bc[2]; - u8 ctrlreg; - u8 dmactrl; - u8 auxd; - u8 last_is0; - u8 irqmask0; - char log[LOG_SIZE]; -}; - -static LIST_HEAD(Cards); -static DEFINE_RWLOCK(card_lock); /* protect Cards */ -static u32 debug; -static int nj_cnt; - -static void -_set_debug(struct tiger_hw *card) -{ - card->isac.dch.debug = debug; - card->bc[0].bch.debug = debug; - card->bc[1].bch.debug = debug; -} - -static int -set_debug(const char *val, const struct kernel_param *kp) -{ - int ret; - struct tiger_hw *card; - - ret = param_set_uint(val, kp); - if (!ret) { - read_lock(&card_lock); - list_for_each_entry(card, &Cards, list) - _set_debug(card); - read_unlock(&card_lock); - } - return ret; -} - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("mISDN driver for NETJet cards"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(NETJET_REV); -module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Netjet debug mask"); - -static void -nj_disable_hwirq(struct tiger_hw *card) -{ - outb(0, card->base + NJ_IRQMASK0); - outb(0, card->base + NJ_IRQMASK1); -} - - -static u8 -ReadISAC_nj(void *p, u8 offset) -{ - struct tiger_hw *card = p; - u8 ret; - - card->auxd &= 0xfc; - card->auxd |= (offset >> 4) & 3; - outb(card->auxd, card->base + NJ_AUXDATA); - ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); - return ret; -} - -static void -WriteISAC_nj(void *p, u8 offset, u8 value) -{ - struct tiger_hw *card = p; - - card->auxd &= 0xfc; - card->auxd |= (offset >> 4) & 3; - outb(card->auxd, card->base + NJ_AUXDATA); - outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); -} - -static void -ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) -{ - struct tiger_hw *card = p; - - card->auxd &= 0xfc; - outb(card->auxd, card->base + NJ_AUXDATA); - insb(card->base + NJ_ISAC_OFF, data, size); -} - -static void -WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) -{ - struct tiger_hw *card = p; - - card->auxd &= 0xfc; - outb(card->auxd, card->base + NJ_AUXDATA); - outsb(card->base + NJ_ISAC_OFF, data, size); -} - -static void -fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill) -{ - struct tiger_hw *card = bc->bch.hw; - u32 mask = 0xff, val; - - pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name, - bc->bch.nr, fill, cnt, idx, card->send.idx); - if (bc->bch.nr & 2) { - fill <<= 8; - mask <<= 8; - } - mask ^= 0xffffffff; - while (cnt--) { - val = card->send.start[idx]; - val &= mask; - val |= fill; - card->send.start[idx++] = val; - if (idx >= card->send.size) - idx = 0; - } -} - -static int -mode_tiger(struct tiger_ch *bc, u32 protocol) -{ - struct tiger_hw *card = bc->bch.hw; - - pr_debug("%s: B%1d protocol %x-->%x\n", card->name, - bc->bch.nr, bc->bch.state, protocol); - switch (protocol) { - case ISDN_P_NONE: - if (bc->bch.state == ISDN_P_NONE) - break; - fill_mem(bc, 0, card->send.size, 0xff); - bc->bch.state = protocol; - /* only stop dma and interrupts if both channels NULL */ - if ((card->bc[0].bch.state == ISDN_P_NONE) && - (card->bc[1].bch.state == ISDN_P_NONE)) { - card->dmactrl = 0; - outb(card->dmactrl, card->base + NJ_DMACTRL); - outb(0, card->base + NJ_IRQMASK0); - } - test_and_clear_bit(FLG_HDLC, &bc->bch.Flags); - test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags); - bc->txstate = 0; - bc->rxstate = 0; - bc->lastrx = -1; - break; - case ISDN_P_B_RAW: - test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags); - bc->bch.state = protocol; - bc->idx = 0; - bc->free = card->send.size / 2; - bc->rxstate = 0; - bc->txstate = TX_INIT | TX_IDLE; - bc->lastrx = -1; - if (!card->dmactrl) { - card->dmactrl = 1; - outb(card->dmactrl, card->base + NJ_DMACTRL); - outb(0x0f, card->base + NJ_IRQMASK0); - } - break; - case ISDN_P_B_HDLC: - test_and_set_bit(FLG_HDLC, &bc->bch.Flags); - bc->bch.state = protocol; - bc->idx = 0; - bc->free = card->send.size / 2; - bc->rxstate = 0; - bc->txstate = TX_INIT | TX_IDLE; - isdnhdlc_rcv_init(&bc->hrecv, 0); - isdnhdlc_out_init(&bc->hsend, 0); - bc->lastrx = -1; - if (!card->dmactrl) { - card->dmactrl = 1; - outb(card->dmactrl, card->base + NJ_DMACTRL); - outb(0x0f, card->base + NJ_IRQMASK0); - } - break; - default: - pr_info("%s: %s protocol %x not handled\n", card->name, - __func__, protocol); - return -ENOPROTOOPT; - } - card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR); - card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR); - card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; - card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; - pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n", - card->name, __func__, - inb(card->base + NJ_DMACTRL), - inb(card->base + NJ_IRQMASK0), - inb(card->base + NJ_IRQSTAT0), - card->send.idx, - card->recv.idx); - return 0; -} - -static void -nj_reset(struct tiger_hw *card) -{ - outb(0xff, card->base + NJ_CTRL); /* Reset On */ - mdelay(1); - - /* now edge triggered for TJ320 GE 13/07/00 */ - /* see comment in IRQ function */ - if (card->typ == NETJET_S_TJ320) /* TJ320 */ - card->ctrlreg = 0x40; /* Reset Off and status read clear */ - else - card->ctrlreg = 0x00; /* Reset Off and status read clear */ - outb(card->ctrlreg, card->base + NJ_CTRL); - mdelay(10); - - /* configure AUX pins (all output except ISAC IRQ pin) */ - card->auxd = 0; - card->dmactrl = 0; - outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL); - outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1); - outb(card->auxd, card->base + NJ_AUXDATA); -} - -static int -inittiger(struct tiger_hw *card) -{ - int i; - - card->dma_p = dma_alloc_coherent(&card->pdev->dev, NJ_DMA_SIZE, - &card->dma, GFP_ATOMIC); - if (!card->dma_p) { - pr_info("%s: No DMA memory\n", card->name); - return -ENOMEM; - } - if ((u64)card->dma > 0xffffffff) { - pr_info("%s: DMA outside 32 bit\n", card->name); - return -ENOMEM; - } - for (i = 0; i < 2; i++) { - card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_ATOMIC); - if (!card->bc[i].hsbuf) { - pr_info("%s: no B%d send buffer\n", card->name, i + 1); - return -ENOMEM; - } - card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_ATOMIC); - if (!card->bc[i].hrbuf) { - pr_info("%s: no B%d recv buffer\n", card->name, i + 1); - return -ENOMEM; - } - } - memset(card->dma_p, 0xff, NJ_DMA_SIZE); - - card->send.start = card->dma_p; - card->send.dmastart = (u32)card->dma; - card->send.dmaend = card->send.dmastart + - (4 * (NJ_DMA_TXSIZE - 1)); - card->send.dmairq = card->send.dmastart + - (4 * ((NJ_DMA_TXSIZE / 2) - 1)); - card->send.size = NJ_DMA_TXSIZE; - - if (debug & DEBUG_HW) - pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p" - " size %zu u32\n", card->name, - card->send.dmastart, card->send.dmairq, - card->send.dmaend, card->send.start, card->send.size); - - outl(card->send.dmastart, card->base + NJ_DMA_READ_START); - outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ); - outl(card->send.dmaend, card->base + NJ_DMA_READ_END); - - card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2); - card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2); - card->recv.dmaend = card->recv.dmastart + - (4 * (NJ_DMA_RXSIZE - 1)); - card->recv.dmairq = card->recv.dmastart + - (4 * ((NJ_DMA_RXSIZE / 2) - 1)); - card->recv.size = NJ_DMA_RXSIZE; - - if (debug & DEBUG_HW) - pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p" - " size %zu u32\n", card->name, - card->recv.dmastart, card->recv.dmairq, - card->recv.dmaend, card->recv.start, card->recv.size); - - outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START); - outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ); - outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END); - return 0; -} - -static void -read_dma(struct tiger_ch *bc, u32 idx, int cnt) -{ - struct tiger_hw *card = bc->bch.hw; - int i, stat; - u32 val; - u8 *p, *pn; - - if (bc->lastrx == idx) { - bc->rxstate |= RX_OVERRUN; - pr_info("%s: B%1d overrun at idx %d\n", card->name, - bc->bch.nr, idx); - } - bc->lastrx = idx; - if (test_bit(FLG_RX_OFF, &bc->bch.Flags)) { - bc->bch.dropcnt += cnt; - return; - } - stat = bchannel_get_rxbuf(&bc->bch, cnt); - /* only transparent use the count here, HDLC overun is detected later */ - if (stat == -ENOMEM) { - pr_warn("%s.B%d: No memory for %d bytes\n", - card->name, bc->bch.nr, cnt); - return; - } - if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) - p = skb_put(bc->bch.rx_skb, cnt); - else - p = bc->hrbuf; - - for (i = 0; i < cnt; i++) { - val = card->recv.start[idx++]; - if (bc->bch.nr & 2) - val >>= 8; - if (idx >= card->recv.size) - idx = 0; - p[i] = val & 0xff; - } - - if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { - recv_Bchannel(&bc->bch, 0, false); - return; - } - - pn = bc->hrbuf; - while (cnt > 0) { - stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, - bc->bch.rx_skb->data, bc->bch.maxlen); - if (stat > 0) { /* valid frame received */ - p = skb_put(bc->bch.rx_skb, stat); - if (debug & DEBUG_HW_BFIFO) { - snprintf(card->log, LOG_SIZE, - "B%1d-recv %s %d ", bc->bch.nr, - card->name, stat); - print_hex_dump_bytes(card->log, - DUMP_PREFIX_OFFSET, p, - stat); - } - recv_Bchannel(&bc->bch, 0, false); - stat = bchannel_get_rxbuf(&bc->bch, bc->bch.maxlen); - if (stat < 0) { - pr_warn("%s.B%d: No memory for %d bytes\n", - card->name, bc->bch.nr, cnt); - return; - } - } else if (stat == -HDLC_CRC_ERROR) { - pr_info("%s: B%1d receive frame CRC error\n", - card->name, bc->bch.nr); - } else if (stat == -HDLC_FRAMING_ERROR) { - pr_info("%s: B%1d receive framing error\n", - card->name, bc->bch.nr); - } else if (stat == -HDLC_LENGTH_ERROR) { - pr_info("%s: B%1d receive frame too long (> %d)\n", - card->name, bc->bch.nr, bc->bch.maxlen); - } - pn += i; - cnt -= i; - } -} - -static void -recv_tiger(struct tiger_hw *card, u8 irq_stat) -{ - u32 idx; - int cnt = card->recv.size / 2; - - /* Note receive is via the WRITE DMA channel */ - card->last_is0 &= ~NJ_IRQM0_WR_MASK; - card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK); - - if (irq_stat & NJ_IRQM0_WR_END) - idx = cnt - 1; - else - idx = card->recv.size - 1; - - if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags)) - read_dma(&card->bc[0], idx, cnt); - if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags)) - read_dma(&card->bc[1], idx, cnt); -} - -/* sync with current DMA address at start or after exception */ -static void -resync(struct tiger_ch *bc, struct tiger_hw *card) -{ - card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); - card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; - if (bc->free > card->send.size / 2) - bc->free = card->send.size / 2; - /* currently we simple sync to the next complete free area - * this hast the advantage that we have always maximum time to - * handle TX irq - */ - if (card->send.idx < ((card->send.size / 2) - 1)) - bc->idx = (card->recv.size / 2) - 1; - else - bc->idx = card->recv.size - 1; - bc->txstate = TX_RUN; - pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name, - __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx); -} - -static int bc_next_frame(struct tiger_ch *); - -static void -fill_hdlc_flag(struct tiger_ch *bc) -{ - struct tiger_hw *card = bc->bch.hw; - int count, i; - u32 m, v; - u8 *p; - - if (bc->free == 0) - return; - pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name, - __func__, bc->bch.nr, bc->free, bc->txstate, - bc->idx, card->send.idx); - if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) - resync(bc, card); - count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i, - bc->hsbuf, bc->free); - pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name, - bc->bch.nr, count); - bc->free -= count; - p = bc->hsbuf; - m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; - for (i = 0; i < count; i++) { - if (bc->idx >= card->send.size) - bc->idx = 0; - v = card->send.start[bc->idx]; - v &= m; - v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; - card->send.start[bc->idx++] = v; - } - if (debug & DEBUG_HW_BFIFO) { - snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", - bc->bch.nr, card->name, count); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); - } -} - -static void -fill_dma(struct tiger_ch *bc) -{ - struct tiger_hw *card = bc->bch.hw; - int count, i, fillempty = 0; - u32 m, v, n = 0; - u8 *p; - - if (bc->free == 0) - return; - if (!bc->bch.tx_skb) { - if (!test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) - return; - fillempty = 1; - count = card->send.size >> 1; - p = bc->bch.fill; - } else { - count = bc->bch.tx_skb->len - bc->bch.tx_idx; - if (count <= 0) - return; - pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", - card->name, __func__, bc->bch.nr, count, bc->free, - bc->bch.tx_idx, bc->bch.tx_skb->len, bc->txstate, - bc->idx, card->send.idx); - p = bc->bch.tx_skb->data + bc->bch.tx_idx; - } - if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) - resync(bc, card); - if (test_bit(FLG_HDLC, &bc->bch.Flags) && !fillempty) { - count = isdnhdlc_encode(&bc->hsend, p, count, &i, - bc->hsbuf, bc->free); - pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name, - bc->bch.nr, i, count); - bc->bch.tx_idx += i; - bc->free -= count; - p = bc->hsbuf; - } else { - if (count > bc->free) - count = bc->free; - if (!fillempty) - bc->bch.tx_idx += count; - bc->free -= count; - } - m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; - if (fillempty) { - n = p[0]; - if (!(bc->bch.nr & 1)) - n <<= 8; - for (i = 0; i < count; i++) { - if (bc->idx >= card->send.size) - bc->idx = 0; - v = card->send.start[bc->idx]; - v &= m; - v |= n; - card->send.start[bc->idx++] = v; - } - } else { - for (i = 0; i < count; i++) { - if (bc->idx >= card->send.size) - bc->idx = 0; - v = card->send.start[bc->idx]; - v &= m; - n = p[i]; - v |= (bc->bch.nr & 1) ? n : n << 8; - card->send.start[bc->idx++] = v; - } - } - if (debug & DEBUG_HW_BFIFO) { - snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", - bc->bch.nr, card->name, count); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); - } - if (bc->free) - bc_next_frame(bc); -} - - -static int -bc_next_frame(struct tiger_ch *bc) -{ - int ret = 1; - - if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) { - fill_dma(bc); - } else { - dev_kfree_skb(bc->bch.tx_skb); - if (get_next_bframe(&bc->bch)) { - fill_dma(bc); - test_and_clear_bit(FLG_TX_EMPTY, &bc->bch.Flags); - } else if (test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) { - fill_dma(bc); - } else if (test_bit(FLG_FILLEMPTY, &bc->bch.Flags)) { - test_and_set_bit(FLG_TX_EMPTY, &bc->bch.Flags); - ret = 0; - } else { - ret = 0; - } - } - return ret; -} - -static void -send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc) -{ - int ret; - - bc->free += card->send.size / 2; - if (bc->free >= card->send.size) { - if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) { - pr_info("%s: B%1d TX underrun state %x\n", card->name, - bc->bch.nr, bc->txstate); - bc->txstate |= TX_UNDERRUN; - } - bc->free = card->send.size; - } - ret = bc_next_frame(bc); - if (!ret) { - if (test_bit(FLG_HDLC, &bc->bch.Flags)) { - fill_hdlc_flag(bc); - return; - } - pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name, - bc->bch.nr, bc->free, bc->idx, card->send.idx); - if (!(bc->txstate & (TX_IDLE | TX_INIT))) { - fill_mem(bc, bc->idx, bc->free, 0xff); - if (bc->free == card->send.size) - bc->txstate |= TX_IDLE; - } - } -} - -static void -send_tiger(struct tiger_hw *card, u8 irq_stat) -{ - int i; - - /* Note send is via the READ DMA channel */ - if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) { - pr_info("%s: tiger warn write double dma %x/%x\n", - card->name, irq_stat, card->last_is0); - return; - } else { - card->last_is0 &= ~NJ_IRQM0_RD_MASK; - card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK); - } - for (i = 0; i < 2; i++) { - if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags)) - send_tiger_bc(card, &card->bc[i]); - } -} - -static irqreturn_t -nj_irq(int intno, void *dev_id) -{ - struct tiger_hw *card = dev_id; - u8 val, s1val, s0val; - - spin_lock(&card->lock); - s0val = inb(card->base | NJ_IRQSTAT0); - s1val = inb(card->base | NJ_IRQSTAT1); - if ((s1val & NJ_ISACIRQ) && (s0val == 0)) { - /* shared IRQ */ - spin_unlock(&card->lock); - return IRQ_NONE; - } - pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val); - card->irqcnt++; - if (!(s1val & NJ_ISACIRQ)) { - val = ReadISAC_nj(card, ISAC_ISTA); - if (val) - mISDNisac_irq(&card->isac, val); - } - - if (s0val) - /* write to clear */ - outb(s0val, card->base | NJ_IRQSTAT0); - else - goto end; - s1val = s0val; - /* set bits in sval to indicate which page is free */ - card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR); - card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; - if (card->recv.dmacur < card->recv.dmairq) - s0val = 0x08; /* the 2nd write area is free */ - else - s0val = 0x04; /* the 1st write area is free */ - - card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); - card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; - if (card->send.dmacur < card->send.dmairq) - s0val |= 0x02; /* the 2nd read area is free */ - else - s0val |= 0x01; /* the 1st read area is free */ - - pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name, - s1val, s0val, card->last_is0, - card->recv.idx, card->send.idx); - /* test if we have a DMA interrupt */ - if (s0val != card->last_is0) { - if ((s0val & NJ_IRQM0_RD_MASK) != - (card->last_is0 & NJ_IRQM0_RD_MASK)) - /* got a write dma int */ - send_tiger(card, s0val); - if ((s0val & NJ_IRQM0_WR_MASK) != - (card->last_is0 & NJ_IRQM0_WR_MASK)) - /* got a read dma int */ - recv_tiger(card, s0val); - } -end: - spin_unlock(&card->lock); - return IRQ_HANDLED; -} - -static int -nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) -{ - int ret = -EINVAL; - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); - struct tiger_hw *card = bch->hw; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(&card->lock, flags); - ret = bchannel_senddata(bch, skb); - if (ret > 0) { /* direct TX */ - fill_dma(bc); - ret = 0; - } - spin_unlock_irqrestore(&card->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - spin_lock_irqsave(&card->lock, flags); - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) - ret = mode_tiger(bc, ch->protocol); - else - ret = 0; - spin_unlock_irqrestore(&card->lock, flags); - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - break; - case PH_DEACTIVATE_REQ: - spin_lock_irqsave(&card->lock, flags); - mISDN_clear_bchannel(bch); - mode_tiger(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - ret = 0; - break; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq) -{ - return mISDN_ctrl_bchannel(&bc->bch, cq); -} - -static int -nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); - struct tiger_hw *card = bch->hw; - int ret = -EINVAL; - u_long flags; - - pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - cancel_work_sync(&bch->workq); - spin_lock_irqsave(&card->lock, flags); - mISDN_clear_bchannel(bch); - mode_tiger(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(THIS_MODULE); - ret = 0; - break; - case CONTROL_CHANNEL: - ret = channel_bctrl(bc, arg); - break; - default: - pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd); - } - return ret; -} - -static int -channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; - break; - case MISDN_CTRL_LOOP: - /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ - if (cq->channel < 0 || cq->channel > 3) { - ret = -EINVAL; - break; - } - ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel); - break; - case MISDN_CTRL_L1_TIMER3: - ret = card->isac.ctrl(&card->isac, HW_TIMER3_VALUE, cq->p1); - break; - default: - pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -open_bchannel(struct tiger_hw *card, struct channel_req *rq) -{ - struct bchannel *bch; - - if (rq->adr.channel == 0 || rq->adr.channel > 2) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - bch = &card->bc[rq->adr.channel - 1].bch; - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; - return 0; -} - -/* - * device control function - */ -static int -nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct tiger_hw *card = dch->hw; - struct channel_req *rq; - int err = 0; - - pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - if (rq->protocol == ISDN_P_TE_S0) - err = card->isac.open(&card->isac, rq); - else - err = open_bchannel(card, rq); - if (err) - break; - if (!try_module_get(THIS_MODULE)) - pr_info("%s: cannot get module\n", card->name); - break; - case CLOSE_CHANNEL: - pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id, - __builtin_return_address(0)); - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - err = channel_ctrl(card, arg); - break; - default: - pr_debug("%s: %s unknown command %x\n", - card->name, __func__, cmd); - return -EINVAL; - } - return err; -} - -static int -nj_init_card(struct tiger_hw *card) -{ - u_long flags; - int ret; - - spin_lock_irqsave(&card->lock, flags); - nj_disable_hwirq(card); - spin_unlock_irqrestore(&card->lock, flags); - - card->irq = card->pdev->irq; - if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) { - pr_info("%s: couldn't get interrupt %d\n", - card->name, card->irq); - card->irq = -1; - return -EIO; - } - - spin_lock_irqsave(&card->lock, flags); - nj_reset(card); - ret = card->isac.init(&card->isac); - if (ret) - goto error; - ret = inittiger(card); - if (ret) - goto error; - mode_tiger(&card->bc[0], ISDN_P_NONE); - mode_tiger(&card->bc[1], ISDN_P_NONE); -error: - spin_unlock_irqrestore(&card->lock, flags); - return ret; -} - - -static void -nj_release(struct tiger_hw *card) -{ - u_long flags; - int i; - - if (card->base_s) { - spin_lock_irqsave(&card->lock, flags); - nj_disable_hwirq(card); - mode_tiger(&card->bc[0], ISDN_P_NONE); - mode_tiger(&card->bc[1], ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - card->isac.release(&card->isac); - release_region(card->base, card->base_s); - card->base_s = 0; - } - if (card->irq > 0) - free_irq(card->irq, card); - if (device_is_registered(&card->isac.dch.dev.dev)) - mISDN_unregister_device(&card->isac.dch.dev); - - for (i = 0; i < 2; i++) { - mISDN_freebchannel(&card->bc[i].bch); - kfree(card->bc[i].hsbuf); - kfree(card->bc[i].hrbuf); - } - if (card->dma_p) - dma_free_coherent(&card->pdev->dev, NJ_DMA_SIZE, card->dma_p, - card->dma); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - pci_disable_device(card->pdev); - pci_set_drvdata(card->pdev, NULL); - kfree(card); -} - - -static int -nj_setup(struct tiger_hw *card) -{ - card->base = pci_resource_start(card->pdev, 0); - card->base_s = pci_resource_len(card->pdev, 0); - if (!request_region(card->base, card->base_s, card->name)) { - pr_info("%s: NETjet config port %#x-%#x already in use\n", - card->name, card->base, - (u32)(card->base + card->base_s - 1)); - card->base_s = 0; - return -EIO; - } - ASSIGN_FUNC(nj, ISAC, card->isac); - return 0; -} - - -static int -setup_instance(struct tiger_hw *card) -{ - int i, err; - u_long flags; - - snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1); - write_lock_irqsave(&card_lock, flags); - list_add_tail(&card->list, &Cards); - write_unlock_irqrestore(&card_lock, flags); - - _set_debug(card); - card->isac.name = card->name; - spin_lock_init(&card->lock); - card->isac.hwlock = &card->lock; - mISDNisac_init(&card->isac, card); - - card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - card->isac.dch.dev.D.ctrl = nj_dctrl; - for (i = 0; i < 2; i++) { - card->bc[i].bch.nr = i + 1; - set_channelmap(i + 1, card->isac.dch.dev.channelmap); - mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, - NJ_DMA_RXSIZE >> 1); - card->bc[i].bch.hw = card; - card->bc[i].bch.ch.send = nj_l2l1B; - card->bc[i].bch.ch.ctrl = nj_bctrl; - card->bc[i].bch.ch.nr = i + 1; - list_add(&card->bc[i].bch.ch.list, - &card->isac.dch.dev.bchannels); - card->bc[i].bch.hw = card; - } - err = nj_setup(card); - if (err) - goto error; - err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, - card->name); - if (err) - goto error; - err = nj_init_card(card); - if (!err) { - nj_cnt++; - pr_notice("Netjet %d cards installed\n", nj_cnt); - return 0; - } -error: - nj_release(card); - return err; -} - -static int -nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - int cfg; - struct tiger_hw *card; - - if (pdev->subsystem_vendor == 0x8086 && - pdev->subsystem_device == 0x0003) { - pr_notice("Netjet: Digium X100P/X101P not handled\n"); - return -ENODEV; - } - - if (pdev->subsystem_vendor == 0x55 && - pdev->subsystem_device == 0x02) { - pr_notice("Netjet: Enter!Now not handled yet\n"); - return -ENODEV; - } - - if (pdev->subsystem_vendor == 0xb100 && - pdev->subsystem_device == 0x0003) { - pr_notice("Netjet: Digium TDM400P not handled yet\n"); - return -ENODEV; - } - - card = kzalloc_obj(struct tiger_hw); - if (!card) { - pr_info("No kmem for Netjet\n"); - return err; - } - - card->pdev = pdev; - - err = pci_enable_device(pdev); - if (err) { - kfree(card); - return err; - } - - printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n", - pci_name(pdev)); - - pci_set_master(pdev); - - /* the TJ300 and TJ320 must be detected, the IRQ handling is different - * unfortunately the chips use the same device ID, but the TJ320 has - * the bit20 in status PCI cfg register set - */ - pci_read_config_dword(pdev, 0x04, &cfg); - if (cfg & 0x00100000) - card->typ = NETJET_S_TJ320; - else - card->typ = NETJET_S_TJ300; - - card->base = pci_resource_start(pdev, 0); - pci_set_drvdata(pdev, card); - err = setup_instance(card); - if (err) - pci_set_drvdata(pdev, NULL); - - return err; -} - - -static void nj_remove(struct pci_dev *pdev) -{ - struct tiger_hw *card = pci_get_drvdata(pdev); - - if (card) - nj_release(card); - else - pr_info("%s drvdata already removed\n", __func__); -} - -/* We cannot select cards with PCI_SUB... IDs, since here are cards with - * SUB IDs set to PCI_ANY_ID, so we need to match all and reject - * known other cards which not work with this driver - see probe function */ -static const struct pci_device_id nj_pci_ids[] = { - { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { } -}; -MODULE_DEVICE_TABLE(pci, nj_pci_ids); - -static struct pci_driver nj_driver = { - .name = "netjet", - .probe = nj_probe, - .remove = nj_remove, - .id_table = nj_pci_ids, -}; - -static int __init nj_init(void) -{ - int err; - - pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV); - err = pci_register_driver(&nj_driver); - return err; -} - -static void __exit nj_cleanup(void) -{ - pci_unregister_driver(&nj_driver); -} - -module_init(nj_init); -module_exit(nj_cleanup); diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h deleted file mode 100644 index b23ad9f6d4d0..000000000000 --- a/drivers/isdn/hardware/mISDN/netjet.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * NETjet common header file - * - * Author Karsten Keil - * based on work of Matt Henderson and Daniel Potts, - * Traverse Technologies P/L www.traverse.com.au - * - * Copyright 2009 by Karsten Keil - */ - -#define NJ_CTRL 0x00 -#define NJ_DMACTRL 0x01 -#define NJ_AUXCTRL 0x02 -#define NJ_AUXDATA 0x03 -#define NJ_IRQMASK0 0x04 -#define NJ_IRQMASK1 0x05 -#define NJ_IRQSTAT0 0x06 -#define NJ_IRQSTAT1 0x07 -#define NJ_DMA_READ_START 0x08 -#define NJ_DMA_READ_IRQ 0x0c -#define NJ_DMA_READ_END 0x10 -#define NJ_DMA_READ_ADR 0x14 -#define NJ_DMA_WRITE_START 0x18 -#define NJ_DMA_WRITE_IRQ 0x1c -#define NJ_DMA_WRITE_END 0x20 -#define NJ_DMA_WRITE_ADR 0x24 -#define NJ_PULSE_CNT 0x28 - -#define NJ_ISAC_OFF 0xc0 -#define NJ_ISACIRQ 0x10 - -#define NJ_IRQM0_RD_MASK 0x03 -#define NJ_IRQM0_RD_IRQ 0x01 -#define NJ_IRQM0_RD_END 0x02 -#define NJ_IRQM0_WR_MASK 0x0c -#define NJ_IRQM0_WR_IRQ 0x04 -#define NJ_IRQM0_WR_END 0x08 - -/* one page here is no need to be smaller */ -#define NJ_DMA_SIZE 4096 -/* 2 * 64 byte is a compromise between IRQ count and latency */ -#define NJ_DMA_RXSIZE 128 /* 2 * 64 */ -#define NJ_DMA_TXSIZE 128 /* 2 * 64 */ diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c deleted file mode 100644 index ab24c3c460e6..000000000000 --- a/drivers/isdn/hardware/mISDN/speedfax.c +++ /dev/null @@ -1,520 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * speedfax.c low level stuff for Sedlbauer Speedfax+ cards - * based on the ISAR DSP - * Thanks to Sedlbauer AG for informations and HW - * - * Author Karsten Keil - * - * Copyright 2009 by Karsten Keil - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ipac.h" -#include "isar.h" - -#define SPEEDFAX_REV "2.0" - -#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 -#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 -#define PCI_SUB_ID_SEDLBAUER 0x01 - -#define SFAX_PCI_ADDR 0xc8 -#define SFAX_PCI_ISAC 0xd0 -#define SFAX_PCI_ISAR 0xe0 - -/* TIGER 100 Registers */ - -#define TIGER_RESET_ADDR 0x00 -#define TIGER_EXTERN_RESET_ON 0x01 -#define TIGER_EXTERN_RESET_OFF 0x00 -#define TIGER_AUX_CTRL 0x02 -#define TIGER_AUX_DATA 0x03 -#define TIGER_AUX_IRQMASK 0x05 -#define TIGER_AUX_STATUS 0x07 - -/* Tiger AUX BITs */ -#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */ -#define SFAX_ISAR_RESET_BIT_OFF 0x00 -#define SFAX_ISAR_RESET_BIT_ON 0x01 -#define SFAX_TIGER_IRQ_BIT 0x02 -#define SFAX_LED1_BIT 0x08 -#define SFAX_LED2_BIT 0x10 - -#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON) -#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT) - -static int sfax_cnt; -static u32 debug; -static u32 irqloops = 4; - -struct sfax_hw { - struct list_head list; - struct pci_dev *pdev; - char name[MISDN_MAX_IDLEN]; - u32 irq; - u32 irqcnt; - u32 cfg; - struct _ioport p_isac; - struct _ioport p_isar; - u8 aux_data; - spinlock_t lock; /* HW access lock */ - struct isac_hw isac; - struct isar_hw isar; -}; - -static LIST_HEAD(Cards); -static DEFINE_RWLOCK(card_lock); /* protect Cards */ - -static void -_set_debug(struct sfax_hw *card) -{ - card->isac.dch.debug = debug; - card->isar.ch[0].bch.debug = debug; - card->isar.ch[1].bch.debug = debug; -} - -static int -set_debug(const char *val, const struct kernel_param *kp) -{ - int ret; - struct sfax_hw *card; - - ret = param_set_uint(val, kp); - if (!ret) { - read_lock(&card_lock); - list_for_each_entry(card, &Cards, list) - _set_debug(card); - read_unlock(&card_lock); - } - return ret; -} - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("mISDN driver for Sedlbauer Speedfax+ cards"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(SPEEDFAX_REV); -MODULE_FIRMWARE("isdn/ISAR.BIN"); -module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Speedfax debug mask"); -module_param(irqloops, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)"); - -IOFUNC_IND(ISAC, sfax_hw, p_isac) -IOFUNC_IND(ISAR, sfax_hw, p_isar) - -static irqreturn_t -speedfax_irq(int intno, void *dev_id) -{ - struct sfax_hw *sf = dev_id; - u8 val; - int cnt = irqloops; - - spin_lock(&sf->lock); - val = inb(sf->cfg + TIGER_AUX_STATUS); - if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */ - spin_unlock(&sf->lock); - return IRQ_NONE; /* shared */ - } - sf->irqcnt++; - val = ReadISAR_IND(sf, ISAR_IRQBIT); -Start_ISAR: - if (val & ISAR_IRQSTA) - mISDNisar_irq(&sf->isar); - val = ReadISAC_IND(sf, ISAC_ISTA); - if (val) - mISDNisac_irq(&sf->isac, val); - val = ReadISAR_IND(sf, ISAR_IRQBIT); - if ((val & ISAR_IRQSTA) && cnt--) - goto Start_ISAR; - if (cnt < irqloops) - pr_debug("%s: %d irqloops cpu%d\n", sf->name, - irqloops - cnt, smp_processor_id()); - if (irqloops && !cnt) - pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name, - irqloops, smp_processor_id()); - spin_unlock(&sf->lock); - return IRQ_HANDLED; -} - -static void -enable_hwirq(struct sfax_hw *sf) -{ - WriteISAC_IND(sf, ISAC_MASK, 0); - WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK); - outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK); -} - -static void -disable_hwirq(struct sfax_hw *sf) -{ - WriteISAC_IND(sf, ISAC_MASK, 0xFF); - WriteISAR_IND(sf, ISAR_IRQBIT, 0); - outb(0, sf->cfg + TIGER_AUX_IRQMASK); -} - -static void -reset_speedfax(struct sfax_hw *sf) -{ - - pr_debug("%s: resetting card\n", sf->name); - outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR); - outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA); - mdelay(1); - outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR); - sf->aux_data = SFAX_PCI_RESET_OFF; - outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); - mdelay(1); -} - -static int -sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg) -{ - int ret = 0; - - switch (cmd) { - case HW_RESET_REQ: - reset_speedfax(sf); - break; - case HW_ACTIVATE_IND: - if (arg & 1) - sf->aux_data &= ~SFAX_LED1_BIT; - if (arg & 2) - sf->aux_data &= ~SFAX_LED2_BIT; - outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); - break; - case HW_DEACT_IND: - if (arg & 1) - sf->aux_data |= SFAX_LED1_BIT; - if (arg & 2) - sf->aux_data |= SFAX_LED2_BIT; - outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); - break; - default: - pr_info("%s: %s unknown command %x %lx\n", - sf->name, __func__, cmd, arg); - ret = -EINVAL; - break; - } - return ret; -} - -static int -channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; - break; - case MISDN_CTRL_LOOP: - /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ - if (cq->channel < 0 || cq->channel > 3) { - ret = -EINVAL; - break; - } - ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel); - break; - case MISDN_CTRL_L1_TIMER3: - ret = sf->isac.ctrl(&sf->isac, HW_TIMER3_VALUE, cq->p1); - break; - default: - pr_info("%s: unknown Op %x\n", sf->name, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct sfax_hw *sf = dch->hw; - struct channel_req *rq; - int err = 0; - - pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - if (rq->protocol == ISDN_P_TE_S0) - err = sf->isac.open(&sf->isac, rq); - else - err = sf->isar.open(&sf->isar, rq); - if (err) - break; - if (!try_module_get(THIS_MODULE)) - pr_info("%s: cannot get module\n", sf->name); - break; - case CLOSE_CHANNEL: - pr_debug("%s: dev(%d) close from %p\n", sf->name, - dch->dev.id, __builtin_return_address(0)); - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - err = channel_ctrl(sf, arg); - break; - default: - pr_debug("%s: unknown command %x\n", sf->name, cmd); - return -EINVAL; - } - return err; -} - -static int -init_card(struct sfax_hw *sf) -{ - int ret, cnt = 3; - u_long flags; - - ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf); - if (ret) { - pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq); - return ret; - } - while (cnt--) { - spin_lock_irqsave(&sf->lock, flags); - ret = sf->isac.init(&sf->isac); - if (ret) { - spin_unlock_irqrestore(&sf->lock, flags); - pr_info("%s: ISAC init failed with %d\n", - sf->name, ret); - break; - } - enable_hwirq(sf); - /* RESET Receiver and Transmitter */ - WriteISAC_IND(sf, ISAC_CMDR, 0x41); - spin_unlock_irqrestore(&sf->lock, flags); - msleep_interruptible(10); - if (debug & DEBUG_HW) - pr_notice("%s: IRQ %d count %d\n", sf->name, - sf->irq, sf->irqcnt); - if (!sf->irqcnt) { - pr_info("%s: IRQ(%d) got no requests during init %d\n", - sf->name, sf->irq, 3 - cnt); - } else - return 0; - } - free_irq(sf->irq, sf); - return -EIO; -} - - -static int -setup_speedfax(struct sfax_hw *sf) -{ - u_long flags; - - if (!request_region(sf->cfg, 256, sf->name)) { - pr_info("mISDN: %s config port %x-%x already in use\n", - sf->name, sf->cfg, sf->cfg + 255); - return -EIO; - } - outb(0xff, sf->cfg); - outb(0, sf->cfg); - outb(0xdd, sf->cfg + TIGER_AUX_CTRL); - outb(0, sf->cfg + TIGER_AUX_IRQMASK); - - sf->isac.type = IPAC_TYPE_ISAC; - sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR; - sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC; - sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR; - sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR; - ASSIGN_FUNC(IND, ISAC, sf->isac); - ASSIGN_FUNC(IND, ISAR, sf->isar); - spin_lock_irqsave(&sf->lock, flags); - reset_speedfax(sf); - disable_hwirq(sf); - spin_unlock_irqrestore(&sf->lock, flags); - return 0; -} - -static void -release_card(struct sfax_hw *card) { - u_long flags; - - spin_lock_irqsave(&card->lock, flags); - disable_hwirq(card); - spin_unlock_irqrestore(&card->lock, flags); - card->isac.release(&card->isac); - free_irq(card->irq, card); - card->isar.release(&card->isar); - mISDN_unregister_device(&card->isac.dch.dev); - release_region(card->cfg, 256); - pci_disable_device(card->pdev); - pci_set_drvdata(card->pdev, NULL); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - kfree(card); - sfax_cnt--; -} - -static int -setup_instance(struct sfax_hw *card) -{ - const struct firmware *firmware; - int i, err; - u_long flags; - - snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1); - write_lock_irqsave(&card_lock, flags); - list_add_tail(&card->list, &Cards); - write_unlock_irqrestore(&card_lock, flags); - _set_debug(card); - spin_lock_init(&card->lock); - card->isac.hwlock = &card->lock; - card->isar.hwlock = &card->lock; - card->isar.ctrl = (void *)&sfax_ctrl; - card->isac.name = card->name; - card->isar.name = card->name; - card->isar.owner = THIS_MODULE; - - err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev); - if (err < 0) { - pr_info("%s: firmware request failed %d\n", - card->name, err); - goto error_fw; - } - if (debug & DEBUG_HW) - pr_notice("%s: got firmware %zu bytes\n", - card->name, firmware->size); - - mISDNisac_init(&card->isac, card); - - card->isac.dch.dev.D.ctrl = sfax_dctrl; - card->isac.dch.dev.Bprotocols = - mISDNisar_init(&card->isar, card); - for (i = 0; i < 2; i++) { - set_channelmap(i + 1, card->isac.dch.dev.channelmap); - list_add(&card->isar.ch[i].bch.ch.list, - &card->isac.dch.dev.bchannels); - } - - err = setup_speedfax(card); - if (err) - goto error_setup; - err = card->isar.init(&card->isar); - if (err) - goto error; - err = mISDN_register_device(&card->isac.dch.dev, - &card->pdev->dev, card->name); - if (err) - goto error; - err = init_card(card); - if (err) - goto error_init; - err = card->isar.firmware(&card->isar, firmware->data, firmware->size); - if (!err) { - release_firmware(firmware); - sfax_cnt++; - pr_notice("SpeedFax %d cards installed\n", sfax_cnt); - return 0; - } - disable_hwirq(card); - free_irq(card->irq, card); -error_init: - mISDN_unregister_device(&card->isac.dch.dev); -error: - release_region(card->cfg, 256); -error_setup: - card->isac.release(&card->isac); - card->isar.release(&card->isar); - release_firmware(firmware); -error_fw: - pci_disable_device(card->pdev); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - kfree(card); - return err; -} - -static int -sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - struct sfax_hw *card = kzalloc_obj(struct sfax_hw); - - if (!card) { - pr_info("No memory for Speedfax+ PCI\n"); - return err; - } - card->pdev = pdev; - err = pci_enable_device(pdev); - if (err) { - kfree(card); - return err; - } - - pr_notice("mISDN: Speedfax found adapter %s at %s\n", - (char *)ent->driver_data, pci_name(pdev)); - - card->cfg = pci_resource_start(pdev, 0); - card->irq = pdev->irq; - pci_set_drvdata(pdev, card); - err = setup_instance(card); - if (err) - pci_set_drvdata(pdev, NULL); - return err; -} - -static void -sfax_remove_pci(struct pci_dev *pdev) -{ - struct sfax_hw *card = pci_get_drvdata(pdev); - - if (card) - release_card(card); - else - pr_debug("%s: drvdata already removed\n", __func__); -} - -static struct pci_device_id sfaxpci_ids[] = { - { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, - PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER, - 0, 0, (unsigned long) "Pyramid Speedfax + PCI" - }, - { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, - PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER, - 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI" - }, - { } -}; -MODULE_DEVICE_TABLE(pci, sfaxpci_ids); - -static struct pci_driver sfaxpci_driver = { - .name = "speedfax+ pci", - .probe = sfaxpci_probe, - .remove = sfax_remove_pci, - .id_table = sfaxpci_ids, -}; - -static int __init -Speedfax_init(void) -{ - int err; - - pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n", - SPEEDFAX_REV); - err = pci_register_driver(&sfaxpci_driver); - return err; -} - -static void __exit -Speedfax_cleanup(void) -{ - pci_unregister_driver(&sfaxpci_driver); -} - -module_init(Speedfax_init); -module_exit(Speedfax_cleanup); diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c deleted file mode 100644 index a341470c042f..000000000000 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ /dev/null @@ -1,1417 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * w6692.c mISDN driver for Winbond w6692 based cards - * - * Author Karsten Keil - * based on the w6692 I4L driver from Petr Novak - * - * Copyright 2009 by Karsten Keil - */ - -#include -#include -#include -#include -#include -#include -#include "w6692.h" - -#define W6692_REV "2.0" - -#define DBUSY_TIMER_VALUE 80 - -enum { - W6692_ASUS, - W6692_WINBOND, - W6692_USR -}; - -/* private data in the PCI devices list */ -struct w6692map { - u_int subtype; - char *name; -}; - -static const struct w6692map w6692_map[] = -{ - {W6692_ASUS, "Dynalink/AsusCom IS64PH"}, - {W6692_WINBOND, "Winbond W6692"}, - {W6692_USR, "USR W6692"} -}; - -#define PCI_DEVICE_ID_USR_6692 0x3409 - -struct w6692_ch { - struct bchannel bch; - u32 addr; - struct timer_list timer; - u8 b_mode; -}; - -struct w6692_hw { - struct list_head list; - struct pci_dev *pdev; - char name[MISDN_MAX_IDLEN]; - u32 irq; - u32 irqcnt; - u32 addr; - u32 fmask; /* feature mask - bit set per card nr */ - int subtype; - spinlock_t lock; /* hw lock */ - u8 imask; - u8 pctl; - u8 xaddr; - u8 xdata; - u8 state; - struct w6692_ch bc[2]; - struct dchannel dch; - char log[64]; -}; - -static LIST_HEAD(Cards); -static DEFINE_RWLOCK(card_lock); /* protect Cards */ - -static int w6692_cnt; -static int debug; -static u32 led; -static u32 pots; - -static void -_set_debug(struct w6692_hw *card) -{ - card->dch.debug = debug; - card->bc[0].bch.debug = debug; - card->bc[1].bch.debug = debug; -} - -static int -set_debug(const char *val, const struct kernel_param *kp) -{ - int ret; - struct w6692_hw *card; - - ret = param_set_uint(val, kp); - if (!ret) { - read_lock(&card_lock); - list_for_each_entry(card, &Cards, list) - _set_debug(card); - read_unlock(&card_lock); - } - return ret; -} - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("mISDN driver for Winbond w6692 based cards"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(W6692_REV); -module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "W6692 debug mask"); -module_param(led, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)"); -module_param(pots, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)"); - -static inline u8 -ReadW6692(struct w6692_hw *card, u8 offset) -{ - return inb(card->addr + offset); -} - -static inline void -WriteW6692(struct w6692_hw *card, u8 offset, u8 value) -{ - outb(value, card->addr + offset); -} - -static inline u8 -ReadW6692B(struct w6692_ch *bc, u8 offset) -{ - return inb(bc->addr + offset); -} - -static inline void -WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value) -{ - outb(value, bc->addr + offset); -} - -static void -enable_hwirq(struct w6692_hw *card) -{ - WriteW6692(card, W_IMASK, card->imask); -} - -static void -disable_hwirq(struct w6692_hw *card) -{ - WriteW6692(card, W_IMASK, 0xff); -} - -static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"}; - -static void -W6692Version(struct w6692_hw *card) -{ - int val; - - val = ReadW6692(card, W_D_RBCH); - pr_notice("%s: Winbond W6692 version: %s\n", card->name, - W6692Ver[(val >> 6) & 3]); -} - -static void -w6692_led_handler(struct w6692_hw *card, int on) -{ - if ((!(card->fmask & led)) || card->subtype == W6692_USR) - return; - if (on) { - card->xdata &= 0xfb; /* LED ON */ - WriteW6692(card, W_XDATA, card->xdata); - } else { - card->xdata |= 0x04; /* LED OFF */ - WriteW6692(card, W_XDATA, card->xdata); - } -} - -static void -ph_command(struct w6692_hw *card, u8 cmd) -{ - pr_debug("%s: ph_command %x\n", card->name, cmd); - WriteW6692(card, W_CIX, cmd); -} - -static void -W6692_new_ph(struct w6692_hw *card) -{ - if (card->state == W_L1CMD_RST) - ph_command(card, W_L1CMD_DRC); - schedule_event(&card->dch, FLG_PHCHANGE); -} - -static void -W6692_ph_bh(struct dchannel *dch) -{ - struct w6692_hw *card = dch->hw; - - switch (card->state) { - case W_L1CMD_RST: - dch->state = 0; - l1_event(dch->l1, HW_RESET_IND); - break; - case W_L1IND_CD: - dch->state = 3; - l1_event(dch->l1, HW_DEACT_CNF); - break; - case W_L1IND_DRD: - dch->state = 3; - l1_event(dch->l1, HW_DEACT_IND); - break; - case W_L1IND_CE: - dch->state = 4; - l1_event(dch->l1, HW_POWERUP_IND); - break; - case W_L1IND_LD: - if (dch->state <= 5) { - dch->state = 5; - l1_event(dch->l1, ANYSIGNAL); - } else { - dch->state = 8; - l1_event(dch->l1, LOSTFRAMING); - } - break; - case W_L1IND_ARD: - dch->state = 6; - l1_event(dch->l1, INFO2); - break; - case W_L1IND_AI8: - dch->state = 7; - l1_event(dch->l1, INFO4_P8); - break; - case W_L1IND_AI10: - dch->state = 7; - l1_event(dch->l1, INFO4_P10); - break; - default: - pr_debug("%s: TE unknown state %02x dch state %02x\n", - card->name, card->state, dch->state); - break; - } - pr_debug("%s: TE newstate %02x\n", card->name, dch->state); -} - -static void -W6692_empty_Dfifo(struct w6692_hw *card, int count) -{ - struct dchannel *dch = &card->dch; - u8 *ptr; - - pr_debug("%s: empty_Dfifo %d\n", card->name, count); - if (!dch->rx_skb) { - dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC); - if (!dch->rx_skb) { - pr_info("%s: D receive out of memory\n", card->name); - WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); - return; - } - } - if ((dch->rx_skb->len + count) >= dch->maxlen) { - pr_debug("%s: empty_Dfifo overrun %d\n", card->name, - dch->rx_skb->len + count); - WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); - return; - } - ptr = skb_put(dch->rx_skb, count); - insb(card->addr + W_D_RFIFO, ptr, count); - WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); - if (debug & DEBUG_HW_DFIFO) { - snprintf(card->log, 63, "D-recv %s %d ", - card->name, count); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); - } -} - -static void -W6692_fill_Dfifo(struct w6692_hw *card) -{ - struct dchannel *dch = &card->dch; - int count; - u8 *ptr; - u8 cmd = W_D_CMDR_XMS; - - pr_debug("%s: fill_Dfifo\n", card->name); - if (!dch->tx_skb) - return; - count = dch->tx_skb->len - dch->tx_idx; - if (count <= 0) - return; - if (count > W_D_FIFO_THRESH) - count = W_D_FIFO_THRESH; - else - cmd |= W_D_CMDR_XME; - ptr = dch->tx_skb->data + dch->tx_idx; - dch->tx_idx += count; - outsb(card->addr + W_D_XFIFO, ptr, count); - WriteW6692(card, W_D_CMDR, cmd); - if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) { - pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name); - timer_delete(&dch->timer); - } - dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); - add_timer(&dch->timer); - if (debug & DEBUG_HW_DFIFO) { - snprintf(card->log, 63, "D-send %s %d ", - card->name, count); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); - } -} - -static void -d_retransmit(struct w6692_hw *card) -{ - struct dchannel *dch = &card->dch; - - if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) - timer_delete(&dch->timer); -#ifdef FIXME - if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) - dchannel_sched_event(dch, D_CLEARBUSY); -#endif - if (test_bit(FLG_TX_BUSY, &dch->Flags)) { - /* Restart frame */ - dch->tx_idx = 0; - W6692_fill_Dfifo(card); - } else if (dch->tx_skb) { /* should not happen */ - pr_info("%s: %s without TX_BUSY\n", card->name, __func__); - test_and_set_bit(FLG_TX_BUSY, &dch->Flags); - dch->tx_idx = 0; - W6692_fill_Dfifo(card); - } else { - pr_info("%s: XDU no TX_BUSY\n", card->name); - if (get_next_dframe(dch)) - W6692_fill_Dfifo(card); - } -} - -static void -handle_rxD(struct w6692_hw *card) { - u8 stat; - int count; - - stat = ReadW6692(card, W_D_RSTA); - if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { - if (stat & W_D_RSTA_RDOV) { - pr_debug("%s: D-channel RDOV\n", card->name); -#ifdef ERROR_STATISTIC - card->dch.err_rx++; -#endif - } - if (stat & W_D_RSTA_CRCE) { - pr_debug("%s: D-channel CRC error\n", card->name); -#ifdef ERROR_STATISTIC - card->dch.err_crc++; -#endif - } - if (stat & W_D_RSTA_RMB) { - pr_debug("%s: D-channel ABORT\n", card->name); -#ifdef ERROR_STATISTIC - card->dch.err_rx++; -#endif - } - dev_kfree_skb(card->dch.rx_skb); - card->dch.rx_skb = NULL; - WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); - } else { - count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1); - if (count == 0) - count = W_D_FIFO_THRESH; - W6692_empty_Dfifo(card, count); - recv_Dchannel(&card->dch); - } -} - -static void -handle_txD(struct w6692_hw *card) { - if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags)) - timer_delete(&card->dch.timer); - if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) { - W6692_fill_Dfifo(card); - } else { - dev_kfree_skb(card->dch.tx_skb); - if (get_next_dframe(&card->dch)) - W6692_fill_Dfifo(card); - } -} - -static void -handle_statusD(struct w6692_hw *card) -{ - struct dchannel *dch = &card->dch; - u8 exval, v1, cir; - - exval = ReadW6692(card, W_D_EXIR); - - pr_debug("%s: D_EXIR %02x\n", card->name, exval); - if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { - /* Transmit underrun/collision */ - pr_debug("%s: D-channel underrun/collision\n", card->name); -#ifdef ERROR_STATISTIC - dch->err_tx++; -#endif - d_retransmit(card); - } - if (exval & W_D_EXI_RDOV) { /* RDOV */ - pr_debug("%s: D-channel RDOV\n", card->name); - WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST); - } - if (exval & W_D_EXI_TIN2) /* TIN2 - never */ - pr_debug("%s: spurious TIN2 interrupt\n", card->name); - if (exval & W_D_EXI_MOC) { /* MOC - not supported */ - v1 = ReadW6692(card, W_MOSR); - pr_debug("%s: spurious MOC interrupt MOSR %02x\n", - card->name, v1); - } - if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ - cir = ReadW6692(card, W_CIR); - pr_debug("%s: ISC CIR %02X\n", card->name, cir); - if (cir & W_CIR_ICC) { - v1 = cir & W_CIR_COD_MASK; - pr_debug("%s: ph_state_change %x -> %x\n", card->name, - dch->state, v1); - card->state = v1; - if (card->fmask & led) { - switch (v1) { - case W_L1IND_AI8: - case W_L1IND_AI10: - w6692_led_handler(card, 1); - break; - default: - w6692_led_handler(card, 0); - break; - } - } - W6692_new_ph(card); - } - if (cir & W_CIR_SCC) { - v1 = ReadW6692(card, W_SQR); - pr_debug("%s: SCC SQR %02X\n", card->name, v1); - } - } - if (exval & W_D_EXI_WEXP) - pr_debug("%s: spurious WEXP interrupt!\n", card->name); - if (exval & W_D_EXI_TEXP) - pr_debug("%s: spurious TEXP interrupt!\n", card->name); -} - -static void -W6692_empty_Bfifo(struct w6692_ch *wch, int count) -{ - struct w6692_hw *card = wch->bch.hw; - u8 *ptr; - int maxlen; - - pr_debug("%s: empty_Bfifo %d\n", card->name, count); - if (unlikely(wch->bch.state == ISDN_P_NONE)) { - pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - if (wch->bch.rx_skb) - skb_trim(wch->bch.rx_skb, 0); - return; - } - if (test_bit(FLG_RX_OFF, &wch->bch.Flags)) { - wch->bch.dropcnt += count; - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - return; - } - maxlen = bchannel_get_rxbuf(&wch->bch, count); - if (maxlen < 0) { - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - if (wch->bch.rx_skb) - skb_trim(wch->bch.rx_skb, 0); - pr_warn("%s.B%d: No bufferspace for %d bytes\n", - card->name, wch->bch.nr, count); - return; - } - ptr = skb_put(wch->bch.rx_skb, count); - insb(wch->addr + W_B_RFIFO, ptr, count); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - if (debug & DEBUG_HW_DFIFO) { - snprintf(card->log, 63, "B%1d-recv %s %d ", - wch->bch.nr, card->name, count); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); - } -} - -static void -W6692_fill_Bfifo(struct w6692_ch *wch) -{ - struct w6692_hw *card = wch->bch.hw; - int count, fillempty = 0; - u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; - - pr_debug("%s: fill Bfifo\n", card->name); - if (!wch->bch.tx_skb) { - if (!test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) - return; - ptr = wch->bch.fill; - count = W_B_FIFO_THRESH; - fillempty = 1; - } else { - count = wch->bch.tx_skb->len - wch->bch.tx_idx; - if (count <= 0) - return; - ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; - } - if (count > W_B_FIFO_THRESH) - count = W_B_FIFO_THRESH; - else if (test_bit(FLG_HDLC, &wch->bch.Flags)) - cmd |= W_B_CMDR_XME; - - pr_debug("%s: fill Bfifo%d/%d\n", card->name, - count, wch->bch.tx_idx); - wch->bch.tx_idx += count; - if (fillempty) { - while (count > 0) { - outsb(wch->addr + W_B_XFIFO, ptr, MISDN_BCH_FILL_SIZE); - count -= MISDN_BCH_FILL_SIZE; - } - } else { - outsb(wch->addr + W_B_XFIFO, ptr, count); - } - WriteW6692B(wch, W_B_CMDR, cmd); - if ((debug & DEBUG_HW_BFIFO) && !fillempty) { - snprintf(card->log, 63, "B%1d-send %s %d ", - wch->bch.nr, card->name, count); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); - } -} - -#if 0 -static int -setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb) -{ - struct w6692_hw *card = wch->bch.hw; - u16 *vol = (u16 *)skb->data; - u8 val; - - if ((!(card->fmask & pots)) || - !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) - return -ENODEV; - if (skb->len < 2) - return -EINVAL; - if (*vol > 7) - return -EINVAL; - val = *vol & 7; - val = 7 - val; - if (mic) { - val <<= 3; - card->xaddr &= 0xc7; - } else { - card->xaddr &= 0xf8; - } - card->xaddr |= val; - WriteW6692(card, W_XADDR, card->xaddr); - return 0; -} - -static int -enable_pots(struct w6692_ch *wch) -{ - struct w6692_hw *card = wch->bch.hw; - - if ((!(card->fmask & pots)) || - !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) - return -ENODEV; - wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0; - WriteW6692B(wch, W_B_MODE, wch->b_mode); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); - card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0); - WriteW6692(card, W_PCTL, card->pctl); - return 0; -} -#endif - -static int -disable_pots(struct w6692_ch *wch) -{ - struct w6692_hw *card = wch->bch.hw; - - if (!(card->fmask & pots)) - return -ENODEV; - wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0); - WriteW6692B(wch, W_B_MODE, wch->b_mode); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | - W_B_CMDR_XRST); - return 0; -} - -static int -w6692_mode(struct w6692_ch *wch, u32 pr) -{ - struct w6692_hw *card; - - card = wch->bch.hw; - pr_debug("%s: B%d protocol %x-->%x\n", card->name, - wch->bch.nr, wch->bch.state, pr); - switch (pr) { - case ISDN_P_NONE: - if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM)) - disable_pots(wch); - wch->b_mode = 0; - mISDN_clear_bchannel(&wch->bch); - WriteW6692B(wch, W_B_MODE, wch->b_mode); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); - test_and_clear_bit(FLG_HDLC, &wch->bch.Flags); - test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags); - break; - case ISDN_P_B_RAW: - wch->b_mode = W_B_MODE_MMS; - WriteW6692B(wch, W_B_MODE, wch->b_mode); - WriteW6692B(wch, W_B_EXIM, 0); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | - W_B_CMDR_XRST); - test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags); - break; - case ISDN_P_B_HDLC: - wch->b_mode = W_B_MODE_ITF; - WriteW6692B(wch, W_B_MODE, wch->b_mode); - WriteW6692B(wch, W_B_ADM1, 0xff); - WriteW6692B(wch, W_B_ADM2, 0xff); - WriteW6692B(wch, W_B_EXIM, 0); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | - W_B_CMDR_XRST); - test_and_set_bit(FLG_HDLC, &wch->bch.Flags); - break; - default: - pr_info("%s: protocol %x not known\n", card->name, pr); - return -ENOPROTOOPT; - } - wch->bch.state = pr; - return 0; -} - -static void -send_next(struct w6692_ch *wch) -{ - if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) { - W6692_fill_Bfifo(wch); - } else { - dev_kfree_skb(wch->bch.tx_skb); - if (get_next_bframe(&wch->bch)) { - W6692_fill_Bfifo(wch); - test_and_clear_bit(FLG_TX_EMPTY, &wch->bch.Flags); - } else if (test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) { - W6692_fill_Bfifo(wch); - } - } -} - -static void -W6692B_interrupt(struct w6692_hw *card, int ch) -{ - struct w6692_ch *wch = &card->bc[ch]; - int count; - u8 stat, star = 0; - - stat = ReadW6692B(wch, W_B_EXIR); - pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat); - if (stat & W_B_EXI_RME) { - star = ReadW6692B(wch, W_B_STAR); - if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { - if ((star & W_B_STAR_RDOV) && - test_bit(FLG_ACTIVE, &wch->bch.Flags)) { - pr_debug("%s: B%d RDOV proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); -#ifdef ERROR_STATISTIC - wch->bch.err_rdo++; -#endif - } - if (test_bit(FLG_HDLC, &wch->bch.Flags)) { - if (star & W_B_STAR_CRCE) { - pr_debug("%s: B%d CRC error\n", - card->name, wch->bch.nr); -#ifdef ERROR_STATISTIC - wch->bch.err_crc++; -#endif - } - if (star & W_B_STAR_RMB) { - pr_debug("%s: B%d message abort\n", - card->name, wch->bch.nr); -#ifdef ERROR_STATISTIC - wch->bch.err_inv++; -#endif - } - } - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | - W_B_CMDR_RRST | W_B_CMDR_RACT); - if (wch->bch.rx_skb) - skb_trim(wch->bch.rx_skb, 0); - } else { - count = ReadW6692B(wch, W_B_RBCL) & - (W_B_FIFO_THRESH - 1); - if (count == 0) - count = W_B_FIFO_THRESH; - W6692_empty_Bfifo(wch, count); - recv_Bchannel(&wch->bch, 0, false); - } - } - if (stat & W_B_EXI_RMR) { - if (!(stat & W_B_EXI_RME)) - star = ReadW6692B(wch, W_B_STAR); - if (star & W_B_STAR_RDOV) { - pr_debug("%s: B%d RDOV proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); -#ifdef ERROR_STATISTIC - wch->bch.err_rdo++; -#endif - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | - W_B_CMDR_RRST | W_B_CMDR_RACT); - } else { - W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); - if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) - recv_Bchannel(&wch->bch, 0, false); - } - } - if (stat & W_B_EXI_RDOV) { - /* only if it is not handled yet */ - if (!(star & W_B_STAR_RDOV)) { - pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); -#ifdef ERROR_STATISTIC - wch->bch.err_rdo++; -#endif - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | - W_B_CMDR_RRST | W_B_CMDR_RACT); - } - } - if (stat & W_B_EXI_XFR) { - if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) { - star = ReadW6692B(wch, W_B_STAR); - pr_debug("%s: B%d star %02x\n", card->name, - wch->bch.nr, star); - } - if (star & W_B_STAR_XDOW) { - pr_warn("%s: B%d XDOW proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); -#ifdef ERROR_STATISTIC - wch->bch.err_xdu++; -#endif - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | - W_B_CMDR_RACT); - /* resend */ - if (wch->bch.tx_skb) { - if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) - wch->bch.tx_idx = 0; - } - } - send_next(wch); - if (star & W_B_STAR_XDOW) - return; /* handle XDOW only once */ - } - if (stat & W_B_EXI_XDUN) { - pr_warn("%s: B%d XDUN proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); -#ifdef ERROR_STATISTIC - wch->bch.err_xdu++; -#endif - /* resend - no XRST needed */ - if (wch->bch.tx_skb) { - if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) - wch->bch.tx_idx = 0; - } else if (test_bit(FLG_FILLEMPTY, &wch->bch.Flags)) { - test_and_set_bit(FLG_TX_EMPTY, &wch->bch.Flags); - } - send_next(wch); - } -} - -static irqreturn_t -w6692_irq(int intno, void *dev_id) -{ - struct w6692_hw *card = dev_id; - u8 ista; - - spin_lock(&card->lock); - ista = ReadW6692(card, W_ISTA); - if ((ista | card->imask) == card->imask) { - /* possible a shared IRQ reqest */ - spin_unlock(&card->lock); - return IRQ_NONE; - } - card->irqcnt++; - pr_debug("%s: ista %02x\n", card->name, ista); - ista &= ~card->imask; - if (ista & W_INT_B1_EXI) - W6692B_interrupt(card, 0); - if (ista & W_INT_B2_EXI) - W6692B_interrupt(card, 1); - if (ista & W_INT_D_RME) - handle_rxD(card); - if (ista & W_INT_D_RMR) - W6692_empty_Dfifo(card, W_D_FIFO_THRESH); - if (ista & W_INT_D_XFR) - handle_txD(card); - if (ista & W_INT_D_EXI) - handle_statusD(card); - if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */ - pr_debug("%s: W6692 spurious XINT!\n", card->name); -/* End IRQ Handler */ - spin_unlock(&card->lock); - return IRQ_HANDLED; -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct dchannel *dch = timer_container_of(dch, t, timer); - struct w6692_hw *card = dch->hw; - int rbch, star; - u_long flags; - - if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) { - spin_lock_irqsave(&card->lock, flags); - rbch = ReadW6692(card, W_D_RBCH); - star = ReadW6692(card, W_D_STAR); - pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", - card->name, rbch, star); - if (star & W_D_STAR_XBZ) /* D-Channel Busy */ - test_and_set_bit(FLG_L1_BUSY, &dch->Flags); - else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags); - if (dch->tx_idx) - dch->tx_idx = 0; - else - pr_info("%s: W6692 D-Channel Busy no tx_idx\n", - card->name); - /* Transmitter reset */ - WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST); - } - spin_unlock_irqrestore(&card->lock, flags); - } -} - -static void initW6692(struct w6692_hw *card) -{ - u8 val; - - timer_setup(&card->dch.timer, dbusy_timer_handler, 0); - w6692_mode(&card->bc[0], ISDN_P_NONE); - w6692_mode(&card->bc[1], ISDN_P_NONE); - WriteW6692(card, W_D_CTL, 0x00); - disable_hwirq(card); - WriteW6692(card, W_D_SAM, 0xff); - WriteW6692(card, W_D_TAM, 0xff); - WriteW6692(card, W_D_MODE, W_D_MODE_RACT); - card->state = W_L1CMD_RST; - ph_command(card, W_L1CMD_RST); - ph_command(card, W_L1CMD_ECK); - /* enable all IRQ but extern */ - card->imask = 0x18; - WriteW6692(card, W_D_EXIM, 0x00); - WriteW6692B(&card->bc[0], W_B_EXIM, 0); - WriteW6692B(&card->bc[1], W_B_EXIM, 0); - /* Reset D-chan receiver and transmitter */ - WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); - /* Reset B-chan receiver and transmitter */ - WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); - WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); - /* enable peripheral */ - if (card->subtype == W6692_USR) { - /* seems that USR implemented some power control features - * Pin 79 is connected to the oscilator circuit so we - * have to handle it here - */ - card->pctl = 0x80; - card->xdata = 0; - WriteW6692(card, W_PCTL, card->pctl); - WriteW6692(card, W_XDATA, card->xdata); - } else { - card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | - W_PCTL_OE1 | W_PCTL_OE0; - card->xaddr = 0x00;/* all sw off */ - if (card->fmask & pots) - card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */ - if (card->fmask & led) - card->xdata |= 0x04; /* LED OFF */ - if ((card->fmask & pots) || (card->fmask & led)) { - WriteW6692(card, W_PCTL, card->pctl); - WriteW6692(card, W_XADDR, card->xaddr); - WriteW6692(card, W_XDATA, card->xdata); - val = ReadW6692(card, W_XADDR); - if (debug & DEBUG_HW) - pr_notice("%s: W_XADDR=%02x\n", - card->name, val); - } - } -} - -static void -reset_w6692(struct w6692_hw *card) -{ - WriteW6692(card, W_D_CTL, W_D_CTL_SRST); - mdelay(10); - WriteW6692(card, W_D_CTL, 0); -} - -static int -init_card(struct w6692_hw *card) -{ - int cnt = 3; - u_long flags; - - spin_lock_irqsave(&card->lock, flags); - disable_hwirq(card); - spin_unlock_irqrestore(&card->lock, flags); - if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) { - pr_info("%s: couldn't get interrupt %d\n", card->name, - card->irq); - return -EIO; - } - while (cnt--) { - spin_lock_irqsave(&card->lock, flags); - initW6692(card); - enable_hwirq(card); - spin_unlock_irqrestore(&card->lock, flags); - /* Timeout 10ms */ - msleep_interruptible(10); - if (debug & DEBUG_HW) - pr_notice("%s: IRQ %d count %d\n", card->name, - card->irq, card->irqcnt); - if (!card->irqcnt) { - pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", - card->name, card->irq, 3 - cnt); - reset_w6692(card); - } else - return 0; - } - free_irq(card->irq, card); - return -EIO; -} - -static int -w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); - struct w6692_hw *card = bch->hw; - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(&card->lock, flags); - ret = bchannel_senddata(bch, skb); - if (ret > 0) { /* direct TX */ - ret = 0; - W6692_fill_Bfifo(bc); - } - spin_unlock_irqrestore(&card->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - spin_lock_irqsave(&card->lock, flags); - if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) - ret = w6692_mode(bc, ch->protocol); - else - ret = 0; - spin_unlock_irqrestore(&card->lock, flags); - if (!ret) - _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - break; - case PH_DEACTIVATE_REQ: - spin_lock_irqsave(&card->lock, flags); - mISDN_clear_bchannel(bch); - w6692_mode(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - ret = 0; - break; - default: - pr_info("%s: %s unknown prim(%x,%x)\n", - card->name, __func__, hh->prim, hh->id); - ret = -EINVAL; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - return mISDN_ctrl_bchannel(bch, cq); -} - -static int -open_bchannel(struct w6692_hw *card, struct channel_req *rq) -{ - struct bchannel *bch; - - if (rq->adr.channel == 0 || rq->adr.channel > 2) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - bch = &card->bc[rq->adr.channel - 1].bch; - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; - return 0; -} - -static int -channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_L1_TIMER3; - break; - case MISDN_CTRL_L1_TIMER3: - ret = l1_event(card->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); - break; - default: - pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); - struct w6692_hw *card = bch->hw; - int ret = -EINVAL; - u_long flags; - - pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - cancel_work_sync(&bch->workq); - spin_lock_irqsave(&card->lock, flags); - mISDN_clear_bchannel(bch); - w6692_mode(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(THIS_MODULE); - ret = 0; - break; - case CONTROL_CHANNEL: - ret = channel_bctrl(bch, arg); - break; - default: - pr_info("%s: %s unknown prim(%x)\n", - card->name, __func__, cmd); - } - return ret; -} - -static int -w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - u32 id; - u_long flags; - - switch (hh->prim) { - case PH_DATA_REQ: - spin_lock_irqsave(&card->lock, flags); - ret = dchannel_senddata(dch, skb); - if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ - W6692_fill_Dfifo(card); - ret = 0; - spin_unlock_irqrestore(&card->lock, flags); - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&card->lock, flags); - return ret; - case PH_ACTIVATE_REQ: - ret = l1_event(dch->l1, hh->prim); - break; - case PH_DEACTIVATE_REQ: - test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); - ret = l1_event(dch->l1, hh->prim); - break; - } - - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -w6692_l1callback(struct dchannel *dch, u32 cmd) -{ - struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); - u_long flags; - - pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state); - switch (cmd) { - case INFO3_P8: - spin_lock_irqsave(&card->lock, flags); - ph_command(card, W_L1CMD_AR8); - spin_unlock_irqrestore(&card->lock, flags); - break; - case INFO3_P10: - spin_lock_irqsave(&card->lock, flags); - ph_command(card, W_L1CMD_AR10); - spin_unlock_irqrestore(&card->lock, flags); - break; - case HW_RESET_REQ: - spin_lock_irqsave(&card->lock, flags); - if (card->state != W_L1IND_DRD) - ph_command(card, W_L1CMD_RST); - ph_command(card, W_L1CMD_ECK); - spin_unlock_irqrestore(&card->lock, flags); - break; - case HW_DEACT_REQ: - skb_queue_purge(&dch->squeue); - if (dch->tx_skb) { - dev_kfree_skb(dch->tx_skb); - dch->tx_skb = NULL; - } - dch->tx_idx = 0; - if (dch->rx_skb) { - dev_kfree_skb(dch->rx_skb); - dch->rx_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) - timer_delete(&dch->timer); - break; - case HW_POWERUP_REQ: - spin_lock_irqsave(&card->lock, flags); - ph_command(card, W_L1CMD_ECK); - spin_unlock_irqrestore(&card->lock, flags); - break; - case PH_ACTIVATE_IND: - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - case PH_DEACTIVATE_IND: - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); - break; - default: - pr_debug("%s: %s unknown command %x\n", card->name, - __func__, cmd); - return -1; - } - return 0; -} - -static int -open_dchannel(struct w6692_hw *card, struct channel_req *rq, void *caller) -{ - pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__, - card->dch.dev.id, caller); - if (rq->protocol != ISDN_P_TE_S0) - return -EINVAL; - if (rq->adr.channel == 1) - /* E-Channel not supported */ - return -EINVAL; - rq->ch = &card->dch.dev.D; - rq->ch->protocol = rq->protocol; - if (card->dch.state == 7) - _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - return 0; -} - -static int -w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); - struct channel_req *rq; - int err = 0; - - pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - if (rq->protocol == ISDN_P_TE_S0) - err = open_dchannel(card, rq, __builtin_return_address(0)); - else - err = open_bchannel(card, rq); - if (err) - break; - if (!try_module_get(THIS_MODULE)) - pr_info("%s: cannot get module\n", card->name); - break; - case CLOSE_CHANNEL: - pr_debug("%s: dev(%d) close from %p\n", card->name, - dch->dev.id, __builtin_return_address(0)); - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - err = channel_ctrl(card, arg); - break; - default: - pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd); - return -EINVAL; - } - return err; -} - -static int -setup_w6692(struct w6692_hw *card) -{ - u32 val; - - if (!request_region(card->addr, 256, card->name)) { - pr_info("%s: config port %x-%x already in use\n", card->name, - card->addr, card->addr + 255); - return -EIO; - } - W6692Version(card); - card->bc[0].addr = card->addr; - card->bc[1].addr = card->addr + 0x40; - val = ReadW6692(card, W_ISTA); - if (debug & DEBUG_HW) - pr_notice("%s ISTA=%02x\n", card->name, val); - val = ReadW6692(card, W_IMASK); - if (debug & DEBUG_HW) - pr_notice("%s IMASK=%02x\n", card->name, val); - val = ReadW6692(card, W_D_EXIR); - if (debug & DEBUG_HW) - pr_notice("%s D_EXIR=%02x\n", card->name, val); - val = ReadW6692(card, W_D_EXIM); - if (debug & DEBUG_HW) - pr_notice("%s D_EXIM=%02x\n", card->name, val); - val = ReadW6692(card, W_D_RSTA); - if (debug & DEBUG_HW) - pr_notice("%s D_RSTA=%02x\n", card->name, val); - return 0; -} - -static void -release_card(struct w6692_hw *card) -{ - u_long flags; - - spin_lock_irqsave(&card->lock, flags); - disable_hwirq(card); - w6692_mode(&card->bc[0], ISDN_P_NONE); - w6692_mode(&card->bc[1], ISDN_P_NONE); - if ((card->fmask & led) || card->subtype == W6692_USR) { - card->xdata |= 0x04; /* LED OFF */ - WriteW6692(card, W_XDATA, card->xdata); - } - spin_unlock_irqrestore(&card->lock, flags); - free_irq(card->irq, card); - l1_event(card->dch.l1, CLOSE_CHANNEL); - mISDN_unregister_device(&card->dch.dev); - release_region(card->addr, 256); - mISDN_freebchannel(&card->bc[1].bch); - mISDN_freebchannel(&card->bc[0].bch); - mISDN_freedchannel(&card->dch); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - pci_disable_device(card->pdev); - pci_set_drvdata(card->pdev, NULL); - kfree(card); -} - -static int -setup_instance(struct w6692_hw *card) -{ - int i, err; - u_long flags; - - snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1); - write_lock_irqsave(&card_lock, flags); - list_add_tail(&card->list, &Cards); - write_unlock_irqrestore(&card_lock, flags); - card->fmask = (1 << w6692_cnt); - _set_debug(card); - spin_lock_init(&card->lock); - mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh); - card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); - card->dch.dev.D.send = w6692_l2l1D; - card->dch.dev.D.ctrl = w6692_dctrl; - card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - card->dch.hw = card; - card->dch.dev.nrbchan = 2; - for (i = 0; i < 2; i++) { - mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, - W_B_FIFO_THRESH); - card->bc[i].bch.hw = card; - card->bc[i].bch.nr = i + 1; - card->bc[i].bch.ch.nr = i + 1; - card->bc[i].bch.ch.send = w6692_l2l1B; - card->bc[i].bch.ch.ctrl = w6692_bctrl; - set_channelmap(i + 1, card->dch.dev.channelmap); - list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels); - } - err = setup_w6692(card); - if (err) - goto error_setup; - err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, - card->name); - if (err) - goto error_reg; - err = init_card(card); - if (err) - goto error_init; - err = create_l1(&card->dch, w6692_l1callback); - if (!err) { - w6692_cnt++; - pr_notice("W6692 %d cards installed\n", w6692_cnt); - return 0; - } - - free_irq(card->irq, card); -error_init: - mISDN_unregister_device(&card->dch.dev); -error_reg: - release_region(card->addr, 256); -error_setup: - mISDN_freebchannel(&card->bc[1].bch); - mISDN_freebchannel(&card->bc[0].bch); - mISDN_freedchannel(&card->dch); - write_lock_irqsave(&card_lock, flags); - list_del(&card->list); - write_unlock_irqrestore(&card_lock, flags); - kfree(card); - return err; -} - -static int -w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - struct w6692_hw *card; - struct w6692map *m = (struct w6692map *)ent->driver_data; - - card = kzalloc_obj(struct w6692_hw); - if (!card) { - pr_info("No kmem for w6692 card\n"); - return err; - } - card->pdev = pdev; - card->subtype = m->subtype; - err = pci_enable_device(pdev); - if (err) { - kfree(card); - return err; - } - - printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n", - m->name, pci_name(pdev)); - - card->addr = pci_resource_start(pdev, 1); - card->irq = pdev->irq; - pci_set_drvdata(pdev, card); - err = setup_instance(card); - if (err) - pci_set_drvdata(pdev, NULL); - return err; -} - -static void -w6692_remove_pci(struct pci_dev *pdev) -{ - struct w6692_hw *card = pci_get_drvdata(pdev); - - if (card) - release_card(card); - else - if (debug) - pr_notice("%s: drvdata already removed\n", __func__); -} - -static const struct pci_device_id w6692_ids[] = { - { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]}, - { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, - PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0, - (ulong)&w6692_map[2]}, - { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]}, - { } -}; -MODULE_DEVICE_TABLE(pci, w6692_ids); - -static struct pci_driver w6692_driver = { - .name = "w6692", - .probe = w6692_probe, - .remove = w6692_remove_pci, - .id_table = w6692_ids, -}; - -static int __init w6692_init(void) -{ - int err; - - pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV); - - err = pci_register_driver(&w6692_driver); - return err; -} - -static void __exit w6692_cleanup(void) -{ - pci_unregister_driver(&w6692_driver); -} - -module_init(w6692_init); -module_exit(w6692_cleanup); diff --git a/drivers/isdn/hardware/mISDN/w6692.h b/drivers/isdn/hardware/mISDN/w6692.h deleted file mode 100644 index 45e1dc5d6c2d..000000000000 --- a/drivers/isdn/hardware/mISDN/w6692.h +++ /dev/null @@ -1,177 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Winbond W6692 specific defines - * - * Author Karsten Keil - * based on the w6692 I4L driver from Petr Novak - * - * Copyright 2009 by Karsten Keil - */ - -/* Specifications of W6692 registers */ - -#define W_D_RFIFO 0x00 /* R */ -#define W_D_XFIFO 0x04 /* W */ -#define W_D_CMDR 0x08 /* W */ -#define W_D_MODE 0x0c /* R/W */ -#define W_D_TIMR 0x10 /* R/W */ -#define W_ISTA 0x14 /* R_clr */ -#define W_IMASK 0x18 /* R/W */ -#define W_D_EXIR 0x1c /* R_clr */ -#define W_D_EXIM 0x20 /* R/W */ -#define W_D_STAR 0x24 /* R */ -#define W_D_RSTA 0x28 /* R */ -#define W_D_SAM 0x2c /* R/W */ -#define W_D_SAP1 0x30 /* R/W */ -#define W_D_SAP2 0x34 /* R/W */ -#define W_D_TAM 0x38 /* R/W */ -#define W_D_TEI1 0x3c /* R/W */ -#define W_D_TEI2 0x40 /* R/W */ -#define W_D_RBCH 0x44 /* R */ -#define W_D_RBCL 0x48 /* R */ -#define W_TIMR2 0x4c /* W */ -#define W_L1_RC 0x50 /* R/W */ -#define W_D_CTL 0x54 /* R/W */ -#define W_CIR 0x58 /* R */ -#define W_CIX 0x5c /* W */ -#define W_SQR 0x60 /* R */ -#define W_SQX 0x64 /* W */ -#define W_PCTL 0x68 /* R/W */ -#define W_MOR 0x6c /* R */ -#define W_MOX 0x70 /* R/W */ -#define W_MOSR 0x74 /* R_clr */ -#define W_MOCR 0x78 /* R/W */ -#define W_GCR 0x7c /* R/W */ - -#define W_B_RFIFO 0x80 /* R */ -#define W_B_XFIFO 0x84 /* W */ -#define W_B_CMDR 0x88 /* W */ -#define W_B_MODE 0x8c /* R/W */ -#define W_B_EXIR 0x90 /* R_clr */ -#define W_B_EXIM 0x94 /* R/W */ -#define W_B_STAR 0x98 /* R */ -#define W_B_ADM1 0x9c /* R/W */ -#define W_B_ADM2 0xa0 /* R/W */ -#define W_B_ADR1 0xa4 /* R/W */ -#define W_B_ADR2 0xa8 /* R/W */ -#define W_B_RBCL 0xac /* R */ -#define W_B_RBCH 0xb0 /* R */ - -#define W_XADDR 0xf4 /* R/W */ -#define W_XDATA 0xf8 /* R/W */ -#define W_EPCTL 0xfc /* W */ - -/* W6692 register bits */ - -#define W_D_CMDR_XRST 0x01 -#define W_D_CMDR_XME 0x02 -#define W_D_CMDR_XMS 0x08 -#define W_D_CMDR_STT 0x10 -#define W_D_CMDR_RRST 0x40 -#define W_D_CMDR_RACK 0x80 - -#define W_D_MODE_RLP 0x01 -#define W_D_MODE_DLP 0x02 -#define W_D_MODE_MFD 0x04 -#define W_D_MODE_TEE 0x08 -#define W_D_MODE_TMS 0x10 -#define W_D_MODE_RACT 0x40 -#define W_D_MODE_MMS 0x80 - -#define W_INT_B2_EXI 0x01 -#define W_INT_B1_EXI 0x02 -#define W_INT_D_EXI 0x04 -#define W_INT_XINT0 0x08 -#define W_INT_XINT1 0x10 -#define W_INT_D_XFR 0x20 -#define W_INT_D_RME 0x40 -#define W_INT_D_RMR 0x80 - -#define W_D_EXI_WEXP 0x01 -#define W_D_EXI_TEXP 0x02 -#define W_D_EXI_ISC 0x04 -#define W_D_EXI_MOC 0x08 -#define W_D_EXI_TIN2 0x10 -#define W_D_EXI_XCOL 0x20 -#define W_D_EXI_XDUN 0x40 -#define W_D_EXI_RDOV 0x80 - -#define W_D_STAR_DRDY 0x10 -#define W_D_STAR_XBZ 0x20 -#define W_D_STAR_XDOW 0x80 - -#define W_D_RSTA_RMB 0x10 -#define W_D_RSTA_CRCE 0x20 -#define W_D_RSTA_RDOV 0x40 - -#define W_D_CTL_SRST 0x20 - -#define W_CIR_SCC 0x80 -#define W_CIR_ICC 0x40 -#define W_CIR_COD_MASK 0x0f - -#define W_PCTL_PCX 0x01 -#define W_PCTL_XMODE 0x02 -#define W_PCTL_OE0 0x04 -#define W_PCTL_OE1 0x08 -#define W_PCTL_OE2 0x10 -#define W_PCTL_OE3 0x20 -#define W_PCTL_OE4 0x40 -#define W_PCTL_OE5 0x80 - -#define W_B_CMDR_XRST 0x01 -#define W_B_CMDR_XME 0x02 -#define W_B_CMDR_XMS 0x04 -#define W_B_CMDR_RACT 0x20 -#define W_B_CMDR_RRST 0x40 -#define W_B_CMDR_RACK 0x80 - -#define W_B_MODE_FTS0 0x01 -#define W_B_MODE_FTS1 0x02 -#define W_B_MODE_SW56 0x04 -#define W_B_MODE_BSW0 0x08 -#define W_B_MODE_BSW1 0x10 -#define W_B_MODE_EPCM 0x20 -#define W_B_MODE_ITF 0x40 -#define W_B_MODE_MMS 0x80 - -#define W_B_EXI_XDUN 0x01 -#define W_B_EXI_XFR 0x02 -#define W_B_EXI_RDOV 0x10 -#define W_B_EXI_RME 0x20 -#define W_B_EXI_RMR 0x40 - -#define W_B_STAR_XBZ 0x01 -#define W_B_STAR_XDOW 0x04 -#define W_B_STAR_RMB 0x10 -#define W_B_STAR_CRCE 0x20 -#define W_B_STAR_RDOV 0x40 - -#define W_B_RBCH_LOV 0x20 - -/* W6692 Layer1 commands */ - -#define W_L1CMD_ECK 0x00 -#define W_L1CMD_RST 0x01 -#define W_L1CMD_SCP 0x04 -#define W_L1CMD_SSP 0x02 -#define W_L1CMD_AR8 0x08 -#define W_L1CMD_AR10 0x09 -#define W_L1CMD_EAL 0x0a -#define W_L1CMD_DRC 0x0f - -/* W6692 Layer1 indications */ - -#define W_L1IND_CE 0x07 -#define W_L1IND_DRD 0x00 -#define W_L1IND_LD 0x04 -#define W_L1IND_ARD 0x08 -#define W_L1IND_TI 0x0a -#define W_L1IND_ATI 0x0b -#define W_L1IND_AI8 0x0c -#define W_L1IND_AI10 0x0d -#define W_L1IND_CD 0x0f - -/* FIFO thresholds */ -#define W_D_FIFO_THRESH 64 -#define W_B_FIFO_THRESH 64 diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig deleted file mode 100644 index c9a53c222472..000000000000 --- a/drivers/isdn/mISDN/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# modularer ISDN driver -# - -menuconfig MISDN - tristate "Modular ISDN driver" - help - Enable support for the modular ISDN driver. - -if MISDN != n - -config MISDN_DSP - tristate "Digital Audio Processing of transparent data" - depends on MISDN - select BITREVERSE - help - Enable support for digital audio processing capability. - - This module may be used for special applications that require - cross connecting of bchannels, conferencing, dtmf decoding, - echo cancellation, tone generation, and Blowfish encryption and - decryption. It may use hardware features if available. - - E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu - and get more information about this module and its usage. - - If unsure, say 'N'. - -config MISDN_L1OIP - tristate "ISDN over IP tunnel" - depends on MISDN - help - Enable support for ISDN over IP tunnel. - - It features: - - dynamic IP exchange, if one or both peers have dynamic IPs - - BRI (S0) and PRI (S2M) interface - - layer 1 control via network keepalive frames - - direct tunneling of physical interface via IP - - NOTE: This protocol is called 'Layer 1 over IP' and is not - compatible with ISDNoIP (Agfeo) or TDMoIP. Protocol description is - provided in the source code. - -source "drivers/isdn/hardware/mISDN/Kconfig" - -endif #MISDN diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile deleted file mode 100644 index f3b4b7fa85f8..000000000000 --- a/drivers/isdn/mISDN/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the modular ISDN driver -# - -obj-$(CONFIG_MISDN) += mISDN_core.o -obj-$(CONFIG_MISDN_DSP) += mISDN_dsp.o -obj-$(CONFIG_MISDN_L1OIP) += l1oip.o - -# multi objects - -mISDN_core-objs := core.o fsm.o socket.o clock.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o -mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o -l1oip-objs := l1oip_core.o l1oip_codec.o diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c deleted file mode 100644 index 2668be9de20a..000000000000 --- a/drivers/isdn/mISDN/clock.c +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2008 by Andreas Eversberg - * - * Quick API description: - * - * A clock source registers using mISDN_register_clock: - * name = text string to name clock source - * priority = value to priorize clock sources (0 = default) - * ctl = callback function to enable/disable clock source - * priv = private pointer of clock source - * return = pointer to clock source structure; - * - * Note: Callback 'ctl' can be called before mISDN_register_clock returns! - * Also it can be called during mISDN_unregister_clock. - * - * A clock source calls mISDN_clock_update with given samples elapsed, if - * enabled. If function call is delayed, tv must be set with the timestamp - * of the actual event. - * - * A clock source unregisters using mISDN_unregister_clock. - * - * To get current clock, call mISDN_clock_get. The signed short value - * counts the number of samples since. Time since last clock event is added. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "core.h" - -static u_int *debug; -static LIST_HEAD(iclock_list); -static DEFINE_RWLOCK(iclock_lock); -static u16 iclock_count; /* counter of last clock */ -static ktime_t iclock_timestamp; /* time stamp of last clock */ -static int iclock_timestamp_valid; /* already received one timestamp */ -static struct mISDNclock *iclock_current; - -void -mISDN_init_clock(u_int *dp) -{ - debug = dp; - iclock_timestamp = ktime_get(); -} - -static void -select_iclock(void) -{ - struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL; - int pri = -128; - - list_for_each_entry(iclock, &iclock_list, list) { - if (iclock->pri > pri) { - pri = iclock->pri; - bestclock = iclock; - } - if (iclock_current == iclock) - lastclock = iclock; - } - if (lastclock && bestclock != lastclock) { - /* last used clock source still exists but changes, disable */ - if (*debug & DEBUG_CLOCK) - printk(KERN_DEBUG "Old clock source '%s' disable.\n", - lastclock->name); - lastclock->ctl(lastclock->priv, 0); - } - if (bestclock && bestclock != iclock_current) { - /* new clock source selected, enable */ - if (*debug & DEBUG_CLOCK) - printk(KERN_DEBUG "New clock source '%s' enable.\n", - bestclock->name); - bestclock->ctl(bestclock->priv, 1); - } - if (bestclock != iclock_current) { - /* no clock received yet */ - iclock_timestamp_valid = 0; - } - iclock_current = bestclock; -} - -struct mISDNclock -*mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv) -{ - u_long flags; - struct mISDNclock *iclock; - - if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) - printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri); - iclock = kzalloc_obj(struct mISDNclock, GFP_ATOMIC); - if (!iclock) { - printk(KERN_ERR "%s: No memory for clock entry.\n", __func__); - return NULL; - } - strscpy(iclock->name, name, sizeof(iclock->name)); - iclock->pri = pri; - iclock->priv = priv; - iclock->ctl = ctl; - write_lock_irqsave(&iclock_lock, flags); - list_add_tail(&iclock->list, &iclock_list); - select_iclock(); - write_unlock_irqrestore(&iclock_lock, flags); - return iclock; -} -EXPORT_SYMBOL(mISDN_register_clock); - -void -mISDN_unregister_clock(struct mISDNclock *iclock) -{ - u_long flags; - - if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) - printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name, - iclock->pri); - write_lock_irqsave(&iclock_lock, flags); - if (iclock_current == iclock) { - if (*debug & DEBUG_CLOCK) - printk(KERN_DEBUG - "Current clock source '%s' unregisters.\n", - iclock->name); - iclock->ctl(iclock->priv, 0); - } - list_del(&iclock->list); - select_iclock(); - write_unlock_irqrestore(&iclock_lock, flags); -} -EXPORT_SYMBOL(mISDN_unregister_clock); - -void -mISDN_clock_update(struct mISDNclock *iclock, int samples, ktime_t *timestamp) -{ - u_long flags; - ktime_t timestamp_now; - u16 delta; - - write_lock_irqsave(&iclock_lock, flags); - if (iclock_current != iclock) { - printk(KERN_ERR "%s: '%s' sends us clock updates, but we do " - "listen to '%s'. This is a bug!\n", __func__, - iclock->name, - iclock_current ? iclock_current->name : "nothing"); - iclock->ctl(iclock->priv, 0); - write_unlock_irqrestore(&iclock_lock, flags); - return; - } - if (iclock_timestamp_valid) { - /* increment sample counter by given samples */ - iclock_count += samples; - if (timestamp) { /* timestamp must be set, if function call is delayed */ - iclock_timestamp = *timestamp; - } else { - iclock_timestamp = ktime_get(); - } - } else { - /* calc elapsed time by system clock */ - if (timestamp) { /* timestamp must be set, if function call is delayed */ - timestamp_now = *timestamp; - } else { - timestamp_now = ktime_get(); - } - delta = ktime_divns(ktime_sub(timestamp_now, iclock_timestamp), - (NSEC_PER_SEC / 8000)); - /* add elapsed time to counter and set new timestamp */ - iclock_count += delta; - iclock_timestamp = timestamp_now; - iclock_timestamp_valid = 1; - if (*debug & DEBUG_CLOCK) - printk("Received first clock from source '%s'.\n", - iclock_current ? iclock_current->name : "nothing"); - } - write_unlock_irqrestore(&iclock_lock, flags); -} -EXPORT_SYMBOL(mISDN_clock_update); - -unsigned short -mISDN_clock_get(void) -{ - u_long flags; - ktime_t timestamp_now; - u16 delta; - u16 count; - - read_lock_irqsave(&iclock_lock, flags); - /* calc elapsed time by system clock */ - timestamp_now = ktime_get(); - delta = ktime_divns(ktime_sub(timestamp_now, iclock_timestamp), - (NSEC_PER_SEC / 8000)); - /* add elapsed time to counter */ - count = iclock_count + delta; - read_unlock_irqrestore(&iclock_lock, flags); - return count; -} -EXPORT_SYMBOL(mISDN_clock_get); diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c deleted file mode 100644 index 8ec2d4d4f135..000000000000 --- a/drivers/isdn/mISDN/core.c +++ /dev/null @@ -1,400 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include -#include -#include -#include -#include "core.h" - -static u_int debug; - -MODULE_AUTHOR("Karsten Keil"); -MODULE_DESCRIPTION("Modular ISDN core driver"); -MODULE_LICENSE("GPL"); -module_param(debug, uint, S_IRUGO | S_IWUSR); - -static u64 device_ids; -#define MAX_DEVICE_ID 63 - -static LIST_HEAD(Bprotocols); -static DEFINE_RWLOCK(bp_lock); - -static void mISDN_dev_release(struct device *dev) -{ - /* nothing to do: the device is part of its parent's data structure */ -} - -static ssize_t id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mISDNdevice *mdev = dev_to_mISDN(dev); - - if (!mdev) - return -ENODEV; - return sprintf(buf, "%d\n", mdev->id); -} -static DEVICE_ATTR_RO(id); - -static ssize_t nrbchan_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mISDNdevice *mdev = dev_to_mISDN(dev); - - if (!mdev) - return -ENODEV; - return sprintf(buf, "%d\n", mdev->nrbchan); -} -static DEVICE_ATTR_RO(nrbchan); - -static ssize_t d_protocols_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mISDNdevice *mdev = dev_to_mISDN(dev); - - if (!mdev) - return -ENODEV; - return sprintf(buf, "%d\n", mdev->Dprotocols); -} -static DEVICE_ATTR_RO(d_protocols); - -static ssize_t b_protocols_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mISDNdevice *mdev = dev_to_mISDN(dev); - - if (!mdev) - return -ENODEV; - return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols()); -} -static DEVICE_ATTR_RO(b_protocols); - -static ssize_t protocol_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mISDNdevice *mdev = dev_to_mISDN(dev); - - if (!mdev) - return -ENODEV; - return sprintf(buf, "%d\n", mdev->D.protocol); -} -static DEVICE_ATTR_RO(protocol); - -static ssize_t name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - strcpy(buf, dev_name(dev)); - return strlen(buf); -} -static DEVICE_ATTR_RO(name); - -#if 0 /* hangs */ -static ssize_t name_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int err = 0; - char *out = kmalloc(count + 1, GFP_KERNEL); - - if (!out) - return -ENOMEM; - - memcpy(out, buf, count); - if (count && out[count - 1] == '\n') - out[--count] = 0; - if (count) - err = device_rename(dev, out); - kfree(out); - - return (err < 0) ? err : count; -} -static DEVICE_ATTR_RW(name); -#endif - -static ssize_t channelmap_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mISDNdevice *mdev = dev_to_mISDN(dev); - char *bp = buf; - int i; - - for (i = 0; i <= mdev->nrbchan; i++) - *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0'; - - return bp - buf; -} -static DEVICE_ATTR_RO(channelmap); - -static struct attribute *mISDN_attrs[] = { - &dev_attr_id.attr, - &dev_attr_d_protocols.attr, - &dev_attr_b_protocols.attr, - &dev_attr_protocol.attr, - &dev_attr_channelmap.attr, - &dev_attr_nrbchan.attr, - &dev_attr_name.attr, - NULL, -}; -ATTRIBUTE_GROUPS(mISDN); - -static int mISDN_uevent(const struct device *dev, struct kobj_uevent_env *env) -{ - const struct mISDNdevice *mdev = dev_to_mISDN(dev); - - if (!mdev) - return 0; - - if (add_uevent_var(env, "nchans=%d", mdev->nrbchan)) - return -ENOMEM; - - return 0; -} - -static struct class mISDN_class = { - .name = "mISDN", - .dev_uevent = mISDN_uevent, - .dev_groups = mISDN_groups, - .dev_release = mISDN_dev_release, -}; - -static int -_get_mdevice(struct device *dev, const void *id) -{ - struct mISDNdevice *mdev = dev_to_mISDN(dev); - - if (!mdev) - return 0; - if (mdev->id != *(const u_int *)id) - return 0; - return 1; -} - -struct mISDNdevice -*get_mdevice(u_int id) -{ - return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id, - _get_mdevice)); -} - -static int -_get_mdevice_count(struct device *dev, void *cnt) -{ - *(int *)cnt += 1; - return 0; -} - -int -get_mdevice_count(void) -{ - int cnt = 0; - - class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count); - return cnt; -} - -static int -get_free_devid(void) -{ - u_int i; - - for (i = 0; i <= MAX_DEVICE_ID; i++) - if (!test_and_set_bit(i, (u_long *)&device_ids)) - break; - if (i > MAX_DEVICE_ID) - return -EBUSY; - return i; -} - -int -mISDN_register_device(struct mISDNdevice *dev, - struct device *parent, char *name) -{ - int err; - - err = get_free_devid(); - if (err < 0) - return err; - dev->id = err; - - device_initialize(&dev->dev); - if (name && name[0]) - dev_set_name(&dev->dev, "%s", name); - else - dev_set_name(&dev->dev, "mISDN%d", dev->id); - if (debug & DEBUG_CORE) - printk(KERN_DEBUG "mISDN_register %s %d\n", - dev_name(&dev->dev), dev->id); - dev->dev.class = &mISDN_class; - - err = create_stack(dev); - if (err) - goto error1; - - dev->dev.platform_data = dev; - dev->dev.parent = parent; - dev_set_drvdata(&dev->dev, dev); - - err = device_add(&dev->dev); - if (err) - goto error3; - return 0; - -error3: - delete_stack(dev); -error1: - put_device(&dev->dev); - return err; - -} -EXPORT_SYMBOL(mISDN_register_device); - -void -mISDN_unregister_device(struct mISDNdevice *dev) { - if (debug & DEBUG_CORE) - printk(KERN_DEBUG "mISDN_unregister %s %d\n", - dev_name(&dev->dev), dev->id); - /* sysfs_remove_link(&dev->dev.kobj, "device"); */ - device_del(&dev->dev); - dev_set_drvdata(&dev->dev, NULL); - - test_and_clear_bit(dev->id, (u_long *)&device_ids); - delete_stack(dev); - put_device(&dev->dev); -} -EXPORT_SYMBOL(mISDN_unregister_device); - -u_int -get_all_Bprotocols(void) -{ - struct Bprotocol *bp; - u_int m = 0; - - read_lock(&bp_lock); - list_for_each_entry(bp, &Bprotocols, list) - m |= bp->Bprotocols; - read_unlock(&bp_lock); - return m; -} - -struct Bprotocol * -get_Bprotocol4mask(u_int m) -{ - struct Bprotocol *bp; - - read_lock(&bp_lock); - list_for_each_entry(bp, &Bprotocols, list) - if (bp->Bprotocols & m) { - read_unlock(&bp_lock); - return bp; - } - read_unlock(&bp_lock); - return NULL; -} - -int -mISDN_register_Bprotocol(struct Bprotocol *bp) -{ - u_long flags; - struct Bprotocol *old; - - if (debug & DEBUG_CORE) - printk(KERN_DEBUG "%s: %s/%x\n", __func__, - bp->name, bp->Bprotocols); - old = get_Bprotocol4mask(bp->Bprotocols); - if (old) { - printk(KERN_WARNING - "register duplicate protocol old %s/%x new %s/%x\n", - old->name, old->Bprotocols, bp->name, bp->Bprotocols); - return -EBUSY; - } - write_lock_irqsave(&bp_lock, flags); - list_add_tail(&bp->list, &Bprotocols); - write_unlock_irqrestore(&bp_lock, flags); - return 0; -} -EXPORT_SYMBOL(mISDN_register_Bprotocol); - -void -mISDN_unregister_Bprotocol(struct Bprotocol *bp) -{ - u_long flags; - - if (debug & DEBUG_CORE) - printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name, - bp->Bprotocols); - write_lock_irqsave(&bp_lock, flags); - list_del(&bp->list); - write_unlock_irqrestore(&bp_lock, flags); -} -EXPORT_SYMBOL(mISDN_unregister_Bprotocol); - -static const char *msg_no_channel = ""; -static const char *msg_no_stack = ""; -static const char *msg_no_stackdev = ""; - -const char *mISDNDevName4ch(struct mISDNchannel *ch) -{ - if (!ch) - return msg_no_channel; - if (!ch->st) - return msg_no_stack; - if (!ch->st->dev) - return msg_no_stackdev; - return dev_name(&ch->st->dev->dev); -}; -EXPORT_SYMBOL(mISDNDevName4ch); - -static int -mISDNInit(void) -{ - int err; - - printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", - MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); - mISDN_init_clock(&debug); - mISDN_initstack(&debug); - err = class_register(&mISDN_class); - if (err) - goto error1; - err = mISDN_inittimer(&debug); - if (err) - goto error2; - err = Isdnl1_Init(&debug); - if (err) - goto error3; - err = Isdnl2_Init(&debug); - if (err) - goto error4; - err = misdn_sock_init(&debug); - if (err) - goto error5; - return 0; - -error5: - Isdnl2_cleanup(); -error4: - Isdnl1_cleanup(); -error3: - mISDN_timer_cleanup(); -error2: - class_unregister(&mISDN_class); -error1: - return err; -} - -static void mISDN_cleanup(void) -{ - misdn_sock_cleanup(); - Isdnl2_cleanup(); - Isdnl1_cleanup(); - mISDN_timer_cleanup(); - class_unregister(&mISDN_class); - - printk(KERN_DEBUG "mISDNcore unloaded\n"); -} - -module_init(mISDNInit); -module_exit(mISDN_cleanup); diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h deleted file mode 100644 index 5617c06de8e4..000000000000 --- a/drivers/isdn/mISDN/core.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright 2008 by Karsten Keil - */ - -#ifndef mISDN_CORE_H -#define mISDN_CORE_H - -extern struct mISDNdevice *get_mdevice(u_int); -extern int get_mdevice_count(void); - -/* stack status flag */ -#define mISDN_STACK_ACTION_MASK 0x0000ffff -#define mISDN_STACK_COMMAND_MASK 0x000f0000 -#define mISDN_STACK_STATUS_MASK 0xfff00000 -/* action bits 0-15 */ -#define mISDN_STACK_WORK 0 -#define mISDN_STACK_SETUP 1 -#define mISDN_STACK_CLEARING 2 -#define mISDN_STACK_RESTART 3 -#define mISDN_STACK_WAKEUP 4 -#define mISDN_STACK_ABORT 15 -/* command bits 16-19 */ -#define mISDN_STACK_STOPPED 16 -#define mISDN_STACK_INIT 17 -#define mISDN_STACK_THREADSTART 18 -/* status bits 20-31 */ -#define mISDN_STACK_BCHANNEL 20 -#define mISDN_STACK_ACTIVE 29 -#define mISDN_STACK_RUNNING 30 -#define mISDN_STACK_KILLED 31 - - -/* manager options */ -#define MGR_OPT_USER 24 -#define MGR_OPT_NETWORK 25 - -extern int connect_Bstack(struct mISDNdevice *, struct mISDNchannel *, - u_int, struct sockaddr_mISDN *); -extern int connect_layer1(struct mISDNdevice *, struct mISDNchannel *, - u_int, struct sockaddr_mISDN *); -extern int create_l2entity(struct mISDNdevice *, struct mISDNchannel *, - u_int, struct sockaddr_mISDN *); - -extern int create_stack(struct mISDNdevice *); -extern int create_teimanager(struct mISDNdevice *); -extern void delete_teimanager(struct mISDNchannel *); -extern void delete_channel(struct mISDNchannel *); -extern void delete_stack(struct mISDNdevice *); -extern void mISDN_initstack(u_int *); -extern int misdn_sock_init(u_int *); -extern void misdn_sock_cleanup(void); -extern void add_layer2(struct mISDNchannel *, struct mISDNstack *); -extern void __add_layer2(struct mISDNchannel *, struct mISDNstack *); - -extern u_int get_all_Bprotocols(void); -struct Bprotocol *get_Bprotocol4mask(u_int); - -extern int mISDN_inittimer(u_int *); -extern void mISDN_timer_cleanup(void); - -extern int Isdnl1_Init(u_int *); -extern void Isdnl1_cleanup(void); -extern int Isdnl2_Init(u_int *); -extern void Isdnl2_cleanup(void); - -extern void mISDN_init_clock(u_int *); - -#endif diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h deleted file mode 100644 index baf31258f5c9..000000000000 --- a/drivers/isdn/mISDN/dsp.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Audio support data for ISDN4Linux. - * - * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define DEBUG_DSP_CTRL 0x0001 -#define DEBUG_DSP_CORE 0x0002 -#define DEBUG_DSP_DTMF 0x0004 -#define DEBUG_DSP_CMX 0x0010 -#define DEBUG_DSP_TONE 0x0020 -#define DEBUG_DSP_BLOWFISH 0x0040 -#define DEBUG_DSP_DELAY 0x0100 -#define DEBUG_DSP_CLOCK 0x0200 -#define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */ - -/* options may be: - * - * bit 0 = use ulaw instead of alaw - * bit 1 = enable hfc hardware acceleration for all channels - * - */ -#define DSP_OPT_ULAW (1 << 0) -#define DSP_OPT_NOHARDWARE (1 << 1) - -#include -#include - -#include "dsp_ecdis.h" - -extern int dsp_options; -extern int dsp_debug; -extern int dsp_poll; -extern int dsp_tics; -extern spinlock_t dsp_lock; -extern struct work_struct dsp_workq; -extern u32 dsp_poll_diff; /* calculated fix-comma corrected poll value */ - -/*************** - * audio stuff * - ***************/ - -extern s32 dsp_audio_alaw_to_s32[256]; -extern s32 dsp_audio_ulaw_to_s32[256]; -extern s32 *dsp_audio_law_to_s32; -extern u8 dsp_audio_s16_to_law[65536]; -extern u8 dsp_audio_alaw_to_ulaw[256]; -extern u8 dsp_audio_mix_law[65536]; -extern u8 dsp_audio_seven2law[128]; -extern u8 dsp_audio_law2seven[256]; -extern void dsp_audio_generate_law_tables(void); -extern void dsp_audio_generate_s2law_table(void); -extern void dsp_audio_generate_seven(void); -extern void dsp_audio_generate_mix_table(void); -extern void dsp_audio_generate_ulaw_samples(void); -extern void dsp_audio_generate_volume_changes(void); -extern u8 dsp_silence; - - -/************* - * cmx stuff * - *************/ - -#define MAX_POLL 256 /* maximum number of send-chunks */ - -#define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */ -#define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */ -#define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */ - -/* how many seconds will we check the lowest delay until the jitter buffer - is reduced by that delay */ -#define MAX_SECONDS_JITTER_CHECK 5 - -extern struct timer_list dsp_spl_tl; - -/* the datatype need to match jiffies datatype */ -extern unsigned long dsp_spl_jiffies; - -/* the structure of conferences: - * - * each conference has a unique number, given by user space. - * the conferences are linked in a chain. - * each conference has members linked in a chain. - * each dsplayer points to a member, each member points to a dsplayer. - */ - -/* all members within a conference (this is linked 1:1 with the dsp) */ -struct dsp; -struct dsp_conf_member { - struct list_head list; - struct dsp *dsp; -}; - -/* the list of all conferences */ -struct dsp_conf { - struct list_head list; - u32 id; - /* all cmx stacks with the same ID are - connected */ - struct list_head mlist; - int software; /* conf is processed by software */ - int hardware; /* conf is processed by hardware */ - /* note: if both unset, has only one member */ -}; - - -/************** - * DTMF stuff * - **************/ - -#define DSP_DTMF_NPOINTS 102 - -#define ECHOCAN_BUFF_SIZE 0x400 /* must be 2**n */ -#define ECHOCAN_BUFF_MASK 0x3ff /* -1 */ - -struct dsp_dtmf { - int enable; /* dtmf is enabled */ - int treshold; /* above this is dtmf (square of) */ - int software; /* dtmf uses software decoding */ - int hardware; /* dtmf uses hardware decoding */ - int size; /* number of bytes in buffer */ - signed short buffer[DSP_DTMF_NPOINTS]; - /* buffers one full dtmf frame */ - u8 lastwhat, lastdigit; - int count; - u8 digits[16]; /* dtmf result */ -}; - - -/****************** - * pipeline stuff * - ******************/ -struct dsp_pipeline { - rwlock_t lock; - struct list_head list; - int inuse; -}; - -/*************** - * tones stuff * - ***************/ - -struct dsp_tone { - int software; /* tones are generated by software */ - int hardware; /* tones are generated by hardware */ - int tone; - void *pattern; - int count; - int index; - struct timer_list tl; -}; - -/*************** - * echo stuff * - ***************/ - -struct dsp_echo { - int software; /* echo is generated by software */ - int hardware; /* echo is generated by hardware */ -}; - -/***************** - * general stuff * - *****************/ - -struct dsp { - struct list_head list; - struct mISDNchannel ch; - struct mISDNchannel *up; - unsigned char name[64]; - int b_active; - struct dsp_echo echo; - int rx_disabled; /* what the user wants */ - int rx_is_off; /* what the card is */ - int tx_mix; - struct dsp_tone tone; - struct dsp_dtmf dtmf; - int tx_volume, rx_volume; - - /* queue for sending frames */ - struct work_struct workq; - struct sk_buff_head sendq; - int hdlc; /* if mode is hdlc */ - int data_pending; /* currently an unconfirmed frame */ - - /* conference stuff */ - u32 conf_id; - struct dsp_conf *conf; - struct dsp_conf_member - *member; - - /* buffer stuff */ - int rx_W; /* current write pos for data without timestamp */ - int rx_R; /* current read pos for transmit clock */ - int rx_init; /* if set, pointers will be adjusted first */ - int tx_W; /* current write pos for transmit data */ - int tx_R; /* current read pos for transmit clock */ - int rx_delay[MAX_SECONDS_JITTER_CHECK]; - int tx_delay[MAX_SECONDS_JITTER_CHECK]; - u8 tx_buff[CMX_BUFF_SIZE]; - u8 rx_buff[CMX_BUFF_SIZE]; - int last_tx; /* if set, we transmitted last poll interval */ - int cmx_delay; /* initial delay of buffers, - or 0 for dynamic jitter buffer */ - int tx_dejitter; /* if set, dejitter tx buffer */ - int tx_data; /* enables tx-data of CMX to upper layer */ - - /* hardware stuff */ - struct dsp_features features; - int features_rx_off; /* set if rx_off is featured */ - int features_fill_empty; /* set if fill_empty is featured */ - int pcm_slot_rx; /* current PCM slot (or -1) */ - int pcm_bank_rx; - int pcm_slot_tx; - int pcm_bank_tx; - int hfc_conf; /* unique id of current conference (or -1) */ - - /* encryption stuff */ - int bf_enable; - u32 bf_p[18]; - u32 bf_s[1024]; - int bf_crypt_pos; - u8 bf_data_in[9]; - u8 bf_crypt_out[9]; - int bf_decrypt_in_pos; - int bf_decrypt_out_pos; - u8 bf_crypt_inring[16]; - u8 bf_data_out[9]; - int bf_sync; - - struct dsp_pipeline - pipeline; -}; - -/* functions */ - -extern void dsp_change_volume(struct sk_buff *skb, int volume); - -extern struct list_head dsp_ilist; -extern struct list_head conf_ilist; -extern void dsp_cmx_debug(struct dsp *dsp); -extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp); -extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id); -extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb); -extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb); -extern void dsp_cmx_send(struct timer_list *arg); -extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb); -extern int dsp_cmx_del_conf_member(struct dsp *dsp); -extern int dsp_cmx_del_conf(struct dsp_conf *conf); - -extern void dsp_dtmf_goertzel_init(struct dsp *dsp); -extern void dsp_dtmf_hardware(struct dsp *dsp); -extern u8 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, - int fmt); - -extern int dsp_tone(struct dsp *dsp, int tone); -extern void dsp_tone_copy(struct dsp *dsp, u8 *data, int len); -extern void dsp_tone_timeout(struct timer_list *t); - -extern void dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len); -extern void dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len); -extern int dsp_bf_init(struct dsp *dsp, const u8 *key, unsigned int keylen); -extern void dsp_bf_cleanup(struct dsp *dsp); - -extern int dsp_pipeline_module_init(void); -extern void dsp_pipeline_module_exit(void); -extern int dsp_pipeline_init(struct dsp_pipeline *pipeline); -extern void dsp_pipeline_destroy(struct dsp_pipeline *pipeline); -extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); -extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, - int len); -extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, - int len, unsigned int txlen); diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c deleted file mode 100644 index bbef98e7a16e..000000000000 --- a/drivers/isdn/mISDN/dsp_audio.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Audio support data for mISDN_dsp. - * - * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) - * Rewritten by Peter - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include "core.h" -#include "dsp.h" - -/* ulaw[unsigned char] -> signed 16-bit */ -s32 dsp_audio_ulaw_to_s32[256]; -/* alaw[unsigned char] -> signed 16-bit */ -s32 dsp_audio_alaw_to_s32[256]; - -s32 *dsp_audio_law_to_s32; -EXPORT_SYMBOL(dsp_audio_law_to_s32); - -/* signed 16-bit -> law */ -u8 dsp_audio_s16_to_law[65536]; -EXPORT_SYMBOL(dsp_audio_s16_to_law); - -/* alaw -> ulaw */ -u8 dsp_audio_alaw_to_ulaw[256]; -/* ulaw -> alaw */ -static u8 dsp_audio_ulaw_to_alaw[256]; -u8 dsp_silence; - - -/***************************************************** - * generate table for conversion of s16 to alaw/ulaw * - *****************************************************/ - -#define AMI_MASK 0x55 - -static inline unsigned char linear2alaw(short int linear) -{ - int mask; - int seg; - int pcm_val; - static int seg_end[8] = { - 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF - }; - - pcm_val = linear; - if (pcm_val >= 0) { - /* Sign (7th) bit = 1 */ - mask = AMI_MASK | 0x80; - } else { - /* Sign bit = 0 */ - mask = AMI_MASK; - pcm_val = -pcm_val; - } - - /* Convert the scaled magnitude to segment number. */ - for (seg = 0; seg < 8; seg++) { - if (pcm_val <= seg_end[seg]) - break; - } - /* Combine the sign, segment, and quantization bits. */ - return ((seg << 4) | - ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; -} - - -static inline short int alaw2linear(unsigned char alaw) -{ - int i; - int seg; - - alaw ^= AMI_MASK; - i = ((alaw & 0x0F) << 4) + 8 /* rounding error */; - seg = (((int) alaw & 0x70) >> 4); - if (seg) - i = (i + 0x100) << (seg - 1); - return (short int) ((alaw & 0x80) ? i : -i); -} - -static inline short int ulaw2linear(unsigned char ulaw) -{ - short mu, e, f, y; - static short etab[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764}; - - mu = 255 - ulaw; - e = (mu & 0x70) / 16; - f = mu & 0x0f; - y = f * (1 << (e + 3)); - y += etab[e]; - if (mu & 0x80) - y = -y; - return y; -} - -#define BIAS 0x84 /*!< define the add-in bias for 16 bit samples */ - -static unsigned char linear2ulaw(short sample) -{ - static int exp_lut[256] = { - 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; - int sign, exponent, mantissa; - unsigned char ulawbyte; - - /* Get the sample into sign-magnitude. */ - sign = (sample >> 8) & 0x80; /* set aside the sign */ - if (sign != 0) - sample = -sample; /* get magnitude */ - - /* Convert from 16 bit linear to ulaw. */ - sample = sample + BIAS; - exponent = exp_lut[(sample >> 7) & 0xFF]; - mantissa = (sample >> (exponent + 3)) & 0x0F; - ulawbyte = ~(sign | (exponent << 4) | mantissa); - - return ulawbyte; -} - -void dsp_audio_generate_law_tables(void) -{ - int i; - for (i = 0; i < 256; i++) - dsp_audio_alaw_to_s32[i] = alaw2linear(bitrev8((u8)i)); - - for (i = 0; i < 256; i++) - dsp_audio_ulaw_to_s32[i] = ulaw2linear(bitrev8((u8)i)); - - for (i = 0; i < 256; i++) { - dsp_audio_alaw_to_ulaw[i] = - linear2ulaw(dsp_audio_alaw_to_s32[i]); - dsp_audio_ulaw_to_alaw[i] = - linear2alaw(dsp_audio_ulaw_to_s32[i]); - } -} - -void -dsp_audio_generate_s2law_table(void) -{ - int i; - - if (dsp_options & DSP_OPT_ULAW) { - /* generating ulaw-table */ - for (i = -32768; i < 32768; i++) { - dsp_audio_s16_to_law[i & 0xffff] = - bitrev8(linear2ulaw(i)); - } - } else { - /* generating alaw-table */ - for (i = -32768; i < 32768; i++) { - dsp_audio_s16_to_law[i & 0xffff] = - bitrev8(linear2alaw(i)); - } - } -} - - -/* - * the seven bit sample is the number of every second alaw-sample ordered by - * aplitude. 0x00 is negative, 0x7f is positive amplitude. - */ -u8 dsp_audio_seven2law[128]; -u8 dsp_audio_law2seven[256]; - -/******************************************************************** - * generate table for conversion law from/to 7-bit alaw-like sample * - ********************************************************************/ - -void -dsp_audio_generate_seven(void) -{ - int i, j, k; - u8 spl; - u8 sorted_alaw[256]; - - /* generate alaw table, sorted by the linear value */ - for (i = 0; i < 256; i++) { - j = 0; - for (k = 0; k < 256; k++) { - if (dsp_audio_alaw_to_s32[k] - < dsp_audio_alaw_to_s32[i]) - j++; - } - sorted_alaw[j] = i; - } - - /* generate tabels */ - for (i = 0; i < 256; i++) { - /* spl is the source: the law-sample (converted to alaw) */ - spl = i; - if (dsp_options & DSP_OPT_ULAW) - spl = dsp_audio_ulaw_to_alaw[i]; - /* find the 7-bit-sample */ - for (j = 0; j < 256; j++) { - if (sorted_alaw[j] == spl) - break; - } - /* write 7-bit audio value */ - dsp_audio_law2seven[i] = j >> 1; - } - for (i = 0; i < 128; i++) { - spl = sorted_alaw[i << 1]; - if (dsp_options & DSP_OPT_ULAW) - spl = dsp_audio_alaw_to_ulaw[spl]; - dsp_audio_seven2law[i] = spl; - } -} - - -/* mix 2*law -> law */ -u8 dsp_audio_mix_law[65536]; - -/****************************************************** - * generate mix table to mix two law samples into one * - ******************************************************/ - -void -dsp_audio_generate_mix_table(void) -{ - int i, j; - s32 sample; - - i = 0; - while (i < 256) { - j = 0; - while (j < 256) { - sample = dsp_audio_law_to_s32[i]; - sample += dsp_audio_law_to_s32[j]; - if (sample > 32767) - sample = 32767; - if (sample < -32768) - sample = -32768; - dsp_audio_mix_law[(i << 8) | j] = - dsp_audio_s16_to_law[sample & 0xffff]; - j++; - } - i++; - } -} - - -/************************************* - * generate different volume changes * - *************************************/ - -static u8 dsp_audio_reduce8[256]; -static u8 dsp_audio_reduce7[256]; -static u8 dsp_audio_reduce6[256]; -static u8 dsp_audio_reduce5[256]; -static u8 dsp_audio_reduce4[256]; -static u8 dsp_audio_reduce3[256]; -static u8 dsp_audio_reduce2[256]; -static u8 dsp_audio_reduce1[256]; -static u8 dsp_audio_increase1[256]; -static u8 dsp_audio_increase2[256]; -static u8 dsp_audio_increase3[256]; -static u8 dsp_audio_increase4[256]; -static u8 dsp_audio_increase5[256]; -static u8 dsp_audio_increase6[256]; -static u8 dsp_audio_increase7[256]; -static u8 dsp_audio_increase8[256]; - -static u8 *dsp_audio_volume_change[16] = { - dsp_audio_reduce8, - dsp_audio_reduce7, - dsp_audio_reduce6, - dsp_audio_reduce5, - dsp_audio_reduce4, - dsp_audio_reduce3, - dsp_audio_reduce2, - dsp_audio_reduce1, - dsp_audio_increase1, - dsp_audio_increase2, - dsp_audio_increase3, - dsp_audio_increase4, - dsp_audio_increase5, - dsp_audio_increase6, - dsp_audio_increase7, - dsp_audio_increase8, -}; - -void -dsp_audio_generate_volume_changes(void) -{ - register s32 sample; - int i; - int num[] = { 110, 125, 150, 175, 200, 300, 400, 500 }; - int denum[] = { 100, 100, 100, 100, 100, 100, 100, 100 }; - - i = 0; - while (i < 256) { - dsp_audio_reduce8[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[7] / num[7]) & 0xffff]; - dsp_audio_reduce7[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[6] / num[6]) & 0xffff]; - dsp_audio_reduce6[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[5] / num[5]) & 0xffff]; - dsp_audio_reduce5[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[4] / num[4]) & 0xffff]; - dsp_audio_reduce4[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[3] / num[3]) & 0xffff]; - dsp_audio_reduce3[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[2] / num[2]) & 0xffff]; - dsp_audio_reduce2[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[1] / num[1]) & 0xffff]; - dsp_audio_reduce1[i] = dsp_audio_s16_to_law[ - (dsp_audio_law_to_s32[i] * denum[0] / num[0]) & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[0] / denum[0]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[1] / denum[1]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[2] / denum[2]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[3] / denum[3]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[4] / denum[4]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[5] / denum[5]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[6] / denum[6]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff]; - sample = dsp_audio_law_to_s32[i] * num[7] / denum[7]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff]; - - i++; - } -} - - -/************************************** - * change the volume of the given skb * - **************************************/ - -/* this is a helper function for changing volume of skb. the range may be - * -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8 - */ -void -dsp_change_volume(struct sk_buff *skb, int volume) -{ - u8 *volume_change; - int i, ii; - u8 *p; - int shift; - - if (volume == 0) - return; - - /* get correct conversion table */ - if (volume < 0) { - shift = volume + 8; - if (shift < 0) - shift = 0; - } else { - shift = volume + 7; - if (shift > 15) - shift = 15; - } - volume_change = dsp_audio_volume_change[shift]; - i = 0; - ii = skb->len; - p = skb->data; - /* change volume */ - while (i < ii) { - *p = volume_change[*p]; - p++; - i++; - } -} diff --git a/drivers/isdn/mISDN/dsp_biquad.h b/drivers/isdn/mISDN/dsp_biquad.h deleted file mode 100644 index f40d52a4c4ee..000000000000 --- a/drivers/isdn/mISDN/dsp_biquad.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * SpanDSP - a series of DSP components for telephony - * - * biquad.h - General telephony bi-quad section routines (currently this just - * handles canonic/type 2 form) - * - * Written by Steve Underwood - * - * Copyright (C) 2001 Steve Underwood - * - * All rights reserved. - */ - -struct biquad2_state { - int32_t gain; - int32_t a1; - int32_t a2; - int32_t b1; - int32_t b2; - - int32_t z1; - int32_t z2; -}; - -static inline void biquad2_init(struct biquad2_state *bq, - int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2) -{ - bq->gain = gain; - bq->a1 = a1; - bq->a2 = a2; - bq->b1 = b1; - bq->b2 = b2; - - bq->z1 = 0; - bq->z2 = 0; -} - -static inline int16_t biquad2(struct biquad2_state *bq, int16_t sample) -{ - int32_t y; - int32_t z0; - - z0 = sample * bq->gain + bq->z1 * bq->a1 + bq->z2 * bq->a2; - y = z0 + bq->z1 * bq->b1 + bq->z2 * bq->b2; - - bq->z2 = bq->z1; - bq->z1 = z0 >> 15; - y >>= 15; - return y; -} diff --git a/drivers/isdn/mISDN/dsp_blowfish.c b/drivers/isdn/mISDN/dsp_blowfish.c deleted file mode 100644 index 0e77c282c862..000000000000 --- a/drivers/isdn/mISDN/dsp_blowfish.c +++ /dev/null @@ -1,667 +0,0 @@ -/* - * Blowfish encryption/decryption for mISDN_dsp. - * - * Copyright Andreas Eversberg (jolly@eversberg.eu) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include "core.h" -#include "dsp.h" - -/* - * how to encode a sample stream to 64-bit blocks that will be encryped - * - * first of all, data is collected until a block of 9 samples are received. - * of course, a packet may have much more than 9 sample, but is may have - * not excacly the multiple of 9 samples. if there is a rest, the next - * received data will complete the block. - * - * the block is then converted to 9 uLAW samples without the least sigificant - * bit. the result is a 7-bit encoded sample. - * - * the samples will be reoganised to form 8 bytes of data: - * (5(6) means: encoded sample no. 5, bit 6) - * - * 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) 0(0) 1(6) - * 1(5) 1(4) 1(3) 1(2) 1(1) 1(0) 2(6) 2(5) - * 2(4) 2(3) 2(2) 2(1) 2(0) 3(6) 3(5) 3(4) - * 3(3) 3(2) 3(1) 3(0) 4(6) 4(5) 4(4) 4(3) - * 4(2) 4(1) 4(0) 5(6) 5(5) 5(4) 5(3) 5(2) - * 5(1) 5(0) 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) - * 6(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) - * 8(6) 8(5) 8(4) 8(3) 8(2) 8(1) 8(0) - * - * the missing bit 0 of the last byte is filled with some - * random noise, to fill all 8 bytes. - * - * the 8 bytes will be encrypted using blowfish. - * - * the result will be converted into 9 bytes. the bit 7 is used for - * checksumme (CS) for sync (0, 1) and for the last bit: - * (5(6) means: crypted byte 5, bit 6) - * - * 1 0(7) 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) - * 0 0(0) 1(7) 1(6) 1(5) 1(4) 1(3) 1(2) - * 0 1(1) 1(0) 2(7) 2(6) 2(5) 2(4) 2(3) - * 0 2(2) 2(1) 2(0) 3(7) 3(6) 3(5) 3(4) - * 0 3(3) 3(2) 3(1) 3(0) 4(7) 4(6) 4(5) - * CS 4(4) 4(3) 4(2) 4(1) 4(0) 5(7) 5(6) - * CS 5(5) 5(4) 5(3) 5(2) 5(1) 5(0) 6(7) - * CS 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) 6(0) - * 7(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) - * - * the checksum is used to detect transmission errors and frame drops. - * - * synchronisation of received block is done by shifting the upper bit of each - * byte (bit 7) to a shift register. if the rigister has the first five bits - * (10000), this is used to find the sync. only if sync has been found, the - * current block of 9 received bytes are decrypted. before that the check - * sum is calculated. if it is incorrect the block is dropped. - * this will avoid loud noise due to corrupt encrypted data. - * - * if the last block is corrupt, the current decoded block is repeated - * until a valid block has been received. - */ - -/* - * some blowfish parts are taken from the - * crypto-api for faster implementation - */ - -static const u32 bf_pbox[16 + 2] = { - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, - 0x9216d5d9, 0x8979fb1b, -}; - -static const u32 bf_sbox[256 * 4] = { - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, - 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, - 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, - 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, - 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, - 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, - 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, - 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, - 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, - 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, - 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, - 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, - 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, - 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, - 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, - 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, - 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, - 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, - 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, - 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, - 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, - 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, - 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, - 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, - 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, - 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, - 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, - 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, - 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, - 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, - 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, - 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, - 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, - 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, - 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, - 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, - 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, - 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, - 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, - 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, - 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, - 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, - 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, - 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, - 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, - 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, - 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, - 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, - 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, - 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, - 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, - 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, - 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, - 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, - 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, - 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, - 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, - 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, - 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, - 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, - 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, - 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, - 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, - 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, - 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, - 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, - 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, - 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, - 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, - 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, - 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, - 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, - 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, - 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, - 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, - 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, - 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, - 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, - 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, - 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, - 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, - 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, - 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, - 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, - 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, - 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, - 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, - 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, - 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, - 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, - 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, - 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, - 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, - 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, - 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, - 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, - 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, - 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, - 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, - 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, - 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, - 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, - 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, - 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, - 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, - 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, - 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, - 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, - 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, - 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, - 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, - 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, - 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, - 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, - 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, - 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, - 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, - 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, - 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, - 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, - 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, - 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, - 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, - 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, - 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, - 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, - 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, - 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, - 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, - 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, - 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, - 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, - 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, - 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, - 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, - 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, - 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, - 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, - 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, - 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, - 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, - 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, - 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, - 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, - 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, - 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, - 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, - 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, - 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, - 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, - 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, - 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, - 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, - 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, - 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, - 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, - 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, - 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, - 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, - 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, - 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, - 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, - 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, - 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, - 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, - 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, - 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, - 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, - 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, -}; - -/* - * Round loop unrolling macros, S is a pointer to a S-Box array - * organized in 4 unsigned longs at a row. - */ -#define GET32_3(x) (((x) & 0xff)) -#define GET32_2(x) (((x) >> (8)) & (0xff)) -#define GET32_1(x) (((x) >> (16)) & (0xff)) -#define GET32_0(x) (((x) >> (24)) & (0xff)) - -#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \ - S[512 + GET32_2(x)]) + S[768 + GET32_3(x)]) - -#define EROUND(a, b, n) do { b ^= P[n]; a ^= bf_F(b); } while (0) -#define DROUND(a, b, n) do { a ^= bf_F(b); b ^= P[n]; } while (0) - - -/* - * encrypt isdn data frame - * every block with 9 samples is encrypted - */ -void -dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len) -{ - int i = 0, j = dsp->bf_crypt_pos; - u8 *bf_data_in = dsp->bf_data_in; - u8 *bf_crypt_out = dsp->bf_crypt_out; - u32 *P = dsp->bf_p; - u32 *S = dsp->bf_s; - u32 yl, yr; - u32 cs; - u8 nibble; - - while (i < len) { - /* collect a block of 9 samples */ - if (j < 9) { - bf_data_in[j] = *data; - *data++ = bf_crypt_out[j++]; - i++; - continue; - } - j = 0; - /* transcode 9 samples xlaw to 8 bytes */ - yl = dsp_audio_law2seven[bf_data_in[0]]; - yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[1]]; - yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[2]]; - yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[3]]; - nibble = dsp_audio_law2seven[bf_data_in[4]]; - yr = nibble; - yl = (yl << 4) | (nibble >> 3); - yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[5]]; - yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[6]]; - yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[7]]; - yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[8]]; - yr = (yr << 1) | (bf_data_in[0] & 1); - - /* fill unused bit with random noise of audio input */ - /* encrypt */ - - EROUND(yr, yl, 0); - EROUND(yl, yr, 1); - EROUND(yr, yl, 2); - EROUND(yl, yr, 3); - EROUND(yr, yl, 4); - EROUND(yl, yr, 5); - EROUND(yr, yl, 6); - EROUND(yl, yr, 7); - EROUND(yr, yl, 8); - EROUND(yl, yr, 9); - EROUND(yr, yl, 10); - EROUND(yl, yr, 11); - EROUND(yr, yl, 12); - EROUND(yl, yr, 13); - EROUND(yr, yl, 14); - EROUND(yl, yr, 15); - yl ^= P[16]; - yr ^= P[17]; - - /* calculate 3-bit checksumme */ - cs = yl ^ (yl >> 3) ^ (yl >> 6) ^ (yl >> 9) ^ (yl >> 12) ^ (yl >> 15) - ^ (yl >> 18) ^ (yl >> 21) ^ (yl >> 24) ^ (yl >> 27) ^ (yl >> 30) - ^ (yr << 2) ^ (yr >> 1) ^ (yr >> 4) ^ (yr >> 7) ^ (yr >> 10) - ^ (yr >> 13) ^ (yr >> 16) ^ (yr >> 19) ^ (yr >> 22) ^ (yr >> 25) - ^ (yr >> 28) ^ (yr >> 31); - - /* - * transcode 8 crypted bytes to 9 data bytes with sync - * and checksum information - */ - bf_crypt_out[0] = (yl >> 25) | 0x80; - bf_crypt_out[1] = (yl >> 18) & 0x7f; - bf_crypt_out[2] = (yl >> 11) & 0x7f; - bf_crypt_out[3] = (yl >> 4) & 0x7f; - bf_crypt_out[4] = ((yl << 3) & 0x78) | ((yr >> 29) & 0x07); - bf_crypt_out[5] = ((yr >> 22) & 0x7f) | ((cs << 5) & 0x80); - bf_crypt_out[6] = ((yr >> 15) & 0x7f) | ((cs << 6) & 0x80); - bf_crypt_out[7] = ((yr >> 8) & 0x7f) | (cs << 7); - bf_crypt_out[8] = yr; - } - - /* write current count */ - dsp->bf_crypt_pos = j; - -} - - -/* - * decrypt isdn data frame - * every block with 9 bytes is decrypted - */ -void -dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len) -{ - int i = 0; - u8 j = dsp->bf_decrypt_in_pos; - u8 k = dsp->bf_decrypt_out_pos; - u8 *bf_crypt_inring = dsp->bf_crypt_inring; - u8 *bf_data_out = dsp->bf_data_out; - u16 sync = dsp->bf_sync; - u32 *P = dsp->bf_p; - u32 *S = dsp->bf_s; - u32 yl, yr; - u8 nibble; - u8 cs, cs0, cs1, cs2; - - while (i < len) { - /* - * shift upper bit and rotate data to buffer ring - * send current decrypted data - */ - sync = (sync << 1) | ((*data) >> 7); - bf_crypt_inring[j++ & 15] = *data; - *data++ = bf_data_out[k++]; - i++; - if (k == 9) - k = 0; /* repeat if no sync has been found */ - /* check if not in sync */ - if ((sync & 0x1f0) != 0x100) - continue; - j -= 9; - /* transcode receive data to 64 bit block of encrypted data */ - yl = bf_crypt_inring[j++ & 15]; - yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ - yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ - yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ - nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ - yr = nibble; - yl = (yl << 4) | (nibble >> 3); - cs2 = bf_crypt_inring[j++ & 15]; - yr = (yr << 7) | (cs2 & 0x7f); - cs1 = bf_crypt_inring[j++ & 15]; - yr = (yr << 7) | (cs1 & 0x7f); - cs0 = bf_crypt_inring[j++ & 15]; - yr = (yr << 7) | (cs0 & 0x7f); - yr = (yr << 8) | bf_crypt_inring[j++ & 15]; - - /* calculate 3-bit checksumme */ - cs = yl ^ (yl >> 3) ^ (yl >> 6) ^ (yl >> 9) ^ (yl >> 12) ^ (yl >> 15) - ^ (yl >> 18) ^ (yl >> 21) ^ (yl >> 24) ^ (yl >> 27) ^ (yl >> 30) - ^ (yr << 2) ^ (yr >> 1) ^ (yr >> 4) ^ (yr >> 7) ^ (yr >> 10) - ^ (yr >> 13) ^ (yr >> 16) ^ (yr >> 19) ^ (yr >> 22) ^ (yr >> 25) - ^ (yr >> 28) ^ (yr >> 31); - - /* check if frame is valid */ - if ((cs & 0x7) != (((cs2 >> 5) & 4) | ((cs1 >> 6) & 2) | (cs0 >> 7))) { - if (dsp_debug & DEBUG_DSP_BLOWFISH) - printk(KERN_DEBUG - "DSP BLOWFISH: received corrupt frame, " - "checksumme is not correct\n"); - continue; - } - - /* decrypt */ - yr ^= P[17]; - yl ^= P[16]; - DROUND(yl, yr, 15); - DROUND(yr, yl, 14); - DROUND(yl, yr, 13); - DROUND(yr, yl, 12); - DROUND(yl, yr, 11); - DROUND(yr, yl, 10); - DROUND(yl, yr, 9); - DROUND(yr, yl, 8); - DROUND(yl, yr, 7); - DROUND(yr, yl, 6); - DROUND(yl, yr, 5); - DROUND(yr, yl, 4); - DROUND(yl, yr, 3); - DROUND(yr, yl, 2); - DROUND(yl, yr, 1); - DROUND(yr, yl, 0); - - /* transcode 8 crypted bytes to 9 sample bytes */ - bf_data_out[0] = dsp_audio_seven2law[(yl >> 25) & 0x7f]; - bf_data_out[1] = dsp_audio_seven2law[(yl >> 18) & 0x7f]; - bf_data_out[2] = dsp_audio_seven2law[(yl >> 11) & 0x7f]; - bf_data_out[3] = dsp_audio_seven2law[(yl >> 4) & 0x7f]; - bf_data_out[4] = dsp_audio_seven2law[((yl << 3) & 0x78) | - ((yr >> 29) & 0x07)]; - - bf_data_out[5] = dsp_audio_seven2law[(yr >> 22) & 0x7f]; - bf_data_out[6] = dsp_audio_seven2law[(yr >> 15) & 0x7f]; - bf_data_out[7] = dsp_audio_seven2law[(yr >> 8) & 0x7f]; - bf_data_out[8] = dsp_audio_seven2law[(yr >> 1) & 0x7f]; - k = 0; /* start with new decoded frame */ - } - - /* write current count and sync */ - dsp->bf_decrypt_in_pos = j; - dsp->bf_decrypt_out_pos = k; - dsp->bf_sync = sync; -} - - -/* used to encrypt S and P boxes */ -static inline void -encrypt_block(const u32 *P, const u32 *S, u32 *dst, u32 *src) -{ - u32 yl = src[0]; - u32 yr = src[1]; - - EROUND(yr, yl, 0); - EROUND(yl, yr, 1); - EROUND(yr, yl, 2); - EROUND(yl, yr, 3); - EROUND(yr, yl, 4); - EROUND(yl, yr, 5); - EROUND(yr, yl, 6); - EROUND(yl, yr, 7); - EROUND(yr, yl, 8); - EROUND(yl, yr, 9); - EROUND(yr, yl, 10); - EROUND(yl, yr, 11); - EROUND(yr, yl, 12); - EROUND(yl, yr, 13); - EROUND(yr, yl, 14); - EROUND(yl, yr, 15); - - yl ^= P[16]; - yr ^= P[17]; - - dst[0] = yr; - dst[1] = yl; -} - -/* - * initialize the dsp for encryption and decryption using the same key - * Calculates the blowfish S and P boxes for encryption and decryption. - * The margin of keylen must be 4-56 bytes. - * returns 0 if ok. - */ -int -dsp_bf_init(struct dsp *dsp, const u8 *key, uint keylen) -{ - short i, j, count; - u32 data[2], temp; - u32 *P = (u32 *)dsp->bf_p; - u32 *S = (u32 *)dsp->bf_s; - - if (keylen < 4 || keylen > 56) - return 1; - - /* Set dsp states */ - i = 0; - while (i < 9) { - dsp->bf_crypt_out[i] = 0xff; - dsp->bf_data_out[i] = dsp_silence; - i++; - } - dsp->bf_crypt_pos = 0; - dsp->bf_decrypt_in_pos = 0; - dsp->bf_decrypt_out_pos = 0; - dsp->bf_sync = 0x1ff; - dsp->bf_enable = 1; - - /* Copy the initialization s-boxes */ - for (i = 0, count = 0; i < 256; i++) - for (j = 0; j < 4; j++, count++) - S[count] = bf_sbox[count]; - - /* Set the p-boxes */ - for (i = 0; i < 16 + 2; i++) - P[i] = bf_pbox[i]; - - /* Actual subkey generation */ - for (j = 0, i = 0; i < 16 + 2; i++) { - temp = (((u32)key[j] << 24) | - ((u32)key[(j + 1) % keylen] << 16) | - ((u32)key[(j + 2) % keylen] << 8) | - ((u32)key[(j + 3) % keylen])); - - P[i] = P[i] ^ temp; - j = (j + 4) % keylen; - } - - data[0] = 0x00000000; - data[1] = 0x00000000; - - for (i = 0; i < 16 + 2; i += 2) { - encrypt_block(P, S, data, data); - - P[i] = data[0]; - P[i + 1] = data[1]; - } - - for (i = 0; i < 4; i++) { - for (j = 0, count = i * 256; j < 256; j += 2, count += 2) { - encrypt_block(P, S, data, data); - - S[count] = data[0]; - S[count + 1] = data[1]; - } - } - - return 0; -} - - -/* - * turn encryption off - */ -void -dsp_bf_cleanup(struct dsp *dsp) -{ - dsp->bf_enable = 0; -} diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c deleted file mode 100644 index d5eb2349c414..000000000000 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ /dev/null @@ -1,1949 +0,0 @@ -/* - * Audio crossconnecting/conferrencing (hardware level). - * - * Copyright 2002 by Andreas Eversberg (jolly@eversberg.eu) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* - * The process of adding and removing parties to/from a conference: - * - * There is a chain of struct dsp_conf which has one or more members in a chain - * of struct dsp_conf_member. - * - * After a party is added, the conference is checked for hardware capability. - * Also if a party is removed, the conference is checked again. - * - * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect - * 1-n = hardware-conference. The n will give the conference number. - * - * Depending on the change after removal or insertion of a party, hardware - * commands are given. - * - * The current solution is stored within the struct dsp_conf entry. - */ - -/* - * HOW THE CMX WORKS: - * - * There are 3 types of interaction: One member is alone, in this case only - * data flow from upper to lower layer is done. - * Two members will also exchange their data so they are crossconnected. - * Three or more members will be added in a conference and will hear each - * other but will not receive their own speech (echo) if not enabled. - * - * Features of CMX are: - * - Crossconnecting or even conference, if more than two members are together. - * - Force mixing of transmit data with other crossconnect/conference members. - * - Echo generation to benchmark the delay of audio processing. - * - Use hardware to minimize cpu load, disable FIFO load and minimize delay. - * - Dejittering and clock generation. - * - * There are 2 buffers: - * - * - * RX-Buffer - * R W - * | | - * ----------------+-------------+------------------- - * - * The rx-buffer is a ring buffer used to store the received data for each - * individual member. This is only the case if data needs to be dejittered - * or in case of a conference where different clocks require reclocking. - * The transmit-clock (R) will read the buffer. - * If the clock overruns the write-pointer, we will have a buffer underrun. - * If the write pointer always has a certain distance from the transmit- - * clock, we will have a delay. The delay will dynamically be increased and - * reduced. - * - * - * TX-Buffer - * R W - * | | - * -----------------+--------+----------------------- - * - * The tx-buffer is a ring buffer to queue the transmit data from user space - * until it will be mixed or sent. There are two pointers, R and W. If the write - * pointer W would reach or overrun R, the buffer would overrun. In this case - * (some) data is dropped so that it will not overrun. - * Additionally a dynamic dejittering can be enabled. this allows data from - * user space that have jitter and different clock source. - * - * - * Clock: - * - * A Clock is not required, if the data source has exactly one clock. In this - * case the data source is forwarded to the destination. - * - * A Clock is required, because the data source - * - has multiple clocks. - * - has no usable clock due to jitter or packet loss (VoIP). - * In this case the system's clock is used. The clock resolution depends on - * the jiffy resolution. - * - * If a member joins a conference: - * - * - If a member joins, its rx_buff is set to silence and change read pointer - * to transmit clock. - * - * The procedure of received data from card is explained in cmx_receive. - * The procedure of received data from user space is explained in cmx_transmit. - * The procedure of transmit data to card is cmx_send. - * - * - * Interaction with other features: - * - * DTMF: - * DTMF decoding is done before the data is crossconnected. - * - * Volume change: - * Changing rx-volume is done before the data is crossconnected. The tx-volume - * must be changed whenever data is transmitted to the card by the cmx. - * - * Tones: - * If a tone is enabled, it will be processed whenever data is transmitted to - * the card. It will replace the tx-data from the user space. - * If tones are generated by hardware, this conference member is removed for - * this time. - * - * Disable rx-data: - * If cmx is realized in hardware, rx data will be disabled if requested by - * the upper layer. If dtmf decoding is done by software and enabled, rx data - * will not be disabled but blocked to the upper layer. - * - * HFC conference engine: - * If it is possible to realize all features using hardware, hardware will be - * used if not forbidden by control command. Disabling rx-data provides - * absolutely traffic free audio processing. (except for the quick 1-frame - * upload of a tone loop, only once for a new tone) - * - */ - -/* delay.h is required for hw_lock.h */ - -#include -#include -#include -#include -#include "core.h" -#include "dsp.h" -/* - * debugging of multi party conference, - * by using conference even with two members - */ - -/* #define CMX_CONF_DEBUG */ - -/*#define CMX_DEBUG * massive read/write pointer output */ -/*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */ -/*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ - -/* - * debug cmx memory structure - */ -void -dsp_cmx_debug(struct dsp *dsp) -{ - struct dsp_conf *conf; - struct dsp_conf_member *member; - struct dsp *odsp; - - printk(KERN_DEBUG "-----Current DSP\n"); - list_for_each_entry(odsp, &dsp_ilist, list) { - printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d", - odsp->name, odsp->echo.hardware, odsp->echo.software, - odsp->tx_mix); - if (odsp->conf) - printk(" (Conf %d)", odsp->conf->id); - if (dsp == odsp) - printk(" *this*"); - printk("\n"); - } - printk(KERN_DEBUG "-----Current Conf:\n"); - list_for_each_entry(conf, &conf_ilist, list) { - printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf); - list_for_each_entry(member, &conf->mlist, list) { - printk(KERN_DEBUG - " - member = %s (slot_tx %d, bank_tx %d, " - "slot_rx %d, bank_rx %d hfc_conf %d " - "tx_data %d rx_is_off %d)%s\n", - member->dsp->name, member->dsp->pcm_slot_tx, - member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, - member->dsp->pcm_bank_rx, member->dsp->hfc_conf, - member->dsp->tx_data, member->dsp->rx_is_off, - (member->dsp == dsp) ? " *this*" : ""); - } - } - printk(KERN_DEBUG "-----end\n"); -} - -/* - * search conference - */ -static struct dsp_conf * -dsp_cmx_search_conf(u32 id) -{ - struct dsp_conf *conf; - - if (!id) { - printk(KERN_WARNING "%s: conference ID is 0.\n", __func__); - return NULL; - } - - /* search conference */ - list_for_each_entry(conf, &conf_ilist, list) - if (conf->id == id) - return conf; - - return NULL; -} - - -/* - * add member to conference - */ -static int -dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) -{ - struct dsp_conf_member *member; - - if (!conf || !dsp) { - printk(KERN_WARNING "%s: conf or dsp is 0.\n", __func__); - return -EINVAL; - } - if (dsp->member) { - printk(KERN_WARNING "%s: dsp is already member in a conf.\n", - __func__); - return -EINVAL; - } - - if (dsp->conf) { - printk(KERN_WARNING "%s: dsp is already in a conf.\n", - __func__); - return -EINVAL; - } - - member = kzalloc_obj(struct dsp_conf_member, GFP_ATOMIC); - if (!member) { - printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n"); - return -ENOMEM; - } - member->dsp = dsp; - /* clear rx buffer */ - memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); - dsp->rx_init = 1; /* rx_W and rx_R will be adjusted on first frame */ - dsp->rx_W = 0; - dsp->rx_R = 0; - - list_add_tail(&member->list, &conf->mlist); - - dsp->conf = conf; - dsp->member = member; - - return 0; -} - - -/* - * del member from conference - */ -int -dsp_cmx_del_conf_member(struct dsp *dsp) -{ - struct dsp_conf_member *member; - - if (!dsp) { - printk(KERN_WARNING "%s: dsp is 0.\n", - __func__); - return -EINVAL; - } - - if (!dsp->conf) { - printk(KERN_WARNING "%s: dsp is not in a conf.\n", - __func__); - return -EINVAL; - } - - if (list_empty(&dsp->conf->mlist)) { - printk(KERN_WARNING "%s: dsp has linked an empty conf.\n", - __func__); - return -EINVAL; - } - - /* find us in conf */ - list_for_each_entry(member, &dsp->conf->mlist, list) { - if (member->dsp == dsp) { - list_del(&member->list); - dsp->conf = NULL; - dsp->member = NULL; - kfree(member); - return 0; - } - } - printk(KERN_WARNING - "%s: dsp is not present in its own conf_member list.\n", - __func__); - - return -EINVAL; -} - - -/* - * new conference - */ -static struct dsp_conf -*dsp_cmx_new_conf(u32 id) -{ - struct dsp_conf *conf; - - if (!id) { - printk(KERN_WARNING "%s: id is 0.\n", - __func__); - return NULL; - } - - conf = kzalloc_obj(struct dsp_conf, GFP_ATOMIC); - if (!conf) { - printk(KERN_ERR "kzalloc struct dsp_conf failed\n"); - return NULL; - } - INIT_LIST_HEAD(&conf->mlist); - conf->id = id; - - list_add_tail(&conf->list, &conf_ilist); - - return conf; -} - - -/* - * del conference - */ -int -dsp_cmx_del_conf(struct dsp_conf *conf) -{ - if (!conf) { - printk(KERN_WARNING "%s: conf is null.\n", - __func__); - return -EINVAL; - } - - if (!list_empty(&conf->mlist)) { - printk(KERN_WARNING "%s: conf not empty.\n", - __func__); - return -EINVAL; - } - list_del(&conf->list); - kfree(conf); - - return 0; -} - - -/* - * send HW message to hfc card - */ -static void -dsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2, - u32 param3, u32 param4) -{ - struct mISDN_ctrl_req cq; - - memset(&cq, 0, sizeof(cq)); - cq.op = message; - cq.p1 = param1 | (param2 << 8); - cq.p2 = param3 | (param4 << 8); - if (dsp->ch.peer) - dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq); -} - - -/* - * do hardware update and set the software/hardware flag - * - * either a conference or a dsp instance can be given - * if only dsp instance is given, the instance is not associated with a conf - * and therefore removed. if a conference is given, the dsp is expected to - * be member of that conference. - */ -void -dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) -{ - struct dsp_conf_member *member, *nextm; - struct dsp *finddsp; - int memb = 0, i, ii, i1, i2; - int freeunits[8]; - u_char freeslots[256]; - int same_hfc = -1, same_pcm = -1, current_conf = -1, - all_conf = 1, tx_data = 0; - - /* dsp gets updated (no conf) */ - if (!conf) { - if (!dsp) - return; - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG "%s checking dsp %s\n", - __func__, dsp->name); - one_member: - /* remove HFC conference if enabled */ - if (dsp->hfc_conf >= 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s removing %s from HFC conf %d " - "because dsp is split\n", __func__, - dsp->name, dsp->hfc_conf); - dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT, - 0, 0, 0, 0); - dsp->hfc_conf = -1; - } - /* process hw echo */ - if (dsp->features.pcm_banks < 1) - return; - if (!dsp->echo.software && !dsp->echo.hardware) { - /* NO ECHO: remove PCM slot if assigned */ - if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG "%s removing %s from" - " PCM slot %d (TX) %d (RX) because" - " dsp is split (no echo)\n", - __func__, dsp->name, - dsp->pcm_slot_tx, dsp->pcm_slot_rx); - dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC, - 0, 0, 0, 0); - dsp->pcm_slot_tx = -1; - dsp->pcm_bank_tx = -1; - dsp->pcm_slot_rx = -1; - dsp->pcm_bank_rx = -1; - } - return; - } - /* echo is enabled, find out if we use soft or hardware */ - dsp->echo.software = dsp->tx_data; - dsp->echo.hardware = 0; - /* ECHO: already echo */ - if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && - dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) { - dsp->echo.hardware = 1; - return; - } - /* ECHO: if slot already assigned */ - if (dsp->pcm_slot_tx >= 0) { - dsp->pcm_slot_rx = dsp->pcm_slot_tx; - dsp->pcm_bank_tx = 2; /* 2 means loop */ - dsp->pcm_bank_rx = 2; - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s refresh %s for echo using slot %d\n", - __func__, dsp->name, - dsp->pcm_slot_tx); - dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, - dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); - dsp->echo.hardware = 1; - return; - } - /* ECHO: find slot */ - dsp->pcm_slot_tx = -1; - dsp->pcm_slot_rx = -1; - memset(freeslots, 1, sizeof(freeslots)); - list_for_each_entry(finddsp, &dsp_ilist, list) { - if (finddsp->features.pcm_id == dsp->features.pcm_id) { - if (finddsp->pcm_slot_rx >= 0 && - finddsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[finddsp->pcm_slot_rx] = 0; - if (finddsp->pcm_slot_tx >= 0 && - finddsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[finddsp->pcm_slot_tx] = 0; - } - } - i = 0; - ii = dsp->features.pcm_slots; - while (i < ii) { - if (freeslots[i]) - break; - i++; - } - if (i == ii) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s no slot available for echo\n", - __func__); - /* no more slots available */ - dsp->echo.software = 1; - return; - } - /* assign free slot */ - dsp->pcm_slot_tx = i; - dsp->pcm_slot_rx = i; - dsp->pcm_bank_tx = 2; /* loop */ - dsp->pcm_bank_rx = 2; - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s assign echo for %s using slot %d\n", - __func__, dsp->name, dsp->pcm_slot_tx); - dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, - dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); - dsp->echo.hardware = 1; - return; - } - - /* conf gets updated (all members) */ - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG "%s checking conference %d\n", - __func__, conf->id); - - if (list_empty(&conf->mlist)) { - printk(KERN_ERR "%s: conference without members\n", - __func__); - return; - } - member = list_entry(conf->mlist.next, struct dsp_conf_member, list); - same_hfc = member->dsp->features.hfc_id; - same_pcm = member->dsp->features.pcm_id; - /* check all members in our conference */ - list_for_each_entry(member, &conf->mlist, list) { - /* check if member uses mixing */ - if (member->dsp->tx_mix) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_mix is turned on\n", __func__, - member->dsp->name); - conf_software: - list_for_each_entry(member, &conf->mlist, list) { - dsp = member->dsp; - /* remove HFC conference if enabled */ - if (dsp->hfc_conf >= 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s removing %s from HFC " - "conf %d because not " - "possible with hardware\n", - __func__, - dsp->name, - dsp->hfc_conf); - dsp_cmx_hw_message(dsp, - MISDN_CTRL_HFC_CONF_SPLIT, - 0, 0, 0, 0); - dsp->hfc_conf = -1; - } - /* remove PCM slot if assigned */ - if (dsp->pcm_slot_tx >= 0 || - dsp->pcm_slot_rx >= 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG "%s removing " - "%s from PCM slot %d (TX)" - " slot %d (RX) because not" - " possible with hardware\n", - __func__, - dsp->name, - dsp->pcm_slot_tx, - dsp->pcm_slot_rx); - dsp_cmx_hw_message(dsp, - MISDN_CTRL_HFC_PCM_DISC, - 0, 0, 0, 0); - dsp->pcm_slot_tx = -1; - dsp->pcm_bank_tx = -1; - dsp->pcm_slot_rx = -1; - dsp->pcm_bank_rx = -1; - } - } - conf->hardware = 0; - conf->software = 1; - return; - } - /* check if member has echo turned on */ - if (member->dsp->echo.hardware || member->dsp->echo.software) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "echo is turned on\n", __func__, - member->dsp->name); - goto conf_software; - } - /* check if member has tx_mix turned on */ - if (member->dsp->tx_mix) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_mix is turned on\n", - __func__, member->dsp->name); - goto conf_software; - } - /* check if member changes volume at an not suppoted level */ - if (member->dsp->tx_volume) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_volume is changed\n", - __func__, member->dsp->name); - goto conf_software; - } - if (member->dsp->rx_volume) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "rx_volume is changed\n", - __func__, member->dsp->name); - goto conf_software; - } - /* check if tx-data turned on */ - if (member->dsp->tx_data) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s tx_data is turned on\n", - __func__, member->dsp->name); - tx_data = 1; - } - /* check if pipeline exists */ - if (member->dsp->pipeline.inuse) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "pipeline exists\n", __func__, - member->dsp->name); - goto conf_software; - } - /* check if encryption is enabled */ - if (member->dsp->bf_enable) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG "%s dsp %s cannot form a " - "conf, because encryption is enabled\n", - __func__, member->dsp->name); - goto conf_software; - } - /* check if member is on a card with PCM support */ - if (member->dsp->features.pcm_id < 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "dsp has no PCM bus\n", - __func__, member->dsp->name); - goto conf_software; - } - /* check if relations are on the same PCM bus */ - if (member->dsp->features.pcm_id != same_pcm) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "dsp is on a different PCM bus than the " - "first dsp\n", - __func__, member->dsp->name); - goto conf_software; - } - /* determine if members are on the same hfc chip */ - if (same_hfc != member->dsp->features.hfc_id) - same_hfc = -1; - /* if there are members already in a conference */ - if (current_conf < 0 && member->dsp->hfc_conf >= 0) - current_conf = member->dsp->hfc_conf; - /* if any member is not in a conference */ - if (member->dsp->hfc_conf < 0) - all_conf = 0; - - memb++; - } - - /* if no member, this is an error */ - if (memb < 1) - return; - - /* one member */ - if (memb == 1) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s conf %d cannot form a HW conference, " - "because dsp is alone\n", __func__, conf->id); - conf->hardware = 0; - conf->software = 0; - member = list_entry(conf->mlist.next, struct dsp_conf_member, - list); - dsp = member->dsp; - goto one_member; - } - - /* - * ok, now we are sure that all members are on the same pcm. - * now we will see if we have only two members, so we can do - * crossconnections, which don't have any limitations. - */ - - /* if we have only two members */ - if (memb == 2) { - member = list_entry(conf->mlist.next, struct dsp_conf_member, - list); - nextm = list_entry(member->list.next, struct dsp_conf_member, - list); - /* remove HFC conference if enabled */ - if (member->dsp->hfc_conf >= 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s removing %s from HFC conf %d because " - "two parties require only a PCM slot\n", - __func__, member->dsp->name, - member->dsp->hfc_conf); - dsp_cmx_hw_message(member->dsp, - MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); - member->dsp->hfc_conf = -1; - } - if (nextm->dsp->hfc_conf >= 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s removing %s from HFC conf %d because " - "two parties require only a PCM slot\n", - __func__, nextm->dsp->name, - nextm->dsp->hfc_conf); - dsp_cmx_hw_message(nextm->dsp, - MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); - nextm->dsp->hfc_conf = -1; - } - /* if members have two banks (and not on the same chip) */ - if (member->dsp->features.pcm_banks > 1 && - nextm->dsp->features.pcm_banks > 1 && - member->dsp->features.hfc_id != - nextm->dsp->features.hfc_id) { - /* if both members have same slots with crossed banks */ - if (member->dsp->pcm_slot_tx >= 0 && - member->dsp->pcm_slot_rx >= 0 && - nextm->dsp->pcm_slot_tx >= 0 && - nextm->dsp->pcm_slot_rx >= 0 && - nextm->dsp->pcm_slot_tx == - member->dsp->pcm_slot_rx && - nextm->dsp->pcm_slot_rx == - member->dsp->pcm_slot_tx && - nextm->dsp->pcm_slot_tx == - member->dsp->pcm_slot_tx && - member->dsp->pcm_bank_tx != - member->dsp->pcm_bank_rx && - nextm->dsp->pcm_bank_tx != - nextm->dsp->pcm_bank_rx) { - /* all members have same slot */ - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s & %s stay joined on " - "PCM slot %d bank %d (TX) bank %d " - "(RX) (on different chips)\n", - __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx, - member->dsp->pcm_bank_tx, - member->dsp->pcm_bank_rx); - conf->hardware = 1; - conf->software = tx_data; - return; - } - /* find a new slot */ - memset(freeslots, 1, sizeof(freeslots)); - list_for_each_entry(dsp, &dsp_ilist, list) { - if (dsp != member->dsp && - dsp != nextm->dsp && - member->dsp->features.pcm_id == - dsp->features.pcm_id) { - if (dsp->pcm_slot_rx >= 0 && - dsp->pcm_slot_rx < - sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; - if (dsp->pcm_slot_tx >= 0 && - dsp->pcm_slot_tx < - sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; - } - } - i = 0; - ii = member->dsp->features.pcm_slots; - while (i < ii) { - if (freeslots[i]) - break; - i++; - } - if (i == ii) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s no slot available for " - "%s & %s\n", __func__, - member->dsp->name, - nextm->dsp->name); - /* no more slots available */ - goto conf_software; - } - /* assign free slot */ - member->dsp->pcm_slot_tx = i; - member->dsp->pcm_slot_rx = i; - nextm->dsp->pcm_slot_tx = i; - nextm->dsp->pcm_slot_rx = i; - member->dsp->pcm_bank_rx = 0; - member->dsp->pcm_bank_tx = 1; - nextm->dsp->pcm_bank_rx = 1; - nextm->dsp->pcm_bank_tx = 0; - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s adding %s & %s to new PCM slot %d " - "(TX and RX on different chips) because " - "both members have not same slots\n", - __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx); - dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, - member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, - member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); - dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, - nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, - nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); - conf->hardware = 1; - conf->software = tx_data; - return; - /* if members have one bank (or on the same chip) */ - } else { - /* if both members have different crossed slots */ - if (member->dsp->pcm_slot_tx >= 0 && - member->dsp->pcm_slot_rx >= 0 && - nextm->dsp->pcm_slot_tx >= 0 && - nextm->dsp->pcm_slot_rx >= 0 && - nextm->dsp->pcm_slot_tx == - member->dsp->pcm_slot_rx && - nextm->dsp->pcm_slot_rx == - member->dsp->pcm_slot_tx && - member->dsp->pcm_slot_tx != - member->dsp->pcm_slot_rx && - member->dsp->pcm_bank_tx == 0 && - member->dsp->pcm_bank_rx == 0 && - nextm->dsp->pcm_bank_tx == 0 && - nextm->dsp->pcm_bank_rx == 0) { - /* all members have same slot */ - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s dsp %s & %s stay joined on PCM " - "slot %d (TX) %d (RX) on same chip " - "or one bank PCM)\n", __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx, - member->dsp->pcm_slot_rx); - conf->hardware = 1; - conf->software = tx_data; - return; - } - /* find two new slot */ - memset(freeslots, 1, sizeof(freeslots)); - list_for_each_entry(dsp, &dsp_ilist, list) { - if (dsp != member->dsp && - dsp != nextm->dsp && - member->dsp->features.pcm_id == - dsp->features.pcm_id) { - if (dsp->pcm_slot_rx >= 0 && - dsp->pcm_slot_rx < - sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; - if (dsp->pcm_slot_tx >= 0 && - dsp->pcm_slot_tx < - sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; - } - } - i1 = 0; - ii = member->dsp->features.pcm_slots; - while (i1 < ii) { - if (freeslots[i1]) - break; - i1++; - } - if (i1 == ii) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s no slot available " - "for %s & %s\n", __func__, - member->dsp->name, - nextm->dsp->name); - /* no more slots available */ - goto conf_software; - } - i2 = i1 + 1; - while (i2 < ii) { - if (freeslots[i2]) - break; - i2++; - } - if (i2 == ii) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s no slot available " - "for %s & %s\n", - __func__, - member->dsp->name, - nextm->dsp->name); - /* no more slots available */ - goto conf_software; - } - /* assign free slots */ - member->dsp->pcm_slot_tx = i1; - member->dsp->pcm_slot_rx = i2; - nextm->dsp->pcm_slot_tx = i2; - nextm->dsp->pcm_slot_rx = i1; - member->dsp->pcm_bank_rx = 0; - member->dsp->pcm_bank_tx = 0; - nextm->dsp->pcm_bank_rx = 0; - nextm->dsp->pcm_bank_tx = 0; - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s adding %s & %s to new PCM slot %d " - "(TX) %d (RX) on same chip or one bank " - "PCM, because both members have not " - "crossed slots\n", __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx, - member->dsp->pcm_slot_rx); - dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, - member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, - member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); - dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, - nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, - nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); - conf->hardware = 1; - conf->software = tx_data; - return; - } - } - - /* - * if we have more than two, we may check if we have a conference - * unit available on the chip. also all members must be on the same - */ - - /* if not the same HFC chip */ - if (same_hfc < 0) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s conference %d cannot be formed, because " - "members are on different chips or not " - "on HFC chip\n", - __func__, conf->id); - goto conf_software; - } - - /* for more than two members.. */ - - /* if all members already have the same conference */ - if (all_conf) { - conf->hardware = 1; - conf->software = tx_data; - return; - } - - /* - * if there is an existing conference, but not all members have joined - */ - if (current_conf >= 0) { - join_members: - list_for_each_entry(member, &conf->mlist, list) { - /* if no conference engine on our chip, change to - * software */ - if (!member->dsp->features.hfc_conf) - goto conf_software; - /* in case of hdlc, change to software */ - if (member->dsp->hdlc) - goto conf_software; - /* join to current conference */ - if (member->dsp->hfc_conf == current_conf) - continue; - /* get a free timeslot first */ - memset(freeslots, 1, sizeof(freeslots)); - list_for_each_entry(dsp, &dsp_ilist, list) { - /* - * not checking current member, because - * slot will be overwritten. - */ - if ( - dsp != member->dsp && - /* dsp must be on the same PCM */ - member->dsp->features.pcm_id == - dsp->features.pcm_id) { - /* dsp must be on a slot */ - if (dsp->pcm_slot_tx >= 0 && - dsp->pcm_slot_tx < - sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; - if (dsp->pcm_slot_rx >= 0 && - dsp->pcm_slot_rx < - sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; - } - } - i = 0; - ii = member->dsp->features.pcm_slots; - while (i < ii) { - if (freeslots[i]) - break; - i++; - } - if (i == ii) { - /* no more slots available */ - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s conference %d cannot be formed," - " because no slot free\n", - __func__, conf->id); - goto conf_software; - } - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s changing dsp %s to HW conference " - "%d slot %d\n", __func__, - member->dsp->name, current_conf, i); - /* assign free slot & set PCM & join conf */ - member->dsp->pcm_slot_tx = i; - member->dsp->pcm_slot_rx = i; - member->dsp->pcm_bank_tx = 2; /* loop */ - member->dsp->pcm_bank_rx = 2; - member->dsp->hfc_conf = current_conf; - dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, - i, 2, i, 2); - dsp_cmx_hw_message(member->dsp, - MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); - } - conf->hardware = 1; - conf->software = tx_data; - return; - } - - /* - * no member is in a conference yet, so we find a free one - */ - memset(freeunits, 1, sizeof(freeunits)); - list_for_each_entry(dsp, &dsp_ilist, list) { - /* dsp must be on the same chip */ - if (dsp->features.hfc_id == same_hfc && - /* dsp must have joined a HW conference */ - dsp->hfc_conf >= 0 && - /* slot must be within range */ - dsp->hfc_conf < 8) - freeunits[dsp->hfc_conf] = 0; - } - i = 0; - ii = 8; - while (i < ii) { - if (freeunits[i]) - break; - i++; - } - if (i == ii) { - /* no more conferences available */ - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s conference %d cannot be formed, because " - "no conference number free\n", - __func__, conf->id); - goto conf_software; - } - /* join all members */ - current_conf = i; - goto join_members; -} - - -/* - * conf_id != 0: join or change conference - * conf_id == 0: split from conference if not already - */ -int -dsp_cmx_conf(struct dsp *dsp, u32 conf_id) -{ - int err; - struct dsp_conf *conf; - struct dsp_conf_member *member; - - /* if conference doesn't change */ - if (dsp->conf_id == conf_id) - return 0; - - /* first remove us from current conf */ - if (dsp->conf_id) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG "removing us from conference %d\n", - dsp->conf->id); - /* remove us from conf */ - conf = dsp->conf; - err = dsp_cmx_del_conf_member(dsp); - if (err) - return err; - dsp->conf_id = 0; - - /* update hardware */ - dsp_cmx_hardware(NULL, dsp); - - /* conf now empty? */ - if (list_empty(&conf->mlist)) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "conference is empty, so we remove it.\n"); - err = dsp_cmx_del_conf(conf); - if (err) - return err; - } else { - /* update members left on conf */ - dsp_cmx_hardware(conf, NULL); - } - } - - /* if split */ - if (!conf_id) - return 0; - - /* now add us to conf */ - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG "searching conference %d\n", - conf_id); - conf = dsp_cmx_search_conf(conf_id); - if (!conf) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "conference doesn't exist yet, creating.\n"); - /* the conference doesn't exist, so we create */ - conf = dsp_cmx_new_conf(conf_id); - if (!conf) - return -EINVAL; - } else if (!list_empty(&conf->mlist)) { - member = list_entry(conf->mlist.next, struct dsp_conf_member, - list); - if (dsp->hdlc && !member->dsp->hdlc) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "cannot join transparent conference.\n"); - return -EINVAL; - } - if (!dsp->hdlc && member->dsp->hdlc) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "cannot join hdlc conference.\n"); - return -EINVAL; - } - } - /* add conference member */ - err = dsp_cmx_add_conf_member(dsp, conf); - if (err) - return err; - dsp->conf_id = conf_id; - - /* if we are alone, we do nothing! */ - if (list_empty(&conf->mlist)) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "we are alone in this conference, so exit.\n"); - /* update hardware */ - dsp_cmx_hardware(NULL, dsp); - return 0; - } - - /* update members on conf */ - dsp_cmx_hardware(conf, NULL); - - return 0; -} - -#ifdef CMX_DELAY_DEBUG -int delaycount; -static void -showdelay(struct dsp *dsp, int samples, int delay) -{ - char bar[] = "--------------------------------------------------|"; - int sdelay; - - delaycount += samples; - if (delaycount < 8000) - return; - delaycount = 0; - - sdelay = delay * 50 / (dsp_poll << 2); - - printk(KERN_DEBUG "DELAY (%s) %3d >%s\n", dsp->name, delay, - sdelay > 50 ? "..." : bar + 50 - sdelay); -} -#endif - -/* - * audio data is received from card - */ -void -dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) -{ - u8 *d, *p; - int len = skb->len; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - int w, i, ii; - - /* check if we have sompen */ - if (len < 1) - return; - - /* half of the buffer should be larger than maximum packet size */ - if (len >= CMX_BUFF_HALF) { - printk(KERN_ERR - "%s line %d: packet from card is too large (%d bytes). " - "please make card send smaller packets OR increase " - "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len); - return; - } - - /* - * initialize pointers if not already - - * also add delay if requested by PH_SIGNAL - */ - if (dsp->rx_init) { - dsp->rx_init = 0; - if (dsp->features.unordered) { - dsp->rx_R = (hh->id & CMX_BUFF_MASK); - if (dsp->cmx_delay) - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; - else - dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) - & CMX_BUFF_MASK; - } else { - dsp->rx_R = 0; - if (dsp->cmx_delay) - dsp->rx_W = dsp->cmx_delay; - else - dsp->rx_W = dsp_poll >> 1; - } - } - /* if frame contains time code, write directly */ - if (dsp->features.unordered) { - dsp->rx_W = (hh->id & CMX_BUFF_MASK); - /* printk(KERN_DEBUG "%s %08x\n", dsp->name, hh->id); */ - } - /* - * if we underrun (or maybe overrun), - * we set our new read pointer, and write silence to buffer - */ - if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { - if (dsp_debug & DEBUG_DSP_CLOCK) - printk(KERN_DEBUG - "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " - "maximum delay), adjusting read pointer! " - "(inst %s)\n", (u_long)dsp, dsp->name); - /* flush rx buffer and set delay to dsp_poll / 2 */ - if (dsp->features.unordered) { - dsp->rx_R = (hh->id & CMX_BUFF_MASK); - if (dsp->cmx_delay) - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; - else - dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) - & CMX_BUFF_MASK; - } else { - dsp->rx_R = 0; - if (dsp->cmx_delay) - dsp->rx_W = dsp->cmx_delay; - else - dsp->rx_W = dsp_poll >> 1; - } - memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); - } - /* if we have reached double delay, jump back to middle */ - if (dsp->cmx_delay) - if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= - (dsp->cmx_delay << 1)) { - if (dsp_debug & DEBUG_DSP_CLOCK) - printk(KERN_DEBUG - "cmx_receive(dsp=%lx): OVERRUN (because " - "twice the delay is reached), adjusting " - "read pointer! (inst %s)\n", - (u_long)dsp, dsp->name); - /* flush buffer */ - if (dsp->features.unordered) { - dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; - } else { - dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; - } - memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); - } - - /* show where to write */ -#ifdef CMX_DEBUG - printk(KERN_DEBUG - "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n", - (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name); -#endif - - /* write data into rx_buffer */ - p = skb->data; - d = dsp->rx_buff; - w = dsp->rx_W; - i = 0; - ii = len; - while (i < ii) { - d[w++ & CMX_BUFF_MASK] = *p++; - i++; - } - - /* increase write-pointer */ - dsp->rx_W = ((dsp->rx_W + len) & CMX_BUFF_MASK); -#ifdef CMX_DELAY_DEBUG - showdelay(dsp, len, (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK); -#endif -} - - -/* - * send (mixed) audio data to card and control jitter - */ -static void -dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) -{ - struct dsp_conf *conf = dsp->conf; - struct dsp *member, *other; - register s32 sample; - u8 *d, *p, *q, *o_q; - struct sk_buff *nskb, *txskb; - int r, rr, t, tt, o_r, o_rr; - int preload = 0; - struct mISDNhead *hh, *thh; - int tx_data_only = 0; - - /* don't process if: */ - if (!dsp->b_active) { /* if not active */ - dsp->last_tx = 0; - return; - } - if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */ - dsp->echo.hardware) && /* OR hardware echo */ - dsp->tx_R == dsp->tx_W && /* AND no tx-data */ - !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ - if (!dsp->tx_data) { /* no tx_data for user space required */ - dsp->last_tx = 0; - return; - } - if (dsp->conf && dsp->conf->software && dsp->conf->hardware) - tx_data_only = 1; - if (dsp->echo.software && dsp->echo.hardware) - tx_data_only = 1; - } - -#ifdef CMX_DEBUG - printk(KERN_DEBUG - "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", - members, dsp->name, conf, dsp->rx_R, dsp->rx_W); -#endif - - /* preload if we have delay set */ - if (dsp->cmx_delay && !dsp->last_tx) { - preload = len; - if (preload < 128) - preload = 128; - } - - /* PREPARE RESULT */ - nskb = mI_alloc_skb(len + preload, GFP_ATOMIC); - if (!nskb) { - printk(KERN_ERR - "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", - len + preload); - return; - } - hh = mISDN_HEAD_P(nskb); - hh->prim = PH_DATA_REQ; - hh->id = 0; - dsp->last_tx = 1; - - /* set pointers, indexes and stuff */ - member = dsp; - p = dsp->tx_buff; /* transmit data */ - q = dsp->rx_buff; /* received data */ - d = skb_put(nskb, preload + len); /* result */ - t = dsp->tx_R; /* tx-pointers */ - tt = dsp->tx_W; - r = dsp->rx_R; /* rx-pointers */ - rr = (r + len) & CMX_BUFF_MASK; - - /* preload with silence, if required */ - if (preload) { - memset(d, dsp_silence, preload); - d += preload; - } - - /* PROCESS TONES/TX-DATA ONLY */ - if (dsp->tone.tone && dsp->tone.software) { - /* -> copy tone */ - dsp_tone_copy(dsp, d, len); - dsp->tx_R = 0; /* clear tx buffer */ - dsp->tx_W = 0; - goto send_packet; - } - /* if we have tx-data but do not use mixing */ - if (!dsp->tx_mix && t != tt) { - /* -> send tx-data and continue when not enough */ -#ifdef CMX_TX_DEBUG - sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p); -#endif - while (r != rr && t != tt) { -#ifdef CMX_TX_DEBUG - if (strlen(debugbuf) < 48) - sprintf(debugbuf + strlen(debugbuf), " %02x", - p[t]); -#endif - *d++ = p[t]; /* write tx_buff */ - t = (t + 1) & CMX_BUFF_MASK; - r = (r + 1) & CMX_BUFF_MASK; - } - if (r == rr) { - dsp->tx_R = t; -#ifdef CMX_TX_DEBUG - printk(KERN_DEBUG "%s\n", debugbuf); -#endif - goto send_packet; - } - } -#ifdef CMX_TX_DEBUG - printk(KERN_DEBUG "%s\n", debugbuf); -#endif - - /* PROCESS DATA (one member / no conf) */ - if (!conf || members <= 1) { - /* -> if echo is NOT enabled */ - if (!dsp->echo.software) { - /* -> send tx-data if available or use 0-volume */ - while (r != rr && t != tt) { - *d++ = p[t]; /* write tx_buff */ - t = (t + 1) & CMX_BUFF_MASK; - r = (r + 1) & CMX_BUFF_MASK; - } - if (r != rr) { - if (dsp_debug & DEBUG_DSP_CLOCK) - printk(KERN_DEBUG "%s: RX empty\n", - __func__); - memset(d, dsp_silence, (rr - r) & CMX_BUFF_MASK); - } - /* -> if echo is enabled */ - } else { - /* - * -> mix tx-data with echo if available, - * or use echo only - */ - while (r != rr && t != tt) { - *d++ = dsp_audio_mix_law[(p[t] << 8) | q[r]]; - t = (t + 1) & CMX_BUFF_MASK; - r = (r + 1) & CMX_BUFF_MASK; - } - while (r != rr) { - *d++ = q[r]; /* echo */ - r = (r + 1) & CMX_BUFF_MASK; - } - } - dsp->tx_R = t; - goto send_packet; - } - /* PROCESS DATA (two members) */ -#ifdef CMX_CONF_DEBUG - if (0) { -#else - if (members == 2) { -#endif - /* "other" becomes other party */ - other = (list_entry(conf->mlist.next, - struct dsp_conf_member, list))->dsp; - if (other == member) - other = (list_entry(conf->mlist.prev, - struct dsp_conf_member, list))->dsp; - o_q = other->rx_buff; /* received data */ - o_rr = (other->rx_R + len) & CMX_BUFF_MASK; - /* end of rx-pointer */ - o_r = (o_rr - rr + r) & CMX_BUFF_MASK; - /* start rx-pointer at current read position*/ - /* -> if echo is NOT enabled */ - if (!dsp->echo.software) { - /* - * -> copy other member's rx-data, - * if tx-data is available, mix - */ - while (o_r != o_rr && t != tt) { - *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]]; - t = (t + 1) & CMX_BUFF_MASK; - o_r = (o_r + 1) & CMX_BUFF_MASK; - } - while (o_r != o_rr) { - *d++ = o_q[o_r]; - o_r = (o_r + 1) & CMX_BUFF_MASK; - } - /* -> if echo is enabled */ - } else { - /* - * -> mix other member's rx-data with echo, - * if tx-data is available, mix - */ - while (r != rr && t != tt) { - sample = dsp_audio_law_to_s32[p[t]] + - dsp_audio_law_to_s32[q[r]] + - dsp_audio_law_to_s32[o_q[o_r]]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* tx-data + rx_data + echo */ - t = (t + 1) & CMX_BUFF_MASK; - r = (r + 1) & CMX_BUFF_MASK; - o_r = (o_r + 1) & CMX_BUFF_MASK; - } - while (r != rr) { - *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]]; - r = (r + 1) & CMX_BUFF_MASK; - o_r = (o_r + 1) & CMX_BUFF_MASK; - } - } - dsp->tx_R = t; - goto send_packet; - } - /* PROCESS DATA (three or more members) */ - /* -> if echo is NOT enabled */ - if (!dsp->echo.software) { - /* - * -> subtract rx-data from conf-data, - * if tx-data is available, mix - */ - while (r != rr && t != tt) { - sample = dsp_audio_law_to_s32[p[t]] + *c++ - - dsp_audio_law_to_s32[q[r]]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf-rx+tx */ - r = (r + 1) & CMX_BUFF_MASK; - t = (t + 1) & CMX_BUFF_MASK; - } - while (r != rr) { - sample = *c++ - dsp_audio_law_to_s32[q[r]]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf-rx */ - r = (r + 1) & CMX_BUFF_MASK; - } - /* -> if echo is enabled */ - } else { - /* - * -> encode conf-data, if tx-data - * is available, mix - */ - while (r != rr && t != tt) { - sample = dsp_audio_law_to_s32[p[t]] + *c++; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf(echo)+tx */ - t = (t + 1) & CMX_BUFF_MASK; - r = (r + 1) & CMX_BUFF_MASK; - } - while (r != rr) { - sample = *c++; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf(echo) */ - r = (r + 1) & CMX_BUFF_MASK; - } - } - dsp->tx_R = t; - goto send_packet; - -send_packet: - /* - * send tx-data if enabled - don't filter, - * because we want what we send, not what we filtered - */ - if (dsp->tx_data) { - if (tx_data_only) { - hh->prim = DL_DATA_REQ; - hh->id = 0; - /* queue and trigger */ - skb_queue_tail(&dsp->sendq, nskb); - schedule_work(&dsp->workq); - /* exit because only tx_data is used */ - return; - } else { - txskb = mI_alloc_skb(len, GFP_ATOMIC); - if (!txskb) { - printk(KERN_ERR - "FATAL ERROR in mISDN_dsp.o: " - "cannot alloc %d bytes\n", len); - } else { - thh = mISDN_HEAD_P(txskb); - thh->prim = DL_DATA_REQ; - thh->id = 0; - skb_put_data(txskb, nskb->data + preload, len); - /* queue (trigger later) */ - skb_queue_tail(&dsp->sendq, txskb); - } - } - } - - /* send data only to card, if we don't just calculated tx_data */ - /* adjust volume */ - if (dsp->tx_volume) - dsp_change_volume(nskb, dsp->tx_volume); - /* pipeline */ - if (dsp->pipeline.inuse) - dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, - nskb->len); - /* crypt */ - if (dsp->bf_enable) - dsp_bf_encrypt(dsp, nskb->data, nskb->len); - /* queue and trigger */ - skb_queue_tail(&dsp->sendq, nskb); - schedule_work(&dsp->workq); -} - -static u32 jittercount; /* counter for jitter check */ -struct timer_list dsp_spl_tl; -unsigned long dsp_spl_jiffies; /* calculate the next time to fire */ -static u16 dsp_count; /* last sample count */ -static int dsp_count_valid; /* if we have last sample count */ - -void -dsp_cmx_send(struct timer_list *arg) -{ - struct dsp_conf *conf; - struct dsp_conf_member *member; - struct dsp *dsp; - int mustmix, members; - static s32 mixbuffer[MAX_POLL + 100]; - s32 *c; - u8 *p, *q; - int r, rr; - int jittercheck = 0, delay, i; - u_long flags; - u16 length, count; - - /* lock */ - spin_lock_irqsave(&dsp_lock, flags); - - if (!dsp_count_valid) { - dsp_count = mISDN_clock_get(); - length = dsp_poll; - dsp_count_valid = 1; - } else { - count = mISDN_clock_get(); - length = count - dsp_count; - dsp_count = count; - } - if (length > MAX_POLL + 100) - length = MAX_POLL + 100; - /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */ - - /* - * check if jitter needs to be checked (this is every second) - */ - jittercount += length; - if (jittercount >= 8000) { - jittercount -= 8000; - jittercheck = 1; - } - - /* loop all members that do not require conference mixing */ - list_for_each_entry(dsp, &dsp_ilist, list) { - if (dsp->hdlc) - continue; - conf = dsp->conf; - mustmix = 0; - members = 0; - if (conf) { - members = list_count_nodes(&conf->mlist); -#ifdef CMX_CONF_DEBUG - if (conf->software && members > 1) -#else - if (conf->software && members > 2) -#endif - mustmix = 1; - } - - /* transmission required */ - if (!mustmix) { - dsp_cmx_send_member(dsp, length, mixbuffer, members); - - /* - * unused mixbuffer is given to prevent a - * potential null-pointer-bug - */ - } - } - - /* loop all members that require conference mixing */ - list_for_each_entry(conf, &conf_ilist, list) { - /* count members and check hardware */ - members = list_count_nodes(&conf->mlist); -#ifdef CMX_CONF_DEBUG - if (conf->software && members > 1) { -#else - if (conf->software && members > 2) { -#endif - /* check for hdlc conf */ - member = list_entry(conf->mlist.next, - struct dsp_conf_member, list); - if (member->dsp->hdlc) - continue; - /* mix all data */ - memset(mixbuffer, 0, length * sizeof(s32)); - list_for_each_entry(member, &conf->mlist, list) { - dsp = member->dsp; - /* get range of data to mix */ - c = mixbuffer; - q = dsp->rx_buff; - r = dsp->rx_R; - rr = (r + length) & CMX_BUFF_MASK; - /* add member's data */ - while (r != rr) { - *c++ += dsp_audio_law_to_s32[q[r]]; - r = (r + 1) & CMX_BUFF_MASK; - } - } - - /* process each member */ - list_for_each_entry(member, &conf->mlist, list) { - /* transmission */ - dsp_cmx_send_member(member->dsp, length, - mixbuffer, members); - } - } - } - - /* delete rx-data, increment buffers, change pointers */ - list_for_each_entry(dsp, &dsp_ilist, list) { - if (dsp->hdlc) - continue; - p = dsp->rx_buff; - q = dsp->tx_buff; - r = dsp->rx_R; - /* move receive pointer when receiving */ - if (!dsp->rx_is_off) { - rr = (r + length) & CMX_BUFF_MASK; - /* delete rx-data */ - while (r != rr) { - p[r] = dsp_silence; - r = (r + 1) & CMX_BUFF_MASK; - } - /* increment rx-buffer pointer */ - dsp->rx_R = r; /* write incremented read pointer */ - } - - /* check current rx_delay */ - delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK; - if (delay >= CMX_BUFF_HALF) - delay = 0; /* will be the delay before next write */ - /* check for lower delay */ - if (delay < dsp->rx_delay[0]) - dsp->rx_delay[0] = delay; - /* check current tx_delay */ - delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK; - if (delay >= CMX_BUFF_HALF) - delay = 0; /* will be the delay before next write */ - /* check for lower delay */ - if (delay < dsp->tx_delay[0]) - dsp->tx_delay[0] = delay; - if (jittercheck) { - /* find the lowest of all rx_delays */ - delay = dsp->rx_delay[0]; - i = 1; - while (i < MAX_SECONDS_JITTER_CHECK) { - if (delay > dsp->rx_delay[i]) - delay = dsp->rx_delay[i]; - i++; - } - /* - * remove rx_delay only if we have delay AND we - * have not preset cmx_delay AND - * the delay is greater dsp_poll - */ - if (delay > dsp_poll && !dsp->cmx_delay) { - if (dsp_debug & DEBUG_DSP_CLOCK) - printk(KERN_DEBUG - "%s lowest rx_delay of %d bytes for" - " dsp %s are now removed.\n", - __func__, delay, - dsp->name); - r = dsp->rx_R; - rr = (r + delay - (dsp_poll >> 1)) - & CMX_BUFF_MASK; - /* delete rx-data */ - while (r != rr) { - p[r] = dsp_silence; - r = (r + 1) & CMX_BUFF_MASK; - } - /* increment rx-buffer pointer */ - dsp->rx_R = r; - /* write incremented read pointer */ - } - /* find the lowest of all tx_delays */ - delay = dsp->tx_delay[0]; - i = 1; - while (i < MAX_SECONDS_JITTER_CHECK) { - if (delay > dsp->tx_delay[i]) - delay = dsp->tx_delay[i]; - i++; - } - /* - * remove delay only if we have delay AND we - * have enabled tx_dejitter - */ - if (delay > dsp_poll && dsp->tx_dejitter) { - if (dsp_debug & DEBUG_DSP_CLOCK) - printk(KERN_DEBUG - "%s lowest tx_delay of %d bytes for" - " dsp %s are now removed.\n", - __func__, delay, - dsp->name); - r = dsp->tx_R; - rr = (r + delay - (dsp_poll >> 1)) - & CMX_BUFF_MASK; - /* delete tx-data */ - while (r != rr) { - q[r] = dsp_silence; - r = (r + 1) & CMX_BUFF_MASK; - } - /* increment rx-buffer pointer */ - dsp->tx_R = r; - /* write incremented read pointer */ - } - /* scroll up delays */ - i = MAX_SECONDS_JITTER_CHECK - 1; - while (i) { - dsp->rx_delay[i] = dsp->rx_delay[i - 1]; - dsp->tx_delay[i] = dsp->tx_delay[i - 1]; - i--; - } - dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ - dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ - } - } - - /* if next event would be in the past ... */ - if ((s32)(dsp_spl_jiffies + dsp_tics-jiffies) <= 0) - dsp_spl_jiffies = jiffies + 1; - else - dsp_spl_jiffies += dsp_tics; - - dsp_spl_tl.expires = dsp_spl_jiffies; - add_timer(&dsp_spl_tl); - - /* unlock */ - spin_unlock_irqrestore(&dsp_lock, flags); -} - -/* - * audio data is transmitted from upper layer to the dsp - */ -void -dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) -{ - u_int w, ww; - u8 *d, *p; - int space; /* todo: , l = skb->len; */ -#ifdef CMX_TX_DEBUG - char debugbuf[256] = ""; -#endif - - /* check if there is enough space, and then copy */ - w = dsp->tx_W; - ww = dsp->tx_R; - p = dsp->tx_buff; - d = skb->data; - space = (ww - w - 1) & CMX_BUFF_MASK; - /* write-pointer should not overrun nor reach read pointer */ - if (space < skb->len) { - /* write to the space we have left */ - ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */ - if (dsp_debug & DEBUG_DSP_CLOCK) - printk(KERN_DEBUG "%s: TX overflow space=%d skb->len=" - "%d, w=0x%04x, ww=0x%04x\n", __func__, space, - skb->len, w, ww); - } else - /* write until all byte are copied */ - ww = (w + skb->len) & CMX_BUFF_MASK; - dsp->tx_W = ww; - /* show current buffer */ -#ifdef CMX_DEBUG - printk(KERN_DEBUG - "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", - (u_long)dsp, (ww - w) & CMX_BUFF_MASK, w, ww, dsp->name); -#endif - - /* copy transmit data to tx-buffer */ -#ifdef CMX_TX_DEBUG - sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p); -#endif - while (w != ww) { -#ifdef CMX_TX_DEBUG - if (strlen(debugbuf) < 48) - sprintf(debugbuf + strlen(debugbuf), " %02x", *d); -#endif - p[w] = *d++; - w = (w + 1) & CMX_BUFF_MASK; - } -#ifdef CMX_TX_DEBUG - printk(KERN_DEBUG "%s\n", debugbuf); -#endif - -} - -/* - * hdlc data is received from card and sent to all members. - */ -void -dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) -{ - struct sk_buff *nskb = NULL; - struct dsp_conf_member *member; - struct mISDNhead *hh; - - /* not if not active */ - if (!dsp->b_active) - return; - - /* check if we have sompen */ - if (skb->len < 1) - return; - - /* no conf */ - if (!dsp->conf) { - /* in case of software echo */ - if (dsp->echo.software) { - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - hh = mISDN_HEAD_P(nskb); - hh->prim = PH_DATA_REQ; - hh->id = 0; - skb_queue_tail(&dsp->sendq, nskb); - schedule_work(&dsp->workq); - } - } - return; - } - /* in case of hardware conference */ - if (dsp->conf->hardware) - return; - list_for_each_entry(member, &dsp->conf->mlist, list) { - if (dsp->echo.software || member->dsp != dsp) { - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - hh = mISDN_HEAD_P(nskb); - hh->prim = PH_DATA_REQ; - hh->id = 0; - skb_queue_tail(&member->dsp->sendq, nskb); - schedule_work(&member->dsp->workq); - } - } - } -} diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c deleted file mode 100644 index d0aa415a6b09..000000000000 --- a/drivers/isdn/mISDN/dsp_core.c +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * Author Andreas Eversberg (jolly@eversberg.eu) - * Based on source code structure by - * Karsten Keil (keil@isdn4linux.de) - * - * This file is (c) under GNU PUBLIC LICENSE - * - * Thanks to Karsten Keil (great drivers) - * Cologne Chip (great chips) - * - * This module does: - * Real-time tone generation - * DTMF detection - * Real-time cross-connection and conferrence - * Compensate jitter due to system load and hardware fault. - * All features are done in kernel space and will be realized - * using hardware, if available and supported by chip set. - * Blowfish encryption/decryption - */ - -/* STRUCTURE: - * - * The dsp module provides layer 2 for b-channels (64kbit). It provides - * transparent audio forwarding with special digital signal processing: - * - * - (1) generation of tones - * - (2) detection of dtmf tones - * - (3) crossconnecting and conferences (clocking) - * - (4) echo generation for delay test - * - (5) volume control - * - (6) disable receive data - * - (7) pipeline - * - (8) encryption/decryption - * - * Look: - * TX RX - * ------upper layer------ - * | ^ - * | |(6) - * v | - * +-----+-------------+-----+ - * |(3)(4) | - * | CMX | - * | | - * | +-------------+ - * | | ^ - * | | | - * |+---------+| +----+----+ - * ||(1) || |(2) | - * || || | | - * || Tones || | DTMF | - * || || | | - * || || | | - * |+----+----+| +----+----+ - * +-----+-----+ ^ - * | | - * v | - * +----+----+ +----+----+ - * |(5) | |(5) | - * | | | | - * |TX Volume| |RX Volume| - * | | | | - * | | | | - * +----+----+ +----+----+ - * | ^ - * | | - * v | - * +----+-------------+----+ - * |(7) | - * | | - * | Pipeline Processing | - * | | - * | | - * +----+-------------+----+ - * | ^ - * | | - * v | - * +----+----+ +----+----+ - * |(8) | |(8) | - * | | | | - * | Encrypt | | Decrypt | - * | | | | - * | | | | - * +----+----+ +----+----+ - * | ^ - * | | - * v | - * ------card layer------ - * TX RX - * - * Above you can see the logical data flow. If software is used to do the - * process, it is actually the real data flow. If hardware is used, data - * may not flow, but hardware commands to the card, to provide the data flow - * as shown. - * - * NOTE: The channel must be activated in order to make dsp work, even if - * no data flow to the upper layer is intended. Activation can be done - * after and before controlling the setting using PH_CONTROL requests. - * - * DTMF: Will be detected by hardware if possible. It is done before CMX - * processing. - * - * Tones: Will be generated via software if endless looped audio fifos are - * not supported by hardware. Tones will override all data from CMX. - * It is not required to join a conference to use tones at any time. - * - * CMX: Is transparent when not used. When it is used, it will do - * crossconnections and conferences via software if not possible through - * hardware. If hardware capability is available, hardware is used. - * - * Echo: Is generated by CMX and is used to check performance of hard and - * software CMX. - * - * The CMX has special functions for conferences with one, two and more - * members. It will allow different types of data flow. Receive and transmit - * data to/form upper layer may be switched on/off individually without losing - * features of CMX, Tones and DTMF. - * - * Echo Cancellation: Sometimes we like to cancel echo from the interface. - * Note that a VoIP call may not have echo caused by the IP phone. The echo - * is generated by the telephone line connected to it. Because the delay - * is high, it becomes an echo. RESULT: Echo Cachelation is required if - * both echo AND delay is applied to an interface. - * Remember that software CMX always generates a more or less delay. - * - * If all used features can be realized in hardware, and if transmit and/or - * receive data ist disabled, the card may not send/receive any data at all. - * Not receiving is useful if only announcements are played. Not sending is - * useful if an answering machine records audio. Not sending and receiving is - * useful during most states of the call. If supported by hardware, tones - * will be played without cpu load. Small PBXs and NT-Mode applications will - * not need expensive hardware when processing calls. - * - * - * LOCKING: - * - * When data is received from upper or lower layer (card), the complete dsp - * module is locked by a global lock. This lock MUST lock irq, because it - * must lock timer events by DSP poll timer. - * When data is ready to be transmitted down, the data is queued and sent - * outside lock and timer event. - * PH_CONTROL must not change any settings, join or split conference members - * during process of data. - * - * HDLC: - * - * It works quite the same as transparent, except that HDLC data is forwarded - * to all other conference members if no hardware bridging is possible. - * Send data will be writte to sendq. Sendq will be sent if confirm is received. - * Conference cannot join, if one member is not hdlc. - * - */ - -#include -#include -#include -#include -#include -#include -#include "core.h" -#include "dsp.h" - -static const char *mISDN_dsp_revision = "2.0"; - -static int debug; -static int options; -static int poll; -static int dtmfthreshold = 100; - -MODULE_AUTHOR("Andreas Eversberg"); -module_param(debug, uint, S_IRUGO | S_IWUSR); -module_param(options, uint, S_IRUGO | S_IWUSR); -module_param(poll, uint, S_IRUGO | S_IWUSR); -module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR); -MODULE_DESCRIPTION("mISDN driver for Digital Audio Processing of transparent data"); -MODULE_LICENSE("GPL"); - -/*int spinnest = 0;*/ - -DEFINE_SPINLOCK(dsp_lock); /* global dsp lock */ -LIST_HEAD(dsp_ilist); -LIST_HEAD(conf_ilist); -int dsp_debug; -int dsp_options; -int dsp_poll, dsp_tics; - -/* check if rx may be turned off or must be turned on */ -static void -dsp_rx_off_member(struct dsp *dsp) -{ - struct mISDN_ctrl_req cq; - int rx_off = 1; - - memset(&cq, 0, sizeof(cq)); - - if (!dsp->features_rx_off) - return; - - /* not disabled */ - if (!dsp->rx_disabled) - rx_off = 0; - /* software dtmf */ - else if (dsp->dtmf.software) - rx_off = 0; - /* echo in software */ - else if (dsp->echo.software) - rx_off = 0; - /* bridge in software */ - else if (dsp->conf && dsp->conf->software) - rx_off = 0; - /* data is not required by user space and not required - * for echo dtmf detection, soft-echo, soft-bridging */ - - if (rx_off == dsp->rx_is_off) - return; - - if (!dsp->ch.peer) { - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: no peer, no rx_off\n", - __func__); - return; - } - cq.op = MISDN_CTRL_RX_OFF; - cq.p1 = rx_off; - if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { - printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", - __func__); - return; - } - dsp->rx_is_off = rx_off; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: %s set rx_off = %d\n", - __func__, dsp->name, rx_off); -} -static void -dsp_rx_off(struct dsp *dsp) -{ - struct dsp_conf_member *member; - - if (dsp_options & DSP_OPT_NOHARDWARE) - return; - - /* no conf */ - if (!dsp->conf) { - dsp_rx_off_member(dsp); - return; - } - /* check all members in conf */ - list_for_each_entry(member, &dsp->conf->mlist, list) { - dsp_rx_off_member(member->dsp); - } -} - -/* enable "fill empty" feature */ -static void -dsp_fill_empty(struct dsp *dsp) -{ - struct mISDN_ctrl_req cq; - - memset(&cq, 0, sizeof(cq)); - - if (!dsp->ch.peer) { - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: no peer, no fill_empty\n", - __func__); - return; - } - cq.op = MISDN_CTRL_FILL_EMPTY; - cq.p1 = 1; - cq.p2 = dsp_silence; - if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { - printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", - __func__); - return; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: %s set fill_empty = 1\n", - __func__, dsp->name); -} - -static int -dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) -{ - struct sk_buff *nskb; - int ret = 0; - int cont; - u8 *data; - int len; - - if (skb->len < sizeof(int)) { - printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__); - return -EINVAL; - } - cont = *((int *)skb->data); - len = skb->len - sizeof(int); - data = skb->data + sizeof(int); - - switch (cont) { - case DTMF_TONE_START: /* turn on DTMF */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: start dtmf\n", __func__); - if (len == sizeof(int)) { - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_NOTICE "changing DTMF Threshold " - "to %d\n", *((int *)data)); - dsp->dtmf.treshold = (*(int *)data) * 10000; - } - dsp->dtmf.enable = 1; - /* init goertzel */ - dsp_dtmf_goertzel_init(dsp); - - /* check dtmf hardware */ - dsp_dtmf_hardware(dsp); - dsp_rx_off(dsp); - break; - case DTMF_TONE_STOP: /* turn off DTMF */ - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: stop dtmf\n", __func__); - dsp->dtmf.enable = 0; - dsp->dtmf.hardware = 0; - dsp->dtmf.software = 0; - break; - case DSP_CONF_JOIN: /* join / update conference */ - if (len < sizeof(int)) { - ret = -EINVAL; - break; - } - if (*((u32 *)data) == 0) - goto conf_split; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: join conference %d\n", - __func__, *((u32 *)data)); - ret = dsp_cmx_conf(dsp, *((u32 *)data)); - /* dsp_cmx_hardware will also be called here */ - dsp_rx_off(dsp); - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; - case DSP_CONF_SPLIT: /* remove from conference */ - conf_split: - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: release conference\n", __func__); - ret = dsp_cmx_conf(dsp, 0); - /* dsp_cmx_hardware will also be called here */ - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - dsp_rx_off(dsp); - break; - case DSP_TONE_PATT_ON: /* play tone */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (len < sizeof(int)) { - ret = -EINVAL; - break; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: turn tone 0x%x on\n", - __func__, *((int *)skb->data)); - ret = dsp_tone(dsp, *((int *)data)); - if (!ret) { - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - } - if (!dsp->tone.tone) - goto tone_off; - break; - case DSP_TONE_PATT_OFF: /* stop tone */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: turn tone off\n", __func__); - dsp_tone(dsp, 0); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - /* reset tx buffers (user space data) */ - tone_off: - dsp->rx_W = 0; - dsp->rx_R = 0; - break; - case DSP_VOL_CHANGE_TX: /* change volume */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (len < sizeof(int)) { - ret = -EINVAL; - break; - } - dsp->tx_volume = *((int *)data); - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: change tx vol to %d\n", - __func__, dsp->tx_volume); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_dtmf_hardware(dsp); - dsp_rx_off(dsp); - break; - case DSP_VOL_CHANGE_RX: /* change volume */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (len < sizeof(int)) { - ret = -EINVAL; - break; - } - dsp->rx_volume = *((int *)data); - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: change rx vol to %d\n", - __func__, dsp->tx_volume); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_dtmf_hardware(dsp); - dsp_rx_off(dsp); - break; - case DSP_ECHO_ON: /* enable echo */ - dsp->echo.software = 1; /* soft echo */ - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; - case DSP_ECHO_OFF: /* disable echo */ - dsp->echo.software = 0; - dsp->echo.hardware = 0; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; - case DSP_RECEIVE_ON: /* enable receive to user space */ - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: enable receive to user " - "space\n", __func__); - dsp->rx_disabled = 0; - dsp_rx_off(dsp); - break; - case DSP_RECEIVE_OFF: /* disable receive to user space */ - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: disable receive to " - "user space\n", __func__); - dsp->rx_disabled = 1; - dsp_rx_off(dsp); - break; - case DSP_MIX_ON: /* enable mixing of tx data */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: enable mixing of " - "tx-data with conf members\n", __func__); - dsp->tx_mix = 1; - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; - case DSP_MIX_OFF: /* disable mixing of tx data */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: disable mixing of " - "tx-data with conf members\n", __func__); - dsp->tx_mix = 0; - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; - case DSP_TXDATA_ON: /* enable txdata */ - dsp->tx_data = 1; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: enable tx-data\n", __func__); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; - case DSP_TXDATA_OFF: /* disable txdata */ - dsp->tx_data = 0; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: disable tx-data\n", __func__); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - if (dsp_debug & DEBUG_DSP_CMX) - dsp_cmx_debug(dsp); - break; - case DSP_DELAY: /* use delay algorithm instead of dynamic - jitter algorithm */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (len < sizeof(int)) { - ret = -EINVAL; - break; - } - dsp->cmx_delay = (*((int *)data)) << 3; - /* milliseconds to samples */ - if (dsp->cmx_delay >= (CMX_BUFF_HALF >> 1)) - /* clip to half of maximum usable buffer - (half of half buffer) */ - dsp->cmx_delay = (CMX_BUFF_HALF >> 1) - 1; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: use delay algorithm to " - "compensate jitter (%d samples)\n", - __func__, dsp->cmx_delay); - break; - case DSP_JITTER: /* use dynamic jitter algorithm instead of - delay algorithm */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - dsp->cmx_delay = 0; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: use jitter algorithm to " - "compensate jitter\n", __func__); - break; - case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - dsp->tx_dejitter = 1; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: use dejitter on TX " - "buffer\n", __func__); - break; - case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - dsp->tx_dejitter = 0; - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: use TX buffer without " - "dejittering\n", __func__); - break; - case DSP_PIPELINE_CFG: - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (len > 0 && ((char *)data)[len - 1]) { - printk(KERN_DEBUG "%s: pipeline config string " - "is not NULL terminated!\n", __func__); - ret = -EINVAL; - } else { - dsp->pipeline.inuse = 1; - dsp_cmx_hardware(dsp->conf, dsp); - ret = dsp_pipeline_build(&dsp->pipeline, - len > 0 ? data : NULL); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - } - break; - case DSP_BF_ENABLE_KEY: /* turn blowfish on */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (len < 4 || len > 56) { - ret = -EINVAL; - break; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: turn blowfish on (key " - "not shown)\n", __func__); - ret = dsp_bf_init(dsp, (u8 *)data, len); - /* set new cont */ - if (!ret) - cont = DSP_BF_ACCEPT; - else - cont = DSP_BF_REJECT; - /* send indication if it worked to set it */ - nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY, - sizeof(int), &cont, GFP_ATOMIC); - if (nskb) { - if (dsp->up) { - if (dsp->up->send(dsp->up, nskb)) - dev_kfree_skb(nskb); - } else - dev_kfree_skb(nskb); - } - if (!ret) { - dsp_cmx_hardware(dsp->conf, dsp); - dsp_dtmf_hardware(dsp); - dsp_rx_off(dsp); - } - break; - case DSP_BF_DISABLE: /* turn blowfish off */ - if (dsp->hdlc) { - ret = -EINVAL; - break; - } - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: turn blowfish off\n", __func__); - dsp_bf_cleanup(dsp); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_dtmf_hardware(dsp); - dsp_rx_off(dsp); - break; - default: - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", - __func__, cont); - ret = -EINVAL; - } - return ret; -} - -static void -get_features(struct mISDNchannel *ch) -{ - struct dsp *dsp = container_of(ch, struct dsp, ch); - struct mISDN_ctrl_req cq; - - if (!ch->peer) { - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: no peer, no features\n", - __func__); - return; - } - memset(&cq, 0, sizeof(cq)); - cq.op = MISDN_CTRL_GETOP; - if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) { - printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", - __func__); - return; - } - if (cq.op & MISDN_CTRL_RX_OFF) - dsp->features_rx_off = 1; - if (cq.op & MISDN_CTRL_FILL_EMPTY) - dsp->features_fill_empty = 1; - if (dsp_options & DSP_OPT_NOHARDWARE) - return; - if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { - cq.op = MISDN_CTRL_HW_FEATURES; - *((u_long *)&cq.p1) = (u_long)&dsp->features; - if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) { - printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", - __func__); - } - } else - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: features not supported for %s\n", - __func__, dsp->name); -} - -static int -dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct dsp *dsp = container_of(ch, struct dsp, ch); - struct mISDNhead *hh; - int ret = 0; - u8 *digits = NULL; - u_long flags; - - hh = mISDN_HEAD_P(skb); - switch (hh->prim) { - /* FROM DOWN */ - case (PH_DATA_CNF): - dsp->data_pending = 0; - /* trigger next hdlc frame, if any */ - if (dsp->hdlc) { - spin_lock_irqsave(&dsp_lock, flags); - if (dsp->b_active) - schedule_work(&dsp->workq); - spin_unlock_irqrestore(&dsp_lock, flags); - } - break; - case (PH_DATA_IND): - case (DL_DATA_IND): - if (skb->len < 1) { - ret = -EINVAL; - break; - } - if (dsp->rx_is_off) { - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: rx-data during rx_off" - " for %s\n", - __func__, dsp->name); - } - if (dsp->hdlc) { - /* hdlc */ - spin_lock_irqsave(&dsp_lock, flags); - dsp_cmx_hdlc(dsp, skb); - spin_unlock_irqrestore(&dsp_lock, flags); - if (dsp->rx_disabled) { - /* if receive is not allowed */ - break; - } - hh->prim = DL_DATA_IND; - if (dsp->up) - return dsp->up->send(dsp->up, skb); - break; - } - - spin_lock_irqsave(&dsp_lock, flags); - - /* decrypt if enabled */ - if (dsp->bf_enable) - dsp_bf_decrypt(dsp, skb->data, skb->len); - /* pipeline */ - if (dsp->pipeline.inuse) - dsp_pipeline_process_rx(&dsp->pipeline, skb->data, - skb->len, hh->id); - /* change volume if requested */ - if (dsp->rx_volume) - dsp_change_volume(skb, dsp->rx_volume); - /* check if dtmf soft decoding is turned on */ - if (dsp->dtmf.software) { - digits = dsp_dtmf_goertzel_decode(dsp, skb->data, - skb->len, (dsp_options & DSP_OPT_ULAW) ? 1 : 0); - } - /* we need to process receive data if software */ - if (dsp->conf && dsp->conf->software) { - /* process data from card at cmx */ - dsp_cmx_receive(dsp, skb); - } - - spin_unlock_irqrestore(&dsp_lock, flags); - - /* send dtmf result, if any */ - if (digits) { - while (*digits) { - int k; - struct sk_buff *nskb; - if (dsp_debug & DEBUG_DSP_DTMF) - printk(KERN_DEBUG "%s: digit" - "(%c) to layer %s\n", - __func__, *digits, dsp->name); - k = *digits | DTMF_TONE_VAL; - nskb = _alloc_mISDN_skb(PH_CONTROL_IND, - MISDN_ID_ANY, sizeof(int), &k, - GFP_ATOMIC); - if (nskb) { - if (dsp->up) { - if (dsp->up->send( - dsp->up, nskb)) - dev_kfree_skb(nskb); - } else - dev_kfree_skb(nskb); - } - digits++; - } - } - if (dsp->rx_disabled) { - /* if receive is not allowed */ - break; - } - hh->prim = DL_DATA_IND; - if (dsp->up) - return dsp->up->send(dsp->up, skb); - break; - case (PH_CONTROL_IND): - if (dsp_debug & DEBUG_DSP_DTMFCOEFF) - printk(KERN_DEBUG "%s: PH_CONTROL INDICATION " - "received: %x (len %d) %s\n", __func__, - hh->id, skb->len, dsp->name); - switch (hh->id) { - case (DTMF_HFC_COEF): /* getting coefficients */ - if (!dsp->dtmf.hardware) { - if (dsp_debug & DEBUG_DSP_DTMFCOEFF) - printk(KERN_DEBUG "%s: ignoring DTMF " - "coefficients from HFC\n", - __func__); - break; - } - digits = dsp_dtmf_goertzel_decode(dsp, skb->data, - skb->len, 2); - while (*digits) { - int k; - struct sk_buff *nskb; - if (dsp_debug & DEBUG_DSP_DTMF) - printk(KERN_DEBUG "%s: digit" - "(%c) to layer %s\n", - __func__, *digits, dsp->name); - k = *digits | DTMF_TONE_VAL; - nskb = _alloc_mISDN_skb(PH_CONTROL_IND, - MISDN_ID_ANY, sizeof(int), &k, - GFP_ATOMIC); - if (nskb) { - if (dsp->up) { - if (dsp->up->send( - dsp->up, nskb)) - dev_kfree_skb(nskb); - } else - dev_kfree_skb(nskb); - } - digits++; - } - break; - case (HFC_VOL_CHANGE_TX): /* change volume */ - if (skb->len != sizeof(int)) { - ret = -EINVAL; - break; - } - spin_lock_irqsave(&dsp_lock, flags); - dsp->tx_volume = *((int *)skb->data); - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: change tx volume to " - "%d\n", __func__, dsp->tx_volume); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_dtmf_hardware(dsp); - dsp_rx_off(dsp); - spin_unlock_irqrestore(&dsp_lock, flags); - break; - default: - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: ctrl ind %x unhandled " - "%s\n", __func__, hh->id, dsp->name); - ret = -EINVAL; - } - break; - case (PH_ACTIVATE_IND): - case (PH_ACTIVATE_CNF): - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: b_channel is now active %s\n", - __func__, dsp->name); - /* bchannel now active */ - spin_lock_irqsave(&dsp_lock, flags); - dsp->b_active = 1; - dsp->data_pending = 0; - dsp->rx_init = 1; - /* rx_W and rx_R will be adjusted on first frame */ - dsp->rx_W = 0; - dsp->rx_R = 0; - memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff)); - dsp_cmx_hardware(dsp->conf, dsp); - dsp_dtmf_hardware(dsp); - dsp_rx_off(dsp); - spin_unlock_irqrestore(&dsp_lock, flags); - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: done with activation, sending " - "confirm to user space. %s\n", __func__, - dsp->name); - /* send activation to upper layer */ - hh->prim = DL_ESTABLISH_CNF; - if (dsp->up) - return dsp->up->send(dsp->up, skb); - break; - case (PH_DEACTIVATE_IND): - case (PH_DEACTIVATE_CNF): - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", - __func__, dsp->name); - /* bchannel now inactive */ - spin_lock_irqsave(&dsp_lock, flags); - dsp->b_active = 0; - dsp->data_pending = 0; - dsp_cmx_hardware(dsp->conf, dsp); - dsp_rx_off(dsp); - spin_unlock_irqrestore(&dsp_lock, flags); - hh->prim = DL_RELEASE_CNF; - if (dsp->up) - return dsp->up->send(dsp->up, skb); - break; - /* FROM UP */ - case (DL_DATA_REQ): - case (PH_DATA_REQ): - if (skb->len < 1) { - ret = -EINVAL; - break; - } - if (dsp->hdlc) { - /* hdlc */ - if (!dsp->b_active) { - ret = -EIO; - break; - } - hh->prim = PH_DATA_REQ; - spin_lock_irqsave(&dsp_lock, flags); - skb_queue_tail(&dsp->sendq, skb); - schedule_work(&dsp->workq); - spin_unlock_irqrestore(&dsp_lock, flags); - return 0; - } - /* send data to tx-buffer (if no tone is played) */ - if (!dsp->tone.tone) { - spin_lock_irqsave(&dsp_lock, flags); - dsp_cmx_transmit(dsp, skb); - spin_unlock_irqrestore(&dsp_lock, flags); - } - break; - case (PH_CONTROL_REQ): - spin_lock_irqsave(&dsp_lock, flags); - ret = dsp_control_req(dsp, hh, skb); - spin_unlock_irqrestore(&dsp_lock, flags); - break; - case (DL_ESTABLISH_REQ): - case (PH_ACTIVATE_REQ): - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: activating b_channel %s\n", - __func__, dsp->name); - if (dsp->dtmf.hardware || dsp->dtmf.software) - dsp_dtmf_goertzel_init(dsp); - get_features(ch); - /* enable fill_empty feature */ - if (dsp->features_fill_empty) - dsp_fill_empty(dsp); - /* send ph_activate */ - hh->prim = PH_ACTIVATE_REQ; - if (ch->peer) - return ch->recv(ch->peer, skb); - break; - case (DL_RELEASE_REQ): - case (PH_DEACTIVATE_REQ): - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: releasing b_channel %s\n", - __func__, dsp->name); - spin_lock_irqsave(&dsp_lock, flags); - dsp->tone.tone = 0; - dsp->tone.hardware = 0; - dsp->tone.software = 0; - if (timer_pending(&dsp->tone.tl)) - timer_delete(&dsp->tone.tl); - if (dsp->conf) - dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be - called here */ - skb_queue_purge(&dsp->sendq); - spin_unlock_irqrestore(&dsp_lock, flags); - hh->prim = PH_DEACTIVATE_REQ; - if (ch->peer) - return ch->recv(ch->peer, skb); - break; - default: - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: msg %x unhandled %s\n", - __func__, hh->prim, dsp->name); - ret = -EINVAL; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct dsp *dsp = container_of(ch, struct dsp, ch); - u_long flags; - - if (debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); - - switch (cmd) { - case OPEN_CHANNEL: - break; - case CLOSE_CHANNEL: - if (dsp->ch.peer) - dsp->ch.peer->ctrl(dsp->ch.peer, CLOSE_CHANNEL, NULL); - - /* wait until workqueue has finished, - * must lock here, or we may hit send-process currently - * queueing. */ - spin_lock_irqsave(&dsp_lock, flags); - dsp->b_active = 0; - spin_unlock_irqrestore(&dsp_lock, flags); - /* MUST not be locked, because it waits until queue is done. */ - cancel_work_sync(&dsp->workq); - spin_lock_irqsave(&dsp_lock, flags); - if (timer_pending(&dsp->tone.tl)) - timer_delete(&dsp->tone.tl); - skb_queue_purge(&dsp->sendq); - if (dsp_debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s: releasing member %s\n", - __func__, dsp->name); - dsp->b_active = 0; - dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be called - here */ - dsp_pipeline_destroy(&dsp->pipeline); - - if (dsp_debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s: remove & destroy object %s\n", - __func__, dsp->name); - list_del(&dsp->list); - spin_unlock_irqrestore(&dsp_lock, flags); - - if (dsp_debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s: dsp instance released\n", - __func__); - vfree(dsp); - module_put(THIS_MODULE); - break; - } - return 0; -} - -static void -dsp_send_bh(struct work_struct *work) -{ - struct dsp *dsp = container_of(work, struct dsp, workq); - struct sk_buff *skb; - struct mISDNhead *hh; - - if (dsp->hdlc && dsp->data_pending) - return; /* wait until data has been acknowledged */ - - /* send queued data */ - while ((skb = skb_dequeue(&dsp->sendq))) { - /* in locked date, we must have still data in queue */ - if (dsp->data_pending) { - if (dsp_debug & DEBUG_DSP_CORE) - printk(KERN_DEBUG "%s: fifo full %s, this is " - "no bug!\n", __func__, dsp->name); - /* flush transparent data, if not acked */ - dev_kfree_skb(skb); - continue; - } - hh = mISDN_HEAD_P(skb); - if (hh->prim == DL_DATA_REQ) { - /* send packet up */ - if (dsp->up) { - if (dsp->up->send(dsp->up, skb)) - dev_kfree_skb(skb); - } else - dev_kfree_skb(skb); - } else { - /* send packet down */ - if (dsp->ch.peer) { - dsp->data_pending = 1; - if (dsp->ch.recv(dsp->ch.peer, skb)) { - dev_kfree_skb(skb); - dsp->data_pending = 0; - } - } else - dev_kfree_skb(skb); - } - } -} - -static int -dspcreate(struct channel_req *crq) -{ - struct dsp *ndsp; - u_long flags; - - if (crq->protocol != ISDN_P_B_L2DSP - && crq->protocol != ISDN_P_B_L2DSPHDLC) - return -EPROTONOSUPPORT; - ndsp = vzalloc(sizeof(struct dsp)); - if (!ndsp) { - printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__); - return -ENOMEM; - } - if (dsp_debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__); - - /* default enabled */ - INIT_WORK(&ndsp->workq, (void *)dsp_send_bh); - skb_queue_head_init(&ndsp->sendq); - ndsp->ch.send = dsp_function; - ndsp->ch.ctrl = dsp_ctrl; - ndsp->up = crq->ch; - crq->ch = &ndsp->ch; - if (crq->protocol == ISDN_P_B_L2DSP) { - crq->protocol = ISDN_P_B_RAW; - ndsp->hdlc = 0; - } else { - crq->protocol = ISDN_P_B_HDLC; - ndsp->hdlc = 1; - } - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s:cannot get module\n", - __func__); - - sprintf(ndsp->name, "DSP_C%x(0x%p)", - ndsp->up->st->dev->id + 1, ndsp); - /* set frame size to start */ - ndsp->features.hfc_id = -1; /* current PCM id */ - ndsp->features.pcm_id = -1; /* current PCM id */ - ndsp->pcm_slot_rx = -1; /* current CPM slot */ - ndsp->pcm_slot_tx = -1; - ndsp->pcm_bank_rx = -1; - ndsp->pcm_bank_tx = -1; - ndsp->hfc_conf = -1; /* current conference number */ - /* set tone timer */ - timer_setup(&ndsp->tone.tl, dsp_tone_timeout, 0); - - if (dtmfthreshold < 20 || dtmfthreshold > 500) - dtmfthreshold = 200; - ndsp->dtmf.treshold = dtmfthreshold * 10000; - - /* init pipeline append to list */ - spin_lock_irqsave(&dsp_lock, flags); - dsp_pipeline_init(&ndsp->pipeline); - list_add_tail(&ndsp->list, &dsp_ilist); - spin_unlock_irqrestore(&dsp_lock, flags); - - return 0; -} - - -static struct Bprotocol DSP = { - .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK)) - | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)), - .name = "dsp", - .create = dspcreate -}; - -static int __init dsp_init(void) -{ - int err; - int tics; - - printk(KERN_INFO "DSP module %s\n", mISDN_dsp_revision); - - dsp_options = options; - dsp_debug = debug; - - /* set packet size */ - dsp_poll = poll; - if (dsp_poll) { - if (dsp_poll > MAX_POLL) { - printk(KERN_ERR "%s: Wrong poll value (%d), use %d " - "maximum.\n", __func__, poll, MAX_POLL); - err = -EINVAL; - return err; - } - if (dsp_poll < 8) { - printk(KERN_ERR "%s: Wrong poll value (%d), use 8 " - "minimum.\n", __func__, dsp_poll); - err = -EINVAL; - return err; - } - dsp_tics = poll * HZ / 8000; - if (dsp_tics * 8000 != poll * HZ) { - printk(KERN_INFO "mISDN_dsp: Cannot clock every %d " - "samples (0,125 ms). It is not a multiple of " - "%d HZ.\n", poll, HZ); - err = -EINVAL; - return err; - } - } else { - poll = 8; - while (poll <= MAX_POLL) { - tics = (poll * HZ) / 8000; - if (tics * 8000 == poll * HZ) { - dsp_tics = tics; - dsp_poll = poll; - if (poll >= 64) - break; - } - poll++; - } - } - if (dsp_poll == 0) { - printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel " - "clock that equals exactly the duration of 8-256 " - "samples. (Choose kernel clock speed like 100, 250, " - "300, 1000)\n"); - err = -EINVAL; - return err; - } - printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals " - "%d jiffies.\n", dsp_poll, dsp_tics); - - /* init conversion tables */ - dsp_audio_generate_law_tables(); - dsp_silence = (dsp_options & DSP_OPT_ULAW) ? 0xff : 0x2a; - dsp_audio_law_to_s32 = (dsp_options & DSP_OPT_ULAW) ? - dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32; - dsp_audio_generate_s2law_table(); - dsp_audio_generate_seven(); - dsp_audio_generate_mix_table(); - if (dsp_options & DSP_OPT_ULAW) - dsp_audio_generate_ulaw_samples(); - dsp_audio_generate_volume_changes(); - - err = dsp_pipeline_module_init(); - if (err) { - printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, " - "error(%d)\n", err); - return err; - } - - err = mISDN_register_Bprotocol(&DSP); - if (err) { - printk(KERN_ERR "Can't register %s error(%d)\n", DSP.name, err); - return err; - } - - /* set sample timer */ - timer_setup(&dsp_spl_tl, dsp_cmx_send, 0); - dsp_spl_tl.expires = jiffies + dsp_tics; - dsp_spl_jiffies = dsp_spl_tl.expires; - add_timer(&dsp_spl_tl); - - return 0; -} - - -static void __exit dsp_cleanup(void) -{ - mISDN_unregister_Bprotocol(&DSP); - - timer_delete_sync(&dsp_spl_tl); - - if (!list_empty(&dsp_ilist)) { - printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not " - "empty.\n"); - } - if (!list_empty(&conf_ilist)) { - printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not " - "all memory freed.\n"); - } - - dsp_pipeline_module_exit(); -} - -module_init(dsp_init); -module_exit(dsp_cleanup); diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c deleted file mode 100644 index 642f30be5ce2..000000000000 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * DTMF decoder. - * - * Copyright by Andreas Eversberg (jolly@eversberg.eu) - * based on different decoders such as ISDN4Linux - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include "core.h" -#include "dsp.h" - -#define NCOEFF 8 /* number of frequencies to be analyzed */ - -/* For DTMF recognition: - * 2 * cos(2 * PI * k / N) precalculated for all k - */ -static u64 cos2pik[NCOEFF] = -{ - /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */ - 55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630 -}; - -/* digit matrix */ -static char dtmf_matrix[4][4] = -{ - {'1', '2', '3', 'A'}, - {'4', '5', '6', 'B'}, - {'7', '8', '9', 'C'}, - {'*', '0', '#', 'D'} -}; - -/* dtmf detection using goertzel algorithm - * init function - */ -void dsp_dtmf_goertzel_init(struct dsp *dsp) -{ - dsp->dtmf.size = 0; - dsp->dtmf.lastwhat = '\0'; - dsp->dtmf.lastdigit = '\0'; - dsp->dtmf.count = 0; -} - -/* check for hardware or software features - */ -void dsp_dtmf_hardware(struct dsp *dsp) -{ - int hardware = 1; - - if (!dsp->dtmf.enable) - return; - - if (!dsp->features.hfc_dtmf) - hardware = 0; - - /* check for volume change */ - if (dsp->tx_volume) { - if (dsp_debug & DEBUG_DSP_DTMF) - printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because tx_volume is changed\n", - __func__, dsp->name); - hardware = 0; - } - if (dsp->rx_volume) { - if (dsp_debug & DEBUG_DSP_DTMF) - printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because rx_volume is changed\n", - __func__, dsp->name); - hardware = 0; - } - /* check if encryption is enabled */ - if (dsp->bf_enable) { - if (dsp_debug & DEBUG_DSP_DTMF) - printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because encryption is enabled\n", - __func__, dsp->name); - hardware = 0; - } - /* check if pipeline exists */ - if (dsp->pipeline.inuse) { - if (dsp_debug & DEBUG_DSP_DTMF) - printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because pipeline exists.\n", - __func__, dsp->name); - hardware = 0; - } - - dsp->dtmf.hardware = hardware; - dsp->dtmf.software = !hardware; -} - - -/************************************************************* - * calculate the coefficients of the given sample and decode * - *************************************************************/ - -/* the given sample is decoded. if the sample is not long enough for a - * complete frame, the decoding is finished and continued with the next - * call of this function. - * - * the algorithm is very good for detection with a minimum of errors. i - * tested it allot. it even works with very short tones (40ms). the only - * disadvantage is, that it doesn't work good with different volumes of both - * tones. this will happen, if accoustically coupled dialers are used. - * it sometimes detects tones during speech, which is normal for decoders. - * use sequences to given commands during calls. - * - * dtmf - points to a structure of the current dtmf state - * spl and len - the sample - * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder - */ - -u8 -*dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt) -{ - u8 what; - int size; - signed short *buf; - s32 sk, sk1, sk2; - int k, n, i; - s32 *hfccoeff; - s32 result[NCOEFF], tresh, treshl; - int lowgroup, highgroup; - s64 cos2pik_; - - dsp->dtmf.digits[0] = '\0'; - - /* Note: The function will loop until the buffer has not enough samples - * left to decode a full frame. - */ -again: - /* convert samples */ - size = dsp->dtmf.size; - buf = dsp->dtmf.buffer; - switch (fmt) { - case 0: /* alaw */ - case 1: /* ulaw */ - while (size < DSP_DTMF_NPOINTS && len) { - buf[size++] = dsp_audio_law_to_s32[*data++]; - len--; - } - break; - - case 2: /* HFC coefficients */ - default: - if (len < 64) { - if (len > 0) - printk(KERN_ERR "%s: coefficients have invalid " - "size. (is=%d < must=%d)\n", - __func__, len, 64); - return dsp->dtmf.digits; - } - hfccoeff = (s32 *)data; - for (k = 0; k < NCOEFF; k++) { - sk2 = (*hfccoeff++) >> 4; - sk = (*hfccoeff++) >> 4; - if (sk > 32767 || sk < -32767 || sk2 > 32767 - || sk2 < -32767) - printk(KERN_WARNING - "DTMF-Detection overflow\n"); - /* compute |X(k)|**2 */ - result[k] = - (sk * sk) - - (((cos2pik[k] * sk) >> 15) * sk2) + - (sk2 * sk2); - } - data += 64; - len -= 64; - goto coefficients; - break; - } - dsp->dtmf.size = size; - - if (size < DSP_DTMF_NPOINTS) - return dsp->dtmf.digits; - - dsp->dtmf.size = 0; - - /* now we have a full buffer of signed long samples - we do goertzel */ - for (k = 0; k < NCOEFF; k++) { - sk = 0; - sk1 = 0; - sk2 = 0; - buf = dsp->dtmf.buffer; - cos2pik_ = cos2pik[k]; - for (n = 0; n < DSP_DTMF_NPOINTS; n++) { - sk = ((cos2pik_ * sk1) >> 15) - sk2 + (*buf++); - sk2 = sk1; - sk1 = sk; - } - sk >>= 8; - sk2 >>= 8; - if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767) - printk(KERN_WARNING "DTMF-Detection overflow\n"); - /* compute |X(k)|**2 */ - result[k] = - (sk * sk) - - (((cos2pik[k] * sk) >> 15) * sk2) + - (sk2 * sk2); - } - - /* our (squared) coefficients have been calculated, we need to process - * them. - */ -coefficients: - tresh = 0; - for (i = 0; i < NCOEFF; i++) { - if (result[i] < 0) - result[i] = 0; - if (result[i] > dsp->dtmf.treshold) { - if (result[i] > tresh) - tresh = result[i]; - } - } - - if (tresh == 0) { - what = 0; - goto storedigit; - } - - if (dsp_debug & DEBUG_DSP_DTMFCOEFF) { - s32 tresh_100 = tresh/100; - - if (tresh_100 == 0) { - tresh_100 = 1; - printk(KERN_DEBUG - "tresh(%d) too small set tresh/100 to 1\n", - tresh); - } - printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" - " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", - result[0] / 10000, result[1] / 10000, result[2] / 10000, - result[3] / 10000, result[4] / 10000, result[5] / 10000, - result[6] / 10000, result[7] / 10000, tresh / 10000, - result[0] / (tresh_100), result[1] / (tresh_100), - result[2] / (tresh_100), result[3] / (tresh_100), - result[4] / (tresh_100), result[5] / (tresh_100), - result[6] / (tresh_100), result[7] / (tresh_100)); - } - - /* calc digit (lowgroup/highgroup) */ - lowgroup = -1; - highgroup = -1; - treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */ - tresh = tresh >> 2; /* touchtones must match within 6 dB */ - for (i = 0; i < NCOEFF; i++) { - if (result[i] < treshl) - continue; /* ignore */ - if (result[i] < tresh) { - lowgroup = -1; - highgroup = -1; - break; /* noise in between */ - } - /* good level found. This is allowed only one time per group */ - if (i < NCOEFF / 2) { - /* lowgroup */ - if (lowgroup >= 0) { - /* Bad. Another tone found. */ - lowgroup = -1; - break; - } else - lowgroup = i; - } else { - /* higroup */ - if (highgroup >= 0) { - /* Bad. Another tone found. */ - highgroup = -1; - break; - } else - highgroup = i - (NCOEFF / 2); - } - } - - /* get digit or null */ - what = 0; - if (lowgroup >= 0 && highgroup >= 0) - what = dtmf_matrix[lowgroup][highgroup]; - -storedigit: - if (what && (dsp_debug & DEBUG_DSP_DTMF)) - printk(KERN_DEBUG "DTMF what: %c\n", what); - - if (dsp->dtmf.lastwhat != what) - dsp->dtmf.count = 0; - - /* the tone (or no tone) must remain 3 times without change */ - if (dsp->dtmf.count == 2) { - if (dsp->dtmf.lastdigit != what) { - dsp->dtmf.lastdigit = what; - if (what) { - if (dsp_debug & DEBUG_DSP_DTMF) - printk(KERN_DEBUG "DTMF digit: %c\n", - what); - if ((strlen(dsp->dtmf.digits) + 1) - < sizeof(dsp->dtmf.digits)) { - dsp->dtmf.digits[strlen( - dsp->dtmf.digits) + 1] = '\0'; - dsp->dtmf.digits[strlen( - dsp->dtmf.digits)] = what; - } - } - } - } else - dsp->dtmf.count++; - - dsp->dtmf.lastwhat = what; - - goto again; -} diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h deleted file mode 100644 index 4bcdf321875d..000000000000 --- a/drivers/isdn/mISDN/dsp_ecdis.h +++ /dev/null @@ -1,96 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * SpanDSP - a series of DSP components for telephony - * - * ec_disable_detector.h - A detector which should eventually meet the - * G.164/G.165 requirements for detecting the - * 2100Hz echo cancellor disable tone. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 Steve Underwood - * - * All rights reserved. - */ - -#include "dsp_biquad.h" - -struct ec_disable_detector_state { - struct biquad2_state notch; - int notch_level; - int channel_level; - int tone_present; - int tone_cycle_duration; - int good_cycles; - int hit; -}; - - -#define FALSE 0 -#define TRUE (!FALSE) - -static inline void -echo_can_disable_detector_init(struct ec_disable_detector_state *det) -{ - /* Elliptic notch */ - /* This is actually centred at 2095Hz, but gets the balance we want, due - to the asymmetric walls of the notch */ - biquad2_init(&det->notch, - (int32_t)(-0.7600000 * 32768.0), - (int32_t)(-0.1183852 * 32768.0), - (int32_t)(-0.5104039 * 32768.0), - (int32_t)(0.1567596 * 32768.0), - (int32_t)(1.0000000 * 32768.0)); - - det->channel_level = 0; - det->notch_level = 0; - det->tone_present = FALSE; - det->tone_cycle_duration = 0; - det->good_cycles = 0; - det->hit = 0; -} -/*- End of function --------------------------------------------------------*/ - -static inline int -echo_can_disable_detector_update(struct ec_disable_detector_state *det, - int16_t amp) -{ - int16_t notched; - - notched = biquad2(&det->notch, amp); - /* Estimate the overall energy in the channel, and the energy in - the notch (i.e. overall channel energy - tone energy => noise). - Use abs instead of multiply for speed (is it really faster?). - Damp the overall energy a little more for a stable result. - Damp the notch energy a little less, so we don't damp out the - blip every time the phase reverses */ - det->channel_level += ((abs(amp) - det->channel_level) >> 5); - det->notch_level += ((abs(notched) - det->notch_level) >> 4); - if (det->channel_level > 280) { - /* There is adequate energy in the channel. - Is it mostly at 2100Hz? */ - if (det->notch_level * 6 < det->channel_level) { - /* The notch says yes, so we have the tone. */ - if (!det->tone_present) { - /* Do we get a kick every 450+-25ms? */ - if (det->tone_cycle_duration >= 425 * 8 - && det->tone_cycle_duration <= 475 * 8) { - det->good_cycles++; - if (det->good_cycles > 2) - det->hit = TRUE; - } - det->tone_cycle_duration = 0; - } - det->tone_present = TRUE; - } else - det->tone_present = FALSE; - det->tone_cycle_duration++; - } else { - det->tone_present = FALSE; - det->tone_cycle_duration = 0; - det->good_cycles = 0; - } - return det->hit; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c deleted file mode 100644 index 0cd216e28f00..000000000000 --- a/drivers/isdn/mISDN/dsp_hwec.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * dsp_hwec.c: - * builtin mISDN dsp pipeline element for enabling the hw echocanceller - * - * Copyright (C) 2007, Nadi Sarrar - * - * Nadi Sarrar - */ - -#include -#include -#include -#include -#include "core.h" -#include "dsp.h" -#include "dsp_hwec.h" - -static struct mISDN_dsp_element_arg args[] = { - { "deftaps", "128", "Set the number of taps of cancellation." }, -}; - -static struct mISDN_dsp_element dsp_hwec_p = { - .name = "hwec", - .new = NULL, - .free = NULL, - .process_tx = NULL, - .process_rx = NULL, - .num_args = ARRAY_SIZE(args), - .args = args, -}; -struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p; - -void dsp_hwec_enable(struct dsp *dsp, const char *arg) -{ - int deftaps = 128, - len; - struct mISDN_ctrl_req cq; - - if (!dsp) { - printk(KERN_ERR "%s: failed to enable hwec: dsp is NULL\n", - __func__); - return; - } - - if (!arg) - goto _do; - - len = strlen(arg); - if (!len) - goto _do; - - { - char *dup, *next, *tok, *name, *val; - int tmp; - - dup = next = kstrdup(arg, GFP_ATOMIC); - if (!dup) - return; - - while ((tok = strsep(&next, ","))) { - if (!strlen(tok)) - continue; - name = strsep(&tok, "="); - val = tok; - - if (!val) - continue; - - if (!strcmp(name, "deftaps")) { - if (sscanf(val, "%d", &tmp) == 1) - deftaps = tmp; - } - } - - kfree(dup); - } - -_do: - printk(KERN_DEBUG "%s: enabling hwec with deftaps=%d\n", - __func__, deftaps); - memset(&cq, 0, sizeof(cq)); - cq.op = MISDN_CTRL_HFC_ECHOCAN_ON; - cq.p1 = deftaps; - if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { - printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", - __func__); - return; - } -} - -void dsp_hwec_disable(struct dsp *dsp) -{ - struct mISDN_ctrl_req cq; - - if (!dsp) { - printk(KERN_ERR "%s: failed to disable hwec: dsp is NULL\n", - __func__); - return; - } - - printk(KERN_DEBUG "%s: disabling hwec\n", __func__); - memset(&cq, 0, sizeof(cq)); - cq.op = MISDN_CTRL_HFC_ECHOCAN_OFF; - if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { - printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", - __func__); - return; - } -} - -int dsp_hwec_init(void) -{ - mISDN_dsp_element_register(dsp_hwec); - - return 0; -} - -void dsp_hwec_exit(void) -{ - mISDN_dsp_element_unregister(dsp_hwec); -} diff --git a/drivers/isdn/mISDN/dsp_hwec.h b/drivers/isdn/mISDN/dsp_hwec.h deleted file mode 100644 index c9cb0ea249da..000000000000 --- a/drivers/isdn/mISDN/dsp_hwec.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * dsp_hwec.h - */ - -extern struct mISDN_dsp_element *dsp_hwec; -extern void dsp_hwec_enable(struct dsp *dsp, const char *arg); -extern void dsp_hwec_disable(struct dsp *dsp); -extern int dsp_hwec_init(void); -extern void dsp_hwec_exit(void); diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c deleted file mode 100644 index 55693dc7206b..000000000000 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ /dev/null @@ -1,300 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * dsp_pipeline.c: pipelined audio processing - * - * Copyright (C) 2007, Nadi Sarrar - * - * Nadi Sarrar - */ - -#include -#include -#include -#include -#include -#include -#include -#include "dsp.h" -#include "dsp_hwec.h" - -struct dsp_pipeline_entry { - struct mISDN_dsp_element *elem; - void *p; - struct list_head list; -}; -struct dsp_element_entry { - struct mISDN_dsp_element *elem; - struct device dev; - struct list_head list; -}; - -static LIST_HEAD(dsp_elements); - -/* sysfs */ -static const struct class elements_class = { - .name = "dsp_pipeline", -}; - -static ssize_t -attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct mISDN_dsp_element *elem = dev_get_drvdata(dev); - int i; - char *p = buf; - - *buf = 0; - for (i = 0; i < elem->num_args; i++) - p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n", - elem->args[i].name, - elem->args[i].def ? "Default: " : "", - elem->args[i].def ? elem->args[i].def : "", - elem->args[i].def ? "\n" : "", - elem->args[i].desc); - - return p - buf; -} - -static struct device_attribute element_attributes[] = { - __ATTR(args, 0444, attr_show_args, NULL), -}; - -static void -mISDN_dsp_dev_release(struct device *dev) -{ - struct dsp_element_entry *entry = - container_of(dev, struct dsp_element_entry, dev); - list_del(&entry->list); - kfree(entry); -} - -int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) -{ - struct dsp_element_entry *entry; - int ret, i; - - if (!elem) - return -EINVAL; - - entry = kzalloc_obj(struct dsp_element_entry, GFP_ATOMIC); - if (!entry) - return -ENOMEM; - - INIT_LIST_HEAD(&entry->list); - entry->elem = elem; - - entry->dev.class = &elements_class; - entry->dev.release = mISDN_dsp_dev_release; - dev_set_drvdata(&entry->dev, elem); - dev_set_name(&entry->dev, "%s", elem->name); - ret = device_register(&entry->dev); - if (ret) { - printk(KERN_ERR "%s: failed to register %s\n", - __func__, elem->name); - goto err1; - } - list_add_tail(&entry->list, &dsp_elements); - - for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) { - ret = device_create_file(&entry->dev, - &element_attributes[i]); - if (ret) { - printk(KERN_ERR "%s: failed to create device file\n", - __func__); - goto err2; - } - } - - return 0; - -err2: - device_unregister(&entry->dev); - return ret; -err1: - put_device(&entry->dev); - return ret; -} -EXPORT_SYMBOL(mISDN_dsp_element_register); - -void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem) -{ - struct dsp_element_entry *entry, *n; - - if (!elem) - return; - - list_for_each_entry_safe(entry, n, &dsp_elements, list) - if (entry->elem == elem) { - device_unregister(&entry->dev); - return; - } - printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name); -} -EXPORT_SYMBOL(mISDN_dsp_element_unregister); - -int dsp_pipeline_module_init(void) -{ - int err; - - err = class_register(&elements_class); - if (err) - return err; - - dsp_hwec_init(); - - return 0; -} - -void dsp_pipeline_module_exit(void) -{ - struct dsp_element_entry *entry, *n; - - dsp_hwec_exit(); - - class_unregister(&elements_class); - - list_for_each_entry_safe(entry, n, &dsp_elements, list) { - list_del(&entry->list); - printk(KERN_WARNING "%s: element was still registered: %s\n", - __func__, entry->elem->name); - kfree(entry); - } -} - -int dsp_pipeline_init(struct dsp_pipeline *pipeline) -{ - if (!pipeline) - return -EINVAL; - - INIT_LIST_HEAD(&pipeline->list); - - return 0; -} - -static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline) -{ - struct dsp_pipeline_entry *entry, *n; - - list_for_each_entry_safe(entry, n, &pipeline->list, list) { - list_del(&entry->list); - if (entry->elem == dsp_hwec) - dsp_hwec_disable(container_of(pipeline, struct dsp, - pipeline)); - else - entry->elem->free(entry->p); - kfree(entry); - } -} - -void dsp_pipeline_destroy(struct dsp_pipeline *pipeline) -{ - - if (!pipeline) - return; - - _dsp_pipeline_destroy(pipeline); -} - -int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) -{ - int found = 0; - char *dup, *next, *tok, *name, *args; - struct dsp_element_entry *entry, *n; - struct dsp_pipeline_entry *pipeline_entry; - struct mISDN_dsp_element *elem; - - if (!pipeline) - return -EINVAL; - - if (!list_empty(&pipeline->list)) - _dsp_pipeline_destroy(pipeline); - - dup = next = kstrdup(cfg, GFP_ATOMIC); - if (!dup) - return 0; - while ((tok = strsep(&next, "|"))) { - if (!strlen(tok)) - continue; - name = strsep(&tok, "("); - args = strsep(&tok, ")"); - if (args && !*args) - args = NULL; - - list_for_each_entry_safe(entry, n, &dsp_elements, list) - if (!strcmp(entry->elem->name, name)) { - elem = entry->elem; - - pipeline_entry = kmalloc_obj(struct dsp_pipeline_entry, - GFP_ATOMIC); - if (!pipeline_entry) { - printk(KERN_ERR "%s: failed to add " - "entry to pipeline: %s (out of " - "memory)\n", __func__, elem->name); - goto _out; - } - pipeline_entry->elem = elem; - - if (elem == dsp_hwec) { - /* This is a hack to make the hwec - available as a pipeline module */ - dsp_hwec_enable(container_of(pipeline, - struct dsp, pipeline), args); - list_add_tail(&pipeline_entry->list, - &pipeline->list); - } else { - pipeline_entry->p = elem->new(args); - if (pipeline_entry->p) { - list_add_tail(&pipeline_entry-> - list, &pipeline->list); - } else { - printk(KERN_ERR "%s: failed " - "to add entry to pipeline: " - "%s (new() returned NULL)\n", - __func__, elem->name); - kfree(pipeline_entry); - } - } - found = 1; - break; - } - - if (found) - found = 0; - else - printk(KERN_ERR "%s: element not found, skipping: " - "%s\n", __func__, name); - } - -_out: - if (!list_empty(&pipeline->list)) - pipeline->inuse = 1; - else - pipeline->inuse = 0; - - kfree(dup); - return 0; -} - -void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len) -{ - struct dsp_pipeline_entry *entry; - - if (!pipeline) - return; - - list_for_each_entry(entry, &pipeline->list, list) - if (entry->elem->process_tx) - entry->elem->process_tx(entry->p, data, len); -} - -void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len, - unsigned int txlen) -{ - struct dsp_pipeline_entry *entry; - - if (!pipeline) - return; - - list_for_each_entry_reverse(entry, &pipeline->list, list) - if (entry->elem->process_rx) - entry->elem->process_rx(entry->p, data, len, txlen); -} diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c deleted file mode 100644 index fa7813ae8d97..000000000000 --- a/drivers/isdn/mISDN/dsp_tones.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Audio support data for ISDN4Linux. - * - * Copyright Andreas Eversberg (jolly@eversberg.eu) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include "core.h" -#include "dsp.h" - - -#define DATA_S sample_silence -#define SIZE_S (&sizeof_silence) -#define DATA_GA sample_german_all -#define SIZE_GA (&sizeof_german_all) -#define DATA_GO sample_german_old -#define SIZE_GO (&sizeof_german_old) -#define DATA_DT sample_american_dialtone -#define SIZE_DT (&sizeof_american_dialtone) -#define DATA_RI sample_american_ringing -#define SIZE_RI (&sizeof_american_ringing) -#define DATA_BU sample_american_busy -#define SIZE_BU (&sizeof_american_busy) -#define DATA_S1 sample_special1 -#define SIZE_S1 (&sizeof_special1) -#define DATA_S2 sample_special2 -#define SIZE_S2 (&sizeof_special2) -#define DATA_S3 sample_special3 -#define SIZE_S3 (&sizeof_special3) - -/***************/ -/* tones loops */ -/***************/ - -/* all tones are alaw encoded */ -/* the last sample+1 is in phase with the first sample. the error is low */ - -static u8 sample_german_all[] = { - 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, - 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, - 0xdc, 0xfc, 0x6c, - 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, - 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, - 0xdc, 0xfc, 0x6c, - 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, - 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, - 0xdc, 0xfc, 0x6c, - 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, - 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, - 0xdc, 0xfc, 0x6c, -}; -static u32 sizeof_german_all = sizeof(sample_german_all); - -static u8 sample_german_old[] = { - 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, - 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, - 0x8c, - 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, - 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, - 0x8c, - 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, - 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, - 0x8c, - 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, - 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, - 0x8c, -}; -static u32 sizeof_german_old = sizeof(sample_german_old); - -static u8 sample_american_dialtone[] = { - 0x2a, 0x18, 0x90, 0x6c, 0x4c, 0xbc, 0x4c, 0x6c, - 0x10, 0x58, 0x32, 0xb9, 0x31, 0x2d, 0x8d, 0x0d, - 0x8d, 0x2d, 0x31, 0x99, 0x0f, 0x28, 0x60, 0xf0, - 0xd0, 0x50, 0xd0, 0x30, 0x60, 0x08, 0x8e, 0x67, - 0x09, 0x19, 0x21, 0xe1, 0xd9, 0xb9, 0x29, 0x67, - 0x83, 0x02, 0xce, 0xbe, 0xee, 0x1a, 0x1b, 0xef, - 0xbf, 0xcf, 0x03, 0x82, 0x66, 0x28, 0xb8, 0xd8, - 0xe0, 0x20, 0x18, 0x08, 0x66, 0x8f, 0x09, 0x61, - 0x31, 0xd1, 0x51, 0xd1, 0xf1, 0x61, 0x29, 0x0e, - 0x98, 0x30, 0x2c, 0x8c, 0x0c, 0x8c, 0x2c, 0x30, - 0xb8, 0x33, 0x59, 0x11, 0x6d, 0x4d, 0xbd, 0x4d, - 0x6d, 0x91, 0x19, -}; -static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone); - -static u8 sample_american_ringing[] = { - 0x2a, 0xe0, 0xac, 0x0c, 0xbc, 0x4c, 0x8c, 0x90, - 0x48, 0xc7, 0xc1, 0xed, 0xcd, 0x4d, 0xcd, 0xed, - 0xc1, 0xb7, 0x08, 0x30, 0xec, 0xcc, 0xcc, 0x8c, - 0x10, 0x58, 0x1a, 0x99, 0x71, 0xed, 0x8d, 0x8d, - 0x2d, 0x41, 0x89, 0x9e, 0x20, 0x70, 0x2c, 0xec, - 0x2c, 0x70, 0x20, 0x86, 0x77, 0xe1, 0x31, 0x11, - 0xd1, 0xf1, 0x81, 0x09, 0xa3, 0x56, 0x58, 0x00, - 0x40, 0xc0, 0x60, 0x38, 0x46, 0x43, 0x57, 0x39, - 0xd9, 0x59, 0x99, 0xc9, 0x77, 0x2f, 0x2e, 0xc6, - 0xd6, 0x28, 0xd6, 0x36, 0x26, 0x2e, 0x8a, 0xa3, - 0x43, 0x63, 0x4b, 0x4a, 0x62, 0x42, 0xa2, 0x8b, - 0x2f, 0x27, 0x37, 0xd7, 0x29, 0xd7, 0xc7, 0x2f, - 0x2e, 0x76, 0xc8, 0x98, 0x58, 0xd8, 0x38, 0x56, - 0x42, 0x47, 0x39, 0x61, 0xc1, 0x41, 0x01, 0x59, - 0x57, 0xa2, 0x08, 0x80, 0xf0, 0xd0, 0x10, 0x30, - 0xe0, 0x76, 0x87, 0x21, 0x71, 0x2d, 0xed, 0x2d, - 0x71, 0x21, 0x9f, 0x88, 0x40, 0x2c, 0x8c, 0x8c, - 0xec, 0x70, 0x98, 0x1b, 0x59, 0x11, 0x8d, 0xcd, - 0xcd, 0xed, 0x31, 0x09, 0xb6, 0xc0, 0xec, 0xcc, - 0x4c, 0xcc, 0xec, 0xc0, 0xc6, 0x49, 0x91, 0x8d, - 0x4d, 0xbd, 0x0d, 0xad, 0xe1, -}; -static u32 sizeof_american_ringing = sizeof(sample_american_ringing); - -static u8 sample_american_busy[] = { - 0x2a, 0x00, 0x6c, 0x4c, 0x4c, 0x6c, 0xb0, 0x66, - 0x99, 0x11, 0x6d, 0x8d, 0x2d, 0x41, 0xd7, 0x96, - 0x60, 0xf0, 0x70, 0x40, 0x58, 0xf6, 0x53, 0x57, - 0x09, 0x89, 0xd7, 0x5f, 0xe3, 0x2a, 0xe3, 0x5f, - 0xd7, 0x89, 0x09, 0x57, 0x53, 0xf6, 0x58, 0x40, - 0x70, 0xf0, 0x60, 0x96, 0xd7, 0x41, 0x2d, 0x8d, - 0x6d, 0x11, 0x99, 0x66, 0xb0, 0x6c, 0x4c, 0x4c, - 0x6c, 0x00, 0x2a, 0x01, 0x6d, 0x4d, 0x4d, 0x6d, - 0xb1, 0x67, 0x98, 0x10, 0x6c, 0x8c, 0x2c, 0x40, - 0xd6, 0x97, 0x61, 0xf1, 0x71, 0x41, 0x59, 0xf7, - 0x52, 0x56, 0x08, 0x88, 0xd6, 0x5e, 0xe2, 0x2a, - 0xe2, 0x5e, 0xd6, 0x88, 0x08, 0x56, 0x52, 0xf7, - 0x59, 0x41, 0x71, 0xf1, 0x61, 0x97, 0xd6, 0x40, - 0x2c, 0x8c, 0x6c, 0x10, 0x98, 0x67, 0xb1, 0x6d, - 0x4d, 0x4d, 0x6d, 0x01, -}; -static u32 sizeof_american_busy = sizeof(sample_american_busy); - -static u8 sample_special1[] = { - 0x2a, 0x2c, 0xbc, 0x6c, 0xd6, 0x71, 0xbd, 0x0d, - 0xd9, 0x80, 0xcc, 0x4c, 0x40, 0x39, 0x0d, 0xbd, - 0x11, 0x86, 0xec, 0xbc, 0xec, 0x0e, 0x51, 0xbd, - 0x8d, 0x89, 0x30, 0x4c, 0xcc, 0xe0, 0xe1, 0xcd, - 0x4d, 0x31, 0x88, 0x8c, 0xbc, 0x50, 0x0f, 0xed, - 0xbd, 0xed, 0x87, 0x10, 0xbc, 0x0c, 0x38, 0x41, - 0x4d, 0xcd, 0x81, 0xd8, 0x0c, 0xbc, 0x70, 0xd7, - 0x6d, 0xbd, 0x2d, -}; -static u32 sizeof_special1 = sizeof(sample_special1); - -static u8 sample_special2[] = { - 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, - 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, - 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, - 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, - 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, - 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, - 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, - 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, - 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, - 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, -}; -static u32 sizeof_special2 = sizeof(sample_special2); - -static u8 sample_special3[] = { - 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, - 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, - 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, - 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, - 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, - 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, - 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, - 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, - 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, - 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, -}; -static u32 sizeof_special3 = sizeof(sample_special3); - -static u8 sample_silence[] = { - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, -}; -static u32 sizeof_silence = sizeof(sample_silence); - -struct tones_samples { - u32 *len; - u8 *data; -}; -static struct -tones_samples samples[] = { - {&sizeof_german_all, sample_german_all}, - {&sizeof_german_old, sample_german_old}, - {&sizeof_american_dialtone, sample_american_dialtone}, - {&sizeof_american_ringing, sample_american_ringing}, - {&sizeof_american_busy, sample_american_busy}, - {&sizeof_special1, sample_special1}, - {&sizeof_special2, sample_special2}, - {&sizeof_special3, sample_special3}, - {NULL, NULL}, -}; - -/*********************************** - * generate ulaw from alaw samples * - ***********************************/ - -void -dsp_audio_generate_ulaw_samples(void) -{ - int i, j; - - i = 0; - while (samples[i].len) { - j = 0; - while (j < (*samples[i].len)) { - samples[i].data[j] = - dsp_audio_alaw_to_ulaw[samples[i].data[j]]; - j++; - } - i++; - } -} - - -/**************************** - * tone sequence definition * - ****************************/ - -static struct pattern { - int tone; - u8 *data[10]; - u32 *siz[10]; - u32 seq[10]; -} pattern[] = { - {TONE_GERMAN_DIALTONE, - {DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_OLDDIALTONE, - {DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_AMERICAN_DIALTONE, - {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_DIALPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, - NULL}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, - NULL}, - {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, - - {TONE_GERMAN_OLDDIALPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, - NULL}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, - NULL}, - {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, - - {TONE_AMERICAN_DIALPBX, - {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, - NULL}, - {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, - NULL}, - {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, - - {TONE_GERMAN_RINGING, - {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_OLDRINGING, - {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_AMERICAN_RINGING, - {DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_RINGPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_OLDRINGPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, - - {TONE_AMERICAN_RINGPBX, - {DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_BUSY, - {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_OLDBUSY, - {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_AMERICAN_BUSY, - {DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_HANGUP, - {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_OLDHANGUP, - {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_AMERICAN_HANGUP, - {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_SPECIAL_INFO, - {DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_GASSENBESETZT, - {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, - - {TONE_GERMAN_AUFSCHALTTON, - {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, - {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, - - {0, - {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, -}; - -/****************** - * copy tone data * - ******************/ - -/* an sk_buff is generated from the number of samples needed. - * the count will be changed and may begin from 0 each pattern period. - * the clue is to precalculate the pointers and legths to use only one - * memcpy per function call, or two memcpy if the tone sequence changes. - * - * pattern - the type of the pattern - * count - the sample from the beginning of the pattern (phase) - * len - the number of bytes - * - * return - the sk_buff with the sample - * - * if tones has finished (e.g. knocking tone), dsp->tones is turned off - */ -void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) -{ - int index, count, start, num; - struct pattern *pat; - struct dsp_tone *tone = &dsp->tone; - - /* if we have no tone, we copy silence */ - if (!tone->tone) { - memset(data, dsp_silence, len); - return; - } - - /* process pattern */ - pat = (struct pattern *)tone->pattern; - /* points to the current pattern */ - index = tone->index; /* gives current sequence index */ - count = tone->count; /* gives current sample */ - - /* copy sample */ - while (len) { - /* find sample to start with */ - while (42) { - /* wrap around */ - if (!pat->seq[index]) { - count = 0; - index = 0; - } - /* check if we are currently playing this tone */ - if (count < pat->seq[index]) - break; - if (dsp_debug & DEBUG_DSP_TONE) - printk(KERN_DEBUG "%s: reaching next sequence " - "(index=%d)\n", __func__, index); - count -= pat->seq[index]; - index++; - } - /* calculate start and number of samples */ - start = count % (*(pat->siz[index])); - num = len; - if (num + count > pat->seq[index]) - num = pat->seq[index] - count; - if (num + start > (*(pat->siz[index]))) - num = (*(pat->siz[index])) - start; - /* copy memory */ - memcpy(data, pat->data[index] + start, num); - /* reduce length */ - data += num; - count += num; - len -= num; - } - tone->index = index; - tone->count = count; - - /* return sk_buff */ - return; -} - - -/******************************* - * send HW message to hfc card * - *******************************/ - -static void -dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) -{ - struct sk_buff *nskb; - - /* unlocking is not required, because we don't expect a response */ - nskb = _alloc_mISDN_skb(PH_CONTROL_REQ, - (len) ? HFC_SPL_LOOP_ON : HFC_SPL_LOOP_OFF, len, sample, - GFP_ATOMIC); - if (nskb) { - if (dsp->ch.peer) { - if (dsp->ch.recv(dsp->ch.peer, nskb)) - dev_kfree_skb(nskb); - } else - dev_kfree_skb(nskb); - } -} - - -/***************** - * timer expires * - *****************/ -void -dsp_tone_timeout(struct timer_list *t) -{ - struct dsp *dsp = timer_container_of(dsp, t, tone.tl); - struct dsp_tone *tone = &dsp->tone; - struct pattern *pat = (struct pattern *)tone->pattern; - int index = tone->index; - - if (!tone->tone) - return; - - index++; - if (!pat->seq[index]) - index = 0; - tone->index = index; - - /* set next tone */ - if (pat->data[index] == DATA_S) - dsp_tone_hw_message(dsp, NULL, 0); - else - dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index])); - /* set timer */ - tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000; - add_timer(&tone->tl); -} - - -/******************** - * set/release tone * - ********************/ - -/* - * tones are relaized by streaming or by special loop commands if supported - * by hardware. when hardware is used, the patterns will be controlled by - * timers. - */ -int -dsp_tone(struct dsp *dsp, int tone) -{ - struct pattern *pat; - int i; - struct dsp_tone *tonet = &dsp->tone; - - tonet->software = 0; - tonet->hardware = 0; - - /* we turn off the tone */ - if (!tone) { - if (dsp->features.hfc_loops && timer_pending(&tonet->tl)) - timer_delete(&tonet->tl); - if (dsp->features.hfc_loops) - dsp_tone_hw_message(dsp, NULL, 0); - tonet->tone = 0; - return 0; - } - - pat = NULL; - i = 0; - while (pattern[i].tone) { - if (pattern[i].tone == tone) { - pat = &pattern[i]; - break; - } - i++; - } - if (!pat) { - printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone); - return -EINVAL; - } - if (dsp_debug & DEBUG_DSP_TONE) - printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", - __func__, tone, 0); - tonet->tone = tone; - tonet->pattern = pat; - tonet->index = 0; - tonet->count = 0; - - if (dsp->features.hfc_loops) { - tonet->hardware = 1; - /* set first tone */ - dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0])); - /* set timer */ - if (timer_pending(&tonet->tl)) - timer_delete(&tonet->tl); - tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000; - add_timer(&tonet->tl); - } else { - tonet->software = 1; - } - - return 0; -} diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c deleted file mode 100644 index 825b686496d2..000000000000 --- a/drivers/isdn/mISDN/fsm.c +++ /dev/null @@ -1,176 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * finite state machine implementation - * - * Author Karsten Keil - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include -#include -#include "fsm.h" - -#define FSM_TIMER_DEBUG 0 - -int -mISDN_FsmNew(struct Fsm *fsm, - struct FsmNode *fnlist, int fncount) -{ - int i; - - fsm->jumpmatrix = - kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count, - fsm->event_count), - GFP_KERNEL); - if (fsm->jumpmatrix == NULL) - return -ENOMEM; - - for (i = 0; i < fncount; i++) - if ((fnlist[i].state >= fsm->state_count) || - (fnlist[i].event >= fsm->event_count)) { - printk(KERN_ERR - "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n", - i, (long)fnlist[i].state, (long)fsm->state_count, - (long)fnlist[i].event, (long)fsm->event_count); - } else - fsm->jumpmatrix[fsm->state_count * fnlist[i].event + - fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; - return 0; -} -EXPORT_SYMBOL(mISDN_FsmNew); - -void -mISDN_FsmFree(struct Fsm *fsm) -{ - kfree((void *) fsm->jumpmatrix); -} -EXPORT_SYMBOL(mISDN_FsmFree); - -int -mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg) -{ - FSMFNPTR r; - - if ((fi->state >= fi->fsm->state_count) || - (event >= fi->fsm->event_count)) { - printk(KERN_ERR - "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", - (long)fi->state, (long)fi->fsm->state_count, event, - (long)fi->fsm->event_count); - return 1; - } - r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; - if (r) { - if (fi->debug) - fi->printdebug(fi, "State %s Event %s", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - r(fi, event, arg); - return 0; - } else { - if (fi->debug) - fi->printdebug(fi, "State %s Event %s no action", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - return 1; - } -} -EXPORT_SYMBOL(mISDN_FsmEvent); - -void -mISDN_FsmChangeState(struct FsmInst *fi, int newstate) -{ - fi->state = newstate; - if (fi->debug) - fi->printdebug(fi, "ChangeState %s", - fi->fsm->strState[newstate]); -} -EXPORT_SYMBOL(mISDN_FsmChangeState); - -static void -FsmExpireTimer(struct timer_list *t) -{ - struct FsmTimer *ft = timer_container_of(ft, t, tl); -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); -#endif - mISDN_FsmEvent(ft->fi, ft->event, ft->arg); -} - -void -mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) -{ - ft->fi = fi; -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft); -#endif - timer_setup(&ft->tl, FsmExpireTimer, 0); -} -EXPORT_SYMBOL(mISDN_FsmInitTimer); - -void -mISDN_FsmDelTimer(struct FsmTimer *ft, int where) -{ -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", - (long) ft, where); -#endif - timer_delete(&ft->tl); -} -EXPORT_SYMBOL(mISDN_FsmDelTimer); - -int -mISDN_FsmAddTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) { - if (ft->fi->debug) { - printk(KERN_WARNING - "mISDN_FsmAddTimer: timer already active!\n"); - ft->fi->printdebug(ft->fi, - "mISDN_FsmAddTimer already active!"); - } - return -1; - } - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); - return 0; -} -EXPORT_SYMBOL(mISDN_FsmAddTimer); - -void -mISDN_FsmRestartTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) - timer_delete(&ft->tl); - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); -} -EXPORT_SYMBOL(mISDN_FsmRestartTimer); diff --git a/drivers/isdn/mISDN/fsm.h b/drivers/isdn/mISDN/fsm.h deleted file mode 100644 index 211554b997f8..000000000000 --- a/drivers/isdn/mISDN/fsm.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * - * Author Karsten Keil - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Copyright 2008 by Karsten Keil - */ - -#ifndef _MISDN_FSM_H -#define _MISDN_FSM_H - -#include - -/* Statemachine */ - -struct FsmInst; - -typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); - -struct Fsm { - FSMFNPTR *jumpmatrix; - int state_count, event_count; - char **strEvent, **strState; -}; - -struct FsmInst { - struct Fsm *fsm; - int state; - int debug; - void *userdata; - int userint; - void (*printdebug) (struct FsmInst *, char *, ...); -}; - -struct FsmNode { - int state, event; - void (*routine) (struct FsmInst *, int, void *); -}; - -struct FsmTimer { - struct FsmInst *fi; - struct timer_list tl; - int event; - void *arg; -}; - -extern int mISDN_FsmNew(struct Fsm *, struct FsmNode *, int); -extern void mISDN_FsmFree(struct Fsm *); -extern int mISDN_FsmEvent(struct FsmInst *, int , void *); -extern void mISDN_FsmChangeState(struct FsmInst *, int); -extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *); -extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int); -extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int); -extern void mISDN_FsmDelTimer(struct FsmTimer *, int); - -#endif diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c deleted file mode 100644 index 8c93af06ed02..000000000000 --- a/drivers/isdn/mISDN/hwchannel.c +++ /dev/null @@ -1,516 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include - -static void -dchannel_bh(struct work_struct *ws) -{ - struct dchannel *dch = container_of(ws, struct dchannel, workq); - struct sk_buff *skb; - int err; - - if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) { - while ((skb = skb_dequeue(&dch->rqueue))) { - if (likely(dch->dev.D.peer)) { - err = dch->dev.D.recv(dch->dev.D.peer, skb); - if (err) - dev_kfree_skb(skb); - } else - dev_kfree_skb(skb); - } - } - if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) { - if (dch->phfunc) - dch->phfunc(dch); - } -} - -static void -bchannel_bh(struct work_struct *ws) -{ - struct bchannel *bch = container_of(ws, struct bchannel, workq); - struct sk_buff *skb; - int err; - - if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { - while ((skb = skb_dequeue(&bch->rqueue))) { - bch->rcount--; - if (likely(bch->ch.peer)) { - err = bch->ch.recv(bch->ch.peer, skb); - if (err) - dev_kfree_skb(skb); - } else - dev_kfree_skb(skb); - } - } -} - -int -mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) -{ - test_and_set_bit(FLG_HDLC, &ch->Flags); - ch->maxlen = maxlen; - ch->hw = NULL; - ch->rx_skb = NULL; - ch->tx_skb = NULL; - ch->tx_idx = 0; - ch->phfunc = phf; - skb_queue_head_init(&ch->squeue); - skb_queue_head_init(&ch->rqueue); - INIT_LIST_HEAD(&ch->dev.bchannels); - INIT_WORK(&ch->workq, dchannel_bh); - return 0; -} -EXPORT_SYMBOL(mISDN_initdchannel); - -int -mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen, - unsigned short minlen) -{ - ch->Flags = 0; - ch->minlen = minlen; - ch->next_minlen = minlen; - ch->init_minlen = minlen; - ch->maxlen = maxlen; - ch->next_maxlen = maxlen; - ch->init_maxlen = maxlen; - ch->hw = NULL; - ch->rx_skb = NULL; - ch->tx_skb = NULL; - ch->tx_idx = 0; - skb_queue_head_init(&ch->rqueue); - ch->rcount = 0; - ch->next_skb = NULL; - INIT_WORK(&ch->workq, bchannel_bh); - return 0; -} -EXPORT_SYMBOL(mISDN_initbchannel); - -int -mISDN_freedchannel(struct dchannel *ch) -{ - if (ch->tx_skb) { - dev_kfree_skb(ch->tx_skb); - ch->tx_skb = NULL; - } - if (ch->rx_skb) { - dev_kfree_skb(ch->rx_skb); - ch->rx_skb = NULL; - } - skb_queue_purge(&ch->squeue); - skb_queue_purge(&ch->rqueue); - flush_work(&ch->workq); - return 0; -} -EXPORT_SYMBOL(mISDN_freedchannel); - -void -mISDN_clear_bchannel(struct bchannel *ch) -{ - if (ch->tx_skb) { - dev_kfree_skb(ch->tx_skb); - ch->tx_skb = NULL; - } - ch->tx_idx = 0; - if (ch->rx_skb) { - dev_kfree_skb(ch->rx_skb); - ch->rx_skb = NULL; - } - if (ch->next_skb) { - dev_kfree_skb(ch->next_skb); - ch->next_skb = NULL; - } - test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); - test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); - test_and_clear_bit(FLG_ACTIVE, &ch->Flags); - test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); - test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); - test_and_clear_bit(FLG_RX_OFF, &ch->Flags); - ch->dropcnt = 0; - ch->minlen = ch->init_minlen; - ch->next_minlen = ch->init_minlen; - ch->maxlen = ch->init_maxlen; - ch->next_maxlen = ch->init_maxlen; - skb_queue_purge(&ch->rqueue); - ch->rcount = 0; -} -EXPORT_SYMBOL(mISDN_clear_bchannel); - -void -mISDN_freebchannel(struct bchannel *ch) -{ - cancel_work_sync(&ch->workq); - mISDN_clear_bchannel(ch); -} -EXPORT_SYMBOL(mISDN_freebchannel); - -int -mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY | - MISDN_CTRL_RX_OFF; - break; - case MISDN_CTRL_FILL_EMPTY: - if (cq->p1) { - memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE); - test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); - } else { - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); - } - break; - case MISDN_CTRL_RX_OFF: - /* read back dropped byte count */ - cq->p2 = bch->dropcnt; - if (cq->p1) - test_and_set_bit(FLG_RX_OFF, &bch->Flags); - else - test_and_clear_bit(FLG_RX_OFF, &bch->Flags); - bch->dropcnt = 0; - break; - case MISDN_CTRL_RX_BUFFER: - if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) - bch->next_maxlen = cq->p2; - if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE) - bch->next_minlen = cq->p1; - /* we return the old values */ - cq->p1 = bch->minlen; - cq->p2 = bch->maxlen; - break; - default: - pr_info("mISDN unhandled control %x operation\n", cq->op); - ret = -EINVAL; - break; - } - return ret; -} -EXPORT_SYMBOL(mISDN_ctrl_bchannel); - -static inline u_int -get_sapi_tei(u_char *p) -{ - u_int sapi, tei; - - sapi = *p >> 2; - tei = p[1] >> 1; - return sapi | (tei << 8); -} - -void -recv_Dchannel(struct dchannel *dch) -{ - struct mISDNhead *hh; - - if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */ - dev_kfree_skb(dch->rx_skb); - dch->rx_skb = NULL; - return; - } - hh = mISDN_HEAD_P(dch->rx_skb); - hh->prim = PH_DATA_IND; - hh->id = get_sapi_tei(dch->rx_skb->data); - skb_queue_tail(&dch->rqueue, dch->rx_skb); - dch->rx_skb = NULL; - schedule_event(dch, FLG_RECVQUEUE); -} -EXPORT_SYMBOL(recv_Dchannel); - -void -recv_Echannel(struct dchannel *ech, struct dchannel *dch) -{ - struct mISDNhead *hh; - - if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */ - dev_kfree_skb(ech->rx_skb); - ech->rx_skb = NULL; - return; - } - hh = mISDN_HEAD_P(ech->rx_skb); - hh->prim = PH_DATA_E_IND; - hh->id = get_sapi_tei(ech->rx_skb->data); - skb_queue_tail(&dch->rqueue, ech->rx_skb); - ech->rx_skb = NULL; - schedule_event(dch, FLG_RECVQUEUE); -} -EXPORT_SYMBOL(recv_Echannel); - -void -recv_Bchannel(struct bchannel *bch, unsigned int id, bool force) -{ - struct mISDNhead *hh; - - /* if allocation did fail upper functions still may call us */ - if (unlikely(!bch->rx_skb)) - return; - if (unlikely(!bch->rx_skb->len)) { - /* we have no data to send - this may happen after recovery - * from overflow or too small allocation. - * We need to free the buffer here */ - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } else { - if (test_bit(FLG_TRANSPARENT, &bch->Flags) && - (bch->rx_skb->len < bch->minlen) && !force) - return; - hh = mISDN_HEAD_P(bch->rx_skb); - hh->prim = PH_DATA_IND; - hh->id = id; - if (bch->rcount >= 64) { - printk(KERN_WARNING - "B%d receive queue overflow - flushing!\n", - bch->nr); - skb_queue_purge(&bch->rqueue); - } - bch->rcount++; - skb_queue_tail(&bch->rqueue, bch->rx_skb); - bch->rx_skb = NULL; - schedule_event(bch, FLG_RECVQUEUE); - } -} -EXPORT_SYMBOL(recv_Bchannel); - -void -recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb) -{ - skb_queue_tail(&dch->rqueue, skb); - schedule_event(dch, FLG_RECVQUEUE); -} -EXPORT_SYMBOL(recv_Dchannel_skb); - -void -recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) -{ - if (bch->rcount >= 64) { - printk(KERN_WARNING "B-channel %p receive queue overflow, " - "flushing!\n", bch); - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } - bch->rcount++; - skb_queue_tail(&bch->rqueue, skb); - schedule_event(bch, FLG_RECVQUEUE); -} -EXPORT_SYMBOL(recv_Bchannel_skb); - -static void -confirm_Dsend(struct dchannel *dch) -{ - struct sk_buff *skb; - - skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), - 0, NULL, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "%s: no skb id %x\n", __func__, - mISDN_HEAD_ID(dch->tx_skb)); - return; - } - skb_queue_tail(&dch->rqueue, skb); - schedule_event(dch, FLG_RECVQUEUE); -} - -int -get_next_dframe(struct dchannel *dch) -{ - dch->tx_idx = 0; - dch->tx_skb = skb_dequeue(&dch->squeue); - if (dch->tx_skb) { - confirm_Dsend(dch); - return 1; - } - dch->tx_skb = NULL; - test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); - return 0; -} -EXPORT_SYMBOL(get_next_dframe); - -static void -confirm_Bsend(struct bchannel *bch) -{ - struct sk_buff *skb; - - if (bch->rcount >= 64) { - printk(KERN_WARNING "B-channel %p receive queue overflow, " - "flushing!\n", bch); - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } - skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), - 0, NULL, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "%s: no skb id %x\n", __func__, - mISDN_HEAD_ID(bch->tx_skb)); - return; - } - bch->rcount++; - skb_queue_tail(&bch->rqueue, skb); - schedule_event(bch, FLG_RECVQUEUE); -} - -int -get_next_bframe(struct bchannel *bch) -{ - bch->tx_idx = 0; - if (test_bit(FLG_TX_NEXT, &bch->Flags)) { - bch->tx_skb = bch->next_skb; - if (bch->tx_skb) { - bch->next_skb = NULL; - test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); - /* confirm imediately to allow next data */ - confirm_Bsend(bch); - return 1; - } else { - test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); - printk(KERN_WARNING "B TX_NEXT without skb\n"); - } - } - bch->tx_skb = NULL; - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); - return 0; -} -EXPORT_SYMBOL(get_next_bframe); - -void -queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb) -{ - struct mISDNhead *hh; - - if (!skb) { - _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC); - } else { - if (ch->peer) { - hh = mISDN_HEAD_P(skb); - hh->prim = pr; - hh->id = id; - if (!ch->recv(ch->peer, skb)) - return; - } - dev_kfree_skb(skb); - } -} -EXPORT_SYMBOL(queue_ch_frame); - -int -dchannel_senddata(struct dchannel *ch, struct sk_buff *skb) -{ - /* check oversize */ - if (skb->len <= 0) { - printk(KERN_WARNING "%s: skb too small\n", __func__); - return -EINVAL; - } - if (skb->len > ch->maxlen) { - printk(KERN_WARNING "%s: skb too large(%d/%d)\n", - __func__, skb->len, ch->maxlen); - return -EINVAL; - } - /* HW lock must be obtained */ - if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { - skb_queue_tail(&ch->squeue, skb); - return 0; - } else { - /* write to fifo */ - ch->tx_skb = skb; - ch->tx_idx = 0; - return 1; - } -} -EXPORT_SYMBOL(dchannel_senddata); - -int -bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) -{ - - /* check oversize */ - if (skb->len <= 0) { - printk(KERN_WARNING "%s: skb too small\n", __func__); - return -EINVAL; - } - if (skb->len > ch->maxlen) { - printk(KERN_WARNING "%s: skb too large(%d/%d)\n", - __func__, skb->len, ch->maxlen); - return -EINVAL; - } - /* HW lock must be obtained */ - /* check for pending next_skb */ - if (ch->next_skb) { - printk(KERN_WARNING - "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", - __func__, skb->len, ch->next_skb->len); - return -EBUSY; - } - if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { - test_and_set_bit(FLG_TX_NEXT, &ch->Flags); - ch->next_skb = skb; - return 0; - } else { - /* write to fifo */ - ch->tx_skb = skb; - ch->tx_idx = 0; - confirm_Bsend(ch); - return 1; - } -} -EXPORT_SYMBOL(bchannel_senddata); - -/* The function allocates a new receive skb on demand with a size for the - * requirements of the current protocol. It returns the tailroom of the - * receive skb or an error. - */ -int -bchannel_get_rxbuf(struct bchannel *bch, int reqlen) -{ - int len; - - if (bch->rx_skb) { - len = skb_tailroom(bch->rx_skb); - if (len < reqlen) { - pr_warn("B%d no space for %d (only %d) bytes\n", - bch->nr, reqlen, len); - if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { - /* send what we have now and try a new buffer */ - recv_Bchannel(bch, 0, true); - } else { - /* on HDLC we have to drop too big frames */ - return -EMSGSIZE; - } - } else { - return len; - } - } - /* update current min/max length first */ - if (unlikely(bch->maxlen != bch->next_maxlen)) - bch->maxlen = bch->next_maxlen; - if (unlikely(bch->minlen != bch->next_minlen)) - bch->minlen = bch->next_minlen; - if (unlikely(reqlen > bch->maxlen)) - return -EMSGSIZE; - if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { - if (reqlen >= bch->minlen) { - len = reqlen; - } else { - len = 2 * bch->minlen; - if (len > bch->maxlen) - len = bch->maxlen; - } - } else { - /* with HDLC we do not know the length yet */ - len = bch->maxlen; - } - bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); - if (!bch->rx_skb) { - pr_warn("B%d receive no memory for %d bytes\n", bch->nr, len); - len = -ENOMEM; - } - return len; -} -EXPORT_SYMBOL(bchannel_get_rxbuf); diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h deleted file mode 100644 index 48133d022812..000000000000 --- a/drivers/isdn/mISDN/l1oip.h +++ /dev/null @@ -1,92 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * see notice in l1oip.c - */ - -/* debugging */ -#define DEBUG_L1OIP_INIT 0x00010000 -#define DEBUG_L1OIP_SOCKET 0x00020000 -#define DEBUG_L1OIP_MGR 0x00040000 -#define DEBUG_L1OIP_MSG 0x00080000 - -/* enable to disorder received bchannels by sequence 2143658798... */ -/* - #define REORDER_DEBUG -*/ - -/* frames */ -#define L1OIP_MAX_LEN 2048 /* max packet size form l2 */ -#define L1OIP_MAX_PERFRAME 1400 /* max data size in one frame */ - - -/* timers */ -#define L1OIP_KEEPALIVE 15 -#define L1OIP_TIMEOUT 65 - - -/* socket */ -#define L1OIP_DEFAULTPORT 931 - - -/* channel structure */ -struct l1oip_chan { - struct dchannel *dch; - struct bchannel *bch; - u32 tx_counter; /* counts xmit bytes/packets */ - u32 rx_counter; /* counts recv bytes/packets */ - u32 codecstate; /* used by codec to save data */ -#ifdef REORDER_DEBUG - int disorder_flag; - struct sk_buff *disorder_skb; - u32 disorder_cnt; -#endif -}; - - -/* card structure */ -struct l1oip { - struct list_head list; - - /* card */ - int registered; /* if registered with mISDN */ - char name[MISDN_MAX_IDLEN]; - int idx; /* card index */ - int pri; /* 1=pri, 0=bri */ - int d_idx; /* current dchannel number */ - int b_num; /* number of bchannels */ - u32 id; /* id of connection */ - int ondemand; /* if transmis. is on demand */ - int bundle; /* bundle channels in one frm */ - int codec; /* codec to use for transmis. */ - int limit; /* limit number of bchannels */ - bool shutdown; /* if card is released */ - - /* timer */ - struct timer_list keep_tl; - struct timer_list timeout_tl; - int timeout_on; - struct work_struct workq; - - /* socket */ - struct socket *socket; /* if set, socket is created */ - struct completion socket_complete;/* completion of sock thread */ - struct task_struct *socket_thread; - spinlock_t socket_lock; /* access sock outside thread */ - u32 remoteip; /* if all set, ip is assigned */ - u16 localport; /* must always be set */ - u16 remoteport; /* must always be set */ - struct sockaddr_in sin_local; /* local socket name */ - struct sockaddr_in sin_remote; /* remote socket name */ - struct msghdr sendmsg; /* ip message to send */ - struct kvec sendiov; /* iov for message */ - - /* frame */ - struct l1oip_chan chan[128]; /* channel instances */ -}; - -extern int l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state); -extern int l1oip_4bit_to_law(u8 *data, int len, u8 *result); -extern int l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result); -extern int l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result); -extern void l1oip_4bit_free(void); -extern int l1oip_4bit_alloc(int ulaw); diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c deleted file mode 100644 index 1059234fbc67..000000000000 --- a/drivers/isdn/mISDN/l1oip_codec.c +++ /dev/null @@ -1,358 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - - * l1oip_codec.c generic codec using lookup table - * -> conversion from a-Law to u-Law - * -> conversion from u-Law to a-Law - * -> compression by reducing the number of sample resolution to 4 - * - * NOTE: It is not compatible with any standard codec like ADPCM. - * - * Author Andreas Eversberg (jolly@eversberg.eu) - * - - */ - -/* - - How the codec works: - -------------------- - - The volume is increased to increase the dynamic range of the audio signal. - Each sample is converted to a-LAW with only 16 steps of level resolution. - A pair of two samples are stored in one byte. - - The first byte is stored in the upper bits, the second byte is stored in the - lower bits. - - To speed up compression and decompression, two lookup tables are formed: - - - 16 bits index for two samples (law encoded) with 8 bit compressed result. - - 8 bits index for one compressed data with 16 bits decompressed result. - - NOTE: The bytes are handled as they are law-encoded. - -*/ - -#include -#include -#include -#include "core.h" -#include "l1oip.h" - -/* definitions of codec. don't use calculations, code may run slower. */ - -static u8 *table_com; -static u16 *table_dec; - - -/* alaw -> ulaw */ -static u8 alaw_to_ulaw[256] = -{ - 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, - 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, - 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, - 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, - 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, - 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, - 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, - 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, - 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, - 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, - 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, - 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, - 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, - 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, - 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, - 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, - 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, - 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, - 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, - 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, - 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, - 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, - 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, - 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, - 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, - 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, - 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, - 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, - 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, - 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, - 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, - 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 -}; - -/* ulaw -> alaw */ -static u8 ulaw_to_alaw[256] = -{ - 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, - 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, - 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, - 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, - 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, - 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, - 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, - 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, - 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, - 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, - 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, - 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, - 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, - 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, - 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, - 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, - 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, - 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, - 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, - 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, - 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, - 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, - 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, - 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, - 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, - 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, - 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, - 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, - 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, - 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, - 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, - 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a -}; - -/* alaw -> 4bit compression */ -static u8 alaw_to_4bit[256] = { - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0d, 0x02, - 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x01, 0x0a, 0x05, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x09, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, - 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, - 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, -}; - -/* 4bit -> alaw decompression */ -static u8 _4bit_to_alaw[16] = { - 0x5d, 0x51, 0xd9, 0xd7, 0x5f, 0x53, 0xa3, 0x4b, - 0x2a, 0x3a, 0x22, 0x2e, 0x26, 0x56, 0x20, 0x2c, -}; - -/* ulaw -> 4bit compression */ -static u8 ulaw_to_4bit[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, -}; - -/* 4bit -> ulaw decompression */ -static u8 _4bit_to_ulaw[16] = { - 0x11, 0x21, 0x31, 0x40, 0x4e, 0x5c, 0x68, 0x71, - 0xfe, 0xef, 0xe7, 0xdb, 0xcd, 0xbf, 0xaf, 0x9f, -}; - - -/* - * Compresses data to the result buffer - * The result size must be at least half of the input buffer. - * The number of samples also must be even! - */ -int -l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state) -{ - int ii, i = 0, o = 0; - - if (!len) - return 0; - - /* send saved byte and first input byte */ - if (*state) { - *result++ = table_com[(((*state) << 8) & 0xff00) | (*data++)]; - len--; - o++; - } - - ii = len >> 1; - - while (i < ii) { - *result++ = table_com[(data[0]<<8) | (data[1])]; - data += 2; - i++; - o++; - } - - /* if len has an odd number, we save byte for next call */ - if (len & 1) - *state = 0x100 + *data; - else - *state = 0; - - return o; -} - -/* Decompress data to the result buffer - * The result size must be the number of sample in packet. (2 * input data) - * The number of samples in the result are even! - */ -int -l1oip_4bit_to_law(u8 *data, int len, u8 *result) -{ - int i = 0; - u16 r; - - while (i < len) { - r = table_dec[*data++]; - *result++ = r >> 8; - *result++ = r; - i++; - } - - return len << 1; -} - - -/* - * law conversion - */ -int -l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result) -{ - int i = 0; - - while (i < len) { - *result++ = alaw_to_ulaw[*data++]; - i++; - } - - return len; -} - -int -l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result) -{ - int i = 0; - - while (i < len) { - *result++ = ulaw_to_alaw[*data++]; - i++; - } - - return len; -} - - -/* - * generate/free compression and decompression table - */ -void -l1oip_4bit_free(void) -{ - vfree(table_dec); - vfree(table_com); - table_com = NULL; - table_dec = NULL; -} - -int -l1oip_4bit_alloc(int ulaw) -{ - int i1, i2, c, sample; - - /* in case, it is called again */ - if (table_dec) - return 0; - - /* alloc conversion tables */ - table_com = vzalloc(65536); - table_dec = vzalloc(512); - if (!table_com || !table_dec) { - l1oip_4bit_free(); - return -ENOMEM; - } - /* generate compression table */ - i1 = 0; - while (i1 < 256) { - if (ulaw) - c = ulaw_to_4bit[i1]; - else - c = alaw_to_4bit[i1]; - i2 = 0; - while (i2 < 256) { - table_com[(i1 << 8) | i2] |= (c << 4); - table_com[(i2 << 8) | i1] |= c; - i2++; - } - i1++; - } - - /* generate decompression table */ - i1 = 0; - while (i1 < 16) { - if (ulaw) - sample = _4bit_to_ulaw[i1]; - else - sample = _4bit_to_alaw[i1]; - i2 = 0; - while (i2 < 16) { - table_dec[(i1 << 4) | i2] |= (sample << 8); - table_dec[(i2 << 4) | i1] |= sample; - i2++; - } - i1++; - } - - return 0; -} diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c deleted file mode 100644 index 6866a0d6b382..000000000000 --- a/drivers/isdn/mISDN/l1oip_core.c +++ /dev/null @@ -1,1505 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - - * l1oip.c low level driver for tunneling layer 1 over IP - * - * NOTE: It is not compatible with TDMoIP nor "ISDN over IP". - * - * Author Andreas Eversberg (jolly@eversberg.eu) - */ - -/* module parameters: - * type: - Value 1 = BRI - Value 2 = PRI - Value 3 = BRI (multi channel frame, not supported yet) - Value 4 = PRI (multi channel frame, not supported yet) - A multi channel frame reduces overhead to a single frame for all - b-channels, but increases delay. - (NOTE: Multi channel frames are not implemented yet.) - - * codec: - Value 0 = transparent (default) - Value 1 = transfer ALAW - Value 2 = transfer ULAW - Value 3 = transfer generic 4 bit compression. - - * ulaw: - 0 = we use a-Law (default) - 1 = we use u-Law - - * limit: - limitation of B-channels to control bandwidth (1...126) - BRI: 1 or 2 - PRI: 1-30, 31-126 (126, because dchannel ist not counted here) - Also limited ressources are used for stack, resulting in less channels. - It is possible to have more channels than 30 in PRI mode, this must - be supported by the application. - - * ip: - byte representation of remote ip address (127.0.0.1 -> 127,0,0,1) - If not given or four 0, no remote address is set. - For multiple interfaces, concat ip addresses. (127,0,0,1,127,0,0,1) - - * port: - port number (local interface) - If not given or 0, port 931 is used for fist instance, 932 for next... - For multiple interfaces, different ports must be given. - - * remoteport: - port number (remote interface) - If not given or 0, remote port equals local port - For multiple interfaces on equal sites, different ports must be given. - - * ondemand: - 0 = fixed (always transmit packets, even when remote side timed out) - 1 = on demand (only transmit packets, when remote side is detected) - the default is 0 - NOTE: ID must also be set for on demand. - - * id: - optional value to identify frames. This value must be equal on both - peers and should be random. If omitted or 0, no ID is transmitted. - - * debug: - NOTE: only one debug value must be given for all cards - enable debugging (see l1oip.h for debug options) - - - Special mISDN controls: - - op = MISDN_CTRL_SETPEER* - p1 = bytes 0-3 : remote IP address in network order (left element first) - p2 = bytes 1-2 : remote port in network order (high byte first) - optional: - p2 = bytes 3-4 : local port in network order (high byte first) - - op = MISDN_CTRL_UNSETPEER* - - * Use l1oipctrl for comfortable setting or removing ip address. - (Layer 1 Over IP CTRL) - - - L1oIP-Protocol - -------------- - - Frame Header: - - 7 6 5 4 3 2 1 0 - +---------------+ - |Ver|T|I|Coding | - +---------------+ - | ID byte 3 * | - +---------------+ - | ID byte 2 * | - +---------------+ - | ID byte 1 * | - +---------------+ - | ID byte 0 * | - +---------------+ - |M| Channel | - +---------------+ - | Length * | - +---------------+ - | Time Base MSB | - +---------------+ - | Time Base LSB | - +---------------+ - | Data.... | - - ... - - | | - +---------------+ - |M| Channel | - +---------------+ - | Length * | - +---------------+ - | Time Base MSB | - +---------------+ - | Time Base LSB | - +---------------+ - | Data.... | - - ... - - - * Only included in some cases. - - - Ver = Version - If version is missmatch, the frame must be ignored. - - - T = Type of interface - Must be 0 for S0 or 1 for E1. - - - I = Id present - If bit is set, four ID bytes are included in frame. - - - ID = Connection ID - Additional ID to prevent Denial of Service attacs. Also it prevents hijacking - connections with dynamic IP. The ID should be random and must not be 0. - - - Coding = Type of codec - Must be 0 for no transcoding. Also for D-channel and other HDLC frames. - 1 and 2 are reserved for explicitly use of a-LAW or u-LAW codec. - 3 is used for generic table compressor. - - - M = More channels to come. If this flag is 1, the following byte contains - the length of the channel data. After the data block, the next channel will - be defined. The flag for the last channel block (or if only one channel is - transmitted), must be 0 and no length is given. - - - Channel = Channel number - 0 reserved - 1-3 channel data for S0 (3 is D-channel) - 1-31 channel data for E1 (16 is D-channel) - 32-127 channel data for extended E1 (16 is D-channel) - - - The length is used if the M-flag is 1. It is used to find the next channel - inside frame. - NOTE: A value of 0 equals 256 bytes of data. - -> For larger data blocks, a single frame must be used. - -> For larger streams, a single frame or multiple blocks with same channel ID - must be used. - - - Time Base = Timestamp of first sample in frame - The "Time Base" is used to rearange packets and to detect packet loss. - The 16 bits are sent in network order (MSB first) and count 1/8000 th of a - second. This causes a wrap around each 8,192 seconds. There is no requirement - for the initial "Time Base", but 0 should be used for the first packet. - In case of HDLC data, this timestamp counts the packet or byte number. - - - Two Timers: - - After initialisation, a timer of 15 seconds is started. Whenever a packet is - transmitted, the timer is reset to 15 seconds again. If the timer expires, an - empty packet is transmitted. This keep the connection alive. - - When a valid packet is received, a timer 65 seconds is started. The interface - become ACTIVE. If the timer expires, the interface becomes INACTIVE. - - - Dynamic IP handling: - - To allow dynamic IP, the ID must be non 0. In this case, any packet with the - correct port number and ID will be accepted. If the remote side changes its IP - the new IP is used for all transmitted packets until it changes again. - - - On Demand: - - If the ondemand parameter is given, the remote IP is set to 0 on timeout. - This will stop keepalive traffic to remote. If the remote is online again, - traffic will continue to the remote address. This is useful for road warriors. - This feature only works with ID set, otherwhise it is highly unsecure. - - - Socket and Thread - ----------------- - - The complete socket opening and closing is done by a thread. - When the thread opened a socket, the hc->socket descriptor is set. Whenever a - packet shall be sent to the socket, the hc->socket must be checked whether not - NULL. To prevent change in socket descriptor, the hc->socket_lock must be used. - To change the socket, a recall of l1oip_socket_open() will safely kill the - socket process and create a new one. - -*/ - -#define L1OIP_VERSION 0 /* 0...3 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "core.h" -#include "l1oip.h" - -static const char *l1oip_revision = "2.00"; - -static int l1oip_cnt; -static DEFINE_SPINLOCK(l1oip_lock); -static LIST_HEAD(l1oip_ilist); - -#define MAX_CARDS 16 -static u_int type[MAX_CARDS]; -static u_int codec[MAX_CARDS]; -static u_int ip[MAX_CARDS * 4]; -static u_int port[MAX_CARDS]; -static u_int remoteport[MAX_CARDS]; -static u_int ondemand[MAX_CARDS]; -static u_int limit[MAX_CARDS]; -static u_int id[MAX_CARDS]; -static int debug; -static int ulaw; - -MODULE_AUTHOR("Andreas Eversberg"); -MODULE_DESCRIPTION("mISDN driver for tunneling layer 1 over IP"); -MODULE_LICENSE("GPL"); -module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(codec, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(ip, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(remoteport, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(ondemand, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(limit, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(id, uint, NULL, S_IRUGO | S_IWUSR); -module_param(ulaw, uint, S_IRUGO | S_IWUSR); -module_param(debug, uint, S_IRUGO | S_IWUSR); - -/* - * send a frame via socket, if open and restart timer - */ -static int -l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, - u16 timebase, u8 *buf, int len) -{ - u8 *p; - u8 frame[MAX_DFRAME_LEN_L1 + 32]; - struct socket *socket = NULL; - - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n", - __func__, len); - - p = frame; - - /* restart timer */ - if (time_before(hc->keep_tl.expires, jiffies + 5 * HZ) && !hc->shutdown) - mod_timer(&hc->keep_tl, jiffies + L1OIP_KEEPALIVE * HZ); - else - hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE * HZ; - - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: resetting timer\n", __func__); - - /* drop if we have no remote ip or port */ - if (!hc->sin_remote.sin_addr.s_addr || !hc->sin_remote.sin_port) { - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: dropping frame, because remote " - "IP is not set.\n", __func__); - return len; - } - - /* assemble frame */ - *p++ = (L1OIP_VERSION << 6) /* version and coding */ - | (hc->pri ? 0x20 : 0x00) /* type */ - | (hc->id ? 0x10 : 0x00) /* id */ - | localcodec; - if (hc->id) { - *p++ = hc->id >> 24; /* id */ - *p++ = hc->id >> 16; - *p++ = hc->id >> 8; - *p++ = hc->id; - } - *p++ = 0x00 + channel; /* m-flag, channel */ - *p++ = timebase >> 8; /* time base */ - *p++ = timebase; - - if (buf && len) { /* add data to frame */ - if (localcodec == 1 && ulaw) - l1oip_ulaw_to_alaw(buf, len, p); - else if (localcodec == 2 && !ulaw) - l1oip_alaw_to_ulaw(buf, len, p); - else if (localcodec == 3) - len = l1oip_law_to_4bit(buf, len, p, - &hc->chan[channel].codecstate); - else - memcpy(p, buf, len); - } - len += p - frame; - - /* check for socket in safe condition */ - spin_lock(&hc->socket_lock); - if (!hc->socket) { - spin_unlock(&hc->socket_lock); - return 0; - } - /* seize socket */ - socket = hc->socket; - hc->socket = NULL; - spin_unlock(&hc->socket_lock); - /* send packet */ - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: sending packet to socket (len " - "= %d)\n", __func__, len); - hc->sendiov.iov_base = frame; - hc->sendiov.iov_len = len; - len = kernel_sendmsg(socket, &hc->sendmsg, &hc->sendiov, 1, len); - /* give socket back */ - hc->socket = socket; /* no locking required */ - - return len; -} - - -/* - * receive channel data from socket - */ -static void -l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, - u8 *buf, int len) -{ - struct sk_buff *nskb; - struct bchannel *bch; - struct dchannel *dch; - u8 *p; - u32 rx_counter; - - if (len == 0) { - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: received empty keepalive data, " - "ignoring\n", __func__); - return; - } - - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: received data, sending to mISDN (%d)\n", - __func__, len); - - if (channel < 1 || channel > 127) { - printk(KERN_WARNING "%s: packet error - channel %d out of " - "range\n", __func__, channel); - return; - } - dch = hc->chan[channel].dch; - bch = hc->chan[channel].bch; - if (!dch && !bch) { - printk(KERN_WARNING "%s: packet error - channel %d not in " - "stack\n", __func__, channel); - return; - } - - /* prepare message */ - nskb = mI_alloc_skb((remotecodec == 3) ? (len << 1) : len, GFP_ATOMIC); - if (!nskb) { - printk(KERN_ERR "%s: No mem for skb.\n", __func__); - return; - } - p = skb_put(nskb, (remotecodec == 3) ? (len << 1) : len); - - if (remotecodec == 1 && ulaw) - l1oip_alaw_to_ulaw(buf, len, p); - else if (remotecodec == 2 && !ulaw) - l1oip_ulaw_to_alaw(buf, len, p); - else if (remotecodec == 3) - len = l1oip_4bit_to_law(buf, len, p); - else - memcpy(p, buf, len); - - /* send message up */ - if (dch && len >= 2) { - dch->rx_skb = nskb; - recv_Dchannel(dch); - } - if (bch) { - /* expand 16 bit sequence number to 32 bit sequence number */ - rx_counter = hc->chan[channel].rx_counter; - if (((s16)(timebase - rx_counter)) >= 0) { - /* time has changed forward */ - if (timebase >= (rx_counter & 0xffff)) - rx_counter = - (rx_counter & 0xffff0000) | timebase; - else - rx_counter = ((rx_counter & 0xffff0000) + 0x10000) - | timebase; - } else { - /* time has changed backwards */ - if (timebase < (rx_counter & 0xffff)) - rx_counter = - (rx_counter & 0xffff0000) | timebase; - else - rx_counter = ((rx_counter & 0xffff0000) - 0x10000) - | timebase; - } - hc->chan[channel].rx_counter = rx_counter; - -#ifdef REORDER_DEBUG - if (hc->chan[channel].disorder_flag) { - swap(hc->chan[channel].disorder_skb, nskb); - swap(hc->chan[channel].disorder_cnt, rx_counter); - } - hc->chan[channel].disorder_flag ^= 1; - if (nskb) -#endif - queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); - } -} - - -/* - * parse frame and extract channel data - */ -static void -l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) -{ - u32 packet_id; - u8 channel; - u8 remotecodec; - u16 timebase; - int m, mlen; - int len_start = len; /* initial frame length */ - struct dchannel *dch = hc->chan[hc->d_idx].dch; - - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: received frame, parsing... (%d)\n", - __func__, len); - - /* check length */ - if (len < 1 + 1 + 2) { - printk(KERN_WARNING "%s: packet error - length %d below " - "4 bytes\n", __func__, len); - return; - } - - /* check version */ - if (((*buf) >> 6) != L1OIP_VERSION) { - printk(KERN_WARNING "%s: packet error - unknown version %d\n", - __func__, buf[0]>>6); - return; - } - - /* check type */ - if (((*buf) & 0x20) && !hc->pri) { - printk(KERN_WARNING "%s: packet error - received E1 packet " - "on S0 interface\n", __func__); - return; - } - if (!((*buf) & 0x20) && hc->pri) { - printk(KERN_WARNING "%s: packet error - received S0 packet " - "on E1 interface\n", __func__); - return; - } - - /* get id flag */ - packet_id = (*buf >> 4) & 1; - - /* check coding */ - remotecodec = (*buf) & 0x0f; - if (remotecodec > 3) { - printk(KERN_WARNING "%s: packet error - remotecodec %d " - "unsupported\n", __func__, remotecodec); - return; - } - buf++; - len--; - - /* check packet_id */ - if (packet_id) { - if (!hc->id) { - printk(KERN_WARNING "%s: packet error - packet has id " - "0x%x, but we have not\n", __func__, packet_id); - return; - } - if (len < 4) { - printk(KERN_WARNING "%s: packet error - packet too " - "short for ID value\n", __func__); - return; - } - packet_id = (*buf++) << 24; - packet_id += (*buf++) << 16; - packet_id += (*buf++) << 8; - packet_id += (*buf++); - len -= 4; - - if (packet_id != hc->id) { - printk(KERN_WARNING "%s: packet error - ID mismatch, " - "got 0x%x, we 0x%x\n", - __func__, packet_id, hc->id); - return; - } - } else { - if (hc->id) { - printk(KERN_WARNING "%s: packet error - packet has no " - "ID, but we have\n", __func__); - return; - } - } - -multiframe: - if (len < 1) { - printk(KERN_WARNING "%s: packet error - packet too short, " - "channel expected at position %d.\n", - __func__, len-len_start + 1); - return; - } - - /* get channel and multiframe flag */ - channel = *buf & 0x7f; - m = *buf >> 7; - buf++; - len--; - - /* check length on multiframe */ - if (m) { - if (len < 1) { - printk(KERN_WARNING "%s: packet error - packet too " - "short, length expected at position %d.\n", - __func__, len_start - len - 1); - return; - } - - mlen = *buf++; - len--; - if (mlen == 0) - mlen = 256; - if (len < mlen + 3) { - printk(KERN_WARNING "%s: packet error - length %d at " - "position %d exceeds total length %d.\n", - __func__, mlen, len_start-len - 1, len_start); - return; - } - if (len == mlen + 3) { - printk(KERN_WARNING "%s: packet error - length %d at " - "position %d will not allow additional " - "packet.\n", - __func__, mlen, len_start-len + 1); - return; - } - } else - mlen = len - 2; /* single frame, subtract timebase */ - - if (len < 2) { - printk(KERN_WARNING "%s: packet error - packet too short, time " - "base expected at position %d.\n", - __func__, len-len_start + 1); - return; - } - - /* get time base */ - timebase = (*buf++) << 8; - timebase |= (*buf++); - len -= 2; - - /* if inactive, we send up a PH_ACTIVATE and activate */ - if (!test_bit(FLG_ACTIVE, &dch->Flags)) { - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: interface become active due to " - "received packet\n", __func__); - test_and_set_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_ATOMIC); - } - - /* distribute packet */ - l1oip_socket_recv(hc, remotecodec, channel, timebase, buf, mlen); - buf += mlen; - len -= mlen; - - /* multiframe */ - if (m) - goto multiframe; - - /* restart timer */ - if ((time_before(hc->timeout_tl.expires, jiffies + 5 * HZ) || - !hc->timeout_on) && - !hc->shutdown) { - hc->timeout_on = 1; - mod_timer(&hc->timeout_tl, jiffies + L1OIP_TIMEOUT * HZ); - } else /* only adjust timer */ - hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT * HZ; - - /* if ip or source port changes */ - if ((hc->sin_remote.sin_addr.s_addr != sin->sin_addr.s_addr) - || (hc->sin_remote.sin_port != sin->sin_port)) { - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: remote address changes from " - "0x%08x to 0x%08x (port %d to %d)\n", __func__, - ntohl(hc->sin_remote.sin_addr.s_addr), - ntohl(sin->sin_addr.s_addr), - ntohs(hc->sin_remote.sin_port), - ntohs(sin->sin_port)); - hc->sin_remote.sin_addr.s_addr = sin->sin_addr.s_addr; - hc->sin_remote.sin_port = sin->sin_port; - } -} - - -/* - * socket stuff - */ -static int -l1oip_socket_thread(void *data) -{ - struct l1oip *hc = (struct l1oip *)data; - int ret = 0; - struct sockaddr_in sin_rx; - struct kvec iov; - struct msghdr msg = {.msg_name = &sin_rx, - .msg_namelen = sizeof(sin_rx)}; - unsigned char *recvbuf; - size_t recvbuf_size = 1500; - int recvlen; - struct socket *socket = NULL; - DECLARE_COMPLETION_ONSTACK(wait); - - /* allocate buffer memory */ - recvbuf = kmalloc(recvbuf_size, GFP_KERNEL); - if (!recvbuf) { - printk(KERN_ERR "%s: Failed to alloc recvbuf.\n", __func__); - ret = -ENOMEM; - goto fail; - } - - iov.iov_base = recvbuf; - iov.iov_len = recvbuf_size; - - /* make daemon */ - allow_signal(SIGTERM); - - /* create socket */ - if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) { - printk(KERN_ERR "%s: Failed to create socket.\n", __func__); - ret = -EIO; - goto fail; - } - - /* set incoming address */ - hc->sin_local.sin_family = AF_INET; - hc->sin_local.sin_addr.s_addr = INADDR_ANY; - hc->sin_local.sin_port = htons((unsigned short)hc->localport); - - /* set outgoing address */ - hc->sin_remote.sin_family = AF_INET; - hc->sin_remote.sin_addr.s_addr = htonl(hc->remoteip); - hc->sin_remote.sin_port = htons((unsigned short)hc->remoteport); - - /* bind to incoming port */ - if (socket->ops->bind(socket, (struct sockaddr_unsized *)&hc->sin_local, - sizeof(hc->sin_local))) { - printk(KERN_ERR "%s: Failed to bind socket to port %d.\n", - __func__, hc->localport); - ret = -EINVAL; - goto fail; - } - - /* check sk */ - if (socket->sk == NULL) { - printk(KERN_ERR "%s: socket->sk == NULL\n", __func__); - ret = -EIO; - goto fail; - } - - /* build send message */ - hc->sendmsg.msg_name = &hc->sin_remote; - hc->sendmsg.msg_namelen = sizeof(hc->sin_remote); - hc->sendmsg.msg_control = NULL; - hc->sendmsg.msg_controllen = 0; - - /* give away socket */ - spin_lock(&hc->socket_lock); - hc->socket = socket; - spin_unlock(&hc->socket_lock); - - /* read loop */ - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: socket created and open\n", - __func__); - while (!signal_pending(current)) { - iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, recvbuf_size); - recvlen = sock_recvmsg(socket, &msg, 0); - if (recvlen > 0) { - l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); - } else { - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_WARNING - "%s: broken pipe on socket\n", __func__); - } - } - - /* get socket back, check first if in use, maybe by send function */ - spin_lock(&hc->socket_lock); - /* if hc->socket is NULL, it is in use until it is given back */ - while (!hc->socket) { - spin_unlock(&hc->socket_lock); - schedule_timeout(HZ / 10); - spin_lock(&hc->socket_lock); - } - hc->socket = NULL; - spin_unlock(&hc->socket_lock); - - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: socket thread terminating\n", - __func__); - -fail: - /* free recvbuf */ - kfree(recvbuf); - - /* close socket */ - if (socket) - sock_release(socket); - - /* if we got killed, signal completion */ - complete(&hc->socket_complete); - hc->socket_thread = NULL; /* show termination of thread */ - - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: socket thread terminated\n", - __func__); - return ret; -} - -static void -l1oip_socket_close(struct l1oip *hc) -{ - struct dchannel *dch = hc->chan[hc->d_idx].dch; - - /* kill thread */ - if (hc->socket_thread) { - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: socket thread exists, " - "killing...\n", __func__); - send_sig(SIGTERM, hc->socket_thread, 0); - wait_for_completion(&hc->socket_complete); - } - - /* if active, we send up a PH_DEACTIVATE and deactivate */ - if (test_bit(FLG_ACTIVE, &dch->Flags)) { - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: interface become deactivated " - "due to timeout\n", __func__); - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_ATOMIC); - } -} - -static int -l1oip_socket_open(struct l1oip *hc) -{ - /* in case of reopen, we need to close first */ - l1oip_socket_close(hc); - - init_completion(&hc->socket_complete); - - /* create receive process */ - hc->socket_thread = kthread_run(l1oip_socket_thread, hc, "l1oip_%s", - hc->name); - if (IS_ERR(hc->socket_thread)) { - int err = PTR_ERR(hc->socket_thread); - printk(KERN_ERR "%s: Failed (%d) to create socket process.\n", - __func__, err); - hc->socket_thread = NULL; - sock_release(hc->socket); - return err; - } - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: socket thread created\n", __func__); - - return 0; -} - - -static void -l1oip_send_bh(struct work_struct *work) -{ - struct l1oip *hc = container_of(work, struct l1oip, workq); - - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: keepalive timer expired, sending empty " - "frame on dchannel\n", __func__); - - /* send an empty l1oip frame at D-channel */ - l1oip_socket_send(hc, 0, hc->d_idx, 0, 0, NULL, 0); -} - - -/* - * timer stuff - */ -static void -l1oip_keepalive(struct timer_list *t) -{ - struct l1oip *hc = timer_container_of(hc, t, keep_tl); - - schedule_work(&hc->workq); -} - -static void -l1oip_timeout(struct timer_list *t) -{ - struct l1oip *hc = timer_container_of(hc, t, - timeout_tl); - struct dchannel *dch = hc->chan[hc->d_idx].dch; - - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: timeout timer expired, turn layer one " - "down.\n", __func__); - - hc->timeout_on = 0; /* state that timer must be initialized next time */ - - /* if timeout, we send up a PH_DEACTIVATE and deactivate */ - if (test_bit(FLG_ACTIVE, &dch->Flags)) { - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: interface become deactivated " - "due to timeout\n", __func__); - test_and_clear_bit(FLG_ACTIVE, &dch->Flags); - _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_ATOMIC); - } - - /* if we have ondemand set, we remove ip address */ - if (hc->ondemand) { - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: on demand causes ip address to " - "be removed\n", __func__); - hc->sin_remote.sin_addr.s_addr = 0; - } -} - - -/* - * message handling - */ -static int -handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct l1oip *hc = dch->hw; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret = -EINVAL; - int l, ll; - unsigned char *p; - - switch (hh->prim) { - case PH_DATA_REQ: - if (skb->len < 1) { - printk(KERN_WARNING "%s: skb too small\n", - __func__); - break; - } - if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { - printk(KERN_WARNING "%s: skb too large\n", - __func__); - break; - } - /* send frame */ - p = skb->data; - l = skb->len; - while (l) { - /* - * This is technically bounded by L1OIP_MAX_PERFRAME but - * MAX_DFRAME_LEN_L1 < L1OIP_MAX_PERFRAME - */ - ll = (l < MAX_DFRAME_LEN_L1) ? l : MAX_DFRAME_LEN_L1; - l1oip_socket_send(hc, 0, dch->slot, 0, - hc->chan[dch->slot].tx_counter++, p, ll); - p += ll; - l -= ll; - } - skb_trim(skb, 0); - queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); - return 0; - case PH_ACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" - , __func__, dch->slot, hc->b_num + 1); - skb_trim(skb, 0); - if (test_bit(FLG_ACTIVE, &dch->Flags)) - queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); - else - queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); - return 0; - case PH_DEACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " - "(1..%d)\n", __func__, dch->slot, - hc->b_num + 1); - skb_trim(skb, 0); - if (test_bit(FLG_ACTIVE, &dch->Flags)) - queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); - else - queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); - return 0; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - struct l1oip *hc = dch->hw; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER - | MISDN_CTRL_GETPEER; - break; - case MISDN_CTRL_SETPEER: - hc->remoteip = (u32)cq->p1; - hc->remoteport = cq->p2 & 0xffff; - hc->localport = cq->p2 >> 16; - if (!hc->remoteport) - hc->remoteport = hc->localport; - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: got new ip address from user " - "space.\n", __func__); - l1oip_socket_open(hc); - break; - case MISDN_CTRL_UNSETPEER: - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: removing ip address.\n", - __func__); - hc->remoteip = 0; - l1oip_socket_open(hc); - break; - case MISDN_CTRL_GETPEER: - if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_DEBUG "%s: getting ip address.\n", - __func__); - cq->p1 = hc->remoteip; - cq->p2 = hc->remoteport | (hc->localport << 16); - break; - default: - printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -open_dchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) -{ - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, - dch->dev.id, __builtin_return_address(0)); - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - if ((dch->dev.D.protocol != ISDN_P_NONE) && - (dch->dev.D.protocol != rq->protocol)) { - if (debug & DEBUG_HW_OPEN) - printk(KERN_WARNING "%s: change protocol %x to %x\n", - __func__, dch->dev.D.protocol, rq->protocol); - } - if (dch->dev.D.protocol != rq->protocol) - dch->dev.D.protocol = rq->protocol; - - if (test_bit(FLG_ACTIVE, &dch->Flags)) { - _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); - } - rq->ch = &dch->dev.D; - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s:cannot get module\n", __func__); - return 0; -} - -static int -open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) -{ - struct bchannel *bch; - int ch; - - if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) - return -EINVAL; - if (rq->protocol == ISDN_P_NONE) - return -EINVAL; - ch = rq->adr.channel; /* BRI: 1=B1 2=B2 PRI: 1..15,17.. */ - bch = hc->chan[ch].bch; - if (!bch) { - printk(KERN_ERR "%s:internal error ch %d has no bch\n", - __func__, ch); - return -EINVAL; - } - if (test_and_set_bit(FLG_OPEN, &bch->Flags)) - return -EBUSY; /* b-channel can be only open once */ - bch->ch.protocol = rq->protocol; - rq->ch = &bch->ch; - if (!try_module_get(THIS_MODULE)) - printk(KERN_WARNING "%s:cannot get module\n", __func__); - return 0; -} - -static int -l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); - struct dchannel *dch = container_of(dev, struct dchannel, dev); - struct l1oip *hc = dch->hw; - struct channel_req *rq; - int err = 0; - - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: cmd:%x %p\n", - __func__, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - rq = arg; - switch (rq->protocol) { - case ISDN_P_TE_S0: - case ISDN_P_NT_S0: - if (hc->pri) { - err = -EINVAL; - break; - } - err = open_dchannel(hc, dch, rq); - break; - case ISDN_P_TE_E1: - case ISDN_P_NT_E1: - if (!hc->pri) { - err = -EINVAL; - break; - } - err = open_dchannel(hc, dch, rq); - break; - default: - err = open_bchannel(hc, dch, rq); - } - break; - case CLOSE_CHANNEL: - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: dev(%d) close from %p\n", - __func__, dch->dev.id, - __builtin_return_address(0)); - module_put(THIS_MODULE); - break; - case CONTROL_CHANNEL: - err = channel_dctrl(dch, arg); - break; - default: - if (dch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: unknown command %x\n", - __func__, cmd); - err = -EINVAL; - } - return err; -} - -static int -handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - struct l1oip *hc = bch->hw; - int ret = -EINVAL; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - int l, ll; - unsigned char *p; - - switch (hh->prim) { - case PH_DATA_REQ: - if (skb->len <= 0) { - printk(KERN_WARNING "%s: skb too small\n", - __func__); - break; - } - if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { - printk(KERN_WARNING "%s: skb too large\n", - __func__); - break; - } - /* check for AIS / ulaw-silence */ - l = skb->len; - if (!memchr_inv(skb->data, 0xff, l)) { - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: got AIS, not sending, " - "but counting\n", __func__); - hc->chan[bch->slot].tx_counter += l; - skb_trim(skb, 0); - queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); - return 0; - } - /* check for silence */ - l = skb->len; - if (!memchr_inv(skb->data, 0x2a, l)) { - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: got silence, not sending" - ", but counting\n", __func__); - hc->chan[bch->slot].tx_counter += l; - skb_trim(skb, 0); - queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); - return 0; - } - - /* send frame */ - p = skb->data; - l = skb->len; - while (l) { - /* - * This is technically bounded by L1OIP_MAX_PERFRAME but - * MAX_DFRAME_LEN_L1 < L1OIP_MAX_PERFRAME - */ - ll = (l < MAX_DFRAME_LEN_L1) ? l : MAX_DFRAME_LEN_L1; - l1oip_socket_send(hc, hc->codec, bch->slot, 0, - hc->chan[bch->slot].tx_counter, p, ll); - hc->chan[bch->slot].tx_counter += ll; - p += ll; - l -= ll; - } - skb_trim(skb, 0); - queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); - return 0; - case PH_ACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" - , __func__, bch->slot, hc->b_num + 1); - hc->chan[bch->slot].codecstate = 0; - test_and_set_bit(FLG_ACTIVE, &bch->Flags); - skb_trim(skb, 0); - queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); - return 0; - case PH_DEACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) - printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " - "(1..%d)\n", __func__, bch->slot, - hc->b_num + 1); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - skb_trim(skb, 0); - queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); - return 0; - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) -{ - int ret = 0; - struct dsp_features *features = - (struct dsp_features *)(*((u_long *)&cq->p1)); - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_HW_FEATURES_OP; - break; - case MISDN_CTRL_HW_FEATURES: /* fill features structure */ - if (debug & DEBUG_L1OIP_MSG) - printk(KERN_DEBUG "%s: HW_FEATURE request\n", - __func__); - /* create confirm */ - features->unclocked = 1; - features->unordered = 1; - break; - default: - printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; -} - -static int -l1oip_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct bchannel *bch = container_of(ch, struct bchannel, ch); - int err = -EINVAL; - - if (bch->debug & DEBUG_HW) - printk(KERN_DEBUG "%s: cmd:%x %p\n", - __func__, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - test_and_clear_bit(FLG_OPEN, &bch->Flags); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - ch->protocol = ISDN_P_NONE; - ch->peer = NULL; - module_put(THIS_MODULE); - err = 0; - break; - case CONTROL_CHANNEL: - err = channel_bctrl(bch, arg); - break; - default: - printk(KERN_WARNING "%s: unknown prim(%x)\n", - __func__, cmd); - } - return err; -} - - -/* - * cleanup module and stack - */ -static void -release_card(struct l1oip *hc) -{ - int ch; - - hc->shutdown = true; - - timer_shutdown_sync(&hc->keep_tl); - timer_shutdown_sync(&hc->timeout_tl); - - cancel_work_sync(&hc->workq); - - if (hc->socket_thread) - l1oip_socket_close(hc); - - if (hc->registered && hc->chan[hc->d_idx].dch) - mISDN_unregister_device(&hc->chan[hc->d_idx].dch->dev); - for (ch = 0; ch < 128; ch++) { - if (hc->chan[ch].dch) { - mISDN_freedchannel(hc->chan[ch].dch); - kfree(hc->chan[ch].dch); - } - if (hc->chan[ch].bch) { - mISDN_freebchannel(hc->chan[ch].bch); - kfree(hc->chan[ch].bch); -#ifdef REORDER_DEBUG - dev_kfree_skb(hc->chan[ch].disorder_skb); -#endif - } - } - - spin_lock(&l1oip_lock); - list_del(&hc->list); - spin_unlock(&l1oip_lock); - - kfree(hc); -} - -static void -l1oip_cleanup(void) -{ - struct l1oip *hc, *next; - - list_for_each_entry_safe(hc, next, &l1oip_ilist, list) - release_card(hc); - - l1oip_4bit_free(); -} - - -/* - * module and stack init - */ -static int -init_card(struct l1oip *hc, int pri, int bundle) -{ - struct dchannel *dch; - struct bchannel *bch; - int ret; - int i, ch; - - spin_lock_init(&hc->socket_lock); - hc->idx = l1oip_cnt; - hc->pri = pri; - hc->d_idx = pri ? 16 : 3; - hc->b_num = pri ? 30 : 2; - hc->bundle = bundle; - if (hc->pri) - sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1); - else - sprintf(hc->name, "l1oip-s0.%d", l1oip_cnt + 1); - - switch (codec[l1oip_cnt]) { - case 0: /* as is */ - case 1: /* alaw */ - case 2: /* ulaw */ - case 3: /* 4bit */ - break; - default: - printk(KERN_ERR "Codec(%d) not supported.\n", - codec[l1oip_cnt]); - return -EINVAL; - } - hc->codec = codec[l1oip_cnt]; - if (debug & DEBUG_L1OIP_INIT) - printk(KERN_DEBUG "%s: using codec %d\n", - __func__, hc->codec); - - if (id[l1oip_cnt] == 0) { - printk(KERN_WARNING "Warning: No 'id' value given or " - "0, this is highly unsecure. Please use 32 " - "bit random number 0x...\n"); - } - hc->id = id[l1oip_cnt]; - if (debug & DEBUG_L1OIP_INIT) - printk(KERN_DEBUG "%s: using id 0x%x\n", __func__, hc->id); - - hc->ondemand = ondemand[l1oip_cnt]; - if (hc->ondemand && !hc->id) { - printk(KERN_ERR "%s: ondemand option only allowed in " - "conjunction with non 0 ID\n", __func__); - return -EINVAL; - } - - if (limit[l1oip_cnt]) - hc->b_num = limit[l1oip_cnt]; - if (!pri && hc->b_num > 2) { - printk(KERN_ERR "Maximum limit for BRI interface is 2 " - "channels.\n"); - return -EINVAL; - } - if (pri && hc->b_num > 126) { - printk(KERN_ERR "Maximum limit for PRI interface is 126 " - "channels.\n"); - return -EINVAL; - } - if (pri && hc->b_num > 30) { - printk(KERN_WARNING "Maximum limit for BRI interface is 30 " - "channels.\n"); - printk(KERN_WARNING "Your selection of %d channels must be " - "supported by application.\n", hc->limit); - } - - hc->remoteip = ip[l1oip_cnt << 2] << 24 - | ip[(l1oip_cnt << 2) + 1] << 16 - | ip[(l1oip_cnt << 2) + 2] << 8 - | ip[(l1oip_cnt << 2) + 3]; - hc->localport = port[l1oip_cnt]?:(L1OIP_DEFAULTPORT + l1oip_cnt); - if (remoteport[l1oip_cnt]) - hc->remoteport = remoteport[l1oip_cnt]; - else - hc->remoteport = hc->localport; - if (debug & DEBUG_L1OIP_INIT) - printk(KERN_DEBUG "%s: using local port %d remote ip " - "%d.%d.%d.%d port %d ondemand %d\n", __func__, - hc->localport, hc->remoteip >> 24, - (hc->remoteip >> 16) & 0xff, - (hc->remoteip >> 8) & 0xff, hc->remoteip & 0xff, - hc->remoteport, hc->ondemand); - - dch = kzalloc_obj(struct dchannel); - if (!dch) - return -ENOMEM; - dch->debug = debug; - mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, NULL); - dch->hw = hc; - if (pri) - dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); - else - dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); - dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - dch->dev.D.send = handle_dmsg; - dch->dev.D.ctrl = l1oip_dctrl; - dch->dev.nrbchan = hc->b_num; - dch->slot = hc->d_idx; - hc->chan[hc->d_idx].dch = dch; - i = 1; - for (ch = 0; ch < dch->dev.nrbchan; ch++) { - if (ch == 15) - i++; - bch = kzalloc_obj(struct bchannel); - if (!bch) { - printk(KERN_ERR "%s: no memory for bchannel\n", - __func__); - return -ENOMEM; - } - bch->nr = i + ch; - bch->slot = i + ch; - bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM, 0); - bch->hw = hc; - bch->ch.send = handle_bmsg; - bch->ch.ctrl = l1oip_bctrl; - bch->ch.nr = i + ch; - list_add(&bch->ch.list, &dch->dev.bchannels); - hc->chan[i + ch].bch = bch; - set_channelmap(bch->nr, dch->dev.channelmap); - } - /* TODO: create a parent device for this driver */ - ret = mISDN_register_device(&dch->dev, NULL, hc->name); - if (ret) - return ret; - hc->registered = 1; - - if (debug & DEBUG_L1OIP_INIT) - printk(KERN_DEBUG "%s: Setting up network card(%d)\n", - __func__, l1oip_cnt + 1); - ret = l1oip_socket_open(hc); - if (ret) - return ret; - - timer_setup(&hc->keep_tl, l1oip_keepalive, 0); - hc->keep_tl.expires = jiffies + 2 * HZ; /* two seconds first time */ - add_timer(&hc->keep_tl); - - timer_setup(&hc->timeout_tl, l1oip_timeout, 0); - hc->timeout_on = 0; /* state that we have timer off */ - - return 0; -} - -static int __init -l1oip_init(void) -{ - int pri, bundle; - struct l1oip *hc; - int ret; - - printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n", - l1oip_revision); - - if (l1oip_4bit_alloc(ulaw)) - return -ENOMEM; - - l1oip_cnt = 0; - while (l1oip_cnt < MAX_CARDS && type[l1oip_cnt]) { - switch (type[l1oip_cnt] & 0xff) { - case 1: - pri = 0; - bundle = 0; - break; - case 2: - pri = 1; - bundle = 0; - break; - case 3: - pri = 0; - bundle = 1; - break; - case 4: - pri = 1; - bundle = 1; - break; - default: - printk(KERN_ERR "Card type(%d) not supported.\n", - type[l1oip_cnt] & 0xff); - l1oip_cleanup(); - return -EINVAL; - } - - if (debug & DEBUG_L1OIP_INIT) - printk(KERN_DEBUG "%s: interface %d is %s with %s.\n", - __func__, l1oip_cnt, pri ? "PRI" : "BRI", - bundle ? "bundled IP packet for all B-channels" : - "separate IP packets for every B-channel"); - - hc = kzalloc_obj(struct l1oip, GFP_ATOMIC); - if (!hc) { - printk(KERN_ERR "No kmem for L1-over-IP driver.\n"); - l1oip_cleanup(); - return -ENOMEM; - } - INIT_WORK(&hc->workq, (void *)l1oip_send_bh); - - spin_lock(&l1oip_lock); - list_add_tail(&hc->list, &l1oip_ilist); - spin_unlock(&l1oip_lock); - - ret = init_card(hc, pri, bundle); - if (ret) { - l1oip_cleanup(); - return ret; - } - - l1oip_cnt++; - } - printk(KERN_INFO "%d virtual devices registered\n", l1oip_cnt); - return 0; -} - -module_init(l1oip_init); -module_exit(l1oip_cleanup); diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c deleted file mode 100644 index 3fbc170acf9a..000000000000 --- a/drivers/isdn/mISDN/layer1.c +++ /dev/null @@ -1,415 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - */ - - -#include -#include -#include -#include "core.h" -#include "layer1.h" -#include "fsm.h" - -static u_int *debug; - -struct layer1 { - u_long Flags; - struct FsmInst l1m; - struct FsmTimer timer3; - struct FsmTimer timerX; - int delay; - int t3_value; - struct dchannel *dch; - dchannel_l1callback *dcb; -}; - -#define TIMER3_DEFAULT_VALUE 7000 - -static -struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; - -enum { - ST_L1_F2, - ST_L1_F3, - ST_L1_F4, - ST_L1_F5, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1S_STATE_COUNT (ST_L1_F8 + 1) - -static char *strL1SState[] = -{ - "ST_L1_F2", - "ST_L1_F3", - "ST_L1_F4", - "ST_L1_F5", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -enum { - EV_PH_ACTIVATE, - EV_PH_DEACTIVATE, - EV_RESET_IND, - EV_DEACT_CNF, - EV_DEACT_IND, - EV_POWER_UP, - EV_ANYSIG_IND, - EV_INFO2_IND, - EV_INFO4_IND, - EV_TIMER_DEACT, - EV_TIMER_ACT, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -static char *strL1Event[] = -{ - "EV_PH_ACTIVATE", - "EV_PH_DEACTIVATE", - "EV_RESET_IND", - "EV_DEACT_CNF", - "EV_DEACT_IND", - "EV_POWER_UP", - "EV_ANYSIG_IND", - "EV_INFO2_IND", - "EV_INFO4_IND", - "EV_TIMER_DEACT", - "EV_TIMER_ACT", - "EV_TIMER3", -}; - -static void -l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - struct layer1 *l1 = fi->userdata; - struct va_format vaf; - va_list va; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - printk(KERN_DEBUG "%s: %pV\n", dev_name(&l1->dch->dev.dev), &vaf); - - va_end(va); -} - -static void -l1_reset(struct FsmInst *fi, int event, void *arg) -{ - mISDN_FsmChangeState(fi, ST_L1_F3); -} - -static void -l1_deact_cnf(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - mISDN_FsmChangeState(fi, ST_L1_F3); - if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) - l1->dcb(l1->dch, HW_POWERUP_REQ); -} - -static void -l1_deact_req_s(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - mISDN_FsmChangeState(fi, ST_L1_F3); - mISDN_FsmRestartTimer(&l1->timerX, 550, EV_TIMER_DEACT, NULL, 2); - test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); -} - -static void -l1_power_up_s(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) { - mISDN_FsmChangeState(fi, ST_L1_F4); - l1->dcb(l1->dch, INFO3_P8); - } else - mISDN_FsmChangeState(fi, ST_L1_F3); -} - -static void -l1_go_F5(struct FsmInst *fi, int event, void *arg) -{ - mISDN_FsmChangeState(fi, ST_L1_F5); -} - -static void -l1_go_F8(struct FsmInst *fi, int event, void *arg) -{ - mISDN_FsmChangeState(fi, ST_L1_F8); -} - -static void -l1_info2_ind(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - mISDN_FsmChangeState(fi, ST_L1_F6); - l1->dcb(l1->dch, INFO3_P8); -} - -static void -l1_info4_ind(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - mISDN_FsmChangeState(fi, ST_L1_F7); - l1->dcb(l1->dch, INFO3_P8); - if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timerX, 4); - if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { - if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timer3, 3); - mISDN_FsmRestartTimer(&l1->timerX, 110, EV_TIMER_ACT, NULL, 2); - test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); - } -} - -static void -l1_timer3(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags); - if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) { - if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) - l1->dcb(l1->dch, HW_D_NOBLOCKED); - l1->dcb(l1->dch, PH_DEACTIVATE_IND); - } - if (l1->l1m.state != ST_L1_F6) { - mISDN_FsmChangeState(fi, ST_L1_F3); - /* do not force anything here, we need send INFO 0 */ - } -} - -static void -l1_timer_act(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags); - test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags); - l1->dcb(l1->dch, PH_ACTIVATE_IND); -} - -static void -l1_timer_deact(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags); - test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags); - if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) - l1->dcb(l1->dch, HW_D_NOBLOCKED); - l1->dcb(l1->dch, PH_DEACTIVATE_IND); - l1->dcb(l1->dch, HW_DEACT_REQ); -} - -static void -l1_activate_s(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - mISDN_FsmRestartTimer(&l1->timer3, l1->t3_value, EV_TIMER3, NULL, 2); - test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); - /* Tell HW to send INFO 1 */ - l1->dcb(l1->dch, HW_RESET_REQ); -} - -static void -l1_activate_no(struct FsmInst *fi, int event, void *arg) -{ - struct layer1 *l1 = fi->userdata; - - if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) && - (!test_bit(FLG_L1_T3RUN, &l1->Flags))) { - test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags); - if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) - l1->dcb(l1->dch, HW_D_NOBLOCKED); - l1->dcb(l1->dch, PH_DEACTIVATE_IND); - } -} - -static struct FsmNode L1SFnList[] = -{ - {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, - {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, - {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, - {ST_L1_F3, EV_RESET_IND, l1_reset}, - {ST_L1_F4, EV_RESET_IND, l1_reset}, - {ST_L1_F5, EV_RESET_IND, l1_reset}, - {ST_L1_F6, EV_RESET_IND, l1_reset}, - {ST_L1_F7, EV_RESET_IND, l1_reset}, - {ST_L1_F8, EV_RESET_IND, l1_reset}, - {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, - {ST_L1_F4, EV_ANYSIG_IND, l1_go_F5}, - {ST_L1_F6, EV_ANYSIG_IND, l1_go_F8}, - {ST_L1_F7, EV_ANYSIG_IND, l1_go_F8}, - {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F3, EV_TIMER3, l1_timer3}, - {ST_L1_F4, EV_TIMER3, l1_timer3}, - {ST_L1_F5, EV_TIMER3, l1_timer3}, - {ST_L1_F6, EV_TIMER3, l1_timer3}, - {ST_L1_F8, EV_TIMER3, l1_timer3}, - {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, - {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, -}; - -static void -release_l1(struct layer1 *l1) { - mISDN_FsmDelTimer(&l1->timerX, 0); - mISDN_FsmDelTimer(&l1->timer3, 0); - if (l1->dch) - l1->dch->l1 = NULL; - module_put(THIS_MODULE); - kfree(l1); -} - -int -l1_event(struct layer1 *l1, u_int event) -{ - int err = 0; - - if (!l1) - return -EINVAL; - switch (event) { - case HW_RESET_IND: - mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL); - break; - case HW_DEACT_IND: - mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL); - break; - case HW_POWERUP_IND: - mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL); - break; - case HW_DEACT_CNF: - mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL); - break; - case ANYSIGNAL: - mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); - break; - case LOSTFRAMING: - mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); - break; - case INFO2: - mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL); - break; - case INFO4_P8: - mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); - break; - case INFO4_P10: - mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); - break; - case PH_ACTIVATE_REQ: - if (test_bit(FLG_L1_ACTIVATED, &l1->Flags)) - l1->dcb(l1->dch, PH_ACTIVATE_IND); - else { - test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags); - mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL); - } - break; - case CLOSE_CHANNEL: - release_l1(l1); - break; - default: - if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) { - int val = event & HW_TIMER3_VMASK; - - if (val < 5) - val = 5; - if (val > 30) - val = 30; - l1->t3_value = val; - break; - } - if (*debug & DEBUG_L1) - printk(KERN_DEBUG "%s %x unhandled\n", - __func__, event); - err = -EINVAL; - } - return err; -} -EXPORT_SYMBOL(l1_event); - -int -create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { - struct layer1 *nl1; - - nl1 = kzalloc_obj(struct layer1, GFP_ATOMIC); - if (!nl1) { - printk(KERN_ERR "kmalloc struct layer1 failed\n"); - return -ENOMEM; - } - nl1->l1m.fsm = &l1fsm_s; - nl1->l1m.state = ST_L1_F3; - nl1->Flags = 0; - nl1->t3_value = TIMER3_DEFAULT_VALUE; - nl1->l1m.debug = *debug & DEBUG_L1_FSM; - nl1->l1m.userdata = nl1; - nl1->l1m.userint = 0; - nl1->l1m.printdebug = l1m_debug; - nl1->dch = dch; - nl1->dcb = dcb; - mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer3); - mISDN_FsmInitTimer(&nl1->l1m, &nl1->timerX); - __module_get(THIS_MODULE); - dch->l1 = nl1; - return 0; -} -EXPORT_SYMBOL(create_l1); - -int -Isdnl1_Init(u_int *deb) -{ - debug = deb; - l1fsm_s.state_count = L1S_STATE_COUNT; - l1fsm_s.event_count = L1_EVENT_COUNT; - l1fsm_s.strEvent = strL1Event; - l1fsm_s.strState = strL1SState; - return mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); -} - -void -Isdnl1_cleanup(void) -{ - mISDN_FsmFree(&l1fsm_s); -} diff --git a/drivers/isdn/mISDN/layer1.h b/drivers/isdn/mISDN/layer1.h deleted file mode 100644 index f03e86450daf..000000000000 --- a/drivers/isdn/mISDN/layer1.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * - * Layer 1 defines - * - * Copyright 2008 by Karsten Keil - */ - -#define FLG_L1_ACTIVATING 1 -#define FLG_L1_ACTIVATED 2 -#define FLG_L1_DEACTTIMER 3 -#define FLG_L1_ACTTIMER 4 -#define FLG_L1_T3RUN 5 -#define FLG_L1_PULL_REQ 6 -#define FLG_L1_UINT 7 -#define FLG_L1_DBLOCKED 8 diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c deleted file mode 100644 index b75869c9f78f..000000000000 --- a/drivers/isdn/mISDN/layer2.c +++ /dev/null @@ -1,2266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include "core.h" -#include "fsm.h" -#include "layer2.h" - -static u_int *debug; - -static -struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; - -static char *strL2State[] = -{ - "ST_L2_1", - "ST_L2_2", - "ST_L2_3", - "ST_L2_4", - "ST_L2_5", - "ST_L2_6", - "ST_L2_7", - "ST_L2_8", -}; - -enum { - EV_L2_UI, - EV_L2_SABME, - EV_L2_DISC, - EV_L2_DM, - EV_L2_UA, - EV_L2_FRMR, - EV_L2_SUPER, - EV_L2_I, - EV_L2_DL_DATA, - EV_L2_ACK_PULL, - EV_L2_DL_UNITDATA, - EV_L2_DL_ESTABLISH_REQ, - EV_L2_DL_RELEASE_REQ, - EV_L2_MDL_ASSIGN, - EV_L2_MDL_REMOVE, - EV_L2_MDL_ERROR, - EV_L1_DEACTIVATE, - EV_L2_T200, - EV_L2_T203, - EV_L2_T200I, - EV_L2_T203I, - EV_L2_SET_OWN_BUSY, - EV_L2_CLEAR_OWN_BUSY, - EV_L2_FRAME_ERROR, -}; - -#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1) - -static char *strL2Event[] = -{ - "EV_L2_UI", - "EV_L2_SABME", - "EV_L2_DISC", - "EV_L2_DM", - "EV_L2_UA", - "EV_L2_FRMR", - "EV_L2_SUPER", - "EV_L2_I", - "EV_L2_DL_DATA", - "EV_L2_ACK_PULL", - "EV_L2_DL_UNITDATA", - "EV_L2_DL_ESTABLISH_REQ", - "EV_L2_DL_RELEASE_REQ", - "EV_L2_MDL_ASSIGN", - "EV_L2_MDL_REMOVE", - "EV_L2_MDL_ERROR", - "EV_L1_DEACTIVATE", - "EV_L2_T200", - "EV_L2_T203", - "EV_L2_T200I", - "EV_L2_T203I", - "EV_L2_SET_OWN_BUSY", - "EV_L2_CLEAR_OWN_BUSY", - "EV_L2_FRAME_ERROR", -}; - -static void -l2m_debug(struct FsmInst *fi, char *fmt, ...) -{ - struct layer2 *l2 = fi->userdata; - struct va_format vaf; - va_list va; - - if (!(*debug & DEBUG_L2_FSM)) - return; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n", - mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf); - - va_end(va); -} - -inline u_int -l2headersize(struct layer2 *l2, int ui) -{ - return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + - (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); -} - -inline u_int -l2addrsize(struct layer2 *l2) -{ - return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1; -} - -static u_int -l2_newid(struct layer2 *l2) -{ - u_int id; - - id = l2->next_id++; - if (id == 0x7fff) - l2->next_id = 1; - id <<= 16; - id |= l2->tei << 8; - id |= l2->sapi; - return id; -} - -static void -l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) -{ - int err; - - if (!l2->up) - return; - mISDN_HEAD_PRIM(skb) = prim; - mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; - err = l2->up->send(l2->up, skb); - if (err) { - printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, - mISDNDevName4ch(&l2->ch), err); - dev_kfree_skb(skb); - } -} - -static void -l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) -{ - struct sk_buff *skb; - struct mISDNhead *hh; - int err; - - if (!l2->up) - return; - skb = mI_alloc_skb(len, GFP_ATOMIC); - if (!skb) - return; - hh = mISDN_HEAD_P(skb); - hh->prim = prim; - hh->id = (l2->ch.nr << 16) | l2->ch.addr; - if (len) - skb_put_data(skb, arg, len); - err = l2->up->send(l2->up, skb); - if (err) { - printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, - mISDNDevName4ch(&l2->ch), err); - dev_kfree_skb(skb); - } -} - -static int -l2down_skb(struct layer2 *l2, struct sk_buff *skb) { - int ret; - - ret = l2->ch.recv(l2->ch.peer, skb); - if (ret && (*debug & DEBUG_L2_RECV)) - printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n", - mISDNDevName4ch(&l2->ch), ret); - return ret; -} - -static int -l2down_raw(struct layer2 *l2, struct sk_buff *skb) -{ - struct mISDNhead *hh = mISDN_HEAD_P(skb); - - if (hh->prim == PH_DATA_REQ) { - if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { - skb_queue_tail(&l2->down_queue, skb); - return 0; - } - l2->down_id = mISDN_HEAD_ID(skb); - } - return l2down_skb(l2, skb); -} - -static int -l2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb) -{ - struct mISDNhead *hh = mISDN_HEAD_P(skb); - - hh->prim = prim; - hh->id = id; - return l2down_raw(l2, skb); -} - -static int -l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg) -{ - struct sk_buff *skb; - int err; - struct mISDNhead *hh; - - skb = mI_alloc_skb(len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - hh = mISDN_HEAD_P(skb); - hh->prim = prim; - hh->id = id; - if (len) - skb_put_data(skb, arg, len); - err = l2down_raw(l2, skb); - if (err) - dev_kfree_skb(skb); - return err; -} - -static int -ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { - struct sk_buff *nskb = skb; - int ret = -EAGAIN; - - if (test_bit(FLG_L1_NOTREADY, &l2->flag)) { - if (hh->id == l2->down_id) { - nskb = skb_dequeue(&l2->down_queue); - if (nskb) { - l2->down_id = mISDN_HEAD_ID(nskb); - if (l2down_skb(l2, nskb)) { - dev_kfree_skb(nskb); - l2->down_id = MISDN_ID_NONE; - } - } else - l2->down_id = MISDN_ID_NONE; - if (ret) { - dev_kfree_skb(skb); - ret = 0; - } - if (l2->down_id == MISDN_ID_NONE) { - test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); - mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); - } - } - } - if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { - nskb = skb_dequeue(&l2->down_queue); - if (nskb) { - l2->down_id = mISDN_HEAD_ID(nskb); - if (l2down_skb(l2, nskb)) { - dev_kfree_skb(nskb); - l2->down_id = MISDN_ID_NONE; - test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); - } - } else - test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); - } - return ret; -} - -static void -l2_timeout(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb; - struct mISDNhead *hh; - - skb = mI_alloc_skb(0, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n", - mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, - l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); - return; - } - hh = mISDN_HEAD_P(skb); - hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND; - hh->id = l2->ch.nr; - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n", - mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, - l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); - if (l2->ch.st) - l2->ch.st->own.recv(&l2->ch.st->own, skb); -} - -static int -l2mgr(struct layer2 *l2, u_int prim, void *arg) { - long c = (long)arg; - - printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n", - mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c); - if (test_bit(FLG_LAPD, &l2->flag) && - !test_bit(FLG_FIXED_TEI, &l2->flag)) { - switch (c) { - case 'C': - case 'D': - case 'G': - case 'H': - l2_tei(l2, prim, (u_long)arg); - break; - } - } - return 0; -} - -static void -set_peer_busy(struct layer2 *l2) { - test_and_set_bit(FLG_PEER_BUSY, &l2->flag); - if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue)) - test_and_set_bit(FLG_L2BLOCK, &l2->flag); -} - -static void -clear_peer_busy(struct layer2 *l2) { - if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag)) - test_and_clear_bit(FLG_L2BLOCK, &l2->flag); -} - -static void -InitWin(struct layer2 *l2) -{ - int i; - - for (i = 0; i < MAX_WINDOW; i++) - l2->windowar[i] = NULL; -} - -static int -freewin(struct layer2 *l2) -{ - int i, cnt = 0; - - for (i = 0; i < MAX_WINDOW; i++) { - if (l2->windowar[i]) { - cnt++; - dev_kfree_skb(l2->windowar[i]); - l2->windowar[i] = NULL; - } - } - return cnt; -} - -static void -ReleaseWin(struct layer2 *l2) -{ - int cnt = freewin(l2); - - if (cnt) - printk(KERN_WARNING - "isdnl2 freed %d skbuffs in release\n", cnt); -} - -inline unsigned int -cansend(struct layer2 *l2) -{ - unsigned int p1; - - if (test_bit(FLG_MOD128, &l2->flag)) - p1 = (l2->vs - l2->va) % 128; - else - p1 = (l2->vs - l2->va) % 8; - return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag); -} - -inline void -clear_exception(struct layer2 *l2) -{ - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - test_and_clear_bit(FLG_REJEXC, &l2->flag); - test_and_clear_bit(FLG_OWN_BUSY, &l2->flag); - clear_peer_busy(l2); -} - -static int -sethdraddr(struct layer2 *l2, u_char *header, int rsp) -{ - u_char *ptr = header; - int crbit = rsp; - - if (test_bit(FLG_LAPD, &l2->flag)) { - if (test_bit(FLG_LAPD_NET, &l2->flag)) - crbit = !crbit; - *ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0); - *ptr++ = (l2->tei << 1) | 1; - return 2; - } else { - if (test_bit(FLG_ORIG, &l2->flag)) - crbit = !crbit; - if (crbit) - *ptr++ = l2->addr.B; - else - *ptr++ = l2->addr.A; - return 1; - } -} - -static inline void -enqueue_super(struct layer2 *l2, struct sk_buff *skb) -{ - if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) - dev_kfree_skb(skb); -} - -static inline void -enqueue_ui(struct layer2 *l2, struct sk_buff *skb) -{ - if (l2->tm) - l2_tei(l2, MDL_STATUS_UI_IND, 0); - if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) - dev_kfree_skb(skb); -} - -inline int -IsUI(u_char *data) -{ - return (data[0] & 0xef) == UI; -} - -inline int -IsUA(u_char *data) -{ - return (data[0] & 0xef) == UA; -} - -inline int -IsDM(u_char *data) -{ - return (data[0] & 0xef) == DM; -} - -inline int -IsDISC(u_char *data) -{ - return (data[0] & 0xef) == DISC; -} - -inline int -IsRR(u_char *data, struct layer2 *l2) -{ - if (test_bit(FLG_MOD128, &l2->flag)) - return data[0] == RR; - else - return (data[0] & 0xf) == 1; -} - -inline int -IsSFrame(u_char *data, struct layer2 *l2) -{ - register u_char d = *data; - - if (!test_bit(FLG_MOD128, &l2->flag)) - d &= 0xf; - return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c); -} - -inline int -IsSABME(u_char *data, struct layer2 *l2) -{ - u_char d = data[0] & ~0x10; - - return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM; -} - -inline int -IsREJ(u_char *data, struct layer2 *l2) -{ - return test_bit(FLG_MOD128, &l2->flag) ? - data[0] == REJ : (data[0] & 0xf) == REJ; -} - -inline int -IsFRMR(u_char *data) -{ - return (data[0] & 0xef) == FRMR; -} - -inline int -IsRNR(u_char *data, struct layer2 *l2) -{ - return test_bit(FLG_MOD128, &l2->flag) ? - data[0] == RNR : (data[0] & 0xf) == RNR; -} - -static int -iframe_error(struct layer2 *l2, struct sk_buff *skb) -{ - u_int i; - int rsp = *skb->data & 0x2; - - i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1); - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - if (rsp) - return 'L'; - if (skb->len < i) - return 'N'; - if ((skb->len - i) > l2->maxlen) - return 'O'; - return 0; -} - -static int -super_error(struct layer2 *l2, struct sk_buff *skb) -{ - if (skb->len != l2addrsize(l2) + - (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1)) - return 'N'; - return 0; -} - -static int -unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) -{ - int rsp = (*skb->data & 0x2) >> 1; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - if (rsp != wantrsp) - return 'L'; - if (skb->len != l2addrsize(l2) + 1) - return 'N'; - return 0; -} - -static int -UI_error(struct layer2 *l2, struct sk_buff *skb) -{ - int rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - if (rsp) - return 'L'; - if (skb->len > l2->maxlen + l2addrsize(l2) + 1) - return 'O'; - return 0; -} - -static int -FRMR_error(struct layer2 *l2, struct sk_buff *skb) -{ - u_int headers = l2addrsize(l2) + 1; - u_char *datap = skb->data + headers; - int rsp = *skb->data & 0x2; - - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - if (!rsp) - return 'L'; - if (test_bit(FLG_MOD128, &l2->flag)) { - if (skb->len < headers + 5) - return 'N'; - else if (*debug & DEBUG_L2) - l2m_debug(&l2->l2m, - "FRMR information %2x %2x %2x %2x %2x", - datap[0], datap[1], datap[2], datap[3], datap[4]); - } else { - if (skb->len < headers + 3) - return 'N'; - else if (*debug & DEBUG_L2) - l2m_debug(&l2->l2m, - "FRMR information %2x %2x %2x", - datap[0], datap[1], datap[2]); - } - return 0; -} - -static unsigned int -legalnr(struct layer2 *l2, unsigned int nr) -{ - if (test_bit(FLG_MOD128, &l2->flag)) - return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); - else - return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); -} - -static void -setva(struct layer2 *l2, unsigned int nr) -{ - struct sk_buff *skb; - - while (l2->va != nr) { - l2->va++; - if (test_bit(FLG_MOD128, &l2->flag)) - l2->va %= 128; - else - l2->va %= 8; - if (l2->windowar[l2->sow]) { - skb_trim(l2->windowar[l2->sow], 0); - skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]); - l2->windowar[l2->sow] = NULL; - } - l2->sow = (l2->sow + 1) % l2->window; - } - skb = skb_dequeue(&l2->tmp_queue); - while (skb) { - dev_kfree_skb(skb); - skb = skb_dequeue(&l2->tmp_queue); - } -} - -static void -send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) -{ - u_char tmp[MAX_L2HEADER_LEN]; - int i; - - i = sethdraddr(l2, tmp, cr); - tmp[i++] = cmd; - if (skb) - skb_trim(skb, 0); - else { - skb = mI_alloc_skb(i, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "%s: can't alloc skbuff in %s\n", - mISDNDevName4ch(&l2->ch), __func__); - return; - } - } - skb_put_data(skb, tmp, i); - enqueue_super(l2, skb); -} - - -inline u_char -get_PollFlag(struct layer2 *l2, struct sk_buff *skb) -{ - return skb->data[l2addrsize(l2)] & 0x10; -} - -inline u_char -get_PollFlagFree(struct layer2 *l2, struct sk_buff *skb) -{ - u_char PF; - - PF = get_PollFlag(l2, skb); - dev_kfree_skb(skb); - return PF; -} - -inline void -start_t200(struct layer2 *l2, int i) -{ - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); - test_and_set_bit(FLG_T200_RUN, &l2->flag); -} - -inline void -restart_t200(struct layer2 *l2, int i) -{ - mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); - test_and_set_bit(FLG_T200_RUN, &l2->flag); -} - -inline void -stop_t200(struct layer2 *l2, int i) -{ - if (test_and_clear_bit(FLG_T200_RUN, &l2->flag)) - mISDN_FsmDelTimer(&l2->t200, i); -} - -inline void -st5_dl_release_l2l3(struct layer2 *l2) -{ - int pr; - - if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) - pr = DL_RELEASE_CNF; - else - pr = DL_RELEASE_IND; - l2up_create(l2, pr, 0, NULL); -} - -inline void -lapb_dl_release_l2l3(struct layer2 *l2, int f) -{ - if (test_bit(FLG_LAPB, &l2->flag)) - l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL); - l2up_create(l2, f, 0, NULL); -} - -static void -establishlink(struct FsmInst *fi) -{ - struct layer2 *l2 = fi->userdata; - u_char cmd; - - clear_exception(l2); - l2->rc = 0; - cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10; - send_uframe(l2, NULL, cmd, CMD); - mISDN_FsmDelTimer(&l2->t203, 1); - restart_t200(l2, 1); - test_and_clear_bit(FLG_PEND_REL, &l2->flag); - freewin(l2); - mISDN_FsmChangeState(fi, ST_L2_5); -} - -static void -l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct layer2 *l2 = fi->userdata; - - if (get_PollFlagFree(l2, skb)) - l2mgr(l2, MDL_ERROR_IND, (void *) 'C'); - else - l2mgr(l2, MDL_ERROR_IND, (void *) 'D'); - -} - -static void -l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct layer2 *l2 = fi->userdata; - - if (get_PollFlagFree(l2, skb)) - l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); - else { - l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &l2->flag); - } -} - -static void -l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct layer2 *l2 = fi->userdata; - - if (get_PollFlagFree(l2, skb)) - l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); - else - l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &l2->flag); -} - -static void -l2_go_st3(struct FsmInst *fi, int event, void *arg) -{ - dev_kfree_skb((struct sk_buff *)arg); - mISDN_FsmChangeState(fi, ST_L2_3); -} - -static void -l2_mdl_assign(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - mISDN_FsmChangeState(fi, ST_L2_3); - dev_kfree_skb((struct sk_buff *)arg); - l2_tei(l2, MDL_ASSIGN_IND, 0); -} - -static void -l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&l2->ui_queue, skb); - mISDN_FsmChangeState(fi, ST_L2_2); - l2_tei(l2, MDL_ASSIGN_IND, 0); -} - -static void -l2_queue_ui(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&l2->ui_queue, skb); -} - -static void -tx_ui(struct layer2 *l2) -{ - struct sk_buff *skb; - u_char header[MAX_L2HEADER_LEN]; - int i; - - i = sethdraddr(l2, header, CMD); - if (test_bit(FLG_LAPD_NET, &l2->flag)) - header[1] = 0xff; /* tei 127 */ - header[i++] = UI; - while ((skb = skb_dequeue(&l2->ui_queue))) { - memcpy(skb_push(skb, i), header, i); - enqueue_ui(l2, skb); - } -} - -static void -l2_send_ui(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&l2->ui_queue, skb); - tx_ui(l2); -} - -static void -l2_got_ui(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_pull(skb, l2headersize(l2, 1)); -/* - * in states 1-3 for broadcast - */ - - if (l2->tm) - l2_tei(l2, MDL_STATUS_UI_IND, 0); - l2up(l2, DL_UNITDATA_IND, skb); -} - -static void -l2_establish(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct layer2 *l2 = fi->userdata; - - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &l2->flag); - dev_kfree_skb(skb); -} - -static void -l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct layer2 *l2 = fi->userdata; - - skb_queue_purge(&l2->i_queue); - test_and_set_bit(FLG_L3_INIT, &l2->flag); - test_and_clear_bit(FLG_PEND_REL, &l2->flag); - dev_kfree_skb(skb); -} - -static void -l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct layer2 *l2 = fi->userdata; - - skb_queue_purge(&l2->i_queue); - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &l2->flag); - dev_kfree_skb(skb); -} - -static void -l2_release(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_trim(skb, 0); - l2up(l2, DL_RELEASE_CNF, skb); -} - -static void -l2_pend_rel(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct layer2 *l2 = fi->userdata; - - test_and_set_bit(FLG_PEND_REL, &l2->flag); - dev_kfree_skb(skb); -} - -static void -l2_disconnect(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_purge(&l2->i_queue); - freewin(l2); - mISDN_FsmChangeState(fi, ST_L2_6); - l2->rc = 0; - send_uframe(l2, NULL, DISC | 0x10, CMD); - mISDN_FsmDelTimer(&l2->t203, 1); - restart_t200(l2, 2); - dev_kfree_skb(skb); -} - -static void -l2_start_multi(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - l2->vs = 0; - l2->va = 0; - l2->vr = 0; - l2->sow = 0; - clear_exception(l2); - send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP); - mISDN_FsmChangeState(fi, ST_L2_7); - mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); - skb_trim(skb, 0); - l2up(l2, DL_ESTABLISH_IND, skb); - if (l2->tm) - l2_tei(l2, MDL_STATUS_UP_IND, 0); -} - -static void -l2_send_UA(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); -} - -static void -l2_send_DM(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP); -} - -static void -l2_restart_multi(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - int est = 0; - - send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); - - l2mgr(l2, MDL_ERROR_IND, (void *) 'F'); - - if (l2->vs != l2->va) { - skb_queue_purge(&l2->i_queue); - est = 1; - } - - clear_exception(l2); - l2->vs = 0; - l2->va = 0; - l2->vr = 0; - l2->sow = 0; - mISDN_FsmChangeState(fi, ST_L2_7); - stop_t200(l2, 3); - mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); - - if (est) - l2up_create(l2, DL_ESTABLISH_IND, 0, NULL); -/* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, - * MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED, - * 0, NULL, 0); - */ - if (skb_queue_len(&l2->i_queue) && cansend(l2)) - mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); -} - -static void -l2_stop_multi(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - mISDN_FsmChangeState(fi, ST_L2_4); - mISDN_FsmDelTimer(&l2->t203, 3); - stop_t200(l2, 4); - - send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); - skb_queue_purge(&l2->i_queue); - freewin(l2); - lapb_dl_release_l2l3(l2, DL_RELEASE_IND); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); -} - -static void -l2_connected(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - int pr = -1; - - if (!get_PollFlag(l2, skb)) { - l2_mdl_error_ua(fi, event, arg); - return; - } - dev_kfree_skb(skb); - if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) - l2_disconnect(fi, event, NULL); - if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) { - pr = DL_ESTABLISH_CNF; - } else if (l2->vs != l2->va) { - skb_queue_purge(&l2->i_queue); - pr = DL_ESTABLISH_IND; - } - stop_t200(l2, 5); - l2->vr = 0; - l2->vs = 0; - l2->va = 0; - l2->sow = 0; - mISDN_FsmChangeState(fi, ST_L2_7); - mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4); - if (pr != -1) - l2up_create(l2, pr, 0, NULL); - - if (skb_queue_len(&l2->i_queue) && cansend(l2)) - mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); - - if (l2->tm) - l2_tei(l2, MDL_STATUS_UP_IND, 0); -} - -static void -l2_released(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - if (!get_PollFlag(l2, skb)) { - l2_mdl_error_ua(fi, event, arg); - return; - } - dev_kfree_skb(skb); - stop_t200(l2, 6); - lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); - mISDN_FsmChangeState(fi, ST_L2_4); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); -} - -static void -l2_reestablish(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - if (!get_PollFlagFree(l2, skb)) { - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &l2->flag); - } -} - -static void -l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - if (get_PollFlagFree(l2, skb)) { - stop_t200(l2, 7); - if (!test_bit(FLG_L3_INIT, &l2->flag)) - skb_queue_purge(&l2->i_queue); - if (test_bit(FLG_LAPB, &l2->flag)) - l2down_create(l2, PH_DEACTIVATE_REQ, - l2_newid(l2), 0, NULL); - st5_dl_release_l2l3(l2); - mISDN_FsmChangeState(fi, ST_L2_4); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); - } -} - -static void -l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - if (get_PollFlagFree(l2, skb)) { - stop_t200(l2, 8); - lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); - mISDN_FsmChangeState(fi, ST_L2_4); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); - } -} - -static void -enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) -{ - struct sk_buff *skb; - u_char tmp[MAX_L2HEADER_LEN]; - int i; - - i = sethdraddr(l2, tmp, cr); - if (test_bit(FLG_MOD128, &l2->flag)) { - tmp[i++] = typ; - tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); - } else - tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); - skb = mI_alloc_skb(i, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n", - mISDNDevName4ch(&l2->ch), __func__); - return; - } - skb_put_data(skb, tmp, i); - enqueue_super(l2, skb); -} - -inline void -enquiry_response(struct layer2 *l2) -{ - if (test_bit(FLG_OWN_BUSY, &l2->flag)) - enquiry_cr(l2, RNR, RSP, 1); - else - enquiry_cr(l2, RR, RSP, 1); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); -} - -inline void -transmit_enquiry(struct layer2 *l2) -{ - if (test_bit(FLG_OWN_BUSY, &l2->flag)) - enquiry_cr(l2, RNR, CMD, 1); - else - enquiry_cr(l2, RR, CMD, 1); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - start_t200(l2, 9); -} - - -static void -nrerrorrecovery(struct FsmInst *fi) -{ - struct layer2 *l2 = fi->userdata; - - l2mgr(l2, MDL_ERROR_IND, (void *) 'J'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &l2->flag); -} - -static void -invoke_retransmission(struct layer2 *l2, unsigned int nr) -{ - u_int p1; - - if (l2->vs != nr) { - while (l2->vs != nr) { - (l2->vs)--; - if (test_bit(FLG_MOD128, &l2->flag)) { - l2->vs %= 128; - p1 = (l2->vs - l2->va) % 128; - } else { - l2->vs %= 8; - p1 = (l2->vs - l2->va) % 8; - } - p1 = (p1 + l2->sow) % l2->window; - if (l2->windowar[p1]) - skb_queue_head(&l2->i_queue, l2->windowar[p1]); - else - printk(KERN_WARNING - "%s: windowar[%d] is NULL\n", - mISDNDevName4ch(&l2->ch), p1); - l2->windowar[p1] = NULL; - } - mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); - } -} - -static void -l2_st7_got_super(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - int PollFlag, rsp, typ = RR; - unsigned int nr; - - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - - skb_pull(skb, l2addrsize(l2)); - if (IsRNR(skb->data, l2)) { - set_peer_busy(l2); - typ = RNR; - } else - clear_peer_busy(l2); - if (IsREJ(skb->data, l2)) - typ = REJ; - - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } - dev_kfree_skb(skb); - - if (PollFlag) { - if (rsp) - l2mgr(l2, MDL_ERROR_IND, (void *) 'A'); - else - enquiry_response(l2); - } - if (legalnr(l2, nr)) { - if (typ == REJ) { - setva(l2, nr); - invoke_retransmission(l2, nr); - stop_t200(l2, 10); - if (mISDN_FsmAddTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 6)) - l2m_debug(&l2->l2m, "Restart T203 ST7 REJ"); - } else if ((nr == l2->vs) && (typ == RR)) { - setva(l2, nr); - stop_t200(l2, 11); - mISDN_FsmRestartTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 7); - } else if ((l2->va != nr) || (typ == RNR)) { - setva(l2, nr); - if (typ != RR) - mISDN_FsmDelTimer(&l2->t203, 9); - restart_t200(l2, 12); - } - if (skb_queue_len(&l2->i_queue) && (typ == RR)) - mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); - } else - nrerrorrecovery(fi); -} - -static void -l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - if (!test_bit(FLG_L3_INIT, &l2->flag)) - skb_queue_tail(&l2->i_queue, skb); - else - dev_kfree_skb(skb); -} - -static void -l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&l2->i_queue, skb); - mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); -} - -static void -l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&l2->i_queue, skb); -} - -static void -l2_got_iframe(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - int PollFlag, i; - u_int ns, nr; - - i = l2addrsize(l2); - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); - ns = skb->data[i] >> 1; - nr = (skb->data[i + 1] >> 1) & 0x7f; - } else { - PollFlag = (skb->data[i] & 0x10); - ns = (skb->data[i] >> 1) & 0x7; - nr = (skb->data[i] >> 5) & 0x7; - } - if (test_bit(FLG_OWN_BUSY, &l2->flag)) { - dev_kfree_skb(skb); - if (PollFlag) - enquiry_response(l2); - } else { - if (l2->vr == ns) { - l2->vr++; - if (test_bit(FLG_MOD128, &l2->flag)) - l2->vr %= 128; - else - l2->vr %= 8; - test_and_clear_bit(FLG_REJEXC, &l2->flag); - if (PollFlag) - enquiry_response(l2); - else - test_and_set_bit(FLG_ACK_PEND, &l2->flag); - skb_pull(skb, l2headersize(l2, 0)); - l2up(l2, DL_DATA_IND, skb); - } else { - /* n(s)!=v(r) */ - dev_kfree_skb(skb); - if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { - if (PollFlag) - enquiry_response(l2); - } else { - enquiry_cr(l2, REJ, RSP, PollFlag); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - } - } - } - if (legalnr(l2, nr)) { - if (!test_bit(FLG_PEER_BUSY, &l2->flag) && - (fi->state == ST_L2_7)) { - if (nr == l2->vs) { - stop_t200(l2, 13); - mISDN_FsmRestartTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 7); - } else if (nr != l2->va) - restart_t200(l2, 14); - } - setva(l2, nr); - } else { - nrerrorrecovery(fi); - return; - } - if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7)) - mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); - if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag)) - enquiry_cr(l2, RR, RSP, 0); -} - -static void -l2_got_tei(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - u_int info; - - l2->tei = (signed char)(long)arg; - set_channel_address(&l2->ch, l2->sapi, l2->tei); - info = DL_INFO_L2_CONNECT; - l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info); - if (fi->state == ST_L2_3) { - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &l2->flag); - } else - mISDN_FsmChangeState(fi, ST_L2_4); - if (skb_queue_len(&l2->ui_queue)) - tx_ui(l2); -} - -static void -l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); - } else if (l2->rc == l2->N200) { - mISDN_FsmChangeState(fi, ST_L2_4); - test_and_clear_bit(FLG_T200_RUN, &l2->flag); - skb_queue_purge(&l2->i_queue); - l2mgr(l2, MDL_ERROR_IND, (void *) 'G'); - if (test_bit(FLG_LAPB, &l2->flag)) - l2down_create(l2, PH_DEACTIVATE_REQ, - l2_newid(l2), 0, NULL); - st5_dl_release_l2l3(l2); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); - } else { - l2->rc++; - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); - send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ? - SABME : SABM) | 0x10, CMD); - } -} - -static void -l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); - } else if (l2->rc == l2->N200) { - mISDN_FsmChangeState(fi, ST_L2_4); - test_and_clear_bit(FLG_T200_RUN, &l2->flag); - l2mgr(l2, MDL_ERROR_IND, (void *) 'H'); - lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); - } else { - l2->rc++; - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, - NULL, 9); - send_uframe(l2, NULL, DISC | 0x10, CMD); - } -} - -static void -l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); - return; - } - test_and_clear_bit(FLG_T200_RUN, &l2->flag); - l2->rc = 0; - mISDN_FsmChangeState(fi, ST_L2_8); - transmit_enquiry(l2); - l2->rc++; -} - -static void -l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); - return; - } - test_and_clear_bit(FLG_T200_RUN, &l2->flag); - if (l2->rc == l2->N200) { - l2mgr(l2, MDL_ERROR_IND, (void *) 'I'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &l2->flag); - } else { - transmit_enquiry(l2); - l2->rc++; - } -} - -static void -l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { - mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9); - return; - } - mISDN_FsmChangeState(fi, ST_L2_8); - transmit_enquiry(l2); - l2->rc = 0; -} - -static void -l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb, *nskb; - u_char header[MAX_L2HEADER_LEN]; - u_int i, p1; - - if (!cansend(l2)) - return; - - skb = skb_dequeue(&l2->i_queue); - if (!skb) - return; - i = sethdraddr(l2, header, CMD); - if (test_bit(FLG_MOD128, &l2->flag)) { - header[i++] = l2->vs << 1; - header[i++] = l2->vr << 1; - } else - header[i++] = (l2->vr << 5) | (l2->vs << 1); - nskb = skb_realloc_headroom(skb, i); - if (!nskb) { - printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n", - mISDNDevName4ch(&l2->ch), i); - skb_queue_head(&l2->i_queue, skb); - return; - } - if (test_bit(FLG_MOD128, &l2->flag)) { - p1 = (l2->vs - l2->va) % 128; - l2->vs = (l2->vs + 1) % 128; - } else { - p1 = (l2->vs - l2->va) % 8; - l2->vs = (l2->vs + 1) % 8; - } - p1 = (p1 + l2->sow) % l2->window; - if (l2->windowar[p1]) { - printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n", - mISDNDevName4ch(&l2->ch), p1); - dev_kfree_skb(l2->windowar[p1]); - } - l2->windowar[p1] = skb; - memcpy(skb_push(nskb, i), header, i); - l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) { - mISDN_FsmDelTimer(&l2->t203, 13); - mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11); - } -} - -static void -l2_st8_got_super(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - int PollFlag, rsp, rnr = 0; - unsigned int nr; - - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - - skb_pull(skb, l2addrsize(l2)); - - if (IsRNR(skb->data, l2)) { - set_peer_busy(l2); - rnr = 1; - } else - clear_peer_busy(l2); - - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } - dev_kfree_skb(skb); - if (rsp && PollFlag) { - if (legalnr(l2, nr)) { - if (rnr) { - restart_t200(l2, 15); - } else { - stop_t200(l2, 16); - mISDN_FsmAddTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 5); - setva(l2, nr); - } - invoke_retransmission(l2, nr); - mISDN_FsmChangeState(fi, ST_L2_7); - if (skb_queue_len(&l2->i_queue) && cansend(l2)) - mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); - } else - nrerrorrecovery(fi); - } else { - if (!rsp && PollFlag) - enquiry_response(l2); - if (legalnr(l2, nr)) - setva(l2, nr); - else - nrerrorrecovery(fi); - } -} - -static void -l2_got_FRMR(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_pull(skb, l2addrsize(l2) + 1); - - if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ - (IsUA(skb->data) && (fi->state == ST_L2_7))) { - l2mgr(l2, MDL_ERROR_IND, (void *) 'K'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &l2->flag); - } - dev_kfree_skb(skb); -} - -static void -l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - skb_queue_purge(&l2->ui_queue); - l2->tei = GROUP_TEI; - mISDN_FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - skb_queue_purge(&l2->ui_queue); - l2->tei = GROUP_TEI; - l2up_create(l2, DL_RELEASE_IND, 0, NULL); - mISDN_FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - skb_queue_purge(&l2->i_queue); - skb_queue_purge(&l2->ui_queue); - freewin(l2); - l2->tei = GROUP_TEI; - stop_t200(l2, 17); - st5_dl_release_l2l3(l2); - mISDN_FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - skb_queue_purge(&l2->ui_queue); - l2->tei = GROUP_TEI; - stop_t200(l2, 18); - l2up_create(l2, DL_RELEASE_IND, 0, NULL); - mISDN_FsmChangeState(fi, ST_L2_1); -} - -static void -l2_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - skb_queue_purge(&l2->i_queue); - skb_queue_purge(&l2->ui_queue); - freewin(l2); - l2->tei = GROUP_TEI; - stop_t200(l2, 17); - mISDN_FsmDelTimer(&l2->t203, 19); - l2up_create(l2, DL_RELEASE_IND, 0, NULL); -/* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, - * MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED, - * 0, NULL, 0); - */ - mISDN_FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_purge(&l2->i_queue); - skb_queue_purge(&l2->ui_queue); - if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) - l2up(l2, DL_RELEASE_IND, skb); - else - dev_kfree_skb(skb); -} - -static void -l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_purge(&l2->i_queue); - skb_queue_purge(&l2->ui_queue); - freewin(l2); - stop_t200(l2, 19); - st5_dl_release_l2l3(l2); - mISDN_FsmChangeState(fi, ST_L2_4); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); - dev_kfree_skb(skb); -} - -static void -l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_purge(&l2->ui_queue); - stop_t200(l2, 20); - l2up(l2, DL_RELEASE_CNF, skb); - mISDN_FsmChangeState(fi, ST_L2_4); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); -} - -static void -l2_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_purge(&l2->i_queue); - skb_queue_purge(&l2->ui_queue); - freewin(l2); - stop_t200(l2, 19); - mISDN_FsmDelTimer(&l2->t203, 19); - l2up(l2, DL_RELEASE_IND, skb); - mISDN_FsmChangeState(fi, ST_L2_4); - if (l2->tm) - l2_tei(l2, MDL_STATUS_DOWN_IND, 0); -} - -static void -l2_set_own_busy(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) { - enquiry_cr(l2, RNR, RSP, 0); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - } - dev_kfree_skb(skb); -} - -static void -l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - struct sk_buff *skb = arg; - - if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) { - enquiry_cr(l2, RR, RSP, 0); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - } - dev_kfree_skb(skb); -} - -static void -l2_frame_error(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - l2mgr(l2, MDL_ERROR_IND, arg); -} - -static void -l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) -{ - struct layer2 *l2 = fi->userdata; - - l2mgr(l2, MDL_ERROR_IND, arg); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &l2->flag); -} - -static struct FsmNode L2FnList[] = -{ - {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, - {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, - {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, - {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, - {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, - {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, - {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, - {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, - {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, - {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, - {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, - {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, - {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, - {ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign}, - {ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui}, - {ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui}, - {ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui}, - {ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui}, - {ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui}, - {ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui}, - {ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui}, - {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, - {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, - {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, - {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, - {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, - {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_4, EV_L2_SABME, l2_start_multi}, - {ST_L2_5, EV_L2_SABME, l2_send_UA}, - {ST_L2_6, EV_L2_SABME, l2_send_DM}, - {ST_L2_7, EV_L2_SABME, l2_restart_multi}, - {ST_L2_8, EV_L2_SABME, l2_restart_multi}, - {ST_L2_4, EV_L2_DISC, l2_send_DM}, - {ST_L2_5, EV_L2_DISC, l2_send_DM}, - {ST_L2_6, EV_L2_DISC, l2_send_UA}, - {ST_L2_7, EV_L2_DISC, l2_stop_multi}, - {ST_L2_8, EV_L2_DISC, l2_stop_multi}, - {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_5, EV_L2_UA, l2_connected}, - {ST_L2_6, EV_L2_UA, l2_released}, - {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_4, EV_L2_DM, l2_reestablish}, - {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, - {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, - {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, - {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, - {ST_L2_1, EV_L2_UI, l2_got_ui}, - {ST_L2_2, EV_L2_UI, l2_got_ui}, - {ST_L2_3, EV_L2_UI, l2_got_ui}, - {ST_L2_4, EV_L2_UI, l2_got_ui}, - {ST_L2_5, EV_L2_UI, l2_got_ui}, - {ST_L2_6, EV_L2_UI, l2_got_ui}, - {ST_L2_7, EV_L2_UI, l2_got_ui}, - {ST_L2_8, EV_L2_UI, l2_got_ui}, - {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, - {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, - {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, - {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, - {ST_L2_7, EV_L2_I, l2_got_iframe}, - {ST_L2_8, EV_L2_I, l2_got_iframe}, - {ST_L2_5, EV_L2_T200, l2_timeout}, - {ST_L2_6, EV_L2_T200, l2_timeout}, - {ST_L2_7, EV_L2_T200, l2_timeout}, - {ST_L2_8, EV_L2_T200, l2_timeout}, - {ST_L2_7, EV_L2_T203, l2_timeout}, - {ST_L2_5, EV_L2_T200I, l2_st5_tout_200}, - {ST_L2_6, EV_L2_T200I, l2_st6_tout_200}, - {ST_L2_7, EV_L2_T200I, l2_st7_tout_200}, - {ST_L2_8, EV_L2_T200I, l2_st8_tout_200}, - {ST_L2_7, EV_L2_T203I, l2_st7_tout_203}, - {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, - {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, - {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, - {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, - {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, - {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da}, - {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, - {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da}, - {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da}, - {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, -}; - -static int -ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) -{ - u_char *datap = skb->data; - int ret = -EINVAL; - int psapi, ptei; - u_int l; - int c = 0; - - l = l2addrsize(l2); - if (skb->len <= l) { - mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N'); - return ret; - } - if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */ - psapi = *datap++; - ptei = *datap++; - if ((psapi & 1) || !(ptei & 1)) { - printk(KERN_WARNING - "%s l2 D-channel frame wrong EA0/EA1\n", - mISDNDevName4ch(&l2->ch)); - return ret; - } - psapi >>= 2; - ptei >>= 1; - if (psapi != l2->sapi) { - /* not our business */ - if (*debug & DEBUG_L2) - printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n", - mISDNDevName4ch(&l2->ch), psapi, - l2->sapi); - dev_kfree_skb(skb); - return 0; - } - if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { - /* not our business */ - if (*debug & DEBUG_L2) - printk(KERN_DEBUG "%s: tei %d/%d mismatch\n", - mISDNDevName4ch(&l2->ch), ptei, l2->tei); - dev_kfree_skb(skb); - return 0; - } - } else - datap += l; - if (!(*datap & 1)) { /* I-Frame */ - c = iframe_error(l2, skb); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb); - } else if (IsSFrame(datap, l2)) { /* S-Frame */ - c = super_error(l2, skb); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb); - } else if (IsUI(datap)) { - c = UI_error(l2, skb); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb); - } else if (IsSABME(datap, l2)) { - c = unnum_error(l2, skb, CMD); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb); - } else if (IsUA(datap)) { - c = unnum_error(l2, skb, RSP); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb); - } else if (IsDISC(datap)) { - c = unnum_error(l2, skb, CMD); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb); - } else if (IsDM(datap)) { - c = unnum_error(l2, skb, RSP); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb); - } else if (IsFRMR(datap)) { - c = FRMR_error(l2, skb); - if (!c) - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb); - } else - c = 'L'; - if (c) { - printk(KERN_WARNING "%s:l2 D-channel frame error %c\n", - mISDNDevName4ch(&l2->ch), c); - mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); - } - return ret; -} - -static int -l2_send(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct layer2 *l2 = container_of(ch, struct layer2, ch); - struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret = -EINVAL; - - if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n", - __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id, - l2->sapi, l2->tei); - if (hh->prim == DL_INTERN_MSG) { - struct mISDNhead *chh = hh + 1; /* saved copy */ - - *hh = *chh; - if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n", - mISDNDevName4ch(&l2->ch), hh->prim, hh->id); - } - switch (hh->prim) { - case PH_DATA_IND: - ret = ph_data_indication(l2, hh, skb); - break; - case PH_DATA_CNF: - ret = ph_data_confirm(l2, hh, skb); - break; - case PH_ACTIVATE_IND: - test_and_set_bit(FLG_L1_ACTIV, &l2->flag); - l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL); - if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) - ret = mISDN_FsmEvent(&l2->l2m, - EV_L2_DL_ESTABLISH_REQ, skb); - break; - case PH_DEACTIVATE_IND: - test_and_clear_bit(FLG_L1_ACTIV, &l2->flag); - l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL); - ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb); - break; - case MPH_INFORMATION_IND: - if (!l2->up) - break; - ret = l2->up->send(l2->up, skb); - break; - case DL_DATA_REQ: - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb); - break; - case DL_UNITDATA_REQ: - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb); - break; - case DL_ESTABLISH_REQ: - if (test_bit(FLG_LAPB, &l2->flag)) - test_and_set_bit(FLG_ORIG, &l2->flag); - if (test_bit(FLG_L1_ACTIV, &l2->flag)) { - if (test_bit(FLG_LAPD, &l2->flag) || - test_bit(FLG_ORIG, &l2->flag)) - ret = mISDN_FsmEvent(&l2->l2m, - EV_L2_DL_ESTABLISH_REQ, skb); - } else { - if (test_bit(FLG_LAPD, &l2->flag) || - test_bit(FLG_ORIG, &l2->flag)) { - test_and_set_bit(FLG_ESTAB_PEND, - &l2->flag); - } - ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2), - skb); - } - break; - case DL_RELEASE_REQ: - if (test_bit(FLG_LAPB, &l2->flag)) - l2down_create(l2, PH_DEACTIVATE_REQ, - l2_newid(l2), 0, NULL); - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, - skb); - break; - case DL_TIMER200_IND: - mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL); - break; - case DL_TIMER203_IND: - mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL); - break; - default: - if (*debug & DEBUG_L2) - l2m_debug(&l2->l2m, "l2 unknown pr %04x", - hh->prim); - } - if (ret) { - dev_kfree_skb(skb); - ret = 0; - } - return ret; -} - -int -tei_l2(struct layer2 *l2, u_int cmd, u_long arg) -{ - int ret = -EINVAL; - - if (*debug & DEBUG_L2_TEI) - printk(KERN_DEBUG "%s: cmd(%x) in %s\n", - mISDNDevName4ch(&l2->ch), cmd, __func__); - switch (cmd) { - case (MDL_ASSIGN_REQ): - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); - break; - case (MDL_REMOVE_REQ): - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL); - break; - case (MDL_ERROR_IND): - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); - break; - case (MDL_ERROR_RSP): - /* ETS 300-125 5.3.2.1 Test: TC13010 */ - printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n", - mISDNDevName4ch(&l2->ch)); - ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); - break; - } - return ret; -} - -static void -release_l2(struct layer2 *l2) -{ - mISDN_FsmDelTimer(&l2->t200, 21); - mISDN_FsmDelTimer(&l2->t203, 16); - skb_queue_purge(&l2->i_queue); - skb_queue_purge(&l2->ui_queue); - skb_queue_purge(&l2->down_queue); - ReleaseWin(l2); - if (test_bit(FLG_LAPD, &l2->flag)) { - TEIrelease(l2); - if (l2->ch.st) - l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, - CLOSE_CHANNEL, NULL); - } - kfree(l2); -} - -static int -l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct layer2 *l2 = container_of(ch, struct layer2, ch); - u_int info; - - if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s: %s cmd(%x)\n", - mISDNDevName4ch(ch), __func__, cmd); - - switch (cmd) { - case OPEN_CHANNEL: - if (test_bit(FLG_LAPD, &l2->flag)) { - set_channel_address(&l2->ch, l2->sapi, l2->tei); - info = DL_INFO_L2_CONNECT; - l2up_create(l2, DL_INFORMATION_IND, - sizeof(info), &info); - } - break; - case CLOSE_CHANNEL: - if (l2->ch.peer) - l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL); - release_l2(l2); - break; - } - return 0; -} - -struct layer2 * -create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei, - int sapi) -{ - struct layer2 *l2; - struct channel_req rq; - - l2 = kzalloc_obj(struct layer2); - if (!l2) { - printk(KERN_ERR "kzalloc layer2 failed\n"); - return NULL; - } - l2->next_id = 1; - l2->down_id = MISDN_ID_NONE; - l2->up = ch; - l2->ch.st = ch->st; - l2->ch.send = l2_send; - l2->ch.ctrl = l2_ctrl; - switch (protocol) { - case ISDN_P_LAPD_NT: - test_and_set_bit(FLG_LAPD, &l2->flag); - test_and_set_bit(FLG_LAPD_NET, &l2->flag); - test_and_set_bit(FLG_MOD128, &l2->flag); - l2->sapi = sapi; - l2->maxlen = MAX_DFRAME_LEN; - if (test_bit(OPTION_L2_PMX, &options)) - l2->window = 7; - else - l2->window = 1; - if (test_bit(OPTION_L2_PTP, &options)) - test_and_set_bit(FLG_PTP, &l2->flag); - if (test_bit(OPTION_L2_FIXEDTEI, &options)) - test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = tei; - l2->T200 = 1000; - l2->N200 = 3; - l2->T203 = 10000; - if (test_bit(OPTION_L2_PMX, &options)) - rq.protocol = ISDN_P_NT_E1; - else - rq.protocol = ISDN_P_NT_S0; - rq.adr.channel = 0; - l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); - break; - case ISDN_P_LAPD_TE: - test_and_set_bit(FLG_LAPD, &l2->flag); - test_and_set_bit(FLG_MOD128, &l2->flag); - test_and_set_bit(FLG_ORIG, &l2->flag); - l2->sapi = sapi; - l2->maxlen = MAX_DFRAME_LEN; - if (test_bit(OPTION_L2_PMX, &options)) - l2->window = 7; - else - l2->window = 1; - if (test_bit(OPTION_L2_PTP, &options)) - test_and_set_bit(FLG_PTP, &l2->flag); - if (test_bit(OPTION_L2_FIXEDTEI, &options)) - test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = tei; - l2->T200 = 1000; - l2->N200 = 3; - l2->T203 = 10000; - if (test_bit(OPTION_L2_PMX, &options)) - rq.protocol = ISDN_P_TE_E1; - else - rq.protocol = ISDN_P_TE_S0; - rq.adr.channel = 0; - l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); - break; - case ISDN_P_B_X75SLP: - test_and_set_bit(FLG_LAPB, &l2->flag); - l2->window = 7; - l2->maxlen = MAX_DATA_SIZE; - l2->T200 = 1000; - l2->N200 = 4; - l2->T203 = 5000; - l2->addr.A = 3; - l2->addr.B = 1; - break; - default: - printk(KERN_ERR "layer2 create failed prt %x\n", - protocol); - kfree(l2); - return NULL; - } - skb_queue_head_init(&l2->i_queue); - skb_queue_head_init(&l2->ui_queue); - skb_queue_head_init(&l2->down_queue); - skb_queue_head_init(&l2->tmp_queue); - InitWin(l2); - l2->l2m.fsm = &l2fsm; - if (test_bit(FLG_LAPB, &l2->flag) || - test_bit(FLG_FIXED_TEI, &l2->flag) || - test_bit(FLG_LAPD_NET, &l2->flag)) - l2->l2m.state = ST_L2_4; - else - l2->l2m.state = ST_L2_1; - l2->l2m.debug = *debug; - l2->l2m.userdata = l2; - l2->l2m.userint = 0; - l2->l2m.printdebug = l2m_debug; - - mISDN_FsmInitTimer(&l2->l2m, &l2->t200); - mISDN_FsmInitTimer(&l2->l2m, &l2->t203); - return l2; -} - -static int -x75create(struct channel_req *crq) -{ - struct layer2 *l2; - - if (crq->protocol != ISDN_P_B_X75SLP) - return -EPROTONOSUPPORT; - l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0); - if (!l2) - return -ENOMEM; - crq->ch = &l2->ch; - crq->protocol = ISDN_P_B_HDLC; - return 0; -} - -static struct Bprotocol X75SLP = { - .Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)), - .name = "X75SLP", - .create = x75create -}; - -int -Isdnl2_Init(u_int *deb) -{ - int res; - debug = deb; - mISDN_register_Bprotocol(&X75SLP); - l2fsm.state_count = L2_STATE_COUNT; - l2fsm.event_count = L2_EVENT_COUNT; - l2fsm.strEvent = strL2Event; - l2fsm.strState = strL2State; - res = mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); - if (res) - goto error; - res = TEIInit(deb); - if (res) - goto error_fsm; - return 0; - -error_fsm: - mISDN_FsmFree(&l2fsm); -error: - mISDN_unregister_Bprotocol(&X75SLP); - return res; -} - -void -Isdnl2_cleanup(void) -{ - mISDN_unregister_Bprotocol(&X75SLP); - TEIFree(); - mISDN_FsmFree(&l2fsm); -} diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h deleted file mode 100644 index c466fd94aa02..000000000000 --- a/drivers/isdn/mISDN/layer2.h +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Layer 2 defines - * - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include "fsm.h" - -#define MAX_WINDOW 8 - -struct manager { - struct mISDNchannel ch; - struct mISDNchannel bcast; - u_long options; - struct list_head layer2; - rwlock_t lock; - struct FsmInst deact; - struct FsmTimer datimer; - struct sk_buff_head sendq; - struct mISDNchannel *up; - u_int nextid; - u_int lastid; -}; - -struct teimgr { - int ri; - int rcnt; - struct FsmInst tei_m; - struct FsmTimer timer; - int tval, nval; - struct layer2 *l2; - struct manager *mgr; -}; - -struct laddr { - u_char A; - u_char B; -}; - -struct layer2 { - struct list_head list; - struct mISDNchannel ch; - u_long flag; - int id; - struct mISDNchannel *up; - signed char sapi; - signed char tei; - struct laddr addr; - u_int maxlen; - struct teimgr *tm; - u_int vs, va, vr; - int rc; - u_int window; - u_int sow; - struct FsmInst l2m; - struct FsmTimer t200, t203; - int T200, N200, T203; - u_int next_id; - u_int down_id; - struct sk_buff *windowar[MAX_WINDOW]; - struct sk_buff_head i_queue; - struct sk_buff_head ui_queue; - struct sk_buff_head down_queue; - struct sk_buff_head tmp_queue; -}; - -enum { - ST_L2_1, - ST_L2_2, - ST_L2_3, - ST_L2_4, - ST_L2_5, - ST_L2_6, - ST_L2_7, - ST_L2_8, -}; - -#define L2_STATE_COUNT (ST_L2_8 + 1) - -extern struct layer2 *create_l2(struct mISDNchannel *, u_int, - u_long, int, int); -extern int tei_l2(struct layer2 *, u_int, u_long arg); - - -/* from tei.c */ -extern int l2_tei(struct layer2 *, u_int, u_long arg); -extern void TEIrelease(struct layer2 *); -extern int TEIInit(u_int *); -extern void TEIFree(void); - -#define MAX_L2HEADER_LEN 4 - -#define RR 0x01 -#define RNR 0x05 -#define REJ 0x09 -#define SABME 0x6f -#define SABM 0x2f -#define DM 0x0f -#define UI 0x03 -#define DISC 0x43 -#define UA 0x63 -#define FRMR 0x87 -#define XID 0xaf - -#define CMD 0 -#define RSP 1 - -#define LC_FLUSH_WAIT 1 - -#define FLG_LAPB 0 -#define FLG_LAPD 1 -#define FLG_ORIG 2 -#define FLG_MOD128 3 -#define FLG_PEND_REL 4 -#define FLG_L3_INIT 5 -#define FLG_T200_RUN 6 -#define FLG_ACK_PEND 7 -#define FLG_REJEXC 8 -#define FLG_OWN_BUSY 9 -#define FLG_PEER_BUSY 10 -#define FLG_DCHAN_BUSY 11 -#define FLG_L1_ACTIV 12 -#define FLG_ESTAB_PEND 13 -#define FLG_PTP 14 -#define FLG_FIXED_TEI 15 -#define FLG_L2BLOCK 16 -#define FLG_L1_NOTREADY 17 -#define FLG_LAPD_NET 18 diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c deleted file mode 100644 index 77b900db1cac..000000000000 --- a/drivers/isdn/mISDN/socket.c +++ /dev/null @@ -1,825 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include -#include "core.h" - -static u_int *debug; - -static struct proto mISDN_proto = { - .name = "misdn", - .owner = THIS_MODULE, - .obj_size = sizeof(struct mISDN_sock) -}; - -#define _pms(sk) ((struct mISDN_sock *)sk) - -static struct mISDN_sock_list data_sockets = { - .lock = __RW_LOCK_UNLOCKED(data_sockets.lock) -}; - -static struct mISDN_sock_list base_sockets = { - .lock = __RW_LOCK_UNLOCKED(base_sockets.lock) -}; - -#define L2_HEADER_LEN 4 - -static inline struct sk_buff * -_l2_alloc_skb(unsigned int len, gfp_t gfp_mask) -{ - struct sk_buff *skb; - - skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask); - if (likely(skb)) - skb_reserve(skb, L2_HEADER_LEN); - return skb; -} - -static void -mISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk) -{ - write_lock_bh(&l->lock); - sk_add_node(sk, &l->head); - write_unlock_bh(&l->lock); -} - -static void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk) -{ - write_lock_bh(&l->lock); - sk_del_node_init(sk); - write_unlock_bh(&l->lock); -} - -static int -mISDN_send(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct mISDN_sock *msk; - int err; - - msk = container_of(ch, struct mISDN_sock, ch); - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb); - if (msk->sk.sk_state == MISDN_CLOSED) - return -EUNATCH; - __net_timestamp(skb); - err = sock_queue_rcv_skb(&msk->sk, skb); - if (err) - printk(KERN_WARNING "%s: error %d\n", __func__, err); - return err; -} - -static int -mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct mISDN_sock *msk; - - msk = container_of(ch, struct mISDN_sock, ch); - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg); - switch (cmd) { - case CLOSE_CHANNEL: - msk->sk.sk_state = MISDN_CLOSED; - break; - } - return 0; -} - -static inline void -mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) -{ - struct __kernel_old_timeval tv; - - if (_pms(sk)->cmask & MISDN_TIME_STAMP) { - skb_get_timestamp(skb, &tv); - put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv); - } -} - -static int -mISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, - int flags) -{ - struct sk_buff *skb; - struct sock *sk = sock->sk; - - int copied, err; - - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n", - __func__, (int)len, flags, _pms(sk)->ch.nr, - sk->sk_protocol); - if (flags & (MSG_OOB)) - return -EOPNOTSUPP; - - if (sk->sk_state == MISDN_CLOSED) - return 0; - - skb = skb_recv_datagram(sk, flags, &err); - if (!skb) - return err; - - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name); - - maddr->family = AF_ISDN; - maddr->dev = _pms(sk)->dev->id; - if ((sk->sk_protocol == ISDN_P_LAPD_TE) || - (sk->sk_protocol == ISDN_P_LAPD_NT)) { - maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff; - maddr->tei = (mISDN_HEAD_ID(skb) >> 8) & 0xff; - maddr->sapi = mISDN_HEAD_ID(skb) & 0xff; - } else { - maddr->channel = _pms(sk)->ch.nr; - maddr->sapi = _pms(sk)->ch.addr & 0xFF; - maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; - } - msg->msg_namelen = sizeof(*maddr); - } - - copied = skb->len + MISDN_HEADER_LEN; - if (len < copied) { - if (flags & MSG_PEEK) - refcount_dec(&skb->users); - else - skb_queue_head(&sk->sk_receive_queue, skb); - return -ENOSPC; - } - memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb), - MISDN_HEADER_LEN); - - err = skb_copy_datagram_msg(skb, 0, msg, copied); - - mISDN_sock_cmsg(sk, msg, skb); - - skb_free_datagram(sk, skb); - - return err ? : copied; -} - -static int -mISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) -{ - struct sock *sk = sock->sk; - struct sk_buff *skb; - int err = -ENOMEM; - - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n", - __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, - sk->sk_protocol); - - if (msg->msg_flags & MSG_OOB) - return -EOPNOTSUPP; - - if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE)) - return -EINVAL; - - if (len < MISDN_HEADER_LEN) - return -EINVAL; - - if (sk->sk_state != MISDN_BOUND) - return -EBADFD; - - lock_sock(sk); - - skb = _l2_alloc_skb(len, GFP_KERNEL); - if (!skb) - goto done; - - if (memcpy_from_msg(skb_put(skb, len), msg, len)) { - err = -EFAULT; - goto done; - } - - memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); - skb_pull(skb, MISDN_HEADER_LEN); - - if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { - /* if we have a address, we use it */ - DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name); - mISDN_HEAD_ID(skb) = maddr->channel; - } else { /* use default for L2 messages */ - if ((sk->sk_protocol == ISDN_P_LAPD_TE) || - (sk->sk_protocol == ISDN_P_LAPD_NT)) - mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; - } - - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s: ID:%x\n", - __func__, mISDN_HEAD_ID(skb)); - - err = -ENODEV; - if (!_pms(sk)->ch.peer) - goto done; - err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb); - if (err) - goto done; - else { - skb = NULL; - err = len; - } - -done: - kfree_skb(skb); - release_sock(sk); - return err; -} - -static int -data_sock_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); - if (!sk) - return 0; - switch (sk->sk_protocol) { - case ISDN_P_TE_S0: - case ISDN_P_NT_S0: - case ISDN_P_TE_E1: - case ISDN_P_NT_E1: - if (sk->sk_state == MISDN_BOUND) - delete_channel(&_pms(sk)->ch); - else - mISDN_sock_unlink(&data_sockets, sk); - break; - case ISDN_P_LAPD_TE: - case ISDN_P_LAPD_NT: - case ISDN_P_B_RAW: - case ISDN_P_B_HDLC: - case ISDN_P_B_X75SLP: - case ISDN_P_B_L2DTMF: - case ISDN_P_B_L2DSP: - case ISDN_P_B_L2DSPHDLC: - delete_channel(&_pms(sk)->ch); - mISDN_sock_unlink(&data_sockets, sk); - break; - } - - lock_sock(sk); - - sock_orphan(sk); - skb_queue_purge(&sk->sk_receive_queue); - - release_sock(sk); - sock_put(sk); - - return 0; -} - -static int -data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) -{ - struct mISDN_ctrl_req cq; - int err = -EINVAL, val[2]; - struct mISDNchannel *bchan, *next; - - lock_sock(sk); - if (!_pms(sk)->dev) { - err = -ENODEV; - goto done; - } - switch (cmd) { - case IMCTRLREQ: - if (copy_from_user(&cq, p, sizeof(cq))) { - err = -EFAULT; - break; - } - if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) { - list_for_each_entry_safe(bchan, next, - &_pms(sk)->dev->bchannels, list) { - if (bchan->nr == cq.channel) { - err = bchan->ctrl(bchan, - CONTROL_CHANNEL, &cq); - break; - } - } - } else - err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D, - CONTROL_CHANNEL, &cq); - if (err) - break; - if (copy_to_user(p, &cq, sizeof(cq))) - err = -EFAULT; - break; - case IMCLEAR_L2: - if (sk->sk_protocol != ISDN_P_LAPD_NT) { - err = -EINVAL; - break; - } - val[0] = cmd; - if (get_user(val[1], (int __user *)p)) { - err = -EFAULT; - break; - } - err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, - CONTROL_CHANNEL, val); - break; - case IMHOLD_L1: - if (sk->sk_protocol != ISDN_P_LAPD_NT - && sk->sk_protocol != ISDN_P_LAPD_TE) { - err = -EINVAL; - break; - } - val[0] = cmd; - if (get_user(val[1], (int __user *)p)) { - err = -EFAULT; - break; - } - err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, - CONTROL_CHANNEL, val); - break; - default: - err = -EINVAL; - break; - } -done: - release_sock(sk); - return err; -} - -static int -data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - int err = 0, id; - struct sock *sk = sock->sk; - struct mISDNdevice *dev; - struct mISDNversion ver; - - switch (cmd) { - case IMGETVERSION: - ver.major = MISDN_MAJOR_VERSION; - ver.minor = MISDN_MINOR_VERSION; - ver.release = MISDN_RELEASE; - if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) - err = -EFAULT; - break; - case IMGETCOUNT: - id = get_mdevice_count(); - if (put_user(id, (int __user *)arg)) - err = -EFAULT; - break; - case IMGETDEVINFO: - if (get_user(id, (int __user *)arg)) { - err = -EFAULT; - break; - } - dev = get_mdevice(id); - if (dev) { - struct mISDN_devinfo di; - - memset(&di, 0, sizeof(di)); - di.id = dev->id; - di.Dprotocols = dev->Dprotocols; - di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); - di.protocol = dev->D.protocol; - memcpy(di.channelmap, dev->channelmap, - sizeof(di.channelmap)); - di.nrbchan = dev->nrbchan; - strscpy(di.name, dev_name(&dev->dev), sizeof(di.name)); - if (copy_to_user((void __user *)arg, &di, sizeof(di))) - err = -EFAULT; - } else - err = -ENODEV; - break; - default: - if (sk->sk_state == MISDN_BOUND) - err = data_sock_ioctl_bound(sk, cmd, - (void __user *)arg); - else - err = -ENOTCONN; - } - return err; -} - -static int data_sock_setsockopt(struct socket *sock, int level, int optname, - sockptr_t optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - int err = 0, opt = 0; - - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s(%p, %d, %x, optval, %d)\n", __func__, sock, - level, optname, optlen); - - lock_sock(sk); - - switch (optname) { - case MISDN_TIME_STAMP: - err = copy_safe_from_sockptr(&opt, sizeof(opt), - optval, optlen); - if (err) - break; - - if (opt) - _pms(sk)->cmask |= MISDN_TIME_STAMP; - else - _pms(sk)->cmask &= ~MISDN_TIME_STAMP; - break; - default: - err = -ENOPROTOOPT; - break; - } - release_sock(sk); - return err; -} - -static int data_sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - int len, opt; - - if (get_user(len, optlen)) - return -EFAULT; - - if (len != sizeof(char)) - return -EINVAL; - - switch (optname) { - case MISDN_TIME_STAMP: - if (_pms(sk)->cmask & MISDN_TIME_STAMP) - opt = 1; - else - opt = 0; - - if (put_user(opt, optval)) - return -EFAULT; - break; - default: - return -ENOPROTOOPT; - } - - return 0; -} - -static int -data_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr_len) -{ - struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; - struct sock *sk = sock->sk; - struct sock *csk; - int err = 0; - - if (*debug & DEBUG_SOCKET) - printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); - if (addr_len != sizeof(struct sockaddr_mISDN)) - return -EINVAL; - if (!maddr || maddr->family != AF_ISDN) - return -EINVAL; - - lock_sock(sk); - - if (_pms(sk)->dev) { - err = -EALREADY; - goto done; - } - _pms(sk)->dev = get_mdevice(maddr->dev); - if (!_pms(sk)->dev) { - err = -ENODEV; - goto done; - } - - if (sk->sk_protocol < ISDN_P_B_START) { - read_lock_bh(&data_sockets.lock); - sk_for_each(csk, &data_sockets.head) { - if (sk == csk) - continue; - if (_pms(csk)->dev != _pms(sk)->dev) - continue; - if (csk->sk_protocol >= ISDN_P_B_START) - continue; - if (IS_ISDN_P_TE(csk->sk_protocol) - == IS_ISDN_P_TE(sk->sk_protocol)) - continue; - read_unlock_bh(&data_sockets.lock); - err = -EBUSY; - goto done; - } - read_unlock_bh(&data_sockets.lock); - } - - _pms(sk)->ch.send = mISDN_send; - _pms(sk)->ch.ctrl = mISDN_ctrl; - - switch (sk->sk_protocol) { - case ISDN_P_TE_S0: - case ISDN_P_NT_S0: - case ISDN_P_TE_E1: - case ISDN_P_NT_E1: - mISDN_sock_unlink(&data_sockets, sk); - err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch, - sk->sk_protocol, maddr); - if (err) - mISDN_sock_link(&data_sockets, sk); - break; - case ISDN_P_LAPD_TE: - case ISDN_P_LAPD_NT: - err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch, - sk->sk_protocol, maddr); - break; - case ISDN_P_B_RAW: - case ISDN_P_B_HDLC: - case ISDN_P_B_X75SLP: - case ISDN_P_B_L2DTMF: - case ISDN_P_B_L2DSP: - case ISDN_P_B_L2DSPHDLC: - err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch, - sk->sk_protocol, maddr); - break; - default: - err = -EPROTONOSUPPORT; - } - if (err) - goto done; - sk->sk_state = MISDN_BOUND; - _pms(sk)->ch.protocol = sk->sk_protocol; - -done: - release_sock(sk); - return err; -} - -static int -data_sock_getname(struct socket *sock, struct sockaddr *addr, - int peer) -{ - struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; - struct sock *sk = sock->sk; - - if (!_pms(sk)->dev) - return -EBADFD; - - lock_sock(sk); - - maddr->family = AF_ISDN; - maddr->dev = _pms(sk)->dev->id; - maddr->channel = _pms(sk)->ch.nr; - maddr->sapi = _pms(sk)->ch.addr & 0xff; - maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff; - release_sock(sk); - return sizeof(*maddr); -} - -static const struct proto_ops data_sock_ops = { - .family = PF_ISDN, - .owner = THIS_MODULE, - .release = data_sock_release, - .ioctl = data_sock_ioctl, - .bind = data_sock_bind, - .getname = data_sock_getname, - .sendmsg = mISDN_sock_sendmsg, - .recvmsg = mISDN_sock_recvmsg, - .poll = datagram_poll, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = data_sock_setsockopt, - .getsockopt = data_sock_getsockopt, - .connect = sock_no_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .mmap = sock_no_mmap -}; - -static int -data_sock_create(struct net *net, struct socket *sock, int protocol, int kern) -{ - struct sock *sk; - - if (sock->type != SOCK_DGRAM) - return -ESOCKTNOSUPPORT; - - sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern); - if (!sk) - return -ENOMEM; - - sock_init_data(sock, sk); - - sock->ops = &data_sock_ops; - sock->state = SS_UNCONNECTED; - sock_reset_flag(sk, SOCK_ZAPPED); - - sk->sk_protocol = protocol; - sk->sk_state = MISDN_OPEN; - mISDN_sock_link(&data_sockets, sk); - - return 0; -} - -static int -base_sock_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); - if (!sk) - return 0; - - mISDN_sock_unlink(&base_sockets, sk); - sock_orphan(sk); - sock_put(sk); - - return 0; -} - -static int -base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - int err = 0, id; - struct mISDNdevice *dev; - struct mISDNversion ver; - - switch (cmd) { - case IMGETVERSION: - ver.major = MISDN_MAJOR_VERSION; - ver.minor = MISDN_MINOR_VERSION; - ver.release = MISDN_RELEASE; - if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) - err = -EFAULT; - break; - case IMGETCOUNT: - id = get_mdevice_count(); - if (put_user(id, (int __user *)arg)) - err = -EFAULT; - break; - case IMGETDEVINFO: - if (get_user(id, (int __user *)arg)) { - err = -EFAULT; - break; - } - dev = get_mdevice(id); - if (dev) { - struct mISDN_devinfo di; - - memset(&di, 0, sizeof(di)); - di.id = dev->id; - di.Dprotocols = dev->Dprotocols; - di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); - di.protocol = dev->D.protocol; - memcpy(di.channelmap, dev->channelmap, - sizeof(di.channelmap)); - di.nrbchan = dev->nrbchan; - strscpy(di.name, dev_name(&dev->dev), sizeof(di.name)); - if (copy_to_user((void __user *)arg, &di, sizeof(di))) - err = -EFAULT; - } else - err = -ENODEV; - break; - case IMSETDEVNAME: - { - struct mISDN_devrename dn; - if (copy_from_user(&dn, (void __user *)arg, - sizeof(dn))) { - err = -EFAULT; - break; - } - dn.name[sizeof(dn.name) - 1] = '\0'; - dev = get_mdevice(dn.id); - if (dev) - err = device_rename(&dev->dev, dn.name); - else - err = -ENODEV; - } - break; - default: - err = -EINVAL; - } - return err; -} - -static int -base_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr_len) -{ - struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; - struct sock *sk = sock->sk; - int err = 0; - - if (addr_len < sizeof(struct sockaddr_mISDN)) - return -EINVAL; - - if (!maddr || maddr->family != AF_ISDN) - return -EINVAL; - - lock_sock(sk); - - if (_pms(sk)->dev) { - err = -EALREADY; - goto done; - } - - _pms(sk)->dev = get_mdevice(maddr->dev); - if (!_pms(sk)->dev) { - err = -ENODEV; - goto done; - } - sk->sk_state = MISDN_BOUND; - -done: - release_sock(sk); - return err; -} - -static const struct proto_ops base_sock_ops = { - .family = PF_ISDN, - .owner = THIS_MODULE, - .release = base_sock_release, - .ioctl = base_sock_ioctl, - .bind = base_sock_bind, - .getname = sock_no_getname, - .sendmsg = sock_no_sendmsg, - .recvmsg = sock_no_recvmsg, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .connect = sock_no_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .mmap = sock_no_mmap -}; - - -static int -base_sock_create(struct net *net, struct socket *sock, int protocol, int kern) -{ - struct sock *sk; - - if (sock->type != SOCK_RAW) - return -ESOCKTNOSUPPORT; - if (!capable(CAP_NET_RAW)) - return -EPERM; - - sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern); - if (!sk) - return -ENOMEM; - - sock_init_data(sock, sk); - sock->ops = &base_sock_ops; - sock->state = SS_UNCONNECTED; - sock_reset_flag(sk, SOCK_ZAPPED); - sk->sk_protocol = protocol; - sk->sk_state = MISDN_OPEN; - mISDN_sock_link(&base_sockets, sk); - - return 0; -} - -static int -mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern) -{ - int err = -EPROTONOSUPPORT; - - switch (proto) { - case ISDN_P_BASE: - err = base_sock_create(net, sock, proto, kern); - break; - case ISDN_P_TE_S0: - case ISDN_P_NT_S0: - case ISDN_P_TE_E1: - case ISDN_P_NT_E1: - case ISDN_P_LAPD_TE: - case ISDN_P_LAPD_NT: - case ISDN_P_B_RAW: - case ISDN_P_B_HDLC: - case ISDN_P_B_X75SLP: - case ISDN_P_B_L2DTMF: - case ISDN_P_B_L2DSP: - case ISDN_P_B_L2DSPHDLC: - err = data_sock_create(net, sock, proto, kern); - break; - default: - return err; - } - - return err; -} - -static const struct net_proto_family mISDN_sock_family_ops = { - .owner = THIS_MODULE, - .family = PF_ISDN, - .create = mISDN_sock_create, -}; - -int -misdn_sock_init(u_int *deb) -{ - int err; - - debug = deb; - err = sock_register(&mISDN_sock_family_ops); - if (err) - printk(KERN_ERR "%s: error(%d)\n", __func__, err); - return err; -} - -void -misdn_sock_cleanup(void) -{ - sock_unregister(PF_ISDN); -} diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c deleted file mode 100644 index 4e96684af0aa..000000000000 --- a/drivers/isdn/mISDN/stack.c +++ /dev/null @@ -1,654 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include -#include -#include -#include - -#include "core.h" - -static u_int *debug; - -static inline void -_queue_message(struct mISDNstack *st, struct sk_buff *skb) -{ - struct mISDNhead *hh = mISDN_HEAD_P(skb); - - if (*debug & DEBUG_QUEUE_FUNC) - printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", - __func__, hh->prim, hh->id, skb); - skb_queue_tail(&st->msgq, skb); - if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) { - test_and_set_bit(mISDN_STACK_WORK, &st->status); - wake_up_interruptible(&st->workq); - } -} - -static int -mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) -{ - _queue_message(ch->st, skb); - return 0; -} - -static struct mISDNchannel * -get_channel4id(struct mISDNstack *st, u_int id) -{ - struct mISDNchannel *ch; - - mutex_lock(&st->lmutex); - list_for_each_entry(ch, &st->layer2, list) { - if (id == ch->nr) - goto unlock; - } - ch = NULL; -unlock: - mutex_unlock(&st->lmutex); - return ch; -} - -static void -send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) -{ - struct sock *sk; - struct sk_buff *cskb = NULL; - - read_lock(&sl->lock); - sk_for_each(sk, &sl->head) { - if (sk->sk_state != MISDN_BOUND) - continue; - if (!cskb) - cskb = skb_copy(skb, GFP_ATOMIC); - if (!cskb) { - printk(KERN_WARNING "%s no skb\n", __func__); - break; - } - if (!sock_queue_rcv_skb(sk, cskb)) - cskb = NULL; - } - read_unlock(&sl->lock); - dev_kfree_skb(cskb); -} - -static void -send_layer2(struct mISDNstack *st, struct sk_buff *skb) -{ - struct sk_buff *cskb; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - struct mISDNchannel *ch; - int ret; - - if (!st) - return; - mutex_lock(&st->lmutex); - if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */ - list_for_each_entry(ch, &st->layer2, list) { - if (list_is_last(&ch->list, &st->layer2)) { - cskb = skb; - skb = NULL; - } else { - cskb = skb_copy(skb, GFP_KERNEL); - } - if (cskb) { - ret = ch->send(ch, cskb); - if (ret) { - if (*debug & DEBUG_SEND_ERR) - printk(KERN_DEBUG - "%s ch%d prim(%x) addr(%x)" - " err %d\n", - __func__, ch->nr, - hh->prim, ch->addr, ret); - dev_kfree_skb(cskb); - } - } else { - printk(KERN_WARNING "%s ch%d addr %x no mem\n", - __func__, ch->nr, ch->addr); - goto out; - } - } - } else { - list_for_each_entry(ch, &st->layer2, list) { - if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) { - ret = ch->send(ch, skb); - if (!ret) - skb = NULL; - goto out; - } - } - ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb); - if (!ret) - skb = NULL; - else if (*debug & DEBUG_SEND_ERR) - printk(KERN_DEBUG - "%s mgr prim(%x) err %d\n", - __func__, hh->prim, ret); - } -out: - mutex_unlock(&st->lmutex); - dev_kfree_skb(skb); -} - -static inline int -send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) -{ - struct mISDNhead *hh = mISDN_HEAD_P(skb); - struct mISDNchannel *ch; - int lm; - - lm = hh->prim & MISDN_LAYERMASK; - if (*debug & DEBUG_QUEUE_FUNC) - printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", - __func__, hh->prim, hh->id, skb); - if (lm == 0x1) { - if (!hlist_empty(&st->l1sock.head)) { - __net_timestamp(skb); - send_socklist(&st->l1sock, skb); - } - return st->layer1->send(st->layer1, skb); - } else if (lm == 0x2) { - if (!hlist_empty(&st->l1sock.head)) - send_socklist(&st->l1sock, skb); - send_layer2(st, skb); - return 0; - } else if (lm == 0x4) { - ch = get_channel4id(st, hh->id); - if (ch) - return ch->send(ch, skb); - else - printk(KERN_WARNING - "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, dev_name(&st->dev->dev), hh->prim, - hh->id); - } else if (lm == 0x8) { - WARN_ON(lm == 0x8); - ch = get_channel4id(st, hh->id); - if (ch) - return ch->send(ch, skb); - else - printk(KERN_WARNING - "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, dev_name(&st->dev->dev), hh->prim, - hh->id); - } else { - /* broadcast not handled yet */ - printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", - __func__, dev_name(&st->dev->dev), hh->prim); - } - return -ESRCH; -} - -static void -do_clear_stack(struct mISDNstack *st) -{ -} - -static int -mISDNStackd(void *data) -{ - struct mISDNstack *st = data; -#ifdef MISDN_MSG_STATS - u64 utime, stime; -#endif - int err = 0; - - sigfillset(¤t->blocked); - if (*debug & DEBUG_MSG_THREAD) - printk(KERN_DEBUG "mISDNStackd %s started\n", - dev_name(&st->dev->dev)); - - if (st->notify != NULL) { - complete(st->notify); - st->notify = NULL; - } - - for (;;) { - struct sk_buff *skb; - - if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) { - test_and_clear_bit(mISDN_STACK_WORK, &st->status); - test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); - } else - test_and_set_bit(mISDN_STACK_RUNNING, &st->status); - while (test_bit(mISDN_STACK_WORK, &st->status)) { - skb = skb_dequeue(&st->msgq); - if (!skb) { - test_and_clear_bit(mISDN_STACK_WORK, - &st->status); - /* test if a race happens */ - skb = skb_dequeue(&st->msgq); - if (!skb) - continue; - test_and_set_bit(mISDN_STACK_WORK, - &st->status); - } -#ifdef MISDN_MSG_STATS - st->msg_cnt++; -#endif - err = send_msg_to_layer(st, skb); - if (unlikely(err)) { - if (*debug & DEBUG_SEND_ERR) - printk(KERN_DEBUG - "%s: %s prim(%x) id(%x) " - "send call(%d)\n", - __func__, dev_name(&st->dev->dev), - mISDN_HEAD_PRIM(skb), - mISDN_HEAD_ID(skb), err); - dev_kfree_skb(skb); - continue; - } - if (unlikely(test_bit(mISDN_STACK_STOPPED, - &st->status))) { - test_and_clear_bit(mISDN_STACK_WORK, - &st->status); - test_and_clear_bit(mISDN_STACK_RUNNING, - &st->status); - break; - } - } - if (test_bit(mISDN_STACK_CLEARING, &st->status)) { - test_and_set_bit(mISDN_STACK_STOPPED, &st->status); - test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); - do_clear_stack(st); - test_and_clear_bit(mISDN_STACK_CLEARING, &st->status); - test_and_set_bit(mISDN_STACK_RESTART, &st->status); - } - if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) { - test_and_clear_bit(mISDN_STACK_STOPPED, &st->status); - test_and_set_bit(mISDN_STACK_RUNNING, &st->status); - if (!skb_queue_empty(&st->msgq)) - test_and_set_bit(mISDN_STACK_WORK, - &st->status); - } - if (test_bit(mISDN_STACK_ABORT, &st->status)) - break; - if (st->notify != NULL) { - complete(st->notify); - st->notify = NULL; - } -#ifdef MISDN_MSG_STATS - st->sleep_cnt++; -#endif - test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); - wait_event_interruptible(st->workq, (st->status & - mISDN_STACK_ACTION_MASK)); - if (*debug & DEBUG_MSG_THREAD) - printk(KERN_DEBUG "%s: %s wake status %08lx\n", - __func__, dev_name(&st->dev->dev), st->status); - test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); - - test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); - - if (test_bit(mISDN_STACK_STOPPED, &st->status)) { - test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); -#ifdef MISDN_MSG_STATS - st->stopped_cnt++; -#endif - } - } -#ifdef MISDN_MSG_STATS - printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " - "msg %d sleep %d stopped\n", - dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt, - st->stopped_cnt); - task_cputime(st->thread, &utime, &stime); - printk(KERN_DEBUG - "mISDNStackd daemon for %s utime(%llu) stime(%llu)\n", - dev_name(&st->dev->dev), utime, stime); - printk(KERN_DEBUG - "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", - dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw); - printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", - dev_name(&st->dev->dev)); -#endif - test_and_set_bit(mISDN_STACK_KILLED, &st->status); - test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); - test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); - test_and_clear_bit(mISDN_STACK_ABORT, &st->status); - skb_queue_purge(&st->msgq); - st->thread = NULL; - if (st->notify != NULL) { - complete(st->notify); - st->notify = NULL; - } - return 0; -} - -static int -l1_receive(struct mISDNchannel *ch, struct sk_buff *skb) -{ - if (!ch->st) - return -ENODEV; - __net_timestamp(skb); - _queue_message(ch->st, skb); - return 0; -} - -void -set_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei) -{ - ch->addr = sapi | (tei << 8); -} - -void -__add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) -{ - list_add_tail(&ch->list, &st->layer2); -} - -void -add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) -{ - mutex_lock(&st->lmutex); - __add_layer2(ch, st); - mutex_unlock(&st->lmutex); -} - -static int -st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - if (!ch->st || !ch->st->layer1) - return -EINVAL; - return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); -} - -int -create_stack(struct mISDNdevice *dev) -{ - struct mISDNstack *newst; - int err; - DECLARE_COMPLETION_ONSTACK(done); - - newst = kzalloc_obj(struct mISDNstack); - if (!newst) { - printk(KERN_ERR "kmalloc mISDN_stack failed\n"); - return -ENOMEM; - } - newst->dev = dev; - INIT_LIST_HEAD(&newst->layer2); - INIT_HLIST_HEAD(&newst->l1sock.head); - rwlock_init(&newst->l1sock.lock); - init_waitqueue_head(&newst->workq); - skb_queue_head_init(&newst->msgq); - mutex_init(&newst->lmutex); - dev->D.st = newst; - err = create_teimanager(dev); - if (err) { - printk(KERN_ERR "kmalloc teimanager failed\n"); - kfree(newst); - return err; - } - dev->teimgr->peer = &newst->own; - dev->teimgr->recv = mISDN_queue_message; - dev->teimgr->st = newst; - newst->layer1 = &dev->D; - dev->D.recv = l1_receive; - dev->D.peer = &newst->own; - newst->own.st = newst; - newst->own.ctrl = st_own_ctrl; - newst->own.send = mISDN_queue_message; - newst->own.recv = mISDN_queue_message; - if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%s)\n", __func__, - dev_name(&newst->dev->dev)); - newst->notify = &done; - newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", - dev_name(&newst->dev->dev)); - if (IS_ERR(newst->thread)) { - err = PTR_ERR(newst->thread); - printk(KERN_ERR - "mISDN:cannot create kernel thread for %s (%d)\n", - dev_name(&newst->dev->dev), err); - delete_teimanager(dev->teimgr); - kfree(newst); - } else - wait_for_completion(&done); - return err; -} - -int -connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, - u_int protocol, struct sockaddr_mISDN *adr) -{ - struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); - struct channel_req rq; - int err; - - - if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev_name(&dev->dev), protocol, adr->dev, - adr->channel, adr->sapi, adr->tei); - switch (protocol) { - case ISDN_P_NT_S0: - case ISDN_P_NT_E1: - case ISDN_P_TE_S0: - case ISDN_P_TE_E1: - ch->recv = mISDN_queue_message; - ch->peer = &dev->D.st->own; - ch->st = dev->D.st; - rq.protocol = protocol; - rq.adr.channel = adr->channel; - err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); - printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err, - dev->id); - if (err) - return err; - write_lock_bh(&dev->D.st->l1sock.lock); - sk_add_node(&msk->sk, &dev->D.st->l1sock.head); - write_unlock_bh(&dev->D.st->l1sock.lock); - break; - default: - return -ENOPROTOOPT; - } - return 0; -} - -int -connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, - u_int protocol, struct sockaddr_mISDN *adr) -{ - struct channel_req rq, rq2; - int pmask, err; - struct Bprotocol *bp; - - if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev_name(&dev->dev), protocol, - adr->dev, adr->channel, adr->sapi, - adr->tei); - ch->st = dev->D.st; - pmask = 1 << (protocol & ISDN_P_B_MASK); - if (pmask & dev->Bprotocols) { - rq.protocol = protocol; - rq.adr = *adr; - err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); - if (err) - return err; - ch->recv = rq.ch->send; - ch->peer = rq.ch; - rq.ch->recv = ch->send; - rq.ch->peer = ch; - rq.ch->st = dev->D.st; - } else { - bp = get_Bprotocol4mask(pmask); - if (!bp) - return -ENOPROTOOPT; - rq2.protocol = protocol; - rq2.adr = *adr; - rq2.ch = ch; - err = bp->create(&rq2); - if (err) - return err; - ch->recv = rq2.ch->send; - ch->peer = rq2.ch; - rq2.ch->st = dev->D.st; - rq.protocol = rq2.protocol; - rq.adr = *adr; - err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); - if (err) { - rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL); - return err; - } - rq2.ch->recv = rq.ch->send; - rq2.ch->peer = rq.ch; - rq.ch->recv = rq2.ch->send; - rq.ch->peer = rq2.ch; - rq.ch->st = dev->D.st; - } - ch->protocol = protocol; - ch->nr = rq.ch->nr; - return 0; -} - -int -create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, - u_int protocol, struct sockaddr_mISDN *adr) -{ - struct channel_req rq; - int err; - - if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev_name(&dev->dev), protocol, - adr->dev, adr->channel, adr->sapi, - adr->tei); - rq.protocol = ISDN_P_TE_S0; - if (dev->Dprotocols & (1 << ISDN_P_TE_E1)) - rq.protocol = ISDN_P_TE_E1; - switch (protocol) { - case ISDN_P_LAPD_NT: - rq.protocol = ISDN_P_NT_S0; - if (dev->Dprotocols & (1 << ISDN_P_NT_E1)) - rq.protocol = ISDN_P_NT_E1; - fallthrough; - case ISDN_P_LAPD_TE: - ch->recv = mISDN_queue_message; - ch->peer = &dev->D.st->own; - ch->st = dev->D.st; - rq.adr.channel = 0; - err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); - printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); - if (err) - break; - rq.protocol = protocol; - rq.adr = *adr; - rq.ch = ch; - err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq); - printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err); - if (!err) { - if ((protocol == ISDN_P_LAPD_NT) && !rq.ch) - break; - add_layer2(rq.ch, dev->D.st); - rq.ch->recv = mISDN_queue_message; - rq.ch->peer = &dev->D.st->own; - rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */ - } - break; - default: - err = -EPROTONOSUPPORT; - } - return err; -} - -void -delete_channel(struct mISDNchannel *ch) -{ - struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); - struct mISDNchannel *pch; - - if (!ch->st) { - printk(KERN_WARNING "%s: no stack\n", __func__); - return; - } - if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, - dev_name(&ch->st->dev->dev), ch->protocol); - if (ch->protocol >= ISDN_P_B_START) { - if (ch->peer) { - ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); - ch->peer = NULL; - } - return; - } - switch (ch->protocol) { - case ISDN_P_NT_S0: - case ISDN_P_TE_S0: - case ISDN_P_NT_E1: - case ISDN_P_TE_E1: - write_lock_bh(&ch->st->l1sock.lock); - sk_del_node_init(&msk->sk); - write_unlock_bh(&ch->st->l1sock.lock); - ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL); - break; - case ISDN_P_LAPD_TE: - pch = get_channel4id(ch->st, ch->nr); - if (pch) { - mutex_lock(&ch->st->lmutex); - list_del(&pch->list); - mutex_unlock(&ch->st->lmutex); - pch->ctrl(pch, CLOSE_CHANNEL, NULL); - pch = ch->st->dev->teimgr; - pch->ctrl(pch, CLOSE_CHANNEL, NULL); - } else - printk(KERN_WARNING "%s: no l2 channel\n", - __func__); - break; - case ISDN_P_LAPD_NT: - pch = ch->st->dev->teimgr; - if (pch) { - pch->ctrl(pch, CLOSE_CHANNEL, NULL); - } else - printk(KERN_WARNING "%s: no l2 channel\n", - __func__); - break; - default: - break; - } - return; -} - -void -delete_stack(struct mISDNdevice *dev) -{ - struct mISDNstack *st = dev->D.st; - DECLARE_COMPLETION_ONSTACK(done); - - if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%s)\n", __func__, - dev_name(&st->dev->dev)); - if (dev->teimgr) - delete_teimanager(dev->teimgr); - if (st->thread) { - if (st->notify) { - printk(KERN_WARNING "%s: notifier in use\n", - __func__); - complete(st->notify); - } - st->notify = &done; - test_and_set_bit(mISDN_STACK_ABORT, &st->status); - test_and_set_bit(mISDN_STACK_WAKEUP, &st->status); - wake_up_interruptible(&st->workq); - wait_for_completion(&done); - } - if (!list_empty(&st->layer2)) - printk(KERN_WARNING "%s: layer2 list not empty\n", - __func__); - if (!hlist_empty(&st->l1sock.head)) - printk(KERN_WARNING "%s: layer1 list not empty\n", - __func__); - kfree(st); -} - -void -mISDN_initstack(u_int *dp) -{ - debug = dp; -} diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c deleted file mode 100644 index 2bad3083be90..000000000000 --- a/drivers/isdn/mISDN/tei.c +++ /dev/null @@ -1,1416 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - */ -#include "layer2.h" -#include -#include -#include "core.h" - -#define ID_REQUEST 1 -#define ID_ASSIGNED 2 -#define ID_DENIED 3 -#define ID_CHK_REQ 4 -#define ID_CHK_RES 5 -#define ID_REMOVE 6 -#define ID_VERIFY 7 - -#define TEI_ENTITY_ID 0xf - -#define MGR_PH_ACTIVE 16 -#define MGR_PH_NOTREADY 17 - -#define DATIMER_VAL 10000 - -static u_int *debug; - -static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; -static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; -static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; - -enum { - ST_L1_DEACT, - ST_L1_DEACT_PENDING, - ST_L1_ACTIV, -}; -#define DEACT_STATE_COUNT (ST_L1_ACTIV + 1) - -static char *strDeactState[] = -{ - "ST_L1_DEACT", - "ST_L1_DEACT_PENDING", - "ST_L1_ACTIV", -}; - -enum { - EV_ACTIVATE, - EV_ACTIVATE_IND, - EV_DEACTIVATE, - EV_DEACTIVATE_IND, - EV_UI, - EV_DATIMER, -}; - -#define DEACT_EVENT_COUNT (EV_DATIMER + 1) - -static char *strDeactEvent[] = -{ - "EV_ACTIVATE", - "EV_ACTIVATE_IND", - "EV_DEACTIVATE", - "EV_DEACTIVATE_IND", - "EV_UI", - "EV_DATIMER", -}; - -static void -da_debug(struct FsmInst *fi, char *fmt, ...) -{ - struct manager *mgr = fi->userdata; - struct va_format vaf; - va_list va; - - if (!(*debug & DEBUG_L2_TEIFSM)) - return; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf); - - va_end(va); -} - -static void -da_activate(struct FsmInst *fi, int event, void *arg) -{ - struct manager *mgr = fi->userdata; - - if (fi->state == ST_L1_DEACT_PENDING) - mISDN_FsmDelTimer(&mgr->datimer, 1); - mISDN_FsmChangeState(fi, ST_L1_ACTIV); -} - -static void -da_deactivate_ind(struct FsmInst *fi, int event, void *arg) -{ - mISDN_FsmChangeState(fi, ST_L1_DEACT); -} - -static void -da_deactivate(struct FsmInst *fi, int event, void *arg) -{ - struct manager *mgr = fi->userdata; - struct layer2 *l2; - u_long flags; - - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { - if (l2->l2m.state > ST_L2_4) { - /* have still activ TEI */ - read_unlock_irqrestore(&mgr->lock, flags); - return; - } - } - read_unlock_irqrestore(&mgr->lock, flags); - /* All TEI are inactiv */ - if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, - NULL, 1); - mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); - } -} - -static void -da_ui(struct FsmInst *fi, int event, void *arg) -{ - struct manager *mgr = fi->userdata; - - /* restart da timer */ - if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { - mISDN_FsmDelTimer(&mgr->datimer, 2); - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, - NULL, 2); - } -} - -static void -da_timer(struct FsmInst *fi, int event, void *arg) -{ - struct manager *mgr = fi->userdata; - struct layer2 *l2; - u_long flags; - - /* check again */ - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { - if (l2->l2m.state > ST_L2_4) { - /* have still activ TEI */ - read_unlock_irqrestore(&mgr->lock, flags); - mISDN_FsmChangeState(fi, ST_L1_ACTIV); - return; - } - } - read_unlock_irqrestore(&mgr->lock, flags); - /* All TEI are inactiv */ - mISDN_FsmChangeState(fi, ST_L1_DEACT); - _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); -} - -static struct FsmNode DeactFnList[] = -{ - {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, - {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, - {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, - {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, - {ST_L1_DEACT_PENDING, EV_UI, da_ui}, - {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, -}; - -enum { - ST_TEI_NOP, - ST_TEI_IDREQ, - ST_TEI_IDVERIFY, -}; - -#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1) - -static char *strTeiState[] = -{ - "ST_TEI_NOP", - "ST_TEI_IDREQ", - "ST_TEI_IDVERIFY", -}; - -enum { - EV_IDREQ, - EV_ASSIGN, - EV_ASSIGN_REQ, - EV_DENIED, - EV_CHKREQ, - EV_CHKRESP, - EV_REMOVE, - EV_VERIFY, - EV_TIMER, -}; - -#define TEI_EVENT_COUNT (EV_TIMER + 1) - -static char *strTeiEvent[] = -{ - "EV_IDREQ", - "EV_ASSIGN", - "EV_ASSIGN_REQ", - "EV_DENIED", - "EV_CHKREQ", - "EV_CHKRESP", - "EV_REMOVE", - "EV_VERIFY", - "EV_TIMER", -}; - -static void -tei_debug(struct FsmInst *fi, char *fmt, ...) -{ - struct teimgr *tm = fi->userdata; - struct va_format vaf; - va_list va; - - if (!(*debug & DEBUG_L2_TEIFSM)) - return; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n", - tm->l2->sapi, tm->l2->tei, &vaf); - - va_end(va); -} - - - -static int -get_free_id(struct manager *mgr) -{ - DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; - int i; - struct layer2 *l2; - - list_for_each_entry(l2, &mgr->layer2, list) { - if (l2->ch.nr > 63) { - printk(KERN_WARNING - "%s: more as 63 layer2 for one device\n", - __func__); - return -EBUSY; - } - __set_bit(l2->ch.nr, ids); - } - i = find_next_zero_bit(ids, 64, 1); - if (i < 64) - return i; - printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", - __func__); - return -EBUSY; -} - -static int -get_free_tei(struct manager *mgr) -{ - DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; - int i; - struct layer2 *l2; - - list_for_each_entry(l2, &mgr->layer2, list) { - if (l2->ch.nr == 0) - continue; - if ((l2->ch.addr & 0xff) != 0) - continue; - i = l2->ch.addr >> 8; - if (i < 64) - continue; - i -= 64; - - __set_bit(i, ids); - } - i = find_first_zero_bit(ids, 64); - if (i < 64) - return i + 64; - printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", - __func__); - return -1; -} - -static void -teiup_create(struct manager *mgr, u_int prim, int len, void *arg) -{ - struct sk_buff *skb; - struct mISDNhead *hh; - int err; - - skb = mI_alloc_skb(len, GFP_ATOMIC); - if (!skb) - return; - hh = mISDN_HEAD_P(skb); - hh->prim = prim; - hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; - if (len) - skb_put_data(skb, arg, len); - err = mgr->up->send(mgr->up, skb); - if (err) { - printk(KERN_WARNING "%s: err=%d\n", __func__, err); - dev_kfree_skb(skb); - } -} - -static u_int -new_id(struct manager *mgr) -{ - u_int id; - - id = mgr->nextid++; - if (id == 0x7fff) - mgr->nextid = 1; - id <<= 16; - id |= GROUP_TEI << 8; - id |= TEI_SAPI; - return id; -} - -static void -do_send(struct manager *mgr) -{ - if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) - return; - - if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { - struct sk_buff *skb = skb_dequeue(&mgr->sendq); - - if (!skb) { - test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); - return; - } - mgr->lastid = mISDN_HEAD_ID(skb); - mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); - if (mgr->ch.recv(mgr->ch.peer, skb)) { - dev_kfree_skb(skb); - test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); - mgr->lastid = MISDN_ID_NONE; - } - } -} - -static void -do_ack(struct manager *mgr, u_int id) -{ - if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { - if (id == mgr->lastid) { - if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { - struct sk_buff *skb; - - skb = skb_dequeue(&mgr->sendq); - if (skb) { - mgr->lastid = mISDN_HEAD_ID(skb); - if (!mgr->ch.recv(mgr->ch.peer, skb)) - return; - dev_kfree_skb(skb); - } - } - mgr->lastid = MISDN_ID_NONE; - test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); - } - } -} - -static void -mgr_send_down(struct manager *mgr, struct sk_buff *skb) -{ - skb_queue_tail(&mgr->sendq, skb); - if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { - _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - } else { - do_send(mgr); - } -} - -static int -dl_unit_data(struct manager *mgr, struct sk_buff *skb) -{ - if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ - return -EINVAL; - if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) - _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); - skb_push(skb, 3); - skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ - skb->data[1] = 0xff; /* TEI 127 */ - skb->data[2] = UI; /* UI frame */ - mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; - mISDN_HEAD_ID(skb) = new_id(mgr); - skb_queue_tail(&mgr->sendq, skb); - do_send(mgr); - return 0; -} - -static unsigned int -random_ri(void) -{ - u16 x; - - get_random_bytes(&x, sizeof(x)); - return x; -} - -static struct layer2 * -findtei(struct manager *mgr, int tei) -{ - struct layer2 *l2; - u_long flags; - - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { - if ((l2->sapi == 0) && (l2->tei > 0) && - (l2->tei != GROUP_TEI) && (l2->tei == tei)) - goto done; - } - l2 = NULL; -done: - read_unlock_irqrestore(&mgr->lock, flags); - return l2; -} - -static void -put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei) -{ - struct sk_buff *skb; - u_char bp[8]; - - bp[0] = (TEI_SAPI << 2); - if (test_bit(MGR_OPT_NETWORK, &mgr->options)) - bp[0] |= 2; /* CR:=1 for net command */ - bp[1] = (GROUP_TEI << 1) | 0x1; - bp[2] = UI; - bp[3] = TEI_ENTITY_ID; - bp[4] = ri >> 8; - bp[5] = ri & 0xff; - bp[6] = m_id; - bp[7] = ((tei << 1) & 0xff) | 1; - skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); - return; - } - mgr_send_down(mgr, skb); -} - -static void -tei_id_request(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - - if (tm->l2->tei != GROUP_TEI) { - tm->tei_m.printdebug(&tm->tei_m, - "assign request for already assigned tei %d", - tm->l2->tei); - return; - } - tm->ri = random_ri(); - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(&tm->tei_m, - "assign request ri %d", tm->ri); - put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); - mISDN_FsmChangeState(fi, ST_TEI_IDREQ); - mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); - tm->nval = 3; -} - -static void -tei_id_assign(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - struct layer2 *l2; - u_char *dp = arg; - int ri, tei; - - ri = ((unsigned int) *dp++ << 8); - ri += *dp++; - dp++; - tei = *dp >> 1; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", - ri, tei); - l2 = findtei(tm->mgr, tei); - if (l2) { /* same tei is in use */ - if (ri != l2->tm->ri) { - tm->tei_m.printdebug(fi, - "possible duplicate assignment tei %d", tei); - tei_l2(l2, MDL_ERROR_RSP, 0); - } - } else if (ri == tm->ri) { - mISDN_FsmDelTimer(&tm->timer, 1); - mISDN_FsmChangeState(fi, ST_TEI_NOP); - tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); - } -} - -static void -tei_id_test_dup(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - struct layer2 *l2; - u_char *dp = arg; - int tei, ri; - - ri = ((unsigned int) *dp++ << 8); - ri += *dp++; - dp++; - tei = *dp >> 1; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", - ri, tei); - l2 = findtei(tm->mgr, tei); - if (l2) { /* same tei is in use */ - if (ri != l2->tm->ri) { /* and it wasn't our request */ - tm->tei_m.printdebug(fi, - "possible duplicate assignment tei %d", tei); - mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); - } - } -} - -static void -tei_id_denied(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - u_char *dp = arg; - int ri, tei; - - ri = ((unsigned int) *dp++ << 8); - ri += *dp++; - dp++; - tei = *dp >> 1; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", - ri, tei); -} - -static void -tei_id_chk_req(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - u_char *dp = arg; - int tei; - - tei = *(dp + 3) >> 1; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "identity check req tei %d", tei); - if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || - (tei == tm->l2->tei))) { - mISDN_FsmDelTimer(&tm->timer, 4); - mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); - put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); - } -} - -static void -tei_id_remove(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - u_char *dp = arg; - int tei; - - tei = *(dp + 3) >> 1; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "identity remove tei %d", tei); - if ((tm->l2->tei != GROUP_TEI) && - ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { - mISDN_FsmDelTimer(&tm->timer, 5); - mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); - tei_l2(tm->l2, MDL_REMOVE_REQ, 0); - } -} - -static void -tei_id_verify(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "id verify request for tei %d", - tm->l2->tei); - put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); - mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); - mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); - tm->nval = 2; -} - -static void -tei_id_req_tout(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - - if (--tm->nval) { - tm->ri = random_ri(); - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "assign req(%d) ri %d", - 4 - tm->nval, tm->ri); - put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); - mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); - } else { - tm->tei_m.printdebug(fi, "assign req failed"); - tei_l2(tm->l2, MDL_ERROR_RSP, 0); - mISDN_FsmChangeState(fi, ST_TEI_NOP); - } -} - -static void -tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - - if (--tm->nval) { - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, - "id verify req(%d) for tei %d", - 3 - tm->nval, tm->l2->tei); - put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); - mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); - } else { - tm->tei_m.printdebug(fi, "verify req for tei %d failed", - tm->l2->tei); - tei_l2(tm->l2, MDL_REMOVE_REQ, 0); - mISDN_FsmChangeState(fi, ST_TEI_NOP); - } -} - -static struct FsmNode TeiFnListUser[] = -{ - {ST_TEI_NOP, EV_IDREQ, tei_id_request}, - {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, - {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, - {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, - {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, - {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, - {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, - {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, - {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, - {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, - {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, -}; - -static void -tei_l2remove(struct layer2 *l2) -{ - put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); - tei_l2(l2, MDL_REMOVE_REQ, 0); - list_del(&l2->ch.list); - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); -} - -static void -tei_assign_req(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - u_char *dp = arg; - - if (tm->l2->tei == GROUP_TEI) { - tm->tei_m.printdebug(&tm->tei_m, - "net tei assign request without tei"); - return; - } - tm->ri = ((unsigned int) *dp++ << 8); - tm->ri += *dp++; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(&tm->tei_m, - "net assign request ri %d teim %d", tm->ri, *dp); - put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); - mISDN_FsmChangeState(fi, ST_TEI_NOP); -} - -static void -tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "id check request for tei %d", - tm->l2->tei); - tm->rcnt = 0; - put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); - mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); - mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); - tm->nval = 2; -} - -static void -tei_id_chk_resp(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - u_char *dp = arg; - int tei; - - tei = dp[3] >> 1; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); - if (tei == tm->l2->tei) - tm->rcnt++; -} - -static void -tei_id_verify_net(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - u_char *dp = arg; - int tei; - - tei = dp[3] >> 1; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", - tei, tm->l2->tei); - if (tei == tm->l2->tei) - tei_id_chk_req_net(fi, event, arg); -} - -static void -tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) -{ - struct teimgr *tm = fi->userdata; - - if (tm->rcnt == 1) { - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, - "check req for tei %d successful\n", tm->l2->tei); - mISDN_FsmChangeState(fi, ST_TEI_NOP); - } else if (tm->rcnt > 1) { - /* duplicate assignment; remove */ - tei_l2remove(tm->l2); - } else if (--tm->nval) { - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(fi, - "id check req(%d) for tei %d", - 3 - tm->nval, tm->l2->tei); - put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); - mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); - } else { - tm->tei_m.printdebug(fi, "check req for tei %d failed", - tm->l2->tei); - mISDN_FsmChangeState(fi, ST_TEI_NOP); - tei_l2remove(tm->l2); - } -} - -static struct FsmNode TeiFnListNet[] = -{ - {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, - {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, - {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, - {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, - {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, -}; - -static void -tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) -{ - if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) - return; - if (*debug & DEBUG_L2_TEI) - tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); - if (mt == ID_ASSIGNED) - mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); - else if (mt == ID_DENIED) - mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); - else if (mt == ID_CHK_REQ) - mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); - else if (mt == ID_REMOVE) - mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); - else if (mt == ID_VERIFY) - mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); - else if (mt == ID_CHK_RES) - mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); -} - -static struct layer2 * -create_new_tei(struct manager *mgr, int tei, int sapi) -{ - unsigned long opt = 0; - unsigned long flags; - int id; - struct layer2 *l2; - struct channel_req rq; - - if (!mgr->up) - return NULL; - if ((tei >= 0) && (tei < 64)) - test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); - if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | - (1 << ISDN_P_NT_E1))) { - test_and_set_bit(OPTION_L2_PMX, &opt); - rq.protocol = ISDN_P_NT_E1; - } else { - rq.protocol = ISDN_P_NT_S0; - } - l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); - if (!l2) { - printk(KERN_WARNING "%s:no memory for layer2\n", __func__); - return NULL; - } - l2->tm = kzalloc_obj(struct teimgr); - if (!l2->tm) { - kfree(l2); - printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); - return NULL; - } - l2->tm->mgr = mgr; - l2->tm->l2 = l2; - l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; - l2->tm->tei_m.userdata = l2->tm; - l2->tm->tei_m.printdebug = tei_debug; - l2->tm->tei_m.fsm = &teifsmn; - l2->tm->tei_m.state = ST_TEI_NOP; - l2->tm->tval = 2000; /* T202 2 sec */ - mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); - write_lock_irqsave(&mgr->lock, flags); - id = get_free_id(mgr); - list_add_tail(&l2->list, &mgr->layer2); - write_unlock_irqrestore(&mgr->lock, flags); - if (id < 0) { - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - printk(KERN_WARNING "%s:no free id\n", __func__); - return NULL; - } else { - l2->ch.nr = id; - __add_layer2(&l2->ch, mgr->ch.st); - l2->ch.recv = mgr->ch.recv; - l2->ch.peer = mgr->ch.peer; - l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); - /* We need open here L1 for the manager as well (refcounting) */ - rq.adr.dev = mgr->ch.st->dev->id; - id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq); - if (id < 0) { - printk(KERN_WARNING "%s: cannot open L1\n", __func__); - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - l2 = NULL; - } - } - return l2; -} - -static void -new_tei_req(struct manager *mgr, u_char *dp) -{ - int tei, ri; - struct layer2 *l2; - - ri = dp[0] << 8; - ri += dp[1]; - if (!mgr->up) - goto denied; - if (!(dp[3] & 1)) /* Extension bit != 1 */ - goto denied; - if (dp[3] != 0xff) - tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */ - else - tei = get_free_tei(mgr); - if (tei < 0) { - printk(KERN_WARNING "%s:No free tei\n", __func__); - goto denied; - } - l2 = create_new_tei(mgr, tei, CTRL_SAPI); - if (!l2) - goto denied; - else - mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); - return; -denied: - put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); -} - -static int -ph_data_ind(struct manager *mgr, struct sk_buff *skb) -{ - int ret = -EINVAL; - struct layer2 *l2, *nl2; - u_char mt; - - if (skb->len < 8) { - if (*debug & DEBUG_L2_TEI) - printk(KERN_DEBUG "%s: short mgr frame %d/8\n", - __func__, skb->len); - goto done; - } - - if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ - goto done; - if (skb->data[0] & 1) /* EA0 formal error */ - goto done; - if (!(skb->data[1] & 1)) /* EA1 formal error */ - goto done; - if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ - goto done; - if ((skb->data[2] & 0xef) != UI) /* not UI */ - goto done; - if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ - goto done; - mt = skb->data[6]; - switch (mt) { - case ID_REQUEST: - case ID_CHK_RES: - case ID_VERIFY: - if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) - goto done; - break; - case ID_ASSIGNED: - case ID_DENIED: - case ID_CHK_REQ: - case ID_REMOVE: - if (test_bit(MGR_OPT_NETWORK, &mgr->options)) - goto done; - break; - default: - goto done; - } - ret = 0; - if (mt == ID_REQUEST) { - new_tei_req(mgr, &skb->data[4]); - goto done; - } - list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { - tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); - } -done: - return ret; -} - -int -l2_tei(struct layer2 *l2, u_int cmd, u_long arg) -{ - struct teimgr *tm = l2->tm; - - if (test_bit(FLG_FIXED_TEI, &l2->flag)) - return 0; - if (*debug & DEBUG_L2_TEI) - printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); - switch (cmd) { - case MDL_ASSIGN_IND: - mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); - break; - case MDL_ERROR_IND: - if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) - mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); - if (test_bit(MGR_OPT_USER, &tm->mgr->options)) - mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); - break; - case MDL_STATUS_UP_IND: - if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) - mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); - break; - case MDL_STATUS_DOWN_IND: - if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) - mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); - break; - case MDL_STATUS_UI_IND: - if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) - mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); - break; - } - return 0; -} - -void -TEIrelease(struct layer2 *l2) -{ - struct teimgr *tm = l2->tm; - u_long flags; - - mISDN_FsmDelTimer(&tm->timer, 1); - write_lock_irqsave(&tm->mgr->lock, flags); - list_del(&l2->list); - write_unlock_irqrestore(&tm->mgr->lock, flags); - l2->tm = NULL; - kfree(tm); -} - -static int -create_teimgr(struct manager *mgr, struct channel_req *crq) -{ - struct layer2 *l2; - unsigned long opt = 0; - unsigned long flags; - int id; - struct channel_req l1rq; - - if (*debug & DEBUG_L2_TEI) - printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev_name(&mgr->ch.st->dev->dev), - crq->protocol, crq->adr.dev, crq->adr.channel, - crq->adr.sapi, crq->adr.tei); - if (crq->adr.tei > GROUP_TEI) - return -EINVAL; - if (crq->adr.tei < 64) - test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); - if (crq->adr.tei == 0) - test_and_set_bit(OPTION_L2_PTP, &opt); - if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { - if (crq->protocol == ISDN_P_LAPD_TE) - return -EPROTONOSUPPORT; - if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) - return -EINVAL; - if (mgr->up) { - printk(KERN_WARNING - "%s: only one network manager is allowed\n", - __func__); - return -EBUSY; - } - } else if (test_bit(MGR_OPT_USER, &mgr->options)) { - if (crq->protocol == ISDN_P_LAPD_NT) - return -EPROTONOSUPPORT; - if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) - return -EINVAL; /* dyn tei */ - } else { - if (crq->protocol == ISDN_P_LAPD_NT) - test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); - if (crq->protocol == ISDN_P_LAPD_TE) - test_and_set_bit(MGR_OPT_USER, &mgr->options); - } - l1rq.adr = crq->adr; - if (mgr->ch.st->dev->Dprotocols - & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) - test_and_set_bit(OPTION_L2_PMX, &opt); - if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { - mgr->up = crq->ch; - id = DL_INFO_L2_CONNECT; - teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); - if (test_bit(MGR_PH_ACTIVE, &mgr->options)) - teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); - crq->ch = NULL; - if (!list_empty(&mgr->layer2)) { - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { - l2->up = mgr->up; - l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); - } - read_unlock_irqrestore(&mgr->lock, flags); - } - return 0; - } - l2 = create_l2(crq->ch, crq->protocol, opt, - crq->adr.tei, crq->adr.sapi); - if (!l2) - return -ENOMEM; - l2->tm = kzalloc_obj(struct teimgr); - if (!l2->tm) { - kfree(l2); - printk(KERN_ERR "kmalloc teimgr failed\n"); - return -ENOMEM; - } - l2->tm->mgr = mgr; - l2->tm->l2 = l2; - l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; - l2->tm->tei_m.userdata = l2->tm; - l2->tm->tei_m.printdebug = tei_debug; - if (crq->protocol == ISDN_P_LAPD_TE) { - l2->tm->tei_m.fsm = &teifsmu; - l2->tm->tei_m.state = ST_TEI_NOP; - l2->tm->tval = 1000; /* T201 1 sec */ - if (test_bit(OPTION_L2_PMX, &opt)) - l1rq.protocol = ISDN_P_TE_E1; - else - l1rq.protocol = ISDN_P_TE_S0; - } else { - l2->tm->tei_m.fsm = &teifsmn; - l2->tm->tei_m.state = ST_TEI_NOP; - l2->tm->tval = 2000; /* T202 2 sec */ - if (test_bit(OPTION_L2_PMX, &opt)) - l1rq.protocol = ISDN_P_NT_E1; - else - l1rq.protocol = ISDN_P_NT_S0; - } - mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); - write_lock_irqsave(&mgr->lock, flags); - id = get_free_id(mgr); - list_add_tail(&l2->list, &mgr->layer2); - write_unlock_irqrestore(&mgr->lock, flags); - if (id >= 0) { - l2->ch.nr = id; - l2->up->nr = id; - crq->ch = &l2->ch; - /* We need open here L1 for the manager as well (refcounting) */ - id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, - &l1rq); - } - if (id < 0) - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - return id; -} - -static int -mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct manager *mgr; - struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret = -EINVAL; - - mgr = container_of(ch, struct manager, ch); - if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", - __func__, hh->prim, hh->id); - switch (hh->prim) { - case PH_DATA_IND: - mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); - ret = ph_data_ind(mgr, skb); - break; - case PH_DATA_CNF: - do_ack(mgr, hh->id); - ret = 0; - break; - case PH_ACTIVATE_IND: - test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); - if (mgr->up) - teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); - mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); - do_send(mgr); - ret = 0; - break; - case PH_DEACTIVATE_IND: - test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); - if (mgr->up) - teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL); - mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); - ret = 0; - break; - case DL_UNITDATA_REQ: - return dl_unit_data(mgr, skb); - } - if (!ret) - dev_kfree_skb(skb); - return ret; -} - -static int -free_teimanager(struct manager *mgr) -{ - struct layer2 *l2, *nl2; - - test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); - if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { - /* not locked lock is taken in release tei */ - mgr->up = NULL; - if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { - list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { - put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); - mutex_lock(&mgr->ch.st->lmutex); - list_del(&l2->ch.list); - mutex_unlock(&mgr->ch.st->lmutex); - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - } - test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); - } else { - list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { - l2->up = NULL; - } - } - } - if (test_bit(MGR_OPT_USER, &mgr->options)) { - if (list_empty(&mgr->layer2)) - test_and_clear_bit(MGR_OPT_USER, &mgr->options); - } - mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); - return 0; -} - -static int -ctrl_teimanager(struct manager *mgr, void *arg) -{ - /* currently we only have one option */ - unsigned int *val = (unsigned int *)arg; - - switch (val[0]) { - case IMCLEAR_L2: - if (val[1]) - test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); - else - test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); - break; - case IMHOLD_L1: - if (val[1]) - test_and_set_bit(OPTION_L1_HOLD, &mgr->options); - else - test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); - break; - default: - return -EINVAL; - } - return 0; -} - -/* This function does create a L2 for fixed TEI in NT Mode */ -static int -check_data(struct manager *mgr, struct sk_buff *skb) -{ - struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret, tei, sapi; - struct layer2 *l2; - - if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", - __func__, hh->prim, hh->id); - if (test_bit(MGR_OPT_USER, &mgr->options)) - return -ENOTCONN; - if (hh->prim != PH_DATA_IND) - return -ENOTCONN; - if (skb->len != 3) - return -ENOTCONN; - if (skb->data[0] & 3) /* EA0 and CR must be 0 */ - return -EINVAL; - sapi = skb->data[0] >> 2; - if (!(skb->data[1] & 1)) /* invalid EA1 */ - return -EINVAL; - tei = skb->data[1] >> 1; - if (tei > 63) /* not a fixed tei */ - return -ENOTCONN; - if ((skb->data[2] & ~0x10) != SABME) - return -ENOTCONN; - /* We got a SABME for a fixed TEI */ - if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n", - __func__, sapi, tei); - l2 = create_new_tei(mgr, tei, sapi); - if (!l2) { - if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s: failed to create new tei\n", - __func__); - return -ENOMEM; - } - ret = l2->ch.send(&l2->ch, skb); - return ret; -} - -void -delete_teimanager(struct mISDNchannel *ch) -{ - struct manager *mgr; - struct layer2 *l2, *nl2; - - mgr = container_of(ch, struct manager, ch); - /* not locked lock is taken in release tei */ - list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { - mutex_lock(&mgr->ch.st->lmutex); - list_del(&l2->ch.list); - mutex_unlock(&mgr->ch.st->lmutex); - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - } - list_del(&mgr->ch.list); - list_del(&mgr->bcast.list); - skb_queue_purge(&mgr->sendq); - kfree(mgr); -} - -static int -mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - struct manager *mgr; - int ret = -EINVAL; - - mgr = container_of(ch, struct manager, ch); - if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); - switch (cmd) { - case OPEN_CHANNEL: - ret = create_teimgr(mgr, arg); - break; - case CLOSE_CHANNEL: - ret = free_teimanager(mgr); - break; - case CONTROL_CHANNEL: - ret = ctrl_teimanager(mgr, arg); - break; - case CHECK_DATA: - ret = check_data(mgr, arg); - break; - } - return ret; -} - -static int -mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) -{ - struct manager *mgr = container_of(ch, struct manager, bcast); - struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb); - struct sk_buff *cskb = NULL; - struct layer2 *l2; - u_long flags; - int ret; - - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { - if ((hh->id & MISDN_ID_SAPI_MASK) == - (l2->ch.addr & MISDN_ID_SAPI_MASK)) { - if (list_is_last(&l2->list, &mgr->layer2)) { - cskb = skb; - skb = NULL; - } else { - if (!cskb) - cskb = skb_copy(skb, GFP_ATOMIC); - } - if (cskb) { - hhc = mISDN_HEAD_P(cskb); - /* save original header behind normal header */ - hhc++; - *hhc = *hh; - hhc--; - hhc->prim = DL_INTERN_MSG; - hhc->id = l2->ch.nr; - ret = ch->st->own.recv(&ch->st->own, cskb); - if (ret) { - if (*debug & DEBUG_SEND_ERR) - printk(KERN_DEBUG - "%s ch%d prim(%x) addr(%x)" - " err %d\n", - __func__, l2->ch.nr, - hh->prim, l2->ch.addr, ret); - } else - cskb = NULL; - } else { - printk(KERN_WARNING "%s ch%d addr %x no mem\n", - __func__, ch->nr, ch->addr); - goto out; - } - } - } -out: - read_unlock_irqrestore(&mgr->lock, flags); - dev_kfree_skb(cskb); - dev_kfree_skb(skb); - return 0; -} - -static int -mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) -{ - - return -EINVAL; -} - -int -create_teimanager(struct mISDNdevice *dev) -{ - struct manager *mgr; - - mgr = kzalloc_obj(struct manager); - if (!mgr) - return -ENOMEM; - INIT_LIST_HEAD(&mgr->layer2); - rwlock_init(&mgr->lock); - skb_queue_head_init(&mgr->sendq); - mgr->nextid = 1; - mgr->lastid = MISDN_ID_NONE; - mgr->ch.send = mgr_send; - mgr->ch.ctrl = mgr_ctrl; - mgr->ch.st = dev->D.st; - set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); - add_layer2(&mgr->ch, dev->D.st); - mgr->bcast.send = mgr_bcast; - mgr->bcast.ctrl = mgr_bcast_ctrl; - mgr->bcast.st = dev->D.st; - set_channel_address(&mgr->bcast, 0, GROUP_TEI); - add_layer2(&mgr->bcast, dev->D.st); - mgr->deact.debug = *debug & DEBUG_MANAGER; - mgr->deact.userdata = mgr; - mgr->deact.printdebug = da_debug; - mgr->deact.fsm = &deactfsm; - mgr->deact.state = ST_L1_DEACT; - mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); - dev->teimgr = &mgr->ch; - return 0; -} - -int TEIInit(u_int *deb) -{ - int res; - debug = deb; - teifsmu.state_count = TEI_STATE_COUNT; - teifsmu.event_count = TEI_EVENT_COUNT; - teifsmu.strEvent = strTeiEvent; - teifsmu.strState = strTeiState; - res = mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); - if (res) - goto error; - teifsmn.state_count = TEI_STATE_COUNT; - teifsmn.event_count = TEI_EVENT_COUNT; - teifsmn.strEvent = strTeiEvent; - teifsmn.strState = strTeiState; - res = mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); - if (res) - goto error_smn; - deactfsm.state_count = DEACT_STATE_COUNT; - deactfsm.event_count = DEACT_EVENT_COUNT; - deactfsm.strEvent = strDeactEvent; - deactfsm.strState = strDeactState; - res = mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); - if (res) - goto error_deact; - return 0; - -error_deact: - mISDN_FsmFree(&teifsmn); -error_smn: - mISDN_FsmFree(&teifsmu); -error: - return res; -} - -void TEIFree(void) -{ - mISDN_FsmFree(&teifsmu); - mISDN_FsmFree(&teifsmn); - mISDN_FsmFree(&deactfsm); -} diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c deleted file mode 100644 index a18845755633..000000000000 --- a/drivers/isdn/mISDN/timerdev.c +++ /dev/null @@ -1,295 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * general timer device for using in ISDN stacks - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core.h" - -static DEFINE_MUTEX(mISDN_mutex); -static u_int *debug; - - -struct mISDNtimerdev { - int next_id; - struct list_head pending; - struct list_head expired; - wait_queue_head_t wait; - u_int work; - spinlock_t lock; /* protect lists */ -}; - -struct mISDNtimer { - struct list_head list; - struct mISDNtimerdev *dev; - struct timer_list tl; - int id; -}; - -static int -mISDN_open(struct inode *ino, struct file *filep) -{ - struct mISDNtimerdev *dev; - - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); - dev = kmalloc_obj(struct mISDNtimerdev); - if (!dev) - return -ENOMEM; - dev->next_id = 1; - INIT_LIST_HEAD(&dev->pending); - INIT_LIST_HEAD(&dev->expired); - spin_lock_init(&dev->lock); - dev->work = 0; - init_waitqueue_head(&dev->wait); - filep->private_data = dev; - return nonseekable_open(ino, filep); -} - -static int -mISDN_close(struct inode *ino, struct file *filep) -{ - struct mISDNtimerdev *dev = filep->private_data; - struct list_head *list = &dev->pending; - struct mISDNtimer *timer, *next; - - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); - - spin_lock_irq(&dev->lock); - while (!list_empty(list)) { - timer = list_first_entry(list, struct mISDNtimer, list); - spin_unlock_irq(&dev->lock); - timer_shutdown_sync(&timer->tl); - spin_lock_irq(&dev->lock); - /* it might have been moved to ->expired */ - list_del(&timer->list); - kfree(timer); - } - spin_unlock_irq(&dev->lock); - - list_for_each_entry_safe(timer, next, &dev->expired, list) { - kfree(timer); - } - kfree(dev); - return 0; -} - -static ssize_t -mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off) -{ - struct mISDNtimerdev *dev = filep->private_data; - struct list_head *list = &dev->expired; - struct mISDNtimer *timer; - int ret = 0; - - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__, - filep, buf, (int)count, off); - - if (count < sizeof(int)) - return -ENOSPC; - - spin_lock_irq(&dev->lock); - while (list_empty(list) && (dev->work == 0)) { - spin_unlock_irq(&dev->lock); - if (filep->f_flags & O_NONBLOCK) - return -EAGAIN; - wait_event_interruptible(dev->wait, (READ_ONCE(dev->work) || - !list_empty(list))); - if (signal_pending(current)) - return -ERESTARTSYS; - spin_lock_irq(&dev->lock); - } - if (dev->work) - WRITE_ONCE(dev->work, 0); - if (!list_empty(list)) { - timer = list_first_entry(list, struct mISDNtimer, list); - list_del(&timer->list); - spin_unlock_irq(&dev->lock); - if (put_user(timer->id, (int __user *)buf)) - ret = -EFAULT; - else - ret = sizeof(int); - kfree(timer); - } else { - spin_unlock_irq(&dev->lock); - } - return ret; -} - -static __poll_t -mISDN_poll(struct file *filep, poll_table *wait) -{ - struct mISDNtimerdev *dev = filep->private_data; - __poll_t mask = EPOLLERR; - - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait); - if (dev) { - u32 work; - - poll_wait(filep, &dev->wait, wait); - mask = 0; - work = READ_ONCE(dev->work); - if (work || !list_empty(&dev->expired)) - mask |= (EPOLLIN | EPOLLRDNORM); - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__, - work, list_empty(&dev->expired)); - } - return mask; -} - -static void -dev_expire_timer(struct timer_list *t) -{ - struct mISDNtimer *timer = timer_container_of(timer, t, tl); - u_long flags; - - spin_lock_irqsave(&timer->dev->lock, flags); - if (timer->id >= 0) - list_move_tail(&timer->list, &timer->dev->expired); - wake_up_interruptible(&timer->dev->wait); - spin_unlock_irqrestore(&timer->dev->lock, flags); -} - -static int -misdn_add_timer(struct mISDNtimerdev *dev, int timeout) -{ - int id; - struct mISDNtimer *timer; - - if (!timeout) { - WRITE_ONCE(dev->work, 1); - wake_up_interruptible(&dev->wait); - id = 0; - } else { - timer = kzalloc_obj(struct mISDNtimer); - if (!timer) - return -ENOMEM; - timer->dev = dev; - timer_setup(&timer->tl, dev_expire_timer, 0); - spin_lock_irq(&dev->lock); - id = timer->id = dev->next_id++; - if (dev->next_id < 0) - dev->next_id = 1; - list_add_tail(&timer->list, &dev->pending); - timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); - add_timer(&timer->tl); - spin_unlock_irq(&dev->lock); - } - return id; -} - -static int -misdn_del_timer(struct mISDNtimerdev *dev, int id) -{ - struct mISDNtimer *timer; - - spin_lock_irq(&dev->lock); - list_for_each_entry(timer, &dev->pending, list) { - if (timer->id == id) { - list_del_init(&timer->list); - timer->id = -1; - spin_unlock_irq(&dev->lock); - timer_shutdown_sync(&timer->tl); - kfree(timer); - return id; - } - } - spin_unlock_irq(&dev->lock); - return 0; -} - -static long -mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - struct mISDNtimerdev *dev = filep->private_data; - int id, tout, ret = 0; - - - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__, - filep, cmd, arg); - mutex_lock(&mISDN_mutex); - switch (cmd) { - case IMADDTIMER: - if (get_user(tout, (int __user *)arg)) { - ret = -EFAULT; - break; - } - id = misdn_add_timer(dev, tout); - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s add %d id %d\n", __func__, - tout, id); - if (id < 0) { - ret = id; - break; - } - if (put_user(id, (int __user *)arg)) - ret = -EFAULT; - break; - case IMDELTIMER: - if (get_user(id, (int __user *)arg)) { - ret = -EFAULT; - break; - } - if (*debug & DEBUG_TIMER) - printk(KERN_DEBUG "%s del id %d\n", __func__, id); - id = misdn_del_timer(dev, id); - if (put_user(id, (int __user *)arg)) - ret = -EFAULT; - break; - default: - ret = -EINVAL; - } - mutex_unlock(&mISDN_mutex); - return ret; -} - -static const struct file_operations mISDN_fops = { - .owner = THIS_MODULE, - .read = mISDN_read, - .poll = mISDN_poll, - .unlocked_ioctl = mISDN_ioctl, - .open = mISDN_open, - .release = mISDN_close, -}; - -static struct miscdevice mISDNtimer = { - .minor = MISC_DYNAMIC_MINOR, - .name = "mISDNtimer", - .fops = &mISDN_fops, -}; - -int -mISDN_inittimer(u_int *deb) -{ - int err; - - debug = deb; - err = misc_register(&mISDNtimer); - if (err) - printk(KERN_WARNING "mISDN: Could not register timer device\n"); - return err; -} - -void mISDN_timer_cleanup(void) -{ - misc_deregister(&mISDNtimer); -} diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index edaab759dc50..8ec98f6dfef9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -503,8 +503,6 @@ source "drivers/net/arcnet/Kconfig" source "drivers/atm/Kconfig" -source "drivers/net/caif/Kconfig" - source "drivers/net/dsa/Kconfig" source "drivers/net/ethernet/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5b01215f6829..b87a741fc952 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -48,14 +48,12 @@ obj-$(CONFIG_MHI_NET) += mhi_net.o # Networking Drivers # obj-$(CONFIG_ARCNET) += arcnet/ -obj-$(CONFIG_CAIF) += caif/ obj-$(CONFIG_CAN) += can/ ifdef CONFIG_NET_DSA obj-y += dsa/ endif obj-$(CONFIG_ETHERNET) += ethernet/ obj-$(CONFIG_FDDI) += fddi/ -obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_QCOM_IPA) += ipa/ obj-$(CONFIG_PLIP) += plip/ obj-$(CONFIG_PPP) += ppp/ diff --git a/drivers/net/Space.c b/drivers/net/Space.c index c01e2c2f7d6c..305f0a712a64 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -200,24 +200,9 @@ static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe) * look for EISA/PCI cards in addition to ISA cards). */ static struct devprobe2 isa_probes[] __initdata = { -#ifdef CONFIG_3C515 - {tc515_probe, 0}, -#endif -#ifdef CONFIG_ULTRA - {ultra_probe, 0}, -#endif -#ifdef CONFIG_WD80x3 - {wd_probe, 0}, -#endif #if defined(CONFIG_NE2000) /* ISA (use ne2k-pci for PCI cards) */ {ne_probe, 0}, #endif -#ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */ - {lance_probe, 0}, -#endif -#ifdef CONFIG_SMC9194 - {smc_init, 0}, -#endif #ifdef CONFIG_CS89x0_ISA {cs89x0_probe, 0}, #endif diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig deleted file mode 100644 index 709660cb38f8..000000000000 --- a/drivers/net/caif/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# CAIF physical drivers -# - -menuconfig CAIF_DRIVERS - bool "CAIF transport drivers" - depends on CAIF - help - Enable this to see CAIF physical drivers. - -if CAIF_DRIVERS - -config CAIF_TTY - tristate "CAIF TTY transport driver" - depends on CAIF && TTY - default n - help - The CAIF TTY transport driver is a Line Discipline (ldisc) - identified as N_CAIF. When this ldisc is opened from user space - it will redirect the TTY's traffic into the CAIF stack. - -config CAIF_VIRTIO - tristate "CAIF virtio transport driver" - depends on CAIF && HAS_DMA - select VHOST_RING - select VIRTIO - select GENERIC_ALLOCATOR - default n - help - The CAIF driver for CAIF over Virtio. - -endif # CAIF_DRIVERS diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile deleted file mode 100644 index 97f664f8016c..000000000000 --- a/drivers/net/caif/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG - -# Serial interface -obj-$(CONFIG_CAIF_TTY) += caif_serial.o - -# Virtio interface -obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c deleted file mode 100644 index 1873d8287bb9..000000000000 --- a/drivers/net/caif/caif_serial.c +++ /dev/null @@ -1,443 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Sjur Brendeland"); -MODULE_DESCRIPTION("CAIF serial device TTY line discipline"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_CAIF); - -#define SEND_QUEUE_LOW 10 -#define SEND_QUEUE_HIGH 100 -#define CAIF_SENDING 1 /* Bit 1 = 0x02*/ -#define CAIF_FLOW_OFF_SENT 4 /* Bit 4 = 0x10 */ -#define MAX_WRITE_CHUNK 4096 -#define ON 1 -#define OFF 0 -#define CAIF_MAX_MTU 4096 - -static DEFINE_SPINLOCK(ser_lock); -static LIST_HEAD(ser_list); -static LIST_HEAD(ser_release_list); - -static bool ser_loop; -module_param(ser_loop, bool, 0444); -MODULE_PARM_DESC(ser_loop, "Run in simulated loopback mode."); - -static bool ser_use_stx = true; -module_param(ser_use_stx, bool, 0444); -MODULE_PARM_DESC(ser_use_stx, "STX enabled or not."); - -static bool ser_use_fcs = true; - -module_param(ser_use_fcs, bool, 0444); -MODULE_PARM_DESC(ser_use_fcs, "FCS enabled or not."); - -static int ser_write_chunk = MAX_WRITE_CHUNK; -module_param(ser_write_chunk, int, 0444); - -MODULE_PARM_DESC(ser_write_chunk, "Maximum size of data written to UART."); - -static struct dentry *debugfsdir; - -static int caif_net_open(struct net_device *dev); -static int caif_net_close(struct net_device *dev); - -struct ser_device { - struct caif_dev_common common; - struct list_head node; - struct net_device *dev; - struct sk_buff_head head; - struct tty_struct *tty; - bool tx_started; - unsigned long state; -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_tty_dir; - struct debugfs_blob_wrapper tx_blob; - struct debugfs_blob_wrapper rx_blob; - u8 rx_data[128]; - u8 tx_data[128]; - u8 tty_status; - -#endif -}; - -static void caifdev_setup(struct net_device *dev); -static void ldisc_tx_wakeup(struct tty_struct *tty); -#ifdef CONFIG_DEBUG_FS -static inline void update_tty_status(struct ser_device *ser) -{ - ser->tty_status = - ser->tty->flow.stopped << 5 | - ser->tty->flow.tco_stopped << 3 | - ser->tty->ctrl.packet << 2; -} -static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty) -{ - ser->debugfs_tty_dir = debugfs_create_dir(tty->name, debugfsdir); - - debugfs_create_blob("last_tx_msg", 0400, ser->debugfs_tty_dir, - &ser->tx_blob); - - debugfs_create_blob("last_rx_msg", 0400, ser->debugfs_tty_dir, - &ser->rx_blob); - - debugfs_create_xul("ser_state", 0400, ser->debugfs_tty_dir, - &ser->state); - - debugfs_create_x8("tty_status", 0400, ser->debugfs_tty_dir, - &ser->tty_status); - - ser->tx_blob.data = ser->tx_data; - ser->tx_blob.size = 0; - ser->rx_blob.data = ser->rx_data; - ser->rx_blob.size = 0; -} - -static inline void debugfs_deinit(struct ser_device *ser) -{ - debugfs_remove_recursive(ser->debugfs_tty_dir); -} - -static inline void debugfs_rx(struct ser_device *ser, const u8 *data, int size) -{ - if (size > sizeof(ser->rx_data)) - size = sizeof(ser->rx_data); - memcpy(ser->rx_data, data, size); - ser->rx_blob.data = ser->rx_data; - ser->rx_blob.size = size; -} -#else -static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty) -{ -} - -static inline void debugfs_deinit(struct ser_device *ser) -{ -} - -static inline void update_tty_status(struct ser_device *ser) -{ -} - -static inline void debugfs_rx(struct ser_device *ser, const u8 *data, int size) -{ -} -#endif - -static void ldisc_receive(struct tty_struct *tty, const u8 *data, - const u8 *flags, size_t count) -{ - struct sk_buff *skb = NULL; - struct ser_device *ser; - int ret; - - ser = tty->disc_data; - - /* - * NOTE: flags may contain information about break or overrun. - * This is not yet handled. - */ - - - /* - * Workaround for garbage at start of transmission, - * only enable if STX handling is not enabled. - */ - if (!ser->common.use_stx && !ser->tx_started) { - dev_info(&ser->dev->dev, - "Bytes received before initial transmission -" - "bytes discarded.\n"); - return; - } - - BUG_ON(ser->dev == NULL); - - /* Get a suitable caif packet and copy in data. */ - skb = netdev_alloc_skb(ser->dev, count+1); - if (skb == NULL) - return; - skb_put_data(skb, data, count); - - skb->protocol = htons(ETH_P_CAIF); - skb_reset_mac_header(skb); - debugfs_rx(ser, data, count); - /* Push received packet up the stack. */ - ret = netif_rx(skb); - if (!ret) { - ser->dev->stats.rx_packets++; - ser->dev->stats.rx_bytes += count; - } else - ++ser->dev->stats.rx_dropped; - update_tty_status(ser); -} - -static int handle_tx(struct ser_device *ser) -{ - struct tty_struct *tty; - struct sk_buff *skb; - int tty_wr, len, room; - - tty = ser->tty; - ser->tx_started = true; - - /* Enter critical section */ - if (test_and_set_bit(CAIF_SENDING, &ser->state)) - return 0; - - /* skb_peek is safe because handle_tx is called after skb_queue_tail */ - while ((skb = skb_peek(&ser->head)) != NULL) { - - /* Make sure you don't write too much */ - len = skb->len; - room = tty_write_room(tty); - if (!room) - break; - if (room > ser_write_chunk) - room = ser_write_chunk; - if (len > room) - len = room; - - /* Write to tty or loopback */ - if (!ser_loop) { - tty_wr = tty->ops->write(tty, skb->data, len); - update_tty_status(ser); - } else { - tty_wr = len; - ldisc_receive(tty, skb->data, NULL, len); - } - ser->dev->stats.tx_packets++; - ser->dev->stats.tx_bytes += tty_wr; - - /* Error on TTY ?! */ - if (tty_wr < 0) - goto error; - /* Reduce buffer written, and discard if empty */ - skb_pull(skb, tty_wr); - if (skb->len == 0) { - struct sk_buff *tmp = skb_dequeue(&ser->head); - WARN_ON(tmp != skb); - dev_consume_skb_any(skb); - } - } - /* Send flow off if queue is empty */ - if (ser->head.qlen <= SEND_QUEUE_LOW && - test_and_clear_bit(CAIF_FLOW_OFF_SENT, &ser->state) && - ser->common.flowctrl != NULL) - ser->common.flowctrl(ser->dev, ON); - clear_bit(CAIF_SENDING, &ser->state); - return 0; -error: - clear_bit(CAIF_SENDING, &ser->state); - return tty_wr; -} - -static netdev_tx_t caif_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ser_device *ser; - - ser = netdev_priv(dev); - - /* Send flow off once, on high water mark */ - if (ser->head.qlen > SEND_QUEUE_HIGH && - !test_and_set_bit(CAIF_FLOW_OFF_SENT, &ser->state) && - ser->common.flowctrl != NULL) - - ser->common.flowctrl(ser->dev, OFF); - - skb_queue_tail(&ser->head, skb); - return handle_tx(ser); -} - - -static void ldisc_tx_wakeup(struct tty_struct *tty) -{ - struct ser_device *ser; - - ser = tty->disc_data; - BUG_ON(ser == NULL); - WARN_ON(ser->tty != tty); - handle_tx(ser); -} - - -static void ser_release(struct work_struct *work) -{ - struct list_head list; - struct ser_device *ser, *tmp; - struct tty_struct *tty; - - spin_lock(&ser_lock); - list_replace_init(&ser_release_list, &list); - spin_unlock(&ser_lock); - - if (!list_empty(&list)) { - rtnl_lock(); - list_for_each_entry_safe(ser, tmp, &list, node) { - tty = ser->tty; - dev_close(ser->dev); - unregister_netdevice(ser->dev); - debugfs_deinit(ser); - tty_kref_put(tty->link); - tty_kref_put(tty); - } - rtnl_unlock(); - } -} - -static DECLARE_WORK(ser_release_work, ser_release); - -static int ldisc_open(struct tty_struct *tty) -{ - struct ser_device *ser; - struct net_device *dev; - char name[64]; - int result; - - /* No write no play */ - if (tty->ops->write == NULL) - return -EOPNOTSUPP; - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; - - /* release devices to avoid name collision */ - ser_release(NULL); - - result = snprintf(name, sizeof(name), "cf%s", tty->name); - if (result >= IFNAMSIZ) - return -EINVAL; - dev = alloc_netdev(sizeof(*ser), name, NET_NAME_UNKNOWN, - caifdev_setup); - if (!dev) - return -ENOMEM; - - ser = netdev_priv(dev); - ser->tty = tty_kref_get(tty); - tty_kref_get(tty->link); - ser->dev = dev; - debugfs_init(ser, tty); - tty->receive_room = 4096; - tty->disc_data = ser; - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - rtnl_lock(); - result = register_netdevice(dev); - if (result) { - tty_kref_put(tty->link); - tty_kref_put(tty); - rtnl_unlock(); - free_netdev(dev); - return -ENODEV; - } - - spin_lock(&ser_lock); - list_add(&ser->node, &ser_list); - spin_unlock(&ser_lock); - rtnl_unlock(); - netif_stop_queue(dev); - update_tty_status(ser); - return 0; -} - -static void ldisc_close(struct tty_struct *tty) -{ - struct ser_device *ser = tty->disc_data; - - spin_lock(&ser_lock); - list_move(&ser->node, &ser_release_list); - spin_unlock(&ser_lock); - schedule_work(&ser_release_work); -} - -/* The line discipline structure. */ -static struct tty_ldisc_ops caif_ldisc = { - .owner = THIS_MODULE, - .num = N_CAIF, - .name = "n_caif", - .open = ldisc_open, - .close = ldisc_close, - .receive_buf = ldisc_receive, - .write_wakeup = ldisc_tx_wakeup -}; - -static const struct net_device_ops netdev_ops = { - .ndo_open = caif_net_open, - .ndo_stop = caif_net_close, - .ndo_start_xmit = caif_xmit -}; - -static void caifdev_setup(struct net_device *dev) -{ - struct ser_device *serdev = netdev_priv(dev); - - dev->features = 0; - dev->netdev_ops = &netdev_ops; - dev->type = ARPHRD_CAIF; - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - dev->mtu = CAIF_MAX_MTU; - dev->priv_flags |= IFF_NO_QUEUE; - dev->needs_free_netdev = true; - skb_queue_head_init(&serdev->head); - serdev->common.link_select = CAIF_LINK_LOW_LATENCY; - serdev->common.use_frag = true; - serdev->common.use_stx = ser_use_stx; - serdev->common.use_fcs = ser_use_fcs; - serdev->dev = dev; -} - - -static int caif_net_open(struct net_device *dev) -{ - netif_wake_queue(dev); - return 0; -} - -static int caif_net_close(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -static int __init caif_ser_init(void) -{ - int ret; - - ret = tty_register_ldisc(&caif_ldisc); - if (ret < 0) - pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF, ret); - - debugfsdir = debugfs_create_dir("caif_serial", NULL); - return ret; -} - -static void __exit caif_ser_exit(void) -{ - spin_lock(&ser_lock); - list_splice(&ser_list, &ser_release_list); - spin_unlock(&ser_lock); - ser_release(NULL); - cancel_work_sync(&ser_release_work); - tty_unregister_ldisc(&caif_ldisc); - debugfs_remove_recursive(debugfsdir); -} - -module_init(caif_ser_init); -module_exit(caif_ser_exit); diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c deleted file mode 100644 index 8ac1a4b8e055..000000000000 --- a/drivers/net/caif/caif_virtio.c +++ /dev/null @@ -1,791 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2013 - * Authors: Vicram Arv - * Dmitry Tarnyagin - * Sjur Brendeland - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Vicram Arv"); -MODULE_AUTHOR("Sjur Brendeland"); -MODULE_DESCRIPTION("Virtio CAIF Driver"); - -/* NAPI schedule quota */ -#define CFV_DEFAULT_QUOTA 32 - -/* Defaults used if virtio config space is unavailable */ -#define CFV_DEF_MTU_SIZE 4096 -#define CFV_DEF_HEADROOM 32 -#define CFV_DEF_TAILROOM 32 - -/* Required IP header alignment */ -#define IP_HDR_ALIGN 4 - -/* struct cfv_napi_contxt - NAPI context info - * @riov: IOV holding data read from the ring. Note that riov may - * still hold data when cfv_rx_poll() returns. - * @head: Last descriptor ID we received from vringh_getdesc_kern. - * We use this to put descriptor back on the used ring. USHRT_MAX is - * used to indicate invalid head-id. - */ -struct cfv_napi_context { - struct vringh_kiov riov; - unsigned short head; -}; - -/* struct cfv_stats - statistics for debugfs - * @rx_napi_complete: Number of NAPI completions (RX) - * @rx_napi_resched: Number of calls where the full quota was used (RX) - * @rx_nomem: Number of SKB alloc failures (RX) - * @rx_kicks: Number of RX kicks - * @tx_full_ring: Number times TX ring was full - * @tx_no_mem: Number of times TX went out of memory - * @tx_flow_on: Number of flow on (TX) - * @tx_kicks: Number of TX kicks - */ -struct cfv_stats { - u32 rx_napi_complete; - u32 rx_napi_resched; - u32 rx_nomem; - u32 rx_kicks; - u32 tx_full_ring; - u32 tx_no_mem; - u32 tx_flow_on; - u32 tx_kicks; -}; - -/* struct cfv_info - Caif Virtio control structure - * @cfdev: caif common header - * @vdev: Associated virtio device - * @vr_rx: rx/downlink host vring - * @vq_tx: tx/uplink virtqueue - * @ndev: CAIF link layer device - * @watermark_tx: indicates number of free descriptors we need - * to reopen the tx-queues after overload. - * @tx_lock: protects vq_tx from concurrent use - * @tx_release_tasklet: Tasklet for freeing consumed TX buffers - * @napi: Napi context used in cfv_rx_poll() - * @ctx: Context data used in cfv_rx_poll() - * @tx_hr: transmit headroom - * @rx_hr: receive headroom - * @tx_tr: transmit tail room - * @rx_tr: receive tail room - * @mtu: transmit max size - * @mru: receive max size - * @allocsz: size of dma memory reserved for TX buffers - * @alloc_addr: virtual address to dma memory for TX buffers - * @alloc_dma: dma address to dma memory for TX buffers - * @genpool: Gen Pool used for allocating TX buffers - * @reserved_mem: Pointer to memory reserve allocated from genpool - * @reserved_size: Size of memory reserve allocated from genpool - * @stats: Statistics exposed in sysfs - * @debugfs: Debugfs dentry for statistic counters - */ -struct cfv_info { - struct caif_dev_common cfdev; - struct virtio_device *vdev; - struct vringh *vr_rx; - struct virtqueue *vq_tx; - struct net_device *ndev; - unsigned int watermark_tx; - /* Protect access to vq_tx */ - spinlock_t tx_lock; - struct tasklet_struct tx_release_tasklet; - struct napi_struct napi; - struct cfv_napi_context ctx; - u16 tx_hr; - u16 rx_hr; - u16 tx_tr; - u16 rx_tr; - u32 mtu; - u32 mru; - size_t allocsz; - void *alloc_addr; - dma_addr_t alloc_dma; - struct gen_pool *genpool; - unsigned long reserved_mem; - size_t reserved_size; - struct cfv_stats stats; - struct dentry *debugfs; -}; - -/* struct buf_info - maintains transmit buffer data handle - * @size: size of transmit buffer - * @dma_handle: handle to allocated dma device memory area - * @vaddr: virtual address mapping to allocated memory area - */ -struct buf_info { - size_t size; - u8 *vaddr; -}; - -/* Called from virtio device, in IRQ context */ -static void cfv_release_cb(struct virtqueue *vq_tx) -{ - struct cfv_info *cfv = vq_tx->vdev->priv; - - ++cfv->stats.tx_kicks; - tasklet_schedule(&cfv->tx_release_tasklet); -} - -static void free_buf_info(struct cfv_info *cfv, struct buf_info *buf_info) -{ - if (!buf_info) - return; - gen_pool_free(cfv->genpool, (unsigned long) buf_info->vaddr, - buf_info->size); - kfree(buf_info); -} - -/* This is invoked whenever the remote processor completed processing - * a TX msg we just sent, and the buffer is put back to the used ring. - */ -static void cfv_release_used_buf(struct virtqueue *vq_tx) -{ - struct cfv_info *cfv = vq_tx->vdev->priv; - unsigned long flags; - - BUG_ON(vq_tx != cfv->vq_tx); - - for (;;) { - unsigned int len; - struct buf_info *buf_info; - - /* Get used buffer from used ring to recycle used descriptors */ - spin_lock_irqsave(&cfv->tx_lock, flags); - buf_info = virtqueue_get_buf(vq_tx, &len); - spin_unlock_irqrestore(&cfv->tx_lock, flags); - - /* Stop looping if there are no more buffers to free */ - if (!buf_info) - break; - - free_buf_info(cfv, buf_info); - - /* watermark_tx indicates if we previously stopped the tx - * queues. If we have enough free stots in the virtio ring, - * re-establish memory reserved and open up tx queues. - */ - if (cfv->vq_tx->num_free <= cfv->watermark_tx) - continue; - - /* Re-establish memory reserve */ - if (cfv->reserved_mem == 0 && cfv->genpool) - cfv->reserved_mem = - gen_pool_alloc(cfv->genpool, - cfv->reserved_size); - - /* Open up the tx queues */ - if (cfv->reserved_mem) { - cfv->watermark_tx = - virtqueue_get_vring_size(cfv->vq_tx); - netif_tx_wake_all_queues(cfv->ndev); - /* Buffers are recycled in cfv_netdev_tx, so - * disable notifications when queues are opened. - */ - virtqueue_disable_cb(cfv->vq_tx); - ++cfv->stats.tx_flow_on; - } else { - /* if no memory reserve, wait for more free slots */ - WARN_ON(cfv->watermark_tx > - virtqueue_get_vring_size(cfv->vq_tx)); - cfv->watermark_tx += - virtqueue_get_vring_size(cfv->vq_tx) / 4; - } - } -} - -/* Allocate a SKB and copy packet data to it */ -static struct sk_buff *cfv_alloc_and_copy_skb(int *err, - struct cfv_info *cfv, - u8 *frm, u32 frm_len) -{ - struct sk_buff *skb; - u32 cfpkt_len, pad_len; - - *err = 0; - /* Verify that packet size with down-link header and mtu size */ - if (frm_len > cfv->mru || frm_len <= cfv->rx_hr + cfv->rx_tr) { - netdev_err(cfv->ndev, - "Invalid frmlen:%u mtu:%u hr:%d tr:%d\n", - frm_len, cfv->mru, cfv->rx_hr, - cfv->rx_tr); - *err = -EPROTO; - return NULL; - } - - cfpkt_len = frm_len - (cfv->rx_hr + cfv->rx_tr); - pad_len = (unsigned long)(frm + cfv->rx_hr) & (IP_HDR_ALIGN - 1); - - skb = netdev_alloc_skb(cfv->ndev, frm_len + pad_len); - if (!skb) { - *err = -ENOMEM; - return NULL; - } - - skb_reserve(skb, cfv->rx_hr + pad_len); - - skb_put_data(skb, frm + cfv->rx_hr, cfpkt_len); - return skb; -} - -/* Get packets from the host vring */ -static int cfv_rx_poll(struct napi_struct *napi, int quota) -{ - struct cfv_info *cfv = container_of(napi, struct cfv_info, napi); - int rxcnt = 0; - int err = 0; - void *buf; - struct sk_buff *skb; - struct vringh_kiov *riov = &cfv->ctx.riov; - unsigned int skb_len; - - do { - skb = NULL; - - /* Put the previous iovec back on the used ring and - * fetch a new iovec if we have processed all elements. - */ - if (riov->i == riov->used) { - if (cfv->ctx.head != USHRT_MAX) { - vringh_complete_kern(cfv->vr_rx, - cfv->ctx.head, - 0); - cfv->ctx.head = USHRT_MAX; - } - - err = vringh_getdesc_kern( - cfv->vr_rx, - riov, - NULL, - &cfv->ctx.head, - GFP_ATOMIC); - - if (err <= 0) - goto exit; - } - - buf = phys_to_virt((unsigned long) riov->iov[riov->i].iov_base); - /* TODO: Add check on valid buffer address */ - - skb = cfv_alloc_and_copy_skb(&err, cfv, buf, - riov->iov[riov->i].iov_len); - if (unlikely(err)) - goto exit; - - /* Push received packet up the stack. */ - skb_len = skb->len; - skb->protocol = htons(ETH_P_CAIF); - skb_reset_mac_header(skb); - skb->dev = cfv->ndev; - err = netif_receive_skb(skb); - if (unlikely(err)) { - ++cfv->ndev->stats.rx_dropped; - } else { - ++cfv->ndev->stats.rx_packets; - cfv->ndev->stats.rx_bytes += skb_len; - } - - ++riov->i; - ++rxcnt; - } while (rxcnt < quota); - - ++cfv->stats.rx_napi_resched; - goto out; - -exit: - switch (err) { - case 0: - ++cfv->stats.rx_napi_complete; - - /* Really out of packets? (stolen from virtio_net)*/ - napi_complete(napi); - if (unlikely(!vringh_notify_enable_kern(cfv->vr_rx)) && - napi_schedule_prep(napi)) { - vringh_notify_disable_kern(cfv->vr_rx); - __napi_schedule(napi); - } - break; - - case -ENOMEM: - ++cfv->stats.rx_nomem; - dev_kfree_skb(skb); - /* Stop NAPI poll on OOM, we hope to be polled later */ - napi_complete(napi); - vringh_notify_enable_kern(cfv->vr_rx); - break; - - default: - /* We're doomed, any modem fault is fatal */ - netdev_warn(cfv->ndev, "Bad ring, disable device\n"); - cfv->ndev->stats.rx_dropped = riov->used - riov->i; - napi_complete(napi); - vringh_notify_disable_kern(cfv->vr_rx); - netif_carrier_off(cfv->ndev); - break; - } -out: - if (rxcnt && vringh_need_notify_kern(cfv->vr_rx) > 0) - vringh_notify(cfv->vr_rx); - return rxcnt; -} - -static void cfv_recv(struct virtio_device *vdev, struct vringh *vr_rx) -{ - struct cfv_info *cfv = vdev->priv; - - ++cfv->stats.rx_kicks; - vringh_notify_disable_kern(cfv->vr_rx); - napi_schedule(&cfv->napi); -} - -static void cfv_destroy_genpool(struct cfv_info *cfv) -{ - if (cfv->alloc_addr) - dma_free_coherent(cfv->vdev->dev.parent->parent, - cfv->allocsz, cfv->alloc_addr, - cfv->alloc_dma); - - if (!cfv->genpool) - return; - gen_pool_free(cfv->genpool, cfv->reserved_mem, - cfv->reserved_size); - gen_pool_destroy(cfv->genpool); - cfv->genpool = NULL; -} - -static int cfv_create_genpool(struct cfv_info *cfv) -{ - int err; - - /* dma_alloc can only allocate whole pages, and we need a more - * fine graned allocation so we use genpool. We ask for space needed - * by IP and a full ring. If the dma allcoation fails we retry with a - * smaller allocation size. - */ - err = -ENOMEM; - cfv->allocsz = (virtqueue_get_vring_size(cfv->vq_tx) * - (ETH_DATA_LEN + cfv->tx_hr + cfv->tx_tr) * 11)/10; - if (cfv->allocsz <= (num_possible_cpus() + 1) * cfv->ndev->mtu) - return -EINVAL; - - for (;;) { - if (cfv->allocsz <= num_possible_cpus() * cfv->ndev->mtu) { - netdev_info(cfv->ndev, "Not enough device memory\n"); - return -ENOMEM; - } - - cfv->alloc_addr = dma_alloc_coherent( - cfv->vdev->dev.parent->parent, - cfv->allocsz, &cfv->alloc_dma, - GFP_ATOMIC); - if (cfv->alloc_addr) - break; - - cfv->allocsz = (cfv->allocsz * 3) >> 2; - } - - netdev_dbg(cfv->ndev, "Allocated %zd bytes from dma-memory\n", - cfv->allocsz); - - /* Allocate on 128 bytes boundaries (1 << 7)*/ - cfv->genpool = gen_pool_create(7, -1); - if (!cfv->genpool) - goto err; - - err = gen_pool_add_virt(cfv->genpool, (unsigned long)cfv->alloc_addr, - (phys_addr_t)virt_to_phys(cfv->alloc_addr), - cfv->allocsz, -1); - if (err) - goto err; - - /* Reserve some memory for low memory situations. If we hit the roof - * in the memory pool, we stop TX flow and release the reserve. - */ - cfv->reserved_size = num_possible_cpus() * cfv->ndev->mtu; - cfv->reserved_mem = gen_pool_alloc(cfv->genpool, - cfv->reserved_size); - if (!cfv->reserved_mem) { - err = -ENOMEM; - goto err; - } - - cfv->watermark_tx = virtqueue_get_vring_size(cfv->vq_tx); - return 0; -err: - cfv_destroy_genpool(cfv); - return err; -} - -/* Enable the CAIF interface and allocate the memory-pool */ -static int cfv_netdev_open(struct net_device *netdev) -{ - struct cfv_info *cfv = netdev_priv(netdev); - - if (cfv_create_genpool(cfv)) - return -ENOMEM; - - netif_carrier_on(netdev); - napi_enable(&cfv->napi); - - /* Schedule NAPI to read any pending packets */ - napi_schedule(&cfv->napi); - return 0; -} - -/* Disable the CAIF interface and free the memory-pool */ -static int cfv_netdev_close(struct net_device *netdev) -{ - struct cfv_info *cfv = netdev_priv(netdev); - unsigned long flags; - struct buf_info *buf_info; - - /* Disable interrupts, queues and NAPI polling */ - netif_carrier_off(netdev); - virtqueue_disable_cb(cfv->vq_tx); - vringh_notify_disable_kern(cfv->vr_rx); - napi_disable(&cfv->napi); - - /* Release any TX buffers on both used and available rings */ - cfv_release_used_buf(cfv->vq_tx); - spin_lock_irqsave(&cfv->tx_lock, flags); - while ((buf_info = virtqueue_detach_unused_buf(cfv->vq_tx))) - free_buf_info(cfv, buf_info); - spin_unlock_irqrestore(&cfv->tx_lock, flags); - - /* Release all dma allocated memory and destroy the pool */ - cfv_destroy_genpool(cfv); - return 0; -} - -/* Allocate a buffer in dma-memory and copy skb to it */ -static struct buf_info *cfv_alloc_and_copy_to_shm(struct cfv_info *cfv, - struct sk_buff *skb, - struct scatterlist *sg) -{ - struct caif_payload_info *info = (void *)&skb->cb; - struct buf_info *buf_info = NULL; - u8 pad_len, hdr_ofs; - - if (!cfv->genpool) - goto err; - - if (unlikely(cfv->tx_hr + skb->len + cfv->tx_tr > cfv->mtu)) { - netdev_warn(cfv->ndev, "Invalid packet len (%d > %d)\n", - cfv->tx_hr + skb->len + cfv->tx_tr, cfv->mtu); - goto err; - } - - buf_info = kmalloc_obj(struct buf_info, GFP_ATOMIC); - if (unlikely(!buf_info)) - goto err; - - /* Make the IP header aligned in the buffer */ - hdr_ofs = cfv->tx_hr + info->hdr_len; - pad_len = hdr_ofs & (IP_HDR_ALIGN - 1); - buf_info->size = cfv->tx_hr + skb->len + cfv->tx_tr + pad_len; - - /* allocate dma memory buffer */ - buf_info->vaddr = (void *)gen_pool_alloc(cfv->genpool, buf_info->size); - if (unlikely(!buf_info->vaddr)) - goto err; - - /* copy skbuf contents to send buffer */ - skb_copy_bits(skb, 0, buf_info->vaddr + cfv->tx_hr + pad_len, skb->len); - sg_init_one(sg, buf_info->vaddr + pad_len, - skb->len + cfv->tx_hr + cfv->rx_hr); - - return buf_info; -err: - kfree(buf_info); - return NULL; -} - -/* Put the CAIF packet on the virtio ring and kick the receiver */ -static netdev_tx_t cfv_netdev_tx(struct sk_buff *skb, struct net_device *netdev) -{ - struct cfv_info *cfv = netdev_priv(netdev); - struct buf_info *buf_info; - struct scatterlist sg; - unsigned long flags; - bool flow_off = false; - int ret; - - /* garbage collect released buffers */ - cfv_release_used_buf(cfv->vq_tx); - spin_lock_irqsave(&cfv->tx_lock, flags); - - /* Flow-off check takes into account number of cpus to make sure - * virtqueue will not be overfilled in any possible smp conditions. - * - * Flow-on is triggered when sufficient buffers are freed - */ - if (unlikely(cfv->vq_tx->num_free <= num_present_cpus())) { - flow_off = true; - cfv->stats.tx_full_ring++; - } - - /* If we run out of memory, we release the memory reserve and retry - * allocation. - */ - buf_info = cfv_alloc_and_copy_to_shm(cfv, skb, &sg); - if (unlikely(!buf_info)) { - cfv->stats.tx_no_mem++; - flow_off = true; - - if (cfv->reserved_mem && cfv->genpool) { - gen_pool_free(cfv->genpool, cfv->reserved_mem, - cfv->reserved_size); - cfv->reserved_mem = 0; - buf_info = cfv_alloc_and_copy_to_shm(cfv, skb, &sg); - } - } - - if (unlikely(flow_off)) { - /* Turn flow on when a 1/4 of the descriptors are released */ - cfv->watermark_tx = virtqueue_get_vring_size(cfv->vq_tx) / 4; - /* Enable notifications of recycled TX buffers */ - virtqueue_enable_cb(cfv->vq_tx); - netif_tx_stop_all_queues(netdev); - } - - if (unlikely(!buf_info)) { - /* If the memory reserve does it's job, this shouldn't happen */ - netdev_warn(cfv->ndev, "Out of gen_pool memory\n"); - goto err; - } - - ret = virtqueue_add_outbuf(cfv->vq_tx, &sg, 1, buf_info, GFP_ATOMIC); - if (unlikely((ret < 0))) { - /* If flow control works, this shouldn't happen */ - netdev_warn(cfv->ndev, "Failed adding buffer to TX vring:%d\n", - ret); - goto err; - } - - /* update netdev statistics */ - cfv->ndev->stats.tx_packets++; - cfv->ndev->stats.tx_bytes += skb->len; - spin_unlock_irqrestore(&cfv->tx_lock, flags); - - /* tell the remote processor it has a pending message to read */ - virtqueue_kick(cfv->vq_tx); - - dev_kfree_skb(skb); - return NETDEV_TX_OK; -err: - spin_unlock_irqrestore(&cfv->tx_lock, flags); - cfv->ndev->stats.tx_dropped++; - free_buf_info(cfv, buf_info); - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static void cfv_tx_release_tasklet(struct tasklet_struct *t) -{ - struct cfv_info *cfv = from_tasklet(cfv, t, tx_release_tasklet); - cfv_release_used_buf(cfv->vq_tx); -} - -static const struct net_device_ops cfv_netdev_ops = { - .ndo_open = cfv_netdev_open, - .ndo_stop = cfv_netdev_close, - .ndo_start_xmit = cfv_netdev_tx, -}; - -static void cfv_netdev_setup(struct net_device *netdev) -{ - netdev->netdev_ops = &cfv_netdev_ops; - netdev->type = ARPHRD_CAIF; - netdev->tx_queue_len = 100; - netdev->flags = IFF_POINTOPOINT | IFF_NOARP; - netdev->mtu = CFV_DEF_MTU_SIZE; - netdev->needs_free_netdev = true; -} - -/* Create debugfs counters for the device */ -static inline void debugfs_init(struct cfv_info *cfv) -{ - cfv->debugfs = debugfs_create_dir(netdev_name(cfv->ndev), NULL); - - debugfs_create_u32("rx-napi-complete", 0400, cfv->debugfs, - &cfv->stats.rx_napi_complete); - debugfs_create_u32("rx-napi-resched", 0400, cfv->debugfs, - &cfv->stats.rx_napi_resched); - debugfs_create_u32("rx-nomem", 0400, cfv->debugfs, - &cfv->stats.rx_nomem); - debugfs_create_u32("rx-kicks", 0400, cfv->debugfs, - &cfv->stats.rx_kicks); - debugfs_create_u32("tx-full-ring", 0400, cfv->debugfs, - &cfv->stats.tx_full_ring); - debugfs_create_u32("tx-no-mem", 0400, cfv->debugfs, - &cfv->stats.tx_no_mem); - debugfs_create_u32("tx-kicks", 0400, cfv->debugfs, - &cfv->stats.tx_kicks); - debugfs_create_u32("tx-flow-on", 0400, cfv->debugfs, - &cfv->stats.tx_flow_on); -} - -/* Setup CAIF for the a virtio device */ -static int cfv_probe(struct virtio_device *vdev) -{ - vrh_callback_t *vrh_cbs = cfv_recv; - const char *cfv_netdev_name = "cfvrt"; - struct net_device *netdev; - struct cfv_info *cfv; - int err; - - netdev = alloc_netdev(sizeof(struct cfv_info), cfv_netdev_name, - NET_NAME_UNKNOWN, cfv_netdev_setup); - if (!netdev) - return -ENOMEM; - - cfv = netdev_priv(netdev); - cfv->vdev = vdev; - cfv->ndev = netdev; - - spin_lock_init(&cfv->tx_lock); - - /* Get the RX virtio ring. This is a "host side vring". */ - err = -ENODEV; - if (!vdev->vringh_config || !vdev->vringh_config->find_vrhs) - goto err; - - err = vdev->vringh_config->find_vrhs(vdev, 1, &cfv->vr_rx, &vrh_cbs); - if (err) - goto err; - - /* Get the TX virtio ring. This is a "guest side vring". */ - cfv->vq_tx = virtio_find_single_vq(vdev, cfv_release_cb, "output"); - if (IS_ERR(cfv->vq_tx)) { - err = PTR_ERR(cfv->vq_tx); - goto err; - } - - /* Get the CAIF configuration from virtio config space, if available */ - if (vdev->config->get) { - virtio_cread(vdev, struct virtio_caif_transf_config, headroom, - &cfv->tx_hr); - virtio_cread(vdev, struct virtio_caif_transf_config, headroom, - &cfv->rx_hr); - virtio_cread(vdev, struct virtio_caif_transf_config, tailroom, - &cfv->tx_tr); - virtio_cread(vdev, struct virtio_caif_transf_config, tailroom, - &cfv->rx_tr); - virtio_cread(vdev, struct virtio_caif_transf_config, mtu, - &cfv->mtu); - virtio_cread(vdev, struct virtio_caif_transf_config, mtu, - &cfv->mru); - } else { - cfv->tx_hr = CFV_DEF_HEADROOM; - cfv->rx_hr = CFV_DEF_HEADROOM; - cfv->tx_tr = CFV_DEF_TAILROOM; - cfv->rx_tr = CFV_DEF_TAILROOM; - cfv->mtu = CFV_DEF_MTU_SIZE; - cfv->mru = CFV_DEF_MTU_SIZE; - } - - netdev->needed_headroom = cfv->tx_hr; - netdev->needed_tailroom = cfv->tx_tr; - - /* Disable buffer release interrupts unless we have stopped TX queues */ - virtqueue_disable_cb(cfv->vq_tx); - - netdev->mtu = cfv->mtu - cfv->tx_tr; - vdev->priv = cfv; - - /* Initialize NAPI poll context data */ - vringh_kiov_init(&cfv->ctx.riov, NULL, 0); - cfv->ctx.head = USHRT_MAX; - netif_napi_add_weight(netdev, &cfv->napi, cfv_rx_poll, - CFV_DEFAULT_QUOTA); - - tasklet_setup(&cfv->tx_release_tasklet, cfv_tx_release_tasklet); - - /* Carrier is off until netdevice is opened */ - netif_carrier_off(netdev); - - /* serialize netdev register + virtio_device_ready() with ndo_open() */ - rtnl_lock(); - - /* register Netdev */ - err = register_netdevice(netdev); - if (err) { - rtnl_unlock(); - dev_err(&vdev->dev, "Unable to register netdev (%d)\n", err); - goto err; - } - - virtio_device_ready(vdev); - - rtnl_unlock(); - - debugfs_init(cfv); - - return 0; -err: - netdev_warn(cfv->ndev, "CAIF Virtio probe failed:%d\n", err); - - if (cfv->vr_rx) - vdev->vringh_config->del_vrhs(cfv->vdev); - if (cfv->vq_tx) - vdev->config->del_vqs(cfv->vdev); - free_netdev(netdev); - return err; -} - -static void cfv_remove(struct virtio_device *vdev) -{ - struct cfv_info *cfv = vdev->priv; - - rtnl_lock(); - dev_close(cfv->ndev); - rtnl_unlock(); - - tasklet_kill(&cfv->tx_release_tasklet); - debugfs_remove_recursive(cfv->debugfs); - - vringh_kiov_cleanup(&cfv->ctx.riov); - virtio_reset_device(vdev); - vdev->vringh_config->del_vrhs(cfv->vdev); - cfv->vr_rx = NULL; - vdev->config->del_vqs(cfv->vdev); - unregister_netdev(cfv->ndev); -} - -static struct virtio_device_id id_table[] = { - { VIRTIO_ID_CAIF, VIRTIO_DEV_ANY_ID }, - { 0 }, -}; - -static unsigned int features[] = { -}; - -static struct virtio_driver caif_virtio_driver = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), - .driver.name = KBUILD_MODNAME, - .id_table = id_table, - .probe = cfv_probe, - .remove = cfv_remove, -}; - -module_virtio_driver(caif_virtio_driver); -MODULE_DEVICE_TABLE(virtio, id_table); diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c deleted file mode 100644 index fb68339e1511..000000000000 --- a/drivers/net/ethernet/3com/3c509.c +++ /dev/null @@ -1,1448 +0,0 @@ -/* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ -/* - Written 1993-2000 by Donald Becker. - - Copyright 1994-2000 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may be used and - distributed according to the terms of the GNU General Public License, - incorporated herein by reference. - - This driver is for the 3Com EtherLinkIII series. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Known limitations: - Because of the way 3c509 ISA detection works it's difficult to predict - a priori which of several ISA-mode cards will be detected first. - - This driver does not use predictive interrupt mode, resulting in higher - packet latency but lower overhead. If interrupts are disabled for an - unusually long time it could also result in missed packets, but in - practice this rarely happens. - - - FIXES: - Alan Cox: Removed the 'Unexpected interrupt' bug. - Michael Meskes: Upgraded to Donald Becker's version 1.07. - Alan Cox: Increased the eeprom delay. Regardless of - what the docs say some people definitely - get problems with lower (but in card spec) - delays - v1.10 4/21/97 Fixed module code so that multiple cards may be detected, - other cleanups. -djb - Andrea Arcangeli: Upgraded to Donald Becker's version 1.12. - Rick Payne: Fixed SMP race condition - v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb - v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb - v1.15 1/31/98 Faster recovery for Tx errors. -djb - v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb - v1.18 12Mar2001 Andrew Morton - - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz) - - Reviewed against 1.18 from scyld.com - v1.18a 17Nov2001 Jeff Garzik - - ethtool support - v1.18b 1Mar2002 Zwane Mwaikambo - - Power Management support - v1.18c 1Mar2002 David Ruggiero - - Full duplex support - v1.19 16Oct2002 Zwane Mwaikambo - - Additional ethtool features - v1.19a 28Oct2002 Davud Ruggiero - - Increase *read_eeprom udelay to workaround oops with 2 cards. - v1.19b 08Nov2002 Marc Zyngier - - Introduce driver model for EISA cards. - v1.20 04Feb2008 Ondrej Zary - - convert to isa_driver and pnp_driver and some cleanups -*/ - -#define DRV_NAME "3c509" - -/* A few values that may be tweaked. */ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (400*HZ/1000) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for udelay() */ -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef EL3_DEBUG -static int el3_debug = EL3_DEBUG; -#else -static int el3_debug = 2; -#endif - -/* Used to do a global count of all the cards in the system. Must be - * a global variable so that the eisa probe routines can increment - * it */ -static int el3_cards = 0; -#define EL3_MAX_CARDS 8 - -/* To minimize the size of the driver source I only define operating - constants if they are used several times. You'll need the manual - anyway if you want to understand driver details. */ -/* Offsets from base I/O address. */ -#define EL3_DATA 0x00 -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e -#define EEPROM_READ 0x80 - -#define EL3_IO_EXTENT 16 - -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) - - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. */ -enum c509cmd { - TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, - RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11, - TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, - FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, - SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, - SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11, - StatsDisable = 22<<11, StopCoax = 23<<11, PowerUp = 27<<11, - PowerDown = 28<<11, PowerAuto = 29<<11}; - -enum c509status { - IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, - TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, - IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000, }; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 }; - -/* Register window 1 offsets, the window used in normal operation. */ -#define TX_FIFO 0x00 -#define RX_FIFO 0x00 -#define RX_STATUS 0x08 -#define TX_STATUS 0x0B -#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ - -#define WN0_CONF_CTRL 0x04 /* Window 0: Configuration control register */ -#define WN0_ADDR_CONF 0x06 /* Window 0: Address configuration register */ -#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ -#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ -#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ -#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ - -/* - * Must be a power of two (we use a binary and in the - * circular queue) - */ -#define SKB_QUEUE_SIZE 64 - -enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_EISA }; - -struct el3_private { - spinlock_t lock; - /* skb send-queue */ - int head, size; - struct sk_buff *queue[SKB_QUEUE_SIZE]; - enum el3_cardtype type; -}; -static int id_port; -static int current_tag; -static struct net_device *el3_devs[EL3_MAX_CARDS]; - -/* Parameters that may be passed into the module. */ -static int debug = -1; -static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 10; -#ifdef CONFIG_PNP -static int nopnp; -#endif - -static int el3_common_init(struct net_device *dev); -static void el3_common_remove(struct net_device *dev); -static ushort id_read_eeprom(int index); -static ushort read_eeprom(int ioaddr, int index); -static int el3_open(struct net_device *dev); -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id); -static void update_stats(struct net_device *dev); -static struct net_device_stats *el3_get_stats(struct net_device *dev); -static int el3_rx(struct net_device *dev); -static int el3_close(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void el3_tx_timeout (struct net_device *dev, unsigned int txqueue); -static void el3_down(struct net_device *dev); -static void el3_up(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; -#ifdef CONFIG_PM -static int el3_suspend(struct device *, pm_message_t); -static int el3_resume(struct device *); -#else -#define el3_suspend NULL -#define el3_resume NULL -#endif - - -/* generic device remove for all device types */ -static int el3_device_remove (struct device *device); -#ifdef CONFIG_NET_POLL_CONTROLLER -static void el3_poll_controller(struct net_device *dev); -#endif - -/* Return 0 on success, 1 on error, 2 when found already detected PnP card */ -static int el3_isa_id_sequence(__be16 *phys_addr) -{ - short lrs_state = 0xff; - int i; - - /* ISA boards are detected by sending the ID sequence to the - ID_PORT. We find cards past the first by setting the 'current_tag' - on cards as they are found. Cards with their tag set will not - respond to subsequent ID sequences. */ - - outb(0x00, id_port); - outb(0x00, id_port); - for (i = 0; i < 255; i++) { - outb(lrs_state, id_port); - lrs_state <<= 1; - lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; - } - /* For the first probe, clear all board's tag registers. */ - if (current_tag == 0) - outb(0xd0, id_port); - else /* Otherwise kill off already-found boards. */ - outb(0xd8, id_port); - if (id_read_eeprom(7) != 0x6d50) - return 1; - /* Read in EEPROM data, which does contention-select. - Only the lowest address board will stay "on-line". - 3Com got the byte order backwards. */ - for (i = 0; i < 3; i++) - phys_addr[i] = htons(id_read_eeprom(i)); -#ifdef CONFIG_PNP - if (!nopnp) { - /* The ISA PnP 3c509 cards respond to the ID sequence too. - This check is needed in order not to register them twice. */ - for (i = 0; i < el3_cards; i++) { - struct el3_private *lp = netdev_priv(el3_devs[i]); - if (lp->type == EL3_PNP && - ether_addr_equal((u8 *)phys_addr, el3_devs[i]->dev_addr)) { - if (el3_debug > 3) - pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", - phys_addr[0] & 0xff, phys_addr[0] >> 8, - phys_addr[1] & 0xff, phys_addr[1] >> 8, - phys_addr[2] & 0xff, phys_addr[2] >> 8); - /* Set the adaptor tag so that the next card can be found. */ - outb(0xd0 + ++current_tag, id_port); - return 2; - } - } - } -#endif /* CONFIG_PNP */ - return 0; - -} - -static void el3_dev_fill(struct net_device *dev, __be16 *phys_addr, int ioaddr, - int irq, int if_port, enum el3_cardtype type) -{ - struct el3_private *lp = netdev_priv(dev); - - eth_hw_addr_set(dev, (u8 *)phys_addr); - dev->base_addr = ioaddr; - dev->irq = irq; - dev->if_port = if_port; - lp->type = type; -} - -static int el3_isa_match(struct device *pdev, unsigned int ndev) -{ - struct net_device *dev; - int ioaddr, isa_irq, if_port, err; - unsigned int iobase; - __be16 phys_addr[3]; - - while ((err = el3_isa_id_sequence(phys_addr)) == 2) - ; /* Skip to next card when PnP card found */ - if (err == 1) - return 0; - - iobase = id_read_eeprom(8); - if_port = iobase >> 14; - ioaddr = 0x200 + ((iobase & 0x1f) << 4); - if (irq[el3_cards] > 1 && irq[el3_cards] < 16) - isa_irq = irq[el3_cards]; - else - isa_irq = id_read_eeprom(9) >> 12; - - dev = alloc_etherdev(sizeof(struct el3_private)); - if (!dev) - return -ENOMEM; - - SET_NETDEV_DEV(dev, pdev); - - if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) { - free_netdev(dev); - return 0; - } - - /* Set the adaptor tag so that the next card can be found. */ - outb(0xd0 + ++current_tag, id_port); - - /* Activate the adaptor at the EEPROM location. */ - outb((ioaddr >> 4) | 0xe0, id_port); - - EL3WINDOW(0); - if (inw(ioaddr) != 0x6d50) { - free_netdev(dev); - return 0; - } - - /* Free the interrupt so that some other card can use it. */ - outw(0x0f00, ioaddr + WN0_IRQ); - - el3_dev_fill(dev, phys_addr, ioaddr, isa_irq, if_port, EL3_ISA); - dev_set_drvdata(pdev, dev); - if (el3_common_init(dev)) { - free_netdev(dev); - return 0; - } - - el3_devs[el3_cards++] = dev; - return 1; -} - -static void el3_isa_remove(struct device *pdev, - unsigned int ndev) -{ - el3_device_remove(pdev); - dev_set_drvdata(pdev, NULL); -} - -#ifdef CONFIG_PM -static int el3_isa_suspend(struct device *dev, unsigned int n, - pm_message_t state) -{ - current_tag = 0; - return el3_suspend(dev, state); -} - -static int el3_isa_resume(struct device *dev, unsigned int n) -{ - struct net_device *ndev = dev_get_drvdata(dev); - int ioaddr = ndev->base_addr, err; - __be16 phys_addr[3]; - - while ((err = el3_isa_id_sequence(phys_addr)) == 2) - ; /* Skip to next card when PnP card found */ - if (err == 1) - return 0; - /* Set the adaptor tag so that the next card can be found. */ - outb(0xd0 + ++current_tag, id_port); - /* Enable the card */ - outb((ioaddr >> 4) | 0xe0, id_port); - EL3WINDOW(0); - if (inw(ioaddr) != 0x6d50) - return 1; - /* Free the interrupt so that some other card can use it. */ - outw(0x0f00, ioaddr + WN0_IRQ); - return el3_resume(dev); -} -#endif - -static struct isa_driver el3_isa_driver = { - .match = el3_isa_match, - .remove = el3_isa_remove, -#ifdef CONFIG_PM - .suspend = el3_isa_suspend, - .resume = el3_isa_resume, -#endif - .driver = { - .name = "3c509" - }, -}; -static int isa_registered; - -#ifdef CONFIG_PNP -static const struct pnp_device_id el3_pnp_ids[] = { - { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */ - { .id = "TCM5091" }, /* 3Com Etherlink III */ - { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */ - { .id = "TCM5095" }, /* 3Com Etherlink III (TPO) */ - { .id = "TCM5098" }, /* 3Com Etherlink III (TPC) */ - { .id = "PNP80f7" }, /* 3Com Etherlink III compatible */ - { .id = "PNP80f8" }, /* 3Com Etherlink III compatible */ - { .id = "" } -}; -MODULE_DEVICE_TABLE(pnp, el3_pnp_ids); - -static int el3_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id) -{ - short i; - int ioaddr, irq, if_port; - __be16 phys_addr[3]; - struct net_device *dev = NULL; - int err; - - ioaddr = pnp_port_start(pdev, 0); - if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-pnp")) - return -EBUSY; - irq = pnp_irq(pdev, 0); - EL3WINDOW(0); - for (i = 0; i < 3; i++) - phys_addr[i] = htons(read_eeprom(ioaddr, i)); - if_port = read_eeprom(ioaddr, 8) >> 14; - dev = alloc_etherdev(sizeof(struct el3_private)); - if (!dev) { - release_region(ioaddr, EL3_IO_EXTENT); - return -ENOMEM; - } - SET_NETDEV_DEV(dev, &pdev->dev); - - el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_PNP); - pnp_set_drvdata(pdev, dev); - err = el3_common_init(dev); - - if (err) { - pnp_set_drvdata(pdev, NULL); - free_netdev(dev); - return err; - } - - el3_devs[el3_cards++] = dev; - return 0; -} - -static void el3_pnp_remove(struct pnp_dev *pdev) -{ - el3_common_remove(pnp_get_drvdata(pdev)); - pnp_set_drvdata(pdev, NULL); -} - -#ifdef CONFIG_PM -static int el3_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) -{ - return el3_suspend(&pdev->dev, state); -} - -static int el3_pnp_resume(struct pnp_dev *pdev) -{ - return el3_resume(&pdev->dev); -} -#endif - -static struct pnp_driver el3_pnp_driver = { - .name = "3c509", - .id_table = el3_pnp_ids, - .probe = el3_pnp_probe, - .remove = el3_pnp_remove, -#ifdef CONFIG_PM - .suspend = el3_pnp_suspend, - .resume = el3_pnp_resume, -#endif -}; -static int pnp_registered; -#endif /* CONFIG_PNP */ - -#ifdef CONFIG_EISA -static const struct eisa_device_id el3_eisa_ids[] = { - { "TCM5090" }, - { "TCM5091" }, - { "TCM5092" }, - { "TCM5093" }, - { "TCM5094" }, - { "TCM5095" }, - { "TCM5098" }, - { "" } -}; -MODULE_DEVICE_TABLE(eisa, el3_eisa_ids); - -static int el3_eisa_probe (struct device *device); - -static struct eisa_driver el3_eisa_driver = { - .id_table = el3_eisa_ids, - .driver = { - .name = "3c579", - .probe = el3_eisa_probe, - .remove = el3_device_remove, - .suspend = el3_suspend, - .resume = el3_resume, - } -}; -static int eisa_registered; -#endif - -static const struct net_device_ops netdev_ops = { - .ndo_open = el3_open, - .ndo_stop = el3_close, - .ndo_start_xmit = el3_start_xmit, - .ndo_get_stats = el3_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_tx_timeout = el3_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = el3_poll_controller, -#endif -}; - -static int el3_common_init(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - int err; - static const char * const if_names[] = { - "10baseT", "AUI", "undefined", "BNC" - }; - - spin_lock_init(&lp->lock); - - if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ - dev->if_port = (dev->mem_start & 0x0f); - } else { /* xcvr codes 0/8 */ - /* use eeprom value, but save user's full-duplex selection */ - dev->if_port |= (dev->mem_start & 0x08); - } - - /* The EL3-specific entries in the device structure. */ - dev->netdev_ops = &netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; - dev->ethtool_ops = ðtool_ops; - - err = register_netdev(dev); - if (err) { - pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n", - dev->base_addr, dev->irq); - release_region(dev->base_addr, EL3_IO_EXTENT); - return err; - } - - pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n", - dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], - dev->dev_addr, dev->irq); - - return 0; - -} - -static void el3_common_remove (struct net_device *dev) -{ - unregister_netdev (dev); - release_region(dev->base_addr, EL3_IO_EXTENT); - free_netdev (dev); -} - -#ifdef CONFIG_EISA -static int el3_eisa_probe(struct device *device) -{ - short i; - int ioaddr, irq, if_port; - __be16 phys_addr[3]; - struct net_device *dev = NULL; - struct eisa_device *edev; - int err; - - /* Yeepee, The driver framework is calling us ! */ - edev = to_eisa_device (device); - ioaddr = edev->base_addr; - - if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa")) - return -EBUSY; - - /* Change the register set to the configuration window 0. */ - outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD); - - irq = inw(ioaddr + WN0_IRQ) >> 12; - if_port = inw(ioaddr + 6)>>14; - for (i = 0; i < 3; i++) - phys_addr[i] = htons(read_eeprom(ioaddr, i)); - - /* Restore the "Product ID" to the EEPROM read register. */ - read_eeprom(ioaddr, 3); - - dev = alloc_etherdev(sizeof (struct el3_private)); - if (dev == NULL) { - release_region(ioaddr, EL3_IO_EXTENT); - return -ENOMEM; - } - - SET_NETDEV_DEV(dev, device); - - el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA); - eisa_set_drvdata (edev, dev); - err = el3_common_init(dev); - - if (err) { - eisa_set_drvdata (edev, NULL); - free_netdev(dev); - return err; - } - - el3_devs[el3_cards++] = dev; - return 0; -} -#endif - -/* This remove works for all device types. - * - * The net dev must be stored in the driver data field */ -static int el3_device_remove(struct device *device) -{ - struct net_device *dev; - - dev = dev_get_drvdata(device); - - el3_common_remove (dev); - return 0; -} - -/* Read a word from the EEPROM using the regular EEPROM access register. - Assume that we are in register window zero. - */ -static ushort read_eeprom(int ioaddr, int index) -{ - outw(EEPROM_READ + index, ioaddr + 10); - /* Pause for at least 162 us. for the read to take place. - Some chips seem to require much longer */ - mdelay(2); - return inw(ioaddr + 12); -} - -/* Read a word from the EEPROM when in the ISA ID probe state. */ -static ushort id_read_eeprom(int index) -{ - int bit, word = 0; - - /* Issue read command, and pause for at least 162 us. for it to complete. - Assume extra-fast 16Mhz bus. */ - outb(EEPROM_READ + index, id_port); - - /* Pause for at least 162 us. for the read to take place. */ - /* Some chips seem to require much longer */ - mdelay(4); - - for (bit = 15; bit >= 0; bit--) - word = (word << 1) + (inb(id_port) & 0x01); - - if (el3_debug > 3) - pr_debug(" 3c509 EEPROM word %d %#4.4x.\n", index, word); - - return word; -} - - -static int -el3_open(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - int i; - - outw(TxReset, ioaddr + EL3_CMD); - outw(RxReset, ioaddr + EL3_CMD); - outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - - i = request_irq(dev->irq, el3_interrupt, 0, dev->name, dev); - if (i) - return i; - - EL3WINDOW(0); - if (el3_debug > 3) - pr_debug("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, - dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS)); - - el3_up(dev); - - if (el3_debug > 3) - pr_debug("%s: Opened 3c509 IRQ %d status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + EL3_STATUS)); - - return 0; -} - -static void -el3_tx_timeout (struct net_device *dev, unsigned int txqueue) -{ - int ioaddr = dev->base_addr; - - /* Transmitter timeout, serious problems. */ - pr_warn("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d\n", - dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), - inw(ioaddr + TX_FREE)); - dev->stats.tx_errors++; - netif_trans_update(dev); /* prevent tx timeout */ - /* Issue TX_RESET and TX_START commands. */ - outw(TxReset, ioaddr + EL3_CMD); - outw(TxEnable, ioaddr + EL3_CMD); - netif_wake_queue(dev); -} - - -static netdev_tx_t -el3_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - unsigned long flags; - - netif_stop_queue (dev); - - dev->stats.tx_bytes += skb->len; - - if (el3_debug > 4) { - pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n", - dev->name, skb->len, inw(ioaddr + EL3_STATUS)); - } - /* - * We lock the driver against other processors. Note - * we don't need to lock versus the IRQ as we suspended - * that. This means that we lose the ability to take - * an RX during a TX upload. That sucks a bit with SMP - * on an original 3c509 (2K buffer) - * - * Using disable_irq stops us crapping on other - * time sensitive devices. - */ - - spin_lock_irqsave(&lp->lock, flags); - - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0x00, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - - if (inw(ioaddr + TX_FREE) > 1536) - netif_start_queue(dev); - else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); - - spin_unlock_irqrestore(&lp->lock, flags); - - dev_consume_skb_any (skb); - - /* Clear the Tx status stack. */ - { - short tx_status; - int i = 4; - - while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) { - if (tx_status & 0x38) dev->stats.tx_aborted_errors++; - if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); - if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); - outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ - } - } - return NETDEV_TX_OK; -} - -/* The EL3 interrupt handler. */ -static irqreturn_t -el3_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct el3_private *lp; - int ioaddr, status; - int i = max_interrupt_work; - - lp = netdev_priv(dev); - spin_lock(&lp->lock); - - ioaddr = dev->base_addr; - - if (el3_debug > 4) { - status = inw(ioaddr + EL3_STATUS); - pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status); - } - - while ((status = inw(ioaddr + EL3_STATUS)) & - (IntLatch | RxComplete | StatsFull)) { - - if (status & RxComplete) - el3_rx(dev); - - if (status & TxAvailable) { - if (el3_debug > 5) - pr_debug(" TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue (dev); - } - if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) { - /* Handle all uncommon interrupts. */ - if (status & StatsFull) /* Empty statistics. */ - update_stats(dev); - if (status & RxEarly) { /* Rx early is unused. */ - el3_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & TxComplete) { /* Really Tx error. */ - short tx_status; - int i = 4; - - while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) { - if (tx_status & 0x38) dev->stats.tx_aborted_errors++; - if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); - if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); - outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ - } - } - if (status & AdapterFailure) { - /* Adapter failure requires Rx reset and reinit. */ - outw(RxReset, ioaddr + EL3_CMD); - /* Set the Rx filter to the current state. */ - outw(SetRxFilter | RxStation | RxBroadcast - | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0) - | (dev->flags & IFF_PROMISC ? RxProm : 0), - ioaddr + EL3_CMD); - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); - } - } - - if (--i < 0) { - pr_err("%s: Infinite loop in interrupt, status %4.4x.\n", - dev->name, status); - /* Clear all interrupts. */ - outw(AckIntr | 0xFF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */ - } - - if (el3_debug > 4) { - pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, - inw(ioaddr + EL3_STATUS)); - } - spin_unlock(&lp->lock); - return IRQ_HANDLED; -} - - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling receive - used by netconsole and other diagnostic tools - * to allow network i/o with interrupts disabled. - */ -static void el3_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - el3_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -static struct net_device_stats * -el3_get_stats(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - unsigned long flags; - - /* - * This is fast enough not to bother with disable IRQ - * stuff. - */ - - spin_lock_irqsave(&lp->lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->lock, flags); - return &dev->stats; -} - -/* Update statistics. We change to register window 6, so this should be run - single-threaded if the device is active. This is expected to be a rare - operation, and it's simpler for the rest of the driver to assume that - window 1 is always valid rather than use a special window-state variable. - */ -static void update_stats(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - - if (el3_debug > 5) - pr_debug(" Updating the statistics.\n"); - /* Turn off statistics updates while reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors += inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - dev->stats.collisions += inb(ioaddr + 3); - dev->stats.tx_window_errors += inb(ioaddr + 4); - dev->stats.rx_fifo_errors += inb(ioaddr + 5); - dev->stats.tx_packets += inb(ioaddr + 6); - /* Rx packets */ inb(ioaddr + 7); - /* Tx deferrals */ inb(ioaddr + 8); - inw(ioaddr + 10); /* Total Rx and Tx octets. */ - inw(ioaddr + 12); - - /* Back to window 1, and turn statistics back on. */ - EL3WINDOW(1); - outw(StatsEnable, ioaddr + EL3_CMD); -} - -static int -el3_rx(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - short rx_status; - - if (el3_debug > 5) - pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); - while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { - if (rx_status & 0x4000) { /* Error, update stats. */ - short error = rx_status & 0x3800; - - outw(RxDiscard, ioaddr + EL3_CMD); - dev->stats.rx_errors++; - switch (error) { - case 0x0000: dev->stats.rx_over_errors++; break; - case 0x0800: dev->stats.rx_length_errors++; break; - case 0x1000: dev->stats.rx_frame_errors++; break; - case 0x1800: dev->stats.rx_length_errors++; break; - case 0x2000: dev->stats.rx_frame_errors++; break; - case 0x2800: dev->stats.rx_crc_errors++; break; - } - } else { - short pkt_len = rx_status & 0x7ff; - struct sk_buff *skb; - - skb = netdev_alloc_skb(dev, pkt_len + 5); - if (el3_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb != NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte */ - - /* 'skb->data' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len), - (pkt_len + 3) >> 2); - - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ - skb->protocol = eth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_bytes += pkt_len; - dev->stats.rx_packets++; - continue; - } - outw(RxDiscard, ioaddr + EL3_CMD); - dev->stats.rx_dropped++; - if (el3_debug) - pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", - dev->name, pkt_len); - } - inw(ioaddr + EL3_STATUS); /* Delay. */ - while (inw(ioaddr + EL3_STATUS) & 0x1000) - pr_debug(" Waiting for 3c509 to discard packet, status %x.\n", - inw(ioaddr + EL3_STATUS) ); - } - - return 0; -} - -/* - * Set or clear the multicast filter for this adaptor. - */ -static void -set_multicast_list(struct net_device *dev) -{ - unsigned long flags; - struct el3_private *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - int mc_count = netdev_mc_count(dev); - - if (el3_debug > 1) { - static int old; - if (old != mc_count) { - old = mc_count; - pr_debug("%s: Setting Rx mode to %d addresses.\n", - dev->name, mc_count); - } - } - spin_lock_irqsave(&lp->lock, flags); - if (dev->flags&IFF_PROMISC) { - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, - ioaddr + EL3_CMD); - } - else if (mc_count || (dev->flags&IFF_ALLMULTI)) { - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD); - } - else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); - spin_unlock_irqrestore(&lp->lock, flags); -} - -static int -el3_close(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct el3_private *lp = netdev_priv(dev); - - if (el3_debug > 2) - pr_debug("%s: Shutting down ethercard.\n", dev->name); - - el3_down(dev); - - free_irq(dev->irq, dev); - /* Switching back to window 0 disables the IRQ. */ - EL3WINDOW(0); - if (lp->type != EL3_EISA) { - /* But we explicitly zero the IRQ line select anyway. Don't do - * it on EISA cards, it prevents the module from getting an - * IRQ after unload+reload... */ - outw(0x0f00, ioaddr + WN0_IRQ); - } - - return 0; -} - -static int -el3_link_ok(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - u16 tmp; - - EL3WINDOW(4); - tmp = inw(ioaddr + WN4_MEDIA); - EL3WINDOW(1); - return tmp & (1<<11); -} - -static void -el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_link_ksettings *cmd) -{ - u16 tmp; - int ioaddr = dev->base_addr; - u32 supported; - - EL3WINDOW(0); - /* obtain current transceiver via WN4_MEDIA? */ - tmp = inw(ioaddr + WN0_ADDR_CONF); - switch (tmp >> 14) { - case 0: - cmd->base.port = PORT_TP; - break; - case 1: - cmd->base.port = PORT_AUI; - break; - case 3: - cmd->base.port = PORT_BNC; - break; - default: - break; - } - - cmd->base.duplex = DUPLEX_HALF; - supported = 0; - tmp = inw(ioaddr + WN0_CONF_CTRL); - if (tmp & (1<<13)) - supported |= SUPPORTED_AUI; - if (tmp & (1<<12)) - supported |= SUPPORTED_BNC; - if (tmp & (1<<9)) { - supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full; /* hmm... */ - EL3WINDOW(4); - tmp = inw(ioaddr + WN4_NETDIAG); - if (tmp & FD_ENABLE) - cmd->base.duplex = DUPLEX_FULL; - } - - ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, - supported); - cmd->base.speed = SPEED_10; - EL3WINDOW(1); -} - -static int -el3_netdev_set_ecmd(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - u16 tmp; - int ioaddr = dev->base_addr; - - if (cmd->base.speed != SPEED_10) - return -EINVAL; - if ((cmd->base.duplex != DUPLEX_HALF) && - (cmd->base.duplex != DUPLEX_FULL)) - return -EINVAL; - - /* change XCVR type */ - EL3WINDOW(0); - tmp = inw(ioaddr + WN0_ADDR_CONF); - switch (cmd->base.port) { - case PORT_TP: - tmp &= ~(3<<14); - dev->if_port = 0; - break; - case PORT_AUI: - tmp |= (1<<14); - dev->if_port = 1; - break; - case PORT_BNC: - tmp |= (3<<14); - dev->if_port = 3; - break; - default: - return -EINVAL; - } - - outw(tmp, ioaddr + WN0_ADDR_CONF); - if (dev->if_port == 3) { - /* fire up the DC-DC convertor if BNC gets enabled */ - tmp = inw(ioaddr + WN0_ADDR_CONF); - if (tmp & (3 << 14)) { - outw(StartCoax, ioaddr + EL3_CMD); - udelay(800); - } else - return -EIO; - } - - EL3WINDOW(4); - tmp = inw(ioaddr + WN4_NETDIAG); - if (cmd->base.duplex == DUPLEX_FULL) - tmp |= FD_ENABLE; - else - tmp &= ~FD_ENABLE; - outw(tmp, ioaddr + WN4_NETDIAG); - EL3WINDOW(1); - - return 0; -} - -static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); -} - -static int el3_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct el3_private *lp = netdev_priv(dev); - - spin_lock_irq(&lp->lock); - el3_netdev_get_ecmd(dev, cmd); - spin_unlock_irq(&lp->lock); - return 0; -} - -static int el3_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct el3_private *lp = netdev_priv(dev); - int ret; - - spin_lock_irq(&lp->lock); - ret = el3_netdev_set_ecmd(dev, cmd); - spin_unlock_irq(&lp->lock); - return ret; -} - -static u32 el3_get_link(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - u32 ret; - - spin_lock_irq(&lp->lock); - ret = el3_link_ok(dev); - spin_unlock_irq(&lp->lock); - return ret; -} - -static u32 el3_get_msglevel(struct net_device *dev) -{ - return el3_debug; -} - -static void el3_set_msglevel(struct net_device *dev, u32 v) -{ - el3_debug = v; -} - -static const struct ethtool_ops ethtool_ops = { - .get_drvinfo = el3_get_drvinfo, - .get_link = el3_get_link, - .get_msglevel = el3_get_msglevel, - .set_msglevel = el3_set_msglevel, - .get_link_ksettings = el3_get_link_ksettings, - .set_link_ksettings = el3_set_link_ksettings, -}; - -static void -el3_down(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - - netif_stop_queue(dev); - - /* Turn off statistics ASAP. We update lp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port == 3) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 0) { - /* Disable link beat and jabber, if_port may change here next open(). */ - EL3WINDOW(4); - outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); - } - - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - - update_stats(dev); -} - -static void -el3_up(struct net_device *dev) -{ - int i, sw_info, net_diag; - int ioaddr = dev->base_addr; - - /* Activating the board required and does no harm otherwise */ - outw(0x0001, ioaddr + 4); - - /* Set the IRQ line. */ - outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ); - - /* Set the station address in window 2 each time opened. */ - EL3WINDOW(2); - - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - - if ((dev->if_port & 0x03) == 3) /* BNC interface */ - /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); - else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */ - /* Combine secondary sw_info word (the adapter level) and primary - sw_info word (duplex setting plus other useless bits) */ - EL3WINDOW(0); - sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) | - (read_eeprom(ioaddr, 0x0d) & 0xBff0); - - EL3WINDOW(4); - net_diag = inw(ioaddr + WN4_NETDIAG); - net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */ - pr_info("%s: ", dev->name); - switch (dev->if_port & 0x0c) { - case 12: - /* force full-duplex mode if 3c5x9b */ - if (sw_info & 0x000f) { - pr_cont("Forcing 3c5x9b full-duplex mode"); - break; - } - fallthrough; - case 8: - /* set full-duplex mode based on eeprom config setting */ - if ((sw_info & 0x000f) && (sw_info & 0x8000)) { - pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)"); - break; - } - fallthrough; - default: - /* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */ - pr_cont("Setting 3c5x9/3c5x9B half-duplex mode"); - net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */ - } - - outw(net_diag, ioaddr + WN4_NETDIAG); - pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); - if (el3_debug > 3) - pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag); - /* Enable link beat and jabber check. */ - outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); - } - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i = 0; i < 9; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - - /* Switch to register set 1 for normal use. */ - EL3WINDOW(1); - - /* Accept b-case and phys addr only. */ - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull, - ioaddr + EL3_CMD); - - netif_start_queue(dev); -} - -/* Power Management support functions */ -#ifdef CONFIG_PM - -static int -el3_suspend(struct device *pdev, pm_message_t state) -{ - unsigned long flags; - struct net_device *dev; - struct el3_private *lp; - int ioaddr; - - dev = dev_get_drvdata(pdev); - lp = netdev_priv(dev); - ioaddr = dev->base_addr; - - spin_lock_irqsave(&lp->lock, flags); - - if (netif_running(dev)) - netif_device_detach(dev); - - el3_down(dev); - outw(PowerDown, ioaddr + EL3_CMD); - - spin_unlock_irqrestore(&lp->lock, flags); - return 0; -} - -static int -el3_resume(struct device *pdev) -{ - unsigned long flags; - struct net_device *dev; - struct el3_private *lp; - int ioaddr; - - dev = dev_get_drvdata(pdev); - lp = netdev_priv(dev); - ioaddr = dev->base_addr; - - spin_lock_irqsave(&lp->lock, flags); - - outw(PowerUp, ioaddr + EL3_CMD); - EL3WINDOW(0); - el3_up(dev); - - if (netif_running(dev)) - netif_device_attach(dev); - - spin_unlock_irqrestore(&lp->lock, flags); - return 0; -} - -#endif /* CONFIG_PM */ - -module_param(debug,int, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param(max_interrupt_work, int, 0); -MODULE_PARM_DESC(debug, "debug level (0-6)"); -MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); -MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt"); -#ifdef CONFIG_PNP -module_param(nopnp, int, 0); -MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)"); -#endif /* CONFIG_PNP */ -MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ethernet driver"); -MODULE_LICENSE("GPL"); - -static int __init el3_init_module(void) -{ - int ret = 0; - - if (debug >= 0) - el3_debug = debug; - -#ifdef CONFIG_PNP - if (!nopnp) { - ret = pnp_register_driver(&el3_pnp_driver); - if (!ret) - pnp_registered = 1; - } -#endif - /* Select an open I/O location at 0x1*0 to do ISA contention select. */ - /* Start with 0x110 to avoid some sound cards.*/ - for (id_port = 0x110 ; id_port < 0x200; id_port += 0x10) { - if (!request_region(id_port, 1, "3c509-control")) - continue; - outb(0x00, id_port); - outb(0xff, id_port); - if (inb(id_port) & 0x01) - break; - else - release_region(id_port, 1); - } - if (id_port >= 0x200) { - id_port = 0; - pr_err("No I/O port available for 3c509 activation.\n"); - } else { - ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS); - if (!ret) - isa_registered = 1; - } -#ifdef CONFIG_EISA - ret = eisa_driver_register(&el3_eisa_driver); - if (!ret) - eisa_registered = 1; -#endif - -#ifdef CONFIG_PNP - if (pnp_registered) - ret = 0; -#endif - if (isa_registered) - ret = 0; -#ifdef CONFIG_EISA - if (eisa_registered) - ret = 0; -#endif - return ret; -} - -static void __exit el3_cleanup_module(void) -{ -#ifdef CONFIG_PNP - if (pnp_registered) - pnp_unregister_driver(&el3_pnp_driver); -#endif - if (isa_registered) - isa_unregister_driver(&el3_isa_driver); - if (id_port) - release_region(id_port, 1); -#ifdef CONFIG_EISA - if (eisa_registered) - eisa_driver_unregister(&el3_eisa_driver); -#endif -} - -module_init (el3_init_module); -module_exit (el3_cleanup_module); diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c deleted file mode 100644 index 2227c83a4862..000000000000 --- a/drivers/net/ethernet/3com/3c515.c +++ /dev/null @@ -1,1566 +0,0 @@ -/* - Written 1997-1998 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - This driver is for the 3Com ISA EtherLink XL "Corkscrew" 3c515 ethercard. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - - 2000/2/2- Added support for kernel-level ISAPnP - by Stephen Frost and Alessandro Zummo - Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox. - - 2001/11/17 - Added ethtool support (jgarzik) - - 2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk) - -*/ - -#define DRV_NAME "3c515" - -#define CORKSCREW 1 - -/* "Knobs" that adjust features and parameters. */ -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1512 effectively disables this feature. */ -static int rx_copybreak = 200; - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; - -/* Enable the automatic media selection code -- usually set. */ -#define AUTOMEDIA 1 - -/* Allow the use of fragment bus master transfers instead of only - programmed-I/O for Vortex cards. Full-bus-master transfers are always - enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined, - the feature may be turned on using 'options'. */ -#define VORTEX_BUS_MASTER - -/* A few values that may be tweaked. */ -/* Keep the ring sizes a power of two for efficiency. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 16 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#define NEW_MULTICAST -#include - -#define MAX_UNITS 8 - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver"); -MODULE_LICENSE("GPL"); - -/* "Knobs" for adjusting internal parameters. */ -/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */ -#define DRIVER_DEBUG 1 -/* Some values here only for performance evaluation and path-coverage - debugging. */ -static int rx_nocopy, rx_copy, queued_packet; - -/* Number of times to check to see if the Tx FIFO has space, used in some - limited cases. */ -#define WAIT_TX_AVAIL 200 - -/* Operational parameter that usually are not changed. */ -#define TX_TIMEOUT ((4*HZ)/10) /* Time in jiffies before concluding Tx hung */ - -/* The size here is somewhat misleading: the Corkscrew also uses the ISA - aliased registers at +0x400. - */ -#define CORKSCREW_TOTAL_SIZE 0x20 - -#ifdef DRIVER_DEBUG -static int corkscrew_debug = DRIVER_DEBUG; -#else -static int corkscrew_debug = 1; -#endif - -#define CORKSCREW_ID 10 - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the 3Com 3c515 ISA Fast EtherLink XL, -3Com's ISA bus adapter for Fast Ethernet. Due to the unique I/O port layout, -it's not practical to integrate this driver with the other EtherLink drivers. - -II. Board-specific settings - -The Corkscrew has an EEPROM for configuration, but no special settings are -needed for Linux. - -III. Driver operation - -The 3c515 series use an interface that's very similar to the 3c900 "Boomerang" -PCI cards, with the bus master interface extensively modified to work with -the ISA bus. - -The card is capable of full-bus-master transfers with separate -lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet, -DEC Tulip and Intel Speedo3. - -This driver uses a "RX_COPYBREAK" scheme rather than a fixed intermediate -receive buffer. This scheme allocates full-sized skbuffs as receive -buffers. The value RX_COPYBREAK is used as the copying breakpoint: it is -chosen to trade-off the memory wasted by passing the full-sized skbuff to -the queue layer for all frames vs. the copying cost of copying a frame to a -correctly-sized skbuff. - - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the netif -layer. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -IV. Notes - -Thanks to Terry Murphy of 3Com for providing documentation and a development -board. - -The names "Vortex", "Boomerang" and "Corkscrew" are the internal 3Com -project names. I use these names to eliminate confusion -- 3Com product -numbers and names are very similar and often confused. - -The new chips support both ethernet (1.5K) and FDDI (4.5K) frame sizes! -This driver only supports ethernet frames because of the recent MTU limit -of 1.5K, but the changes to support 4.5K are minimal. -*/ - -/* Operational definitions. - These are not used by other compilation units and thus are not - exported in a ".h" file. - - First the windows. There are eight register windows, with the command - and status registers available in each. - */ -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. - Note that 11 parameters bits was fine for ethernet, but the new chips - can handle FDDI length frames (~4500 octets) and now parameters count - 32-bit 'Dwords' rather than octets. */ - -enum corkscrew_cmd { - TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11, - RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11, - UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, DownStall = (6 << 11) + 2, - DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11, - TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11, - AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11, - SetRxFilter = 16 << 11, SetRxThreshold = 17 << 11, - SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, StartDMAUp = 20 << 11, - StartDMADown = (20 << 11) + 1, StatsEnable = 21 << 11, - StatsDisable = 22 << 11, StopCoax = 23 << 11, -}; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 -}; - -/* Bits in the general status register. */ -enum corkscrew_status { - IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, - TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, - IntReq = 0x0040, StatsFull = 0x0080, - DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10, - DMAInProgress = 1 << 11, /* DMA controller is still busy. */ - CmdInProgress = 1 << 12, /* EL3_CMD is still busy. */ -}; - -/* Register window 1 offsets, the window used in normal operation. - On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */ -enum Window1 { - TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14, - RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B, - TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */ -}; -enum Window0 { - Wn0IRQ = 0x08, -#if defined(CORKSCREW) - Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */ - Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */ -#else - Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ - Wn0EepromData = 12, /* Window 0: EEPROM results register. */ -#endif -}; -enum Win0_EEPROM_bits { - EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, - EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ -}; - -/* EEPROM locations. */ -enum eeprom_offset { - PhysAddr01 = 0, PhysAddr23 = 1, PhysAddr45 = 2, ModelID = 3, - EtherLink3ID = 7, -}; - -enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8, -}; -enum wn3_config { - Ram_size = 7, - Ram_width = 8, - Ram_speed = 0x30, - Rom_size = 0xc0, - Ram_split_shift = 16, - Ram_split = 3 << Ram_split_shift, - Xcvr_shift = 20, - Xcvr = 7 << Xcvr_shift, - Autoselect = 0x1000000, -}; - -enum Window4 { - Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */ -}; -enum Win4_Media_bits { - Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ - Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */ - Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ - Media_LnkBeat = 0x0800, -}; -enum Window7 { /* Window 7: Bus Master control. */ - Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, -}; - -/* Boomerang-style bus master control registers. Note ISA aliases! */ -enum MasterCtrl { - PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen = - 0x40c, - TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418, -}; - -/* The Rx and Tx descriptor lists. - Caution Alpha hackers: these types are 32 bits! Note also the 8 byte - alignment contraint on tx_ring[] and rx_ring[]. */ -struct boom_rx_desc { - u32 next; - s32 status; - u32 addr; - s32 length; -}; - -/* Values for the Rx status entry. */ -enum rx_desc_status { - RxDComplete = 0x00008000, RxDError = 0x4000, - /* See boomerang_rx() for actual error bits */ -}; - -struct boom_tx_desc { - u32 next; - s32 status; - u32 addr; - s32 length; -}; - -struct corkscrew_private { - const char *product_name; - struct list_head list; - struct net_device *our_dev; - /* The Rx and Tx rings are here to keep them quad-word-aligned. */ - struct boom_rx_desc rx_ring[RX_RING_SIZE]; - struct boom_tx_desc tx_ring[TX_RING_SIZE]; - /* The addresses of transmit- and receive-in-place skbuffs. */ - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */ - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ - struct timer_list timer; /* Media selection timer. */ - int capabilities ; /* Adapter capabilities word. */ - int options; /* User-settable misc. driver options. */ - int last_rx_packets; /* For media autoselection. */ - unsigned int available_media:8, /* From Wn3_Options */ - media_override:3, /* Passed-in media type. */ - default_media:3, /* Read from the EEPROM. */ - full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ - full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */ - tx_full:1; - spinlock_t lock; - struct device *dev; -}; - -/* The action to take with a media selection timer tick. - Note that we deviate from the 3Com order by checking 10base2 before AUI. - */ -enum xcvr_types { - XCVR_10baseT = 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx, - XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8, -}; - -static struct media_table { - char *name; - unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ - mask:8, /* The transceiver-present bit in Wn3_Config. */ - next:8; /* The media type to try next. */ - short wait; /* Time before we check media status. */ -} media_tbl[] = { - { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 }, - { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10}, - { "undefined", 0, 0x80, XCVR_10baseT, 10000}, - { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10}, - { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10}, - { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10}, - { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ}, - { "undefined", 0, 0x01, XCVR_10baseT, 10000}, - { "Default", 0, 0xFF, XCVR_10baseT, 10000}, -}; - -#ifdef __ISAPNP__ -static struct isapnp_device_id corkscrew_isapnp_adapters[] = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), - (long) "3Com Fast EtherLink ISA" }, - { } /* terminate list */ -}; - -MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters); - -static int nopnp; -#endif /* __ISAPNP__ */ - -static struct net_device *corkscrew_scan(int unit); -static int corkscrew_setup(struct net_device *dev, int ioaddr, - struct pnp_dev *idev, int card_number); -static int corkscrew_open(struct net_device *dev); -static void corkscrew_timer(struct timer_list *t); -static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int corkscrew_rx(struct net_device *dev); -static void corkscrew_timeout(struct net_device *dev, unsigned int txqueue); -static int boomerang_rx(struct net_device *dev); -static irqreturn_t corkscrew_interrupt(int irq, void *dev_id); -static int corkscrew_close(struct net_device *dev); -static void update_stats(int addr, struct net_device *dev); -static struct net_device_stats *corkscrew_get_stats(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static const struct ethtool_ops netdev_ethtool_ops; - - -/* - Unfortunately maximizing the shared code between the integrated and - module version of the driver results in a complicated set of initialization - procedures. - init_module() -- modules / tc59x_init() -- built-in - The wrappers for corkscrew_scan() - corkscrew_scan() The common routine that scans for PCI and EISA cards - corkscrew_found_device() Allocate a device structure when we find a card. - Different versions exist for modules and built-in. - corkscrew_probe1() Fill in the device structure -- this is separated - so that the modules code can put it in dev->init. -*/ -/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ -/* Note: this is the only limit on the number of cards supported!! */ -static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1, }; - -#ifdef MODULE -static int debug = -1; - -module_param(debug, int, 0); -module_param_array(options, int, NULL, 0); -module_param(rx_copybreak, int, 0); -module_param(max_interrupt_work, int, 0); -MODULE_PARM_DESC(debug, "3c515 debug level (0-6)"); -MODULE_PARM_DESC(options, "3c515: Bits 0-2: media type, bit 3: full duplex, bit 4: bus mastering"); -MODULE_PARM_DESC(rx_copybreak, "3c515 copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(max_interrupt_work, "3c515 maximum events handled per interrupt"); - -/* A list of all installed Vortex devices, for removing the driver module. */ -/* we will need locking (and refcounting) if we ever use it for more */ -static LIST_HEAD(root_corkscrew_dev); - -static int corkscrew_init_module(void) -{ - int found = 0; - if (debug >= 0) - corkscrew_debug = debug; - while (corkscrew_scan(-1)) - found++; - return found ? 0 : -ENODEV; -} -module_init(corkscrew_init_module); - -#else -struct net_device *tc515_probe(int unit) -{ - struct net_device *dev = corkscrew_scan(unit); - - if (!dev) - return ERR_PTR(-ENODEV); - - return dev; -} -#endif /* not MODULE */ - -static int check_device(unsigned ioaddr) -{ - int timer; - - if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515")) - return 0; - /* Check the resource configuration for a matching ioaddr. */ - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) { - release_region(ioaddr, CORKSCREW_TOTAL_SIZE); - return 0; - } - /* Verify by reading the device ID from the EEPROM. */ - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) - break; - } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) { - release_region(ioaddr, CORKSCREW_TOTAL_SIZE); - return 0; - } - return 1; -} - -static void cleanup_card(struct net_device *dev) -{ - struct corkscrew_private *vp = netdev_priv(dev); - list_del_init(&vp->list); - if (dev->dma) - free_dma(dev->dma); - outw(TotalReset, dev->base_addr + EL3_CMD); - release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE); - if (vp->dev) - pnp_device_detach(to_pnp_dev(vp->dev)); -} - -static struct net_device *corkscrew_scan(int unit) -{ - struct net_device *dev; - static int cards_found = 0; - static int ioaddr; - int err; -#ifdef __ISAPNP__ - short i; - static int pnp_cards; -#endif - - dev = alloc_etherdev(sizeof(struct corkscrew_private)); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - -#ifdef __ISAPNP__ - if(nopnp == 1) - goto no_pnp; - for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) { - struct pnp_dev *idev = NULL; - int irq; - while((idev = pnp_find_dev(NULL, - corkscrew_isapnp_adapters[i].vendor, - corkscrew_isapnp_adapters[i].function, - idev))) { - - if (pnp_device_attach(idev) < 0) - continue; - if (pnp_activate_dev(idev) < 0) { - pr_warn("pnp activate failed (out of resources?)\n"); - pnp_device_detach(idev); - continue; - } - if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) { - pnp_device_detach(idev); - continue; - } - ioaddr = pnp_port_start(idev, 0); - irq = pnp_irq(idev, 0); - if (!check_device(ioaddr)) { - pnp_device_detach(idev); - continue; - } - if(corkscrew_debug) - pr_debug("ISAPNP reports %s at i/o 0x%x, irq %d\n", - (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); - pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", - inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ - SET_NETDEV_DEV(dev, &idev->dev); - pnp_cards++; - err = corkscrew_setup(dev, ioaddr, idev, cards_found++); - if (!err) - return dev; - cleanup_card(dev); - } - } -no_pnp: -#endif /* __ISAPNP__ */ - - /* Check all locations on the ISA bus -- evil! */ - for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - if (!check_device(ioaddr)) - continue; - - pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", - inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - err = corkscrew_setup(dev, ioaddr, NULL, cards_found++); - if (!err) - return dev; - cleanup_card(dev); - } - free_netdev(dev); - return NULL; -} - - -static const struct net_device_ops netdev_ops = { - .ndo_open = corkscrew_open, - .ndo_stop = corkscrew_close, - .ndo_start_xmit = corkscrew_start_xmit, - .ndo_tx_timeout = corkscrew_timeout, - .ndo_get_stats = corkscrew_get_stats, - .ndo_set_rx_mode = set_rx_mode, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - - -static int corkscrew_setup(struct net_device *dev, int ioaddr, - struct pnp_dev *idev, int card_number) -{ - struct corkscrew_private *vp = netdev_priv(dev); - unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - __be16 addr[ETH_ALEN / 2]; - int i; - int irq; - -#ifdef __ISAPNP__ - if (idev) { - irq = pnp_irq(idev, 0); - vp->dev = &idev->dev; - } else { - irq = inw(ioaddr + 0x2002) & 15; - } -#else - irq = inw(ioaddr + 0x2002) & 15; -#endif - - dev->base_addr = ioaddr; - dev->irq = irq; - dev->dma = inw(ioaddr + 0x2000) & 7; - vp->product_name = "3c515"; - vp->options = dev->mem_start; - vp->our_dev = dev; - - if (!vp->options) { - if (card_number >= MAX_UNITS) - vp->options = -1; - else - vp->options = options[card_number]; - } - - if (vp->options >= 0) { - vp->media_override = vp->options & 7; - if (vp->media_override == 2) - vp->media_override = 0; - vp->full_duplex = (vp->options & 8) ? 1 : 0; - vp->bus_master = (vp->options & 16) ? 1 : 0; - } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; - } -#ifdef MODULE - list_add(&vp->list, &root_corkscrew_dev); -#endif - - pr_info("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); - - spin_lock_init(&vp->lock); - - timer_setup(&vp->timer, corkscrew_timer, 0); - - /* Read the station address from the EEPROM. */ - EL3WINDOW(0); - for (i = 0; i < 0x18; i++) { - int timer; - outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) - break; - } - eeprom[i] = inw(ioaddr + Wn0EepromData); - checksum ^= eeprom[i]; - if (i < 3) - addr[i] = htons(eeprom[i]); - } - eth_hw_addr_set(dev, (u8 *)addr); - checksum = (checksum ^ (checksum >> 8)) & 0xff; - if (checksum != 0x00) - pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); - pr_cont(" %pM", dev->dev_addr); - if (eeprom[16] == 0x11c7) { /* Corkscrew */ - if (request_dma(dev->dma, "3c515")) { - pr_cont(", DMA %d allocation failed", dev->dma); - dev->dma = 0; - } else - pr_cont(", DMA %d", dev->dma); - } - pr_cont(", IRQ %d\n", dev->irq); - /* Tell them about an invalid IRQ. */ - if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15)) - pr_warn(" *** Warning: this IRQ is unlikely to work! ***\n"); - - { - static const char * const ram_split[] = { - "5:3", "3:1", "1:1", "3:5" - }; - __u32 config; - EL3WINDOW(3); - vp->available_media = inw(ioaddr + Wn3_Options); - config = inl(ioaddr + Wn3_Config); - if (corkscrew_debug > 1) - pr_info(" Internal config register is %4.4x, transceivers %#x.\n", - config, inw(ioaddr + Wn3_Options)); - pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << config & Ram_size, - config & Ram_width ? "word" : "byte", - ram_split[(config & Ram_split) >> Ram_split_shift], - config & Autoselect ? "autoselect/" : "", - media_tbl[(config & Xcvr) >> Xcvr_shift].name); - vp->default_media = (config & Xcvr) >> Xcvr_shift; - vp->autoselect = config & Autoselect ? 1 : 0; - dev->if_port = vp->default_media; - } - if (vp->media_override != 7) { - pr_info(" Media override to transceiver type %d (%s).\n", - vp->media_override, - media_tbl[vp->media_override].name); - dev->if_port = vp->media_override; - } - - vp->capabilities = eeprom[16]; - vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0; - /* Rx is broken at 10mbps, so we always disable it. */ - /* vp->full_bus_master_rx = 0; */ - vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0; - - /* The 3c51x-specific entries in the device structure. */ - dev->netdev_ops = &netdev_ops; - dev->watchdog_timeo = (400 * HZ) / 1000; - dev->ethtool_ops = &netdev_ethtool_ops; - - return register_netdev(dev); -} - - -static int corkscrew_open(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct corkscrew_private *vp = netdev_priv(dev); - bool armtimer = false; - __u32 config; - int i; - - /* Before initializing select the active media port. */ - EL3WINDOW(3); - if (vp->full_duplex) - outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ - config = inl(ioaddr + Wn3_Config); - - if (vp->media_override != 7) { - if (corkscrew_debug > 1) - pr_info("%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); - dev->if_port = vp->media_override; - } else if (vp->autoselect) { - /* Find first available media type, starting with 100baseTx. */ - dev->if_port = 4; - while (!(vp->available_media & media_tbl[dev->if_port].mask)) - dev->if_port = media_tbl[dev->if_port].next; - - if (corkscrew_debug > 1) - pr_debug("%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); - armtimer = true; - } else - dev->if_port = vp->default_media; - - config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift); - outl(config, ioaddr + Wn3_Config); - - if (corkscrew_debug > 1) { - pr_debug("%s: corkscrew_open() InternalConfig %8.8x.\n", - dev->name, config); - } - - outw(TxReset, ioaddr + EL3_CMD); - for (i = 20; i >= 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - - outw(RxReset, ioaddr + EL3_CMD); - /* Wait a few ticks for the RxReset command to complete. */ - for (i = 20; i >= 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - - outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - - /* Use the now-standard shared IRQ implementation. */ - if (vp->capabilities == 0x11c7) { - /* Corkscrew: Cannot share ISA resources. */ - if (dev->irq == 0 || - dev->dma == 0 || - request_irq(dev->irq, corkscrew_interrupt, 0, - vp->product_name, dev)) - return -EAGAIN; - enable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - } else if (request_irq(dev->irq, corkscrew_interrupt, IRQF_SHARED, - vp->product_name, dev)) { - return -EAGAIN; - } - - if (armtimer) - mod_timer(&vp->timer, jiffies + media_tbl[dev->if_port].wait); - - if (corkscrew_debug > 1) { - EL3WINDOW(4); - pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + Wn4_Media)); - } - - /* Set the station address and mask in window 2 each time opened. */ - EL3WINDOW(2); - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - for (; i < 12; i += 2) - outw(0, ioaddr + i); - - if (dev->if_port == 3) - /* Start the thinnet transceiver. We should really wait 50ms... */ - outw(StartCoax, ioaddr + EL3_CMD); - EL3WINDOW(4); - outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i = 0; i < 10; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - /* New: On the Vortex we must also clear the BadSSD counter. */ - EL3WINDOW(4); - inb(ioaddr + 12); - /* ..and on the Boomerang we enable the extra statistics bits. */ - outw(0x0040, ioaddr + Wn4_NetDiag); - - /* Switch to register set 7 for normal use. */ - EL3WINDOW(7); - - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ - vp->cur_rx = vp->dirty_rx = 0; - if (corkscrew_debug > 2) - pr_debug("%s: Filling in the Rx ring.\n", dev->name); - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - if (i < (RX_RING_SIZE - 1)) - vp->rx_ring[i].next = - isa_virt_to_bus(&vp->rx_ring[i + 1]); - else - vp->rx_ring[i].next = 0; - vp->rx_ring[i].status = 0; /* Clear complete bit. */ - vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000; - skb = netdev_alloc_skb(dev, PKT_BUF_SZ); - vp->rx_skbuff[i] = skb; - if (skb == NULL) - break; /* Bad news! */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = isa_virt_to_bus(skb->data); - } - if (i != 0) - vp->rx_ring[i - 1].next = - isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ - outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); - } - if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ - vp->cur_tx = vp->dirty_tx = 0; - outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold); /* Room for a packet. */ - /* Clear the Tx ring. */ - for (i = 0; i < TX_RING_SIZE; i++) - vp->tx_skbuff[i] = NULL; - outl(0, ioaddr + DownListPtr); - } - /* Set receiver mode: presumably accept b-case and phys addr only. */ - set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - netif_start_queue(dev); - - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull | - (vp->full_bus_master_tx ? DownComplete : TxAvailable) | - (vp->full_bus_master_rx ? UpComplete : RxComplete) | - (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete, - ioaddr + EL3_CMD); - - return 0; -} - -static void corkscrew_timer(struct timer_list *t) -{ -#ifdef AUTOMEDIA - struct corkscrew_private *vp = timer_container_of(vp, t, timer); - struct net_device *dev = vp->our_dev; - int ioaddr = dev->base_addr; - unsigned long flags; - int ok = 0; - - if (corkscrew_debug > 1) - pr_debug("%s: Media selection timer tick happened, %s.\n", - dev->name, media_tbl[dev->if_port].name); - - spin_lock_irqsave(&vp->lock, flags); - - { - int old_window = inw(ioaddr + EL3_CMD) >> 13; - int media_status; - EL3WINDOW(4); - media_status = inw(ioaddr + Wn4_Media); - switch (dev->if_port) { - case 0: - case 4: - case 5: /* 10baseT, 100baseTX, 100baseFX */ - if (media_status & Media_LnkBeat) { - ok = 1; - if (corkscrew_debug > 1) - pr_debug("%s: Media %s has link beat, %x.\n", - dev->name, - media_tbl[dev->if_port].name, - media_status); - } else if (corkscrew_debug > 1) - pr_debug("%s: Media %s is has no link beat, %x.\n", - dev->name, - media_tbl[dev->if_port].name, - media_status); - - break; - default: /* Other media types handled by Tx timeouts. */ - if (corkscrew_debug > 1) - pr_debug("%s: Media %s is has no indication, %x.\n", - dev->name, - media_tbl[dev->if_port].name, - media_status); - ok = 1; - } - if (!ok) { - __u32 config; - - do { - dev->if_port = - media_tbl[dev->if_port].next; - } - while (!(vp->available_media & media_tbl[dev->if_port].mask)); - - if (dev->if_port == 8) { /* Go back to default. */ - dev->if_port = vp->default_media; - if (corkscrew_debug > 1) - pr_debug("%s: Media selection failing, using default %s port.\n", - dev->name, - media_tbl[dev->if_port].name); - } else { - if (corkscrew_debug > 1) - pr_debug("%s: Media selection failed, now trying %s port.\n", - dev->name, - media_tbl[dev->if_port].name); - vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; - add_timer(&vp->timer); - } - outw((media_status & ~(Media_10TP | Media_SQE)) | - media_tbl[dev->if_port].media_bits, - ioaddr + Wn4_Media); - - EL3WINDOW(3); - config = inl(ioaddr + Wn3_Config); - config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift); - outl(config, ioaddr + Wn3_Config); - - outw(dev->if_port == 3 ? StartCoax : StopCoax, - ioaddr + EL3_CMD); - } - EL3WINDOW(old_window); - } - - spin_unlock_irqrestore(&vp->lock, flags); - if (corkscrew_debug > 1) - pr_debug("%s: Media selection timer finished, %s.\n", - dev->name, media_tbl[dev->if_port].name); - -#endif /* AUTOMEDIA */ -} - -static void corkscrew_timeout(struct net_device *dev, unsigned int txqueue) -{ - int i; - struct corkscrew_private *vp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - pr_warn("%s: transmit timed out, tx_status %2.2x status %4.4x\n", - dev->name, inb(ioaddr + TxStatus), - inw(ioaddr + EL3_STATUS)); - /* Slight code bloat to be user friendly. */ - if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) - pr_warn("%s: Transmitter encountered 16 collisions -- network cable problem?\n", - dev->name); -#ifndef final_version - pr_debug(" Flags; bus-master %d, full %d; dirty %d current %d.\n", - vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, - vp->cur_tx); - pr_debug(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), - &vp->tx_ring[0]); - for (i = 0; i < TX_RING_SIZE; i++) { - pr_debug(" %d: %p length %8.8x status %8.8x\n", i, - &vp->tx_ring[i], - vp->tx_ring[i].length, vp->tx_ring[i].status); - } -#endif - /* Issue TX_RESET and TX_START commands. */ - outw(TxReset, ioaddr + EL3_CMD); - for (i = 20; i >= 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - outw(TxEnable, ioaddr + EL3_CMD); - netif_trans_update(dev); /* prevent tx timeout */ - dev->stats.tx_errors++; - dev->stats.tx_dropped++; - netif_wake_queue(dev); -} - -static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct corkscrew_private *vp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - /* Block a timer-based transmit from overlapping. */ - - netif_stop_queue(dev); - - if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */ - /* Calculate the next Tx descriptor entry. */ - int entry = vp->cur_tx % TX_RING_SIZE; - struct boom_tx_desc *prev_entry; - unsigned long flags; - int i; - - if (vp->tx_full) /* No room to transmit with */ - return NETDEV_TX_BUSY; - if (vp->cur_tx != 0) - prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE]; - else - prev_entry = NULL; - if (corkscrew_debug > 3) - pr_debug("%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); - /* vp->tx_full = 1; */ - vp->tx_skbuff[entry] = skb; - vp->tx_ring[entry].next = 0; - vp->tx_ring[entry].addr = isa_virt_to_bus(skb->data); - vp->tx_ring[entry].length = skb->len | 0x80000000; - vp->tx_ring[entry].status = skb->len | 0x80000000; - - spin_lock_irqsave(&vp->lock, flags); - outw(DownStall, ioaddr + EL3_CMD); - /* Wait for the stall to complete. */ - for (i = 20; i >= 0; i--) - if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) - break; - if (prev_entry) - prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]); - if (inl(ioaddr + DownListPtr) == 0) { - outl(isa_virt_to_bus(&vp->tx_ring[entry]), - ioaddr + DownListPtr); - queued_packet++; - } - outw(DownUnstall, ioaddr + EL3_CMD); - spin_unlock_irqrestore(&vp->lock, flags); - - vp->cur_tx++; - if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) - vp->tx_full = 1; - else { /* Clear previous interrupt enable. */ - if (prev_entry) - prev_entry->status &= ~0x80000000; - netif_wake_queue(dev); - } - return NETDEV_TX_OK; - } - /* Put out the doubleword header... */ - outl(skb->len, ioaddr + TX_FIFO); - dev->stats.tx_bytes += skb->len; -#ifdef VORTEX_BUS_MASTER - if (vp->bus_master) { - /* Set the bus-master controller to transfer the packet. */ - outl(isa_virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr); - outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); - vp->tx_skb = skb; - outw(StartDMADown, ioaddr + EL3_CMD); - /* queue will be woken at the DMADone interrupt. */ - } else { - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb(skb); - if (inw(ioaddr + TxFree) > 1536) { - netif_wake_queue(dev); - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536 >> 2), - ioaddr + EL3_CMD); - } -#else - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb(skb); - if (inw(ioaddr + TxFree) > 1536) { - netif_wake_queue(dev); - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD); -#endif /* bus master */ - - - /* Clear the Tx status stack. */ - { - short tx_status; - int i = 4; - - while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { - if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ - if (corkscrew_debug > 2) - pr_debug("%s: Tx error, status %2.2x.\n", - dev->name, tx_status); - if (tx_status & 0x04) - dev->stats.tx_fifo_errors++; - if (tx_status & 0x38) - dev->stats.tx_aborted_errors++; - if (tx_status & 0x30) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j = 20; j >= 0; j--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - } - outw(TxEnable, ioaddr + EL3_CMD); - } - outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ - } - } - return NETDEV_TX_OK; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ - -static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) -{ - /* Use the now-standard shared IRQ implementation. */ - struct net_device *dev = dev_id; - struct corkscrew_private *lp = netdev_priv(dev); - int ioaddr, status; - int latency; - int i = max_interrupt_work; - - ioaddr = dev->base_addr; - latency = inb(ioaddr + Timer); - - spin_lock(&lp->lock); - - status = inw(ioaddr + EL3_STATUS); - - if (corkscrew_debug > 4) - pr_debug("%s: interrupt, status %4.4x, timer %d.\n", - dev->name, status, latency); - if ((status & 0xE000) != 0xE000) { - static int donedidthis; - /* Some interrupt controllers store a bogus interrupt from boot-time. - Ignore a single early interrupt, but don't hang the machine for - other interrupt problems. */ - if (donedidthis++ > 100) { - pr_err("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", - dev->name, status, netif_running(dev)); - free_irq(dev->irq, dev); - dev->irq = -1; - } - } - - do { - if (corkscrew_debug > 5) - pr_debug("%s: In interrupt loop, status %4.4x.\n", - dev->name, status); - if (status & RxComplete) - corkscrew_rx(dev); - - if (status & TxAvailable) { - if (corkscrew_debug > 5) - pr_debug(" TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); - } - if (status & DownComplete) { - unsigned int dirty_tx = lp->dirty_tx; - - while (lp->cur_tx - dirty_tx > 0) { - int entry = dirty_tx % TX_RING_SIZE; - if (inl(ioaddr + DownListPtr) == isa_virt_to_bus(&lp->tx_ring[entry])) - break; /* It still hasn't been processed. */ - if (lp->tx_skbuff[entry]) { - dev_consume_skb_irq(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] = NULL; - } - dirty_tx++; - } - lp->dirty_tx = dirty_tx; - outw(AckIntr | DownComplete, ioaddr + EL3_CMD); - if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { - lp->tx_full = 0; - netif_wake_queue(dev); - } - } -#ifdef VORTEX_BUS_MASTER - if (status & DMADone) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - dev_consume_skb_irq(lp->tx_skb); /* Release the transferred buffer */ - netif_wake_queue(dev); - } -#endif - if (status & UpComplete) { - boomerang_rx(dev); - outw(AckIntr | UpComplete, ioaddr + EL3_CMD); - } - if (status & (AdapterFailure | RxEarly | StatsFull)) { - /* Handle all uncommon interrupts at once. */ - if (status & RxEarly) { /* Rx early is unused. */ - corkscrew_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & StatsFull) { /* Empty statistics. */ - static int DoneDidThat; - if (corkscrew_debug > 4) - pr_debug("%s: Updating stats.\n", dev->name); - update_stats(ioaddr, dev); - /* DEBUG HACK: Disable statistics as an interrupt source. */ - /* This occurs when we have the wrong media type! */ - if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) { - int win, reg; - pr_notice("%s: Updating stats failed, disabling stats as an interrupt source.\n", - dev->name); - for (win = 0; win < 8; win++) { - EL3WINDOW(win); - pr_notice("Vortex window %d:", win); - for (reg = 0; reg < 16; reg++) - pr_cont(" %2.2x", inb(ioaddr + reg)); - pr_cont("\n"); - } - EL3WINDOW(7); - outw(SetIntrEnb | TxAvailable | - RxComplete | AdapterFailure | - UpComplete | DownComplete | - TxComplete, ioaddr + EL3_CMD); - DoneDidThat++; - } - } - if (status & AdapterFailure) { - /* Adapter failure requires Rx reset and reinit. */ - outw(RxReset, ioaddr + EL3_CMD); - /* Set the Rx filter to the current state. */ - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | AdapterFailure, - ioaddr + EL3_CMD); - } - } - - if (--i < 0) { - pr_err("%s: Too much work in interrupt, status %4.4x. Disabling functions (%4.4x).\n", - dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); - /* Disable all pending interrupts. */ - outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); - outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); - - spin_unlock(&lp->lock); - - if (corkscrew_debug > 4) - pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); - return IRQ_HANDLED; -} - -static int corkscrew_rx(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - int i; - short rx_status; - - if (corkscrew_debug > 5) - pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); - while ((rx_status = inw(ioaddr + RxStatus)) > 0) { - if (rx_status & 0x4000) { /* Error, update stats. */ - unsigned char rx_error = inb(ioaddr + RxErrors); - if (corkscrew_debug > 2) - pr_debug(" Rx error: status %2.2x.\n", - rx_error); - dev->stats.rx_errors++; - if (rx_error & 0x01) - dev->stats.rx_over_errors++; - if (rx_error & 0x02) - dev->stats.rx_length_errors++; - if (rx_error & 0x04) - dev->stats.rx_frame_errors++; - if (rx_error & 0x08) - dev->stats.rx_crc_errors++; - if (rx_error & 0x10) - dev->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - short pkt_len = rx_status & 0x1fff; - struct sk_buff *skb; - - skb = netdev_alloc_skb(dev, pkt_len + 5 + 2); - if (corkscrew_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb != NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, - skb_put(skb, pkt_len), - (pkt_len + 3) >> 2); - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - /* Wait a limited time to go to next packet. */ - for (i = 200; i >= 0; i--) - if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - continue; - } else if (corkscrew_debug) - pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); - } - outw(RxDiscard, ioaddr + EL3_CMD); - dev->stats.rx_dropped++; - /* Wait a limited time to skip this packet. */ - for (i = 200; i >= 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - } - return 0; -} - -static int boomerang_rx(struct net_device *dev) -{ - struct corkscrew_private *vp = netdev_priv(dev); - int entry = vp->cur_rx % RX_RING_SIZE; - int ioaddr = dev->base_addr; - int rx_status; - - if (corkscrew_debug > 5) - pr_debug(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); - while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) { - if (rx_status & RxDError) { /* Error, update stats. */ - unsigned char rx_error = rx_status >> 16; - if (corkscrew_debug > 2) - pr_debug(" Rx error: status %2.2x.\n", - rx_error); - dev->stats.rx_errors++; - if (rx_error & 0x01) - dev->stats.rx_over_errors++; - if (rx_error & 0x02) - dev->stats.rx_length_errors++; - if (rx_error & 0x04) - dev->stats.rx_frame_errors++; - if (rx_error & 0x08) - dev->stats.rx_crc_errors++; - if (rx_error & 0x10) - dev->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - short pkt_len = rx_status & 0x1fff; - struct sk_buff *skb; - - dev->stats.rx_bytes += pkt_len; - if (corkscrew_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - - /* Check if the packet is long enough to just accept without - copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb = netdev_alloc_skb(dev, pkt_len + 4)) != NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - skb_put_data(skb, - isa_bus_to_virt(vp->rx_ring[entry].addr), - pkt_len); - rx_copy++; - } else { - void *temp; - /* Pass up the skbuff already on the Rx ring. */ - skb = vp->rx_skbuff[entry]; - vp->rx_skbuff[entry] = NULL; - temp = skb_put(skb, pkt_len); - /* Remove this checking code for final release. */ - if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp) - pr_warn("%s: Warning -- the skbuff addresses do not match in boomerang_rx: %p vs. %p / %p\n", - dev->name, - isa_bus_to_virt(vp->rx_ring[entry].addr), - skb->head, temp); - rx_nocopy++; - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - } - entry = (++vp->cur_rx) % RX_RING_SIZE; - } - /* Refill the Rx ring buffers. */ - for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) { - struct sk_buff *skb; - entry = vp->dirty_rx % RX_RING_SIZE; - if (vp->rx_skbuff[entry] == NULL) { - skb = netdev_alloc_skb(dev, PKT_BUF_SZ); - if (skb == NULL) - break; /* Bad news! */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data); - vp->rx_skbuff[entry] = skb; - } - vp->rx_ring[entry].status = 0; /* Clear complete bit. */ - } - return 0; -} - -static int corkscrew_close(struct net_device *dev) -{ - struct corkscrew_private *vp = netdev_priv(dev); - int ioaddr = dev->base_addr; - int i; - - netif_stop_queue(dev); - - if (corkscrew_debug > 1) { - pr_debug("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n", - dev->name, inw(ioaddr + EL3_STATUS), - inb(ioaddr + TxStatus)); - pr_debug("%s: corkscrew close stats: rx_nocopy %d rx_copy %d tx_queued %d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet); - } - - timer_delete_sync(&vp->timer); - - /* Turn off statistics ASAP. We update lp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port == XCVR_10base2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - - free_irq(dev->irq, dev); - - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - - update_stats(ioaddr, dev); - if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ - outl(0, ioaddr + UpListPtr); - for (i = 0; i < RX_RING_SIZE; i++) - if (vp->rx_skbuff[i]) { - dev_kfree_skb(vp->rx_skbuff[i]); - vp->rx_skbuff[i] = NULL; - } - } - if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - outl(0, ioaddr + DownListPtr); - for (i = 0; i < TX_RING_SIZE; i++) - if (vp->tx_skbuff[i]) { - dev_kfree_skb(vp->tx_skbuff[i]); - vp->tx_skbuff[i] = NULL; - } - } - - return 0; -} - -static struct net_device_stats *corkscrew_get_stats(struct net_device *dev) -{ - struct corkscrew_private *vp = netdev_priv(dev); - unsigned long flags; - - if (netif_running(dev)) { - spin_lock_irqsave(&vp->lock, flags); - update_stats(dev->base_addr, dev); - spin_unlock_irqrestore(&vp->lock, flags); - } - return &dev->stats; -} - -/* Update statistics. - Unlike with the EL3 we need not worry about interrupts changing - the window setting from underneath us, but we must still guard - against a race condition with a StatsUpdate interrupt updating the - table. This is done by checking that the ASM (!) code generated uses - atomic updates with '+='. - */ -static void update_stats(int ioaddr, struct net_device *dev) -{ - /* Unlike the 3c5x9 we need not turn off stats updates while reading. */ - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors += inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - dev->stats.collisions += inb(ioaddr + 3); - dev->stats.tx_window_errors += inb(ioaddr + 4); - dev->stats.rx_fifo_errors += inb(ioaddr + 5); - dev->stats.tx_packets += inb(ioaddr + 6); - dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); - /* Must read to clear */ - /* Tx deferrals */ inb(ioaddr + 8); - /* Don't bother with register 9, an extension of registers 6&7. - If we do use the 6&7 values the atomic update assumption above - is invalid. */ - inw(ioaddr + 10); /* Total Rx and Tx octets. */ - inw(ioaddr + 12); - /* New: On the Vortex we must also clear the BadSSD counter. */ - EL3WINDOW(4); - inb(ioaddr + 12); - - /* We change back to window 7 (not 1) with the Vortex. */ - EL3WINDOW(7); -} - -/* This new version of set_rx_mode() supports v1.4 kernels. - The Vortex chip has no documented multicast filter, so the only - multicast setting is to receive all multicast frames. At least - the chip has a very clean way to set the mode, unlike many others. */ -static void set_rx_mode(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - unsigned short new_mode; - - if (dev->flags & IFF_PROMISC) { - if (corkscrew_debug > 3) - pr_debug("%s: Setting promiscuous mode.\n", - dev->name); - new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm; - } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) { - new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast; - } else - new_mode = SetRxFilter | RxStation | RxBroadcast; - - outw(new_mode, ioaddr + EL3_CMD); -} - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - snprintf(info->bus_info, sizeof(info->bus_info), "ISA 0x%lx", - dev->base_addr); -} - -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return corkscrew_debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 level) -{ - corkscrew_debug = level; -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, - .get_msglevel = netdev_get_msglevel, - .set_msglevel = netdev_set_msglevel, -}; - -#ifdef MODULE -static void __exit corkscrew_exit_module(void) -{ - while (!list_empty(&root_corkscrew_dev)) { - struct net_device *dev; - struct corkscrew_private *vp; - - vp = list_entry(root_corkscrew_dev.next, - struct corkscrew_private, list); - dev = vp->our_dev; - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } -} -module_exit(corkscrew_exit_module); -#endif /* MODULE */ diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c deleted file mode 100644 index 1f2070497a75..000000000000 --- a/drivers/net/ethernet/3com/3c574_cs.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner". - - Written 1993-1998 by - Donald Becker, becker@scyld.com, (driver core) and - David Hinds, dahinds@users.sourceforge.net (from his PC card code). - Locking fixes (C) Copyright 2003 Red Hat Inc - - This software may be used and distributed according to the terms of - the GNU General Public License, incorporated herein by reference. - - This driver derives from Donald Becker's 3c509 core, which has the - following copyright: - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - - -*/ - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the 3Com 3c574 PC card Fast Ethernet -Adapter. - -II. Board-specific settings - -None -- PC cards are autoconfigured. - -III. Driver operation - -The 3c574 uses a Boomerang-style interface, without the bus-master capability. -See the Boomerang driver and documentation for most details. - -IV. Notes and chip documentation. - -Two added registers are used to enhance PIO performance, RunnerRdCtrl and -RunnerWrCtrl. These are 11 bit down-counters that are preloaded with the -count of word (16 bits) reads or writes the driver is about to do to the Rx -or Tx FIFO. The chip is then able to hide the internal-PCI-bus to PC-card -translation latency by buffering the I/O operations with an 8 word FIFO. -Note: No other chip accesses are permitted when this buffer is used. - -A second enhancement is that both attribute and common memory space -0x0800-0x0fff can translated to the PIO FIFO. Thus memory operations (faster -with *some* PCcard bridges) may be used instead of I/O operations. -This is enabled by setting the 0x10 bit in the PCMCIA LAN COR. - -Some slow PC card bridges work better if they never see a WAIT signal. -This is configured by setting the 0x20 bit in the PCMCIA LAN COR. -Only do this after testing that it is reliable and improves performance. - -The upper five bits of RunnerRdCtrl are used to window into PCcard -configuration space registers. Window 0 is the regular Boomerang/Odie -register set, 1-5 are various PC card control registers, and 16-31 are -the (reversed!) CIS table. - -A final note: writing the InternalConfig register in window 3 with an -invalid ramWidth is Very Bad. - -V. References - -http://www.scyld.com/expert/NWay.html -http://www.national.com/opf/DP/DP83840A.html - -Thanks to Terry Murphy of 3Com for providing development information for -earlier 3Com products. - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("3Com 3c574 series PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -INT_MODULE_PARM(max_interrupt_work, 32); - -/* Force full duplex modes? */ -INT_MODULE_PARM(full_duplex, 0); - -/* Autodetect link polarity reversal? */ -INT_MODULE_PARM(auto_polarity, 1); - - -/*====================================================================*/ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((800*HZ)/1000) - -/* To minimize the size of the driver source and make the driver more - readable not all constants are symbolically defined. - You'll need the manual if you want to understand driver details anyway. */ -/* Offsets from base I/O address. */ -#define EL3_DATA 0x00 -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. */ -enum el3_cmds { - TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, - RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11, - TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, - FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, - SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, - SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11, - StatsDisable = 22<<11, StopCoax = 23<<11, -}; - -enum elxl_status { - IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, - TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, - IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 }; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 -}; - -enum Window0 { - Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */ - IntrStatus=0x0E, /* Valid in all windows. */ -}; -/* These assumes the larger EEPROM. */ -enum Win0_EEPROM_cmds { - EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300, - EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ -}; - -/* Register window 1 offsets, the window used in normal operation. - On the "Odie" this window is always mapped at offsets 0x10-0x1f. - Except for TxFree, which is overlapped by RunnerWrCtrl. */ -enum Window1 { - TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14, - RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B, - TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */ - RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c, -}; - -enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, -}; -enum wn3_config { - Ram_size = 7, - Ram_width = 8, - Ram_speed = 0x30, - Rom_size = 0xc0, - Ram_split_shift = 16, - Ram_split = 3 << Ram_split_shift, - Xcvr_shift = 20, - Xcvr = 7 << Xcvr_shift, - Autoselect = 0x1000000, -}; - -enum Window4 { /* Window 4: Xcvr/media bits. */ - Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10, -}; - -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ - -struct el3_private { - struct pcmcia_device *p_dev; - u16 advertising, partner; /* NWay media advertisement */ - unsigned char phys; /* MII device address */ - unsigned int autoselect:1, default_media:3; /* Read from the EEPROM/Wn3_Config. */ - /* for transceiver monitoring */ - struct timer_list media; - unsigned short media_status; - unsigned short fast_poll; - unsigned long last_irq; - spinlock_t window_lock; /* Guards the Window selection */ -}; - -/* Set iff a MII transceiver on any interface requires mdio preamble. - This only set with the original DP83840 on older 3c905 boards, so the extra - code size of a per-interface flag is not worthwhile. */ -static char mii_preamble_required = 0; - -/* Index of functions. */ - -static int tc574_config(struct pcmcia_device *link); -static void tc574_release(struct pcmcia_device *link); - -static void mdio_sync(unsigned int ioaddr, int bits); -static int mdio_read(unsigned int ioaddr, int phy_id, int location); -static void mdio_write(unsigned int ioaddr, int phy_id, int location, - int value); -static unsigned short read_eeprom(unsigned int ioaddr, int index); -static void tc574_wait_for_completion(struct net_device *dev, int cmd); - -static void tc574_reset(struct net_device *dev); -static void media_check(struct timer_list *t); -static int el3_open(struct net_device *dev); -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id); -static void update_stats(struct net_device *dev); -static struct net_device_stats *el3_get_stats(struct net_device *dev); -static int el3_rx(struct net_device *dev, int worklimit); -static int el3_close(struct net_device *dev); -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue); -static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); - -static void tc574_detach(struct pcmcia_device *p_dev); - -/* - tc574_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. -*/ -static const struct net_device_ops el3_netdev_ops = { - .ndo_open = el3_open, - .ndo_stop = el3_close, - .ndo_start_xmit = el3_start_xmit, - .ndo_tx_timeout = el3_tx_timeout, - .ndo_get_stats = el3_get_stats, - .ndo_eth_ioctl = el3_ioctl, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int tc574_probe(struct pcmcia_device *link) -{ - struct el3_private *lp; - struct net_device *dev; - - dev_dbg(&link->dev, "3c574_attach()\n"); - - /* Create the PC card device object. */ - dev = alloc_etherdev(sizeof(struct el3_private)); - if (!dev) - return -ENOMEM; - lp = netdev_priv(dev); - link->priv = dev; - lp->p_dev = link; - - spin_lock_init(&lp->window_lock); - link->resource[0]->end = 32; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; - link->config_flags |= CONF_ENABLE_IRQ; - link->config_index = 1; - - dev->netdev_ops = &el3_netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - return tc574_config(link); -} - -static void tc574_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - dev_dbg(&link->dev, "3c574_detach()\n"); - - unregister_netdev(dev); - - tc574_release(link); - - free_netdev(dev); -} /* tc574_detach */ - -static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - -static int tc574_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct el3_private *lp = netdev_priv(dev); - int ret, i, j; - __be16 addr[ETH_ALEN / 2]; - unsigned int ioaddr; - char *cardname; - __u32 config; - u8 *buf; - size_t len; - - dev_dbg(&link->dev, "3c574_config()\n"); - - link->io_lines = 16; - - for (i = j = 0; j < 0x400; j += 0x20) { - link->resource[0]->start = j ^ 0x300; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) - goto failed; - - ret = pcmcia_request_irq(link, el3_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - - ioaddr = dev->base_addr; - - /* The 3c574 normally uses an EEPROM for configuration info, including - the hardware address. The future products may include a modem chip - and put the address in the CIS. */ - - len = pcmcia_get_tuple(link, 0x88, &buf); - if (buf && len >= 6) { - for (i = 0; i < 3; i++) - addr[i] = htons(le16_to_cpu(buf[i * 2])); - kfree(buf); - } else { - kfree(buf); /* 0 < len < 6 */ - EL3WINDOW(0); - for (i = 0; i < 3; i++) - addr[i] = htons(read_eeprom(ioaddr, i + 10)); - if (addr[0] == htons(0x6060)) { - pr_notice("IO port conflict at 0x%03lx-0x%03lx\n", - dev->base_addr, dev->base_addr+15); - goto failed; - } - } - eth_hw_addr_set(dev, (u8 *)addr); - if (link->prod_id[1]) - cardname = link->prod_id[1]; - else - cardname = "3Com 3c574"; - - { - u_char mcr; - outw(2<<11, ioaddr + RunnerRdCtrl); - mcr = inb(ioaddr + 2); - outw(0<<11, ioaddr + RunnerRdCtrl); - pr_info(" ASIC rev %d,", mcr>>3); - EL3WINDOW(3); - config = inl(ioaddr + Wn3_Config); - lp->default_media = (config & Xcvr) >> Xcvr_shift; - lp->autoselect = config & Autoselect ? 1 : 0; - } - - timer_setup(&lp->media, media_check, 0); - - { - int phy; - - /* Roadrunner only: Turn on the MII transceiver */ - outw(0x8040, ioaddr + Wn3_Options); - mdelay(1); - outw(0xc040, ioaddr + Wn3_Options); - tc574_wait_for_completion(dev, TxReset); - tc574_wait_for_completion(dev, RxReset); - mdelay(1); - outw(0x8040, ioaddr + Wn3_Options); - - EL3WINDOW(4); - for (phy = 1; phy <= 32; phy++) { - int mii_status; - mdio_sync(ioaddr, 32); - mii_status = mdio_read(ioaddr, phy & 0x1f, 1); - if (mii_status != 0xffff) { - lp->phys = phy & 0x1f; - dev_dbg(&link->dev, " MII transceiver at " - "index %d, status %x.\n", - phy, mii_status); - if ((mii_status & 0x0040) == 0) - mii_preamble_required = 1; - break; - } - } - if (phy > 32) { - pr_notice(" No MII transceivers found!\n"); - goto failed; - } - i = mdio_read(ioaddr, lp->phys, 16) | 0x40; - mdio_write(ioaddr, lp->phys, 16, i); - lp->advertising = mdio_read(ioaddr, lp->phys, 4); - if (full_duplex) { - /* Only advertise the FD media types. */ - lp->advertising &= ~0x02a0; - mdio_write(ioaddr, lp->phys, 4, lp->advertising); - } - } - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) != 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n", - cardname, dev->base_addr, dev->irq, dev->dev_addr); - netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n", - 8 << (config & Ram_size), - ram_split[(config & Ram_split) >> Ram_split_shift], - config & Autoselect ? "autoselect " : ""); - - return 0; - -failed: - tc574_release(link); - return -ENODEV; - -} /* tc574_config */ - -static void tc574_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int tc574_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int tc574_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - tc574_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -static void dump_status(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - EL3WINDOW(1); - netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x, tx free %04x\n", - inw(ioaddr+EL3_STATUS), - inw(ioaddr+RxStatus), inb(ioaddr+TxStatus), - inw(ioaddr+TxFree)); - EL3WINDOW(4); - netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n", - inw(ioaddr+0x04), inw(ioaddr+0x06), - inw(ioaddr+0x08), inw(ioaddr+0x0a)); - EL3WINDOW(1); -} - -/* - Use this for commands that may take time to finish -*/ -static void tc574_wait_for_completion(struct net_device *dev, int cmd) -{ - int i = 1500; - outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; - if (i == 0) - netdev_notice(dev, "command 0x%04x did not complete!\n", cmd); -} - -/* Read a word from the EEPROM using the regular EEPROM access register. - Assume that we are in register window zero. - */ -static unsigned short read_eeprom(unsigned int ioaddr, int index) -{ - int timer; - outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 usec for the read to take place. */ - for (timer = 1620; timer >= 0; timer--) { - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) - break; - } - return inw(ioaddr + Wn0EepromData); -} - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. - The maxium data clock rate is 2.5 Mhz. The timing is easily met by the - slow PC card interface. */ - -#define MDIO_SHIFT_CLK 0x01 -#define MDIO_DIR_WRITE 0x04 -#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE) -#define MDIO_DATA_READ 0x02 -#define MDIO_ENB_IN 0x00 - -/* Generate the preamble required for initial synchronization and - a few older transceivers. */ -static void mdio_sync(unsigned int ioaddr, int bits) -{ - unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt; - - /* Establish sync by sending at least 32 logic ones. */ - while (-- bits >= 0) { - outw(MDIO_DATA_WRITE1, mdio_addr); - outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - } -} - -static int mdio_read(unsigned int ioaddr, int phy_id, int location) -{ - int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; - unsigned int retval = 0; - unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt; - - if (mii_preamble_required) - mdio_sync(ioaddr, 32); - - /* Shift the read command bits out. */ - for (i = 14; i >= 0; i--) { - int dataval = (read_cmd&(1< 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); - retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(unsigned int ioaddr, int phy_id, int location, int value) -{ - int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; - unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt; - int i; - - if (mii_preamble_required) - mdio_sync(ioaddr, 32); - - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (write_cmd&(1<= 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - } -} - -/* Reset and restore all of the 3c574 registers. */ -static void tc574_reset(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - int i; - unsigned int ioaddr = dev->base_addr; - unsigned long flags; - - tc574_wait_for_completion(dev, TotalReset|0x10); - - spin_lock_irqsave(&lp->window_lock, flags); - /* Clear any transactions in progress. */ - outw(0, ioaddr + RunnerWrCtrl); - outw(0, ioaddr + RunnerRdCtrl); - - /* Set the station address and mask. */ - EL3WINDOW(2); - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - for (; i < 12; i+=2) - outw(0, ioaddr + i); - - /* Reset config options */ - EL3WINDOW(3); - outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); - outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b, - ioaddr + Wn3_Config); - /* Roadrunner only: Turn on the MII transceiver. */ - outw(0x8040, ioaddr + Wn3_Options); - mdelay(1); - outw(0xc040, ioaddr + Wn3_Options); - EL3WINDOW(1); - spin_unlock_irqrestore(&lp->window_lock, flags); - - tc574_wait_for_completion(dev, TxReset); - tc574_wait_for_completion(dev, RxReset); - mdelay(1); - spin_lock_irqsave(&lp->window_lock, flags); - EL3WINDOW(3); - outw(0x8040, ioaddr + Wn3_Options); - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i = 0; i < 10; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - EL3WINDOW(4); - inb(ioaddr + 12); - inb(ioaddr + 13); - - /* .. enable any extra statistics bits.. */ - outw(0x0040, ioaddr + Wn4_NetDiag); - - EL3WINDOW(1); - spin_unlock_irqrestore(&lp->window_lock, flags); - - /* .. re-sync MII and re-fill what NWay is advertising. */ - mdio_sync(ioaddr, 32); - mdio_write(ioaddr, lp->phys, 4, lp->advertising); - if (!auto_polarity) { - /* works for TDK 78Q2120 series MII's */ - i = mdio_read(ioaddr, lp->phys, 16) | 0x20; - mdio_write(ioaddr, lp->phys, 16, i); - } - - spin_lock_irqsave(&lp->window_lock, flags); - /* Switch to register set 1 for normal use, just for TxFree. */ - set_rx_mode(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | AdapterFailure | RxEarly, ioaddr + EL3_CMD); -} - -static int el3_open(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - link->open++; - netif_start_queue(dev); - - tc574_reset(dev); - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); - - dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", - dev->name, inw(dev->base_addr + EL3_STATUS)); - - return 0; -} - -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - unsigned int ioaddr = dev->base_addr; - - netdev_notice(dev, "Transmit timed out!\n"); - dump_status(dev); - dev->stats.tx_errors++; - netif_trans_update(dev); /* prevent tx timeout */ - /* Issue TX_RESET and TX_START commands. */ - tc574_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - netif_wake_queue(dev); -} - -static void pop_tx_status(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - int i; - - /* Clear the Tx status stack. */ - for (i = 32; i > 0; i--) { - u_char tx_status = inb(ioaddr + TxStatus); - if (!(tx_status & 0x84)) - break; - /* reset transmitter on jabber error or underrun */ - if (tx_status & 0x30) - tc574_wait_for_completion(dev, TxReset); - if (tx_status & 0x38) { - pr_debug("%s: transmit error: status 0x%02x\n", - dev->name, tx_status); - outw(TxEnable, ioaddr + EL3_CMD); - dev->stats.tx_aborted_errors++; - } - outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ - } -} - -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct el3_private *lp = netdev_priv(dev); - unsigned long flags; - - pr_debug("%s: el3_start_xmit(length = %ld) called, " - "status %4.4x.\n", dev->name, (long)skb->len, - inw(ioaddr + EL3_STATUS)); - - spin_lock_irqsave(&lp->window_lock, flags); - - dev->stats.tx_bytes += skb->len; - - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2); - - /* TxFree appears only in Window 1, not offset 0x1c. */ - if (inw(ioaddr + TxFree) <= 1536) { - netif_stop_queue(dev); - /* Interrupt us when the FIFO has room for max-sized packet. - The threshold is in units of dwords. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - } - - pop_tx_status(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -/* The EL3 interrupt handler. */ -static irqreturn_t el3_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct el3_private *lp = netdev_priv(dev); - unsigned int ioaddr; - unsigned status; - int work_budget = max_interrupt_work; - int handled = 0; - - if (!netif_device_present(dev)) - return IRQ_NONE; - ioaddr = dev->base_addr; - - pr_debug("%s: interrupt, status %4.4x.\n", - dev->name, inw(ioaddr + EL3_STATUS)); - - spin_lock(&lp->window_lock); - - while ((status = inw(ioaddr + EL3_STATUS)) & - (IntLatch | RxComplete | RxEarly | StatsFull)) { - if (!netif_device_present(dev) || - ((status & 0xe000) != 0x2000)) { - pr_debug("%s: Interrupt from dead card\n", dev->name); - break; - } - - handled = 1; - - if (status & RxComplete) - work_budget = el3_rx(dev, work_budget); - - if (status & TxAvailable) { - pr_debug(" TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); - } - - if (status & TxComplete) - pop_tx_status(dev); - - if (status & (AdapterFailure | RxEarly | StatsFull)) { - /* Handle all uncommon interrupts. */ - if (status & StatsFull) - update_stats(dev); - if (status & RxEarly) { - work_budget = el3_rx(dev, work_budget); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & AdapterFailure) { - u16 fifo_diag; - EL3WINDOW(4); - fifo_diag = inw(ioaddr + Wn4_FIFODiag); - EL3WINDOW(1); - netdev_notice(dev, "adapter failure, FIFO diagnostic register %04x\n", - fifo_diag); - if (fifo_diag & 0x0400) { - /* Tx overrun */ - tc574_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - } - if (fifo_diag & 0x2000) { - /* Rx underrun */ - tc574_wait_for_completion(dev, RxReset); - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); - } - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); - } - } - - if (--work_budget < 0) { - pr_debug("%s: Too much work in interrupt, " - "status %4.4x.\n", dev->name, status); - /* Clear all interrupts */ - outw(AckIntr | 0xFF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } - - pr_debug("%s: exiting interrupt, status %4.4x.\n", - dev->name, inw(ioaddr + EL3_STATUS)); - - spin_unlock(&lp->window_lock); - return IRQ_RETVAL(handled); -} - -/* - This timer serves two purposes: to check for missed interrupts - (and as a last resort, poll the NIC for events), and to monitor - the MII, reporting changes in cable status. -*/ -static void media_check(struct timer_list *t) -{ - struct el3_private *lp = timer_container_of(lp, t, media); - struct net_device *dev = lp->p_dev->priv; - unsigned int ioaddr = dev->base_addr; - unsigned long flags; - unsigned short /* cable, */ media, partner; - - if (!netif_device_present(dev)) - goto reschedule; - - /* Check for pending interrupt with expired latency timer: with - this, we can limp along even if the interrupt is blocked */ - if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) { - if (!lp->fast_poll) - netdev_info(dev, "interrupt(s) dropped!\n"); - - local_irq_save(flags); - el3_interrupt(dev->irq, dev); - local_irq_restore(flags); - - lp->fast_poll = HZ; - } - if (lp->fast_poll) { - lp->fast_poll--; - lp->media.expires = jiffies + 2*HZ/100; - add_timer(&lp->media); - return; - } - - spin_lock_irqsave(&lp->window_lock, flags); - EL3WINDOW(4); - media = mdio_read(ioaddr, lp->phys, 1); - partner = mdio_read(ioaddr, lp->phys, 5); - EL3WINDOW(1); - - if (media != lp->media_status) { - if ((media ^ lp->media_status) & 0x0004) - netdev_info(dev, "%s link beat\n", - (lp->media_status & 0x0004) ? "lost" : "found"); - if ((media ^ lp->media_status) & 0x0020) { - lp->partner = 0; - if (lp->media_status & 0x0020) { - netdev_info(dev, "autonegotiation restarted\n"); - } else if (partner) { - partner &= lp->advertising; - lp->partner = partner; - netdev_info(dev, "autonegotiation complete: " - "%dbaseT-%cD selected\n", - (partner & 0x0180) ? 100 : 10, - (partner & 0x0140) ? 'F' : 'H'); - } else { - netdev_info(dev, "link partner did not autonegotiate\n"); - } - - EL3WINDOW(3); - outb((partner & 0x0140 ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); - EL3WINDOW(1); - - } - if (media & 0x0010) - netdev_info(dev, "remote fault detected\n"); - if (media & 0x0002) - netdev_info(dev, "jabber detected\n"); - lp->media_status = media; - } - spin_unlock_irqrestore(&lp->window_lock, flags); - -reschedule: - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); -} - -static struct net_device_stats *el3_get_stats(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - - if (netif_device_present(dev)) { - unsigned long flags; - spin_lock_irqsave(&lp->window_lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - } - return &dev->stats; -} - -/* Update statistics. - Surprisingly this need not be run single-threaded, but it effectively is. - The counters clear when read, so the adds must merely be atomic. - */ -static void update_stats(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - u8 up; - - pr_debug("%s: updating the statistics.\n", dev->name); - - if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */ - return; - - /* Unlike the 3c509 we need not turn off stats updates while reading. */ - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors += inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - dev->stats.collisions += inb(ioaddr + 3); - dev->stats.tx_window_errors += inb(ioaddr + 4); - dev->stats.rx_fifo_errors += inb(ioaddr + 5); - dev->stats.tx_packets += inb(ioaddr + 6); - up = inb(ioaddr + 9); - dev->stats.tx_packets += (up&0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); - /* Tx deferrals */ inb(ioaddr + 8); - /* rx */ inw(ioaddr + 10); - /* tx */ inw(ioaddr + 12); - - EL3WINDOW(4); - /* BadSSD */ inb(ioaddr + 12); - up = inb(ioaddr + 13); - - EL3WINDOW(1); -} - -static int el3_rx(struct net_device *dev, int worklimit) -{ - unsigned int ioaddr = dev->base_addr; - short rx_status; - - pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n", - dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); - while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) && - worklimit > 0) { - worklimit--; - if (rx_status & 0x4000) { /* Error, update stats. */ - short error = rx_status & 0x3800; - dev->stats.rx_errors++; - switch (error) { - case 0x0000: dev->stats.rx_over_errors++; break; - case 0x0800: dev->stats.rx_length_errors++; break; - case 0x1000: dev->stats.rx_frame_errors++; break; - case 0x1800: dev->stats.rx_length_errors++; break; - case 0x2000: dev->stats.rx_frame_errors++; break; - case 0x2800: dev->stats.rx_crc_errors++; break; - } - } else { - short pkt_len = rx_status & 0x7ff; - struct sk_buff *skb; - - skb = netdev_alloc_skb(dev, pkt_len + 5); - - pr_debug(" Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb != NULL) { - skb_reserve(skb, 2); - insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), - ((pkt_len+3)>>2)); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } else { - pr_debug("%s: couldn't allocate a sk_buff of" - " size %d.\n", dev->name, pkt_len); - dev->stats.rx_dropped++; - } - } - tc574_wait_for_completion(dev, RxDiscard); - } - - return worklimit; -} - -/* Provide ioctl() calls to examine the MII xcvr state. */ -static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct el3_private *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - struct mii_ioctl_data *data = if_mii(rq); - int phy = lp->phys & 0x1f; - - pr_debug("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", - dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data->phy_id, data->reg_num, data->val_in, data->val_out); - - switch(cmd) { - case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data->phy_id = phy; - fallthrough; - case SIOCGMIIREG: /* Read the specified MII register. */ - { - int saved_window; - unsigned long flags; - - spin_lock_irqsave(&lp->window_lock, flags); - saved_window = inw(ioaddr + EL3_CMD) >> 13; - EL3WINDOW(4); - data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, - data->reg_num & 0x1f); - EL3WINDOW(saved_window); - spin_unlock_irqrestore(&lp->window_lock, flags); - return 0; - } - case SIOCSMIIREG: /* Write the specified MII register */ - { - int saved_window; - unsigned long flags; - - spin_lock_irqsave(&lp->window_lock, flags); - saved_window = inw(ioaddr + EL3_CMD) >> 13; - EL3WINDOW(4); - mdio_write(ioaddr, data->phy_id & 0x1f, - data->reg_num & 0x1f, data->val_in); - EL3WINDOW(saved_window); - spin_unlock_irqrestore(&lp->window_lock, flags); - return 0; - } - default: - return -EOPNOTSUPP; - } -} - -/* The Odie chip has a 64 bin multicast filter, but the bit layout is not - documented. Until it is we revert to receiving all multicast frames when - any multicast reception is desired. - Note: My other drivers emit a log message whenever promiscuous mode is - entered to help detect password sniffers. This is less desirable on - typical PC card machines, so we omit the message. - */ - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - - if (dev->flags & IFF_PROMISC) - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, - ioaddr + EL3_CMD); - else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) - outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); - else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); -} - -static void set_multicast_list(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&lp->window_lock, flags); - set_rx_mode(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); -} - -static int el3_close(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct el3_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - - dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); - - if (pcmcia_dev_present(link)) { - unsigned long flags; - - /* Turn off statistics ASAP. We update lp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - /* Note: Switching to window 0 may disable the IRQ. */ - EL3WINDOW(0); - spin_lock_irqsave(&lp->window_lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - - /* force interrupts off */ - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - } - - link->open--; - netif_stop_queue(dev); - timer_delete_sync(&lp->media); - - return 0; -} - -static const struct pcmcia_device_id tc574_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, tc574_ids); - -static struct pcmcia_driver tc574_driver = { - .owner = THIS_MODULE, - .name = "3c574_cs", - .probe = tc574_probe, - .remove = tc574_detach, - .id_table = tc574_ids, - .suspend = tc574_suspend, - .resume = tc574_resume, -}; -module_pcmcia_driver(tc574_driver); diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c deleted file mode 100644 index ea49be43b8c3..000000000000 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ /dev/null @@ -1,974 +0,0 @@ -/* ====================================================================== - * - * A PCMCIA ethernet driver for the 3com 3c589 card. - * - * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - * - * 3c589_cs.c 1.162 2001/10/13 00:08:50 - * - * The network driver code is based on Donald Becker's 3c589 code: - * - * Written 1994 by Donald Becker. - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. This software may be used and - * distributed according to the terms of the GNU General Public License, - * incorporated herein by reference. - * Donald Becker may be reached at becker@scyld.com - * - * Updated for 2.5.x by Alan Cox - * - * ====================================================================== - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DRV_NAME "3c589_cs" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -/* To minimize the size of the driver source I only define operating - * constants if they are used several times. You'll need the manual - * if you want to understand driver details. - */ - -/* Offsets from base I/O address. */ -#define EL3_DATA 0x00 -#define EL3_TIMER 0x0a -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -#define EEPROM_READ 0x0080 -#define EEPROM_BUSY 0x8000 - -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) - -/* The top five bits written to EL3_CMD are a command, the lower - * 11 bits are the parameter, if applicable. - */ - -enum c509cmd { - TotalReset = 0<<11, - SelectWindow = 1<<11, - StartCoax = 2<<11, - RxDisable = 3<<11, - RxEnable = 4<<11, - RxReset = 5<<11, - RxDiscard = 8<<11, - TxEnable = 9<<11, - TxDisable = 10<<11, - TxReset = 11<<11, - FakeIntr = 12<<11, - AckIntr = 13<<11, - SetIntrEnb = 14<<11, - SetStatusEnb = 15<<11, - SetRxFilter = 16<<11, - SetRxThreshold = 17<<11, - SetTxThreshold = 18<<11, - SetTxStart = 19<<11, - StatsEnable = 21<<11, - StatsDisable = 22<<11, - StopCoax = 23<<11 -}; - -enum c509status { - IntLatch = 0x0001, - AdapterFailure = 0x0002, - TxComplete = 0x0004, - TxAvailable = 0x0008, - RxComplete = 0x0010, - RxEarly = 0x0020, - IntReq = 0x0040, - StatsFull = 0x0080, - CmdBusy = 0x1000 -}; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation = 1, - RxMulticast = 2, - RxBroadcast = 4, - RxProm = 8 -}; - -/* Register window 1 offsets, the window used in normal operation. */ -#define TX_FIFO 0x00 -#define RX_FIFO 0x00 -#define RX_STATUS 0x08 -#define TX_STATUS 0x0B -#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ - -#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ -#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ -#define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */ - -/* Time in jiffies before concluding Tx hung */ -#define TX_TIMEOUT ((400*HZ)/1000) - -struct el3_private { - struct pcmcia_device *p_dev; - /* For transceiver monitoring */ - struct timer_list media; - u16 media_status; - u16 fast_poll; - unsigned long last_irq; - spinlock_t lock; -}; - -static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" }; - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -/* Special hook for setting if_port when module is loaded */ -INT_MODULE_PARM(if_port, 0); - - -/*====================================================================*/ - -static int tc589_config(struct pcmcia_device *link); -static void tc589_release(struct pcmcia_device *link); - -static u16 read_eeprom(unsigned int ioaddr, int index); -static void tc589_reset(struct net_device *dev); -static void media_check(struct timer_list *t); -static int el3_config(struct net_device *dev, struct ifmap *map); -static int el3_open(struct net_device *dev); -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id); -static void update_stats(struct net_device *dev); -static struct net_device_stats *el3_get_stats(struct net_device *dev); -static int el3_rx(struct net_device *dev); -static int el3_close(struct net_device *dev); -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue); -static void set_rx_mode(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static const struct ethtool_ops netdev_ethtool_ops; - -static void tc589_detach(struct pcmcia_device *p_dev); - -static const struct net_device_ops el3_netdev_ops = { - .ndo_open = el3_open, - .ndo_stop = el3_close, - .ndo_start_xmit = el3_start_xmit, - .ndo_tx_timeout = el3_tx_timeout, - .ndo_set_config = el3_config, - .ndo_get_stats = el3_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int tc589_probe(struct pcmcia_device *link) -{ - struct el3_private *lp; - struct net_device *dev; - int ret; - - dev_dbg(&link->dev, "3c589_attach()\n"); - - /* Create new ethernet device */ - dev = alloc_etherdev(sizeof(struct el3_private)); - if (!dev) - return -ENOMEM; - lp = netdev_priv(dev); - link->priv = dev; - lp->p_dev = link; - - spin_lock_init(&lp->lock); - link->resource[0]->end = 16; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; - - link->config_flags |= CONF_ENABLE_IRQ; - link->config_index = 1; - - dev->netdev_ops = &el3_netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - dev->ethtool_ops = &netdev_ethtool_ops; - - ret = tc589_config(link); - if (ret) - goto err_free_netdev; - - return 0; - -err_free_netdev: - free_netdev(dev); - return ret; -} - -static void tc589_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - dev_dbg(&link->dev, "3c589_detach\n"); - - unregister_netdev(dev); - - tc589_release(link); - - free_netdev(dev); -} /* tc589_detach */ - -static int tc589_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - int ret, i, j, multi = 0, fifo; - __be16 addr[ETH_ALEN / 2]; - unsigned int ioaddr; - static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - u8 *buf; - size_t len; - - dev_dbg(&link->dev, "3c589_config\n"); - - /* Is this a 3c562? */ - if (link->manf_id != MANFID_3COM) - dev_info(&link->dev, "hmmm, is this really a 3Com card??\n"); - multi = (link->card_id == PRODID_3COM_3C562); - - link->io_lines = 16; - - /* For the 3c562, the base address must be xx00-xx7f */ - for (i = j = 0; j < 0x400; j += 0x10) { - if (multi && (j & 0x80)) - continue; - link->resource[0]->start = j ^ 0x300; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) - goto failed; - - ret = pcmcia_request_irq(link, el3_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - ioaddr = dev->base_addr; - EL3WINDOW(0); - - /* The 3c589 has an extra EEPROM for configuration info, including - * the hardware address. The 3c562 puts the address in the CIS. - */ - len = pcmcia_get_tuple(link, 0x88, &buf); - if (buf && len >= 6) { - for (i = 0; i < 3; i++) - addr[i] = htons(le16_to_cpu(buf[i*2])); - kfree(buf); - } else { - kfree(buf); /* 0 < len < 6 */ - for (i = 0; i < 3; i++) - addr[i] = htons(read_eeprom(ioaddr, i)); - if (addr[0] == htons(0x6060)) { - dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n", - dev->base_addr, dev->base_addr+15); - goto failed; - } - } - eth_hw_addr_set(dev, (u8 *)addr); - - /* The address and resource configuration register aren't loaded from - * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. - */ - - outw(0x3f00, ioaddr + 8); - fifo = inl(ioaddr); - - /* The if_port symbol can be set when the module is loaded */ - if ((if_port >= 0) && (if_port <= 3)) - dev->if_port = if_port; - else - dev_err(&link->dev, "invalid if_port requested\n"); - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) != 0) { - dev_err(&link->dev, "register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n", - (multi ? "562" : "589"), dev->base_addr, dev->irq, - dev->dev_addr); - netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n", - (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], - if_names[dev->if_port]); - return 0; - -failed: - tc589_release(link); - return -ENODEV; -} /* tc589_config */ - -static void tc589_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int tc589_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int tc589_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - tc589_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -/*====================================================================*/ - -/* Use this for commands that may take time to finish */ - -static void tc589_wait_for_completion(struct net_device *dev, int cmd) -{ - int i = 100; - outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) - break; - if (i == 0) - netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); -} - -/* Read a word from the EEPROM using the regular EEPROM access register. - * Assume that we are in register window zero. - */ - -static u16 read_eeprom(unsigned int ioaddr, int index) -{ - int i; - outw(EEPROM_READ + index, ioaddr + 10); - /* Reading the eeprom takes 162 us */ - for (i = 1620; i >= 0; i--) - if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0) - break; - return inw(ioaddr + 12); -} - -/* Set transceiver type, perhaps to something other than what the user - * specified in dev->if_port. - */ - -static void tc589_set_xcvr(struct net_device *dev, int if_port) -{ - struct el3_private *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - - EL3WINDOW(0); - switch (if_port) { - case 0: - case 1: - outw(0, ioaddr + 6); - break; - case 2: - outw(3<<14, ioaddr + 6); - break; - case 3: - outw(1<<14, ioaddr + 6); - break; - } - /* On PCMCIA, this just turns on the LED */ - outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); - /* 10baseT interface, enable link beat and jabber check. */ - EL3WINDOW(4); - outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); - EL3WINDOW(1); - if (if_port == 2) - lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000); - else - lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800); -} - -static void dump_status(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - EL3WINDOW(1); - netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), - inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); - EL3WINDOW(4); - netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n", - inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), - inw(ioaddr+0x0a)); - EL3WINDOW(1); -} - -/* Reset and restore all of the 3c589 registers. */ -static void tc589_reset(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - int i; - - EL3WINDOW(0); - outw(0x0001, ioaddr + 4); /* Activate board. */ - outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ - - /* Set the station address in window 2. */ - EL3WINDOW(2); - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - - tc589_set_xcvr(dev, dev->if_port); - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i = 0; i < 9; i++) - inb(ioaddr+i); - inw(ioaddr + 10); - inw(ioaddr + 12); - - /* Switch to register set 1 for normal use. */ - EL3WINDOW(1); - - set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | AdapterFailure, ioaddr + EL3_CMD); -} - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - snprintf(info->bus_info, sizeof(info->bus_info), - "PCMCIA 0x%lx", dev->base_addr); -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, -}; - -static int el3_config(struct net_device *dev, struct ifmap *map) -{ - if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - if (map->port <= 3) { - WRITE_ONCE(dev->if_port, map->port); - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - tc589_set_xcvr(dev, dev->if_port); - } else { - return -EINVAL; - } - } - return 0; -} - -static int el3_open(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - link->open++; - netif_start_queue(dev); - - tc589_reset(dev); - timer_setup(&lp->media, media_check, 0); - mod_timer(&lp->media, jiffies + HZ); - - dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", - dev->name, inw(dev->base_addr + EL3_STATUS)); - - return 0; -} - -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - unsigned int ioaddr = dev->base_addr; - - netdev_warn(dev, "Transmit timed out!\n"); - dump_status(dev); - dev->stats.tx_errors++; - netif_trans_update(dev); /* prevent tx timeout */ - /* Issue TX_RESET and TX_START commands. */ - tc589_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - netif_wake_queue(dev); -} - -static void pop_tx_status(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - int i; - - /* Clear the Tx status stack. */ - for (i = 32; i > 0; i--) { - u_char tx_status = inb(ioaddr + TX_STATUS); - if (!(tx_status & 0x84)) - break; - /* reset transmitter on jabber error or underrun */ - if (tx_status & 0x30) - tc589_wait_for_completion(dev, TxReset); - if (tx_status & 0x38) { - netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status); - outw(TxEnable, ioaddr + EL3_CMD); - dev->stats.tx_aborted_errors++; - } - outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ - } -} - -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct el3_private *priv = netdev_priv(dev); - unsigned long flags; - - netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n", - (long)skb->len, inw(ioaddr + EL3_STATUS)); - - spin_lock_irqsave(&priv->lock, flags); - - dev->stats.tx_bytes += skb->len; - - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0x00, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - - if (inw(ioaddr + TX_FREE) <= 1536) { - netif_stop_queue(dev); - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); - } - - pop_tx_status(dev); - spin_unlock_irqrestore(&priv->lock, flags); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -/* The EL3 interrupt handler. */ -static irqreturn_t el3_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct el3_private *lp = netdev_priv(dev); - unsigned int ioaddr; - __u16 status; - int i = 0, handled = 1; - - if (!netif_device_present(dev)) - return IRQ_NONE; - - ioaddr = dev->base_addr; - - netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); - - spin_lock(&lp->lock); - while ((status = inw(ioaddr + EL3_STATUS)) & - (IntLatch | RxComplete | StatsFull)) { - if ((status & 0xe000) != 0x2000) { - netdev_dbg(dev, "interrupt from dead card\n"); - handled = 0; - break; - } - if (status & RxComplete) - el3_rx(dev); - if (status & TxAvailable) { - netdev_dbg(dev, " TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); - } - if (status & TxComplete) - pop_tx_status(dev); - if (status & (AdapterFailure | RxEarly | StatsFull)) { - /* Handle all uncommon interrupts. */ - if (status & StatsFull) /* Empty statistics. */ - update_stats(dev); - if (status & RxEarly) { - /* Rx early is unused. */ - el3_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & AdapterFailure) { - u16 fifo_diag; - EL3WINDOW(4); - fifo_diag = inw(ioaddr + 4); - EL3WINDOW(1); - netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", - fifo_diag); - if (fifo_diag & 0x0400) { - /* Tx overrun */ - tc589_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - } - if (fifo_diag & 0x2000) { - /* Rx underrun */ - tc589_wait_for_completion(dev, RxReset); - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); - } - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); - } - } - if (++i > 10) { - netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", - status); - /* Clear all interrupts */ - outw(AckIntr | 0xFF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } - lp->last_irq = jiffies; - spin_unlock(&lp->lock); - netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", - inw(ioaddr + EL3_STATUS)); - return IRQ_RETVAL(handled); -} - -static void media_check(struct timer_list *t) -{ - struct el3_private *lp = timer_container_of(lp, t, media); - struct net_device *dev = lp->p_dev->priv; - unsigned int ioaddr = dev->base_addr; - u16 media, errs; - unsigned long flags; - - if (!netif_device_present(dev)) - goto reschedule; - - /* Check for pending interrupt with expired latency timer: with - * this, we can limp along even if the interrupt is blocked - */ - if ((inw(ioaddr + EL3_STATUS) & IntLatch) && - (inb(ioaddr + EL3_TIMER) == 0xff)) { - if (!lp->fast_poll) - netdev_warn(dev, "interrupt(s) dropped!\n"); - - local_irq_save(flags); - el3_interrupt(dev->irq, dev); - local_irq_restore(flags); - - lp->fast_poll = HZ; - } - if (lp->fast_poll) { - lp->fast_poll--; - lp->media.expires = jiffies + HZ/100; - add_timer(&lp->media); - return; - } - - /* lp->lock guards the EL3 window. Window should always be 1 except - * when the lock is held - */ - - spin_lock_irqsave(&lp->lock, flags); - EL3WINDOW(4); - media = inw(ioaddr+WN4_MEDIA) & 0xc810; - - /* Ignore collisions unless we've had no irq's recently */ - if (time_before(jiffies, lp->last_irq + HZ)) { - media &= ~0x0010; - } else { - /* Try harder to detect carrier errors */ - EL3WINDOW(6); - outw(StatsDisable, ioaddr + EL3_CMD); - errs = inb(ioaddr + 0); - outw(StatsEnable, ioaddr + EL3_CMD); - dev->stats.tx_carrier_errors += errs; - if (errs || (lp->media_status & 0x0010)) - media |= 0x0010; - } - - if (media != lp->media_status) { - if ((media & lp->media_status & 0x8000) && - ((lp->media_status ^ media) & 0x0800)) - netdev_info(dev, "%s link beat\n", - (lp->media_status & 0x0800 ? "lost" : "found")); - else if ((media & lp->media_status & 0x4000) && - ((lp->media_status ^ media) & 0x0010)) - netdev_info(dev, "coax cable %s\n", - (lp->media_status & 0x0010 ? "ok" : "problem")); - if (dev->if_port == 0) { - if (media & 0x8000) { - if (media & 0x0800) - netdev_info(dev, "flipped to 10baseT\n"); - else - tc589_set_xcvr(dev, 2); - } else if (media & 0x4000) { - if (media & 0x0010) - tc589_set_xcvr(dev, 1); - else - netdev_info(dev, "flipped to 10base2\n"); - } - } - lp->media_status = media; - } - - EL3WINDOW(1); - spin_unlock_irqrestore(&lp->lock, flags); - -reschedule: - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); -} - -static struct net_device_stats *el3_get_stats(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link = lp->p_dev; - - if (pcmcia_dev_present(link)) { - spin_lock_irqsave(&lp->lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->lock, flags); - } - return &dev->stats; -} - -/* Update statistics. We change to register window 6, so this should be run -* single-threaded if the device is active. This is expected to be a rare -* operation, and it's simpler for the rest of the driver to assume that -* window 1 is always valid rather than use a special window-state variable. -* -* Caller must hold the lock for this -*/ - -static void update_stats(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - - netdev_dbg(dev, "updating the statistics.\n"); - /* Turn off statistics updates while reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors += inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); - /* Multiple collisions. */ - inb(ioaddr + 2); - dev->stats.collisions += inb(ioaddr + 3); - dev->stats.tx_window_errors += inb(ioaddr + 4); - dev->stats.rx_fifo_errors += inb(ioaddr + 5); - dev->stats.tx_packets += inb(ioaddr + 6); - /* Rx packets */ - inb(ioaddr + 7); - /* Tx deferrals */ - inb(ioaddr + 8); - /* Rx octets */ - inw(ioaddr + 10); - /* Tx octets */ - inw(ioaddr + 12); - - /* Back to window 1, and turn statistics back on. */ - EL3WINDOW(1); - outw(StatsEnable, ioaddr + EL3_CMD); -} - -static int el3_rx(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - int worklimit = 32; - short rx_status; - - netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); - while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) && - worklimit > 0) { - worklimit--; - if (rx_status & 0x4000) { /* Error, update stats. */ - short error = rx_status & 0x3800; - dev->stats.rx_errors++; - switch (error) { - case 0x0000: - dev->stats.rx_over_errors++; - break; - case 0x0800: - dev->stats.rx_length_errors++; - break; - case 0x1000: - dev->stats.rx_frame_errors++; - break; - case 0x1800: - dev->stats.rx_length_errors++; - break; - case 0x2000: - dev->stats.rx_frame_errors++; - break; - case 0x2800: - dev->stats.rx_crc_errors++; - break; - } - } else { - short pkt_len = rx_status & 0x7ff; - struct sk_buff *skb; - - skb = netdev_alloc_skb(dev, pkt_len + 5); - - netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb != NULL) { - skb_reserve(skb, 2); - insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), - (pkt_len+3)>>2); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } else { - netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n", - pkt_len); - dev->stats.rx_dropped++; - } - } - /* Pop the top of the Rx FIFO */ - tc589_wait_for_completion(dev, RxDiscard); - } - if (worklimit == 0) - netdev_warn(dev, "too much work in el3_rx!\n"); - return 0; -} - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - u16 opts = SetRxFilter | RxStation | RxBroadcast; - - if (dev->flags & IFF_PROMISC) - opts |= RxMulticast | RxProm; - else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) - opts |= RxMulticast; - outw(opts, ioaddr + EL3_CMD); -} - -static void set_multicast_list(struct net_device *dev) -{ - struct el3_private *priv = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - set_rx_mode(dev); - spin_unlock_irqrestore(&priv->lock, flags); -} - -static int el3_close(struct net_device *dev) -{ - struct el3_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - unsigned int ioaddr = dev->base_addr; - - dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); - - if (pcmcia_dev_present(link)) { - /* Turn off statistics ASAP. We update dev->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port == 2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 1) { - /* Disable link beat and jabber */ - EL3WINDOW(4); - outw(0, ioaddr + WN4_MEDIA); - } - - /* Switching back to window 0 disables the IRQ. */ - EL3WINDOW(0); - /* But we explicitly zero the IRQ line select anyway. */ - outw(0x0f00, ioaddr + WN0_IRQ); - - /* Check if the card still exists */ - if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000) - update_stats(dev); - } - - link->open--; - netif_stop_queue(dev); - timer_delete_sync(&lp->media); - - return 0; -} - -static const struct pcmcia_device_id tc589_ids[] = { - PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562), - PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77), - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589), - PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, tc589_ids); - -static struct pcmcia_driver tc589_driver = { - .owner = THIS_MODULE, - .name = "3c589_cs", - .probe = tc589_probe, - .remove = tc589_detach, - .id_table = tc589_ids, - .suspend = tc589_suspend, - .resume = tc589_resume, -}; -module_pcmcia_driver(tc589_driver); diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig index 1fbab79e2be4..399cb6c56198 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -17,51 +17,6 @@ config NET_VENDOR_3COM if NET_VENDOR_3COM -config EL3 - tristate "3c509/3c579 \"EtherLink III\" support" - depends on (ISA || EISA) - help - If you have a network (Ethernet) card belonging to the 3Com - EtherLinkIII series, say Y here. - - If your card is not working you may need to use the DOS - setup disk to disable Plug & Play mode, and to select the default - media type. - - To compile this driver as a module, choose M here. The module - will be called 3c509. - -config 3C515 - tristate "3c515 ISA \"Fast EtherLink\"" - depends on ISA && ISA_DMA_API && !PPC32 - select NETDEV_LEGACY_INIT - help - If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet - network card, say Y here. - - To compile this driver as a module, choose M here. The module - will be called 3c515. - -config PCMCIA_3C574 - tristate "3Com 3c574 PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA - (PC-card) Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called 3c574_cs. If unsure, say N. - -config PCMCIA_3C589 - tristate "3Com 3c589 PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA - (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called 3c589_cs. If unsure, say N. - config VORTEX tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support" depends on (PCI || EISA) && HAS_IOPORT_MAP diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile index f8b73babc510..5c4d07f1d456 100644 --- a/drivers/net/ethernet/3com/Makefile +++ b/drivers/net/ethernet/3com/Makefile @@ -3,9 +3,5 @@ # Makefile for the 3Com Ethernet device drivers # -obj-$(CONFIG_EL3) += 3c509.o -obj-$(CONFIG_3C515) += 3c515.o -obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o -obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_TYPHOON) += typhoon.o diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index 345f250781c6..5d12a595ab19 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -17,18 +17,6 @@ config NET_VENDOR_8390 if NET_VENDOR_8390 -config PCMCIA_AXNET - tristate "Asix AX88190 PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach an Asix AX88190-based PCMCIA - (PC-card) Fast Ethernet card to your computer. These cards are - nearly NE2000 compatible but need a separate driver due to a few - misfeatures. - - To compile this driver as a module, choose M here: the module will be - called axnet_cs. If unsure, say N. - config AX88796 tristate "ASIX AX88796 NE2000 clone support" if !ZORRO depends on (ARM || MIPS || SUPERH || ZORRO || COMPILE_TEST) @@ -167,35 +155,6 @@ config STNIC If unsure, say N. -config ULTRA - tristate "SMC Ultra support" - depends on ISA - select NETDEV_LEGACY_INIT - select CRC32 - help - If you have a network (Ethernet) card of this type, say Y here. - - Important: There have been many reports that, with some motherboards - mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, - such as some BusLogic models) causes corruption problems with many - operating systems. The Linux smc-ultra driver has a work-around for - this but keep it in mind if you have such a SCSI card and have - problems. - - To compile this driver as a module, choose M here. The module - will be called smc-ultra. - -config WD80x3 - tristate "WD80*3 support" - depends on ISA - select NETDEV_LEGACY_INIT - select CRC32 - help - If you have a network (Ethernet) card of this type, say Y here. - - To compile this driver as a module, choose M here. The module - will be called wd. - config ZORRO8390 tristate "Zorro NS8390-based Ethernet support" depends on ZORRO diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile index 85c83c566ec6..bca5babdadc7 100644 --- a/drivers/net/ethernet/8390/Makefile +++ b/drivers/net/ethernet/8390/Makefile @@ -11,10 +11,7 @@ obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_MCF8390) += mcf8390.o obj-$(CONFIG_NE2000) += ne.o 8390p.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o -obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o -obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o -obj-$(CONFIG_WD80x3) += wd.o 8390.o obj-$(CONFIG_XSURF100) += xsurf100.o obj-$(CONFIG_ZORRO8390) += zorro8390.o diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c deleted file mode 100644 index 7c8213011b5c..000000000000 --- a/drivers/net/ethernet/8390/axnet_cs.c +++ /dev/null @@ -1,1707 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ - -/*====================================================================== - - A PCMCIA ethernet driver for Asix AX88190-based cards - - The Asix AX88190 is a NS8390-derived chipset with a few nasty - idiosyncracies that make it very inconvenient to support with a - standard 8390 driver. This driver is based on pcnet_cs, with the - tweaked 8390 code grafted on the end. Much of what I did was to - clean up and update a similar driver supplied by Asix, which was - adapted by William Lee, william@asix.com.tw. - - Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net - - axnet_cs.c 1.28 2002/06/29 06:27:37 - - The network driver code is based on Donald Becker's NE2000 code: - - Written 1992,1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - Donald Becker may be reached at becker@scyld.com - -======================================================================*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "8390.h" - -#include -#include -#include -#include - -#include -#include -#include - -#define AXNET_CMD 0x00 -#define AXNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ -#define AXNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ -#define AXNET_MII_EEP 0x14 /* Offset of MII access port */ -#define AXNET_TEST 0x15 /* Offset of TEST Register port */ -#define AXNET_GPIO 0x17 /* Offset of General Purpose Register Port */ - -#define AXNET_START_PG 0x40 /* First page of TX buffer */ -#define AXNET_STOP_PG 0x80 /* Last page +1 of RX ring */ - -#define AXNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ - -#define IS_AX88190 0x0001 -#define IS_AX88790 0x0002 - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - - -/*====================================================================*/ - -static int axnet_config(struct pcmcia_device *link); -static void axnet_release(struct pcmcia_device *link); -static int axnet_open(struct net_device *dev); -static int axnet_close(struct net_device *dev); -static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static struct net_device_stats *get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue); -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id); -static void ei_watchdog(struct timer_list *t); -static void axnet_reset_8390(struct net_device *dev); - -static int mdio_read(unsigned int addr, int phy_id, int loc); -static void mdio_write(unsigned int addr, int phy_id, int loc, int value); - -static void get_8390_hdr(struct net_device *, - struct e8390_pkt_hdr *, int); -static void block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void block_output(struct net_device *dev, int count, - const u_char *buf, const int start_page); - -static void axnet_detach(struct pcmcia_device *p_dev); - -static void AX88190_init(struct net_device *dev, int startp); -static int ax_open(struct net_device *dev); -static int ax_close(struct net_device *dev); -static irqreturn_t ax_interrupt(int irq, void *dev_id); - -/*====================================================================*/ - -struct axnet_dev { - struct pcmcia_device *p_dev; - caddr_t base; - struct timer_list watchdog; - int stale, fast_poll; - u_short link_status; - u_char duplex_flag; - int phy_id; - int flags; - int active_low; -}; - -static inline struct axnet_dev *PRIV(struct net_device *dev) -{ - void *p = (char *)netdev_priv(dev) + sizeof(struct ei_device); - return p; -} - -static const struct net_device_ops axnet_netdev_ops = { - .ndo_open = axnet_open, - .ndo_stop = axnet_close, - .ndo_eth_ioctl = axnet_ioctl, - .ndo_start_xmit = axnet_start_xmit, - .ndo_tx_timeout = axnet_tx_timeout, - .ndo_get_stats = get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int axnet_probe(struct pcmcia_device *link) -{ - struct axnet_dev *info; - struct net_device *dev; - struct ei_device *ei_local; - - dev_dbg(&link->dev, "axnet_attach()\n"); - - dev = alloc_etherdev(sizeof(struct ei_device) + sizeof(struct axnet_dev)); - if (!dev) - return -ENOMEM; - - ei_local = netdev_priv(dev); - spin_lock_init(&ei_local->page_lock); - - info = PRIV(dev); - info->p_dev = link; - link->priv = dev; - link->config_flags |= CONF_ENABLE_IRQ; - - dev->netdev_ops = &axnet_netdev_ops; - - dev->watchdog_timeo = TX_TIMEOUT; - - return axnet_config(link); -} /* axnet_attach */ - -static void axnet_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - dev_dbg(&link->dev, "axnet_detach(0x%p)\n", link); - - unregister_netdev(dev); - - axnet_release(link); - - free_netdev(dev); -} /* axnet_detach */ - -/*====================================================================== - - This probes for a card's hardware address by reading the PROM. - -======================================================================*/ - -static int get_prom(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - unsigned int ioaddr = dev->base_addr; - u8 addr[ETH_ALEN]; - int i, j; - - /* This is based on drivers/net/ethernet/8390/ne.c */ - struct { - u_char value, offset; - } program_seq[] = { - {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ - {0x01, EN0_DCFG}, /* Set word-wide access. */ - {0x00, EN0_RCNTLO}, /* Clear the count regs. */ - {0x00, EN0_RCNTHI}, - {0x00, EN0_IMR}, /* Mask completion irq. */ - {0xFF, EN0_ISR}, - {E8390_RXOFF|0x40, EN0_RXCR}, /* 0x60 Set to monitor */ - {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ - {0x10, EN0_RCNTLO}, - {0x00, EN0_RCNTHI}, - {0x00, EN0_RSARLO}, /* DMA starting at 0x0400. */ - {0x04, EN0_RSARHI}, - {E8390_RREAD+E8390_START, E8390_CMD}, - }; - - /* Not much of a test, but the alternatives are messy */ - if (link->config_base != 0x03c0) - return 0; - - axnet_reset_8390(dev); - mdelay(10); - - for (i = 0; i < ARRAY_SIZE(program_seq); i++) - outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); - - for (i = 0; i < 6; i += 2) { - j = inw(ioaddr + AXNET_DATAPORT); - addr[i] = j & 0xff; - addr[i+1] = j >> 8; - } - eth_hw_addr_set(dev, addr); - - return 1; -} /* get_prom */ - -static int try_io_port(struct pcmcia_device *link) -{ - int j, ret; - link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; - if (link->resource[0]->end == 32) { - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - /* for master/slave multifunction cards */ - if (link->resource[1]->end > 0) - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - } else { - /* This should be two 16-port windows */ - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16; - } - if (link->resource[0]->start == 0) { - for (j = 0; j < 0x400; j += 0x20) { - link->resource[0]->start = j ^ 0x300; - link->resource[1]->start = (j ^ 0x300) + 0x10; - link->io_lines = 16; - ret = pcmcia_request_io(link); - if (ret == 0) - return ret; - } - return ret; - } else { - return pcmcia_request_io(link); - } -} - -static int axnet_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - p_dev->config_index = 0x05; - if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32) - return -ENODEV; - - return try_io_port(p_dev); -} - -static int axnet_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct axnet_dev *info = PRIV(dev); - int i, j, j2, ret; - - dev_dbg(&link->dev, "axnet_config(0x%p)\n", link); - - /* don't trust the CIS on this; Linksys got it wrong */ - link->config_regs = 0x63; - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - ret = pcmcia_loop_config(link, axnet_configcheck, NULL); - if (ret != 0) - goto failed; - - if (!link->irq) - goto failed; - - if (resource_size(link->resource[1]) == 8) - link->config_flags |= CONF_ENABLE_SPKR; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - - if (!get_prom(link)) { - pr_notice("this is not an AX88190 card!\n"); - pr_notice("use pcnet_cs instead.\n"); - goto failed; - } - - ei_status.name = "AX88190"; - ei_status.word16 = 1; - ei_status.tx_start_page = AXNET_START_PG; - ei_status.rx_start_page = AXNET_START_PG + TX_PAGES; - ei_status.stop_page = AXNET_STOP_PG; - ei_status.reset_8390 = axnet_reset_8390; - ei_status.get_8390_hdr = get_8390_hdr; - ei_status.block_input = block_input; - ei_status.block_output = block_output; - - if (inb(dev->base_addr + AXNET_TEST) != 0) - info->flags |= IS_AX88790; - else - info->flags |= IS_AX88190; - - if (info->flags & IS_AX88790) - outb(0x10, dev->base_addr + AXNET_GPIO); /* select Internal PHY */ - - info->active_low = 0; - - for (i = 0; i < 32; i++) { - j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); - j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2); - if (j == j2) continue; - if ((j != 0) && (j != 0xffff)) break; - } - - if (i == 32) { - /* Maybe PHY is in power down mode. (PPD_SET = 1) - Bit 2 of CCSR is active low. */ - pcmcia_write_config_byte(link, CISREG_CCSR, 0x04); - for (i = 0; i < 32; i++) { - j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); - j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2); - if (j == j2) continue; - if ((j != 0) && (j != 0xffff)) { - info->active_low = 1; - break; - } - } - } - - info->phy_id = (i < 32) ? i : -1; - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) != 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "Asix AX88%d90: io %#3lx, irq %d, hw_addr %pM\n", - ((info->flags & IS_AX88790) ? 7 : 1), - dev->base_addr, dev->irq, dev->dev_addr); - if (info->phy_id != -1) { - netdev_dbg(dev, " MII transceiver at index %d, status %x\n", - info->phy_id, j); - } else { - netdev_notice(dev, " No MII transceivers found!\n"); - } - return 0; - -failed: - axnet_release(link); - return -ENODEV; -} /* axnet_config */ - -static void axnet_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int axnet_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int axnet_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct axnet_dev *info = PRIV(dev); - - if (link->open) { - if (info->active_low == 1) - pcmcia_write_config_byte(link, CISREG_CCSR, 0x04); - - axnet_reset_8390(dev); - AX88190_init(dev, 1); - netif_device_attach(dev); - } - - return 0; -} - - -/*====================================================================== - - MII interface support - -======================================================================*/ - -#define MDIO_SHIFT_CLK 0x01 -#define MDIO_DATA_WRITE0 0x00 -#define MDIO_DATA_WRITE1 0x08 -#define MDIO_DATA_READ 0x04 -#define MDIO_MASK 0x0f -#define MDIO_ENB_IN 0x02 - -static void mdio_sync(unsigned int addr) -{ - int bits; - for (bits = 0; bits < 32; bits++) { - outb_p(MDIO_DATA_WRITE1, addr); - outb_p(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); - } -} - -static int mdio_read(unsigned int addr, int phy_id, int loc) -{ - u_int cmd = (0xf6<<10)|(phy_id<<5)|loc; - int i, retval = 0; - - mdio_sync(addr); - for (i = 14; i >= 0; i--) { - int dat = (cmd&(1< 0; i--) { - outb_p(MDIO_ENB_IN, addr); - retval = (retval << 1) | ((inb_p(addr) & MDIO_DATA_READ) != 0); - outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(unsigned int addr, int phy_id, int loc, int value) -{ - u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; - int i; - - mdio_sync(addr); - for (i = 31; i >= 0; i--) { - int dat = (cmd&(1<= 0; i--) { - outb_p(MDIO_ENB_IN, addr); - outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr); - } -} - -/*====================================================================*/ - -static int axnet_open(struct net_device *dev) -{ - int ret; - struct axnet_dev *info = PRIV(dev); - struct pcmcia_device *link = info->p_dev; - unsigned int nic_base = dev->base_addr; - - dev_dbg(&link->dev, "axnet_open('%s')\n", dev->name); - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */ - ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev); - if (ret) - return ret; - - link->open++; - - info->link_status = 0x00; - timer_setup(&info->watchdog, ei_watchdog, 0); - mod_timer(&info->watchdog, jiffies + HZ); - - return ax_open(dev); -} /* axnet_open */ - -/*====================================================================*/ - -static int axnet_close(struct net_device *dev) -{ - struct axnet_dev *info = PRIV(dev); - struct pcmcia_device *link = info->p_dev; - - dev_dbg(&link->dev, "axnet_close('%s')\n", dev->name); - - ax_close(dev); - free_irq(dev->irq, dev); - - link->open--; - netif_stop_queue(dev); - timer_delete_sync(&info->watchdog); - - return 0; -} /* axnet_close */ - -/*====================================================================== - - Hard reset the card. This used to pause for the same period that - a 8390 reset command required, but that shouldn't be necessary. - -======================================================================*/ - -static void axnet_reset_8390(struct net_device *dev) -{ - unsigned int nic_base = dev->base_addr; - int i; - - ei_status.txing = ei_status.dmaing = 0; - - outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD); - - outb(inb(nic_base + AXNET_RESET), nic_base + AXNET_RESET); - - for (i = 0; i < 100; i++) { - if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0) - break; - udelay(100); - } - outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */ - - if (i == 100) - netdev_err(dev, "axnet_reset_8390() did not complete\n"); - -} /* axnet_reset_8390 */ - -/*====================================================================*/ - -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - PRIV(dev)->stale = 0; - return ax_interrupt(irq, dev_id); -} - -static void ei_watchdog(struct timer_list *t) -{ - struct axnet_dev *info = timer_container_of(info, t, watchdog); - struct net_device *dev = info->p_dev->priv; - unsigned int nic_base = dev->base_addr; - unsigned int mii_addr = nic_base + AXNET_MII_EEP; - u_short link; - - if (!netif_device_present(dev)) goto reschedule; - - /* Check for pending interrupt with expired latency timer: with - this, we can limp along even if the interrupt is blocked */ - if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) { - if (!info->fast_poll) - netdev_info(dev, "interrupt(s) dropped!\n"); - ei_irq_wrapper(dev->irq, dev); - info->fast_poll = HZ; - } - if (info->fast_poll) { - info->fast_poll--; - info->watchdog.expires = jiffies + 1; - add_timer(&info->watchdog); - return; - } - - if (info->phy_id < 0) - goto reschedule; - link = mdio_read(mii_addr, info->phy_id, 1); - if (!link || (link == 0xffff)) { - netdev_info(dev, "MII is missing!\n"); - info->phy_id = -1; - goto reschedule; - } - - link &= 0x0004; - if (link != info->link_status) { - u_short p = mdio_read(mii_addr, info->phy_id, 5); - netdev_info(dev, "%s link beat\n", link ? "found" : "lost"); - if (link) { - info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00; - if (p) - netdev_info(dev, "autonegotiation complete: %dbaseT-%cD selected\n", - (p & 0x0180) ? 100 : 10, (p & 0x0140) ? 'F' : 'H'); - else - netdev_info(dev, "link partner did not autonegotiate\n"); - AX88190_init(dev, 1); - } - info->link_status = link; - } - -reschedule: - info->watchdog.expires = jiffies + HZ; - add_timer(&info->watchdog); -} - -/*====================================================================*/ - -static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct axnet_dev *info = PRIV(dev); - struct mii_ioctl_data *data = if_mii(rq); - unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP; - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = info->phy_id; - fallthrough; - case SIOCGMIIREG: /* Read MII PHY register. */ - data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f); - return 0; - case SIOCSMIIREG: /* Write MII PHY register. */ - mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in); - return 0; - } - return -EOPNOTSUPP; -} - -/*====================================================================*/ - -static void get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, - int ring_page) -{ - unsigned int nic_base = dev->base_addr; - - outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ - outb_p(ring_page, nic_base + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD); - - insw(nic_base + AXNET_DATAPORT, hdr, - sizeof(struct e8390_pkt_hdr)>>1); - /* Fix for big endian systems */ - hdr->count = le16_to_cpu(hdr->count); - -} - -/*====================================================================*/ - -static void block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset) -{ - unsigned int nic_base = dev->base_addr; - struct ei_device *ei_local = netdev_priv(dev); - char *buf = skb->data; - - if ((netif_msg_rx_status(ei_local)) && (count != 4)) - netdev_dbg(dev, "[bi=%d]\n", count+4); - outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); - outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD); - - insw(nic_base + AXNET_DATAPORT,buf,count>>1); - if (count & 0x01) { - buf[count-1] = inb(nic_base + AXNET_DATAPORT); - } -} - -/*====================================================================*/ - -static void block_output(struct net_device *dev, int count, - const u_char *buf, const int start_page) -{ - unsigned int nic_base = dev->base_addr; - - pr_debug("%s: [bo=%d]\n", dev->name, count); - - /* Round the count up for word writes. Do we need to do this? - What effect will an odd byte count have on the 8390? - I should check someday. */ - if (count & 0x01) - count++; - - outb_p(0x00, nic_base + EN0_RSARLO); - outb_p(start_page, nic_base + EN0_RSARHI); - outb_p(E8390_RWRITE+E8390_START, nic_base + AXNET_CMD); - outsw(nic_base + AXNET_DATAPORT, buf, count>>1); -} - -static const struct pcmcia_device_id axnet_ids[] = { - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081), - PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301), - PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106), - PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), - PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), - PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090), - PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc), - PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef), - PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef), - PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1), - PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc), - PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXM", 0x5261440f, 0x3abbd061), - PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90), - PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2), - PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8), - PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609), - PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058), - PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6, 0xab9be5ef), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, axnet_ids); - -static struct pcmcia_driver axnet_cs_driver = { - .owner = THIS_MODULE, - .name = "axnet_cs", - .probe = axnet_probe, - .remove = axnet_detach, - .id_table = axnet_ids, - .suspend = axnet_suspend, - .resume = axnet_resume, -}; -module_pcmcia_driver(axnet_cs_driver); - -/*====================================================================*/ - -/* 8390.c: A general NS8390 ethernet driver core for linux. */ -/* - Written 1992-94 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - This is the chip-specific code for many 8390-based ethernet adaptors. - This is not a complete driver, it must be combined with board-specific - code such as ne.c, wd.c, 3c503.c, etc. - - Seeing how at least eight drivers use this code, (not counting the - PCMCIA ones either) it is easy to break some card by what seems like - a simple innocent change. Please contact me or Donald if you think - you have found something that needs changing. -- PG - - Changelog: - - Paul Gortmaker : remove set_bit lock, other cleanups. - Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to - ei_block_input() for eth_io_copy_and_sum(). - Paul Gortmaker : exchange static int ei_pingpong for a #define, - also add better Tx error handling. - Paul Gortmaker : rewrite Rx overrun handling as per NS specs. - Alexey Kuznetsov : use the 8390's six bit hash multicast filter. - Paul Gortmaker : tweak ANK's above multicast changes a bit. - Paul Gortmaker : update packet statistics for v2.1.x - Alan Cox : support arbitrary stupid port mappings on the - 68K Macintosh. Support >16bit I/O spaces - Paul Gortmaker : add kmod support for auto-loading of the 8390 - module by all drivers that require it. - Alan Cox : Spinlocking work, added 'BUG_83C690' - Paul Gortmaker : Separate out Tx timeout code from Tx path. - - Sources: - The National Semiconductor LAN Databook, and the 3Com 3c503 databook. - - */ - -#include -#include -#include -#include -#include - -#define BUG_83C690 - -/* These are the operational function interfaces to board-specific - routines. - void reset_8390(struct net_device *dev) - Resets the board associated with DEV, including a hardware reset of - the 8390. This is only called when there is a transmit timeout, and - it is always followed by 8390_init(). - void block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) - Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The - "page" value uses the 8390's 256-byte pages. - void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page) - Read the 4 byte, page aligned 8390 header. *If* there is a - subsequent read, it will be of the rest of the packet. - void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) - Read COUNT bytes from the packet buffer into the skb data area. Start - reading from RING_OFFSET, the address as the 8390 sees it. This will always - follow the read of the 8390 header. -*/ -#define ei_reset_8390 (ei_local->reset_8390) -#define ei_block_output (ei_local->block_output) -#define ei_block_input (ei_local->block_input) -#define ei_get_8390_hdr (ei_local->get_8390_hdr) - -/* Index to functions. */ -static void ei_tx_intr(struct net_device *dev); -static void ei_tx_err(struct net_device *dev); -static void ei_receive(struct net_device *dev); -static void ei_rx_overrun(struct net_device *dev); - -/* Routines generic to NS8390-based boards. */ -static void NS8390_trigger_send(struct net_device *dev, unsigned int length, - int start_page); -static void do_set_multicast_list(struct net_device *dev); - -/* - * SMP and the 8390 setup. - * - * The 8390 isn't exactly designed to be multithreaded on RX/TX. There is - * a page register that controls bank and packet buffer access. We guard - * this with ei_local->page_lock. Nobody should assume or set the page other - * than zero when the lock is not held. Lock holders must restore page 0 - * before unlocking. Even pure readers must take the lock to protect in - * page 0. - * - * To make life difficult the chip can also be very slow. We therefore can't - * just use spinlocks. For the longer lockups we disable the irq the device - * sits on and hold the lock. We must hold the lock because there is a dual - * processor case other than interrupts (get stats/set multicast list in - * parallel with each other and transmit). - * - * Note: in theory we can just disable the irq on the card _but_ there is - * a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs" - * enter lock, take the queued irq. So we waddle instead of flying. - * - * Finally by special arrangement for the purpose of being generally - * annoying the transmit function is called bh atomic. That places - * restrictions on the user context callers as disable_irq won't save - * them. - */ - -/** - * ax_open - Open/initialize the board. - * @dev: network device to initialize - * - * This routine goes all-out, setting everything - * up anew at each open, even though many of these registers should only - * need to be set once at boot. - */ -static int ax_open(struct net_device *dev) -{ - unsigned long flags; - struct ei_device *ei_local = netdev_priv(dev); - - /* - * Grab the page lock so we own the register set, then call - * the init function. - */ - - spin_lock_irqsave(&ei_local->page_lock, flags); - AX88190_init(dev, 1); - /* Set the flag before we drop the lock, That way the IRQ arrives - after its set and we get no silly warnings */ - netif_start_queue(dev); - spin_unlock_irqrestore(&ei_local->page_lock, flags); - ei_local->irqlock = 0; - return 0; -} - -#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock) - -/** - * ax_close - shut down network device - * @dev: network device to close - * - * Opposite of ax_open(). Only used when "ifconfig down" is done. - */ -static int ax_close(struct net_device *dev) -{ - unsigned long flags; - - /* - * Hold the page lock during close - */ - - spin_lock_irqsave(&dev_lock(dev), flags); - AX88190_init(dev, 0); - spin_unlock_irqrestore(&dev_lock(dev), flags); - netif_stop_queue(dev); - return 0; -} - -/** - * axnet_tx_timeout - handle transmit time out condition - * @dev: network device which has apparently fallen asleep - * @txqueue: unused - * - * Called by kernel when device never acknowledges a transmit has - * completed (or failed) - i.e. never posted a Tx related interrupt. - */ - -static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - long e8390_base = dev->base_addr; - struct ei_device *ei_local = netdev_priv(dev); - int txsr, isr, tickssofar = jiffies - dev_trans_start(dev); - unsigned long flags; - - dev->stats.tx_errors++; - - spin_lock_irqsave(&ei_local->page_lock, flags); - txsr = inb(e8390_base+EN0_TSR); - isr = inb(e8390_base+EN0_ISR); - spin_unlock_irqrestore(&ei_local->page_lock, flags); - - netdev_dbg(dev, "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n", - (txsr & ENTSR_ABT) ? "excess collisions." : - (isr) ? "lost interrupt?" : "cable problem?", - txsr, isr, tickssofar); - - if (!isr && !dev->stats.tx_packets) - { - /* The 8390 probably hasn't gotten on the cable yet. */ - ei_local->interface_num ^= 1; /* Try a different xcvr. */ - } - - /* Ugly but a reset can be slow, yet must be protected */ - - spin_lock_irqsave(&ei_local->page_lock, flags); - - /* Try to restart the card. Perhaps the user has fixed something. */ - ei_reset_8390(dev); - AX88190_init(dev, 1); - - spin_unlock_irqrestore(&ei_local->page_lock, flags); - netif_wake_queue(dev); -} - -/** - * axnet_start_xmit - begin packet transmission - * @skb: packet to be sent - * @dev: network device to which packet is sent - * - * Sends a packet to an 8390 network device. - */ - -static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - long e8390_base = dev->base_addr; - struct ei_device *ei_local = netdev_priv(dev); - int length, send_length, output_page; - unsigned long flags; - u8 packet[ETH_ZLEN]; - - netif_stop_queue(dev); - - length = skb->len; - - /* Mask interrupts from the ethercard. - SMP: We have to grab the lock here otherwise the IRQ handler - on another CPU can flip window and race the IRQ mask set. We end - up trashing the mcast filter not disabling irqs if we don't lock */ - - spin_lock_irqsave(&ei_local->page_lock, flags); - outb_p(0x00, e8390_base + EN0_IMR); - - /* - * Slow phase with lock held. - */ - - ei_local->irqlock = 1; - - send_length = max(length, ETH_ZLEN); - - /* - * We have two Tx slots available for use. Find the first free - * slot, and then perform some sanity checks. With two Tx bufs, - * you get very close to transmitting back-to-back packets. With - * only one Tx buf, the transmitter sits idle while you reload the - * card, leaving a substantial gap between each transmitted packet. - */ - - if (ei_local->tx1 == 0) - { - output_page = ei_local->tx_start_page; - ei_local->tx1 = send_length; - if ((netif_msg_tx_queued(ei_local)) && - ei_local->tx2 > 0) - netdev_dbg(dev, - "idle transmitter tx2=%d, lasttx=%d, txing=%d\n", - ei_local->tx2, ei_local->lasttx, - ei_local->txing); - } - else if (ei_local->tx2 == 0) - { - output_page = ei_local->tx_start_page + TX_PAGES/2; - ei_local->tx2 = send_length; - if ((netif_msg_tx_queued(ei_local)) && - ei_local->tx1 > 0) - netdev_dbg(dev, - "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n", - ei_local->tx1, ei_local->lasttx, - ei_local->txing); - } - else - { /* We should never get here. */ - netif_dbg(ei_local, tx_err, dev, - "No Tx buffers free! tx1=%d tx2=%d last=%d\n", - ei_local->tx1, ei_local->tx2, - ei_local->lasttx); - ei_local->irqlock = 0; - netif_stop_queue(dev); - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - spin_unlock_irqrestore(&ei_local->page_lock, flags); - dev->stats.tx_errors++; - return NETDEV_TX_BUSY; - } - - /* - * Okay, now upload the packet and trigger a send if the transmitter - * isn't already sending. If it is busy, the interrupt handler will - * trigger the send later, upon receiving a Tx done interrupt. - */ - - if (length == skb->len) - ei_block_output(dev, length, skb->data, output_page); - else { - memset(packet, 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, packet, skb->len); - ei_block_output(dev, length, packet, output_page); - } - - if (! ei_local->txing) - { - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, output_page); - netif_trans_update(dev); - if (output_page == ei_local->tx_start_page) - { - ei_local->tx1 = -1; - ei_local->lasttx = -1; - } - else - { - ei_local->tx2 = -1; - ei_local->lasttx = -2; - } - } - else ei_local->txqueue++; - - if (ei_local->tx1 && ei_local->tx2) - netif_stop_queue(dev); - else - netif_start_queue(dev); - - /* Turn 8390 interrupts back on. */ - ei_local->irqlock = 0; - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - - spin_unlock_irqrestore(&ei_local->page_lock, flags); - - dev_kfree_skb (skb); - dev->stats.tx_bytes += send_length; - - return NETDEV_TX_OK; -} - -/** - * ax_interrupt - handle the interrupts from an 8390 - * @irq: interrupt number - * @dev_id: a pointer to the net_device - * - * Handle the ether interface interrupts. We pull packets from - * the 8390 via the card specific functions and fire them at the networking - * stack. We also handle transmit completions and wake the transmit path if - * necessary. We also update the counters and do other housekeeping as - * needed. - */ - -static irqreturn_t ax_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - long e8390_base; - int interrupts, nr_serviced = 0, i; - struct ei_device *ei_local; - int handled = 0; - unsigned long flags; - - e8390_base = dev->base_addr; - ei_local = netdev_priv(dev); - - /* - * Protect the irq test too. - */ - - spin_lock_irqsave(&ei_local->page_lock, flags); - - if (ei_local->irqlock) { -#if 1 /* This might just be an interrupt for a PCI device sharing this line */ - const char *msg; - /* The "irqlock" check is only for testing. */ - if (ei_local->irqlock) - msg = "Interrupted while interrupts are masked!"; - else - msg = "Reentering the interrupt handler!"; - netdev_info(dev, "%s, isr=%#2x imr=%#2x\n", - msg, - inb_p(e8390_base + EN0_ISR), - inb_p(e8390_base + EN0_IMR)); -#endif - spin_unlock_irqrestore(&ei_local->page_lock, flags); - return IRQ_NONE; - } - - netif_dbg(ei_local, intr, dev, "interrupt(isr=%#2.2x)\n", - inb_p(e8390_base + EN0_ISR)); - - outb_p(0x00, e8390_base + EN0_ISR); - ei_local->irqlock = 1; - - /* !!Assumption!! -- we stay in page 0. Don't break this. */ - while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 && - ++nr_serviced < MAX_SERVICE) - { - if (!netif_running(dev) || (interrupts == 0xff)) { - netif_warn(ei_local, intr, dev, - "interrupt from stopped card\n"); - outb_p(interrupts, e8390_base + EN0_ISR); - interrupts = 0; - break; - } - handled = 1; - - /* AX88190 bug fix. */ - outb_p(interrupts, e8390_base + EN0_ISR); - for (i = 0; i < 10; i++) { - if (!(inb(e8390_base + EN0_ISR) & interrupts)) - break; - outb_p(0, e8390_base + EN0_ISR); - outb_p(interrupts, e8390_base + EN0_ISR); - } - if (interrupts & ENISR_OVER) - ei_rx_overrun(dev); - else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) - { - /* Got a good (?) packet. */ - ei_receive(dev); - } - /* Push the next to-transmit packet through. */ - if (interrupts & ENISR_TX) - ei_tx_intr(dev); - else if (interrupts & ENISR_TX_ERR) - ei_tx_err(dev); - - if (interrupts & ENISR_COUNTERS) - { - dev->stats.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0); - dev->stats.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1); - dev->stats.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2); - } - } - - if (interrupts && (netif_msg_intr(ei_local))) - { - handled = 1; - if (nr_serviced >= MAX_SERVICE) - { - /* 0xFF is valid for a card removal */ - if (interrupts != 0xFF) - netdev_warn(dev, - "Too much work at interrupt, status %#2.2x\n", - interrupts); - outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */ - } else { - netdev_warn(dev, "unknown interrupt %#2x\n", - interrupts); - outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */ - } - } - - /* Turn 8390 interrupts back on. */ - ei_local->irqlock = 0; - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - - spin_unlock_irqrestore(&ei_local->page_lock, flags); - return IRQ_RETVAL(handled); -} - -/** - * ei_tx_err - handle transmitter error - * @dev: network device which threw the exception - * - * A transmitter error has happened. Most likely excess collisions (which - * is a fairly normal condition). If the error is one where the Tx will - * have been aborted, we try and send another one right away, instead of - * letting the failed packet sit and collect dust in the Tx buffer. This - * is a much better solution as it avoids kernel based Tx timeouts, and - * an unnecessary card reset. - * - * Called with lock held. - */ - -static void ei_tx_err(struct net_device *dev) -{ - long e8390_base = dev->base_addr; - unsigned char txsr = inb_p(e8390_base+EN0_TSR); - unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); - -#ifdef VERBOSE_ERROR_DUMP - netdev_dbg(dev, "transmitter error (%#2x):", txsr); - if (txsr & ENTSR_ABT) - pr_cont(" excess-collisions"); - if (txsr & ENTSR_ND) - pr_cont(" non-deferral"); - if (txsr & ENTSR_CRS) - pr_cont(" lost-carrier"); - if (txsr & ENTSR_FU) - pr_cont(" FIFO-underrun"); - if (txsr & ENTSR_CDH) - pr_cont(" lost-heartbeat"); - pr_cont("\n"); -#endif - - if (tx_was_aborted) - ei_tx_intr(dev); - else - { - dev->stats.tx_errors++; - if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++; - if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++; - if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++; - } -} - -/** - * ei_tx_intr - transmit interrupt handler - * @dev: network device for which tx intr is handled - * - * We have finished a transmit: check for errors and then trigger the next - * packet to be sent. Called with lock held. - */ - -static void ei_tx_intr(struct net_device *dev) -{ - long e8390_base = dev->base_addr; - struct ei_device *ei_local = netdev_priv(dev); - int status = inb(e8390_base + EN0_TSR); - - /* - * There are two Tx buffers, see which one finished, and trigger - * the send of another one if it exists. - */ - ei_local->txqueue--; - - if (ei_local->tx1 < 0) - { - if (ei_local->lasttx != 1 && ei_local->lasttx != -1) - netdev_err(dev, "%s: bogus last_tx_buffer %d, tx1=%d\n", - ei_local->name, ei_local->lasttx, - ei_local->tx1); - ei_local->tx1 = 0; - if (ei_local->tx2 > 0) - { - ei_local->txing = 1; - NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6); - netif_trans_update(dev); - ei_local->tx2 = -1; - ei_local->lasttx = 2; - } else { - ei_local->lasttx = 20; - ei_local->txing = 0; - } - } - else if (ei_local->tx2 < 0) - { - if (ei_local->lasttx != 2 && ei_local->lasttx != -2) - netdev_err(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n", - ei_local->name, ei_local->lasttx, - ei_local->tx2); - ei_local->tx2 = 0; - if (ei_local->tx1 > 0) - { - ei_local->txing = 1; - NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page); - netif_trans_update(dev); - ei_local->tx1 = -1; - ei_local->lasttx = 1; - } else { - ei_local->lasttx = 10; - ei_local->txing = 0; - } - } -// else -// netdev_warn(dev, "unexpected TX-done interrupt, lasttx=%d\n", -// ei_local->lasttx); - - /* Minimize Tx latency: update the statistics after we restart TXing. */ - if (status & ENTSR_COL) - dev->stats.collisions++; - if (status & ENTSR_PTX) - dev->stats.tx_packets++; - else - { - dev->stats.tx_errors++; - if (status & ENTSR_ABT) - { - dev->stats.tx_aborted_errors++; - dev->stats.collisions += 16; - } - if (status & ENTSR_CRS) - dev->stats.tx_carrier_errors++; - if (status & ENTSR_FU) - dev->stats.tx_fifo_errors++; - if (status & ENTSR_CDH) - dev->stats.tx_heartbeat_errors++; - if (status & ENTSR_OWC) - dev->stats.tx_window_errors++; - } - netif_wake_queue(dev); -} - -/** - * ei_receive - receive some packets - * @dev: network device with which receive will be run - * - * We have a good packet(s), get it/them out of the buffers. - * Called with lock held. - */ - -static void ei_receive(struct net_device *dev) -{ - long e8390_base = dev->base_addr; - struct ei_device *ei_local = netdev_priv(dev); - unsigned char rxing_page, this_frame, next_frame; - unsigned short current_offset; - int rx_pkt_count = 0; - struct e8390_pkt_hdr rx_frame; - - while (++rx_pkt_count < 10) - { - int pkt_len, pkt_stat; - - /* Get the rx page (incoming packet pointer). */ - rxing_page = inb_p(e8390_base + EN1_CURPAG -1); - - /* Remove one frame from the ring. Boundary is always a page behind. */ - this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1; - if (this_frame >= ei_local->stop_page) - this_frame = ei_local->rx_start_page; - - /* Someday we'll omit the previous, iff we never get this message. - (There is at least one clone claimed to have a problem.) - - Keep quiet if it looks like a card removal. One problem here - is that some clones crash in roughly the same way. - */ - if ((netif_msg_rx_err(ei_local)) && - this_frame != ei_local->current_page && - (this_frame != 0x0 || rxing_page != 0xFF)) - netdev_err(dev, "mismatched read page pointers %2x vs %2x\n", - this_frame, ei_local->current_page); - - if (this_frame == rxing_page) /* Read all the frames? */ - break; /* Done for now */ - - current_offset = this_frame << 8; - ei_get_8390_hdr(dev, &rx_frame, this_frame); - - pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr); - pkt_stat = rx_frame.status; - - next_frame = this_frame + 1 + ((pkt_len+4)>>8); - - if (pkt_len < 60 || pkt_len > 1518) - { - netif_err(ei_local, rx_err, dev, - "bogus packet size: %d, status=%#2x nxpg=%#2x\n", - rx_frame.count, rx_frame.status, - rx_frame.next); - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - } - else if ((pkt_stat & 0x0F) == ENRSR_RXOK) - { - struct sk_buff *skb; - - skb = netdev_alloc_skb(dev, pkt_len + 2); - if (skb == NULL) - { - netif_err(ei_local, rx_err, dev, - "Couldn't allocate a sk_buff of size %d\n", - pkt_len); - dev->stats.rx_dropped++; - break; - } - else - { - skb_reserve(skb,2); /* IP headers on 16 byte boundaries */ - skb_put(skb, pkt_len); /* Make room */ - ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - if (pkt_stat & ENRSR_PHY) - dev->stats.multicast++; - } - } - else - { - netif_err(ei_local, rx_err, dev, - "bogus packet: status=%#2x nxpg=%#2x size=%d\n", - rx_frame.status, rx_frame.next, - rx_frame.count); - dev->stats.rx_errors++; - /* NB: The NIC counts CRC, frame and missed errors. */ - if (pkt_stat & ENRSR_FO) - dev->stats.rx_fifo_errors++; - } - next_frame = rx_frame.next; - - /* This _should_ never happen: it's here for avoiding bad clones. */ - if (next_frame >= ei_local->stop_page) { - netdev_info(dev, "next frame inconsistency, %#2x\n", - next_frame); - next_frame = ei_local->rx_start_page; - } - ei_local->current_page = next_frame; - outb_p(next_frame-1, e8390_base+EN0_BOUNDARY); - } -} - -/** - * ei_rx_overrun - handle receiver overrun - * @dev: network device which threw exception - * - * We have a receiver overrun: we have to kick the 8390 to get it started - * again. Problem is that you have to kick it exactly as NS prescribes in - * the updated datasheets, or "the NIC may act in an unpredictable manner." - * This includes causing "the NIC to defer indefinitely when it is stopped - * on a busy network." Ugh. - * Called with lock held. Don't call this with the interrupts off or your - * computer will hate you - it takes 10ms or so. - */ - -static void ei_rx_overrun(struct net_device *dev) -{ - struct axnet_dev *info = PRIV(dev); - long e8390_base = dev->base_addr; - unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = netdev_priv(dev); - - /* - * Record whether a Tx was in progress and then issue the - * stop command. - */ - was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS; - outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); - - netif_dbg(ei_local, rx_err, dev, "Receiver overrun\n"); - dev->stats.rx_over_errors++; - - /* - * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total. - * We wait at least 2ms. - */ - - mdelay(2); - - /* - * Reset RBCR[01] back to zero as per magic incantation. - */ - outb_p(0x00, e8390_base+EN0_RCNTLO); - outb_p(0x00, e8390_base+EN0_RCNTHI); - - /* - * See if any Tx was interrupted or not. According to NS, this - * step is vital, and skipping it will cause no end of havoc. - */ - - if (was_txing) - { - unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR); - if (!tx_completed) - must_resend = 1; - } - - /* - * Have to enter loopback mode and then restart the NIC before - * you are allowed to slurp packets up off the ring. - */ - outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); - outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD); - - /* - * Clear the Rx ring of all the debris, and ack the interrupt. - */ - ei_receive(dev); - - /* - * Leave loopback mode, and resend any packet that got stopped. - */ - outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); - if (must_resend) - outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD); -} - -/* - * Collect the stats. This is called unlocked and from several contexts. - */ - -static struct net_device_stats *get_stats(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct ei_device *ei_local = netdev_priv(dev); - unsigned long flags; - - /* If the card is stopped, just return the present stats. */ - if (!netif_running(dev)) - return &dev->stats; - - spin_lock_irqsave(&ei_local->page_lock,flags); - /* Read the counter registers, assuming we are in page 0. */ - dev->stats.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0); - dev->stats.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1); - dev->stats.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2); - spin_unlock_irqrestore(&ei_local->page_lock, flags); - - return &dev->stats; -} - -/* - * Form the 64 bit 8390 multicast table from the linked list of addresses - * associated with this dev structure. - */ - -static inline void make_mc_bits(u8 *bits, struct net_device *dev) -{ - struct netdev_hw_addr *ha; - u32 crc; - - netdev_for_each_mc_addr(ha, dev) { - crc = ether_crc(ETH_ALEN, ha->addr); - /* - * The 8390 uses the 6 most significant bits of the - * CRC to index the multicast table. - */ - bits[crc>>29] |= (1<<((crc>>26)&7)); - } -} - -/** - * do_set_multicast_list - set/clear multicast filter - * @dev: net device for which multicast filter is adjusted - * - * Set or clear the multicast filter for this adaptor. - * Must be called with lock held. - */ - -static void do_set_multicast_list(struct net_device *dev) -{ - long e8390_base = dev->base_addr; - int i; - struct ei_device *ei_local = netdev_priv(dev); - - if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { - memset(ei_local->mcfilter, 0, 8); - if (!netdev_mc_empty(dev)) - make_mc_bits(ei_local->mcfilter, dev); - } else { - /* set to accept-all */ - memset(ei_local->mcfilter, 0xFF, 8); - } - - outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD); - for(i = 0; i < 8; i++) - { - outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i)); - } - outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD); - - if(dev->flags&IFF_PROMISC) - outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR); - else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) - outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR); - else - outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); - - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD); -} - -/* - * Called without lock held. This is invoked from user context and may - * be parallel to just about everything else. Its also fairly quick and - * not called too often. Must protect against both bh and irq users - */ - -static void set_multicast_list(struct net_device *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev_lock(dev), flags); - do_set_multicast_list(dev); - spin_unlock_irqrestore(&dev_lock(dev), flags); -} - -/* This page of functions should be 8390 generic */ -/* Follow National Semi's recommendations for initializing the "NIC". */ - -/** - * AX88190_init - initialize 8390 hardware - * @dev: network device to initialize - * @startp: boolean. non-zero value to initiate chip processing - * - * Must be called with lock held. - */ - -static void AX88190_init(struct net_device *dev, int startp) -{ - struct axnet_dev *info = PRIV(dev); - long e8390_base = dev->base_addr; - struct ei_device *ei_local = netdev_priv(dev); - int i; - int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; - - if(sizeof(struct e8390_pkt_hdr)!=4) - panic("8390.c: header struct mispacked\n"); - /* Follow National Semi's recommendations for initing the DP83902. */ - outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */ - outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */ - /* Clear the remote byte count registers. */ - outb_p(0x00, e8390_base + EN0_RCNTLO); - outb_p(0x00, e8390_base + EN0_RCNTHI); - /* Set to monitor and loopback mode -- this is vital!. */ - outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */ - outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */ - /* Set the transmit page and receive ring. */ - outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR); - ei_local->tx1 = ei_local->tx2 = 0; - outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG); - outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/ - ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */ - outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG); - /* Clear the pending interrupts and mask. */ - outb_p(0xFF, e8390_base + EN0_ISR); - outb_p(0x00, e8390_base + EN0_IMR); - - /* Copy the station address into the DS8390 registers. */ - - outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */ - for(i = 0; i < 6; i++) - { - outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i)); - if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i]) - netdev_err(dev, "Hw. address read/write mismap %d\n", i); - } - - outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); - outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); - - netif_start_queue(dev); - ei_local->tx1 = ei_local->tx2 = 0; - ei_local->txing = 0; - - if (info->flags & IS_AX88790) /* select Internal PHY */ - outb(0x10, e8390_base + AXNET_GPIO); - - if (startp) - { - outb_p(0xff, e8390_base + EN0_ISR); - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD); - outb_p(E8390_TXCONFIG | info->duplex_flag, - e8390_base + EN0_TXCR); /* xmit on. */ - /* 3c503 TechMan says rxconfig only after the NIC is started. */ - outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */ - do_set_multicast_list(dev); /* (re)load the mcast table */ - } -} - -/* Trigger a transmit start, assuming the length is valid. - Always called with the page lock held */ - -static void NS8390_trigger_send(struct net_device *dev, unsigned int length, - int start_page) -{ - long e8390_base = dev->base_addr; - struct ei_device *ei_local __attribute((unused)) = netdev_priv(dev); - - if (inb_p(e8390_base) & E8390_TRANS) - { - netdev_warn(dev, "trigger_send() called with the transmitter busy\n"); - return; - } - outb_p(length & 0xff, e8390_base + EN0_TCNTLO); - outb_p(length >> 8, e8390_base + EN0_TCNTHI); - outb_p(start_page, e8390_base + EN0_TPSR); - outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD); -} diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c deleted file mode 100644 index 22ca804b2e95..000000000000 --- a/drivers/net/ethernet/8390/smc-ultra.c +++ /dev/null @@ -1,630 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ -/* smc-ultra.c: A SMC Ultra ethernet driver for linux. */ -/* - This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards. - - Written 1993-1998 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - This driver uses the cards in the 8390-compatible mode. - Most of the run-time complexity is handled by the generic code in - 8390.c. The code in this file is responsible for - - ultra_probe() Detecting and initializing the card. - ultra_probe1() - ultra_probe_isapnp() - - ultra_open() The card-specific details of starting, stopping - ultra_reset_8390() and resetting the 8390 NIC core. - ultra_close() - - ultra_block_input() Routines for reading and writing blocks of - ultra_block_output() packet buffer memory. - ultra_pio_input() - ultra_pio_output() - - This driver enables the shared memory only when doing the actual data - transfers to avoid a bug in early version of the card that corrupted - data transferred by a AHA1542. - - This driver now supports the programmed-I/O (PIO) data transfer mode of - the EtherEZ. It does not use the non-8390-compatible "Altego" mode. - That support (if available) is in smc-ez.c. - - Changelog: - - Paul Gortmaker : multiple card support for module users. - Donald Becker : 4/17/96 PIO support, minor potential problems avoided. - Donald Becker : 6/6/96 correctly set auto-wrap bit. - Alexander Sotirov : 1/20/01 Added support for ISAPnP cards - - Note about the ISA PnP support: - - This driver can not autoprobe for more than one SMC EtherEZ PnP card. - You have to configure the second card manually through the /proc/isapnp - interface and then load the module with an explicit io=0x___ option. -*/ - -static const char version[] = - "smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "8390.h" - -#define DRV_NAME "smc-ultra" - -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int ultra_portlist[] __initdata = -{0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0}; - -static int ultra_probe1(struct net_device *dev, int ioaddr); - -#ifdef __ISAPNP__ -static int ultra_probe_isapnp(struct net_device *dev); -#endif - -static int ultra_open(struct net_device *dev); -static void ultra_reset_8390(struct net_device *dev); -static void ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page); -static void ultra_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void ultra_block_output(struct net_device *dev, int count, - const unsigned char *buf, const int start_page); -static void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page); -static void ultra_pio_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void ultra_pio_output(struct net_device *dev, int count, - const unsigned char *buf, const int start_page); -static int ultra_close_card(struct net_device *dev); - -#ifdef __ISAPNP__ -static struct isapnp_device_id ultra_device_ids[] __initdata = { - { ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), - ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), - (long) "SMC EtherEZ (8416)" }, - { } /* terminate list */ -}; - -MODULE_DEVICE_TABLE(isapnp, ultra_device_ids); -#endif - -static u32 ultra_msg_enable; - -#define START_PG 0x00 /* First page of TX buffer */ - -#define ULTRA_CMDREG 0 /* Offset to ASIC command register. */ -#define ULTRA_RESET 0x80 /* Board reset, in ULTRA_CMDREG. */ -#define ULTRA_MEMENB 0x40 /* Enable the shared memory. */ -#define IOPD 0x02 /* I/O Pipe Data (16 bits), PIO operation. */ -#define IOPA 0x07 /* I/O Pipe Address for PIO operation. */ -#define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */ -#define ULTRA_IO_EXTENT 32 -#define EN0_ERWCNT 0x08 /* Early receive warning count. */ - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void ultra_poll(struct net_device *dev) -{ - disable_irq(dev->irq); - ei_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif -/* Probe for the Ultra. This looks like a 8013 with the station - address PROM at I/O ports +8 to +13, with a checksum - following. -*/ - -static int __init do_ultra_probe(struct net_device *dev) -{ - int i; - int base_addr = dev->base_addr; - int irq = dev->irq; - - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ultra_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - -#ifdef __ISAPNP__ - /* Look for any installed ISAPnP cards */ - if (isapnp_present() && (ultra_probe_isapnp(dev) == 0)) - return 0; -#endif - - for (i = 0; ultra_portlist[i]; i++) { - dev->irq = irq; - if (ultra_probe1(dev, ultra_portlist[i]) == 0) - return 0; - } - - return -ENODEV; -} - -#ifndef MODULE -struct net_device * __init ultra_probe(int unit) -{ - struct net_device *dev = alloc_ei_netdev(); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err = do_ultra_probe(dev); - if (err) - goto out; - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif - -static const struct net_device_ops ultra_netdev_ops = { - .ndo_open = ultra_open, - .ndo_stop = ultra_close_card, - - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_rx_mode = ei_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ultra_poll, -#endif -}; - -static int __init ultra_probe1(struct net_device *dev, int ioaddr) -{ - int i, retval; - int checksum = 0; - u8 macaddr[ETH_ALEN]; - const char *model_name; - unsigned char eeprom_irq = 0; - static unsigned version_printed; - /* Values from various config regs. */ - unsigned char num_pages, irqreg, addr, piomode; - unsigned char idreg = inb(ioaddr + 7); - unsigned char reg4 = inb(ioaddr + 4) & 0x7f; - struct ei_device *ei_local = netdev_priv(dev); - - if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) - return -EBUSY; - - /* Check the ID nibble. */ - if ((idreg & 0xF0) != 0x20 /* SMC Ultra */ - && (idreg & 0xF0) != 0x40) { /* SMC EtherEZ */ - retval = -ENODEV; - goto out; - } - - /* Select the station address register set. */ - outb(reg4, ioaddr + 4); - - for (i = 0; i < 8; i++) - checksum += inb(ioaddr + 8 + i); - if ((checksum & 0xff) != 0xFF) { - retval = -ENODEV; - goto out; - } - - if ((ultra_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) - netdev_info(dev, version); - - model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ"; - - for (i = 0; i < 6; i++) - macaddr[i] = inb(ioaddr + 8 + i); - eth_hw_addr_set(dev, macaddr); - - netdev_info(dev, "%s at %#3x, %pM", model_name, - ioaddr, dev->dev_addr); - - /* Switch from the station address to the alternate register set and - read the useful registers there. */ - outb(0x80 | reg4, ioaddr + 4); - - /* Enabled FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */ - outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c); - piomode = inb(ioaddr + 0x8); - addr = inb(ioaddr + 0xb); - irqreg = inb(ioaddr + 0xd); - - /* Switch back to the station address register set so that the MS-DOS driver - can find the card after a warm boot. */ - outb(reg4, ioaddr + 4); - - if (dev->irq < 2) { - unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15}; - int irq; - - /* The IRQ bits are split. */ - irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)]; - - if (irq == 0) { - pr_cont(", failed to detect IRQ line.\n"); - retval = -EAGAIN; - goto out; - } - dev->irq = irq; - eeprom_irq = 1; - } - - /* The 8390 isn't at the base address, so fake the offset */ - dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; - - { - static const int addr_tbl[4] = { - 0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000 - }; - static const short num_pages_tbl[4] = { - 0x20, 0x40, 0x80, 0xff - }; - - dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ; - num_pages = num_pages_tbl[(addr >> 4) & 3]; - } - - ei_status.name = model_name; - ei_status.word16 = 1; - ei_status.tx_start_page = START_PG; - ei_status.rx_start_page = START_PG + TX_PAGES; - ei_status.stop_page = num_pages; - - ei_status.mem = ioremap(dev->mem_start, (ei_status.stop_page - START_PG)*256); - if (!ei_status.mem) { - pr_cont(", failed to ioremap.\n"); - retval = -ENOMEM; - goto out; - } - - dev->mem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256; - - if (piomode) { - pr_cont(", %s IRQ %d programmed-I/O mode.\n", - eeprom_irq ? "EEPROM" : "assigned ", dev->irq); - ei_status.block_input = &ultra_pio_input; - ei_status.block_output = &ultra_pio_output; - ei_status.get_8390_hdr = &ultra_pio_get_hdr; - } else { - pr_cont(", %s IRQ %d memory %#lx-%#lx.\n", - eeprom_irq ? "" : "assigned ", dev->irq, dev->mem_start, - dev->mem_end-1); - ei_status.block_input = &ultra_block_input; - ei_status.block_output = &ultra_block_output; - ei_status.get_8390_hdr = &ultra_get_8390_hdr; - } - ei_status.reset_8390 = &ultra_reset_8390; - - dev->netdev_ops = &ultra_netdev_ops; - NS8390_init(dev, 0); - ei_local->msg_enable = ultra_msg_enable; - - retval = register_netdev(dev); - if (retval) - goto out; - return 0; -out: - release_region(ioaddr, ULTRA_IO_EXTENT); - return retval; -} - -#ifdef __ISAPNP__ -static int __init ultra_probe_isapnp(struct net_device *dev) -{ - int i; - - for (i = 0; ultra_device_ids[i].vendor != 0; i++) { - struct pnp_dev *idev = NULL; - - while ((idev = pnp_find_dev(NULL, - ultra_device_ids[i].vendor, - ultra_device_ids[i].function, - idev))) { - /* Avoid already found cards from previous calls */ - if (pnp_device_attach(idev) < 0) - continue; - if (pnp_activate_dev(idev) < 0) { - __again: - pnp_device_detach(idev); - continue; - } - /* if no io and irq, search for next */ - if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) - goto __again; - /* found it */ - dev->base_addr = pnp_port_start(idev, 0); - dev->irq = pnp_irq(idev, 0); - netdev_info(dev, - "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", - (char *) ultra_device_ids[i].driver_data, - dev->base_addr, dev->irq); - if (ultra_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ - netdev_err(dev, - "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n", - dev->base_addr); - pnp_device_detach(idev); - return -ENXIO; - } - ei_status.priv = (unsigned long)idev; - break; - } - if (!idev) - continue; - return 0; - } - - return -ENODEV; -} -#endif - -static int -ultra_open(struct net_device *dev) -{ - int retval; - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ - unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40, - 0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, }; - - retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); - if (retval) - return retval; - - outb(0x00, ioaddr); /* Disable shared memory for safety. */ - outb(0x80, ioaddr + 5); - /* Set the IRQ line. */ - outb(inb(ioaddr + 4) | 0x80, ioaddr + 4); - outb((inb(ioaddr + 13) & ~0x4C) | irq2reg[dev->irq], ioaddr + 13); - outb(inb(ioaddr + 4) & 0x7f, ioaddr + 4); - - if (ei_status.block_input == &ultra_pio_input) { - outb(0x11, ioaddr + 6); /* Enable interrupts and PIO. */ - outb(0x01, ioaddr + 0x19); /* Enable ring read auto-wrap. */ - } else - outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */ - /* Set the early receive warning level in window 0 high enough not - to receive ERW interrupts. */ - outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr); - outb(0xff, dev->base_addr + EN0_ERWCNT); - ei_open(dev); - return 0; -} - -static void -ultra_reset_8390(struct net_device *dev) -{ - int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */ - struct ei_device *ei_local = netdev_priv(dev); - - outb(ULTRA_RESET, cmd_port); - netif_dbg(ei_local, hw, dev, "resetting Ultra, t=%ld...\n", jiffies); - ei_status.txing = 0; - - outb(0x00, cmd_port); /* Disable shared memory for safety. */ - outb(0x80, cmd_port + 5); - if (ei_status.block_input == &ultra_pio_input) - outb(0x11, cmd_port + 6); /* Enable interrupts and PIO. */ - else - outb(0x01, cmd_port + 6); /* Enable interrupts and memory. */ - - netif_dbg(ei_local, hw, dev, "reset done\n"); -} - -/* Grab the 8390 specific header. Similar to the block_input routine, but - we don't need to be concerned with ring wrap as the header will be at - the start of a page, so we optimize accordingly. */ - -static void -ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) -{ - void __iomem *hdr_start = ei_status.mem + ((ring_page - START_PG)<<8); - - outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem on */ -#ifdef __BIG_ENDIAN - /* Officially this is what we are doing, but the readl() is faster */ - /* unfortunately it isn't endian aware of the struct */ - memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); - hdr->count = le16_to_cpu(hdr->count); -#else - ((unsigned int*)hdr)[0] = readl(hdr_start); -#endif - outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */ -} - -/* Block input and output are easy on shared memory ethercards, the only - complication is when the ring buffer wraps. */ - -static void -ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) -{ - void __iomem *xfer_start = ei_status.mem + ring_offset - (START_PG<<8); - - /* Enable shared memory. */ - outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); - - if (ring_offset + count > ei_status.stop_page*256) { - /* We must wrap the input move. */ - int semi_count = ei_status.stop_page*256 - ring_offset; - memcpy_fromio(skb->data, xfer_start, semi_count); - count -= semi_count; - memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); - } else { - memcpy_fromio(skb->data, xfer_start, count); - } - - outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ -} - -static void -ultra_block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) -{ - void __iomem *shmem = ei_status.mem + ((start_page - START_PG)<<8); - - /* Enable shared memory. */ - outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); - - memcpy_toio(shmem, buf, count); - - outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ -} - -/* The identical operations for programmed I/O cards. - The PIO model is trivial to use: the 16 bit start address is written - byte-sequentially to IOPA, with no intervening I/O operations, and the - data is read or written to the IOPD data port. - The only potential complication is that the address register is shared - and must be always be rewritten between each read/write direction change. - This is no problem for us, as the 8390 code ensures that we are single - threaded. */ -static void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page) -{ - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ - outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ - outb(ring_page, ioaddr + IOPA); - insw(ioaddr + IOPD, hdr, sizeof(struct e8390_pkt_hdr)>>1); -} - -static void ultra_pio_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset) -{ - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ - char *buf = skb->data; - - /* For now set the address again, although it should already be correct. */ - outb(ring_offset, ioaddr + IOPA); /* Set the address, LSB first. */ - outb(ring_offset >> 8, ioaddr + IOPA); - /* We know skbuffs are padded to at least word alignment. */ - insw(ioaddr + IOPD, buf, (count+1)>>1); -} -static void ultra_pio_output(struct net_device *dev, int count, - const unsigned char *buf, const int start_page) -{ - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ - outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ - outb(start_page, ioaddr + IOPA); - /* An extra odd byte is OK here as well. */ - outsw(ioaddr + IOPD, buf, (count+1)>>1); -} - -static int -ultra_close_card(struct net_device *dev) -{ - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */ - struct ei_device *ei_local = netdev_priv(dev); - - netif_stop_queue(dev); - - netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n"); - - outb(0x00, ioaddr + 6); /* Disable interrupts. */ - free_irq(dev->irq, dev); - - NS8390_init(dev, 0); - - /* We should someday disable shared memory and change to 8-bit mode - "just in case"... */ - - return 0; -} - - -#ifdef MODULE -#define MAX_ULTRA_CARDS 4 /* Max number of Ultra cards per module */ -static struct net_device *dev_ultra[MAX_ULTRA_CARDS]; -static int io[MAX_ULTRA_CARDS]; -static int irq[MAX_ULTRA_CARDS]; - -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_named(msg_enable, ultra_msg_enable, uint, 0444); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); -MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); -MODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver"); -MODULE_LICENSE("GPL"); - -/* This is set up so that only a single autoprobe takes place per call. -ISA device autoprobes on a running machine are not recommended. */ -static int __init ultra_init_module(void) -{ - struct net_device *dev; - int this_dev, found = 0; - - for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - if (io[this_dev] == 0) { - if (this_dev != 0) break; /* only autoprobe 1st one */ - printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n"); - } - dev = alloc_ei_netdev(); - if (!dev) - break; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - if (do_ultra_probe(dev) == 0) { - dev_ultra[found++] = dev; - continue; - } - free_netdev(dev); - printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); - break; - } - if (found) - return 0; - return -ENXIO; -} -module_init(ultra_init_module); - -static void cleanup_card(struct net_device *dev) -{ - /* NB: ultra_close_card() does free_irq */ -#ifdef __ISAPNP__ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); -#endif - release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); - iounmap(ei_status.mem); -} - -static void __exit ultra_cleanup_module(void) -{ - int this_dev; - - for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev = dev_ultra[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -module_exit(ultra_cleanup_module); -#endif /* MODULE */ diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c deleted file mode 100644 index ffd639477dfc..000000000000 --- a/drivers/net/ethernet/8390/wd.c +++ /dev/null @@ -1,575 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ -/* wd.c: A WD80x3 ethernet driver for linux. */ -/* - Written 1993-94 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - This is a driver for WD8003 and WD8013 "compatible" ethercards. - - Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013. - - Changelog: - - Paul Gortmaker : multiple card support for module users, support - for non-standard memory sizes. - - -*/ - -static const char version[] = - "wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "8390.h" - -#define DRV_NAME "wd" - -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int wd_portlist[] __initdata = -{0x300, 0x280, 0x380, 0x240, 0}; - -static int wd_probe1(struct net_device *dev, int ioaddr); - -static int wd_open(struct net_device *dev); -static void wd_reset_8390(struct net_device *dev); -static void wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page); -static void wd_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void wd_block_output(struct net_device *dev, int count, - const unsigned char *buf, int start_page); -static int wd_close(struct net_device *dev); - -static u32 wd_msg_enable; - -#define WD_START_PG 0x00 /* First page of TX buffer */ -#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ -#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ - -#define WD_CMDREG 0 /* Offset to ASIC command register. */ -#define WD_RESET 0x80 /* Board reset, in WD_CMDREG. */ -#define WD_MEMENB 0x40 /* Enable the shared memory. */ -#define WD_CMDREG5 5 /* Offset to 16-bit-only ASIC register 5. */ -#define ISA16 0x80 /* Enable 16 bit access from the ISA bus. */ -#define NIC16 0x40 /* Enable 16 bit access from the 8390. */ -#define WD_NIC_OFFSET 16 /* Offset to the 8390 from the base_addr. */ -#define WD_IO_EXTENT 32 - - -/* Probe for the WD8003 and WD8013. These cards have the station - address PROM at I/O ports +8 to +13, with a checksum - following. A Soundblaster can have the same checksum as an WDethercard, - so we have an extra exclusionary check for it. - - The wd_probe1() routine initializes the card and fills the - station address field. */ - -static int __init do_wd_probe(struct net_device *dev) -{ - int i; - struct resource *r; - int base_addr = dev->base_addr; - int irq = dev->irq; - int mem_start = dev->mem_start; - int mem_end = dev->mem_end; - - if (base_addr > 0x1ff) { /* Check a user specified location. */ - r = request_region(base_addr, WD_IO_EXTENT, "wd-probe"); - if ( r == NULL) - return -EBUSY; - i = wd_probe1(dev, base_addr); - if (i != 0) - release_region(base_addr, WD_IO_EXTENT); - else - r->name = dev->name; - return i; - } - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; wd_portlist[i]; i++) { - int ioaddr = wd_portlist[i]; - r = request_region(ioaddr, WD_IO_EXTENT, "wd-probe"); - if (r == NULL) - continue; - if (wd_probe1(dev, ioaddr) == 0) { - r->name = dev->name; - return 0; - } - release_region(ioaddr, WD_IO_EXTENT); - dev->irq = irq; - dev->mem_start = mem_start; - dev->mem_end = mem_end; - } - - return -ENODEV; -} - -#ifndef MODULE -struct net_device * __init wd_probe(int unit) -{ - struct net_device *dev = alloc_ei_netdev(); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err = do_wd_probe(dev); - if (err) - goto out; - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif - -static const struct net_device_ops wd_netdev_ops = { - .ndo_open = wd_open, - .ndo_stop = wd_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_rx_mode = ei_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, -#endif -}; - -static int __init wd_probe1(struct net_device *dev, int ioaddr) -{ - int i; - int err; - int checksum = 0; - int ancient = 0; /* An old card without config registers. */ - int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */ - u8 addr[ETH_ALEN]; - const char *model_name; - static unsigned version_printed; - struct ei_device *ei_local = netdev_priv(dev); - - for (i = 0; i < 8; i++) - checksum += inb(ioaddr + 8 + i); - if (inb(ioaddr + 8) == 0xff /* Extra check to avoid soundcard. */ - || inb(ioaddr + 9) == 0xff - || (checksum & 0xff) != 0xFF) - return -ENODEV; - - /* Check for semi-valid mem_start/end values if supplied. */ - if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) { - netdev_warn(dev, - "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n"); - dev->mem_start = 0; - dev->mem_end = 0; - } - - if ((wd_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) - netdev_info(dev, version); - - for (i = 0; i < 6; i++) - addr[i] = inb(ioaddr + 8 + i); - eth_hw_addr_set(dev, addr); - - netdev_info(dev, "WD80x3 at %#3x, %pM", ioaddr, dev->dev_addr); - - /* The following PureData probe code was contributed by - Mike Jagdis . Puredata does software - configuration differently from others so we have to check for them. - This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card. - */ - if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') { - unsigned char reg5 = inb(ioaddr+5); - - switch (inb(ioaddr+2)) { - case 0x03: word16 = 0; model_name = "PDI8023-8"; break; - case 0x05: word16 = 0; model_name = "PDUC8023"; break; - case 0x0a: word16 = 1; model_name = "PDI8023-16"; break; - /* Either 0x01 (dumb) or they've released a new version. */ - default: word16 = 0; model_name = "PDI8023"; break; - } - dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12; - dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1; - } else { /* End of PureData probe */ - /* This method of checking for a 16-bit board is borrowed from the - we.c driver. A simpler method is just to look in ASIC reg. 0x03. - I'm comparing the two method in alpha test to make certain they - return the same result. */ - /* Check for the old 8 bit board - it has register 0/8 aliasing. - Do NOT check i>=6 here -- it hangs the old 8003 boards! */ - for (i = 0; i < 6; i++) - if (inb(ioaddr+i) != inb(ioaddr+8+i)) - break; - if (i >= 6) { - ancient = 1; - model_name = "WD8003-old"; - word16 = 0; - } else { - int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */ - outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */ - if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */ - && (tmp & 0x01) == 0x01 ) { /* In a 16 slot. */ - int asic_reg5 = inb(ioaddr+WD_CMDREG5); - /* Magic to set ASIC to word-wide mode. */ - outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5); - outb(tmp, ioaddr+1); - model_name = "WD8013"; - word16 = 1; /* We have a 16bit board here! */ - } else { - model_name = "WD8003"; - word16 = 0; - } - outb(tmp, ioaddr+1); /* Restore original reg1 value. */ - } -#ifndef final_version - if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01)) - pr_cont("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).", - word16 ? 16 : 8, - (inb(ioaddr+1) & 0x01) ? 16 : 8); -#endif - } - -#if defined(WD_SHMEM) && WD_SHMEM > 0x80000 - /* Allow a compile-time override. */ - dev->mem_start = WD_SHMEM; -#else - if (dev->mem_start == 0) { - /* Sanity and old 8003 check */ - int reg0 = inb(ioaddr); - if (reg0 == 0xff || reg0 == 0) { - /* Future plan: this could check a few likely locations first. */ - dev->mem_start = 0xd0000; - pr_cont(" assigning address %#lx", dev->mem_start); - } else { - int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f; - /* Some boards don't have the register 5 -- it returns 0xff. */ - if (high_addr_bits == 0x1f || word16 == 0) - high_addr_bits = 0x01; - dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19); - } - } -#endif - - /* The 8390 isn't at the base address -- the ASIC regs are there! */ - dev->base_addr = ioaddr+WD_NIC_OFFSET; - - if (dev->irq < 2) { - static const int irqmap[] = {9, 3, 5, 7, 10, 11, 15, 4}; - int reg1 = inb(ioaddr+1); - int reg4 = inb(ioaddr+4); - if (ancient || reg1 == 0xff) { /* Ack!! No way to read the IRQ! */ - short nic_addr = ioaddr+WD_NIC_OFFSET; - unsigned long irq_mask; - - /* We have an old-style ethercard that doesn't report its IRQ - line. Do autoirq to find the IRQ line. Note that this IS NOT - a reliable way to trigger an interrupt. */ - outb_p(E8390_NODMA + E8390_STOP, nic_addr); - outb(0x00, nic_addr+EN0_IMR); /* Disable all intrs. */ - - irq_mask = probe_irq_on(); - outb_p(0xff, nic_addr + EN0_IMR); /* Enable all interrupts. */ - outb_p(0x00, nic_addr + EN0_RCNTLO); - outb_p(0x00, nic_addr + EN0_RCNTHI); - outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */ - mdelay(20); - dev->irq = probe_irq_off(irq_mask); - - outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */ - - if (wd_msg_enable & NETIF_MSG_PROBE) - pr_cont(" autoirq is %d", dev->irq); - if (dev->irq < 2) - dev->irq = word16 ? 10 : 5; - } else - dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)]; - } else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */ - dev->irq = 9; - - /* Snarf the interrupt now. There's no point in waiting since we cannot - share and the board will usually be enabled. */ - i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev); - if (i) { - pr_cont(" unable to get IRQ %d.\n", dev->irq); - return i; - } - - /* OK, were are certain this is going to work. Setup the device. */ - ei_status.name = model_name; - ei_status.word16 = word16; - ei_status.tx_start_page = WD_START_PG; - ei_status.rx_start_page = WD_START_PG + TX_PAGES; - - /* Don't map in the shared memory until the board is actually opened. */ - - /* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */ - if (dev->mem_end != 0) { - ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; - ei_status.priv = dev->mem_end - dev->mem_start; - } else { - ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG; - dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256; - ei_status.priv = (ei_status.stop_page - WD_START_PG)*256; - } - - ei_status.mem = ioremap(dev->mem_start, ei_status.priv); - if (!ei_status.mem) { - free_irq(dev->irq, dev); - return -ENOMEM; - } - - pr_cont(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", - model_name, dev->irq, dev->mem_start, dev->mem_end-1); - - ei_status.reset_8390 = wd_reset_8390; - ei_status.block_input = wd_block_input; - ei_status.block_output = wd_block_output; - ei_status.get_8390_hdr = wd_get_8390_hdr; - - dev->netdev_ops = &wd_netdev_ops; - NS8390_init(dev, 0); - ei_local->msg_enable = wd_msg_enable; - -#if 1 - /* Enable interrupt generation on softconfig cards -- M.U */ - /* .. but possibly potentially unsafe - Donald */ - if (inb(ioaddr+14) & 0x20) - outb(inb(ioaddr+4)|0x80, ioaddr+4); -#endif - - err = register_netdev(dev); - if (err) { - free_irq(dev->irq, dev); - iounmap(ei_status.mem); - } - return err; -} - -static int -wd_open(struct net_device *dev) -{ - int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - - /* Map in the shared memory. Always set register 0 last to remain - compatible with very old boards. */ - ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB; - ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16; - - if (ei_status.word16) - outb(ei_status.reg5, ioaddr+WD_CMDREG5); - outb(ei_status.reg0, ioaddr); /* WD_CMDREG */ - - return ei_open(dev); -} - -static void -wd_reset_8390(struct net_device *dev) -{ - int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - struct ei_device *ei_local = netdev_priv(dev); - - outb(WD_RESET, wd_cmd_port); - netif_dbg(ei_local, hw, dev, "resetting the WD80x3 t=%lu...\n", - jiffies); - ei_status.txing = 0; - - /* Set up the ASIC registers, just in case something changed them. */ - outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port); - if (ei_status.word16) - outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5); - - netif_dbg(ei_local, hw, dev, "reset done\n"); -} - -/* Grab the 8390 specific header. Similar to the block_input routine, but - we don't need to be concerned with ring wrap as the header will be at - the start of a page, so we optimize accordingly. */ - -static void -wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) -{ - - int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - void __iomem *hdr_start = ei_status.mem + ((ring_page - WD_START_PG)<<8); - - /* We'll always get a 4 byte header read followed by a packet read, so - we enable 16 bit mode before the header, and disable after the body. */ - if (ei_status.word16) - outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5); - -#ifdef __BIG_ENDIAN - /* Officially this is what we are doing, but the readl() is faster */ - /* unfortunately it isn't endian aware of the struct */ - memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); - hdr->count = le16_to_cpu(hdr->count); -#else - ((unsigned int*)hdr)[0] = readl(hdr_start); -#endif -} - -/* Block input and output are easy on shared memory ethercards, and trivial - on the Western digital card where there is no choice of how to do it. - The only complications are that the ring buffer wraps, and need to map - switch between 8- and 16-bit modes. */ - -static void -wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) -{ - int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - unsigned long offset = ring_offset - (WD_START_PG<<8); - void __iomem *xfer_start = ei_status.mem + offset; - - if (offset + count > ei_status.priv) { - /* We must wrap the input move. */ - int semi_count = ei_status.priv - offset; - memcpy_fromio(skb->data, xfer_start, semi_count); - count -= semi_count; - memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); - } else { - /* Packet is in one chunk -- we can copy + cksum. */ - memcpy_fromio(skb->data, xfer_start, count); - } - - /* Turn off 16 bit access so that reboot works. ISA brain-damage */ - if (ei_status.word16) - outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5); -} - -static void -wd_block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) -{ - int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - void __iomem *shmem = ei_status.mem + ((start_page - WD_START_PG)<<8); - - - if (ei_status.word16) { - /* Turn on and off 16 bit access so that reboot works. */ - outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5); - memcpy_toio(shmem, buf, count); - outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5); - } else - memcpy_toio(shmem, buf, count); -} - - -static int -wd_close(struct net_device *dev) -{ - int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - struct ei_device *ei_local = netdev_priv(dev); - - netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n"); - ei_close(dev); - - /* Change from 16-bit to 8-bit shared memory so reboot works. */ - if (ei_status.word16) - outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 ); - - /* And disable the shared memory. */ - outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg); - - return 0; -} - - -#ifdef MODULE -#define MAX_WD_CARDS 4 /* Max number of wd cards per module */ -static struct net_device *dev_wd[MAX_WD_CARDS]; -static int io[MAX_WD_CARDS]; -static int irq[MAX_WD_CARDS]; -static int mem[MAX_WD_CARDS]; -static int mem_end[MAX_WD_CARDS]; /* for non std. mem size */ - -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_hw_array(mem, int, iomem, NULL, 0); -module_param_hw_array(mem_end, int, iomem, NULL, 0); -module_param_named(msg_enable, wd_msg_enable, uint, 0444); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)"); -MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)"); -MODULE_PARM_DESC(mem_end, "memory end address(es)"); -MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); -MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver"); -MODULE_LICENSE("GPL"); - -/* This is set up so that only a single autoprobe takes place per call. -ISA device autoprobes on a running machine are not recommended. */ - -static int __init wd_init_module(void) -{ - struct net_device *dev; - int this_dev, found = 0; - - for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - if (io[this_dev] == 0) { - if (this_dev != 0) break; /* only autoprobe 1st one */ - printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n"); - } - dev = alloc_ei_netdev(); - if (!dev) - break; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; - dev->mem_end = mem_end[this_dev]; - if (do_wd_probe(dev) == 0) { - dev_wd[found++] = dev; - continue; - } - free_netdev(dev); - printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); - break; - } - if (found) - return 0; - return -ENXIO; -} -module_init(wd_init_module); - -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); - iounmap(ei_status.mem); -} - -static void __exit wd_cleanup_module(void) -{ - int this_dev; - - for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev = dev_wd[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -module_exit(wd_cleanup_module); -#endif /* MODULE */ diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index bdc29d143160..b8f70e2a1763 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -61,7 +61,6 @@ source "drivers/net/ethernet/engleder/Kconfig" source "drivers/net/ethernet/ezchip/Kconfig" source "drivers/net/ethernet/faraday/Kconfig" source "drivers/net/ethernet/freescale/Kconfig" -source "drivers/net/ethernet/fujitsu/Kconfig" source "drivers/net/ethernet/fungible/Kconfig" source "drivers/net/ethernet/google/Kconfig" source "drivers/net/ethernet/hisilicon/Kconfig" @@ -157,7 +156,6 @@ config OA_TC6 To know the implementation details, refer documentation in . -source "drivers/net/ethernet/packetengines/Kconfig" source "drivers/net/ethernet/pasemi/Kconfig" source "drivers/net/ethernet/pensando/Kconfig" source "drivers/net/ethernet/qlogic/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 6bffb60ba644..57344fec6ce0 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_NET_VENDOR_ENGLEDER) += engleder/ obj-$(CONFIG_NET_VENDOR_EZCHIP) += ezchip/ obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/ obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/ -obj-$(CONFIG_NET_VENDOR_FUJITSU) += fujitsu/ obj-$(CONFIG_NET_VENDOR_FUNGIBLE) += fungible/ obj-$(CONFIG_NET_VENDOR_GOOGLE) += google/ obj-$(CONFIG_NET_VENDOR_HISILICON) += hisilicon/ @@ -73,7 +72,6 @@ obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/ obj-$(CONFIG_LPC_ENET) += nxp/ obj-$(CONFIG_NET_VENDOR_OKI) += oki-semi/ obj-$(CONFIG_ETHOC) += ethoc.o -obj-$(CONFIG_NET_VENDOR_PACKET_ENGINES) += packetengines/ obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/ obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/ obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/ diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 45e8d698781c..e35991141a1a 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -43,17 +43,6 @@ config AMD8111_ETH To compile this driver as a module, choose M here. The module will be called amd8111e. -config LANCE - tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" - depends on ISA && ISA_DMA_API && !ARM && !PPC32 - select NETDEV_LEGACY_INIT - help - If you have a network (Ethernet) card of this type, say Y here. - Some LinkSys cards are of this type. - - To compile this driver as a module, choose M here: the module - will be called lance. This is recommended. - config PCNET32 tristate "AMD PCnet32 PCI support" depends on PCI && HAS_IOPORT @@ -120,16 +109,6 @@ config MVME147_NET driver for this chip in your kernel. To compile this driver as a module, choose M here. -config PCMCIA_NMCLAN - tristate "New Media PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach a New Media Ethernet or LiveWire - PCMCIA (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called nmclan_cs. If unsure, say N. - config SUN3LANCE tristate "Sun3/Sun3x on-board LANCE support" depends on (SUN3 || SUN3X) diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile index 2dcfb84731e1..e485fae235a7 100644 --- a/drivers/net/ethernet/amd/Makefile +++ b/drivers/net/ethernet/amd/Makefile @@ -9,10 +9,8 @@ obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_ATARILANCE) += atarilance.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o -obj-$(CONFIG_LANCE) += lance.o obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o -obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_SUN3LANCE) += sun3lance.o obj-$(CONFIG_SUNLANCE) += sunlance.o diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c deleted file mode 100644 index 98afd8cb0efb..000000000000 --- a/drivers/net/ethernet/amd/lance.c +++ /dev/null @@ -1,1317 +0,0 @@ -/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */ -/* - Written/copyright 1993-1998 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - This driver is for the Allied Telesis AT1500 and HP J2405A, and should work - with most other LANCE-based bus-master (NE2100/NE2500) ethercards. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Andrey V. Savochkin: - - alignment problem with 1.3.* kernel and some minor changes. - Thomas Bogendoerfer (tsbogend@bigbug.franken.de): - - added support for Linux/Alpha, but removed most of it, because - it worked only for the PCI chip. - - added hook for the 32bit lance driver - - added PCnetPCI II (79C970A) to chip table - Paul Gortmaker (gpg109@rsphy1.anu.edu.au): - - hopefully fix above so Linux/Alpha can use ISA cards too. - 8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb - v1.12 10/27/97 Module support -djb - v1.14 2/3/98 Module support modified, made PCI support optional -djb - v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed - before unregister_netdev() which caused NULL pointer - reference later in the chain (in rtnetlink_fill_ifinfo()) - -- Mika Kuoppala - - Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from - the 2.1 version of the old driver - Alan Cox - - Get rid of check_region, check kmalloc return in lance_probe1 - Arnaldo Carvalho de Melo - 11/01/2001 - - Reworked detection, added support for Racal InterLan EtherBlaster cards - Vesselin Kostadinov - 22/4/2004 -*/ - -static const char version[] = "lance.c:v1.16 2006/11/09 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0}; -static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options); -static int __init do_lance_probe(struct net_device *dev); - - -static struct card { - char id_offset14; - char id_offset15; -} cards[] = { - { //"normal" - .id_offset14 = 0x57, - .id_offset15 = 0x57, - }, - { //NI6510EB - .id_offset14 = 0x52, - .id_offset15 = 0x44, - }, - { //Racal InterLan EtherBlaster - .id_offset14 = 0x52, - .id_offset15 = 0x49, - }, -}; -#define NUM_CARDS 3 - -#ifdef LANCE_DEBUG -static int lance_debug = LANCE_DEBUG; -#else -static int lance_debug = 1; -#endif - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the AMD 79C960, the "PCnet-ISA -single-chip ethernet controller for ISA". This chip is used in a wide -variety of boards from vendors such as Allied Telesis, HP, Kingston, -and Boca. This driver is also intended to work with older AMD 7990 -designs, such as the NE1500 and NE2100, and newer 79C961. For convenience, -I use the name LANCE to refer to all of the AMD chips, even though it properly -refers only to the original 7990. - -II. Board-specific settings - -The driver is designed to work the boards that use the faster -bus-master mode, rather than in shared memory mode. (Only older designs -have on-board buffer memory needed to support the slower shared memory mode.) - -Most ISA boards have jumpered settings for the I/O base, IRQ line, and DMA -channel. This driver probes the likely base addresses: -{0x300, 0x320, 0x340, 0x360}. -After the board is found it generates a DMA-timeout interrupt and uses -autoIRQ to find the IRQ line. The DMA channel can be set with the low bits -of the otherwise-unused dev->mem_start value (aka PARAM1). If unset it is -probed for by enabling each free DMA channel in turn and checking if -initialization succeeds. - -The HP-J2405A board is an exception: with this board it is easy to read the -EEPROM-set values for the base, IRQ, and DMA. (Of course you must already -_know_ the base address -- that field is for writing the EEPROM.) - -III. Driver operation - -IIIa. Ring buffers -The LANCE uses ring buffers of Tx and Rx descriptors. Each entry describes -the base and length of the data buffer, along with status bits. The length -of these buffers is set by LANCE_LOG_{RX,TX}_BUFFERS, which is log_2() of -the buffer length (rather than being directly the buffer length) for -implementation ease. The current values are 2 (Tx) and 4 (Rx), which leads to -ring sizes of 4 (Tx) and 16 (Rx). Increasing the number of ring entries -needlessly uses extra space and reduces the chance that an upper layer will -be able to reorder queued Tx packets based on priority. Decreasing the number -of entries makes it more difficult to achieve back-to-back packet transmission -and increases the chance that Rx ring will overflow. (Consider the worst case -of receiving back-to-back minimum-sized packets.) - -The LANCE has the capability to "chain" both Rx and Tx buffers, but this driver -statically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers to -avoid the administrative overhead. For the Rx side this avoids dynamically -allocating full-sized buffers "just in case", at the expense of a -memory-to-memory data copy for each packet received. For most systems this -is a good tradeoff: the Rx buffer will always be in low memory, the copy -is inexpensive, and it primes the cache for later packet processing. For Tx -the buffers are only used when needed as low-memory bounce buffers. - -IIIB. 16M memory limitations. -For the ISA bus master mode all structures used directly by the LANCE, -the initialization block, Rx and Tx rings, and data buffers, must be -accessible from the ISA bus, i.e. in the lower 16M of real memory. -This is a problem for current Linux kernels on >16M machines. The network -devices are initialized after memory initialization, and the kernel doles out -memory from the top of memory downward. The current solution is to have a -special network initialization routine that's called before memory -initialization; this will eventually be generalized for all network devices. -As mentioned before, low-memory "bounce-buffers" are used when needed. - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'lp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so -we can't avoid the interrupt overhead by having the Tx routine reap the Tx -stats.) After reaping the stats, it marks the queue entry as empty by setting -the 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the -tx_full and tbusy flags. - -*/ - -/* Set the number of Tx and Rx buffers, using Log_2(# buffers). - Reasonable default values are 16 Tx buffers, and 16 Rx buffers. - That translates to 4 and 4 (16 == 2^^4). - This is a compile-time option for efficiency. - */ -#ifndef LANCE_LOG_TX_BUFFERS -#define LANCE_LOG_TX_BUFFERS 4 -#define LANCE_LOG_RX_BUFFERS 4 -#endif - -#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) - -#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) - -#define PKT_BUF_SZ 1544 - -/* Offsets from base I/O address. */ -#define LANCE_DATA 0x10 -#define LANCE_ADDR 0x12 -#define LANCE_RESET 0x14 -#define LANCE_BUS_IF 0x16 -#define LANCE_TOTAL_SIZE 0x18 - -#define TX_TIMEOUT (HZ/5) - -/* The LANCE Rx and Tx ring descriptors. */ -struct lance_rx_head { - s32 base; - s16 buf_length; /* This length is 2s complement (negative)! */ - s16 msg_length; /* This length is "normal". */ -}; - -struct lance_tx_head { - s32 base; - s16 length; /* Length is 2s complement (negative)! */ - s16 misc; -}; - -/* The LANCE initialization block, described in databook. */ -struct lance_init_block { - u16 mode; /* Pre-set mode (reg. 15) */ - u8 phys_addr[6]; /* Physical ethernet address */ - u32 filter[2]; /* Multicast filter (unused). */ - /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; /* Tx and Rx ring base pointers */ - u32 tx_ring; -}; - -struct lance_private { - /* The Tx and Rx ring entries must be aligned on 8-byte boundaries. */ - struct lance_rx_head rx_ring[RX_RING_SIZE]; - struct lance_tx_head tx_ring[TX_RING_SIZE]; - struct lance_init_block init_block; - const char *name; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - unsigned long rx_buffs; /* Address of Rx and Tx buffers. */ - /* Tx low-memory "bounce buffer" address. */ - char (*tx_bounce_buffs)[PKT_BUF_SZ]; - int cur_rx, cur_tx; /* The next free ring entry */ - int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - int dma; - unsigned char chip_version; /* See lance_chip_type. */ - spinlock_t devlock; -}; - -#define LANCE_MUST_PAD 0x00000001 -#define LANCE_ENABLE_AUTOSELECT 0x00000002 -#define LANCE_MUST_REINIT_RING 0x00000004 -#define LANCE_MUST_UNRESET 0x00000008 -#define LANCE_HAS_MISSED_FRAME 0x00000010 - -/* A mapping from the chip ID number to the part number and features. - These are from the datasheets -- in real life the '970 version - reportedly has the same ID as the '965. */ -static struct lance_chip_type { - int id_number; - const char *name; - int flags; -} chip_table[] = { - {0x0000, "LANCE 7990", /* Ancient lance chip. */ - LANCE_MUST_PAD + LANCE_MUST_UNRESET}, - {0x0003, "PCnet/ISA 79C960", /* 79C960 PCnet/ISA. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x2260, "PCnet/ISA+ 79C961", /* 79C961 PCnet/ISA+, Plug-n-Play. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x2420, "PCnet/PCI 79C970", /* 79C970 or 79C974 PCnet-SCSI, PCI. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - /* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call - it the PCnet32. */ - {0x2430, "PCnet32", /* 79C965 PCnet for VL bus. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x0, "PCnet (unknown)", - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, -}; - -enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_PCI_II=5, LANCE_UNKNOWN=6}; - - -/* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers. - Assume yes until we know the memory size. */ -static unsigned char lance_need_isa_bounce_buffers = 1; - -static int lance_open(struct net_device *dev); -static void lance_init_ring(struct net_device *dev, gfp_t mode); -static netdev_tx_t lance_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int lance_rx(struct net_device *dev); -static irqreturn_t lance_interrupt(int irq, void *dev_id); -static int lance_close(struct net_device *dev); -static struct net_device_stats *lance_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void lance_tx_timeout (struct net_device *dev, unsigned int txqueue); - - - -#ifdef MODULE -#define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ - -static struct net_device *dev_lance[MAX_CARDS]; -static int io[MAX_CARDS]; -static int dma[MAX_CARDS]; -static int irq[MAX_CARDS]; - -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(dma, int, dma, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param(lance_debug, int, 0); -MODULE_PARM_DESC(io, "LANCE/PCnet I/O base address(es),required"); -MODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devices)"); -MODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)"); -MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)"); - -static int __init lance_init_module(void) -{ - struct net_device *dev; - int this_dev, found = 0; - - for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - if (io[this_dev] == 0) { - if (this_dev != 0) /* only complain once */ - break; - printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n"); - return -EPERM; - } - dev = alloc_etherdev(0); - if (!dev) - break; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->dma = dma[this_dev]; - if (do_lance_probe(dev) == 0) { - dev_lance[found++] = dev; - continue; - } - free_netdev(dev); - break; - } - if (found != 0) - return 0; - return -ENXIO; -} -module_init(lance_init_module); - -static void cleanup_card(struct net_device *dev) -{ - struct lance_private *lp = dev->ml_priv; - if (dev->dma != 4) - free_dma(dev->dma); - release_region(dev->base_addr, LANCE_TOTAL_SIZE); - kfree(lp->tx_bounce_buffs); - kfree((void*)lp->rx_buffs); - kfree(lp); -} - -static void __exit lance_cleanup_module(void) -{ - int this_dev; - - for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev = dev_lance[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -module_exit(lance_cleanup_module); -#endif /* MODULE */ -MODULE_DESCRIPTION("AMD LANCE/PCnet Ethernet driver"); -MODULE_LICENSE("GPL"); - - -/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other - board probes now that kmalloc() can allocate ISA DMA-able regions. - This also allows the LANCE driver to be used as a module. - */ -static int __init do_lance_probe(struct net_device *dev) -{ - unsigned int *port; - int result; - - if (high_memory <= phys_to_virt(16*1024*1024)) - lance_need_isa_bounce_buffers = 0; - - for (port = lance_portlist; *port; port++) { - int ioaddr = *port; - struct resource *r = request_region(ioaddr, LANCE_TOTAL_SIZE, - "lance-probe"); - - if (r) { - /* Detect the card with minimal I/O reads */ - char offset14 = inb(ioaddr + 14); - int card; - for (card = 0; card < NUM_CARDS; ++card) - if (cards[card].id_offset14 == offset14) - break; - if (card < NUM_CARDS) {/*yes, the first byte matches*/ - char offset15 = inb(ioaddr + 15); - for (card = 0; card < NUM_CARDS; ++card) - if ((cards[card].id_offset14 == offset14) && - (cards[card].id_offset15 == offset15)) - break; - } - if (card < NUM_CARDS) { /*Signature OK*/ - result = lance_probe1(dev, ioaddr, 0, 0); - if (!result) { - struct lance_private *lp = dev->ml_priv; - int ver = lp->chip_version; - - r->name = chip_table[ver].name; - return 0; - } - } - release_region(ioaddr, LANCE_TOTAL_SIZE); - } - } - return -ENODEV; -} - -#ifndef MODULE -struct net_device * __init lance_probe(int unit) -{ - struct net_device *dev = alloc_etherdev(0); - int err; - - if (!dev) - return ERR_PTR(-ENODEV); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err = do_lance_probe(dev); - if (err) - goto out; - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif - -static const struct net_device_ops lance_netdev_ops = { - .ndo_open = lance_open, - .ndo_start_xmit = lance_start_xmit, - .ndo_stop = lance_close, - .ndo_get_stats = lance_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_tx_timeout = lance_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options) -{ - struct lance_private *lp; - unsigned long dma_channels; /* Mark spuriously-busy DMA channels */ - int i, reset_val, lance_version; - const char *chipname; - /* Flags for specific chips or boards. */ - unsigned char hpJ2405A = 0; /* HP ISA adaptor */ - int hp_builtin = 0; /* HP on-board ethernet. */ - static int did_version; /* Already printed version info. */ - unsigned long flags; - int err = -ENOMEM; - void __iomem *bios; - u8 addr[ETH_ALEN]; - - /* First we look for special cases. - Check for HP's on-board ethernet by looking for 'HP' in the BIOS. - There are two HP versions, check the BIOS for the configuration port. - This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com. - */ - bios = ioremap(0xf00f0, 0x14); - if (!bios) - return -ENOMEM; - if (readw(bios + 0x12) == 0x5048) { - static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360}; - int hp_port = (readl(bios + 1) & 1) ? 0x499 : 0x99; - /* We can have boards other than the built-in! Verify this is on-board. */ - if ((inb(hp_port) & 0xc0) == 0x80 && - ioaddr_table[inb(hp_port) & 3] == ioaddr) - hp_builtin = hp_port; - } - iounmap(bios); - /* We also recognize the HP Vectra on-board here, but check below. */ - hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00 && - inb(ioaddr+2) == 0x09); - - /* Reset the LANCE. */ - reset_val = inw(ioaddr+LANCE_RESET); /* Reset the LANCE */ - - /* The Un-Reset needed is only needed for the real NE2100, and will - confuse the HP board. */ - if (!hpJ2405A) - outw(reset_val, ioaddr+LANCE_RESET); - - outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */ - if (inw(ioaddr+LANCE_DATA) != 0x0004) - return -ENODEV; - - /* Get the version of the chip. */ - outw(88, ioaddr+LANCE_ADDR); - if (inw(ioaddr+LANCE_ADDR) != 88) { - lance_version = 0; - } else { /* Good, it's a newer chip. */ - int chip_version = inw(ioaddr+LANCE_DATA); - outw(89, ioaddr+LANCE_ADDR); - chip_version |= inw(ioaddr+LANCE_DATA) << 16; - if (lance_debug > 2) - printk(" LANCE chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) != 0x003) - return -ENODEV; - chip_version = (chip_version >> 12) & 0xffff; - for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) { - if (chip_table[lance_version].id_number == chip_version) - break; - } - } - - /* We can't allocate private data from alloc_etherdev() because it must - a ISA DMA-able region. */ - chipname = chip_table[lance_version].name; - printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr); - - /* There is a 16 byte station address PROM at the base address. - The first six bytes are the station address. */ - for (i = 0; i < 6; i++) - addr[i] = inb(ioaddr + i); - eth_hw_addr_set(dev, addr); - printk("%pM", dev->dev_addr); - - dev->base_addr = ioaddr; - /* Make certain the data structures used by the LANCE are aligned and DMAble. */ - - lp = kzalloc_obj(*lp, GFP_DMA | GFP_KERNEL); - if (!lp) - return -ENOMEM; - if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); - dev->ml_priv = lp; - lp->name = chipname; - lp->rx_buffs = (unsigned long)kmalloc_array(RX_RING_SIZE, PKT_BUF_SZ, - GFP_DMA | GFP_KERNEL); - if (!lp->rx_buffs) - goto out_lp; - if (lance_need_isa_bounce_buffers) { - lp->tx_bounce_buffs = kmalloc_array(TX_RING_SIZE, PKT_BUF_SZ, - GFP_DMA | GFP_KERNEL); - if (!lp->tx_bounce_buffs) - goto out_rx; - } else - lp->tx_bounce_buffs = NULL; - - lp->chip_version = lance_version; - spin_lock_init(&lp->devlock); - - lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */ - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.filter[0] = 0x00000000; - lp->init_block.filter[1] = 0x00000000; - lp->init_block.rx_ring = ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS; - lp->init_block.tx_ring = ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS; - - outw(0x0001, ioaddr+LANCE_ADDR); - inw(ioaddr+LANCE_ADDR); - outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA); - outw(0x0002, ioaddr+LANCE_ADDR); - inw(ioaddr+LANCE_ADDR); - outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA); - outw(0x0000, ioaddr+LANCE_ADDR); - inw(ioaddr+LANCE_ADDR); - - if (irq) { /* Set iff PCI card. */ - dev->dma = 4; /* Native bus-master, no DMA channel needed. */ - dev->irq = irq; - } else if (hp_builtin) { - static const char dma_tbl[4] = {3, 5, 6, 0}; - static const char irq_tbl[4] = {3, 4, 5, 9}; - unsigned char port_val = inb(hp_builtin); - dev->dma = dma_tbl[(port_val >> 4) & 3]; - dev->irq = irq_tbl[(port_val >> 2) & 3]; - printk(" HP Vectra IRQ %d DMA %d.\n", dev->irq, dev->dma); - } else if (hpJ2405A) { - static const char dma_tbl[4] = {3, 5, 6, 7}; - static const char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15}; - short reset_val = inw(ioaddr+LANCE_RESET); - dev->dma = dma_tbl[(reset_val >> 2) & 3]; - dev->irq = irq_tbl[(reset_val >> 4) & 7]; - printk(" HP J2405A IRQ %d DMA %d.\n", dev->irq, dev->dma); - } else if (lance_version == PCNET_ISAP) { /* The plug-n-play version. */ - short bus_info; - outw(8, ioaddr+LANCE_ADDR); - bus_info = inw(ioaddr+LANCE_BUS_IF); - dev->dma = bus_info & 0x07; - dev->irq = (bus_info >> 4) & 0x0F; - } else { - /* The DMA channel may be passed in PARAM1. */ - if (dev->mem_start & 0x07) - dev->dma = dev->mem_start & 0x07; - } - - if (dev->dma == 0) { - /* Read the DMA channel status register, so that we can avoid - stuck DMA channels in the DMA detection below. */ - dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | - (inb(DMA2_STAT_REG) & 0xf0); - } - err = -ENODEV; - if (dev->irq >= 2) - printk(" assigned IRQ %d", dev->irq); - else if (lance_version != 0) { /* 7990 boards need DMA detection first. */ - unsigned long irq_mask; - - /* To auto-IRQ we enable the initialization-done and DMA error - interrupts. For ISA boards we get a DMA error, but VLB and PCI - boards will work. */ - irq_mask = probe_irq_on(); - - /* Trigger an initialization just for the interrupt. */ - outw(0x0041, ioaddr+LANCE_DATA); - - mdelay(20); - dev->irq = probe_irq_off(irq_mask); - if (dev->irq) - printk(", probed IRQ %d", dev->irq); - else { - printk(", failed to detect IRQ line.\n"); - goto out_tx; - } - - /* Check for the initialization done bit, 0x0100, which means - that we don't need a DMA channel. */ - if (inw(ioaddr+LANCE_DATA) & 0x0100) - dev->dma = 4; - } - - if (dev->dma == 4) { - printk(", no DMA needed.\n"); - } else if (dev->dma) { - if (request_dma(dev->dma, chipname)) { - printk("DMA %d allocation failed.\n", dev->dma); - goto out_tx; - } else - printk(", assigned DMA %d.\n", dev->dma); - } else { /* OK, we have to auto-DMA. */ - for (i = 0; i < 4; i++) { - static const char dmas[] = { 5, 6, 7, 3 }; - int dma = dmas[i]; - int boguscnt; - - /* Don't enable a permanently busy DMA channel, or the machine - will hang. */ - if (test_bit(dma, &dma_channels)) - continue; - outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */ - if (request_dma(dma, chipname)) - continue; - - flags=claim_dma_lock(); - set_dma_mode(dma, DMA_MODE_CASCADE); - enable_dma(dma); - release_dma_lock(flags); - - /* Trigger an initialization. */ - outw(0x0001, ioaddr+LANCE_DATA); - for (boguscnt = 100; boguscnt > 0; --boguscnt) - if (inw(ioaddr+LANCE_DATA) & 0x0900) - break; - if (inw(ioaddr+LANCE_DATA) & 0x0100) { - dev->dma = dma; - printk(", DMA %d.\n", dev->dma); - break; - } else { - flags=claim_dma_lock(); - disable_dma(dma); - release_dma_lock(flags); - free_dma(dma); - } - } - if (i == 4) { /* Failure: bail. */ - printk("DMA detection failed.\n"); - goto out_tx; - } - } - - if (lance_version == 0 && dev->irq == 0) { - /* We may auto-IRQ now that we have a DMA channel. */ - /* Trigger an initialization just for the interrupt. */ - unsigned long irq_mask; - - irq_mask = probe_irq_on(); - outw(0x0041, ioaddr+LANCE_DATA); - - mdelay(40); - dev->irq = probe_irq_off(irq_mask); - if (dev->irq == 0) { - printk(" Failed to detect the 7990 IRQ line.\n"); - goto out_dma; - } - printk(" Auto-IRQ detected IRQ%d.\n", dev->irq); - } - - if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) { - /* Turn on auto-select of media (10baseT or BNC) so that the user - can watch the LEDs even if the board isn't opened. */ - outw(0x0002, ioaddr+LANCE_ADDR); - /* Don't touch 10base2 power bit. */ - outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF); - } - - if (lance_debug > 0 && did_version++ == 0) - printk(version); - - /* The LANCE-specific entries in the device structure. */ - dev->netdev_ops = &lance_netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - err = register_netdev(dev); - if (err) - goto out_dma; - return 0; -out_dma: - if (dev->dma != 4) - free_dma(dev->dma); -out_tx: - kfree(lp->tx_bounce_buffs); -out_rx: - kfree((void*)lp->rx_buffs); -out_lp: - kfree(lp); - return err; -} - - -static int -lance_open(struct net_device *dev) -{ - struct lance_private *lp = dev->ml_priv; - int ioaddr = dev->base_addr; - int i; - - if (dev->irq == 0 || - request_irq(dev->irq, lance_interrupt, 0, dev->name, dev)) { - return -EAGAIN; - } - - /* We used to allocate DMA here, but that was silly. - DMA lines can't be shared! We now permanently allocate them. */ - - /* Reset the LANCE */ - inw(ioaddr+LANCE_RESET); - - /* The DMA controller is used as a no-operation slave, "cascade mode". */ - if (dev->dma != 4) { - unsigned long flags=claim_dma_lock(); - enable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - release_dma_lock(flags); - } - - /* Un-Reset the LANCE, needed only for the NE2100. */ - if (chip_table[lp->chip_version].flags & LANCE_MUST_UNRESET) - outw(0, ioaddr+LANCE_RESET); - - if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) { - /* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */ - outw(0x0002, ioaddr+LANCE_ADDR); - /* Only touch autoselect bit. */ - outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF); - } - - if (lance_debug > 1) - printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n", - dev->name, dev->irq, dev->dma, - (u32) isa_virt_to_bus(lp->tx_ring), - (u32) isa_virt_to_bus(lp->rx_ring), - (u32) isa_virt_to_bus(&lp->init_block)); - - lance_init_ring(dev, GFP_KERNEL); - /* Re-initialize the LANCE, and start it when done. */ - outw(0x0001, ioaddr+LANCE_ADDR); - outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA); - outw(0x0002, ioaddr+LANCE_ADDR); - outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA); - - outw(0x0004, ioaddr+LANCE_ADDR); - outw(0x0915, ioaddr+LANCE_DATA); - - outw(0x0000, ioaddr+LANCE_ADDR); - outw(0x0001, ioaddr+LANCE_DATA); - - netif_start_queue (dev); - - i = 0; - while (i++ < 100) - if (inw(ioaddr+LANCE_DATA) & 0x0100) - break; - /* - * We used to clear the InitDone bit, 0x0100, here but Mark Stockton - * reports that doing so triggers a bug in the '974. - */ - outw(0x0042, ioaddr+LANCE_DATA); - - if (lance_debug > 2) - printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n", - dev->name, i, (u32) isa_virt_to_bus(&lp->init_block), inw(ioaddr+LANCE_DATA)); - - return 0; /* Always succeed */ -} - -/* The LANCE has been halted for one reason or another (busmaster memory - arbitration error, Tx FIFO underflow, driver stopped it to reconfigure, - etc.). Modern LANCE variants always reload their ring-buffer - configuration when restarted, so we must reinitialize our ring - context before restarting. As part of this reinitialization, - find all packets still on the Tx ring and pretend that they had been - sent (in effect, drop the packets on the floor) - the higher-level - protocols will time out and retransmit. It'd be better to shuffle - these skbs to a temp list and then actually re-Tx them after - restarting the chip, but I'm too lazy to do so right now. dplatt@3do.com -*/ - -static void -lance_purge_ring(struct net_device *dev) -{ - struct lance_private *lp = dev->ml_priv; - int i; - - /* Free all the skbuffs in the Rx and Tx queues. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = lp->rx_skbuff[i]; - lp->rx_skbuff[i] = NULL; - lp->rx_ring[i].base = 0; /* Not owned by LANCE chip. */ - if (skb) - dev_kfree_skb_any(skb); - } - for (i = 0; i < TX_RING_SIZE; i++) { - if (lp->tx_skbuff[i]) { - dev_kfree_skb_any(lp->tx_skbuff[i]); - lp->tx_skbuff[i] = NULL; - } - } -} - - -/* Initialize the LANCE Rx and Tx rings. */ -static void -lance_init_ring(struct net_device *dev, gfp_t gfp) -{ - struct lance_private *lp = dev->ml_priv; - int i; - - lp->cur_rx = lp->cur_tx = 0; - lp->dirty_rx = lp->dirty_tx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - void *rx_buff; - - skb = alloc_skb(PKT_BUF_SZ, GFP_DMA | gfp); - lp->rx_skbuff[i] = skb; - if (skb) - rx_buff = skb->data; - else - rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp); - if (!rx_buff) - lp->rx_ring[i].base = 0; - else - lp->rx_ring[i].base = (u32)isa_virt_to_bus(rx_buff) | 0x80000000; - lp->rx_ring[i].buf_length = -PKT_BUF_SZ; - } - /* The Tx buffer address is filled in as needed, but we do need to clear - the upper ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - lp->tx_skbuff[i] = NULL; - lp->tx_ring[i].base = 0; - } - - lp->init_block.mode = 0x0000; - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.filter[0] = 0x00000000; - lp->init_block.filter[1] = 0x00000000; - lp->init_block.rx_ring = ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS; - lp->init_block.tx_ring = ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS; -} - -static void -lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit) -{ - struct lance_private *lp = dev->ml_priv; - - if (must_reinit || - (chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) { - lance_purge_ring(dev); - lance_init_ring(dev, GFP_ATOMIC); - } - outw(0x0000, dev->base_addr + LANCE_ADDR); - outw(csr0_bits, dev->base_addr + LANCE_DATA); -} - - -static void lance_tx_timeout (struct net_device *dev, unsigned int txqueue) -{ - struct lance_private *lp = (struct lance_private *) dev->ml_priv; - int ioaddr = dev->base_addr; - - outw (0, ioaddr + LANCE_ADDR); - printk ("%s: transmit timed out, status %4.4x, resetting.\n", - dev->name, inw (ioaddr + LANCE_DATA)); - outw (0x0004, ioaddr + LANCE_DATA); - dev->stats.tx_errors++; -#ifndef final_version - if (lance_debug > 3) { - int i; - printk (" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", - lp->dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? " (full)" : "", - lp->cur_rx); - for (i = 0; i < RX_RING_SIZE; i++) - printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, - lp->rx_ring[i].msg_length); - for (i = 0; i < TX_RING_SIZE; i++) - printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - lp->tx_ring[i].base, -lp->tx_ring[i].length, - lp->tx_ring[i].misc); - printk ("\n"); - } -#endif - lance_restart (dev, 0x0043, 1); - - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue (dev); -} - - -static netdev_tx_t lance_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct lance_private *lp = dev->ml_priv; - int ioaddr = dev->base_addr; - int entry; - unsigned long flags; - - spin_lock_irqsave(&lp->devlock, flags); - - if (lance_debug > 3) { - outw(0x0000, ioaddr+LANCE_ADDR); - printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, - inw(ioaddr+LANCE_DATA)); - outw(0x0000, ioaddr+LANCE_DATA); - } - - /* Fill in a Tx ring entry */ - - /* Mask to ring buffer boundary. */ - entry = lp->cur_tx & TX_RING_MOD_MASK; - - /* Caution: the write order is important here, set the base address - with the "ownership" bits last. */ - - /* The old LANCE chips doesn't automatically pad buffers to min. size. */ - if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) { - if (skb->len < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) - goto out; - lp->tx_ring[entry].length = -ETH_ZLEN; - } - else - lp->tx_ring[entry].length = -skb->len; - } else - lp->tx_ring[entry].length = -skb->len; - - lp->tx_ring[entry].misc = 0x0000; - - dev->stats.tx_bytes += skb->len; - - /* If any part of this buffer is >16M we must copy it to a low-memory - buffer. */ - if ((u32)isa_virt_to_bus(skb->data) + skb->len > 0x01000000) { - if (lance_debug > 5) - printk("%s: bouncing a high-memory packet (%#x).\n", - dev->name, (u32)isa_virt_to_bus(skb->data)); - skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len); - lp->tx_ring[entry].base = - ((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000; - dev_consume_skb_irq(skb); - } else { - lp->tx_skbuff[entry] = skb; - lp->tx_ring[entry].base = ((u32)isa_virt_to_bus(skb->data) & 0xffffff) | 0x83000000; - } - lp->cur_tx++; - - /* Trigger an immediate send poll. */ - outw(0x0000, ioaddr+LANCE_ADDR); - outw(0x0048, ioaddr+LANCE_DATA); - - if ((lp->cur_tx - lp->dirty_tx) >= TX_RING_SIZE) - netif_stop_queue(dev); - -out: - spin_unlock_irqrestore(&lp->devlock, flags); - return NETDEV_TX_OK; -} - -/* The LANCE interrupt handler. */ -static irqreturn_t lance_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct lance_private *lp; - int csr0, ioaddr, boguscnt=10; - int must_restart; - - ioaddr = dev->base_addr; - lp = dev->ml_priv; - - spin_lock (&lp->devlock); - - outw(0x00, dev->base_addr + LANCE_ADDR); - while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600 && - --boguscnt >= 0) { - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA); - - must_restart = 0; - - if (lance_debug > 5) - printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", - dev->name, csr0, inw(dev->base_addr + LANCE_DATA)); - - if (csr0 & 0x0400) /* Rx interrupt */ - lance_rx(dev); - - if (csr0 & 0x0200) { /* Tx-done interrupt */ - int dirty_tx = lp->dirty_tx; - - while (dirty_tx < lp->cur_tx) { - int entry = dirty_tx & TX_RING_MOD_MASK; - int status = lp->tx_ring[entry].base; - - if (status < 0) - break; /* It still hasn't been Txed */ - - lp->tx_ring[entry].base = 0; - - if (status & 0x40000000) { - /* There was an major error, log it. */ - int err_status = lp->tx_ring[entry].misc; - dev->stats.tx_errors++; - if (err_status & 0x0400) - dev->stats.tx_aborted_errors++; - if (err_status & 0x0800) - dev->stats.tx_carrier_errors++; - if (err_status & 0x1000) - dev->stats.tx_window_errors++; - if (err_status & 0x4000) { - /* Ackk! On FIFO errors the Tx unit is turned off! */ - dev->stats.tx_fifo_errors++; - /* Remove this verbosity later! */ - printk("%s: Tx FIFO error! Status %4.4x.\n", - dev->name, csr0); - /* Restart the chip. */ - must_restart = 1; - } - } else { - if (status & 0x18000000) - dev->stats.collisions++; - dev->stats.tx_packets++; - } - - /* We must free the original skb if it's not a data-only copy - in the bounce buffer. */ - if (lp->tx_skbuff[entry]) { - dev_consume_skb_irq(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] = NULL; - } - dirty_tx++; - } - -#ifndef final_version - if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { - printk("out-of-sync dirty pointer, %d vs. %d, full=%s.\n", - dirty_tx, lp->cur_tx, - netif_queue_stopped(dev) ? "yes" : "no"); - dirty_tx += TX_RING_SIZE; - } -#endif - - /* if the ring is no longer full, accept more packets */ - if (netif_queue_stopped(dev) && - dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) - netif_wake_queue (dev); - - lp->dirty_tx = dirty_tx; - } - - /* Log misc errors. */ - if (csr0 & 0x4000) - dev->stats.tx_errors++; /* Tx babble. */ - if (csr0 & 0x1000) - dev->stats.rx_errors++; /* Missed a Rx frame. */ - if (csr0 & 0x0800) { - printk("%s: Bus master arbitration failure, status %4.4x.\n", - dev->name, csr0); - /* Restart the chip. */ - must_restart = 1; - } - - if (must_restart) { - /* stop the chip to clear the error condition, then restart */ - outw(0x0000, dev->base_addr + LANCE_ADDR); - outw(0x0004, dev->base_addr + LANCE_DATA); - lance_restart(dev, 0x0002, 0); - } - } - - /* Clear any other interrupt, and set interrupt enable. */ - outw(0x0000, dev->base_addr + LANCE_ADDR); - outw(0x7940, dev->base_addr + LANCE_DATA); - - if (lance_debug > 4) - printk("%s: exiting interrupt, csr%d=%#4.4x.\n", - dev->name, inw(ioaddr + LANCE_ADDR), - inw(dev->base_addr + LANCE_DATA)); - - spin_unlock (&lp->devlock); - return IRQ_HANDLED; -} - -static int -lance_rx(struct net_device *dev) -{ - struct lance_private *lp = dev->ml_priv; - int entry = lp->cur_rx & RX_RING_MOD_MASK; - int i; - - /* If we own the next entry, it's a new packet. Send it up. */ - while (lp->rx_ring[entry].base >= 0) { - int status = lp->rx_ring[entry].base >> 24; - - if (status != 0x03) { /* There was an error. */ - /* There is a tricky error noted by John Murphy, - to Russ Nelson: Even with full-sized - buffers it's possible for a jabber packet to use two - buffers, with only the last correctly noting the error. */ - if (status & 0x01) /* Only count a general error at the */ - dev->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x20) - dev->stats.rx_frame_errors++; - if (status & 0x10) - dev->stats.rx_over_errors++; - if (status & 0x08) - dev->stats.rx_crc_errors++; - if (status & 0x04) - dev->stats.rx_fifo_errors++; - lp->rx_ring[entry].base &= 0x03ffffff; - } - else - { - /* Malloc up new buffer, compatible with net3. */ - short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4; - struct sk_buff *skb; - - if(pkt_len<60) - { - printk("%s: Runt packet!\n",dev->name); - dev->stats.rx_errors++; - } - else - { - skb = dev_alloc_skb(pkt_len+2); - if (!skb) - { - printk("%s: Memory squeeze, deferring packet.\n", dev->name); - for (i=0; i < RX_RING_SIZE; i++) - if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0) - break; - - if (i > RX_RING_SIZE -2) - { - dev->stats.rx_dropped++; - lp->rx_ring[entry].base |= 0x80000000; - lp->cur_rx++; - } - break; - } - skb_reserve(skb,2); /* 16 byte align */ - skb_put(skb,pkt_len); /* Make room */ - skb_copy_to_linear_data(skb, - (unsigned char *)isa_bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)), - pkt_len); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - } - /* The docs say that the buffer length isn't touched, but Andrew Boyd - of QNX reports that some revs of the 79C965 clear it. */ - lp->rx_ring[entry].buf_length = -PKT_BUF_SZ; - lp->rx_ring[entry].base |= 0x80000000; - entry = (++lp->cur_rx) & RX_RING_MOD_MASK; - } - - /* We should check that at least two ring entries are free. If not, - we should free one and mark stats->rx_dropped++. */ - - return 0; -} - -static int -lance_close(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct lance_private *lp = dev->ml_priv; - - netif_stop_queue (dev); - - if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { - outw(112, ioaddr+LANCE_ADDR); - dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA); - } - outw(0, ioaddr+LANCE_ADDR); - - if (lance_debug > 1) - printk("%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inw(ioaddr+LANCE_DATA)); - - /* We stop the LANCE here -- it occasionally polls - memory if we don't. */ - outw(0x0004, ioaddr+LANCE_DATA); - - if (dev->dma != 4) - { - unsigned long flags=claim_dma_lock(); - disable_dma(dev->dma); - release_dma_lock(flags); - } - free_irq(dev->irq, dev); - - lance_purge_ring(dev); - - return 0; -} - -static struct net_device_stats *lance_get_stats(struct net_device *dev) -{ - struct lance_private *lp = dev->ml_priv; - - if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { - short ioaddr = dev->base_addr; - short saved_addr; - unsigned long flags; - - spin_lock_irqsave(&lp->devlock, flags); - saved_addr = inw(ioaddr+LANCE_ADDR); - outw(112, ioaddr+LANCE_ADDR); - dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA); - outw(saved_addr, ioaddr+LANCE_ADDR); - spin_unlock_irqrestore(&lp->devlock, flags); - } - - return &dev->stats; -} - -/* Set or clear the multicast filter for this adaptor. - */ - -static void set_multicast_list(struct net_device *dev) -{ - short ioaddr = dev->base_addr; - - outw(0, ioaddr+LANCE_ADDR); - outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */ - - if (dev->flags&IFF_PROMISC) { - outw(15, ioaddr+LANCE_ADDR); - outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */ - } else { - short multicast_table[4]; - int i; - int num_addrs=netdev_mc_count(dev); - if(dev->flags&IFF_ALLMULTI) - num_addrs=1; - /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */ - memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table)); - for (i = 0; i < 4; i++) { - outw(8 + i, ioaddr+LANCE_ADDR); - outw(multicast_table[i], ioaddr+LANCE_DATA); - } - outw(15, ioaddr+LANCE_ADDR); - outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */ - } - - lance_restart(dev, 0x0142, 0); /* Resume normal operation */ - -} - diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c deleted file mode 100644 index 37054a670407..000000000000 --- a/drivers/net/ethernet/amd/nmclan_cs.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* ---------------------------------------------------------------------------- -Linux PCMCIA ethernet adapter driver for the New Media Ethernet LAN. - nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao - - The Ethernet LAN uses the Advanced Micro Devices (AMD) Am79C940 Media - Access Controller for Ethernet (MACE). It is essentially the Am2150 - PCMCIA Ethernet card contained in the Am2150 Demo Kit. - -Written by Roger C. Pao - Copyright 1995 Roger C. Pao - Linux 2.5 cleanups Copyright Red Hat 2003 - - This software may be used and distributed according to the terms of - the GNU General Public License. - -Ported to Linux 1.3.* network driver environment by - Matti Aarnio - -References - - Am2150 Technical Reference Manual, Revision 1.0, August 17, 1993 - Am79C940 (MACE) Data Sheet, 1994 - Am79C90 (C-LANCE) Data Sheet, 1994 - Linux PCMCIA Programmer's Guide v1.17 - /usr/src/linux/net/inet/dev.c, Linux kernel 1.2.8 - - Eric Mears, New Media Corporation - Tom Pollard, New Media Corporation - Dean Siasoyco, New Media Corporation - Ken Lesniak, Silicon Graphics, Inc. - Donald Becker - David Hinds - - The Linux client driver is based on the 3c589_cs.c client driver by - David Hinds. - - The Linux network driver outline is based on the 3c589_cs.c driver, - the 8390.c driver, and the example skeleton.c kernel code, which are - by Donald Becker. - - The Am2150 network driver hardware interface code is based on the - OS/9000 driver for the New Media Ethernet LAN by Eric Mears. - - Special thanks for testing and help in debugging this driver goes - to Ken Lesniak. - -------------------------------------------------------------------------------- -Driver Notes and Issues -------------------------------------------------------------------------------- - -1. Developed on a Dell 320SLi - PCMCIA Card Services 2.6.2 - Linux dell 1.2.10 #1 Thu Jun 29 20:23:41 PDT 1995 i386 - -2. rc.pcmcia may require loading pcmcia_core with io_speed=300: - 'insmod pcmcia_core.o io_speed=300'. - This will avoid problems with fast systems which causes rx_framecnt - to return random values. - -3. If hot extraction does not work for you, use 'ifconfig eth0 down' - before extraction. - -4. There is a bad slow-down problem in this driver. - -5. Future: Multicast processing. In the meantime, do _not_ compile your - kernel with multicast ip enabled. - -------------------------------------------------------------------------------- -History -------------------------------------------------------------------------------- -Log: nmclan_cs.c,v - * 2.5.75-ac1 2003/07/11 Alan Cox - * Fixed hang on card eject as we probe it - * Cleaned up to use new style locking. - * - * Revision 0.16 1995/07/01 06:42:17 rpao - * Bug fix: nmclan_reset() called CardServices incorrectly. - * - * Revision 0.15 1995/05/24 08:09:47 rpao - * Re-implement MULTI_TX dev->tbusy handling. - * - * Revision 0.14 1995/05/23 03:19:30 rpao - * Added, in nmclan_config(), "tuple.Attributes = 0;". - * Modified MACE ID check to ignore chip revision level. - * Avoid tx_free_frames race condition between _start_xmit and _interrupt. - * - * Revision 0.13 1995/05/18 05:56:34 rpao - * Statistics changes. - * Bug fix: nmclan_reset did not enable TX and RX: call restore_multicast_list. - * Bug fix: mace_interrupt checks ~MACE_IMR_DEFAULT. Fixes driver lockup. - * - * Revision 0.12 1995/05/14 00:12:23 rpao - * Statistics overhaul. - * - -95/05/13 rpao V0.10a - Bug fix: MACE statistics counters used wrong I/O ports. - Bug fix: mace_interrupt() needed to allow statistics to be - processed without RX or TX interrupts pending. -95/05/11 rpao V0.10 - Multiple transmit request processing. - Modified statistics to use MACE counters where possible. -95/05/10 rpao V0.09 Bug fix: Must use IO_DATA_PATH_WIDTH_AUTO. - *Released -95/05/10 rpao V0.08 - Bug fix: Make all non-exported functions private by using - static keyword. - Bug fix: Test IntrCnt _before_ reading MACE_IR. -95/05/10 rpao V0.07 Statistics. -95/05/09 rpao V0.06 Fix rx_framecnt problem by addition of PCIC wait states. - ----------------------------------------------------------------------------- */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DRV_NAME "nmclan_cs" - -/* ---------------------------------------------------------------------------- -Conditional Compilation Options ----------------------------------------------------------------------------- */ - -#define MULTI_TX 0 -#define RESET_ON_TIMEOUT 1 -#define TX_INTERRUPTABLE 1 -#define RESET_XILINX 0 - -/* ---------------------------------------------------------------------------- -Include Files ----------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/* ---------------------------------------------------------------------------- -Defines ----------------------------------------------------------------------------- */ - -#define MACE_LADRF_LEN 8 - /* 8 bytes in Logical Address Filter */ - -/* Loop Control Defines */ -#define MACE_MAX_IR_ITERATIONS 10 -#define MACE_MAX_RX_ITERATIONS 12 - /* - TBD: Dean brought this up, and I assumed the hardware would - handle it: - - If MACE_MAX_RX_ITERATIONS is > 1, rx_framecnt may still be - non-zero when the isr exits. We may not get another interrupt - to process the remaining packets for some time. - */ - -/* -The Am2150 has a Xilinx XC3042 field programmable gate array (FPGA) -which manages the interface between the MACE and the PCMCIA bus. It -also includes buffer management for the 32K x 8 SRAM to control up to -four transmit and 12 receive frames at a time. -*/ -#define AM2150_MAX_TX_FRAMES 4 -#define AM2150_MAX_RX_FRAMES 12 - -/* Am2150 Ethernet Card I/O Mapping */ -#define AM2150_RCV 0x00 -#define AM2150_XMT 0x04 -#define AM2150_XMT_SKIP 0x09 -#define AM2150_RCV_NEXT 0x0A -#define AM2150_RCV_FRAME_COUNT 0x0B -#define AM2150_MACE_BANK 0x0C -#define AM2150_MACE_BASE 0x10 - -/* MACE Registers */ -#define MACE_RCVFIFO 0 -#define MACE_XMTFIFO 1 -#define MACE_XMTFC 2 -#define MACE_XMTFS 3 -#define MACE_XMTRC 4 -#define MACE_RCVFC 5 -#define MACE_RCVFS 6 -#define MACE_FIFOFC 7 -#define MACE_IR 8 -#define MACE_IMR 9 -#define MACE_PR 10 -#define MACE_BIUCC 11 -#define MACE_FIFOCC 12 -#define MACE_MACCC 13 -#define MACE_PLSCC 14 -#define MACE_PHYCC 15 -#define MACE_CHIPIDL 16 -#define MACE_CHIPIDH 17 -#define MACE_IAC 18 -/* Reserved */ -#define MACE_LADRF 20 -#define MACE_PADR 21 -/* Reserved */ -/* Reserved */ -#define MACE_MPC 24 -/* Reserved */ -#define MACE_RNTPC 26 -#define MACE_RCVCC 27 -/* Reserved */ -#define MACE_UTR 29 -#define MACE_RTR1 30 -#define MACE_RTR2 31 - -/* MACE Bit Masks */ -#define MACE_XMTRC_EXDEF 0x80 -#define MACE_XMTRC_XMTRC 0x0F - -#define MACE_XMTFS_XMTSV 0x80 -#define MACE_XMTFS_UFLO 0x40 -#define MACE_XMTFS_LCOL 0x20 -#define MACE_XMTFS_MORE 0x10 -#define MACE_XMTFS_ONE 0x08 -#define MACE_XMTFS_DEFER 0x04 -#define MACE_XMTFS_LCAR 0x02 -#define MACE_XMTFS_RTRY 0x01 - -#define MACE_RCVFS_RCVSTS 0xF000 -#define MACE_RCVFS_OFLO 0x8000 -#define MACE_RCVFS_CLSN 0x4000 -#define MACE_RCVFS_FRAM 0x2000 -#define MACE_RCVFS_FCS 0x1000 - -#define MACE_FIFOFC_RCVFC 0xF0 -#define MACE_FIFOFC_XMTFC 0x0F - -#define MACE_IR_JAB 0x80 -#define MACE_IR_BABL 0x40 -#define MACE_IR_CERR 0x20 -#define MACE_IR_RCVCCO 0x10 -#define MACE_IR_RNTPCO 0x08 -#define MACE_IR_MPCO 0x04 -#define MACE_IR_RCVINT 0x02 -#define MACE_IR_XMTINT 0x01 - -#define MACE_MACCC_PROM 0x80 -#define MACE_MACCC_DXMT2PD 0x40 -#define MACE_MACCC_EMBA 0x20 -#define MACE_MACCC_RESERVED 0x10 -#define MACE_MACCC_DRCVPA 0x08 -#define MACE_MACCC_DRCVBC 0x04 -#define MACE_MACCC_ENXMT 0x02 -#define MACE_MACCC_ENRCV 0x01 - -#define MACE_PHYCC_LNKFL 0x80 -#define MACE_PHYCC_DLNKTST 0x40 -#define MACE_PHYCC_REVPOL 0x20 -#define MACE_PHYCC_DAPC 0x10 -#define MACE_PHYCC_LRT 0x08 -#define MACE_PHYCC_ASEL 0x04 -#define MACE_PHYCC_RWAKE 0x02 -#define MACE_PHYCC_AWAKE 0x01 - -#define MACE_IAC_ADDRCHG 0x80 -#define MACE_IAC_PHYADDR 0x04 -#define MACE_IAC_LOGADDR 0x02 - -#define MACE_UTR_RTRE 0x80 -#define MACE_UTR_RTRD 0x40 -#define MACE_UTR_RPA 0x20 -#define MACE_UTR_FCOLL 0x10 -#define MACE_UTR_RCVFCSE 0x08 -#define MACE_UTR_LOOP_INCL_MENDEC 0x06 -#define MACE_UTR_LOOP_NO_MENDEC 0x04 -#define MACE_UTR_LOOP_EXTERNAL 0x02 -#define MACE_UTR_LOOP_NONE 0x00 -#define MACE_UTR_RESERVED 0x01 - -/* Switch MACE register bank (only 0 and 1 are valid) */ -#define MACEBANK(win_num) outb((win_num), ioaddr + AM2150_MACE_BANK) - -#define MACE_IMR_DEFAULT \ - (0xFF - \ - ( \ - MACE_IR_CERR | \ - MACE_IR_RCVCCO | \ - MACE_IR_RNTPCO | \ - MACE_IR_MPCO | \ - MACE_IR_RCVINT | \ - MACE_IR_XMTINT \ - ) \ - ) -#undef MACE_IMR_DEFAULT -#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */ - -#define TX_TIMEOUT ((400*HZ)/1000) - -/* ---------------------------------------------------------------------------- -Type Definitions ----------------------------------------------------------------------------- */ - -typedef struct _mace_statistics { - /* MACE_XMTFS */ - int xmtsv; - int uflo; - int lcol; - int more; - int one; - int defer; - int lcar; - int rtry; - - /* MACE_XMTRC */ - int exdef; - int xmtrc; - - /* RFS1--Receive Status (RCVSTS) */ - int oflo; - int clsn; - int fram; - int fcs; - - /* RFS2--Runt Packet Count (RNTPC) */ - int rfs_rntpc; - - /* RFS3--Receive Collision Count (RCVCC) */ - int rfs_rcvcc; - - /* MACE_IR */ - int jab; - int babl; - int cerr; - int rcvcco; - int rntpco; - int mpco; - - /* MACE_MPC */ - int mpc; - - /* MACE_RNTPC */ - int rntpc; - - /* MACE_RCVCC */ - int rcvcc; -} mace_statistics; - -typedef struct _mace_private { - struct pcmcia_device *p_dev; - mace_statistics mace_stats; /* MACE chip statistics counters */ - - /* restore_multicast_list() state variables */ - int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */ - int multicast_num_addrs; - - char tx_free_frames; /* Number of free transmit frame buffers */ - char tx_irq_disabled; /* MACE TX interrupt disabled */ - - spinlock_t bank_lock; /* Must be held if you step off bank 0 */ -} mace_private; - -/* ---------------------------------------------------------------------------- -Private Global Variables ----------------------------------------------------------------------------- */ - -static const char *if_names[]={ - "Auto", "10baseT", "BNC", -}; - -/* ---------------------------------------------------------------------------- -Parameters - These are the parameters that can be set during loading with - 'insmod'. ----------------------------------------------------------------------------- */ - -MODULE_DESCRIPTION("New Media PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -/* 0=auto, 1=10baseT, 2 = 10base2, default=auto */ -INT_MODULE_PARM(if_port, 0); - - -/* ---------------------------------------------------------------------------- -Function Prototypes ----------------------------------------------------------------------------- */ - -static int nmclan_config(struct pcmcia_device *link); -static void nmclan_release(struct pcmcia_device *link); - -static void nmclan_reset(struct net_device *dev); -static int mace_config(struct net_device *dev, struct ifmap *map); -static int mace_open(struct net_device *dev); -static int mace_close(struct net_device *dev); -static netdev_tx_t mace_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static void mace_tx_timeout(struct net_device *dev, unsigned int txqueue); -static irqreturn_t mace_interrupt(int irq, void *dev_id); -static struct net_device_stats *mace_get_stats(struct net_device *dev); -static int mace_rx(struct net_device *dev, unsigned char RxCnt); -static void restore_multicast_list(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static const struct ethtool_ops netdev_ethtool_ops; - - -static void nmclan_detach(struct pcmcia_device *p_dev); - -static const struct net_device_ops mace_netdev_ops = { - .ndo_open = mace_open, - .ndo_stop = mace_close, - .ndo_start_xmit = mace_start_xmit, - .ndo_tx_timeout = mace_tx_timeout, - .ndo_set_config = mace_config, - .ndo_get_stats = mace_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int nmclan_probe(struct pcmcia_device *link) -{ - mace_private *lp; - struct net_device *dev; - - dev_dbg(&link->dev, "nmclan_attach()\n"); - - /* Create new ethernet device */ - dev = alloc_etherdev(sizeof(mace_private)); - if (!dev) - return -ENOMEM; - lp = netdev_priv(dev); - lp->p_dev = link; - link->priv = dev; - - spin_lock_init(&lp->bank_lock); - link->resource[0]->end = 32; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->config_flags |= CONF_ENABLE_IRQ; - link->config_index = 1; - link->config_regs = PRESENT_OPTION; - - lp->tx_free_frames=AM2150_MAX_TX_FRAMES; - - dev->netdev_ops = &mace_netdev_ops; - dev->ethtool_ops = &netdev_ethtool_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - return nmclan_config(link); -} /* nmclan_attach */ - -static void nmclan_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - dev_dbg(&link->dev, "nmclan_detach\n"); - - unregister_netdev(dev); - - nmclan_release(link); - - free_netdev(dev); -} /* nmclan_detach */ - -/* ---------------------------------------------------------------------------- -mace_read - Reads a MACE register. This is bank independent; however, the - caller must ensure that this call is not interruptable. We are - assuming that during normal operation, the MACE is always in - bank 0. ----------------------------------------------------------------------------- */ -static int mace_read(mace_private *lp, unsigned int ioaddr, int reg) -{ - int data = 0xFF; - unsigned long flags; - - switch (reg >> 4) { - case 0: /* register 0-15 */ - data = inb(ioaddr + AM2150_MACE_BASE + reg); - break; - case 1: /* register 16-31 */ - spin_lock_irqsave(&lp->bank_lock, flags); - MACEBANK(1); - data = inb(ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); - MACEBANK(0); - spin_unlock_irqrestore(&lp->bank_lock, flags); - break; - } - return data & 0xFF; -} /* mace_read */ - -/* ---------------------------------------------------------------------------- -mace_write - Writes to a MACE register. This is bank independent; however, - the caller must ensure that this call is not interruptable. We - are assuming that during normal operation, the MACE is always in - bank 0. ----------------------------------------------------------------------------- */ -static void mace_write(mace_private *lp, unsigned int ioaddr, int reg, - int data) -{ - unsigned long flags; - - switch (reg >> 4) { - case 0: /* register 0-15 */ - outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + reg); - break; - case 1: /* register 16-31 */ - spin_lock_irqsave(&lp->bank_lock, flags); - MACEBANK(1); - outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); - MACEBANK(0); - spin_unlock_irqrestore(&lp->bank_lock, flags); - break; - } -} /* mace_write */ - -/* ---------------------------------------------------------------------------- -mace_init - Resets the MACE chip. ----------------------------------------------------------------------------- */ -static int mace_init(mace_private *lp, unsigned int ioaddr, - const char *enet_addr) -{ - int i; - int ct = 0; - - /* MACE Software reset */ - mace_write(lp, ioaddr, MACE_BIUCC, 1); - while (mace_read(lp, ioaddr, MACE_BIUCC) & 0x01) { - /* Wait for reset bit to be cleared automatically after <= 200ns */; - if(++ct > 500) - { - pr_err("reset failed, card removed?\n"); - return -1; - } - udelay(1); - } - mace_write(lp, ioaddr, MACE_BIUCC, 0); - - /* The Am2150 requires that the MACE FIFOs operate in burst mode. */ - mace_write(lp, ioaddr, MACE_FIFOCC, 0x0F); - - mace_write(lp,ioaddr, MACE_RCVFC, 0); /* Disable Auto Strip Receive */ - mace_write(lp, ioaddr, MACE_IMR, 0xFF); /* Disable all interrupts until _open */ - - /* - * Bit 2-1 PORTSEL[1-0] Port Select. - * 00 AUI/10Base-2 - * 01 10Base-T - * 10 DAI Port (reserved in Am2150) - * 11 GPSI - * For this card, only the first two are valid. - * So, PLSCC should be set to - * 0x00 for 10Base-2 - * 0x02 for 10Base-T - * Or just set ASEL in PHYCC below! - */ - switch (if_port) { - case 1: - mace_write(lp, ioaddr, MACE_PLSCC, 0x02); - break; - case 2: - mace_write(lp, ioaddr, MACE_PLSCC, 0x00); - break; - default: - mace_write(lp, ioaddr, MACE_PHYCC, /* ASEL */ 4); - /* ASEL Auto Select. When set, the PORTSEL[1-0] bits are overridden, - and the MACE device will automatically select the operating media - interface port. */ - break; - } - - mace_write(lp, ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_PHYADDR); - /* Poll ADDRCHG bit */ - ct = 0; - while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG) - { - if(++ ct > 500) - { - pr_err("ADDRCHG timeout, card removed?\n"); - return -1; - } - } - /* Set PADR register */ - for (i = 0; i < ETH_ALEN; i++) - mace_write(lp, ioaddr, MACE_PADR, enet_addr[i]); - - /* MAC Configuration Control Register should be written last */ - /* Let set_multicast_list set this. */ - /* mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */ - mace_write(lp, ioaddr, MACE_MACCC, 0x00); - return 0; -} /* mace_init */ - -static int nmclan_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - mace_private *lp = netdev_priv(dev); - u8 *buf; - size_t len; - int i, ret; - unsigned int ioaddr; - - dev_dbg(&link->dev, "nmclan_config\n"); - - link->io_lines = 5; - ret = pcmcia_request_io(link); - if (ret) - goto failed; - ret = pcmcia_request_irq(link, mace_interrupt); - if (ret) - goto failed; - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - - ioaddr = dev->base_addr; - - /* Read the ethernet address from the CIS. */ - len = pcmcia_get_tuple(link, 0x80, &buf); - if (!buf || len < ETH_ALEN) { - kfree(buf); - goto failed; - } - eth_hw_addr_set(dev, buf); - kfree(buf); - - /* Verify configuration by reading the MACE ID. */ - { - char sig[2]; - - sig[0] = mace_read(lp, ioaddr, MACE_CHIPIDL); - sig[1] = mace_read(lp, ioaddr, MACE_CHIPIDH); - if ((sig[0] == 0x40) && ((sig[1] & 0x0F) == 0x09)) { - dev_dbg(&link->dev, "nmclan_cs configured: mace id=%x %x\n", - sig[0], sig[1]); - } else { - pr_notice("mace id not found: %x %x should be 0x40 0x?9\n", - sig[0], sig[1]); - goto failed; - } - } - - if(mace_init(lp, ioaddr, dev->dev_addr) == -1) - goto failed; - - /* The if_port symbol can be set when the module is loaded */ - if (if_port <= 2) - dev->if_port = if_port; - else - pr_notice("invalid if_port requested\n"); - - SET_NETDEV_DEV(dev, &link->dev); - - i = register_netdev(dev); - if (i != 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "nmclan: port %#3lx, irq %d, %s port, hw_addr %pM\n", - dev->base_addr, dev->irq, if_names[dev->if_port], dev->dev_addr); - return 0; - -failed: - nmclan_release(link); - return -ENODEV; -} /* nmclan_config */ - -static void nmclan_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "nmclan_release\n"); - pcmcia_disable_device(link); -} - -static int nmclan_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int nmclan_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - nmclan_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -/* ---------------------------------------------------------------------------- -nmclan_reset - Reset and restore all of the Xilinx and MACE registers. ----------------------------------------------------------------------------- */ -static void nmclan_reset(struct net_device *dev) -{ - mace_private *lp = netdev_priv(dev); - -#if RESET_XILINX - struct pcmcia_device *link = &lp->link; - u8 OrigCorValue; - - /* Save original COR value */ - pcmcia_read_config_byte(link, CISREG_COR, &OrigCorValue); - - /* Reset Xilinx */ - dev_dbg(&link->dev, "nmclan_reset: OrigCorValue=0x%x, resetting...\n", - OrigCorValue); - pcmcia_write_config_byte(link, CISREG_COR, COR_SOFT_RESET); - /* Need to wait for 20 ms for PCMCIA to finish reset. */ - - /* Restore original COR configuration index */ - pcmcia_write_config_byte(link, CISREG_COR, - (COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK))); - /* Xilinx is now completely reset along with the MACE chip. */ - lp->tx_free_frames=AM2150_MAX_TX_FRAMES; - -#endif /* #if RESET_XILINX */ - - /* Xilinx is now completely reset along with the MACE chip. */ - lp->tx_free_frames=AM2150_MAX_TX_FRAMES; - - /* Reinitialize the MACE chip for operation. */ - mace_init(lp, dev->base_addr, dev->dev_addr); - mace_write(lp, dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT); - - /* Restore the multicast list and enable TX and RX. */ - restore_multicast_list(dev); -} /* nmclan_reset */ - -/* ---------------------------------------------------------------------------- -mace_config - [Someone tell me what this is supposed to do? Is if_port a defined - standard? If so, there should be defines to indicate 1=10Base-T, - 2=10Base-2, etc. including limited automatic detection.] ----------------------------------------------------------------------------- */ -static int mace_config(struct net_device *dev, struct ifmap *map) -{ - if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - if (map->port <= 2) { - WRITE_ONCE(dev->if_port, map->port); - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - } else - return -EINVAL; - } - return 0; -} /* mace_config */ - -/* ---------------------------------------------------------------------------- -mace_open - Open device driver. ----------------------------------------------------------------------------- */ -static int mace_open(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - mace_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - link->open++; - - MACEBANK(0); - - netif_start_queue(dev); - nmclan_reset(dev); - - return 0; /* Always succeed */ -} /* mace_open */ - -/* ---------------------------------------------------------------------------- -mace_close - Closes device driver. ----------------------------------------------------------------------------- */ -static int mace_close(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - mace_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - - dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); - - /* Mask off all interrupts from the MACE chip. */ - outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR); - - link->open--; - netif_stop_queue(dev); - - return 0; -} /* mace_close */ - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - snprintf(info->bus_info, sizeof(info->bus_info), - "PCMCIA 0x%lx", dev->base_addr); -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, -}; - -/* ---------------------------------------------------------------------------- -mace_start_xmit - This routine begins the packet transmit function. When completed, - it will generate a transmit interrupt. - - According to /usr/src/linux/net/inet/dev.c, if _start_xmit - returns 0, the "packet is now solely the responsibility of the - driver." If _start_xmit returns non-zero, the "transmission - failed, put skb back into a list." ----------------------------------------------------------------------------- */ - -static void mace_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - mace_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - - netdev_notice(dev, "transmit timed out -- "); -#if RESET_ON_TIMEOUT - pr_cont("resetting card\n"); - pcmcia_reset_card(link->socket); -#else /* #if RESET_ON_TIMEOUT */ - pr_cont("NOT resetting card\n"); -#endif /* #if RESET_ON_TIMEOUT */ - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); -} - -static netdev_tx_t mace_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - mace_private *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - - netif_stop_queue(dev); - - pr_debug("%s: mace_start_xmit(length = %ld) called.\n", - dev->name, (long)skb->len); - -#if (!TX_INTERRUPTABLE) - /* Disable MACE TX interrupts. */ - outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT, - ioaddr + AM2150_MACE_BASE + MACE_IMR); - lp->tx_irq_disabled=1; -#endif /* #if (!TX_INTERRUPTABLE) */ - - { - /* This block must not be interrupted by another transmit request! - mace_tx_timeout will take care of timer-based retransmissions from - the upper layers. The interrupt handler is guaranteed never to - service a transmit interrupt while we are in here. - */ - - dev->stats.tx_bytes += skb->len; - lp->tx_free_frames--; - - /* WARNING: Write the _exact_ number of bytes written in the header! */ - /* Put out the word header [must be an outw()] . . . */ - outw(skb->len, ioaddr + AM2150_XMT); - /* . . . and the packet [may be any combination of outw() and outb()] */ - outsw(ioaddr + AM2150_XMT, skb->data, skb->len >> 1); - if (skb->len & 1) { - /* Odd byte transfer */ - outb(skb->data[skb->len-1], ioaddr + AM2150_XMT); - } - -#if MULTI_TX - if (lp->tx_free_frames > 0) - netif_start_queue(dev); -#endif /* #if MULTI_TX */ - } - -#if (!TX_INTERRUPTABLE) - /* Re-enable MACE TX interrupts. */ - lp->tx_irq_disabled=0; - outb(MACE_IMR_DEFAULT, ioaddr + AM2150_MACE_BASE + MACE_IMR); -#endif /* #if (!TX_INTERRUPTABLE) */ - - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} /* mace_start_xmit */ - -/* ---------------------------------------------------------------------------- -mace_interrupt - The interrupt handler. ----------------------------------------------------------------------------- */ -static irqreturn_t mace_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - mace_private *lp = netdev_priv(dev); - unsigned int ioaddr; - int status; - int IntrCnt = MACE_MAX_IR_ITERATIONS; - - if (!dev) { - pr_debug("mace_interrupt(): irq 0x%X for unknown device.\n", - irq); - return IRQ_NONE; - } - - ioaddr = dev->base_addr; - - if (lp->tx_irq_disabled) { - const char *msg; - if (lp->tx_irq_disabled) - msg = "Interrupt with tx_irq_disabled"; - else - msg = "Re-entering the interrupt handler"; - netdev_notice(dev, "%s [isr=%02X, imr=%02X]\n", - msg, - inb(ioaddr + AM2150_MACE_BASE + MACE_IR), - inb(ioaddr + AM2150_MACE_BASE + MACE_IMR)); - /* WARNING: MACE_IR has been read! */ - return IRQ_NONE; - } - - if (!netif_device_present(dev)) { - netdev_dbg(dev, "interrupt from dead card\n"); - return IRQ_NONE; - } - - do { - /* WARNING: MACE_IR is a READ/CLEAR port! */ - status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); - if (!(status & ~MACE_IMR_DEFAULT) && IntrCnt == MACE_MAX_IR_ITERATIONS) - return IRQ_NONE; - - pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); - - if (status & MACE_IR_RCVINT) { - mace_rx(dev, MACE_MAX_RX_ITERATIONS); - } - - if (status & MACE_IR_XMTINT) { - unsigned char fifofc; - unsigned char xmtrc; - unsigned char xmtfs; - - fifofc = inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC); - if ((fifofc & MACE_FIFOFC_XMTFC)==0) { - dev->stats.tx_errors++; - outb(0xFF, ioaddr + AM2150_XMT_SKIP); - } - - /* Transmit Retry Count (XMTRC, reg 4) */ - xmtrc = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC); - if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++; - lp->mace_stats.xmtrc += (xmtrc & MACE_XMTRC_XMTRC); - - if ( - (xmtfs = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) & - MACE_XMTFS_XMTSV /* Transmit Status Valid */ - ) { - lp->mace_stats.xmtsv++; - - if (xmtfs & ~MACE_XMTFS_XMTSV) { - if (xmtfs & MACE_XMTFS_UFLO) { - /* Underflow. Indicates that the Transmit FIFO emptied before - the end of frame was reached. */ - lp->mace_stats.uflo++; - } - if (xmtfs & MACE_XMTFS_LCOL) { - /* Late Collision */ - lp->mace_stats.lcol++; - } - if (xmtfs & MACE_XMTFS_MORE) { - /* MORE than one retry was needed */ - lp->mace_stats.more++; - } - if (xmtfs & MACE_XMTFS_ONE) { - /* Exactly ONE retry occurred */ - lp->mace_stats.one++; - } - if (xmtfs & MACE_XMTFS_DEFER) { - /* Transmission was defered */ - lp->mace_stats.defer++; - } - if (xmtfs & MACE_XMTFS_LCAR) { - /* Loss of carrier */ - lp->mace_stats.lcar++; - } - if (xmtfs & MACE_XMTFS_RTRY) { - /* Retry error: transmit aborted after 16 attempts */ - lp->mace_stats.rtry++; - } - } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */ - - } /* if (xmtfs & MACE_XMTFS_XMTSV) */ - - dev->stats.tx_packets++; - lp->tx_free_frames++; - netif_wake_queue(dev); - } /* if (status & MACE_IR_XMTINT) */ - - if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) { - if (status & MACE_IR_JAB) { - /* Jabber Error. Excessive transmit duration (20-150ms). */ - lp->mace_stats.jab++; - } - if (status & MACE_IR_BABL) { - /* Babble Error. >1518 bytes transmitted. */ - lp->mace_stats.babl++; - } - if (status & MACE_IR_CERR) { - /* Collision Error. CERR indicates the absence of the - Signal Quality Error Test message after a packet - transmission. */ - lp->mace_stats.cerr++; - } - if (status & MACE_IR_RCVCCO) { - /* Receive Collision Count Overflow; */ - lp->mace_stats.rcvcco++; - } - if (status & MACE_IR_RNTPCO) { - /* Runt Packet Count Overflow */ - lp->mace_stats.rntpco++; - } - if (status & MACE_IR_MPCO) { - /* Missed Packet Count Overflow */ - lp->mace_stats.mpco++; - } - } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) */ - - } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt)); - - return IRQ_HANDLED; -} /* mace_interrupt */ - -/* ---------------------------------------------------------------------------- -mace_rx - Receives packets. ----------------------------------------------------------------------------- */ -static int mace_rx(struct net_device *dev, unsigned char RxCnt) -{ - mace_private *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - unsigned char rx_framecnt; - unsigned short rx_status; - - while ( - ((rx_framecnt = inb(ioaddr + AM2150_RCV_FRAME_COUNT)) > 0) && - (rx_framecnt <= 12) && /* rx_framecnt==0xFF if card is extracted. */ - (RxCnt--) - ) { - rx_status = inw(ioaddr + AM2150_RCV); - - pr_debug("%s: in mace_rx(), framecnt 0x%X, rx_status" - " 0x%X.\n", dev->name, rx_framecnt, rx_status); - - if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */ - dev->stats.rx_errors++; - if (rx_status & MACE_RCVFS_OFLO) { - lp->mace_stats.oflo++; - } - if (rx_status & MACE_RCVFS_CLSN) { - lp->mace_stats.clsn++; - } - if (rx_status & MACE_RCVFS_FRAM) { - lp->mace_stats.fram++; - } - if (rx_status & MACE_RCVFS_FCS) { - lp->mace_stats.fcs++; - } - } else { - short pkt_len = (rx_status & ~MACE_RCVFS_RCVSTS) - 4; - /* Auto Strip is off, always subtract 4 */ - struct sk_buff *skb; - - lp->mace_stats.rfs_rntpc += inb(ioaddr + AM2150_RCV); - /* runt packet count */ - lp->mace_stats.rfs_rcvcc += inb(ioaddr + AM2150_RCV); - /* rcv collision count */ - - pr_debug(" receiving packet size 0x%X rx_status" - " 0x%X.\n", pkt_len, rx_status); - - skb = netdev_alloc_skb(dev, pkt_len + 2); - - if (skb) { - skb_reserve(skb, 2); - insw(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1); - if (pkt_len & 1) - *(skb_tail_pointer(skb) - 1) = inb(ioaddr + AM2150_RCV); - skb->protocol = eth_type_trans(skb, dev); - - netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ - - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ - continue; - } else { - pr_debug("%s: couldn't allocate a sk_buff of size" - " %d.\n", dev->name, pkt_len); - dev->stats.rx_dropped++; - } - } - outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ - } /* while */ - - return 0; -} /* mace_rx */ - -/* ---------------------------------------------------------------------------- -pr_linux_stats ----------------------------------------------------------------------------- */ -static void pr_linux_stats(struct net_device_stats *pstats) -{ - pr_debug("pr_linux_stats\n"); - pr_debug(" rx_packets=%-7ld tx_packets=%ld\n", - (long)pstats->rx_packets, (long)pstats->tx_packets); - pr_debug(" rx_errors=%-7ld tx_errors=%ld\n", - (long)pstats->rx_errors, (long)pstats->tx_errors); - pr_debug(" rx_dropped=%-7ld tx_dropped=%ld\n", - (long)pstats->rx_dropped, (long)pstats->tx_dropped); - pr_debug(" multicast=%-7ld collisions=%ld\n", - (long)pstats->multicast, (long)pstats->collisions); - - pr_debug(" rx_length_errors=%-7ld rx_over_errors=%ld\n", - (long)pstats->rx_length_errors, (long)pstats->rx_over_errors); - pr_debug(" rx_crc_errors=%-7ld rx_frame_errors=%ld\n", - (long)pstats->rx_crc_errors, (long)pstats->rx_frame_errors); - pr_debug(" rx_fifo_errors=%-7ld rx_missed_errors=%ld\n", - (long)pstats->rx_fifo_errors, (long)pstats->rx_missed_errors); - - pr_debug(" tx_aborted_errors=%-7ld tx_carrier_errors=%ld\n", - (long)pstats->tx_aborted_errors, (long)pstats->tx_carrier_errors); - pr_debug(" tx_fifo_errors=%-7ld tx_heartbeat_errors=%ld\n", - (long)pstats->tx_fifo_errors, (long)pstats->tx_heartbeat_errors); - pr_debug(" tx_window_errors=%ld\n", - (long)pstats->tx_window_errors); -} /* pr_linux_stats */ - -/* ---------------------------------------------------------------------------- -pr_mace_stats ----------------------------------------------------------------------------- */ -static void pr_mace_stats(mace_statistics *pstats) -{ - pr_debug("pr_mace_stats\n"); - - pr_debug(" xmtsv=%-7d uflo=%d\n", - pstats->xmtsv, pstats->uflo); - pr_debug(" lcol=%-7d more=%d\n", - pstats->lcol, pstats->more); - pr_debug(" one=%-7d defer=%d\n", - pstats->one, pstats->defer); - pr_debug(" lcar=%-7d rtry=%d\n", - pstats->lcar, pstats->rtry); - - /* MACE_XMTRC */ - pr_debug(" exdef=%-7d xmtrc=%d\n", - pstats->exdef, pstats->xmtrc); - - /* RFS1--Receive Status (RCVSTS) */ - pr_debug(" oflo=%-7d clsn=%d\n", - pstats->oflo, pstats->clsn); - pr_debug(" fram=%-7d fcs=%d\n", - pstats->fram, pstats->fcs); - - /* RFS2--Runt Packet Count (RNTPC) */ - /* RFS3--Receive Collision Count (RCVCC) */ - pr_debug(" rfs_rntpc=%-7d rfs_rcvcc=%d\n", - pstats->rfs_rntpc, pstats->rfs_rcvcc); - - /* MACE_IR */ - pr_debug(" jab=%-7d babl=%d\n", - pstats->jab, pstats->babl); - pr_debug(" cerr=%-7d rcvcco=%d\n", - pstats->cerr, pstats->rcvcco); - pr_debug(" rntpco=%-7d mpco=%d\n", - pstats->rntpco, pstats->mpco); - - /* MACE_MPC */ - pr_debug(" mpc=%d\n", pstats->mpc); - - /* MACE_RNTPC */ - pr_debug(" rntpc=%d\n", pstats->rntpc); - - /* MACE_RCVCC */ - pr_debug(" rcvcc=%d\n", pstats->rcvcc); - -} /* pr_mace_stats */ - -/* ---------------------------------------------------------------------------- -update_stats - Update statistics. We change to register window 1, so this - should be run single-threaded if the device is active. This is - expected to be a rare operation, and it's simpler for the rest - of the driver to assume that window 0 is always valid rather - than use a special window-state variable. - - oflo & uflo should _never_ occur since it would mean the Xilinx - was not able to transfer data between the MACE FIFO and the - card's SRAM fast enough. If this happens, something is - seriously wrong with the hardware. ----------------------------------------------------------------------------- */ -static void update_stats(unsigned int ioaddr, struct net_device *dev) -{ - mace_private *lp = netdev_priv(dev); - - lp->mace_stats.rcvcc += mace_read(lp, ioaddr, MACE_RCVCC); - lp->mace_stats.rntpc += mace_read(lp, ioaddr, MACE_RNTPC); - lp->mace_stats.mpc += mace_read(lp, ioaddr, MACE_MPC); - /* At this point, mace_stats is fully updated for this call. - We may now update the netdev stats. */ - - /* The MACE has no equivalent for netdev stats field which are commented - out. */ - - /* dev->stats.multicast; */ - dev->stats.collisions = - lp->mace_stats.rcvcco * 256 + lp->mace_stats.rcvcc; - /* Collision: The MACE may retry sending a packet 15 times - before giving up. The retry count is in XMTRC. - Does each retry constitute a collision? - If so, why doesn't the RCVCC record these collisions? */ - - /* detailed rx_errors: */ - dev->stats.rx_length_errors = - lp->mace_stats.rntpco * 256 + lp->mace_stats.rntpc; - /* dev->stats.rx_over_errors */ - dev->stats.rx_crc_errors = lp->mace_stats.fcs; - dev->stats.rx_frame_errors = lp->mace_stats.fram; - dev->stats.rx_fifo_errors = lp->mace_stats.oflo; - dev->stats.rx_missed_errors = - lp->mace_stats.mpco * 256 + lp->mace_stats.mpc; - - /* detailed tx_errors */ - dev->stats.tx_aborted_errors = lp->mace_stats.rtry; - dev->stats.tx_carrier_errors = lp->mace_stats.lcar; - /* LCAR usually results from bad cabling. */ - dev->stats.tx_fifo_errors = lp->mace_stats.uflo; - dev->stats.tx_heartbeat_errors = lp->mace_stats.cerr; - /* dev->stats.tx_window_errors; */ -} /* update_stats */ - -/* ---------------------------------------------------------------------------- -mace_get_stats - Gathers ethernet statistics from the MACE chip. ----------------------------------------------------------------------------- */ -static struct net_device_stats *mace_get_stats(struct net_device *dev) -{ - mace_private *lp = netdev_priv(dev); - - update_stats(dev->base_addr, dev); - - pr_debug("%s: updating the statistics.\n", dev->name); - pr_linux_stats(&dev->stats); - pr_mace_stats(&lp->mace_stats); - - return &dev->stats; -} /* net_device_stats */ - -/* ---------------------------------------------------------------------------- -updateCRC - Modified from Am79C90 data sheet. ----------------------------------------------------------------------------- */ - -#ifdef BROKEN_MULTICAST - -static void updateCRC(int *CRC, int bit) -{ - static const int poly[]={ - 1,1,1,0, 1,1,0,1, - 1,0,1,1, 1,0,0,0, - 1,0,0,0, 0,0,1,1, - 0,0,1,0, 0,0,0,0 - }; /* CRC polynomial. poly[n] = coefficient of the x**n term of the - CRC generator polynomial. */ - - int j; - - /* shift CRC and control bit (CRC[32]) */ - for (j = 32; j > 0; j--) - CRC[j] = CRC[j-1]; - CRC[0] = 0; - - /* If bit XOR(control bit) = 1, set CRC = CRC XOR polynomial. */ - if (bit ^ CRC[32]) - for (j = 0; j < 32; j++) - CRC[j] ^= poly[j]; -} /* updateCRC */ - -/* ---------------------------------------------------------------------------- -BuildLAF - Build logical address filter. - Modified from Am79C90 data sheet. - -Input - ladrf: logical address filter (contents initialized to 0) - adr: ethernet address ----------------------------------------------------------------------------- */ -static void BuildLAF(int *ladrf, int *adr) -{ - int CRC[33]={1}; /* CRC register, 1 word/bit + extra control bit */ - - int i, byte; /* temporary array indices */ - int hashcode; /* the output object */ - - CRC[32]=0; - - for (byte = 0; byte < 6; byte++) - for (i = 0; i < 8; i++) - updateCRC(CRC, (adr[byte] >> i) & 1); - - hashcode = 0; - for (i = 0; i < 6; i++) - hashcode = (hashcode << 1) + CRC[i]; - - byte = hashcode >> 3; - ladrf[byte] |= (1 << (hashcode & 7)); - -#ifdef PCMCIA_DEBUG - if (0) - printk(KERN_DEBUG " adr =%pM\n", adr); - printk(KERN_DEBUG " hashcode = %d(decimal), ladrf[0:63] =", hashcode); - for (i = 0; i < 8; i++) - pr_cont(" %02X", ladrf[i]); - pr_cont("\n"); -#endif -} /* BuildLAF */ - -/* ---------------------------------------------------------------------------- -restore_multicast_list - Restores the multicast filter for MACE chip to the last - set_multicast_list() call. - -Input - multicast_num_addrs - multicast_ladrf[] ----------------------------------------------------------------------------- */ -static void restore_multicast_list(struct net_device *dev) -{ - mace_private *lp = netdev_priv(dev); - int num_addrs = lp->multicast_num_addrs; - int *ladrf = lp->multicast_ladrf; - unsigned int ioaddr = dev->base_addr; - int i; - - pr_debug("%s: restoring Rx mode to %d addresses.\n", - dev->name, num_addrs); - - if (num_addrs > 0) { - - pr_debug("Attempt to restore multicast list detected.\n"); - - mace_write(lp, ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_LOGADDR); - /* Poll ADDRCHG bit */ - while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG) - ; - /* Set LADRF register */ - for (i = 0; i < MACE_LADRF_LEN; i++) - mace_write(lp, ioaddr, MACE_LADRF, ladrf[i]); - - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_RCVFCSE | MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); - - } else if (num_addrs < 0) { - - /* Promiscuous mode: receive all packets */ - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, - MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV - ); - - } else { - - /* Normal mode */ - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); - - } -} /* restore_multicast_list */ - -/* ---------------------------------------------------------------------------- -set_multicast_list - Set or clear the multicast filter for this adaptor. - -Input - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. -Output - multicast_num_addrs - multicast_ladrf[] ----------------------------------------------------------------------------- */ - -static void set_multicast_list(struct net_device *dev) -{ - mace_private *lp = netdev_priv(dev); - int adr[ETH_ALEN] = {0}; /* Ethernet address */ - struct netdev_hw_addr *ha; - -#ifdef PCMCIA_DEBUG - { - static int old; - if (netdev_mc_count(dev) != old) { - old = netdev_mc_count(dev); - pr_debug("%s: setting Rx mode to %d addresses.\n", - dev->name, old); - } - } -#endif - - /* Set multicast_num_addrs. */ - lp->multicast_num_addrs = netdev_mc_count(dev); - - /* Set multicast_ladrf. */ - if (num_addrs > 0) { - /* Calculate multicast logical address filter */ - memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN); - netdev_for_each_mc_addr(ha, dev) { - memcpy(adr, ha->addr, ETH_ALEN); - BuildLAF(lp->multicast_ladrf, adr); - } - } - - restore_multicast_list(dev); - -} /* set_multicast_list */ - -#endif /* BROKEN_MULTICAST */ - -static void restore_multicast_list(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - mace_private *lp = netdev_priv(dev); - - pr_debug("%s: restoring Rx mode to %d addresses.\n", dev->name, - lp->multicast_num_addrs); - - if (dev->flags & IFF_PROMISC) { - /* Promiscuous mode: receive all packets */ - mace_write(lp,ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, - MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV - ); - } else { - /* Normal mode */ - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); - } -} /* restore_multicast_list */ - -static void set_multicast_list(struct net_device *dev) -{ - mace_private *lp = netdev_priv(dev); - -#ifdef PCMCIA_DEBUG - { - static int old; - if (netdev_mc_count(dev) != old) { - old = netdev_mc_count(dev); - pr_debug("%s: setting Rx mode to %d addresses.\n", - dev->name, old); - } - } -#endif - - lp->multicast_num_addrs = netdev_mc_count(dev); - restore_multicast_list(dev); - -} /* set_multicast_list */ - -static const struct pcmcia_device_id nmclan_ids[] = { - PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941), - PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad673aaf), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, nmclan_ids); - -static struct pcmcia_driver nmclan_cs_driver = { - .owner = THIS_MODULE, - .name = "nmclan_cs", - .probe = nmclan_probe, - .remove = nmclan_detach, - .id_table = nmclan_ids, - .suspend = nmclan_suspend, - .resume = nmclan_resume, -}; -module_pcmcia_driver(nmclan_cs_driver); diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig deleted file mode 100644 index 06a28bce5d27..000000000000 --- a/drivers/net/ethernet/fujitsu/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Fujitsu Network device configuration -# - -config NET_VENDOR_FUJITSU - bool "Fujitsu devices" - default y - depends on PCMCIA - help - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - the questions about Fujitsu cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_FUJITSU - -config PCMCIA_FMVJ18X - tristate "Fujitsu FMV-J18x PCMCIA support" - depends on PCMCIA && HAS_IOPORT - select CRC32 - help - Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible - PCMCIA (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called fmvj18x_cs. If unsure, say N. - -endif # NET_VENDOR_FUJITSU diff --git a/drivers/net/ethernet/fujitsu/Makefile b/drivers/net/ethernet/fujitsu/Makefile deleted file mode 100644 index 74feebbf4572..000000000000 --- a/drivers/net/ethernet/fujitsu/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the Fujitsu network device drivers. -# - -obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c deleted file mode 100644 index 4859493471db..000000000000 --- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c +++ /dev/null @@ -1,1176 +0,0 @@ -/*====================================================================== - fmvj18x_cs.c 2.8 2002/03/23 - - A fmvj18x (and its compatibles) PCMCIA client driver - - Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp - - TDK LAK-CD021 and CONTEC C-NET(PC)C support added by - Nobuhiro Katayama, kata-n@po.iijnet.or.jp - - The PCMCIA client code is based on code written by David Hinds. - Network code is based on the "FMV-18x driver" by Yutaka TAMIYA - but is actually largely Donald Becker's AT1700 driver, which - carries the following attribution: - - Written 1993-94 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - -======================================================================*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DRV_NAME "fmvj18x_cs" -#define DRV_VERSION "2.9" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -/* SRAM configuration */ -/* 0:4KB*2 TX buffer else:8KB*2 TX buffer */ -INT_MODULE_PARM(sram_config, 0); - - -/*====================================================================*/ -/* - PCMCIA event handlers - */ -static int fmvj18x_config(struct pcmcia_device *link); -static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id); -static int fmvj18x_setup_mfc(struct pcmcia_device *link); -static void fmvj18x_release(struct pcmcia_device *link); -static void fmvj18x_detach(struct pcmcia_device *p_dev); - -/* - LAN controller(MBH86960A) specific routines - */ -static int fjn_config(struct net_device *dev, struct ifmap *map); -static int fjn_open(struct net_device *dev); -static int fjn_close(struct net_device *dev); -static netdev_tx_t fjn_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t fjn_interrupt(int irq, void *dev_id); -static void fjn_rx(struct net_device *dev); -static void fjn_reset(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue); -static const struct ethtool_ops netdev_ethtool_ops; - -/* - card type - */ -enum cardtype { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN, - XXX10304, NEC, KME -}; - -/* - driver specific data structure -*/ -struct local_info { - struct pcmcia_device *p_dev; - long open_time; - uint tx_started:1; - uint tx_queue; - u_short tx_queue_len; - enum cardtype cardtype; - u_short sent; - u_char __iomem *base; -}; - -#define MC_FILTERBREAK 64 - -/*====================================================================*/ -/* - ioport offset from the base address - */ -#define TX_STATUS 0 /* transmit status register */ -#define RX_STATUS 1 /* receive status register */ -#define TX_INTR 2 /* transmit interrupt mask register */ -#define RX_INTR 3 /* receive interrupt mask register */ -#define TX_MODE 4 /* transmit mode register */ -#define RX_MODE 5 /* receive mode register */ -#define CONFIG_0 6 /* configuration register 0 */ -#define CONFIG_1 7 /* configuration register 1 */ - -#define NODE_ID 8 /* node ID register (bank 0) */ -#define MAR_ADR 8 /* multicast address registers (bank 1) */ - -#define DATAPORT 8 /* buffer mem port registers (bank 2) */ -#define TX_START 10 /* transmit start register */ -#define COL_CTRL 11 /* 16 collision control register */ -#define BMPR12 12 /* reserved */ -#define BMPR13 13 /* reserved */ -#define RX_SKIP 14 /* skip received packet register */ - -#define LAN_CTRL 16 /* LAN card control register */ - -#define MAC_ID 0x1a /* hardware address */ -#define UNGERMANN_MAC_ID 0x18 /* UNGERMANN-BASS hardware address */ - -/* - control bits - */ -#define ENA_TMT_OK 0x80 -#define ENA_TMT_REC 0x20 -#define ENA_COL 0x04 -#define ENA_16_COL 0x02 -#define ENA_TBUS_ERR 0x01 - -#define ENA_PKT_RDY 0x80 -#define ENA_BUS_ERR 0x40 -#define ENA_LEN_ERR 0x08 -#define ENA_ALG_ERR 0x04 -#define ENA_CRC_ERR 0x02 -#define ENA_OVR_FLO 0x01 - -/* flags */ -#define F_TMT_RDY 0x80 /* can accept new packet */ -#define F_NET_BSY 0x40 /* carrier is detected */ -#define F_TMT_OK 0x20 /* send packet successfully */ -#define F_SRT_PKT 0x10 /* short packet error */ -#define F_COL_ERR 0x04 /* collision error */ -#define F_16_COL 0x02 /* 16 collision error */ -#define F_TBUS_ERR 0x01 /* bus read error */ - -#define F_PKT_RDY 0x80 /* packet(s) in buffer */ -#define F_BUS_ERR 0x40 /* bus read error */ -#define F_LEN_ERR 0x08 /* short packet */ -#define F_ALG_ERR 0x04 /* frame error */ -#define F_CRC_ERR 0x02 /* CRC error */ -#define F_OVR_FLO 0x01 /* overflow error */ - -#define F_BUF_EMP 0x40 /* receive buffer is empty */ - -#define F_SKP_PKT 0x05 /* drop packet in buffer */ - -/* default bitmaps */ -#define D_TX_INTR ( ENA_TMT_OK ) -#define D_RX_INTR ( ENA_PKT_RDY | ENA_LEN_ERR \ - | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO ) -#define TX_STAT_M ( F_TMT_RDY ) -#define RX_STAT_M ( F_PKT_RDY | F_LEN_ERR \ - | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO ) - -/* commands */ -#define D_TX_MODE 0x06 /* no tests, detect carrier */ -#define ID_MATCHED 0x02 /* (RX_MODE) */ -#define RECV_ALL 0x03 /* (RX_MODE) */ -#define CONFIG0_DFL 0x5a /* 16bit bus, 4K x 2 Tx queues */ -#define CONFIG0_DFL_1 0x5e /* 16bit bus, 8K x 2 Tx queues */ -#define CONFIG0_RST 0xda /* Data Link Controller off (CONFIG_0) */ -#define CONFIG0_RST_1 0xde /* Data Link Controller off (CONFIG_0) */ -#define BANK_0 0xa0 /* bank 0 (CONFIG_1) */ -#define BANK_1 0xa4 /* bank 1 (CONFIG_1) */ -#define BANK_2 0xa8 /* bank 2 (CONFIG_1) */ -#define CHIP_OFF 0x80 /* contrl chip power off (CONFIG_1) */ -#define DO_TX 0x80 /* do transmit packet */ -#define SEND_PKT 0x81 /* send a packet */ -#define AUTO_MODE 0x07 /* Auto skip packet on 16 col detected */ -#define MANU_MODE 0x03 /* Stop and skip packet on 16 col */ -#define TDK_AUTO_MODE 0x47 /* Auto skip packet on 16 col detected */ -#define TDK_MANU_MODE 0x43 /* Stop and skip packet on 16 col */ -#define INTR_OFF 0x0d /* LAN controller ignores interrupts */ -#define INTR_ON 0x1d /* LAN controller will catch interrupts */ - -#define TX_TIMEOUT ((400*HZ)/1000) - -#define BANK_0U 0x20 /* bank 0 (CONFIG_1) */ -#define BANK_1U 0x24 /* bank 1 (CONFIG_1) */ -#define BANK_2U 0x28 /* bank 2 (CONFIG_1) */ - -static const struct net_device_ops fjn_netdev_ops = { - .ndo_open = fjn_open, - .ndo_stop = fjn_close, - .ndo_start_xmit = fjn_start_xmit, - .ndo_tx_timeout = fjn_tx_timeout, - .ndo_set_config = fjn_config, - .ndo_set_rx_mode = set_rx_mode, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int fmvj18x_probe(struct pcmcia_device *link) -{ - struct local_info *lp; - struct net_device *dev; - - dev_dbg(&link->dev, "fmvj18x_attach()\n"); - - /* Make up a FMVJ18x specific data structure */ - dev = alloc_etherdev(sizeof(struct local_info)); - if (!dev) - return -ENOMEM; - lp = netdev_priv(dev); - link->priv = dev; - lp->p_dev = link; - lp->base = NULL; - - /* The io structure describes IO port mapping */ - link->resource[0]->end = 32; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - /* General socket configuration */ - link->config_flags |= CONF_ENABLE_IRQ; - - dev->netdev_ops = &fjn_netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - dev->ethtool_ops = &netdev_ethtool_ops; - - return fmvj18x_config(link); -} /* fmvj18x_attach */ - -/*====================================================================*/ - -static void fmvj18x_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - dev_dbg(&link->dev, "fmvj18x_detach\n"); - - unregister_netdev(dev); - - fmvj18x_release(link); - - free_netdev(dev); -} /* fmvj18x_detach */ - -/*====================================================================*/ - -static int mfc_try_io_port(struct pcmcia_device *link) -{ - int i, ret; - static const unsigned int serial_base[5] = - { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - - for (i = 0; i < 5; i++) { - link->resource[1]->start = serial_base[i]; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - if (link->resource[1]->start == 0) { - link->resource[1]->end = 0; - pr_notice("out of resource for serial\n"); - } - ret = pcmcia_request_io(link); - if (ret == 0) - return ret; - } - return ret; -} - -static int ungermann_try_io_port(struct pcmcia_device *link) -{ - int ret; - unsigned int ioaddr; - /* - Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360 - 0x380,0x3c0 only for ioport. - */ - for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) { - link->resource[0]->start = ioaddr; - ret = pcmcia_request_io(link); - if (ret == 0) { - /* calculate ConfigIndex value */ - link->config_index = - ((link->resource[0]->start & 0x0f0) >> 3) | 0x22; - return ret; - } - } - return ret; /* RequestIO failed */ -} - -static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data) -{ - return 0; /* strange, but that's what the code did already before... */ -} - -static int fmvj18x_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct local_info *lp = netdev_priv(dev); - int i, ret; - unsigned int ioaddr; - enum cardtype cardtype; - char *card_name = "unknown"; - u8 *buf; - size_t len; - u_char buggybuf[32]; - u8 addr[ETH_ALEN]; - - dev_dbg(&link->dev, "fmvj18x_config\n"); - - link->io_lines = 5; - - len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); - kfree(buf); - - if (len) { - /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ - ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL); - if (ret != 0) - goto failed; - - switch (link->manf_id) { - case MANFID_TDK: - cardtype = TDK; - if (link->card_id == PRODID_TDK_GN3410 || - link->card_id == PRODID_TDK_NP9610 || - link->card_id == PRODID_TDK_MN3200) { - /* MultiFunction Card */ - link->config_base = 0x800; - link->config_index = 0x47; - link->resource[1]->end = 8; - } - break; - case MANFID_NEC: - cardtype = NEC; /* MultiFunction Card */ - link->config_base = 0x800; - link->config_index = 0x47; - link->resource[1]->end = 8; - break; - case MANFID_KME: - cardtype = KME; /* MultiFunction Card */ - link->config_base = 0x800; - link->config_index = 0x47; - link->resource[1]->end = 8; - break; - case MANFID_CONTEC: - cardtype = CONTEC; - break; - case MANFID_FUJITSU: - if (link->config_base == 0x0fe0) - cardtype = MBH10302; - else if (link->card_id == PRODID_FUJITSU_MBH10302) - /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302), - but these are MBH10304 based card. */ - cardtype = MBH10304; - else if (link->card_id == PRODID_FUJITSU_MBH10304) - cardtype = MBH10304; - else - cardtype = LA501; - break; - default: - cardtype = MBH10304; - } - } else { - /* old type card */ - switch (link->manf_id) { - case MANFID_FUJITSU: - if (link->card_id == PRODID_FUJITSU_MBH10304) { - cardtype = XXX10304; /* MBH10304 with buggy CIS */ - link->config_index = 0x20; - } else { - cardtype = MBH10302; /* NextCom NC5310, etc. */ - link->config_index = 1; - } - break; - case MANFID_UNGERMANN: - cardtype = UNGERMANN; - break; - default: - cardtype = MBH10302; - link->config_index = 1; - } - } - - if (link->resource[1]->end != 0) { - ret = mfc_try_io_port(link); - if (ret != 0) goto failed; - } else if (cardtype == UNGERMANN) { - ret = ungermann_try_io_port(link); - if (ret != 0) goto failed; - } else { - ret = pcmcia_request_io(link); - if (ret) - goto failed; - } - ret = pcmcia_request_irq(link, fjn_interrupt); - if (ret) - goto failed; - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - - if (resource_size(link->resource[1]) != 0) { - ret = fmvj18x_setup_mfc(link); - if (ret != 0) goto failed; - } - - ioaddr = dev->base_addr; - - /* Reset controller */ - if (sram_config == 0) - outb(CONFIG0_RST, ioaddr + CONFIG_0); - else - outb(CONFIG0_RST_1, ioaddr + CONFIG_0); - - /* Power On chip and select bank 0 */ - if (cardtype == MBH10302) - outb(BANK_0, ioaddr + CONFIG_1); - else - outb(BANK_0U, ioaddr + CONFIG_1); - - /* Set hardware address */ - switch (cardtype) { - case MBH10304: - case TDK: - case LA501: - case CONTEC: - case NEC: - case KME: - if (cardtype == MBH10304) { - card_name = "FMV-J182"; - - len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); - if (len < 11) { - kfree(buf); - goto failed; - } - /* Read MACID from CIS */ - eth_hw_addr_set(dev, &buf[5]); - kfree(buf); - } else { - if (pcmcia_get_mac_from_cis(link, dev)) - goto failed; - if( cardtype == TDK ) { - card_name = "TDK LAK-CD021"; - } else if( cardtype == LA501 ) { - card_name = "LA501"; - } else if( cardtype == NEC ) { - card_name = "PK-UG-J001"; - } else if( cardtype == KME ) { - card_name = "Panasonic"; - } else { - card_name = "C-NET(PC)C"; - } - } - break; - case UNGERMANN: - /* Read MACID from register */ - for (i = 0; i < 6; i++) - addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i); - eth_hw_addr_set(dev, addr); - card_name = "Access/CARD"; - break; - case XXX10304: - /* Read MACID from Buggy CIS */ - if (fmvj18x_get_hwinfo(link, buggybuf) == -1) { - pr_notice("unable to read hardware net address\n"); - goto failed; - } - eth_hw_addr_set(dev, buggybuf); - card_name = "FMV-J182"; - break; - case MBH10302: - default: - /* Read MACID from register */ - for (i = 0; i < 6; i++) - addr[i] = inb(ioaddr + MAC_ID + i); - eth_hw_addr_set(dev, addr); - card_name = "FMV-J181"; - break; - } - - lp->cardtype = cardtype; - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) != 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - /* print current configuration */ - netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n", - card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", - dev->base_addr, dev->irq, dev->dev_addr); - - return 0; - -failed: - fmvj18x_release(link); - return -ENODEV; -} /* fmvj18x_config */ -/*====================================================================*/ - -static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) -{ - u_char __iomem *base; - int i, j; - - /* Allocate a small memory window */ - link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - link->resource[2]->start = 0; link->resource[2]->end = 0; - i = pcmcia_request_window(link, link->resource[2], 0); - if (i != 0) - return -1; - - base = ioremap(link->resource[2]->start, resource_size(link->resource[2])); - if (!base) { - pcmcia_release_window(link, link->resource[2]); - return -1; - } - - pcmcia_map_mem_page(link, link->resource[2], 0); - - /* - * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format - * 22 0d xx xx xx 04 06 yy yy yy yy yy yy ff - * 'xx' is garbage. - * 'yy' is MAC address. - */ - for (i = 0; i < 0x200; i++) { - if (readb(base+i*2) == 0x22) { - if (readb(base+(i-1)*2) == 0xff && - readb(base+(i+5)*2) == 0x04 && - readb(base+(i+6)*2) == 0x06 && - readb(base+(i+13)*2) == 0xff) - break; - } - } - - if (i != 0x200) { - for (j = 0 ; j < 6; j++,i++) { - node_id[j] = readb(base+(i+7)*2); - } - } - - iounmap(base); - j = pcmcia_release_window(link, link->resource[2]); - return (i != 0x200) ? 0 : -1; - -} /* fmvj18x_get_hwinfo */ -/*====================================================================*/ - -static int fmvj18x_setup_mfc(struct pcmcia_device *link) -{ - int i; - struct net_device *dev = link->priv; - unsigned int ioaddr; - struct local_info *lp = netdev_priv(dev); - - /* Allocate a small memory window */ - link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - link->resource[3]->start = link->resource[3]->end = 0; - i = pcmcia_request_window(link, link->resource[3], 0); - if (i != 0) - return -1; - - lp->base = ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - if (lp->base == NULL) { - netdev_notice(dev, "ioremap failed\n"); - return -1; - } - - i = pcmcia_map_mem_page(link, link->resource[3], 0); - if (i != 0) { - iounmap(lp->base); - lp->base = NULL; - return -1; - } - - ioaddr = dev->base_addr; - writeb(0x47, lp->base+0x800); /* Config Option Register of LAN */ - writeb(0x0, lp->base+0x802); /* Config and Status Register */ - - writeb(ioaddr & 0xff, lp->base+0x80a); /* I/O Base(Low) of LAN */ - writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */ - - writeb(0x45, lp->base+0x820); /* Config Option Register of Modem */ - writeb(0x8, lp->base+0x822); /* Config and Status Register */ - - return 0; - -} -/*====================================================================*/ - -static void fmvj18x_release(struct pcmcia_device *link) -{ - - struct net_device *dev = link->priv; - struct local_info *lp = netdev_priv(dev); - u_char __iomem *tmp; - - dev_dbg(&link->dev, "fmvj18x_release\n"); - - if (lp->base != NULL) { - tmp = lp->base; - lp->base = NULL; /* set NULL before iounmap */ - iounmap(tmp); - } - - pcmcia_disable_device(link); - -} - -static int fmvj18x_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int fmvj18x_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - fjn_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -/*====================================================================*/ - -static const struct pcmcia_device_id fmvj18x_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004), - PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59), - PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922), - PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922), - PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db), - PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e), - PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2), - PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4), - PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0 ", 0x8cef4d3a, 0x075fc7b6), - PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0 ", 0x8cef4d3a, 0xbccf43e6), - PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666), - PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70), - PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a), - PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2), - PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304 ES", 0x2599f454), - PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da), - PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids); - -static struct pcmcia_driver fmvj18x_cs_driver = { - .owner = THIS_MODULE, - .name = "fmvj18x_cs", - .probe = fmvj18x_probe, - .remove = fmvj18x_detach, - .id_table = fmvj18x_ids, - .suspend = fmvj18x_suspend, - .resume = fmvj18x_resume, -}; -module_pcmcia_driver(fmvj18x_cs_driver); - -/*====================================================================*/ - -static irqreturn_t fjn_interrupt(int dummy, void *dev_id) -{ - struct net_device *dev = dev_id; - struct local_info *lp = netdev_priv(dev); - unsigned int ioaddr; - unsigned short tx_stat, rx_stat; - - ioaddr = dev->base_addr; - - /* avoid multiple interrupts */ - outw(0x0000, ioaddr + TX_INTR); - - /* wait for a while */ - udelay(1); - - /* get status */ - tx_stat = inb(ioaddr + TX_STATUS); - rx_stat = inb(ioaddr + RX_STATUS); - - /* clear status */ - outb(tx_stat, ioaddr + TX_STATUS); - outb(rx_stat, ioaddr + RX_STATUS); - - pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat); - pr_debug(" tx_status %02x.\n", tx_stat); - - if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { - /* there is packet(s) in rx buffer */ - fjn_rx(dev); - } - if (tx_stat & F_TMT_RDY) { - dev->stats.tx_packets += lp->sent ; - lp->sent = 0 ; - if (lp->tx_queue) { - outb(DO_TX | lp->tx_queue, ioaddr + TX_START); - lp->sent = lp->tx_queue ; - lp->tx_queue = 0; - lp->tx_queue_len = 0; - netif_trans_update(dev); - } else { - lp->tx_started = 0; - } - netif_wake_queue(dev); - } - pr_debug("%s: exiting interrupt,\n", dev->name); - pr_debug(" tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat); - - outb(D_TX_INTR, ioaddr + TX_INTR); - outb(D_RX_INTR, ioaddr + RX_INTR); - - if (lp->base != NULL) { - /* Ack interrupt for multifunction card */ - writeb(0x01, lp->base+0x802); - writeb(0x09, lp->base+0x822); - } - - return IRQ_HANDLED; - -} /* fjn_interrupt */ - -/*====================================================================*/ - -static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct local_info *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - - netdev_notice(dev, "transmit timed out with status %04x, %s?\n", - htons(inw(ioaddr + TX_STATUS)), - inb(ioaddr + TX_STATUS) & F_TMT_RDY - ? "IRQ conflict" : "network cable problem"); - netdev_notice(dev, "timeout registers: %04x %04x %04x " - "%04x %04x %04x %04x %04x.\n", - htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)), - htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)), - htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)), - htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14))); - dev->stats.tx_errors++; - /* ToDo: We should try to restart the adaptor... */ - local_irq_disable(); - fjn_reset(dev); - - lp->tx_started = 0; - lp->tx_queue = 0; - lp->tx_queue_len = 0; - lp->sent = 0; - lp->open_time = jiffies; - local_irq_enable(); - netif_wake_queue(dev); -} - -static netdev_tx_t fjn_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct local_info *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - short length = skb->len; - - if (length < ETH_ZLEN) - { - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - length = ETH_ZLEN; - } - - netif_stop_queue(dev); - - { - unsigned char *buf = skb->data; - - if (length > ETH_FRAME_LEN) { - netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n", - length); - return NETDEV_TX_BUSY; - } - - netdev_dbg(dev, "Transmitting a packet of length %lu\n", - (unsigned long)skb->len); - dev->stats.tx_bytes += skb->len; - - /* Disable both interrupts. */ - outw(0x0000, ioaddr + TX_INTR); - - /* wait for a while */ - udelay(1); - - outw(length, ioaddr + DATAPORT); - outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); - - lp->tx_queue++; - lp->tx_queue_len += ((length+3) & ~1); - - if (lp->tx_started == 0) { - /* If the Tx is idle, always trigger a transmit. */ - outb(DO_TX | lp->tx_queue, ioaddr + TX_START); - lp->sent = lp->tx_queue ; - lp->tx_queue = 0; - lp->tx_queue_len = 0; - lp->tx_started = 1; - netif_start_queue(dev); - } else { - if( sram_config == 0 ) { - if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) ) - /* Yes, there is room for one more packet. */ - netif_start_queue(dev); - } else { - if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && - lp->tx_queue < 127 ) - /* Yes, there is room for one more packet. */ - netif_start_queue(dev); - } - } - - /* Re-enable interrupts */ - outb(D_TX_INTR, ioaddr + TX_INTR); - outb(D_RX_INTR, ioaddr + RX_INTR); - } - dev_kfree_skb (skb); - - return NETDEV_TX_OK; -} /* fjn_start_xmit */ - -/*====================================================================*/ - -static void fjn_reset(struct net_device *dev) -{ - struct local_info *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - int i; - - netdev_dbg(dev, "fjn_reset() called\n"); - - /* Reset controller */ - if( sram_config == 0 ) - outb(CONFIG0_RST, ioaddr + CONFIG_0); - else - outb(CONFIG0_RST_1, ioaddr + CONFIG_0); - - /* Power On chip and select bank 0 */ - if (lp->cardtype == MBH10302) - outb(BANK_0, ioaddr + CONFIG_1); - else - outb(BANK_0U, ioaddr + CONFIG_1); - - /* Set Tx modes */ - outb(D_TX_MODE, ioaddr + TX_MODE); - /* set Rx modes */ - outb(ID_MATCHED, ioaddr + RX_MODE); - - /* Set hardware address */ - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + NODE_ID + i); - - /* (re)initialize the multicast table */ - set_rx_mode(dev); - - /* Switch to bank 2 (runtime mode) */ - if (lp->cardtype == MBH10302) - outb(BANK_2, ioaddr + CONFIG_1); - else - outb(BANK_2U, ioaddr + CONFIG_1); - - /* set 16col ctrl bits */ - if( lp->cardtype == TDK || lp->cardtype == CONTEC) - outb(TDK_AUTO_MODE, ioaddr + COL_CTRL); - else - outb(AUTO_MODE, ioaddr + COL_CTRL); - - /* clear Reserved Regs */ - outb(0x00, ioaddr + BMPR12); - outb(0x00, ioaddr + BMPR13); - - /* reset Skip packet reg. */ - outb(0x01, ioaddr + RX_SKIP); - - /* Enable Tx and Rx */ - if( sram_config == 0 ) - outb(CONFIG0_DFL, ioaddr + CONFIG_0); - else - outb(CONFIG0_DFL_1, ioaddr + CONFIG_0); - - /* Init receive pointer ? */ - inw(ioaddr + DATAPORT); - inw(ioaddr + DATAPORT); - - /* Clear all status */ - outb(0xff, ioaddr + TX_STATUS); - outb(0xff, ioaddr + RX_STATUS); - - if (lp->cardtype == MBH10302) - outb(INTR_OFF, ioaddr + LAN_CTRL); - - /* Turn on Rx interrupts */ - outb(D_TX_INTR, ioaddr + TX_INTR); - outb(D_RX_INTR, ioaddr + RX_INTR); - - /* Turn on interrupts from LAN card controller */ - if (lp->cardtype == MBH10302) - outb(INTR_ON, ioaddr + LAN_CTRL); -} /* fjn_reset */ - -/*====================================================================*/ - -static void fjn_rx(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - int boguscount = 10; /* 5 -> 10: by agy 19940922 */ - - pr_debug("%s: in rx_packet(), rx_status %02x.\n", - dev->name, inb(ioaddr + RX_STATUS)); - - while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { - u_short status = inw(ioaddr + DATAPORT); - - netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n", - inb(ioaddr + RX_MODE), status); -#ifndef final_version - if (status == 0) { - outb(F_SKP_PKT, ioaddr + RX_SKIP); - break; - } -#endif - if ((status & 0xF0) != 0x20) { /* There was an error. */ - dev->stats.rx_errors++; - if (status & F_LEN_ERR) dev->stats.rx_length_errors++; - if (status & F_ALG_ERR) dev->stats.rx_frame_errors++; - if (status & F_CRC_ERR) dev->stats.rx_crc_errors++; - if (status & F_OVR_FLO) dev->stats.rx_over_errors++; - } else { - u_short pkt_len = inw(ioaddr + DATAPORT); - /* Malloc up new buffer. */ - struct sk_buff *skb; - - if (pkt_len > 1550) { - netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n", - pkt_len); - outb(F_SKP_PKT, ioaddr + RX_SKIP); - dev->stats.rx_errors++; - break; - } - skb = netdev_alloc_skb(dev, pkt_len + 2); - if (skb == NULL) { - outb(F_SKP_PKT, ioaddr + RX_SKIP); - dev->stats.rx_dropped++; - break; - } - - skb_reserve(skb, 2); - insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), - (pkt_len + 1) >> 1); - skb->protocol = eth_type_trans(skb, dev); - - { - int i; - pr_debug("%s: Rxed packet of length %d: ", - dev->name, pkt_len); - for (i = 0; i < 14; i++) - pr_debug(" %02x", skb->data[i]); - pr_debug(".\n"); - } - - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - if (--boguscount <= 0) - break; - } - - /* If any worth-while packets have been received, dev_rint() - has done a netif_wake_queue() for us and will work on them - when we get to the bottom-half routine. */ -/* - if (lp->cardtype != TDK) { - int i; - for (i = 0; i < 20; i++) { - if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP) - break; - (void)inw(ioaddr + DATAPORT); /+ dummy status read +/ - outb(F_SKP_PKT, ioaddr + RX_SKIP); - } - - if (i > 0) - pr_debug("%s: Exint Rx packet with mode %02x after " - "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); - } -*/ -} /* fjn_rx */ - -/*====================================================================*/ - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->version, DRV_VERSION, sizeof(info->version)); - snprintf(info->bus_info, sizeof(info->bus_info), - "PCMCIA 0x%lx", dev->base_addr); -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, -}; - -static int fjn_config(struct net_device *dev, struct ifmap *map){ - return 0; -} - -static int fjn_open(struct net_device *dev) -{ - struct local_info *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - - pr_debug("fjn_open('%s').\n", dev->name); - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - link->open++; - - fjn_reset(dev); - - lp->tx_started = 0; - lp->tx_queue = 0; - lp->tx_queue_len = 0; - lp->open_time = jiffies; - netif_start_queue(dev); - - return 0; -} /* fjn_open */ - -/*====================================================================*/ - -static int fjn_close(struct net_device *dev) -{ - struct local_info *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - unsigned int ioaddr = dev->base_addr; - - pr_debug("fjn_close('%s').\n", dev->name); - - lp->open_time = 0; - netif_stop_queue(dev); - - /* Set configuration register 0 to disable Tx and Rx. */ - if( sram_config == 0 ) - outb(CONFIG0_RST ,ioaddr + CONFIG_0); - else - outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0); - - /* Update the statistics -- ToDo. */ - - /* Power-down the chip. Green, green, green! */ - outb(CHIP_OFF ,ioaddr + CONFIG_1); - - /* Set the ethernet adaptor disable IRQ */ - if (lp->cardtype == MBH10302) - outb(INTR_OFF, ioaddr + LAN_CTRL); - - link->open--; - - return 0; -} /* fjn_close */ - -/*====================================================================*/ - -/* - Set the multicast/promiscuous mode for this adaptor. -*/ - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - u_char mc_filter[8]; /* Multicast hash filter */ - u_long flags; - int i; - - int saved_bank; - int saved_config_0 = inb(ioaddr + CONFIG_0); - - local_irq_save(flags); - - /* Disable Tx and Rx */ - if (sram_config == 0) - outb(CONFIG0_RST, ioaddr + CONFIG_0); - else - outb(CONFIG0_RST_1, ioaddr + CONFIG_0); - - if (dev->flags & IFF_PROMISC) { - memset(mc_filter, 0xff, sizeof(mc_filter)); - outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ - } else if (netdev_mc_count(dev) > MC_FILTERBREAK || - (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter perfectly -- accept all multicasts. */ - memset(mc_filter, 0xff, sizeof(mc_filter)); - outb(2, ioaddr + RX_MODE); /* Use normal mode. */ - } else if (netdev_mc_empty(dev)) { - memset(mc_filter, 0x00, sizeof(mc_filter)); - outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */ - } else { - struct netdev_hw_addr *ha; - - memset(mc_filter, 0, sizeof(mc_filter)); - netdev_for_each_mc_addr(ha, dev) { - unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26; - mc_filter[bit >> 3] |= (1 << (bit & 7)); - } - outb(2, ioaddr + RX_MODE); /* Use normal mode. */ - } - - /* Switch to bank 1 and set the multicast table. */ - saved_bank = inb(ioaddr + CONFIG_1); - outb(0xe4, ioaddr + CONFIG_1); - - for (i = 0; i < 8; i++) - outb(mc_filter[i], ioaddr + MAR_ADR + i); - outb(saved_bank, ioaddr + CONFIG_1); - - outb(saved_config_0, ioaddr + CONFIG_0); - - local_irq_restore(flags); -} diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig deleted file mode 100644 index de91331dcb7d..000000000000 --- a/drivers/net/ethernet/packetengines/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Packet Engines device configuration -# - -config NET_VENDOR_PACKET_ENGINES - bool "Packet Engines devices" - default y - depends on PCI - help - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Packet Engines devices. If you say Y, you will - be asked for your specific card in the following questions. - -if NET_VENDOR_PACKET_ENGINES - -config HAMACHI - tristate "Packet Engines Hamachi GNIC-II support" - depends on PCI - select MII - help - If you have a Gigabit Ethernet card of this type, say Y here. - - To compile this driver as a module, choose M here. The module will be - called hamachi. - -config YELLOWFIN - tristate "Packet Engines Yellowfin Gigabit-NIC support" - depends on PCI - select CRC32 - help - Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet - adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is - used by the Beowulf Linux cluster project. See - for more - information about this driver in particular and Beowulf in general. - - To compile this driver as a module, choose M here: the module - will be called yellowfin. This is recommended. - -endif # NET_VENDOR_PACKET_ENGINES diff --git a/drivers/net/ethernet/packetengines/Makefile b/drivers/net/ethernet/packetengines/Makefile deleted file mode 100644 index cf054b796d11..000000000000 --- a/drivers/net/ethernet/packetengines/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the Packet Engines network device drivers. -# - -obj-$(CONFIG_HAMACHI) += hamachi.o -obj-$(CONFIG_YELLOWFIN) += yellowfin.o diff --git a/drivers/net/ethernet/packetengines/hamachi.c b/drivers/net/ethernet/packetengines/hamachi.c deleted file mode 100644 index b0de7e9f12a5..000000000000 --- a/drivers/net/ethernet/packetengines/hamachi.c +++ /dev/null @@ -1,1967 +0,0 @@ -/* hamachi.c: A Packet Engines GNIC-II Gigabit Ethernet driver for Linux. */ -/* - Written 1998-2000 by Donald Becker. - Updates 2000 by Keith Underwood. - - 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 or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. This file is not - a complete program and may only be used when the entire operating - system is licensed under the GPL. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - This driver is for the Packet Engines GNIC-II PCI Gigabit Ethernet - adapter. - - Support and updates available at - http://www.scyld.com/network/hamachi.html - [link no longer provides useful info -jgarzik] - or - http://www.parl.clemson.edu/~keithu/hamachi.html - -*/ - -#define DRV_NAME "hamachi" -#define DRV_VERSION "2.1" -#define DRV_RELDATE "Sept 11, 2006" - - -/* A few user-configurable values. */ - -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -#define final_version -#define hamachi_debug debug -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 40; -static int mtu; -/* Default values selected by testing on a dual processor PIII-450 */ -/* These six interrupt control parameters may be set directly when loading the - * module, or through the rx_params and tx_params variables - */ -static int max_rx_latency = 0x11; -static int max_rx_gap = 0x05; -static int min_rx_pkt = 0x18; -static int max_tx_latency = 0x00; -static int max_tx_gap = 0x00; -static int min_tx_pkt = 0x30; - -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - -Setting to > 1518 causes all frames to be copied - -Setting to 0 disables copies -*/ -static int rx_copybreak; - -/* An override for the hardware detection of bus width. - Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit. - Add 2 to disable parity detection. -*/ -static int force32; - - -/* Used to pass the media type, etc. - These exist for driver interoperability. - No media types are currently defined. - - The lower 4 bits are reserved for the media type. - - The next three bits may be set to one of the following: - 0x00000000 : Autodetect PCI bus - 0x00000010 : Force 32 bit PCI bus - 0x00000020 : Disable parity detection - 0x00000040 : Force 64 bit PCI bus - Default is autodetect - - The next bit can be used to force half-duplex. This is a bad - idea since no known implementations implement half-duplex, and, - in general, half-duplex for gigabit ethernet is a bad idea. - 0x00000080 : Force half-duplex - Default is full-duplex. - - In the original driver, the ninth bit could be used to force - full-duplex. Maintain that for compatibility - 0x00000200 : Force full-duplex -*/ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -/* The Hamachi chipset supports 3 parameters each for Rx and Tx - * interruput management. Parameters will be loaded as specified into - * the TxIntControl and RxIntControl registers. - * - * The registers are arranged as follows: - * 23 - 16 15 - 8 7 - 0 - * _________________________________ - * | min_pkt | max_gap | max_latency | - * --------------------------------- - * min_pkt : The minimum number of packets processed between - * interrupts. - * max_gap : The maximum inter-packet gap in units of 8.192 us - * max_latency : The absolute time between interrupts in units of 8.192 us - * - */ -static int rx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Operational parameters that are set at compile time. */ - -/* Keep the ring sizes a power of two for compile efficiency. - The compiler will convert '%'<2^N> into a bit mask. - Making the Tx ring too large decreases the effectiveness of channel - bonding and packet priority. - There are no ill effects from too-large receive rings, except for - excessive memory usage */ -/* Empirically it appears that the Tx ring needs to be a little bigger - for these Gbit adapters or you get into an overrun condition really - easily. Also, things appear to work a bit better in back-to-back - configurations if the Rx ring is 8 times the size of the Tx ring -*/ -#define TX_RING_SIZE 64 -#define RX_RING_SIZE 512 -#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct hamachi_desc) -#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct hamachi_desc) - -/* - * Enable netdev_ioctl. Added interrupt coalescing parameter adjustment. - * 2/19/99 Pete Wyckoff - */ - -/* play with 64-bit addrlen; seems to be a teensy bit slower --pw */ -/* #define ADDRLEN 64 */ - -/* - * RX_CHECKSUM turns on card-generated receive checksum generation for - * TCP and UDP packets. Otherwise the upper layers do the calculation. - * 3/10/1999 Pete Wyckoff - */ -#define RX_CHECKSUM - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (5*HZ) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include - -static const char version[] = -KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" -" Some modifications by Eric kasten \n" -" Further modifications by Keith Underwood \n"; - - -/* IP_MF appears to be only defined in , however, - we need it for hardware checksumming support. FYI... some of - the definitions in conflict/duplicate those in - other linux headers causing many compiler warnings. -*/ -#ifndef IP_MF - #define IP_MF 0x2000 /* IP more frags from */ -#endif - -/* Define IP_OFFSET to be IPOPT_OFFSET */ -#ifndef IP_OFFSET - #ifdef IPOPT_OFFSET - #define IP_OFFSET IPOPT_OFFSET - #else - #define IP_OFFSET 2 - #endif -#endif - -#define RUN_AT(x) (jiffies + (x)) - -#ifndef ADDRLEN -#define ADDRLEN 32 -#endif - -/* Condensed bus+endian portability operations. */ -#if ADDRLEN == 64 -#define cpu_to_leXX(addr) cpu_to_le64(addr) -#define leXX_to_cpu(addr) le64_to_cpu(addr) -#else -#define cpu_to_leXX(addr) cpu_to_le32(addr) -#define leXX_to_cpu(addr) le32_to_cpu(addr) -#endif - - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the Packet Engines "Hamachi" -Gigabit Ethernet chip. The only PCA currently supported is the GNIC-II 64-bit -66Mhz PCI card. - -II. Board-specific settings - -No jumpers exist on the board. The chip supports software correction of -various motherboard wiring errors, however this driver does not support -that feature. - -III. Driver operation - -IIIa. Ring buffers - -The Hamachi uses a typical descriptor based bus-master architecture. -The descriptor list is similar to that used by the Digital Tulip. -This driver uses two statically allocated fixed-size descriptor lists -formed into rings by a branch from the final descriptor to the beginning of -the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. - -This driver uses a zero-copy receive and transmit scheme similar my other -network drivers. -The driver allocates full frame size skbuffs for the Rx ring buffers at -open() time and passes the skb->data field to the Hamachi as receive data -buffers. When an incoming frame is less than RX_COPYBREAK bytes long, -a fresh skbuff is allocated and the frame is copied to the new skbuff. -When the incoming frame is larger, the skbuff is passed directly up the -protocol stack and replaced by a newly allocated skbuff. - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. Gigabit cards are typically used on generously configured machines -and the underfilled buffers have negligible impact compared to the benefit of -a single allocation size, so the default value of zero results in never -copying packets. - -IIIb/c. Transmit/Receive Structure - -The Rx and Tx descriptor structure are straight-forward, with no historical -baggage that must be explained. Unlike the awkward DBDMA structure, there -are no unused fields or option bits that had only one allowable setting. - -Two details should be noted about the descriptors: The chip supports both 32 -bit and 64 bit address structures, and the length field is overwritten on -the receive descriptors. The descriptor length is set in the control word -for each channel. The development driver uses 32 bit addresses only, however -64 bit addresses may be enabled for 64 bit architectures e.g. the Alpha. - -IIId. Synchronization - -This driver is very similar to my other network drivers. -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'hmp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff the 'hmp->tx_full' flag is set, it -clears both the tx_full and tbusy flags. - -IV. Notes - -Thanks to Kim Stearns of Packet Engines for providing a pair of GNIC-II boards. - -IVb. References - -Hamachi Engineering Design Specification, 5/15/97 -(Note: This version was marked "Confidential".) - -IVc. Errata - -None noted. - -V. Recent Changes - -01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears - to help avoid some stall conditions -- this needs further research. - -01/15/1999 EPK Creation of the hamachi_tx function. This function cleans - the Tx ring and is called from hamachi_start_xmit (this used to be - called from hamachi_interrupt but it tends to delay execution of the - interrupt handler and thus reduce bandwidth by reducing the latency - between hamachi_rx()'s). Notably, some modification has been made so - that the cleaning loop checks only to make sure that the DescOwn bit - isn't set in the status flag since the card is not required - to set the entire flag to zero after processing. - -01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is - checked before attempting to add a buffer to the ring. If the ring is full - an attempt is made to free any dirty buffers and thus find space for - the new buffer or the function returns non-zero which should case the - scheduler to reschedule the buffer later. - -01/15/1999 EPK Some adjustments were made to the chip initialization. - End-to-end flow control should now be fully active and the interrupt - algorithm vars have been changed. These could probably use further tuning. - -01/15/1999 EPK Added the max_{rx,tx}_latency options. These are used to - set the rx and tx latencies for the Hamachi interrupts. If you're having - problems with network stalls, try setting these to higher values. - Valid values are 0x00 through 0xff. - -01/15/1999 EPK In general, the overall bandwidth has increased and - latencies are better (sometimes by a factor of 2). Stalls are rare at - this point, however there still appears to be a bug somewhere between the - hardware and driver. TCP checksum errors under load also appear to be - eliminated at this point. - -01/18/1999 EPK Ensured that the DescEndRing bit was being set on both the - Rx and Tx rings. This appears to have been affecting whether a particular - peer-to-peer connection would hang under high load. I believe the Rx - rings was typically getting set correctly, but the Tx ring wasn't getting - the DescEndRing bit set during initialization. ??? Does this mean the - hamachi card is using the DescEndRing in processing even if a particular - slot isn't in use -- hypothetically, the card might be searching the - entire Tx ring for slots with the DescOwn bit set and then processing - them. If the DescEndRing bit isn't set, then it might just wander off - through memory until it hits a chunk of data with that bit set - and then looping back. - -02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout - problem (TxCmd and RxCmd need only to be set when idle or stopped. - -02/09/1999 EPK Added code to check/reset dev->tbusy in hamachi_interrupt. - (Michel Mueller pointed out the ``permanently busy'' potential - problem here). - -02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies. - -02/23/1999 EPK Verified that the interrupt status field bits for Tx were - incorrectly defined and corrected (as per Michel Mueller). - -02/23/1999 EPK Corrected the Tx full check to check that at least 4 slots - were available before resetting the tbusy and tx_full flags - (as per Michel Mueller). - -03/11/1999 EPK Added Pete Wyckoff's hardware checksumming support. - -12/31/1999 KDU Cleaned up assorted things and added Don's code to force -32 bit. - -02/20/2000 KDU Some of the control was just plain odd. Cleaned up the -hamachi_start_xmit() and hamachi_interrupt() code. There is still some -re-structuring I would like to do. - -03/01/2000 KDU Experimenting with a WIDE range of interrupt mitigation -parameters on a dual P3-450 setup yielded the new default interrupt -mitigation parameters. Tx should interrupt VERY infrequently due to -Eric's scheme. Rx should be more often... - -03/13/2000 KDU Added a patch to make the Rx Checksum code interact -nicely with non-linux machines. - -03/13/2000 KDU Experimented with some of the configuration values: - - -It seems that enabling PCI performance commands for descriptors - (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal - performance impact for any of my tests. (ttcp, netpipe, netperf) I will - leave them that way until I hear further feedback. - - -Increasing the PCI_LATENCY_TIMER to 130 - (2 + (burst size of 128 * (0 wait states + 1))) seems to slightly - degrade performance. Leaving default at 64 pending further information. - -03/14/2000 KDU Further tuning: - - -adjusted boguscnt in hamachi_rx() to depend on interrupt - mitigation parameters chosen. - - -Selected a set of interrupt parameters based on some extensive testing. - These may change with more testing. - -TO DO: - --Consider borrowing from the acenic driver code to check PCI_COMMAND for -PCI_COMMAND_INVALIDATE. Set maximum burst size to cache line size in -that case. - --fix the reset procedure. It doesn't quite work. -*/ - -/* A few values that may be tweaked. */ -/* Size of each temporary Rx buffer, calculated as: - * 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for - * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum - */ -#define PKT_BUF_SZ 1536 - -/* For now, this is going to be set to the maximum size of an ethernet - * packet. Eventually, we may want to make it a variable that is - * related to the MTU - */ -#define MAX_FRAME_SIZE 1518 - -/* The rest of these values should never change. */ - -static void hamachi_timer(struct timer_list *t); - -enum capability_flags {CanHaveMII=1, }; -static const struct chip_info { - u16 vendor_id, device_id, device_id_mask, pad; - const char *name; - void (*media_timer)(struct timer_list *t); - int flags; -} chip_tbl[] = { - {0x1318, 0x0911, 0xffff, 0, "Hamachi GNIC-II", hamachi_timer, 0}, - {0,}, -}; - -/* Offsets to the Hamachi registers. Various sizes. */ -enum hamachi_offsets { - TxDMACtrl=0x00, TxCmd=0x04, TxStatus=0x06, TxPtr=0x08, TxCurPtr=0x10, - RxDMACtrl=0x20, RxCmd=0x24, RxStatus=0x26, RxPtr=0x28, RxCurPtr=0x30, - PCIClkMeas=0x060, MiscStatus=0x066, ChipRev=0x68, ChipReset=0x06B, - LEDCtrl=0x06C, VirtualJumpers=0x06D, GPIO=0x6E, - TxChecksum=0x074, RxChecksum=0x076, - TxIntrCtrl=0x078, RxIntrCtrl=0x07C, - InterruptEnable=0x080, InterruptClear=0x084, IntrStatus=0x088, - EventStatus=0x08C, - MACCnfg=0x0A0, FrameGap0=0x0A2, FrameGap1=0x0A4, - /* See enum MII_offsets below. */ - MACCnfg2=0x0B0, RxDepth=0x0B8, FlowCtrl=0x0BC, MaxFrameSize=0x0CE, - AddrMode=0x0D0, StationAddr=0x0D2, - /* Gigabit AutoNegotiation. */ - ANCtrl=0x0E0, ANStatus=0x0E2, ANXchngCtrl=0x0E4, ANAdvertise=0x0E8, - ANLinkPartnerAbility=0x0EA, - EECmdStatus=0x0F0, EEData=0x0F1, EEAddr=0x0F2, - FIFOcfg=0x0F8, -}; - -/* Offsets to the MII-mode registers. */ -enum MII_offsets { - MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, - MII_Status=0xAE, -}; - -/* Bits in the interrupt status/mask registers. */ -enum intr_status_bits { - IntrRxDone=0x01, IntrRxPCIFault=0x02, IntrRxPCIErr=0x04, - IntrTxDone=0x100, IntrTxPCIFault=0x200, IntrTxPCIErr=0x400, - LinkChange=0x10000, NegotiationChange=0x20000, StatsMax=0x40000, }; - -/* The Hamachi Rx and Tx buffer descriptors. */ -struct hamachi_desc { - __le32 status_n_length; -#if ADDRLEN == 64 - u32 pad; - __le64 addr; -#else - __le32 addr; -#endif -}; - -/* Bits in hamachi_desc.status_n_length */ -enum desc_status_bits { - DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000, - DescIntr=0x10000000, -}; - -#define PRIV_ALIGN 15 /* Required alignment mask */ -#define MII_CNT 4 -struct hamachi_private { - /* Descriptor rings first for alignment. Tx requires a second descriptor - for status. */ - struct hamachi_desc *rx_ring; - struct hamachi_desc *tx_ring; - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - dma_addr_t tx_ring_dma; - dma_addr_t rx_ring_dma; - struct timer_list timer; /* Media selection timer. */ - /* Frequently used and paired value: keep adjacent for cache effect. */ - spinlock_t lock; - int chip_id; - unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int cur_tx, dirty_tx; - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int duplex_lock:1; - unsigned int default_port:4; /* Last dev->if_port value. */ - /* MII transceiver section. */ - int mii_cnt; /* MII device addresses. */ - struct mii_if_info mii_if; /* MII lib hooks/info */ - unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ - u32 rx_int_var, tx_int_var; /* interrupt control variables */ - u32 option; /* Hold on to a copy of the options */ - struct pci_dev *pci_dev; - void __iomem *base; -}; - -MODULE_AUTHOR("Donald Becker , Eric Kasten , Keith Underwood "); -MODULE_DESCRIPTION("Packet Engines 'Hamachi' GNIC-II Gigabit Ethernet driver"); -MODULE_LICENSE("GPL"); - -module_param(max_interrupt_work, int, 0); -module_param(mtu, int, 0); -module_param(debug, int, 0); -module_param(min_rx_pkt, int, 0); -module_param(max_rx_gap, int, 0); -module_param(max_rx_latency, int, 0); -module_param(min_tx_pkt, int, 0); -module_param(max_tx_gap, int, 0); -module_param(max_tx_latency, int, 0); -module_param(rx_copybreak, int, 0); -module_param_array(rx_params, int, NULL, 0); -module_param_array(tx_params, int, NULL, 0); -module_param_array(options, int, NULL, 0); -module_param_array(full_duplex, int, NULL, 0); -module_param(force32, int, 0); -MODULE_PARM_DESC(max_interrupt_work, "GNIC-II maximum events handled per interrupt"); -MODULE_PARM_DESC(mtu, "GNIC-II MTU (all boards)"); -MODULE_PARM_DESC(debug, "GNIC-II debug level (0-7)"); -MODULE_PARM_DESC(min_rx_pkt, "GNIC-II minimum Rx packets processed between interrupts"); -MODULE_PARM_DESC(max_rx_gap, "GNIC-II maximum Rx inter-packet gap in 8.192 microsecond units"); -MODULE_PARM_DESC(max_rx_latency, "GNIC-II time between Rx interrupts in 8.192 microsecond units"); -MODULE_PARM_DESC(min_tx_pkt, "GNIC-II minimum Tx packets processed between interrupts"); -MODULE_PARM_DESC(max_tx_gap, "GNIC-II maximum Tx inter-packet gap in 8.192 microsecond units"); -MODULE_PARM_DESC(max_tx_latency, "GNIC-II time between Tx interrupts in 8.192 microsecond units"); -MODULE_PARM_DESC(rx_copybreak, "GNIC-II copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(rx_params, "GNIC-II min_rx_pkt+max_rx_gap+max_rx_latency"); -MODULE_PARM_DESC(tx_params, "GNIC-II min_tx_pkt+max_tx_gap+max_tx_latency"); -MODULE_PARM_DESC(options, "GNIC-II Bits 0-3: media type, bits 4-6: as force32, bit 7: half duplex, bit 9 full duplex"); -MODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)"); -MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)"); - -static int read_eeprom(void __iomem *ioaddr, int location); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int hamachi_open(struct net_device *dev); -static int hamachi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int hamachi_siocdevprivate(struct net_device *dev, struct ifreq *rq, - void __user *data, int cmd); -static void hamachi_timer(struct timer_list *t); -static void hamachi_tx_timeout(struct net_device *dev, unsigned int txqueue); -static void hamachi_init_ring(struct net_device *dev); -static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t hamachi_interrupt(int irq, void *dev_instance); -static int hamachi_rx(struct net_device *dev); -static inline int hamachi_tx(struct net_device *dev); -static void hamachi_error(struct net_device *dev, int intr_status); -static int hamachi_close(struct net_device *dev); -static struct net_device_stats *hamachi_get_stats(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; -static const struct ethtool_ops ethtool_ops_no_mii; - -static const struct net_device_ops hamachi_netdev_ops = { - .ndo_open = hamachi_open, - .ndo_stop = hamachi_close, - .ndo_start_xmit = hamachi_start_xmit, - .ndo_get_stats = hamachi_get_stats, - .ndo_set_rx_mode = set_rx_mode, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_tx_timeout = hamachi_tx_timeout, - .ndo_eth_ioctl = hamachi_ioctl, - .ndo_siocdevprivate = hamachi_siocdevprivate, -}; - - -static int hamachi_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct hamachi_private *hmp; - int option, i, rx_int_var, tx_int_var, boguscnt; - int chip_id = ent->driver_data; - int irq; - void __iomem *ioaddr; - unsigned long base; - static int card_idx; - struct net_device *dev; - void *ring_space; - dma_addr_t ring_dma; - int ret = -ENOMEM; - u8 addr[ETH_ALEN]; - -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); -#endif - - if (pci_enable_device(pdev)) { - ret = -EIO; - goto err_out; - } - - base = pci_resource_start(pdev, 0); -#ifdef __alpha__ /* Really "64 bit addrs" */ - base |= (pci_resource_start(pdev, 1) << 32); -#endif - - pci_set_master(pdev); - - i = pci_request_regions(pdev, DRV_NAME); - if (i) - return i; - - irq = pdev->irq; - ioaddr = ioremap(base, 0x400); - if (!ioaddr) - goto err_out_release; - - dev = alloc_etherdev(sizeof(struct hamachi_private)); - if (!dev) - goto err_out_iounmap; - - SET_NETDEV_DEV(dev, &pdev->dev); - - for (i = 0; i < 6; i++) - addr[i] = read_eeprom(ioaddr, 4 + i); - eth_hw_addr_set(dev, addr); - -#if ! defined(final_version) - if (hamachi_debug > 4) - for (i = 0; i < 0x10; i++) - printk("%2.2x%s", - read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n"); -#endif - - hmp = netdev_priv(dev); - spin_lock_init(&hmp->lock); - - hmp->mii_if.dev = dev; - hmp->mii_if.mdio_read = mdio_read; - hmp->mii_if.mdio_write = mdio_write; - hmp->mii_if.phy_id_mask = 0x1f; - hmp->mii_if.reg_num_mask = 0x1f; - - ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma, - GFP_KERNEL); - if (!ring_space) - goto err_out_cleardev; - hmp->tx_ring = ring_space; - hmp->tx_ring_dma = ring_dma; - - ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma, - GFP_KERNEL); - if (!ring_space) - goto err_out_unmap_tx; - hmp->rx_ring = ring_space; - hmp->rx_ring_dma = ring_dma; - - /* Check for options being passed in */ - option = card_idx < MAX_UNITS ? options[card_idx] : 0; - if (dev->mem_start) - option = dev->mem_start; - - /* If the bus size is misidentified, do the following. */ - force32 = force32 ? force32 : - ((option >= 0) ? ((option & 0x00000070) >> 4) : 0 ); - if (force32) - writeb(force32, ioaddr + VirtualJumpers); - - /* Hmmm, do we really need to reset the chip???. */ - writeb(0x01, ioaddr + ChipReset); - - /* After a reset, the clock speed measurement of the PCI bus will not - * be valid for a moment. Wait for a little while until it is. If - * it takes more than 10ms, forget it. - */ - udelay(10); - i = readb(ioaddr + PCIClkMeas); - for (boguscnt = 0; (!(i & 0x080)) && boguscnt < 1000; boguscnt++){ - udelay(10); - i = readb(ioaddr + PCIClkMeas); - } - - hmp->base = ioaddr; - pci_set_drvdata(pdev, dev); - - hmp->chip_id = chip_id; - hmp->pci_dev = pdev; - - /* The lower four bits are the media type. */ - if (option > 0) { - hmp->option = option; - if (option & 0x200) - hmp->mii_if.full_duplex = 1; - else if (option & 0x080) - hmp->mii_if.full_duplex = 0; - hmp->default_port = option & 15; - if (hmp->default_port) - hmp->mii_if.force_media = 1; - } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - hmp->mii_if.full_duplex = 1; - - /* lock the duplex mode if someone specified a value */ - if (hmp->mii_if.full_duplex || (option & 0x080)) - hmp->duplex_lock = 1; - - /* Set interrupt tuning parameters */ - max_rx_latency = max_rx_latency & 0x00ff; - max_rx_gap = max_rx_gap & 0x00ff; - min_rx_pkt = min_rx_pkt & 0x00ff; - max_tx_latency = max_tx_latency & 0x00ff; - max_tx_gap = max_tx_gap & 0x00ff; - min_tx_pkt = min_tx_pkt & 0x00ff; - - rx_int_var = card_idx < MAX_UNITS ? rx_params[card_idx] : -1; - tx_int_var = card_idx < MAX_UNITS ? tx_params[card_idx] : -1; - hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var : - (min_rx_pkt << 16 | max_rx_gap << 8 | max_rx_latency); - hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var : - (min_tx_pkt << 16 | max_tx_gap << 8 | max_tx_latency); - - - /* The Hamachi-specific entries in the device structure. */ - dev->netdev_ops = &hamachi_netdev_ops; - dev->ethtool_ops = (chip_tbl[hmp->chip_id].flags & CanHaveMII) ? - ðtool_ops : ðtool_ops_no_mii; - dev->watchdog_timeo = TX_TIMEOUT; - if (mtu) - dev->mtu = mtu; - - i = register_netdev(dev); - if (i) { - ret = i; - goto err_out_unmap_rx; - } - - printk(KERN_INFO "%s: %s type %x at %p, %pM, IRQ %d.\n", - dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), - ioaddr, dev->dev_addr, irq); - i = readb(ioaddr + PCIClkMeas); - printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " - "%2.2x, LPA %4.4x.\n", - dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, - i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), - readw(ioaddr + ANLinkPartnerAbility)); - - if (chip_tbl[hmp->chip_id].flags & CanHaveMII) { - int phy, phy_idx = 0; - for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, MII_BMSR); - if (mii_status != 0xffff && - mii_status != 0x0000) { - hmp->phys[phy_idx++] = phy; - hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, hmp->mii_if.advertising); - } - } - hmp->mii_cnt = phy_idx; - if (hmp->mii_cnt > 0) - hmp->mii_if.phy_id = hmp->phys[0]; - else - memset(&hmp->mii_if, 0, sizeof(hmp->mii_if)); - } - /* Configure gigabit autonegotiation. */ - writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ - writew(0x08e0, ioaddr + ANAdvertise); /* Set our advertise word. */ - writew(0x1000, ioaddr + ANCtrl); /* Enable negotiation */ - - card_idx++; - return 0; - -err_out_unmap_rx: - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, hmp->rx_ring, - hmp->rx_ring_dma); -err_out_unmap_tx: - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, hmp->tx_ring, - hmp->tx_ring_dma); -err_out_cleardev: - free_netdev (dev); -err_out_iounmap: - iounmap(ioaddr); -err_out_release: - pci_release_regions(pdev); -err_out: - return ret; -} - -static int read_eeprom(void __iomem *ioaddr, int location) -{ - int bogus_cnt = 1000; - - /* We should check busy first - per docs -KDU */ - while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); - writew(location, ioaddr + EEAddr); - writeb(0x02, ioaddr + EECmdStatus); - bogus_cnt = 1000; - while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); - if (hamachi_debug > 5) - printk(" EEPROM status is %2.2x after %d ticks.\n", - (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt); - return readb(ioaddr + EEData); -} - -/* MII Managemen Data I/O accesses. - These routines assume the MDIO controller is idle, and do not exit until - the command is finished. */ - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - int i; - - /* We should check busy first - per docs -KDU */ - for (i = 10000; i >= 0; i--) - if ((readw(ioaddr + MII_Status) & 1) == 0) - break; - writew((phy_id<<8) + location, ioaddr + MII_Addr); - writew(0x0001, ioaddr + MII_Cmd); - for (i = 10000; i >= 0; i--) - if ((readw(ioaddr + MII_Status) & 1) == 0) - break; - return readw(ioaddr + MII_Rd_Data); -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - int i; - - /* We should check busy first - per docs -KDU */ - for (i = 10000; i >= 0; i--) - if ((readw(ioaddr + MII_Status) & 1) == 0) - break; - writew((phy_id<<8) + location, ioaddr + MII_Addr); - writew(value, ioaddr + MII_Wr_Data); - - /* Wait for the command to finish. */ - for (i = 10000; i >= 0; i--) - if ((readw(ioaddr + MII_Status) & 1) == 0) - break; -} - - -static int hamachi_open(struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - int i; - u32 rx_int_var, tx_int_var; - u16 fifo_info; - - i = request_irq(hmp->pci_dev->irq, hamachi_interrupt, IRQF_SHARED, - dev->name, dev); - if (i) - return i; - - hamachi_init_ring(dev); - -#if ADDRLEN == 64 - /* writellll anyone ? */ - writel(hmp->rx_ring_dma, ioaddr + RxPtr); - writel(hmp->rx_ring_dma >> 32, ioaddr + RxPtr + 4); - writel(hmp->tx_ring_dma, ioaddr + TxPtr); - writel(hmp->tx_ring_dma >> 32, ioaddr + TxPtr + 4); -#else - writel(hmp->rx_ring_dma, ioaddr + RxPtr); - writel(hmp->tx_ring_dma, ioaddr + TxPtr); -#endif - - /* TODO: It would make sense to organize this as words since the card - * documentation does. -KDU - */ - for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + i); - - /* Initialize other registers: with so many this eventually this will - converted to an offset/value list. */ - - /* Configure the FIFO */ - fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6; - switch (fifo_info){ - case 0 : - /* No FIFO */ - writew(0x0000, ioaddr + FIFOcfg); - break; - case 1 : - /* Configure the FIFO for 512K external, 16K used for Tx. */ - writew(0x0028, ioaddr + FIFOcfg); - break; - case 2 : - /* Configure the FIFO for 1024 external, 32K used for Tx. */ - writew(0x004C, ioaddr + FIFOcfg); - break; - case 3 : - /* Configure the FIFO for 2048 external, 32K used for Tx. */ - writew(0x006C, ioaddr + FIFOcfg); - break; - default : - printk(KERN_WARNING "%s: Unsupported external memory config!\n", - dev->name); - /* Default to no FIFO */ - writew(0x0000, ioaddr + FIFOcfg); - break; - } - - if (dev->if_port == 0) - dev->if_port = hmp->default_port; - - - /* Setting the Rx mode will start the Rx process. */ - /* If someone didn't choose a duplex, default to full-duplex */ - if (hmp->duplex_lock != 1) - hmp->mii_if.full_duplex = 1; - - /* always 1, takes no more time to do it */ - writew(0x0001, ioaddr + RxChecksum); - writew(0x0000, ioaddr + TxChecksum); - writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ - writew(0x215F, ioaddr + MACCnfg); - writew(0x000C, ioaddr + FrameGap0); - /* WHAT?!?!? Why isn't this documented somewhere? -KDU */ - writew(0x1018, ioaddr + FrameGap1); - /* Why do we enable receives/transmits here? -KDU */ - writew(0x0780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */ - /* Enable automatic generation of flow control frames, period 0xffff. */ - writel(0x0030FFFF, ioaddr + FlowCtrl); - writew(MAX_FRAME_SIZE, ioaddr + MaxFrameSize); /* dev->mtu+14 ??? */ - - /* Enable legacy links. */ - writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ - /* Initial Link LED to blinking red. */ - writeb(0x03, ioaddr + LEDCtrl); - - /* Configure interrupt mitigation. This has a great effect on - performance, so systems tuning should start here!. */ - - rx_int_var = hmp->rx_int_var; - tx_int_var = hmp->tx_int_var; - - if (hamachi_debug > 1) { - printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n", - tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8, - (tx_int_var & 0x00ff0000) >> 16); - printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n", - rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8, - (rx_int_var & 0x00ff0000) >> 16); - printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var); - } - - writel(tx_int_var, ioaddr + TxIntrCtrl); - writel(rx_int_var, ioaddr + RxIntrCtrl); - - set_rx_mode(dev); - - netif_start_queue(dev); - - /* Enable interrupts by setting the interrupt mask. */ - writel(0x80878787, ioaddr + InterruptEnable); - writew(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ - - /* Configure and start the DMA channels. */ - /* Burst sizes are in the low three bits: size = 4<<(val&7) */ -#if ADDRLEN == 64 - writew(0x005D, ioaddr + RxDMACtrl); /* 128 dword bursts */ - writew(0x005D, ioaddr + TxDMACtrl); -#else - writew(0x001D, ioaddr + RxDMACtrl); - writew(0x001D, ioaddr + TxDMACtrl); -#endif - writew(0x0001, ioaddr + RxCmd); - - if (hamachi_debug > 2) { - printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n", - dev->name, readw(ioaddr + RxStatus), readw(ioaddr + TxStatus)); - } - /* Set the timer to check for link beat. */ - timer_setup(&hmp->timer, hamachi_timer, 0); - hmp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ - add_timer(&hmp->timer); - - return 0; -} - -static inline int hamachi_tx(struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - - /* Update the dirty pointer until we find an entry that is - still owned by the card */ - for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) { - int entry = hmp->dirty_tx % TX_RING_SIZE; - struct sk_buff *skb; - - if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) - break; - /* Free the original skb. */ - skb = hmp->tx_skbuff[entry]; - if (skb) { - dma_unmap_single(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->tx_ring[entry].addr), - skb->len, DMA_TO_DEVICE); - dev_kfree_skb(skb); - hmp->tx_skbuff[entry] = NULL; - } - hmp->tx_ring[entry].status_n_length = 0; - if (entry >= TX_RING_SIZE-1) - hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= - cpu_to_le32(DescEndRing); - dev->stats.tx_packets++; - } - - return 0; -} - -static void hamachi_timer(struct timer_list *t) -{ - struct hamachi_private *hmp = timer_container_of(hmp, t, timer); - struct net_device *dev = hmp->mii_if.dev; - void __iomem *ioaddr = hmp->base; - int next_tick = 10*HZ; - - if (hamachi_debug > 2) { - printk(KERN_INFO "%s: Hamachi Autonegotiation status %4.4x, LPA " - "%4.4x.\n", dev->name, readw(ioaddr + ANStatus), - readw(ioaddr + ANLinkPartnerAbility)); - printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x " - "%4.4x %4.4x %4.4x.\n", dev->name, - readw(ioaddr + 0x0e0), - readw(ioaddr + 0x0e2), - readw(ioaddr + 0x0e4), - readw(ioaddr + 0x0e6), - readw(ioaddr + 0x0e8), - readw(ioaddr + 0x0eA)); - } - /* We could do something here... nah. */ - hmp->timer.expires = RUN_AT(next_tick); - add_timer(&hmp->timer); -} - -static void hamachi_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - int i; - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - - printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," - " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); - - { - printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - printk(KERN_CONT " %8.8x", - le32_to_cpu(hmp->rx_ring[i].status_n_length)); - printk(KERN_CONT "\n"); - printk(KERN_DEBUG" Tx ring %p: ", hmp->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_CONT " %4.4x", - le32_to_cpu(hmp->tx_ring[i].status_n_length)); - printk(KERN_CONT "\n"); - } - - /* Reinit the hardware and make sure the Rx and Tx processes - are up and running. - */ - dev->if_port = 0; - /* The right way to do Reset. -KDU - * -Clear OWN bit in all Rx/Tx descriptors - * -Wait 50 uS for channels to go idle - * -Turn off MAC receiver - * -Issue Reset - */ - - for (i = 0; i < RX_RING_SIZE; i++) - hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn); - - /* Presume that all packets in the Tx queue are gone if we have to - * re-init the hardware. - */ - for (i = 0; i < TX_RING_SIZE; i++){ - struct sk_buff *skb; - - if (i >= TX_RING_SIZE - 1) - hmp->tx_ring[i].status_n_length = - cpu_to_le32(DescEndRing) | - (hmp->tx_ring[i].status_n_length & - cpu_to_le32(0x0000ffff)); - else - hmp->tx_ring[i].status_n_length &= cpu_to_le32(0x0000ffff); - skb = hmp->tx_skbuff[i]; - if (skb){ - dma_unmap_single(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->tx_ring[i].addr), - skb->len, DMA_TO_DEVICE); - dev_kfree_skb(skb); - hmp->tx_skbuff[i] = NULL; - } - } - - udelay(60); /* Sleep 60 us just for safety sake */ - writew(0x0002, ioaddr + RxCmd); /* STOP Rx */ - - writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */ - - hmp->tx_full = 0; - hmp->cur_rx = hmp->cur_tx = 0; - hmp->dirty_rx = hmp->dirty_tx = 0; - /* Rx packets are also presumed lost; however, we need to make sure a - * ring of buffers is in tact. -KDU - */ - for (i = 0; i < RX_RING_SIZE; i++){ - struct sk_buff *skb = hmp->rx_skbuff[i]; - - if (skb){ - dma_unmap_single(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->rx_ring[i].addr), - hmp->rx_buf_sz, DMA_FROM_DEVICE); - dev_kfree_skb(skb); - hmp->rx_skbuff[i] = NULL; - } - } - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - - skb = netdev_alloc_skb_ip_align(dev, hmp->rx_buf_sz); - hmp->rx_skbuff[i] = skb; - if (skb == NULL) - break; - - hmp->rx_ring[i].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, - skb->data, - hmp->rx_buf_sz, - DMA_FROM_DEVICE)); - hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | - DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); - } - hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - /* Mark the last entry as wrapping the ring. */ - hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); - - /* Trigger an immediate transmit demand. */ - netif_trans_update(dev); /* prevent tx timeout */ - dev->stats.tx_errors++; - - /* Restart the chip's Tx/Rx processes . */ - writew(0x0002, ioaddr + TxCmd); /* STOP Tx */ - writew(0x0001, ioaddr + TxCmd); /* START Tx */ - writew(0x0001, ioaddr + RxCmd); /* START Rx */ - - netif_wake_queue(dev); -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void hamachi_init_ring(struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - int i; - - hmp->tx_full = 0; - hmp->cur_rx = hmp->cur_tx = 0; - hmp->dirty_rx = hmp->dirty_tx = 0; - - /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the - * card needs room to do 8 byte alignment, +2 so we can reserve - * the first 2 bytes, and +16 gets room for the status word from the - * card. -KDU - */ - hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ : - (((dev->mtu+26+7) & ~7) + 16)); - - /* Initialize all Rx descriptors. */ - for (i = 0; i < RX_RING_SIZE; i++) { - hmp->rx_ring[i].status_n_length = 0; - hmp->rx_skbuff[i] = NULL; - } - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz + 2); - hmp->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb_reserve(skb, 2); /* 16 byte align the IP header. */ - hmp->rx_ring[i].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, - skb->data, - hmp->rx_buf_sz, - DMA_FROM_DEVICE)); - /* -2 because it doesn't REALLY have that first 2 bytes -KDU */ - hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | - DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); - } - hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); - - for (i = 0; i < TX_RING_SIZE; i++) { - hmp->tx_skbuff[i] = NULL; - hmp->tx_ring[i].status_n_length = 0; - } - /* Mark the last entry of the ring */ - hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); -} - - -static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - unsigned entry; - u16 status; - - /* Ok, now make sure that the queue has space before trying to - add another skbuff. if we return non-zero the scheduler - should interpret this as a queue full and requeue the buffer - for later. - */ - if (hmp->tx_full) { - /* We should NEVER reach this point -KDU */ - printk(KERN_WARNING "%s: Hamachi transmit queue full at slot %d.\n",dev->name, hmp->cur_tx); - - /* Wake the potentially-idle transmit channel. */ - /* If we don't need to read status, DON'T -KDU */ - status=readw(hmp->base + TxStatus); - if( !(status & 0x0001) || (status & 0x0002)) - writew(0x0001, hmp->base + TxCmd); - return NETDEV_TX_BUSY; - } - - /* Caution: the write order is important here, set the field - with the "ownership" bits last. */ - - /* Calculate the next Tx descriptor entry. */ - entry = hmp->cur_tx % TX_RING_SIZE; - - hmp->tx_skbuff[entry] = skb; - - hmp->tx_ring[entry].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, - skb->data, - skb->len, - DMA_TO_DEVICE)); - - /* Hmmmm, could probably put a DescIntr on these, but the way - the driver is currently coded makes Tx interrupts unnecessary - since the clearing of the Tx ring is handled by the start_xmit - routine. This organization helps mitigate the interrupts a - bit and probably renders the max_tx_latency param useless. - - Update: Putting a DescIntr bit on all of the descriptors and - mitigating interrupt frequency with the tx_min_pkt parameter. -KDU - */ - if (entry >= TX_RING_SIZE-1) /* Wrap ring */ - hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | - DescEndPacket | DescEndRing | DescIntr | skb->len); - else - hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | - DescEndPacket | DescIntr | skb->len); - hmp->cur_tx++; - - /* Non-x86 Todo: explicitly flush cache lines here. */ - - /* Wake the potentially-idle transmit channel. */ - /* If we don't need to read status, DON'T -KDU */ - status=readw(hmp->base + TxStatus); - if( !(status & 0x0001) || (status & 0x0002)) - writew(0x0001, hmp->base + TxCmd); - - /* Immediately before returning, let's clear as many entries as we can. */ - hamachi_tx(dev); - - /* We should kick the bottom half here, since we are not accepting - * interrupts with every packet. i.e. realize that Gigabit ethernet - * can transmit faster than ordinary machines can load packets; - * hence, any packet that got put off because we were in the transmit - * routine should IMMEDIATELY get a chance to be re-queued. -KDU - */ - if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4)) - netif_wake_queue(dev); /* Typical path */ - else { - hmp->tx_full = 1; - netif_stop_queue(dev); - } - - if (hamachi_debug > 4) { - printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", - dev->name, hmp->cur_tx, entry); - } - return NETDEV_TX_OK; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static irqreturn_t hamachi_interrupt(int irq, void *dev_instance) -{ - struct net_device *dev = dev_instance; - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - long boguscnt = max_interrupt_work; - int handled = 0; - -#ifndef final_version /* Can never occur. */ - if (dev == NULL) { - printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } -#endif - - spin_lock(&hmp->lock); - - do { - u32 intr_status = readl(ioaddr + InterruptClear); - - if (hamachi_debug > 4) - printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n", - dev->name, intr_status); - - if (intr_status == 0) - break; - - handled = 1; - - if (intr_status & IntrRxDone) - hamachi_rx(dev); - - if (intr_status & IntrTxDone){ - /* This code should RARELY need to execute. After all, this is - * a gigabit link, it should consume packets as fast as we put - * them in AND we clear the Tx ring in hamachi_start_xmit(). - */ - if (hmp->tx_full){ - for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){ - int entry = hmp->dirty_tx % TX_RING_SIZE; - struct sk_buff *skb; - - if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) - break; - skb = hmp->tx_skbuff[entry]; - /* Free the original skb. */ - if (skb){ - dma_unmap_single(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->tx_ring[entry].addr), - skb->len, - DMA_TO_DEVICE); - dev_consume_skb_irq(skb); - hmp->tx_skbuff[entry] = NULL; - } - hmp->tx_ring[entry].status_n_length = 0; - if (entry >= TX_RING_SIZE-1) - hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= - cpu_to_le32(DescEndRing); - dev->stats.tx_packets++; - } - if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){ - /* The ring is no longer full */ - hmp->tx_full = 0; - netif_wake_queue(dev); - } - } else { - netif_wake_queue(dev); - } - } - - - /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & - (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr | - LinkChange | NegotiationChange | StatsMax)) - hamachi_error(dev, intr_status); - - if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", - dev->name, intr_status); - break; - } - } while (1); - - if (hamachi_debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); - -#ifndef final_version - /* Code that should never be run! Perhaps remove after testing.. */ - { - static int stopit = 10; - if (dev->start == 0 && --stopit < 0) { - printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", - dev->name); - free_irq(irq, dev); - } - } -#endif - - spin_unlock(&hmp->lock); - return IRQ_RETVAL(handled); -} - -/* This routine is logically part of the interrupt handler, but separated - for clarity and better register allocation. */ -static int hamachi_rx(struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - int entry = hmp->cur_rx % RX_RING_SIZE; - int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx; - - if (hamachi_debug > 4) { - printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n", - entry, hmp->rx_ring[entry].status_n_length); - } - - /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (1) { - struct hamachi_desc *desc = &(hmp->rx_ring[entry]); - u32 desc_status = le32_to_cpu(desc->status_n_length); - u16 data_size = desc_status; /* Implicit truncate */ - u8 *buf_addr; - s32 frame_status; - - if (desc_status & DescOwn) - break; - dma_sync_single_for_cpu(&hmp->pci_dev->dev, - leXX_to_cpu(desc->addr), - hmp->rx_buf_sz, DMA_FROM_DEVICE); - buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; - frame_status = get_unaligned_le32(&(buf_addr[data_size - 12])); - if (hamachi_debug > 4) - printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", - frame_status); - if (--boguscnt < 0) - break; - if ( ! (desc_status & DescEndPacket)) { - printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " - "multiple buffers, entry %#x length %d status %4.4x!\n", - dev->name, hmp->cur_rx, data_size, desc_status); - printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", - dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]); - printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status %x/%x last status %x.\n", - dev->name, - le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0xffff0000, - le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0x0000ffff, - le32_to_cpu(hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length)); - dev->stats.rx_length_errors++; - } /* else Omit for prototype errata??? */ - if (frame_status & 0x00380000) { - /* There was an error. */ - if (hamachi_debug > 2) - printk(KERN_DEBUG " hamachi_rx() Rx error was %8.8x.\n", - frame_status); - dev->stats.rx_errors++; - if (frame_status & 0x00600000) - dev->stats.rx_length_errors++; - if (frame_status & 0x00080000) - dev->stats.rx_frame_errors++; - if (frame_status & 0x00100000) - dev->stats.rx_crc_errors++; - if (frame_status < 0) - dev->stats.rx_dropped++; - } else { - struct sk_buff *skb; - /* Omit CRC */ - u16 pkt_len = (frame_status & 0x07ff) - 4; -#ifdef RX_CHECKSUM - u32 pfck = *(u32 *) &buf_addr[data_size - 8]; -#endif - - -#ifndef final_version - if (hamachi_debug > 4) - printk(KERN_DEBUG " hamachi_rx() normal Rx pkt length %d" - " of %d, bogus_cnt %d.\n", - pkt_len, data_size, boguscnt); - if (hamachi_debug > 5) - printk(KERN_DEBUG"%s: rx status %8.8x %8.8x %8.8x %8.8x %8.8x.\n", - dev->name, - *(s32*)&(buf_addr[data_size - 20]), - *(s32*)&(buf_addr[data_size - 16]), - *(s32*)&(buf_addr[data_size - 12]), - *(s32*)&(buf_addr[data_size - 8]), - *(s32*)&(buf_addr[data_size - 4])); -#endif - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { -#ifdef RX_CHECKSUM - printk(KERN_ERR "%s: rx_copybreak non-zero " - "not good with RX_CHECKSUM\n", dev->name); -#endif - skb_reserve(skb, 2); /* 16 byte align the IP header */ - dma_sync_single_for_cpu(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->rx_ring[entry].addr), - hmp->rx_buf_sz, - DMA_FROM_DEVICE); - /* Call copy + cksum if available. */ -#if 1 || USE_IP_COPYSUM - skb_copy_to_linear_data(skb, - hmp->rx_skbuff[entry]->data, pkt_len); - skb_put(skb, pkt_len); -#else - skb_put_data(skb, hmp->rx_ring_dma - + entry*sizeof(*desc), pkt_len); -#endif - dma_sync_single_for_device(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->rx_ring[entry].addr), - hmp->rx_buf_sz, - DMA_FROM_DEVICE); - } else { - dma_unmap_single(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->rx_ring[entry].addr), - hmp->rx_buf_sz, - DMA_FROM_DEVICE); - skb_put(skb = hmp->rx_skbuff[entry], pkt_len); - hmp->rx_skbuff[entry] = NULL; - } - skb->protocol = eth_type_trans(skb, dev); - - -#ifdef RX_CHECKSUM - /* TCP or UDP on ipv4, DIX encoding */ - if (pfck>>24 == 0x91 || pfck>>24 == 0x51) { - struct iphdr *ih = (struct iphdr *) skb->data; - /* Check that IP packet is at least 46 bytes, otherwise, - * there may be pad bytes included in the hardware checksum. - * This wouldn't happen if everyone padded with 0. - */ - if (ntohs(ih->tot_len) >= 46){ - /* don't worry about frags */ - if (!(ih->frag_off & cpu_to_be16(IP_MF|IP_OFFSET))) { - u32 inv = *(u32 *) &buf_addr[data_size - 16]; - u32 *p = (u32 *) &buf_addr[data_size - 20]; - register u32 crc, p_r, p_r1; - - if (inv & 4) { - inv &= ~4; - --p; - } - p_r = *p; - p_r1 = *(p-1); - switch (inv) { - case 0: - crc = (p_r & 0xffff) + (p_r >> 16); - break; - case 1: - crc = (p_r >> 16) + (p_r & 0xffff) - + (p_r1 >> 16 & 0xff00); - break; - case 2: - crc = p_r + (p_r1 >> 16); - break; - case 3: - crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16); - break; - default: /*NOTREACHED*/ crc = 0; - } - if (crc & 0xffff0000) { - crc &= 0xffff; - ++crc; - } - /* tcp/udp will add in pseudo */ - skb->csum = ntohs(pfck & 0xffff); - if (skb->csum > crc) - skb->csum -= crc; - else - skb->csum += (~crc & 0xffff); - /* - * could do the pseudo myself and return - * CHECKSUM_UNNECESSARY - */ - skb->ip_summed = CHECKSUM_COMPLETE; - } - } - } -#endif /* RX_CHECKSUM */ - - netif_rx(skb); - dev->stats.rx_packets++; - } - entry = (++hmp->cur_rx) % RX_RING_SIZE; - } - - /* Refill the Rx ring buffers. */ - for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) { - struct hamachi_desc *desc; - - entry = hmp->dirty_rx % RX_RING_SIZE; - desc = &(hmp->rx_ring[entry]); - if (hmp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz + 2); - - hmp->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - desc->addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, - skb->data, - hmp->rx_buf_sz, - DMA_FROM_DEVICE)); - } - desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz); - if (entry >= RX_RING_SIZE-1) - desc->status_n_length |= cpu_to_le32(DescOwn | - DescEndPacket | DescEndRing | DescIntr); - else - desc->status_n_length |= cpu_to_le32(DescOwn | - DescEndPacket | DescIntr); - } - - /* Restart Rx engine if stopped. */ - /* If we don't need to check status, don't. -KDU */ - if (readw(hmp->base + RxStatus) & 0x0002) - writew(0x0001, hmp->base + RxCmd); - - return 0; -} - -/* This is more properly named "uncommon interrupt events", as it covers more - than just errors. */ -static void hamachi_error(struct net_device *dev, int intr_status) -{ - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - - if (intr_status & (LinkChange|NegotiationChange)) { - if (hamachi_debug > 1) - printk(KERN_INFO "%s: Link changed: AutoNegotiation Ctrl" - " %4.4x, Status %4.4x %4.4x Intr status %4.4x.\n", - dev->name, readw(ioaddr + 0x0E0), readw(ioaddr + 0x0E2), - readw(ioaddr + ANLinkPartnerAbility), - readl(ioaddr + IntrStatus)); - if (readw(ioaddr + ANStatus) & 0x20) - writeb(0x01, ioaddr + LEDCtrl); - else - writeb(0x03, ioaddr + LEDCtrl); - } - if (intr_status & StatsMax) { - hamachi_get_stats(dev); - /* Read the overflow bits to clear. */ - readl(ioaddr + 0x370); - readl(ioaddr + 0x3F0); - } - if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange|IntrRxDone|IntrTxDone)) && - hamachi_debug) - printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", - dev->name, intr_status); - /* Hmmmmm, it's not clear how to recover from PCI faults. */ - if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) - dev->stats.tx_fifo_errors++; - if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) - dev->stats.rx_fifo_errors++; -} - -static int hamachi_close(struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - struct sk_buff *skb; - int i; - - netif_stop_queue(dev); - - if (hamachi_debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", - dev->name, readw(ioaddr + TxStatus), - readw(ioaddr + RxStatus), readl(ioaddr + IntrStatus)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", - dev->name, hmp->cur_tx, hmp->dirty_tx, hmp->cur_rx, hmp->dirty_rx); - } - - /* Disable interrupts by clearing the interrupt mask. */ - writel(0x0000, ioaddr + InterruptEnable); - - /* Stop the chip's Tx and Rx processes. */ - writel(2, ioaddr + RxCmd); - writew(2, ioaddr + TxCmd); - -#ifdef __i386__ - if (hamachi_debug > 2) { - printk(KERN_DEBUG " Tx ring at %8.8x:\n", - (int)hmp->tx_ring_dma); - for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x.\n", - readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ', - i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr); - printk(KERN_DEBUG " Rx ring %8.8x:\n", - (int)hmp->rx_ring_dma); - for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " %c #%d desc. %4.4x %8.8x\n", - readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', - i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); - if (hamachi_debug > 6) { - if (*(u8*)hmp->rx_skbuff[i]->data != 0x69) { - u16 *addr = (u16 *) - hmp->rx_skbuff[i]->data; - int j; - printk(KERN_DEBUG "Addr: "); - for (j = 0; j < 0x50; j++) - printk(" %4.4x", addr[j]); - printk("\n"); - } - } - } - } -#endif /* __i386__ debugging only */ - - free_irq(hmp->pci_dev->irq, dev); - - timer_delete_sync(&hmp->timer); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - skb = hmp->rx_skbuff[i]; - hmp->rx_ring[i].status_n_length = 0; - if (skb) { - dma_unmap_single(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->rx_ring[i].addr), - hmp->rx_buf_sz, DMA_FROM_DEVICE); - dev_kfree_skb(skb); - hmp->rx_skbuff[i] = NULL; - } - hmp->rx_ring[i].addr = cpu_to_leXX(0xBADF00D0); /* An invalid address. */ - } - for (i = 0; i < TX_RING_SIZE; i++) { - skb = hmp->tx_skbuff[i]; - if (skb) { - dma_unmap_single(&hmp->pci_dev->dev, - leXX_to_cpu(hmp->tx_ring[i].addr), - skb->len, DMA_TO_DEVICE); - dev_kfree_skb(skb); - hmp->tx_skbuff[i] = NULL; - } - } - - writeb(0x00, ioaddr + LEDCtrl); - - return 0; -} - -static struct net_device_stats *hamachi_get_stats(struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - - /* We should lock this segment of code for SMP eventually, although - the vulnerability window is very small and statistics are - non-critical. */ - /* Ok, what goes here? This appears to be stuck at 21 packets - according to ifconfig. It does get incremented in hamachi_tx(), - so I think I'll comment it out here and see if better things - happen. - */ - /* dev->stats.tx_packets = readl(ioaddr + 0x000); */ - - /* Total Uni+Brd+Multi */ - dev->stats.rx_bytes = readl(ioaddr + 0x330); - /* Total Uni+Brd+Multi */ - dev->stats.tx_bytes = readl(ioaddr + 0x3B0); - /* Multicast Rx */ - dev->stats.multicast = readl(ioaddr + 0x320); - - /* Over+Undersized */ - dev->stats.rx_length_errors = readl(ioaddr + 0x368); - /* Jabber */ - dev->stats.rx_over_errors = readl(ioaddr + 0x35C); - /* Jabber */ - dev->stats.rx_crc_errors = readl(ioaddr + 0x360); - /* Symbol Errs */ - dev->stats.rx_frame_errors = readl(ioaddr + 0x364); - /* Dropped */ - dev->stats.rx_missed_errors = readl(ioaddr + 0x36C); - - return &dev->stats; -} - -static void set_rx_mode(struct net_device *dev) -{ - struct hamachi_private *hmp = netdev_priv(dev); - void __iomem *ioaddr = hmp->base; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - writew(0x000F, ioaddr + AddrMode); - } else if ((netdev_mc_count(dev) > 63) || (dev->flags & IFF_ALLMULTI)) { - /* Too many to match, or accept all multicasts. */ - writew(0x000B, ioaddr + AddrMode); - } else if (!netdev_mc_empty(dev)) { /* Must use the CAM filter. */ - struct netdev_hw_addr *ha; - int i = 0; - - netdev_for_each_mc_addr(ha, dev) { - writel(*(u32 *)(ha->addr), ioaddr + 0x100 + i*8); - writel(0x20000 | (*(u16 *)&ha->addr[4]), - ioaddr + 0x104 + i*8); - i++; - } - /* Clear remaining entries. */ - for (; i < 64; i++) - writel(0, ioaddr + 0x104 + i*8); - writew(0x0003, ioaddr + AddrMode); - } else { /* Normal, unicast/broadcast-only mode. */ - writew(0x0001, ioaddr + AddrMode); - } -} - -static int check_if_running(struct net_device *dev) -{ - if (!netif_running(dev)) - return -EINVAL; - return 0; -} - -static void hamachi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct hamachi_private *np = netdev_priv(dev); - - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->version, DRV_VERSION, sizeof(info->version)); - strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); -} - -static int hamachi_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct hamachi_private *np = netdev_priv(dev); - spin_lock_irq(&np->lock); - mii_ethtool_get_link_ksettings(&np->mii_if, cmd); - spin_unlock_irq(&np->lock); - return 0; -} - -static int hamachi_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct hamachi_private *np = netdev_priv(dev); - int res; - spin_lock_irq(&np->lock); - res = mii_ethtool_set_link_ksettings(&np->mii_if, cmd); - spin_unlock_irq(&np->lock); - return res; -} - -static int hamachi_nway_reset(struct net_device *dev) -{ - struct hamachi_private *np = netdev_priv(dev); - return mii_nway_restart(&np->mii_if); -} - -static u32 hamachi_get_link(struct net_device *dev) -{ - struct hamachi_private *np = netdev_priv(dev); - return mii_link_ok(&np->mii_if); -} - -static const struct ethtool_ops ethtool_ops = { - .begin = check_if_running, - .get_drvinfo = hamachi_get_drvinfo, - .nway_reset = hamachi_nway_reset, - .get_link = hamachi_get_link, - .get_link_ksettings = hamachi_get_link_ksettings, - .set_link_ksettings = hamachi_set_link_ksettings, -}; - -static const struct ethtool_ops ethtool_ops_no_mii = { - .begin = check_if_running, - .get_drvinfo = hamachi_get_drvinfo, -}; - -/* private ioctl: set rx,tx intr params */ -static int hamachi_siocdevprivate(struct net_device *dev, struct ifreq *rq, - void __user *data, int cmd) -{ - struct hamachi_private *np = netdev_priv(dev); - u32 *d = (u32 *)&rq->ifr_ifru; - - if (!netif_running(dev)) - return -EINVAL; - - if (cmd != SIOCDEVPRIVATE + 3) - return -EOPNOTSUPP; - - /* Should add this check here or an ordinary user can do nasty - * things. -KDU - * - * TODO: Shut down the Rx and Tx engines while doing this. - */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - writel(d[0], np->base + TxIntrCtrl); - writel(d[1], np->base + RxIntrCtrl); - printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name, - (u32)readl(np->base + TxIntrCtrl), - (u32)readl(np->base + RxIntrCtrl)); - - return 0; -} - -static int hamachi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct hamachi_private *np = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(rq); - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL); - spin_unlock_irq(&np->lock); - - return rc; -} - - -static void hamachi_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev) { - struct hamachi_private *hmp = netdev_priv(dev); - - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, hmp->rx_ring, - hmp->rx_ring_dma); - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, hmp->tx_ring, - hmp->tx_ring_dma); - unregister_netdev(dev); - iounmap(hmp->base); - free_netdev(dev); - pci_release_regions(pdev); - } -} - -static const struct pci_device_id hamachi_pci_tbl[] = { - { 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, hamachi_pci_tbl); - -static struct pci_driver hamachi_driver = { - .name = DRV_NAME, - .id_table = hamachi_pci_tbl, - .probe = hamachi_init_one, - .remove = hamachi_remove_one, -}; - -static int __init hamachi_init (void) -{ -/* when a module, this is printed whether or not devices are found in probe */ -#ifdef MODULE - printk(version); -#endif - return pci_register_driver(&hamachi_driver); -} - -static void __exit hamachi_exit (void) -{ - pci_unregister_driver(&hamachi_driver); -} - - -module_init(hamachi_init); -module_exit(hamachi_exit); diff --git a/drivers/net/ethernet/packetengines/yellowfin.c b/drivers/net/ethernet/packetengines/yellowfin.c deleted file mode 100644 index 1e25ac13a7d8..000000000000 --- a/drivers/net/ethernet/packetengines/yellowfin.c +++ /dev/null @@ -1,1438 +0,0 @@ -/* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */ -/* - Written 1997-2001 by Donald Becker. - - 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 or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. This file is not - a complete program and may only be used when the entire operating - system is licensed under the GPL. - - This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter. - It also supports the Symbios Logic version of the same chip core. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Support and updates available at - http://www.scyld.com/network/yellowfin.html - [link no longer provides useful info -jgarzik] - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DRV_NAME "yellowfin" -#define DRV_VERSION "2.1" -#define DRV_RELDATE "Sep 11, 2006" - -/* The user-configurable values. - These may be modified when a driver module is loaded.*/ - -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; -static int mtu; -#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ -/* System-wide count of bogus-rx frames. */ -static int bogus_rx; -static int dma_ctrl = 0x004A0263; /* Constrained by errata */ -static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ -#elif defined(YF_NEW) /* A future perfect board :->. */ -static int dma_ctrl = 0x00CAC277; /* Override when loading module! */ -static int fifo_cfg = 0x0028; -#else -static const int dma_ctrl = 0x004A0263; /* Constrained by errata */ -static const int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ -#endif - -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1514 effectively disables this feature. */ -static int rx_copybreak; - -/* Used to pass the media type, etc. - No media types are currently defined. These exist for driver - interoperability. -*/ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Do ugly workaround for GX server chipset errata. */ -static int gx_fix; - -/* Operational parameters that are set at compile time. */ - -/* Keep the ring sizes a power of two for efficiency. - Making the Tx ring too long decreases the effectiveness of channel - bonding and packet priority. - There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define TX_QUEUE_SIZE 12 /* Must be > 4 && <= TX_RING_SIZE */ -#define RX_RING_SIZE 64 -#define STATUS_TOTAL_SIZE TX_RING_SIZE*sizeof(struct tx_status_words) -#define TX_TOTAL_SIZE 2*TX_RING_SIZE*sizeof(struct yellowfin_desc) -#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct yellowfin_desc) - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ - -#define yellowfin_debug debug - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include - -/* These identify the driver base version and may not be removed. */ -static const char version[] = - KERN_INFO DRV_NAME ".c:v1.05 1/09/2001 Written by Donald Becker \n" - " (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n"; - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver"); -MODULE_LICENSE("GPL"); - -module_param(max_interrupt_work, int, 0); -module_param(mtu, int, 0); -module_param(debug, int, 0); -module_param(rx_copybreak, int, 0); -module_param_array(options, int, NULL, 0); -module_param_array(full_duplex, int, NULL, 0); -module_param(gx_fix, int, 0); -MODULE_PARM_DESC(max_interrupt_work, "G-NIC maximum events handled per interrupt"); -MODULE_PARM_DESC(mtu, "G-NIC MTU (all boards)"); -MODULE_PARM_DESC(debug, "G-NIC debug level (0-7)"); -MODULE_PARM_DESC(rx_copybreak, "G-NIC copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(options, "G-NIC: Bits 0-3: media type, bit 17: full duplex"); -MODULE_PARM_DESC(full_duplex, "G-NIC full duplex setting(s) (1)"); -MODULE_PARM_DESC(gx_fix, "G-NIC: enable GX server chipset bug workaround (0-1)"); - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the Packet Engines "Yellowfin" Gigabit -Ethernet adapter. The G-NIC 64-bit PCI card is supported, as well as the -Symbios 53C885E dual function chip. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS preferably should assign the -PCI INTA signal to an otherwise unused system IRQ line. -Note: Kernel versions earlier than 1.3.73 do not support shared PCI -interrupt lines. - -III. Driver operation - -IIIa. Ring buffers - -The Yellowfin uses the Descriptor Based DMA Architecture specified by Apple. -This is a descriptor list scheme similar to that used by the EEPro100 and -Tulip. This driver uses two statically allocated fixed-size descriptor lists -formed into rings by a branch from the final descriptor to the beginning of -the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. - -The driver allocates full frame size skbuffs for the Rx ring buffers at -open() time and passes the skb->data field to the Yellowfin as receive data -buffers. When an incoming frame is less than RX_COPYBREAK bytes long, -a fresh skbuff is allocated and the frame is copied to the new skbuff. -When the incoming frame is larger, the skbuff is passed directly up the -protocol stack and replaced by a newly allocated skbuff. - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. For small frames the copying cost is negligible (esp. considering -that we are pre-loading the cache with immediately useful header -information). For large frames the copying cost is non-trivial, and the -larger copy might flush the cache of useful data. - -IIIC. Synchronization - -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'yp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff the 'yp->tx_full' flag is set, it -clears both the tx_full and tbusy flags. - -IV. Notes - -Thanks to Kim Stearns of Packet Engines for providing a pair of G-NIC boards. -Thanks to Bruce Faust of Digitalscape for providing both their SYM53C885 board -and an AlphaStation to verify the Alpha port! - -IVb. References - -Yellowfin Engineering Design Specification, 4/23/97 Preliminary/Confidential -Symbios SYM53C885 PCI-SCSI/Fast Ethernet Multifunction Controller Preliminary - Data Manual v3.0 -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html - -IVc. Errata - -See Packet Engines confidential appendix (prototype chips only). -*/ - - - -enum capability_flags { - HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16, - HasMACAddrBug=32, /* Only on early revs. */ - DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */ -}; - -/* The PCI I/O space extent. */ -enum { - YELLOWFIN_SIZE = 0x100, -}; - -struct pci_id_info { - const char *name; - struct match_info { - int pci, pci_mask, subsystem, subsystem_mask; - int revision, revision_mask; /* Only 8 bits. */ - } id; - int drv_flags; /* Driver use, intended as capability flags. */ -}; - -static const struct pci_id_info pci_id_tbl[] = { - {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff}, - FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom}, - {"Symbios SYM83C885", { 0x07011000, 0xffffffff}, - HasMII | DontUseEeprom }, - { } -}; - -static const struct pci_device_id yellowfin_pci_tbl[] = { - { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { } -}; -MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl); - - -/* Offsets to the Yellowfin registers. Various sizes and alignments. */ -enum yellowfin_offsets { - TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C, - TxIntrSel=0x10, TxBranchSel=0x14, TxWaitSel=0x18, - RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C, - RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58, - EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86, - ChipRev=0x8C, DMACtrl=0x90, TxThreshold=0x94, - Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4, - MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, - MII_Status=0xAE, - RxDepth=0xB8, FlowCtrl=0xBC, - AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, FIFOcfg=0xF8, - EEStatus=0xF0, EECtrl=0xF1, EEAddr=0xF2, EERead=0xF3, EEWrite=0xF4, - EEFeature=0xF5, -}; - -/* The Yellowfin Rx and Tx buffer descriptors. - Elements are written as 32 bit for endian portability. */ -struct yellowfin_desc { - __le32 dbdma_cmd; - __le32 addr; - __le32 branch_addr; - __le32 result_status; -}; - -struct tx_status_words { -#ifdef __BIG_ENDIAN - u16 tx_errs; - u16 tx_cnt; - u16 paused; - u16 total_tx_cnt; -#else /* Little endian chips. */ - u16 tx_cnt; - u16 tx_errs; - u16 total_tx_cnt; - u16 paused; -#endif /* __BIG_ENDIAN */ -}; - -/* Bits in yellowfin_desc.cmd */ -enum desc_cmd_bits { - CMD_TX_PKT=0x10000000, CMD_RX_BUF=0x20000000, CMD_TXSTATUS=0x30000000, - CMD_NOP=0x60000000, CMD_STOP=0x70000000, - BRANCH_ALWAYS=0x0C0000, INTR_ALWAYS=0x300000, WAIT_ALWAYS=0x030000, - BRANCH_IFTRUE=0x040000, -}; - -/* Bits in yellowfin_desc.status */ -enum desc_status_bits { RX_EOP=0x0040, }; - -/* Bits in the interrupt status/mask registers. */ -enum intr_status_bits { - IntrRxDone=0x01, IntrRxInvalid=0x02, IntrRxPCIFault=0x04,IntrRxPCIErr=0x08, - IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80, - IntrEarlyRx=0x100, IntrWakeup=0x200, }; - -#define PRIV_ALIGN 31 /* Required alignment mask */ -#define MII_CNT 4 -struct yellowfin_private { - /* Descriptor rings first for alignment. - Tx requires a second descriptor for status. */ - struct yellowfin_desc *rx_ring; - struct yellowfin_desc *tx_ring; - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - dma_addr_t rx_ring_dma; - dma_addr_t tx_ring_dma; - - struct tx_status_words *tx_status; - dma_addr_t tx_status_dma; - - struct timer_list timer; /* Media selection timer. */ - /* Frequently used and paired value: keep adjacent for cache effect. */ - int chip_id, drv_flags; - struct pci_dev *pci_dev; - unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - struct tx_status_words *tx_tail_desc; - unsigned int cur_tx, dirty_tx; - int tx_threshold; - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int duplex_lock:1; - unsigned int medialock:1; /* Do not sense media. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - /* MII transceiver section. */ - int mii_cnt; /* MII device addresses. */ - u16 advertising; /* NWay media advertisement */ - unsigned char phys[MII_CNT]; /* MII device addresses, only first one used */ - spinlock_t lock; - void __iomem *base; -}; - -static int read_eeprom(void __iomem *ioaddr, int location); -static int mdio_read(void __iomem *ioaddr, int phy_id, int location); -static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value); -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int yellowfin_open(struct net_device *dev); -static void yellowfin_timer(struct timer_list *t); -static void yellowfin_tx_timeout(struct net_device *dev, unsigned int txqueue); -static int yellowfin_init_ring(struct net_device *dev); -static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance); -static int yellowfin_rx(struct net_device *dev); -static void yellowfin_error(struct net_device *dev, int intr_status); -static int yellowfin_close(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; - -static const struct net_device_ops netdev_ops = { - .ndo_open = yellowfin_open, - .ndo_stop = yellowfin_close, - .ndo_start_xmit = yellowfin_start_xmit, - .ndo_set_rx_mode = set_rx_mode, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_eth_ioctl = netdev_ioctl, - .ndo_tx_timeout = yellowfin_tx_timeout, -}; - -static int yellowfin_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - struct yellowfin_private *np; - int irq; - int chip_idx = ent->driver_data; - static int find_cnt; - void __iomem *ioaddr; - int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; - int drv_flags = pci_id_tbl[chip_idx].drv_flags; - void *ring_space; - dma_addr_t ring_dma; -#ifdef USE_IO_OPS - int bar = 0; -#else - int bar = 1; -#endif - u8 addr[ETH_ALEN]; - -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); -#endif - - i = pci_enable_device(pdev); - if (i) return i; - - dev = alloc_etherdev(sizeof(*np)); - if (!dev) - return -ENOMEM; - - SET_NETDEV_DEV(dev, &pdev->dev); - - np = netdev_priv(dev); - - if (pci_request_regions(pdev, DRV_NAME)) - goto err_out_free_netdev; - - pci_set_master (pdev); - - ioaddr = pci_iomap(pdev, bar, YELLOWFIN_SIZE); - if (!ioaddr) - goto err_out_free_res; - - irq = pdev->irq; - - if (drv_flags & DontUseEeprom) - for (i = 0; i < 6; i++) - addr[i] = ioread8(ioaddr + StnAddr + i); - else { - int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); - for (i = 0; i < 6; i++) - addr[i] = read_eeprom(ioaddr, ee_offset + i); - } - eth_hw_addr_set(dev, addr); - - /* Reset the chip. */ - iowrite32(0x80000000, ioaddr + DMACtrl); - - pci_set_drvdata(pdev, dev); - spin_lock_init(&np->lock); - - np->pci_dev = pdev; - np->chip_id = chip_idx; - np->drv_flags = drv_flags; - np->base = ioaddr; - - ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma, - GFP_KERNEL); - if (!ring_space) - goto err_out_cleardev; - np->tx_ring = ring_space; - np->tx_ring_dma = ring_dma; - - ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma, - GFP_KERNEL); - if (!ring_space) - goto err_out_unmap_tx; - np->rx_ring = ring_space; - np->rx_ring_dma = ring_dma; - - ring_space = dma_alloc_coherent(&pdev->dev, STATUS_TOTAL_SIZE, - &ring_dma, GFP_KERNEL); - if (!ring_space) - goto err_out_unmap_rx; - np->tx_status = ring_space; - np->tx_status_dma = ring_dma; - - if (dev->mem_start) - option = dev->mem_start; - - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x200) - np->full_duplex = 1; - np->default_port = option & 15; - if (np->default_port) - np->medialock = 1; - } - if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) - np->full_duplex = 1; - - if (np->full_duplex) - np->duplex_lock = 1; - - /* The Yellowfin-specific entries in the device structure. */ - dev->netdev_ops = &netdev_ops; - dev->ethtool_ops = ðtool_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - if (mtu) - dev->mtu = mtu; - - i = register_netdev(dev); - if (i) - goto err_out_unmap_status; - - netdev_info(dev, "%s type %8x at %p, %pM, IRQ %d\n", - pci_id_tbl[chip_idx].name, - ioread32(ioaddr + ChipRev), ioaddr, - dev->dev_addr, irq); - - if (np->drv_flags & HasMII) { - int phy, phy_idx = 0; - for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phy; - np->advertising = mdio_read(ioaddr, phy, 4); - netdev_info(dev, "MII PHY found at address %d, status 0x%04x advertising %04x\n", - phy, mii_status, np->advertising); - } - } - np->mii_cnt = phy_idx; - } - - find_cnt++; - - return 0; - -err_out_unmap_status: - dma_free_coherent(&pdev->dev, STATUS_TOTAL_SIZE, np->tx_status, - np->tx_status_dma); -err_out_unmap_rx: - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring, - np->rx_ring_dma); -err_out_unmap_tx: - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring, - np->tx_ring_dma); -err_out_cleardev: - pci_iounmap(pdev, ioaddr); -err_out_free_res: - pci_release_regions(pdev); -err_out_free_netdev: - free_netdev (dev); - return -ENODEV; -} - -static int read_eeprom(void __iomem *ioaddr, int location) -{ - int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */ - - iowrite8(location, ioaddr + EEAddr); - iowrite8(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); - while ((ioread8(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) - ; - return ioread8(ioaddr + EERead); -} - -/* MII Managemen Data I/O accesses. - These routines assume the MDIO controller is idle, and do not exit until - the command is finished. */ - -static int mdio_read(void __iomem *ioaddr, int phy_id, int location) -{ - int i; - - iowrite16((phy_id<<8) + location, ioaddr + MII_Addr); - iowrite16(1, ioaddr + MII_Cmd); - for (i = 10000; i >= 0; i--) - if ((ioread16(ioaddr + MII_Status) & 1) == 0) - break; - return ioread16(ioaddr + MII_Rd_Data); -} - -static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value) -{ - int i; - - iowrite16((phy_id<<8) + location, ioaddr + MII_Addr); - iowrite16(value, ioaddr + MII_Wr_Data); - - /* Wait for the command to finish. */ - for (i = 10000; i >= 0; i--) - if ((ioread16(ioaddr + MII_Status) & 1) == 0) - break; -} - - -static int yellowfin_open(struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - const int irq = yp->pci_dev->irq; - void __iomem *ioaddr = yp->base; - int i, rc; - - /* Reset the chip. */ - iowrite32(0x80000000, ioaddr + DMACtrl); - - rc = request_irq(irq, yellowfin_interrupt, IRQF_SHARED, dev->name, dev); - if (rc) - return rc; - - rc = yellowfin_init_ring(dev); - if (rc < 0) - goto err_free_irq; - - iowrite32(yp->rx_ring_dma, ioaddr + RxPtr); - iowrite32(yp->tx_ring_dma, ioaddr + TxPtr); - - for (i = 0; i < 6; i++) - iowrite8(dev->dev_addr[i], ioaddr + StnAddr + i); - - /* Set up various condition 'select' registers. - There are no options here. */ - iowrite32(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */ - iowrite32(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */ - iowrite32(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */ - iowrite32(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */ - iowrite32(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */ - iowrite32(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */ - - /* Initialize other registers: with so many this eventually this will - converted to an offset/value list. */ - iowrite32(dma_ctrl, ioaddr + DMACtrl); - iowrite16(fifo_cfg, ioaddr + FIFOcfg); - /* Enable automatic generation of flow control frames, period 0xffff. */ - iowrite32(0x0030FFFF, ioaddr + FlowCtrl); - - yp->tx_threshold = 32; - iowrite32(yp->tx_threshold, ioaddr + TxThreshold); - - if (dev->if_port == 0) - dev->if_port = yp->default_port; - - netif_start_queue(dev); - - /* Setting the Rx mode will start the Rx process. */ - if (yp->drv_flags & IsGigabit) { - /* We are always in full-duplex mode with gigabit! */ - yp->full_duplex = 1; - iowrite16(0x01CF, ioaddr + Cnfg); - } else { - iowrite16(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ - iowrite16(0x1018, ioaddr + FrameGap1); - iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); - } - set_rx_mode(dev); - - /* Enable interrupts by setting the interrupt mask. */ - iowrite16(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ - iowrite16(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ - iowrite32(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */ - iowrite32(0x80008000, ioaddr + TxCtrl); - - if (yellowfin_debug > 2) { - netdev_printk(KERN_DEBUG, dev, "Done %s()\n", __func__); - } - - /* Set the timer to check for link beat. */ - timer_setup(&yp->timer, yellowfin_timer, 0); - yp->timer.expires = jiffies + 3*HZ; - add_timer(&yp->timer); -out: - return rc; - -err_free_irq: - free_irq(irq, dev); - goto out; -} - -static void yellowfin_timer(struct timer_list *t) -{ - struct yellowfin_private *yp = timer_container_of(yp, t, timer); - struct net_device *dev = pci_get_drvdata(yp->pci_dev); - void __iomem *ioaddr = yp->base; - int next_tick = 60*HZ; - - if (yellowfin_debug > 3) { - netdev_printk(KERN_DEBUG, dev, "Yellowfin timer tick, status %08x\n", - ioread16(ioaddr + IntrStatus)); - } - - if (yp->mii_cnt) { - int bmsr = mdio_read(ioaddr, yp->phys[0], MII_BMSR); - int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA); - int negotiated = lpa & yp->advertising; - if (yellowfin_debug > 1) - netdev_printk(KERN_DEBUG, dev, "MII #%d status register is %04x, link partner capability %04x\n", - yp->phys[0], bmsr, lpa); - - yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated); - - iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); - - if (bmsr & BMSR_LSTATUS) - next_tick = 60*HZ; - else - next_tick = 3*HZ; - } - - yp->timer.expires = jiffies + next_tick; - add_timer(&yp->timer); -} - -static void yellowfin_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct yellowfin_private *yp = netdev_priv(dev); - void __iomem *ioaddr = yp->base; - - netdev_warn(dev, "Yellowfin transmit timed out at %d/%d Tx status %04x, Rx status %04x, resetting...\n", - yp->cur_tx, yp->dirty_tx, - ioread32(ioaddr + TxStatus), - ioread32(ioaddr + RxStatus)); - - /* Note: these should be KERN_DEBUG. */ - if (yellowfin_debug) { - int i; - pr_warn(" Rx ring %p: ", yp->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - pr_cont(" %08x", yp->rx_ring[i].result_status); - pr_cont("\n"); - pr_warn(" Tx ring %p: ", yp->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - pr_cont(" %04x /%08x", - yp->tx_status[i].tx_errs, - yp->tx_ring[i].result_status); - pr_cont("\n"); - } - - /* If the hardware is found to hang regularly, we will update the code - to reinitialize the chip here. */ - dev->if_port = 0; - - /* Wake the potentially-idle transmit channel. */ - iowrite32(0x10001000, yp->base + TxCtrl); - if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) - netif_wake_queue (dev); /* Typical path */ - - netif_trans_update(dev); /* prevent tx timeout */ - dev->stats.tx_errors++; -} - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static int yellowfin_init_ring(struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - int i, j; - - yp->tx_full = 0; - yp->cur_rx = yp->cur_tx = 0; - yp->dirty_tx = 0; - - yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - - for (i = 0; i < RX_RING_SIZE; i++) { - yp->rx_ring[i].dbdma_cmd = - cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz); - yp->rx_ring[i].branch_addr = cpu_to_le32(yp->rx_ring_dma + - ((i+1)%RX_RING_SIZE)*sizeof(struct yellowfin_desc)); - } - - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2); - yp->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb_reserve(skb, 2); /* 16 byte align the IP header. */ - yp->rx_ring[i].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev, - skb->data, - yp->rx_buf_sz, - DMA_FROM_DEVICE)); - } - if (i != RX_RING_SIZE) { - for (j = 0; j < i; j++) - dev_kfree_skb(yp->rx_skbuff[j]); - return -ENOMEM; - } - yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - -#define NO_TXSTATS -#ifdef NO_TXSTATS - /* In this mode the Tx ring needs only a single descriptor. */ - for (i = 0; i < TX_RING_SIZE; i++) { - yp->tx_skbuff[i] = NULL; - yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->tx_ring[i].branch_addr = cpu_to_le32(yp->tx_ring_dma + - ((i+1)%TX_RING_SIZE)*sizeof(struct yellowfin_desc)); - } - /* Wrap ring */ - yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS); -#else -{ - /* Tx ring needs a pair of descriptors, the second for the status. */ - for (i = 0; i < TX_RING_SIZE; i++) { - j = 2*i; - yp->tx_skbuff[i] = 0; - /* Branch on Tx error. */ - yp->tx_ring[j].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + - (j+1)*sizeof(struct yellowfin_desc)); - j++; - if (yp->flags & FullTxStatus) { - yp->tx_ring[j].dbdma_cmd = - cpu_to_le32(CMD_TXSTATUS | sizeof(*yp->tx_status)); - yp->tx_ring[j].request_cnt = sizeof(*yp->tx_status); - yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + - i*sizeof(struct tx_status_words)); - } else { - /* Symbios chips write only tx_errs word. */ - yp->tx_ring[j].dbdma_cmd = - cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2); - yp->tx_ring[j].request_cnt = 2; - /* Om pade ummmmm... */ - yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + - i*sizeof(struct tx_status_words) + - &(yp->tx_status[0].tx_errs) - - &(yp->tx_status[0])); - } - yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + - ((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc)); - } - /* Wrap ring */ - yp->tx_ring[++j].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS); -} -#endif - yp->tx_tail_desc = &yp->tx_status[0]; - return 0; -} - -static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - unsigned entry; - int len = skb->len; - - netif_stop_queue (dev); - - /* Note: Ordering is important here, set the field with the - "ownership" bit last, and only then increment cur_tx. */ - - /* Calculate the next Tx descriptor entry. */ - entry = yp->cur_tx % TX_RING_SIZE; - - if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */ - int cacheline_end = ((unsigned long)skb->data + skb->len) % 32; - /* Fix GX chipset errata. */ - if (cacheline_end > 24 || cacheline_end == 0) { - len = skb->len + 32 - cacheline_end + 1; - if (skb_padto(skb, len)) { - yp->tx_skbuff[entry] = NULL; - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - } - } - yp->tx_skbuff[entry] = skb; - -#ifdef NO_TXSTATS - yp->tx_ring[entry].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev, - skb->data, - len, DMA_TO_DEVICE)); - yp->tx_ring[entry].result_status = 0; - if (entry >= TX_RING_SIZE-1) { - /* New stop command. */ - yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd = - cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | len); - } else { - yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->tx_ring[entry].dbdma_cmd = - cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | len); - } - yp->cur_tx++; -#else - yp->tx_ring[entry<<1].request_cnt = len; - yp->tx_ring[entry<<1].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev, - skb->data, - len, DMA_TO_DEVICE)); - /* The input_last (status-write) command is constant, but we must - rewrite the subsequent 'stop' command. */ - - yp->cur_tx++; - { - unsigned next_entry = yp->cur_tx % TX_RING_SIZE; - yp->tx_ring[next_entry<<1].dbdma_cmd = cpu_to_le32(CMD_STOP); - } - /* Final step -- overwrite the old 'stop' command. */ - - yp->tx_ring[entry<<1].dbdma_cmd = - cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE : - CMD_TX_PKT | BRANCH_IFTRUE) | len); -#endif - - /* Non-x86 Todo: explicitly flush cache lines here. */ - - /* Wake the potentially-idle transmit channel. */ - iowrite32(0x10001000, yp->base + TxCtrl); - - if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) - netif_start_queue (dev); /* Typical path */ - else - yp->tx_full = 1; - - if (yellowfin_debug > 4) { - netdev_printk(KERN_DEBUG, dev, "Yellowfin transmit frame #%d queued in slot %d\n", - yp->cur_tx, entry); - } - return NETDEV_TX_OK; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) -{ - struct net_device *dev = dev_instance; - struct yellowfin_private *yp; - void __iomem *ioaddr; - int boguscnt = max_interrupt_work; - unsigned int handled = 0; - - yp = netdev_priv(dev); - ioaddr = yp->base; - - spin_lock (&yp->lock); - - do { - u16 intr_status = ioread16(ioaddr + IntrClear); - - if (yellowfin_debug > 4) - netdev_printk(KERN_DEBUG, dev, "Yellowfin interrupt, status %04x\n", - intr_status); - - if (intr_status == 0) - break; - handled = 1; - - if (intr_status & (IntrRxDone | IntrEarlyRx)) { - yellowfin_rx(dev); - iowrite32(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */ - } - -#ifdef NO_TXSTATS - for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) { - int entry = yp->dirty_tx % TX_RING_SIZE; - struct sk_buff *skb; - - if (yp->tx_ring[entry].result_status == 0) - break; - skb = yp->tx_skbuff[entry]; - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - /* Free the original skb. */ - dma_unmap_single(&yp->pci_dev->dev, - le32_to_cpu(yp->tx_ring[entry].addr), - skb->len, DMA_TO_DEVICE); - dev_consume_skb_irq(skb); - yp->tx_skbuff[entry] = NULL; - } - if (yp->tx_full && - yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) { - /* The ring is no longer full, clear tbusy. */ - yp->tx_full = 0; - netif_wake_queue(dev); - } -#else - if ((intr_status & IntrTxDone) || (yp->tx_tail_desc->tx_errs)) { - unsigned dirty_tx = yp->dirty_tx; - - for (dirty_tx = yp->dirty_tx; yp->cur_tx - dirty_tx > 0; - dirty_tx++) { - /* Todo: optimize this. */ - int entry = dirty_tx % TX_RING_SIZE; - u16 tx_errs = yp->tx_status[entry].tx_errs; - struct sk_buff *skb; - -#ifndef final_version - if (yellowfin_debug > 5) - netdev_printk(KERN_DEBUG, dev, "Tx queue %d check, Tx status %04x %04x %04x %04x\n", - entry, - yp->tx_status[entry].tx_cnt, - yp->tx_status[entry].tx_errs, - yp->tx_status[entry].total_tx_cnt, - yp->tx_status[entry].paused); -#endif - if (tx_errs == 0) - break; /* It still hasn't been Txed */ - skb = yp->tx_skbuff[entry]; - if (tx_errs & 0xF810) { - /* There was an major error, log it. */ -#ifndef final_version - if (yellowfin_debug > 1) - netdev_printk(KERN_DEBUG, dev, "Transmit error, Tx status %04x\n", - tx_errs); -#endif - dev->stats.tx_errors++; - if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++; - if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++; - if (tx_errs & 0x2000) dev->stats.tx_window_errors++; - if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++; - } else { -#ifndef final_version - if (yellowfin_debug > 4) - netdev_printk(KERN_DEBUG, dev, "Normal transmit, Tx status %04x\n", - tx_errs); -#endif - dev->stats.tx_bytes += skb->len; - dev->stats.collisions += tx_errs & 15; - dev->stats.tx_packets++; - } - /* Free the original skb. */ - dma_unmap_single(&yp->pci_dev->dev, - yp->tx_ring[entry << 1].addr, - skb->len, DMA_TO_DEVICE); - dev_consume_skb_irq(skb); - yp->tx_skbuff[entry] = 0; - /* Mark status as empty. */ - yp->tx_status[entry].tx_errs = 0; - } - -#ifndef final_version - if (yp->cur_tx - dirty_tx > TX_RING_SIZE) { - netdev_err(dev, "Out-of-sync dirty pointer, %d vs. %d, full=%d\n", - dirty_tx, yp->cur_tx, yp->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - - if (yp->tx_full && - yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) { - /* The ring is no longer full, clear tbusy. */ - yp->tx_full = 0; - netif_wake_queue(dev); - } - - yp->dirty_tx = dirty_tx; - yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE]; - } -#endif - - /* Log errors and other uncommon events. */ - if (intr_status & 0x2ee) /* Abnormal error summary. */ - yellowfin_error(dev, intr_status); - - if (--boguscnt < 0) { - netdev_warn(dev, "Too much work at interrupt, status=%#04x\n", - intr_status); - break; - } - } while (1); - - if (yellowfin_debug > 3) - netdev_printk(KERN_DEBUG, dev, "exiting interrupt, status=%#04x\n", - ioread16(ioaddr + IntrStatus)); - - spin_unlock (&yp->lock); - return IRQ_RETVAL(handled); -} - -/* This routine is logically part of the interrupt handler, but separated - for clarity and better register allocation. */ -static int yellowfin_rx(struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - int entry = yp->cur_rx % RX_RING_SIZE; - int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx; - - if (yellowfin_debug > 4) { - printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %08x\n", - entry, yp->rx_ring[entry].result_status); - printk(KERN_DEBUG " #%d desc. %08x %08x %08x\n", - entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr, - yp->rx_ring[entry].result_status); - } - - /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (1) { - struct yellowfin_desc *desc = &yp->rx_ring[entry]; - struct sk_buff *rx_skb = yp->rx_skbuff[entry]; - s16 frame_status; - u16 desc_status; - int data_size, __maybe_unused yf_size; - u8 *buf_addr; - - if(!desc->result_status) - break; - dma_sync_single_for_cpu(&yp->pci_dev->dev, - le32_to_cpu(desc->addr), - yp->rx_buf_sz, DMA_FROM_DEVICE); - desc_status = le32_to_cpu(desc->result_status) >> 16; - buf_addr = rx_skb->data; - data_size = (le32_to_cpu(desc->dbdma_cmd) - - le32_to_cpu(desc->result_status)) & 0xffff; - frame_status = get_unaligned_le16(&(buf_addr[data_size - 2])); - if (yellowfin_debug > 4) - printk(KERN_DEBUG " %s() status was %04x\n", - __func__, frame_status); - if (--boguscnt < 0) - break; - - yf_size = sizeof(struct yellowfin_desc); - - if ( ! (desc_status & RX_EOP)) { - if (data_size != 0) - netdev_warn(dev, "Oversized Ethernet frame spanned multiple buffers, status %04x, data_size %d!\n", - desc_status, data_size); - dev->stats.rx_length_errors++; - } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) { - /* There was a error. */ - if (yellowfin_debug > 3) - printk(KERN_DEBUG " %s() Rx error was %04x\n", - __func__, frame_status); - dev->stats.rx_errors++; - if (frame_status & 0x0060) dev->stats.rx_length_errors++; - if (frame_status & 0x0008) dev->stats.rx_frame_errors++; - if (frame_status & 0x0010) dev->stats.rx_crc_errors++; - if (frame_status < 0) dev->stats.rx_dropped++; - } else if ( !(yp->drv_flags & IsGigabit) && - ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) { - u8 status1 = buf_addr[data_size-2]; - u8 status2 = buf_addr[data_size-1]; - dev->stats.rx_errors++; - if (status1 & 0xC0) dev->stats.rx_length_errors++; - if (status2 & 0x03) dev->stats.rx_frame_errors++; - if (status2 & 0x04) dev->stats.rx_crc_errors++; - if (status2 & 0x80) dev->stats.rx_dropped++; -#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ - } else if ((yp->flags & HasMACAddrBug) && - !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma + - entry * yf_size), - dev->dev_addr) && - !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma + - entry * yf_size), - "\377\377\377\377\377\377")) { - if (bogus_rx++ == 0) - netdev_warn(dev, "Bad frame to %pM\n", - buf_addr); -#endif - } else { - struct sk_buff *skb; - int pkt_len = data_size - - (yp->chip_id ? 7 : 8 + buf_addr[data_size - 8]); - /* To verify: Yellowfin Length should omit the CRC! */ - -#ifndef final_version - if (yellowfin_debug > 4) - printk(KERN_DEBUG " %s() normal Rx pkt length %d of %d, bogus_cnt %d\n", - __func__, pkt_len, data_size, boguscnt); -#endif - /* Check if the packet is long enough to just pass up the skbuff - without copying to a properly sized skbuff. */ - if (pkt_len > rx_copybreak) { - skb_put(skb = rx_skb, pkt_len); - dma_unmap_single(&yp->pci_dev->dev, - le32_to_cpu(yp->rx_ring[entry].addr), - yp->rx_buf_sz, - DMA_FROM_DEVICE); - yp->rx_skbuff[entry] = NULL; - } else { - skb = netdev_alloc_skb(dev, pkt_len + 2); - if (skb == NULL) - break; - skb_reserve(skb, 2); /* 16 byte align the IP header */ - skb_copy_to_linear_data(skb, rx_skb->data, pkt_len); - skb_put(skb, pkt_len); - dma_sync_single_for_device(&yp->pci_dev->dev, - le32_to_cpu(desc->addr), - yp->rx_buf_sz, - DMA_FROM_DEVICE); - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - entry = (++yp->cur_rx) % RX_RING_SIZE; - } - - /* Refill the Rx ring buffers. */ - for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) { - entry = yp->dirty_rx % RX_RING_SIZE; - if (yp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2); - if (skb == NULL) - break; /* Better luck next round. */ - yp->rx_skbuff[entry] = skb; - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - yp->rx_ring[entry].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev, - skb->data, - yp->rx_buf_sz, - DMA_FROM_DEVICE)); - } - yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */ - if (entry != 0) - yp->rx_ring[entry - 1].dbdma_cmd = - cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz); - else - yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd = - cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS - | yp->rx_buf_sz); - } - - return 0; -} - -static void yellowfin_error(struct net_device *dev, int intr_status) -{ - netdev_err(dev, "Something Wicked happened! %04x\n", intr_status); - /* Hmmmmm, it's not clear what to do here. */ - if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) - dev->stats.tx_errors++; - if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) - dev->stats.rx_errors++; -} - -static int yellowfin_close(struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - void __iomem *ioaddr = yp->base; - int i; - - netif_stop_queue (dev); - - if (yellowfin_debug > 1) { - netdev_printk(KERN_DEBUG, dev, "Shutting down ethercard, status was Tx %04x Rx %04x Int %02x\n", - ioread16(ioaddr + TxStatus), - ioread16(ioaddr + RxStatus), - ioread16(ioaddr + IntrStatus)); - netdev_printk(KERN_DEBUG, dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n", - yp->cur_tx, yp->dirty_tx, - yp->cur_rx, yp->dirty_rx); - } - - /* Disable interrupts by clearing the interrupt mask. */ - iowrite16(0x0000, ioaddr + IntrEnb); - - /* Stop the chip's Tx and Rx processes. */ - iowrite32(0x80000000, ioaddr + RxCtrl); - iowrite32(0x80000000, ioaddr + TxCtrl); - - timer_delete(&yp->timer); - -#if defined(__i386__) - if (yellowfin_debug > 2) { - printk(KERN_DEBUG " Tx ring at %08llx:\n", - (unsigned long long)yp->tx_ring_dma); - for (i = 0; i < TX_RING_SIZE*2; i++) - printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x %08x\n", - ioread32(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ', - i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr, - yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status); - printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status); - for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_DEBUG " #%d status %04x %04x %04x %04x\n", - i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs, - yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused); - - printk(KERN_DEBUG " Rx ring %08llx:\n", - (unsigned long long)yp->rx_ring_dma); - for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x\n", - ioread32(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ', - i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr, - yp->rx_ring[i].result_status); - if (yellowfin_debug > 6) { - if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) { - int j; - - printk(KERN_DEBUG); - for (j = 0; j < 0x50; j++) - pr_cont(" %04x", - get_unaligned(((u16*)yp->rx_ring[i].addr) + j)); - pr_cont("\n"); - } - } - } - } -#endif /* __i386__ debugging only */ - - free_irq(yp->pci_dev->irq, dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (yp->rx_skbuff[i]) { - dev_kfree_skb(yp->rx_skbuff[i]); - } - yp->rx_skbuff[i] = NULL; - } - for (i = 0; i < TX_RING_SIZE; i++) { - dev_kfree_skb(yp->tx_skbuff[i]); - yp->tx_skbuff[i] = NULL; - } - -#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ - if (yellowfin_debug > 0) { - netdev_printk(KERN_DEBUG, dev, "Received %d frames that we should not have\n", - bogus_rx); - } -#endif - - return 0; -} - -/* Set or clear the multicast filter for this adaptor. */ - -static void set_rx_mode(struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - void __iomem *ioaddr = yp->base; - u16 cfg_value = ioread16(ioaddr + Cnfg); - - /* Stop the Rx process to change any value. */ - iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg); - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - iowrite16(0x000F, ioaddr + AddrMode); - } else if ((netdev_mc_count(dev) > 64) || - (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter well, or accept all multicasts. */ - iowrite16(0x000B, ioaddr + AddrMode); - } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */ - struct netdev_hw_addr *ha; - u16 hash_table[4]; - int i; - - memset(hash_table, 0, sizeof(hash_table)); - netdev_for_each_mc_addr(ha, dev) { - unsigned int bit; - - /* Due to a bug in the early chip versions, multiple filter - slots must be set for each address. */ - if (yp->drv_flags & HasMulticastBug) { - bit = (ether_crc_le(3, ha->addr) >> 3) & 0x3f; - hash_table[bit >> 4] |= (1 << bit); - bit = (ether_crc_le(4, ha->addr) >> 3) & 0x3f; - hash_table[bit >> 4] |= (1 << bit); - bit = (ether_crc_le(5, ha->addr) >> 3) & 0x3f; - hash_table[bit >> 4] |= (1 << bit); - } - bit = (ether_crc_le(6, ha->addr) >> 3) & 0x3f; - hash_table[bit >> 4] |= (1 << bit); - } - /* Copy the hash table to the chip. */ - for (i = 0; i < 4; i++) - iowrite16(hash_table[i], ioaddr + HashTbl + i*2); - iowrite16(0x0003, ioaddr + AddrMode); - } else { /* Normal, unicast/broadcast-only mode. */ - iowrite16(0x0001, ioaddr + AddrMode); - } - /* Restart the Rx process. */ - iowrite16(cfg_value | 0x1000, ioaddr + Cnfg); -} - -static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct yellowfin_private *np = netdev_priv(dev); - - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->version, DRV_VERSION, sizeof(info->version)); - strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); -} - -static const struct ethtool_ops ethtool_ops = { - .get_drvinfo = yellowfin_get_drvinfo -}; - -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct yellowfin_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - struct mii_ioctl_data *data = if_mii(rq); - - switch(cmd) { - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - data->phy_id = np->phys[0] & 0x1f; - fallthrough; - - case SIOCGMIIREG: /* Read MII PHY register. */ - data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f); - return 0; - - case SIOCSMIIREG: /* Write MII PHY register. */ - if (data->phy_id == np->phys[0]) { - u16 value = data->val_in; - switch (data->reg_num) { - case 0: - /* Check for autonegotiation on or reset. */ - np->medialock = (value & 0x9000) ? 0 : 1; - if (np->medialock) - np->full_duplex = (value & 0x0100) ? 1 : 0; - break; - case 4: np->advertising = value; break; - } - /* Perhaps check_duplex(dev), depending on chip semantics. */ - } - mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); - return 0; - default: - return -EOPNOTSUPP; - } -} - - -static void yellowfin_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct yellowfin_private *np; - - BUG_ON(!dev); - np = netdev_priv(dev); - - dma_free_coherent(&pdev->dev, STATUS_TOTAL_SIZE, np->tx_status, - np->tx_status_dma); - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring, - np->rx_ring_dma); - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring, - np->tx_ring_dma); - unregister_netdev (dev); - - pci_iounmap(pdev, np->base); - - pci_release_regions (pdev); - - free_netdev (dev); -} - - -static struct pci_driver yellowfin_driver = { - .name = DRV_NAME, - .id_table = yellowfin_pci_tbl, - .probe = yellowfin_init_one, - .remove = yellowfin_remove_one, -}; - - -static int __init yellowfin_init (void) -{ -/* when a module, this is printed whether or not devices are found in probe */ -#ifdef MODULE - printk(version); -#endif - return pci_register_driver(&yellowfin_driver); -} - - -static void __exit yellowfin_cleanup (void) -{ - pci_unregister_driver (&yellowfin_driver); -} - - -module_init(yellowfin_init); -module_exit(yellowfin_cleanup); diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 13ce9086a9ca..66bca803b19c 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -19,21 +19,6 @@ config NET_VENDOR_SMSC if NET_VENDOR_SMSC -config SMC9194 - tristate "SMC 9194 support" - depends on ISA - select CRC32 - select NETDEV_LEGACY_INIT - help - This is support for the SMC9xxx based Ethernet cards. Choose this - option if you have a DELL laptop with the docking station, or - another SMC9192/9194 based chipset. Say Y if you want it compiled - into the kernel, and read the file - . - - To compile this driver as a module, choose M here. The module - will be called smc9194. - config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 @@ -52,18 +37,6 @@ config SMC91X The module will be called smc91x. If you want to compile it as a module, say M here and read . -config PCMCIA_SMC91C92 - tristate "SMC 91Cxx PCMCIA support" - depends on PCMCIA && HAS_IOPORT - select CRC32 - select MII - help - Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA - (PC-card) Ethernet or Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called smc91c92_cs. If unsure, say N. - config EPIC100 tristate "SMC EtherPower II" depends on PCI diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc/Makefile index 1501fa364c13..ab6f03f7ba17 100644 --- a/drivers/net/ethernet/smsc/Makefile +++ b/drivers/net/ethernet/smsc/Makefile @@ -3,9 +3,7 @@ # Makefile for the SMSC network device drivers. # -obj-$(CONFIG_SMC9194) += smc9194.o obj-$(CONFIG_SMC91X) += smc91x.o -obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SMSC9420) += smsc9420.o obj-$(CONFIG_SMSC911X) += smsc911x.o diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c deleted file mode 100644 index e2e7b1c68563..000000000000 --- a/drivers/net/ethernet/smsc/smc9194.c +++ /dev/null @@ -1,1535 +0,0 @@ -/*------------------------------------------------------------------------ - . smc9194.c - . This is a driver for SMC's 9000 series of Ethernet cards. - . - . Copyright (C) 1996 by Erik Stahlman - . This software may be used and distributed according to the terms - . of the GNU General Public License, incorporated herein by reference. - . - . "Features" of the SMC chip: - . 4608 byte packet memory. ( for the 91C92. Others have more ) - . EEPROM for configuration - . AUI/TP selection ( mine has 10Base2/10BaseT select ) - . - . Arguments: - . io = for the base address - . irq = for the IRQ - . ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 ) - . - . author: - . Erik Stahlman ( erik@vt.edu ) - . contributors: - . Arnaldo Carvalho de Melo - . - . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) - . - . Sources: - . o SMC databook - . o skeleton.c by Donald Becker ( becker@scyld.com ) - . o ( a LOT of advice from Becker as well ) - . - . History: - . 12/07/95 Erik Stahlman written, got receive/xmit handled - . 01/03/96 Erik Stahlman worked out some bugs, actually usable!!! :-) - . 01/06/96 Erik Stahlman cleaned up some, better testing, etc - . 01/29/96 Erik Stahlman fixed autoirq, added multicast - . 02/01/96 Erik Stahlman 1. disabled all interrupts in smc_reset - . 2. got rid of post-decrementing bug -- UGH. - . 02/13/96 Erik Stahlman Tried to fix autoirq failure. Added more - . descriptive error messages. - . 02/15/96 Erik Stahlman Fixed typo that caused detection failure - . 02/23/96 Erik Stahlman Modified it to fit into kernel tree - . Added support to change hardware address - . Cleared stats on opens - . 02/26/96 Erik Stahlman Trial support for Kernel 1.2.13 - . Kludge for automatic IRQ detection - . 03/04/96 Erik Stahlman Fixed kernel 1.3.70 + - . Fixed bug reported by Gardner Buchanan in - . smc_enable, with outw instead of outb - . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert - . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory - . allocation - . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet - . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" - . 11/08/01 Matt Domsch Use common crc32 function - ----------------------------------------------------------------------------*/ - -static const char version[] = - "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "smc9194.h" - -#define DRV_NAME "smc9194" - -/*------------------------------------------------------------------------ - . - . Configuration options, for the experienced user to change. - . - -------------------------------------------------------------------------*/ - -/* - . Do you want to use 32 bit xfers? This should work on all chips, as - . the chipset is designed to accommodate them. -*/ -#ifdef __sh__ -#undef USE_32_BIT -#else -#define USE_32_BIT 1 -#endif - -/* - .the SMC9194 can be at any of the following port addresses. To change, - .for a slightly different card, you can add it to the array. Keep in - .mind that the array must end in zero. -*/ - -struct devlist { - unsigned int port; - unsigned int irq; -}; - -static struct devlist smc_devlist[] __initdata = { - {.port = 0x200, .irq = 0}, - {.port = 0x220, .irq = 0}, - {.port = 0x240, .irq = 0}, - {.port = 0x260, .irq = 0}, - {.port = 0x280, .irq = 0}, - {.port = 0x2A0, .irq = 0}, - {.port = 0x2C0, .irq = 0}, - {.port = 0x2E0, .irq = 0}, - {.port = 0x300, .irq = 0}, - {.port = 0x320, .irq = 0}, - {.port = 0x340, .irq = 0}, - {.port = 0x360, .irq = 0}, - {.port = 0x380, .irq = 0}, - {.port = 0x3A0, .irq = 0}, - {.port = 0x3C0, .irq = 0}, - {.port = 0x3E0, .irq = 0}, - {.port = 0, .irq = 0}, -}; -/* - . Wait time for memory to be free. This probably shouldn't be - . tuned that much, as waiting for this means nothing else happens - . in the system -*/ -#define MEMORY_WAIT_TIME 16 - -/* - . DEBUGGING LEVELS - . - . 0 for normal operation - . 1 for slightly more details - . >2 for various levels of increasingly useless information - . 2 for interrupt tracking, status flags - . 3 for packet dumps, etc. -*/ -#define SMC_DEBUG 0 - -#if (SMC_DEBUG > 2 ) -#define PRINTK3(x) printk x -#else -#define PRINTK3(x) -#endif - -#if SMC_DEBUG > 1 -#define PRINTK2(x) printk x -#else -#define PRINTK2(x) -#endif - -#ifdef SMC_DEBUG -#define PRINTK(x) printk x -#else -#define PRINTK(x) -#endif - - -/*------------------------------------------------------------------------ - . - . The internal workings of the driver. If you are changing anything - . here with the SMC stuff, you should have the datasheet and known - . what you are doing. - . - -------------------------------------------------------------------------*/ -#define CARDNAME "SMC9194" - - -/* store this information for the driver.. */ -struct smc_local { - /* - If I have to wait until memory is available to send - a packet, I will store the skbuff here, until I get the - desired memory. Then, I'll send it out and free it. - */ - struct sk_buff * saved_skb; - - /* - . This keeps track of how many packets that I have - . sent out. When an TX_EMPTY interrupt comes, I know - . that all of these have been sent. - */ - int packets_waiting; -}; - - -/*----------------------------------------------------------------- - . - . The driver can be entered at any of the following entry points. - . - .------------------------------------------------------------------ */ - -/* - . This is called by register_netdev(). It is responsible for - . checking the portlist for the SMC9000 series chipset. If it finds - . one, then it will initialize the device, find the hardware information, - . and sets up the appropriate device parameters. - . NOTE: Interrupts are *OFF* when this procedure is called. - . - . NB:This shouldn't be static since it is referred to externally. -*/ -struct net_device *smc_init(int unit); - -/* - . The kernel calls this function when someone wants to use the device, - . typically 'ifconfig ethX up'. -*/ -static int smc_open(struct net_device *dev); - -/* - . Our watchdog timed out. Called by the networking layer -*/ -static void smc_timeout(struct net_device *dev, unsigned int txqueue); - -/* - . This is called by the kernel in response to 'ifconfig ethX down'. It - . is responsible for cleaning up everything that the open routine - . does, and maybe putting the card into a powerdown state. -*/ -static int smc_close(struct net_device *dev); - -/* - . Finally, a call to set promiscuous mode ( for TCPDUMP and related - . programs ) and multicast modes. -*/ -static void smc_set_multicast_list(struct net_device *dev); - - -/*--------------------------------------------------------------- - . - . Interrupt level calls.. - . - ----------------------------------------------------------------*/ - -/* - . Handles the actual interrupt -*/ -static irqreturn_t smc_interrupt(int irq, void *); -/* - . This is a separate procedure to handle the receipt of a packet, to - . leave the interrupt code looking slightly cleaner -*/ -static inline void smc_rcv( struct net_device *dev ); -/* - . This handles a TX interrupt, which is only called when an error - . relating to a packet is sent. -*/ -static inline void smc_tx( struct net_device * dev ); - -/* - ------------------------------------------------------------ - . - . Internal routines - . - ------------------------------------------------------------ -*/ - -/* - . Test if a given location contains a chip, trying to cause as - . little damage as possible if it's not a SMC chip. -*/ -static int smc_probe(struct net_device *dev, int ioaddr); - -/* - . A rather simple routine to print out a packet for debugging purposes. -*/ -#if SMC_DEBUG > 2 -static void print_packet( byte *, int ); -#endif - -#define tx_done(dev) 1 - -/* this is called to actually send the packet to the chip */ -static void smc_hardware_send_packet( struct net_device * dev ); - -/* Since I am not sure if I will have enough room in the chip's ram - . to store the packet, I call this routine, which either sends it - . now, or generates an interrupt when the card is ready for the - . packet */ -static netdev_tx_t smc_wait_to_send_packet( struct sk_buff * skb, - struct net_device *dev ); - -/* this does a soft reset on the device */ -static void smc_reset( int ioaddr ); - -/* Enable Interrupts, Receive, and Transmit */ -static void smc_enable( int ioaddr ); - -/* this puts the device in an inactive state */ -static void smc_shutdown( int ioaddr ); - -/* This routine will find the IRQ of the driver if one is not - . specified in the input to the device. */ -static int smc_findirq( int ioaddr ); - -/* - . Function: smc_reset( int ioaddr ) - . Purpose: - . This sets the SMC91xx chip to its normal state, hopefully from whatever - . mess that any other DOS driver has put it in. - . - . Maybe I should reset more registers to defaults in here? SOFTRESET should - . do that for me. - . - . Method: - . 1. send a SOFT RESET - . 2. wait for it to finish - . 3. enable autorelease mode - . 4. reset the memory management unit - . 5. clear all interrupts - . -*/ -static void smc_reset( int ioaddr ) -{ - /* This resets the registers mostly to defaults, but doesn't - affect EEPROM. That seems unnecessary */ - SMC_SELECT_BANK( 0 ); - outw( RCR_SOFTRESET, ioaddr + RCR ); - - /* this should pause enough for the chip to be happy */ - SMC_DELAY( ); - - /* Set the transmit and receive configuration registers to - default values */ - outw( RCR_CLEAR, ioaddr + RCR ); - outw( TCR_CLEAR, ioaddr + TCR ); - - /* set the control register to automatically - release successfully transmitted packets, to make the best - use out of our limited memory */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); - - /* Reset the MMU */ - SMC_SELECT_BANK( 2 ); - outw( MC_RESET, ioaddr + MMU_CMD ); - - /* Note: It doesn't seem that waiting for the MMU busy is needed here, - but this is a place where future chipsets _COULD_ break. Be wary - of issuing another MMU command right after this */ - - outb( 0, ioaddr + INT_MASK ); -} - -/* - . Function: smc_enable - . Purpose: let the chip talk to the outside work - . Method: - . 1. Enable the transmitter - . 2. Enable the receiver - . 3. Enable interrupts -*/ -static void smc_enable( int ioaddr ) -{ - SMC_SELECT_BANK( 0 ); - /* see the header file for options in TCR/RCR NORMAL*/ - outw( TCR_NORMAL, ioaddr + TCR ); - outw( RCR_NORMAL, ioaddr + RCR ); - - /* now, enable interrupts */ - SMC_SELECT_BANK( 2 ); - outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK ); -} - -/* - . Function: smc_shutdown - . Purpose: closes down the SMC91xxx chip. - . Method: - . 1. zero the interrupt mask - . 2. clear the enable receive flag - . 3. clear the enable xmit flags - . - . TODO: - . (1) maybe utilize power down mode. - . Why not yet? Because while the chip will go into power down mode, - . the manual says that it will wake up in response to any I/O requests - . in the register space. Empirical results do not show this working. -*/ -static void smc_shutdown( int ioaddr ) -{ - /* no more interrupts for me */ - SMC_SELECT_BANK( 2 ); - outb( 0, ioaddr + INT_MASK ); - - /* and tell the card to stay away from that nasty outside world */ - SMC_SELECT_BANK( 0 ); - outb( RCR_CLEAR, ioaddr + RCR ); - outb( TCR_CLEAR, ioaddr + TCR ); -#if 0 - /* finally, shut the chip down */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL ); -#endif -} - - -/* - . Function: smc_setmulticast( int ioaddr, struct net_device *dev ) - . Purpose: - . This sets the internal hardware table to filter out unwanted multicast - . packets before they take up memory. - . - . The SMC chip uses a hash table where the high 6 bits of the CRC of - . address are the offset into the table. If that bit is 1, then the - . multicast packet is accepted. Otherwise, it's dropped silently. - . - . To use the 6 bits as an offset into the table, the high 3 bits are the - . number of the 8 bit register, while the low 3 bits are the bit within - . that register. - . - . This routine is based very heavily on the one provided by Peter Cammaert. -*/ - - -static void smc_setmulticast(int ioaddr, struct net_device *dev) -{ - int i; - unsigned char multicast_table[ 8 ]; - struct netdev_hw_addr *ha; - /* table for flipping the order of 3 bits */ - unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; - - /* start with a table of all zeros: reject all */ - memset( multicast_table, 0, sizeof( multicast_table ) ); - - netdev_for_each_mc_addr(ha, dev) { - int position; - - /* only use the low order bits */ - position = ether_crc_le(6, ha->addr) & 0x3f; - - /* do some messy swapping to put the bit in the right spot */ - multicast_table[invert3[position&7]] |= - (1<>3)&7]); - - } - /* now, the table can be loaded into the chipset */ - SMC_SELECT_BANK( 3 ); - - for ( i = 0; i < 8 ; i++ ) { - outb( multicast_table[i], ioaddr + MULTICAST1 + i ); - } -} - -/* - . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) - . Purpose: - . Attempt to allocate memory for a packet, if chip-memory is not - . available, then tell the card to generate an interrupt when it - . is available. - . - . Algorithm: - . - . o if the saved_skb is not currently null, then drop this packet - . on the floor. This should never happen, because of TBUSY. - . o if the saved_skb is null, then replace it with the current packet, - . o See if I can sending it now. - . o (NO): Enable interrupts and let the interrupt handler deal with it. - . o (YES):Send it now. -*/ -static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - word length; - unsigned short numPages; - word time_out; - - netif_stop_queue(dev); - /* Well, I want to send the packet.. but I don't know - if I can send it right now... */ - - if ( lp->saved_skb) { - /* THIS SHOULD NEVER HAPPEN. */ - dev->stats.tx_aborted_errors++; - printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); - return NETDEV_TX_BUSY; - } - lp->saved_skb = skb; - - length = skb->len; - - if (length < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) { - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - length = ETH_ZLEN; - } - - /* - ** The MMU wants the number of pages to be the number of 256 bytes - ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) - ** - ** Pkt size for allocating is data length +6 (for additional status words, - ** length and ctl!) If odd size last byte is included in this header. - */ - numPages = ((length & 0xfffe) + 6) / 256; - - if (numPages > 7 ) { - printk(CARDNAME": Far too big packet error.\n"); - /* freeing the packet is a good thing here... but should - . any packets of this size get down here? */ - dev_kfree_skb (skb); - lp->saved_skb = NULL; - /* this IS an error, but, i don't want the skb saved */ - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - /* either way, a packet is waiting now */ - lp->packets_waiting++; - - /* now, try to allocate the memory */ - SMC_SELECT_BANK( 2 ); - outw( MC_ALLOC | numPages, ioaddr + MMU_CMD ); - /* - . Performance Hack - . - . wait a short amount of time.. if I can send a packet now, I send - . it now. Otherwise, I enable an interrupt and wait for one to be - . available. - . - . I could have handled this a slightly different way, by checking to - . see if any memory was available in the FREE MEMORY register. However, - . either way, I need to generate an allocation, and the allocation works - . no matter what, so I saw no point in checking free memory. - */ - time_out = MEMORY_WAIT_TIME; - do { - word status; - - status = inb( ioaddr + INTERRUPT ); - if ( status & IM_ALLOC_INT ) { - /* acknowledge the interrupt */ - outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); - break; - } - } while ( -- time_out ); - - if ( !time_out ) { - /* oh well, wait until the chip finds memory later */ - SMC_ENABLE_INT( IM_ALLOC_INT ); - PRINTK2((CARDNAME": memory allocation deferred.\n")); - /* it's deferred, but I'll handle it later */ - return NETDEV_TX_OK; - } - /* or YES! I can send the packet now.. */ - smc_hardware_send_packet(dev); - netif_wake_queue(dev); - return NETDEV_TX_OK; -} - -/* - . Function: smc_hardware_send_packet(struct net_device * ) - . Purpose: - . This sends the actual packet to the SMC9xxx chip. - . - . Algorithm: - . First, see if a saved_skb is available. - . ( this should NOT be called if there is no 'saved_skb' - . Now, find the packet number that the chip allocated - . Point the data pointers at it in memory - . Set the length word in the chip's memory - . Dump the packet to chip memory - . Check if a last byte is needed ( odd length packet ) - . if so, set the control flag right - . Tell the card to send it - . Enable the transmit interrupt, so I know if it failed - . Free the kernel data if I actually sent it. -*/ -static void smc_hardware_send_packet( struct net_device * dev ) -{ - struct smc_local *lp = netdev_priv(dev); - byte packet_no; - struct sk_buff * skb = lp->saved_skb; - word length; - unsigned int ioaddr; - byte * buf; - - ioaddr = dev->base_addr; - - if ( !skb ) { - PRINTK((CARDNAME": In XMIT with no packet to send\n")); - return; - } - length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buf = skb->data; - - /* If I get here, I _know_ there is a packet slot waiting for me */ - packet_no = inb( ioaddr + PNR_ARR + 1 ); - if ( packet_no & 0x80 ) { - /* or isn't there? BAD CHIP! */ - netdev_dbg(dev, CARDNAME": Memory allocation failed.\n"); - dev_kfree_skb_any(skb); - lp->saved_skb = NULL; - netif_wake_queue(dev); - return; - } - - /* we have a packet address, so tell the card to use it */ - outb( packet_no, ioaddr + PNR_ARR ); - - /* point to the beginning of the packet */ - outw( PTR_AUTOINC , ioaddr + POINTER ); - - PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length)); -#if SMC_DEBUG > 2 - print_packet( buf, length ); -#endif - - /* send the packet length ( +6 for status, length and ctl byte ) - and the status word ( set to zeros ) */ -#ifdef USE_32_BIT - outl( (length +6 ) << 16 , ioaddr + DATA_1 ); -#else - outw( 0, ioaddr + DATA_1 ); - /* send the packet length ( +6 for status words, length, and ctl*/ - outb( (length+6) & 0xFF,ioaddr + DATA_1 ); - outb( (length+6) >> 8 , ioaddr + DATA_1 ); -#endif - - /* send the actual data - . I _think_ it's faster to send the longs first, and then - . mop up by sending the last word. It depends heavily - . on alignment, at least on the 486. Maybe it would be - . a good idea to check which is optimal? But that could take - . almost as much time as is saved? - */ -#ifdef USE_32_BIT - if ( length & 0x2 ) { - outsl(ioaddr + DATA_1, buf, length >> 2 ); - outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); - } - else - outsl(ioaddr + DATA_1, buf, length >> 2 ); -#else - outsw(ioaddr + DATA_1 , buf, (length ) >> 1); -#endif - /* Send the last byte, if there is one. */ - - if ( (length & 1) == 0 ) { - outw( 0, ioaddr + DATA_1 ); - } else { - outb( buf[length -1 ], ioaddr + DATA_1 ); - outb( 0x20, ioaddr + DATA_1); - } - - /* enable the interrupts */ - SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); - - /* and let the chipset deal with it */ - outw( MC_ENQUEUE , ioaddr + MMU_CMD ); - - PRINTK2((CARDNAME": Sent packet of length %d\n", length)); - - lp->saved_skb = NULL; - dev_kfree_skb_any (skb); - - netif_trans_update(dev); - - /* we can send another packet */ - netif_wake_queue(dev); -} - -/*------------------------------------------------------------------------- - | - | smc_init(int unit) - | Input parameters: - | dev->base_addr == 0, try to find all possible locations - | dev->base_addr == 1, return failure code - | dev->base_addr == 2, always allocate space, and return success - | dev->base_addr == this is the address to check - | - | Output: - | pointer to net_device or ERR_PTR(error) - | - --------------------------------------------------------------------------- -*/ -static int io; -static int irq; -static int ifport; - -struct net_device * __init smc_init(int unit) -{ - struct net_device *dev = alloc_etherdev(sizeof(struct smc_local)); - struct devlist *smcdev = smc_devlist; - int err = 0; - - if (!dev) - return ERR_PTR(-ENODEV); - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - io = dev->base_addr; - irq = dev->irq; - } - - if (io > 0x1ff) { /* Check a single specified location. */ - err = smc_probe(dev, io); - } else if (io != 0) { /* Don't probe at all. */ - err = -ENXIO; - } else { - for (;smcdev->port; smcdev++) { - if (smc_probe(dev, smcdev->port) == 0) - break; - } - if (!smcdev->port) - err = -ENODEV; - } - if (err) - goto out; - err = register_netdev(dev); - if (err) - goto out1; - return dev; -out1: - free_irq(dev->irq, dev); - release_region(dev->base_addr, SMC_IO_EXTENT); -out: - free_netdev(dev); - return ERR_PTR(err); -} - -/*---------------------------------------------------------------------- - . smc_findirq - . - . This routine has a simple purpose -- make the SMC chip generate an - . interrupt, so an auto-detect routine can detect it, and find the IRQ, - ------------------------------------------------------------------------ -*/ -static int __init smc_findirq(int ioaddr) -{ -#ifndef NO_AUTOPROBE - int timeout = 20; - unsigned long cookie; - - - cookie = probe_irq_on(); - - /* - * What I try to do here is trigger an ALLOC_INT. This is done - * by allocating a small chunk of memory, which will give an interrupt - * when done. - */ - - - SMC_SELECT_BANK(2); - /* enable ALLOCation interrupts ONLY */ - outb( IM_ALLOC_INT, ioaddr + INT_MASK ); - - /* - . Allocate 512 bytes of memory. Note that the chip was just - . reset so all the memory is available - */ - outw( MC_ALLOC | 1, ioaddr + MMU_CMD ); - - /* - . Wait until positive that the interrupt has been generated - */ - while ( timeout ) { - byte int_status; - - int_status = inb( ioaddr + INTERRUPT ); - - if ( int_status & IM_ALLOC_INT ) - break; /* got the interrupt */ - timeout--; - } - /* there is really nothing that I can do here if timeout fails, - as probe_irq_off will return a 0 anyway, which is what I - want in this case. Plus, the clean up is needed in both - cases. */ - - /* DELAY HERE! - On a fast machine, the status might change before the interrupt - is given to the processor. This means that the interrupt was - never detected, and probe_irq_off fails to report anything. - This should fix probe_irq_* problems. - */ - SMC_DELAY(); - SMC_DELAY(); - - /* and disable all interrupts again */ - outb( 0, ioaddr + INT_MASK ); - - /* and return what I found */ - return probe_irq_off(cookie); -#else /* NO_AUTOPROBE */ - struct devlist *smcdev; - for (smcdev = smc_devlist; smcdev->port; smcdev++) { - if (smcdev->port == ioaddr) - return smcdev->irq; - } - return 0; -#endif -} - -static const struct net_device_ops smc_netdev_ops = { - .ndo_open = smc_open, - .ndo_stop = smc_close, - .ndo_start_xmit = smc_wait_to_send_packet, - .ndo_tx_timeout = smc_timeout, - .ndo_set_rx_mode = smc_set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/*---------------------------------------------------------------------- - . Function: smc_probe( int ioaddr ) - . - . Purpose: - . Tests to see if a given ioaddr points to an SMC9xxx chip. - . Returns a 0 on success - . - . Algorithm: - . (1) see if the high byte of BANK_SELECT is 0x33 - . (2) compare the ioaddr with the base register's address - . (3) see if I recognize the chip ID in the appropriate register - . - .--------------------------------------------------------------------- - */ - -/*--------------------------------------------------------------- - . Here I do typical initialization tasks. - . - . o Initialize the structure if needed - . o print out my vanity message if not done so already - . o print out what type of hardware is detected - . o print out the ethernet address - . o find the IRQ - . o set up my private data - . o configure the dev structure with my subroutines - . o actually GRAB the irq. - . o GRAB the region - .----------------------------------------------------------------- -*/ -static int __init smc_probe(struct net_device *dev, int ioaddr) -{ - int i, memory, retval; - unsigned int bank; - - const char *version_string; - const char *if_string; - - /* registers */ - word revision_register; - word base_address_register; - word configuration_register; - word memory_info_register; - word memory_cfg_register; - u8 addr[ETH_ALEN]; - - /* Grab the region so that no one else tries to probe our ioports. */ - if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) - return -EBUSY; - - dev->irq = irq; - dev->if_port = ifport; - - /* First, see if the high byte is 0x33 */ - bank = inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00) != 0x3300 ) { - retval = -ENODEV; - goto err_out; - } - /* The above MIGHT indicate a device, but I need to write to further - test this. */ - outw( 0x0, ioaddr + BANK_SELECT ); - bank = inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00 ) != 0x3300 ) { - retval = -ENODEV; - goto err_out; - } - /* well, we've already written once, so hopefully another time won't - hurt. This time, I need to switch the bank register to bank 1, - so I can access the base address register */ - SMC_SELECT_BANK(1); - base_address_register = inw( ioaddr + BASE ); - if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) { - printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). " - "Probably not a SMC chip\n", - ioaddr, base_address_register >> 3 & 0x3E0 ); - /* well, the base address register didn't match. Must not have - been a SMC chip after all. */ - retval = -ENODEV; - goto err_out; - } - - /* check if the revision register is something that I recognize. - These might need to be added to later, as future revisions - could be added. */ - SMC_SELECT_BANK(3); - revision_register = inw( ioaddr + REVISION ); - if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { - /* I don't recognize this chip, so... */ - printk(CARDNAME ": IO %x: Unrecognized revision register:" - " %x, Contact author.\n", ioaddr, revision_register); - - retval = -ENODEV; - goto err_out; - } - - /* at this point I'll assume that the chip is an SMC9xxx. - It might be prudent to check a listing of MAC addresses - against the hardware address, or do some other tests. */ - - pr_info_once("%s\n", version); - - /* fill in some of the fields */ - dev->base_addr = ioaddr; - - /* - . Get the MAC address ( bank 1, regs 4 - 9 ) - */ - SMC_SELECT_BANK( 1 ); - for ( i = 0; i < 6; i += 2 ) { - word address; - - address = inw( ioaddr + ADDR0 + i ); - addr[i + 1] = address >> 8; - addr[i] = address & 0xFF; - } - eth_hw_addr_set(dev, addr); - - /* get the memory information */ - - SMC_SELECT_BANK( 0 ); - memory_info_register = inw( ioaddr + MIR ); - memory_cfg_register = inw( ioaddr + MCR ); - memory = ( memory_cfg_register >> 9 ) & 0x7; /* multiplier */ - memory *= 256 * ( memory_info_register & 0xFF ); - - /* - Now, I want to find out more about the chip. This is sort of - redundant, but it's cleaner to have it in both, rather than having - one VERY long probe procedure. - */ - SMC_SELECT_BANK(3); - revision_register = inw( ioaddr + REVISION ); - version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ]; - if ( !version_string ) { - /* I shouldn't get here because this call was done before.... */ - retval = -ENODEV; - goto err_out; - } - - /* is it using AUI or 10BaseT ? */ - if ( dev->if_port == 0 ) { - SMC_SELECT_BANK(1); - configuration_register = inw( ioaddr + CONFIG ); - if ( configuration_register & CFG_AUI_SELECT ) - dev->if_port = 2; - else - dev->if_port = 1; - } - if_string = interfaces[ dev->if_port - 1 ]; - - /* now, reset the chip, and put it into a known state */ - smc_reset( ioaddr ); - - /* - . If dev->irq is 0, then the device has to be banged on to see - . what the IRQ is. - . - . This banging doesn't always detect the IRQ, for unknown reasons. - . a workaround is to reset the chip and try again. - . - . Interestingly, the DOS packet driver *SETS* the IRQ on the card to - . be what is requested on the command line. I don't do that, mostly - . because the card that I have uses a non-standard method of accessing - . the IRQs, and because this _should_ work in most configurations. - . - . Specifying an IRQ is done with the assumption that the user knows - . what (s)he is doing. No checking is done!!!! - . - */ - if ( dev->irq < 2 ) { - int trials; - - trials = 3; - while ( trials-- ) { - dev->irq = smc_findirq( ioaddr ); - if ( dev->irq ) - break; - /* kick the card and try again */ - smc_reset( ioaddr ); - } - } - if (dev->irq == 0 ) { - printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n"); - retval = -ENODEV; - goto err_out; - } - - /* now, print out the card info, in a short format.. */ - - netdev_info(dev, "%s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", - version_string, revision_register & 0xF, ioaddr, dev->irq, - if_string, memory); - /* - . Print the Ethernet address - */ - netdev_info(dev, "ADDR: %pM\n", dev->dev_addr); - - /* Grab the IRQ */ - retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev); - if (retval) { - netdev_warn(dev, "%s: unable to get IRQ %d (irqval=%d).\n", - DRV_NAME, dev->irq, retval); - goto err_out; - } - - dev->netdev_ops = &smc_netdev_ops; - dev->watchdog_timeo = HZ/20; - - return 0; - -err_out: - release_region(ioaddr, SMC_IO_EXTENT); - return retval; -} - -#if SMC_DEBUG > 2 -static void print_packet( byte * buf, int length ) -{ -#if 0 - print_hex_dump_debug(DRV_NAME, DUMP_PREFIX_OFFSET, 16, 1, - buf, length, true); -#endif -} -#endif - - -/* - * Open and Initialize the board - * - * Set up everything, reset the card, etc .. - * - */ -static int smc_open(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - - int i; /* used to set hw ethernet address */ - - /* clear out all the junk that was put here before... */ - memset(netdev_priv(dev), 0, sizeof(struct smc_local)); - - /* reset the hardware */ - - smc_reset( ioaddr ); - smc_enable( ioaddr ); - - /* Select which interface to use */ - - SMC_SELECT_BANK( 1 ); - if ( dev->if_port == 1 ) { - outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT, - ioaddr + CONFIG ); - } - else if ( dev->if_port == 2 ) { - outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT, - ioaddr + CONFIG ); - } - - /* - According to Becker, I have to set the hardware address - at this point, because the (l)user can set it with an - ioctl. Easily done... - */ - SMC_SELECT_BANK( 1 ); - for ( i = 0; i < 6; i += 2 ) { - word address; - - address = dev->dev_addr[ i + 1 ] << 8 ; - address |= dev->dev_addr[ i ]; - outw( address, ioaddr + ADDR0 + i ); - } - - netif_start_queue(dev); - return 0; -} - -/*-------------------------------------------------------- - . Called by the kernel to send a packet out into the void - . of the net. This routine is largely based on - . skeleton.c, from Becker. - .-------------------------------------------------------- -*/ - -static void smc_timeout(struct net_device *dev, unsigned int txqueue) -{ - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - netdev_warn(dev, CARDNAME": transmit timed out, %s?\n", - tx_done(dev) ? "IRQ conflict" : "network cable problem"); - /* "kick" the adaptor */ - smc_reset( dev->base_addr ); - smc_enable( dev->base_addr ); - netif_trans_update(dev); /* prevent tx timeout */ - /* clear anything saved */ - ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL; - netif_wake_queue(dev); -} - -/*------------------------------------------------------------- - . - . smc_rcv - receive a packet from the card - . - . There is ( at least ) a packet waiting to be read from - . chip-memory. - . - . o Read the status - . o If an error, record it - . o otherwise, read in the packet - -------------------------------------------------------------- -*/ -static void smc_rcv(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - int packet_number; - word status; - word packet_length; - - /* assume bank 2 */ - - packet_number = inw( ioaddr + FIFO_PORTS ); - - if ( packet_number & FP_RXEMPTY ) { - /* we got called , but nothing was on the FIFO */ - PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO.\n")); - /* don't need to restore anything */ - return; - } - - /* start reading from the start of the packet */ - outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER ); - - /* First two words are status and packet_length */ - status = inw( ioaddr + DATA_1 ); - packet_length = inw( ioaddr + DATA_1 ); - - packet_length &= 0x07ff; /* mask off top bits */ - - PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length )); - /* - . the packet length contains 3 extra words : - . status, length, and an extra word with an odd byte . - */ - packet_length -= 6; - - if ( !(status & RS_ERRORS ) ){ - /* do stuff to make a new packet */ - struct sk_buff * skb; - byte * data; - - /* read one extra byte */ - if ( status & RS_ODDFRAME ) - packet_length++; - - /* set multicast stats */ - if ( status & RS_MULTICAST ) - dev->stats.multicast++; - - skb = netdev_alloc_skb(dev, packet_length + 5); - if ( skb == NULL ) { - dev->stats.rx_dropped++; - goto done; - } - - /* - ! This should work without alignment, but it could be - ! in the worse case - */ - - skb_reserve( skb, 2 ); /* 16 bit alignment */ - - data = skb_put( skb, packet_length); - -#ifdef USE_32_BIT - /* QUESTION: Like in the TX routine, do I want - to send the DWORDs or the bytes first, or some - mixture. A mixture might improve already slow PIO - performance */ - PRINTK3((" Reading %d dwords (and %d bytes)\n", - packet_length >> 2, packet_length & 3 )); - insl(ioaddr + DATA_1 , data, packet_length >> 2 ); - /* read the left over bytes */ - insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC), - packet_length & 0x3 ); -#else - PRINTK3((" Reading %d words and %d byte(s)\n", - (packet_length >> 1 ), packet_length & 1 )); - insw(ioaddr + DATA_1 , data, packet_length >> 1); - if ( packet_length & 1 ) { - data += packet_length & ~1; - *(data++) = inb( ioaddr + DATA_1 ); - } -#endif -#if SMC_DEBUG > 2 - print_packet( data, packet_length ); -#endif - - skb->protocol = eth_type_trans(skb, dev ); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += packet_length; - } else { - /* error ... */ - dev->stats.rx_errors++; - - if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++; - if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) - dev->stats.rx_length_errors++; - if ( status & RS_BADCRC) dev->stats.rx_crc_errors++; - } - -done: - /* error or good, tell the card to get rid of this packet */ - outw( MC_RELEASE, ioaddr + MMU_CMD ); -} - - -/************************************************************************* - . smc_tx - . - . Purpose: Handle a transmit error message. This will only be called - . when an error, because of the AUTO_RELEASE mode. - . - . Algorithm: - . Save pointer and packet no - . Get the packet no from the top of the queue - . check if it's valid ( if not, is this an error??? ) - . read the status word - . record the error - . ( resend? Not really, since we don't want old packets around ) - . Restore saved values - ************************************************************************/ -static void smc_tx( struct net_device * dev ) -{ - int ioaddr = dev->base_addr; - struct smc_local *lp = netdev_priv(dev); - byte saved_packet; - byte packet_no; - word tx_status; - - - /* assume bank 2 */ - - saved_packet = inb( ioaddr + PNR_ARR ); - packet_no = inw( ioaddr + FIFO_PORTS ); - packet_no &= 0x7F; - - /* select this as the packet to read from */ - outb( packet_no, ioaddr + PNR_ARR ); - - /* read the first word from this packet */ - outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER ); - - tx_status = inw( ioaddr + DATA_1 ); - PRINTK3((CARDNAME": TX DONE STATUS: %4x\n", tx_status)); - - dev->stats.tx_errors++; - if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++; - if ( tx_status & TS_LATCOL ) { - netdev_dbg(dev, CARDNAME": Late collision occurred on last xmit.\n"); - dev->stats.tx_window_errors++; - } -#if 0 - if ( tx_status & TS_16COL ) { ... } -#endif - - if ( tx_status & TS_SUCCESS ) { - netdev_info(dev, CARDNAME": Successful packet caused interrupt\n"); - } - /* re-enable transmit */ - SMC_SELECT_BANK( 0 ); - outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR ); - - /* kill the packet */ - SMC_SELECT_BANK( 2 ); - outw( MC_FREEPKT, ioaddr + MMU_CMD ); - - /* one less packet waiting for me */ - lp->packets_waiting--; - - outb( saved_packet, ioaddr + PNR_ARR ); -} - -/*-------------------------------------------------------------------- - . - . This is the main routine of the driver, to handle the device when - . it needs some attention. - . - . So: - . first, save state of the chipset - . branch off into routines to handle each case, and acknowledge - . each to the interrupt register - . and finally restore state. - . - ---------------------------------------------------------------------*/ - -static irqreturn_t smc_interrupt(int irq, void * dev_id) -{ - struct net_device *dev = dev_id; - int ioaddr = dev->base_addr; - struct smc_local *lp = netdev_priv(dev); - - byte status; - word card_stats; - byte mask; - int timeout; - /* state registers */ - word saved_bank; - word saved_pointer; - int handled = 0; - - - PRINTK3((CARDNAME": SMC interrupt started\n")); - - saved_bank = inw( ioaddr + BANK_SELECT ); - - SMC_SELECT_BANK(2); - saved_pointer = inw( ioaddr + POINTER ); - - mask = inb( ioaddr + INT_MASK ); - /* clear all interrupts */ - outb( 0, ioaddr + INT_MASK ); - - - /* set a timeout value, so I don't stay here forever */ - timeout = 4; - - PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x\n", mask)); - do { - /* read the status flag, and mask it */ - status = inb( ioaddr + INTERRUPT ) & mask; - if (!status ) - break; - - handled = 1; - - PRINTK3((KERN_WARNING CARDNAME - ": Handling interrupt status %x\n", status)); - - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - PRINTK2((KERN_WARNING CARDNAME - ": Receive Interrupt\n")); - smc_rcv(dev); - } else if (status & IM_TX_INT ) { - PRINTK2((KERN_WARNING CARDNAME - ": TX ERROR handled\n")); - smc_tx(dev); - outb(IM_TX_INT, ioaddr + INTERRUPT ); - } else if (status & IM_TX_EMPTY_INT ) { - /* update stats */ - SMC_SELECT_BANK( 0 ); - card_stats = inw( ioaddr + COUNTER ); - /* single collisions */ - dev->stats.collisions += card_stats & 0xF; - card_stats >>= 4; - /* multiple collisions */ - dev->stats.collisions += card_stats & 0xF; - - /* these are for when linux supports these statistics */ - - SMC_SELECT_BANK( 2 ); - PRINTK2((KERN_WARNING CARDNAME - ": TX_BUFFER_EMPTY handled\n")); - outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); - mask &= ~IM_TX_EMPTY_INT; - dev->stats.tx_packets += lp->packets_waiting; - lp->packets_waiting = 0; - - } else if (status & IM_ALLOC_INT ) { - PRINTK2((KERN_DEBUG CARDNAME - ": Allocation interrupt\n")); - /* clear this interrupt so it doesn't happen again */ - mask &= ~IM_ALLOC_INT; - - smc_hardware_send_packet( dev ); - - /* enable xmit interrupts based on this */ - mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - - PRINTK2((CARDNAME": Handoff done successfully.\n")); - } else if (status & IM_RX_OVRN_INT ) { - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); - } else if (status & IM_EPH_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT\n")); - } else if (status & IM_ERCV_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT\n")); - outb( IM_ERCV_INT, ioaddr + INTERRUPT ); - } - } while ( timeout -- ); - - - /* restore state register */ - SMC_SELECT_BANK( 2 ); - outb( mask, ioaddr + INT_MASK ); - - PRINTK3((KERN_WARNING CARDNAME ": MASK is now %x\n", mask)); - outw( saved_pointer, ioaddr + POINTER ); - - SMC_SELECT_BANK( saved_bank ); - - PRINTK3((CARDNAME ": Interrupt done\n")); - return IRQ_RETVAL(handled); -} - - -/*---------------------------------------------------- - . smc_close - . - . this makes the board clean up everything that it can - . and not talk to the outside world. Caused by - . an 'ifconfig ethX down' - . - -----------------------------------------------------*/ -static int smc_close(struct net_device *dev) -{ - netif_stop_queue(dev); - /* clear everything */ - smc_shutdown( dev->base_addr ); - - /* Update the statistics here. */ - return 0; -} - -/*----------------------------------------------------------- - . smc_set_multicast_list - . - . This routine will, depending on the values passed to it, - . either make it accept multicast packets, go into - . promiscuous mode ( for TCPDUMP and cousins ) or accept - . a select set of multicast packets -*/ -static void smc_set_multicast_list(struct net_device *dev) -{ - short ioaddr = dev->base_addr; - - SMC_SELECT_BANK(0); - if ( dev->flags & IFF_PROMISC ) - outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR ); - -/* BUG? I never disable promiscuous mode if multicasting was turned on. - Now, I turn off promiscuous mode, but I don't do anything to multicasting - when promiscuous mode is turned on. -*/ - - /* Here, I am setting this to accept all multicast packets. - I don't need to zero the multicast table, because the flag is - checked before the table is - */ - else if (dev->flags & IFF_ALLMULTI) - outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR ); - - /* We just get all multicast packets even if we only want them - . from one source. This will be changed at some future - . point. */ - else if (!netdev_mc_empty(dev)) { - /* support hardware multicasting */ - - /* be sure I get rid of flags I might have set */ - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); - /* NOTE: this has to set the bank, so make sure it is the - last thing called. The bank is set to zero at the top */ - smc_setmulticast(ioaddr, dev); - } - else { - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); - - /* - since I'm disabling all multicast entirely, I need to - clear the multicast list - */ - SMC_SELECT_BANK( 3 ); - outw( 0, ioaddr + MULTICAST1 ); - outw( 0, ioaddr + MULTICAST2 ); - outw( 0, ioaddr + MULTICAST3 ); - outw( 0, ioaddr + MULTICAST4 ); - } -} - -#ifdef MODULE - -static struct net_device *devSMC9194; -MODULE_DESCRIPTION("SMC 9194 Ethernet driver"); -MODULE_LICENSE("GPL"); - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param(ifport, int, 0); -MODULE_PARM_DESC(io, "SMC 99194 I/O base address"); -MODULE_PARM_DESC(irq, "SMC 99194 IRQ number"); -MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)"); - -static int __init smc_init_module(void) -{ - if (io == 0) - printk(KERN_WARNING - CARDNAME": You shouldn't use auto-probing with insmod!\n" ); - - /* copy the parameters from insmod into the device structure */ - devSMC9194 = smc_init(-1); - return PTR_ERR_OR_ZERO(devSMC9194); -} -module_init(smc_init_module); - -static void __exit smc_cleanup_module(void) -{ - unregister_netdev(devSMC9194); - free_irq(devSMC9194->irq, devSMC9194); - release_region(devSMC9194->base_addr, SMC_IO_EXTENT); - free_netdev(devSMC9194); -} -module_exit(smc_cleanup_module); - -#endif /* MODULE */ diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c deleted file mode 100644 index cc0c75694351..000000000000 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ /dev/null @@ -1,2059 +0,0 @@ -/*====================================================================== - - A PCMCIA ethernet driver for SMC91c92-based cards. - - This driver supports Megahertz PCMCIA ethernet cards; and - Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem - multifunction cards. - - Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - - smc91c92_cs.c 1.122 2002/10/25 06:26:39 - - This driver contains code written by Donald Becker - (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au), - David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman - (erik@vt.edu). Donald wrote the SMC 91c92 code using parts of - Erik's SMC 91c94 driver. Rowan wrote a similar driver, and I've - incorporated some parts of his driver here. I (Dave) wrote most - of the PCMCIA glue code, and the Ositech support code. Kelly - Stephens (kstephen@holli.com) added support for the Motorola - Mariner, with help from Allen Brost. - - This software may be used and distributed according to the terms of - the GNU General Public License, incorporated herein by reference. - -======================================================================*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -/*====================================================================*/ - -static const char *if_names[] = { "auto", "10baseT", "10base2"}; - -/* Firmware name */ -#define FIRMWARE_NAME "ositech/Xilinx7OD.bin" - -/* Module parameters */ - -MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FIRMWARE_NAME); - -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -/* - Transceiver/media type. - 0 = auto - 1 = 10baseT (and autoselect if #define AUTOSELECT), - 2 = AUI/10base2, -*/ -INT_MODULE_PARM(if_port, 0); - - -#define DRV_NAME "smc91c92_cs" -#define DRV_VERSION "1.123" - -/*====================================================================*/ - -/* Operational parameter that usually are not changed. */ - -/* Time in jiffies before concluding Tx hung */ -#define TX_TIMEOUT ((400*HZ)/1000) - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -#define INTR_WORK 4 - -/* Times to check the check the chip before concluding that it doesn't - currently have room for another Tx packet. */ -#define MEMORY_WAIT_TIME 8 - -struct smc_private { - struct pcmcia_device *p_dev; - spinlock_t lock; - u_short manfid; - u_short cardid; - - struct sk_buff *saved_skb; - int packets_waiting; - void __iomem *base; - u_short cfg; - struct timer_list media; - int watchdog, tx_err; - u_short media_status; - u_short fast_poll; - u_short link_status; - struct mii_if_info mii_if; - int duplex; - int rx_ovrn; - unsigned long last_rx; -}; - -/* Special definitions for Megahertz multifunction cards */ -#define MEGAHERTZ_ISR 0x0380 - -/* Special function registers for Motorola Mariner */ -#define MOT_LAN 0x0000 -#define MOT_UART 0x0020 -#define MOT_EEPROM 0x20 - -#define MOT_NORMAL \ -(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA) - -/* Special function registers for Ositech cards */ -#define OSITECH_AUI_CTL 0x0c -#define OSITECH_PWRDOWN 0x0d -#define OSITECH_RESET 0x0e -#define OSITECH_ISR 0x0f -#define OSITECH_AUI_PWR 0x0c -#define OSITECH_RESET_ISR 0x0e - -#define OSI_AUI_PWR 0x40 -#define OSI_LAN_PWRDOWN 0x02 -#define OSI_MODEM_PWRDOWN 0x01 -#define OSI_LAN_RESET 0x02 -#define OSI_MODEM_RESET 0x01 - -/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */ -#define BANK_SELECT 14 /* Window select register. */ -#define SMC_SELECT_BANK(x) { outw(x, ioaddr + BANK_SELECT); } - -/* Bank 0 registers. */ -#define TCR 0 /* transmit control register */ -#define TCR_CLEAR 0 /* do NOTHING */ -#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */ -#define TCR_PAD_EN 0x0080 /* pads short packets to 64 bytes */ -#define TCR_MONCSN 0x0400 /* Monitor Carrier. */ -#define TCR_FDUPLX 0x0800 /* Full duplex mode. */ -#define TCR_NORMAL TCR_ENABLE | TCR_PAD_EN - -#define EPH 2 /* Ethernet Protocol Handler report. */ -#define EPH_TX_SUC 0x0001 -#define EPH_SNGLCOL 0x0002 -#define EPH_MULCOL 0x0004 -#define EPH_LTX_MULT 0x0008 -#define EPH_16COL 0x0010 -#define EPH_SQET 0x0020 -#define EPH_LTX_BRD 0x0040 -#define EPH_TX_DEFR 0x0080 -#define EPH_LAT_COL 0x0200 -#define EPH_LOST_CAR 0x0400 -#define EPH_EXC_DEF 0x0800 -#define EPH_CTR_ROL 0x1000 -#define EPH_RX_OVRN 0x2000 -#define EPH_LINK_OK 0x4000 -#define EPH_TX_UNRN 0x8000 -#define MEMINFO 8 /* Memory Information Register */ -#define MEMCFG 10 /* Memory Configuration Register */ - -/* Bank 1 registers. */ -#define CONFIG 0 -#define CFG_MII_SELECT 0x8000 /* 91C100 only */ -#define CFG_NO_WAIT 0x1000 -#define CFG_FULL_STEP 0x0400 -#define CFG_SET_SQLCH 0x0200 -#define CFG_AUI_SELECT 0x0100 -#define CFG_16BIT 0x0080 -#define CFG_DIS_LINK 0x0040 -#define CFG_STATIC 0x0030 -#define CFG_IRQ_SEL_1 0x0004 -#define CFG_IRQ_SEL_0 0x0002 -#define BASE_ADDR 2 -#define ADDR0 4 -#define GENERAL 10 -#define CONTROL 12 -#define CTL_STORE 0x0001 -#define CTL_RELOAD 0x0002 -#define CTL_EE_SELECT 0x0004 -#define CTL_TE_ENABLE 0x0020 -#define CTL_CR_ENABLE 0x0040 -#define CTL_LE_ENABLE 0x0080 -#define CTL_AUTO_RELEASE 0x0800 -#define CTL_POWERDOWN 0x2000 - -/* Bank 2 registers. */ -#define MMU_CMD 0 -#define MC_ALLOC 0x20 /* or with number of 256 byte packets */ -#define MC_RESET 0x40 -#define MC_RELEASE 0x80 /* remove and release the current rx packet */ -#define MC_FREEPKT 0xA0 /* Release packet in PNR register */ -#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */ -#define PNR_ARR 2 -#define FIFO_PORTS 4 -#define FP_RXEMPTY 0x8000 -#define POINTER 6 -#define PTR_AUTO_INC 0x0040 -#define PTR_READ 0x2000 -#define PTR_AUTOINC 0x4000 -#define PTR_RCV 0x8000 -#define DATA_1 8 -#define INTERRUPT 12 -#define IM_RCV_INT 0x1 -#define IM_TX_INT 0x2 -#define IM_TX_EMPTY_INT 0x4 -#define IM_ALLOC_INT 0x8 -#define IM_RX_OVRN_INT 0x10 -#define IM_EPH_INT 0x20 - -#define RCR 4 -enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002, - RxEnable = 0x0100, RxStripCRC = 0x0200}; -#define RCR_SOFTRESET 0x8000 /* resets the chip */ -#define RCR_STRIP_CRC 0x200 /* strips CRC */ -#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */ -#define RCR_ALMUL 0x4 /* receive all multicast packets */ -#define RCR_PROMISC 0x2 /* enable promiscuous mode */ - -/* the normal settings for the RCR register : */ -#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE) -#define RCR_CLEAR 0x0 /* set it to a base state */ -#define COUNTER 6 - -/* BANK 3 -- not the same values as in smc9194! */ -#define MULTICAST0 0 -#define MULTICAST2 2 -#define MULTICAST4 4 -#define MULTICAST6 6 -#define MGMT 8 -#define REVISION 0x0a - -/* Transmit status bits. */ -#define TS_SUCCESS 0x0001 -#define TS_16COL 0x0010 -#define TS_LATCOL 0x0200 -#define TS_LOSTCAR 0x0400 - -/* Receive status bits. */ -#define RS_ALGNERR 0x8000 -#define RS_BADCRC 0x2000 -#define RS_ODDFRAME 0x1000 -#define RS_TOOLONG 0x0800 -#define RS_TOOSHORT 0x0400 -#define RS_MULTICAST 0x0001 -#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) - -#define set_bits(v, p) outw(inw(p)|(v), (p)) -#define mask_bits(v, p) outw(inw(p)&(v), (p)) - -/*====================================================================*/ - -static void smc91c92_detach(struct pcmcia_device *p_dev); -static int smc91c92_config(struct pcmcia_device *link); -static void smc91c92_release(struct pcmcia_device *link); - -static int smc_open(struct net_device *dev); -static int smc_close(struct net_device *dev); -static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue); -static netdev_tx_t smc_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t smc_interrupt(int irq, void *dev_id); -static void smc_rx(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static int s9k_config(struct net_device *dev, struct ifmap *map); -static void smc_set_xcvr(struct net_device *dev, int if_port); -static void smc_reset(struct net_device *dev); -static void media_check(struct timer_list *t); -static void mdio_sync(unsigned int addr); -static int mdio_read(struct net_device *dev, int phy_id, int loc); -static void mdio_write(struct net_device *dev, int phy_id, int loc, int value); -static int smc_link_ok(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; - -static const struct net_device_ops smc_netdev_ops = { - .ndo_open = smc_open, - .ndo_stop = smc_close, - .ndo_start_xmit = smc_start_xmit, - .ndo_tx_timeout = smc_tx_timeout, - .ndo_set_config = s9k_config, - .ndo_set_rx_mode = set_rx_mode, - .ndo_eth_ioctl = smc_ioctl, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int smc91c92_probe(struct pcmcia_device *link) -{ - struct smc_private *smc; - struct net_device *dev; - - dev_dbg(&link->dev, "smc91c92_attach()\n"); - - /* Create new ethernet device */ - dev = alloc_etherdev(sizeof(struct smc_private)); - if (!dev) - return -ENOMEM; - smc = netdev_priv(dev); - smc->p_dev = link; - link->priv = dev; - - spin_lock_init(&smc->lock); - - /* The SMC91c92-specific entries in the device structure. */ - dev->netdev_ops = &smc_netdev_ops; - dev->ethtool_ops = ðtool_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - smc->mii_if.dev = dev; - smc->mii_if.mdio_read = mdio_read; - smc->mii_if.mdio_write = mdio_write; - smc->mii_if.phy_id_mask = 0x1f; - smc->mii_if.reg_num_mask = 0x1f; - - return smc91c92_config(link); -} /* smc91c92_attach */ - -static void smc91c92_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - dev_dbg(&link->dev, "smc91c92_detach\n"); - - unregister_netdev(dev); - - smc91c92_release(link); - - free_netdev(dev); -} /* smc91c92_detach */ - -/*====================================================================*/ - -static int cvt_ascii_address(struct net_device *dev, char *s) -{ - u8 mac[ETH_ALEN]; - int i, j, da, c; - - if (strlen(s) != 12) - return -1; - for (i = 0; i < 6; i++) { - da = 0; - for (j = 0; j < 2; j++) { - c = *s++; - da <<= 4; - da += ((c >= '0') && (c <= '9')) ? - (c - '0') : ((c & 0x0f) + 9); - } - mac[i] = da; - } - eth_hw_addr_set(dev, mac); - return 0; -} - -/*==================================================================== - - Configuration stuff for Megahertz cards - - mhz_3288_power() is used to power up a 3288's ethernet chip. - mhz_mfc_config() handles socket setup for multifunction (1144 - and 3288) cards. mhz_setup() gets a card's hardware ethernet - address. - -======================================================================*/ - -static int mhz_3288_power(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - u_char tmp; - - /* Read the ISR twice... */ - readb(smc->base+MEGAHERTZ_ISR); - udelay(5); - readb(smc->base+MEGAHERTZ_ISR); - - /* Pause 200ms... */ - mdelay(200); - - /* Now read and write the COR... */ - tmp = readb(smc->base + link->config_base + CISREG_COR); - udelay(5); - writeb(tmp, smc->base + link->config_base + CISREG_COR); - - return 0; -} - -static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - int k; - p_dev->io_lines = 16; - p_dev->resource[1]->start = p_dev->resource[0]->start; - p_dev->resource[1]->end = 8; - p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - for (k = 0; k < 0x400; k += 0x10) { - if (k & 0x80) - continue; - p_dev->resource[0]->start = k ^ 0x300; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; -} - -static int mhz_mfc_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - unsigned int offset; - int i; - - link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ | - CONF_AUTO_SET_IO; - - /* The Megahertz combo cards have modem-like CIS entries, so - we have to explicitly try a bunch of port combinations. */ - if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL)) - return -ENODEV; - - dev->base_addr = link->resource[0]->start; - - /* Allocate a memory window, for accessing the ISR */ - link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - link->resource[2]->start = link->resource[2]->end = 0; - i = pcmcia_request_window(link, link->resource[2], 0); - if (i != 0) - return -ENODEV; - - smc->base = ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0; - i = pcmcia_map_mem_page(link, link->resource[2], offset); - if ((i == 0) && - (smc->manfid == MANFID_MEGAHERTZ) && - (smc->cardid == PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); - - return 0; -} - -static int pcmcia_get_versmac(struct pcmcia_device *p_dev, - tuple_t *tuple, - void *priv) -{ - struct net_device *dev = priv; - cisparse_t parse; - u8 *buf; - - if (pcmcia_parse_tuple(tuple, &parse)) - return -EINVAL; - - buf = parse.version_1.str + parse.version_1.ofs[3]; - - if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0)) - return 0; - - return -EINVAL; -}; - -static int mhz_setup(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - size_t len; - u8 *buf; - int rc; - - /* Read the station address from the CIS. It is stored as the last - (fourth) string in the Version 1 Version/ID tuple. */ - if ((link->prod_id[3]) && - (cvt_ascii_address(dev, link->prod_id[3]) == 0)) - return 0; - - /* Workarounds for broken cards start here. */ - /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev)) - return 0; - - /* Another possibility: for the EM3288, in a special tuple */ - rc = -1; - len = pcmcia_get_tuple(link, 0x81, &buf); - if (buf && len >= 13) { - buf[12] = '\0'; - if (cvt_ascii_address(dev, buf) == 0) - rc = 0; - } - kfree(buf); - - return rc; -}; - -/*====================================================================== - - Configuration stuff for the Motorola Mariner - - mot_config() writes directly to the Mariner configuration - registers because the CIS is just bogus. - -======================================================================*/ - -static void mot_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - unsigned int iouart = link->resource[1]->start; - - /* Set UART base address and force map with COR bit 1 */ - writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0); - writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1); - writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR); - - /* Set SMC base address and force map with COR bit 1 */ - writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0); - writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1); - writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR); - - /* Wait for things to settle down */ - mdelay(100); -} - -static int mot_setup(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - unsigned int ioaddr = dev->base_addr; - int i, wait, loop; - u8 mac[ETH_ALEN]; - u_int addr; - - /* Read Ethernet address from Serial EEPROM */ - - for (i = 0; i < 3; i++) { - SMC_SELECT_BANK(2); - outw(MOT_EEPROM + i, ioaddr + POINTER); - SMC_SELECT_BANK(1); - outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL); - - for (loop = wait = 0; loop < 200; loop++) { - udelay(10); - wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL)); - if (wait == 0) break; - } - - if (wait) - return -1; - - addr = inw(ioaddr + GENERAL); - mac[2*i] = addr & 0xff; - mac[2*i+1] = (addr >> 8) & 0xff; - } - eth_hw_addr_set(dev, mac); - - return 0; -} - -/*====================================================================*/ - -static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - return pcmcia_request_io(p_dev); -} - -static int smc_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - int i; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - i = pcmcia_loop_config(link, smc_configcheck, NULL); - if (!i) - dev->base_addr = link->resource[0]->start; - - return i; -} - - -static int smc_setup(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - /* Check for a LAN function extension tuple */ - if (!pcmcia_get_mac_from_cis(link, dev)) - return 0; - - /* Try the third string in the Version 1 Version/ID tuple. */ - if (link->prod_id[2]) { - if (cvt_ascii_address(dev, link->prod_id[2]) == 0) - return 0; - } - return -1; -} - -/*====================================================================*/ - -static int osi_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; - int i, j; - - link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ; - link->resource[0]->end = 64; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[1]->end = 8; - - /* Enable Hard Decode, LAN, Modem */ - link->io_lines = 16; - link->config_index = 0x23; - - for (i = j = 0; j < 4; j++) { - link->resource[1]->start = com[j]; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) { - /* Fallback: turn off hard decode */ - link->config_index = 0x03; - link->resource[1]->end = 0; - i = pcmcia_request_io(link); - } - dev->base_addr = link->resource[0]->start + 0x10; - return i; -} - -static int osi_load_firmware(struct pcmcia_device *link) -{ - const struct firmware *fw; - int i, err; - - err = request_firmware(&fw, FIRMWARE_NAME, &link->dev); - if (err) { - pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME); - return err; - } - - /* Download the Seven of Diamonds firmware */ - for (i = 0; i < fw->size; i++) { - outb(fw->data[i], link->resource[0]->start + 2); - udelay(50); - } - release_firmware(fw); - return err; -} - -static int pcmcia_osi_mac(struct pcmcia_device *p_dev, - tuple_t *tuple, - void *priv) -{ - struct net_device *dev = priv; - - if (tuple->TupleDataLen < 8) - return -EINVAL; - if (tuple->TupleData[0] != 0x04) - return -EINVAL; - - eth_hw_addr_set(dev, &tuple->TupleData[2]); - return 0; -}; - - -static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) -{ - struct net_device *dev = link->priv; - int rc; - - /* Read the station address from tuple 0x90, subtuple 0x04 */ - if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev)) - return -1; - - if (((manfid == MANFID_OSITECH) && - (cardid == PRODID_OSITECH_SEVEN)) || - ((manfid == MANFID_PSION) && - (cardid == PRODID_PSION_NET100))) { - rc = osi_load_firmware(link); - if (rc) - return rc; - } else if (manfid == MANFID_OSITECH) { - /* Make sure both functions are powered up */ - set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR); - /* Now, turn on the interrupt for both card functions */ - set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR); - dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n", - inw(link->resource[0]->start + OSITECH_AUI_PWR), - inw(link->resource[0]->start + OSITECH_RESET_ISR)); - } - return 0; -} - -static int smc91c92_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int smc91c92_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - int i; - - if ((smc->manfid == MANFID_MEGAHERTZ) && - (smc->cardid == PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); - if (smc->manfid == MANFID_MOTOROLA) - mot_config(link); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) { - /* Power up the card and enable interrupts */ - set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); - set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); - } - if (((smc->manfid == MANFID_OSITECH) && - (smc->cardid == PRODID_OSITECH_SEVEN)) || - ((smc->manfid == MANFID_PSION) && - (smc->cardid == PRODID_PSION_NET100))) { - i = osi_load_firmware(link); - if (i) { - netdev_err(dev, "Failed to load firmware\n"); - return i; - } - } - if (link->open) { - smc_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -/*====================================================================== - - This verifies that the chip is some SMC91cXX variant, and returns - the revision code if successful. Otherwise, it returns -ENODEV. - -======================================================================*/ - -static int check_sig(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - unsigned int ioaddr = dev->base_addr; - int width; - u_short s; - - SMC_SELECT_BANK(1); - if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) { - /* Try powering up the chip */ - outw(0, ioaddr + CONTROL); - mdelay(55); - } - - /* Try setting bus width */ - width = (link->resource[0]->flags == IO_DATA_PATH_WIDTH_AUTO); - s = inb(ioaddr + CONFIG); - if (width) - s |= CFG_16BIT; - else - s &= ~CFG_16BIT; - outb(s, ioaddr + CONFIG); - - /* Check Base Address Register to make sure bus width is OK */ - s = inw(ioaddr + BASE_ADDR); - if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) && - ((s >> 8) != (s & 0xff))) { - SMC_SELECT_BANK(3); - s = inw(ioaddr + REVISION); - return s & 0xff; - } - - if (width) { - netdev_info(dev, "using 8-bit IO window\n"); - - smc91c92_suspend(link); - pcmcia_fixup_iowidth(link); - smc91c92_resume(link); - return check_sig(link); - } - return -ENODEV; -} - -static int smc91c92_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - char *name; - int i, rev, j = 0; - unsigned int ioaddr; - u_long mir; - - dev_dbg(&link->dev, "smc91c92_config\n"); - - smc->manfid = link->manf_id; - smc->cardid = link->card_id; - - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) { - i = osi_config(link); - } else if ((smc->manfid == MANFID_MOTOROLA) || - ((smc->manfid == MANFID_MEGAHERTZ) && - ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) || - (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) { - i = mhz_mfc_config(link); - } else { - i = smc_config(link); - } - if (i) - goto config_failed; - - i = pcmcia_request_irq(link, smc_interrupt); - if (i) - goto config_failed; - i = pcmcia_enable_device(link); - if (i) - goto config_failed; - - if (smc->manfid == MANFID_MOTOROLA) - mot_config(link); - - dev->irq = link->irq; - - if ((if_port >= 0) && (if_port <= 2)) - dev->if_port = if_port; - else - dev_notice(&link->dev, "invalid if_port requested\n"); - - switch (smc->manfid) { - case MANFID_OSITECH: - case MANFID_PSION: - i = osi_setup(link, smc->manfid, smc->cardid); break; - case MANFID_SMC: - case MANFID_NEW_MEDIA: - i = smc_setup(link); break; - case 0x128: /* For broken Megahertz cards */ - case MANFID_MEGAHERTZ: - i = mhz_setup(link); break; - case MANFID_MOTOROLA: - default: /* get the hw address from EEPROM */ - i = mot_setup(link); break; - } - - if (i != 0) { - dev_notice(&link->dev, "Unable to find hardware address.\n"); - goto config_failed; - } - - smc->duplex = 0; - smc->rx_ovrn = 0; - - rev = check_sig(link); - name = "???"; - if (rev > 0) - switch (rev >> 4) { - case 3: name = "92"; break; - case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break; - case 5: name = "95"; break; - case 7: name = "100"; break; - case 8: name = "100-FD"; break; - case 9: name = "110"; break; - } - - ioaddr = dev->base_addr; - if (rev > 0) { - u_long mcr; - SMC_SELECT_BANK(0); - mir = inw(ioaddr + MEMINFO) & 0xff; - if (mir == 0xff) mir++; - /* Get scale factor for memory size */ - mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200; - mir *= 128 * (1<<((mcr >> 9) & 7)); - SMC_SELECT_BANK(1); - smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; - smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC; - if (smc->manfid == MANFID_OSITECH) - smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0; - if ((rev >> 4) >= 7) - smc->cfg |= CFG_MII_SELECT; - } else - mir = 0; - - if (smc->cfg & CFG_MII_SELECT) { - SMC_SELECT_BANK(3); - - for (i = 0; i < 32; i++) { - j = mdio_read(dev, i, 1); - if ((j != 0) && (j != 0xffff)) break; - } - smc->mii_if.phy_id = (i < 32) ? i : -1; - - SMC_SELECT_BANK(0); - } - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) != 0) { - dev_err(&link->dev, "register_netdev() failed\n"); - goto config_undo; - } - - netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n", - name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr); - - if (rev > 0) { - if (mir & 0x3ff) - netdev_info(dev, " %lu byte", mir); - else - netdev_info(dev, " %lu kb", mir>>10); - pr_cont(" buffer, %s xcvr\n", - (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]); - } - - if (smc->cfg & CFG_MII_SELECT) { - if (smc->mii_if.phy_id != -1) { - netdev_dbg(dev, " MII transceiver at index %d, status %x\n", - smc->mii_if.phy_id, j); - } else { - netdev_notice(dev, " No MII transceivers found!\n"); - } - } - return 0; - -config_undo: - unregister_netdev(dev); -config_failed: - smc91c92_release(link); - free_netdev(dev); - return -ENODEV; -} /* smc91c92_config */ - -static void smc91c92_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "smc91c92_release\n"); - if (link->resource[2]->end) { - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - iounmap(smc->base); - } - pcmcia_disable_device(link); -} - -/*====================================================================== - - MII interface support for SMC91cXX based cards -======================================================================*/ - -#define MDIO_SHIFT_CLK 0x04 -#define MDIO_DATA_OUT 0x01 -#define MDIO_DIR_WRITE 0x08 -#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT) -#define MDIO_DATA_READ 0x02 - -static void mdio_sync(unsigned int addr) -{ - int bits; - for (bits = 0; bits < 32; bits++) { - outb(MDIO_DATA_WRITE1, addr); - outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); - } -} - -static int mdio_read(struct net_device *dev, int phy_id, int loc) -{ - unsigned int addr = dev->base_addr + MGMT; - u_int cmd = (0x06<<10)|(phy_id<<5)|loc; - int i, retval = 0; - - mdio_sync(addr); - for (i = 13; i >= 0; i--) { - int dat = (cmd&(1< 0; i--) { - outb(0, addr); - retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0); - outb(MDIO_SHIFT_CLK, addr); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) -{ - unsigned int addr = dev->base_addr + MGMT; - u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; - int i; - - mdio_sync(addr); - for (i = 31; i >= 0; i--) { - int dat = (cmd&(1<= 0; i--) { - outb(0, addr); - outb(MDIO_SHIFT_CLK, addr); - } -} - -/*====================================================================== - - The driver core code, most of which should be common with a - non-PCMCIA implementation. - -======================================================================*/ - -#ifdef PCMCIA_DEBUG -static void smc_dump(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - u_short i, w, save; - save = inw(ioaddr + BANK_SELECT); - for (w = 0; w < 4; w++) { - SMC_SELECT_BANK(w); - netdev_dbg(dev, "bank %d: ", w); - for (i = 0; i < 14; i += 2) - pr_cont(" %04x", inw(ioaddr + i)); - pr_cont("\n"); - } - outw(save, ioaddr + BANK_SELECT); -} -#endif - -static int smc_open(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - struct pcmcia_device *link = smc->p_dev; - - dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n", - dev->name, dev, inw(dev->base_addr + BANK_SELECT)); -#ifdef PCMCIA_DEBUG - smc_dump(dev); -#endif - - /* Check that the PCMCIA card is still here. */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - /* Physical device present signature. */ - if (check_sig(link) < 0) { - netdev_info(dev, "Yikes! Bad chip signature!\n"); - return -ENODEV; - } - link->open++; - - netif_start_queue(dev); - smc->saved_skb = NULL; - smc->packets_waiting = 0; - - smc_reset(dev); - timer_setup(&smc->media, media_check, 0); - mod_timer(&smc->media, jiffies + HZ); - - return 0; -} /* smc_open */ - -/*====================================================================*/ - -static int smc_close(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - struct pcmcia_device *link = smc->p_dev; - unsigned int ioaddr = dev->base_addr; - - dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n", - dev->name, inw(ioaddr + BANK_SELECT)); - - netif_stop_queue(dev); - - /* Shut off all interrupts, and turn off the Tx and Rx sections. - Don't bother to check for chip present. */ - SMC_SELECT_BANK(2); /* Nominally paranoia, but do no assume... */ - outw(0, ioaddr + INTERRUPT); - SMC_SELECT_BANK(0); - mask_bits(0xff00, ioaddr + RCR); - mask_bits(0xff00, ioaddr + TCR); - - /* Put the chip into power-down mode. */ - SMC_SELECT_BANK(1); - outw(CTL_POWERDOWN, ioaddr + CONTROL ); - - link->open--; - timer_delete_sync(&smc->media); - - return 0; -} /* smc_close */ - -/*====================================================================== - - Transfer a packet to the hardware and trigger the packet send. - This may be called at either from either the Tx queue code - or the interrupt handler. - -======================================================================*/ - -static void smc_hardware_send_packet(struct net_device * dev) -{ - struct smc_private *smc = netdev_priv(dev); - struct sk_buff *skb = smc->saved_skb; - unsigned int ioaddr = dev->base_addr; - u_char packet_no; - - if (!skb) { - netdev_err(dev, "In XMIT with no packet to send\n"); - return; - } - - /* There should be a packet slot waiting. */ - packet_no = inw(ioaddr + PNR_ARR) >> 8; - if (packet_no & 0x80) { - /* If not, there is a hardware problem! Likely an ejected card. */ - netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n", - packet_no); - dev_kfree_skb_irq(skb); - smc->saved_skb = NULL; - netif_start_queue(dev); - return; - } - - dev->stats.tx_bytes += skb->len; - /* The card should use the just-allocated buffer. */ - outw(packet_no, ioaddr + PNR_ARR); - /* point to the beginning of the packet */ - outw(PTR_AUTOINC , ioaddr + POINTER); - - /* Send the packet length (+6 for status, length and ctl byte) - and the status word (set to zeros). */ - { - u_char *buf = skb->data; - u_int length = skb->len; /* The chip will pad to ethernet min. */ - - netdev_dbg(dev, "Trying to xmit packet of length %d\n", length); - - /* send the packet length: +6 for status word, length, and ctl */ - outw(0, ioaddr + DATA_1); - outw(length + 6, ioaddr + DATA_1); - outsw(ioaddr + DATA_1, buf, length >> 1); - - /* The odd last byte, if there is one, goes in the control word. */ - outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1); - } - - /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */ - outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) | - (inw(ioaddr + INTERRUPT) & 0xff00), - ioaddr + INTERRUPT); - - /* The chip does the rest of the work. */ - outw(MC_ENQUEUE , ioaddr + MMU_CMD); - - smc->saved_skb = NULL; - dev_kfree_skb_irq(skb); - netif_trans_update(dev); - netif_start_queue(dev); -} - -/*====================================================================*/ - -static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - - netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\n", - inw(ioaddr)&0xff, inw(ioaddr + 2)); - dev->stats.tx_errors++; - smc_reset(dev); - netif_trans_update(dev); /* prevent tx timeout */ - smc->saved_skb = NULL; - netif_wake_queue(dev); -} - -static netdev_tx_t smc_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u_short num_pages; - short time_out, ir; - unsigned long flags; - - netif_stop_queue(dev); - - netdev_dbg(dev, "smc_start_xmit(length = %d) called, status %04x\n", - skb->len, inw(ioaddr + 2)); - - if (smc->saved_skb) { - /* THIS SHOULD NEVER HAPPEN. */ - dev->stats.tx_aborted_errors++; - netdev_dbg(dev, "Internal error -- sent packet while busy\n"); - return NETDEV_TX_BUSY; - } - smc->saved_skb = skb; - - num_pages = skb->len >> 8; - - if (num_pages > 7) { - netdev_err(dev, "Far too big packet error: %d pages\n", num_pages); - dev_kfree_skb (skb); - smc->saved_skb = NULL; - dev->stats.tx_dropped++; - return NETDEV_TX_OK; /* Do not re-queue this packet. */ - } - /* A packet is now waiting. */ - smc->packets_waiting++; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(2); /* Paranoia, we should always be in window 2 */ - - /* need MC_RESET to keep the memory consistent. errata? */ - if (smc->rx_ovrn) { - outw(MC_RESET, ioaddr + MMU_CMD); - smc->rx_ovrn = 0; - } - - /* Allocate the memory; send the packet now if we win. */ - outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD); - for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) { - ir = inw(ioaddr+INTERRUPT); - if (ir & IM_ALLOC_INT) { - /* Acknowledge the interrupt, send the packet. */ - outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT); - smc_hardware_send_packet(dev); /* Send the packet now.. */ - spin_unlock_irqrestore(&smc->lock, flags); - return NETDEV_TX_OK; - } - } - - /* Otherwise defer until the Tx-space-allocated interrupt. */ - netdev_dbg(dev, "memory allocation deferred.\n"); - outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); - spin_unlock_irqrestore(&smc->lock, flags); - - return NETDEV_TX_OK; -} - -/*====================================================================== - - Handle a Tx anomalous event. Entered while in Window 2. - -======================================================================*/ - -static void smc_tx_err(struct net_device * dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - int saved_packet = inw(ioaddr + PNR_ARR) & 0xff; - int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f; - int tx_status; - - /* select this as the packet to read from */ - outw(packet_no, ioaddr + PNR_ARR); - - /* read the first word from this packet */ - outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER); - - tx_status = inw(ioaddr + DATA_1); - - dev->stats.tx_errors++; - if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++; - if (tx_status & TS_LATCOL) dev->stats.tx_window_errors++; - if (tx_status & TS_16COL) { - dev->stats.tx_aborted_errors++; - smc->tx_err++; - } - - if (tx_status & TS_SUCCESS) { - netdev_notice(dev, "Successful packet caused error interrupt?\n"); - } - /* re-enable transmit */ - SMC_SELECT_BANK(0); - outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR); - SMC_SELECT_BANK(2); - - outw(MC_FREEPKT, ioaddr + MMU_CMD); /* Free the packet memory. */ - - /* one less packet waiting for me */ - smc->packets_waiting--; - - outw(saved_packet, ioaddr + PNR_ARR); -} - -/*====================================================================*/ - -static void smc_eph_irq(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u_short card_stats, ephs; - - SMC_SELECT_BANK(0); - ephs = inw(ioaddr + EPH); - netdev_dbg(dev, "Ethernet protocol handler interrupt, status %4.4x.\n", - ephs); - /* Could be a counter roll-over warning: update stats. */ - card_stats = inw(ioaddr + COUNTER); - /* single collisions */ - dev->stats.collisions += card_stats & 0xF; - card_stats >>= 4; - /* multiple collisions */ - dev->stats.collisions += card_stats & 0xF; -#if 0 /* These are for when linux supports these statistics */ - card_stats >>= 4; /* deferred */ - card_stats >>= 4; /* excess deferred */ -#endif - /* If we had a transmit error we must re-enable the transmitter. */ - outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR); - - /* Clear a link error interrupt. */ - SMC_SELECT_BANK(1); - outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL); - outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, - ioaddr + CONTROL); - SMC_SELECT_BANK(2); -} - -/*====================================================================*/ - -static irqreturn_t smc_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr; - u_short saved_bank, saved_pointer, mask, status; - unsigned int handled = 1; - char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ - - if (!netif_device_present(dev)) - return IRQ_NONE; - - ioaddr = dev->base_addr; - - netdev_dbg(dev, "SMC91c92 interrupt %d at %#x.\n", - irq, ioaddr); - - spin_lock(&smc->lock); - smc->watchdog = 0; - saved_bank = inw(ioaddr + BANK_SELECT); - if ((saved_bank & 0xff00) != 0x3300) { - /* The device does not exist -- the card could be off-line, or - maybe it has been ejected. */ - netdev_dbg(dev, "SMC91c92 interrupt %d for non-existent/ejected device.\n", - irq); - handled = 0; - goto irq_done; - } - - SMC_SELECT_BANK(2); - saved_pointer = inw(ioaddr + POINTER); - mask = inw(ioaddr + INTERRUPT) >> 8; - /* clear all interrupts */ - outw(0, ioaddr + INTERRUPT); - - do { /* read the status flag, and mask it */ - status = inw(ioaddr + INTERRUPT) & 0xff; - netdev_dbg(dev, "Status is %#2.2x (mask %#2.2x).\n", - status, mask); - if ((status & mask) == 0) { - if (bogus_cnt == INTR_WORK) - handled = 0; - break; - } - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - smc_rx(dev); - } - if (status & IM_TX_INT) { - smc_tx_err(dev); - outw(IM_TX_INT, ioaddr + INTERRUPT); - } - status &= mask; - if (status & IM_TX_EMPTY_INT) { - outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT); - mask &= ~IM_TX_EMPTY_INT; - dev->stats.tx_packets += smc->packets_waiting; - smc->packets_waiting = 0; - } - if (status & IM_ALLOC_INT) { - /* Clear this interrupt so it doesn't happen again */ - mask &= ~IM_ALLOC_INT; - - smc_hardware_send_packet(dev); - - /* enable xmit interrupts based on this */ - mask |= (IM_TX_EMPTY_INT | IM_TX_INT); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - } - if (status & IM_RX_OVRN_INT) { - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - if (smc->duplex) - smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */ - outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT); - } - if (status & IM_EPH_INT) - smc_eph_irq(dev); - } while (--bogus_cnt); - - netdev_dbg(dev, " Restoring saved registers mask %2.2x bank %4.4x pointer %4.4x.\n", - mask, saved_bank, saved_pointer); - - /* restore state register */ - outw((mask<<8), ioaddr + INTERRUPT); - outw(saved_pointer, ioaddr + POINTER); - SMC_SELECT_BANK(saved_bank); - - netdev_dbg(dev, "Exiting interrupt IRQ%d.\n", irq); - -irq_done: - - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) { - /* Retrigger interrupt if needed */ - mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR); - set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR); - } - if (smc->manfid == MANFID_MOTOROLA) { - u_char cor; - cor = readb(smc->base + MOT_UART + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR); - writeb(cor, smc->base + MOT_UART + CISREG_COR); - cor = readb(smc->base + MOT_LAN + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR); - writeb(cor, smc->base + MOT_LAN + CISREG_COR); - } - - if ((smc->base != NULL) && /* Megahertz MFC's */ - (smc->manfid == MANFID_MEGAHERTZ) && - (smc->cardid == PRODID_MEGAHERTZ_EM3288)) { - - u_char tmp; - tmp = readb(smc->base+MEGAHERTZ_ISR); - tmp = readb(smc->base+MEGAHERTZ_ISR); - - /* Retrigger interrupt if needed */ - writeb(tmp, smc->base + MEGAHERTZ_ISR); - writeb(tmp, smc->base + MEGAHERTZ_ISR); - } - - spin_unlock(&smc->lock); - return IRQ_RETVAL(handled); -} - -/*====================================================================*/ - -static void smc_rx(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - int rx_status; - int packet_length; /* Caution: not frame length, rather words - to transfer from the chip. */ - - /* Assertion: we are in Window 2. */ - - if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) { - netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n"); - return; - } - - /* Reset the read pointer, and read the status and packet length. */ - outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER); - rx_status = inw(ioaddr + DATA_1); - packet_length = inw(ioaddr + DATA_1) & 0x07ff; - - netdev_dbg(dev, "Receive status %4.4x length %d.\n", - rx_status, packet_length); - - if (!(rx_status & RS_ERRORS)) { - /* do stuff to make a new packet */ - struct sk_buff *skb; - struct smc_private *smc = netdev_priv(dev); - - /* Note: packet_length adds 5 or 6 extra bytes here! */ - skb = netdev_alloc_skb(dev, packet_length+2); - - if (skb == NULL) { - netdev_dbg(dev, "Low memory, packet dropped.\n"); - dev->stats.rx_dropped++; - outw(MC_RELEASE, ioaddr + MMU_CMD); - return; - } - - packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6); - skb_reserve(skb, 2); - insw(ioaddr+DATA_1, skb_put(skb, packet_length), - (packet_length+1)>>1); - skb->protocol = eth_type_trans(skb, dev); - - netif_rx(skb); - smc->last_rx = jiffies; - dev->stats.rx_packets++; - dev->stats.rx_bytes += packet_length; - if (rx_status & RS_MULTICAST) - dev->stats.multicast++; - } else { - /* error ... */ - dev->stats.rx_errors++; - - if (rx_status & RS_ALGNERR) dev->stats.rx_frame_errors++; - if (rx_status & (RS_TOOSHORT | RS_TOOLONG)) - dev->stats.rx_length_errors++; - if (rx_status & RS_BADCRC) dev->stats.rx_crc_errors++; - } - /* Let the MMU free the memory of this packet. */ - outw(MC_RELEASE, ioaddr + MMU_CMD); -} - -/*====================================================================== - - Set the receive mode. - - This routine is used by both the protocol level to notify us of - promiscuous/multicast mode changes, and by the open/reset code to - initialize the Rx registers. We always set the multicast list and - leave the receiver running. - -======================================================================*/ - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct smc_private *smc = netdev_priv(dev); - unsigned char multicast_table[8]; - unsigned long flags; - u_short rx_cfg_setting; - int i; - - memset(multicast_table, 0, sizeof(multicast_table)); - - if (dev->flags & IFF_PROMISC) { - rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti; - } else if (dev->flags & IFF_ALLMULTI) - rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti; - else { - if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, dev) { - u_int position = ether_crc(6, ha->addr); - multicast_table[position >> 29] |= 1 << ((position >> 26) & 7); - } - } - rx_cfg_setting = RxStripCRC | RxEnable; - } - - /* Load MC table and Rx setting into the chip without interrupts. */ - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - for (i = 0; i < 8; i++) - outb(multicast_table[i], ioaddr + MULTICAST0 + i); - SMC_SELECT_BANK(0); - outw(rx_cfg_setting, ioaddr + RCR); - SMC_SELECT_BANK(2); - spin_unlock_irqrestore(&smc->lock, flags); -} - -/*====================================================================== - - Senses when a card's config changes. Here, it's coax or TP. - -======================================================================*/ - -static int s9k_config(struct net_device *dev, struct ifmap *map) -{ - struct smc_private *smc = netdev_priv(dev); - if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - if (smc->cfg & CFG_MII_SELECT) - return -EOPNOTSUPP; - else if (map->port > 2) - return -EINVAL; - WRITE_ONCE(dev->if_port, map->port); - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - smc_reset(dev); - } - return 0; -} - -/*====================================================================== - - Reset the chip, reloading every register that might be corrupted. - -======================================================================*/ - -/* - Set transceiver type, perhaps to something other than what the user - specified in dev->if_port. -*/ -static void smc_set_xcvr(struct net_device *dev, int if_port) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u_short saved_bank; - - saved_bank = inw(ioaddr + BANK_SELECT); - SMC_SELECT_BANK(1); - if (if_port == 2) { - outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) - set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002); - } else { - outw(smc->cfg, ioaddr + CONFIG); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) - mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001); - } - SMC_SELECT_BANK(saved_bank); -} - -static void smc_reset(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct smc_private *smc = netdev_priv(dev); - int i; - - netdev_dbg(dev, "smc91c92 reset called.\n"); - - /* The first interaction must be a write to bring the chip out - of sleep mode. */ - SMC_SELECT_BANK(0); - /* Reset the chip. */ - outw(RCR_SOFTRESET, ioaddr + RCR); - udelay(10); - - /* Clear the transmit and receive configuration registers. */ - outw(RCR_CLEAR, ioaddr + RCR); - outw(TCR_CLEAR, ioaddr + TCR); - - /* Set the Window 1 control, configuration and station addr registers. - No point in writing the I/O base register ;-> */ - SMC_SELECT_BANK(1); - /* Automatically release successfully transmitted packets, - Accept link errors, counter and Tx error interrupts. */ - outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, - ioaddr + CONTROL); - smc_set_xcvr(dev, dev->if_port); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) - outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) | - (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00), - ioaddr - 0x10 + OSITECH_AUI_PWR); - - /* Fill in the physical address. The databook is wrong about the order! */ - for (i = 0; i < 6; i += 2) - outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i], - ioaddr + ADDR0 + i); - - /* Reset the MMU */ - SMC_SELECT_BANK(2); - outw(MC_RESET, ioaddr + MMU_CMD); - outw(0, ioaddr + INTERRUPT); - - /* Re-enable the chip. */ - SMC_SELECT_BANK(0); - outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) | - TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR); - set_rx_mode(dev); - - if (smc->cfg & CFG_MII_SELECT) { - SMC_SELECT_BANK(3); - - /* Reset MII */ - mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000); - - /* Advertise 100F, 100H, 10F, 10H */ - mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1); - - /* Restart MII autonegotiation */ - mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000); - mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200); - } - - /* Enable interrupts. */ - SMC_SELECT_BANK(2); - outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8, - ioaddr + INTERRUPT); -} - -/*====================================================================== - - Media selection timer routine - -======================================================================*/ - -static void media_check(struct timer_list *t) -{ - struct smc_private *smc = timer_container_of(smc, t, media); - struct net_device *dev = smc->mii_if.dev; - unsigned int ioaddr = dev->base_addr; - u_short i, media, saved_bank; - u_short link; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - - saved_bank = inw(ioaddr + BANK_SELECT); - - if (!netif_device_present(dev)) - goto reschedule; - - SMC_SELECT_BANK(2); - - /* need MC_RESET to keep the memory consistent. errata? */ - if (smc->rx_ovrn) { - outw(MC_RESET, ioaddr + MMU_CMD); - smc->rx_ovrn = 0; - } - i = inw(ioaddr + INTERRUPT); - SMC_SELECT_BANK(0); - media = inw(ioaddr + EPH) & EPH_LINK_OK; - SMC_SELECT_BANK(1); - media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1; - - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - - /* Check for pending interrupt with watchdog flag set: with - this, we can limp along even if the interrupt is blocked */ - if (smc->watchdog++ && ((i>>8) & i)) { - if (!smc->fast_poll) - netdev_info(dev, "interrupt(s) dropped!\n"); - local_irq_save(flags); - smc_interrupt(dev->irq, dev); - local_irq_restore(flags); - smc->fast_poll = HZ; - } - if (smc->fast_poll) { - smc->fast_poll--; - smc->media.expires = jiffies + HZ/100; - add_timer(&smc->media); - return; - } - - spin_lock_irqsave(&smc->lock, flags); - - saved_bank = inw(ioaddr + BANK_SELECT); - - if (smc->cfg & CFG_MII_SELECT) { - if (smc->mii_if.phy_id < 0) - goto reschedule; - - SMC_SELECT_BANK(3); - link = mdio_read(dev, smc->mii_if.phy_id, 1); - if (!link || (link == 0xffff)) { - netdev_info(dev, "MII is missing!\n"); - smc->mii_if.phy_id = -1; - goto reschedule; - } - - link &= 0x0004; - if (link != smc->link_status) { - u_short p = mdio_read(dev, smc->mii_if.phy_id, 5); - netdev_info(dev, "%s link beat\n", link ? "found" : "lost"); - smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40)) - ? TCR_FDUPLX : 0); - if (link) { - netdev_info(dev, "autonegotiation complete: " - "%dbaseT-%cD selected\n", - (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H'); - } - SMC_SELECT_BANK(0); - outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR); - smc->link_status = link; - } - goto reschedule; - } - - /* Ignore collisions unless we've had no rx's recently */ - if (time_after(jiffies, smc->last_rx + HZ)) { - if (smc->tx_err || (smc->media_status & EPH_16COL)) - media |= EPH_16COL; - } - smc->tx_err = 0; - - if (media != smc->media_status) { - if ((media & smc->media_status & 1) && - ((smc->media_status ^ media) & EPH_LINK_OK)) - netdev_info(dev, "%s link beat\n", - smc->media_status & EPH_LINK_OK ? "lost" : "found"); - else if ((media & smc->media_status & 2) && - ((smc->media_status ^ media) & EPH_16COL)) - netdev_info(dev, "coax cable %s\n", - media & EPH_16COL ? "problem" : "ok"); - if (dev->if_port == 0) { - if (media & 1) { - if (media & EPH_LINK_OK) - netdev_info(dev, "flipped to 10baseT\n"); - else - smc_set_xcvr(dev, 2); - } else { - if (media & EPH_16COL) - smc_set_xcvr(dev, 1); - else - netdev_info(dev, "flipped to 10base2\n"); - } - } - smc->media_status = media; - } - -reschedule: - smc->media.expires = jiffies + HZ; - add_timer(&smc->media); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); -} - -static int smc_link_ok(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct smc_private *smc = netdev_priv(dev); - - if (smc->cfg & CFG_MII_SELECT) { - return mii_link_ok(&smc->mii_if); - } else { - SMC_SELECT_BANK(0); - return inw(ioaddr + EPH) & EPH_LINK_OK; - } -} - -static void smc_netdev_get_ecmd(struct net_device *dev, - struct ethtool_link_ksettings *ecmd) -{ - u16 tmp; - unsigned int ioaddr = dev->base_addr; - u32 supported; - - supported = (SUPPORTED_TP | SUPPORTED_AUI | - SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full); - - SMC_SELECT_BANK(1); - tmp = inw(ioaddr + CONFIG); - ecmd->base.port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP; - ecmd->base.speed = SPEED_10; - ecmd->base.phy_address = ioaddr + MGMT; - - SMC_SELECT_BANK(0); - tmp = inw(ioaddr + TCR); - ecmd->base.duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF; - - ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported, - supported); -} - -static int smc_netdev_set_ecmd(struct net_device *dev, - const struct ethtool_link_ksettings *ecmd) -{ - u16 tmp; - unsigned int ioaddr = dev->base_addr; - - if (ecmd->base.speed != SPEED_10) - return -EINVAL; - if (ecmd->base.duplex != DUPLEX_HALF && - ecmd->base.duplex != DUPLEX_FULL) - return -EINVAL; - if (ecmd->base.port != PORT_TP && ecmd->base.port != PORT_AUI) - return -EINVAL; - - if (ecmd->base.port == PORT_AUI) - smc_set_xcvr(dev, 1); - else - smc_set_xcvr(dev, 0); - - SMC_SELECT_BANK(0); - tmp = inw(ioaddr + TCR); - if (ecmd->base.duplex == DUPLEX_FULL) - tmp |= TCR_FDUPLX; - else - tmp &= ~TCR_FDUPLX; - outw(tmp, ioaddr + TCR); - - return 0; -} - -static int check_if_running(struct net_device *dev) -{ - if (!netif_running(dev)) - return -EINVAL; - return 0; -} - -static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->version, DRV_VERSION, sizeof(info->version)); -} - -static int smc_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *ecmd) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - if (smc->cfg & CFG_MII_SELECT) - mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd); - else - smc_netdev_get_ecmd(dev, ecmd); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return 0; -} - -static int smc_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *ecmd) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - int ret; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - if (smc->cfg & CFG_MII_SELECT) - ret = mii_ethtool_set_link_ksettings(&smc->mii_if, ecmd); - else - ret = smc_netdev_set_ecmd(dev, ecmd); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return ret; -} - -static u32 smc_get_link(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - u32 ret; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - ret = smc_link_ok(dev); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return ret; -} - -static int smc_nway_reset(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - if (smc->cfg & CFG_MII_SELECT) { - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - int res; - - SMC_SELECT_BANK(3); - res = mii_nway_restart(&smc->mii_if); - SMC_SELECT_BANK(saved_bank); - - return res; - } else - return -EOPNOTSUPP; -} - -static const struct ethtool_ops ethtool_ops = { - .begin = check_if_running, - .get_drvinfo = smc_get_drvinfo, - .get_link = smc_get_link, - .nway_reset = smc_nway_reset, - .get_link_ksettings = smc_get_link_ksettings, - .set_link_ksettings = smc_set_link_ksettings, -}; - -static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct smc_private *smc = netdev_priv(dev); - struct mii_ioctl_data *mii = if_mii(rq); - int rc = 0; - u16 saved_bank; - unsigned int ioaddr = dev->base_addr; - unsigned long flags; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irqsave(&smc->lock, flags); - saved_bank = inw(ioaddr + BANK_SELECT); - SMC_SELECT_BANK(3); - rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return rc; -} - -static const struct pcmcia_device_id smc91c92_ids[] = { - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed), - PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020), - PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023), - PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb), - PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc), - PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1), - PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5), - PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9), - PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953), - PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a), - PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314), - PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc), - PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9), - PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d), - /* These conflict with other cards! */ - /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */ - /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids); - -static struct pcmcia_driver smc91c92_cs_driver = { - .owner = THIS_MODULE, - .name = "smc91c92_cs", - .probe = smc91c92_probe, - .remove = smc91c92_detach, - .id_table = smc91c92_ids, - .suspend = smc91c92_suspend, - .resume = smc91c92_resume, -}; -module_pcmcia_driver(smc91c92_cs_driver); diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c deleted file mode 100644 index c8b2dc5c1bec..000000000000 --- a/drivers/net/hamradio/6pack.c +++ /dev/null @@ -1,912 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * 6pack.c This module implements the 6pack protocol for kernel-based - * devices like TTY. It interfaces between a raw TTY and the - * kernel's AX.25 protocol layers. - * - * Authors: Andreas Könsgen - * Ralf Baechle DL5RB - * - * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by - * - * Laurence Culhane, - * Fred N. van Kempen, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* sixpack priority commands */ -#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */ -#define SIXP_TX_URUN 0x48 /* transmit overrun */ -#define SIXP_RX_ORUN 0x50 /* receive overrun */ -#define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */ - -#define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */ - -/* masks to get certain bits out of the status bytes sent by the TNC */ - -#define SIXP_CMD_MASK 0xC0 -#define SIXP_CHN_MASK 0x07 -#define SIXP_PRIO_CMD_MASK 0x80 -#define SIXP_STD_CMD_MASK 0x40 -#define SIXP_PRIO_DATA_MASK 0x38 -#define SIXP_TX_MASK 0x20 -#define SIXP_RX_MASK 0x10 -#define SIXP_RX_DCD_MASK 0x18 -#define SIXP_LEDS_ON 0x78 -#define SIXP_LEDS_OFF 0x60 -#define SIXP_CON 0x08 -#define SIXP_STA 0x10 - -#define SIXP_FOUND_TNC 0xe9 -#define SIXP_CON_ON 0x68 -#define SIXP_DCD_MASK 0x08 -#define SIXP_DAMA_OFF 0 - -/* default level 2 parameters */ -#define SIXP_TXDELAY 25 /* 250 ms */ -#define SIXP_PERSIST 50 /* in 256ths */ -#define SIXP_SLOTTIME 10 /* 100 ms */ -#define SIXP_INIT_RESYNC_TIMEOUT (3*HZ/2) /* in 1 s */ -#define SIXP_RESYNC_TIMEOUT 5*HZ /* in 1 s */ - -/* 6pack configuration. */ -#define SIXP_NRUNIT 31 /* MAX number of 6pack channels */ -#define SIXP_MTU 256 /* Default MTU */ - -enum sixpack_flags { - SIXPF_ERROR, /* Parity, etc. error */ -}; - -struct sixpack { - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ - - /* These are pointers to the malloc()ed frame buffers. */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ - - u8 raw_buf[4]; - u8 cooked_buf[400]; - - unsigned int rx_count; - unsigned int rx_count_cooked; - spinlock_t rxlock; - - unsigned long flags; /* Flag values/ mode etc */ - unsigned char mode; /* 6pack mode */ - - /* 6pack stuff */ - unsigned char tx_delay; - unsigned char persistence; - unsigned char slottime; - unsigned char duplex; - unsigned char led_state; - u8 status; - u8 status1; - unsigned char status2; - unsigned char tx_enable; - unsigned char tnc_state; - - struct timer_list tx_t; - struct timer_list resync_t; - spinlock_t lock; -}; - -#define AX25_6PACK_HEADER_LEN 0 - -static void sixpack_decode(struct sixpack *, const u8 *, size_t); -static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); - -/* - * Perform the persistence/slottime algorithm for CSMA access. If the - * persistence check was successful, write the data to the serial driver. - * Note that in case of DAMA operation, the data is not sent here. - */ - -static void sp_xmit_on_air(struct timer_list *t) -{ - struct sixpack *sp = timer_container_of(sp, t, tx_t); - int actual, when = sp->slottime; - static unsigned char random; - - random = random * 17 + 41; - - if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) { - sp->led_state = 0x70; - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - sp->tx_enable = 1; - actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2); - sp->xleft -= actual; - sp->xhead += actual; - sp->led_state = 0x60; - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - sp->status2 = 0; - } else - mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100); -} - -/* ----> 6pack timer interrupt handler and friends. <---- */ - -/* Encapsulate one AX.25 frame and stuff into a TTY queue. */ -static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len) -{ - unsigned char *msg, *p = icp; - int actual, count; - - if (len > AX25_MTU + 73) { - msg = "oversized transmit packet!"; - goto out_drop; - } - - if (p[0] > 5) { - msg = "invalid KISS command"; - goto out_drop; - } - - if ((p[0] != 0) && (len > 2)) { - msg = "KISS control packet too long"; - goto out_drop; - } - - if ((p[0] == 0) && (len < 15)) { - msg = "bad AX.25 packet to transmit"; - goto out_drop; - } - - count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay); - set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags); - - switch (p[0]) { - case 1: sp->tx_delay = p[1]; - return; - case 2: sp->persistence = p[1]; - return; - case 3: sp->slottime = p[1]; - return; - case 4: /* ignored */ - return; - case 5: sp->duplex = p[1]; - return; - } - - if (p[0] != 0) - return; - - /* - * In case of fullduplex or DAMA operation, we don't take care about the - * state of the DCD or of any timers, as the determination of the - * correct time to send is the job of the AX.25 layer. We send - * immediately after data has arrived. - */ - if (sp->duplex == 1) { - sp->led_state = 0x70; - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - sp->tx_enable = 1; - actual = sp->tty->ops->write(sp->tty, sp->xbuff, count); - sp->xleft = count - actual; - sp->xhead = sp->xbuff + actual; - sp->led_state = 0x60; - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - } else { - sp->xleft = count; - sp->xhead = sp->xbuff; - sp->status2 = count; - sp_xmit_on_air(&sp->tx_t); - } - - return; - -out_drop: - sp->dev->stats.tx_dropped++; - netif_start_queue(sp->dev); - if (net_ratelimit()) - printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg); -} - -/* Encapsulate an IP datagram and kick it into a TTY queue. */ - -static netdev_tx_t sp_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct sixpack *sp = netdev_priv(dev); - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - spin_lock_bh(&sp->lock); - /* We were not busy, so we are now... :-) */ - netif_stop_queue(dev); - dev->stats.tx_bytes += skb->len; - sp_encaps(sp, skb->data, skb->len); - spin_unlock_bh(&sp->lock); - - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static int sp_open_dev(struct net_device *dev) -{ - struct sixpack *sp = netdev_priv(dev); - - if (sp->tty == NULL) - return -ENODEV; - return 0; -} - -/* Close the low-level part of the 6pack channel. */ -static int sp_close(struct net_device *dev) -{ - struct sixpack *sp = netdev_priv(dev); - - spin_lock_bh(&sp->lock); - if (sp->tty) { - /* TTY discipline is running. */ - clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags); - } - netif_stop_queue(dev); - spin_unlock_bh(&sp->lock); - - return 0; -} - -static int sp_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr_ax25 *sa = addr; - - netif_tx_lock_bh(dev); - netif_addr_lock(dev); - __dev_addr_set(dev, &sa->sax25_call, AX25_ADDR_LEN); - netif_addr_unlock(dev); - netif_tx_unlock_bh(dev); - - return 0; -} - -static const struct net_device_ops sp_netdev_ops = { - .ndo_open = sp_open_dev, - .ndo_stop = sp_close, - .ndo_start_xmit = sp_xmit, - .ndo_set_mac_address = sp_set_mac_address, -}; - -static void sp_setup(struct net_device *dev) -{ - /* Finish setting up the DEVICE info. */ - dev->netdev_ops = &sp_netdev_ops; - dev->mtu = SIXP_MTU; - dev->hard_header_len = AX25_MAX_HEADER_LEN; - dev->header_ops = &ax25_header_ops; - - dev->addr_len = AX25_ADDR_LEN; - dev->type = ARPHRD_AX25; - dev->tx_queue_len = 10; - - /* Only activated in AX.25 mode */ - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&ax25_defaddr); - - dev->flags = 0; -} - -/* Send one completely decapsulated IP datagram to the IP layer. */ - -/* - * This is the routine that sends the received data to the kernel AX.25. - * 'cmd' is the KISS command. For AX.25 data, it is zero. - */ - -static void sp_bump(struct sixpack *sp, char cmd) -{ - struct sk_buff *skb; - int count; - u8 *ptr; - - count = sp->rcount + 1; - - sp->dev->stats.rx_bytes += count; - - if ((skb = dev_alloc_skb(count + 1)) == NULL) - goto out_mem; - - ptr = skb_put(skb, count + 1); - *ptr++ = cmd; /* KISS command */ - - memcpy(ptr, sp->cooked_buf + 1, count); - skb->protocol = ax25_type_trans(skb, sp->dev); - netif_rx(skb); - sp->dev->stats.rx_packets++; - - return; - -out_mem: - sp->dev->stats.rx_dropped++; -} - - -/* ----------------------------------------------------------------------- */ - -/* - * Called by the TTY driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void sixpack_write_wakeup(struct tty_struct *tty) -{ - struct sixpack *sp = tty->disc_data; - int actual; - - if (!sp) - return; - if (sp->xleft <= 0) { - /* Now serial buffer is almost free & we can start - * transmission of another packet */ - sp->dev->stats.tx_packets++; - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sp->tx_enable = 0; - netif_wake_queue(sp->dev); - return; - } - - if (sp->tx_enable) { - actual = tty->ops->write(tty, sp->xhead, sp->xleft); - sp->xleft -= actual; - sp->xhead += actual; - } -} - -/* ----------------------------------------------------------------------- */ - -/* - * Handle the 'receiver data ready' interrupt. - * This function is called by the tty module in the kernel when - * a block of 6pack data has been received, which can now be decapsulated - * and sent on to some IP layer for further processing. - */ -static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, - const u8 *fp, size_t count) -{ - struct sixpack *sp; - - if (!count) - return; - - sp = tty->disc_data; - if (!sp) - return; - - /* Read the characters out of the buffer */ - while (count--) { - if (fp && *fp++) { - if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) - sp->dev->stats.rx_errors++; - cp++; - continue; - } - sixpack_decode(sp, cp, 1); - cp++; - } - - tty_unthrottle(tty); -} - -/* - * Try to resync the TNC. Called by the resync timer defined in - * decode_prio_command - */ - -#define TNC_UNINITIALIZED 0 -#define TNC_UNSYNC_STARTUP 1 -#define TNC_UNSYNCED 2 -#define TNC_IN_SYNC 3 - -static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state) -{ - char *msg; - - switch (new_tnc_state) { - default: /* gcc oh piece-o-crap ... */ - case TNC_UNSYNC_STARTUP: - msg = "Synchronizing with TNC"; - break; - case TNC_UNSYNCED: - msg = "Lost synchronization with TNC\n"; - break; - case TNC_IN_SYNC: - msg = "Found TNC"; - break; - } - - sp->tnc_state = new_tnc_state; - printk(KERN_INFO "%s: %s\n", sp->dev->name, msg); -} - -static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state) -{ - int old_tnc_state = sp->tnc_state; - - if (old_tnc_state != new_tnc_state) - __tnc_set_sync_state(sp, new_tnc_state); -} - -static void resync_tnc(struct timer_list *t) -{ - struct sixpack *sp = timer_container_of(sp, t, resync_t); - static char resync_cmd = 0xe8; - - /* clear any data that might have been received */ - - sp->rx_count = 0; - sp->rx_count_cooked = 0; - - /* reset state machine */ - - sp->status = 1; - sp->status1 = 1; - sp->status2 = 0; - - /* resync the TNC */ - - sp->led_state = 0x60; - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - sp->tty->ops->write(sp->tty, &resync_cmd, 1); - - - /* Start resync timer again -- the TNC might be still absent */ - mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT); -} - -static inline int tnc_init(struct sixpack *sp) -{ - unsigned char inbyte = 0xe8; - - tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP); - - sp->tty->ops->write(sp->tty, &inbyte, 1); - - mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT); - - return 0; -} - -/* - * Open the high-level part of the 6pack channel. - * This function is called by the TTY module when the - * 6pack line discipline is called for. Because we are - * sure the tty line exists, we only have to link it to - * a free 6pcack channel... - */ -static int sixpack_open(struct tty_struct *tty) -{ - char *xbuff = NULL; - struct net_device *dev; - struct sixpack *sp; - unsigned long len; - int err = 0; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (tty->ops->write == NULL) - return -EOPNOTSUPP; - - dev = alloc_netdev(sizeof(struct sixpack), "sp%d", NET_NAME_UNKNOWN, - sp_setup); - if (!dev) { - err = -ENOMEM; - goto out; - } - - sp = netdev_priv(dev); - sp->dev = dev; - - spin_lock_init(&sp->lock); - spin_lock_init(&sp->rxlock); - - /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */ - - len = dev->mtu * 2; - - xbuff = kmalloc(len + 4, GFP_KERNEL); - if (xbuff == NULL) { - err = -ENOBUFS; - goto out_free; - } - - spin_lock_bh(&sp->lock); - - sp->tty = tty; - - sp->xbuff = xbuff; - - sp->rcount = 0; - sp->rx_count = 0; - sp->rx_count_cooked = 0; - sp->xleft = 0; - - sp->flags = 0; /* Clear ESCAPE & ERROR flags */ - - sp->duplex = 0; - sp->tx_delay = SIXP_TXDELAY; - sp->persistence = SIXP_PERSIST; - sp->slottime = SIXP_SLOTTIME; - sp->led_state = 0x60; - sp->status = 1; - sp->status1 = 1; - sp->status2 = 0; - sp->tx_enable = 0; - - netif_start_queue(dev); - - timer_setup(&sp->tx_t, sp_xmit_on_air, 0); - - timer_setup(&sp->resync_t, resync_tnc, 0); - - spin_unlock_bh(&sp->lock); - - /* Done. We have linked the TTY line to a channel. */ - tty->disc_data = sp; - tty->receive_room = 65536; - - /* Now we're ready to register. */ - err = register_netdev(dev); - if (err) - goto out_free; - - tnc_init(sp); - - return 0; - -out_free: - kfree(xbuff); - - free_netdev(dev); - -out: - return err; -} - - -/* - * Close down a 6pack channel. - * This means flushing out any pending queues, and then restoring the - * TTY line discipline to what it was before it got hooked to 6pack - * (which usually is TTY again). - */ -static void sixpack_close(struct tty_struct *tty) -{ - struct sixpack *sp; - - sp = tty->disc_data; - if (!sp) - return; - - tty->disc_data = NULL; - - /* We must stop the queue to avoid potentially scribbling - * on the free buffers. The sp->dead completion is not sufficient - * to protect us from sp->xbuff access. - */ - netif_stop_queue(sp->dev); - - unregister_netdev(sp->dev); - - timer_delete_sync(&sp->tx_t); - timer_delete_sync(&sp->resync_t); - - /* Free all 6pack frame buffers after unreg. */ - kfree(sp->xbuff); - - free_netdev(sp->dev); -} - -/* Perform I/O control on an active 6pack channel. */ -static int sixpack_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct sixpack *sp = tty->disc_data; - struct net_device *dev; - unsigned int tmp, err; - - if (!sp) - return -ENXIO; - dev = sp->dev; - - switch(cmd) { - case SIOCGIFNAME: - err = copy_to_user((void __user *) arg, dev->name, - strlen(dev->name) + 1) ? -EFAULT : 0; - break; - - case SIOCGIFENCAP: - err = put_user(0, (int __user *) arg); - break; - - case SIOCSIFENCAP: - if (get_user(tmp, (int __user *) arg)) { - err = -EFAULT; - break; - } - - sp->mode = tmp; - dev->addr_len = AX25_ADDR_LEN; - dev->hard_header_len = AX25_KISS_HEADER_LEN + - AX25_MAX_HEADER_LEN + 3; - dev->type = ARPHRD_AX25; - - err = 0; - break; - - case SIOCSIFHWADDR: { - char addr[AX25_ADDR_LEN]; - - if (copy_from_user(&addr, - (void __user *)arg, AX25_ADDR_LEN)) { - err = -EFAULT; - break; - } - - netif_tx_lock_bh(dev); - __dev_addr_set(dev, &addr, AX25_ADDR_LEN); - netif_tx_unlock_bh(dev); - err = 0; - break; - } - default: - err = tty_mode_ioctl(tty, cmd, arg); - } - - return err; -} - -static struct tty_ldisc_ops sp_ldisc = { - .owner = THIS_MODULE, - .num = N_6PACK, - .name = "6pack", - .open = sixpack_open, - .close = sixpack_close, - .ioctl = sixpack_ioctl, - .receive_buf = sixpack_receive_buf, - .write_wakeup = sixpack_write_wakeup, -}; - -/* Initialize 6pack control device -- register 6pack line discipline */ - -static int __init sixpack_init_driver(void) -{ - int status; - - /* Register the provided line protocol discipline */ - status = tty_register_ldisc(&sp_ldisc); - if (status) - pr_err("6pack: can't register line discipline (err = %d)\n", status); - - return status; -} - -static void __exit sixpack_exit_driver(void) -{ - tty_unregister_ldisc(&sp_ldisc); -} - -/* encode an AX.25 packet into 6pack */ - -static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, - int length, unsigned char tx_delay) -{ - int count = 0; - unsigned char checksum = 0, buf[400]; - int raw_count = 0; - - tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK; - tx_buf_raw[raw_count++] = SIXP_SEOF; - - buf[0] = tx_delay; - for (count = 1; count < length; count++) - buf[count] = tx_buf[count]; - - for (count = 0; count < length; count++) - checksum += buf[count]; - buf[length] = (unsigned char) 0xff - checksum; - - for (count = 0; count <= length; count++) { - if ((count % 3) == 0) { - tx_buf_raw[raw_count++] = (buf[count] & 0x3f); - tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30); - } else if ((count % 3) == 1) { - tx_buf_raw[raw_count++] |= (buf[count] & 0x0f); - tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x3c); - } else { - tx_buf_raw[raw_count++] |= (buf[count] & 0x03); - tx_buf_raw[raw_count++] = (buf[count] >> 2); - } - } - if ((length % 3) != 2) - raw_count++; - tx_buf_raw[raw_count++] = SIXP_SEOF; - return raw_count; -} - -/* decode 4 sixpack-encoded bytes into 3 data bytes */ - -static void decode_data(struct sixpack *sp, u8 inbyte) -{ - u8 *buf; - - if (sp->rx_count != 3) { - sp->raw_buf[sp->rx_count++] = inbyte; - - return; - } - - if (sp->rx_count_cooked + 2 >= sizeof(sp->cooked_buf)) { - pr_err("6pack: cooked buffer overrun, data loss\n"); - sp->rx_count = 0; - return; - } - - buf = sp->raw_buf; - sp->cooked_buf[sp->rx_count_cooked++] = - buf[0] | ((buf[1] << 2) & 0xc0); - sp->cooked_buf[sp->rx_count_cooked++] = - (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); - sp->cooked_buf[sp->rx_count_cooked++] = - (buf[2] & 0x03) | (inbyte << 2); - sp->rx_count = 0; -} - -/* identify and execute a 6pack priority command byte */ - -static void decode_prio_command(struct sixpack *sp, u8 cmd) -{ - ssize_t actual; - - if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ - - /* RX and DCD flags can only be set in the same prio command, - if the DCD flag has been set without the RX flag in the previous - prio command. If DCD has not been set before, something in the - transmission has gone wrong. In this case, RX and DCD are - cleared in order to prevent the decode_data routine from - reading further data that might be corrupt. */ - - if (((sp->status & SIXP_DCD_MASK) == 0) && - ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) { - if (sp->status != 1) - printk(KERN_DEBUG "6pack: protocol violation\n"); - else - sp->status = 0; - cmd &= ~SIXP_RX_DCD_MASK; - } - sp->status = cmd & SIXP_PRIO_DATA_MASK; - } else { /* output watchdog char if idle */ - if ((sp->status2 != 0) && (sp->duplex == 1)) { - sp->led_state = 0x70; - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - sp->tx_enable = 1; - actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2); - sp->xleft -= actual; - sp->xhead += actual; - sp->led_state = 0x60; - sp->status2 = 0; - - } - } - - /* needed to trigger the TNC watchdog */ - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - - /* if the state byte has been received, the TNC is present, - so the resync timer can be reset. */ - - if (sp->tnc_state == TNC_IN_SYNC) - mod_timer(&sp->resync_t, jiffies + SIXP_INIT_RESYNC_TIMEOUT); - - sp->status1 = cmd & SIXP_PRIO_DATA_MASK; -} - -/* identify and execute a standard 6pack command byte */ - -static void decode_std_command(struct sixpack *sp, u8 cmd) -{ - u8 checksum = 0, rest = 0; - short i; - - switch (cmd & SIXP_CMD_MASK) { /* normal command */ - case SIXP_SEOF: - if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) { - if ((sp->status & SIXP_RX_DCD_MASK) == - SIXP_RX_DCD_MASK) { - sp->led_state = 0x68; - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - } - } else { - sp->led_state = 0x60; - /* fill trailing bytes with zeroes */ - sp->tty->ops->write(sp->tty, &sp->led_state, 1); - spin_lock_bh(&sp->rxlock); - rest = sp->rx_count; - if (rest != 0) - for (i = rest; i <= 3; i++) - decode_data(sp, 0); - if (rest == 2) - sp->rx_count_cooked -= 2; - else if (rest == 3) - sp->rx_count_cooked -= 1; - for (i = 0; i < sp->rx_count_cooked; i++) - checksum += sp->cooked_buf[i]; - if (checksum != SIXP_CHKSUM) { - printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum); - } else { - sp->rcount = sp->rx_count_cooked-2; - sp_bump(sp, 0); - } - sp->rx_count_cooked = 0; - spin_unlock_bh(&sp->rxlock); - } - break; - case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n"); - break; - case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n"); - break; - case SIXP_RX_BUF_OVL: - printk(KERN_DEBUG "6pack: RX buffer overflow\n"); - } -} - -/* decode a 6pack packet */ - -static void -sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count) -{ - size_t count1; - u8 inbyte; - - for (count1 = 0; count1 < count; count1++) { - inbyte = pre_rbuff[count1]; - if (inbyte == SIXP_FOUND_TNC) { - tnc_set_sync_state(sp, TNC_IN_SYNC); - timer_delete(&sp->resync_t); - } - if ((inbyte & SIXP_PRIO_CMD_MASK) != 0) - decode_prio_command(sp, inbyte); - else if ((inbyte & SIXP_STD_CMD_MASK) != 0) - decode_std_command(sp, inbyte); - else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) { - spin_lock_bh(&sp->rxlock); - decode_data(sp, inbyte); - spin_unlock_bh(&sp->rxlock); - } - } -} - -MODULE_AUTHOR("Ralf Baechle DO1GRB "); -MODULE_DESCRIPTION("6pack driver for AX.25"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_6PACK); - -module_init(sixpack_init_driver); -module_exit(sixpack_exit_driver); diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig deleted file mode 100644 index 36a9aade9f33..000000000000 --- a/drivers/net/hamradio/Kconfig +++ /dev/null @@ -1,162 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config MKISS - tristate "Serial port KISS driver" - depends on AX25 && TTY - select CRC16 - help - KISS is a protocol used for the exchange of data between a computer - and a Terminal Node Controller (a small embedded system commonly - used for networking over AX.25 amateur radio connections; it - connects the computer's serial port with the radio's microphone - input and speaker output). - - Although KISS is less advanced than the 6pack protocol, it has - the advantage that it is already supported by most modern TNCs - without the need for a firmware upgrade. - - To compile this driver as a module, choose M here: the module - will be called mkiss. - -config 6PACK - tristate "Serial port 6PACK driver" - depends on AX25 && TTY - help - 6pack is a transmission protocol for the data exchange between your - PC and your TNC (the Terminal Node Controller acts as a kind of - modem connecting your computer's serial port to your radio's - microphone input and speaker output). This protocol can be used as - an alternative to KISS for networking over AX.25 amateur radio - connections, but it has some extended functionality. - - Note that this driver is still experimental and might cause - problems. For details about the features and the usage of the - driver, read . - - To compile this driver as a module, choose M here: the module - will be called 6pack. - -config BPQETHER - tristate "BPQ Ethernet driver" - depends on AX25 - help - AX.25 is the protocol used for computer communication over amateur - radio. If you say Y here, you will be able to send and receive AX.25 - traffic over Ethernet (also called "BPQ AX.25"), which could be - useful if some other computer on your local network has a direct - amateur radio connection. - -config SCC - tristate "Z8530 SCC driver" - depends on ISA && AX25 - help - These cards are used to connect your Linux box to an amateur radio - in order to communicate with other computers. If you want to use - this, read - - and the AX25-HOWTO, available from - . Also make sure to say Y - to "Amateur Radio AX.25 Level 2" support. - - To compile this driver as a module, choose M here: the module - will be called scc. - -config SCC_DELAY - bool "additional delay for PA0HZP OptoSCC compatible boards" - depends on SCC - help - Say Y here if you experience problems with the SCC driver not - working properly; please read - - for details. - - If unsure, say N. - -config SCC_TRXECHO - bool "support for TRX that feedback the tx signal to rx" - depends on SCC - help - Some transmitters feed the transmitted signal back to the receive - line. Say Y here to foil this by explicitly disabling the receiver - during data transmission. - - If in doubt, say Y. - -config BAYCOM_SER_FDX - tristate "BAYCOM ser12 fullduplex driver for AX.25" - depends on AX25 && HAS_IOPORT - select CRC_CCITT - help - This is one of two drivers for Baycom style simple amateur radio - modems that connect to a serial interface. The driver supports the - ser12 design in full-duplex mode. In addition, it allows the - baudrate to be set between 300 and 4800 baud (however not all modems - support all baudrates). This is the preferred driver. The next - driver, "BAYCOM ser12 half-duplex driver for AX.25" is the old - driver and still provided in case this driver does not work with - your serial interface chip. To configure the driver, use the sethdlc - utility available in the standard ax25 utilities package. - For more information on the modems, see - . - - To compile this driver as a module, choose M here: the module - will be called baycom_ser_fdx. This is recommended. - -config BAYCOM_SER_HDX - tristate "BAYCOM ser12 halfduplex driver for AX.25" - depends on AX25 && HAS_IOPORT - select CRC_CCITT - help - This is one of two drivers for Baycom style simple amateur radio - modems that connect to a serial interface. The driver supports the - ser12 design in half-duplex mode. This is the old driver. It is - still provided in case your serial interface chip does not work with - the full-duplex driver. This driver is deprecated. To configure - the driver, use the sethdlc utility available in the standard ax25 - utilities package. For more information on the modems, see - . - - To compile this driver as a module, choose M here: the module - will be called baycom_ser_hdx. This is recommended. - -config BAYCOM_PAR - tristate "BAYCOM picpar and par96 driver for AX.25" - depends on PARPORT && AX25 - select CRC_CCITT - help - This is a driver for Baycom style simple amateur radio modems that - connect to a parallel interface. The driver supports the picpar and - par96 designs. To configure the driver, use the sethdlc utility - available in the standard ax25 utilities package. - For more information on the modems, see - . - - To compile this driver as a module, choose M here: the module - will be called baycom_par. This is recommended. - -config BAYCOM_EPP - tristate "BAYCOM epp driver for AX.25" - depends on PARPORT && AX25 && !64BIT - select CRC_CCITT - help - This is a driver for Baycom style simple amateur radio modems that - connect to a parallel interface. The driver supports the EPP - designs. To configure the driver, use the sethdlc utility available - in the standard ax25 utilities package. - For more information on the modems, see - . - - To compile this driver as a module, choose M here: the module - will be called baycom_epp. This is recommended. - -config YAM - tristate "YAM driver for AX.25" - depends on AX25 && HAS_IOPORT - help - The YAM is a modem for packet radio which connects to the serial - port and includes some of the functions of a Terminal Node - Controller. If you have one of those, say Y here. - - To compile this driver as a module, choose M here: the module - will be called yam. - - diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile deleted file mode 100644 index 25fc400369ba..000000000000 --- a/drivers/net/hamradio/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the Linux AX.25 and HFMODEM device drivers. -# -# -# 19971130 Moved the amateur radio related network drivers from -# drivers/net/ to drivers/hamradio for easier maintenance. -# Joerg Reuter DL1BKE -# -# 20000806 Rewritten to use lists instead of if-statements. -# Christoph Hellwig -# - -obj-$(CONFIG_SCC) += scc.o -obj-$(CONFIG_MKISS) += mkiss.o -obj-$(CONFIG_6PACK) += 6pack.o -obj-$(CONFIG_YAM) += yam.o -obj-$(CONFIG_BPQETHER) += bpqether.o -obj-$(CONFIG_BAYCOM_SER_FDX) += baycom_ser_fdx.o hdlcdrv.o -obj-$(CONFIG_BAYCOM_SER_HDX) += baycom_ser_hdx.o hdlcdrv.o -obj-$(CONFIG_BAYCOM_PAR) += baycom_par.o hdlcdrv.o -obj-$(CONFIG_BAYCOM_EPP) += baycom_epp.o hdlcdrv.o diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c deleted file mode 100644 index 5fda7a0fcce0..000000000000 --- a/drivers/net/hamradio/baycom_epp.c +++ /dev/null @@ -1,1316 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*****************************************************************************/ - -/* - * baycom_epp.c -- baycom epp radio modem driver. - * - * Copyright (C) 1998-2000 - * Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * History: - * 0.1 xx.xx.1998 Initial version by Matthias Welwarsky (dg2fef) - * 0.2 21.04.1998 Massive rework by Thomas Sailer - * Integrated FPGA EPP modem configuration routines - * 0.3 11.05.1998 Took FPGA config out and moved it into a separate program - * 0.4 26.07.1999 Adapted to new lowlevel parport driver interface - * 0.5 03.08.1999 adapt to Linus' new __setup/__initcall - * removed some pre-2.2 kernel compatibility cruft - * 0.6 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts - * 0.7 12.02.2000 adapted to softnet driver interface - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* --------------------------------------------------------------------- */ - -#define BAYCOM_DEBUG -#define BAYCOM_MAGIC 19730510 - -/* --------------------------------------------------------------------- */ - -static const char paranoia_str[] = KERN_ERR - "baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n"; - -static const char bc_drvname[] = "baycom_epp"; -static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_epp: version 0.7\n"; - -/* --------------------------------------------------------------------- */ - -#define NR_PORTS 4 - -static struct net_device *baycom_device[NR_PORTS]; - -/* --------------------------------------------------------------------- */ - -/* EPP status register */ -#define EPP_DCDBIT 0x80 -#define EPP_PTTBIT 0x08 -#define EPP_NREF 0x01 -#define EPP_NRAEF 0x02 -#define EPP_NRHF 0x04 -#define EPP_NTHF 0x20 -#define EPP_NTAEF 0x10 -#define EPP_NTEF EPP_PTTBIT - -/* EPP control register */ -#define EPP_TX_FIFO_ENABLE 0x10 -#define EPP_RX_FIFO_ENABLE 0x08 -#define EPP_MODEM_ENABLE 0x20 -#define EPP_LEDS 0xC0 -#define EPP_IRQ_ENABLE 0x10 - -/* LPT registers */ -#define LPTREG_ECONTROL 0x402 -#define LPTREG_CONFIGB 0x401 -#define LPTREG_CONFIGA 0x400 -#define LPTREG_EPPDATA 0x004 -#define LPTREG_EPPADDR 0x003 -#define LPTREG_CONTROL 0x002 -#define LPTREG_STATUS 0x001 -#define LPTREG_DATA 0x000 - -/* LPT control register */ -#define LPTCTRL_PROGRAM 0x04 /* 0 to reprogram */ -#define LPTCTRL_WRITE 0x01 -#define LPTCTRL_ADDRSTB 0x08 -#define LPTCTRL_DATASTB 0x02 -#define LPTCTRL_INTEN 0x10 - -/* LPT status register */ -#define LPTSTAT_SHIFT_NINTR 6 -#define LPTSTAT_WAIT 0x80 -#define LPTSTAT_NINTR (1<0;len--) - crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff]; - crc ^= 0xffff; - *buffer++ = crc; - *buffer++ = crc >> 8; -} -#endif - -/*---------------------------------------------------------------------------*/ - -static inline int check_crc_ccitt(const unsigned char *buf, int cnt) -{ - return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8; -} - -/*---------------------------------------------------------------------------*/ - -static inline int calc_crc_ccitt(const unsigned char *buf, int cnt) -{ - return (crc_ccitt(0xffff, buf, cnt) ^ 0xffff) & 0xffff; -} - -/* ---------------------------------------------------------------------- */ - -#define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800) - -/* --------------------------------------------------------------------- */ - -static inline void baycom_int_freq(struct baycom_state *bc) -{ -#ifdef BAYCOM_DEBUG - unsigned long cur_jiffies = jiffies; - /* - * measure the interrupt frequency - */ - bc->debug_vals.cur_intcnt++; - if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { - bc->debug_vals.last_jiffies = cur_jiffies; - bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; - bc->debug_vals.cur_intcnt = 0; - bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; - bc->debug_vals.cur_pllcorr = 0; - } -#endif /* BAYCOM_DEBUG */ -} - -/* ---------------------------------------------------------------------- */ -/* - * eppconfig_path should be setable via /proc/sys. - */ - -static char const eppconfig_path[] = "/usr/sbin/eppfpga"; - -static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; - -/* eppconfig: called during ifconfig up to configure the modem */ -static int eppconfig(struct baycom_state *bc) -{ - char modearg[256]; - char portarg[16]; - char *argv[] = { - (char *)eppconfig_path, - "-s", - "-p", portarg, - "-m", modearg, - NULL }; - - /* set up arguments */ - sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", - bc->cfg.intclk ? "int" : "ext", - bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, - (bc->cfg.fclk + 8 * bc->cfg.bps) / (16 * bc->cfg.bps), - bc->cfg.loopback ? ",loopback" : ""); - sprintf(portarg, "%ld", bc->pdev->port->base); - printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg); - - return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC); -} - -/* ---------------------------------------------------------------------- */ - -static inline void do_kiss_params(struct baycom_state *bc, - unsigned char *data, unsigned long len) -{ - -#ifdef KISS_VERBOSE -#define PKP(a,b) printk(KERN_INFO "baycomm_epp: channel params: " a "\n", b) -#else /* KISS_VERBOSE */ -#define PKP(a,b) -#endif /* KISS_VERBOSE */ - - if (len < 2) - return; - switch(data[0]) { - case PARAM_TXDELAY: - bc->ch_params.tx_delay = data[1]; - PKP("TX delay = %ums", 10 * bc->ch_params.tx_delay); - break; - case PARAM_PERSIST: - bc->ch_params.ppersist = data[1]; - PKP("p persistence = %u", bc->ch_params.ppersist); - break; - case PARAM_SLOTTIME: - bc->ch_params.slottime = data[1]; - PKP("slot time = %ums", bc->ch_params.slottime); - break; - case PARAM_TXTAIL: - bc->ch_params.tx_tail = data[1]; - PKP("TX tail = %ums", bc->ch_params.tx_tail); - break; - case PARAM_FULLDUP: - bc->ch_params.fulldup = !!data[1]; - PKP("%s duplex", bc->ch_params.fulldup ? "full" : "half"); - break; - default: - break; - } -#undef PKP -} - -/* --------------------------------------------------------------------- */ - -static void encode_hdlc(struct baycom_state *bc) -{ - struct sk_buff *skb; - unsigned char *wp, *bp; - int pkt_len; - unsigned bitstream, notbitstream, bitbuf, numbit, crc; - unsigned char crcarr[2]; - int j; - - if (bc->hdlctx.bufcnt > 0) - return; - skb = bc->skb; - if (!skb) - return; - bc->skb = NULL; - pkt_len = skb->len-1; /* strip KISS byte */ - wp = bc->hdlctx.buf; - bp = skb->data+1; - crc = calc_crc_ccitt(bp, pkt_len); - crcarr[0] = crc; - crcarr[1] = crc >> 8; - *wp++ = 0x7e; - bitstream = bitbuf = numbit = 0; - while (pkt_len > -2) { - bitstream >>= 8; - bitstream |= ((unsigned int)*bp) << 8; - bitbuf |= ((unsigned int)*bp) << numbit; - notbitstream = ~bitstream; - bp++; - pkt_len--; - if (!pkt_len) - bp = crcarr; - for (j = 0; j < 8; j++) - if (unlikely(!(notbitstream & (0x1f0 << j)))) { - bitstream &= ~(0x100 << j); - bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) | - ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1); - numbit++; - notbitstream = ~bitstream; - } - numbit += 8; - while (numbit >= 8) { - *wp++ = bitbuf; - bitbuf >>= 8; - numbit -= 8; - } - } - bitbuf |= 0x7e7e << numbit; - numbit += 16; - while (numbit >= 8) { - *wp++ = bitbuf; - bitbuf >>= 8; - numbit -= 8; - } - bc->hdlctx.bufptr = bc->hdlctx.buf; - bc->hdlctx.bufcnt = wp - bc->hdlctx.buf; - dev_kfree_skb(skb); - bc->dev->stats.tx_packets++; -} - -/* ---------------------------------------------------------------------- */ - -static int transmit(struct baycom_state *bc, int cnt, unsigned char stat) -{ - struct parport *pp = bc->pdev->port; - unsigned char tmp[128]; - int i, j; - - if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT)) - bc->hdlctx.state = tx_idle; - if (bc->hdlctx.state == tx_idle && bc->hdlctx.calibrate <= 0) { - if (bc->hdlctx.bufcnt <= 0) - encode_hdlc(bc); - if (bc->hdlctx.bufcnt <= 0) - return 0; - if (!bc->ch_params.fulldup) { - if (!(stat & EPP_DCDBIT)) { - bc->hdlctx.slotcnt = bc->ch_params.slottime; - return 0; - } - if ((--bc->hdlctx.slotcnt) > 0) - return 0; - bc->hdlctx.slotcnt = bc->ch_params.slottime; - if (get_random_u8() > bc->ch_params.ppersist) - return 0; - } - } - if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) { - bc->hdlctx.state = tx_keyup; - bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_delay); - bc->ptt_keyed++; - } - while (cnt > 0) { - switch (bc->hdlctx.state) { - case tx_keyup: - i = min_t(int, cnt, bc->hdlctx.flags); - cnt -= i; - bc->hdlctx.flags -= i; - if (bc->hdlctx.flags <= 0) - bc->hdlctx.state = tx_data; - memset(tmp, 0x7e, sizeof(tmp)); - while (i > 0) { - j = (i > sizeof(tmp)) ? sizeof(tmp) : i; - if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) - return -1; - i -= j; - } - break; - - case tx_data: - if (bc->hdlctx.bufcnt <= 0) { - encode_hdlc(bc); - if (bc->hdlctx.bufcnt <= 0) { - bc->hdlctx.state = tx_tail; - bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_tail); - break; - } - } - i = min_t(int, cnt, bc->hdlctx.bufcnt); - bc->hdlctx.bufcnt -= i; - cnt -= i; - if (i != pp->ops->epp_write_data(pp, bc->hdlctx.bufptr, i, 0)) - return -1; - bc->hdlctx.bufptr += i; - break; - - case tx_tail: - encode_hdlc(bc); - if (bc->hdlctx.bufcnt > 0) { - bc->hdlctx.state = tx_data; - break; - } - i = min_t(int, cnt, bc->hdlctx.flags); - if (i) { - cnt -= i; - bc->hdlctx.flags -= i; - memset(tmp, 0x7e, sizeof(tmp)); - while (i > 0) { - j = (i > sizeof(tmp)) ? sizeof(tmp) : i; - if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) - return -1; - i -= j; - } - break; - } - fallthrough; - - default: - if (bc->hdlctx.calibrate <= 0) - return 0; - i = min_t(int, cnt, bc->hdlctx.calibrate); - cnt -= i; - bc->hdlctx.calibrate -= i; - memset(tmp, 0, sizeof(tmp)); - while (i > 0) { - j = (i > sizeof(tmp)) ? sizeof(tmp) : i; - if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) - return -1; - i -= j; - } - break; - } - } - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static void do_rxpacket(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - struct sk_buff *skb; - unsigned char *cp; - unsigned pktlen; - - if (bc->hdlcrx.bufcnt < 4) - return; - if (!check_crc_ccitt(bc->hdlcrx.buf, bc->hdlcrx.bufcnt)) - return; - pktlen = bc->hdlcrx.bufcnt-2+1; /* KISS kludge */ - if (!(skb = dev_alloc_skb(pktlen))) { - printk("%s: memory squeeze, dropping packet\n", dev->name); - dev->stats.rx_dropped++; - return; - } - cp = skb_put(skb, pktlen); - *cp++ = 0; /* KISS kludge */ - memcpy(cp, bc->hdlcrx.buf, pktlen - 1); - skb->protocol = ax25_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; -} - -static int receive(struct net_device *dev, int cnt) -{ - struct baycom_state *bc = netdev_priv(dev); - struct parport *pp = bc->pdev->port; - unsigned int bitbuf, notbitstream, bitstream, numbits, state; - unsigned char tmp[128]; - unsigned char *cp; - int cnt2, ret = 0; - int j; - - numbits = bc->hdlcrx.numbits; - state = bc->hdlcrx.state; - bitstream = bc->hdlcrx.bitstream; - bitbuf = bc->hdlcrx.bitbuf; - while (cnt > 0) { - cnt2 = (cnt > sizeof(tmp)) ? sizeof(tmp) : cnt; - cnt -= cnt2; - if (cnt2 != pp->ops->epp_read_data(pp, tmp, cnt2, 0)) { - ret = -1; - break; - } - cp = tmp; - for (; cnt2 > 0; cnt2--, cp++) { - bitstream >>= 8; - bitstream |= (*cp) << 8; - bitbuf >>= 8; - bitbuf |= (*cp) << 8; - numbits += 8; - notbitstream = ~bitstream; - for (j = 0; j < 8; j++) { - - /* flag or abort */ - if (unlikely(!(notbitstream & (0x0fc << j)))) { - - /* abort received */ - if (!(notbitstream & (0x1fc << j))) - state = 0; - - /* flag received */ - else if ((bitstream & (0x1fe << j)) == (0x0fc << j)) { - if (state) - do_rxpacket(dev); - bc->hdlcrx.bufcnt = 0; - bc->hdlcrx.bufptr = bc->hdlcrx.buf; - state = 1; - numbits = 7-j; - } - } - - /* stuffed bit */ - else if (unlikely((bitstream & (0x1f8 << j)) == (0xf8 << j))) { - numbits--; - bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1); - } - } - while (state && numbits >= 8) { - if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) { - state = 0; - } else { - *(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits); - bc->hdlcrx.bufcnt++; - numbits -= 8; - } - } - } - } - bc->hdlcrx.numbits = numbits; - bc->hdlcrx.state = state; - bc->hdlcrx.bitstream = bitstream; - bc->hdlcrx.bitbuf = bitbuf; - return ret; -} - -/* --------------------------------------------------------------------- */ - -#define GETTICK(x) \ -({ \ - x = (unsigned int)get_cycles(); \ -}) - -static void epp_bh(struct work_struct *work) -{ - struct net_device *dev; - struct baycom_state *bc; - struct parport *pp; - unsigned char stat; - unsigned char tmp[2]; - unsigned int time1 = 0, time2 = 0, time3 = 0; - int cnt, cnt2; - - bc = container_of(work, struct baycom_state, run_work.work); - dev = bc->dev; - if (!bc->work_running) - return; - baycom_int_freq(bc); - pp = bc->pdev->port; - /* update status */ - if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) - goto epptimeout; - bc->stat = stat; - bc->debug_vals.last_pllcorr = stat; - GETTICK(time1); - if (bc->modem == EPP_FPGAEXTSTATUS) { - /* get input count */ - tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1; - if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) - goto epptimeout; - if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) - goto epptimeout; - cnt = tmp[0] | (tmp[1] << 8); - cnt &= 0x7fff; - /* get output count */ - tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2; - if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) - goto epptimeout; - if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) - goto epptimeout; - cnt2 = tmp[0] | (tmp[1] << 8); - cnt2 = 16384 - (cnt2 & 0x7fff); - /* return to normal */ - tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; - if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) - goto epptimeout; - if (transmit(bc, cnt2, stat)) - goto epptimeout; - GETTICK(time2); - if (receive(dev, cnt)) - goto epptimeout; - if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) - goto epptimeout; - bc->stat = stat; - } else { - /* try to tx */ - switch (stat & (EPP_NTAEF|EPP_NTHF)) { - case EPP_NTHF: - cnt = 2048 - 256; - break; - - case EPP_NTAEF: - cnt = 2048 - 1793; - break; - - case 0: - cnt = 0; - break; - - default: - cnt = 2048 - 1025; - break; - } - if (transmit(bc, cnt, stat)) - goto epptimeout; - GETTICK(time2); - /* do receiver */ - while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) { - switch (stat & (EPP_NRAEF|EPP_NRHF)) { - case EPP_NRAEF: - cnt = 1025; - break; - - case 0: - cnt = 1793; - break; - - default: - cnt = 256; - break; - } - if (receive(dev, cnt)) - goto epptimeout; - if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) - goto epptimeout; - } - cnt = 0; - if (bc->bitrate < 50000) - cnt = 256; - else if (bc->bitrate < 100000) - cnt = 128; - while (cnt > 0 && stat & EPP_NREF) { - if (receive(dev, 1)) - goto epptimeout; - cnt--; - if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) - goto epptimeout; - } - } - GETTICK(time3); -#ifdef BAYCOM_DEBUG - bc->debug_vals.mod_cycles = time2 - time1; - bc->debug_vals.demod_cycles = time3 - time2; -#endif /* BAYCOM_DEBUG */ - schedule_delayed_work(&bc->run_work, 1); - if (!bc->skb) - netif_wake_queue(dev); - return; - epptimeout: - printk(KERN_ERR "%s: EPP timeout!\n", bc_drvname); -} - -/* ---------------------------------------------------------------------- */ -/* - * ===================== network driver interface ========================= - */ - -static netdev_tx_t baycom_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - if (skb->data[0] != 0) { - do_kiss_params(bc, skb->data, skb->len); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - if (bc->skb) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - /* strip KISS byte */ - if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - netif_stop_queue(dev); - bc->skb = skb; - return NETDEV_TX_OK; -} - -/* --------------------------------------------------------------------- */ - -static int baycom_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *)addr; - - /* addr is an AX.25 shifted ASCII mac address */ - dev_addr_set(dev, sa->sa_data); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static void epp_wakeup(void *handle) -{ - struct net_device *dev = (struct net_device *)handle; - struct baycom_state *bc = netdev_priv(dev); - - printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name); - if (!parport_claim(bc->pdev)) - printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name); -} - -/* --------------------------------------------------------------------- */ - -/* - * Open/initialize the board. 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 epp_open(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - struct parport *pp = parport_find_base(dev->base_addr); - unsigned int i, j; - unsigned char tmp[128]; - unsigned char stat; - unsigned long tstart; - struct pardev_cb par_cb; - - if (!pp) { - printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr); - return -ENXIO; - } -#if 0 - if (pp->irq < 0) { - printk(KERN_ERR "%s: parport at 0x%lx has no irq\n", bc_drvname, pp->base); - parport_put_port(pp); - return -ENXIO; - } -#endif - if ((~pp->modes) & (PARPORT_MODE_TRISTATE | PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) { - printk(KERN_ERR "%s: parport at 0x%lx cannot be used\n", - bc_drvname, pp->base); - parport_put_port(pp); - return -EIO; - } - memset(&bc->modem, 0, sizeof(bc->modem)); - memset(&par_cb, 0, sizeof(par_cb)); - par_cb.wakeup = epp_wakeup; - par_cb.private = (void *)dev; - par_cb.flags = PARPORT_DEV_EXCL; - for (i = 0; i < NR_PORTS; i++) - if (baycom_device[i] == dev) - break; - - if (i == NR_PORTS) { - pr_err("%s: no device found\n", bc_drvname); - parport_put_port(pp); - return -ENODEV; - } - - bc->pdev = parport_register_dev_model(pp, dev->name, &par_cb, i); - parport_put_port(pp); - if (!bc->pdev) { - printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base); - return -ENXIO; - } - if (parport_claim(bc->pdev)) { - printk(KERN_ERR "%s: parport at 0x%lx busy\n", bc_drvname, pp->base); - parport_unregister_device(bc->pdev); - return -EBUSY; - } - dev->irq = /*pp->irq*/ 0; - INIT_DELAYED_WORK(&bc->run_work, epp_bh); - bc->work_running = 1; - bc->modem = EPP_CONVENTIONAL; - if (eppconfig(bc)) - printk(KERN_INFO "%s: no FPGA detected, assuming conventional EPP modem\n", bc_drvname); - else - bc->modem = /*EPP_FPGA*/ EPP_FPGAEXTSTATUS; - parport_write_control(pp, LPTCTRL_PROGRAM); /* prepare EPP mode; we aren't using interrupts */ - /* reset the modem */ - tmp[0] = 0; - tmp[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; - if (pp->ops->epp_write_addr(pp, tmp, 2, 0) != 2) - goto epptimeout; - /* autoprobe baud rate */ - tstart = jiffies; - i = 0; - while (time_before(jiffies, tstart + HZ/3)) { - if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) - goto epptimeout; - if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) { - schedule(); - continue; - } - if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) - goto epptimeout; - if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) - goto epptimeout; - i += 256; - } - for (j = 0; j < 256; j++) { - if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) - goto epptimeout; - if (!(stat & EPP_NREF)) - break; - if (pp->ops->epp_read_data(pp, tmp, 1, 0) != 1) - goto epptimeout; - i++; - } - tstart = jiffies - tstart; - bc->bitrate = i * (8 * HZ) / tstart; - j = 1; - i = bc->bitrate >> 3; - while (j < 7 && i > 150) { - j++; - i >>= 1; - } - printk(KERN_INFO "%s: autoprobed bitrate: %d int divider: %d int rate: %d\n", - bc_drvname, bc->bitrate, j, bc->bitrate >> (j+2)); - tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/; - if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) - goto epptimeout; - /* - * initialise hdlc variables - */ - bc->hdlcrx.state = 0; - bc->hdlcrx.numbits = 0; - bc->hdlctx.state = tx_idle; - bc->hdlctx.bufcnt = 0; - bc->hdlctx.slotcnt = bc->ch_params.slottime; - bc->hdlctx.calibrate = 0; - /* start the bottom half stuff */ - schedule_delayed_work(&bc->run_work, 1); - netif_start_queue(dev); - return 0; - - epptimeout: - printk(KERN_ERR "%s: epp timeout during bitrate probe\n", bc_drvname); - parport_write_control(pp, 0); /* reset the adapter */ - parport_release(bc->pdev); - parport_unregister_device(bc->pdev); - return -EIO; -} - -/* --------------------------------------------------------------------- */ - -static int epp_close(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - struct parport *pp = bc->pdev->port; - unsigned char tmp[1]; - - bc->work_running = 0; - cancel_delayed_work_sync(&bc->run_work); - bc->stat = EPP_DCDBIT; - tmp[0] = 0; - pp->ops->epp_write_addr(pp, tmp, 1, 0); - parport_write_control(pp, 0); /* reset the adapter */ - parport_release(bc->pdev); - parport_unregister_device(bc->pdev); - dev_kfree_skb(bc->skb); - bc->skb = NULL; - printk(KERN_INFO "%s: close epp at iobase 0x%lx irq %u\n", - bc_drvname, dev->base_addr, dev->irq); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int baycom_setmode(struct baycom_state *bc, const char *modestr) -{ - const char *cp; - - if (strstr(modestr,"intclk")) - bc->cfg.intclk = 1; - if (strstr(modestr,"extclk")) - bc->cfg.intclk = 0; - if (strstr(modestr,"intmodem")) - bc->cfg.extmodem = 0; - if (strstr(modestr,"extmodem")) - bc->cfg.extmodem = 1; - if (strstr(modestr,"loopback")) - bc->cfg.loopback = 1; - if (strstr(modestr, "noloopback")) - bc->cfg.loopback = 0; - if ((cp = strstr(modestr,"fclk="))) { - bc->cfg.fclk = simple_strtoul(cp+5, NULL, 0); - if (bc->cfg.fclk < 1000000) - bc->cfg.fclk = 1000000; - if (bc->cfg.fclk > 25000000) - bc->cfg.fclk = 25000000; - } - if ((cp = strstr(modestr,"bps="))) { - bc->cfg.bps = simple_strtoul(cp+4, NULL, 0); - if (bc->cfg.bps < 1000) - bc->cfg.bps = 1000; - if (bc->cfg.bps > 1500000) - bc->cfg.bps = 1500000; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int baycom_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd) -{ - struct baycom_state *bc = netdev_priv(dev); - struct hdlcdrv_ioctl hi; - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (copy_from_user(&hi, data, sizeof(hi))) - return -EFAULT; - switch (hi.cmd) { - default: - return -ENOIOCTLCMD; - - case HDLCDRVCTL_GETCHANNELPAR: - hi.data.cp.tx_delay = bc->ch_params.tx_delay; - hi.data.cp.tx_tail = bc->ch_params.tx_tail; - hi.data.cp.slottime = bc->ch_params.slottime; - hi.data.cp.ppersist = bc->ch_params.ppersist; - hi.data.cp.fulldup = bc->ch_params.fulldup; - break; - - case HDLCDRVCTL_SETCHANNELPAR: - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - bc->ch_params.tx_delay = hi.data.cp.tx_delay; - bc->ch_params.tx_tail = hi.data.cp.tx_tail; - bc->ch_params.slottime = hi.data.cp.slottime; - bc->ch_params.ppersist = hi.data.cp.ppersist; - bc->ch_params.fulldup = hi.data.cp.fulldup; - bc->hdlctx.slotcnt = 1; - return 0; - - case HDLCDRVCTL_GETMODEMPAR: - hi.data.mp.iobase = dev->base_addr; - hi.data.mp.irq = dev->irq; - hi.data.mp.dma = dev->dma; - hi.data.mp.dma2 = 0; - hi.data.mp.seriobase = 0; - hi.data.mp.pariobase = 0; - hi.data.mp.midiiobase = 0; - break; - - case HDLCDRVCTL_SETMODEMPAR: - if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev)) - return -EACCES; - dev->base_addr = hi.data.mp.iobase; - dev->irq = /*hi.data.mp.irq*/0; - dev->dma = /*hi.data.mp.dma*/0; - return 0; - - case HDLCDRVCTL_GETSTAT: - hi.data.cs.ptt = !!(bc->stat & EPP_PTTBIT); - hi.data.cs.dcd = !(bc->stat & EPP_DCDBIT); - hi.data.cs.ptt_keyed = bc->ptt_keyed; - hi.data.cs.tx_packets = dev->stats.tx_packets; - hi.data.cs.tx_errors = dev->stats.tx_errors; - hi.data.cs.rx_packets = dev->stats.rx_packets; - hi.data.cs.rx_errors = dev->stats.rx_errors; - break; - - case HDLCDRVCTL_OLDGETSTAT: - hi.data.ocs.ptt = !!(bc->stat & EPP_PTTBIT); - hi.data.ocs.dcd = !(bc->stat & EPP_DCDBIT); - hi.data.ocs.ptt_keyed = bc->ptt_keyed; - break; - - case HDLCDRVCTL_CALIBRATE: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - bc->hdlctx.calibrate = hi.data.calibrate * bc->bitrate / 8; - return 0; - - case HDLCDRVCTL_DRIVERNAME: - strscpy_pad(hi.data.drivername, "baycom_epp"); - break; - - case HDLCDRVCTL_GETMODE: - sprintf(hi.data.modename, "%sclk,%smodem,fclk=%d,bps=%d%s", - bc->cfg.intclk ? "int" : "ext", - bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, - bc->cfg.loopback ? ",loopback" : ""); - break; - - case HDLCDRVCTL_SETMODE: - if (!capable(CAP_NET_ADMIN) || netif_running(dev)) - return -EACCES; - hi.data.modename[sizeof(hi.data.modename)-1] = '\0'; - return baycom_setmode(bc, hi.data.modename); - - case HDLCDRVCTL_MODELIST: - strscpy_pad(hi.data.modename, "intclk,extclk,intmodem,extmodem,divider=x"); - break; - - case HDLCDRVCTL_MODEMPARMASK: - return HDLCDRV_PARMASK_IOBASE; - - } - if (copy_to_user(data, &hi, sizeof(hi))) - return -EFAULT; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static const struct net_device_ops baycom_netdev_ops = { - .ndo_open = epp_open, - .ndo_stop = epp_close, - .ndo_siocdevprivate = baycom_siocdevprivate, - .ndo_start_xmit = baycom_send_packet, - .ndo_set_mac_address = baycom_set_mac_address, -}; - -/* - * Check for a network adaptor of this type, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). - */ -static void baycom_probe(struct net_device *dev) -{ - const struct hdlcdrv_channel_params dflt_ch_params = { - 20, 2, 10, 40, 0 - }; - struct baycom_state *bc; - - /* - * not a real probe! only initialize data structures - */ - bc = netdev_priv(dev); - /* - * initialize the baycom_state struct - */ - bc->ch_params = dflt_ch_params; - bc->ptt_keyed = 0; - - /* - * initialize the device struct - */ - - /* Fill in the fields of the device structure */ - bc->skb = NULL; - - dev->netdev_ops = &baycom_netdev_ops; - dev->header_ops = &ax25_header_ops; - - dev->type = ARPHRD_AX25; /* AF_AX25 device */ - dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; - dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ - dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&null_ax25_address); - dev->tx_queue_len = 16; - - /* New style flags */ - dev->flags = 0; -} - -/* --------------------------------------------------------------------- */ - -/* - * command line settable parameters - */ -static char *mode[NR_PORTS] = { "", }; -static int iobase[NR_PORTS] = { 0x378, }; - -module_param_array(mode, charp, NULL, 0); -MODULE_PARM_DESC(mode, "baycom operating mode"); -module_param_hw_array(iobase, int, ioport, NULL, 0); -MODULE_PARM_DESC(iobase, "baycom io base address"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom epp amateur radio modem driver"); -MODULE_LICENSE("GPL"); - -/* --------------------------------------------------------------------- */ - -static int baycom_epp_par_probe(struct pardevice *par_dev) -{ - struct device_driver *drv = par_dev->dev.driver; - int len = strlen(drv->name); - - if (strncmp(par_dev->name, drv->name, len)) - return -ENODEV; - - return 0; -} - -static struct parport_driver baycom_epp_par_driver = { - .name = "bce", - .probe = baycom_epp_par_probe, -}; - -static void __init baycom_epp_dev_setup(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - - /* - * initialize part of the baycom_state struct - */ - bc->dev = dev; - bc->magic = BAYCOM_MAGIC; - bc->cfg.fclk = 19666600; - bc->cfg.bps = 9600; - /* - * initialize part of the device struct - */ - baycom_probe(dev); -} - -static int __init init_baycomepp(void) -{ - int i, found = 0, ret; - char set_hw = 1; - - printk(bc_drvinfo); - - ret = parport_register_driver(&baycom_epp_par_driver); - if (ret) - return ret; - - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct baycom_state), "bce%d", - NET_NAME_UNKNOWN, baycom_epp_dev_setup); - - if (!dev) { - printk(KERN_WARNING "bce%d : out of memory\n", i); - return found ? 0 : -ENOMEM; - } - - sprintf(dev->name, "bce%d", i); - dev->base_addr = iobase[i]; - - if (!mode[i]) - set_hw = 0; - if (!set_hw) - iobase[i] = 0; - - if (register_netdev(dev)) { - printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name); - free_netdev(dev); - break; - } - if (set_hw && baycom_setmode(netdev_priv(dev), mode[i])) - set_hw = 0; - baycom_device[i] = dev; - found++; - } - - if (found == 0) { - parport_unregister_driver(&baycom_epp_par_driver); - return -ENXIO; - } - - return 0; -} - -static void __exit cleanup_baycomepp(void) -{ - int i; - - for(i = 0; i < NR_PORTS; i++) { - struct net_device *dev = baycom_device[i]; - - if (dev) { - struct baycom_state *bc = netdev_priv(dev); - if (bc->magic == BAYCOM_MAGIC) { - unregister_netdev(dev); - free_netdev(dev); - } else - printk(paranoia_str, "cleanup_module"); - } - } - parport_unregister_driver(&baycom_epp_par_driver); -} - -module_init(init_baycomepp); -module_exit(cleanup_baycomepp); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* - * format: baycom_epp=io,mode - * mode: fpga config options - */ - -static int __init baycom_epp_setup(char *str) -{ - static unsigned __initdata nr_dev = 0; - int ints[2]; - - if (nr_dev >= NR_PORTS) - return 0; - str = get_options(str, 2, ints); - if (ints[0] < 1) - return 0; - mode[nr_dev] = str; - iobase[nr_dev] = ints[1]; - nr_dev++; - return 1; -} - -__setup("baycom_epp=", baycom_epp_setup); - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c deleted file mode 100644 index f03797103c6a..000000000000 --- a/drivers/net/hamradio/baycom_par.c +++ /dev/null @@ -1,598 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*****************************************************************************/ - -/* - * baycom_par.c -- baycom par96 and picpar radio modem driver. - * - * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * Supported modems - * - * par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard. - * The modem does all the filtering and regenerates the receiver clock. - * Data is transferred from and to the PC via a shift register. - * The shift register is filled with 16 bits and an interrupt is - * signalled. The PC then empties the shift register in a burst. This - * modem connects to the parallel port, hence the name. The modem - * leaves the implementation of the HDLC protocol and the scrambler - * polynomial to the PC. This modem is no longer available (at least - * from Baycom) and has been replaced by the PICPAR modem (see below). - * You may however still build one from the schematics published in - * cq-DL :-). - * - * picpar: This is a redesign of the par96 modem by Henning Rech, DF9IC. The - * modem is protocol compatible to par96, but uses only three low - * power ICs and can therefore be fed from the parallel port and - * does not require an additional power supply. It features - * built in DCD circuitry. The driver should therefore be configured - * for hardware DCD. - * - * Command line options (insmod command line) - * - * mode driver mode string. Valid choices are par96 and picpar. - * iobase base address of the port; common values are 0x378, 0x278, 0x3bc - * - * History: - * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface - * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) - * 0.3 26.04.1997 init code/data tagged - * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints) - * 0.5 11.11.1997 split into separate files for ser12/par96 - * 0.6 03.08.1999 adapt to Linus' new __setup/__initcall - * removed some pre-2.2 kernel compatibility cruft - * 0.7 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts - * 0.8 12.02.2000 adapted to softnet driver interface - * removed direct parport access, uses parport driver methods - * 0.9 03.07.2000 fix interface name handling - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* --------------------------------------------------------------------- */ - -#define BAYCOM_DEBUG - -/* - * modem options; bit mask - */ -#define BAYCOM_OPTIONS_SOFTDCD 1 - -/* --------------------------------------------------------------------- */ - -static const char bc_drvname[] = "baycom_par"; -static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_par: version 0.9\n"; - -/* --------------------------------------------------------------------- */ - -#define NR_PORTS 4 - -static struct net_device *baycom_device[NR_PORTS]; - -/* --------------------------------------------------------------------- */ - -#define PAR96_BURSTBITS 16 -#define PAR96_BURST 4 -#define PAR96_PTT 2 -#define PAR96_TXBIT 1 -#define PAR96_ACK 0x40 -#define PAR96_RXBIT 0x20 -#define PAR96_DCD 0x10 -#define PAR97_POWER 0xf8 - -/* ---------------------------------------------------------------------- */ -/* - * Information that need to be kept for each board. - */ - -struct baycom_state { - struct hdlcdrv_state hdrv; - - struct pardevice *pdev; - unsigned int options; - - struct modem_state { - short arb_divider; - unsigned char flags; - unsigned int shreg; - struct modem_state_par96 { - int dcd_count; - unsigned int dcd_shreg; - unsigned long descram; - unsigned long scram; - } par96; - } modem; - -#ifdef BAYCOM_DEBUG - struct debug_vals { - unsigned long last_jiffies; - unsigned cur_intcnt; - unsigned last_intcnt; - int cur_pllcorr; - int last_pllcorr; - } debug_vals; -#endif /* BAYCOM_DEBUG */ -}; - -/* --------------------------------------------------------------------- */ - -static inline void baycom_int_freq(struct baycom_state *bc) -{ -#ifdef BAYCOM_DEBUG - unsigned long cur_jiffies = jiffies; - /* - * measure the interrupt frequency - */ - bc->debug_vals.cur_intcnt++; - if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { - bc->debug_vals.last_jiffies = cur_jiffies; - bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; - bc->debug_vals.cur_intcnt = 0; - bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; - bc->debug_vals.cur_pllcorr = 0; - } -#endif /* BAYCOM_DEBUG */ -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== PAR96 specific routines ========================= - */ - -#define PAR96_DESCRAM_TAP1 0x20000 -#define PAR96_DESCRAM_TAP2 0x01000 -#define PAR96_DESCRAM_TAP3 0x00001 - -#define PAR96_DESCRAM_TAPSH1 17 -#define PAR96_DESCRAM_TAPSH2 12 -#define PAR96_DESCRAM_TAPSH3 0 - -#define PAR96_SCRAM_TAP1 0x20000 /* X^17 */ -#define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 */ - -/* --------------------------------------------------------------------- */ - -static inline void par96_tx(struct net_device *dev, struct baycom_state *bc) -{ - int i; - unsigned int data = hdlcdrv_getbits(&bc->hdrv); - struct parport *pp = bc->pdev->port; - - for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) { - unsigned char val = PAR97_POWER; - bc->modem.par96.scram = ((bc->modem.par96.scram << 1) | - (bc->modem.par96.scram & 1)); - if (!(data & 1)) - bc->modem.par96.scram ^= 1; - if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1)) - bc->modem.par96.scram ^= - (PAR96_SCRAM_TAPN << 1); - if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2)) - val |= PAR96_TXBIT; - pp->ops->write_data(pp, val); - pp->ops->write_data(pp, val | PAR96_BURST); - } -} - -/* --------------------------------------------------------------------- */ - -static inline void par96_rx(struct net_device *dev, struct baycom_state *bc) -{ - int i; - unsigned int data, mask, mask2, descx; - struct parport *pp = bc->pdev->port; - - /* - * do receiver; differential decode and descramble on the fly - */ - for(data = i = 0; i < PAR96_BURSTBITS; i++) { - bc->modem.par96.descram = (bc->modem.par96.descram << 1); - if (pp->ops->read_status(pp) & PAR96_RXBIT) - bc->modem.par96.descram |= 1; - descx = bc->modem.par96.descram ^ - (bc->modem.par96.descram >> 1); - /* now the diff decoded data is inverted in descram */ - pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT); - descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^ - (descx >> PAR96_DESCRAM_TAPSH2)); - data >>= 1; - if (!(descx & 1)) - data |= 0x8000; - pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT | PAR96_BURST); - } - hdlcdrv_putbits(&bc->hdrv, data); - /* - * do DCD algorithm - */ - if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { - bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16) - | (data << 16); - /* search for flags and set the dcd counter appropriately */ - for(mask = 0x1fe00, mask2 = 0xfc00, i = 0; - i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) - if ((bc->modem.par96.dcd_shreg & mask) == mask2) - bc->modem.par96.dcd_count = HDLCDRV_MAXFLEN+4; - /* check for abort/noise sequences */ - for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0; - i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) - if (((bc->modem.par96.dcd_shreg & mask) == mask2) && - (bc->modem.par96.dcd_count >= 0)) - bc->modem.par96.dcd_count -= HDLCDRV_MAXFLEN-10; - /* decrement and set the dcd variable */ - if (bc->modem.par96.dcd_count >= 0) - bc->modem.par96.dcd_count -= 2; - hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0); - } else { - hdlcdrv_setdcd(&bc->hdrv, !!(pp->ops->read_status(pp) & PAR96_DCD)); - } -} - -/* --------------------------------------------------------------------- */ - -static void par96_interrupt(void *dev_id) -{ - struct net_device *dev = dev_id; - struct baycom_state *bc = netdev_priv(dev); - - baycom_int_freq(bc); - /* - * check if transmitter active - */ - if (hdlcdrv_ptt(&bc->hdrv)) - par96_tx(dev, bc); - else { - par96_rx(dev, bc); - if (--bc->modem.arb_divider <= 0) { - bc->modem.arb_divider = 6; - local_irq_enable(); - hdlcdrv_arbitrate(dev, &bc->hdrv); - } - } - local_irq_enable(); - hdlcdrv_transmitter(dev, &bc->hdrv); - hdlcdrv_receiver(dev, &bc->hdrv); - local_irq_disable(); -} - -/* --------------------------------------------------------------------- */ - -static void par96_wakeup(void *handle) -{ - struct net_device *dev = (struct net_device *)handle; - struct baycom_state *bc = netdev_priv(dev); - - printk(KERN_DEBUG "baycom_par: %s: why am I being woken up?\n", dev->name); - if (!parport_claim(bc->pdev)) - printk(KERN_DEBUG "baycom_par: %s: I'm broken.\n", dev->name); -} - -/* --------------------------------------------------------------------- */ - -static int par96_open(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - struct pardev_cb par_cb; - struct parport *pp; - int i; - - if (!dev || !bc) - return -ENXIO; - pp = parport_find_base(dev->base_addr); - if (!pp) { - printk(KERN_ERR "baycom_par: parport at 0x%lx unknown\n", dev->base_addr); - return -ENXIO; - } - if (pp->irq < 0) { - printk(KERN_ERR "baycom_par: parport at 0x%lx has no irq\n", pp->base); - parport_put_port(pp); - return -ENXIO; - } - if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) { - printk(KERN_ERR "baycom_par: parport at 0x%lx cannot be used\n", pp->base); - parport_put_port(pp); - return -ENXIO; - } - memset(&bc->modem, 0, sizeof(bc->modem)); - bc->hdrv.par.bitrate = 9600; - memset(&par_cb, 0, sizeof(par_cb)); - par_cb.wakeup = par96_wakeup; - par_cb.irq_func = par96_interrupt; - par_cb.private = (void *)dev; - par_cb.flags = PARPORT_DEV_EXCL; - for (i = 0; i < NR_PORTS; i++) - if (baycom_device[i] == dev) - break; - - if (i == NR_PORTS) { - pr_err("%s: no device found\n", bc_drvname); - parport_put_port(pp); - return -ENODEV; - } - bc->pdev = parport_register_dev_model(pp, dev->name, &par_cb, i); - parport_put_port(pp); - if (!bc->pdev) { - printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", dev->base_addr); - return -ENXIO; - } - if (parport_claim(bc->pdev)) { - printk(KERN_ERR "baycom_par: parport at 0x%lx busy\n", pp->base); - parport_unregister_device(bc->pdev); - return -EBUSY; - } - pp = bc->pdev->port; - dev->irq = pp->irq; - pp->ops->data_forward(pp); - bc->hdrv.par.bitrate = 9600; - pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER); /* switch off PTT */ - pp->ops->enable_irq(pp); - printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n", - bc_drvname, dev->base_addr, dev->irq, bc->options); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int par96_close(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - struct parport *pp; - - if (!dev || !bc) - return -EINVAL; - pp = bc->pdev->port; - /* disable interrupt */ - pp->ops->disable_irq(pp); - /* switch off PTT */ - pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER); - parport_release(bc->pdev); - parport_unregister_device(bc->pdev); - printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n", - bc_drvname, dev->base_addr, dev->irq); - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== hdlcdrv driver interface ========================= - */ - -static int baycom_ioctl(struct net_device *dev, void __user *data, - struct hdlcdrv_ioctl *hi, int cmd); - -/* --------------------------------------------------------------------- */ - -static const struct hdlcdrv_ops par96_ops = { - .drvname = bc_drvname, - .drvinfo = bc_drvinfo, - .open = par96_open, - .close = par96_close, - .ioctl = baycom_ioctl -}; - -/* --------------------------------------------------------------------- */ - -static int baycom_setmode(struct baycom_state *bc, const char *modestr) -{ - if (!strncmp(modestr, "picpar", 6)) - bc->options = 0; - else if (!strncmp(modestr, "par96", 5)) - bc->options = BAYCOM_OPTIONS_SOFTDCD; - else - bc->options = !!strchr(modestr, '*'); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int baycom_ioctl(struct net_device *dev, void __user *data, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct baycom_state *bc; - struct baycom_ioctl bi; - - if (!dev) - return -EINVAL; - - bc = netdev_priv(dev); - BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - switch (hi->cmd) { - default: - break; - - case HDLCDRVCTL_GETMODE: - strscpy(hi->data.modename, bc->options ? "par96" : "picpar"); - if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_SETMODE: - if (netif_running(dev) || !capable(CAP_NET_ADMIN)) - return -EACCES; - hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; - return baycom_setmode(bc, hi->data.modename); - - case HDLCDRVCTL_MODELIST: - strscpy(hi->data.modename, "par96,picpar"); - if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_MODEMPARMASK: - return HDLCDRV_PARMASK_IOBASE; - - } - - if (copy_from_user(&bi, data, sizeof(bi))) - return -EFAULT; - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - -#ifdef BAYCOM_DEBUG - case BAYCOMCTL_GETDEBUG: - bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; - bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; - bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; - break; -#endif /* BAYCOM_DEBUG */ - - } - if (copy_to_user(data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -/* - * command line settable parameters - */ -static char *mode[NR_PORTS] = { "picpar", }; -static int iobase[NR_PORTS] = { 0x378, }; - -module_param_array(mode, charp, NULL, 0); -MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar"); -module_param_hw_array(iobase, int, ioport, NULL, 0); -MODULE_PARM_DESC(iobase, "baycom io base address"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver"); -MODULE_LICENSE("GPL"); - -/* --------------------------------------------------------------------- */ - -static int baycom_par_probe(struct pardevice *par_dev) -{ - struct device_driver *drv = par_dev->dev.driver; - int len = strlen(drv->name); - - if (strncmp(par_dev->name, drv->name, len)) - return -ENODEV; - - return 0; -} - -static struct parport_driver baycom_par_driver = { - .name = "bcp", - .probe = baycom_par_probe, -}; - -static int __init init_baycompar(void) -{ - int i, found = 0, ret; - char set_hw = 1; - - printk(bc_drvinfo); - - ret = parport_register_driver(&baycom_par_driver); - if (ret) - return ret; - - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct net_device *dev; - struct baycom_state *bc; - char ifname[IFNAMSIZ]; - - sprintf(ifname, "bcp%d", i); - - if (!mode[i]) - set_hw = 0; - if (!set_hw) - iobase[i] = 0; - - dev = hdlcdrv_register(&par96_ops, - sizeof(struct baycom_state), - ifname, iobase[i], 0, 0); - if (IS_ERR(dev)) - break; - - bc = netdev_priv(dev); - if (set_hw && baycom_setmode(bc, mode[i])) - set_hw = 0; - found++; - baycom_device[i] = dev; - } - - if (!found) { - parport_unregister_driver(&baycom_par_driver); - return -ENXIO; - } - return 0; -} - -static void __exit cleanup_baycompar(void) -{ - int i; - - for(i = 0; i < NR_PORTS; i++) { - struct net_device *dev = baycom_device[i]; - - if (dev) - hdlcdrv_unregister(dev); - } - parport_unregister_driver(&baycom_par_driver); -} - -module_init(init_baycompar); -module_exit(cleanup_baycompar); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* - * format: baycom_par=io,mode - * mode: par96,picpar - */ - -static int __init baycom_par_setup(char *str) -{ - static unsigned nr_dev; - int ints[2]; - - if (nr_dev >= NR_PORTS) - return 0; - str = get_options(str, 2, ints); - if (ints[0] < 1) - return 0; - mode[nr_dev] = str; - iobase[nr_dev] = ints[1]; - nr_dev++; - return 1; -} - -__setup("baycom_par=", baycom_par_setup); - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c deleted file mode 100644 index ee5bd3c12040..000000000000 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ /dev/null @@ -1,678 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*****************************************************************************/ - -/* - * baycom_ser_fdx.c -- baycom ser12 fullduplex radio modem driver. - * - * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * Supported modems - * - * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only - * of a modulator/demodulator chip, usually a TI TCM3105. The computer - * is responsible for regenerating the receiver bit clock, as well as - * for handling the HDLC protocol. The modem connects to a serial port, - * hence the name. Since the serial port is not used as an async serial - * port, the kernel driver for serial ports cannot be used, and this - * driver only supports standard serial hardware (8250, 16450, 16550A) - * - * This modem usually draws its supply current out of the otherwise unused - * TXD pin of the serial port. Thus a contiguous stream of 0x00-bytes - * is transmitted to achieve a positive supply voltage. - * - * hsk: This is a 4800 baud FSK modem, designed for TNC use. It works fine - * in 'baycom-mode' :-) In contrast to the TCM3105 modem, power is - * externally supplied. So there's no need to provide the 0x00-byte-stream - * when receiving or idle, which drastically reduces interrupt load. - * - * Command line options (insmod command line) - * - * mode ser# hardware DCD - * ser#* software DCD - * ser#+ hardware DCD, inverted signal at DCD pin - * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD' - * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 - * baud baud rate (between 300 and 4800) - * irq interrupt line of the port; common values are 4,3 - * - * History: - * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface - * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) - * 0.3 26.04.1997 init code/data tagged - * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints) - * 0.5 11.11.1997 ser12/par96 split into separate files - * 0.6 24.01.1998 Thorsten Kranzkowski, dl8bcu and Thomas Sailer: - * reduced interrupt load in transmit case - * reworked receiver - * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall - * 0.8 10.08.1999 use module_init/module_exit - * 0.9 12.02.2000 adapted to softnet driver interface - * 0.10 03.07.2000 fix interface name handling - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* --------------------------------------------------------------------- */ - -#define BAYCOM_DEBUG - -/* --------------------------------------------------------------------- */ - -static const char bc_drvname[] = "baycom_ser_fdx"; -static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_ser_fdx: version 0.10\n"; - -/* --------------------------------------------------------------------- */ - -#define NR_PORTS 4 - -static struct net_device *baycom_device[NR_PORTS]; - -/* --------------------------------------------------------------------- */ - -#define RBR(iobase) (iobase+0) -#define THR(iobase) (iobase+0) -#define IER(iobase) (iobase+1) -#define IIR(iobase) (iobase+2) -#define FCR(iobase) (iobase+2) -#define LCR(iobase) (iobase+3) -#define MCR(iobase) (iobase+4) -#define LSR(iobase) (iobase+5) -#define MSR(iobase) (iobase+6) -#define SCR(iobase) (iobase+7) -#define DLL(iobase) (iobase+0) -#define DLM(iobase) (iobase+1) - -#define SER12_EXTENT 8 - -/* ---------------------------------------------------------------------- */ -/* - * Information that need to be kept for each board. - */ - -struct baycom_state { - struct hdlcdrv_state hdrv; - - unsigned int baud, baud_us, baud_arbdiv, baud_uartdiv, baud_dcdtimeout; - int opt_dcd; - - struct modem_state { - unsigned char flags; - unsigned char ptt; - unsigned int shreg; - struct modem_state_ser12 { - unsigned char tx_bit; - unsigned char last_rxbit; - int dcd_sum0, dcd_sum1, dcd_sum2; - int dcd_time; - unsigned int pll_time; - unsigned int txshreg; - } ser12; - } modem; - -#ifdef BAYCOM_DEBUG - struct debug_vals { - unsigned long last_jiffies; - unsigned cur_intcnt; - unsigned last_intcnt; - int cur_pllcorr; - int last_pllcorr; - } debug_vals; -#endif /* BAYCOM_DEBUG */ -}; - -/* --------------------------------------------------------------------- */ - -static inline void baycom_int_freq(struct baycom_state *bc) -{ -#ifdef BAYCOM_DEBUG - unsigned long cur_jiffies = jiffies; - /* - * measure the interrupt frequency - */ - bc->debug_vals.cur_intcnt++; - if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { - bc->debug_vals.last_jiffies = cur_jiffies; - bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; - bc->debug_vals.cur_intcnt = 0; - bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; - bc->debug_vals.cur_pllcorr = 0; - } -#endif /* BAYCOM_DEBUG */ -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== SER12 specific routines ========================= - */ - -/* --------------------------------------------------------------------- */ - -static inline void ser12_set_divisor(struct net_device *dev, - unsigned int divisor) -{ - outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ - outb(divisor, DLL(dev->base_addr)); - outb(divisor >> 8, DLM(dev->base_addr)); - outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ - /* - * make sure the next interrupt is generated; - * 0 must be used to power the modem; the modem draws its - * power from the TxD line - */ - outb(0x00, THR(dev->base_addr)); - /* - * it is important not to set the divider while transmitting; - * this reportedly makes some UARTs generating interrupts - * in the hundredthousands per second region - * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno) - */ -} - -static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc, struct timespec64 *ts, unsigned char curs) -{ - int timediff; - int bdus8 = bc->baud_us >> 3; - int bdus4 = bc->baud_us >> 2; - int bdus2 = bc->baud_us >> 1; - - timediff = 1000000 + ts->tv_nsec / NSEC_PER_USEC - - bc->modem.ser12.pll_time; - while (timediff >= 500000) - timediff -= 1000000; - while (timediff >= bdus2) { - timediff -= bc->baud_us; - bc->modem.ser12.pll_time += bc->baud_us; - bc->modem.ser12.dcd_time--; - /* first check if there is room to add a bit */ - if (bc->modem.shreg & 1) { - hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff); - bc->modem.shreg = 0x10000; - } - /* add a one bit */ - bc->modem.shreg >>= 1; - } - if (bc->modem.ser12.dcd_time <= 0) { - if (!bc->opt_dcd) - hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + - bc->modem.ser12.dcd_sum1 + - bc->modem.ser12.dcd_sum2) < 0); - bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; - bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; - bc->modem.ser12.dcd_sum0 = 2; /* slight bias */ - bc->modem.ser12.dcd_time += 120; - } - if (bc->modem.ser12.last_rxbit != curs) { - bc->modem.ser12.last_rxbit = curs; - bc->modem.shreg |= 0x10000; - /* adjust the PLL */ - if (timediff > 0) - bc->modem.ser12.pll_time += bdus8; - else - bc->modem.ser12.pll_time += 1000000 - bdus8; - /* update DCD */ - if (abs(timediff) > bdus4) - bc->modem.ser12.dcd_sum0 += 4; - else - bc->modem.ser12.dcd_sum0--; -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr = timediff; -#endif /* BAYCOM_DEBUG */ - } - while (bc->modem.ser12.pll_time >= 1000000) - bc->modem.ser12.pll_time -= 1000000; -} - -/* --------------------------------------------------------------------- */ - -static irqreturn_t ser12_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = netdev_priv(dev); - struct timespec64 ts; - unsigned char iir, msr; - unsigned int txcount = 0; - - if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC) - return IRQ_NONE; - /* fast way out for shared irq */ - if ((iir = inb(IIR(dev->base_addr))) & 1) - return IRQ_NONE; - /* get current time */ - ktime_get_ts64(&ts); - msr = inb(MSR(dev->base_addr)); - /* delta DCD */ - if ((msr & 8) && bc->opt_dcd) - hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); - do { - switch (iir & 6) { - case 6: - inb(LSR(dev->base_addr)); - break; - - case 4: - inb(RBR(dev->base_addr)); - break; - - case 2: - /* - * make sure the next interrupt is generated; - * 0 must be used to power the modem; the modem draws its - * power from the TxD line - */ - outb(0x00, THR(dev->base_addr)); - baycom_int_freq(bc); - txcount++; - /* - * first output the last bit (!) then call HDLC transmitter, - * since this may take quite long - */ - if (bc->modem.ptt) - outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); - else - outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ - break; - - default: - msr = inb(MSR(dev->base_addr)); - /* delta DCD */ - if ((msr & 8) && bc->opt_dcd) - hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); - break; - } - iir = inb(IIR(dev->base_addr)); - } while (!(iir & 1)); - ser12_rx(dev, bc, &ts, msr & 0x10); /* CTS */ - if (bc->modem.ptt && txcount) { - if (bc->modem.ser12.txshreg <= 1) { - bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); - if (!hdlcdrv_ptt(&bc->hdrv)) { - ser12_set_divisor(dev, 115200/100/8); - bc->modem.ptt = 0; - goto end_transmit; - } - } - bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1)); - bc->modem.ser12.txshreg >>= 1; - } - end_transmit: - local_irq_enable(); - if (!bc->modem.ptt && txcount) { - hdlcdrv_arbitrate(dev, &bc->hdrv); - if (hdlcdrv_ptt(&bc->hdrv)) { - ser12_set_divisor(dev, bc->baud_uartdiv); - bc->modem.ser12.txshreg = 1; - bc->modem.ptt = 1; - } - } - hdlcdrv_transmitter(dev, &bc->hdrv); - hdlcdrv_receiver(dev, &bc->hdrv); - local_irq_disable(); - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -enum uart { c_uart_unknown, c_uart_8250, - c_uart_16450, c_uart_16550, c_uart_16550A}; -static const char *uart_str[] = { - "unknown", "8250", "16450", "16550", "16550A" -}; - -static enum uart ser12_check_uart(unsigned int iobase) -{ - unsigned char b1,b2,b3; - enum uart u; - enum uart uart_tab[] = - { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; - - b1 = inb(MCR(iobase)); - outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ - b2 = inb(MSR(iobase)); - outb(0x1a, MCR(iobase)); - b3 = inb(MSR(iobase)) & 0xf0; - outb(b1, MCR(iobase)); /* restore old values */ - outb(b2, MSR(iobase)); - if (b3 != 0x90) - return c_uart_unknown; - inb(RBR(iobase)); - inb(RBR(iobase)); - outb(0x01, FCR(iobase)); /* enable FIFOs */ - u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; - if (u == c_uart_16450) { - outb(0x5a, SCR(iobase)); - b1 = inb(SCR(iobase)); - outb(0xa5, SCR(iobase)); - b2 = inb(SCR(iobase)); - if ((b1 != 0x5a) || (b2 != 0xa5)) - u = c_uart_8250; - } - return u; -} - -/* --------------------------------------------------------------------- */ - -static int ser12_open(struct net_device *dev) -{ - const unsigned int nr_irqs = irq_get_nr_irqs(); - struct baycom_state *bc = netdev_priv(dev); - enum uart u; - - if (!dev || !bc) - return -ENXIO; - if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT || - dev->irq < 2 || dev->irq > nr_irqs) { - printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) " - "or irq (2 <= irq <= %d)\n", - 0xffff-SER12_EXTENT, nr_irqs); - return -ENXIO; - } - if (bc->baud < 300 || bc->baud > 4800) { - printk(KERN_INFO "baycom_ser_fdx: invalid baudrate " - "(300...4800)\n"); - return -EINVAL; - } - if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) { - printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy\n", - dev->base_addr); - return -EACCES; - } - memset(&bc->modem, 0, sizeof(bc->modem)); - bc->hdrv.par.bitrate = bc->baud; - bc->baud_us = 1000000/bc->baud; - bc->baud_uartdiv = (115200/8)/bc->baud; - if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown){ - release_region(dev->base_addr, SER12_EXTENT); - return -EIO; - } - outb(0, FCR(dev->base_addr)); /* disable FIFOs */ - outb(0x0d, MCR(dev->base_addr)); - outb(0, IER(dev->base_addr)); - if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED, - "baycom_ser_fdx", dev)) { - release_region(dev->base_addr, SER12_EXTENT); - return -EBUSY; - } - /* - * set the SIO to 6 Bits/character; during receive, - * the baud rate is set to produce 100 ints/sec - * to feed the channel arbitration process, - * during transmit to baud ints/sec to run - * the transmitter - */ - ser12_set_divisor(dev, 115200/100/8); - /* - * enable transmitter empty interrupt and modem status interrupt - */ - outb(0x0a, IER(dev->base_addr)); - /* - * make sure the next interrupt is generated; - * 0 must be used to power the modem; the modem draws its - * power from the TxD line - */ - outb(0x00, THR(dev->base_addr)); - hdlcdrv_setdcd(&bc->hdrv, 0); - printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u baud %u uart %s\n", - bc_drvname, dev->base_addr, dev->irq, bc->baud, uart_str[u]); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int ser12_close(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - - if (!dev || !bc) - return -EINVAL; - /* - * disable interrupts - */ - outb(0, IER(dev->base_addr)); - outb(1, MCR(dev->base_addr)); - free_irq(dev->irq, dev); - release_region(dev->base_addr, SER12_EXTENT); - printk(KERN_INFO "%s: close ser_fdx at iobase 0x%lx irq %u\n", - bc_drvname, dev->base_addr, dev->irq); - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== hdlcdrv driver interface ========================= - */ - -/* --------------------------------------------------------------------- */ - -static int baycom_ioctl(struct net_device *dev, void __user *data, - struct hdlcdrv_ioctl *hi, int cmd); - -/* --------------------------------------------------------------------- */ - -static const struct hdlcdrv_ops ser12_ops = { - .drvname = bc_drvname, - .drvinfo = bc_drvinfo, - .open = ser12_open, - .close = ser12_close, - .ioctl = baycom_ioctl, -}; - -/* --------------------------------------------------------------------- */ - -static int baycom_setmode(struct baycom_state *bc, const char *modestr) -{ - unsigned int baud; - - if (!strncmp(modestr, "ser", 3)) { - baud = simple_strtoul(modestr+3, NULL, 10); - if (baud >= 3 && baud <= 48) - bc->baud = baud*100; - } - if (strchr(modestr, '*')) - bc->opt_dcd = 0; - else if (strchr(modestr, '+')) - bc->opt_dcd = -1; - else - bc->opt_dcd = 1; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int baycom_ioctl(struct net_device *dev, void __user *data, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct baycom_state *bc; - struct baycom_ioctl bi; - - if (!dev) - return -EINVAL; - - bc = netdev_priv(dev); - BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - switch (hi->cmd) { - default: - break; - - case HDLCDRVCTL_GETMODE: - sprintf(hi->data.modename, "ser%u", bc->baud / 100); - if (bc->opt_dcd <= 0) - strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : "+"); - if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_SETMODE: - if (netif_running(dev) || !capable(CAP_NET_ADMIN)) - return -EACCES; - hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; - return baycom_setmode(bc, hi->data.modename); - - case HDLCDRVCTL_MODELIST: - strscpy(hi->data.modename, "ser12,ser3,ser24"); - if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_MODEMPARMASK: - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ; - - } - - if (copy_from_user(&bi, data, sizeof(bi))) - return -EFAULT; - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - -#ifdef BAYCOM_DEBUG - case BAYCOMCTL_GETDEBUG: - bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; - bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; - bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; - break; -#endif /* BAYCOM_DEBUG */ - - } - if (copy_to_user(data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -/* - * command line settable parameters - */ -static char *mode[NR_PORTS] = { "ser12*", }; -static int iobase[NR_PORTS] = { 0x3f8, }; -static int irq[NR_PORTS] = { 4, }; -static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 }; - -module_param_array(mode, charp, NULL, 0); -MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); -module_param_hw_array(iobase, int, ioport, NULL, 0); -MODULE_PARM_DESC(iobase, "baycom io base address"); -module_param_hw_array(irq, int, irq, NULL, 0); -MODULE_PARM_DESC(irq, "baycom irq number"); -module_param_array(baud, int, NULL, 0); -MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver"); -MODULE_LICENSE("GPL"); - -/* --------------------------------------------------------------------- */ - -static int __init init_baycomserfdx(void) -{ - int i, found = 0; - char set_hw = 1; - - printk(bc_drvinfo); - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct net_device *dev; - struct baycom_state *bc; - char ifname[IFNAMSIZ]; - - sprintf(ifname, "bcsf%d", i); - - if (!mode[i]) - set_hw = 0; - if (!set_hw) - iobase[i] = irq[i] = 0; - - dev = hdlcdrv_register(&ser12_ops, - sizeof(struct baycom_state), - ifname, iobase[i], irq[i], 0); - if (IS_ERR(dev)) - break; - - bc = netdev_priv(dev); - if (set_hw && baycom_setmode(bc, mode[i])) - set_hw = 0; - bc->baud = baud[i]; - found++; - baycom_device[i] = dev; - } - - if (!found) - return -ENXIO; - return 0; -} - -static void __exit cleanup_baycomserfdx(void) -{ - int i; - - for(i = 0; i < NR_PORTS; i++) { - struct net_device *dev = baycom_device[i]; - if (dev) - hdlcdrv_unregister(dev); - } -} - -module_init(init_baycomserfdx); -module_exit(cleanup_baycomserfdx); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* - * format: baycom_ser_fdx=io,irq,mode - * mode: ser# hardware DCD - * ser#* software DCD - * ser#+ hardware DCD, inverted signal at DCD pin - * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD' - */ - -static int __init baycom_ser_fdx_setup(char *str) -{ - static unsigned nr_dev; - int ints[4]; - - if (nr_dev >= NR_PORTS) - return 0; - str = get_options(str, 4, ints); - if (ints[0] < 2) - return 0; - mode[nr_dev] = str; - iobase[nr_dev] = ints[1]; - irq[nr_dev] = ints[2]; - if (ints[0] >= 3) - baud[nr_dev] = ints[3]; - nr_dev++; - return 1; -} - -__setup("baycom_ser_fdx=", baycom_ser_fdx_setup); - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c deleted file mode 100644 index 05bdad214799..000000000000 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ /dev/null @@ -1,727 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*****************************************************************************/ - -/* - * baycom_ser_hdx.c -- baycom ser12 halfduplex radio modem driver. - * - * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * Supported modems - * - * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only - * of a modulator/demodulator chip, usually a TI TCM3105. The computer - * is responsible for regenerating the receiver bit clock, as well as - * for handling the HDLC protocol. The modem connects to a serial port, - * hence the name. Since the serial port is not used as an async serial - * port, the kernel driver for serial ports cannot be used, and this - * driver only supports standard serial hardware (8250, 16450, 16550A) - * - * Command line options (insmod command line) - * - * mode ser12 hardware DCD - * ser12* software DCD - * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware - * mutes audio input to the modem - * ser12+ hardware DCD, inverted signal at DCD pin - * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 - * irq interrupt line of the port; common values are 4,3 - * - * History: - * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface - * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) - * 0.3 26.04.1997 init code/data tagged - * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints) - * 0.5 11.11.1997 ser12/par96 split into separate files - * 0.6 14.04.1998 cleanups - * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall - * 0.8 10.08.1999 use module_init/module_exit - * 0.9 12.02.2000 adapted to softnet driver interface - * 0.10 03.07.2000 fix interface name handling - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* --------------------------------------------------------------------- */ - -#define BAYCOM_DEBUG - -/* --------------------------------------------------------------------- */ - -static const char bc_drvname[] = "baycom_ser_hdx"; -static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_ser_hdx: version 0.10\n"; - -/* --------------------------------------------------------------------- */ - -#define NR_PORTS 4 - -static struct net_device *baycom_device[NR_PORTS]; - -/* --------------------------------------------------------------------- */ - -#define RBR(iobase) (iobase+0) -#define THR(iobase) (iobase+0) -#define IER(iobase) (iobase+1) -#define IIR(iobase) (iobase+2) -#define FCR(iobase) (iobase+2) -#define LCR(iobase) (iobase+3) -#define MCR(iobase) (iobase+4) -#define LSR(iobase) (iobase+5) -#define MSR(iobase) (iobase+6) -#define SCR(iobase) (iobase+7) -#define DLL(iobase) (iobase+0) -#define DLM(iobase) (iobase+1) - -#define SER12_EXTENT 8 - -/* ---------------------------------------------------------------------- */ -/* - * Information that need to be kept for each board. - */ - -struct baycom_state { - struct hdlcdrv_state hdrv; - - int opt_dcd; - - struct modem_state { - short arb_divider; - unsigned char flags; - unsigned int shreg; - struct modem_state_ser12 { - unsigned char tx_bit; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned char last_sample; - unsigned char last_rxbit; - unsigned int dcd_shreg; - unsigned int dcd_time; - unsigned int bit_pll; - unsigned char interm_sample; - } ser12; - } modem; - -#ifdef BAYCOM_DEBUG - struct debug_vals { - unsigned long last_jiffies; - unsigned cur_intcnt; - unsigned last_intcnt; - int cur_pllcorr; - int last_pllcorr; - } debug_vals; -#endif /* BAYCOM_DEBUG */ -}; - -/* --------------------------------------------------------------------- */ - -static inline void baycom_int_freq(struct baycom_state *bc) -{ -#ifdef BAYCOM_DEBUG - unsigned long cur_jiffies = jiffies; - /* - * measure the interrupt frequency - */ - bc->debug_vals.cur_intcnt++; - if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { - bc->debug_vals.last_jiffies = cur_jiffies; - bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; - bc->debug_vals.cur_intcnt = 0; - bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; - bc->debug_vals.cur_pllcorr = 0; - } -#endif /* BAYCOM_DEBUG */ -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== SER12 specific routines ========================= - */ - -static inline void ser12_set_divisor(struct net_device *dev, - unsigned char divisor) -{ - outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ - outb(divisor, DLL(dev->base_addr)); - outb(0, DLM(dev->base_addr)); - outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ - /* - * make sure the next interrupt is generated; - * 0 must be used to power the modem; the modem draws its - * power from the TxD line - */ - outb(0x00, THR(dev->base_addr)); - /* - * it is important not to set the divider while transmitting; - * this reportedly makes some UARTs generating interrupts - * in the hundredthousands per second region - * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno) - */ -} - -/* --------------------------------------------------------------------- */ - -/* - * must call the TX arbitrator every 10ms - */ -#define SER12_ARB_DIVIDER(bc) (bc->opt_dcd ? 24 : 36) - -#define SER12_DCD_INTERVAL(bc) (bc->opt_dcd ? 12 : 240) - -static inline void ser12_tx(struct net_device *dev, struct baycom_state *bc) -{ - /* one interrupt per channel bit */ - ser12_set_divisor(dev, 12); - /* - * first output the last bit (!) then call HDLC transmitter, - * since this may take quite long - */ - outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); - if (bc->modem.shreg <= 1) - bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); - bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ - (bc->modem.shreg & 1)); - bc->modem.shreg >>= 1; -} - -/* --------------------------------------------------------------------- */ - -static inline void ser12_rx(struct net_device *dev, struct baycom_state *bc) -{ - unsigned char cur_s; - /* - * do demodulator - */ - cur_s = inb(MSR(dev->base_addr)) & 0x10; /* the CTS line */ - hdlcdrv_channelbit(&bc->hdrv, cur_s); - bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) | - (cur_s != bc->modem.ser12.last_sample); - bc->modem.ser12.last_sample = cur_s; - if(bc->modem.ser12.dcd_shreg & 1) { - if (!bc->opt_dcd) { - unsigned int dcdspos, dcdsneg; - - dcdspos = dcdsneg = 0; - dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); - if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) - dcdspos += 2; - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); - - bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; - } else - bc->modem.ser12.dcd_sum0--; - } - if(!bc->modem.ser12.dcd_time) { - hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + - bc->modem.ser12.dcd_sum1 + - bc->modem.ser12.dcd_sum2) < 0); - bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; - bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; - /* offset to ensure DCD off on silent input */ - bc->modem.ser12.dcd_sum0 = 2; - bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); - } - bc->modem.ser12.dcd_time--; - if (!bc->opt_dcd) { - /* - * PLL code for the improved software DCD algorithm - */ - if (bc->modem.ser12.interm_sample) { - /* - * intermediate sample; set timing correction to normal - */ - ser12_set_divisor(dev, 4); - } else { - /* - * do PLL correction and call HDLC receiver - */ - switch (bc->modem.ser12.dcd_shreg & 7) { - case 1: /* transition too late */ - ser12_set_divisor(dev, 5); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr++; -#endif /* BAYCOM_DEBUG */ - break; - case 4: /* transition too early */ - ser12_set_divisor(dev, 3); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr--; -#endif /* BAYCOM_DEBUG */ - break; - default: - ser12_set_divisor(dev, 4); - break; - } - bc->modem.shreg >>= 1; - if (bc->modem.ser12.last_sample == - bc->modem.ser12.last_rxbit) - bc->modem.shreg |= 0x10000; - bc->modem.ser12.last_rxbit = - bc->modem.ser12.last_sample; - } - if (++bc->modem.ser12.interm_sample >= 3) - bc->modem.ser12.interm_sample = 0; - /* - * DCD stuff - */ - if (bc->modem.ser12.dcd_shreg & 1) { - unsigned int dcdspos, dcdsneg; - - dcdspos = dcdsneg = 0; - dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); - dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) - << 1; - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); - dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); - - bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; - } - } else { - /* - * PLL algorithm for the hardware squelch DCD algorithm - */ - if (bc->modem.ser12.interm_sample) { - /* - * intermediate sample; set timing correction to normal - */ - ser12_set_divisor(dev, 6); - } else { - /* - * do PLL correction and call HDLC receiver - */ - switch (bc->modem.ser12.dcd_shreg & 3) { - case 1: /* transition too late */ - ser12_set_divisor(dev, 7); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr++; -#endif /* BAYCOM_DEBUG */ - break; - case 2: /* transition too early */ - ser12_set_divisor(dev, 5); -#ifdef BAYCOM_DEBUG - bc->debug_vals.cur_pllcorr--; -#endif /* BAYCOM_DEBUG */ - break; - default: - ser12_set_divisor(dev, 6); - break; - } - bc->modem.shreg >>= 1; - if (bc->modem.ser12.last_sample == - bc->modem.ser12.last_rxbit) - bc->modem.shreg |= 0x10000; - bc->modem.ser12.last_rxbit = - bc->modem.ser12.last_sample; - } - bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample; - /* - * DCD stuff - */ - bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1); - } - outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ - if (bc->modem.shreg & 1) { - hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1); - bc->modem.shreg = 0x10000; - } - if(!bc->modem.ser12.dcd_time) { - if (bc->opt_dcd & 1) - hdlcdrv_setdcd(&bc->hdrv, !((inb(MSR(dev->base_addr)) ^ bc->opt_dcd) & 0x80)); - else - hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + - bc->modem.ser12.dcd_sum1 + - bc->modem.ser12.dcd_sum2) < 0); - bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; - bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; - /* offset to ensure DCD off on silent input */ - bc->modem.ser12.dcd_sum0 = 2; - bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); - } - bc->modem.ser12.dcd_time--; -} - -/* --------------------------------------------------------------------- */ - -static irqreturn_t ser12_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = netdev_priv(dev); - unsigned char iir; - - if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) - return IRQ_NONE; - /* fast way out */ - if ((iir = inb(IIR(dev->base_addr))) & 1) - return IRQ_NONE; - baycom_int_freq(bc); - do { - switch (iir & 6) { - case 6: - inb(LSR(dev->base_addr)); - break; - - case 4: - inb(RBR(dev->base_addr)); - break; - - case 2: - /* - * check if transmitter active - */ - if (hdlcdrv_ptt(&bc->hdrv)) - ser12_tx(dev, bc); - else { - ser12_rx(dev, bc); - bc->modem.arb_divider--; - } - outb(0x00, THR(dev->base_addr)); - break; - - default: - inb(MSR(dev->base_addr)); - break; - } - iir = inb(IIR(dev->base_addr)); - } while (!(iir & 1)); - if (bc->modem.arb_divider <= 0) { - bc->modem.arb_divider = SER12_ARB_DIVIDER(bc); - local_irq_enable(); - hdlcdrv_arbitrate(dev, &bc->hdrv); - } - local_irq_enable(); - hdlcdrv_transmitter(dev, &bc->hdrv); - hdlcdrv_receiver(dev, &bc->hdrv); - local_irq_disable(); - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -enum uart { c_uart_unknown, c_uart_8250, - c_uart_16450, c_uart_16550, c_uart_16550A}; -static const char *uart_str[] = { - "unknown", "8250", "16450", "16550", "16550A" -}; - -static enum uart ser12_check_uart(unsigned int iobase) -{ - unsigned char b1,b2,b3; - enum uart u; - enum uart uart_tab[] = - { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; - - b1 = inb(MCR(iobase)); - outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ - b2 = inb(MSR(iobase)); - outb(0x1a, MCR(iobase)); - b3 = inb(MSR(iobase)) & 0xf0; - outb(b1, MCR(iobase)); /* restore old values */ - outb(b2, MSR(iobase)); - if (b3 != 0x90) - return c_uart_unknown; - inb(RBR(iobase)); - inb(RBR(iobase)); - outb(0x01, FCR(iobase)); /* enable FIFOs */ - u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; - if (u == c_uart_16450) { - outb(0x5a, SCR(iobase)); - b1 = inb(SCR(iobase)); - outb(0xa5, SCR(iobase)); - b2 = inb(SCR(iobase)); - if ((b1 != 0x5a) || (b2 != 0xa5)) - u = c_uart_8250; - } - return u; -} - -/* --------------------------------------------------------------------- */ - -static int ser12_open(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - enum uart u; - - if (!dev || !bc) - return -ENXIO; - if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || - dev->irq < 2 || dev->irq > 15) - return -ENXIO; - if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12")) - return -EACCES; - memset(&bc->modem, 0, sizeof(bc->modem)); - bc->hdrv.par.bitrate = 1200; - if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) { - release_region(dev->base_addr, SER12_EXTENT); - return -EIO; - } - outb(0, FCR(dev->base_addr)); /* disable FIFOs */ - outb(0x0d, MCR(dev->base_addr)); - outb(0, IER(dev->base_addr)); - if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED, - "baycom_ser12", dev)) { - release_region(dev->base_addr, SER12_EXTENT); - return -EBUSY; - } - /* - * enable transmitter empty interrupt - */ - outb(2, IER(dev->base_addr)); - /* - * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that - * we get exactly (hopefully) 2 or 3 interrupts per radio symbol, - * depending on the usage of the software DCD routine - */ - ser12_set_divisor(dev, bc->opt_dcd ? 6 : 4); - printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u uart %s\n", - bc_drvname, dev->base_addr, dev->irq, uart_str[u]); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int ser12_close(struct net_device *dev) -{ - struct baycom_state *bc = netdev_priv(dev); - - if (!dev || !bc) - return -EINVAL; - /* - * disable interrupts - */ - outb(0, IER(dev->base_addr)); - outb(1, MCR(dev->base_addr)); - free_irq(dev->irq, dev); - release_region(dev->base_addr, SER12_EXTENT); - printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n", - bc_drvname, dev->base_addr, dev->irq); - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== hdlcdrv driver interface ========================= - */ - -/* --------------------------------------------------------------------- */ - -static int baycom_ioctl(struct net_device *dev, void __user *data, - struct hdlcdrv_ioctl *hi, int cmd); - -/* --------------------------------------------------------------------- */ - -static const struct hdlcdrv_ops ser12_ops = { - .drvname = bc_drvname, - .drvinfo = bc_drvinfo, - .open = ser12_open, - .close = ser12_close, - .ioctl = baycom_ioctl, -}; - -/* --------------------------------------------------------------------- */ - -static int baycom_setmode(struct baycom_state *bc, const char *modestr) -{ - if (strchr(modestr, '*')) - bc->opt_dcd = 0; - else if (strchr(modestr, '+')) - bc->opt_dcd = -1; - else if (strchr(modestr, '@')) - bc->opt_dcd = -2; - else - bc->opt_dcd = 1; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int baycom_ioctl(struct net_device *dev, void __user *data, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct baycom_state *bc; - struct baycom_ioctl bi; - - if (!dev) - return -EINVAL; - - bc = netdev_priv(dev); - BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - switch (hi->cmd) { - default: - break; - - case HDLCDRVCTL_GETMODE: - strscpy(hi->data.modename, "ser12"); - if (bc->opt_dcd <= 0) - strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : (bc->opt_dcd == -2) ? "@" : "+"); - if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_SETMODE: - if (netif_running(dev) || !capable(CAP_NET_ADMIN)) - return -EACCES; - hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; - return baycom_setmode(bc, hi->data.modename); - - case HDLCDRVCTL_MODELIST: - strscpy(hi->data.modename, "ser12"); - if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_MODEMPARMASK: - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ; - - } - - if (copy_from_user(&bi, data, sizeof(bi))) - return -EFAULT; - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - -#ifdef BAYCOM_DEBUG - case BAYCOMCTL_GETDEBUG: - bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; - bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; - bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; - break; -#endif /* BAYCOM_DEBUG */ - - } - if (copy_to_user(data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -/* - * command line settable parameters - */ -static char *mode[NR_PORTS] = { "ser12*", }; -static int iobase[NR_PORTS] = { 0x3f8, }; -static int irq[NR_PORTS] = { 4, }; - -module_param_array(mode, charp, NULL, 0); -MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); -module_param_hw_array(iobase, int, ioport, NULL, 0); -MODULE_PARM_DESC(iobase, "baycom io base address"); -module_param_hw_array(irq, int, irq, NULL, 0); -MODULE_PARM_DESC(irq, "baycom irq number"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver"); -MODULE_LICENSE("GPL"); - -/* --------------------------------------------------------------------- */ - -static int __init init_baycomserhdx(void) -{ - int i, found = 0; - char set_hw = 1; - - printk(bc_drvinfo); - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct net_device *dev; - struct baycom_state *bc; - char ifname[IFNAMSIZ]; - - sprintf(ifname, "bcsh%d", i); - - if (!mode[i]) - set_hw = 0; - if (!set_hw) - iobase[i] = irq[i] = 0; - - dev = hdlcdrv_register(&ser12_ops, - sizeof(struct baycom_state), - ifname, iobase[i], irq[i], 0); - if (IS_ERR(dev)) - break; - - bc = netdev_priv(dev); - if (set_hw && baycom_setmode(bc, mode[i])) - set_hw = 0; - found++; - baycom_device[i] = dev; - } - - if (!found) - return -ENXIO; - return 0; -} - -static void __exit cleanup_baycomserhdx(void) -{ - int i; - - for(i = 0; i < NR_PORTS; i++) { - struct net_device *dev = baycom_device[i]; - - if (dev) - hdlcdrv_unregister(dev); - } -} - -module_init(init_baycomserhdx); -module_exit(cleanup_baycomserhdx); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* - * format: baycom_ser_hdx=io,irq,mode - * mode: ser12 hardware DCD - * ser12* software DCD - * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware - * mutes audio input to the modem - * ser12+ hardware DCD, inverted signal at DCD pin - */ - -static int __init baycom_ser_hdx_setup(char *str) -{ - static unsigned nr_dev; - int ints[3]; - - if (nr_dev >= NR_PORTS) - return 0; - str = get_options(str, 3, ints); - if (ints[0] < 2) - return 0; - mode[nr_dev] = str; - iobase[nr_dev] = ints[1]; - irq[nr_dev] = ints[2]; - nr_dev++; - return 1; -} - -__setup("baycom_ser_hdx=", baycom_ser_hdx_setup); - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c deleted file mode 100644 index 214fd1f819a1..000000000000 --- a/drivers/net/hamradio/bpqether.c +++ /dev/null @@ -1,593 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * G8BPQ compatible "AX.25 via ethernet" driver release 004 - * - * This code REQUIRES 2.0.0 or higher/ NET3.029 - * - * This is a "pseudo" network driver to allow AX.25 over Ethernet - * using G8BPQ encapsulation. It has been extracted from the protocol - * implementation because - * - * - things got unreadable within the protocol stack - * - to cure the protocol stack from "feature-ism" - * - a protocol implementation shouldn't need to know on - * which hardware it is running - * - user-level programs like the AX.25 utilities shouldn't - * need to know about the hardware. - * - IP over ethernet encapsulated AX.25 was impossible - * - rxecho.c did not work - * - to have room for extensions - * - it just deserves to "live" as an own driver - * - * This driver can use any ethernet destination address, and can be - * limited to accept frames from one dedicated ethernet card only. - * - * Note that the driver sets up the BPQ devices automagically on - * startup or (if started before the "insmod" of an ethernet device) - * on "ifconfig up". It hopefully will remove the BPQ on "rmmod"ing - * the ethernet device (in fact: as soon as another ethernet or bpq - * device gets "ifconfig"ured). - * - * I have heard that several people are thinking of experiments - * with highspeed packet radio using existing ethernet cards. - * Well, this driver is prepared for this purpose, just add - * your tx key control and a txdelay / tailtime algorithm, - * probably some buffering, and /voila/... - * - * History - * BPQ 001 Joerg(DL1BKE) Extracted BPQ code from AX.25 - * protocol stack and added my own - * yet existing patches - * BPQ 002 Joerg(DL1BKE) Scan network device list on - * startup. - * BPQ 003 Joerg(DL1BKE) Ethernet destination address - * and accepted source address - * can be configured by an ioctl() - * call. - * Fixed to match Linux networking - * changes - 2.1.15. - * BPQ 004 Joerg(DL1BKE) Fixed to not lock up on ifconfig. - */ - -#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 -#include -#include -#include - -#include - -static const char banner[] __initconst = KERN_INFO \ - "AX.25: bpqether driver version 004\n"; - -static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); -static int bpq_device_event(struct notifier_block *, unsigned long, void *); - -static struct packet_type bpq_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_BPQ), - .func = bpq_rcv, -}; - -static struct notifier_block bpq_dev_notifier = { - .notifier_call = bpq_device_event, -}; - - -struct bpqdev { - struct list_head bpq_list; /* list of bpq devices chain */ - struct net_device *ethdev; /* link to ethernet device */ - struct net_device *axdev; /* bpq device (bpq#) */ - char dest_addr[6]; /* ether destination address */ - char acpt_addr[6]; /* accept ether frames from this address only */ -}; - -static LIST_HEAD(bpq_devices); - -/* ------------------------------------------------------------------------ */ - - -/* - * Get the ethernet device for a BPQ device - */ -static inline struct net_device *bpq_get_ether_dev(struct net_device *dev) -{ - struct bpqdev *bpq = netdev_priv(dev); - - return bpq ? bpq->ethdev : NULL; -} - -/* - * Get the BPQ device for the ethernet device - */ -static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev) -{ - struct bpqdev *bpq; - - list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list, - lockdep_rtnl_is_held()) { - if (bpq->ethdev == dev) - return bpq->axdev; - } - return NULL; -} - -static inline int dev_is_ethdev(struct net_device *dev) -{ - return dev->type == ARPHRD_ETHER && !netdev_need_ops_lock(dev); -} - -/* ------------------------------------------------------------------------ */ - - -/* - * Receive an AX.25 frame via an ethernet interface. - */ -static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) -{ - int len; - char * ptr; - struct ethhdr *eth; - struct bpqdev *bpq; - - if (!net_eq(dev_net(dev), &init_net)) - goto drop; - - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) - return NET_RX_DROP; - - if (!pskb_may_pull(skb, sizeof(struct ethhdr))) - goto drop; - - rcu_read_lock(); - dev = bpq_get_ax25_dev(dev); - - if (dev == NULL || !netif_running(dev)) - goto drop_unlock; - - /* - * if we want to accept frames from just one ethernet device - * we check the source address of the sender. - */ - - bpq = netdev_priv(dev); - - eth = eth_hdr(skb); - - if (!(bpq->acpt_addr[0] & 0x01) && - !ether_addr_equal(eth->h_source, bpq->acpt_addr)) - goto drop_unlock; - - if (skb_cow(skb, sizeof(struct ethhdr))) - goto drop_unlock; - - len = skb->data[0] + skb->data[1] * 256 - 5; - - if (len < 0 || len > skb->len - 2) - goto drop_unlock; - - skb_pull(skb, 2); /* Remove the length bytes */ - skb_trim(skb, len); /* Set the length of the data */ - - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; - - ptr = skb_push(skb, 1); - *ptr = 0; - - skb->protocol = ax25_type_trans(skb, dev); - netif_rx(skb); -unlock: - - rcu_read_unlock(); - - return 0; -drop_unlock: - kfree_skb(skb); - goto unlock; - -drop: - kfree_skb(skb); - return 0; -} - -/* - * Send an AX.25 frame via an ethernet interface - */ -static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev) -{ - unsigned char *ptr; - struct bpqdev *bpq; - struct net_device *orig_dev; - int size; - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - /* - * Just to be *really* sure not to send anything if the interface - * is down, the ethernet device may have gone. - */ - if (!netif_running(dev)) { - kfree_skb(skb); - return NETDEV_TX_OK; - } - - skb_pull(skb, 1); /* Drop KISS byte */ - size = skb->len; - - /* - * We're about to mess with the skb which may still shared with the - * generic networking code so unshare and ensure it's got enough - * space for the BPQ headers. - */ - if (skb_cow(skb, AX25_BPQ_HEADER_LEN)) { - if (net_ratelimit()) - pr_err("bpqether: out of memory\n"); - kfree_skb(skb); - - return NETDEV_TX_OK; - } - - ptr = skb_push(skb, 2); /* Make space for length */ - - *ptr++ = (size + 5) % 256; - *ptr++ = (size + 5) / 256; - - bpq = netdev_priv(dev); - - orig_dev = dev; - if ((dev = bpq_get_ether_dev(dev)) == NULL) { - orig_dev->stats.tx_dropped++; - kfree_skb(skb); - return NETDEV_TX_OK; - } - - skb->protocol = ax25_type_trans(skb, dev); - skb_reset_network_header(skb); - dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); - dev->stats.tx_packets++; - dev->stats.tx_bytes+=skb->len; - - dev_queue_xmit(skb); - netif_wake_queue(dev); - return NETDEV_TX_OK; -} - -/* - * Set AX.25 callsign - */ -static int bpq_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *)addr; - - dev_addr_set(dev, sa->sa_data); - - return 0; -} - -/* Ioctl commands - * - * SIOCSBPQETHOPT reserved for enhancements - * SIOCSBPQETHADDR set the destination and accepted - * source ethernet address (broadcast - * or multicast: accept all) - */ -static int bpq_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd) -{ - struct bpq_ethaddr __user *ethaddr = data; - struct bpqdev *bpq = netdev_priv(dev); - struct bpq_req req; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch (cmd) { - case SIOCSBPQETHOPT: - if (copy_from_user(&req, data, sizeof(struct bpq_req))) - return -EFAULT; - switch (req.cmd) { - case SIOCGBPQETHPARAM: - case SIOCSBPQETHPARAM: - default: - return -EINVAL; - } - - break; - - case SIOCSBPQETHADDR: - if (copy_from_user(bpq->dest_addr, ethaddr->destination, ETH_ALEN)) - return -EFAULT; - if (copy_from_user(bpq->acpt_addr, ethaddr->accept, ETH_ALEN)) - return -EFAULT; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * open/close a device - */ -static int bpq_open(struct net_device *dev) -{ - netif_start_queue(dev); - return 0; -} - -static int bpq_close(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - - -/* ------------------------------------------------------------------------ */ - -#ifdef CONFIG_PROC_FS -/* - * Proc filesystem - */ -static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - int i = 1; - struct bpqdev *bpqdev; - - rcu_read_lock(); - - if (*pos == 0) - return SEQ_START_TOKEN; - - list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) { - if (i == *pos) - return bpqdev; - } - return NULL; -} - -static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct list_head *p; - struct bpqdev *bpqdev = v; - - ++*pos; - - if (v == SEQ_START_TOKEN) - p = rcu_dereference(list_next_rcu(&bpq_devices)); - else - p = rcu_dereference(list_next_rcu(&bpqdev->bpq_list)); - - return (p == &bpq_devices) ? NULL - : list_entry(p, struct bpqdev, bpq_list); -} - -static void bpq_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock(); -} - - -static int bpq_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_puts(seq, - "dev ether destination accept from\n"); - else { - const struct bpqdev *bpqdev = v; - - seq_printf(seq, "%-5s %-10s %pM ", - bpqdev->axdev->name, bpqdev->ethdev->name, - bpqdev->dest_addr); - - if (is_multicast_ether_addr(bpqdev->acpt_addr)) - seq_printf(seq, "*\n"); - else - seq_printf(seq, "%pM\n", bpqdev->acpt_addr); - - } - return 0; -} - -static const struct seq_operations bpq_seqops = { - .start = bpq_seq_start, - .next = bpq_seq_next, - .stop = bpq_seq_stop, - .show = bpq_seq_show, -}; -#endif -/* ------------------------------------------------------------------------ */ - -static const struct net_device_ops bpq_netdev_ops = { - .ndo_open = bpq_open, - .ndo_stop = bpq_close, - .ndo_start_xmit = bpq_xmit, - .ndo_set_mac_address = bpq_set_mac_address, - .ndo_siocdevprivate = bpq_siocdevprivate, -}; - -static void bpq_setup(struct net_device *dev) -{ - netdev_lockdep_set_classes(dev); - - dev->netdev_ops = &bpq_netdev_ops; - dev->needs_free_netdev = true; - - dev->flags = 0; - dev->lltx = true; /* Allow recursion */ - -#if IS_ENABLED(CONFIG_AX25) - dev->header_ops = &ax25_header_ops; -#endif - - dev->type = ARPHRD_AX25; - dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; - dev->mtu = AX25_DEF_PACLEN; - dev->addr_len = AX25_ADDR_LEN; - - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&ax25_defaddr); -} - -/* - * Setup a new device. - */ -static int bpq_new_device(struct net_device *edev) -{ - int err; - struct net_device *ndev; - struct bpqdev *bpq; - - ndev = alloc_netdev(sizeof(struct bpqdev), "bpq%d", NET_NAME_UNKNOWN, - bpq_setup); - if (!ndev) - return -ENOMEM; - - - bpq = netdev_priv(ndev); - dev_hold(edev); - bpq->ethdev = edev; - bpq->axdev = ndev; - - eth_broadcast_addr(bpq->dest_addr); - eth_broadcast_addr(bpq->acpt_addr); - - err = register_netdevice(ndev); - if (err) - goto error; - - /* List protected by RTNL */ - list_add_rcu(&bpq->bpq_list, &bpq_devices); - return 0; - - error: - dev_put(edev); - free_netdev(ndev); - return err; - -} - -static void bpq_free_device(struct net_device *ndev) -{ - struct bpqdev *bpq = netdev_priv(ndev); - - dev_put(bpq->ethdev); - list_del_rcu(&bpq->bpq_list); - - unregister_netdevice(ndev); -} - -/* - * Handle device status changes. - */ -static int bpq_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 (!dev_is_ethdev(dev) && !bpq_get_ax25_dev(dev)) - return NOTIFY_DONE; - - switch (event) { - case NETDEV_UP: /* new ethernet device -> new BPQ interface */ - if (bpq_get_ax25_dev(dev) == NULL) - bpq_new_device(dev); - break; - - case NETDEV_DOWN: /* ethernet device closed -> close BPQ interface */ - if ((dev = bpq_get_ax25_dev(dev)) != NULL) - dev_close(dev); - break; - - case NETDEV_UNREGISTER: /* ethernet device removed -> free BPQ interface */ - if ((dev = bpq_get_ax25_dev(dev)) != NULL) - bpq_free_device(dev); - break; - default: - break; - } - - return NOTIFY_DONE; -} - - -/* ------------------------------------------------------------------------ */ - -/* - * Initialize driver. To be called from af_ax25 if not compiled as a - * module - */ -static int __init bpq_init_driver(void) -{ -#ifdef CONFIG_PROC_FS - if (!proc_create_seq("bpqether", 0444, init_net.proc_net, &bpq_seqops)) { - printk(KERN_ERR - "bpq: cannot create /proc/net/bpqether entry.\n"); - return -ENOENT; - } -#endif /* CONFIG_PROC_FS */ - - dev_add_pack(&bpq_packet_type); - - register_netdevice_notifier(&bpq_dev_notifier); - - printk(banner); - - return 0; -} - -static void __exit bpq_cleanup_driver(void) -{ - struct bpqdev *bpq; - - dev_remove_pack(&bpq_packet_type); - - unregister_netdevice_notifier(&bpq_dev_notifier); - - remove_proc_entry("bpqether", init_net.proc_net); - - rtnl_lock(); - while (!list_empty(&bpq_devices)) { - bpq = list_entry(bpq_devices.next, struct bpqdev, bpq_list); - bpq_free_device(bpq->axdev); - } - rtnl_unlock(); -} - -MODULE_AUTHOR("Joerg Reuter DL1BKE "); -MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet"); -MODULE_LICENSE("GPL"); -module_init(bpq_init_driver); -module_exit(bpq_cleanup_driver); diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c deleted file mode 100644 index 3b88e465d08f..000000000000 --- a/drivers/net/hamradio/hdlcdrv.c +++ /dev/null @@ -1,747 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*****************************************************************************/ - -/* - * hdlcdrv.c -- HDLC packet radio network driver. - * - * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * The driver was derived from Donald Beckers skeleton.c - * Written 1993-94 by Donald Becker. - * - * History: - * 0.1 21.09.1996 Started - * 18.10.1996 Changed to new user space access routines - * (copy_{to,from}_user) - * 0.2 21.11.1996 various small changes - * 0.3 03.03.1997 fixed (hopefully) IP not working with ax.25 as a module - * 0.4 16.04.1997 init code/data tagged - * 0.5 30.07.1997 made HDLC buffers bigger (solves a problem with the - * soundmodem driver) - * 0.6 05.04.1998 add spinlocks - * 0.7 03.08.1999 removed some old compatibility cruft - * 0.8 12.02.2000 adapted to softnet driver interface - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -/* --------------------------------------------------------------------- */ - -#define KISS_VERBOSE - -/* --------------------------------------------------------------------- */ - -#define PARAM_TXDELAY 1 -#define PARAM_PERSIST 2 -#define PARAM_SLOTTIME 3 -#define PARAM_TXTAIL 4 -#define PARAM_FULLDUP 5 -#define PARAM_HARDWARE 6 -#define PARAM_RETURN 255 - -/* --------------------------------------------------------------------- */ -/* - * the CRC routines are stolen from WAMPES - * by Dieter Deyke - */ - - -/*---------------------------------------------------------------------------*/ - -static inline void append_crc_ccitt(unsigned char *buffer, int len) -{ - unsigned int crc = crc_ccitt(0xffff, buffer, len) ^ 0xffff; - buffer += len; - *buffer++ = crc; - *buffer++ = crc >> 8; -} - -/*---------------------------------------------------------------------------*/ - -static inline int check_crc_ccitt(const unsigned char *buf, int cnt) -{ - return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8; -} - -/*---------------------------------------------------------------------------*/ - -#if 0 -static int calc_crc_ccitt(const unsigned char *buf, int cnt) -{ - unsigned int crc = 0xffff; - - for (; cnt > 0; cnt--) - crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; - crc ^= 0xffff; - return crc & 0xffff; -} -#endif - -/* ---------------------------------------------------------------------- */ - -#define tenms_to_2flags(s,tenms) ((tenms * s->par.bitrate) / 100 / 16) - -/* ---------------------------------------------------------------------- */ -/* - * The HDLC routines - */ - -static int hdlc_rx_add_bytes(struct hdlcdrv_state *s, unsigned int bits, - int num) -{ - int added = 0; - - while (s->hdlcrx.rx_state && num >= 8) { - if (s->hdlcrx.len >= sizeof(s->hdlcrx.buffer)) { - s->hdlcrx.rx_state = 0; - return 0; - } - *s->hdlcrx.bp++ = bits >> (32-num); - s->hdlcrx.len++; - num -= 8; - added += 8; - } - return added; -} - -static void hdlc_rx_flag(struct net_device *dev, struct hdlcdrv_state *s) -{ - struct sk_buff *skb; - int pkt_len; - unsigned char *cp; - - if (s->hdlcrx.len < 4) - return; - if (!check_crc_ccitt(s->hdlcrx.buffer, s->hdlcrx.len)) - return; - pkt_len = s->hdlcrx.len - 2 + 1; /* KISS kludge */ - if (!(skb = dev_alloc_skb(pkt_len))) { - printk("%s: memory squeeze, dropping packet\n", dev->name); - dev->stats.rx_dropped++; - return; - } - cp = skb_put(skb, pkt_len); - *cp++ = 0; /* KISS kludge */ - memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); - skb->protocol = ax25_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; -} - -void hdlcdrv_receiver(struct net_device *dev, struct hdlcdrv_state *s) -{ - int i; - unsigned int mask1, mask2, mask3, mask4, mask5, mask6, word; - - if (!s || s->magic != HDLCDRV_MAGIC) - return; - if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx)) - return; - - while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) { - word = hdlcdrv_hbuf_get(&s->hdlcrx.hbuf); - -#ifdef HDLCDRV_DEBUG - hdlcdrv_add_bitbuffer_word(&s->bitbuf_hdlc, word); -#endif /* HDLCDRV_DEBUG */ - s->hdlcrx.bitstream >>= 16; - s->hdlcrx.bitstream |= word << 16; - s->hdlcrx.bitbuf >>= 16; - s->hdlcrx.bitbuf |= word << 16; - s->hdlcrx.numbits += 16; - for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00, - mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff; - i >= 0; - i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1, - mask5 <<= 1, mask6 = (mask6 << 1) | 1) { - if ((s->hdlcrx.bitstream & mask1) == mask1) - s->hdlcrx.rx_state = 0; /* abort received */ - else if ((s->hdlcrx.bitstream & mask2) == mask3) { - /* flag received */ - if (s->hdlcrx.rx_state) { - hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf - << (8+i), - s->hdlcrx.numbits - -8-i); - hdlc_rx_flag(dev, s); - } - s->hdlcrx.len = 0; - s->hdlcrx.bp = s->hdlcrx.buffer; - s->hdlcrx.rx_state = 1; - s->hdlcrx.numbits = i; - } else if ((s->hdlcrx.bitstream & mask4) == mask5) { - /* stuffed bit */ - s->hdlcrx.numbits--; - s->hdlcrx.bitbuf = (s->hdlcrx.bitbuf & (~mask6)) | - ((s->hdlcrx.bitbuf & mask6) << 1); - } - } - s->hdlcrx.numbits -= hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf, - s->hdlcrx.numbits); - } - clear_bit(0, &s->hdlcrx.in_hdlc_rx); -} - -/* ---------------------------------------------------------------------- */ - -static inline void do_kiss_params(struct hdlcdrv_state *s, - unsigned char *data, unsigned long len) -{ - -#ifdef KISS_VERBOSE -#define PKP(a,b) printk(KERN_INFO "hdlcdrv.c: channel params: " a "\n", b) -#else /* KISS_VERBOSE */ -#define PKP(a,b) -#endif /* KISS_VERBOSE */ - - if (len < 2) - return; - switch(data[0]) { - case PARAM_TXDELAY: - s->ch_params.tx_delay = data[1]; - PKP("TX delay = %ums", 10 * s->ch_params.tx_delay); - break; - case PARAM_PERSIST: - s->ch_params.ppersist = data[1]; - PKP("p persistence = %u", s->ch_params.ppersist); - break; - case PARAM_SLOTTIME: - s->ch_params.slottime = data[1]; - PKP("slot time = %ums", s->ch_params.slottime); - break; - case PARAM_TXTAIL: - s->ch_params.tx_tail = data[1]; - PKP("TX tail = %ums", s->ch_params.tx_tail); - break; - case PARAM_FULLDUP: - s->ch_params.fulldup = !!data[1]; - PKP("%s duplex", s->ch_params.fulldup ? "full" : "half"); - break; - default: - break; - } -#undef PKP -} - -/* ---------------------------------------------------------------------- */ - -void hdlcdrv_transmitter(struct net_device *dev, struct hdlcdrv_state *s) -{ - unsigned int mask1, mask2, mask3; - int i; - struct sk_buff *skb; - int pkt_len; - - if (!s || s->magic != HDLCDRV_MAGIC) - return; - if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx)) - return; - for (;;) { - if (s->hdlctx.numbits >= 16) { - if (hdlcdrv_hbuf_full(&s->hdlctx.hbuf)) { - clear_bit(0, &s->hdlctx.in_hdlc_tx); - return; - } - hdlcdrv_hbuf_put(&s->hdlctx.hbuf, s->hdlctx.bitbuf); - s->hdlctx.bitbuf >>= 16; - s->hdlctx.numbits -= 16; - } - switch (s->hdlctx.tx_state) { - default: - clear_bit(0, &s->hdlctx.in_hdlc_tx); - return; - case 0: - case 1: - if (s->hdlctx.numflags) { - s->hdlctx.numflags--; - s->hdlctx.bitbuf |= - 0x7e7e << s->hdlctx.numbits; - s->hdlctx.numbits += 16; - break; - } - if (s->hdlctx.tx_state == 1) { - clear_bit(0, &s->hdlctx.in_hdlc_tx); - return; - } - if (!(skb = s->skb)) { - int flgs = tenms_to_2flags(s, s->ch_params.tx_tail); - if (flgs < 2) - flgs = 2; - s->hdlctx.tx_state = 1; - s->hdlctx.numflags = flgs; - break; - } - s->skb = NULL; - netif_wake_queue(dev); - pkt_len = skb->len-1; /* strip KISS byte */ - if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { - s->hdlctx.tx_state = 0; - s->hdlctx.numflags = 1; - dev_kfree_skb_irq(skb); - break; - } - skb_copy_from_linear_data_offset(skb, 1, - s->hdlctx.buffer, - pkt_len); - dev_kfree_skb_irq(skb); - s->hdlctx.bp = s->hdlctx.buffer; - append_crc_ccitt(s->hdlctx.buffer, pkt_len); - s->hdlctx.len = pkt_len+2; /* the appended CRC */ - s->hdlctx.tx_state = 2; - s->hdlctx.bitstream = 0; - dev->stats.tx_packets++; - break; - case 2: - if (!s->hdlctx.len) { - s->hdlctx.tx_state = 0; - s->hdlctx.numflags = 1; - break; - } - s->hdlctx.len--; - s->hdlctx.bitbuf |= *s->hdlctx.bp << - s->hdlctx.numbits; - s->hdlctx.bitstream >>= 8; - s->hdlctx.bitstream |= (*s->hdlctx.bp++) << 16; - mask1 = 0x1f000; - mask2 = 0x10000; - mask3 = 0xffffffff >> (31-s->hdlctx.numbits); - s->hdlctx.numbits += 8; - for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1, - mask3 = (mask3 << 1) | 1) { - if ((s->hdlctx.bitstream & mask1) != mask1) - continue; - s->hdlctx.bitstream &= ~mask2; - s->hdlctx.bitbuf = - (s->hdlctx.bitbuf & mask3) | - ((s->hdlctx.bitbuf & - (~mask3)) << 1); - s->hdlctx.numbits++; - mask3 = (mask3 << 1) | 1; - } - break; - } - } -} - -/* ---------------------------------------------------------------------- */ - -static void start_tx(struct net_device *dev, struct hdlcdrv_state *s) -{ - s->hdlctx.tx_state = 0; - s->hdlctx.numflags = tenms_to_2flags(s, s->ch_params.tx_delay); - s->hdlctx.bitbuf = s->hdlctx.bitstream = s->hdlctx.numbits = 0; - hdlcdrv_transmitter(dev, s); - s->hdlctx.ptt = 1; - s->ptt_keyed++; -} - -/* ---------------------------------------------------------------------- */ - -void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s) -{ - if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || !s->skb) - return; - if (s->ch_params.fulldup) { - start_tx(dev, s); - return; - } - if (s->hdlcrx.dcd) { - s->hdlctx.slotcnt = s->ch_params.slottime; - return; - } - if ((--s->hdlctx.slotcnt) > 0) - return; - s->hdlctx.slotcnt = s->ch_params.slottime; - if (get_random_u8() > s->ch_params.ppersist) - return; - start_tx(dev, s); -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== network driver interface ========================= - */ - -static netdev_tx_t hdlcdrv_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct hdlcdrv_state *sm = netdev_priv(dev); - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - if (skb->data[0] != 0) { - do_kiss_params(sm, skb->data, skb->len); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - if (sm->skb) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - netif_stop_queue(dev); - sm->skb = skb; - return NETDEV_TX_OK; -} - -/* --------------------------------------------------------------------- */ - -static int hdlcdrv_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *)addr; - - /* addr is an AX.25 shifted ASCII mac address */ - dev_addr_set(dev, sa->sa_data); - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * Open/initialize the board. 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 hdlcdrv_open(struct net_device *dev) -{ - struct hdlcdrv_state *s = netdev_priv(dev); - int i; - - if (!s->ops || !s->ops->open) - return -ENODEV; - - /* - * initialise some variables - */ - s->opened = 1; - s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; - s->hdlcrx.in_hdlc_rx = 0; - s->hdlcrx.rx_state = 0; - - s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; - s->hdlctx.in_hdlc_tx = 0; - s->hdlctx.tx_state = 1; - s->hdlctx.numflags = 0; - s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; - s->hdlctx.ptt = 0; - s->hdlctx.slotcnt = s->ch_params.slottime; - s->hdlctx.calibrate = 0; - - i = s->ops->open(dev); - if (i) - return i; - netif_start_queue(dev); - return 0; -} - -/* --------------------------------------------------------------------- */ -/* - * The inverse routine to hdlcdrv_open(). - */ - -static int hdlcdrv_close(struct net_device *dev) -{ - struct hdlcdrv_state *s = netdev_priv(dev); - int i = 0; - - netif_stop_queue(dev); - - if (s->ops && s->ops->close) - i = s->ops->close(dev); - dev_kfree_skb(s->skb); - s->skb = NULL; - s->opened = 0; - return i; -} - -/* --------------------------------------------------------------------- */ - -static int hdlcdrv_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd) -{ - struct hdlcdrv_state *s = netdev_priv(dev); - struct hdlcdrv_ioctl bi; - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (in_compat_syscall()) /* to be implemented */ - return -ENOIOCTLCMD; - - if (copy_from_user(&bi, data, sizeof(bi))) - return -EFAULT; - - switch (bi.cmd) { - default: - if (s->ops && s->ops->ioctl) - return s->ops->ioctl(dev, data, &bi, cmd); - return -ENOIOCTLCMD; - - case HDLCDRVCTL_GETCHANNELPAR: - bi.data.cp.tx_delay = s->ch_params.tx_delay; - bi.data.cp.tx_tail = s->ch_params.tx_tail; - bi.data.cp.slottime = s->ch_params.slottime; - bi.data.cp.ppersist = s->ch_params.ppersist; - bi.data.cp.fulldup = s->ch_params.fulldup; - break; - - case HDLCDRVCTL_SETCHANNELPAR: - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - s->ch_params.tx_delay = bi.data.cp.tx_delay; - s->ch_params.tx_tail = bi.data.cp.tx_tail; - s->ch_params.slottime = bi.data.cp.slottime; - s->ch_params.ppersist = bi.data.cp.ppersist; - s->ch_params.fulldup = bi.data.cp.fulldup; - s->hdlctx.slotcnt = 1; - return 0; - - case HDLCDRVCTL_GETMODEMPAR: - bi.data.mp.iobase = dev->base_addr; - bi.data.mp.irq = dev->irq; - bi.data.mp.dma = dev->dma; - bi.data.mp.dma2 = s->ptt_out.dma2; - bi.data.mp.seriobase = s->ptt_out.seriobase; - bi.data.mp.pariobase = s->ptt_out.pariobase; - bi.data.mp.midiiobase = s->ptt_out.midiiobase; - break; - - case HDLCDRVCTL_SETMODEMPAR: - if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev)) - return -EACCES; - dev->base_addr = bi.data.mp.iobase; - dev->irq = bi.data.mp.irq; - dev->dma = bi.data.mp.dma; - s->ptt_out.dma2 = bi.data.mp.dma2; - s->ptt_out.seriobase = bi.data.mp.seriobase; - s->ptt_out.pariobase = bi.data.mp.pariobase; - s->ptt_out.midiiobase = bi.data.mp.midiiobase; - return 0; - - case HDLCDRVCTL_GETSTAT: - bi.data.cs.ptt = hdlcdrv_ptt(s); - bi.data.cs.dcd = s->hdlcrx.dcd; - bi.data.cs.ptt_keyed = s->ptt_keyed; - bi.data.cs.tx_packets = dev->stats.tx_packets; - bi.data.cs.tx_errors = dev->stats.tx_errors; - bi.data.cs.rx_packets = dev->stats.rx_packets; - bi.data.cs.rx_errors = dev->stats.rx_errors; - break; - - case HDLCDRVCTL_OLDGETSTAT: - bi.data.ocs.ptt = hdlcdrv_ptt(s); - bi.data.ocs.dcd = s->hdlcrx.dcd; - bi.data.ocs.ptt_keyed = s->ptt_keyed; - break; - - case HDLCDRVCTL_CALIBRATE: - if(!capable(CAP_SYS_RAWIO)) - return -EPERM; - if (s->par.bitrate <= 0) - return -EINVAL; - if (bi.data.calibrate > INT_MAX / s->par.bitrate) - return -EINVAL; - s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16; - return 0; - - case HDLCDRVCTL_GETSAMPLES: -#ifndef HDLCDRV_DEBUG - return -EPERM; -#else /* HDLCDRV_DEBUG */ - if (s->bitbuf_channel.rd == s->bitbuf_channel.wr) - return -EAGAIN; - bi.data.bits = - s->bitbuf_channel.buffer[s->bitbuf_channel.rd]; - s->bitbuf_channel.rd = (s->bitbuf_channel.rd+1) % - sizeof(s->bitbuf_channel.buffer); - break; -#endif /* HDLCDRV_DEBUG */ - - case HDLCDRVCTL_GETBITS: -#ifndef HDLCDRV_DEBUG - return -EPERM; -#else /* HDLCDRV_DEBUG */ - if (s->bitbuf_hdlc.rd == s->bitbuf_hdlc.wr) - return -EAGAIN; - bi.data.bits = - s->bitbuf_hdlc.buffer[s->bitbuf_hdlc.rd]; - s->bitbuf_hdlc.rd = (s->bitbuf_hdlc.rd+1) % - sizeof(s->bitbuf_hdlc.buffer); - break; -#endif /* HDLCDRV_DEBUG */ - - case HDLCDRVCTL_DRIVERNAME: - if (s->ops && s->ops->drvname) { - strscpy(bi.data.drivername, s->ops->drvname, - sizeof(bi.data.drivername)); - break; - } - bi.data.drivername[0] = '\0'; - break; - - } - if (copy_to_user(data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -static const struct net_device_ops hdlcdrv_netdev = { - .ndo_open = hdlcdrv_open, - .ndo_stop = hdlcdrv_close, - .ndo_start_xmit = hdlcdrv_send_packet, - .ndo_siocdevprivate = hdlcdrv_siocdevprivate, - .ndo_set_mac_address = hdlcdrv_set_mac_address, -}; - -/* - * Initialize fields in hdlcdrv - */ -static void hdlcdrv_setup(struct net_device *dev) -{ - static const struct hdlcdrv_channel_params dflt_ch_params = { - 20, 2, 10, 40, 0 - }; - struct hdlcdrv_state *s = netdev_priv(dev); - - /* - * initialize the hdlcdrv_state struct - */ - s->ch_params = dflt_ch_params; - s->ptt_keyed = 0; - - spin_lock_init(&s->hdlcrx.hbuf.lock); - s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; - s->hdlcrx.in_hdlc_rx = 0; - s->hdlcrx.rx_state = 0; - - spin_lock_init(&s->hdlctx.hbuf.lock); - s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; - s->hdlctx.in_hdlc_tx = 0; - s->hdlctx.tx_state = 1; - s->hdlctx.numflags = 0; - s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; - s->hdlctx.ptt = 0; - s->hdlctx.slotcnt = s->ch_params.slottime; - s->hdlctx.calibrate = 0; - -#ifdef HDLCDRV_DEBUG - s->bitbuf_channel.rd = s->bitbuf_channel.wr = 0; - s->bitbuf_channel.shreg = 0x80; - - s->bitbuf_hdlc.rd = s->bitbuf_hdlc.wr = 0; - s->bitbuf_hdlc.shreg = 0x80; -#endif /* HDLCDRV_DEBUG */ - - - /* Fill in the fields of the device structure */ - - s->skb = NULL; - - dev->netdev_ops = &hdlcdrv_netdev; - dev->header_ops = &ax25_header_ops; - - dev->type = ARPHRD_AX25; /* AF_AX25 device */ - dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; - dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ - dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&ax25_defaddr); - dev->tx_queue_len = 16; -} - -/* --------------------------------------------------------------------- */ -struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops, - unsigned int privsize, const char *ifname, - unsigned int baseaddr, unsigned int irq, - unsigned int dma) -{ - struct net_device *dev; - struct hdlcdrv_state *s; - int err; - - if (privsize < sizeof(struct hdlcdrv_state)) - privsize = sizeof(struct hdlcdrv_state); - - dev = alloc_netdev(privsize, ifname, NET_NAME_UNKNOWN, hdlcdrv_setup); - if (!dev) - return ERR_PTR(-ENOMEM); - - /* - * initialize part of the hdlcdrv_state struct - */ - s = netdev_priv(dev); - s->magic = HDLCDRV_MAGIC; - s->ops = ops; - dev->base_addr = baseaddr; - dev->irq = irq; - dev->dma = dma; - - err = register_netdev(dev); - if (err < 0) { - printk(KERN_WARNING "hdlcdrv: cannot register net " - "device %s\n", dev->name); - free_netdev(dev); - dev = ERR_PTR(err); - } - return dev; -} - -/* --------------------------------------------------------------------- */ - -void hdlcdrv_unregister(struct net_device *dev) -{ - struct hdlcdrv_state *s = netdev_priv(dev); - - BUG_ON(s->magic != HDLCDRV_MAGIC); - - if (s->opened && s->ops->close) - s->ops->close(dev); - unregister_netdev(dev); - - free_netdev(dev); -} - -/* --------------------------------------------------------------------- */ - -EXPORT_SYMBOL(hdlcdrv_receiver); -EXPORT_SYMBOL(hdlcdrv_transmitter); -EXPORT_SYMBOL(hdlcdrv_arbitrate); -EXPORT_SYMBOL(hdlcdrv_register); -EXPORT_SYMBOL(hdlcdrv_unregister); - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c deleted file mode 100644 index 5f38a002bd9e..000000000000 --- a/drivers/net/hamradio/mkiss.c +++ /dev/null @@ -1,980 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Copyright (C) Hans Alblas PE1AYX - * Copyright (C) 2004, 05 Ralf Baechle DL5RB - * Copyright (C) 2004, 05 Thomas Osterried DL9SAU - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define AX_MTU 236 - -/* some arch define END as assembly function ending, just undef it */ -#undef END -/* SLIP/KISS protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - -struct mkiss { - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ - - /* These are pointers to the malloc()ed frame buffers. */ - spinlock_t buflock;/* lock for rbuf and xbuf */ - unsigned char *rbuff; /* receiver buffer */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* pointer to next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ - - /* Detailed SLIP statistics. */ - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - - unsigned long flags; /* Flag values/ mode etc */ - /* long req'd: used by set_bit --RR */ -#define AXF_INUSE 0 /* Channel in use */ -#define AXF_ESCAPE 1 /* ESC received */ -#define AXF_ERROR 2 /* Parity, etc. error */ -#define AXF_KEEPTEST 3 /* Keepalive test flag */ -#define AXF_OUTWAIT 4 /* is outpacket was flag */ - - int mode; - int crcmode; /* MW: for FlexNet, SMACK etc. */ - int crcauto; /* CRC auto mode */ - -#define CRC_MODE_NONE 0 -#define CRC_MODE_FLEX 1 -#define CRC_MODE_SMACK 2 -#define CRC_MODE_FLEX_TEST 3 -#define CRC_MODE_SMACK_TEST 4 - - refcount_t refcnt; - struct completion dead; -}; - -/*---------------------------------------------------------------------------*/ - -static const unsigned short crc_flex_table[] = { - 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, - 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, - 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, - 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, - 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, - 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, - 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, - 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, - 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, - 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, - 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, - 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, - 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, - 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, - 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, - 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, - 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, - 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, - 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, - 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, - 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, - 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, - 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, - 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, - 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, - 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, - 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, - 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, - 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, - 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, - 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, - 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff -}; - -static unsigned short calc_crc_flex(unsigned char *cp, int size) -{ - unsigned short crc = 0xffff; - - while (size--) - crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; - - return crc; -} - -static int check_crc_flex(unsigned char *cp, int size) -{ - unsigned short crc = 0xffff; - - if (size < 3) - return -1; - - while (size--) - crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; - - if ((crc & 0xffff) != 0x7070) - return -1; - - return 0; -} - -static int check_crc_16(unsigned char *cp, int size) -{ - unsigned short crc = 0x0000; - - if (size < 3) - return -1; - - crc = crc16(0, cp, size); - - if (crc != 0x0000) - return -1; - - return 0; -} - -/* - * Standard encapsulation - */ - -static int kiss_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; - - /* - * Send an initial END character to flush out any data that may have - * accumulated in the receiver due to line noise. - */ - - *ptr++ = END; - - while (len-- > 0) { - switch (c = *s++) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } - - *ptr++ = END; - - return ptr - d; -} - -/* - * MW: - * OK its ugly, but tell me a better solution without copying the - * packet to a temporary buffer :-) - */ -static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, - int len) -{ - unsigned char *ptr = d; - unsigned char c=0; - - *ptr++ = END; - while (len > 0) { - if (len > 2) - c = *s++; - else if (len > 1) - c = crc >> 8; - else - c = crc & 0xff; - - len--; - - switch (c) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } - *ptr++ = END; - - return ptr - d; -} - -/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ -static void ax_bump(struct mkiss *ax) -{ - struct sk_buff *skb; - int count; - - spin_lock_bh(&ax->buflock); - if (ax->rbuff[0] > 0x0f) { - if (ax->rbuff[0] & 0x80) { - if (check_crc_16(ax->rbuff, ax->rcount) < 0) { - ax->dev->stats.rx_errors++; - spin_unlock_bh(&ax->buflock); - - return; - } - if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) { - printk(KERN_INFO - "mkiss: %s: Switching to crc-smack\n", - ax->dev->name); - ax->crcmode = CRC_MODE_SMACK; - } - ax->rcount -= 2; - *ax->rbuff &= ~0x80; - } else if (ax->rbuff[0] & 0x20) { - if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { - ax->dev->stats.rx_errors++; - spin_unlock_bh(&ax->buflock); - return; - } - if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { - printk(KERN_INFO - "mkiss: %s: Switching to crc-flexnet\n", - ax->dev->name); - ax->crcmode = CRC_MODE_FLEX; - } - ax->rcount -= 2; - - /* - * dl9sau bugfix: the trailling two bytes flexnet crc - * will not be passed to the kernel. thus we have to - * correct the kissparm signature, because it indicates - * a crc but there's none - */ - *ax->rbuff &= ~0x20; - } - } - - count = ax->rcount; - - if ((skb = dev_alloc_skb(count)) == NULL) { - printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", - ax->dev->name); - ax->dev->stats.rx_dropped++; - spin_unlock_bh(&ax->buflock); - return; - } - - skb_put_data(skb, ax->rbuff, count); - skb->protocol = ax25_type_trans(skb, ax->dev); - netif_rx(skb); - ax->dev->stats.rx_packets++; - ax->dev->stats.rx_bytes += count; - spin_unlock_bh(&ax->buflock); -} - -static void kiss_unesc(struct mkiss *ax, unsigned char s) -{ - switch (s) { - case END: - /* drop keeptest bit = VSV */ - if (test_bit(AXF_KEEPTEST, &ax->flags)) - clear_bit(AXF_KEEPTEST, &ax->flags); - - if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) - ax_bump(ax); - - clear_bit(AXF_ESCAPE, &ax->flags); - ax->rcount = 0; - return; - - case ESC: - set_bit(AXF_ESCAPE, &ax->flags); - return; - case ESC_ESC: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = ESC; - break; - case ESC_END: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = END; - break; - } - - spin_lock_bh(&ax->buflock); - if (!test_bit(AXF_ERROR, &ax->flags)) { - if (ax->rcount < ax->buffsize) { - ax->rbuff[ax->rcount++] = s; - spin_unlock_bh(&ax->buflock); - return; - } - - ax->dev->stats.rx_over_errors++; - set_bit(AXF_ERROR, &ax->flags); - } - spin_unlock_bh(&ax->buflock); -} - -static int ax_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr_ax25 *sa = addr; - - netif_tx_lock_bh(dev); - netif_addr_lock(dev); - __dev_addr_set(dev, &sa->sax25_call, AX25_ADDR_LEN); - netif_addr_unlock(dev); - netif_tx_unlock_bh(dev); - - return 0; -} - -/*---------------------------------------------------------------------------*/ - -static void ax_changedmtu(struct mkiss *ax) -{ - struct net_device *dev = ax->dev; - unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; - int len; - - len = dev->mtu * 2; - - /* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (len < 576 * 2) - len = 576 * 2; - - xbuff = kmalloc(len + 4, GFP_ATOMIC); - rbuff = kmalloc(len + 4, GFP_ATOMIC); - - if (xbuff == NULL || rbuff == NULL) { - printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, " - "MTU change cancelled.\n", - ax->dev->name); - dev->mtu = ax->mtu; - kfree(xbuff); - kfree(rbuff); - return; - } - - spin_lock_bh(&ax->buflock); - - oxbuff = ax->xbuff; - ax->xbuff = xbuff; - orbuff = ax->rbuff; - ax->rbuff = rbuff; - - if (ax->xleft) { - if (ax->xleft <= len) { - memcpy(ax->xbuff, ax->xhead, ax->xleft); - } else { - ax->xleft = 0; - dev->stats.tx_dropped++; - } - } - - ax->xhead = ax->xbuff; - - if (ax->rcount) { - if (ax->rcount <= len) { - memcpy(ax->rbuff, orbuff, ax->rcount); - } else { - ax->rcount = 0; - dev->stats.rx_over_errors++; - set_bit(AXF_ERROR, &ax->flags); - } - } - - ax->mtu = dev->mtu + 73; - ax->buffsize = len; - - spin_unlock_bh(&ax->buflock); - - kfree(oxbuff); - kfree(orbuff); -} - -/* Encapsulate one AX.25 packet and stuff into a TTY queue. */ -static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) -{ - struct mkiss *ax = netdev_priv(dev); - unsigned char *p; - int actual, count; - - if (ax->mtu != ax->dev->mtu + 73) /* Someone has been ifconfigging */ - ax_changedmtu(ax); - - if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ - printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name); - dev->stats.tx_dropped++; - netif_start_queue(dev); - return; - } - - p = icp; - - spin_lock_bh(&ax->buflock); - if ((*p & 0x0f) != 0) { - /* Configuration Command (kissparms(1). - * Protocol spec says: never append CRC. - * This fixes a very old bug in the linux - * kiss driver. -- dl9sau */ - switch (*p & 0xff) { - case 0x85: - /* command from userspace especially for us, - * not for delivery to the tnc */ - if (len > 1) { - int cmd = (p[1] & 0xff); - switch(cmd) { - case 3: - ax->crcmode = CRC_MODE_SMACK; - break; - case 2: - ax->crcmode = CRC_MODE_FLEX; - break; - case 1: - ax->crcmode = CRC_MODE_NONE; - break; - case 0: - default: - ax->crcmode = CRC_MODE_SMACK_TEST; - cmd = 0; - } - ax->crcauto = (cmd ? 0 : 1); - printk(KERN_INFO "mkiss: %s: crc mode set to %d\n", - ax->dev->name, cmd); - } - spin_unlock_bh(&ax->buflock); - netif_start_queue(dev); - - return; - default: - count = kiss_esc(p, ax->xbuff, len); - } - } else { - unsigned short crc; - switch (ax->crcmode) { - case CRC_MODE_SMACK_TEST: - ax->crcmode = CRC_MODE_FLEX_TEST; - printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name); - fallthrough; - case CRC_MODE_SMACK: - *p |= 0x80; - crc = swab16(crc16(0, p, len)); - count = kiss_esc_crc(p, ax->xbuff, crc, len+2); - break; - case CRC_MODE_FLEX_TEST: - ax->crcmode = CRC_MODE_NONE; - printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name); - fallthrough; - case CRC_MODE_FLEX: - *p |= 0x20; - crc = calc_crc_flex(p, len); - count = kiss_esc_crc(p, ax->xbuff, crc, len+2); - break; - - default: - count = kiss_esc(p, ax->xbuff, len); - } - } - spin_unlock_bh(&ax->buflock); - - set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); - actual = ax->tty->ops->write(ax->tty, ax->xbuff, count); - dev->stats.tx_packets++; - dev->stats.tx_bytes += actual; - - netif_trans_update(ax->dev); - ax->xleft = count - actual; - ax->xhead = ax->xbuff + actual; -} - -/* Encapsulate an AX.25 packet and kick it into a TTY queue. */ -static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct mkiss *ax = netdev_priv(dev); - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - if (!netif_running(dev)) { - printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - /* - * May be we must check transmitter timeout here ? - * 14 Oct 1994 Dmitry Gorodchanin. - */ - if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ)) { - /* 20 sec timeout not reached */ - return NETDEV_TX_BUSY; - } - - printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, - (tty_chars_in_buffer(ax->tty) || ax->xleft) ? - "bad line quality" : "driver error"); - - ax->xleft = 0; - clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); - netif_start_queue(dev); - } - - /* We were not busy, so we are now... :-) */ - netif_stop_queue(dev); - ax_encaps(dev, skb->data, skb->len); - kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static int ax_open_dev(struct net_device *dev) -{ - struct mkiss *ax = netdev_priv(dev); - - if (ax->tty == NULL) - return -ENODEV; - - return 0; -} - -/* Open the low-level part of the AX25 channel. Easy! */ -static int ax_open(struct net_device *dev) -{ - struct mkiss *ax = netdev_priv(dev); - unsigned long len; - - if (ax->tty == NULL) - return -ENODEV; - - /* - * Allocate the frame buffers: - * - * rbuff Receive buffer. - * xbuff Transmit buffer. - */ - len = dev->mtu * 2; - - /* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (len < 576 * 2) - len = 576 * 2; - - if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) - goto norbuff; - - if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) - goto noxbuff; - - ax->mtu = dev->mtu + 73; - ax->buffsize = len; - ax->rcount = 0; - ax->xleft = 0; - - ax->flags &= (1 << AXF_INUSE); /* Clear ESCAPE & ERROR flags */ - - spin_lock_init(&ax->buflock); - - return 0; - -noxbuff: - kfree(ax->rbuff); - -norbuff: - return -ENOMEM; -} - - -/* Close the low-level part of the AX25 channel. Easy! */ -static int ax_close(struct net_device *dev) -{ - struct mkiss *ax = netdev_priv(dev); - - if (ax->tty) - clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); - - netif_stop_queue(dev); - - return 0; -} - -static const struct net_device_ops ax_netdev_ops = { - .ndo_open = ax_open_dev, - .ndo_stop = ax_close, - .ndo_start_xmit = ax_xmit, - .ndo_set_mac_address = ax_set_mac_address, -}; - -static void ax_setup(struct net_device *dev) -{ - /* Finish setting up the DEVICE info. */ - dev->mtu = AX_MTU; - dev->hard_header_len = AX25_MAX_HEADER_LEN; - dev->addr_len = AX25_ADDR_LEN; - dev->type = ARPHRD_AX25; - dev->tx_queue_len = 10; - dev->header_ops = &ax25_header_ops; - dev->netdev_ops = &ax_netdev_ops; - - - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&ax25_defaddr); - - dev->flags = IFF_BROADCAST | IFF_MULTICAST; -} - -/* - * We have a potential race on dereferencing tty->disc_data, because the tty - * layer provides no locking at all - thus one cpu could be running - * sixpack_receive_buf while another calls sixpack_close, which zeroes - * tty->disc_data and frees the memory that sixpack_receive_buf is using. The - * best way to fix this is to use a rwlock in the tty struct, but for now we - * use a single global rwlock for all ttys in ppp line discipline. - */ -static DEFINE_RWLOCK(disc_data_lock); - -static struct mkiss *mkiss_get(struct tty_struct *tty) -{ - struct mkiss *ax; - - read_lock(&disc_data_lock); - ax = tty->disc_data; - if (ax) - refcount_inc(&ax->refcnt); - read_unlock(&disc_data_lock); - - return ax; -} - -static void mkiss_put(struct mkiss *ax) -{ - if (refcount_dec_and_test(&ax->refcnt)) - complete(&ax->dead); -} - -static int crc_force = 0; /* Can be overridden with insmod */ - -static int mkiss_open(struct tty_struct *tty) -{ - struct net_device *dev; - struct mkiss *ax; - int err; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (tty->ops->write == NULL) - return -EOPNOTSUPP; - - dev = alloc_netdev(sizeof(struct mkiss), "ax%d", NET_NAME_UNKNOWN, - ax_setup); - if (!dev) { - err = -ENOMEM; - goto out; - } - - ax = netdev_priv(dev); - ax->dev = dev; - - spin_lock_init(&ax->buflock); - refcount_set(&ax->refcnt, 1); - init_completion(&ax->dead); - - ax->tty = tty; - tty->disc_data = ax; - tty->receive_room = 65535; - - tty_driver_flush_buffer(tty); - - /* Restore default settings */ - dev->type = ARPHRD_AX25; - - /* Perform the low-level AX25 initialization. */ - err = ax_open(ax->dev); - if (err) - goto out_free_netdev; - - err = register_netdev(dev); - if (err) - goto out_free_buffers; - - /* after register_netdev() - because else printk smashes the kernel */ - switch (crc_force) { - case 3: - ax->crcmode = CRC_MODE_SMACK; - printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n", - ax->dev->name); - break; - case 2: - ax->crcmode = CRC_MODE_FLEX; - printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n", - ax->dev->name); - break; - case 1: - ax->crcmode = CRC_MODE_NONE; - printk(KERN_INFO "mkiss: %s: crc mode disabled.\n", - ax->dev->name); - break; - case 0: - default: - crc_force = 0; - printk(KERN_INFO "mkiss: %s: crc mode is auto.\n", - ax->dev->name); - ax->crcmode = CRC_MODE_SMACK_TEST; - } - ax->crcauto = (crc_force ? 0 : 1); - - netif_start_queue(dev); - - /* Done. We have linked the TTY line to a channel. */ - return 0; - -out_free_buffers: - kfree(ax->rbuff); - kfree(ax->xbuff); - -out_free_netdev: - free_netdev(dev); - -out: - return err; -} - -static void mkiss_close(struct tty_struct *tty) -{ - struct mkiss *ax; - - write_lock_irq(&disc_data_lock); - ax = tty->disc_data; - tty->disc_data = NULL; - write_unlock_irq(&disc_data_lock); - - if (!ax) - return; - - /* - * We have now ensured that nobody can start using ap from now on, but - * we have to wait for all existing users to finish. - */ - if (!refcount_dec_and_test(&ax->refcnt)) - wait_for_completion(&ax->dead); - /* - * Halt the transmit queue so that a new transmit cannot scribble - * on our buffers - */ - netif_stop_queue(ax->dev); - - unregister_netdev(ax->dev); - - /* Free all AX25 frame buffers after unreg. */ - kfree(ax->rbuff); - kfree(ax->xbuff); - - ax->tty = NULL; - - free_netdev(ax->dev); -} - -/* Perform I/O control on an active ax25 channel. */ -static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct mkiss *ax = mkiss_get(tty); - struct net_device *dev; - unsigned int tmp, err; - - /* First make sure we're connected. */ - if (ax == NULL) - return -ENXIO; - dev = ax->dev; - - switch (cmd) { - case SIOCGIFNAME: - err = copy_to_user((void __user *) arg, ax->dev->name, - strlen(ax->dev->name) + 1) ? -EFAULT : 0; - break; - - case SIOCGIFENCAP: - err = put_user(4, (int __user *) arg); - break; - - case SIOCSIFENCAP: - if (get_user(tmp, (int __user *) arg)) { - err = -EFAULT; - break; - } - - ax->mode = tmp; - dev->addr_len = AX25_ADDR_LEN; - dev->hard_header_len = AX25_KISS_HEADER_LEN + - AX25_MAX_HEADER_LEN + 3; - dev->type = ARPHRD_AX25; - - err = 0; - break; - - case SIOCSIFHWADDR: { - char addr[AX25_ADDR_LEN]; - - if (copy_from_user(&addr, - (void __user *) arg, AX25_ADDR_LEN)) { - err = -EFAULT; - break; - } - - netif_tx_lock_bh(dev); - __dev_addr_set(dev, addr, AX25_ADDR_LEN); - netif_tx_unlock_bh(dev); - - err = 0; - break; - } - default: - err = -ENOIOCTLCMD; - } - - mkiss_put(ax); - - return err; -} - -/* - * Handle the 'receiver data ready' interrupt. - * This function is called by the 'tty_io' module in the kernel when - * a block of data has been received, which can now be decapsulated - * and sent on to the AX.25 layer for further processing. - */ -static void mkiss_receive_buf(struct tty_struct *tty, const u8 *cp, - const u8 *fp, size_t count) -{ - struct mkiss *ax = mkiss_get(tty); - - if (!ax) - return; - - /* - * Argh! mtu change time! - costs us the packet part received - * at the change - */ - if (ax->mtu != ax->dev->mtu + 73) - ax_changedmtu(ax); - - /* Read the characters out of the buffer */ - while (count--) { - if (fp != NULL && *fp++) { - if (!test_and_set_bit(AXF_ERROR, &ax->flags)) - ax->dev->stats.rx_errors++; - cp++; - continue; - } - - kiss_unesc(ax, *cp++); - } - - mkiss_put(ax); - tty_unthrottle(tty); -} - -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void mkiss_write_wakeup(struct tty_struct *tty) -{ - struct mkiss *ax = mkiss_get(tty); - int actual; - - if (!ax) - return; - - if (ax->xleft <= 0) { - /* Now serial buffer is almost free & we can start - * transmission of another packet - */ - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - - netif_wake_queue(ax->dev); - goto out; - } - - actual = tty->ops->write(tty, ax->xhead, ax->xleft); - ax->xleft -= actual; - ax->xhead += actual; - -out: - mkiss_put(ax); -} - -static struct tty_ldisc_ops ax_ldisc = { - .owner = THIS_MODULE, - .num = N_AX25, - .name = "mkiss", - .open = mkiss_open, - .close = mkiss_close, - .ioctl = mkiss_ioctl, - .receive_buf = mkiss_receive_buf, - .write_wakeup = mkiss_write_wakeup -}; - -static const char banner[] __initconst = KERN_INFO \ - "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n"; -static const char msg_regfail[] __initconst = KERN_ERR \ - "mkiss: can't register line discipline (err = %d)\n"; - -static int __init mkiss_init_driver(void) -{ - int status; - - printk(banner); - - status = tty_register_ldisc(&ax_ldisc); - if (status != 0) - printk(msg_regfail, status); - - return status; -} - -static void __exit mkiss_exit_driver(void) -{ - tty_unregister_ldisc(&ax_ldisc); -} - -MODULE_AUTHOR("Ralf Baechle DL5RB "); -MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); -module_param(crc_force, int, 0); -MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_AX25); - -module_init(mkiss_init_driver); -module_exit(mkiss_exit_driver); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c deleted file mode 100644 index 8569db4a7140..000000000000 --- a/drivers/net/hamradio/scc.c +++ /dev/null @@ -1,2179 +0,0 @@ -#define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $" - -#define VERSION "3.0" - -/* - * Please use z8530drv-utils-3.0 with this version. - * ------------------ - * - * You can find a subset of the documentation in - * Documentation/networking/device_drivers/hamradio/z8530drv.rst. - */ - -/* - ******************************************************************** - * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 * - ******************************************************************** - - - ******************************************************************** - - Copyright (c) 1993, 2000 Joerg Reuter DL1BKE - - portions (c) 1993 Guido ten Dolle PE1NNZ - - ******************************************************************** - - The driver and the programs in the archive are UNDER CONSTRUCTION. - The code is likely to fail, and so your kernel could --- even - a whole network. - - This driver is intended for Amateur Radio use. If you are running it - for commercial purposes, please drop me a note. I am nosy... - - ...BUT: - - ! You m u s t recognize the appropriate legislations of your country ! - ! before you connect a radio to the SCC board and start to transmit or ! - ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! ! - - For non-Amateur-Radio use please note that you might need a special - allowance/licence from the designer of the SCC Board and/or the - MODEM. - - This program is free software; you can redistribute it and/or modify - it under the terms of the (modified) GNU General Public License - delivered with the Linux kernel source. - - 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 find a copy of the GNU General Public License in - /usr/src/linux/COPYING; - - ******************************************************************** - - - Incomplete history of z8530drv: - ------------------------------- - - 1994-09-13 started to write the driver, rescued most of my own - code (and Hans Alblas' memory buffer pool concept) from - an earlier project "sccdrv" which was initiated by - Guido ten Dolle. Not much of the old driver survived, - though. The first version I put my hands on was sccdrv1.3 - from August 1993. The memory buffer pool concept - appeared in an unauthorized sccdrv version (1.5) from - August 1994. - - 1995-01-31 changed copyright notice to GPL without limitations. - - . - . - . - - 1996-10-05 New semester, new driver... - - * KISS TNC emulator removed (TTY driver) - * Source moved to drivers/net/ - * Includes Z8530 defines from drivers/net/z8530.h - * Uses sk_buffer memory management - * Reduced overhead of /proc/net/z8530drv output - * Streamlined quite a lot things - * Invents brand new bugs... ;-) - - The move to version number 3.0 reflects theses changes. - You can use 'kissbridge' if you need a KISS TNC emulator. - - 1996-12-13 Fixed for Linux networking changes. (G4KLX) - 1997-01-08 Fixed the remaining problems. - 1997-04-02 Hopefully fixed the problems with the new *_timer() - routines, added calibration code. - 1997-10-12 Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO - 1998-01-29 Small fix to avoid lock-up on initialization - 1998-09-29 Fixed the "grouping" bugs, tx_inhibit works again, - using dev->tx_queue_len now instead of MAXQUEUE now. - 1998-10-21 Postponed the spinlock changes, would need a lot of - testing I currently don't have the time to. Softdcd doesn't - work. - 1998-11-04 Softdcd does not work correctly in DPLL mode, in fact it - never did. The DPLL locks on noise, the SYNC unit sees - flags that aren't... Restarting the DPLL does not help - either, it resynchronizes too slow and the first received - frame gets lost. - 2000-02-13 Fixed for new network driver interface changes, still - does TX timeouts itself since it uses its own queue - scheme. - - Thanks to all who contributed to this driver with ideas and bug - reports! - - NB -- if you find errors, change something, please let me know - first before you distribute it... And please don't touch - the version number. Just replace my callsign in - "v3.0.dl1bke" with your own. Just to avoid confusion... - - If you want to add your modification to the linux distribution - please (!) contact me first. - - New versions of the driver will be announced on the linux-hams - mailing list on vger.kernel.org. To subscribe send an e-mail - to majordomo@vger.kernel.org with the following line in - the body of the mail: - - subscribe linux-hams - - The content of the "Subject" field will be ignored. - - vy 73, - Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org - AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU - Internet: jreuter@yaina.de - www : http://yaina.de/jreuter -*/ - -/* ----------------------------------------------------------------------- */ - -#undef SCC_LDELAY /* slow it even a bit more down */ -#undef SCC_DONT_CHECK /* don't look if the SCCs you specified are available */ - -#define SCC_MAXCHIPS 4 /* number of max. supported chips */ -#define SCC_BUFSIZE 384 /* must not exceed 4096 */ -#undef SCC_DEBUG - -#define SCC_DEFAULT_CLOCK 4915200 - /* default pclock if nothing is specified */ - -/* ----------------------------------------------------------------------- */ - -#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 -#include - -#include -#include -#include - -#include "z8530.h" - -static const char banner[] __initconst = KERN_INFO \ - "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n"; - -static void t_dwait(struct timer_list *t); -static void t_txdelay(struct timer_list *t); -static void t_tail(struct timer_list *t); -static void t_busy(struct timer_list *); -static void t_maxkeyup(struct timer_list *); -static void t_idle(struct timer_list *t); -static void scc_tx_done(struct scc_channel *); -static void scc_start_tx_timer(struct scc_channel *, - void (*)(struct timer_list *), unsigned long); -static void scc_start_maxkeyup(struct scc_channel *); -static void scc_start_defer(struct scc_channel *); - -static void z8530_init(void); - -static void init_channel(struct scc_channel *scc); -static void scc_key_trx (struct scc_channel *scc, char tx); -static void scc_init_timer(struct scc_channel *scc); - -static int scc_net_alloc(const char *name, struct scc_channel *scc); -static void scc_net_setup(struct net_device *dev); -static int scc_net_open(struct net_device *dev); -static int scc_net_close(struct net_device *dev); -static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb); -static netdev_tx_t scc_net_tx(struct sk_buff *skb, - struct net_device *dev); -static int scc_net_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd); -static int scc_net_set_mac_address(struct net_device *dev, void *addr); -static struct net_device_stats * scc_net_get_stats(struct net_device *dev); - -static unsigned char SCC_DriverName[] = "scc"; - -static struct irqflags { unsigned char used : 1; } Ivec[NR_IRQS]; - -static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS]; /* information per channel */ - -static struct scc_ctrl { - io_port chan_A; - io_port chan_B; - int irq; -} SCC_ctrl[SCC_MAXCHIPS+1]; - -static unsigned char Driver_Initialized; -static int Nchips; -static io_port Vector_Latch; - - -/* ******************************************************************** */ -/* * Port Access Functions * */ -/* ******************************************************************** */ - -/* These provide interrupt save 2-step access to the Z8530 registers */ - -static DEFINE_SPINLOCK(iolock); /* Guards paired accesses */ - -static inline unsigned char InReg(io_port port, unsigned char reg) -{ - unsigned long flags; - unsigned char r; - - spin_lock_irqsave(&iolock, flags); -#ifdef SCC_LDELAY - Outb(port, reg); - udelay(SCC_LDELAY); - r=Inb(port); - udelay(SCC_LDELAY); -#else - Outb(port, reg); - r=Inb(port); -#endif - spin_unlock_irqrestore(&iolock, flags); - return r; -} - -static inline void OutReg(io_port port, unsigned char reg, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&iolock, flags); -#ifdef SCC_LDELAY - Outb(port, reg); udelay(SCC_LDELAY); - Outb(port, val); udelay(SCC_LDELAY); -#else - Outb(port, reg); - Outb(port, val); -#endif - spin_unlock_irqrestore(&iolock, flags); -} - -static inline void wr(struct scc_channel *scc, unsigned char reg, - unsigned char val) -{ - OutReg(scc->ctrl, reg, (scc->wreg[reg] = val)); -} - -static inline void or(struct scc_channel *scc, unsigned char reg, unsigned char val) -{ - OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val)); -} - -static inline void cl(struct scc_channel *scc, unsigned char reg, unsigned char val) -{ - OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val)); -} - -/* ******************************************************************** */ -/* * Some useful macros * */ -/* ******************************************************************** */ - -static inline void scc_discard_buffers(struct scc_channel *scc) -{ - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - if (scc->tx_buff != NULL) - { - dev_kfree_skb_irq(scc->tx_buff); - scc->tx_buff = NULL; - } - - while (!skb_queue_empty(&scc->tx_queue)) - dev_kfree_skb_irq(skb_dequeue(&scc->tx_queue)); - - spin_unlock_irqrestore(&scc->lock, flags); -} - - - -/* ******************************************************************** */ -/* * Interrupt Service Routines * */ -/* ******************************************************************** */ - - -/* ----> subroutines for the interrupt handlers <---- */ - -static inline void scc_notify(struct scc_channel *scc, int event) -{ - struct sk_buff *skb; - char *bp; - - if (scc->kiss.fulldup != KISS_DUPLEX_OPTIMA) - return; - - skb = dev_alloc_skb(2); - if (skb != NULL) - { - bp = skb_put(skb, 2); - *bp++ = PARAM_HWEVENT; - *bp++ = event; - scc_net_rx(scc, skb); - } else - scc->stat.nospace++; -} - -static inline void flush_rx_FIFO(struct scc_channel *scc) -{ - int k; - - for (k=0; k<3; k++) - Inb(scc->data); - - if(scc->rx_buff != NULL) /* did we receive something? */ - { - scc->stat.rxerrs++; /* then count it as an error */ - dev_kfree_skb_irq(scc->rx_buff); - scc->rx_buff = NULL; - } -} - -static void start_hunt(struct scc_channel *scc) -{ - if ((scc->modem.clocksrc != CLK_EXTERNAL)) - OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */ - or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */ -} - -/* ----> four different interrupt handlers for Tx, Rx, changing of */ -/* DCD/CTS and Rx/Tx errors */ - -/* Transmitter interrupt handler */ -static inline void scc_txint(struct scc_channel *scc) -{ - struct sk_buff *skb; - - scc->stat.txints++; - skb = scc->tx_buff; - - /* send first octet */ - - if (skb == NULL) - { - skb = skb_dequeue(&scc->tx_queue); - scc->tx_buff = skb; - netif_wake_queue(scc->dev); - - if (skb == NULL) - { - scc_tx_done(scc); - Outb(scc->ctrl, RES_Tx_P); - return; - } - - if (skb->len == 0) /* Paranoia... */ - { - dev_kfree_skb_irq(skb); - scc->tx_buff = NULL; - scc_tx_done(scc); - Outb(scc->ctrl, RES_Tx_P); - return; - } - - scc->stat.tx_state = TXS_ACTIVE; - - OutReg(scc->ctrl, R0, RES_Tx_CRC); - /* reset CRC generator */ - or(scc,R10,ABUNDER); /* re-install underrun protection */ - Outb(scc->data,*skb->data); /* send byte */ - skb_pull(skb, 1); - - if (!scc->enhanced) /* reset EOM latch */ - Outb(scc->ctrl,RES_EOM_L); - return; - } - - /* End Of Frame... */ - - if (skb->len == 0) - { - Outb(scc->ctrl, RES_Tx_P); /* reset pending int */ - cl(scc, R10, ABUNDER); /* send CRC */ - dev_kfree_skb_irq(skb); - scc->tx_buff = NULL; - scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */ - return; - } - - /* send octet */ - - Outb(scc->data,*skb->data); - skb_pull(skb, 1); -} - - -/* External/Status interrupt handler */ -static inline void scc_exint(struct scc_channel *scc) -{ - unsigned char status,changes,chg_and_stat; - - scc->stat.exints++; - - status = InReg(scc->ctrl,R0); - changes = status ^ scc->status; - chg_and_stat = changes & status; - - /* ABORT: generated whenever DCD drops while receiving */ - - if (chg_and_stat & BRK_ABRT) /* Received an ABORT */ - flush_rx_FIFO(scc); - - /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */ - - if ((changes & SYNC_HUNT) && scc->kiss.softdcd) - { - if (status & SYNC_HUNT) - { - scc->dcd = 0; - flush_rx_FIFO(scc); - if ((scc->modem.clocksrc != CLK_EXTERNAL)) - OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */ - } else { - scc->dcd = 1; - } - - scc_notify(scc, scc->dcd? HWEV_DCD_OFF:HWEV_DCD_ON); - } - - /* DCD: on = start to receive packet, off = ABORT condition */ - /* (a successfully received packet generates a special condition int) */ - - if((changes & DCD) && !scc->kiss.softdcd) /* DCD input changed state */ - { - if(status & DCD) /* DCD is now ON */ - { - start_hunt(scc); - scc->dcd = 1; - } else { /* DCD is now OFF */ - cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */ - flush_rx_FIFO(scc); - scc->dcd = 0; - } - - scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF); - } - -#ifdef notdef - /* CTS: use external TxDelay (what's that good for?!) - * Anyway: If we _could_ use it (BayCom USCC uses CTS for - * own purposes) we _should_ use the "autoenable" feature - * of the Z8530 and not this interrupt... - */ - - if (chg_and_stat & CTS) /* CTS is now ON */ - { - if (scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */ - scc_start_tx_timer(scc, t_txdelay, 0); - } -#endif - - if (scc->stat.tx_state == TXS_ACTIVE && (status & TxEOM)) - { - scc->stat.tx_under++; /* oops, an underrun! count 'em */ - Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */ - - if (scc->tx_buff != NULL) - { - dev_kfree_skb_irq(scc->tx_buff); - scc->tx_buff = NULL; - } - - or(scc,R10,ABUNDER); - scc_start_tx_timer(scc, t_txdelay, 0); /* restart transmission */ - } - - scc->status = status; - Outb(scc->ctrl,RES_EXT_INT); -} - - -/* Receiver interrupt handler */ -static inline void scc_rxint(struct scc_channel *scc) -{ - struct sk_buff *skb; - - scc->stat.rxints++; - - if((scc->wreg[5] & RTS) && scc->kiss.fulldup == KISS_DUPLEX_HALF) - { - Inb(scc->data); /* discard char */ - or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ - return; - } - - skb = scc->rx_buff; - - if (skb == NULL) - { - skb = dev_alloc_skb(scc->stat.bufsize); - if (skb == NULL) - { - scc->dev_stat.rx_dropped++; - scc->stat.nospace++; - Inb(scc->data); - or(scc, R3, ENT_HM); - return; - } - - scc->rx_buff = skb; - skb_put_u8(skb, 0); /* KISS data */ - } - - if (skb->len >= scc->stat.bufsize) - { -#ifdef notdef - printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n"); -#endif - dev_kfree_skb_irq(skb); - scc->rx_buff = NULL; - Inb(scc->data); - or(scc, R3, ENT_HM); - return; - } - - skb_put_u8(skb, Inb(scc->data)); -} - - -/* Receive Special Condition interrupt handler */ -static inline void scc_spint(struct scc_channel *scc) -{ - unsigned char status; - struct sk_buff *skb; - - scc->stat.spints++; - - status = InReg(scc->ctrl,R1); /* read receiver status */ - - Inb(scc->data); /* throw away Rx byte */ - skb = scc->rx_buff; - - if(status & Rx_OVR) /* receiver overrun */ - { - scc->stat.rx_over++; /* count them */ - or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ - - if (skb != NULL) - dev_kfree_skb_irq(skb); - scc->rx_buff = skb = NULL; - } - - if(status & END_FR && skb != NULL) /* end of frame */ - { - /* CRC okay, frame ends on 8 bit boundary and received something ? */ - - if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0) - { - /* ignore last received byte (first of the CRC bytes) */ - skb_trim(skb, skb->len-1); - scc_net_rx(scc, skb); - scc->rx_buff = NULL; - scc->stat.rxframes++; - } else { /* a bad frame */ - dev_kfree_skb_irq(skb); - scc->rx_buff = NULL; - scc->stat.rxerrs++; - } - } - - Outb(scc->ctrl,ERR_RES); -} - - -/* ----> interrupt service routine for the Z8530 <---- */ - -static void scc_isr_dispatch(struct scc_channel *scc, int vector) -{ - spin_lock(&scc->lock); - switch (vector & VECTOR_MASK) - { - case TXINT: scc_txint(scc); break; - case EXINT: scc_exint(scc); break; - case RXINT: scc_rxint(scc); break; - case SPINT: scc_spint(scc); break; - } - spin_unlock(&scc->lock); -} - -/* If the card has a latch for the interrupt vector (like the PA0HZP card) - use it to get the number of the chip that generated the int. - If not: poll all defined chips. - */ - -#define SCC_IRQTIMEOUT 30000 - -static irqreturn_t scc_isr(int irq, void *dev_id) -{ - int chip_irq = (long) dev_id; - unsigned char vector; - struct scc_channel *scc; - struct scc_ctrl *ctrl; - int k; - - if (Vector_Latch) - { - for(k=0; k < SCC_IRQTIMEOUT; k++) - { - Outb(Vector_Latch, 0); /* Generate INTACK */ - - /* Read the vector */ - if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break; - if (vector & 0x01) break; - - scc=&SCC_Info[vector >> 3 ^ 0x01]; - if (!scc->dev) break; - - scc_isr_dispatch(scc, vector); - - OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */ - } - - if (k == SCC_IRQTIMEOUT) - printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n"); - - return IRQ_HANDLED; - } - - /* Find the SCC generating the interrupt by polling all attached SCCs - * reading RR3A (the interrupt pending register) - */ - - ctrl = SCC_ctrl; - while (ctrl->chan_A) - { - if (ctrl->irq != chip_irq) - { - ctrl++; - continue; - } - - scc = NULL; - for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++) - { - vector=InReg(ctrl->chan_B,R2); /* Read the vector */ - if (vector & 0x01) break; - - scc = &SCC_Info[vector >> 3 ^ 0x01]; - if (!scc->dev) break; - - scc_isr_dispatch(scc, vector); - } - - if (k == SCC_IRQTIMEOUT) - { - printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n"); - break; - } - - /* This looks weird and it is. At least the BayCom USCC doesn't - * use the Interrupt Daisy Chain, thus we'll have to start - * all over again to be sure not to miss an interrupt from - * (any of) the other chip(s)... - * Honestly, the situation *is* braindamaged... - */ - - if (scc != NULL) - { - OutReg(scc->ctrl,R0,RES_H_IUS); - ctrl = SCC_ctrl; - } else - ctrl++; - } - return IRQ_HANDLED; -} - - - -/* ******************************************************************** */ -/* * Init Channel */ -/* ******************************************************************** */ - - -/* ----> set SCC channel speed <---- */ - -static inline void set_brg(struct scc_channel *scc, unsigned int tc) -{ - cl(scc,R14,BRENABL); /* disable baudrate generator */ - wr(scc,R12,tc & 255); /* brg rate LOW */ - wr(scc,R13,tc >> 8); /* brg rate HIGH */ - or(scc,R14,BRENABL); /* enable baudrate generator */ -} - -static inline void set_speed(struct scc_channel *scc) -{ - unsigned long flags; - spin_lock_irqsave(&scc->lock, flags); - - if (scc->modem.speed > 0) /* paranoia... */ - set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2); - - spin_unlock_irqrestore(&scc->lock, flags); -} - - -/* ----> initialize a SCC channel <---- */ - -static inline void init_brg(struct scc_channel *scc) -{ - wr(scc, R14, BRSRC); /* BRG source = PCLK */ - OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */ - OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */ -} - -/* - * Initialization according to the Z8530 manual (SGS-Thomson's version): - * - * 1. Modes and constants - * - * WR9 11000000 chip reset - * WR4 XXXXXXXX Tx/Rx control, async or sync mode - * WR1 0XX00X00 select W/REQ (optional) - * WR2 XXXXXXXX program interrupt vector - * WR3 XXXXXXX0 select Rx control - * WR5 XXXX0XXX select Tx control - * WR6 XXXXXXXX sync character - * WR7 XXXXXXXX sync character - * WR9 000X0XXX select interrupt control - * WR10 XXXXXXXX miscellaneous control (optional) - * WR11 XXXXXXXX clock control - * WR12 XXXXXXXX time constant lower byte (optional) - * WR13 XXXXXXXX time constant upper byte (optional) - * WR14 XXXXXXX0 miscellaneous control - * WR14 XXXSSSSS commands (optional) - * - * 2. Enables - * - * WR14 000SSSS1 baud rate enable - * WR3 SSSSSSS1 Rx enable - * WR5 SSSS1SSS Tx enable - * WR0 10000000 reset Tx CRG (optional) - * WR1 XSS00S00 DMA enable (optional) - * - * 3. Interrupt status - * - * WR15 XXXXXXXX enable external/status - * WR0 00010000 reset external status - * WR0 00010000 reset external status twice - * WR1 SSSXXSXX enable Rx, Tx and Ext/status - * WR9 000SXSSS enable master interrupt enable - * - * 1 = set to one, 0 = reset to zero - * X = user defined, S = same as previous init - * - * - * Note that the implementation differs in some points from above scheme. - * - */ - -static void init_channel(struct scc_channel *scc) -{ - timer_delete(&scc->tx_t); - timer_delete(&scc->tx_wdog); - - disable_irq(scc->irq); - - wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */ - wr(scc,R1,0); /* no W/REQ operation */ - wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */ - wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */ - wr(scc,R6,0); /* SDLC address zero (not used) */ - wr(scc,R7,FLAG); /* SDLC flag value */ - wr(scc,R9,VIS); /* vector includes status */ - wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */ - wr(scc,R14, 0); - - -/* set clock sources: - - CLK_DPLL: normal halfduplex operation - - RxClk: use DPLL - TxClk: use DPLL - TRxC mode DPLL output - - CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem) - - BayCom: others: - - TxClk = pin RTxC TxClk = pin TRxC - RxClk = pin TRxC RxClk = pin RTxC - - - CLK_DIVIDER: - RxClk = use DPLL - TxClk = pin RTxC - - BayCom: others: - pin TRxC = DPLL pin TRxC = BRG - (RxClk * 1) (RxClk * 32) -*/ - - - switch(scc->modem.clocksrc) - { - case CLK_DPLL: - wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP); - init_brg(scc); - break; - - case CLK_DIVIDER: - wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI); - init_brg(scc); - break; - - case CLK_EXTERNAL: - wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP); - OutReg(scc->ctrl, R14, DISDPLL); - break; - - } - - set_speed(scc); /* set baudrate */ - - if(scc->enhanced) - { - or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */ - wr(scc,R7,AUTOEOM); - } - - if(scc->kiss.softdcd || (InReg(scc->ctrl,R0) & DCD)) - /* DCD is now ON */ - { - start_hunt(scc); - } - - /* enable ABORT, DCD & SYNC/HUNT interrupts */ - - wr(scc,R15, BRKIE|TxUIE|(scc->kiss.softdcd? SYNCIE:DCDIE)); - - Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ - Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */ - - or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */ - - scc->status = InReg(scc->ctrl,R0); /* read initial status */ - - or(scc,R9,MIE); /* master interrupt enable */ - - scc_init_timer(scc); - - enable_irq(scc->irq); -} - - - - -/* ******************************************************************** */ -/* * SCC timer functions * */ -/* ******************************************************************** */ - - -/* ----> scc_key_trx sets the time constant for the baudrate - generator and keys the transmitter <---- */ - -static void scc_key_trx(struct scc_channel *scc, char tx) -{ - unsigned int time_const; - - if (scc->brand & PRIMUS) - Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0)); - - if (scc->modem.speed < 300) - scc->modem.speed = 1200; - - time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2; - - disable_irq(scc->irq); - - if (tx) - { - or(scc, R1, TxINT_ENAB); /* t_maxkeyup may have reset these */ - or(scc, R15, TxUIE); - } - - if (scc->modem.clocksrc == CLK_DPLL) - { /* force simplex operation */ - if (tx) - { -#ifdef CONFIG_SCC_TRXECHO - cl(scc, R3, RxENABLE|ENT_HM); /* switch off receiver */ - cl(scc, R15, DCDIE|SYNCIE); /* No DCD changes, please */ -#endif - set_brg(scc, time_const); /* reprogram baudrate generator */ - - /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */ - wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR); - - /* By popular demand: tx_inhibit */ - if (scc->kiss.tx_inhibit) - { - or(scc,R5, TxENAB); - scc->wreg[R5] |= RTS; - } else { - or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */ - } - } else { - cl(scc,R5,RTS|TxENAB); - - set_brg(scc, time_const); /* reprogram baudrate generator */ - - /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */ - wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP); - -#ifndef CONFIG_SCC_TRXECHO - if (scc->kiss.softdcd) -#endif - { - or(scc,R15, scc->kiss.softdcd? SYNCIE:DCDIE); - start_hunt(scc); - } - } - } else { - if (tx) - { -#ifdef CONFIG_SCC_TRXECHO - if (scc->kiss.fulldup == KISS_DUPLEX_HALF) - { - cl(scc, R3, RxENABLE); - cl(scc, R15, DCDIE|SYNCIE); - } -#endif - - if (scc->kiss.tx_inhibit) - { - or(scc,R5, TxENAB); - scc->wreg[R5] |= RTS; - } else { - or(scc,R5,RTS|TxENAB); /* enable tx */ - } - } else { - cl(scc,R5,RTS|TxENAB); /* disable tx */ - - if ((scc->kiss.fulldup == KISS_DUPLEX_HALF) && -#ifndef CONFIG_SCC_TRXECHO - scc->kiss.softdcd) -#else - 1) -#endif - { - or(scc, R15, scc->kiss.softdcd? SYNCIE:DCDIE); - start_hunt(scc); - } - } - } - - enable_irq(scc->irq); -} - - -/* ----> SCC timer interrupt handler and friends. <---- */ - -static void __scc_start_tx_timer(struct scc_channel *scc, - void (*handler)(struct timer_list *t), - unsigned long when) -{ - timer_delete(&scc->tx_t); - - if (when == 0) - { - handler(&scc->tx_t); - } else - if (when != TIMER_OFF) - { - scc->tx_t.function = handler; - scc->tx_t.expires = jiffies + (when*HZ)/100; - add_timer(&scc->tx_t); - } -} - -static void scc_start_tx_timer(struct scc_channel *scc, - void (*handler)(struct timer_list *t), - unsigned long when) -{ - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - __scc_start_tx_timer(scc, handler, when); - spin_unlock_irqrestore(&scc->lock, flags); -} - -static void scc_start_defer(struct scc_channel *scc) -{ - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - timer_delete(&scc->tx_wdog); - - if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF) - { - scc->tx_wdog.function = t_busy; - scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer; - add_timer(&scc->tx_wdog); - } - spin_unlock_irqrestore(&scc->lock, flags); -} - -static void scc_start_maxkeyup(struct scc_channel *scc) -{ - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - timer_delete(&scc->tx_wdog); - - if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF) - { - scc->tx_wdog.function = t_maxkeyup; - scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup; - add_timer(&scc->tx_wdog); - } - spin_unlock_irqrestore(&scc->lock, flags); -} - -/* - * This is called from scc_txint() when there are no more frames to send. - * Not exactly a timer function, but it is a close friend of the family... - */ - -static void scc_tx_done(struct scc_channel *scc) -{ - /* - * trx remains keyed in fulldup mode 2 until t_idle expires. - */ - - switch (scc->kiss.fulldup) - { - case KISS_DUPLEX_LINK: - scc->stat.tx_state = TXS_IDLE2; - if (scc->kiss.idletime != TIMER_OFF) - scc_start_tx_timer(scc, t_idle, - scc->kiss.idletime*100); - break; - case KISS_DUPLEX_OPTIMA: - scc_notify(scc, HWEV_ALL_SENT); - break; - default: - scc->stat.tx_state = TXS_BUSY; - scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); - } - - netif_wake_queue(scc->dev); -} - - -static unsigned char Rand = 17; - -static inline int is_grouped(struct scc_channel *scc) -{ - int k; - struct scc_channel *scc2; - unsigned char grp1, grp2; - - grp1 = scc->kiss.group; - - for (k = 0; k < (Nchips * 2); k++) - { - scc2 = &SCC_Info[k]; - grp2 = scc2->kiss.group; - - if (scc2 == scc || !(scc2->dev && grp2)) - continue; - - if ((grp1 & 0x3f) == (grp2 & 0x3f)) - { - if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) ) - return 1; - - if ( (grp1 & RXGROUP) && scc2->dcd ) - return 1; - } - } - return 0; -} - -/* DWAIT and SLOTTIME expired - * - * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer - * else key trx and start txdelay - * fulldup == 1: key trx and start txdelay - * fulldup == 2: mintime expired, reset status or key trx and start txdelay - */ - -static void t_dwait(struct timer_list *t) -{ - struct scc_channel *scc = timer_container_of(scc, t, tx_t); - - if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ - { - if (skb_queue_empty(&scc->tx_queue)) { /* nothing to send */ - scc->stat.tx_state = TXS_IDLE; - netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */ - return; - } - - scc->stat.tx_state = TXS_BUSY; - } - - if (scc->kiss.fulldup == KISS_DUPLEX_HALF) - { - Rand = Rand * 17 + 31; - - if (scc->dcd || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) ) - { - scc_start_defer(scc); - scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime); - return ; - } - } - - if ( !(scc->wreg[R5] & RTS) ) - { - scc_key_trx(scc, TX_ON); - scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); - } else { - scc_start_tx_timer(scc, t_txdelay, 0); - } -} - - -/* TXDELAY expired - * - * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog. - */ - -static void t_txdelay(struct timer_list *t) -{ - struct scc_channel *scc = timer_container_of(scc, t, tx_t); - - scc_start_maxkeyup(scc); - - if (scc->tx_buff == NULL) - { - disable_irq(scc->irq); - scc_txint(scc); - enable_irq(scc->irq); - } -} - - -/* TAILTIME expired - * - * switch off transmitter. If we were stopped by Maxkeyup restart - * transmission after 'mintime' seconds - */ - -static void t_tail(struct timer_list *t) -{ - struct scc_channel *scc = timer_container_of(scc, t, tx_t); - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - timer_delete(&scc->tx_wdog); - scc_key_trx(scc, TX_OFF); - spin_unlock_irqrestore(&scc->lock, flags); - - if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */ - { - scc->stat.tx_state = TXS_WAIT; - scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); - return; - } - - scc->stat.tx_state = TXS_IDLE; - netif_wake_queue(scc->dev); -} - - -/* BUSY timeout - * - * throw away send buffers if DCD remains active too long. - */ - -static void t_busy(struct timer_list *t) -{ - struct scc_channel *scc = timer_container_of(scc, t, tx_wdog); - - timer_delete(&scc->tx_t); - netif_stop_queue(scc->dev); /* don't pile on the wabbit! */ - - scc_discard_buffers(scc); - scc->stat.txerrs++; - scc->stat.tx_state = TXS_IDLE; - - netif_wake_queue(scc->dev); -} - -/* MAXKEYUP timeout - * - * this is our watchdog. - */ - -static void t_maxkeyup(struct timer_list *t) -{ - struct scc_channel *scc = timer_container_of(scc, t, tx_wdog); - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - /* - * let things settle down before we start to - * accept new data. - */ - - netif_stop_queue(scc->dev); - scc_discard_buffers(scc); - - timer_delete(&scc->tx_t); - - cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */ - cl(scc, R15, TxUIE); /* count it. */ - OutReg(scc->ctrl, R0, RES_Tx_P); - - spin_unlock_irqrestore(&scc->lock, flags); - - scc->stat.txerrs++; - scc->stat.tx_state = TXS_TIMEOUT; - scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); -} - -/* IDLE timeout - * - * in fulldup mode 2 it keys down the transmitter after 'idle' seconds - * of inactivity. We will not restart transmission before 'mintime' - * expires. - */ - -static void t_idle(struct timer_list *t) -{ - struct scc_channel *scc = timer_container_of(scc, t, tx_t); - - timer_delete(&scc->tx_wdog); - - scc_key_trx(scc, TX_OFF); - if(scc->kiss.mintime) - scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); - scc->stat.tx_state = TXS_WAIT; -} - -static void scc_init_timer(struct scc_channel *scc) -{ - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - scc->stat.tx_state = TXS_IDLE; - spin_unlock_irqrestore(&scc->lock, flags); -} - - -/* ******************************************************************** */ -/* * Set/get L1 parameters * */ -/* ******************************************************************** */ - - -/* - * this will set the "hardware" parameters through KISS commands or ioctl() - */ - -#define CAST(x) (unsigned long)(x) - -static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg) -{ - switch (cmd) - { - case PARAM_TXDELAY: scc->kiss.txdelay=arg; break; - case PARAM_PERSIST: scc->kiss.persist=arg; break; - case PARAM_SLOTTIME: scc->kiss.slottime=arg; break; - case PARAM_TXTAIL: scc->kiss.tailtime=arg; break; - case PARAM_FULLDUP: scc->kiss.fulldup=arg; break; - case PARAM_DTR: break; /* does someone need this? */ - case PARAM_GROUP: scc->kiss.group=arg; break; - case PARAM_IDLE: scc->kiss.idletime=arg; break; - case PARAM_MIN: scc->kiss.mintime=arg; break; - case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break; - case PARAM_WAIT: scc->kiss.waittime=arg; break; - case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break; - case PARAM_TX: scc->kiss.tx_inhibit=arg; break; - - case PARAM_SOFTDCD: - scc->kiss.softdcd=arg; - if (arg) - { - or(scc, R15, SYNCIE); - cl(scc, R15, DCDIE); - start_hunt(scc); - } else { - or(scc, R15, DCDIE); - cl(scc, R15, SYNCIE); - } - break; - - case PARAM_SPEED: - if (arg < 256) - scc->modem.speed=arg*100; - else - scc->modem.speed=arg; - - if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */ - set_speed(scc); - break; - - case PARAM_RTS: - if ( !(scc->wreg[R5] & RTS) ) - { - if (arg != TX_OFF) { - scc_key_trx(scc, TX_ON); - scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); - } - } else { - if (arg == TX_OFF) - { - scc->stat.tx_state = TXS_BUSY; - scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); - } - } - break; - - case PARAM_HWEVENT: - scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF); - break; - - default: return -EINVAL; - } - - return 0; -} - - - -static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd) -{ - switch (cmd) - { - case PARAM_TXDELAY: return CAST(scc->kiss.txdelay); - case PARAM_PERSIST: return CAST(scc->kiss.persist); - case PARAM_SLOTTIME: return CAST(scc->kiss.slottime); - case PARAM_TXTAIL: return CAST(scc->kiss.tailtime); - case PARAM_FULLDUP: return CAST(scc->kiss.fulldup); - case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd); - case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0); - case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0); - case PARAM_SPEED: return CAST(scc->modem.speed); - case PARAM_GROUP: return CAST(scc->kiss.group); - case PARAM_IDLE: return CAST(scc->kiss.idletime); - case PARAM_MIN: return CAST(scc->kiss.mintime); - case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup); - case PARAM_WAIT: return CAST(scc->kiss.waittime); - case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer); - case PARAM_TX: return CAST(scc->kiss.tx_inhibit); - default: return NO_SUCH_PARAM; - } - -} - -#undef CAST - -/* ******************************************************************* */ -/* * Send calibration pattern * */ -/* ******************************************************************* */ - -static void scc_stop_calibrate(struct timer_list *t) -{ - struct scc_channel *scc = timer_container_of(scc, t, tx_wdog); - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - timer_delete(&scc->tx_wdog); - scc_key_trx(scc, TX_OFF); - wr(scc, R6, 0); - wr(scc, R7, FLAG); - Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ - Outb(scc->ctrl,RES_EXT_INT); - - netif_wake_queue(scc->dev); - spin_unlock_irqrestore(&scc->lock, flags); -} - - -static void -scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern) -{ - unsigned long flags; - - spin_lock_irqsave(&scc->lock, flags); - netif_stop_queue(scc->dev); - scc_discard_buffers(scc); - - timer_delete(&scc->tx_wdog); - - scc->tx_wdog.function = scc_stop_calibrate; - scc->tx_wdog.expires = jiffies + HZ*duration; - add_timer(&scc->tx_wdog); - - /* This doesn't seem to work. Why not? */ - wr(scc, R6, 0); - wr(scc, R7, pattern); - - /* - * Don't know if this works. - * Damn, where is my Z8530 programming manual...? - */ - - Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ - Outb(scc->ctrl,RES_EXT_INT); - - scc_key_trx(scc, TX_ON); - spin_unlock_irqrestore(&scc->lock, flags); -} - -/* ******************************************************************* */ -/* * Init channel structures, special HW, etc... * */ -/* ******************************************************************* */ - -/* - * Reset the Z8530s and setup special hardware - */ - -static void z8530_init(void) -{ - const unsigned int nr_irqs = irq_get_nr_irqs(); - struct scc_channel *scc; - int chip, k; - unsigned long flags; - char *flag; - - - printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2); - - flag=" "; - for (k = 0; k < nr_irqs; k++) - if (Ivec[k].used) - { - printk("%s%d", flag, k); - flag=","; - } - printk("\n"); - - - /* reset and pre-init all chips in the system */ - for (chip = 0; chip < Nchips; chip++) - { - scc=&SCC_Info[2*chip]; - if (!scc->ctrl) continue; - - /* Special SCC cards */ - - if(scc->brand & EAGLE) /* this is an EAGLE card */ - Outb(scc->special,0x08); /* enable interrupt on the board */ - - if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */ - Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */ - - - /* Reset and pre-init Z8530 */ - - spin_lock_irqsave(&scc->lock, flags); - - Outb(scc->ctrl, 0); - OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */ - udelay(100); /* give it 'a bit' more time than required */ - wr(scc, R2, chip*16); /* interrupt vector */ - wr(scc, R9, VIS); /* vector includes status */ - spin_unlock_irqrestore(&scc->lock, flags); - } - - - Driver_Initialized = 1; -} - -/* - * Allocate device structure, err, instance, and register driver - */ - -static int scc_net_alloc(const char *name, struct scc_channel *scc) -{ - int err; - struct net_device *dev; - - dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, scc_net_setup); - if (!dev) - return -ENOMEM; - - dev->ml_priv = scc; - scc->dev = dev; - spin_lock_init(&scc->lock); - timer_setup(&scc->tx_t, NULL, 0); - timer_setup(&scc->tx_wdog, NULL, 0); - - err = register_netdevice(dev); - if (err) { - printk(KERN_ERR "%s: can't register network device (%d)\n", - name, err); - free_netdev(dev); - scc->dev = NULL; - return err; - } - - return 0; -} - - - -/* ******************************************************************** */ -/* * Network driver methods * */ -/* ******************************************************************** */ - -static const struct net_device_ops scc_netdev_ops = { - .ndo_open = scc_net_open, - .ndo_stop = scc_net_close, - .ndo_start_xmit = scc_net_tx, - .ndo_set_mac_address = scc_net_set_mac_address, - .ndo_get_stats = scc_net_get_stats, - .ndo_siocdevprivate = scc_net_siocdevprivate, -}; - -/* ----> Initialize device <----- */ - -static void scc_net_setup(struct net_device *dev) -{ - dev->tx_queue_len = 16; /* should be enough... */ - - dev->netdev_ops = &scc_netdev_ops; - dev->header_ops = &ax25_header_ops; - - dev->flags = 0; - - dev->type = ARPHRD_AX25; - dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; - dev->mtu = AX25_DEF_PACLEN; - dev->addr_len = AX25_ADDR_LEN; - - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&ax25_defaddr); -} - -/* ----> open network device <---- */ - -static int scc_net_open(struct net_device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; - - if (!scc->init) - return -EINVAL; - - scc->tx_buff = NULL; - skb_queue_head_init(&scc->tx_queue); - - init_channel(scc); - - netif_start_queue(dev); - return 0; -} - -/* ----> close network device <---- */ - -static int scc_net_close(struct net_device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; - unsigned long flags; - - netif_stop_queue(dev); - - spin_lock_irqsave(&scc->lock, flags); - Outb(scc->ctrl,0); /* Make sure pointer is written */ - wr(scc,R1,0); /* disable interrupts */ - wr(scc,R3,0); - spin_unlock_irqrestore(&scc->lock, flags); - - timer_delete_sync(&scc->tx_t); - timer_delete_sync(&scc->tx_wdog); - - scc_discard_buffers(scc); - - return 0; -} - -/* ----> receive frame, called from scc_rxint() <---- */ - -static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) -{ - if (skb->len == 0) { - dev_kfree_skb_irq(skb); - return; - } - - scc->dev_stat.rx_packets++; - scc->dev_stat.rx_bytes += skb->len; - - skb->protocol = ax25_type_trans(skb, scc->dev); - - netif_rx(skb); -} - -/* ----> transmit frame <---- */ - -static netdev_tx_t scc_net_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; - unsigned long flags; - char kisscmd; - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - if (skb->len > scc->stat.bufsize || skb->len < 2) { - scc->dev_stat.tx_dropped++; /* bogus frame */ - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - scc->dev_stat.tx_packets++; - scc->dev_stat.tx_bytes += skb->len; - scc->stat.txframes++; - - kisscmd = *skb->data & 0x1f; - skb_pull(skb, 1); - - if (kisscmd) { - scc_set_param(scc, kisscmd, *skb->data); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - spin_lock_irqsave(&scc->lock, flags); - - if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) { - struct sk_buff *skb_del; - skb_del = skb_dequeue(&scc->tx_queue); - dev_kfree_skb_irq(skb_del); - } - skb_queue_tail(&scc->tx_queue, skb); - netif_trans_update(dev); - - - /* - * Start transmission if the trx state is idle or - * t_idle hasn't expired yet. Use dwait/persistence/slottime - * algorithm for normal halfduplex operation. - */ - - if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) { - scc->stat.tx_state = TXS_BUSY; - if (scc->kiss.fulldup == KISS_DUPLEX_HALF) - __scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime); - else - __scc_start_tx_timer(scc, t_dwait, 0); - } - spin_unlock_irqrestore(&scc->lock, flags); - return NETDEV_TX_OK; -} - -/* ----> ioctl functions <---- */ - -/* - * SIOCSCCCFG - configure driver arg: (struct scc_hw_config *) arg - * SIOCSCCINI - initialize driver arg: --- - * SIOCSCCCHANINI - initialize channel arg: (struct scc_modem *) arg - * SIOCSCCSMEM - set memory arg: (struct scc_mem_config *) arg - * SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg - * SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg - * SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg - * SIOCSCCCAL - send calib. pattern arg: (struct scc_calibrate *) arg - */ - -static int scc_net_siocdevprivate(struct net_device *dev, - struct ifreq *ifr, void __user *arg, int cmd) -{ - struct scc_kiss_cmd kiss_cmd; - struct scc_mem_config memcfg; - struct scc_hw_config hwcfg; - struct scc_calibrate cal; - struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; - int chan; - unsigned char device_name[IFNAMSIZ]; - - if (!Driver_Initialized) - { - if (cmd == SIOCSCCCFG) - { - int found = 1; - - if (!capable(CAP_SYS_RAWIO)) return -EPERM; - if (in_compat_syscall()) - return -EOPNOTSUPP; - - if (!arg) return -EFAULT; - - if (Nchips >= SCC_MAXCHIPS) - return -EINVAL; - - if (copy_from_user(&hwcfg, arg, sizeof(hwcfg))) - return -EFAULT; - - if (hwcfg.irq == 2) hwcfg.irq = 9; - - if (hwcfg.irq < 0 || hwcfg.irq >= irq_get_nr_irqs()) - return -EINVAL; - - if (!Ivec[hwcfg.irq].used && hwcfg.irq) - { - if (request_irq(hwcfg.irq, scc_isr, - 0, "AX.25 SCC", - (void *)(long) hwcfg.irq)) - printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq); - else - Ivec[hwcfg.irq].used = 1; - } - - if (hwcfg.vector_latch && !Vector_Latch) { - if (!request_region(hwcfg.vector_latch, 1, "scc vector latch")) - printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch); - else - Vector_Latch = hwcfg.vector_latch; - } - - if (hwcfg.clock == 0) - hwcfg.clock = SCC_DEFAULT_CLOCK; - -#ifndef SCC_DONT_CHECK - - if(request_region(hwcfg.ctrl_a, 1, "scc-probe")) - { - disable_irq(hwcfg.irq); - Outb(hwcfg.ctrl_a, 0); - OutReg(hwcfg.ctrl_a, R9, FHWRES); - udelay(100); - OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */ - udelay(5); - - if (InReg(hwcfg.ctrl_a,R13) != 0x55) - found = 0; - enable_irq(hwcfg.irq); - release_region(hwcfg.ctrl_a, 1); - } - else - found = 0; -#endif - - if (found) - { - SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a; - SCC_Info[2*Nchips ].data = hwcfg.data_a; - SCC_Info[2*Nchips ].irq = hwcfg.irq; - SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b; - SCC_Info[2*Nchips+1].data = hwcfg.data_b; - SCC_Info[2*Nchips+1].irq = hwcfg.irq; - - SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a; - SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b; - SCC_ctrl[Nchips].irq = hwcfg.irq; - } - - - for (chan = 0; chan < 2; chan++) - { - sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan); - - SCC_Info[2*Nchips+chan].special = hwcfg.special; - SCC_Info[2*Nchips+chan].clock = hwcfg.clock; - SCC_Info[2*Nchips+chan].brand = hwcfg.brand; - SCC_Info[2*Nchips+chan].option = hwcfg.option; - SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc; - -#ifdef SCC_DONT_CHECK - printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n", - device_name, - SCC_Info[2*Nchips+chan].data, - SCC_Info[2*Nchips+chan].ctrl); - -#else - printk(KERN_INFO "%s: data port = 0x%3.3lx control port = 0x%3.3lx -- %s\n", - device_name, - chan? hwcfg.data_b : hwcfg.data_a, - chan? hwcfg.ctrl_b : hwcfg.ctrl_a, - found? "found" : "missing"); -#endif - - if (found) - { - request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl"); - request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data"); - if (Nchips+chan != 0 && - scc_net_alloc(device_name, - &SCC_Info[2*Nchips+chan])) - return -EINVAL; - } - } - - if (found) Nchips++; - - return 0; - } - - if (cmd == SIOCSCCINI) - { - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (Nchips == 0) - return -EINVAL; - - z8530_init(); - return 0; - } - - return -EINVAL; /* confuse the user */ - } - - if (!scc->init) - { - if (cmd == SIOCSCCCHANINI) - { - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (!arg) return -EINVAL; - - scc->stat.bufsize = SCC_BUFSIZE; - - if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem))) - return -EINVAL; - - /* default KISS Params */ - - if (scc->modem.speed < 4800) - { - scc->kiss.txdelay = 36; /* 360 ms */ - scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */ - scc->kiss.slottime = 16; /* 160 ms */ - scc->kiss.tailtime = 4; /* minimal reasonable value */ - scc->kiss.fulldup = 0; /* CSMA */ - scc->kiss.waittime = 50; /* 500 ms */ - scc->kiss.maxkeyup = 10; /* 10 s */ - scc->kiss.mintime = 3; /* 3 s */ - scc->kiss.idletime = 30; /* 30 s */ - scc->kiss.maxdefer = 120; /* 2 min */ - scc->kiss.softdcd = 0; /* hardware dcd */ - } else { - scc->kiss.txdelay = 10; /* 100 ms */ - scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */ - scc->kiss.slottime = 8; /* 160 ms */ - scc->kiss.tailtime = 1; /* minimal reasonable value */ - scc->kiss.fulldup = 0; /* CSMA */ - scc->kiss.waittime = 50; /* 500 ms */ - scc->kiss.maxkeyup = 7; /* 7 s */ - scc->kiss.mintime = 3; /* 3 s */ - scc->kiss.idletime = 30; /* 30 s */ - scc->kiss.maxdefer = 120; /* 2 min */ - scc->kiss.softdcd = 0; /* hardware dcd */ - } - - scc->tx_buff = NULL; - skb_queue_head_init(&scc->tx_queue); - scc->init = 1; - - return 0; - } - - return -EINVAL; - } - - switch(cmd) - { - case SIOCSCCRESERVED: - return -ENOIOCTLCMD; - - case SIOCSCCSMEM: - if (!capable(CAP_SYS_RAWIO)) return -EPERM; - if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) - return -EINVAL; - if (memcfg.bufsize < 16) - return -EINVAL; - scc->stat.bufsize = memcfg.bufsize; - return 0; - - case SIOCSCCGSTAT: - if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat))) - return -EINVAL; - return 0; - - case SIOCSCCGKISS: - if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) - return -EINVAL; - kiss_cmd.param = scc_get_param(scc, kiss_cmd.command); - if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd))) - return -EINVAL; - return 0; - - case SIOCSCCSKISS: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) - return -EINVAL; - return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param); - - case SIOCSCCCAL: - if (!capable(CAP_SYS_RAWIO)) return -EPERM; - if (!arg || copy_from_user(&cal, arg, sizeof(cal)) || cal.time == 0) - return -EINVAL; - - scc_start_calibrate(scc, cal.time, cal.pattern); - return 0; - - default: - return -ENOIOCTLCMD; - - } - - return -EINVAL; -} - -/* ----> set interface callsign <---- */ - -static int scc_net_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *) addr; - dev_addr_set(dev, sa->sa_data); - return 0; -} - -/* ----> get statistics <---- */ - -static struct net_device_stats *scc_net_get_stats(struct net_device *dev) -{ - struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; - - scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over; - scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under; - scc->dev_stat.rx_fifo_errors = scc->stat.rx_over; - scc->dev_stat.tx_fifo_errors = scc->stat.tx_under; - - return &scc->dev_stat; -} - -/* ******************************************************************** */ -/* * dump statistics to /proc/net/z8530drv * */ -/* ******************************************************************** */ - -#ifdef CONFIG_PROC_FS - -static inline struct scc_channel *scc_net_seq_idx(loff_t pos) -{ - int k; - - for (k = 0; k < Nchips*2; ++k) { - if (!SCC_Info[k].init) - continue; - if (pos-- == 0) - return &SCC_Info[k]; - } - return NULL; -} - -static void *scc_net_seq_start(struct seq_file *seq, loff_t *pos) -{ - return *pos ? scc_net_seq_idx(*pos - 1) : SEQ_START_TOKEN; - -} - -static void *scc_net_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - unsigned k; - struct scc_channel *scc = v; - ++*pos; - - for (k = (v == SEQ_START_TOKEN) ? 0 : (scc - SCC_Info)+1; - k < Nchips*2; ++k) { - if (SCC_Info[k].init) - return &SCC_Info[k]; - } - return NULL; -} - -static void scc_net_seq_stop(struct seq_file *seq, void *v) -{ -} - -static int scc_net_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_puts(seq, "z8530drv-"VERSION"\n"); - } else if (!Driver_Initialized) { - seq_puts(seq, "not initialized\n"); - } else if (!Nchips) { - seq_puts(seq, "chips missing\n"); - } else { - const struct scc_channel *scc = v; - const struct scc_stat *stat = &scc->stat; - const struct scc_kiss *kiss = &scc->kiss; - - - /* dev data ctrl irq clock brand enh vector special option - * baud nrz clocksrc softdcd bufsize - * rxints txints exints spints - * rcvd rxerrs over / xmit txerrs under / nospace bufsize - * txd pers slot tail ful wait min maxk idl defr txof grp - * W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## - * R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ## - */ - - seq_printf(seq, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n", - scc->dev->name, - scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand, - scc->enhanced, Vector_Latch, scc->special, - scc->option); - seq_printf(seq, "\t%lu %d %d %d %d\n", - scc->modem.speed, scc->modem.nrz, - scc->modem.clocksrc, kiss->softdcd, - stat->bufsize); - seq_printf(seq, "\t%lu %lu %lu %lu\n", - stat->rxints, stat->txints, stat->exints, stat->spints); - seq_printf(seq, "\t%lu %lu %d / %lu %lu %d / %d %d\n", - stat->rxframes, stat->rxerrs, stat->rx_over, - stat->txframes, stat->txerrs, stat->tx_under, - stat->nospace, stat->tx_state); - -#define K(x) kiss->x - seq_printf(seq, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n", - K(txdelay), K(persist), K(slottime), K(tailtime), - K(fulldup), K(waittime), K(mintime), K(maxkeyup), - K(idletime), K(maxdefer), K(tx_inhibit), K(group)); -#undef K -#ifdef SCC_DEBUG - { - int reg; - - seq_printf(seq, "\tW "); - for (reg = 0; reg < 16; reg++) - seq_printf(seq, "%2.2x ", scc->wreg[reg]); - seq_printf(seq, "\n"); - - seq_printf(seq, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1)); - for (reg = 3; reg < 8; reg++) - seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg)); - seq_printf(seq, "XX "); - for (reg = 9; reg < 16; reg++) - seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg)); - seq_printf(seq, "\n"); - } -#endif - seq_putc(seq, '\n'); - } - - return 0; -} - -static const struct seq_operations scc_net_seq_ops = { - .start = scc_net_seq_start, - .next = scc_net_seq_next, - .stop = scc_net_seq_stop, - .show = scc_net_seq_show, -}; -#endif /* CONFIG_PROC_FS */ - - -/* ******************************************************************** */ -/* * Init SCC driver * */ -/* ******************************************************************** */ - -static int __init scc_init_driver (void) -{ - char devname[IFNAMSIZ]; - - printk(banner); - - sprintf(devname,"%s0", SCC_DriverName); - - rtnl_lock(); - if (scc_net_alloc(devname, SCC_Info)) { - rtnl_unlock(); - printk(KERN_ERR "z8530drv: cannot initialize module\n"); - return -EIO; - } - rtnl_unlock(); - - proc_create_seq("z8530drv", 0, init_net.proc_net, &scc_net_seq_ops); - - return 0; -} - -static void __exit scc_cleanup_driver(void) -{ - const unsigned int nr_irqs = irq_get_nr_irqs(); - io_port ctrl; - int k; - struct scc_channel *scc; - struct net_device *dev; - - if (Nchips == 0 && (dev = SCC_Info[0].dev)) - { - unregister_netdev(dev); - free_netdev(dev); - } - - /* Guard against chip prattle */ - local_irq_disable(); - - for (k = 0; k < Nchips; k++) - if ( (ctrl = SCC_ctrl[k].chan_A) ) - { - Outb(ctrl, 0); - OutReg(ctrl,R9,FHWRES); /* force hardware reset */ - udelay(50); - } - - /* To unload the port must be closed so no real IRQ pending */ - for (k = 0; k < nr_irqs ; k++) - if (Ivec[k].used) free_irq(k, NULL); - - local_irq_enable(); - - /* Now clean up */ - for (k = 0; k < Nchips*2; k++) - { - scc = &SCC_Info[k]; - if (scc->ctrl) - { - release_region(scc->ctrl, 1); - release_region(scc->data, 1); - } - if (scc->dev) - { - unregister_netdev(scc->dev); - free_netdev(scc->dev); - } - } - - - if (Vector_Latch) - release_region(Vector_Latch, 1); - - remove_proc_entry("z8530drv", init_net.proc_net); -} - -MODULE_AUTHOR("Joerg Reuter "); -MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards"); -MODULE_LICENSE("GPL"); -module_init(scc_init_driver); -module_exit(scc_cleanup_driver); diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c deleted file mode 100644 index 4106f0301ab4..000000000000 --- a/drivers/net/hamradio/yam.c +++ /dev/null @@ -1,1191 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/*****************************************************************************/ - -/* - * yam.c -- YAM radio modem driver. - * - * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr) - * Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * History: - * 0.0 F1OAT 06.06.98 Begin of work with baycom.c source code V 0.3 - * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration - * 0.2 F6FBB 08.06.98 Added delay after FPGA programming - * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2 - * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistence - * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics - * 0.6 F6FBB 25.08.98 Added 1200Bds format - * 0.7 F6FBB 12.09.98 Added to the kernel configuration - * 0.8 F6FBB 14.10.98 Fixed slottime/persistence timing bug - * OK1ZIA 2.09.01 Fixed "kfree_skb on hard IRQ" - * using dev_kfree_skb_any(). (important in 2.4 kernel) - */ - -/*****************************************************************************/ - -#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 - -/* --------------------------------------------------------------------- */ - -static const char yam_drvname[] = "yam"; -static const char yam_drvinfo[] __initconst = KERN_INFO \ - "YAM driver version 0.8 by F1OAT/F6FBB\n"; - -/* --------------------------------------------------------------------- */ - -#define FIRMWARE_9600 "yam/9600.bin" -#define FIRMWARE_1200 "yam/1200.bin" - -#define YAM_9600 1 -#define YAM_1200 2 - -#define NR_PORTS 4 -#define YAM_MAGIC 0xF10A7654 - -/* Transmitter states */ - -#define TX_OFF 0 -#define TX_HEAD 1 -#define TX_DATA 2 -#define TX_CRC1 3 -#define TX_CRC2 4 -#define TX_TAIL 5 - -#define YAM_MAX_FRAME 1024 - -#define DEFAULT_BITRATE 9600 /* bps */ -#define DEFAULT_HOLDD 10 /* sec */ -#define DEFAULT_TXD 300 /* ms */ -#define DEFAULT_TXTAIL 10 /* ms */ -#define DEFAULT_SLOT 100 /* ms */ -#define DEFAULT_PERS 64 /* 0->255 */ - -struct yam_port { - int magic; - int bitrate; - int baudrate; - int iobase; - int irq; - int dupmode; - - struct net_device *dev; - - int nb_rxint; - int nb_mdint; - - /* Parameters section */ - - int txd; /* tx delay */ - int holdd; /* duplex ptt delay */ - int txtail; /* txtail delay */ - int slot; /* slottime */ - int pers; /* persistence */ - - /* Tx section */ - - int tx_state; - int tx_count; - int slotcnt; - unsigned char tx_buf[YAM_MAX_FRAME]; - int tx_len; - int tx_crcl, tx_crch; - struct sk_buff_head send_queue; /* Packets awaiting transmission */ - - /* Rx section */ - - int dcd; - unsigned char rx_buf[YAM_MAX_FRAME]; - int rx_len; - int rx_crcl, rx_crch; -}; - -struct yam_mcs { - unsigned char bits[YAM_FPGA_SIZE]; - int bitrate; - struct yam_mcs *next; -}; - -static struct net_device *yam_devs[NR_PORTS]; - -static struct yam_mcs *yam_data; - -static DEFINE_TIMER(yam_timer, NULL); - -/* --------------------------------------------------------------------- */ - -#define RBR(iobase) (iobase+0) -#define THR(iobase) (iobase+0) -#define IER(iobase) (iobase+1) -#define IIR(iobase) (iobase+2) -#define FCR(iobase) (iobase+2) -#define LCR(iobase) (iobase+3) -#define MCR(iobase) (iobase+4) -#define LSR(iobase) (iobase+5) -#define MSR(iobase) (iobase+6) -#define SCR(iobase) (iobase+7) -#define DLL(iobase) (iobase+0) -#define DLM(iobase) (iobase+1) - -#define YAM_EXTENT 8 - -/* Interrupt Identification Register Bit Masks */ -#define IIR_NOPEND 1 -#define IIR_MSR 0 -#define IIR_TX 2 -#define IIR_RX 4 -#define IIR_LSR 6 -#define IIR_TIMEOUT 12 /* Fifo mode only */ - -#define IIR_MASK 0x0F - -/* Interrupt Enable Register Bit Masks */ -#define IER_RX 1 /* enable rx interrupt */ -#define IER_TX 2 /* enable tx interrupt */ -#define IER_LSR 4 /* enable line status interrupts */ -#define IER_MSR 8 /* enable modem status interrupts */ - -/* Modem Control Register Bit Masks */ -#define MCR_DTR 0x01 /* DTR output */ -#define MCR_RTS 0x02 /* RTS output */ -#define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */ -#define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */ -#define MCR_LOOP 0x10 /* Loopback enable */ - -/* Modem Status Register Bit Masks */ -#define MSR_DCTS 0x01 /* Delta CTS input */ -#define MSR_DDSR 0x02 /* Delta DSR */ -#define MSR_DRIN 0x04 /* Delta RI */ -#define MSR_DDCD 0x08 /* Delta DCD */ -#define MSR_CTS 0x10 /* CTS input */ -#define MSR_DSR 0x20 /* DSR input */ -#define MSR_RING 0x40 /* RI input */ -#define MSR_DCD 0x80 /* DCD input */ - -/* line status register bit mask */ -#define LSR_RXC 0x01 -#define LSR_OE 0x02 -#define LSR_PE 0x04 -#define LSR_FE 0x08 -#define LSR_BREAK 0x10 -#define LSR_THRE 0x20 -#define LSR_TSRE 0x40 - -/* Line Control Register Bit Masks */ -#define LCR_DLAB 0x80 -#define LCR_BREAK 0x40 -#define LCR_PZERO 0x28 -#define LCR_PEVEN 0x18 -#define LCR_PODD 0x08 -#define LCR_STOP1 0x00 -#define LCR_STOP2 0x04 -#define LCR_BIT5 0x00 -#define LCR_BIT6 0x02 -#define LCR_BIT7 0x01 -#define LCR_BIT8 0x03 - -/* YAM Modem <-> UART Port mapping */ - -#define TX_RDY MSR_DCTS /* transmitter ready to send */ -#define RX_DCD MSR_DCD /* carrier detect */ -#define RX_FLAG MSR_RING /* hdlc flag received */ -#define FPGA_DONE MSR_DSR /* FPGA is configured */ -#define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */ -#define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */ - -#define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */ -#define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */ -#define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */ - - -/************************************************************************* -* CRC Tables -************************************************************************/ - -static const unsigned char chktabl[256] = -{0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf, 0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e, - 0xf7, 0x81, 0x08, 0x93, 0x1a, 0xa5, 0x2c, 0xb7, 0x3e, 0xc9, 0x40, 0xdb, 0x52, 0xed, 0x64, - 0xff, 0x76, 0x02, 0x8b, 0x10, 0x99, 0x26, 0xaf, 0x34, 0xbd, 0x4a, 0xc3, 0x58, 0xd1, 0x6e, - 0xe7, 0x7c, 0xf5, 0x83, 0x0a, 0x91, 0x18, 0xa7, 0x2e, 0xb5, 0x3c, 0xcb, 0x42, 0xd9, 0x50, - 0xef, 0x66, 0xfd, 0x74, 0x04, 0x8d, 0x16, 0x9f, 0x20, 0xa9, 0x32, 0xbb, 0x4c, 0xc5, 0x5e, - 0xd7, 0x68, 0xe1, 0x7a, 0xf3, 0x85, 0x0c, 0x97, 0x1e, 0xa1, 0x28, 0xb3, 0x3a, 0xcd, 0x44, - 0xdf, 0x56, 0xe9, 0x60, 0xfb, 0x72, 0x06, 0x8f, 0x14, 0x9d, 0x22, 0xab, 0x30, 0xb9, 0x4e, - 0xc7, 0x5c, 0xd5, 0x6a, 0xe3, 0x78, 0xf1, 0x87, 0x0e, 0x95, 0x1c, 0xa3, 0x2a, 0xb1, 0x38, - 0xcf, 0x46, 0xdd, 0x54, 0xeb, 0x62, 0xf9, 0x70, 0x08, 0x81, 0x1a, 0x93, 0x2c, 0xa5, 0x3e, - 0xb7, 0x40, 0xc9, 0x52, 0xdb, 0x64, 0xed, 0x76, 0xff, 0x89, 0x00, 0x9b, 0x12, 0xad, 0x24, - 0xbf, 0x36, 0xc1, 0x48, 0xd3, 0x5a, 0xe5, 0x6c, 0xf7, 0x7e, 0x0a, 0x83, 0x18, 0x91, 0x2e, - 0xa7, 0x3c, 0xb5, 0x42, 0xcb, 0x50, 0xd9, 0x66, 0xef, 0x74, 0xfd, 0x8b, 0x02, 0x99, 0x10, - 0xaf, 0x26, 0xbd, 0x34, 0xc3, 0x4a, 0xd1, 0x58, 0xe7, 0x6e, 0xf5, 0x7c, 0x0c, 0x85, 0x1e, - 0x97, 0x28, 0xa1, 0x3a, 0xb3, 0x44, 0xcd, 0x56, 0xdf, 0x60, 0xe9, 0x72, 0xfb, 0x8d, 0x04, - 0x9f, 0x16, 0xa9, 0x20, 0xbb, 0x32, 0xc5, 0x4c, 0xd7, 0x5e, 0xe1, 0x68, 0xf3, 0x7a, 0x0e, - 0x87, 0x1c, 0x95, 0x2a, 0xa3, 0x38, 0xb1, 0x46, 0xcf, 0x54, 0xdd, 0x62, 0xeb, 0x70, 0xf9, - 0x8f, 0x06, 0x9d, 0x14, 0xab, 0x22, 0xb9, 0x30, 0xc7, 0x4e, 0xd5, 0x5c, 0xe3, 0x6a, 0xf1, - 0x78}; -static const unsigned char chktabh[256] = -{0x00, 0x11, 0x23, 0x32, 0x46, 0x57, 0x65, 0x74, 0x8c, 0x9d, 0xaf, 0xbe, 0xca, 0xdb, 0xe9, - 0xf8, 0x10, 0x01, 0x33, 0x22, 0x56, 0x47, 0x75, 0x64, 0x9c, 0x8d, 0xbf, 0xae, 0xda, 0xcb, - 0xf9, 0xe8, 0x21, 0x30, 0x02, 0x13, 0x67, 0x76, 0x44, 0x55, 0xad, 0xbc, 0x8e, 0x9f, 0xeb, - 0xfa, 0xc8, 0xd9, 0x31, 0x20, 0x12, 0x03, 0x77, 0x66, 0x54, 0x45, 0xbd, 0xac, 0x9e, 0x8f, - 0xfb, 0xea, 0xd8, 0xc9, 0x42, 0x53, 0x61, 0x70, 0x04, 0x15, 0x27, 0x36, 0xce, 0xdf, 0xed, - 0xfc, 0x88, 0x99, 0xab, 0xba, 0x52, 0x43, 0x71, 0x60, 0x14, 0x05, 0x37, 0x26, 0xde, 0xcf, - 0xfd, 0xec, 0x98, 0x89, 0xbb, 0xaa, 0x63, 0x72, 0x40, 0x51, 0x25, 0x34, 0x06, 0x17, 0xef, - 0xfe, 0xcc, 0xdd, 0xa9, 0xb8, 0x8a, 0x9b, 0x73, 0x62, 0x50, 0x41, 0x35, 0x24, 0x16, 0x07, - 0xff, 0xee, 0xdc, 0xcd, 0xb9, 0xa8, 0x9a, 0x8b, 0x84, 0x95, 0xa7, 0xb6, 0xc2, 0xd3, 0xe1, - 0xf0, 0x08, 0x19, 0x2b, 0x3a, 0x4e, 0x5f, 0x6d, 0x7c, 0x94, 0x85, 0xb7, 0xa6, 0xd2, 0xc3, - 0xf1, 0xe0, 0x18, 0x09, 0x3b, 0x2a, 0x5e, 0x4f, 0x7d, 0x6c, 0xa5, 0xb4, 0x86, 0x97, 0xe3, - 0xf2, 0xc0, 0xd1, 0x29, 0x38, 0x0a, 0x1b, 0x6f, 0x7e, 0x4c, 0x5d, 0xb5, 0xa4, 0x96, 0x87, - 0xf3, 0xe2, 0xd0, 0xc1, 0x39, 0x28, 0x1a, 0x0b, 0x7f, 0x6e, 0x5c, 0x4d, 0xc6, 0xd7, 0xe5, - 0xf4, 0x80, 0x91, 0xa3, 0xb2, 0x4a, 0x5b, 0x69, 0x78, 0x0c, 0x1d, 0x2f, 0x3e, 0xd6, 0xc7, - 0xf5, 0xe4, 0x90, 0x81, 0xb3, 0xa2, 0x5a, 0x4b, 0x79, 0x68, 0x1c, 0x0d, 0x3f, 0x2e, 0xe7, - 0xf6, 0xc4, 0xd5, 0xa1, 0xb0, 0x82, 0x93, 0x6b, 0x7a, 0x48, 0x59, 0x2d, 0x3c, 0x0e, 0x1f, - 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e, - 0x0f}; - -/************************************************************************* -* FPGA functions -************************************************************************/ - -static void delay(int ms) -{ - unsigned long timeout = jiffies + ((ms * HZ) / 1000); - while (time_before(jiffies, timeout)) - cpu_relax(); -} - -/* - * reset FPGA - */ - -static void fpga_reset(int iobase) -{ - outb(0, IER(iobase)); - outb(LCR_DLAB | LCR_BIT5, LCR(iobase)); - outb(1, DLL(iobase)); - outb(0, DLM(iobase)); - - outb(LCR_BIT5, LCR(iobase)); - inb(LSR(iobase)); - inb(MSR(iobase)); - /* turn off FPGA supply voltage */ - outb(MCR_OUT1 | MCR_OUT2, MCR(iobase)); - delay(100); - /* turn on FPGA supply voltage again */ - outb(MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2, MCR(iobase)); - delay(100); -} - -/* - * send one byte to FPGA - */ - -static int fpga_write(int iobase, unsigned char wrd) -{ - unsigned char bit; - int k; - unsigned long timeout = jiffies + HZ / 10; - - for (k = 0; k < 8; k++) { - bit = (wrd & 0x80) ? (MCR_RTS | MCR_DTR) : MCR_DTR; - outb(bit | MCR_OUT1 | MCR_OUT2, MCR(iobase)); - wrd <<= 1; - outb(0xfc, THR(iobase)); - while ((inb(LSR(iobase)) & LSR_TSRE) == 0) - if (time_after(jiffies, timeout)) - return -1; - } - - return 0; -} - -/* - * predef should be 0 for loading user defined mcs - * predef should be YAM_1200 for loading predef 1200 mcs - * predef should be YAM_9600 for loading predef 9600 mcs - */ -static unsigned char *add_mcs(unsigned char *bits, int bitrate, - unsigned int predef) -{ - const char *fw_name[2] = {FIRMWARE_9600, FIRMWARE_1200}; - const struct firmware *fw; - struct platform_device *pdev; - struct yam_mcs *p; - int err; - - switch (predef) { - case 0: - fw = NULL; - break; - case YAM_1200: - case YAM_9600: - predef--; - pdev = platform_device_register_simple("yam", 0, NULL, 0); - if (IS_ERR(pdev)) { - printk(KERN_ERR "yam: Failed to register firmware\n"); - return NULL; - } - err = request_firmware(&fw, fw_name[predef], &pdev->dev); - platform_device_unregister(pdev); - if (err) { - printk(KERN_ERR "Failed to load firmware \"%s\"\n", - fw_name[predef]); - return NULL; - } - if (fw->size != YAM_FPGA_SIZE) { - printk(KERN_ERR "Bogus length %zu in firmware \"%s\"\n", - fw->size, fw_name[predef]); - release_firmware(fw); - return NULL; - } - bits = (unsigned char *)fw->data; - break; - default: - printk(KERN_ERR "yam: Invalid predef number %u\n", predef); - return NULL; - } - - /* If it already exists, replace the bit data */ - p = yam_data; - while (p) { - if (p->bitrate == bitrate) { - memcpy(p->bits, bits, YAM_FPGA_SIZE); - goto out; - } - p = p->next; - } - - /* Allocate a new mcs */ - if ((p = kmalloc_obj(struct yam_mcs)) == NULL) { - release_firmware(fw); - return NULL; - } - memcpy(p->bits, bits, YAM_FPGA_SIZE); - p->bitrate = bitrate; - p->next = yam_data; - yam_data = p; - out: - release_firmware(fw); - return p->bits; -} - -static unsigned char *get_mcs(int bitrate) -{ - struct yam_mcs *p; - - p = yam_data; - while (p) { - if (p->bitrate == bitrate) - return p->bits; - p = p->next; - } - - /* Load predefined mcs data */ - switch (bitrate) { - case 1200: - /* setting predef as YAM_1200 for loading predef 1200 mcs */ - return add_mcs(NULL, bitrate, YAM_1200); - default: - /* setting predef as YAM_9600 for loading predef 9600 mcs */ - return add_mcs(NULL, bitrate, YAM_9600); - } -} - -/* - * download bitstream to FPGA - * data is contained in bits[] array in yam1200.h resp. yam9600.h - */ - -static int fpga_download(int iobase, int bitrate) -{ - int i, rc; - unsigned char *pbits; - - pbits = get_mcs(bitrate); - if (pbits == NULL) - return -1; - - fpga_reset(iobase); - for (i = 0; i < YAM_FPGA_SIZE; i++) { - if (fpga_write(iobase, pbits[i])) { - printk(KERN_ERR "yam: error in write cycle\n"); - return -1; /* write... */ - } - } - - fpga_write(iobase, 0xFF); - rc = inb(MSR(iobase)); /* check DONE signal */ - - /* Needed for some hardwares */ - delay(50); - - return (rc & MSR_DSR) ? 0 : -1; -} - - -/************************************************************************ -* Serial port init -************************************************************************/ - -static void yam_set_uart(struct net_device *dev) -{ - struct yam_port *yp = netdev_priv(dev); - int divisor = 115200 / yp->baudrate; - - outb(0, IER(dev->base_addr)); - outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr)); - outb(divisor, DLL(dev->base_addr)); - outb(0, DLM(dev->base_addr)); - outb(LCR_BIT8, LCR(dev->base_addr)); - outb(PTT_OFF, MCR(dev->base_addr)); - outb(0x00, FCR(dev->base_addr)); - - /* Flush pending irq */ - - inb(RBR(dev->base_addr)); - inb(MSR(dev->base_addr)); - - /* Enable rx irq */ - - outb(ENABLE_RTXINT, IER(dev->base_addr)); -} - - -/* --------------------------------------------------------------------- */ - -enum uart { - c_uart_unknown, c_uart_8250, - c_uart_16450, c_uart_16550, c_uart_16550A -}; - -static const char *uart_str[] = -{"unknown", "8250", "16450", "16550", "16550A"}; - -static enum uart yam_check_uart(unsigned int iobase) -{ - unsigned char b1, b2, b3; - enum uart u; - enum uart uart_tab[] = - {c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A}; - - b1 = inb(MCR(iobase)); - outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ - b2 = inb(MSR(iobase)); - outb(0x1a, MCR(iobase)); - b3 = inb(MSR(iobase)) & 0xf0; - outb(b1, MCR(iobase)); /* restore old values */ - outb(b2, MSR(iobase)); - if (b3 != 0x90) - return c_uart_unknown; - inb(RBR(iobase)); - inb(RBR(iobase)); - outb(0x01, FCR(iobase)); /* enable FIFOs */ - u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; - if (u == c_uart_16450) { - outb(0x5a, SCR(iobase)); - b1 = inb(SCR(iobase)); - outb(0xa5, SCR(iobase)); - b2 = inb(SCR(iobase)); - if ((b1 != 0x5a) || (b2 != 0xa5)) - u = c_uart_8250; - } - return u; -} - -/****************************************************************************** -* Rx Section -******************************************************************************/ -static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp) -{ - if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) { - int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */ - struct sk_buff *skb; - - if ((yp->rx_crch & yp->rx_crcl) != 0xFF) { - /* Bad crc */ - } else { - if (!(skb = dev_alloc_skb(pkt_len))) { - printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name); - ++dev->stats.rx_dropped; - } else { - unsigned char *cp; - cp = skb_put(skb, pkt_len); - *cp++ = 0; /* KISS kludge */ - memcpy(cp, yp->rx_buf, pkt_len - 1); - skb->protocol = ax25_type_trans(skb, dev); - netif_rx(skb); - ++dev->stats.rx_packets; - } - } - } - yp->rx_len = 0; - yp->rx_crcl = 0x21; - yp->rx_crch = 0xf3; -} - -static inline void yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb) -{ - if (yp->rx_len < YAM_MAX_FRAME) { - unsigned char c = yp->rx_crcl; - yp->rx_crcl = (chktabl[c] ^ yp->rx_crch); - yp->rx_crch = (chktabh[c] ^ rxb); - yp->rx_buf[yp->rx_len++] = rxb; - } -} - -/******************************************************************************** -* TX Section -********************************************************************************/ - -static void ptt_on(struct net_device *dev) -{ - outb(PTT_ON, MCR(dev->base_addr)); -} - -static void ptt_off(struct net_device *dev) -{ - outb(PTT_OFF, MCR(dev->base_addr)); -} - -static netdev_tx_t yam_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct yam_port *yp = netdev_priv(dev); - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - skb_queue_tail(&yp->send_queue, skb); - netif_trans_update(dev); - return NETDEV_TX_OK; -} - -static void yam_start_tx(struct net_device *dev, struct yam_port *yp) -{ - if ((yp->tx_state == TX_TAIL) || (yp->txd == 0)) - yp->tx_count = 1; - else - yp->tx_count = (yp->bitrate * yp->txd) / 8000; - yp->tx_state = TX_HEAD; - ptt_on(dev); -} - -static void yam_arbitrate(struct net_device *dev) -{ - struct yam_port *yp = netdev_priv(dev); - - if (yp->magic != YAM_MAGIC || yp->tx_state != TX_OFF || - skb_queue_empty(&yp->send_queue)) - return; - /* tx_state is TX_OFF and there is data to send */ - - if (yp->dupmode) { - /* Full duplex mode, don't wait */ - yam_start_tx(dev, yp); - return; - } - if (yp->dcd) { - /* DCD on, wait slotime ... */ - yp->slotcnt = yp->slot / 10; - return; - } - /* Is slottime passed ? */ - if ((--yp->slotcnt) > 0) - return; - - yp->slotcnt = yp->slot / 10; - - /* is random > persist ? */ - if (get_random_u8() > yp->pers) - return; - - yam_start_tx(dev, yp); -} - -static void yam_dotimer(struct timer_list *unused) -{ - int i; - - for (i = 0; i < NR_PORTS; i++) { - struct net_device *dev = yam_devs[i]; - if (dev && netif_running(dev)) - yam_arbitrate(dev); - } - yam_timer.expires = jiffies + HZ / 100; - add_timer(&yam_timer); -} - -static void yam_tx_byte(struct net_device *dev, struct yam_port *yp) -{ - struct sk_buff *skb; - unsigned char b, temp; - - switch (yp->tx_state) { - case TX_OFF: - break; - case TX_HEAD: - if (--yp->tx_count <= 0) { - if (!(skb = skb_dequeue(&yp->send_queue))) { - ptt_off(dev); - yp->tx_state = TX_OFF; - break; - } - yp->tx_state = TX_DATA; - if (skb->data[0] != 0) { -/* do_kiss_params(s, skb->data, skb->len); */ - dev_kfree_skb_any(skb); - break; - } - yp->tx_len = skb->len - 1; /* strip KISS byte */ - if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) { - dev_kfree_skb_any(skb); - break; - } - skb_copy_from_linear_data_offset(skb, 1, - yp->tx_buf, - yp->tx_len); - dev_kfree_skb_any(skb); - yp->tx_count = 0; - yp->tx_crcl = 0x21; - yp->tx_crch = 0xf3; - yp->tx_state = TX_DATA; - } - break; - case TX_DATA: - b = yp->tx_buf[yp->tx_count++]; - outb(b, THR(dev->base_addr)); - temp = yp->tx_crcl; - yp->tx_crcl = chktabl[temp] ^ yp->tx_crch; - yp->tx_crch = chktabh[temp] ^ b; - if (yp->tx_count >= yp->tx_len) { - yp->tx_state = TX_CRC1; - } - break; - case TX_CRC1: - yp->tx_crch = chktabl[yp->tx_crcl] ^ yp->tx_crch; - yp->tx_crcl = chktabh[yp->tx_crcl] ^ chktabl[yp->tx_crch] ^ 0xff; - outb(yp->tx_crcl, THR(dev->base_addr)); - yp->tx_state = TX_CRC2; - break; - case TX_CRC2: - outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr)); - if (skb_queue_empty(&yp->send_queue)) { - yp->tx_count = (yp->bitrate * yp->txtail) / 8000; - if (yp->dupmode == 2) - yp->tx_count += (yp->bitrate * yp->holdd) / 8; - if (yp->tx_count == 0) - yp->tx_count = 1; - yp->tx_state = TX_TAIL; - } else { - yp->tx_count = 1; - yp->tx_state = TX_HEAD; - } - ++dev->stats.tx_packets; - break; - case TX_TAIL: - if (--yp->tx_count <= 0) { - yp->tx_state = TX_OFF; - ptt_off(dev); - } - break; - } -} - -/*********************************************************************************** -* ISR routine -************************************************************************************/ - -static irqreturn_t yam_interrupt(int irq, void *dev_id) -{ - struct net_device *dev; - struct yam_port *yp; - unsigned char iir; - int counter = 100; - int i; - int handled = 0; - - for (i = 0; i < NR_PORTS; i++) { - dev = yam_devs[i]; - yp = netdev_priv(dev); - - if (!netif_running(dev)) - continue; - - while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) { - unsigned char msr = inb(MSR(dev->base_addr)); - unsigned char lsr = inb(LSR(dev->base_addr)); - unsigned char rxb; - - handled = 1; - - if (lsr & LSR_OE) - ++dev->stats.rx_fifo_errors; - - yp->dcd = (msr & RX_DCD) ? 1 : 0; - - if (--counter <= 0) { - printk(KERN_ERR "%s: too many irq iir=%d\n", - dev->name, iir); - goto out; - } - if (msr & TX_RDY) { - ++yp->nb_mdint; - yam_tx_byte(dev, yp); - } - if (lsr & LSR_RXC) { - ++yp->nb_rxint; - rxb = inb(RBR(dev->base_addr)); - if (msr & RX_FLAG) - yam_rx_flag(dev, yp); - else - yam_rx_byte(dev, yp, rxb); - } - } - } -out: - return IRQ_RETVAL(handled); -} - -#ifdef CONFIG_PROC_FS - -static void *yam_seq_start(struct seq_file *seq, loff_t *pos) -{ - return (*pos < NR_PORTS) ? yam_devs[*pos] : NULL; -} - -static void *yam_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return (*pos < NR_PORTS) ? yam_devs[*pos] : NULL; -} - -static void yam_seq_stop(struct seq_file *seq, void *v) -{ -} - -static int yam_seq_show(struct seq_file *seq, void *v) -{ - struct net_device *dev = v; - const struct yam_port *yp = netdev_priv(dev); - - seq_printf(seq, "Device %s\n", dev->name); - seq_printf(seq, " Up %d\n", netif_running(dev)); - seq_printf(seq, " Speed %u\n", yp->bitrate); - seq_printf(seq, " IoBase 0x%x\n", yp->iobase); - seq_printf(seq, " BaudRate %u\n", yp->baudrate); - seq_printf(seq, " IRQ %u\n", yp->irq); - seq_printf(seq, " TxState %u\n", yp->tx_state); - seq_printf(seq, " Duplex %u\n", yp->dupmode); - seq_printf(seq, " HoldDly %u\n", yp->holdd); - seq_printf(seq, " TxDelay %u\n", yp->txd); - seq_printf(seq, " TxTail %u\n", yp->txtail); - seq_printf(seq, " SlotTime %u\n", yp->slot); - seq_printf(seq, " Persist %u\n", yp->pers); - seq_printf(seq, " TxFrames %lu\n", dev->stats.tx_packets); - seq_printf(seq, " RxFrames %lu\n", dev->stats.rx_packets); - seq_printf(seq, " TxInt %u\n", yp->nb_mdint); - seq_printf(seq, " RxInt %u\n", yp->nb_rxint); - seq_printf(seq, " RxOver %lu\n", dev->stats.rx_fifo_errors); - seq_printf(seq, "\n"); - return 0; -} - -static const struct seq_operations yam_seqops = { - .start = yam_seq_start, - .next = yam_seq_next, - .stop = yam_seq_stop, - .show = yam_seq_show, -}; -#endif - - -/* --------------------------------------------------------------------- */ - -static int yam_open(struct net_device *dev) -{ - struct yam_port *yp = netdev_priv(dev); - enum uart u; - int i; - int ret=0; - - printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq); - - if (!yp->bitrate) - return -ENXIO; - if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT || - dev->irq < 2 || dev->irq > 15) { - return -ENXIO; - } - if (!request_region(dev->base_addr, YAM_EXTENT, dev->name)) - { - printk(KERN_ERR "%s: cannot 0x%lx busy\n", dev->name, dev->base_addr); - return -EACCES; - } - if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) { - printk(KERN_ERR "%s: cannot find uart type\n", dev->name); - ret = -EIO; - goto out_release_base; - } - if (fpga_download(dev->base_addr, yp->bitrate)) { - printk(KERN_ERR "%s: cannot init FPGA\n", dev->name); - ret = -EIO; - goto out_release_base; - } - outb(0, IER(dev->base_addr)); - if (request_irq(dev->irq, yam_interrupt, IRQF_SHARED, dev->name, dev)) { - printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq); - ret = -EBUSY; - goto out_release_base; - } - - yam_set_uart(dev); - - netif_start_queue(dev); - - yp->slotcnt = yp->slot / 10; - - /* Reset overruns for all ports - FPGA programming makes overruns */ - for (i = 0; i < NR_PORTS; i++) { - struct net_device *yam_dev = yam_devs[i]; - - inb(LSR(yam_dev->base_addr)); - yam_dev->stats.rx_fifo_errors = 0; - } - - printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq, - uart_str[u]); - return 0; - -out_release_base: - release_region(dev->base_addr, YAM_EXTENT); - return ret; -} - -/* --------------------------------------------------------------------- */ - -static int yam_close(struct net_device *dev) -{ - struct sk_buff *skb; - struct yam_port *yp = netdev_priv(dev); - - if (!dev) - return -EINVAL; - - /* - * disable interrupts - */ - outb(0, IER(dev->base_addr)); - outb(1, MCR(dev->base_addr)); - /* Remove IRQ handler if last */ - free_irq(dev->irq,dev); - release_region(dev->base_addr, YAM_EXTENT); - netif_stop_queue(dev); - while ((skb = skb_dequeue(&yp->send_queue))) - dev_kfree_skb(skb); - - printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n", - yam_drvname, dev->base_addr, dev->irq); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int yam_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void __user *data, int cmd) -{ - struct yam_port *yp = netdev_priv(dev); - struct yamdrv_ioctl_cfg yi; - struct yamdrv_ioctl_mcs *ym; - int ioctl_cmd; - - if (copy_from_user(&ioctl_cmd, data, sizeof(int))) - return -EFAULT; - - if (yp->magic != YAM_MAGIC) - return -EINVAL; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (cmd != SIOCDEVPRIVATE) - return -EINVAL; - - switch (ioctl_cmd) { - - case SIOCYAMRESERVED: - return -EINVAL; /* unused */ - - case SIOCYAMSMCS: - if (netif_running(dev)) - return -EINVAL; /* Cannot change this parameter when up */ - ym = memdup_user(data, sizeof(struct yamdrv_ioctl_mcs)); - if (IS_ERR(ym)) - return PTR_ERR(ym); - if (ym->cmd != SIOCYAMSMCS || ym->bitrate > YAM_MAXBITRATE) { - kfree(ym); - return -EINVAL; - } - /* setting predef as 0 for loading userdefined mcs data */ - add_mcs(ym->bits, ym->bitrate, 0); - kfree(ym); - break; - - case SIOCYAMSCFG: - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - if (copy_from_user(&yi, data, sizeof(struct yamdrv_ioctl_cfg))) - return -EFAULT; - - if (yi.cmd != SIOCYAMSCFG) - return -EINVAL; - if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev)) - return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev)) - return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev)) - return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev)) - return -EINVAL; /* Cannot change this parameter when up */ - - if (yi.cfg.mask & YAM_IOBASE) { - yp->iobase = yi.cfg.iobase; - dev->base_addr = yi.cfg.iobase; - } - if (yi.cfg.mask & YAM_IRQ) { - if (yi.cfg.irq > 15) - return -EINVAL; - yp->irq = yi.cfg.irq; - dev->irq = yi.cfg.irq; - } - if (yi.cfg.mask & YAM_BITRATE) { - if (yi.cfg.bitrate > YAM_MAXBITRATE) - return -EINVAL; - yp->bitrate = yi.cfg.bitrate; - } - if (yi.cfg.mask & YAM_BAUDRATE) { - if (yi.cfg.baudrate > YAM_MAXBAUDRATE) - return -EINVAL; - yp->baudrate = yi.cfg.baudrate; - } - if (yi.cfg.mask & YAM_MODE) { - if (yi.cfg.mode > YAM_MAXMODE) - return -EINVAL; - yp->dupmode = yi.cfg.mode; - } - if (yi.cfg.mask & YAM_HOLDDLY) { - if (yi.cfg.holddly > YAM_MAXHOLDDLY) - return -EINVAL; - yp->holdd = yi.cfg.holddly; - } - if (yi.cfg.mask & YAM_TXDELAY) { - if (yi.cfg.txdelay > YAM_MAXTXDELAY) - return -EINVAL; - yp->txd = yi.cfg.txdelay; - } - if (yi.cfg.mask & YAM_TXTAIL) { - if (yi.cfg.txtail > YAM_MAXTXTAIL) - return -EINVAL; - yp->txtail = yi.cfg.txtail; - } - if (yi.cfg.mask & YAM_PERSIST) { - if (yi.cfg.persist > YAM_MAXPERSIST) - return -EINVAL; - yp->pers = yi.cfg.persist; - } - if (yi.cfg.mask & YAM_SLOTTIME) { - if (yi.cfg.slottime > YAM_MAXSLOTTIME) - return -EINVAL; - yp->slot = yi.cfg.slottime; - yp->slotcnt = yp->slot / 10; - } - break; - - case SIOCYAMGCFG: - memset(&yi, 0, sizeof(yi)); - yi.cfg.mask = 0xffffffff; - yi.cfg.iobase = yp->iobase; - yi.cfg.irq = yp->irq; - yi.cfg.bitrate = yp->bitrate; - yi.cfg.baudrate = yp->baudrate; - yi.cfg.mode = yp->dupmode; - yi.cfg.txdelay = yp->txd; - yi.cfg.holddly = yp->holdd; - yi.cfg.txtail = yp->txtail; - yi.cfg.persist = yp->pers; - yi.cfg.slottime = yp->slot; - if (copy_to_user(data, &yi, sizeof(struct yamdrv_ioctl_cfg))) - return -EFAULT; - break; - - default: - return -EINVAL; - - } - - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int yam_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = (struct sockaddr *) addr; - - /* addr is an AX.25 shifted ASCII mac address */ - dev_addr_set(dev, sa->sa_data); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static const struct net_device_ops yam_netdev_ops = { - .ndo_open = yam_open, - .ndo_stop = yam_close, - .ndo_start_xmit = yam_send_packet, - .ndo_siocdevprivate = yam_siocdevprivate, - .ndo_set_mac_address = yam_set_mac_address, -}; - -static void yam_setup(struct net_device *dev) -{ - struct yam_port *yp = netdev_priv(dev); - - yp->magic = YAM_MAGIC; - yp->bitrate = DEFAULT_BITRATE; - yp->baudrate = DEFAULT_BITRATE * 2; - yp->iobase = 0; - yp->irq = 0; - yp->dupmode = 0; - yp->holdd = DEFAULT_HOLDD; - yp->txd = DEFAULT_TXD; - yp->txtail = DEFAULT_TXTAIL; - yp->slot = DEFAULT_SLOT; - yp->pers = DEFAULT_PERS; - yp->dev = dev; - - dev->base_addr = yp->iobase; - dev->irq = yp->irq; - - skb_queue_head_init(&yp->send_queue); - - dev->netdev_ops = &yam_netdev_ops; - dev->header_ops = &ax25_header_ops; - - dev->type = ARPHRD_AX25; - dev->hard_header_len = AX25_MAX_HEADER_LEN; - dev->mtu = AX25_MTU; - dev->addr_len = AX25_ADDR_LEN; - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&ax25_defaddr); -} - -static int __init yam_init_driver(void) -{ - struct net_device *dev; - int i, err; - char name[IFNAMSIZ]; - - printk(yam_drvinfo); - - for (i = 0; i < NR_PORTS; i++) { - sprintf(name, "yam%d", i); - - dev = alloc_netdev(sizeof(struct yam_port), name, - NET_NAME_UNKNOWN, yam_setup); - if (!dev) { - pr_err("yam: cannot allocate net device\n"); - err = -ENOMEM; - goto error; - } - - err = register_netdev(dev); - if (err) { - printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name); - free_netdev(dev); - goto error; - } - yam_devs[i] = dev; - - } - - timer_setup(&yam_timer, yam_dotimer, 0); - yam_timer.expires = jiffies + HZ / 100; - add_timer(&yam_timer); - - proc_create_seq("yam", 0444, init_net.proc_net, &yam_seqops); - return 0; - error: - while (--i >= 0) { - unregister_netdev(yam_devs[i]); - free_netdev(yam_devs[i]); - } - return err; -} - -/* --------------------------------------------------------------------- */ - -static void __exit yam_cleanup_driver(void) -{ - struct yam_mcs *p; - int i; - - timer_delete_sync(&yam_timer); - for (i = 0; i < NR_PORTS; i++) { - struct net_device *dev = yam_devs[i]; - if (dev) { - unregister_netdev(dev); - free_netdev(dev); - } - } - - while (yam_data) { - p = yam_data; - yam_data = yam_data->next; - kfree(p); - } - - remove_proc_entry("yam", init_net.proc_net); -} - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr"); -MODULE_DESCRIPTION("Yam amateur radio modem driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FIRMWARE_1200); -MODULE_FIRMWARE(FIRMWARE_9600); - -module_init(yam_init_driver); -module_exit(yam_cleanup_driver); - -/* --------------------------------------------------------------------- */ - diff --git a/drivers/net/hamradio/z8530.h b/drivers/net/hamradio/z8530.h deleted file mode 100644 index 1655901d713b..000000000000 --- a/drivers/net/hamradio/z8530.h +++ /dev/null @@ -1,246 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* 8530 Serial Communications Controller Register definitions */ -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ - -/* Write Register 4 */ - -#define PAR_ENA 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENABL 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define ZCIE 2 /* Zero count IE */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define CRC_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - -/* Z85C30/Z85230 Enhanced SCC register definitions */ - -/* Write Register 7' (SDLC/HDLC Programmable Enhancements) */ -#define AUTOTXF 0x01 /* Auto Tx Flag */ -#define AUTOEOM 0x02 /* Auto EOM Latch Reset */ -#define AUTORTS 0x04 /* Auto RTS */ -#define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */ -#define RXFIFOH 0x08 /* Z85230: Int on RX FIFO half full */ -#define FASTDTR 0x10 /* Fast DTR/REQ Mode */ -#define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */ -#define TXFIFOE 0x20 /* Z85230: Int on TX FIFO completely empty */ -#define EXTRDEN 0x40 /* Extended Read Enabled */ - -/* Write Register 15 (external/status interrupt control) */ -#define SHDLCE 1 /* SDLC/HDLC Enhancements Enable */ -#define FIFOE 4 /* FIFO Enable */ - -/* Read Register 6 (frame status FIFO) */ -#define BCLSB 0xff /* LSB of 14 bits count */ - -/* Read Register 7 (frame status FIFO) */ -#define BCMSB 0x3f /* MSB of 14 bits count */ -#define FDA 0x40 /* FIFO Data Available Status */ -#define FOS 0x80 /* FIFO Overflow Status */ diff --git a/include/linux/hdlcdrv.h b/include/linux/hdlcdrv.h deleted file mode 100644 index 5d70c3f98f5b..000000000000 --- a/include/linux/hdlcdrv.h +++ /dev/null @@ -1,276 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * hdlcdrv.h -- HDLC packet radio network driver. - * The Linux soundcard driver for 1200 baud and 9600 baud packet radio - * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA - */ -#ifndef _HDLCDRV_H -#define _HDLCDRV_H - - -#include -#include -#include -#include - -#define HDLCDRV_MAGIC 0x5ac6e778 -#define HDLCDRV_HDLCBUFFER 32 /* should be a power of 2 for speed reasons */ -#define HDLCDRV_BITBUFFER 256 /* should be a power of 2 for speed reasons */ -#undef HDLCDRV_LOOPBACK /* define for HDLC debugging purposes */ -#define HDLCDRV_DEBUG - -/* maximum packet length, excluding CRC */ -#define HDLCDRV_MAXFLEN 400 - - -struct hdlcdrv_hdlcbuffer { - spinlock_t lock; - unsigned rd, wr; - unsigned short buf[HDLCDRV_HDLCBUFFER]; -}; - -#ifdef HDLCDRV_DEBUG -struct hdlcdrv_bitbuffer { - unsigned int rd; - unsigned int wr; - unsigned int shreg; - unsigned char buffer[HDLCDRV_BITBUFFER]; -}; - -static inline void hdlcdrv_add_bitbuffer(struct hdlcdrv_bitbuffer *buf, - unsigned int bit) -{ - unsigned char new; - - new = buf->shreg & 1; - buf->shreg >>= 1; - buf->shreg |= (!!bit) << 7; - if (new) { - buf->buffer[buf->wr] = buf->shreg; - buf->wr = (buf->wr+1) % sizeof(buf->buffer); - buf->shreg = 0x80; - } -} - -static inline void hdlcdrv_add_bitbuffer_word(struct hdlcdrv_bitbuffer *buf, - unsigned int bits) -{ - buf->buffer[buf->wr] = bits & 0xff; - buf->wr = (buf->wr+1) % sizeof(buf->buffer); - buf->buffer[buf->wr] = (bits >> 8) & 0xff; - buf->wr = (buf->wr+1) % sizeof(buf->buffer); - -} -#endif /* HDLCDRV_DEBUG */ - -/* -------------------------------------------------------------------- */ -/* - * Information that need to be kept for each driver. - */ - -struct hdlcdrv_ops { - /* - * first some informations needed by the hdlcdrv routines - */ - const char *drvname; - const char *drvinfo; - /* - * the routines called by the hdlcdrv routines - */ - int (*open)(struct net_device *); - int (*close)(struct net_device *); - int (*ioctl)(struct net_device *, void __user *, - struct hdlcdrv_ioctl *, int); -}; - -struct hdlcdrv_state { - int magic; - int opened; - - const struct hdlcdrv_ops *ops; - - struct { - int bitrate; - } par; - - struct hdlcdrv_pttoutput { - int dma2; - int seriobase; - int pariobase; - int midiiobase; - unsigned int flags; - } ptt_out; - - struct hdlcdrv_channel_params ch_params; - - struct hdlcdrv_hdlcrx { - struct hdlcdrv_hdlcbuffer hbuf; - unsigned long in_hdlc_rx; - /* 0 = sync hunt, != 0 receiving */ - int rx_state; - unsigned int bitstream; - unsigned int bitbuf; - int numbits; - unsigned char dcd; - - int len; - unsigned char *bp; - unsigned char buffer[HDLCDRV_MAXFLEN+2]; - } hdlcrx; - - struct hdlcdrv_hdlctx { - struct hdlcdrv_hdlcbuffer hbuf; - unsigned long in_hdlc_tx; - /* - * 0 = send flags - * 1 = send txtail (flags) - * 2 = send packet - */ - int tx_state; - int numflags; - unsigned int bitstream; - unsigned char ptt; - int calibrate; - int slotcnt; - - unsigned int bitbuf; - int numbits; - - int len; - unsigned char *bp; - unsigned char buffer[HDLCDRV_MAXFLEN+2]; - } hdlctx; - -#ifdef HDLCDRV_DEBUG - struct hdlcdrv_bitbuffer bitbuf_channel; - struct hdlcdrv_bitbuffer bitbuf_hdlc; -#endif /* HDLCDRV_DEBUG */ - - int ptt_keyed; - - /* queued skb for transmission */ - struct sk_buff *skb; -}; - - -/* -------------------------------------------------------------------- */ - -static inline int hdlcdrv_hbuf_full(struct hdlcdrv_hdlcbuffer *hb) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&hb->lock, flags); - ret = !((HDLCDRV_HDLCBUFFER - 1 + hb->rd - hb->wr) % HDLCDRV_HDLCBUFFER); - spin_unlock_irqrestore(&hb->lock, flags); - return ret; -} - -/* -------------------------------------------------------------------- */ - -static inline int hdlcdrv_hbuf_empty(struct hdlcdrv_hdlcbuffer *hb) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&hb->lock, flags); - ret = (hb->rd == hb->wr); - spin_unlock_irqrestore(&hb->lock, flags); - return ret; -} - -/* -------------------------------------------------------------------- */ - -static inline unsigned short hdlcdrv_hbuf_get(struct hdlcdrv_hdlcbuffer *hb) -{ - unsigned long flags; - unsigned short val; - unsigned newr; - - spin_lock_irqsave(&hb->lock, flags); - if (hb->rd == hb->wr) - val = 0; - else { - newr = (hb->rd+1) % HDLCDRV_HDLCBUFFER; - val = hb->buf[hb->rd]; - hb->rd = newr; - } - spin_unlock_irqrestore(&hb->lock, flags); - return val; -} - -/* -------------------------------------------------------------------- */ - -static inline void hdlcdrv_hbuf_put(struct hdlcdrv_hdlcbuffer *hb, - unsigned short val) -{ - unsigned newp; - unsigned long flags; - - spin_lock_irqsave(&hb->lock, flags); - newp = (hb->wr+1) % HDLCDRV_HDLCBUFFER; - if (newp != hb->rd) { - hb->buf[hb->wr] = val & 0xffff; - hb->wr = newp; - } - spin_unlock_irqrestore(&hb->lock, flags); -} - -/* -------------------------------------------------------------------- */ - -static inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits) -{ - hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, bits); -} - -static inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s) -{ - unsigned int ret; - - if (hdlcdrv_hbuf_empty(&s->hdlctx.hbuf)) { - if (s->hdlctx.calibrate > 0) - s->hdlctx.calibrate--; - else - s->hdlctx.ptt = 0; - ret = 0; - } else - ret = hdlcdrv_hbuf_get(&s->hdlctx.hbuf); -#ifdef HDLCDRV_LOOPBACK - hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, ret); -#endif /* HDLCDRV_LOOPBACK */ - return ret; -} - -static inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit) -{ -#ifdef HDLCDRV_DEBUG - hdlcdrv_add_bitbuffer(&s->bitbuf_channel, bit); -#endif /* HDLCDRV_DEBUG */ -} - -static inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd) -{ - s->hdlcrx.dcd = !!dcd; -} - -static inline int hdlcdrv_ptt(struct hdlcdrv_state *s) -{ - return s->hdlctx.ptt || (s->hdlctx.calibrate > 0); -} - -/* -------------------------------------------------------------------- */ - -void hdlcdrv_receiver(struct net_device *, struct hdlcdrv_state *); -void hdlcdrv_transmitter(struct net_device *, struct hdlcdrv_state *); -void hdlcdrv_arbitrate(struct net_device *, struct hdlcdrv_state *); -struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops, - unsigned int privsize, const char *ifname, - unsigned int baseaddr, unsigned int irq, - unsigned int dma); -void hdlcdrv_unregister(struct net_device *dev); - -/* -------------------------------------------------------------------- */ - - - -#endif /* _HDLCDRV_H */ diff --git a/include/linux/isdn/capilli.h b/include/linux/isdn/capilli.h deleted file mode 100644 index 12be09b6883b..000000000000 --- a/include/linux/isdn/capilli.h +++ /dev/null @@ -1,95 +0,0 @@ -/* $Id: capilli.h,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ - * - * Kernel CAPI 2.0 Driver Interface for Linux - * - * Copyright 1999 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __CAPILLI_H__ -#define __CAPILLI_H__ - -#include -#include -#include -#include - -typedef struct capiloaddatapart { - int user; /* data in userspace ? */ - int len; - unsigned char *data; -} capiloaddatapart; - -typedef struct capiloaddata { - capiloaddatapart firmware; - capiloaddatapart configuration; -} capiloaddata; - -typedef struct capicardparams { - unsigned int port; - unsigned irq; - int cardtype; - int cardnr; - unsigned int membase; -} capicardparams; - -struct capi_ctr { - /* filled in before calling attach_capi_ctr */ - struct module *owner; - void *driverdata; /* driver specific */ - char name[32]; /* name of controller */ - char *driver_name; /* name of driver */ - int (*load_firmware)(struct capi_ctr *, capiloaddata *); - void (*reset_ctr)(struct capi_ctr *); - void (*register_appl)(struct capi_ctr *, u16 appl, - capi_register_params *); - void (*release_appl)(struct capi_ctr *, u16 appl); - u16 (*send_message)(struct capi_ctr *, struct sk_buff *skb); - - char *(*procinfo)(struct capi_ctr *); - int (*proc_show)(struct seq_file *, void *); - - /* filled in before calling ready callback */ - u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */ - capi_version version; /* CAPI_GET_VERSION */ - capi_profile profile; /* CAPI_GET_PROFILE */ - u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */ - - /* management information for kcapi */ - - unsigned long nrecvctlpkt; - unsigned long nrecvdatapkt; - unsigned long nsentctlpkt; - unsigned long nsentdatapkt; - - int cnr; /* controller number */ - unsigned short state; /* controller state */ - int blocked; /* output blocked */ - int traceflag; /* capi trace */ - - struct proc_dir_entry *procent; - char procfn[128]; -}; - -int attach_capi_ctr(struct capi_ctr *); -int detach_capi_ctr(struct capi_ctr *); - -void capi_ctr_ready(struct capi_ctr * card); -void capi_ctr_down(struct capi_ctr * card); -void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb); - -// --------------------------------------------------------------------------- -// needed for AVM capi drivers - -struct capi_driver { - char name[32]; /* driver name */ - char revision[32]; - - /* management information for kcapi */ - struct list_head list; -}; - -#endif /* __CAPILLI_H__ */ diff --git a/include/linux/isdn/capiutil.h b/include/linux/isdn/capiutil.h deleted file mode 100644 index 953fd500dff7..000000000000 --- a/include/linux/isdn/capiutil.h +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id: capiutil.h,v 1.5.6.2 2001/09/23 22:24:33 kai Exp $ - * - * CAPI 2.0 defines & types - * - * From CAPI 2.0 Development Kit AVM 1995 (msg.c) - * Rewritten for Linux 1996 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __CAPIUTIL_H__ -#define __CAPIUTIL_H__ - -#include - -#define CAPIMSG_BASELEN 8 -#define CAPIMSG_U8(m, off) (m[off]) -#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8)) -#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24)) -#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0) -#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2) -#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4) -#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5) -#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5])) -#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6) -#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f) -#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8) -#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m) -#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */ - -static inline void capimsg_setu8(void *m, int off, __u8 val) -{ - ((__u8 *)m)[off] = val; -} - -static inline void capimsg_setu16(void *m, int off, __u16 val) -{ - ((__u8 *)m)[off] = val & 0xff; - ((__u8 *)m)[off+1] = (val >> 8) & 0xff; -} - -static inline void capimsg_setu32(void *m, int off, __u32 val) -{ - ((__u8 *)m)[off] = val & 0xff; - ((__u8 *)m)[off+1] = (val >> 8) & 0xff; - ((__u8 *)m)[off+2] = (val >> 16) & 0xff; - ((__u8 *)m)[off+3] = (val >> 24) & 0xff; -} - -#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len) -#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid) -#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd) -#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd) -#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid) -#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr) -#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len) - -#endif /* __CAPIUTIL_H__ */ diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h deleted file mode 100644 index 94ba42bf9da1..000000000000 --- a/include/linux/kernelcapi.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $ - * - * Kernel CAPI 2.0 Interface for Linux - * - * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - */ -#ifndef __KERNELCAPI_H__ -#define __KERNELCAPI_H__ - -#include -#include -#include -#include -#include - -#define CAPI_NOERROR 0x0000 - -#define CAPI_TOOMANYAPPLS 0x1001 -#define CAPI_LOGBLKSIZETOSMALL 0x1002 -#define CAPI_BUFFEXECEEDS64K 0x1003 -#define CAPI_MSGBUFSIZETOOSMALL 0x1004 -#define CAPI_ANZLOGCONNNOTSUPPORTED 0x1005 -#define CAPI_REGRESERVED 0x1006 -#define CAPI_REGBUSY 0x1007 -#define CAPI_REGOSRESOURCEERR 0x1008 -#define CAPI_REGNOTINSTALLED 0x1009 -#define CAPI_REGCTRLERNOTSUPPORTEXTEQUIP 0x100a -#define CAPI_REGCTRLERONLYSUPPORTEXTEQUIP 0x100b - -#define CAPI_ILLAPPNR 0x1101 -#define CAPI_ILLCMDORSUBCMDORMSGTOSMALL 0x1102 -#define CAPI_SENDQUEUEFULL 0x1103 -#define CAPI_RECEIVEQUEUEEMPTY 0x1104 -#define CAPI_RECEIVEOVERFLOW 0x1105 -#define CAPI_UNKNOWNNOTPAR 0x1106 -#define CAPI_MSGBUSY 0x1107 -#define CAPI_MSGOSRESOURCEERR 0x1108 -#define CAPI_MSGNOTINSTALLED 0x1109 -#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a -#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b - -#endif /* __KERNELCAPI_H__ */ diff --git a/include/linux/mISDNdsp.h b/include/linux/mISDNdsp.h deleted file mode 100644 index 00758f45fddc..000000000000 --- a/include/linux/mISDNdsp.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __mISDNdsp_H__ -#define __mISDNdsp_H__ - -struct mISDN_dsp_element_arg { - char *name; - char *def; - char *desc; -}; - -struct mISDN_dsp_element { - char *name; - void *(*new)(const char *arg); - void (*free)(void *p); - void (*process_tx)(void *p, unsigned char *data, int len); - void (*process_rx)(void *p, unsigned char *data, int len, - unsigned int txlen); - int num_args; - struct mISDN_dsp_element_arg - *args; -}; - -extern int mISDN_dsp_element_register(struct mISDN_dsp_element *elem); -extern void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem); - -struct dsp_features { - int hfc_id; /* unique id to identify the chip (or -1) */ - int hfc_dtmf; /* set if HFCmulti card supports dtmf */ - int hfc_conf; /* set if HFCmulti card supports conferences */ - int hfc_loops; /* set if card supports tone loops */ - int hfc_echocanhw; /* set if card supports echocancelation*/ - int pcm_id; /* unique id to identify the pcm bus (or -1) */ - int pcm_slots; /* number of slots on the pcm bus */ - int pcm_banks; /* number of IO banks of pcm bus */ - int unclocked; /* data is not clocked (has jitter/loss) */ - int unordered; /* data is unordered (packets have index) */ -}; - -#endif - diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h deleted file mode 100644 index ef4f8eb02eac..000000000000 --- a/include/linux/mISDNhw.h +++ /dev/null @@ -1,192 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * - * Author Karsten Keil - * - * Basic declarations for the mISDN HW channels - * - * Copyright 2008 by Karsten Keil - */ - -#ifndef MISDNHW_H -#define MISDNHW_H -#include -#include - -/* - * HW DEBUG 0xHHHHGGGG - * H - hardware driver specific bits - * G - for all drivers - */ - -#define DEBUG_HW 0x00000001 -#define DEBUG_HW_OPEN 0x00000002 -#define DEBUG_HW_DCHANNEL 0x00000100 -#define DEBUG_HW_DFIFO 0x00000200 -#define DEBUG_HW_BCHANNEL 0x00001000 -#define DEBUG_HW_BFIFO 0x00002000 - -#define MAX_DFRAME_LEN_L1 300 -#define MAX_MON_FRAME 32 -#define MAX_LOG_SPACE 2048 -#define MISDN_COPY_SIZE 32 - -/* channel->Flags bit field */ -#define FLG_TX_BUSY 0 /* tx_buf in use */ -#define FLG_TX_NEXT 1 /* next_skb in use */ -#define FLG_L1_BUSY 2 /* L1 is permanent busy */ -#define FLG_L2_ACTIVATED 3 /* activated from L2 */ -#define FLG_OPEN 5 /* channel is in use */ -#define FLG_ACTIVE 6 /* channel is activated */ -#define FLG_BUSY_TIMER 7 -/* channel type */ -#define FLG_DCHANNEL 8 /* channel is D-channel */ -#define FLG_BCHANNEL 9 /* channel is B-channel */ -#define FLG_ECHANNEL 10 /* channel is E-channel */ -#define FLG_TRANSPARENT 12 /* channel use transparent data */ -#define FLG_HDLC 13 /* channel use hdlc data */ -#define FLG_L2DATA 14 /* channel use L2 DATA primitivs */ -#define FLG_ORIGIN 15 /* channel is on origin site */ -/* channel specific stuff */ -#define FLG_FILLEMPTY 16 /* fill fifo on first frame (empty) */ -/* arcofi specific */ -#define FLG_ARCOFI_TIMER 17 -#define FLG_ARCOFI_ERROR 18 -/* isar specific */ -#define FLG_INITIALIZED 17 -#define FLG_DLEETX 18 -#define FLG_LASTDLE 19 -#define FLG_FIRST 20 -#define FLG_LASTDATA 21 -#define FLG_NMD_DATA 22 -#define FLG_FTI_RUN 23 -#define FLG_LL_OK 24 -#define FLG_LL_CONN 25 -#define FLG_DTMFSEND 26 -#define FLG_TX_EMPTY 27 -/* stop sending received data upstream */ -#define FLG_RX_OFF 28 -/* workq events */ -#define FLG_RECVQUEUE 30 -#define FLG_PHCHANGE 31 - -#define schedule_event(s, ev) do { \ - test_and_set_bit(ev, &((s)->Flags)); \ - schedule_work(&((s)->workq)); \ - } while (0) - -struct dchannel { - struct mISDNdevice dev; - u_long Flags; - struct work_struct workq; - void (*phfunc) (struct dchannel *); - u_int state; - void *l1; - void *hw; - int slot; /* multiport card channel slot */ - struct timer_list timer; - /* receive data */ - struct sk_buff *rx_skb; - int maxlen; - /* send data */ - struct sk_buff_head squeue; - struct sk_buff_head rqueue; - struct sk_buff *tx_skb; - int tx_idx; - int debug; - /* statistics */ - int err_crc; - int err_tx; - int err_rx; -}; - -typedef int (dchannel_l1callback)(struct dchannel *, u_int); -extern int create_l1(struct dchannel *, dchannel_l1callback *); - -/* private L1 commands */ -#define INFO0 0x8002 -#define INFO1 0x8102 -#define INFO2 0x8202 -#define INFO3_P8 0x8302 -#define INFO3_P10 0x8402 -#define INFO4_P8 0x8502 -#define INFO4_P10 0x8602 -#define LOSTFRAMING 0x8702 -#define ANYSIGNAL 0x8802 -#define HW_POWERDOWN 0x8902 -#define HW_RESET_REQ 0x8a02 -#define HW_POWERUP_REQ 0x8b02 -#define HW_DEACT_REQ 0x8c02 -#define HW_ACTIVATE_REQ 0x8e02 -#define HW_D_NOBLOCKED 0x8f02 -#define HW_RESET_IND 0x9002 -#define HW_POWERUP_IND 0x9102 -#define HW_DEACT_IND 0x9202 -#define HW_ACTIVATE_IND 0x9302 -#define HW_DEACT_CNF 0x9402 -#define HW_TESTLOOP 0x9502 -#define HW_TESTRX_RAW 0x9602 -#define HW_TESTRX_HDLC 0x9702 -#define HW_TESTRX_OFF 0x9802 -#define HW_TIMER3_IND 0x9902 -#define HW_TIMER3_VALUE 0x9a00 -#define HW_TIMER3_VMASK 0x00FF - -struct layer1; -extern int l1_event(struct layer1 *, u_int); - -#define MISDN_BCH_FILL_SIZE 4 - -struct bchannel { - struct mISDNchannel ch; - int nr; - u_long Flags; - struct work_struct workq; - u_int state; - void *hw; - int slot; /* multiport card channel slot */ - struct timer_list timer; - /* receive data */ - u8 fill[MISDN_BCH_FILL_SIZE]; - struct sk_buff *rx_skb; - unsigned short maxlen; - unsigned short init_maxlen; /* initial value */ - unsigned short next_maxlen; /* pending value */ - unsigned short minlen; /* for transparent data */ - unsigned short init_minlen; /* initial value */ - unsigned short next_minlen; /* pending value */ - /* send data */ - struct sk_buff *next_skb; - struct sk_buff *tx_skb; - struct sk_buff_head rqueue; - int rcount; - int tx_idx; - int debug; - /* statistics */ - int err_crc; - int err_tx; - int err_rx; - int dropcnt; -}; - -extern int mISDN_initdchannel(struct dchannel *, int, void *); -extern int mISDN_initbchannel(struct bchannel *, unsigned short, - unsigned short); -extern int mISDN_freedchannel(struct dchannel *); -extern void mISDN_clear_bchannel(struct bchannel *); -extern void mISDN_freebchannel(struct bchannel *); -extern int mISDN_ctrl_bchannel(struct bchannel *, struct mISDN_ctrl_req *); -extern void queue_ch_frame(struct mISDNchannel *, u_int, - int, struct sk_buff *); -extern int dchannel_senddata(struct dchannel *, struct sk_buff *); -extern int bchannel_senddata(struct bchannel *, struct sk_buff *); -extern int bchannel_get_rxbuf(struct bchannel *, int); -extern void recv_Dchannel(struct dchannel *); -extern void recv_Echannel(struct dchannel *, struct dchannel *); -extern void recv_Bchannel(struct bchannel *, unsigned int, bool); -extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *); -extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *); -extern int get_next_bframe(struct bchannel *); -extern int get_next_dframe(struct dchannel *); - -#endif diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h deleted file mode 100644 index 7aab4a769736..000000000000 --- a/include/linux/mISDNif.h +++ /dev/null @@ -1,603 +0,0 @@ -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - * - * This code is free software; you can redistribute it and/or modify - * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE - * version 2.1 as published by the Free Software Foundation. - * - * This code 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. - * - */ - -#ifndef mISDNIF_H -#define mISDNIF_H - -#include -#include -#include - -/* - * ABI Version 32 bit - * - * <8 bit> Major version - * - changed if any interface become backwards incompatible - * - * <8 bit> Minor version - * - changed if any interface is extended but backwards compatible - * - * <16 bit> Release number - * - should be incremented on every checkin - */ -#define MISDN_MAJOR_VERSION 1 -#define MISDN_MINOR_VERSION 1 -#define MISDN_RELEASE 29 - -/* primitives for information exchange - * generell format - * <16 bit 0 > - * <8 bit command> - * BIT 8 = 1 LAYER private - * BIT 7 = 1 answer - * BIT 6 = 1 DATA - * <8 bit target layer mask> - * - * Layer = 00 is reserved for general commands - Layer = 01 L2 -> HW - Layer = 02 HW -> L2 - Layer = 04 L3 -> L2 - Layer = 08 L2 -> L3 - * Layer = FF is reserved for broadcast commands - */ - -#define MISDN_CMDMASK 0xff00 -#define MISDN_LAYERMASK 0x00ff - -/* generell commands */ -#define OPEN_CHANNEL 0x0100 -#define CLOSE_CHANNEL 0x0200 -#define CONTROL_CHANNEL 0x0300 -#define CHECK_DATA 0x0400 - -/* layer 2 -> layer 1 */ -#define PH_ACTIVATE_REQ 0x0101 -#define PH_DEACTIVATE_REQ 0x0201 -#define PH_DATA_REQ 0x2001 -#define MPH_ACTIVATE_REQ 0x0501 -#define MPH_DEACTIVATE_REQ 0x0601 -#define MPH_INFORMATION_REQ 0x0701 -#define PH_CONTROL_REQ 0x0801 - -/* layer 1 -> layer 2 */ -#define PH_ACTIVATE_IND 0x0102 -#define PH_ACTIVATE_CNF 0x4102 -#define PH_DEACTIVATE_IND 0x0202 -#define PH_DEACTIVATE_CNF 0x4202 -#define PH_DATA_IND 0x2002 -#define PH_DATA_E_IND 0x3002 -#define MPH_ACTIVATE_IND 0x0502 -#define MPH_DEACTIVATE_IND 0x0602 -#define MPH_INFORMATION_IND 0x0702 -#define PH_DATA_CNF 0x6002 -#define PH_CONTROL_IND 0x0802 -#define PH_CONTROL_CNF 0x4802 - -/* layer 3 -> layer 2 */ -#define DL_ESTABLISH_REQ 0x1004 -#define DL_RELEASE_REQ 0x1104 -#define DL_DATA_REQ 0x3004 -#define DL_UNITDATA_REQ 0x3104 -#define DL_INFORMATION_REQ 0x0004 - -/* layer 2 -> layer 3 */ -#define DL_ESTABLISH_IND 0x1008 -#define DL_ESTABLISH_CNF 0x5008 -#define DL_RELEASE_IND 0x1108 -#define DL_RELEASE_CNF 0x5108 -#define DL_DATA_IND 0x3008 -#define DL_UNITDATA_IND 0x3108 -#define DL_INFORMATION_IND 0x0008 - -/* intern layer 2 management */ -#define MDL_ASSIGN_REQ 0x1804 -#define MDL_ASSIGN_IND 0x1904 -#define MDL_REMOVE_REQ 0x1A04 -#define MDL_REMOVE_IND 0x1B04 -#define MDL_STATUS_UP_IND 0x1C04 -#define MDL_STATUS_DOWN_IND 0x1D04 -#define MDL_STATUS_UI_IND 0x1E04 -#define MDL_ERROR_IND 0x1F04 -#define MDL_ERROR_RSP 0x5F04 - -/* intern layer 2 */ -#define DL_TIMER200_IND 0x7004 -#define DL_TIMER203_IND 0x7304 -#define DL_INTERN_MSG 0x7804 - -/* DL_INFORMATION_IND types */ -#define DL_INFO_L2_CONNECT 0x0001 -#define DL_INFO_L2_REMOVED 0x0002 - -/* PH_CONTROL types */ -/* TOUCH TONE IS 0x20XX XX "0"..."9", "A","B","C","D","*","#" */ -#define DTMF_TONE_VAL 0x2000 -#define DTMF_TONE_MASK 0x007F -#define DTMF_TONE_START 0x2100 -#define DTMF_TONE_STOP 0x2200 -#define DTMF_HFC_COEF 0x4000 -#define DSP_CONF_JOIN 0x2403 -#define DSP_CONF_SPLIT 0x2404 -#define DSP_RECEIVE_OFF 0x2405 -#define DSP_RECEIVE_ON 0x2406 -#define DSP_ECHO_ON 0x2407 -#define DSP_ECHO_OFF 0x2408 -#define DSP_MIX_ON 0x2409 -#define DSP_MIX_OFF 0x240a -#define DSP_DELAY 0x240b -#define DSP_JITTER 0x240c -#define DSP_TXDATA_ON 0x240d -#define DSP_TXDATA_OFF 0x240e -#define DSP_TX_DEJITTER 0x240f -#define DSP_TX_DEJ_OFF 0x2410 -#define DSP_TONE_PATT_ON 0x2411 -#define DSP_TONE_PATT_OFF 0x2412 -#define DSP_VOL_CHANGE_TX 0x2413 -#define DSP_VOL_CHANGE_RX 0x2414 -#define DSP_BF_ENABLE_KEY 0x2415 -#define DSP_BF_DISABLE 0x2416 -#define DSP_BF_ACCEPT 0x2416 -#define DSP_BF_REJECT 0x2417 -#define DSP_PIPELINE_CFG 0x2418 -#define HFC_VOL_CHANGE_TX 0x2601 -#define HFC_VOL_CHANGE_RX 0x2602 -#define HFC_SPL_LOOP_ON 0x2603 -#define HFC_SPL_LOOP_OFF 0x2604 -/* for T30 FAX and analog modem */ -#define HW_MOD_FRM 0x4000 -#define HW_MOD_FRH 0x4001 -#define HW_MOD_FTM 0x4002 -#define HW_MOD_FTH 0x4003 -#define HW_MOD_FTS 0x4004 -#define HW_MOD_CONNECT 0x4010 -#define HW_MOD_OK 0x4011 -#define HW_MOD_NOCARR 0x4012 -#define HW_MOD_FCERROR 0x4013 -#define HW_MOD_READY 0x4014 -#define HW_MOD_LASTDATA 0x4015 - -/* DSP_TONE_PATT_ON parameter */ -#define TONE_OFF 0x0000 -#define TONE_GERMAN_DIALTONE 0x0001 -#define TONE_GERMAN_OLDDIALTONE 0x0002 -#define TONE_AMERICAN_DIALTONE 0x0003 -#define TONE_GERMAN_DIALPBX 0x0004 -#define TONE_GERMAN_OLDDIALPBX 0x0005 -#define TONE_AMERICAN_DIALPBX 0x0006 -#define TONE_GERMAN_RINGING 0x0007 -#define TONE_GERMAN_OLDRINGING 0x0008 -#define TONE_AMERICAN_RINGPBX 0x000b -#define TONE_GERMAN_RINGPBX 0x000c -#define TONE_GERMAN_OLDRINGPBX 0x000d -#define TONE_AMERICAN_RINGING 0x000e -#define TONE_GERMAN_BUSY 0x000f -#define TONE_GERMAN_OLDBUSY 0x0010 -#define TONE_AMERICAN_BUSY 0x0011 -#define TONE_GERMAN_HANGUP 0x0012 -#define TONE_GERMAN_OLDHANGUP 0x0013 -#define TONE_AMERICAN_HANGUP 0x0014 -#define TONE_SPECIAL_INFO 0x0015 -#define TONE_GERMAN_GASSENBESETZT 0x0016 -#define TONE_GERMAN_AUFSCHALTTON 0x0016 - -/* MPH_INFORMATION_IND */ -#define L1_SIGNAL_LOS_OFF 0x0010 -#define L1_SIGNAL_LOS_ON 0x0011 -#define L1_SIGNAL_AIS_OFF 0x0012 -#define L1_SIGNAL_AIS_ON 0x0013 -#define L1_SIGNAL_RDI_OFF 0x0014 -#define L1_SIGNAL_RDI_ON 0x0015 -#define L1_SIGNAL_SLIP_RX 0x0020 -#define L1_SIGNAL_SLIP_TX 0x0021 - -/* - * protocol ids - * D channel 1-31 - * B channel 33 - 63 - */ - -#define ISDN_P_NONE 0 -#define ISDN_P_BASE 0 -#define ISDN_P_TE_S0 0x01 -#define ISDN_P_NT_S0 0x02 -#define ISDN_P_TE_E1 0x03 -#define ISDN_P_NT_E1 0x04 -#define ISDN_P_TE_UP0 0x05 -#define ISDN_P_NT_UP0 0x06 - -#define IS_ISDN_P_TE(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_TE_E1) || \ - (p == ISDN_P_TE_UP0) || (p == ISDN_P_LAPD_TE)) -#define IS_ISDN_P_NT(p) ((p == ISDN_P_NT_S0) || (p == ISDN_P_NT_E1) || \ - (p == ISDN_P_NT_UP0) || (p == ISDN_P_LAPD_NT)) -#define IS_ISDN_P_S0(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_NT_S0)) -#define IS_ISDN_P_E1(p) ((p == ISDN_P_TE_E1) || (p == ISDN_P_NT_E1)) -#define IS_ISDN_P_UP0(p) ((p == ISDN_P_TE_UP0) || (p == ISDN_P_NT_UP0)) - - -#define ISDN_P_LAPD_TE 0x10 -#define ISDN_P_LAPD_NT 0x11 - -#define ISDN_P_B_MASK 0x1f -#define ISDN_P_B_START 0x20 - -#define ISDN_P_B_RAW 0x21 -#define ISDN_P_B_HDLC 0x22 -#define ISDN_P_B_X75SLP 0x23 -#define ISDN_P_B_L2DTMF 0x24 -#define ISDN_P_B_L2DSP 0x25 -#define ISDN_P_B_L2DSPHDLC 0x26 -#define ISDN_P_B_T30_FAX 0x27 -#define ISDN_P_B_MODEM_ASYNC 0x28 - -#define OPTION_L2_PMX 1 -#define OPTION_L2_PTP 2 -#define OPTION_L2_FIXEDTEI 3 -#define OPTION_L2_CLEANUP 4 -#define OPTION_L1_HOLD 5 - -/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ -#define MISDN_MAX_IDLEN 20 - -struct mISDNhead { - unsigned int prim; - unsigned int id; -} __packed; - -#define MISDN_HEADER_LEN sizeof(struct mISDNhead) -#define MAX_DATA_SIZE 2048 -#define MAX_DATA_MEM (MAX_DATA_SIZE + MISDN_HEADER_LEN) -#define MAX_DFRAME_LEN 260 - -#define MISDN_ID_ADDR_MASK 0xFFFF -#define MISDN_ID_TEI_MASK 0xFF00 -#define MISDN_ID_SAPI_MASK 0x00FF -#define MISDN_ID_TEI_ANY 0x7F00 - -#define MISDN_ID_ANY 0xFFFF -#define MISDN_ID_NONE 0xFFFE - -#define GROUP_TEI 127 -#define TEI_SAPI 63 -#define CTRL_SAPI 0 - -#define MISDN_MAX_CHANNEL 127 -#define MISDN_CHMAP_SIZE ((MISDN_MAX_CHANNEL + 1) >> 3) - -#define SOL_MISDN 0 - -struct sockaddr_mISDN { - sa_family_t family; - unsigned char dev; - unsigned char channel; - unsigned char sapi; - unsigned char tei; -}; - -struct mISDNversion { - unsigned char major; - unsigned char minor; - unsigned short release; -}; - -struct mISDN_devinfo { - u_int id; - u_int Dprotocols; - u_int Bprotocols; - u_int protocol; - u_char channelmap[MISDN_CHMAP_SIZE]; - u_int nrbchan; - char name[MISDN_MAX_IDLEN]; -}; - -struct mISDN_devrename { - u_int id; - char name[MISDN_MAX_IDLEN]; /* new name */ -}; - -/* MPH_INFORMATION_REQ payload */ -struct ph_info_ch { - __u32 protocol; - __u64 Flags; -}; - -struct ph_info_dch { - struct ph_info_ch ch; - __u16 state; - __u16 num_bch; -}; - -struct ph_info { - struct ph_info_dch dch; - struct ph_info_ch bch[]; -}; - -/* timer device ioctl */ -#define IMADDTIMER _IOR('I', 64, int) -#define IMDELTIMER _IOR('I', 65, int) - -/* socket ioctls */ -#define IMGETVERSION _IOR('I', 66, int) -#define IMGETCOUNT _IOR('I', 67, int) -#define IMGETDEVINFO _IOR('I', 68, int) -#define IMCTRLREQ _IOR('I', 69, int) -#define IMCLEAR_L2 _IOR('I', 70, int) -#define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename) -#define IMHOLD_L1 _IOR('I', 72, int) - -static inline int -test_channelmap(u_int nr, u_char *map) -{ - if (nr <= MISDN_MAX_CHANNEL) - return map[nr >> 3] & (1 << (nr & 7)); - else - return 0; -} - -static inline void -set_channelmap(u_int nr, u_char *map) -{ - map[nr >> 3] |= (1 << (nr & 7)); -} - -static inline void -clear_channelmap(u_int nr, u_char *map) -{ - map[nr >> 3] &= ~(1 << (nr & 7)); -} - -/* CONTROL_CHANNEL parameters */ -#define MISDN_CTRL_GETOP 0x0000 -#define MISDN_CTRL_LOOP 0x0001 -#define MISDN_CTRL_CONNECT 0x0002 -#define MISDN_CTRL_DISCONNECT 0x0004 -#define MISDN_CTRL_RX_BUFFER 0x0008 -#define MISDN_CTRL_PCMCONNECT 0x0010 -#define MISDN_CTRL_PCMDISCONNECT 0x0020 -#define MISDN_CTRL_SETPEER 0x0040 -#define MISDN_CTRL_UNSETPEER 0x0080 -#define MISDN_CTRL_RX_OFF 0x0100 -#define MISDN_CTRL_FILL_EMPTY 0x0200 -#define MISDN_CTRL_GETPEER 0x0400 -#define MISDN_CTRL_L1_TIMER3 0x0800 -#define MISDN_CTRL_HW_FEATURES_OP 0x2000 -#define MISDN_CTRL_HW_FEATURES 0x2001 -#define MISDN_CTRL_HFC_OP 0x4000 -#define MISDN_CTRL_HFC_PCM_CONN 0x4001 -#define MISDN_CTRL_HFC_PCM_DISC 0x4002 -#define MISDN_CTRL_HFC_CONF_JOIN 0x4003 -#define MISDN_CTRL_HFC_CONF_SPLIT 0x4004 -#define MISDN_CTRL_HFC_RECEIVE_OFF 0x4005 -#define MISDN_CTRL_HFC_RECEIVE_ON 0x4006 -#define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007 -#define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008 -#define MISDN_CTRL_HFC_WD_INIT 0x4009 -#define MISDN_CTRL_HFC_WD_RESET 0x400A - -/* special RX buffer value for MISDN_CTRL_RX_BUFFER request.p1 is the minimum - * buffer size request.p2 the maximum. Using MISDN_CTRL_RX_SIZE_IGNORE will - * not change the value, but still read back the actual stetting. - */ -#define MISDN_CTRL_RX_SIZE_IGNORE -1 - -/* socket options */ -#define MISDN_TIME_STAMP 0x0001 - -struct mISDN_ctrl_req { - int op; - int channel; - int p1; - int p2; -}; - -/* muxer options */ -#define MISDN_OPT_ALL 1 -#define MISDN_OPT_TEIMGR 2 - -#ifdef __KERNEL__ -#include -#include -#include -#include -#include - -#define DEBUG_CORE 0x000000ff -#define DEBUG_CORE_FUNC 0x00000002 -#define DEBUG_SOCKET 0x00000004 -#define DEBUG_MANAGER 0x00000008 -#define DEBUG_SEND_ERR 0x00000010 -#define DEBUG_MSG_THREAD 0x00000020 -#define DEBUG_QUEUE_FUNC 0x00000040 -#define DEBUG_L1 0x0000ff00 -#define DEBUG_L1_FSM 0x00000200 -#define DEBUG_L2 0x00ff0000 -#define DEBUG_L2_FSM 0x00020000 -#define DEBUG_L2_CTRL 0x00040000 -#define DEBUG_L2_RECV 0x00080000 -#define DEBUG_L2_TEI 0x00100000 -#define DEBUG_L2_TEIFSM 0x00200000 -#define DEBUG_TIMER 0x01000000 -#define DEBUG_CLOCK 0x02000000 - -#define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0]) -#define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim) -#define mISDN_HEAD_ID(s) (((struct mISDNhead *)&s->cb[0])->id) - -/* socket states */ -#define MISDN_OPEN 1 -#define MISDN_BOUND 2 -#define MISDN_CLOSED 3 - -struct mISDNchannel; -struct mISDNdevice; -struct mISDNstack; -struct mISDNclock; - -struct channel_req { - u_int protocol; - struct sockaddr_mISDN adr; - struct mISDNchannel *ch; -}; - -typedef int (ctrl_func_t)(struct mISDNchannel *, u_int, void *); -typedef int (send_func_t)(struct mISDNchannel *, struct sk_buff *); -typedef int (create_func_t)(struct channel_req *); - -struct Bprotocol { - struct list_head list; - char *name; - u_int Bprotocols; - create_func_t *create; -}; - -struct mISDNchannel { - struct list_head list; - u_int protocol; - u_int nr; - u_long opt; - u_int addr; - struct mISDNstack *st; - struct mISDNchannel *peer; - send_func_t *send; - send_func_t *recv; - ctrl_func_t *ctrl; -}; - -struct mISDN_sock_list { - struct hlist_head head; - rwlock_t lock; -}; - -struct mISDN_sock { - struct sock sk; - struct mISDNchannel ch; - u_int cmask; - struct mISDNdevice *dev; -}; - - - -struct mISDNdevice { - struct mISDNchannel D; - u_int id; - u_int Dprotocols; - u_int Bprotocols; - u_int nrbchan; - u_char channelmap[MISDN_CHMAP_SIZE]; - struct list_head bchannels; - struct mISDNchannel *teimgr; - struct device dev; -}; - -struct mISDNstack { - u_long status; - struct mISDNdevice *dev; - struct task_struct *thread; - struct completion *notify; - wait_queue_head_t workq; - struct sk_buff_head msgq; - struct list_head layer2; - struct mISDNchannel *layer1; - struct mISDNchannel own; - struct mutex lmutex; /* protect lists */ - struct mISDN_sock_list l1sock; -#ifdef MISDN_MSG_STATS - u_int msg_cnt; - u_int sleep_cnt; - u_int stopped_cnt; -#endif -}; - -typedef int (clockctl_func_t)(void *, int); - -struct mISDNclock { - struct list_head list; - char name[64]; - int pri; - clockctl_func_t *ctl; - void *priv; -}; - -/* global alloc/queue functions */ - -static inline struct sk_buff * -mI_alloc_skb(unsigned int len, gfp_t gfp_mask) -{ - struct sk_buff *skb; - - skb = alloc_skb(len + MISDN_HEADER_LEN, gfp_mask); - if (likely(skb)) - skb_reserve(skb, MISDN_HEADER_LEN); - return skb; -} - -static inline struct sk_buff * -_alloc_mISDN_skb(u_int prim, u_int id, u_int len, void *dp, gfp_t gfp_mask) -{ - struct sk_buff *skb = mI_alloc_skb(len, gfp_mask); - struct mISDNhead *hh; - - if (!skb) - return NULL; - if (len) - skb_put_data(skb, dp, len); - hh = mISDN_HEAD_P(skb); - hh->prim = prim; - hh->id = id; - return skb; -} - -static inline void -_queue_data(struct mISDNchannel *ch, u_int prim, - u_int id, u_int len, void *dp, gfp_t gfp_mask) -{ - struct sk_buff *skb; - - if (!ch->peer) - return; - skb = _alloc_mISDN_skb(prim, id, len, dp, gfp_mask); - if (!skb) - return; - if (ch->recv(ch->peer, skb)) - dev_kfree_skb(skb); -} - -/* global register/unregister functions */ - -extern int mISDN_register_device(struct mISDNdevice *, - struct device *parent, char *name); -extern void mISDN_unregister_device(struct mISDNdevice *); -extern int mISDN_register_Bprotocol(struct Bprotocol *); -extern void mISDN_unregister_Bprotocol(struct Bprotocol *); -extern struct mISDNclock *mISDN_register_clock(char *, int, clockctl_func_t *, - void *); -extern void mISDN_unregister_clock(struct mISDNclock *); - -static inline struct mISDNdevice *dev_to_mISDN(const struct device *dev) -{ - if (dev) - return dev_get_drvdata(dev); - else - return NULL; -} - -extern void set_channel_address(struct mISDNchannel *, u_int, u_int); -extern void mISDN_clock_update(struct mISDNclock *, int, ktime_t *); -extern unsigned short mISDN_clock_get(void); -extern const char *mISDNDevName4ch(struct mISDNchannel *); - -#endif /* __KERNEL__ */ -#endif /* mISDNIF_H */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 97b435da5771..0e1e581efc5a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -162,7 +162,7 @@ static inline bool dev_xmit_complete(int rc) #if defined(CONFIG_HYPERV_NET) # define LL_MAX_HEADER 128 -#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) +#elif defined(CONFIG_WLAN) # if defined(CONFIG_MAC80211_MESH) # define LL_MAX_HEADER 128 # else @@ -2336,9 +2336,6 @@ struct net_device { #if IS_ENABLED(CONFIG_ATALK) void *atalk_ptr; #endif -#if IS_ENABLED(CONFIG_AX25) - struct ax25_dev __rcu *ax25_ptr; -#endif #if IS_ENABLED(CONFIG_CFG80211) struct wireless_dev *ieee80211_ptr; #endif diff --git a/include/linux/scc.h b/include/linux/scc.h deleted file mode 100644 index 745eabd17c10..000000000000 --- a/include/linux/scc.h +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* $Id: scc.h,v 1.29 1997/04/02 14:56:45 jreuter Exp jreuter $ */ -#ifndef _SCC_H -#define _SCC_H - -#include - - -enum {TX_OFF, TX_ON}; /* command for scc_key_trx() */ - -/* Vector masks in RR2B */ - -#define VECTOR_MASK 0x06 -#define TXINT 0x00 -#define EXINT 0x02 -#define RXINT 0x04 -#define SPINT 0x06 - -#ifdef CONFIG_SCC_DELAY -#define Inb(port) inb_p(port) -#define Outb(port, val) outb_p(val, port) -#else -#define Inb(port) inb(port) -#define Outb(port, val) outb(val, port) -#endif - -/* SCC channel control structure for KISS */ - -struct scc_kiss { - unsigned char txdelay; /* Transmit Delay 10 ms/cnt */ - unsigned char persist; /* Persistence (0-255) as a % */ - unsigned char slottime; /* Delay to wait on persistence hit */ - unsigned char tailtime; /* Delay after last byte written */ - unsigned char fulldup; /* Full Duplex mode 0=CSMA 1=DUP 2=ALWAYS KEYED */ - unsigned char waittime; /* Waittime before any transmit attempt */ - unsigned int maxkeyup; /* Maximum time to transmit (seconds) */ - unsigned int mintime; /* Minimal offtime after MAXKEYUP timeout (seconds) */ - unsigned int idletime; /* Maximum idle time in ALWAYS KEYED mode (seconds) */ - unsigned int maxdefer; /* Timer for CSMA channel busy limit */ - unsigned char tx_inhibit; /* Transmit is not allowed when set */ - unsigned char group; /* Group ID for AX.25 TX interlocking */ - unsigned char mode; /* 'normal' or 'hwctrl' mode (unused) */ - unsigned char softdcd; /* Use DPLL instead of DCD pin for carrier detect */ -}; - - -/* SCC channel structure */ - -struct scc_channel { - int init; /* channel exists? */ - - struct net_device *dev; /* link to device control structure */ - struct net_device_stats dev_stat;/* device statistics */ - - char brand; /* manufacturer of the board */ - long clock; /* used clock */ - - io_port ctrl; /* I/O address of CONTROL register */ - io_port data; /* I/O address of DATA register */ - io_port special; /* I/O address of special function port */ - int irq; /* Number of Interrupt */ - - char option; - char enhanced; /* Enhanced SCC support */ - - unsigned char wreg[16]; /* Copy of last written value in WRx */ - unsigned char status; /* Copy of R0 at last external interrupt */ - unsigned char dcd; /* DCD status */ - - struct scc_kiss kiss; /* control structure for KISS params */ - struct scc_stat stat; /* statistical information */ - struct scc_modem modem; /* modem information */ - - struct sk_buff_head tx_queue; /* next tx buffer */ - struct sk_buff *rx_buff; /* pointer to frame currently received */ - struct sk_buff *tx_buff; /* pointer to frame currently transmitted */ - - /* Timer */ - struct timer_list tx_t; /* tx timer for this channel */ - struct timer_list tx_wdog; /* tx watchdogs */ - - /* Channel lock */ - spinlock_t lock; /* Channel guard lock */ -}; - -#endif /* defined(_SCC_H) */ diff --git a/include/linux/virtio_caif.h b/include/linux/virtio_caif.h deleted file mode 100644 index ea722479510c..000000000000 --- a/include/linux/virtio_caif.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) ST-Ericsson AB 2012 - * Author: Sjur Brændeland - * - * This header is BSD licensed so - * anyone can use the definitions to implement compatible remote processors - */ - -#ifndef VIRTIO_CAIF_H -#define VIRTIO_CAIF_H - -#include -struct virtio_caif_transf_config { - __virtio16 headroom; - __virtio16 tailroom; - __virtio32 mtu; - u8 reserved[4]; -}; - -struct virtio_caif_config { - struct virtio_caif_transf_config uplink, downlink; - u8 reserved[8]; -}; -#endif diff --git a/include/linux/yam.h b/include/linux/yam.h deleted file mode 100644 index a29b04fa1e66..000000000000 --- a/include/linux/yam.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/*****************************************************************************/ - -/* - * yam.h -- YAM radio modem driver. - * - * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr) - * Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - */ - -/*****************************************************************************/ - -#define SIOCYAMRESERVED (0) -#define SIOCYAMSCFG (1) /* Set configuration */ -#define SIOCYAMGCFG (2) /* Get configuration */ -#define SIOCYAMSMCS (3) /* Set mcs data */ - -#define YAM_IOBASE (1 << 0) -#define YAM_IRQ (1 << 1) -#define YAM_BITRATE (1 << 2) /* Bit rate of radio port ->57600 */ -#define YAM_MODE (1 << 3) /* 0=simplex 1=duplex 2=duplex+tempo */ -#define YAM_HOLDDLY (1 << 4) /* duplex tempo (sec) */ -#define YAM_TXDELAY (1 << 5) /* Tx Delay (ms) */ -#define YAM_TXTAIL (1 << 6) /* Tx Tail (ms) */ -#define YAM_PERSIST (1 << 7) /* Persist (ms) */ -#define YAM_SLOTTIME (1 << 8) /* Slottime (ms) */ -#define YAM_BAUDRATE (1 << 9) /* Baud rate of rs232 port ->115200 */ - -#define YAM_MAXBITRATE 57600 -#define YAM_MAXBAUDRATE 115200 -#define YAM_MAXMODE 2 -#define YAM_MAXHOLDDLY 99 -#define YAM_MAXTXDELAY 999 -#define YAM_MAXTXTAIL 999 -#define YAM_MAXPERSIST 255 -#define YAM_MAXSLOTTIME 999 - -#define YAM_FPGA_SIZE 5302 - -struct yamcfg { - unsigned int mask; /* Mask of commands */ - unsigned int iobase; /* IO Base of COM port */ - unsigned int irq; /* IRQ of COM port */ - unsigned int bitrate; /* Bit rate of radio port */ - unsigned int baudrate; /* Baud rate of the RS232 port */ - unsigned int txdelay; /* TxDelay */ - unsigned int txtail; /* TxTail */ - unsigned int persist; /* Persistence */ - unsigned int slottime; /* Slottime */ - unsigned int mode; /* mode 0 (simp), 1(Dupl), 2(Dupl+delay) */ - unsigned int holddly; /* PTT delay in FullDuplex 2 mode */ -}; - -struct yamdrv_ioctl_cfg { - int cmd; - struct yamcfg cfg; -}; - -struct yamdrv_ioctl_mcs { - int cmd; - unsigned int bitrate; - unsigned char bits[YAM_FPGA_SIZE]; -}; diff --git a/include/net/Space.h b/include/net/Space.h index ef42629f4258..6a0b6674d930 100644 --- a/include/net/Space.h +++ b/include/net/Space.h @@ -3,10 +3,5 @@ * ethernet adaptor have the name "eth[0123...]". */ -struct net_device *ultra_probe(int unit); -struct net_device *wd_probe(int unit); struct net_device *ne_probe(int unit); -struct net_device *smc_init(int unit); struct net_device *cs89x0_probe(int unit); -struct net_device *tc515_probe(int unit); -struct net_device *lance_probe(int unit); diff --git a/include/net/atmclip.h b/include/net/atmclip.h deleted file mode 100644 index 70e350e0db3d..000000000000 --- a/include/net/atmclip.h +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* net/atm/atmarp.h - RFC1577 ATM ARP */ - -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - - -#ifndef _ATMCLIP_H -#define _ATMCLIP_H - -#include -#include -#include -#include -#include -#include - - -#define CLIP_VCC(vcc) ((struct clip_vcc *) ((vcc)->user_back)) - -struct sk_buff; - -struct clip_vcc { - struct atm_vcc *vcc; /* VCC descriptor */ - struct atmarp_entry *entry; /* ATMARP table entry, NULL if IP addr. - isn't known yet */ - int xoff; /* 1 if send buffer is full */ - unsigned char encap; /* 0: NULL, 1: LLC/SNAP */ - unsigned long last_use; /* last send or receive operation */ - unsigned long idle_timeout; /* keep open idle for so many jiffies*/ - void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); - /* keep old push fn for chaining */ - void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); - /* keep old pop fn for chaining */ - struct clip_vcc *next; /* next VCC */ -}; - - -struct atmarp_entry { - struct clip_vcc *vccs; /* active VCCs; NULL if resolution is - pending */ - unsigned long expires; /* entry expiration time */ - struct neighbour *neigh; /* neighbour back-pointer */ -}; - -#define PRIV(dev) ((struct clip_priv *) netdev_priv(dev)) - -struct clip_priv { - int number; /* for convenience ... */ - spinlock_t xoff_lock; /* ensures that pop is atomic (SMP) */ - struct net_device *next; /* next CLIP interface */ -}; - -#endif diff --git a/include/net/ax25.h b/include/net/ax25.h index 9fc6a6657266..6b2f518facdb 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -1,480 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * Declarations of AX.25 type objects. - * - * Alan Cox (GW4PTS) 10/11/93 - */ #ifndef _AX25_H -#define _AX25_H +#define _AX25_H #include -#include -#include -#include -#include -#include -#include -#include -#include -#define AX25_T1CLAMPLO 1 -#define AX25_T1CLAMPHI (30 * HZ) - -#define AX25_BPQ_HEADER_LEN 16 -#define AX25_KISS_HEADER_LEN 1 - -#define AX25_HEADER_LEN 17 -#define AX25_ADDR_LEN 7 -#define AX25_DIGI_HEADER_LEN (AX25_MAX_DIGIS * AX25_ADDR_LEN) -#define AX25_MAX_HEADER_LEN (AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN) - -/* AX.25 Protocol IDs */ -#define AX25_P_ROSE 0x01 -#define AX25_P_VJCOMP 0x06 /* Compressed TCP/IP packet */ - /* Van Jacobsen (RFC 1144) */ -#define AX25_P_VJUNCOMP 0x07 /* Uncompressed TCP/IP packet */ - /* Van Jacobsen (RFC 1144) */ -#define AX25_P_SEGMENT 0x08 /* Segmentation fragment */ -#define AX25_P_TEXNET 0xc3 /* TEXTNET datagram protocol */ -#define AX25_P_LQ 0xc4 /* Link Quality Protocol */ -#define AX25_P_ATALK 0xca /* Appletalk */ -#define AX25_P_ATALK_ARP 0xcb /* Appletalk ARP */ -#define AX25_P_IP 0xcc /* ARPA Internet Protocol */ -#define AX25_P_ARP 0xcd /* ARPA Address Resolution */ -#define AX25_P_FLEXNET 0xce /* FlexNet */ -#define AX25_P_NETROM 0xcf /* NET/ROM */ -#define AX25_P_TEXT 0xF0 /* No layer 3 protocol impl. */ - -/* AX.25 Segment control values */ -#define AX25_SEG_REM 0x7F -#define AX25_SEG_FIRST 0x80 - -#define AX25_CBIT 0x80 /* Command/Response bit */ -#define AX25_EBIT 0x01 /* HDLC Address Extension bit */ -#define AX25_HBIT 0x80 /* Has been repeated bit */ - -#define AX25_SSSID_SPARE 0x60 /* Unused bits in SSID for standard AX.25 */ -#define AX25_ESSID_SPARE 0x20 /* Unused bits in SSID for extended AX.25 */ -#define AX25_DAMA_FLAG 0x20 /* Well, it is *NOT* unused! (dl1bke 951121 */ - -#define AX25_COND_ACK_PENDING 0x01 -#define AX25_COND_REJECT 0x02 -#define AX25_COND_PEER_RX_BUSY 0x04 -#define AX25_COND_OWN_RX_BUSY 0x08 -#define AX25_COND_DAMA_MODE 0x10 - -#ifndef _LINUX_NETDEVICE_H -#include -#endif - -/* Upper sub-layer (LAPB) definitions */ - -/* Control field templates */ -#define AX25_I 0x00 /* Information frames */ -#define AX25_S 0x01 /* Supervisory frames */ -#define AX25_RR 0x01 /* Receiver ready */ -#define AX25_RNR 0x05 /* Receiver not ready */ -#define AX25_REJ 0x09 /* Reject */ -#define AX25_U 0x03 /* Unnumbered frames */ -#define AX25_SABM 0x2f /* Set Asynchronous Balanced Mode */ -#define AX25_SABME 0x6f /* Set Asynchronous Balanced Mode Extended */ -#define AX25_DISC 0x43 /* Disconnect */ -#define AX25_DM 0x0f /* Disconnected mode */ -#define AX25_UA 0x63 /* Unnumbered acknowledge */ -#define AX25_FRMR 0x87 /* Frame reject */ -#define AX25_UI 0x03 /* Unnumbered information */ -#define AX25_XID 0xaf /* Exchange information */ -#define AX25_TEST 0xe3 /* Test */ - -#define AX25_PF 0x10 /* Poll/final bit for standard AX.25 */ -#define AX25_EPF 0x01 /* Poll/final bit for extended AX.25 */ - -#define AX25_ILLEGAL 0x100 /* Impossible to be a real frame type */ - -#define AX25_POLLOFF 0 -#define AX25_POLLON 1 - -/* AX25 L2 C-bit */ -#define AX25_COMMAND 1 -#define AX25_RESPONSE 2 - -/* Define Link State constants. */ - -enum { - AX25_STATE_0, /* Listening */ - AX25_STATE_1, /* SABM sent */ - AX25_STATE_2, /* DISC sent */ - AX25_STATE_3, /* Established */ - AX25_STATE_4 /* Recovery */ -}; - -#define AX25_MODULUS 8 /* Standard AX.25 modulus */ -#define AX25_EMODULUS 128 /* Extended AX.25 modulus */ - -enum { - AX25_PROTO_STD_SIMPLEX, - AX25_PROTO_STD_DUPLEX, -#ifdef CONFIG_AX25_DAMA_SLAVE - AX25_PROTO_DAMA_SLAVE, -#endif - __AX25_PROTO_MAX, - AX25_PROTO_MAX = __AX25_PROTO_MAX -1 -}; - -enum { - AX25_VALUES_IPDEFMODE, /* 0=DG 1=VC */ - AX25_VALUES_AXDEFMODE, /* 0=Normal 1=Extended Seq Nos */ - AX25_VALUES_BACKOFF, /* 0=None 1=Linear 2=Exponential */ - AX25_VALUES_CONMODE, /* Allow connected modes - 0=No 1=no "PID text" 2=all PIDs */ - AX25_VALUES_WINDOW, /* Default window size for standard AX.25 */ - AX25_VALUES_EWINDOW, /* Default window size for extended AX.25 */ - AX25_VALUES_T1, /* Default T1 timeout value */ - AX25_VALUES_T2, /* Default T2 timeout value */ - AX25_VALUES_T3, /* Default T3 timeout value */ - AX25_VALUES_IDLE, /* Connected mode idle timer */ - AX25_VALUES_N2, /* Default N2 value */ - AX25_VALUES_PACLEN, /* AX.25 MTU */ - AX25_VALUES_PROTOCOL, /* Std AX.25, DAMA Slave */ -#ifdef CONFIG_AX25_DAMA_SLAVE - AX25_VALUES_DS_TIMEOUT, /* DAMA Slave timeout */ -#endif - AX25_MAX_VALUES /* THIS MUST REMAIN THE LAST ENTRY OF THIS LIST */ -}; - -#define AX25_DEF_IPDEFMODE 0 /* Datagram */ -#define AX25_DEF_AXDEFMODE 0 /* Normal */ -#define AX25_DEF_BACKOFF 1 /* Linear backoff */ -#define AX25_DEF_CONMODE 2 /* Connected mode allowed */ -#define AX25_DEF_WINDOW 2 /* Window=2 */ -#define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */ -#define AX25_DEF_T1 10000 /* T1=10s */ -#define AX25_DEF_T2 3000 /* T2=3s */ -#define AX25_DEF_T3 300000 /* T3=300s */ -#define AX25_DEF_N2 10 /* N2=10 */ -#define AX25_DEF_IDLE 0 /* Idle=None */ -#define AX25_DEF_PACLEN 256 /* Paclen=256 */ -#define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */ -#define AX25_DEF_DS_TIMEOUT 180000 /* DAMA timeout 3 minutes */ - -typedef struct ax25_uid_assoc { - struct hlist_node uid_node; - refcount_t refcount; - kuid_t uid; - ax25_address call; -} ax25_uid_assoc; - -#define ax25_uid_for_each(__ax25, list) \ - hlist_for_each_entry(__ax25, list, uid_node) - -#define ax25_uid_hold(ax25) \ - refcount_inc(&((ax25)->refcount)) - -static inline void ax25_uid_put(ax25_uid_assoc *assoc) -{ - if (refcount_dec_and_test(&assoc->refcount)) { - kfree(assoc); - } -} - -typedef struct { - ax25_address calls[AX25_MAX_DIGIS]; - unsigned char repeated[AX25_MAX_DIGIS]; - unsigned char ndigi; - signed char lastrepeat; -} ax25_digi; - -typedef struct ax25_route { - struct ax25_route *next; - ax25_address callsign; - struct net_device *dev; - ax25_digi *digipeat; - char ip_mode; -} ax25_route; - -void __ax25_put_route(ax25_route *ax25_rt); - -extern rwlock_t ax25_route_lock; - -static inline void ax25_route_lock_use(void) -{ - read_lock(&ax25_route_lock); -} - -static inline void ax25_route_lock_unuse(void) -{ - read_unlock(&ax25_route_lock); -} - -typedef struct { - char slave; /* slave_mode? */ - struct timer_list slave_timer; /* timeout timer */ - unsigned short slave_timeout; /* when? */ -} ax25_dama_info; - -typedef struct ax25_dev { - struct list_head list; - - struct net_device *dev; - netdevice_tracker dev_tracker; - - struct net_device *forward; - struct ctl_table_header *sysheader; - int values[AX25_MAX_VALUES]; -#ifdef CONFIG_AX25_DAMA_SLAVE - ax25_dama_info dama; -#endif - refcount_t refcount; - bool device_up; - struct rcu_head rcu; -} ax25_dev; - -typedef struct ax25_cb { - struct hlist_node ax25_node; - ax25_address source_addr, dest_addr; - ax25_digi *digipeat; - ax25_dev *ax25_dev; - netdevice_tracker dev_tracker; - unsigned char iamdigi; - unsigned char state, modulus, pidincl; - unsigned short vs, vr, va; - unsigned char condition, backoff; - unsigned char n2, n2count; - struct timer_list t1timer, t2timer, t3timer, idletimer; - unsigned long t1, t2, t3, idle, rtt; - unsigned short paclen, fragno, fraglen; - struct sk_buff_head write_queue; - struct sk_buff_head reseq_queue; - struct sk_buff_head ack_queue; - struct sk_buff_head frag_queue; - unsigned char window; - struct timer_list timer, dtimer; - struct sock *sk; /* Backlink to socket */ - refcount_t refcount; -} ax25_cb; - -struct ax25_sock { - struct sock sk; - struct ax25_cb *cb; -}; - -#define ax25_sk(ptr) container_of_const(ptr, struct ax25_sock, sk) - -static inline struct ax25_cb *sk_to_ax25(const struct sock *sk) -{ - return ax25_sk(sk)->cb; -} - -#define ax25_for_each(__ax25, list) \ - hlist_for_each_entry(__ax25, list, ax25_node) - -#define ax25_cb_hold(__ax25) \ - refcount_inc(&((__ax25)->refcount)) - -static __inline__ void ax25_cb_put(ax25_cb *ax25) -{ - if (refcount_dec_and_test(&ax25->refcount)) { - kfree(ax25->digipeat); - kfree(ax25); - } -} - -static inline void ax25_dev_hold(ax25_dev *ax25_dev) -{ - refcount_inc(&ax25_dev->refcount); -} - -static inline void ax25_dev_put(ax25_dev *ax25_dev) -{ - if (refcount_dec_and_test(&ax25_dev->refcount)) - kfree_rcu(ax25_dev, rcu); -} -static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - skb->dev = dev; - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_HOST; - return htons(ETH_P_AX25); -} - -/* af_ax25.c */ -extern struct hlist_head ax25_list; -extern spinlock_t ax25_list_lock; -void ax25_cb_add(ax25_cb *); -struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int); -struct sock *ax25_get_socket(ax25_address *, ax25_address *, int); -ax25_cb *ax25_find_cb(const ax25_address *, ax25_address *, ax25_digi *, - struct net_device *); -void ax25_send_to_raw(ax25_address *, struct sk_buff *, int); -void ax25_destroy_socket(ax25_cb *); -ax25_cb * __must_check ax25_create_cb(void); -void ax25_fillin_cb(ax25_cb *, ax25_dev *); -struct sock *ax25_make_new(struct sock *, struct ax25_dev *); - -/* ax25_addr.c */ -extern const ax25_address ax25_bcast; -extern const ax25_address ax25_defaddr; -extern const ax25_address null_ax25_address; -char *ax2asc(char *buf, const ax25_address *); -void asc2ax(ax25_address *addr, const char *callsign); -int ax25cmp(const ax25_address *, const ax25_address *); -int ax25digicmp(const ax25_digi *, const ax25_digi *); -const unsigned char *ax25_addr_parse(const unsigned char *, int, - ax25_address *, ax25_address *, ax25_digi *, int *, int *); -int ax25_addr_build(unsigned char *, const ax25_address *, - const ax25_address *, const ax25_digi *, int, int); -int ax25_addr_size(const ax25_digi *); -void ax25_digi_invert(const ax25_digi *, ax25_digi *); - -/* ax25_dev.c */ -extern spinlock_t ax25_dev_lock; - -#if IS_ENABLED(CONFIG_AX25) -static inline ax25_dev *ax25_dev_ax25dev(const struct net_device *dev) -{ - return rcu_dereference_rtnl(dev->ax25_ptr); -} -#endif - -ax25_dev *ax25_addr_ax25dev(ax25_address *); -void ax25_dev_device_up(struct net_device *); -void ax25_dev_device_down(struct net_device *); -int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *); -struct net_device *ax25_fwd_dev(struct net_device *); -void ax25_dev_free(void); - -/* ax25_ds_in.c */ -int ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int); - -/* ax25_ds_subr.c */ -void ax25_ds_nr_error_recovery(ax25_cb *); -void ax25_ds_enquiry_response(ax25_cb *); -void ax25_ds_establish_data_link(ax25_cb *); -void ax25_dev_dama_off(ax25_dev *); -void ax25_dama_on(ax25_cb *); -void ax25_dama_off(ax25_cb *); - -/* ax25_ds_timer.c */ -void ax25_ds_setup_timer(ax25_dev *); -void ax25_ds_set_timer(ax25_dev *); -void ax25_ds_del_timer(ax25_dev *); -void ax25_ds_timer(ax25_cb *); -void ax25_ds_t1_timeout(ax25_cb *); -void ax25_ds_heartbeat_expiry(ax25_cb *); -void ax25_ds_t3timer_expiry(ax25_cb *); -void ax25_ds_idletimer_expiry(ax25_cb *); - -/* ax25_iface.c */ - -struct ax25_protocol { - struct ax25_protocol *next; - unsigned int pid; - int (*func)(struct sk_buff *, ax25_cb *); -}; - -void ax25_register_pid(struct ax25_protocol *ap); -void ax25_protocol_release(unsigned int); - -struct ax25_linkfail { - struct hlist_node lf_node; - void (*func)(ax25_cb *, int); -}; - -void ax25_linkfail_register(struct ax25_linkfail *lf); -void ax25_linkfail_release(struct ax25_linkfail *lf); -int __must_check ax25_listen_register(const ax25_address *, - struct net_device *); -void ax25_listen_release(const ax25_address *, struct net_device *); -int(*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *); -int ax25_listen_mine(const ax25_address *, struct net_device *); -void ax25_link_failed(ax25_cb *, int); -int ax25_protocol_is_registered(unsigned int); - -/* ax25_in.c */ -int ax25_rx_iframe(ax25_cb *, struct sk_buff *); -int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, - struct net_device *); - -/* ax25_ip.c */ -netdev_tx_t ax25_ip_xmit(struct sk_buff *skb); -extern const struct header_ops ax25_header_ops; - -/* ax25_out.c */ -ax25_cb *ax25_send_frame(struct sk_buff *, int, const ax25_address *, - ax25_address *, ax25_digi *, struct net_device *); -void ax25_output(ax25_cb *, int, struct sk_buff *); -void ax25_kick(ax25_cb *); -void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int); -void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev); -int ax25_check_iframes_acked(ax25_cb *, unsigned short); - -/* ax25_route.c */ -void ax25_rt_device_down(struct net_device *); -int ax25_rt_ioctl(unsigned int, void __user *); -extern const struct seq_operations ax25_rt_seqops; -ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev); -struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, - ax25_address *, ax25_digi *); -void ax25_rt_free(void); - -/* ax25_std_in.c */ -int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); - -/* ax25_std_subr.c */ -void ax25_std_nr_error_recovery(ax25_cb *); -void ax25_std_establish_data_link(ax25_cb *); -void ax25_std_transmit_enquiry(ax25_cb *); -void ax25_std_enquiry_response(ax25_cb *); -void ax25_std_timeout_response(ax25_cb *); - -/* ax25_std_timer.c */ -void ax25_std_heartbeat_expiry(ax25_cb *); -void ax25_std_t1timer_expiry(ax25_cb *); -void ax25_std_t2timer_expiry(ax25_cb *); -void ax25_std_t3timer_expiry(ax25_cb *); -void ax25_std_idletimer_expiry(ax25_cb *); - -/* ax25_subr.c */ -void ax25_clear_queues(ax25_cb *); -void ax25_frames_acked(ax25_cb *, unsigned short); -void ax25_requeue_frames(ax25_cb *); -int ax25_validate_nr(ax25_cb *, unsigned short); -int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *); -void ax25_send_control(ax25_cb *, int, int, int); -void ax25_return_dm(struct net_device *, ax25_address *, ax25_address *, - ax25_digi *); -void ax25_calculate_t1(ax25_cb *); -void ax25_calculate_rtt(ax25_cb *); -void ax25_disconnect(ax25_cb *, int); - -/* ax25_timer.c */ -void ax25_setup_timers(ax25_cb *); -void ax25_start_heartbeat(ax25_cb *); -void ax25_start_t1timer(ax25_cb *); -void ax25_start_t2timer(ax25_cb *); -void ax25_start_t3timer(ax25_cb *); -void ax25_start_idletimer(ax25_cb *); -void ax25_stop_heartbeat(ax25_cb *); -void ax25_stop_t1timer(ax25_cb *); -void ax25_stop_t2timer(ax25_cb *); -void ax25_stop_t3timer(ax25_cb *); -void ax25_stop_idletimer(ax25_cb *); -int ax25_t1timer_running(ax25_cb *); -unsigned long ax25_display_timer(struct timer_list *); - -/* ax25_uid.c */ -extern int ax25_uid_policy; -ax25_uid_assoc *ax25_findbyuid(kuid_t); -int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *); -extern const struct seq_operations ax25_uid_seqops; -void ax25_uid_free(void); - -/* sysctl_net_ax25.c */ -#ifdef CONFIG_SYSCTL -int ax25_register_dev_sysctl(ax25_dev *ax25_dev); -void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev); -#else -static inline int ax25_register_dev_sysctl(ax25_dev *ax25_dev) { return 0; } -static inline void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev) {} -#endif /* CONFIG_SYSCTL */ +#define AX25_ADDR_LEN 7 +#define AX25_P_IP 0xCC #endif diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h deleted file mode 100644 index b655d8666f55..000000000000 --- a/include/net/caif/caif_dev.h +++ /dev/null @@ -1,128 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CAIF_DEV_H_ -#define CAIF_DEV_H_ - -#include -#include -#include -#include -#include -#include - -/** - * struct caif_param - CAIF parameters. - * @size: Length of data - * @data: Binary Data Blob - */ -struct caif_param { - u16 size; - u8 data[256]; -}; - -/** - * struct caif_connect_request - Request data for CAIF channel setup. - * @protocol: Type of CAIF protocol to use (at, datagram etc) - * @sockaddr: Socket address to connect. - * @priority: Priority of the connection. - * @link_selector: Link selector (high bandwidth or low latency) - * @ifindex: kernel index of the interface. - * @param: Connect Request parameters (CAIF_SO_REQ_PARAM). - * - * This struct is used when connecting a CAIF channel. - * It contains all CAIF channel configuration options. - */ -struct caif_connect_request { - enum caif_protocol_type protocol; - struct sockaddr_caif sockaddr; - enum caif_channel_priority priority; - enum caif_link_selector link_selector; - int ifindex; - struct caif_param param; -}; - -/** - * caif_connect_client - Connect a client to CAIF Core Stack. - * @config: Channel setup parameters, specifying what address - * to connect on the Modem. - * @client_layer: User implementation of client layer. This layer - * MUST have receive and control callback functions - * implemented. - * @ifindex: Link layer interface index used for this connection. - * @headroom: Head room needed by CAIF protocol. - * @tailroom: Tail room needed by CAIF protocol. - * - * This function connects a CAIF channel. The Client must implement - * the struct cflayer. This layer represents the Client layer and holds - * receive functions and control callback functions. Control callback - * function will receive information about connect/disconnect responses, - * flow control etc (see enum caif_control). - * E.g. CAIF Socket will call this function for each socket it connects - * and have one client_layer instance for each socket. - */ -int caif_connect_client(struct net *net, - struct caif_connect_request *conn_req, - struct cflayer *client_layer, int *ifindex, - int *headroom, int *tailroom); - -/** - * caif_disconnect_client - Disconnects a client from the CAIF stack. - * - * @client_layer: Client layer to be disconnected. - */ -int caif_disconnect_client(struct net *net, struct cflayer *client_layer); - - -/** - * caif_client_register_refcnt - register ref-count functions provided by client. - * - * @adapt_layer: Client layer using CAIF Stack. - * @hold: Function provided by client layer increasing ref-count - * @put: Function provided by client layer decreasing ref-count - * - * Client of the CAIF Stack must register functions for reference counting. - * These functions are called by the CAIF Stack for every upstream packet, - * and must therefore be implemented efficiently. - * - * Client should call caif_free_client when reference count degrease to zero. - */ - -void caif_client_register_refcnt(struct cflayer *adapt_layer, - void (*hold)(struct cflayer *lyr), - void (*put)(struct cflayer *lyr)); -/** - * caif_free_client - Free memory used to manage the client in the CAIF Stack. - * - * @client_layer: Client layer to be removed. - * - * This function must be called from client layer in order to free memory. - * Caller must guarantee that no packets are in flight upstream when calling - * this function. - */ -void caif_free_client(struct cflayer *adap_layer); - -/** - * struct caif_enroll_dev - Enroll a net-device as a CAIF Link layer - * @dev: Network device to enroll. - * @caifdev: Configuration information from CAIF Link Layer - * @link_support: Link layer support layer - * @head_room: Head room needed by link support layer - * @layer: Lowest layer in CAIF stack - * @rcv_fun: Receive function for CAIF stack. - * - * This function enroll a CAIF link layer into CAIF Stack and - * expects the interface to be able to handle CAIF payload. - * The link_support layer is used to add any Link Layer specific - * framing. - */ -int caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, - struct cflayer *link_support, int head_room, - struct cflayer **layer, int (**rcv_func)( - struct sk_buff *, struct net_device *, - struct packet_type *, struct net_device *)); - -#endif /* CAIF_DEV_H_ */ diff --git a/include/net/caif/caif_device.h b/include/net/caif/caif_device.h deleted file mode 100644 index 91d1fd5b44a4..000000000000 --- a/include/net/caif/caif_device.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CAIF_DEVICE_H_ -#define CAIF_DEVICE_H_ -#include -#include -#include -#include -#include - -/** - * struct caif_dev_common - data shared between CAIF drivers and stack. - * @flowctrl: Flow Control callback function. This function is - * supplied by CAIF Core Stack and is used by CAIF - * Link Layer to send flow-stop to CAIF Core. - * The flow information will be distributed to all - * clients of CAIF. - * - * @link_select: Profile of device, either high-bandwidth or - * low-latency. This member is set by CAIF Link - * Layer Device in order to indicate if this device - * is a high bandwidth or low latency device. - * - * @use_frag: CAIF Frames may be fragmented. - * Is set by CAIF Link Layer in order to indicate if the - * interface receives fragmented frames that must be - * assembled by CAIF Core Layer. - * - * @use_fcs: Indicate if Frame CheckSum (fcs) is used. - * Is set if the physical interface is - * using Frame Checksum on the CAIF Frames. - * - * @use_stx: Indicate STart of frame eXtension (stx) in use. - * Is set if the CAIF Link Layer expects - * CAIF Frames to start with the STX byte. - * - * This structure is shared between the CAIF drivers and the CAIF stack. - * It is used by the device to register its behavior. - * CAIF Core layer must set the member flowctrl in order to supply - * CAIF Link Layer with the flow control function. - * - */ - struct caif_dev_common { - void (*flowctrl)(struct net_device *net, int on); - enum caif_link_selector link_select; - int use_frag; - int use_fcs; - int use_stx; -}; - -#endif /* CAIF_DEVICE_H_ */ diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h deleted file mode 100644 index 053e7c6a6a66..000000000000 --- a/include/net/caif/caif_layer.h +++ /dev/null @@ -1,277 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CAIF_LAYER_H_ -#define CAIF_LAYER_H_ - -#include - -struct cflayer; -struct cfpkt; -struct caif_payload_info; - -#define CAIF_LAYER_NAME_SZ 16 - -/** - * caif_assert() - Assert function for CAIF. - * @assert: expression to evaluate. - * - * This function will print a error message and a do WARN_ON if the - * assertion fails. Normally this will do a stack up at the current location. - */ -#define caif_assert(assert) \ -do { \ - if (!(assert)) { \ - pr_err("caif:Assert detected:'%s'\n", #assert); \ - WARN_ON(!(assert)); \ - } \ -} while (0) - -/** - * enum caif_ctrlcmd - CAIF Stack Control Signaling sent in layer.ctrlcmd(). - * - * @CAIF_CTRLCMD_FLOW_OFF_IND: Flow Control is OFF, transmit function - * should stop sending data - * - * @CAIF_CTRLCMD_FLOW_ON_IND: Flow Control is ON, transmit function - * can start sending data - * - * @CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND: Remote end modem has decided to close - * down channel - * - * @CAIF_CTRLCMD_INIT_RSP: Called initially when the layer below - * has finished initialization - * - * @CAIF_CTRLCMD_DEINIT_RSP: Called when de-initialization is - * complete - * - * @CAIF_CTRLCMD_INIT_FAIL_RSP: Called if initialization fails - * - * @_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: CAIF Link layer temporarily cannot - * send more packets. - * @_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND: Called if CAIF Link layer is able - * to send packets again. - * @_CAIF_CTRLCMD_PHYIF_DOWN_IND: Called if CAIF Link layer is going - * down. - * - * These commands are sent upwards in the CAIF stack to the CAIF Client. - * They are used for signaling originating from the modem or CAIF Link Layer. - * These are either responses (*_RSP) or events (*_IND). - */ -enum caif_ctrlcmd { - CAIF_CTRLCMD_FLOW_OFF_IND, - CAIF_CTRLCMD_FLOW_ON_IND, - CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, - CAIF_CTRLCMD_INIT_RSP, - CAIF_CTRLCMD_DEINIT_RSP, - CAIF_CTRLCMD_INIT_FAIL_RSP, - _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, - _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND, - _CAIF_CTRLCMD_PHYIF_DOWN_IND, -}; - -/** - * enum caif_modemcmd - Modem Control Signaling, sent from CAIF Client - * to the CAIF Link Layer or modem. - * - * @CAIF_MODEMCMD_FLOW_ON_REQ: Flow Control is ON, transmit function - * can start sending data. - * - * @CAIF_MODEMCMD_FLOW_OFF_REQ: Flow Control is OFF, transmit function - * should stop sending data. - * - * @_CAIF_MODEMCMD_PHYIF_USEFULL: Notify physical layer that it is in use - * - * @_CAIF_MODEMCMD_PHYIF_USELESS: Notify physical layer that it is - * no longer in use. - * - * These are requests sent 'downwards' in the stack. - * Flow ON, OFF can be indicated to the modem. - */ -enum caif_modemcmd { - CAIF_MODEMCMD_FLOW_ON_REQ = 0, - CAIF_MODEMCMD_FLOW_OFF_REQ = 1, - _CAIF_MODEMCMD_PHYIF_USEFULL = 3, - _CAIF_MODEMCMD_PHYIF_USELESS = 4 -}; - -/** - * enum caif_direction - CAIF Packet Direction. - * Indicate if a packet is to be sent out or to be received in. - * @CAIF_DIR_IN: Incoming packet received. - * @CAIF_DIR_OUT: Outgoing packet to be transmitted. - */ -enum caif_direction { - CAIF_DIR_IN = 0, - CAIF_DIR_OUT = 1 -}; - -/** - * struct cflayer - CAIF Stack layer. - * Defines the framework for the CAIF Core Stack. - * @up: Pointer up to the layer above. - * @dn: Pointer down to the layer below. - * @node: List node used when layer participate in a list. - * @receive: Packet receive function. - * @transmit: Packet transmit function. - * @ctrlcmd: Used for control signalling upwards in the stack. - * @modemcmd: Used for control signaling downwards in the stack. - * @id: The identity of this layer - * @name: Name of the layer. - * - * This structure defines the layered structure in CAIF. - * - * It defines CAIF layering structure, used by all CAIF Layers and the - * layers interfacing CAIF. - * - * In order to integrate with CAIF an adaptation layer on top of the CAIF stack - * and PHY layer below the CAIF stack - * must be implemented. These layer must follow the design principles below. - * - * Principles for layering of protocol layers: - * - All layers must use this structure. If embedding it, then place this - * structure first in the layer specific structure. - * - * - Each layer should not depend on any others layer's private data. - * - * - In order to send data upwards do - * layer->up->receive(layer->up, packet); - * - * - In order to send data downwards do - * layer->dn->transmit(layer->dn, info, packet); - */ -struct cflayer { - struct cflayer *up; - struct cflayer *dn; - struct list_head node; - - /* - * receive() - Receive Function (non-blocking). - * Contract: Each layer must implement a receive function passing the - * CAIF packets upwards in the stack. - * Packet handling rules: - * - The CAIF packet (cfpkt) ownership is passed to the - * called receive function. This means that the - * packet cannot be accessed after passing it to the - * above layer using up->receive(). - * - * - If parsing of the packet fails, the packet must be - * destroyed and negative error code returned - * from the function. - * EXCEPTION: If the framing layer (cffrml) returns - * -EILSEQ, the packet is not freed. - * - * - If parsing succeeds (and above layers return OK) then - * the function must return a value >= 0. - * - * Returns result < 0 indicates an error, 0 or positive value - * indicates success. - * - * @layr: Pointer to the current layer the receive function is - * implemented for (this pointer). - * @cfpkt: Pointer to CaifPacket to be handled. - */ - int (*receive)(struct cflayer *layr, struct cfpkt *cfpkt); - - /* - * transmit() - Transmit Function (non-blocking). - * Contract: Each layer must implement a transmit function passing the - * CAIF packet downwards in the stack. - * Packet handling rules: - * - The CAIF packet (cfpkt) ownership is passed to the - * transmit function. This means that the packet - * cannot be accessed after passing it to the below - * layer using dn->transmit(). - * - * - Upon error the packet ownership is still passed on, - * so the packet shall be freed where error is detected. - * Callers of the transmit function shall not free packets, - * but errors shall be returned. - * - * - Return value less than zero means error, zero or - * greater than zero means OK. - * - * Returns result < 0 indicates an error, 0 or positive value - * indicates success. - * - * @layr: Pointer to the current layer the receive function - * isimplemented for (this pointer). - * @cfpkt: Pointer to CaifPacket to be handled. - */ - int (*transmit) (struct cflayer *layr, struct cfpkt *cfpkt); - - /* - * cttrlcmd() - Control Function upwards in CAIF Stack (non-blocking). - * Used for signaling responses (CAIF_CTRLCMD_*_RSP) - * and asynchronous events from the modem (CAIF_CTRLCMD_*_IND) - * - * @layr: Pointer to the current layer the receive function - * is implemented for (this pointer). - * @ctrl: Control Command. - */ - void (*ctrlcmd) (struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid); - - /* - * modemctrl() - Control Function used for controlling the modem. - * Used to signal down-wards in the CAIF stack. - * Returns 0 on success, < 0 upon failure. - * - * @layr: Pointer to the current layer the receive function - * is implemented for (this pointer). - * @ctrl: Control Command. - */ - int (*modemcmd) (struct cflayer *layr, enum caif_modemcmd ctrl); - - unsigned int id; - char name[CAIF_LAYER_NAME_SZ]; -}; - -/** - * layer_set_up() - Set the up pointer for a specified layer. - * @layr: Layer where up pointer shall be set. - * @above: Layer above. - */ -#define layer_set_up(layr, above) ((layr)->up = (struct cflayer *)(above)) - -/** - * layer_set_dn() - Set the down pointer for a specified layer. - * @layr: Layer where down pointer shall be set. - * @below: Layer below. - */ -#define layer_set_dn(layr, below) ((layr)->dn = (struct cflayer *)(below)) - -/** - * struct dev_info - Physical Device info information about physical layer. - * @dev: Pointer to native physical device. - * @id: Physical ID of the physical connection used by the - * logical CAIF connection. Used by service layers to - * identify their physical id to Caif MUX (CFMUXL)so - * that the MUX can add the correct physical ID to the - * packet. - */ -struct dev_info { - void *dev; - unsigned int id; -}; - -/** - * struct caif_payload_info - Payload information embedded in packet (sk_buff). - * - * @dev_info: Information about the receiving device. - * - * @hdr_len: Header length, used to align pay load on 32bit boundary. - * - * @channel_id: Channel ID of the logical CAIF connection. - * Used by mux to insert channel id into the caif packet. - */ -struct caif_payload_info { - struct dev_info *dev_info; - unsigned short hdr_len; - unsigned short channel_id; -}; - -#endif /* CAIF_LAYER_H_ */ diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h deleted file mode 100644 index 8819ff4db35a..000000000000 --- a/include/net/caif/cfcnfg.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CFCNFG_H_ -#define CFCNFG_H_ -#include -#include -#include -#include - -struct cfcnfg; - -/** - * enum cfcnfg_phy_preference - Physical preference HW Abstraction - * - * @CFPHYPREF_UNSPECIFIED: Default physical interface - * - * @CFPHYPREF_LOW_LAT: Default physical interface for low-latency - * traffic - * @CFPHYPREF_HIGH_BW: Default physical interface for high-bandwidth - * traffic - * @CFPHYPREF_LOOP: TEST only Loopback interface simulating modem - * responses. - * - */ -enum cfcnfg_phy_preference { - CFPHYPREF_UNSPECIFIED, - CFPHYPREF_LOW_LAT, - CFPHYPREF_HIGH_BW, - CFPHYPREF_LOOP -}; - -/** - * cfcnfg_create() - Get the CAIF configuration object given network. - * @net: Network for the CAIF configuration object. - */ -struct cfcnfg *get_cfcnfg(struct net *net); - -/** - * cfcnfg_create() - Create the CAIF configuration object. - */ -struct cfcnfg *cfcnfg_create(void); - -/** - * cfcnfg_remove() - Remove the CFCNFG object - * @cfg: config object - */ -void cfcnfg_remove(struct cfcnfg *cfg); - -/** - * cfcnfg_add_phy_layer() - Adds a physical layer to the CAIF stack. - * @cnfg: Pointer to a CAIF configuration object, created by - * cfcnfg_create(). - * @dev: Pointer to link layer device - * @phy_layer: Specify the physical layer. The transmit function - * MUST be set in the structure. - * @pref: The phy (link layer) preference. - * @link_support: Protocol implementation for link layer specific protocol. - * @fcs: Specify if checksum is used in CAIF Framing Layer. - * @head_room: Head space needed by link specific protocol. - */ -int -cfcnfg_add_phy_layer(struct cfcnfg *cnfg, - struct net_device *dev, struct cflayer *phy_layer, - enum cfcnfg_phy_preference pref, - struct cflayer *link_support, - bool fcs, int head_room); - -/** - * cfcnfg_del_phy_layer - Deletes an phy layer from the CAIF stack. - * - * @cnfg: Pointer to a CAIF configuration object, created by - * cfcnfg_create(). - * @phy_layer: Adaptation layer to be removed. - */ -int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer); - -/** - * cfcnfg_set_phy_state() - Set the state of the physical interface device. - * @cnfg: Configuration object - * @phy_layer: Physical Layer representation - * @up: State of device - */ -int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer, - bool up); - -#endif /* CFCNFG_H_ */ diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h deleted file mode 100644 index 86d17315c8a1..000000000000 --- a/include/net/caif/cfctrl.h +++ /dev/null @@ -1,130 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CFCTRL_H_ -#define CFCTRL_H_ -#include -#include - -/* CAIF Control packet commands */ -enum cfctrl_cmd { - CFCTRL_CMD_LINK_SETUP = 0, - CFCTRL_CMD_LINK_DESTROY = 1, - CFCTRL_CMD_LINK_ERR = 2, - CFCTRL_CMD_ENUM = 3, - CFCTRL_CMD_SLEEP = 4, - CFCTRL_CMD_WAKE = 5, - CFCTRL_CMD_LINK_RECONF = 6, - CFCTRL_CMD_START_REASON = 7, - CFCTRL_CMD_RADIO_SET = 8, - CFCTRL_CMD_MODEM_SET = 9, - CFCTRL_CMD_MASK = 0xf -}; - -/* Channel types */ -enum cfctrl_srv { - CFCTRL_SRV_DECM = 0, - CFCTRL_SRV_VEI = 1, - CFCTRL_SRV_VIDEO = 2, - CFCTRL_SRV_DBG = 3, - CFCTRL_SRV_DATAGRAM = 4, - CFCTRL_SRV_RFM = 5, - CFCTRL_SRV_UTIL = 6, - CFCTRL_SRV_MASK = 0xf -}; - -#define CFCTRL_RSP_BIT 0x20 -#define CFCTRL_ERR_BIT 0x10 - -struct cfctrl_rsp { - void (*linksetup_rsp)(struct cflayer *layer, u8 linkid, - enum cfctrl_srv serv, u8 phyid, - struct cflayer *adapt_layer); - void (*linkdestroy_rsp)(struct cflayer *layer, u8 linkid); - void (*linkerror_ind)(void); - void (*enum_rsp)(void); - void (*sleep_rsp)(void); - void (*wake_rsp)(void); - void (*restart_rsp)(void); - void (*radioset_rsp)(void); - void (*reject_rsp)(struct cflayer *layer, u8 linkid, - struct cflayer *client_layer); -}; - -/* Link Setup Parameters for CAIF-Links. */ -struct cfctrl_link_param { - enum cfctrl_srv linktype;/* (T3,T0) Type of Channel */ - u8 priority; /* (P4,P0) Priority of the channel */ - u8 phyid; /* (U2-U0) Physical interface to connect */ - u8 endpoint; /* (E1,E0) Endpoint for data channels */ - u8 chtype; /* (H1,H0) Channel-Type, applies to - * VEI, DEBUG */ - union { - struct { - u8 connid; /* (D7,D0) Video LinkId */ - } video; - - struct { - u32 connid; /* (N31,Ngit0) Connection ID used - * for Datagram */ - } datagram; - - struct { - u32 connid; /* Connection ID used for RFM */ - char volume[20]; /* Volume to mount for RFM */ - } rfm; /* Configuration for RFM */ - - struct { - u16 fifosize_kb; /* Psock FIFO size in KB */ - u16 fifosize_bufs; /* Psock # signal buffers */ - char name[16]; /* Name of the PSOCK service */ - u8 params[255]; /* Link setup Parameters> */ - u16 paramlen; /* Length of Link Setup - * Parameters */ - } utility; /* Configuration for Utility Links (Psock) */ - } u; -}; - -/* This structure is used internally in CFCTRL */ -struct cfctrl_request_info { - int sequence_no; - enum cfctrl_cmd cmd; - u8 channel_id; - struct cfctrl_link_param param; - struct cflayer *client_layer; - struct list_head list; -}; - -struct cfctrl { - struct cfsrvl serv; - struct cfctrl_rsp res; - atomic_t req_seq_no; - atomic_t rsp_seq_no; - struct list_head list; - /* Protects from simultaneous access to first_req list */ - spinlock_t info_list_lock; -#ifndef CAIF_NO_LOOP - u8 loop_linkid; - int loop_linkused[256]; - /* Protects simultaneous access to loop_linkid and loop_linkused */ - spinlock_t loop_linkid_lock; -#endif - -}; - -void cfctrl_enum_req(struct cflayer *cfctrl, u8 physlinkid); -int cfctrl_linkup_request(struct cflayer *cfctrl, - struct cfctrl_link_param *param, - struct cflayer *user_layer); -int cfctrl_linkdown_req(struct cflayer *cfctrl, u8 linkid, - struct cflayer *client); - -struct cflayer *cfctrl_create(void); -struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer); -int cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer); -void cfctrl_remove(struct cflayer *layr); - -#endif /* CFCTRL_H_ */ diff --git a/include/net/caif/cffrml.h b/include/net/caif/cffrml.h deleted file mode 100644 index 1ab8a80ede4d..000000000000 --- a/include/net/caif/cffrml.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CFFRML_H_ -#define CFFRML_H_ -#include -#include - -struct cffrml; -struct cflayer *cffrml_create(u16 phyid, bool use_fcs); -void cffrml_free(struct cflayer *layr); -void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up); -void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn); -void cffrml_put(struct cflayer *layr); -void cffrml_hold(struct cflayer *layr); -int cffrml_refcnt_read(struct cflayer *layr); - -#endif /* CFFRML_H_ */ diff --git a/include/net/caif/cfmuxl.h b/include/net/caif/cfmuxl.h deleted file mode 100644 index 92ccb2648309..000000000000 --- a/include/net/caif/cfmuxl.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CFMUXL_H_ -#define CFMUXL_H_ -#include - -struct cfsrvl; -struct cffrml; - -struct cflayer *cfmuxl_create(void); -int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid); -struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid); -int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *up, u8 phyid); -struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 linkid); - -#endif /* CFMUXL_H_ */ diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h deleted file mode 100644 index acf664227d96..000000000000 --- a/include/net/caif/cfpkt.h +++ /dev/null @@ -1,232 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CFPKT_H_ -#define CFPKT_H_ -#include -#include -struct cfpkt; - -/* Create a CAIF packet. - * len: Length of packet to be created - * @return New packet. - */ -struct cfpkt *cfpkt_create(u16 len); - -/* - * Destroy a CAIF Packet. - * pkt Packet to be destroyed. - */ -void cfpkt_destroy(struct cfpkt *pkt); - -/* - * Extract header from packet. - * - * pkt Packet to extract header data from. - * data Pointer to copy the header data into. - * len Length of head data to copy. - * @return zero on success and error code upon failure - */ -int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len); - -static inline u8 cfpkt_extr_head_u8(struct cfpkt *pkt) -{ - u8 tmp; - - cfpkt_extr_head(pkt, &tmp, 1); - - return tmp; -} - -static inline u16 cfpkt_extr_head_u16(struct cfpkt *pkt) -{ - __le16 tmp; - - cfpkt_extr_head(pkt, &tmp, 2); - - return le16_to_cpu(tmp); -} - -static inline u32 cfpkt_extr_head_u32(struct cfpkt *pkt) -{ - __le32 tmp; - - cfpkt_extr_head(pkt, &tmp, 4); - - return le32_to_cpu(tmp); -} - -/* - * Peek header from packet. - * Reads data from packet without changing packet. - * - * pkt Packet to extract header data from. - * data Pointer to copy the header data into. - * len Length of head data to copy. - * @return zero on success and error code upon failure - */ -int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len); - -/* - * Extract header from trailer (end of packet). - * - * pkt Packet to extract header data from. - * data Pointer to copy the trailer data into. - * len Length of header data to copy. - * @return zero on success and error code upon failure - */ -int cfpkt_extr_trail(struct cfpkt *pkt, void *data, u16 len); - -/* - * Add header to packet. - * - * - * pkt Packet to add header data to. - * data Pointer to data to copy into the header. - * len Length of header data to copy. - * @return zero on success and error code upon failure - */ -int cfpkt_add_head(struct cfpkt *pkt, const void *data, u16 len); - -/* - * Add trailer to packet. - * - * - * pkt Packet to add trailer data to. - * data Pointer to data to copy into the trailer. - * len Length of trailer data to copy. - * @return zero on success and error code upon failure - */ -int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len); - -/* - * Pad trailer on packet. - * Moves data pointer in packet, no content copied. - * - * pkt Packet in which to pad trailer. - * len Length of padding to add. - * @return zero on success and error code upon failure - */ -int cfpkt_pad_trail(struct cfpkt *pkt, u16 len); - -/* - * Add a single byte to packet body (tail). - * - * pkt Packet in which to add byte. - * data Byte to add. - * @return zero on success and error code upon failure - */ -int cfpkt_addbdy(struct cfpkt *pkt, const u8 data); - -/* - * Add a data to packet body (tail). - * - * pkt Packet in which to add data. - * data Pointer to data to copy into the packet body. - * len Length of data to add. - * @return zero on success and error code upon failure - */ -int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len); - -/* - * Checks whether there are more data to process in packet. - * pkt Packet to check. - * @return true if more data are available in packet false otherwise - */ -bool cfpkt_more(struct cfpkt *pkt); - -/* - * Checks whether the packet is erroneous, - * i.e. if it has been attempted to extract more data than available in packet - * or writing more data than has been allocated in cfpkt_create(). - * pkt Packet to check. - * @return true on error false otherwise - */ -bool cfpkt_erroneous(struct cfpkt *pkt); - -/* - * Get the packet length. - * pkt Packet to get length from. - * @return Number of bytes in packet. - */ -u16 cfpkt_getlen(struct cfpkt *pkt); - -/* - * Set the packet length, by adjusting the trailer pointer according to length. - * pkt Packet to set length. - * len Packet length. - * @return Number of bytes in packet. - */ -int cfpkt_setlen(struct cfpkt *pkt, u16 len); - -/* - * cfpkt_append - Appends a packet's data to another packet. - * dstpkt: Packet to append data into, WILL BE FREED BY THIS FUNCTION - * addpkt: Packet to be appended and automatically released, - * WILL BE FREED BY THIS FUNCTION. - * expectlen: Packet's expected total length. This should be considered - * as a hint. - * NB: Input packets will be destroyed after appending and cannot be used - * after calling this function. - * @return The new appended packet. - */ -struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt, - u16 expectlen); - -/* - * cfpkt_split - Split a packet into two packets at the specified split point. - * pkt: Packet to be split (will contain the first part of the data on exit) - * pos: Position to split packet in two parts. - * @return The new packet, containing the second part of the data. - */ -struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos); - -/* - * Iteration function, iterates the packet buffers from start to end. - * - * Checksum iteration function used to iterate buffers - * (we may have packets consisting of a chain of buffers) - * pkt: Packet to calculate checksum for - * iter_func: Function pointer to iteration function - * chks: Checksum calculated so far. - * buf: Pointer to the buffer to checksum - * len: Length of buf. - * data: Initial checksum value. - * @return Checksum of buffer. - */ - -int cfpkt_iterate(struct cfpkt *pkt, - u16 (*iter_func)(u16 chks, void *buf, u16 len), - u16 data); - -/* Map from a "native" packet (e.g. Linux Socket Buffer) to a CAIF packet. - * dir - Direction indicating whether this packet is to be sent or received. - * nativepkt - The native packet to be transformed to a CAIF packet - * @return The mapped CAIF Packet CFPKT. - */ -struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt); - -/* Map from a CAIF packet to a "native" packet (e.g. Linux Socket Buffer). - * pkt - The CAIF packet to be transformed into a "native" packet. - * @return The native packet transformed from a CAIF packet. - */ -void *cfpkt_tonative(struct cfpkt *pkt); - -/* - * Returns packet information for a packet. - * pkt Packet to get info from; - * @return Packet information - */ -struct caif_payload_info *cfpkt_info(struct cfpkt *pkt); - -/** cfpkt_set_prio - set priority for a CAIF packet. - * - * @pkt: The CAIF packet to be adjusted. - * @prio: one of TC_PRIO_ constants. - */ -void cfpkt_set_prio(struct cfpkt *pkt, int prio); - -#endif /* CFPKT_H_ */ diff --git a/include/net/caif/cfserl.h b/include/net/caif/cfserl.h deleted file mode 100644 index 67cce8757175..000000000000 --- a/include/net/caif/cfserl.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CFSERL_H_ -#define CFSERL_H_ -#include - -struct cflayer *cfserl_create(int instance, bool use_stx); -void cfserl_release(struct cflayer *layer); -#endif diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h deleted file mode 100644 index a000dc45f966..000000000000 --- a/include/net/caif/cfsrvl.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#ifndef CFSRVL_H_ -#define CFSRVL_H_ -#include -#include -#include -#include -#include - -struct cfsrvl { - struct cflayer layer; - bool open; - bool phy_flow_on; - bool modem_flow_on; - bool supports_flowctrl; - void (*release)(struct cflayer *layer); - struct dev_info dev_info; - void (*hold)(struct cflayer *lyr); - void (*put)(struct cflayer *lyr); - struct rcu_head rcu; -}; - -struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info); -struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info); -struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info); -struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info); -struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info, - int mtu_size); -struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info); - -bool cfsrvl_phyid_match(struct cflayer *layer, int phyid); - -void cfsrvl_init(struct cfsrvl *service, - u8 channel_id, - struct dev_info *dev_info, - bool supports_flowctrl); -bool cfsrvl_ready(struct cfsrvl *service, int *err); - -static inline void cfsrvl_get(struct cflayer *layr) -{ - struct cfsrvl *s = container_of(layr, struct cfsrvl, layer); - if (layr == NULL || layr->up == NULL || s->hold == NULL) - return; - - s->hold(layr->up); -} - -static inline void cfsrvl_put(struct cflayer *layr) -{ - struct cfsrvl *s = container_of(layr, struct cfsrvl, layer); - if (layr == NULL || layr->up == NULL || s->hold == NULL) - return; - - s->put(layr->up); -} -#endif /* CFSRVL_H_ */ diff --git a/include/net/netrom.h b/include/net/netrom.h deleted file mode 100644 index f0565a5987d1..000000000000 --- a/include/net/netrom.h +++ /dev/null @@ -1,273 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Declarations of NET/ROM type objects. - * - * Jonathan Naylor G4KLX 9/4/95 - */ - -#ifndef _NETROM_H -#define _NETROM_H - -#include -#include -#include -#include -#include -#include -#include - -#define NR_NETWORK_LEN 15 -#define NR_TRANSPORT_LEN 5 - -#define NR_PROTO_IP 0x0C - -#define NR_PROTOEXT 0x00 -#define NR_CONNREQ 0x01 -#define NR_CONNACK 0x02 -#define NR_DISCREQ 0x03 -#define NR_DISCACK 0x04 -#define NR_INFO 0x05 -#define NR_INFOACK 0x06 -#define NR_RESET 0x07 - -#define NR_CHOKE_FLAG 0x80 -#define NR_NAK_FLAG 0x40 -#define NR_MORE_FLAG 0x20 - -/* Define Link State constants. */ -enum { - NR_STATE_0, - NR_STATE_1, - NR_STATE_2, - NR_STATE_3 -}; - -#define NR_COND_ACK_PENDING 0x01 -#define NR_COND_REJECT 0x02 -#define NR_COND_PEER_RX_BUSY 0x04 -#define NR_COND_OWN_RX_BUSY 0x08 - -#define NR_DEFAULT_T1 120000 /* Outstanding frames - 120 seconds */ -#define NR_DEFAULT_T2 5000 /* Response delay - 5 seconds */ -#define NR_DEFAULT_N2 3 /* Number of Retries - 3 */ -#define NR_DEFAULT_T4 180000 /* Busy Delay - 180 seconds */ -#define NR_DEFAULT_IDLE 0 /* No Activity Timeout - none */ -#define NR_DEFAULT_WINDOW 4 /* Default Window Size - 4 */ -#define NR_DEFAULT_OBS 6 /* Default Obsolescence Count - 6 */ -#define NR_DEFAULT_QUAL 10 /* Default Neighbour Quality - 10 */ -#define NR_DEFAULT_TTL 16 /* Default Time To Live - 16 */ -#define NR_DEFAULT_ROUTING 1 /* Is routing enabled ? */ -#define NR_DEFAULT_FAILS 2 /* Link fails until route fails */ -#define NR_DEFAULT_RESET 0 /* Sent / accept reset cmds? */ - -#define NR_MODULUS 256 -#define NR_MAX_WINDOW_SIZE 127 /* Maximum Window Allowable - 127 */ -#define NR_MAX_PACKET_SIZE 236 /* Maximum Packet Length - 236 */ - -struct nr_sock { - struct sock sock; - ax25_address user_addr, source_addr, dest_addr; - struct net_device *device; - unsigned char my_index, my_id; - unsigned char your_index, your_id; - unsigned char state, condition, bpqext, window; - unsigned short vs, vr, va, vl; - unsigned char n2, n2count; - unsigned long t1, t2, t4, idle; - unsigned short fraglen; - struct timer_list t1timer; - struct timer_list t2timer; - struct timer_list t4timer; - struct timer_list idletimer; - struct sk_buff_head ack_queue; - struct sk_buff_head reseq_queue; - struct sk_buff_head frag_queue; -}; - -#define nr_sk(sk) ((struct nr_sock *)(sk)) - -struct nr_neigh { - struct hlist_node neigh_node; - ax25_address callsign; - ax25_digi *digipeat; - ax25_cb *ax25; - struct net_device *dev; - unsigned char quality; - unsigned char locked; - unsigned short count; - unsigned int number; - unsigned char failed; - refcount_t refcount; -}; - -struct nr_route { - unsigned char quality; - unsigned char obs_count; - struct nr_neigh *neighbour; -}; - -struct nr_node { - struct hlist_node node_node; - ax25_address callsign; - char mnemonic[7]; - unsigned char which; - unsigned char count; - struct nr_route routes[3]; - refcount_t refcount; - spinlock_t node_lock; -}; - -/********************************************************************* - * nr_node & nr_neigh lists, refcounting and locking - *********************************************************************/ - -#define nr_node_hold(__nr_node) \ - refcount_inc(&((__nr_node)->refcount)) - -static __inline__ void nr_node_put(struct nr_node *nr_node) -{ - if (refcount_dec_and_test(&nr_node->refcount)) { - kfree(nr_node); - } -} - -#define nr_neigh_hold(__nr_neigh) \ - refcount_inc(&((__nr_neigh)->refcount)) - -static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) -{ - if (refcount_dec_and_test(&nr_neigh->refcount)) { - if (nr_neigh->ax25) - ax25_cb_put(nr_neigh->ax25); - kfree(nr_neigh->digipeat); - kfree(nr_neigh); - } -} - -/* nr_node_lock and nr_node_unlock also hold/put the node's refcounter. - */ -static __inline__ void nr_node_lock(struct nr_node *nr_node) -{ - nr_node_hold(nr_node); - spin_lock_bh(&nr_node->node_lock); -} - -static __inline__ void nr_node_unlock(struct nr_node *nr_node) -{ - spin_unlock_bh(&nr_node->node_lock); - nr_node_put(nr_node); -} - -#define nr_neigh_for_each(__nr_neigh, list) \ - hlist_for_each_entry(__nr_neigh, list, neigh_node) - -#define nr_neigh_for_each_safe(__nr_neigh, node2, list) \ - hlist_for_each_entry_safe(__nr_neigh, node2, list, neigh_node) - -#define nr_node_for_each(__nr_node, list) \ - hlist_for_each_entry(__nr_node, list, node_node) - -#define nr_node_for_each_safe(__nr_node, node2, list) \ - hlist_for_each_entry_safe(__nr_node, node2, list, node_node) - - -/*********************************************************************/ - -/* af_netrom.c */ -extern int sysctl_netrom_default_path_quality; -extern int sysctl_netrom_obsolescence_count_initialiser; -extern int sysctl_netrom_network_ttl_initialiser; -extern int sysctl_netrom_transport_timeout; -extern int sysctl_netrom_transport_maximum_tries; -extern int sysctl_netrom_transport_acknowledge_delay; -extern int sysctl_netrom_transport_busy_delay; -extern int sysctl_netrom_transport_requested_window_size; -extern int sysctl_netrom_transport_no_activity_timeout; -extern int sysctl_netrom_routing_control; -extern int sysctl_netrom_link_fails_count; -extern int sysctl_netrom_reset_circuit; - -int nr_rx_frame(struct sk_buff *, struct net_device *); -void nr_destroy_socket(struct sock *); - -/* nr_dev.c */ -int nr_rx_ip(struct sk_buff *, struct net_device *); -void nr_setup(struct net_device *); - -/* nr_in.c */ -int nr_process_rx_frame(struct sock *, struct sk_buff *); - -/* nr_loopback.c */ -void nr_loopback_init(void); -void nr_loopback_clear(void); -int nr_loopback_queue(struct sk_buff *); - -/* nr_out.c */ -void nr_output(struct sock *, struct sk_buff *); -void nr_send_nak_frame(struct sock *); -void nr_kick(struct sock *); -void nr_transmit_buffer(struct sock *, struct sk_buff *); -void nr_establish_data_link(struct sock *); -void nr_enquiry_response(struct sock *); -void nr_check_iframes_acked(struct sock *, unsigned short); - -/* nr_route.c */ -void nr_rt_device_down(struct net_device *); -struct net_device *nr_dev_first(void); -struct net_device *nr_dev_get(ax25_address *); -int nr_rt_ioctl(unsigned int, void __user *); -void nr_link_failed(ax25_cb *, int); -int nr_route_frame(struct sk_buff *, ax25_cb *); -extern const struct seq_operations nr_node_seqops; -extern const struct seq_operations nr_neigh_seqops; -void nr_rt_free(void); - -/* nr_subr.c */ -void nr_clear_queues(struct sock *); -void nr_frames_acked(struct sock *, unsigned short); -void nr_requeue_frames(struct sock *); -int nr_validate_nr(struct sock *, unsigned short); -int nr_in_rx_window(struct sock *, unsigned short); -void nr_write_internal(struct sock *, int); - -void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags); - -/* - * This routine is called when a Connect Acknowledge with the Choke Flag - * set is needed to refuse a connection. - */ -#define nr_transmit_refusal(skb, mine) \ -do { \ - __nr_transmit_reply((skb), (mine), NR_CONNACK | NR_CHOKE_FLAG); \ -} while (0) - -/* - * This routine is called when we don't have a circuit matching an incoming - * NET/ROM packet. This is an G8PZT Xrouter extension. - */ -#define nr_transmit_reset(skb, mine) \ -do { \ - __nr_transmit_reply((skb), (mine), NR_RESET); \ -} while (0) - -void nr_disconnect(struct sock *, int); - -/* nr_timer.c */ -void nr_init_timers(struct sock *sk); -void nr_start_heartbeat(struct sock *); -void nr_start_t1timer(struct sock *); -void nr_start_t2timer(struct sock *); -void nr_start_t4timer(struct sock *); -void nr_start_idletimer(struct sock *); -void nr_stop_heartbeat(struct sock *); -void nr_stop_t1timer(struct sock *); -void nr_stop_t2timer(struct sock *); -void nr_stop_t4timer(struct sock *); -void nr_stop_idletimer(struct sock *); -int nr_t1timer_running(struct sock *); - -/* sysctl_net_netrom.c */ -int nr_register_sysctl(void); -void nr_unregister_sysctl(void); - -#endif diff --git a/include/net/rose.h b/include/net/rose.h index 2b5491bbf39a..41bfcb224f0b 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -1,266 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * Declarations of Rose type objects. - * - * Jonathan Naylor G4KLX 25/8/96 - */ - #ifndef _ROSE_H -#define _ROSE_H +#define _ROSE_H -#include -#include -#include -#include - -#define ROSE_ADDR_LEN 5 - -#define ROSE_MIN_LEN 3 - -#define ROSE_CALL_REQ_ADDR_LEN_OFF 3 -#define ROSE_CALL_REQ_ADDR_LEN_VAL 0xAA /* each address is 10 digits */ -#define ROSE_CALL_REQ_DEST_ADDR_OFF 4 -#define ROSE_CALL_REQ_SRC_ADDR_OFF 9 -#define ROSE_CALL_REQ_FACILITIES_OFF 14 - -#define ROSE_GFI 0x10 -#define ROSE_Q_BIT 0x80 -#define ROSE_D_BIT 0x40 -#define ROSE_M_BIT 0x10 - -#define ROSE_CALL_REQUEST 0x0B -#define ROSE_CALL_ACCEPTED 0x0F -#define ROSE_CLEAR_REQUEST 0x13 -#define ROSE_CLEAR_CONFIRMATION 0x17 -#define ROSE_DATA 0x00 -#define ROSE_INTERRUPT 0x23 -#define ROSE_INTERRUPT_CONFIRMATION 0x27 -#define ROSE_RR 0x01 -#define ROSE_RNR 0x05 -#define ROSE_REJ 0x09 -#define ROSE_RESET_REQUEST 0x1B -#define ROSE_RESET_CONFIRMATION 0x1F -#define ROSE_REGISTRATION_REQUEST 0xF3 -#define ROSE_REGISTRATION_CONFIRMATION 0xF7 -#define ROSE_RESTART_REQUEST 0xFB -#define ROSE_RESTART_CONFIRMATION 0xFF -#define ROSE_DIAGNOSTIC 0xF1 -#define ROSE_ILLEGAL 0xFD - -/* Define Link State constants. */ - -enum { - ROSE_STATE_0, /* Ready */ - ROSE_STATE_1, /* Awaiting Call Accepted */ - ROSE_STATE_2, /* Awaiting Clear Confirmation */ - ROSE_STATE_3, /* Data Transfer */ - ROSE_STATE_4, /* Awaiting Reset Confirmation */ - ROSE_STATE_5 /* Deferred Call Acceptance */ -}; - -#define ROSE_DEFAULT_T0 180000 /* Default T10 T20 value */ -#define ROSE_DEFAULT_T1 200000 /* Default T11 T21 value */ -#define ROSE_DEFAULT_T2 180000 /* Default T12 T22 value */ -#define ROSE_DEFAULT_T3 180000 /* Default T13 T23 value */ -#define ROSE_DEFAULT_HB 5000 /* Default Holdback value */ -#define ROSE_DEFAULT_IDLE 0 /* No Activity Timeout - none */ -#define ROSE_DEFAULT_ROUTING 1 /* Default routing flag */ -#define ROSE_DEFAULT_FAIL_TIMEOUT 120000 /* Time until link considered usable */ -#define ROSE_DEFAULT_MAXVC 50 /* Maximum number of VCs per neighbour */ -#define ROSE_DEFAULT_WINDOW_SIZE 7 /* Default window size */ - -#define ROSE_MODULUS 8 -#define ROSE_MAX_PACKET_SIZE 251 /* Maximum packet size */ - -#define ROSE_COND_ACK_PENDING 0x01 -#define ROSE_COND_PEER_RX_BUSY 0x02 -#define ROSE_COND_OWN_RX_BUSY 0x04 - -#define FAC_NATIONAL 0x00 -#define FAC_CCITT 0x0F - -#define FAC_NATIONAL_RAND 0x7F -#define FAC_NATIONAL_FLAGS 0x3F -#define FAC_NATIONAL_DEST_DIGI 0xE9 -#define FAC_NATIONAL_SRC_DIGI 0xEB -#define FAC_NATIONAL_FAIL_CALL 0xED -#define FAC_NATIONAL_FAIL_ADD 0xEE -#define FAC_NATIONAL_DIGIS 0xEF - -#define FAC_CCITT_DEST_NSAP 0xC9 -#define FAC_CCITT_SRC_NSAP 0xCB - -struct rose_neigh { - struct rose_neigh *next; - ax25_address callsign; - ax25_digi *digipeat; - ax25_cb *ax25; - struct net_device *dev; - unsigned short count; - refcount_t use; - unsigned int number; - char restarted; - char dce_mode; - char loopback; - struct sk_buff_head queue; - struct timer_list t0timer; - struct timer_list ftimer; -}; - -struct rose_node { - struct rose_node *next; - rose_address address; - unsigned short mask; - unsigned char count; - char loopback; - struct rose_neigh *neighbour[3]; -}; - -struct rose_route { - struct rose_route *next; - unsigned int lci1, lci2; - rose_address src_addr, dest_addr; - ax25_address src_call, dest_call; - struct rose_neigh *neigh1, *neigh2; - unsigned int rand; -}; - -struct rose_sock { - struct sock sock; - rose_address source_addr, dest_addr; - ax25_address source_call, dest_call; - unsigned char source_ndigis, dest_ndigis; - ax25_address source_digis[ROSE_MAX_DIGIS]; - ax25_address dest_digis[ROSE_MAX_DIGIS]; - struct rose_neigh *neighbour; - struct net_device *device; - netdevice_tracker dev_tracker; - unsigned int lci, rand; - unsigned char state, condition, qbitincl, defer; - unsigned char cause, diagnostic; - unsigned short vs, vr, va, vl; - unsigned long t1, t2, t3, hb, idle; -#ifdef M_BIT - unsigned short fraglen; - struct sk_buff_head frag_queue; -#endif - struct sk_buff_head ack_queue; - struct rose_facilities_struct facilities; - struct timer_list timer; - struct timer_list idletimer; -}; - -#define rose_sk(sk) ((struct rose_sock *)(sk)) - -static inline void rose_neigh_hold(struct rose_neigh *rose_neigh) -{ - refcount_inc(&rose_neigh->use); -} - -static inline void rose_neigh_put(struct rose_neigh *rose_neigh) -{ - if (refcount_dec_and_test(&rose_neigh->use)) { - if (rose_neigh->ax25) - ax25_cb_put(rose_neigh->ax25); - kfree(rose_neigh->digipeat); - kfree(rose_neigh); - } -} - -/* af_rose.c */ -extern ax25_address rose_callsign; -extern int sysctl_rose_restart_request_timeout; -extern int sysctl_rose_call_request_timeout; -extern int sysctl_rose_reset_request_timeout; -extern int sysctl_rose_clear_request_timeout; -extern int sysctl_rose_no_activity_timeout; -extern int sysctl_rose_ack_hold_back_timeout; -extern int sysctl_rose_routing_control; -extern int sysctl_rose_link_fail_timeout; -extern int sysctl_rose_maximum_vcs; -extern int sysctl_rose_window_size; - -int rosecmp(const rose_address *, const rose_address *); -int rosecmpm(const rose_address *, const rose_address *, unsigned short); -char *rose2asc(char *buf, const rose_address *); -struct sock *rose_find_socket(unsigned int, struct rose_neigh *); -void rose_kill_by_neigh(struct rose_neigh *); -unsigned int rose_new_lci(struct rose_neigh *); -int rose_rx_call_request(struct sk_buff *, struct net_device *, - struct rose_neigh *, unsigned int); -void rose_destroy_socket(struct sock *); - -/* rose_dev.c */ -void rose_setup(struct net_device *); - -/* rose_in.c */ -int rose_process_rx_frame(struct sock *, struct sk_buff *); - -/* rose_link.c */ -void rose_start_ftimer(struct rose_neigh *); -void rose_stop_ftimer(struct rose_neigh *); -void rose_stop_t0timer(struct rose_neigh *); -int rose_ftimer_running(struct rose_neigh *); -void rose_link_rx_restart(struct sk_buff *, struct rose_neigh *, - unsigned short); -void rose_transmit_clear_request(struct rose_neigh *, unsigned int, - unsigned char, unsigned char); -void rose_transmit_link(struct sk_buff *, struct rose_neigh *); - -/* rose_loopback.c */ -void rose_loopback_init(void); -void rose_loopback_clear(void); -int rose_loopback_queue(struct sk_buff *, struct rose_neigh *); - -/* rose_out.c */ -void rose_kick(struct sock *); -void rose_enquiry_response(struct sock *); - -/* rose_route.c */ -extern struct rose_neigh *rose_loopback_neigh; -extern const struct seq_operations rose_neigh_seqops; -extern const struct seq_operations rose_node_seqops; -extern struct seq_operations rose_route_seqops; - -void rose_add_loopback_neigh(void); -int __must_check rose_add_loopback_node(const rose_address *); -void rose_del_loopback_node(const rose_address *); -void rose_rt_device_down(struct net_device *); -void rose_link_device_down(struct net_device *); -struct net_device *rose_dev_first(void); -struct net_device *rose_dev_get(rose_address *); -struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *); -struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, - unsigned char *, int); -int rose_rt_ioctl(unsigned int, void __user *); -void rose_link_failed(ax25_cb *, int); -int rose_route_frame(struct sk_buff *, ax25_cb *); -void rose_rt_free(void); - -/* rose_subr.c */ -void rose_clear_queues(struct sock *); -void rose_frames_acked(struct sock *, unsigned short); -void rose_requeue_frames(struct sock *); -int rose_validate_nr(struct sock *, unsigned short); -void rose_write_internal(struct sock *, int); -int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *); -int rose_parse_facilities(unsigned char *, unsigned int, - struct rose_facilities_struct *); -void rose_disconnect(struct sock *, int, int, int); - -/* rose_timer.c */ -void rose_start_heartbeat(struct sock *); -void rose_start_t1timer(struct sock *); -void rose_start_t2timer(struct sock *); -void rose_start_t3timer(struct sock *); -void rose_start_hbtimer(struct sock *); -void rose_start_idletimer(struct sock *); -void rose_stop_heartbeat(struct sock *); -void rose_stop_timer(struct sock *); -void rose_stop_idletimer(struct sock *); - -/* sysctl_net_rose.c */ -void rose_register_sysctl(void); -void rose_unregister_sysctl(void); +#define ROSE_ADDR_LEN 5 #endif diff --git a/include/uapi/linux/baycom.h b/include/uapi/linux/baycom.h deleted file mode 100644 index 478cb565ae52..000000000000 --- a/include/uapi/linux/baycom.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * The Linux BAYCOM driver for the Baycom serial 1200 baud modem - * and the parallel 9600 baud modem - * (C) 1997-1998 by Thomas Sailer, HB9JNX/AE4WA - */ - -#ifndef _BAYCOM_H -#define _BAYCOM_H - -/* -------------------------------------------------------------------- */ -/* - * structs for the IOCTL commands - */ - -struct baycom_debug_data { - unsigned long debug1; - unsigned long debug2; - long debug3; -}; - -struct baycom_ioctl { - int cmd; - union { - struct baycom_debug_data dbg; - } data; -}; - -/* -------------------------------------------------------------------- */ - -/* - * ioctl values change for baycom - */ -#define BAYCOMCTL_GETDEBUG 0x92 - -/* -------------------------------------------------------------------- */ - -#endif /* _BAYCOM_H */ - -/* --------------------------------------------------------------------- */ diff --git a/include/uapi/linux/caif/caif_socket.h b/include/uapi/linux/caif/caif_socket.h deleted file mode 100644 index d9970bbaa156..000000000000 --- a/include/uapi/linux/caif/caif_socket.h +++ /dev/null @@ -1,195 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* linux/caif_socket.h - * CAIF Definitions for CAIF socket and network layer - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - * License terms: GNU General Public License (GPL) version 2 - */ - -#ifndef _LINUX_CAIF_SOCKET_H -#define _LINUX_CAIF_SOCKET_H - -#include -#include - -/** - * enum caif_link_selector - Physical Link Selection. - * @CAIF_LINK_HIGH_BANDW: Physical interface for high-bandwidth - * traffic. - * @CAIF_LINK_LOW_LATENCY: Physical interface for low-latency - * traffic. - * - * CAIF Link Layers can register their link properties. - * This enum is used for choosing between CAIF Link Layers when - * setting up CAIF Channels when multiple CAIF Link Layers exists. - */ -enum caif_link_selector { - CAIF_LINK_HIGH_BANDW, - CAIF_LINK_LOW_LATENCY -}; - -/** - * enum caif_channel_priority - CAIF channel priorities. - * - * @CAIF_PRIO_MIN: Min priority for a channel. - * @CAIF_PRIO_LOW: Low-priority channel. - * @CAIF_PRIO_NORMAL: Normal/default priority level. - * @CAIF_PRIO_HIGH: High priority level - * @CAIF_PRIO_MAX: Max priority for channel - * - * Priority can be set on CAIF Channels in order to - * prioritize between traffic on different CAIF Channels. - * These priority levels are recommended, but the priority value - * is not restricted to the values defined in this enum, any value - * between CAIF_PRIO_MIN and CAIF_PRIO_MAX could be used. - */ -enum caif_channel_priority { - CAIF_PRIO_MIN = 0x01, - CAIF_PRIO_LOW = 0x04, - CAIF_PRIO_NORMAL = 0x0f, - CAIF_PRIO_HIGH = 0x14, - CAIF_PRIO_MAX = 0x1F -}; - -/** - * enum caif_protocol_type - CAIF Channel type. - * @CAIFPROTO_AT: Classic AT channel. - * @CAIFPROTO_DATAGRAM: Datagram channel. - * @CAIFPROTO_DATAGRAM_LOOP: Datagram loopback channel, used for testing. - * @CAIFPROTO_UTIL: Utility (Psock) channel. - * @CAIFPROTO_RFM: Remote File Manager - * @CAIFPROTO_DEBUG: Debug link - * - * This enum defines the CAIF Channel type to be used. This defines - * the service to connect to on the modem. - */ -enum caif_protocol_type { - CAIFPROTO_AT, - CAIFPROTO_DATAGRAM, - CAIFPROTO_DATAGRAM_LOOP, - CAIFPROTO_UTIL, - CAIFPROTO_RFM, - CAIFPROTO_DEBUG, - _CAIFPROTO_MAX -}; -#define CAIFPROTO_MAX _CAIFPROTO_MAX - -/** - * enum caif_at_type - AT Service Endpoint - * @CAIF_ATTYPE_PLAIN: Connects to a plain vanilla AT channel. - */ -enum caif_at_type { - CAIF_ATTYPE_PLAIN = 2 -}; - /** - * enum caif_debug_type - Content selection for debug connection - * @CAIF_DEBUG_TRACE_INTERACTIVE: Connection will contain - * both trace and interactive debug. - * @CAIF_DEBUG_TRACE: Connection contains trace only. - * @CAIF_DEBUG_INTERACTIVE: Connection to interactive debug. - */ -enum caif_debug_type { - CAIF_DEBUG_TRACE_INTERACTIVE = 0, - CAIF_DEBUG_TRACE, - CAIF_DEBUG_INTERACTIVE, -}; - -/** - * enum caif_debug_service - Debug Service Endpoint - * @CAIF_RADIO_DEBUG_SERVICE: Debug service on the Radio sub-system - * @CAIF_APP_DEBUG_SERVICE: Debug for the applications sub-system - */ -enum caif_debug_service { - CAIF_RADIO_DEBUG_SERVICE = 1, - CAIF_APP_DEBUG_SERVICE -}; - -/** - * struct sockaddr_caif - the sockaddr structure for CAIF sockets. - * @family: Address family number, must be AF_CAIF. - * @u: Union of address data 'switched' by family. - * : - * @u.at: Applies when family = CAIFPROTO_AT. - * - * @u.at.type: Type of AT link to set up (enum caif_at_type). - * - * @u.util: Applies when family = CAIFPROTO_UTIL - * - * @u.util.service: Utility service name. - * - * @u.dgm: Applies when family = CAIFPROTO_DATAGRAM - * - * @u.dgm.connection_id: Datagram connection id. - * - * @u.dgm.nsapi: NSAPI of the PDP-Context. - * - * @u.rfm: Applies when family = CAIFPROTO_RFM - * - * @u.rfm.connection_id: Connection ID for RFM. - * - * @u.rfm.volume: Volume to mount. - * - * @u.dbg: Applies when family = CAIFPROTO_DEBUG. - * - * @u.dbg.type: Type of debug connection to set up - * (caif_debug_type). - * - * @u.dbg.service: Service sub-system to connect (caif_debug_service - * Description: - * This structure holds the connect parameters used for setting up a - * CAIF Channel. It defines the service to connect to on the modem. - */ -struct sockaddr_caif { - __kernel_sa_family_t family; - union { - struct { - __u8 type; /* type: enum caif_at_type */ - } at; /* CAIFPROTO_AT */ - struct { - char service[16]; - } util; /* CAIFPROTO_UTIL */ - union { - __u32 connection_id; - __u8 nsapi; - } dgm; /* CAIFPROTO_DATAGRAM(_LOOP)*/ - struct { - __u32 connection_id; - char volume[16]; - } rfm; /* CAIFPROTO_RFM */ - struct { - __u8 type; /* type:enum caif_debug_type */ - __u8 service; /* service:caif_debug_service */ - } dbg; /* CAIFPROTO_DEBUG */ - } u; -}; - -/** - * enum caif_socket_opts - CAIF option values for getsockopt and setsockopt. - * - * @CAIFSO_LINK_SELECT: Selector used if multiple CAIF Link layers are - * available. Either a high bandwidth - * link can be selected (CAIF_LINK_HIGH_BANDW) or - * a low latency link (CAIF_LINK_LOW_LATENCY). - * This option is of type __u32. - * Alternatively SO_BINDTODEVICE can be used. - * - * @CAIFSO_REQ_PARAM: Used to set the request parameters for a - * utility channel. (maximum 256 bytes). This - * option must be set before connecting. - * - * @CAIFSO_RSP_PARAM: Gets the response parameters for a utility - * channel. (maximum 256 bytes). This option - * is valid after a successful connect. - * - * - * This enum defines the CAIF Socket options to be used on a socket - * of type PF_CAIF. - * - */ -enum caif_socket_opts { - CAIFSO_LINK_SELECT = 127, - CAIFSO_REQ_PARAM = 128, - CAIFSO_RSP_PARAM = 129, -}; - -#endif /* _LINUX_CAIF_SOCKET_H */ diff --git a/include/uapi/linux/caif/if_caif.h b/include/uapi/linux/caif/if_caif.h deleted file mode 100644 index 74bca19403fa..000000000000 --- a/include/uapi/linux/caif/if_caif.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - * License terms: GNU General Public License (GPL) version 2 - */ - -#ifndef IF_CAIF_H_ -#define IF_CAIF_H_ -#include -#include -#include - -/** - * enum ifla_caif - CAIF NetlinkRT parameters. - * @IFLA_CAIF_IPV4_CONNID: Connection ID for IPv4 PDP Context. - * The type of attribute is NLA_U32. - * @IFLA_CAIF_IPV6_CONNID: Connection ID for IPv6 PDP Context. - * The type of attribute is NLA_U32. - * @IFLA_CAIF_LOOPBACK: If different from zero, device is doing loopback - * The type of attribute is NLA_U8. - * - * When using RT Netlink to create, destroy or configure a CAIF IP interface, - * enum ifla_caif is used to specify the configuration attributes. - */ -enum ifla_caif { - __IFLA_CAIF_UNSPEC, - IFLA_CAIF_IPV4_CONNID, - IFLA_CAIF_IPV6_CONNID, - IFLA_CAIF_LOOPBACK, - __IFLA_CAIF_MAX -}; -#define IFLA_CAIF_MAX (__IFLA_CAIF_MAX-1) - -#endif /*IF_CAIF_H_*/ diff --git a/include/uapi/linux/capi.h b/include/uapi/linux/capi.h deleted file mode 100644 index 31f946f8a88d..000000000000 --- a/include/uapi/linux/capi.h +++ /dev/null @@ -1,134 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: capi.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $ - * - * CAPI 2.0 Interface for Linux - * - * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __LINUX_CAPI_H__ -#define __LINUX_CAPI_H__ - -#include -#include -#ifndef __KERNEL__ -#include -#endif - -/* - * CAPI_REGISTER - */ - -typedef struct capi_register_params { /* CAPI_REGISTER */ - __u32 level3cnt; /* No. of simulatneous user data connections */ - __u32 datablkcnt; /* No. of buffered data messages */ - __u32 datablklen; /* Size of buffered data messages */ -} capi_register_params; - -#define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params) - -/* - * CAPI_GET_MANUFACTURER - */ - -#define CAPI_MANUFACTURER_LEN 64 - -#define CAPI_GET_MANUFACTURER _IOWR('C',0x06,int) /* broken: wanted size 64 (CAPI_MANUFACTURER_LEN) */ - -/* - * CAPI_GET_VERSION - */ - -typedef struct capi_version { - __u32 majorversion; - __u32 minorversion; - __u32 majormanuversion; - __u32 minormanuversion; -} capi_version; - -#define CAPI_GET_VERSION _IOWR('C',0x07,struct capi_version) - -/* - * CAPI_GET_SERIAL - */ - -#define CAPI_SERIAL_LEN 8 -#define CAPI_GET_SERIAL _IOWR('C',0x08,int) /* broken: wanted size 8 (CAPI_SERIAL_LEN) */ - -/* - * CAPI_GET_PROFILE - */ - -typedef struct capi_profile { - __u16 ncontroller; /* number of installed controller */ - __u16 nbchannel; /* number of B-Channels */ - __u32 goptions; /* global options */ - __u32 support1; /* B1 protocols support */ - __u32 support2; /* B2 protocols support */ - __u32 support3; /* B3 protocols support */ - __u32 reserved[6]; /* reserved */ - __u32 manu[5]; /* manufacturer specific information */ -} capi_profile; - -#define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile) - -typedef struct capi_manufacturer_cmd { - unsigned long cmd; - void __user *data; -} capi_manufacturer_cmd; - -/* - * CAPI_MANUFACTURER_CMD - */ - -#define CAPI_MANUFACTURER_CMD _IOWR('C',0x20, struct capi_manufacturer_cmd) - -/* - * CAPI_GET_ERRCODE - * capi errcode is set, * if read, write, or ioctl returns EIO, - * ioctl returns errcode directly, and in arg, if != 0 - */ - -#define CAPI_GET_ERRCODE _IOR('C',0x21, __u16) - -/* - * CAPI_INSTALLED - */ -#define CAPI_INSTALLED _IOR('C',0x22, __u16) - - -/* - * member contr is input for - * CAPI_GET_MANUFACTURER, CAPI_GET_VERSION, CAPI_GET_SERIAL - * and CAPI_GET_PROFILE - */ -typedef union capi_ioctl_struct { - __u32 contr; - capi_register_params rparams; - __u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - __u8 serial[CAPI_SERIAL_LEN]; - capi_profile profile; - capi_manufacturer_cmd cmd; - __u16 errcode; -} capi_ioctl_struct; - -/* - * Middleware extension - */ - -#define CAPIFLAG_HIGHJACKING 0x0001 - -#define CAPI_GET_FLAGS _IOR('C',0x23, unsigned) -#define CAPI_SET_FLAGS _IOR('C',0x24, unsigned) -#define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned) - -#define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned) - -#define CAPI_NCCI_GETUNIT _IOR('C',0x27, unsigned) - -#endif /* __LINUX_CAPI_H__ */ diff --git a/include/uapi/linux/hdlcdrv.h b/include/uapi/linux/hdlcdrv.h deleted file mode 100644 index 9fe9499403a6..000000000000 --- a/include/uapi/linux/hdlcdrv.h +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * hdlcdrv.h -- HDLC packet radio network driver. - * The Linux soundcard driver for 1200 baud and 9600 baud packet radio - * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA - */ - -#ifndef _UAPI_HDLCDRV_H -#define _UAPI_HDLCDRV_H - -/* -------------------------------------------------------------------- */ -/* - * structs for the IOCTL commands - */ - -struct hdlcdrv_params { - int iobase; - int irq; - int dma; - int dma2; - int seriobase; - int pariobase; - int midiiobase; -}; - -struct hdlcdrv_channel_params { - int tx_delay; /* the transmitter keyup delay in 10ms units */ - int tx_tail; /* the transmitter keyoff delay in 10ms units */ - int slottime; /* the slottime in 10ms; usually 10 = 100ms */ - int ppersist; /* the p-persistence 0..255 */ - int fulldup; /* some driver do not support full duplex, setting */ - /* this just makes them send even if DCD is on */ -}; - -struct hdlcdrv_old_channel_state { - int ptt; - int dcd; - int ptt_keyed; -}; - -struct hdlcdrv_channel_state { - int ptt; - int dcd; - int ptt_keyed; - unsigned long tx_packets; - unsigned long tx_errors; - unsigned long rx_packets; - unsigned long rx_errors; -}; - -struct hdlcdrv_ioctl { - int cmd; - union { - struct hdlcdrv_params mp; - struct hdlcdrv_channel_params cp; - struct hdlcdrv_channel_state cs; - struct hdlcdrv_old_channel_state ocs; - unsigned int calibrate; - unsigned char bits; - char modename[128]; - char drivername[32]; - } data; -}; - -/* -------------------------------------------------------------------- */ - -/* - * ioctl values - */ -#define HDLCDRVCTL_GETMODEMPAR 0 -#define HDLCDRVCTL_SETMODEMPAR 1 -#define HDLCDRVCTL_MODEMPARMASK 2 /* not handled by hdlcdrv */ -#define HDLCDRVCTL_GETCHANNELPAR 10 -#define HDLCDRVCTL_SETCHANNELPAR 11 -#define HDLCDRVCTL_OLDGETSTAT 20 -#define HDLCDRVCTL_CALIBRATE 21 -#define HDLCDRVCTL_GETSTAT 22 - -/* - * these are mainly for debugging purposes - */ -#define HDLCDRVCTL_GETSAMPLES 30 -#define HDLCDRVCTL_GETBITS 31 - -/* - * not handled by hdlcdrv, but by its depending drivers - */ -#define HDLCDRVCTL_GETMODE 40 -#define HDLCDRVCTL_SETMODE 41 -#define HDLCDRVCTL_MODELIST 42 -#define HDLCDRVCTL_DRIVERNAME 43 - -/* - * mask of needed modem parameters, returned by HDLCDRVCTL_MODEMPARMASK - */ -#define HDLCDRV_PARMASK_IOBASE (1<<0) -#define HDLCDRV_PARMASK_IRQ (1<<1) -#define HDLCDRV_PARMASK_DMA (1<<2) -#define HDLCDRV_PARMASK_DMA2 (1<<3) -#define HDLCDRV_PARMASK_SERIOBASE (1<<4) -#define HDLCDRV_PARMASK_PARIOBASE (1<<5) -#define HDLCDRV_PARMASK_MIDIIOBASE (1<<6) - -/* -------------------------------------------------------------------- */ - - -/* -------------------------------------------------------------------- */ - -#endif /* _UAPI_HDLCDRV_H */ - -/* -------------------------------------------------------------------- */ diff --git a/include/uapi/linux/isdn/capicmd.h b/include/uapi/linux/isdn/capicmd.h deleted file mode 100644 index 5ec88e7548a9..000000000000 --- a/include/uapi/linux/isdn/capicmd.h +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: capicmd.h,v 1.2.6.2 2001/09/23 22:24:33 kai Exp $ - * - * CAPI 2.0 Interface for Linux - * - * Copyright 1997 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __CAPICMD_H__ -#define __CAPICMD_H__ - -#define CAPI_MSG_BASELEN 8 -#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2) -#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2) -#define CAPI_DISCONNECT_B3_RESP_LEN (CAPI_MSG_BASELEN+4) - -/*----- CAPI commands -----*/ -#define CAPI_ALERT 0x01 -#define CAPI_CONNECT 0x02 -#define CAPI_CONNECT_ACTIVE 0x03 -#define CAPI_CONNECT_B3_ACTIVE 0x83 -#define CAPI_CONNECT_B3 0x82 -#define CAPI_CONNECT_B3_T90_ACTIVE 0x88 -#define CAPI_DATA_B3 0x86 -#define CAPI_DISCONNECT_B3 0x84 -#define CAPI_DISCONNECT 0x04 -#define CAPI_FACILITY 0x80 -#define CAPI_INFO 0x08 -#define CAPI_LISTEN 0x05 -#define CAPI_MANUFACTURER 0xff -#define CAPI_RESET_B3 0x87 -#define CAPI_SELECT_B_PROTOCOL 0x41 - -/*----- CAPI subcommands -----*/ - -#define CAPI_REQ 0x80 -#define CAPI_CONF 0x81 -#define CAPI_IND 0x82 -#define CAPI_RESP 0x83 - -/*----- CAPI combined commands -----*/ - -#define CAPICMD(cmd,subcmd) (((cmd)<<8)|(subcmd)) - -#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ) -#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF) -#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND) -#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP) - -#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ) -#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF) - -#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ) -#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF) -#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND) -#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP) - -#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ) -#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF) -#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND) -#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP) - -#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ) -#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF) - -#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ) -#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF) -#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND) -#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP) - -#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ) -#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF) -#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND) -#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP) - - -#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND) -#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP) - -#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ) -#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF) -#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND) -#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP) - -#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ) -#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF) -#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND) -#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP) - -#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ) -#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF) -#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND) -#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP) - -#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ) -#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF) - -#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ) -#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF) -#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND) -#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP) - -#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ) -#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF) -#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND) -#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP) - -#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ) -#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF) -#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND) -#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP) - -#endif /* __CAPICMD_H__ */ diff --git a/include/uapi/linux/kernelcapi.h b/include/uapi/linux/kernelcapi.h deleted file mode 100644 index 325a856e0e20..000000000000 --- a/include/uapi/linux/kernelcapi.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $ - * - * Kernel CAPI 2.0 Interface for Linux - * - * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - */ - -#ifndef _UAPI__KERNELCAPI_H__ -#define _UAPI__KERNELCAPI_H__ - -#define CAPI_MAXAPPL 240 /* maximum number of applications */ -#define CAPI_MAXCONTR 32 /* maximum number of controller */ -#define CAPI_MAXDATAWINDOW 8 - - -typedef struct kcapi_flagdef { - int contr; - int flag; -} kcapi_flagdef; - -typedef struct kcapi_carddef { - char driver[32]; - unsigned int port; - unsigned irq; - unsigned int membase; - int cardnr; -} kcapi_carddef; - -/* new ioctls >= 10 */ -#define KCAPI_CMD_TRACE 10 -#define KCAPI_CMD_ADDCARD 11 /* OBSOLETE */ - -/* - * flag > 2 => trace also data - * flag & 1 => show trace - */ -#define KCAPI_TRACE_OFF 0 -#define KCAPI_TRACE_SHORT_NO_DATA 1 -#define KCAPI_TRACE_FULL_NO_DATA 2 -#define KCAPI_TRACE_SHORT 3 -#define KCAPI_TRACE_FULL 4 - - - -#endif /* _UAPI__KERNELCAPI_H__ */ diff --git a/include/uapi/linux/netrom.h b/include/uapi/linux/netrom.h deleted file mode 100644 index 7498ea3c3940..000000000000 --- a/include/uapi/linux/netrom.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * These are the public elements of the Linux kernel NET/ROM implementation. - * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the - * definition of the ax25_address structure. - */ - -#ifndef NETROM_KERNEL_H -#define NETROM_KERNEL_H - -#include - -#define NETROM_MTU 236 - -#define NETROM_T1 1 -#define NETROM_T2 2 -#define NETROM_N2 3 -#define NETROM_T4 6 -#define NETROM_IDLE 7 - -#define SIOCNRDECOBS (SIOCPROTOPRIVATE+2) - -struct nr_route_struct { -#define NETROM_NEIGH 0 -#define NETROM_NODE 1 - int type; - ax25_address callsign; - char device[16]; - unsigned int quality; - char mnemonic[7]; - ax25_address neighbour; - unsigned int obs_count; - unsigned int ndigis; - ax25_address digipeaters[AX25_MAX_DIGIS]; -}; - -#endif diff --git a/include/uapi/linux/rose.h b/include/uapi/linux/rose.h deleted file mode 100644 index 19aa4693c8fc..000000000000 --- a/include/uapi/linux/rose.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * These are the public elements of the Linux kernel Rose implementation. - * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the - * definition of the ax25_address structure. - */ - -#ifndef ROSE_KERNEL_H -#define ROSE_KERNEL_H - -#include -#include - -#define ROSE_MTU 251 - -#define ROSE_MAX_DIGIS 6 - -#define ROSE_DEFER 1 -#define ROSE_T1 2 -#define ROSE_T2 3 -#define ROSE_T3 4 -#define ROSE_IDLE 5 -#define ROSE_QBITINCL 6 -#define ROSE_HOLDBACK 7 - -#define SIOCRSGCAUSE (SIOCPROTOPRIVATE+0) -#define SIOCRSSCAUSE (SIOCPROTOPRIVATE+1) -#define SIOCRSL2CALL (SIOCPROTOPRIVATE+2) -#define SIOCRSSL2CALL (SIOCPROTOPRIVATE+2) -#define SIOCRSACCEPT (SIOCPROTOPRIVATE+3) -#define SIOCRSCLRRT (SIOCPROTOPRIVATE+4) -#define SIOCRSGL2CALL (SIOCPROTOPRIVATE+5) -#define SIOCRSGFACILITIES (SIOCPROTOPRIVATE+6) - -#define ROSE_DTE_ORIGINATED 0x00 -#define ROSE_NUMBER_BUSY 0x01 -#define ROSE_INVALID_FACILITY 0x03 -#define ROSE_NETWORK_CONGESTION 0x05 -#define ROSE_OUT_OF_ORDER 0x09 -#define ROSE_ACCESS_BARRED 0x0B -#define ROSE_NOT_OBTAINABLE 0x0D -#define ROSE_REMOTE_PROCEDURE 0x11 -#define ROSE_LOCAL_PROCEDURE 0x13 -#define ROSE_SHIP_ABSENT 0x39 - -typedef struct { - char rose_addr[5]; -} rose_address; - -struct sockaddr_rose { - __kernel_sa_family_t srose_family; - rose_address srose_addr; - ax25_address srose_call; - int srose_ndigis; - ax25_address srose_digi; -}; - -struct full_sockaddr_rose { - __kernel_sa_family_t srose_family; - rose_address srose_addr; - ax25_address srose_call; - unsigned int srose_ndigis; - ax25_address srose_digis[ROSE_MAX_DIGIS]; -}; - -struct rose_route_struct { - rose_address address; - unsigned short mask; - ax25_address neighbour; - char device[16]; - unsigned char ndigis; - ax25_address digipeaters[AX25_MAX_DIGIS]; -}; - -struct rose_cause_struct { - unsigned char cause; - unsigned char diagnostic; -}; - -struct rose_facilities_struct { - rose_address source_addr, dest_addr; - ax25_address source_call, dest_call; - unsigned char source_ndigis, dest_ndigis; - ax25_address source_digis[ROSE_MAX_DIGIS]; - ax25_address dest_digis[ROSE_MAX_DIGIS]; - unsigned int rand; - rose_address fail_addr; - ax25_address fail_call; -}; - -#endif diff --git a/include/uapi/linux/scc.h b/include/uapi/linux/scc.h deleted file mode 100644 index 947edb17ce9d..000000000000 --- a/include/uapi/linux/scc.h +++ /dev/null @@ -1,174 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: scc.h,v 1.29 1997/04/02 14:56:45 jreuter Exp jreuter $ */ - -#ifndef _UAPI_SCC_H -#define _UAPI_SCC_H - -#include - -/* selection of hardware types */ - -#define PA0HZP 0x00 /* hardware type for PA0HZP SCC card and compatible */ -#define EAGLE 0x01 /* hardware type for EAGLE card */ -#define PC100 0x02 /* hardware type for PC100 card */ -#define PRIMUS 0x04 /* hardware type for PRIMUS-PC (DG9BL) card */ -#define DRSI 0x08 /* hardware type for DRSI PC*Packet card */ -#define BAYCOM 0x10 /* hardware type for BayCom (U)SCC */ - -/* DEV ioctl() commands */ - -enum SCC_ioctl_cmds { - SIOCSCCRESERVED = SIOCDEVPRIVATE, - SIOCSCCCFG, - SIOCSCCINI, - SIOCSCCCHANINI, - SIOCSCCSMEM, - SIOCSCCGKISS, - SIOCSCCSKISS, - SIOCSCCGSTAT, - SIOCSCCCAL -}; - -/* Device parameter control (from WAMPES) */ - -enum L1_params { - PARAM_DATA, - PARAM_TXDELAY, - PARAM_PERSIST, - PARAM_SLOTTIME, - PARAM_TXTAIL, - PARAM_FULLDUP, - PARAM_SOFTDCD, /* was: PARAM_HW */ - PARAM_MUTE, /* ??? */ - PARAM_DTR, - PARAM_RTS, - PARAM_SPEED, - PARAM_ENDDELAY, /* ??? */ - PARAM_GROUP, - PARAM_IDLE, - PARAM_MIN, - PARAM_MAXKEY, - PARAM_WAIT, - PARAM_MAXDEFER, - PARAM_TX, - PARAM_HWEVENT = 31, - PARAM_RETURN = 255 /* reset kiss mode */ -}; - -/* fulldup parameter */ - -enum FULLDUP_modes { - KISS_DUPLEX_HALF, /* normal CSMA operation */ - KISS_DUPLEX_FULL, /* fullduplex, key down trx after transmission */ - KISS_DUPLEX_LINK, /* fullduplex, key down trx after 'idletime' sec */ - KISS_DUPLEX_OPTIMA /* fullduplex, let the protocol layer control the hw */ -}; - -/* misc. parameters */ - -#define TIMER_OFF 65535U /* to switch off timers */ -#define NO_SUCH_PARAM 65534U /* param not implemented */ - -/* HWEVENT parameter */ - -enum HWEVENT_opts { - HWEV_DCD_ON, - HWEV_DCD_OFF, - HWEV_ALL_SENT -}; - -/* channel grouping */ - -#define RXGROUP 0100 /* if set, only tx when all channels clear */ -#define TXGROUP 0200 /* if set, don't transmit simultaneously */ - -/* Tx/Rx clock sources */ - -enum CLOCK_sources { - CLK_DPLL, /* normal halfduplex operation */ - CLK_EXTERNAL, /* external clocking (G3RUH/DF9IC modems) */ - CLK_DIVIDER, /* Rx = DPLL, Tx = divider (fullduplex with */ - /* modems without clock regeneration */ - CLK_BRG /* experimental fullduplex mode with DPLL/BRG for */ - /* MODEMs without clock recovery */ -}; - -/* Tx state */ - -enum TX_state { - TXS_IDLE, /* Transmitter off, no data pending */ - TXS_BUSY, /* waiting for permission to send / tailtime */ - TXS_ACTIVE, /* Transmitter on, sending data */ - TXS_NEWFRAME, /* reset CRC and send (next) frame */ - TXS_IDLE2, /* Transmitter on, no data pending */ - TXS_WAIT, /* Waiting for Mintime to expire */ - TXS_TIMEOUT /* We had a transmission timeout */ -}; - -typedef unsigned long io_port; /* type definition for an 'io port address' */ - -/* SCC statistical information */ - -struct scc_stat { - long rxints; /* Receiver interrupts */ - long txints; /* Transmitter interrupts */ - long exints; /* External/status interrupts */ - long spints; /* Special receiver interrupts */ - - long txframes; /* Packets sent */ - long rxframes; /* Number of Frames Actually Received */ - long rxerrs; /* CRC Errors */ - long txerrs; /* KISS errors */ - - unsigned int nospace; /* "Out of buffers" */ - unsigned int rx_over; /* Receiver Overruns */ - unsigned int tx_under; /* Transmitter Underruns */ - - unsigned int tx_state; /* Transmitter state */ - int tx_queued; /* tx frames enqueued */ - - unsigned int maxqueue; /* allocated tx_buffers */ - unsigned int bufsize; /* used buffersize */ -}; - -struct scc_modem { - long speed; /* Line speed, bps */ - char clocksrc; /* 0 = DPLL, 1 = external, 2 = divider */ - char nrz; /* NRZ instead of NRZI */ -}; - -struct scc_kiss_cmd { - int command; /* one of the KISS-Commands defined above */ - unsigned param; /* KISS-Param */ -}; - -struct scc_hw_config { - io_port data_a; /* data port channel A */ - io_port ctrl_a; /* control port channel A */ - io_port data_b; /* data port channel B */ - io_port ctrl_b; /* control port channel B */ - io_port vector_latch; /* INTACK-Latch (#) */ - io_port special; /* special function port */ - - int irq; /* irq */ - long clock; /* clock */ - char option; /* command for function port */ - - char brand; /* hardware type */ - char escc; /* use ext. features of a 8580/85180/85280 */ -}; - -/* (#) only one INTACK latch allowed. */ - - -struct scc_mem_config { - unsigned int dummy; - unsigned int bufsize; -}; - -struct scc_calibrate { - unsigned int time; - unsigned char pattern; -}; - -#endif /* _UAPI_SCC_H */ diff --git a/net/Kconfig b/net/Kconfig index 62266eaf0e95..bdea8aef7983 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -414,7 +414,6 @@ endmenu # Network testing endmenu # Networking options -source "net/ax25/Kconfig" source "net/can/Kconfig" source "net/bluetooth/Kconfig" source "net/rxrpc/Kconfig" @@ -439,7 +438,6 @@ endif # WIRELESS source "net/rfkill/Kconfig" source "net/9p/Kconfig" -source "net/caif/Kconfig" source "net/ceph/Kconfig" source "net/nfc/Kconfig" source "net/psample/Kconfig" diff --git a/net/Makefile b/net/Makefile index 90e3d72bf58b..d2175fce0406 100644 --- a/net/Makefile +++ b/net/Makefile @@ -28,9 +28,6 @@ obj-y += dsa/ obj-$(CONFIG_ATALK) += appletalk/ obj-$(CONFIG_X25) += x25/ obj-$(CONFIG_LAPB) += lapb/ -obj-$(CONFIG_NETROM) += netrom/ -obj-$(CONFIG_ROSE) += rose/ -obj-$(CONFIG_AX25) += ax25/ obj-$(CONFIG_CAN) += can/ obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_SUNRPC) += sunrpc/ @@ -53,7 +50,6 @@ obj-$(CONFIG_IUCV) += iucv/ obj-$(CONFIG_SMC) += smc/ obj-$(CONFIG_RFKILL) += rfkill/ obj-$(CONFIG_NET_9P) += 9p/ -obj-$(CONFIG_CAIF) += caif/ obj-$(CONFIG_DCB) += dcb/ obj-$(CONFIG_6LOWPAN) += 6lowpan/ obj-$(CONFIG_IEEE802154) += ieee802154/ diff --git a/net/atm/Kconfig b/net/atm/Kconfig index 77343d57ff2a..dfdc3a8553ba 100644 --- a/net/atm/Kconfig +++ b/net/atm/Kconfig @@ -19,43 +19,6 @@ config ATM 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 diff --git a/net/atm/Makefile b/net/atm/Makefile index bfec0f2d83b5..484a1b1552cc 100644 --- a/net/atm/Makefile +++ b/net/atm/Makefile @@ -4,13 +4,9 @@ # 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_PPPOATM) += pppoatm.o 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/ioctl.c b/net/atm/ioctl.c index 0f7a39aeccc8..0f3f9ad8301f 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -11,14 +11,10 @@ #include /* struct socket, struct proto_ops */ #include /* ATM stuff */ #include -#include /* CLIP_*ENCAP */ #include /* manifest constants */ #include #include /* for ioctls */ #include -#include -#include -#include #include #include #include @@ -138,16 +134,6 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, } break; } - case ATMMPC_CTRL: - case ATMMPC_DATA: - request_module("mpoa"); - break; - case ATMARPD_CTRL: - request_module("clip"); - break; - case ATMLEC_CTRL: - request_module("lec"); - break; } error = -ENOIOCTLCMD; 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/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.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/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.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_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/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/atm/proc.c b/net/atm/proc.c index 9bf736290e48..b650da764a23 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -21,11 +21,9 @@ #include #include #include -#include #include /* for __init */ #include #include -#include #include #include /* for HZ */ #include @@ -155,15 +153,6 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) class_name[vcc->qos.rxtp.traffic_class], vcc->qos.txtp.min_pcr, class_name[vcc->qos.txtp.traffic_class]); - if (test_bit(ATM_VF_IS_CLIP, &vcc->flags)) { - struct clip_vcc *clip_vcc = CLIP_VCC(vcc); - struct net_device *dev; - - dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL; - seq_printf(seq, "CLIP, Itf:%s, Encap:", - dev ? dev->name : "none?"); - seq_printf(seq, "%s", clip_vcc->encap ? "LLC/SNAP" : "None"); - } seq_putc(seq, '\n'); } diff --git a/net/ax25/Kconfig b/net/ax25/Kconfig deleted file mode 100644 index 310169ce1488..000000000000 --- a/net/ax25/Kconfig +++ /dev/null @@ -1,108 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Amateur Radio protocols and AX.25 device configuration -# - -menuconfig HAMRADIO - depends on NET - bool "Amateur Radio support" - help - If you want to connect your Linux box to an amateur radio, answer Y - here. You want to read - and more specifically about AX.25 on Linux - . - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about amateur radio. - -comment "Packet Radio protocols" - depends on HAMRADIO - -config AX25 - tristate "Amateur Radio AX.25 Level 2 protocol" - depends on HAMRADIO - help - This is the protocol used for computer communication over amateur - radio. It is either used by itself for point-to-point links, or to - carry other protocols such as tcp/ip. To use it, you need a device - that connects your Linux box to your amateur radio. You can either - use a low speed TNC (a Terminal Node Controller acts as a kind of - modem connecting your computer's serial port to your radio's - microphone input and speaker output) supporting the KISS protocol or - one of the various SCC cards that are supported by the generic Z8530 - or the DMA SCC driver. Another option are the Baycom modem serial - and parallel port hacks or the sound card modem (supported by their - own drivers). If you say Y here, you also have to say Y to one of - those drivers. - - Information about where to get supporting software for Linux amateur - radio as well as information about how to configure an AX.25 port is - contained in the AX25-HOWTO, available from - . You might also want to - check out the file in the - kernel source. More information about digital amateur radio in - general is on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called ax25. - -config AX25_DAMA_SLAVE - bool "AX.25 DAMA Slave support" - default y - depends on AX25 - help - DAMA is a mechanism to prevent collisions when doing AX.25 - networking. A DAMA server (called "master") accepts incoming traffic - from clients (called "slaves") and redistributes it to other slaves. - If you say Y here, your Linux box will act as a DAMA slave; this is - transparent in that you don't have to do any special DAMA - configuration. Linux cannot yet act as a DAMA server. This option - only compiles DAMA slave support into the kernel. It still needs to - be enabled at runtime. For more about DAMA see - . If unsure, say Y. - -config NETROM - tristate "Amateur Radio NET/ROM protocol" - depends on AX25 - help - NET/ROM is a network layer protocol on top of AX.25 useful for - routing. - - A comprehensive listing of all the software for Linux amateur radio - users as well as information about how to configure an AX.25 port is - contained in the Linux Ham Wiki, available from - . You also might want to check out - the file . More information - about digital amateur radio in general is on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called netrom. - -config ROSE - tristate "Amateur Radio X.25 PLP (Rose)" - depends on AX25 - help - The Packet Layer Protocol (PLP) is a way to route packets over X.25 - connections in general and amateur radio AX.25 connections in - particular, essentially an alternative to NET/ROM. - - A comprehensive listing of all the software for Linux amateur radio - users as well as information about how to configure an AX.25 port is - contained in the Linux Ham Wiki, available from - . You also might want to check out - the file . More information - about digital amateur radio in general is on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called rose. - -menu "AX.25 network device drivers" - depends on HAMRADIO && AX25 - -source "drivers/net/hamradio/Kconfig" - -endmenu diff --git a/net/ax25/Makefile b/net/ax25/Makefile deleted file mode 100644 index 2e53affc8568..000000000000 --- a/net/ax25/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the Linux AX.25 layer. -# - -obj-$(CONFIG_AX25) += ax25.o - -ax25-y := ax25_addr.o ax25_dev.o ax25_iface.o ax25_in.o ax25_ip.o ax25_out.o \ - ax25_route.o ax25_std_in.o ax25_std_subr.o ax25_std_timer.o \ - ax25_subr.o ax25_timer.o ax25_uid.o af_ax25.o -ax25-$(CONFIG_AX25_DAMA_SLAVE) += ax25_ds_in.o ax25_ds_subr.o ax25_ds_timer.o -ax25-$(CONFIG_SYSCTL) += sysctl_net_ax25.o diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c deleted file mode 100644 index 9d236e64f5f5..000000000000 --- a/net/ax25/af_ax25.c +++ /dev/null @@ -1,2089 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk) - * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) - * Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl) - * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For TIOCINQ/OUTQ */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -HLIST_HEAD(ax25_list); -DEFINE_SPINLOCK(ax25_list_lock); - -static const struct proto_ops ax25_proto_ops; - -static void ax25_free_sock(struct sock *sk) -{ - ax25_cb_put(sk_to_ax25(sk)); -} - -/* - * Socket removal during an interrupt is now safe. - */ -static void ax25_cb_del(ax25_cb *ax25) -{ - spin_lock_bh(&ax25_list_lock); - if (!hlist_unhashed(&ax25->ax25_node)) { - hlist_del_init(&ax25->ax25_node); - ax25_cb_put(ax25); - } - spin_unlock_bh(&ax25_list_lock); -} - -/* - * Kill all bound sockets on a dropped device. - */ -static void ax25_kill_by_device(struct net_device *dev) -{ - ax25_dev *ax25_dev; - ax25_cb *s; - struct sock *sk; - - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) - return; - ax25_dev->device_up = false; - - spin_lock_bh(&ax25_list_lock); -again: - ax25_for_each(s, &ax25_list) { - if (s->ax25_dev == ax25_dev) { - sk = s->sk; - if (!sk) { - spin_unlock_bh(&ax25_list_lock); - ax25_disconnect(s, ENETUNREACH); - s->ax25_dev = NULL; - ax25_cb_del(s); - spin_lock_bh(&ax25_list_lock); - goto again; - } - sock_hold(sk); - spin_unlock_bh(&ax25_list_lock); - lock_sock(sk); - ax25_disconnect(s, ENETUNREACH); - s->ax25_dev = NULL; - if (sk->sk_socket) { - netdev_put(ax25_dev->dev, - &s->dev_tracker); - ax25_dev_put(ax25_dev); - } - ax25_cb_del(s); - release_sock(sk); - spin_lock_bh(&ax25_list_lock); - sock_put(sk); - /* The entry could have been deleted from the - * list meanwhile and thus the next pointer is - * no longer valid. Play it safe and restart - * the scan. Forward progress is ensured - * because we set s->ax25_dev to NULL and we - * are never passed a NULL 'dev' argument. - */ - goto again; - } - } - spin_unlock_bh(&ax25_list_lock); -} - -/* - * Handle device status changes. - */ -static int ax25_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; - - /* Reject non AX.25 devices */ - if (dev->type != ARPHRD_AX25) - return NOTIFY_DONE; - - switch (event) { - case NETDEV_UP: - ax25_dev_device_up(dev); - break; - case NETDEV_DOWN: - ax25_kill_by_device(dev); - ax25_rt_device_down(dev); - ax25_dev_device_down(dev); - break; - default: - break; - } - - return NOTIFY_DONE; -} - -/* - * Add a socket to the bound sockets list. - */ -void ax25_cb_add(ax25_cb *ax25) -{ - spin_lock_bh(&ax25_list_lock); - ax25_cb_hold(ax25); - hlist_add_head(&ax25->ax25_node, &ax25_list); - spin_unlock_bh(&ax25_list_lock); -} - -/* - * Find a socket that wants to accept the SABM we have just - * received. - */ -struct sock *ax25_find_listener(ax25_address *addr, int digi, - struct net_device *dev, int type) -{ - ax25_cb *s; - - spin_lock(&ax25_list_lock); - ax25_for_each(s, &ax25_list) { - if ((s->iamdigi && !digi) || (!s->iamdigi && digi)) - continue; - if (s->sk && !ax25cmp(&s->source_addr, addr) && - s->sk->sk_type == type && s->sk->sk_state == TCP_LISTEN) { - /* If device is null we match any device */ - if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { - sock_hold(s->sk); - spin_unlock(&ax25_list_lock); - return s->sk; - } - } - } - spin_unlock(&ax25_list_lock); - - return NULL; -} - -/* - * Find an AX.25 socket given both ends. - */ -struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr, - int type) -{ - struct sock *sk = NULL; - ax25_cb *s; - - spin_lock(&ax25_list_lock); - ax25_for_each(s, &ax25_list) { - if (s->sk && !ax25cmp(&s->source_addr, my_addr) && - !ax25cmp(&s->dest_addr, dest_addr) && - s->sk->sk_type == type) { - sk = s->sk; - sock_hold(sk); - break; - } - } - - spin_unlock(&ax25_list_lock); - - return sk; -} - -/* - * Find an AX.25 control block given both ends. It will only pick up - * floating AX.25 control blocks or non Raw socket bound control blocks. - */ -ax25_cb *ax25_find_cb(const ax25_address *src_addr, ax25_address *dest_addr, - ax25_digi *digi, struct net_device *dev) -{ - ax25_cb *s; - - spin_lock_bh(&ax25_list_lock); - ax25_for_each(s, &ax25_list) { - if (s->sk && s->sk->sk_type != SOCK_SEQPACKET) - continue; - if (s->ax25_dev == NULL) - continue; - if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) { - if (digi != NULL && digi->ndigi != 0) { - if (s->digipeat == NULL) - continue; - if (ax25digicmp(s->digipeat, digi) != 0) - continue; - } else { - if (s->digipeat != NULL && s->digipeat->ndigi != 0) - continue; - } - ax25_cb_hold(s); - spin_unlock_bh(&ax25_list_lock); - - return s; - } - } - spin_unlock_bh(&ax25_list_lock); - - return NULL; -} - -EXPORT_SYMBOL(ax25_find_cb); - -void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto) -{ - ax25_cb *s; - struct sk_buff *copy; - - spin_lock(&ax25_list_lock); - ax25_for_each(s, &ax25_list) { - if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && - s->sk->sk_type == SOCK_RAW && - s->sk->sk_protocol == proto && - s->ax25_dev->dev == skb->dev && - atomic_read(&s->sk->sk_rmem_alloc) <= s->sk->sk_rcvbuf) { - if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) - continue; - if (sock_queue_rcv_skb(s->sk, copy) != 0) - kfree_skb(copy); - } - } - spin_unlock(&ax25_list_lock); -} - -/* - * Deferred destroy. - */ -void ax25_destroy_socket(ax25_cb *); - -/* - * Handler for deferred kills. - */ -static void ax25_destroy_timer(struct timer_list *t) -{ - ax25_cb *ax25 = timer_container_of(ax25, t, dtimer); - struct sock *sk; - - sk=ax25->sk; - - bh_lock_sock(sk); - sock_hold(sk); - ax25_destroy_socket(ax25); - bh_unlock_sock(sk); - sock_put(sk); -} - -/* - * This is called from user mode and the timers. Thus it protects itself - * against interrupt users but doesn't worry about being called during - * work. Once it is removed from the queue no interrupt or bottom half - * will touch it and we are (fairly 8-) ) safe. - */ -void ax25_destroy_socket(ax25_cb *ax25) -{ - struct sk_buff *skb; - - ax25_cb_del(ax25); - - ax25_stop_heartbeat(ax25); - ax25_stop_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_stop_t3timer(ax25); - ax25_stop_idletimer(ax25); - - ax25_clear_queues(ax25); /* Flush the queues */ - - if (ax25->sk != NULL) { - while ((skb = skb_dequeue(&ax25->sk->sk_receive_queue)) != NULL) { - if (skb->sk != ax25->sk) { - /* A pending connection */ - ax25_cb *sax25 = sk_to_ax25(skb->sk); - - /* Queue the unaccepted socket for death */ - sock_orphan(skb->sk); - - /* 9A4GL: hack to release unaccepted sockets */ - skb->sk->sk_state = TCP_LISTEN; - - ax25_start_heartbeat(sax25); - sax25->state = AX25_STATE_0; - } - - kfree_skb(skb); - } - skb_queue_purge(&ax25->sk->sk_write_queue); - } - - if (ax25->sk != NULL) { - if (sk_has_allocations(ax25->sk)) { - /* Defer: outstanding buffers */ - timer_setup(&ax25->dtimer, ax25_destroy_timer, 0); - ax25->dtimer.expires = jiffies + 2 * HZ; - add_timer(&ax25->dtimer); - } else { - struct sock *sk=ax25->sk; - ax25->sk=NULL; - sock_put(sk); - } - } else { - ax25_cb_put(ax25); - } -} - -/* - * dl1bke 960311: set parameters for existing AX.25 connections, - * includes a KILL command to abort any connection. - * VERY useful for debugging ;-) - */ -static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) -{ - struct ax25_ctl_struct ax25_ctl; - ax25_digi digi; - ax25_dev *ax25_dev; - ax25_cb *ax25; - unsigned int k; - int ret = 0; - - if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl))) - return -EFAULT; - - if (ax25_ctl.digi_count > AX25_MAX_DIGIS) - return -EINVAL; - - if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL) - return -EINVAL; - - ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr); - if (!ax25_dev) - return -ENODEV; - - digi.ndigi = ax25_ctl.digi_count; - for (k = 0; k < digi.ndigi; k++) - digi.calls[k] = ax25_ctl.digi_addr[k]; - - ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev); - if (!ax25) { - ax25_dev_put(ax25_dev); - return -ENOTCONN; - } - - switch (ax25_ctl.cmd) { - case AX25_KILL: - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); -#ifdef CONFIG_AX25_DAMA_SLAVE - if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) - ax25_dama_off(ax25); -#endif - ax25_disconnect(ax25, ENETRESET); - break; - - case AX25_WINDOW: - if (ax25->modulus == AX25_MODULUS) { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) - goto einval_put; - } else { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) - goto einval_put; - } - ax25->window = ax25_ctl.arg; - break; - - case AX25_T1: - if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ) - goto einval_put; - ax25->rtt = (ax25_ctl.arg * HZ) / 2; - ax25->t1 = ax25_ctl.arg * HZ; - break; - - case AX25_T2: - if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ) - goto einval_put; - ax25->t2 = ax25_ctl.arg * HZ; - break; - - case AX25_N2: - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) - goto einval_put; - ax25->n2count = 0; - ax25->n2 = ax25_ctl.arg; - break; - - case AX25_T3: - if (ax25_ctl.arg > ULONG_MAX / HZ) - goto einval_put; - ax25->t3 = ax25_ctl.arg * HZ; - break; - - case AX25_IDLE: - if (ax25_ctl.arg > ULONG_MAX / (60 * HZ)) - goto einval_put; - - ax25->idle = ax25_ctl.arg * 60 * HZ; - break; - - case AX25_PACLEN: - if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) - goto einval_put; - ax25->paclen = ax25_ctl.arg; - break; - - default: - goto einval_put; - } - -out_put: - ax25_dev_put(ax25_dev); - ax25_cb_put(ax25); - return ret; - -einval_put: - ret = -EINVAL; - goto out_put; -} - -static void ax25_fillin_cb_from_dev(ax25_cb *ax25, const ax25_dev *ax25_dev) -{ - ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2; - ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]); - ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]); - ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]); - ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; - ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; - ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]); - ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; - - if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; - } -} - -/* - * Fill in a created AX.25 created control block with the default - * values for a particular device. - */ -void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) -{ - ax25->ax25_dev = ax25_dev; - - if (ax25->ax25_dev != NULL) { - ax25_fillin_cb_from_dev(ax25, ax25_dev); - return; - } - - /* - * No device, use kernel / AX.25 spec default values - */ - ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2; - ax25->t1 = msecs_to_jiffies(AX25_DEF_T1); - ax25->t2 = msecs_to_jiffies(AX25_DEF_T2); - ax25->t3 = msecs_to_jiffies(AX25_DEF_T3); - ax25->n2 = AX25_DEF_N2; - ax25->paclen = AX25_DEF_PACLEN; - ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE); - ax25->backoff = AX25_DEF_BACKOFF; - - if (AX25_DEF_AXDEFMODE) { - ax25->modulus = AX25_EMODULUS; - ax25->window = AX25_DEF_EWINDOW; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = AX25_DEF_WINDOW; - } -} - -/* - * Create an empty AX.25 control block. - */ -ax25_cb *ax25_create_cb(void) -{ - ax25_cb *ax25; - - if ((ax25 = kzalloc_obj(*ax25, GFP_ATOMIC)) == NULL) - return NULL; - - refcount_set(&ax25->refcount, 1); - - skb_queue_head_init(&ax25->write_queue); - skb_queue_head_init(&ax25->frag_queue); - skb_queue_head_init(&ax25->ack_queue); - skb_queue_head_init(&ax25->reseq_queue); - - ax25_setup_timers(ax25); - - ax25_fillin_cb(ax25, NULL); - - ax25->state = AX25_STATE_0; - - return ax25; -} - -/* - * Handling for system calls applied via the various interfaces to an - * AX25 socket object - */ - -static int ax25_setsockopt(struct socket *sock, int level, int optname, - sockptr_t optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - ax25_cb *ax25; - struct net_device *dev; - char devname[IFNAMSIZ]; - unsigned int opt; - int res = 0; - - if (level != SOL_AX25) - return -ENOPROTOOPT; - - if (optlen < sizeof(unsigned int)) - return -EINVAL; - - if (copy_from_sockptr(&opt, optval, sizeof(unsigned int))) - return -EFAULT; - - lock_sock(sk); - ax25 = sk_to_ax25(sk); - - switch (optname) { - case AX25_WINDOW: - if (ax25->modulus == AX25_MODULUS) { - if (opt < 1 || opt > 7) { - res = -EINVAL; - break; - } - } else { - if (opt < 1 || opt > 63) { - res = -EINVAL; - break; - } - } - ax25->window = opt; - break; - - case AX25_T1: - if (opt < 1 || opt > UINT_MAX / HZ) { - res = -EINVAL; - break; - } - ax25->rtt = (opt * HZ) >> 1; - ax25->t1 = opt * HZ; - break; - - case AX25_T2: - if (opt < 1 || opt > UINT_MAX / HZ) { - res = -EINVAL; - break; - } - ax25->t2 = opt * HZ; - break; - - case AX25_N2: - if (opt < 1 || opt > 31) { - res = -EINVAL; - break; - } - ax25->n2 = opt; - break; - - case AX25_T3: - if (opt < 1 || opt > UINT_MAX / HZ) { - res = -EINVAL; - break; - } - ax25->t3 = opt * HZ; - break; - - case AX25_IDLE: - if (opt > UINT_MAX / (60 * HZ)) { - res = -EINVAL; - break; - } - ax25->idle = opt * 60 * HZ; - break; - - case AX25_BACKOFF: - if (opt > 2) { - res = -EINVAL; - break; - } - ax25->backoff = opt; - break; - - case AX25_EXTSEQ: - ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS; - break; - - case AX25_PIDINCL: - ax25->pidincl = opt ? 1 : 0; - break; - - case AX25_IAMDIGI: - ax25->iamdigi = opt ? 1 : 0; - break; - - case AX25_PACLEN: - if (opt < 16 || opt > 65535) { - res = -EINVAL; - break; - } - ax25->paclen = opt; - break; - - case SO_BINDTODEVICE: - if (optlen > IFNAMSIZ - 1) - optlen = IFNAMSIZ - 1; - - memset(devname, 0, sizeof(devname)); - - if (copy_from_sockptr(devname, optval, optlen)) { - res = -EFAULT; - break; - } - - if (sk->sk_type == SOCK_SEQPACKET && - (sock->state != SS_UNCONNECTED || - sk->sk_state == TCP_LISTEN)) { - res = -EADDRNOTAVAIL; - break; - } - - rcu_read_lock(); - dev = dev_get_by_name_rcu(&init_net, devname); - if (!dev) { - rcu_read_unlock(); - res = -ENODEV; - break; - } - - if (ax25->ax25_dev) { - if (dev == ax25->ax25_dev->dev) { - rcu_read_unlock(); - break; - } - netdev_put(ax25->ax25_dev->dev, &ax25->dev_tracker); - ax25_dev_put(ax25->ax25_dev); - } - - ax25->ax25_dev = ax25_dev_ax25dev(dev); - if (!ax25->ax25_dev) { - rcu_read_unlock(); - res = -ENODEV; - break; - } - ax25_fillin_cb(ax25, ax25->ax25_dev); - netdev_hold(dev, &ax25->dev_tracker, GFP_ATOMIC); - ax25_dev_hold(ax25->ax25_dev); - rcu_read_unlock(); - break; - - default: - res = -ENOPROTOOPT; - } - release_sock(sk); - - return res; -} - -static int ax25_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - ax25_cb *ax25; - struct ax25_dev *ax25_dev; - char devname[IFNAMSIZ]; - void *valptr; - int val = 0; - int maxlen, length; - - if (level != SOL_AX25) - return -ENOPROTOOPT; - - if (get_user(maxlen, optlen)) - return -EFAULT; - - if (maxlen < 1) - return -EFAULT; - - valptr = &val; - length = min_t(unsigned int, maxlen, sizeof(int)); - - lock_sock(sk); - ax25 = sk_to_ax25(sk); - - switch (optname) { - case AX25_WINDOW: - val = ax25->window; - break; - - case AX25_T1: - val = ax25->t1 / HZ; - break; - - case AX25_T2: - val = ax25->t2 / HZ; - break; - - case AX25_N2: - val = ax25->n2; - break; - - case AX25_T3: - val = ax25->t3 / HZ; - break; - - case AX25_IDLE: - val = ax25->idle / (60 * HZ); - break; - - case AX25_BACKOFF: - val = ax25->backoff; - break; - - case AX25_EXTSEQ: - val = (ax25->modulus == AX25_EMODULUS); - break; - - case AX25_PIDINCL: - val = ax25->pidincl; - break; - - case AX25_IAMDIGI: - val = ax25->iamdigi; - break; - - case AX25_PACLEN: - val = ax25->paclen; - break; - - case SO_BINDTODEVICE: - ax25_dev = ax25->ax25_dev; - - if (ax25_dev != NULL && ax25_dev->dev != NULL) { - strscpy(devname, ax25_dev->dev->name, sizeof(devname)); - length = strlen(devname) + 1; - } else { - *devname = '\0'; - length = 1; - } - - valptr = devname; - break; - - default: - release_sock(sk); - return -ENOPROTOOPT; - } - release_sock(sk); - - if (put_user(length, optlen)) - return -EFAULT; - - return copy_to_user(optval, valptr, length) ? -EFAULT : 0; -} - -static int ax25_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - int res = 0; - - lock_sock(sk); - if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_LISTEN) { - sk->sk_max_ack_backlog = backlog; - sk->sk_state = TCP_LISTEN; - goto out; - } - res = -EOPNOTSUPP; - -out: - release_sock(sk); - - return res; -} - -/* - * XXX: when creating ax25_sock we should update the .obj_size setting - * below. - */ -static struct proto ax25_proto = { - .name = "AX25", - .owner = THIS_MODULE, - .obj_size = sizeof(struct ax25_sock), -}; - -static int ax25_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct sock *sk; - ax25_cb *ax25; - - if (protocol < 0 || protocol > U8_MAX) - return -EINVAL; - - if (!net_eq(net, &init_net)) - return -EAFNOSUPPORT; - - switch (sock->type) { - case SOCK_DGRAM: - if (protocol == 0 || protocol == PF_AX25) - protocol = AX25_P_TEXT; - break; - - case SOCK_SEQPACKET: - switch (protocol) { - case 0: - case PF_AX25: /* For CLX */ - protocol = AX25_P_TEXT; - break; - case AX25_P_SEGMENT: -#ifdef CONFIG_INET - case AX25_P_ARP: - case AX25_P_IP: -#endif -#ifdef CONFIG_NETROM - case AX25_P_NETROM: -#endif -#ifdef CONFIG_ROSE - case AX25_P_ROSE: -#endif - return -ESOCKTNOSUPPORT; -#ifdef CONFIG_NETROM_MODULE - case AX25_P_NETROM: - if (ax25_protocol_is_registered(AX25_P_NETROM)) - return -ESOCKTNOSUPPORT; - break; -#endif -#ifdef CONFIG_ROSE_MODULE - case AX25_P_ROSE: - if (ax25_protocol_is_registered(AX25_P_ROSE)) - return -ESOCKTNOSUPPORT; - break; -#endif - default: - break; - } - break; - - case SOCK_RAW: - if (!capable(CAP_NET_RAW)) - return -EPERM; - break; - default: - return -ESOCKTNOSUPPORT; - } - - sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto, kern); - if (sk == NULL) - return -ENOMEM; - - ax25 = ax25_sk(sk)->cb = ax25_create_cb(); - if (!ax25) { - sk_free(sk); - return -ENOMEM; - } - - sock_init_data(sock, sk); - - sk->sk_destruct = ax25_free_sock; - sock->ops = &ax25_proto_ops; - sk->sk_protocol = protocol; - - ax25->sk = sk; - - return 0; -} - -struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) -{ - struct sock *sk; - ax25_cb *ax25, *oax25; - - sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot, 0); - if (sk == NULL) - return NULL; - - if ((ax25 = ax25_create_cb()) == NULL) { - sk_free(sk); - return NULL; - } - - switch (osk->sk_type) { - case SOCK_DGRAM: - break; - case SOCK_SEQPACKET: - break; - default: - sk_free(sk); - ax25_cb_put(ax25); - return NULL; - } - - sock_init_data(NULL, sk); - - sk->sk_type = osk->sk_type; - sk->sk_priority = READ_ONCE(osk->sk_priority); - sk->sk_protocol = osk->sk_protocol; - sk->sk_rcvbuf = osk->sk_rcvbuf; - sk->sk_sndbuf = osk->sk_sndbuf; - sk->sk_state = TCP_ESTABLISHED; - sock_copy_flags(sk, osk); - - oax25 = sk_to_ax25(osk); - - ax25->modulus = oax25->modulus; - ax25->backoff = oax25->backoff; - ax25->pidincl = oax25->pidincl; - ax25->iamdigi = oax25->iamdigi; - ax25->rtt = oax25->rtt; - ax25->t1 = oax25->t1; - ax25->t2 = oax25->t2; - ax25->t3 = oax25->t3; - ax25->n2 = oax25->n2; - ax25->idle = oax25->idle; - ax25->paclen = oax25->paclen; - ax25->window = oax25->window; - - ax25->ax25_dev = ax25_dev; - ax25->source_addr = oax25->source_addr; - - if (oax25->digipeat != NULL) { - ax25->digipeat = kmemdup(oax25->digipeat, sizeof(ax25_digi), - GFP_ATOMIC); - if (ax25->digipeat == NULL) { - sk_free(sk); - ax25_cb_put(ax25); - return NULL; - } - } - - ax25_sk(sk)->cb = ax25; - sk->sk_destruct = ax25_free_sock; - ax25->sk = sk; - - return sk; -} - -static int ax25_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - ax25_cb *ax25; - ax25_dev *ax25_dev; - - if (sk == NULL) - return 0; - - sock_hold(sk); - lock_sock(sk); - sock_orphan(sk); - ax25 = sk_to_ax25(sk); - ax25_dev = ax25->ax25_dev; - - if (sk->sk_type == SOCK_SEQPACKET) { - switch (ax25->state) { - case AX25_STATE_0: - if (!sock_flag(ax25->sk, SOCK_DEAD)) { - release_sock(sk); - ax25_disconnect(ax25, 0); - lock_sock(sk); - } - ax25_destroy_socket(ax25); - break; - - case AX25_STATE_1: - case AX25_STATE_2: - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - release_sock(sk); - ax25_disconnect(ax25, 0); - lock_sock(sk); - if (!sock_flag(ax25->sk, SOCK_DESTROY)) - ax25_destroy_socket(ax25); - break; - - case AX25_STATE_3: - case AX25_STATE_4: - ax25_clear_queues(ax25); - ax25->n2count = 0; - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_send_control(ax25, - AX25_DISC, - AX25_POLLON, - AX25_COMMAND); - ax25_stop_t2timer(ax25); - ax25_stop_t3timer(ax25); - ax25_stop_idletimer(ax25); - break; -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - ax25_stop_t3timer(ax25); - ax25_stop_idletimer(ax25); - break; -#endif - } - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); - ax25->state = AX25_STATE_2; - sk->sk_state = TCP_CLOSE; - sk->sk_shutdown |= SEND_SHUTDOWN; - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DESTROY); - break; - - default: - break; - } - } else { - sk->sk_state = TCP_CLOSE; - sk->sk_shutdown |= SEND_SHUTDOWN; - sk->sk_state_change(sk); - ax25_destroy_socket(ax25); - } - if (ax25_dev) { - if (!ax25_dev->device_up) { - timer_delete_sync(&ax25->timer); - timer_delete_sync(&ax25->t1timer); - timer_delete_sync(&ax25->t2timer); - timer_delete_sync(&ax25->t3timer); - timer_delete_sync(&ax25->idletimer); - } - netdev_put(ax25_dev->dev, &ax25->dev_tracker); - ax25_dev_put(ax25_dev); - } - - sock->sk = NULL; - release_sock(sk); - sock_put(sk); - - return 0; -} - -/* - * We support a funny extension here so you can (as root) give any callsign - * digipeated via a local address as source. This hack is obsolete now - * that we've implemented support for SO_BINDTODEVICE. It is however small - * and trivially backward compatible. - */ -static int ax25_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len) -{ - struct sock *sk = sock->sk; - struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; - ax25_dev *ax25_dev = NULL; - ax25_uid_assoc *user; - ax25_address call; - ax25_cb *ax25; - int err = 0; - - if (addr_len != sizeof(struct sockaddr_ax25) && - addr_len != sizeof(struct full_sockaddr_ax25)) - /* support for old structure may go away some time - * ax25_bind(): uses old (6 digipeater) socket structure. - */ - if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) - return -EINVAL; - - if (addr->fsa_ax25.sax25_family != AF_AX25) - return -EINVAL; - - user = ax25_findbyuid(current_euid()); - if (user) { - call = user->call; - ax25_uid_put(user); - } else { - if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) - return -EACCES; - - call = addr->fsa_ax25.sax25_call; - } - - lock_sock(sk); - - ax25 = sk_to_ax25(sk); - if (!sock_flag(sk, SOCK_ZAPPED)) { - err = -EINVAL; - goto out; - } - - ax25->source_addr = call; - - /* - * User already set interface with SO_BINDTODEVICE - */ - if (ax25->ax25_dev != NULL) - goto done; - - if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) { - if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 && - (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) { - err = -EADDRNOTAVAIL; - goto out; - } - } else { - if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) { - err = -EADDRNOTAVAIL; - goto out; - } - } - - if (ax25_dev) { - ax25_fillin_cb(ax25, ax25_dev); - netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC); - } - -done: - ax25_cb_add(ax25); - sock_reset_flag(sk, SOCK_ZAPPED); - -out: - release_sock(sk); - - return err; -} - -/* - * FIXME: nonblock behaviour looks like it may have a bug. - */ -static int __must_check ax25_connect(struct socket *sock, - struct sockaddr_unsized *uaddr, int addr_len, int flags) -{ - struct sock *sk = sock->sk; - ax25_cb *ax25 = sk_to_ax25(sk), *ax25t; - struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; - ax25_digi *digi = NULL; - int ct = 0, err = 0; - - /* - * some sanity checks. code further down depends on this - */ - - if (addr_len == sizeof(struct sockaddr_ax25)) - /* support for this will go away in early 2.5.x - * ax25_connect(): uses obsolete socket structure - */ - ; - else if (addr_len != sizeof(struct full_sockaddr_ax25)) - /* support for old structure may go away some time - * ax25_connect(): uses old (6 digipeater) socket structure. - */ - if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) - return -EINVAL; - - - if (fsa->fsa_ax25.sax25_family != AF_AX25) - return -EINVAL; - - lock_sock(sk); - - /* deal with restarts */ - if (sock->state == SS_CONNECTING) { - switch (sk->sk_state) { - case TCP_SYN_SENT: /* still trying */ - err = -EINPROGRESS; - goto out_release; - - case TCP_ESTABLISHED: /* connection established */ - sock->state = SS_CONNECTED; - goto out_release; - - case TCP_CLOSE: /* connection refused */ - sock->state = SS_UNCONNECTED; - err = -ECONNREFUSED; - goto out_release; - } - } - - if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) { - err = -EISCONN; /* No reconnect on a seqpacket socket */ - goto out_release; - } - - sk->sk_state = TCP_CLOSE; - sock->state = SS_UNCONNECTED; - - kfree(ax25->digipeat); - ax25->digipeat = NULL; - - /* - * Handle digi-peaters to be used. - */ - if (addr_len > sizeof(struct sockaddr_ax25) && - fsa->fsa_ax25.sax25_ndigis != 0) { - /* Valid number of digipeaters ? */ - if (fsa->fsa_ax25.sax25_ndigis < 1 || - fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS || - addr_len < sizeof(struct sockaddr_ax25) + - sizeof(ax25_address) * fsa->fsa_ax25.sax25_ndigis) { - err = -EINVAL; - goto out_release; - } - - if ((digi = kmalloc_obj(ax25_digi)) == NULL) { - err = -ENOBUFS; - goto out_release; - } - - digi->ndigi = fsa->fsa_ax25.sax25_ndigis; - digi->lastrepeat = -1; - - while (ct < fsa->fsa_ax25.sax25_ndigis) { - if ((fsa->fsa_digipeater[ct].ax25_call[6] & - AX25_HBIT) && ax25->iamdigi) { - digi->repeated[ct] = 1; - digi->lastrepeat = ct; - } else { - digi->repeated[ct] = 0; - } - digi->calls[ct] = fsa->fsa_digipeater[ct]; - ct++; - } - } - - /* Must bind first - autobinding does not work. */ - if (sock_flag(sk, SOCK_ZAPPED)) { - kfree(digi); - err = -EINVAL; - goto out_release; - } - - /* Check to see if the device has been filled in, error if it hasn't. */ - if (ax25->ax25_dev == NULL) { - kfree(digi); - err = -EHOSTUNREACH; - goto out_release; - } - - if (sk->sk_type == SOCK_SEQPACKET && - (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, - ax25->ax25_dev->dev))) { - kfree(digi); - err = -EADDRINUSE; /* Already such a connection */ - ax25_cb_put(ax25t); - goto out_release; - } - - ax25->dest_addr = fsa->fsa_ax25.sax25_call; - ax25->digipeat = digi; - - /* First the easy one */ - if (sk->sk_type != SOCK_SEQPACKET) { - sock->state = SS_CONNECTED; - sk->sk_state = TCP_ESTABLISHED; - goto out_release; - } - - /* Move to connecting socket, ax.25 lapb WAIT_UA.. */ - sock->state = SS_CONNECTING; - sk->sk_state = TCP_SYN_SENT; - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_establish_data_link(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - if (ax25->ax25_dev->dama.slave) - ax25_ds_establish_data_link(ax25); - else - ax25_std_establish_data_link(ax25); - break; -#endif - } - - ax25->state = AX25_STATE_1; - - ax25_start_heartbeat(ax25); - - /* Now the loop */ - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { - err = -EINPROGRESS; - goto out_release; - } - - if (sk->sk_state == TCP_SYN_SENT) { - DEFINE_WAIT(wait); - - for (;;) { - prepare_to_wait(sk_sleep(sk), &wait, - TASK_INTERRUPTIBLE); - if (sk->sk_state != TCP_SYN_SENT) - break; - if (!signal_pending(current)) { - release_sock(sk); - schedule(); - lock_sock(sk); - continue; - } - err = -ERESTARTSYS; - break; - } - finish_wait(sk_sleep(sk), &wait); - - if (err) - goto out_release; - } - - if (sk->sk_state != TCP_ESTABLISHED) { - /* Not in ABM, not in WAIT_UA -> failed */ - sock->state = SS_UNCONNECTED; - err = sock_error(sk); /* Always set at this point */ - goto out_release; - } - - sock->state = SS_CONNECTED; - - err = 0; -out_release: - release_sock(sk); - - return err; -} - -static int ax25_accept(struct socket *sock, struct socket *newsock, - struct proto_accept_arg *arg) -{ - struct sk_buff *skb; - struct sock *newsk; - ax25_dev *ax25_dev; - DEFINE_WAIT(wait); - struct sock *sk; - ax25_cb *ax25; - int err = 0; - - if (sock->state != SS_UNCONNECTED) - return -EINVAL; - - if ((sk = sock->sk) == NULL) - return -EINVAL; - - lock_sock(sk); - if (sk->sk_type != SOCK_SEQPACKET) { - err = -EOPNOTSUPP; - goto out; - } - - if (sk->sk_state != TCP_LISTEN) { - err = -EINVAL; - goto out; - } - - /* - * The read queue this time is holding sockets ready to use - * hooked into the SABM we saved - */ - for (;;) { - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - skb = skb_dequeue(&sk->sk_receive_queue); - if (skb) - break; - - if (arg->flags & O_NONBLOCK) { - err = -EWOULDBLOCK; - break; - } - if (!signal_pending(current)) { - release_sock(sk); - schedule(); - lock_sock(sk); - continue; - } - err = -ERESTARTSYS; - break; - } - finish_wait(sk_sleep(sk), &wait); - - if (err) - goto out; - - newsk = skb->sk; - sock_graft(newsk, newsock); - - /* Now attach up the new socket */ - kfree_skb(skb); - sk_acceptq_removed(sk); - newsock->state = SS_CONNECTED; - ax25 = sk_to_ax25(newsk); - ax25_dev = ax25->ax25_dev; - netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC); - ax25_dev_hold(ax25_dev); - -out: - release_sock(sk); - - return err; -} - -static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, - int peer) -{ - struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; - struct sock *sk = sock->sk; - unsigned char ndigi, i; - ax25_cb *ax25; - int err = 0; - - memset(fsa, 0, sizeof(*fsa)); - lock_sock(sk); - ax25 = sk_to_ax25(sk); - - if (peer != 0) { - if (sk->sk_state != TCP_ESTABLISHED) { - err = -ENOTCONN; - goto out; - } - - fsa->fsa_ax25.sax25_family = AF_AX25; - fsa->fsa_ax25.sax25_call = ax25->dest_addr; - - if (ax25->digipeat != NULL) { - ndigi = ax25->digipeat->ndigi; - fsa->fsa_ax25.sax25_ndigis = ndigi; - for (i = 0; i < ndigi; i++) - fsa->fsa_digipeater[i] = - ax25->digipeat->calls[i]; - } - } else { - fsa->fsa_ax25.sax25_family = AF_AX25; - fsa->fsa_ax25.sax25_call = ax25->source_addr; - fsa->fsa_ax25.sax25_ndigis = 1; - if (ax25->ax25_dev != NULL) { - memcpy(&fsa->fsa_digipeater[0], - ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN); - } else { - fsa->fsa_digipeater[0] = null_ax25_address; - } - } - err = sizeof (struct full_sockaddr_ax25); - -out: - release_sock(sk); - - return err; -} - -static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) -{ - DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name); - struct sock *sk = sock->sk; - struct sockaddr_ax25 sax; - struct sk_buff *skb; - ax25_digi dtmp, *dp; - ax25_cb *ax25; - size_t size; - int lv, err, addr_len = msg->msg_namelen; - - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) - return -EINVAL; - - lock_sock(sk); - ax25 = sk_to_ax25(sk); - - if (sock_flag(sk, SOCK_ZAPPED)) { - err = -EADDRNOTAVAIL; - goto out; - } - - if (sk->sk_shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 0); - err = -EPIPE; - goto out; - } - - if (ax25->ax25_dev == NULL) { - err = -ENETUNREACH; - goto out; - } - - if (len > ax25->ax25_dev->dev->mtu) { - err = -EMSGSIZE; - goto out; - } - - if (usax != NULL) { - if (usax->sax25_family != AF_AX25) { - err = -EINVAL; - goto out; - } - - if (addr_len == sizeof(struct sockaddr_ax25)) - /* ax25_sendmsg(): uses obsolete socket structure */ - ; - else if (addr_len != sizeof(struct full_sockaddr_ax25)) - /* support for old structure may go away some time - * ax25_sendmsg(): uses old (6 digipeater) - * socket structure. - */ - if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) { - err = -EINVAL; - goto out; - } - - - if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) { - int ct = 0; - struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax; - - /* Valid number of digipeaters ? */ - if (usax->sax25_ndigis < 1 || - usax->sax25_ndigis > AX25_MAX_DIGIS || - addr_len < sizeof(struct sockaddr_ax25) + - sizeof(ax25_address) * usax->sax25_ndigis) { - err = -EINVAL; - goto out; - } - - dtmp.ndigi = usax->sax25_ndigis; - - while (ct < usax->sax25_ndigis) { - dtmp.repeated[ct] = 0; - dtmp.calls[ct] = fsa->fsa_digipeater[ct]; - ct++; - } - - dtmp.lastrepeat = 0; - } - - sax = *usax; - if (sk->sk_type == SOCK_SEQPACKET && - ax25cmp(&ax25->dest_addr, &sax.sax25_call)) { - err = -EISCONN; - goto out; - } - if (usax->sax25_ndigis == 0) - dp = NULL; - else - dp = &dtmp; - } else { - /* - * FIXME: 1003.1g - if the socket is like this because - * it has become closed (not started closed) and is VC - * we ought to SIGPIPE, EPIPE - */ - if (sk->sk_state != TCP_ESTABLISHED) { - err = -ENOTCONN; - goto out; - } - sax.sax25_family = AF_AX25; - sax.sax25_call = ax25->dest_addr; - dp = ax25->digipeat; - } - - /* Build a packet */ - /* Assume the worst case */ - size = len + ax25->ax25_dev->dev->hard_header_len; - - skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err); - if (skb == NULL) - goto out; - - skb_reserve(skb, size - len); - - /* User data follows immediately after the AX.25 data */ - if (memcpy_from_msg(skb_put(skb, len), msg, len)) { - err = -EFAULT; - kfree_skb(skb); - goto out; - } - - skb_reset_network_header(skb); - - /* Add the PID if one is not supplied by the user in the skb */ - if (!ax25->pidincl) - *(u8 *)skb_push(skb, 1) = sk->sk_protocol; - - if (sk->sk_type == SOCK_SEQPACKET) { - /* Connected mode sockets go via the LAPB machine */ - if (sk->sk_state != TCP_ESTABLISHED) { - kfree_skb(skb); - err = -ENOTCONN; - goto out; - } - - /* Shove it onto the queue and kick */ - ax25_output(ax25, ax25->paclen, skb); - - err = len; - goto out; - } - - skb_push(skb, 1 + ax25_addr_size(dp)); - - /* Building AX.25 Header */ - - /* Build an AX.25 header */ - lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call, - dp, AX25_COMMAND, AX25_MODULUS); - - skb_set_transport_header(skb, lv); - - *skb_transport_header(skb) = AX25_UI; - - /* Datagram frames go straight out of the door as UI */ - ax25_queue_xmit(skb, ax25->ax25_dev->dev); - - err = len; - -out: - release_sock(sk); - - return err; -} - -static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, - int flags) -{ - struct sock *sk = sock->sk; - struct sk_buff *skb, *last; - struct sk_buff_head *sk_queue; - int copied; - int err = 0; - int off = 0; - long timeo; - - lock_sock(sk); - /* - * This works for seqpacket too. The receiver has ordered the - * queue for us! We do one quick check first though - */ - if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_ESTABLISHED) { - err = -ENOTCONN; - goto out; - } - - /* We need support for non-blocking reads. */ - sk_queue = &sk->sk_receive_queue; - skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, &err, &last); - /* If no packet is available, release_sock(sk) and try again. */ - if (!skb) { - if (err != -EAGAIN) - goto out; - release_sock(sk); - timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); - while (timeo && !__skb_wait_for_more_packets(sk, sk_queue, &err, - &timeo, last)) { - skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, - &err, &last); - if (skb) - break; - - if (err != -EAGAIN) - goto done; - } - if (!skb) - goto done; - lock_sock(sk); - } - - if (!sk_to_ax25(sk)->pidincl) - skb_pull(skb, 1); /* Remove PID */ - - skb_reset_transport_header(skb); - copied = skb->len; - - if (copied > size) { - copied = size; - msg->msg_flags |= MSG_TRUNC; - } - - skb_copy_datagram_msg(skb, 0, msg, copied); - - if (msg->msg_name) { - ax25_digi digi; - ax25_address src; - const unsigned char *mac = skb_mac_header(skb); - DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name); - - memset(sax, 0, sizeof(struct full_sockaddr_ax25)); - ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL, - &digi, NULL, NULL); - sax->sax25_family = AF_AX25; - /* We set this correctly, even though we may not let the - application know the digi calls further down (because it - did NOT ask to know them). This could get political... **/ - sax->sax25_ndigis = digi.ndigi; - sax->sax25_call = src; - - if (sax->sax25_ndigis != 0) { - int ct; - struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax; - - for (ct = 0; ct < digi.ndigi; ct++) - fsa->fsa_digipeater[ct] = digi.calls[ct]; - } - msg->msg_namelen = sizeof(struct full_sockaddr_ax25); - } - - skb_free_datagram(sk, skb); - err = copied; - -out: - release_sock(sk); - -done: - return err; -} - -static int ax25_shutdown(struct socket *sk, int how) -{ - /* FIXME - generate DM and RNR states */ - return -EOPNOTSUPP; -} - -static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; - int res = 0; - - lock_sock(sk); - switch (cmd) { - case TIOCOUTQ: { - long amount; - - amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); - if (amount < 0) - amount = 0; - res = put_user(amount, (int __user *)argp); - break; - } - - case TIOCINQ: { - struct sk_buff *skb; - long amount = 0L; - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) - amount = skb->len; - res = put_user(amount, (int __user *) argp); - break; - } - - case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ - case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ - case SIOCAX25GETUID: { - struct sockaddr_ax25 sax25; - if (copy_from_user(&sax25, argp, sizeof(sax25))) { - res = -EFAULT; - break; - } - res = ax25_uid_ioctl(cmd, &sax25); - break; - } - - case SIOCAX25NOUID: { /* Set the default policy (default/bar) */ - long amount; - if (!capable(CAP_NET_ADMIN)) { - res = -EPERM; - break; - } - if (get_user(amount, (long __user *)argp)) { - res = -EFAULT; - break; - } - if (amount < 0 || amount > AX25_NOUID_BLOCK) { - res = -EINVAL; - break; - } - ax25_uid_policy = amount; - res = 0; - break; - } - - case SIOCADDRT: - case SIOCDELRT: - case SIOCAX25OPTRT: - if (!capable(CAP_NET_ADMIN)) { - res = -EPERM; - break; - } - res = ax25_rt_ioctl(cmd, argp); - break; - - case SIOCAX25CTLCON: - if (!capable(CAP_NET_ADMIN)) { - res = -EPERM; - break; - } - res = ax25_ctl_ioctl(cmd, argp); - break; - - case SIOCAX25GETINFO: - case SIOCAX25GETINFOOLD: { - ax25_cb *ax25 = sk_to_ax25(sk); - struct ax25_info_struct ax25_info; - - ax25_info.t1 = ax25->t1 / HZ; - ax25_info.t2 = ax25->t2 / HZ; - ax25_info.t3 = ax25->t3 / HZ; - ax25_info.idle = ax25->idle / (60 * HZ); - ax25_info.n2 = ax25->n2; - ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ; - ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ; - ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ; - ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); - ax25_info.n2count = ax25->n2count; - ax25_info.state = ax25->state; - ax25_info.rcv_q = sk_rmem_alloc_get(sk); - ax25_info.snd_q = sk_wmem_alloc_get(sk); - ax25_info.vs = ax25->vs; - ax25_info.vr = ax25->vr; - ax25_info.va = ax25->va; - ax25_info.vs_max = ax25->vs; /* reserved */ - ax25_info.paclen = ax25->paclen; - ax25_info.window = ax25->window; - - /* old structure? */ - if (cmd == SIOCAX25GETINFOOLD) { - static int warned = 0; - if (!warned) { - printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n", - current->comm); - warned=1; - } - - if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) { - res = -EFAULT; - break; - } - } else { - if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct))) { - res = -EINVAL; - break; - } - } - res = 0; - break; - } - - case SIOCAX25ADDFWD: - case SIOCAX25DELFWD: { - struct ax25_fwd_struct ax25_fwd; - if (!capable(CAP_NET_ADMIN)) { - res = -EPERM; - break; - } - if (copy_from_user(&ax25_fwd, argp, sizeof(ax25_fwd))) { - res = -EFAULT; - break; - } - res = ax25_fwd_ioctl(cmd, &ax25_fwd); - break; - } - - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - res = -EINVAL; - break; - - default: - res = -ENOIOCTLCMD; - break; - } - release_sock(sk); - - return res; -} - -#ifdef CONFIG_PROC_FS - -static void *ax25_info_start(struct seq_file *seq, loff_t *pos) - __acquires(ax25_list_lock) -{ - spin_lock_bh(&ax25_list_lock); - return seq_hlist_start(&ax25_list, *pos); -} - -static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_hlist_next(v, &ax25_list, pos); -} - -static void ax25_info_stop(struct seq_file *seq, void *v) - __releases(ax25_list_lock) -{ - spin_unlock_bh(&ax25_list_lock); -} - -static int ax25_info_show(struct seq_file *seq, void *v) -{ - ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node); - char buf[11]; - int k; - - - /* - * New format: - * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode - */ - - seq_printf(seq, "%p %s %s%s ", - ax25, - ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, - ax2asc(buf, &ax25->source_addr), - ax25->iamdigi? "*":""); - seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr)); - - for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { - seq_printf(seq, ",%s%s", - ax2asc(buf, &ax25->digipeat->calls[k]), - ax25->digipeat->repeated[k]? "*":""); - } - - seq_printf(seq, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", - ax25->state, - ax25->vs, ax25->vr, ax25->va, - ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, - ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, - ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, - ax25_display_timer(&ax25->idletimer) / (60 * HZ), - ax25->idle / (60 * HZ), - ax25->n2count, ax25->n2, - ax25->rtt / HZ, - ax25->window, - ax25->paclen); - - if (ax25->sk != NULL) { - seq_printf(seq, " %d %d %llu\n", - sk_wmem_alloc_get(ax25->sk), - sk_rmem_alloc_get(ax25->sk), - sock_i_ino(ax25->sk)); - } else { - seq_puts(seq, " * * *\n"); - } - return 0; -} - -static const struct seq_operations ax25_info_seqops = { - .start = ax25_info_start, - .next = ax25_info_next, - .stop = ax25_info_stop, - .show = ax25_info_show, -}; -#endif - -static const struct net_proto_family ax25_family_ops = { - .family = PF_AX25, - .create = ax25_create, - .owner = THIS_MODULE, -}; - -static const struct proto_ops ax25_proto_ops = { - .family = PF_AX25, - .owner = THIS_MODULE, - .release = ax25_release, - .bind = ax25_bind, - .connect = ax25_connect, - .socketpair = sock_no_socketpair, - .accept = ax25_accept, - .getname = ax25_getname, - .poll = datagram_poll, - .ioctl = ax25_ioctl, - .gettstamp = sock_gettstamp, - .listen = ax25_listen, - .shutdown = ax25_shutdown, - .setsockopt = ax25_setsockopt, - .getsockopt = ax25_getsockopt, - .sendmsg = ax25_sendmsg, - .recvmsg = ax25_recvmsg, - .mmap = sock_no_mmap, -}; - -/* - * Called by socket.c on kernel start up - */ -static struct packet_type ax25_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_AX25), - .func = ax25_kiss_rcv, -}; - -static struct notifier_block ax25_dev_notifier = { - .notifier_call = ax25_device_event, -}; - -static int __init ax25_init(void) -{ - int rc = proto_register(&ax25_proto, 0); - - if (rc != 0) - goto out; - - sock_register(&ax25_family_ops); - dev_add_pack(&ax25_packet_type); - register_netdevice_notifier(&ax25_dev_notifier); - - proc_create_seq("ax25_route", 0444, init_net.proc_net, &ax25_rt_seqops); - proc_create_seq("ax25", 0444, init_net.proc_net, &ax25_info_seqops); - proc_create_seq("ax25_calls", 0444, init_net.proc_net, - &ax25_uid_seqops); -out: - return rc; -} -module_init(ax25_init); - - -MODULE_AUTHOR("Jonathan Naylor G4KLX "); -MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NETPROTO(PF_AX25); - -static void __exit ax25_exit(void) -{ - remove_proc_entry("ax25_route", init_net.proc_net); - remove_proc_entry("ax25", init_net.proc_net); - remove_proc_entry("ax25_calls", init_net.proc_net); - - unregister_netdevice_notifier(&ax25_dev_notifier); - - dev_remove_pack(&ax25_packet_type); - - sock_unregister(PF_AX25); - proto_unregister(&ax25_proto); - - ax25_rt_free(); - ax25_uid_free(); - ax25_dev_free(); -} -module_exit(ax25_exit); diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c deleted file mode 100644 index f68865a4d0ab..000000000000 --- a/net/ax25/ax25_addr.c +++ /dev/null @@ -1,303 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The default broadcast address of an interface is QST-0; the default address - * is LINUX-1. The null address is defined as a callsign of all spaces with - * an SSID of zero. - */ - -const ax25_address ax25_bcast = - {{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; -const ax25_address ax25_defaddr = - {{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}}; -const ax25_address null_ax25_address = - {{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; - -EXPORT_SYMBOL_GPL(ax25_bcast); -EXPORT_SYMBOL_GPL(ax25_defaddr); -EXPORT_SYMBOL(null_ax25_address); - -/* - * ax25 -> ascii conversion - */ -char *ax2asc(char *buf, const ax25_address *a) -{ - char c, *s; - int n; - - for (n = 0, s = buf; n < 6; n++) { - c = (a->ax25_call[n] >> 1) & 0x7F; - - if (c != ' ') *s++ = c; - } - - *s++ = '-'; - - if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { - *s++ = '1'; - n -= 10; - } - - *s++ = n + '0'; - *s++ = '\0'; - - if (*buf == '\0' || *buf == '-') - return "*"; - - return buf; - -} - -EXPORT_SYMBOL(ax2asc); - -/* - * ascii -> ax25 conversion - */ -void asc2ax(ax25_address *addr, const char *callsign) -{ - const char *s; - int n; - - for (s = callsign, n = 0; n < 6; n++) { - if (*s != '\0' && *s != '-') - addr->ax25_call[n] = *s++; - else - addr->ax25_call[n] = ' '; - addr->ax25_call[n] <<= 1; - addr->ax25_call[n] &= 0xFE; - } - - if (*s++ == '\0') { - addr->ax25_call[6] = 0x00; - return; - } - - addr->ax25_call[6] = *s++ - '0'; - - if (*s != '\0') { - addr->ax25_call[6] *= 10; - addr->ax25_call[6] += *s++ - '0'; - } - - addr->ax25_call[6] <<= 1; - addr->ax25_call[6] &= 0x1E; -} - -EXPORT_SYMBOL(asc2ax); - -/* - * Compare two ax.25 addresses - */ -int ax25cmp(const ax25_address *a, const ax25_address *b) -{ - int ct = 0; - - while (ct < 6) { - if ((a->ax25_call[ct] & 0xFE) != (b->ax25_call[ct] & 0xFE)) /* Clean off repeater bits */ - return 1; - ct++; - } - - if ((a->ax25_call[ct] & 0x1E) == (b->ax25_call[ct] & 0x1E)) /* SSID without control bit */ - return 0; - - return 2; /* Partial match */ -} - -EXPORT_SYMBOL(ax25cmp); - -/* - * Compare two AX.25 digipeater paths. - */ -int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2) -{ - int i; - - if (digi1->ndigi != digi2->ndigi) - return 1; - - if (digi1->lastrepeat != digi2->lastrepeat) - return 1; - - for (i = 0; i < digi1->ndigi; i++) - if (ax25cmp(&digi1->calls[i], &digi2->calls[i]) != 0) - return 1; - - return 0; -} - -/* - * Given an AX.25 address pull of to, from, digi list, command/response and the start of data - * - */ -const unsigned char *ax25_addr_parse(const unsigned char *buf, int len, - ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, - int *dama) -{ - int d = 0; - - if (len < 14) return NULL; - - if (flags != NULL) { - *flags = 0; - - if (buf[6] & AX25_CBIT) - *flags = AX25_COMMAND; - if (buf[13] & AX25_CBIT) - *flags = AX25_RESPONSE; - } - - if (dama != NULL) - *dama = ~buf[13] & AX25_DAMA_FLAG; - - /* Copy to, from */ - if (dest != NULL) - memcpy(dest, buf + 0, AX25_ADDR_LEN); - if (src != NULL) - memcpy(src, buf + 7, AX25_ADDR_LEN); - - buf += 2 * AX25_ADDR_LEN; - len -= 2 * AX25_ADDR_LEN; - - digi->lastrepeat = -1; - digi->ndigi = 0; - - while (!(buf[-1] & AX25_EBIT)) { - if (d >= AX25_MAX_DIGIS) - return NULL; - if (len < AX25_ADDR_LEN) - return NULL; - - memcpy(&digi->calls[d], buf, AX25_ADDR_LEN); - digi->ndigi = d + 1; - - if (buf[6] & AX25_HBIT) { - digi->repeated[d] = 1; - digi->lastrepeat = d; - } else { - digi->repeated[d] = 0; - } - - buf += AX25_ADDR_LEN; - len -= AX25_ADDR_LEN; - d++; - } - - return buf; -} - -/* - * Assemble an AX.25 header from the bits - */ -int ax25_addr_build(unsigned char *buf, const ax25_address *src, - const ax25_address *dest, const ax25_digi *d, int flag, int modulus) -{ - int len = 0; - int ct = 0; - - memcpy(buf, dest, AX25_ADDR_LEN); - buf[6] &= ~(AX25_EBIT | AX25_CBIT); - buf[6] |= AX25_SSSID_SPARE; - - if (flag == AX25_COMMAND) buf[6] |= AX25_CBIT; - - buf += AX25_ADDR_LEN; - len += AX25_ADDR_LEN; - - memcpy(buf, src, AX25_ADDR_LEN); - buf[6] &= ~(AX25_EBIT | AX25_CBIT); - buf[6] &= ~AX25_SSSID_SPARE; - - if (modulus == AX25_MODULUS) - buf[6] |= AX25_SSSID_SPARE; - else - buf[6] |= AX25_ESSID_SPARE; - - if (flag == AX25_RESPONSE) buf[6] |= AX25_CBIT; - - /* - * Fast path the normal digiless path - */ - if (d == NULL || d->ndigi == 0) { - buf[6] |= AX25_EBIT; - return 2 * AX25_ADDR_LEN; - } - - buf += AX25_ADDR_LEN; - len += AX25_ADDR_LEN; - - while (ct < d->ndigi) { - memcpy(buf, &d->calls[ct], AX25_ADDR_LEN); - - if (d->repeated[ct]) - buf[6] |= AX25_HBIT; - else - buf[6] &= ~AX25_HBIT; - - buf[6] &= ~AX25_EBIT; - buf[6] |= AX25_SSSID_SPARE; - - buf += AX25_ADDR_LEN; - len += AX25_ADDR_LEN; - ct++; - } - - buf[-1] |= AX25_EBIT; - - return len; -} - -int ax25_addr_size(const ax25_digi *dp) -{ - if (dp == NULL) - return 2 * AX25_ADDR_LEN; - - return AX25_ADDR_LEN * (2 + dp->ndigi); -} - -/* - * Reverse Digipeat List. May not pass both parameters as same struct - */ -void ax25_digi_invert(const ax25_digi *in, ax25_digi *out) -{ - int ct; - - out->ndigi = in->ndigi; - out->lastrepeat = in->ndigi - in->lastrepeat - 2; - - /* Invert the digipeaters */ - for (ct = 0; ct < in->ndigi; ct++) { - out->calls[ct] = in->calls[in->ndigi - ct - 1]; - - if (ct <= out->lastrepeat) { - out->calls[ct].ax25_call[6] |= AX25_HBIT; - out->repeated[ct] = 1; - } else { - out->calls[ct].ax25_call[6] &= ~AX25_HBIT; - out->repeated[ct] = 0; - } - } -} diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c deleted file mode 100644 index 3c0544fc4ad5..000000000000 --- a/net/ax25/ax25_dev.c +++ /dev/null @@ -1,200 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static LIST_HEAD(ax25_dev_list); -DEFINE_SPINLOCK(ax25_dev_lock); - -ax25_dev *ax25_addr_ax25dev(ax25_address *addr) -{ - ax25_dev *ax25_dev, *res = NULL; - - spin_lock_bh(&ax25_dev_lock); - list_for_each_entry(ax25_dev, &ax25_dev_list, list) - if (ax25cmp(addr, (const ax25_address *)ax25_dev->dev->dev_addr) == 0) { - res = ax25_dev; - ax25_dev_hold(ax25_dev); - break; - } - spin_unlock_bh(&ax25_dev_lock); - - return res; -} - -/* - * This is called when an interface is brought up. These are - * reasonable defaults. - */ -void ax25_dev_device_up(struct net_device *dev) -{ - ax25_dev *ax25_dev; - - ax25_dev = kzalloc_obj(*ax25_dev); - if (!ax25_dev) { - printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n"); - return; - } - - refcount_set(&ax25_dev->refcount, 1); - ax25_dev->dev = dev; - netdev_hold(dev, &ax25_dev->dev_tracker, GFP_KERNEL); - ax25_dev->forward = NULL; - ax25_dev->device_up = true; - - ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; - ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE; - ax25_dev->values[AX25_VALUES_BACKOFF] = AX25_DEF_BACKOFF; - ax25_dev->values[AX25_VALUES_CONMODE] = AX25_DEF_CONMODE; - ax25_dev->values[AX25_VALUES_WINDOW] = AX25_DEF_WINDOW; - ax25_dev->values[AX25_VALUES_EWINDOW] = AX25_DEF_EWINDOW; - ax25_dev->values[AX25_VALUES_T1] = AX25_DEF_T1; - ax25_dev->values[AX25_VALUES_T2] = AX25_DEF_T2; - ax25_dev->values[AX25_VALUES_T3] = AX25_DEF_T3; - ax25_dev->values[AX25_VALUES_IDLE] = AX25_DEF_IDLE; - ax25_dev->values[AX25_VALUES_N2] = AX25_DEF_N2; - ax25_dev->values[AX25_VALUES_PACLEN] = AX25_DEF_PACLEN; - ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL; - -#ifdef CONFIG_AX25_DAMA_SLAVE - ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; - - ax25_ds_setup_timer(ax25_dev); -#endif - - spin_lock_bh(&ax25_dev_lock); - list_add(&ax25_dev->list, &ax25_dev_list); - rcu_assign_pointer(dev->ax25_ptr, ax25_dev); - spin_unlock_bh(&ax25_dev_lock); - - ax25_register_dev_sysctl(ax25_dev); -} - -void ax25_dev_device_down(struct net_device *dev) -{ - ax25_dev *s, *ax25_dev; - - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) - return; - - ax25_unregister_dev_sysctl(ax25_dev); - - spin_lock_bh(&ax25_dev_lock); - -#ifdef CONFIG_AX25_DAMA_SLAVE - timer_shutdown_sync(&ax25_dev->dama.slave_timer); -#endif - - /* - * Remove any packet forwarding that points to this device. - */ - list_for_each_entry(s, &ax25_dev_list, list) - if (s->forward == dev) - s->forward = NULL; - - list_for_each_entry(s, &ax25_dev_list, list) { - if (s == ax25_dev) { - list_del(&s->list); - break; - } - } - - RCU_INIT_POINTER(dev->ax25_ptr, NULL); - spin_unlock_bh(&ax25_dev_lock); - netdev_put(dev, &ax25_dev->dev_tracker); - ax25_dev_put(ax25_dev); -} - -int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) -{ - ax25_dev *ax25_dev, *fwd_dev; - - if ((ax25_dev = ax25_addr_ax25dev(&fwd->port_from)) == NULL) - return -EINVAL; - - switch (cmd) { - case SIOCAX25ADDFWD: - fwd_dev = ax25_addr_ax25dev(&fwd->port_to); - if (!fwd_dev) { - ax25_dev_put(ax25_dev); - return -EINVAL; - } - if (ax25_dev->forward) { - ax25_dev_put(fwd_dev); - ax25_dev_put(ax25_dev); - return -EINVAL; - } - ax25_dev->forward = fwd_dev->dev; - ax25_dev_put(fwd_dev); - ax25_dev_put(ax25_dev); - break; - - case SIOCAX25DELFWD: - if (!ax25_dev->forward) { - ax25_dev_put(ax25_dev); - return -EINVAL; - } - ax25_dev->forward = NULL; - ax25_dev_put(ax25_dev); - break; - - default: - ax25_dev_put(ax25_dev); - return -EINVAL; - } - - return 0; -} - -struct net_device *ax25_fwd_dev(struct net_device *dev) -{ - ax25_dev *ax25_dev; - - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) - return dev; - - if (ax25_dev->forward == NULL) - return dev; - - return ax25_dev->forward; -} - -/* - * Free all memory associated with device structures. - */ -void __exit ax25_dev_free(void) -{ - ax25_dev *s, *n; - - spin_lock_bh(&ax25_dev_lock); - list_for_each_entry_safe(s, n, &ax25_dev_list, list) { - netdev_put(s->dev, &s->dev_tracker); - list_del(&s->list); - ax25_dev_put(s); - } - spin_unlock_bh(&ax25_dev_lock); -} diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c deleted file mode 100644 index c62f8fb06189..000000000000 --- a/net/ax25/ax25_ds_in.c +++ /dev/null @@ -1,298 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * State machine for state 1, Awaiting Connection State. - * The handling of the timer(s) is in file ax25_ds_timer.c. - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) -{ - switch (frametype) { - case AX25_SABM: - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_SABME: - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - break; - - case AX25_UA: - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - if (ax25->sk != NULL) { - bh_lock_sock(ax25->sk); - ax25->sk->sk_state = TCP_ESTABLISHED; - /* - * For WAIT_SABM connections we will produce an accept - * ready socket here - */ - if (!sock_flag(ax25->sk, SOCK_DEAD)) - ax25->sk->sk_state_change(ax25->sk); - bh_unlock_sock(ax25->sk); - } - ax25_dama_on(ax25); - - /* according to DK4EG's spec we are required to - * send a RR RESPONSE FINAL NR=0. - */ - - ax25_std_enquiry_response(ax25); - break; - - case AX25_DM: - if (pf) - ax25_disconnect(ax25, ECONNREFUSED); - break; - - default: - if (pf) - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - break; - } - - return 0; -} - -/* - * State machine for state 2, Awaiting Release State. - * The handling of the timer(s) is in file ax25_ds_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) -{ - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_dama_off(ax25); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_dama_off(ax25); - ax25_disconnect(ax25, 0); - break; - - case AX25_DM: - case AX25_UA: - if (pf) { - ax25_dama_off(ax25); - ax25_disconnect(ax25, 0); - } - break; - - case AX25_I: - case AX25_REJ: - case AX25_RNR: - case AX25_RR: - if (pf) { - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_dama_off(ax25); - } - break; - - default: - break; - } - - return 0; -} - -/* - * State machine for state 3, Connected State. - * The handling of the timer(s) is in file ax25_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) -{ - int queued = 0; - - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->condition = 0x00; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25_requeue_frames(ax25); - ax25_dama_on(ax25); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_dama_off(ax25); - ax25_disconnect(ax25, 0); - break; - - case AX25_DM: - ax25_dama_off(ax25); - ax25_disconnect(ax25, ECONNRESET); - break; - - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - - if (ax25_validate_nr(ax25, nr)) { - if (ax25_check_iframes_acked(ax25, nr)) - ax25->n2count=0; - if (type == AX25_COMMAND && pf) - ax25_ds_enquiry_response(ax25); - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - - if (ax25_validate_nr(ax25, nr)) { - if (ax25->va != nr) - ax25->n2count=0; - - ax25_frames_acked(ax25, nr); - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_requeue_frames(ax25); - - if (type == AX25_COMMAND && pf) - ax25_ds_enquiry_response(ax25); - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - if (ax25->condition & AX25_COND_PEER_RX_BUSY) { - ax25_frames_acked(ax25, nr); - ax25->n2count = 0; - } else { - if (ax25_check_iframes_acked(ax25, nr)) - ax25->n2count = 0; - } - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - if (pf) ax25_ds_enquiry_response(ax25); - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25->vr = ns; /* ax25->vr - 1 */ - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - ax25_ds_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->condition |= AX25_COND_ACK_PENDING; - ax25_start_t2timer(ax25); - } - } - } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) ax25_ds_enquiry_response(ax25); - } else { - ax25->condition |= AX25_COND_REJECT; - ax25_ds_enquiry_response(ax25); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; - - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_ds_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; - - default: - break; - } - - return queued; -} - -/* - * Higher level upcall for a LAPB frame - */ -int ax25_ds_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type) -{ - int queued = 0, frametype, ns, nr, pf; - - frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); - - switch (ax25->state) { - case AX25_STATE_1: - queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_2: - queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_3: - queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type); - break; - } - - return queued; -} diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c deleted file mode 100644 index f00e27df3c76..000000000000 --- a/net/ax25/ax25_ds_subr.c +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void ax25_ds_nr_error_recovery(ax25_cb *ax25) -{ - ax25_ds_establish_data_link(ax25); -} - -/* - * dl1bke 960114: transmit I frames on DAMA poll - */ -void ax25_ds_enquiry_response(ax25_cb *ax25) -{ - ax25_cb *ax25o; - - /* Please note that neither DK4EG's nor DG2FEF's - * DAMA spec mention the following behaviour as seen - * with TheFirmware: - * - * DB0ACH->DL1BKE [DAMA] - * DL1BKE->DB0ACH - * DL1BKE-7->DB0PRA-6 DB0ACH - * DL1BKE->DB0ACH - * - * The Flexnet DAMA Master implementation apparently - * insists on the "proper" AX.25 behaviour: - * - * DB0ACH->DL1BKE [DAMA] - * DL1BKE->DB0ACH - * DL1BKE->DB0ACH - * DL1BKE-7->DB0PRA-6 DB0ACH - * - * Flexnet refuses to send us *any* I frame if we send - * a REJ in case AX25_COND_REJECT is set. It is superfluous in - * this mode anyway (a RR or RNR invokes the retransmission). - * Is this a Flexnet bug? - */ - - ax25_std_enquiry_response(ax25); - - if (!(ax25->condition & AX25_COND_PEER_RX_BUSY)) { - ax25_requeue_frames(ax25); - ax25_kick(ax25); - } - - if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2 || skb_peek(&ax25->ack_queue) != NULL) - ax25_ds_t1_timeout(ax25); - else - ax25->n2count = 0; - - ax25_start_t3timer(ax25); - ax25_ds_set_timer(ax25->ax25_dev); - - spin_lock(&ax25_list_lock); - ax25_for_each(ax25o, &ax25_list) { - if (ax25o == ax25) - continue; - - if (ax25o->ax25_dev != ax25->ax25_dev) - continue; - - if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2) { - ax25_ds_t1_timeout(ax25o); - continue; - } - - if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && ax25o->state == AX25_STATE_3) { - ax25_requeue_frames(ax25o); - ax25_kick(ax25o); - } - - if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL) - ax25_ds_t1_timeout(ax25o); - - /* do not start T3 for listening sockets (tnx DD8NE) */ - - if (ax25o->state != AX25_STATE_0) - ax25_start_t3timer(ax25o); - } - spin_unlock(&ax25_list_lock); -} - -void ax25_ds_establish_data_link(ax25_cb *ax25) -{ - ax25->condition &= AX25_COND_DAMA_MODE; - ax25->n2count = 0; - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_start_t3timer(ax25); -} - -/* - * :::FIXME::: - * This is a kludge. Not all drivers recognize kiss commands. - * We need a driver level request to switch duplex mode, that does - * either SCC changing, PI config or KISS as required. Currently - * this request isn't reliable. - */ -static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char param) -{ - struct sk_buff *skb; - unsigned char *p; - - if (ax25_dev->dev == NULL) - return; - - if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL) - return; - - skb_reset_network_header(skb); - p = skb_put(skb, 2); - - *p++ = cmd; - *p++ = param; - - skb->protocol = ax25_type_trans(skb, ax25_dev->dev); - - dev_queue_xmit(skb); -} - -/* - * A nasty problem arises if we count the number of DAMA connections - * wrong, especially when connections on the device already existed - * and our network node (or the sysop) decides to turn on DAMA Master - * mode. We thus flag the 'real' slave connections with - * ax25->dama_slave=1 and look on every disconnect if still slave - * connections exist. - */ -static int ax25_check_dama_slave(ax25_dev *ax25_dev) -{ - ax25_cb *ax25; - int res = 0; - - spin_lock(&ax25_list_lock); - ax25_for_each(ax25, &ax25_list) - if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) { - res = 1; - break; - } - spin_unlock(&ax25_list_lock); - - return res; -} - -static void ax25_dev_dama_on(ax25_dev *ax25_dev) -{ - if (ax25_dev == NULL) - return; - - if (ax25_dev->dama.slave == 0) - ax25_kiss_cmd(ax25_dev, 5, 1); - - ax25_dev->dama.slave = 1; - ax25_ds_set_timer(ax25_dev); -} - -void ax25_dev_dama_off(ax25_dev *ax25_dev) -{ - if (ax25_dev == NULL) - return; - - if (ax25_dev->dama.slave && !ax25_check_dama_slave(ax25_dev)) { - ax25_kiss_cmd(ax25_dev, 5, 0); - ax25_dev->dama.slave = 0; - ax25_ds_del_timer(ax25_dev); - } -} - -void ax25_dama_on(ax25_cb *ax25) -{ - ax25_dev_dama_on(ax25->ax25_dev); - ax25->condition |= AX25_COND_DAMA_MODE; -} - -void ax25_dama_off(ax25_cb *ax25) -{ - ax25->condition &= ~AX25_COND_DAMA_MODE; - ax25_dev_dama_off(ax25->ax25_dev); -} diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c deleted file mode 100644 index 0c9e7775aa54..000000000000 --- a/net/ax25/ax25_ds_timer.c +++ /dev/null @@ -1,235 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void ax25_ds_timeout(struct timer_list *); - -/* - * Add DAMA slave timeout timer to timer list. - * Unlike the connection based timers the timeout function gets - * triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT - * (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in - * 1/10th of a second. - */ - -void ax25_ds_setup_timer(ax25_dev *ax25_dev) -{ - timer_setup(&ax25_dev->dama.slave_timer, ax25_ds_timeout, 0); -} - -void ax25_ds_del_timer(ax25_dev *ax25_dev) -{ - if (ax25_dev) - timer_delete(&ax25_dev->dama.slave_timer); -} - -void ax25_ds_set_timer(ax25_dev *ax25_dev) -{ - if (ax25_dev == NULL) /* paranoia */ - return; - - ax25_dev->dama.slave_timeout = - msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10; - mod_timer(&ax25_dev->dama.slave_timer, jiffies + HZ); -} - -/* - * DAMA Slave Timeout - * Silently discard all (slave) connections in case our master forgot us... - */ - -static void ax25_ds_timeout(struct timer_list *t) -{ - ax25_dev *ax25_dev = timer_container_of(ax25_dev, t, dama.slave_timer); - ax25_cb *ax25; - - if (ax25_dev == NULL || !ax25_dev->dama.slave) - return; /* Yikes! */ - - if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) { - ax25_ds_set_timer(ax25_dev); - return; - } - - spin_lock(&ax25_list_lock); - ax25_for_each(ax25, &ax25_list) { - if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE)) - continue; - - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_disconnect(ax25, ETIMEDOUT); - } - spin_unlock(&ax25_list_lock); - - ax25_dev_dama_off(ax25_dev); -} - -void ax25_ds_heartbeat_expiry(ax25_cb *ax25) -{ - struct sock *sk=ax25->sk; - - if (sk) - bh_lock_sock(sk); - - switch (ax25->state) { - - case AX25_STATE_0: - case AX25_STATE_2: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (!sk || sock_flag(sk, SOCK_DESTROY) || - (sk->sk_state == TCP_LISTEN && - sock_flag(sk, SOCK_DEAD))) { - if (sk) { - sock_hold(sk); - ax25_destroy_socket(ax25); - bh_unlock_sock(sk); - /* Ungrab socket and destroy it */ - sock_put(sk); - } else - ax25_destroy_socket(ax25); - return; - } - break; - - case AX25_STATE_3: - /* - * Check the state of the receive buffer. - */ - if (sk != NULL) { - if (atomic_read(&sk->sk_rmem_alloc) < - (sk->sk_rcvbuf >> 1) && - (ax25->condition & AX25_COND_OWN_RX_BUSY)) { - ax25->condition &= ~AX25_COND_OWN_RX_BUSY; - ax25->condition &= ~AX25_COND_ACK_PENDING; - break; - } - } - break; - } - - if (sk) - bh_unlock_sock(sk); - - ax25_start_heartbeat(ax25); -} - -/* dl1bke 960114: T3 works much like the IDLE timeout, but - * gets reloaded with every frame for this - * connection. - */ -void ax25_ds_t3timer_expiry(ax25_cb *ax25) -{ - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_dama_off(ax25); - ax25_disconnect(ax25, ETIMEDOUT); -} - -/* dl1bke 960228: close the connection when IDLE expires. - * unlike T3 this timer gets reloaded only on - * I frames. - */ -void ax25_ds_idletimer_expiry(ax25_cb *ax25) -{ - ax25_clear_queues(ax25); - - ax25->n2count = 0; - ax25->state = AX25_STATE_2; - - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); - ax25_stop_t3timer(ax25); - - if (ax25->sk != NULL) { - bh_lock_sock(ax25->sk); - ax25->sk->sk_state = TCP_CLOSE; - ax25->sk->sk_err = 0; - ax25->sk->sk_shutdown |= SEND_SHUTDOWN; - if (!sock_flag(ax25->sk, SOCK_DEAD)) { - ax25->sk->sk_state_change(ax25->sk); - sock_set_flag(ax25->sk, SOCK_DEAD); - } - bh_unlock_sock(ax25->sk); - } -} - -/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC - * within the poll of any connected channel. Remember - * that we are not allowed to send anything unless we - * get polled by the Master. - * - * Thus we'll have to do parts of our T1 handling in - * ax25_enquiry_response(). - */ -void ax25_ds_t1_timeout(ax25_cb *ax25) -{ - switch (ax25->state) { - case AX25_STATE_1: - if (ax25->n2count == ax25->n2) { - if (ax25->modulus == AX25_MODULUS) { - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25->n2count = 0; - ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND); - } - } else { - ax25->n2count++; - if (ax25->modulus == AX25_MODULUS) - ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND); - } - break; - - case AX25_STATE_2: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - if (!sock_flag(ax25->sk, SOCK_DESTROY)) - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->n2count++; - } - break; - - case AX25_STATE_3: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->n2count++; - } - break; - } - - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); -} diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c deleted file mode 100644 index 3ad454416a5c..000000000000 --- a/net/ax25/ax25_iface.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct ax25_protocol *protocol_list; -static DEFINE_RWLOCK(protocol_list_lock); - -static HLIST_HEAD(ax25_linkfail_list); -static DEFINE_SPINLOCK(linkfail_lock); - -static struct listen_struct { - struct listen_struct *next; - ax25_address callsign; - struct net_device *dev; -} *listen_list = NULL; -static DEFINE_SPINLOCK(listen_lock); - -/* - * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT, - * AX25_P_IP or AX25_P_ARP ... - */ -void ax25_register_pid(struct ax25_protocol *ap) -{ - write_lock_bh(&protocol_list_lock); - ap->next = protocol_list; - protocol_list = ap; - write_unlock_bh(&protocol_list_lock); -} - -EXPORT_SYMBOL_GPL(ax25_register_pid); - -void ax25_protocol_release(unsigned int pid) -{ - struct ax25_protocol *protocol; - - write_lock_bh(&protocol_list_lock); - protocol = protocol_list; - if (protocol == NULL) - goto out; - - if (protocol->pid == pid) { - protocol_list = protocol->next; - goto out; - } - - while (protocol != NULL && protocol->next != NULL) { - if (protocol->next->pid == pid) { - protocol->next = protocol->next->next; - goto out; - } - - protocol = protocol->next; - } -out: - write_unlock_bh(&protocol_list_lock); -} - -EXPORT_SYMBOL(ax25_protocol_release); - -void ax25_linkfail_register(struct ax25_linkfail *lf) -{ - spin_lock_bh(&linkfail_lock); - hlist_add_head(&lf->lf_node, &ax25_linkfail_list); - spin_unlock_bh(&linkfail_lock); -} - -EXPORT_SYMBOL(ax25_linkfail_register); - -void ax25_linkfail_release(struct ax25_linkfail *lf) -{ - spin_lock_bh(&linkfail_lock); - hlist_del_init(&lf->lf_node); - spin_unlock_bh(&linkfail_lock); -} - -EXPORT_SYMBOL(ax25_linkfail_release); - -int ax25_listen_register(const ax25_address *callsign, struct net_device *dev) -{ - struct listen_struct *listen; - - if (ax25_listen_mine(callsign, dev)) - return 0; - - if ((listen = kmalloc_obj(*listen, GFP_ATOMIC)) == NULL) - return -ENOMEM; - - listen->callsign = *callsign; - listen->dev = dev; - - spin_lock_bh(&listen_lock); - listen->next = listen_list; - listen_list = listen; - spin_unlock_bh(&listen_lock); - - return 0; -} - -EXPORT_SYMBOL(ax25_listen_register); - -void ax25_listen_release(const ax25_address *callsign, struct net_device *dev) -{ - struct listen_struct *s, *listen; - - spin_lock_bh(&listen_lock); - listen = listen_list; - if (listen == NULL) { - spin_unlock_bh(&listen_lock); - return; - } - - if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { - listen_list = listen->next; - spin_unlock_bh(&listen_lock); - kfree(listen); - return; - } - - while (listen != NULL && listen->next != NULL) { - if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { - s = listen->next; - listen->next = listen->next->next; - spin_unlock_bh(&listen_lock); - kfree(s); - return; - } - - listen = listen->next; - } - spin_unlock_bh(&listen_lock); -} - -EXPORT_SYMBOL(ax25_listen_release); - -int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) -{ - int (*res)(struct sk_buff *, ax25_cb *) = NULL; - struct ax25_protocol *protocol; - - read_lock(&protocol_list_lock); - for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) - if (protocol->pid == pid) { - res = protocol->func; - break; - } - read_unlock(&protocol_list_lock); - - return res; -} - -int ax25_listen_mine(const ax25_address *callsign, struct net_device *dev) -{ - struct listen_struct *listen; - - spin_lock_bh(&listen_lock); - for (listen = listen_list; listen != NULL; listen = listen->next) - if (ax25cmp(&listen->callsign, callsign) == 0 && - (listen->dev == dev || listen->dev == NULL)) { - spin_unlock_bh(&listen_lock); - return 1; - } - spin_unlock_bh(&listen_lock); - - return 0; -} - -void ax25_link_failed(ax25_cb *ax25, int reason) -{ - struct ax25_linkfail *lf; - - spin_lock_bh(&linkfail_lock); - hlist_for_each_entry(lf, &ax25_linkfail_list, lf_node) - lf->func(ax25, reason); - spin_unlock_bh(&linkfail_lock); -} - -int ax25_protocol_is_registered(unsigned int pid) -{ - struct ax25_protocol *protocol; - int res = 0; - - read_lock_bh(&protocol_list_lock); - for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) - if (protocol->pid == pid) { - res = 1; - break; - } - read_unlock_bh(&protocol_list_lock); - - return res; -} diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c deleted file mode 100644 index d75b3e9ed93d..000000000000 --- a/net/ax25/ax25_in.c +++ /dev/null @@ -1,455 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Given a fragment, queue it on the fragment queue and if the fragment - * is complete, send it back to ax25_rx_iframe. - */ -static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) -{ - struct sk_buff *skbn, *skbo; - - if (ax25->fragno != 0) { - if (!(*skb->data & AX25_SEG_FIRST)) { - if ((ax25->fragno - 1) == (*skb->data & AX25_SEG_REM)) { - /* Enqueue fragment */ - ax25->fragno = *skb->data & AX25_SEG_REM; - skb_pull(skb, 1); /* skip fragno */ - ax25->fraglen += skb->len; - skb_queue_tail(&ax25->frag_queue, skb); - - /* Last fragment received ? */ - if (ax25->fragno == 0) { - skbn = alloc_skb(AX25_MAX_HEADER_LEN + - ax25->fraglen, - GFP_ATOMIC); - if (!skbn) { - skb_queue_purge(&ax25->frag_queue); - return 1; - } - - skb_reserve(skbn, AX25_MAX_HEADER_LEN); - - skbn->dev = ax25->ax25_dev->dev; - skb_reset_network_header(skbn); - skb_reset_transport_header(skbn); - - /* Copy data from the fragments */ - while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) { - skb_copy_from_linear_data(skbo, - skb_put(skbn, skbo->len), - skbo->len); - kfree_skb(skbo); - } - - ax25->fraglen = 0; - - if (ax25_rx_iframe(ax25, skbn) == 0) - kfree_skb(skbn); - } - - return 1; - } - } - } else { - /* First fragment received */ - if (*skb->data & AX25_SEG_FIRST) { - skb_queue_purge(&ax25->frag_queue); - ax25->fragno = *skb->data & AX25_SEG_REM; - skb_pull(skb, 1); /* skip fragno */ - ax25->fraglen = skb->len; - skb_queue_tail(&ax25->frag_queue, skb); - return 1; - } - } - - return 0; -} - -/* - * This is where all valid I frames are sent to, to be dispatched to - * whichever protocol requires them. - */ -int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) -{ - int (*func)(struct sk_buff *, ax25_cb *); - unsigned char pid; - int queued = 0; - - if (skb == NULL) return 0; - - ax25_start_idletimer(ax25); - - pid = *skb->data; - - if (pid == AX25_P_IP) { - /* working around a TCP bug to keep additional listeners - * happy. TCP re-uses the buffer and destroys the original - * content. - */ - struct sk_buff *skbn = skb_copy(skb, GFP_ATOMIC); - if (skbn != NULL) { - kfree_skb(skb); - skb = skbn; - } - - skb_pull(skb, 1); /* Remove PID */ - skb->mac_header = skb->network_header; - skb_reset_network_header(skb); - skb->dev = ax25->ax25_dev->dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_IP); - netif_rx(skb); - return 1; - } - if (pid == AX25_P_SEGMENT) { - skb_pull(skb, 1); /* Remove PID */ - return ax25_rx_fragment(ax25, skb); - } - - if ((func = ax25_protocol_function(pid)) != NULL) { - skb_pull(skb, 1); /* Remove PID */ - return (*func)(skb, ax25); - } - - if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2) { - if ((!ax25->pidincl && ax25->sk->sk_protocol == pid) || - ax25->pidincl) { - if (sock_queue_rcv_skb(ax25->sk, skb) == 0) - queued = 1; - else - ax25->condition |= AX25_COND_OWN_RX_BUSY; - } - } - - return queued; -} - -/* - * Higher level upcall for a LAPB frame - */ -static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama) -{ - int queued = 0; - - if (ax25->state == AX25_STATE_0) - return 0; - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - queued = ax25_std_frame_in(ax25, skb, type); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (dama || ax25->ax25_dev->dama.slave) - queued = ax25_ds_frame_in(ax25, skb, type); - else - queued = ax25_std_frame_in(ax25, skb, type); - break; -#endif - } - - return queued; -} - -static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, - const ax25_address *dev_addr, struct packet_type *ptype) -{ - ax25_address src, dest, *next_digi = NULL; - int type = 0, mine = 0, dama; - struct sock *make, *sk; - ax25_digi dp, reverse_dp; - ax25_cb *ax25; - ax25_dev *ax25_dev; - - /* - * Process the AX.25/LAPB frame. - */ - - skb_reset_transport_header(skb); - - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) - goto free; - - /* - * Parse the address header. - */ - - if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) - goto free; - - /* - * Ours perhaps ? - */ - if (dp.lastrepeat + 1 < dp.ndigi) /* Not yet digipeated completely */ - next_digi = &dp.calls[dp.lastrepeat + 1]; - - /* - * Pull of the AX.25 headers leaving the CTRL/PID bytes - */ - skb_pull(skb, ax25_addr_size(&dp)); - - /* For our port addresses ? */ - if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi) - mine = 1; - - /* Also match on any registered callsign from L3/4 */ - if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi) - mine = 1; - - /* UI frame - bypass LAPB processing */ - if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) { - skb_set_transport_header(skb, 2); /* skip control and pid */ - - ax25_send_to_raw(&dest, skb, skb->data[1]); - - if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) - goto free; - - /* Now we are pointing at the pid byte */ - switch (skb->data[1]) { - case AX25_P_IP: - skb_pull(skb,2); /* drop PID/CTRL */ - skb_reset_transport_header(skb); - skb_reset_network_header(skb); - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_IP); - netif_rx(skb); - break; - - case AX25_P_ARP: - skb_pull(skb,2); - skb_reset_transport_header(skb); - skb_reset_network_header(skb); - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_ARP); - netif_rx(skb); - break; - case AX25_P_TEXT: - /* Now find a suitable dgram socket */ - sk = ax25_get_socket(&dest, &src, SOCK_DGRAM); - if (sk != NULL) { - bh_lock_sock(sk); - if (atomic_read(&sk->sk_rmem_alloc) >= - sk->sk_rcvbuf) { - kfree_skb(skb); - } else { - /* - * Remove the control and PID. - */ - skb_pull(skb, 2); - if (sock_queue_rcv_skb(sk, skb) != 0) - kfree_skb(skb); - } - bh_unlock_sock(sk); - sock_put(sk); - } else { - kfree_skb(skb); - } - break; - - default: - kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */ - break; - } - - return 0; - } - - /* - * Is connected mode supported on this device ? - * If not, should we DM the incoming frame (except DMs) or - * silently ignore them. For now we stay quiet. - */ - if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) - goto free; - - /* LAPB */ - - /* AX.25 state 1-4 */ - - ax25_digi_invert(&dp, &reverse_dp); - - if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) { - /* - * Process the frame. If it is queued up internally it - * returns one otherwise we free it immediately. This - * routine itself wakes the user context layers so we do - * no further work - */ - if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) - kfree_skb(skb); - - ax25_cb_put(ax25); - return 0; - } - - /* AX.25 state 0 (disconnected) */ - - /* a) received not a SABM(E) */ - - if ((*skb->data & ~AX25_PF) != AX25_SABM && - (*skb->data & ~AX25_PF) != AX25_SABME) { - /* - * Never reply to a DM. Also ignore any connects for - * addresses that are not our interfaces and not a socket. - */ - if ((*skb->data & ~AX25_PF) != AX25_DM && mine) - ax25_return_dm(dev, &src, &dest, &dp); - - goto free; - } - - /* b) received SABM(E) */ - - if (dp.lastrepeat + 1 == dp.ndigi) - sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET); - else - sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET); - - if (sk != NULL) { - bh_lock_sock(sk); - if (sk_acceptq_is_full(sk) || - (make = ax25_make_new(sk, ax25_dev)) == NULL) { - if (mine) - ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); - bh_unlock_sock(sk); - sock_put(sk); - - return 0; - } - - ax25 = sk_to_ax25(make); - skb_set_owner_r(skb, make); - skb_queue_head(&sk->sk_receive_queue, skb); - - make->sk_state = TCP_ESTABLISHED; - - sk_acceptq_added(sk); - bh_unlock_sock(sk); - } else { - if (!mine) - goto free; - - if ((ax25 = ax25_create_cb()) == NULL) { - ax25_return_dm(dev, &src, &dest, &dp); - goto free; - } - - ax25_fillin_cb(ax25, ax25_dev); - } - - ax25->source_addr = dest; - ax25->dest_addr = src; - - /* - * Sort out any digipeated paths. - */ - if (dp.ndigi && !ax25->digipeat && - (ax25->digipeat = kmalloc_obj(ax25_digi, GFP_ATOMIC)) == NULL) { - kfree_skb(skb); - ax25_destroy_socket(ax25); - if (sk) - sock_put(sk); - return 0; - } - - if (dp.ndigi == 0) { - kfree(ax25->digipeat); - ax25->digipeat = NULL; - } else { - /* Reverse the source SABM's path */ - memcpy(ax25->digipeat, &reverse_dp, sizeof(ax25_digi)); - } - - if ((*skb->data & ~AX25_PF) == AX25_SABME) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; - } - - ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE); - -#ifdef CONFIG_AX25_DAMA_SLAVE - if (dama && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) - ax25_dama_on(ax25); -#endif - - ax25->state = AX25_STATE_3; - - ax25_cb_add(ax25); - - ax25_start_heartbeat(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - - if (sk) { - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); - sock_put(sk); - } else { -free: - kfree_skb(skb); - } - return 0; -} - -/* - * Receive an AX.25 frame via a SLIP interface. - */ -int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *orig_dev) -{ - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - return NET_RX_DROP; - - skb_orphan(skb); - - if (!net_eq(dev_net(dev), &init_net)) { - kfree_skb(skb); - return 0; - } - - if ((*skb->data & 0x0F) != 0) { - kfree_skb(skb); /* Not a KISS data frame */ - return 0; - } - - skb_pull(skb, AX25_KISS_HEADER_LEN); /* Remove the KISS byte */ - - return ax25_rcv(skb, dev, (const ax25_address *)dev->dev_addr, ptype); -} diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c deleted file mode 100644 index 215d4ccf12b9..000000000000 --- a/net/ax25/ax25_ip.c +++ /dev/null @@ -1,247 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For TIOCINQ/OUTQ */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * IP over AX.25 encapsulation. - */ - -/* - * Shove an AX.25 UI header on an IP packet and handle ARP - */ - -#ifdef CONFIG_INET - -static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned int len) -{ - unsigned char *buff; - - /* they sometimes come back to us... */ - if (type == ETH_P_AX25) - return 0; - - /* header is an AX.25 UI frame from us to them */ - buff = skb_push(skb, AX25_HEADER_LEN); - *buff++ = 0x00; /* KISS DATA */ - - if (daddr != NULL) - memcpy(buff, daddr, dev->addr_len); /* Address specified */ - - buff[6] &= ~AX25_CBIT; - buff[6] &= ~AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - if (saddr != NULL) - memcpy(buff, saddr, dev->addr_len); - else - memcpy(buff, dev->dev_addr, dev->addr_len); - - buff[6] &= ~AX25_CBIT; - buff[6] |= AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - *buff++ = AX25_UI; /* UI */ - - /* Append a suitable AX.25 PID */ - switch (type) { - case ETH_P_IP: - *buff++ = AX25_P_IP; - break; - case ETH_P_ARP: - *buff++ = AX25_P_ARP; - break; - default: - printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type); - *buff++ = 0; - break; - } - - if (daddr != NULL) - return AX25_HEADER_LEN; - - return -AX25_HEADER_LEN; /* Unfinished header */ -} - -netdev_tx_t ax25_ip_xmit(struct sk_buff *skb) -{ - struct sk_buff *ourskb; - unsigned char *bp = skb->data; - ax25_route *route; - struct net_device *dev = NULL; - ax25_address *src, *dst; - ax25_digi *digipeat = NULL; - ax25_dev *ax25_dev; - ax25_cb *ax25; - char ip_mode = ' '; - - dst = (ax25_address *)(bp + 1); - src = (ax25_address *)(bp + 8); - - ax25_route_lock_use(); - route = ax25_get_route(dst, NULL); - if (route) { - digipeat = route->digipeat; - dev = route->dev; - ip_mode = route->ip_mode; - } - - if (dev == NULL) - dev = skb->dev; - - rcu_read_lock(); - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { - kfree_skb(skb); - goto put; - } - - if (bp[16] == AX25_P_IP) { - if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { - /* - * We copy the buffer and release the original thereby - * keeping it straight - * - * Note: we report 1 back so the caller will - * not feed the frame direct to the physical device - * We don't want that to happen. (It won't be upset - * as we have pulled the frame from the queue by - * freeing it). - * - * NB: TCP modifies buffers that are still - * on a device queue, thus we use skb_copy() - * instead of using skb_clone() unless this - * gets fixed. - */ - - ax25_address src_c; - ax25_address dst_c; - - if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) { - kfree_skb(skb); - goto put; - } - - if (skb->sk != NULL) - skb_set_owner_w(ourskb, skb->sk); - - kfree_skb(skb); - /* dl9sau: bugfix - * after kfree_skb(), dst and src which were pointer - * to bp which is part of skb->data would not be valid - * anymore hope that after skb_pull(ourskb, ..) our - * dsc_c and src_c will not become invalid - */ - bp = ourskb->data; - dst_c = *(ax25_address *)(bp + 1); - src_c = *(ax25_address *)(bp + 8); - - skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ - skb_reset_network_header(ourskb); - - ax25=ax25_send_frame( - ourskb, - ax25_dev->values[AX25_VALUES_PACLEN], - &src_c, - &dst_c, digipeat, dev); - if (ax25) { - ax25_cb_put(ax25); - } - goto put; - } - } - - bp[7] &= ~AX25_CBIT; - bp[7] &= ~AX25_EBIT; - bp[7] |= AX25_SSSID_SPARE; - - bp[14] &= ~AX25_CBIT; - bp[14] |= AX25_EBIT; - bp[14] |= AX25_SSSID_SPARE; - - skb_pull(skb, AX25_KISS_HEADER_LEN); - - if (digipeat != NULL) { - if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) - goto put; - - skb = ourskb; - } - - ax25_queue_xmit(skb, dev); - -put: - rcu_read_unlock(); - ax25_route_lock_unuse(); - return NETDEV_TX_OK; -} - -#else /* INET */ - -static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned int len) -{ - return -AX25_HEADER_LEN; -} - -netdev_tx_t ax25_ip_xmit(struct sk_buff *skb) -{ - kfree_skb(skb); - return NETDEV_TX_OK; -} -#endif - -static bool ax25_validate_header(const char *header, unsigned int len) -{ - ax25_digi digi; - - if (!len) - return false; - - if (header[0]) - return true; - - return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL, - NULL); -} - -const struct header_ops ax25_header_ops = { - .create = ax25_hard_header, - .validate = ax25_validate_header, -}; - -EXPORT_SYMBOL(ax25_header_ops); -EXPORT_SYMBOL(ax25_ip_xmit); diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c deleted file mode 100644 index 8bca2ace98e5..000000000000 --- a/net/ax25/ax25_out.c +++ /dev/null @@ -1,398 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static DEFINE_SPINLOCK(ax25_frag_lock); - -ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, const ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev) -{ - ax25_dev *ax25_dev; - ax25_cb *ax25; - - /* - * Take the default packet length for the device if zero is - * specified. - */ - if (paclen == 0) { - rcu_read_lock(); - ax25_dev = ax25_dev_ax25dev(dev); - if (!ax25_dev) { - rcu_read_unlock(); - return NULL; - } - paclen = ax25_dev->values[AX25_VALUES_PACLEN]; - rcu_read_unlock(); - } - - /* - * Look for an existing connection. - */ - if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) { - ax25_output(ax25, paclen, skb); - return ax25; /* It already existed */ - } - - rcu_read_lock(); - ax25_dev = ax25_dev_ax25dev(dev); - if (!ax25_dev) { - rcu_read_unlock(); - return NULL; - } - - if ((ax25 = ax25_create_cb()) == NULL) { - rcu_read_unlock(); - return NULL; - } - ax25_fillin_cb(ax25, ax25_dev); - rcu_read_unlock(); - - ax25->source_addr = *src; - ax25->dest_addr = *dest; - - if (digi != NULL) { - ax25->digipeat = kmemdup(digi, sizeof(*digi), GFP_ATOMIC); - if (ax25->digipeat == NULL) { - ax25_cb_put(ax25); - return NULL; - } - } - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_establish_data_link(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25_dev->dama.slave) - ax25_ds_establish_data_link(ax25); - else - ax25_std_establish_data_link(ax25); - break; -#endif - } - - /* - * There is one ref for the state machine; a caller needs - * one more to put it back, just like with the existing one. - */ - ax25_cb_hold(ax25); - - ax25_cb_add(ax25); - - ax25->state = AX25_STATE_1; - - ax25_start_heartbeat(ax25); - - ax25_output(ax25, paclen, skb); - - return ax25; /* We had to create it */ -} - -EXPORT_SYMBOL(ax25_send_frame); - -/* - * All outgoing AX.25 I frames pass via this routine. Therefore this is - * where the fragmentation of frames takes place. If fragment is set to - * zero then we are not allowed to do fragmentation, even if the frame - * is too large. - */ -void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) -{ - struct sk_buff *skbn; - unsigned char *p; - int frontlen, len, fragno, ka9qfrag, first = 1; - - if (paclen < 16) { - WARN_ON_ONCE(1); - kfree_skb(skb); - return; - } - - if ((skb->len - 1) > paclen) { - if (*skb->data == AX25_P_TEXT) { - skb_pull(skb, 1); /* skip PID */ - ka9qfrag = 0; - } else { - paclen -= 2; /* Allow for fragment control info */ - ka9qfrag = 1; - } - - fragno = skb->len / paclen; - if (skb->len % paclen == 0) fragno--; - - frontlen = skb_headroom(skb); /* Address space + CTRL */ - - while (skb->len > 0) { - spin_lock_bh(&ax25_frag_lock); - if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) { - spin_unlock_bh(&ax25_frag_lock); - printk(KERN_CRIT "AX.25: ax25_output - out of memory\n"); - return; - } - - if (skb->sk != NULL) - skb_set_owner_w(skbn, skb->sk); - - spin_unlock_bh(&ax25_frag_lock); - - len = (paclen > skb->len) ? skb->len : paclen; - - if (ka9qfrag == 1) { - skb_reserve(skbn, frontlen + 2); - skb_set_network_header(skbn, - skb_network_offset(skb)); - skb_copy_from_linear_data(skb, skb_put(skbn, len), len); - p = skb_push(skbn, 2); - - *p++ = AX25_P_SEGMENT; - - *p = fragno--; - if (first) { - *p |= AX25_SEG_FIRST; - first = 0; - } - } else { - skb_reserve(skbn, frontlen + 1); - skb_set_network_header(skbn, - skb_network_offset(skb)); - skb_copy_from_linear_data(skb, skb_put(skbn, len), len); - p = skb_push(skbn, 1); - *p = AX25_P_TEXT; - } - - skb_pull(skb, len); - skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */ - } - - kfree_skb(skb); - } else { - skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */ - } - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_kick(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - /* - * A DAMA slave is _required_ to work as normal AX.25L2V2 - * if no DAMA master is available. - */ - case AX25_PROTO_DAMA_SLAVE: - if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); - break; -#endif - } -} - -/* - * This procedure is passed a buffer descriptor for an iframe. It builds - * the rest of the control part of the frame and then writes it out. - */ -static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit) -{ - unsigned char *frame; - - if (skb == NULL) - return; - - skb_reset_network_header(skb); - - if (ax25->modulus == AX25_MODULUS) { - frame = skb_push(skb, 1); - - *frame = AX25_I; - *frame |= (poll_bit) ? AX25_PF : 0; - *frame |= (ax25->vr << 5); - *frame |= (ax25->vs << 1); - } else { - frame = skb_push(skb, 2); - - frame[0] = AX25_I; - frame[0] |= (ax25->vs << 1); - frame[1] = (poll_bit) ? AX25_EPF : 0; - frame[1] |= (ax25->vr << 1); - } - - ax25_start_idletimer(ax25); - - ax25_transmit_buffer(ax25, skb, AX25_COMMAND); -} - -void ax25_kick(ax25_cb *ax25) -{ - struct sk_buff *skb, *skbn; - int last = 1; - unsigned short start, end, next; - - if (ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4) - return; - - if (ax25->condition & AX25_COND_PEER_RX_BUSY) - return; - - if (skb_peek(&ax25->write_queue) == NULL) - return; - - start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs; - end = (ax25->va + ax25->window) % ax25->modulus; - - if (start == end) - return; - - /* - * Transmit data until either we're out of data to send or - * the window is full. Send a poll on the final I frame if - * the window is filled. - */ - - /* - * Dequeue the frame and copy it. - * Check for race with ax25_clear_queues(). - */ - skb = skb_dequeue(&ax25->write_queue); - if (!skb) - return; - - ax25->vs = start; - - do { - if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - skb_queue_head(&ax25->write_queue, skb); - break; - } - - if (skb->sk != NULL) - skb_set_owner_w(skbn, skb->sk); - - next = (ax25->vs + 1) % ax25->modulus; - last = (next == end); - - /* - * Transmit the frame copy. - * bke 960114: do not set the Poll bit on the last frame - * in DAMA mode. - */ - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - ax25_send_iframe(ax25, skbn, AX25_POLLOFF); - break; -#endif - } - - ax25->vs = next; - - /* - * Requeue the original data frame. - */ - skb_queue_tail(&ax25->ack_queue, skb); - - } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL); - - ax25->condition &= ~AX25_COND_ACK_PENDING; - - if (!ax25_t1timer_running(ax25)) { - ax25_stop_t3timer(ax25); - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); - } -} - -void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) -{ - unsigned char *ptr; - int headroom; - - if (ax25->ax25_dev == NULL) { - ax25_disconnect(ax25, ENETUNREACH); - return; - } - - headroom = ax25_addr_size(ax25->digipeat); - - if (unlikely(skb_headroom(skb) < headroom)) { - skb = skb_expand_head(skb, headroom); - if (!skb) { - printk(KERN_CRIT "AX.25: ax25_transmit_buffer - out of memory\n"); - return; - } - } - - ptr = skb_push(skb, headroom); - - ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); - - ax25_queue_xmit(skb, ax25->ax25_dev->dev); -} - -/* - * A small shim to dev_queue_xmit to add the KISS control byte, and do - * any packet forwarding in operation. - */ -void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev) -{ - unsigned char *ptr; - - rcu_read_lock(); - skb->protocol = ax25_type_trans(skb, ax25_fwd_dev(dev)); - rcu_read_unlock(); - - ptr = skb_push(skb, 1); - *ptr = 0x00; /* KISS */ - - dev_queue_xmit(skb); -} - -int ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr) -{ - if (ax25->vs == nr) { - ax25_frames_acked(ax25, nr); - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - return 1; - } else { - if (ax25->va != nr) { - ax25_frames_acked(ax25, nr); - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); - return 1; - } - } - return 0; -} diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c deleted file mode 100644 index 1d5c59ccf142..000000000000 --- a/net/ax25/ax25_route.c +++ /dev/null @@ -1,416 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) - * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) - */ - -#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 - -static ax25_route *ax25_route_list; -DEFINE_RWLOCK(ax25_route_lock); - -void ax25_rt_device_down(struct net_device *dev) -{ - ax25_route *s, *t, *ax25_rt; - - write_lock_bh(&ax25_route_lock); - ax25_rt = ax25_route_list; - while (ax25_rt != NULL) { - s = ax25_rt; - ax25_rt = ax25_rt->next; - - if (s->dev == dev) { - if (ax25_route_list == s) { - ax25_route_list = s->next; - kfree(s->digipeat); - kfree(s); - } else { - for (t = ax25_route_list; t != NULL; t = t->next) { - if (t->next == s) { - t->next = s->next; - kfree(s->digipeat); - kfree(s); - break; - } - } - } - } - } - write_unlock_bh(&ax25_route_lock); -} - -static int __must_check ax25_rt_add(struct ax25_routes_struct *route) -{ - ax25_route *ax25_rt; - ax25_dev *ax25_dev; - int i; - - if (route->digi_count > AX25_MAX_DIGIS) - return -EINVAL; - - ax25_dev = ax25_addr_ax25dev(&route->port_addr); - if (!ax25_dev) - return -EINVAL; - - write_lock_bh(&ax25_route_lock); - - ax25_rt = ax25_route_list; - while (ax25_rt != NULL) { - if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 && - ax25_rt->dev == ax25_dev->dev) { - kfree(ax25_rt->digipeat); - ax25_rt->digipeat = NULL; - if (route->digi_count != 0) { - if ((ax25_rt->digipeat = kmalloc_obj(ax25_digi, GFP_ATOMIC)) == NULL) { - write_unlock_bh(&ax25_route_lock); - ax25_dev_put(ax25_dev); - return -ENOMEM; - } - ax25_rt->digipeat->lastrepeat = -1; - ax25_rt->digipeat->ndigi = route->digi_count; - for (i = 0; i < route->digi_count; i++) { - ax25_rt->digipeat->repeated[i] = 0; - ax25_rt->digipeat->calls[i] = route->digi_addr[i]; - } - } - write_unlock_bh(&ax25_route_lock); - ax25_dev_put(ax25_dev); - return 0; - } - ax25_rt = ax25_rt->next; - } - - if ((ax25_rt = kmalloc_obj(ax25_route, GFP_ATOMIC)) == NULL) { - write_unlock_bh(&ax25_route_lock); - ax25_dev_put(ax25_dev); - return -ENOMEM; - } - - ax25_rt->callsign = route->dest_addr; - ax25_rt->dev = ax25_dev->dev; - ax25_rt->digipeat = NULL; - ax25_rt->ip_mode = ' '; - if (route->digi_count != 0) { - if ((ax25_rt->digipeat = kmalloc_obj(ax25_digi, GFP_ATOMIC)) == NULL) { - write_unlock_bh(&ax25_route_lock); - kfree(ax25_rt); - ax25_dev_put(ax25_dev); - return -ENOMEM; - } - ax25_rt->digipeat->lastrepeat = -1; - ax25_rt->digipeat->ndigi = route->digi_count; - for (i = 0; i < route->digi_count; i++) { - ax25_rt->digipeat->repeated[i] = 0; - ax25_rt->digipeat->calls[i] = route->digi_addr[i]; - } - } - ax25_rt->next = ax25_route_list; - ax25_route_list = ax25_rt; - write_unlock_bh(&ax25_route_lock); - ax25_dev_put(ax25_dev); - - return 0; -} - -void __ax25_put_route(ax25_route *ax25_rt) -{ - kfree(ax25_rt->digipeat); - kfree(ax25_rt); -} - -static int ax25_rt_del(struct ax25_routes_struct *route) -{ - ax25_route *s, *t, *ax25_rt; - ax25_dev *ax25_dev; - - if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL) - return -EINVAL; - - write_lock_bh(&ax25_route_lock); - - ax25_rt = ax25_route_list; - while (ax25_rt != NULL) { - s = ax25_rt; - ax25_rt = ax25_rt->next; - if (s->dev == ax25_dev->dev && - ax25cmp(&route->dest_addr, &s->callsign) == 0) { - if (ax25_route_list == s) { - ax25_route_list = s->next; - __ax25_put_route(s); - } else { - for (t = ax25_route_list; t != NULL; t = t->next) { - if (t->next == s) { - t->next = s->next; - __ax25_put_route(s); - break; - } - } - } - } - } - write_unlock_bh(&ax25_route_lock); - ax25_dev_put(ax25_dev); - - return 0; -} - -static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) -{ - ax25_route *ax25_rt; - ax25_dev *ax25_dev; - int err = 0; - - if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL) - return -EINVAL; - - write_lock_bh(&ax25_route_lock); - - ax25_rt = ax25_route_list; - while (ax25_rt != NULL) { - if (ax25_rt->dev == ax25_dev->dev && - ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) { - switch (rt_option->cmd) { - case AX25_SET_RT_IPMODE: - switch (rt_option->arg) { - case ' ': - case 'D': - case 'V': - ax25_rt->ip_mode = rt_option->arg; - break; - default: - err = -EINVAL; - goto out; - } - break; - default: - err = -EINVAL; - goto out; - } - } - ax25_rt = ax25_rt->next; - } - -out: - write_unlock_bh(&ax25_route_lock); - ax25_dev_put(ax25_dev); - return err; -} - -int ax25_rt_ioctl(unsigned int cmd, void __user *arg) -{ - struct ax25_route_opt_struct rt_option; - struct ax25_routes_struct route; - - switch (cmd) { - case SIOCADDRT: - if (copy_from_user(&route, arg, sizeof(route))) - return -EFAULT; - return ax25_rt_add(&route); - - case SIOCDELRT: - if (copy_from_user(&route, arg, sizeof(route))) - return -EFAULT; - return ax25_rt_del(&route); - - case SIOCAX25OPTRT: - if (copy_from_user(&rt_option, arg, sizeof(rt_option))) - return -EFAULT; - return ax25_rt_opt(&rt_option); - - default: - return -EINVAL; - } -} - -#ifdef CONFIG_PROC_FS - -static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(ax25_route_lock) -{ - struct ax25_route *ax25_rt; - int i = 1; - - read_lock(&ax25_route_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (i == *pos) - return ax25_rt; - ++i; - } - - return NULL; -} - -static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return (v == SEQ_START_TOKEN) ? ax25_route_list : - ((struct ax25_route *) v)->next; -} - -static void ax25_rt_seq_stop(struct seq_file *seq, void *v) - __releases(ax25_route_lock) -{ - read_unlock(&ax25_route_lock); -} - -static int ax25_rt_seq_show(struct seq_file *seq, void *v) -{ - char buf[11]; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, "callsign dev mode digipeaters\n"); - else { - struct ax25_route *ax25_rt = v; - const char *callsign; - int i; - - if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) - callsign = "default"; - else - callsign = ax2asc(buf, &ax25_rt->callsign); - - seq_printf(seq, "%-9s %-4s", - callsign, - ax25_rt->dev ? ax25_rt->dev->name : "???"); - - switch (ax25_rt->ip_mode) { - case 'V': - seq_puts(seq, " vc"); - break; - case 'D': - seq_puts(seq, " dg"); - break; - default: - seq_puts(seq, " *"); - break; - } - - if (ax25_rt->digipeat != NULL) - for (i = 0; i < ax25_rt->digipeat->ndigi; i++) - seq_printf(seq, " %s", - ax2asc(buf, &ax25_rt->digipeat->calls[i])); - - seq_puts(seq, "\n"); - } - return 0; -} - -const struct seq_operations ax25_rt_seqops = { - .start = ax25_rt_seq_start, - .next = ax25_rt_seq_next, - .stop = ax25_rt_seq_stop, - .show = ax25_rt_seq_show, -}; -#endif - -/* - * Find AX.25 route - * - * Only routes with a reference count of zero can be destroyed. - * Must be called with ax25_route_lock read locked. - */ -ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) -{ - ax25_route *ax25_spe_rt = NULL; - ax25_route *ax25_def_rt = NULL; - ax25_route *ax25_rt; - - /* - * Bind to the physical interface we heard them on, or the default - * route if none is found; - */ - for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (dev == NULL) { - if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL) - ax25_spe_rt = ax25_rt; - if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL) - ax25_def_rt = ax25_rt; - } else { - if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev) - ax25_spe_rt = ax25_rt; - if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev) - ax25_def_rt = ax25_rt; - } - } - - ax25_rt = ax25_def_rt; - if (ax25_spe_rt != NULL) - ax25_rt = ax25_spe_rt; - - return ax25_rt; -} - - -struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, - ax25_address *dest, ax25_digi *digi) -{ - unsigned char *bp; - int len; - - len = digi->ndigi * AX25_ADDR_LEN; - - if (unlikely(skb_headroom(skb) < len)) { - skb = skb_expand_head(skb, len); - if (!skb) { - printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n"); - return NULL; - } - } - - bp = skb_push(skb, len); - - ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS); - - return skb; -} - -/* - * Free all memory associated with routing structures. - */ -void __exit ax25_rt_free(void) -{ - ax25_route *s, *ax25_rt = ax25_route_list; - - write_lock_bh(&ax25_route_lock); - while (ax25_rt != NULL) { - s = ax25_rt; - ax25_rt = ax25_rt->next; - - kfree(s->digipeat); - kfree(s); - } - write_unlock_bh(&ax25_route_lock); -} diff --git a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c deleted file mode 100644 index ba176196ae06..000000000000 --- a/net/ax25/ax25_std_in.c +++ /dev/null @@ -1,443 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) - * - * Most of this code is based on the SDL diagrams published in the 7th ARRL - * Computer Networking Conference papers. The diagrams have mistakes in them, - * but are mostly correct. Before you modify the code could you read the SDL - * diagrams as the code is not obvious and probably very easy to break. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * State machine for state 1, Awaiting Connection State. - * The handling of the timer(s) is in file ax25_std_timer.c. - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) -{ - switch (frametype) { - case AX25_SABM: - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_SABME: - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - break; - - case AX25_UA: - if (pf) { - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - if (ax25->sk != NULL) { - bh_lock_sock(ax25->sk); - ax25->sk->sk_state = TCP_ESTABLISHED; - /* For WAIT_SABM connections we will produce an accept ready socket here */ - if (!sock_flag(ax25->sk, SOCK_DEAD)) - ax25->sk->sk_state_change(ax25->sk); - bh_unlock_sock(ax25->sk); - } - } - break; - - case AX25_DM: - if (pf) { - if (ax25->modulus == AX25_MODULUS) { - ax25_disconnect(ax25, ECONNREFUSED); - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } - } - break; - - default: - break; - } - - return 0; -} - -/* - * State machine for state 2, Awaiting Release State. - * The handling of the timer(s) is in file ax25_std_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) -{ - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_disconnect(ax25, 0); - break; - - case AX25_DM: - case AX25_UA: - if (pf) - ax25_disconnect(ax25, 0); - break; - - case AX25_I: - case AX25_REJ: - case AX25_RNR: - case AX25_RR: - if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); - break; - - default: - break; - } - - return 0; -} - -/* - * State machine for state 3, Connected State. - * The handling of the timer(s) is in file ax25_std_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) -{ - int queued = 0; - - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_stop_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->condition = 0x00; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25_requeue_frames(ax25); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_disconnect(ax25, 0); - break; - - case AX25_DM: - ax25_disconnect(ax25, ECONNRESET); - break; - - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - if (type == AX25_COMMAND && pf) - ax25_std_enquiry_response(ax25); - if (ax25_validate_nr(ax25, nr)) { - ax25_check_iframes_acked(ax25, nr); - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - if (type == AX25_COMMAND && pf) - ax25_std_enquiry_response(ax25); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25_calculate_rtt(ax25); - ax25_stop_t1timer(ax25); - ax25_start_t3timer(ax25); - ax25_requeue_frames(ax25); - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - if (ax25->condition & AX25_COND_PEER_RX_BUSY) { - ax25_frames_acked(ax25, nr); - } else { - ax25_check_iframes_acked(ax25, nr); - } - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - if (pf) ax25_std_enquiry_response(ax25); - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25->vr = ns; /* ax25->vr - 1 */ - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - ax25_std_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->condition |= AX25_COND_ACK_PENDING; - ax25_start_t2timer(ax25); - } - } - } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) ax25_std_enquiry_response(ax25); - } else { - ax25->condition |= AX25_COND_REJECT; - ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; - - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_std_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; - - default: - break; - } - - return queued; -} - -/* - * State machine for state 4, Timer Recovery State. - * The handling of the timer(s) is in file ax25_std_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) -{ - int queued = 0; - - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_stop_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); - ax25->condition = 0x00; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - ax25_requeue_frames(ax25); - break; - - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25_disconnect(ax25, 0); - break; - - case AX25_DM: - ax25_disconnect(ax25, ECONNRESET); - break; - - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - if (type == AX25_RESPONSE && pf) { - ax25_stop_t1timer(ax25); - ax25->n2count = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25_start_t3timer(ax25); - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - if (type == AX25_COMMAND && pf) - ax25_std_enquiry_response(ax25); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - if (pf && type == AX25_RESPONSE) { - ax25_stop_t1timer(ax25); - ax25->n2count = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25_start_t3timer(ax25); - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - if (type == AX25_COMMAND && pf) - ax25_std_enquiry_response(ax25); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25_requeue_frames(ax25); - } else { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_std_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - ax25_frames_acked(ax25, nr); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - if (pf) - ax25_std_enquiry_response(ax25); - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25->vr = ns; /* ax25->vr - 1 */ - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - ax25_std_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->condition |= AX25_COND_ACK_PENDING; - ax25_start_t2timer(ax25); - } - } - } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) ax25_std_enquiry_response(ax25); - } else { - ax25->condition |= AX25_COND_REJECT; - ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; - - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_std_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; - - default: - break; - } - - return queued; -} - -/* - * Higher level upcall for a LAPB frame - */ -int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type) -{ - int queued = 0, frametype, ns, nr, pf; - - frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); - - switch (ax25->state) { - case AX25_STATE_1: - queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_2: - queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_3: - queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type); - break; - case AX25_STATE_4: - queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type); - break; - } - - ax25_kick(ax25); - - return queued; -} diff --git a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c deleted file mode 100644 index 4c36f1342558..000000000000 --- a/net/ax25/ax25_std_subr.c +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The following routines are taken from page 170 of the 7th ARRL Computer - * Networking Conference paper, as is the whole state machine. - */ - -void ax25_std_nr_error_recovery(ax25_cb *ax25) -{ - ax25_std_establish_data_link(ax25); -} - -void ax25_std_establish_data_link(ax25_cb *ax25) -{ - ax25->condition = 0x00; - ax25->n2count = 0; - - if (ax25->modulus == AX25_MODULUS) - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); - - ax25_calculate_t1(ax25); - ax25_stop_idletimer(ax25); - ax25_stop_t3timer(ax25); - ax25_stop_t2timer(ax25); - ax25_start_t1timer(ax25); -} - -void ax25_std_transmit_enquiry(ax25_cb *ax25) -{ - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_COMMAND); - - ax25->condition &= ~AX25_COND_ACK_PENDING; - - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); -} - -void ax25_std_enquiry_response(ax25_cb *ax25) -{ - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_RESPONSE); - else - ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_RESPONSE); - - ax25->condition &= ~AX25_COND_ACK_PENDING; -} - -void ax25_std_timeout_response(ax25_cb *ax25) -{ - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25_send_control(ax25, AX25_RNR, AX25_POLLOFF, AX25_RESPONSE); - else - ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); - - ax25->condition &= ~AX25_COND_ACK_PENDING; -} diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c deleted file mode 100644 index b17da41210cb..000000000000 --- a/net/ax25/ax25_std_timer.c +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void ax25_std_heartbeat_expiry(ax25_cb *ax25) -{ - struct sock *sk = ax25->sk; - - if (sk) - bh_lock_sock(sk); - - switch (ax25->state) { - case AX25_STATE_0: - case AX25_STATE_2: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (!sk || sock_flag(sk, SOCK_DESTROY) || - (sk->sk_state == TCP_LISTEN && - sock_flag(sk, SOCK_DEAD))) { - if (sk) { - sock_hold(sk); - ax25_destroy_socket(ax25); - bh_unlock_sock(sk); - /* Ungrab socket and destroy it */ - sock_put(sk); - } else - ax25_destroy_socket(ax25); - return; - } - break; - - case AX25_STATE_3: - case AX25_STATE_4: - /* - * Check the state of the receive buffer. - */ - if (sk != NULL) { - if (atomic_read(&sk->sk_rmem_alloc) < - (sk->sk_rcvbuf >> 1) && - (ax25->condition & AX25_COND_OWN_RX_BUSY)) { - ax25->condition &= ~AX25_COND_OWN_RX_BUSY; - ax25->condition &= ~AX25_COND_ACK_PENDING; - ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); - break; - } - } - } - - if (sk) - bh_unlock_sock(sk); - - ax25_start_heartbeat(ax25); -} - -void ax25_std_t2timer_expiry(ax25_cb *ax25) -{ - if (ax25->condition & AX25_COND_ACK_PENDING) { - ax25->condition &= ~AX25_COND_ACK_PENDING; - ax25_std_timeout_response(ax25); - } -} - -void ax25_std_t3timer_expiry(ax25_cb *ax25) -{ - ax25->n2count = 0; - ax25_std_transmit_enquiry(ax25); - ax25->state = AX25_STATE_4; -} - -void ax25_std_idletimer_expiry(ax25_cb *ax25) -{ - ax25_clear_queues(ax25); - - ax25->n2count = 0; - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25->state = AX25_STATE_2; - - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_stop_t3timer(ax25); - - if (ax25->sk != NULL) { - bh_lock_sock(ax25->sk); - ax25->sk->sk_state = TCP_CLOSE; - ax25->sk->sk_err = 0; - ax25->sk->sk_shutdown |= SEND_SHUTDOWN; - if (!sock_flag(ax25->sk, SOCK_DEAD)) { - ax25->sk->sk_state_change(ax25->sk); - sock_set_flag(ax25->sk, SOCK_DEAD); - } - bh_unlock_sock(ax25->sk); - } -} - -void ax25_std_t1timer_expiry(ax25_cb *ax25) -{ - switch (ax25->state) { - case AX25_STATE_1: - if (ax25->n2count == ax25->n2) { - if (ax25->modulus == AX25_MODULUS) { - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - ax25->n2count = 0; - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - } - } else { - ax25->n2count++; - if (ax25->modulus == AX25_MODULUS) - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); - } - break; - - case AX25_STATE_2: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - if (!sock_flag(ax25->sk, SOCK_DESTROY)) - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->n2count++; - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - } - break; - - case AX25_STATE_3: - ax25->n2count = 1; - ax25_std_transmit_enquiry(ax25); - ax25->state = AX25_STATE_4; - break; - - case AX25_STATE_4: - if (ax25->n2count == ax25->n2) { - ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); - ax25_disconnect(ax25, ETIMEDOUT); - return; - } else { - ax25->n2count++; - ax25_std_transmit_enquiry(ax25); - } - break; - } - - ax25_calculate_t1(ax25); - ax25_start_t1timer(ax25); -} diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c deleted file mode 100644 index bff4b203a893..000000000000 --- a/net/ax25/ax25_subr.c +++ /dev/null @@ -1,296 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This routine purges all the queues of frames. - */ -void ax25_clear_queues(ax25_cb *ax25) -{ - skb_queue_purge(&ax25->write_queue); - skb_queue_purge(&ax25->ack_queue); - skb_queue_purge(&ax25->reseq_queue); - skb_queue_purge(&ax25->frag_queue); -} - -/* - * This routine purges the input queue of those frames that have been - * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the - * SDL diagram. - */ -void ax25_frames_acked(ax25_cb *ax25, unsigned short nr) -{ - struct sk_buff *skb; - - /* - * Remove all the ack-ed frames from the ack queue. - */ - if (ax25->va != nr) { - while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) { - skb = skb_dequeue(&ax25->ack_queue); - kfree_skb(skb); - ax25->va = (ax25->va + 1) % ax25->modulus; - } - } -} - -void ax25_requeue_frames(ax25_cb *ax25) -{ - struct sk_buff *skb; - - /* - * Requeue all the un-ack-ed frames on the output queue to be picked - * up by ax25_kick called from the timer. This arrangement handles the - * possibility of an empty output queue. - */ - while ((skb = skb_dequeue_tail(&ax25->ack_queue)) != NULL) - skb_queue_head(&ax25->write_queue, skb); -} - -/* - * Validate that the value of nr is between va and vs. Return true or - * false for testing. - */ -int ax25_validate_nr(ax25_cb *ax25, unsigned short nr) -{ - unsigned short vc = ax25->va; - - while (vc != ax25->vs) { - if (nr == vc) return 1; - vc = (vc + 1) % ax25->modulus; - } - - if (nr == ax25->vs) return 1; - - return 0; -} - -/* - * This routine is the centralised routine for parsing the control - * information for the different frame formats. - */ -int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf) -{ - unsigned char *frame; - int frametype = AX25_ILLEGAL; - - frame = skb->data; - *ns = *nr = *pf = 0; - - if (ax25->modulus == AX25_MODULUS) { - if ((frame[0] & AX25_S) == 0) { - frametype = AX25_I; /* I frame - carries NR/NS/PF */ - *ns = (frame[0] >> 1) & 0x07; - *nr = (frame[0] >> 5) & 0x07; - *pf = frame[0] & AX25_PF; - } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */ - frametype = frame[0] & 0x0F; - *nr = (frame[0] >> 5) & 0x07; - *pf = frame[0] & AX25_PF; - } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */ - frametype = frame[0] & ~AX25_PF; - *pf = frame[0] & AX25_PF; - } - skb_pull(skb, 1); - } else { - if ((frame[0] & AX25_S) == 0) { - frametype = AX25_I; /* I frame - carries NR/NS/PF */ - *ns = (frame[0] >> 1) & 0x7F; - *nr = (frame[1] >> 1) & 0x7F; - *pf = frame[1] & AX25_EPF; - skb_pull(skb, 2); - } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */ - frametype = frame[0] & 0x0F; - *nr = (frame[1] >> 1) & 0x7F; - *pf = frame[1] & AX25_EPF; - skb_pull(skb, 2); - } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */ - frametype = frame[0] & ~AX25_PF; - *pf = frame[0] & AX25_PF; - skb_pull(skb, 1); - } - } - - return frametype; -} - -/* - * This routine is called when the HDLC layer internally generates a - * command or response for the remote machine ( eg. RR, UA etc. ). - * Only supervisory or unnumbered frames are processed. - */ -void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type) -{ - struct sk_buff *skb; - unsigned char *dptr; - - if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL) - return; - - skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len); - - skb_reset_network_header(skb); - - /* Assume a response - address structure for DTE */ - if (ax25->modulus == AX25_MODULUS) { - dptr = skb_put(skb, 1); - *dptr = frametype; - *dptr |= (poll_bit) ? AX25_PF : 0; - if ((frametype & AX25_U) == AX25_S) /* S frames carry NR */ - *dptr |= (ax25->vr << 5); - } else { - if ((frametype & AX25_U) == AX25_U) { - dptr = skb_put(skb, 1); - *dptr = frametype; - *dptr |= (poll_bit) ? AX25_PF : 0; - } else { - dptr = skb_put(skb, 2); - dptr[0] = frametype; - dptr[1] = (ax25->vr << 1); - dptr[1] |= (poll_bit) ? AX25_EPF : 0; - } - } - - ax25_transmit_buffer(ax25, skb, type); -} - -/* - * Send a 'DM' to an unknown connection attempt, or an invalid caller. - * - * Note: src here is the sender, thus it's the target of the DM - */ -void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi) -{ - struct sk_buff *skb; - char *dptr; - ax25_digi retdigi; - - if (dev == NULL) - return; - - if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL) - return; /* Next SABM will get DM'd */ - - skb_reserve(skb, dev->hard_header_len); - skb_reset_network_header(skb); - - ax25_digi_invert(digi, &retdigi); - - dptr = skb_put(skb, 1); - - *dptr = AX25_DM | AX25_PF; - - /* - * Do the address ourselves - */ - dptr = skb_push(skb, ax25_addr_size(digi)); - dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS); - - ax25_queue_xmit(skb, dev); -} - -/* - * Exponential backoff for AX.25 - */ -void ax25_calculate_t1(ax25_cb *ax25) -{ - int n, t = 2; - - switch (ax25->backoff) { - case 0: - break; - - case 1: - t += 2 * ax25->n2count; - break; - - case 2: - for (n = 0; n < ax25->n2count; n++) - t *= 2; - if (t > 8) t = 8; - break; - } - - ax25->t1 = t * ax25->rtt; -} - -/* - * Calculate the Round Trip Time - */ -void ax25_calculate_rtt(ax25_cb *ax25) -{ - if (ax25->backoff == 0) - return; - - if (ax25_t1timer_running(ax25) && ax25->n2count == 0) - ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10; - - if (ax25->rtt < AX25_T1CLAMPLO) - ax25->rtt = AX25_T1CLAMPLO; - - if (ax25->rtt > AX25_T1CLAMPHI) - ax25->rtt = AX25_T1CLAMPHI; -} - -void ax25_disconnect(ax25_cb *ax25, int reason) -{ - ax25_clear_queues(ax25); - - if (reason == ENETUNREACH) { - timer_delete_sync(&ax25->timer); - timer_delete_sync(&ax25->t1timer); - timer_delete_sync(&ax25->t2timer); - timer_delete_sync(&ax25->t3timer); - timer_delete_sync(&ax25->idletimer); - } else { - if (ax25->sk && !sock_flag(ax25->sk, SOCK_DESTROY)) - ax25_stop_heartbeat(ax25); - ax25_stop_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_stop_t3timer(ax25); - ax25_stop_idletimer(ax25); - } - - ax25->state = AX25_STATE_0; - - ax25_link_failed(ax25, reason); - - if (ax25->sk != NULL) { - local_bh_disable(); - bh_lock_sock(ax25->sk); - ax25->sk->sk_state = TCP_CLOSE; - ax25->sk->sk_err = reason; - ax25->sk->sk_shutdown |= SEND_SHUTDOWN; - if (!sock_flag(ax25->sk, SOCK_DEAD)) { - ax25->sk->sk_state_change(ax25->sk); - sock_set_flag(ax25->sk, SOCK_DEAD); - } - bh_unlock_sock(ax25->sk); - local_bh_enable(); - } -} diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c deleted file mode 100644 index a69bfbc8b679..000000000000 --- a/net/ax25/ax25_timer.c +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi) - * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk) - * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) - * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) - * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void ax25_heartbeat_expiry(struct timer_list *); -static void ax25_t1timer_expiry(struct timer_list *); -static void ax25_t2timer_expiry(struct timer_list *); -static void ax25_t3timer_expiry(struct timer_list *); -static void ax25_idletimer_expiry(struct timer_list *); - -void ax25_setup_timers(ax25_cb *ax25) -{ - timer_setup(&ax25->timer, ax25_heartbeat_expiry, 0); - timer_setup(&ax25->t1timer, ax25_t1timer_expiry, 0); - timer_setup(&ax25->t2timer, ax25_t2timer_expiry, 0); - timer_setup(&ax25->t3timer, ax25_t3timer_expiry, 0); - timer_setup(&ax25->idletimer, ax25_idletimer_expiry, 0); -} - -void ax25_start_heartbeat(ax25_cb *ax25) -{ - mod_timer(&ax25->timer, jiffies + 5 * HZ); -} - -void ax25_start_t1timer(ax25_cb *ax25) -{ - mod_timer(&ax25->t1timer, jiffies + ax25->t1); -} - -void ax25_start_t2timer(ax25_cb *ax25) -{ - mod_timer(&ax25->t2timer, jiffies + ax25->t2); -} - -void ax25_start_t3timer(ax25_cb *ax25) -{ - if (ax25->t3 > 0) - mod_timer(&ax25->t3timer, jiffies + ax25->t3); - else - timer_delete(&ax25->t3timer); -} - -void ax25_start_idletimer(ax25_cb *ax25) -{ - if (ax25->idle > 0) - mod_timer(&ax25->idletimer, jiffies + ax25->idle); - else - timer_delete(&ax25->idletimer); -} - -void ax25_stop_heartbeat(ax25_cb *ax25) -{ - timer_delete(&ax25->timer); -} - -void ax25_stop_t1timer(ax25_cb *ax25) -{ - timer_delete(&ax25->t1timer); -} - -void ax25_stop_t2timer(ax25_cb *ax25) -{ - timer_delete(&ax25->t2timer); -} - -void ax25_stop_t3timer(ax25_cb *ax25) -{ - timer_delete(&ax25->t3timer); -} - -void ax25_stop_idletimer(ax25_cb *ax25) -{ - timer_delete(&ax25->idletimer); -} - -int ax25_t1timer_running(ax25_cb *ax25) -{ - return timer_pending(&ax25->t1timer); -} - -unsigned long ax25_display_timer(struct timer_list *timer) -{ - long delta = timer->expires - jiffies; - - if (!timer_pending(timer)) - return 0; - - return max(0L, delta); -} - -EXPORT_SYMBOL(ax25_display_timer); - -static void ax25_heartbeat_expiry(struct timer_list *t) -{ - int proto = AX25_PROTO_STD_SIMPLEX; - ax25_cb *ax25 = timer_container_of(ax25, t, timer); - - if (ax25->ax25_dev) - proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]; - - switch (proto) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_heartbeat_expiry(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25->ax25_dev->dama.slave) - ax25_ds_heartbeat_expiry(ax25); - else - ax25_std_heartbeat_expiry(ax25); - break; -#endif - } -} - -static void ax25_t1timer_expiry(struct timer_list *t) -{ - ax25_cb *ax25 = timer_container_of(ax25, t, t1timer); - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_t1timer_expiry(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (!ax25->ax25_dev->dama.slave) - ax25_std_t1timer_expiry(ax25); - break; -#endif - } -} - -static void ax25_t2timer_expiry(struct timer_list *t) -{ - ax25_cb *ax25 = timer_container_of(ax25, t, t2timer); - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_t2timer_expiry(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (!ax25->ax25_dev->dama.slave) - ax25_std_t2timer_expiry(ax25); - break; -#endif - } -} - -static void ax25_t3timer_expiry(struct timer_list *t) -{ - ax25_cb *ax25 = timer_container_of(ax25, t, t3timer); - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_t3timer_expiry(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25->ax25_dev->dama.slave) - ax25_ds_t3timer_expiry(ax25); - else - ax25_std_t3timer_expiry(ax25); - break; -#endif - } -} - -static void ax25_idletimer_expiry(struct timer_list *t) -{ - ax25_cb *ax25 = timer_container_of(ax25, t, idletimer); - - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_idletimer_expiry(ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (ax25->ax25_dev->dama.slave) - ax25_ds_idletimer_expiry(ax25); - else - ax25_std_idletimer_expiry(ax25); - break; -#endif - } -} diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c deleted file mode 100644 index 159ce74273f0..000000000000 --- a/net/ax25/ax25_uid.c +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ - -#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 -#include -#include -#include -#include -#include - -/* - * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. - */ - -static HLIST_HEAD(ax25_uid_list); -static DEFINE_RWLOCK(ax25_uid_lock); - -int ax25_uid_policy; - -EXPORT_SYMBOL(ax25_uid_policy); - -ax25_uid_assoc *ax25_findbyuid(kuid_t uid) -{ - ax25_uid_assoc *ax25_uid, *res = NULL; - - read_lock(&ax25_uid_lock); - ax25_uid_for_each(ax25_uid, &ax25_uid_list) { - if (uid_eq(ax25_uid->uid, uid)) { - ax25_uid_hold(ax25_uid); - res = ax25_uid; - break; - } - } - read_unlock(&ax25_uid_lock); - - return res; -} - -EXPORT_SYMBOL(ax25_findbyuid); - -int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) -{ - ax25_uid_assoc *ax25_uid; - ax25_uid_assoc *user; - unsigned long res; - - switch (cmd) { - case SIOCAX25GETUID: - res = -ENOENT; - read_lock(&ax25_uid_lock); - ax25_uid_for_each(ax25_uid, &ax25_uid_list) { - if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { - res = from_kuid_munged(current_user_ns(), ax25_uid->uid); - break; - } - } - read_unlock(&ax25_uid_lock); - - return res; - - case SIOCAX25ADDUID: - { - kuid_t sax25_kuid; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid); - if (!uid_valid(sax25_kuid)) - return -EINVAL; - user = ax25_findbyuid(sax25_kuid); - if (user) { - ax25_uid_put(user); - return -EEXIST; - } - if (sax->sax25_uid == 0) - return -EINVAL; - if ((ax25_uid = kmalloc_obj(*ax25_uid)) == NULL) - return -ENOMEM; - - refcount_set(&ax25_uid->refcount, 1); - ax25_uid->uid = sax25_kuid; - ax25_uid->call = sax->sax25_call; - - write_lock(&ax25_uid_lock); - hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list); - write_unlock(&ax25_uid_lock); - - return 0; - } - case SIOCAX25DELUID: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - ax25_uid = NULL; - write_lock(&ax25_uid_lock); - ax25_uid_for_each(ax25_uid, &ax25_uid_list) { - if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) - break; - } - if (ax25_uid == NULL) { - write_unlock(&ax25_uid_lock); - return -ENOENT; - } - hlist_del_init(&ax25_uid->uid_node); - ax25_uid_put(ax25_uid); - write_unlock(&ax25_uid_lock); - - return 0; - - default: - return -EINVAL; - } - - return -EINVAL; /*NOTREACHED */ -} - -#ifdef CONFIG_PROC_FS - -static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(ax25_uid_lock) -{ - read_lock(&ax25_uid_lock); - return seq_hlist_start_head(&ax25_uid_list, *pos); -} - -static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_hlist_next(v, &ax25_uid_list, pos); -} - -static void ax25_uid_seq_stop(struct seq_file *seq, void *v) - __releases(ax25_uid_lock) -{ - read_unlock(&ax25_uid_lock); -} - -static int ax25_uid_seq_show(struct seq_file *seq, void *v) -{ - char buf[11]; - - if (v == SEQ_START_TOKEN) - seq_printf(seq, "Policy: %d\n", ax25_uid_policy); - else { - struct ax25_uid_assoc *pt; - - pt = hlist_entry(v, struct ax25_uid_assoc, uid_node); - seq_printf(seq, "%6d %s\n", - from_kuid_munged(seq_user_ns(seq), pt->uid), - ax2asc(buf, &pt->call)); - } - return 0; -} - -const struct seq_operations ax25_uid_seqops = { - .start = ax25_uid_seq_start, - .next = ax25_uid_seq_next, - .stop = ax25_uid_seq_stop, - .show = ax25_uid_seq_show, -}; -#endif - -/* - * Free all memory associated with UID/Callsign structures. - */ -void __exit ax25_uid_free(void) -{ - ax25_uid_assoc *ax25_uid; - - write_lock(&ax25_uid_lock); -again: - ax25_uid_for_each(ax25_uid, &ax25_uid_list) { - hlist_del_init(&ax25_uid->uid_node); - ax25_uid_put(ax25_uid); - goto again; - } - write_unlock(&ax25_uid_lock); -} diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c deleted file mode 100644 index 68753aa30334..000000000000 --- a/net/ax25/sysctl_net_ax25.c +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com) - */ -#include -#include -#include -#include -#include - -static int min_ipdefmode[1], max_ipdefmode[] = {1}; -static int min_axdefmode[1], max_axdefmode[] = {1}; -static int min_backoff[1], max_backoff[] = {2}; -static int min_conmode[1], max_conmode[] = {2}; -static int min_window[] = {1}, max_window[] = {7}; -static int min_ewindow[] = {1}, max_ewindow[] = {63}; -static int min_t1[] = {1}, max_t1[] = {30000}; -static int min_t2[] = {1}, max_t2[] = {20000}; -static int min_t3[1], max_t3[] = {3600000}; -static int min_idle[1], max_idle[] = {65535000}; -static int min_n2[] = {1}, max_n2[] = {31}; -static int min_paclen[] = {1}, max_paclen[] = {512}; -static int min_proto[1], max_proto[] = { AX25_PROTO_MAX }; -#ifdef CONFIG_AX25_DAMA_SLAVE -static int min_ds_timeout[1], max_ds_timeout[] = {65535000}; -#endif - -static const struct ctl_table ax25_param_table[] = { - { - .procname = "ip_default_mode", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_ipdefmode, - .extra2 = &max_ipdefmode - }, - { - .procname = "ax25_default_mode", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_axdefmode, - .extra2 = &max_axdefmode - }, - { - .procname = "backoff_type", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_backoff, - .extra2 = &max_backoff - }, - { - .procname = "connect_mode", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_conmode, - .extra2 = &max_conmode - }, - { - .procname = "standard_window_size", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_window, - .extra2 = &max_window - }, - { - .procname = "extended_window_size", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_ewindow, - .extra2 = &max_ewindow - }, - { - .procname = "t1_timeout", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_t1, - .extra2 = &max_t1 - }, - { - .procname = "t2_timeout", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_t2, - .extra2 = &max_t2 - }, - { - .procname = "t3_timeout", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_t3, - .extra2 = &max_t3 - }, - { - .procname = "idle_timeout", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_idle, - .extra2 = &max_idle - }, - { - .procname = "maximum_retry_count", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_n2, - .extra2 = &max_n2 - }, - { - .procname = "maximum_packet_length", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_paclen, - .extra2 = &max_paclen - }, - { - .procname = "protocol", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_proto, - .extra2 = &max_proto - }, -#ifdef CONFIG_AX25_DAMA_SLAVE - { - .procname = "dama_slave_timeout", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_ds_timeout, - .extra2 = &max_ds_timeout - }, -#endif -}; - -int ax25_register_dev_sysctl(ax25_dev *ax25_dev) -{ - char path[sizeof("net/ax25/") + IFNAMSIZ]; - int k; - struct ctl_table *table; - - table = kmemdup(ax25_param_table, sizeof(ax25_param_table), GFP_KERNEL); - if (!table) - return -ENOMEM; - - BUILD_BUG_ON(ARRAY_SIZE(ax25_param_table) != AX25_MAX_VALUES); - for (k = 0; k < AX25_MAX_VALUES; k++) - table[k].data = &ax25_dev->values[k]; - - snprintf(path, sizeof(path), "net/ax25/%s", ax25_dev->dev->name); - ax25_dev->sysheader = register_net_sysctl_sz(&init_net, path, table, - ARRAY_SIZE(ax25_param_table)); - if (!ax25_dev->sysheader) { - kfree(table); - return -ENOMEM; - } - return 0; -} - -void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev) -{ - struct ctl_table_header *header = ax25_dev->sysheader; - const struct ctl_table *table; - - if (header) { - ax25_dev->sysheader = NULL; - table = header->ctl_table_arg; - unregister_net_sysctl_table(header); - kfree(table); - } -} diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 6b2b65a66700..ee6457d1a5ee 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -33,7 +33,6 @@ menuconfig BT HCI Device drivers (Interface to the hardware) RFCOMM Module (RFCOMM Protocol) BNEP Module (Bluetooth Network Encapsulation Protocol) - CMTP Module (CAPI Message Transport Protocol) HIDP Module (Human Interface Device Protocol) Say Y here to compile Bluetooth support into the kernel or say M to @@ -58,8 +57,6 @@ source "net/bluetooth/rfcomm/Kconfig" source "net/bluetooth/bnep/Kconfig" -source "net/bluetooth/cmtp/Kconfig" - source "net/bluetooth/hidp/Kconfig" config BT_LE diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index a7eede7616d8..41049b280887 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_BT) += bluetooth.o obj-$(CONFIG_BT_RFCOMM) += rfcomm/ obj-$(CONFIG_BT_BNEP) += bnep/ -obj-$(CONFIG_BT_CMTP) += cmtp/ obj-$(CONFIG_BT_HIDP) += hidp/ obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o diff --git a/net/bluetooth/cmtp/Kconfig b/net/bluetooth/cmtp/Kconfig deleted file mode 100644 index 34e923466236..000000000000 --- a/net/bluetooth/cmtp/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config BT_CMTP - tristate "CMTP protocol support (DEPRECATED)" - depends on BT_BREDR && ISDN_CAPI && DEPRECATED - help - CMTP (CAPI Message Transport Protocol) is a transport layer - for CAPI messages. CMTP is required for the Bluetooth Common - ISDN Access Profile. - - Say Y here to compile CMTP support into the kernel or say M to - compile it as module (cmtp). - diff --git a/net/bluetooth/cmtp/Makefile b/net/bluetooth/cmtp/Makefile deleted file mode 100644 index b2262ca97499..000000000000 --- a/net/bluetooth/cmtp/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the Linux Bluetooth CMTP layer -# - -obj-$(CONFIG_BT_CMTP) += cmtp.o - -cmtp-objs := core.o sock.o capi.o diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c deleted file mode 100644 index b95413bffa16..000000000000 --- a/net/bluetooth/cmtp/capi.c +++ /dev/null @@ -1,579 +0,0 @@ -/* - CMTP implementation for Linux Bluetooth stack (BlueZ). - Copyright (C) 2002-2003 Marcel Holtmann - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "cmtp.h" - -#define CAPI_INTEROPERABILITY 0x20 - -#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ) -#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF) -#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND) -#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP) - -#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2) -#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4) -#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2) -#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2) - -#define CAPI_FUNCTION_REGISTER 0 -#define CAPI_FUNCTION_RELEASE 1 -#define CAPI_FUNCTION_GET_PROFILE 2 -#define CAPI_FUNCTION_GET_MANUFACTURER 3 -#define CAPI_FUNCTION_GET_VERSION 4 -#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5 -#define CAPI_FUNCTION_MANUFACTURER 6 -#define CAPI_FUNCTION_LOOPBACK 7 - - -#define CMTP_MSGNUM 1 -#define CMTP_APPLID 2 -#define CMTP_MAPPING 3 - -static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl) -{ - struct cmtp_application *app = kzalloc_obj(*app); - - BT_DBG("session %p application %p appl %u", session, app, appl); - - if (!app) - return NULL; - - app->state = BT_OPEN; - app->appl = appl; - - list_add_tail(&app->list, &session->applications); - - return app; -} - -static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app) -{ - BT_DBG("session %p application %p", session, app); - - if (app) { - list_del(&app->list); - kfree(app); - } -} - -static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value) -{ - struct cmtp_application *app; - - list_for_each_entry(app, &session->applications, list) { - switch (pattern) { - case CMTP_MSGNUM: - if (app->msgnum == value) - return app; - break; - case CMTP_APPLID: - if (app->appl == value) - return app; - break; - case CMTP_MAPPING: - if (app->mapping == value) - return app; - break; - } - } - - return NULL; -} - -static int cmtp_msgnum_get(struct cmtp_session *session) -{ - session->msgnum++; - - if ((session->msgnum & 0xff) > 200) - session->msgnum = CMTP_INITIAL_MSGNUM + 1; - - return session->msgnum; -} - -static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) -{ - struct cmtp_scb *scb = (void *) skb->cb; - - BT_DBG("session %p skb %p len %u", session, skb, skb->len); - - scb->id = -1; - scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3); - - skb_queue_tail(&session->transmit, skb); - - wake_up_interruptible(sk_sleep(session->sock->sk)); -} - -static void cmtp_send_interopmsg(struct cmtp_session *session, - __u8 subcmd, __u16 appl, __u16 msgnum, - __u16 function, unsigned char *buf, int len) -{ - struct sk_buff *skb; - unsigned char *s; - - BT_DBG("session %p subcmd 0x%02x appl %u msgnum %u", session, subcmd, appl, msgnum); - - skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC); - if (!skb) { - BT_ERR("Can't allocate memory for interoperability packet"); - return; - } - - s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len); - - capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len); - capimsg_setu16(s, 2, appl); - capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY); - capimsg_setu8 (s, 5, subcmd); - capimsg_setu16(s, 6, msgnum); - - /* Interoperability selector (Bluetooth Device Management) */ - capimsg_setu16(s, 8, 0x0001); - - capimsg_setu8 (s, 10, 3 + len); - capimsg_setu16(s, 11, function); - capimsg_setu8 (s, 13, len); - - if (len > 0) - memcpy(s + 14, buf, len); - - cmtp_send_capimsg(session, skb); -} - -static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb) -{ - struct capi_ctr *ctrl = &session->ctrl; - struct cmtp_application *application; - __u16 appl, msgnum, func, info; - __u32 controller; - - BT_DBG("session %p skb %p len %u", session, skb, skb->len); - - switch (CAPIMSG_SUBCOMMAND(skb->data)) { - case CAPI_CONF: - if (skb->len < CAPI_MSG_BASELEN + 10) - break; - - func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5); - info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8); - - switch (func) { - case CAPI_FUNCTION_REGISTER: - msgnum = CAPIMSG_MSGID(skb->data); - - application = cmtp_application_get(session, CMTP_MSGNUM, msgnum); - if (application) { - application->state = BT_CONNECTED; - application->msgnum = 0; - application->mapping = CAPIMSG_APPID(skb->data); - wake_up_interruptible(&session->wait); - } - - break; - - case CAPI_FUNCTION_RELEASE: - appl = CAPIMSG_APPID(skb->data); - - application = cmtp_application_get(session, CMTP_MAPPING, appl); - if (application) { - application->state = BT_CLOSED; - application->msgnum = 0; - wake_up_interruptible(&session->wait); - } - - break; - - case CAPI_FUNCTION_GET_PROFILE: - if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile)) - break; - - controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11); - msgnum = CAPIMSG_MSGID(skb->data); - - if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) { - session->ncontroller = controller; - wake_up_interruptible(&session->wait); - break; - } - - if (!info && ctrl) { - memcpy(&ctrl->profile, - skb->data + CAPI_MSG_BASELEN + 11, - sizeof(capi_profile)); - session->state = BT_CONNECTED; - capi_ctr_ready(ctrl); - } - - break; - - case CAPI_FUNCTION_GET_MANUFACTURER: - if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 14) - strscpy_pad(ctrl->manu, - skb->data + CAPI_MSG_BASELEN + 15, - skb->data[CAPI_MSG_BASELEN + 14]); - break; - - case CAPI_FUNCTION_GET_VERSION: - if (skb->len < CAPI_MSG_BASELEN + 32) - break; - - if (!info && ctrl) { - ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16); - ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20); - ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24); - ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28); - } - - break; - - case CAPI_FUNCTION_GET_SERIAL_NUMBER: - if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 16) - strscpy_pad(ctrl->serial, - skb->data + CAPI_MSG_BASELEN + 17, - skb->data[CAPI_MSG_BASELEN + 16]); - break; - } - - break; - - case CAPI_IND: - if (skb->len < CAPI_MSG_BASELEN + 6) - break; - - func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3); - - if (func == CAPI_FUNCTION_LOOPBACK) { - int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6, - skb->data[CAPI_MSG_BASELEN + 5]); - appl = CAPIMSG_APPID(skb->data); - msgnum = CAPIMSG_MSGID(skb->data); - cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func, - skb->data + CAPI_MSG_BASELEN + 6, len); - } - - break; - } - - kfree_skb(skb); -} - -void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) -{ - struct capi_ctr *ctrl = &session->ctrl; - struct cmtp_application *application; - __u16 appl; - __u32 contr; - - BT_DBG("session %p skb %p len %u", session, skb, skb->len); - - if (skb->len < CAPI_MSG_BASELEN) - return; - - if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) { - cmtp_recv_interopmsg(session, skb); - return; - } - - if (session->flags & BIT(CMTP_LOOPBACK)) { - kfree_skb(skb); - return; - } - - appl = CAPIMSG_APPID(skb->data); - contr = CAPIMSG_CONTROL(skb->data); - - application = cmtp_application_get(session, CMTP_MAPPING, appl); - if (application) { - appl = application->appl; - CAPIMSG_SETAPPID(skb->data, appl); - } else { - BT_ERR("Can't find application with id %u", appl); - kfree_skb(skb); - return; - } - - if ((contr & 0x7f) == 0x01) { - contr = (contr & 0xffffff80) | session->num; - CAPIMSG_SETCONTROL(skb->data, contr); - } - - capi_ctr_handle_message(ctrl, appl, skb); -} - -static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ - BT_DBG("ctrl %p data %p", ctrl, data); - - return 0; -} - -static void cmtp_reset_ctr(struct capi_ctr *ctrl) -{ - struct cmtp_session *session = ctrl->driverdata; - - BT_DBG("ctrl %p", ctrl); - - capi_ctr_down(ctrl); - - atomic_inc(&session->terminate); - wake_up_process(session->task); -} - -static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) -{ - DECLARE_WAITQUEUE(wait, current); - struct cmtp_session *session = ctrl->driverdata; - struct cmtp_application *application; - unsigned long timeo = CMTP_INTEROP_TIMEOUT; - unsigned char buf[8]; - int err = 0, nconn, want = rp->level3cnt; - - BT_DBG("ctrl %p appl %u level3cnt %u datablkcnt %u datablklen %u", - ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen); - - application = cmtp_application_add(session, appl); - if (!application) { - BT_ERR("Can't allocate memory for new application"); - return; - } - - if (want < 0) - nconn = ctrl->profile.nbchannel * -want; - else - nconn = want; - - if (nconn == 0) - nconn = ctrl->profile.nbchannel; - - capimsg_setu16(buf, 0, nconn); - capimsg_setu16(buf, 2, rp->datablkcnt); - capimsg_setu16(buf, 4, rp->datablklen); - - application->state = BT_CONFIG; - application->msgnum = cmtp_msgnum_get(session); - - cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum, - CAPI_FUNCTION_REGISTER, buf, 6); - - add_wait_queue(&session->wait, &wait); - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - - if (!timeo) { - err = -EAGAIN; - break; - } - - if (application->state == BT_CLOSED) { - err = -application->err; - break; - } - - if (application->state == BT_CONNECTED) - break; - - if (signal_pending(current)) { - err = -EINTR; - break; - } - - timeo = schedule_timeout(timeo); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&session->wait, &wait); - - if (err) { - cmtp_application_del(session, application); - return; - } -} - -static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl) -{ - struct cmtp_session *session = ctrl->driverdata; - struct cmtp_application *application; - - BT_DBG("ctrl %p appl %u", ctrl, appl); - - application = cmtp_application_get(session, CMTP_APPLID, appl); - if (!application) { - BT_ERR("Can't find application"); - return; - } - - application->msgnum = cmtp_msgnum_get(session); - - cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum, - CAPI_FUNCTION_RELEASE, NULL, 0); - - wait_event_interruptible_timeout(session->wait, - (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT); - - cmtp_application_del(session, application); -} - -static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - struct cmtp_session *session = ctrl->driverdata; - struct cmtp_application *application; - __u16 appl; - __u32 contr; - - BT_DBG("ctrl %p skb %p", ctrl, skb); - - appl = CAPIMSG_APPID(skb->data); - contr = CAPIMSG_CONTROL(skb->data); - - application = cmtp_application_get(session, CMTP_APPLID, appl); - if ((!application) || (application->state != BT_CONNECTED)) { - BT_ERR("Can't find application with id %u", appl); - return CAPI_ILLAPPNR; - } - - CAPIMSG_SETAPPID(skb->data, application->mapping); - - if ((contr & 0x7f) == session->num) { - contr = (contr & 0xffffff80) | 0x01; - CAPIMSG_SETCONTROL(skb->data, contr); - } - - cmtp_send_capimsg(session, skb); - - return CAPI_NOERROR; -} - -static char *cmtp_procinfo(struct capi_ctr *ctrl) -{ - return "CAPI Message Transport Protocol"; -} - -static int cmtp_proc_show(struct seq_file *m, void *v) -{ - struct capi_ctr *ctrl = m->private; - struct cmtp_session *session = ctrl->driverdata; - struct cmtp_application *app; - - seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl)); - seq_printf(m, "addr %s\n", session->name); - seq_printf(m, "ctrl %d\n", session->num); - - list_for_each_entry(app, &session->applications, list) { - seq_printf(m, "appl %u -> %u\n", app->appl, app->mapping); - } - - return 0; -} - -int cmtp_attach_device(struct cmtp_session *session) -{ - unsigned char buf[4]; - long ret; - - BT_DBG("session %p", session); - - capimsg_setu32(buf, 0, 0); - - cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM, - CAPI_FUNCTION_GET_PROFILE, buf, 4); - - ret = wait_event_interruptible_timeout(session->wait, - session->ncontroller, CMTP_INTEROP_TIMEOUT); - - BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name); - - if (!ret) - return -ETIMEDOUT; - - if (!session->ncontroller) - return -ENODEV; - - if (session->ncontroller > 1) - BT_INFO("Setting up only CAPI controller 1"); - - session->ctrl.owner = THIS_MODULE; - session->ctrl.driverdata = session; - strcpy(session->ctrl.name, session->name); - - session->ctrl.driver_name = "cmtp"; - session->ctrl.load_firmware = cmtp_load_firmware; - session->ctrl.reset_ctr = cmtp_reset_ctr; - session->ctrl.register_appl = cmtp_register_appl; - session->ctrl.release_appl = cmtp_release_appl; - session->ctrl.send_message = cmtp_send_message; - - session->ctrl.procinfo = cmtp_procinfo; - session->ctrl.proc_show = cmtp_proc_show; - - if (attach_capi_ctr(&session->ctrl) < 0) { - BT_ERR("Can't attach new controller"); - return -EBUSY; - } - - session->num = session->ctrl.cnr; - - BT_DBG("session %p num %d", session, session->num); - - capimsg_setu32(buf, 0, 1); - - cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), - CAPI_FUNCTION_GET_MANUFACTURER, buf, 4); - - cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), - CAPI_FUNCTION_GET_VERSION, buf, 4); - - cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), - CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4); - - cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), - CAPI_FUNCTION_GET_PROFILE, buf, 4); - - return 0; -} - -void cmtp_detach_device(struct cmtp_session *session) -{ - BT_DBG("session %p", session); - - detach_capi_ctr(&session->ctrl); -} diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h deleted file mode 100644 index f6b9dc4e408f..000000000000 --- a/net/bluetooth/cmtp/cmtp.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - CMTP implementation for Linux Bluetooth stack (BlueZ). - Copyright (C) 2002-2003 Marcel Holtmann - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -#ifndef __CMTP_H -#define __CMTP_H - -#include -#include - -#define BTNAMSIZ 21 - -/* CMTP ioctl defines */ -#define CMTPCONNADD _IOW('C', 200, int) -#define CMTPCONNDEL _IOW('C', 201, int) -#define CMTPGETCONNLIST _IOR('C', 210, int) -#define CMTPGETCONNINFO _IOR('C', 211, int) - -#define CMTP_LOOPBACK 0 - -struct cmtp_connadd_req { - int sock; /* Connected socket */ - __u32 flags; -}; - -struct cmtp_conndel_req { - bdaddr_t bdaddr; - __u32 flags; -}; - -struct cmtp_conninfo { - bdaddr_t bdaddr; - __u32 flags; - __u16 state; - int num; -}; - -struct cmtp_connlist_req { - __u32 cnum; - struct cmtp_conninfo __user *ci; -}; - -int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock); -int cmtp_del_connection(struct cmtp_conndel_req *req); -int cmtp_get_connlist(struct cmtp_connlist_req *req); -int cmtp_get_conninfo(struct cmtp_conninfo *ci); - -/* CMTP session defines */ -#define CMTP_INTEROP_TIMEOUT (HZ * 5) -#define CMTP_INITIAL_MSGNUM 0xff00 - -struct cmtp_session { - struct list_head list; - - struct socket *sock; - - bdaddr_t bdaddr; - - unsigned long state; - unsigned long flags; - - uint mtu; - - char name[BTNAMSIZ]; - - atomic_t terminate; - struct task_struct *task; - - wait_queue_head_t wait; - - int ncontroller; - int num; - struct capi_ctr ctrl; - - struct list_head applications; - - unsigned long blockids; - int msgnum; - - struct sk_buff_head transmit; - - struct sk_buff *reassembly[16]; -}; - -struct cmtp_application { - struct list_head list; - - unsigned long state; - int err; - - __u16 appl; - __u16 mapping; - - __u16 msgnum; -}; - -struct cmtp_scb { - int id; - int data; -}; - -int cmtp_attach_device(struct cmtp_session *session); -void cmtp_detach_device(struct cmtp_session *session); - -void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); - -/* CMTP init defines */ -int cmtp_init_sockets(void); -void cmtp_cleanup_sockets(void); - -#endif /* __CMTP_H */ diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c deleted file mode 100644 index 261aeeda3236..000000000000 --- a/net/bluetooth/cmtp/core.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - CMTP implementation for Linux Bluetooth stack (BlueZ). - Copyright (C) 2002-2003 Marcel Holtmann - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "cmtp.h" - -#define VERSION "1.0" - -static DECLARE_RWSEM(cmtp_session_sem); -static LIST_HEAD(cmtp_session_list); - -static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr) -{ - struct cmtp_session *session; - - BT_DBG(""); - - list_for_each_entry(session, &cmtp_session_list, list) - if (!bacmp(bdaddr, &session->bdaddr)) - return session; - - return NULL; -} - -static void __cmtp_link_session(struct cmtp_session *session) -{ - list_add(&session->list, &cmtp_session_list); -} - -static void __cmtp_unlink_session(struct cmtp_session *session) -{ - list_del(&session->list); -} - -static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) -{ - u32 valid_flags = BIT(CMTP_LOOPBACK); - memset(ci, 0, sizeof(*ci)); - bacpy(&ci->bdaddr, &session->bdaddr); - - ci->flags = session->flags & valid_flags; - ci->state = session->state; - - ci->num = session->num; -} - - -static inline int cmtp_alloc_block_id(struct cmtp_session *session) -{ - int i, id = -1; - - for (i = 0; i < 16; i++) - if (!test_and_set_bit(i, &session->blockids)) { - id = i; - break; - } - - return id; -} - -static inline void cmtp_free_block_id(struct cmtp_session *session, int id) -{ - clear_bit(id, &session->blockids); -} - -static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count) -{ - struct sk_buff *skb = session->reassembly[id], *nskb; - int size; - - BT_DBG("session %p buf %p count %d", session, buf, count); - - size = (skb) ? skb->len + count : count; - - nskb = alloc_skb(size, GFP_ATOMIC); - if (!nskb) { - BT_ERR("Can't allocate memory for CAPI message"); - return; - } - - if (skb && (skb->len > 0)) - skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len); - - skb_put_data(nskb, buf, count); - - session->reassembly[id] = nskb; - - kfree_skb(skb); -} - -static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb) -{ - __u8 hdr, hdrlen, id; - __u16 len; - - BT_DBG("session %p skb %p len %d", session, skb, skb->len); - - while (skb->len > 0) { - hdr = skb->data[0]; - - switch (hdr & 0xc0) { - case 0x40: - hdrlen = 2; - len = skb->data[1]; - break; - case 0x80: - hdrlen = 3; - len = skb->data[1] | (skb->data[2] << 8); - break; - default: - hdrlen = 1; - len = 0; - break; - } - - id = (hdr & 0x3c) >> 2; - - BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id); - - if (hdrlen + len > skb->len) { - BT_ERR("Wrong size or header information in CMTP frame"); - break; - } - - if (len == 0) { - skb_pull(skb, hdrlen); - continue; - } - - switch (hdr & 0x03) { - case 0x00: - cmtp_add_msgpart(session, id, skb->data + hdrlen, len); - cmtp_recv_capimsg(session, session->reassembly[id]); - session->reassembly[id] = NULL; - break; - case 0x01: - cmtp_add_msgpart(session, id, skb->data + hdrlen, len); - break; - default: - kfree_skb(session->reassembly[id]); - session->reassembly[id] = NULL; - break; - } - - skb_pull(skb, hdrlen + len); - } - - kfree_skb(skb); - return 0; -} - -static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len) -{ - struct socket *sock = session->sock; - struct kvec iv = { data, len }; - struct msghdr msg; - - BT_DBG("session %p data %p len %d", session, data, len); - - if (!len) - return 0; - - memset(&msg, 0, sizeof(msg)); - - return kernel_sendmsg(sock, &msg, &iv, 1, len); -} - -static void cmtp_process_transmit(struct cmtp_session *session) -{ - struct sk_buff *skb, *nskb; - unsigned char *hdr; - unsigned int size, tail; - - BT_DBG("session %p", session); - - nskb = alloc_skb(session->mtu, GFP_ATOMIC); - if (!nskb) { - BT_ERR("Can't allocate memory for new frame"); - return; - } - - while ((skb = skb_dequeue(&session->transmit))) { - struct cmtp_scb *scb = (void *) skb->cb; - - tail = session->mtu - nskb->len; - if (tail < 5) { - cmtp_send_frame(session, nskb->data, nskb->len); - skb_trim(nskb, 0); - tail = session->mtu; - } - - size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); - - if (scb->id < 0) { - scb->id = cmtp_alloc_block_id(session); - if (scb->id < 0) { - skb_queue_head(&session->transmit, skb); - break; - } - } - - if (size < 256) { - hdr = skb_put(nskb, 2); - hdr[0] = 0x40 - | ((scb->id << 2) & 0x3c) - | ((skb->len == size) ? 0x00 : 0x01); - hdr[1] = size; - } else { - hdr = skb_put(nskb, 3); - hdr[0] = 0x80 - | ((scb->id << 2) & 0x3c) - | ((skb->len == size) ? 0x00 : 0x01); - hdr[1] = size & 0xff; - hdr[2] = size >> 8; - } - - skb_copy_from_linear_data(skb, skb_put(nskb, size), size); - skb_pull(skb, size); - - if (skb->len > 0) { - skb_queue_head(&session->transmit, skb); - } else { - cmtp_free_block_id(session, scb->id); - if (scb->data) { - cmtp_send_frame(session, nskb->data, nskb->len); - skb_trim(nskb, 0); - } - kfree_skb(skb); - } - } - - cmtp_send_frame(session, nskb->data, nskb->len); - - kfree_skb(nskb); -} - -static int cmtp_session(void *arg) -{ - struct cmtp_session *session = arg; - struct sock *sk = session->sock->sk; - struct sk_buff *skb; - DEFINE_WAIT_FUNC(wait, woken_wake_function); - - BT_DBG("session %p", session); - - set_user_nice(current, -15); - - add_wait_queue(sk_sleep(sk), &wait); - while (1) { - if (atomic_read(&session->terminate)) - break; - if (sk->sk_state != BT_CONNECTED) - break; - - while ((skb = skb_dequeue(&sk->sk_receive_queue))) { - skb_orphan(skb); - if (!skb_linearize(skb)) - cmtp_recv_frame(session, skb); - else - kfree_skb(skb); - } - - cmtp_process_transmit(session); - - /* - * wait_woken() performs the necessary memory barriers - * for us; see the header comment for this primitive. - */ - wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); - } - remove_wait_queue(sk_sleep(sk), &wait); - - down_write(&cmtp_session_sem); - - if (!(session->flags & BIT(CMTP_LOOPBACK))) - cmtp_detach_device(session); - - fput(session->sock->file); - - __cmtp_unlink_session(session); - - up_write(&cmtp_session_sem); - - kfree(session); - module_put_and_kthread_exit(0); - return 0; -} - -int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) -{ - u32 valid_flags = BIT(CMTP_LOOPBACK); - struct cmtp_session *session, *s; - int i, err; - - BT_DBG(""); - - if (!l2cap_is_socket(sock)) - return -EBADFD; - - if (req->flags & ~valid_flags) - return -EINVAL; - - session = kzalloc_obj(struct cmtp_session); - if (!session) - return -ENOMEM; - - down_write(&cmtp_session_sem); - - s = __cmtp_get_session(&l2cap_pi(sock->sk)->chan->dst); - if (s && s->state == BT_CONNECTED) { - err = -EEXIST; - goto failed; - } - - bacpy(&session->bdaddr, &l2cap_pi(sock->sk)->chan->dst); - - session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu, - l2cap_pi(sock->sk)->chan->imtu); - - BT_DBG("mtu %d", session->mtu); - - sprintf(session->name, "%pMR", &session->bdaddr); - - session->sock = sock; - session->state = BT_CONFIG; - - init_waitqueue_head(&session->wait); - - session->msgnum = CMTP_INITIAL_MSGNUM; - - INIT_LIST_HEAD(&session->applications); - - skb_queue_head_init(&session->transmit); - - for (i = 0; i < 16; i++) - session->reassembly[i] = NULL; - - session->flags = req->flags; - - __cmtp_link_session(session); - - __module_get(THIS_MODULE); - session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", - session->num); - if (IS_ERR(session->task)) { - module_put(THIS_MODULE); - err = PTR_ERR(session->task); - goto unlink; - } - - if (!(session->flags & BIT(CMTP_LOOPBACK))) { - err = cmtp_attach_device(session); - if (err < 0) { - /* Caller will call fput in case of failure, and so - * will cmtp_session kthread. - */ - get_file(session->sock->file); - - atomic_inc(&session->terminate); - wake_up_interruptible(sk_sleep(session->sock->sk)); - up_write(&cmtp_session_sem); - return err; - } - } - - up_write(&cmtp_session_sem); - return 0; - -unlink: - __cmtp_unlink_session(session); - -failed: - up_write(&cmtp_session_sem); - kfree(session); - return err; -} - -int cmtp_del_connection(struct cmtp_conndel_req *req) -{ - u32 valid_flags = 0; - struct cmtp_session *session; - int err = 0; - - BT_DBG(""); - - if (req->flags & ~valid_flags) - return -EINVAL; - - down_read(&cmtp_session_sem); - - session = __cmtp_get_session(&req->bdaddr); - if (session) { - /* Flush the transmit queue */ - skb_queue_purge(&session->transmit); - - /* Stop session thread */ - atomic_inc(&session->terminate); - - /* - * See the comment preceding the call to wait_woken() - * in cmtp_session(). - */ - wake_up_interruptible(sk_sleep(session->sock->sk)); - } else - err = -ENOENT; - - up_read(&cmtp_session_sem); - return err; -} - -int cmtp_get_connlist(struct cmtp_connlist_req *req) -{ - struct cmtp_session *session; - int err = 0, n = 0; - - BT_DBG(""); - - down_read(&cmtp_session_sem); - - list_for_each_entry(session, &cmtp_session_list, list) { - struct cmtp_conninfo ci; - - __cmtp_copy_session(session, &ci); - - if (copy_to_user(req->ci, &ci, sizeof(ci))) { - err = -EFAULT; - break; - } - - if (++n >= req->cnum) - break; - - req->ci++; - } - req->cnum = n; - - up_read(&cmtp_session_sem); - return err; -} - -int cmtp_get_conninfo(struct cmtp_conninfo *ci) -{ - struct cmtp_session *session; - int err = 0; - - down_read(&cmtp_session_sem); - - session = __cmtp_get_session(&ci->bdaddr); - if (session) - __cmtp_copy_session(session, ci); - else - err = -ENOENT; - - up_read(&cmtp_session_sem); - return err; -} - - -static int __init cmtp_init(void) -{ - BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION); - - return cmtp_init_sockets(); -} - -static void __exit cmtp_exit(void) -{ - cmtp_cleanup_sockets(); -} - -module_init(cmtp_init); -module_exit(cmtp_exit); - -MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("bt-proto-5"); diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c deleted file mode 100644 index 96d49d9fae96..000000000000 --- a/net/bluetooth/cmtp/sock.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - CMTP implementation for Linux Bluetooth stack (BlueZ). - Copyright (C) 2002-2003 Marcel Holtmann - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -#include "cmtp.h" - -static struct bt_sock_list cmtp_sk_list = { - .lock = __RW_LOCK_UNLOCKED(cmtp_sk_list.lock) -}; - -static int cmtp_sock_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - BT_DBG("sock %p sk %p", sock, sk); - - if (!sk) - return 0; - - bt_sock_unlink(&cmtp_sk_list, sk); - - sock_orphan(sk); - sock_put(sk); - - return 0; -} - -static int do_cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp) -{ - struct cmtp_connadd_req ca; - struct cmtp_conndel_req cd; - struct cmtp_connlist_req cl; - struct cmtp_conninfo ci; - struct socket *nsock; - int err; - - BT_DBG("cmd %x arg %p", cmd, argp); - - switch (cmd) { - case CMTPCONNADD: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(&ca, argp, sizeof(ca))) - return -EFAULT; - - nsock = sockfd_lookup(ca.sock, &err); - if (!nsock) - return err; - - if (nsock->sk->sk_state != BT_CONNECTED) { - sockfd_put(nsock); - return -EBADFD; - } - - err = cmtp_add_connection(&ca, nsock); - if (!err) { - if (copy_to_user(argp, &ca, sizeof(ca))) - err = -EFAULT; - } else - sockfd_put(nsock); - - return err; - - case CMTPCONNDEL: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(&cd, argp, sizeof(cd))) - return -EFAULT; - - return cmtp_del_connection(&cd); - - case CMTPGETCONNLIST: - if (copy_from_user(&cl, argp, sizeof(cl))) - return -EFAULT; - - if (cl.cnum <= 0) - return -EINVAL; - - err = cmtp_get_connlist(&cl); - if (!err && copy_to_user(argp, &cl, sizeof(cl))) - return -EFAULT; - - return err; - - case CMTPGETCONNINFO: - if (copy_from_user(&ci, argp, sizeof(ci))) - return -EFAULT; - - err = cmtp_get_conninfo(&ci); - if (!err && copy_to_user(argp, &ci, sizeof(ci))) - return -EFAULT; - - return err; - } - - return -EINVAL; -} - -static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - return do_cmtp_sock_ioctl(sock, cmd, (void __user *)arg); -} - -#ifdef CONFIG_COMPAT -static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - void __user *argp = compat_ptr(arg); - if (cmd == CMTPGETCONNLIST) { - struct cmtp_connlist_req cl; - u32 __user *p = argp; - u32 uci; - int err; - - if (get_user(cl.cnum, p) || get_user(uci, p + 1)) - return -EFAULT; - - cl.ci = compat_ptr(uci); - - if (cl.cnum <= 0) - return -EINVAL; - - err = cmtp_get_connlist(&cl); - - if (!err && put_user(cl.cnum, p)) - err = -EFAULT; - - return err; - } - - return do_cmtp_sock_ioctl(sock, cmd, argp); -} -#endif - -static const struct proto_ops cmtp_sock_ops = { - .family = PF_BLUETOOTH, - .owner = THIS_MODULE, - .release = cmtp_sock_release, - .ioctl = cmtp_sock_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = cmtp_sock_compat_ioctl, -#endif - .bind = sock_no_bind, - .getname = sock_no_getname, - .sendmsg = sock_no_sendmsg, - .recvmsg = sock_no_recvmsg, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .connect = sock_no_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .mmap = sock_no_mmap -}; - -static struct proto cmtp_proto = { - .name = "CMTP", - .owner = THIS_MODULE, - .obj_size = sizeof(struct bt_sock) -}; - -static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct sock *sk; - - BT_DBG("sock %p", sock); - - if (sock->type != SOCK_RAW) - return -ESOCKTNOSUPPORT; - - sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, kern); - if (!sk) - return -ENOMEM; - - sock_init_data(sock, sk); - - sock->ops = &cmtp_sock_ops; - - sock->state = SS_UNCONNECTED; - - sock_reset_flag(sk, SOCK_ZAPPED); - - sk->sk_protocol = protocol; - sk->sk_state = BT_OPEN; - - bt_sock_link(&cmtp_sk_list, sk); - - return 0; -} - -static const struct net_proto_family cmtp_sock_family_ops = { - .family = PF_BLUETOOTH, - .owner = THIS_MODULE, - .create = cmtp_sock_create -}; - -int cmtp_init_sockets(void) -{ - int err; - - err = proto_register(&cmtp_proto, 0); - if (err < 0) - return err; - - err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops); - if (err < 0) { - BT_ERR("Can't register CMTP socket"); - goto error; - } - - err = bt_procfs_init(&init_net, "cmtp", &cmtp_sk_list, NULL); - if (err < 0) { - BT_ERR("Failed to create CMTP proc file"); - bt_sock_unregister(BTPROTO_HIDP); - goto error; - } - - BT_INFO("CMTP socket layer initialized"); - - return 0; - -error: - proto_unregister(&cmtp_proto); - return err; -} - -void cmtp_cleanup_sockets(void) -{ - bt_procfs_cleanup(&init_net, "cmtp"); - bt_sock_unregister(BTPROTO_CMTP); - proto_unregister(&cmtp_proto); -} 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 6eb3ab69a514..ac81e58d5f70 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -896,35 +896,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/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/net/caif/Kconfig b/net/caif/Kconfig deleted file mode 100644 index 87205251cc25..000000000000 --- a/net/caif/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# CAIF net configurations -# - -menuconfig CAIF - tristate "CAIF support" - select CRC_CCITT - default n - help - The "Communication CPU to Application CPU Interface" (CAIF) is a packet - based connection-oriented MUX protocol developed by ST-Ericsson for use - with its modems. It is accessed from user space as sockets (PF_CAIF). - - Say Y (or M) here if you build for a phone product (e.g. Android or - MeeGo) that uses CAIF as transport. If unsure say N. - - If you select to build it as module then CAIF_NETDEV also needs to be - built as a module. You will also need to say Y (or M) to any CAIF - physical devices that your platform requires. - - See Documentation/networking/caif for a further explanation on how to - use and configure CAIF. - -config CAIF_DEBUG - bool "Enable Debug" - depends on CAIF - default n - help - Enable the inclusion of debug code in the CAIF stack. - Be aware that doing this will impact performance. - If unsure say N. - -config CAIF_NETDEV - tristate "CAIF GPRS Network device" - depends on CAIF - default CAIF - help - Say Y if you will be using a CAIF based GPRS network device. - This can be either built-in or a loadable module. - If you select to build it as a built-in then the main CAIF device must - also be a built-in. - If unsure say Y. - -config CAIF_USB - tristate "CAIF USB support" - depends on CAIF - default n - help - Say Y if you are using CAIF over USB CDC NCM. - This can be either built-in or a loadable module. - If you select to build it as a built-in then the main CAIF device must - also be a built-in. - If unsure say N. diff --git a/net/caif/Makefile b/net/caif/Makefile deleted file mode 100644 index 4f6c0517cdfb..000000000000 --- a/net/caif/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG - -caif-y := caif_dev.o \ - cfcnfg.o cfmuxl.o cfctrl.o \ - cffrml.o cfveil.o cfdbgl.o\ - cfserl.o cfdgml.o \ - cfrfml.o cfvidl.o cfutill.o \ - cfsrvl.o cfpkt_skbuff.o - -obj-$(CONFIG_CAIF) += caif.o -obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o -obj-$(CONFIG_CAIF) += caif_socket.o -obj-$(CONFIG_CAIF_USB) += caif_usb.o - -export-y := caif.o diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c deleted file mode 100644 index 922de3d611c0..000000000000 --- a/net/caif/caif_dev.c +++ /dev/null @@ -1,586 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * CAIF Interface registration. - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - * - * Borrowed heavily from file: pn_dev.c. Thanks to Remi Denis-Courmont - * and Sakari Ailus - */ - -#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 - -MODULE_DESCRIPTION("ST-Ericsson CAIF modem protocol support"); -MODULE_LICENSE("GPL"); - -/* Used for local tracking of the CAIF net devices */ -struct caif_device_entry { - struct cflayer layer; - struct list_head list; - struct net_device *netdev; - int __percpu *pcpu_refcnt; - spinlock_t flow_lock; - struct sk_buff *xoff_skb; - void (*xoff_skb_dtor)(struct sk_buff *skb); - bool xoff; -}; - -struct caif_device_entry_list { - struct list_head list; - /* Protects simulanous deletes in list */ - struct mutex lock; -}; - -struct caif_net { - struct cfcnfg *cfg; - struct caif_device_entry_list caifdevs; -}; - -static unsigned int caif_net_id; -static int q_high = 50; /* Percent */ - -struct cfcnfg *get_cfcnfg(struct net *net) -{ - struct caif_net *caifn; - caifn = net_generic(net, caif_net_id); - return caifn->cfg; -} -EXPORT_SYMBOL(get_cfcnfg); - -static struct caif_device_entry_list *caif_device_list(struct net *net) -{ - struct caif_net *caifn; - caifn = net_generic(net, caif_net_id); - return &caifn->caifdevs; -} - -static void caifd_put(struct caif_device_entry *e) -{ - this_cpu_dec(*e->pcpu_refcnt); -} - -static void caifd_hold(struct caif_device_entry *e) -{ - this_cpu_inc(*e->pcpu_refcnt); -} - -static int caifd_refcnt_read(struct caif_device_entry *e) -{ - int i, refcnt = 0; - for_each_possible_cpu(i) - refcnt += *per_cpu_ptr(e->pcpu_refcnt, i); - return refcnt; -} - -/* Allocate new CAIF device. */ -static struct caif_device_entry *caif_device_alloc(struct net_device *dev) -{ - struct caif_device_entry *caifd; - - caifd = kzalloc_obj(*caifd); - if (!caifd) - return NULL; - caifd->pcpu_refcnt = alloc_percpu(int); - if (!caifd->pcpu_refcnt) { - kfree(caifd); - return NULL; - } - caifd->netdev = dev; - dev_hold(dev); - return caifd; -} - -static struct caif_device_entry *caif_get(struct net_device *dev) -{ - struct caif_device_entry_list *caifdevs = - caif_device_list(dev_net(dev)); - struct caif_device_entry *caifd; - - list_for_each_entry_rcu(caifd, &caifdevs->list, list, - lockdep_rtnl_is_held()) { - if (caifd->netdev == dev) - return caifd; - } - return NULL; -} - -static void caif_flow_cb(struct sk_buff *skb) -{ - struct caif_device_entry *caifd; - void (*dtor)(struct sk_buff *skb) = NULL; - bool send_xoff; - - WARN_ON(skb->dev == NULL); - - rcu_read_lock(); - caifd = caif_get(skb->dev); - - WARN_ON(caifd == NULL); - if (!caifd) { - rcu_read_unlock(); - return; - } - - caifd_hold(caifd); - rcu_read_unlock(); - - spin_lock_bh(&caifd->flow_lock); - send_xoff = caifd->xoff; - caifd->xoff = false; - dtor = caifd->xoff_skb_dtor; - - if (WARN_ON(caifd->xoff_skb != skb)) - skb = NULL; - - caifd->xoff_skb = NULL; - caifd->xoff_skb_dtor = NULL; - - spin_unlock_bh(&caifd->flow_lock); - - if (dtor && skb) - dtor(skb); - - if (send_xoff) - caifd->layer.up-> - ctrlcmd(caifd->layer.up, - _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND, - caifd->layer.id); - caifd_put(caifd); -} - -static int transmit(struct cflayer *layer, struct cfpkt *pkt) -{ - int err, high = 0, qlen = 0; - struct caif_device_entry *caifd = - container_of(layer, struct caif_device_entry, layer); - struct sk_buff *skb; - struct netdev_queue *txq; - - rcu_read_lock_bh(); - - skb = cfpkt_tonative(pkt); - skb->dev = caifd->netdev; - skb_reset_network_header(skb); - skb->protocol = htons(ETH_P_CAIF); - - /* Check if we need to handle xoff */ - if (likely(caifd->netdev->priv_flags & IFF_NO_QUEUE)) - goto noxoff; - - if (unlikely(caifd->xoff)) - goto noxoff; - - if (likely(!netif_queue_stopped(caifd->netdev))) { - struct Qdisc *sch; - - /* If we run with a TX queue, check if the queue is too long*/ - txq = netdev_get_tx_queue(skb->dev, 0); - sch = rcu_dereference_bh(txq->qdisc); - if (likely(qdisc_is_empty(sch))) - goto noxoff; - - /* can check for explicit qdisc len value only !NOLOCK, - * always set flow off otherwise - */ - high = (caifd->netdev->tx_queue_len * q_high) / 100; - if (!(sch->flags & TCQ_F_NOLOCK) && likely(sch->q.qlen < high)) - goto noxoff; - } - - /* Hold lock while accessing xoff */ - spin_lock_bh(&caifd->flow_lock); - if (caifd->xoff) { - spin_unlock_bh(&caifd->flow_lock); - goto noxoff; - } - - /* - * Handle flow off, we do this by temporary hi-jacking this - * skb's destructor function, and replace it with our own - * flow-on callback. The callback will set flow-on and call - * the original destructor. - */ - - pr_debug("queue has stopped(%d) or is full (%d > %d)\n", - netif_queue_stopped(caifd->netdev), - qlen, high); - caifd->xoff = true; - caifd->xoff_skb = skb; - caifd->xoff_skb_dtor = skb->destructor; - skb->destructor = caif_flow_cb; - spin_unlock_bh(&caifd->flow_lock); - - caifd->layer.up->ctrlcmd(caifd->layer.up, - _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, - caifd->layer.id); -noxoff: - rcu_read_unlock_bh(); - - err = dev_queue_xmit(skb); - if (err > 0) - err = -EIO; - - return err; -} - -/* - * Stuff received packets into the CAIF stack. - * On error, returns non-zero and releases the skb. - */ -static int receive(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pkttype, struct net_device *orig_dev) -{ - struct cfpkt *pkt; - struct caif_device_entry *caifd; - int err; - - pkt = cfpkt_fromnative(CAIF_DIR_IN, skb); - - rcu_read_lock(); - caifd = caif_get(dev); - - if (!caifd || !caifd->layer.up || !caifd->layer.up->receive || - !netif_oper_up(caifd->netdev)) { - rcu_read_unlock(); - kfree_skb(skb); - return NET_RX_DROP; - } - - /* Hold reference to netdevice while using CAIF stack */ - caifd_hold(caifd); - rcu_read_unlock(); - - err = caifd->layer.up->receive(caifd->layer.up, pkt); - - /* For -EILSEQ the packet is not freed so free it now */ - if (err == -EILSEQ) - cfpkt_destroy(pkt); - - /* Release reference to stack upwards */ - caifd_put(caifd); - - if (err != 0) - err = NET_RX_DROP; - return err; -} - -static struct packet_type caif_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_CAIF), - .func = receive, -}; - -static void dev_flowctrl(struct net_device *dev, int on) -{ - struct caif_device_entry *caifd; - - rcu_read_lock(); - - caifd = caif_get(dev); - if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) { - rcu_read_unlock(); - return; - } - - caifd_hold(caifd); - rcu_read_unlock(); - - caifd->layer.up->ctrlcmd(caifd->layer.up, - on ? - _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND : - _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, - caifd->layer.id); - caifd_put(caifd); -} - -int caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, - struct cflayer *link_support, int head_room, - struct cflayer **layer, - int (**rcv_func)(struct sk_buff *, struct net_device *, - struct packet_type *, - struct net_device *)) -{ - struct caif_device_entry *caifd; - enum cfcnfg_phy_preference pref; - struct cfcnfg *cfg = get_cfcnfg(dev_net(dev)); - struct caif_device_entry_list *caifdevs; - int res; - - caifdevs = caif_device_list(dev_net(dev)); - caifd = caif_device_alloc(dev); - if (!caifd) - return -ENOMEM; - *layer = &caifd->layer; - spin_lock_init(&caifd->flow_lock); - - switch (caifdev->link_select) { - case CAIF_LINK_HIGH_BANDW: - pref = CFPHYPREF_HIGH_BW; - break; - case CAIF_LINK_LOW_LATENCY: - pref = CFPHYPREF_LOW_LAT; - break; - default: - pref = CFPHYPREF_HIGH_BW; - break; - } - mutex_lock(&caifdevs->lock); - list_add_rcu(&caifd->list, &caifdevs->list); - - strscpy(caifd->layer.name, dev->name, - sizeof(caifd->layer.name)); - caifd->layer.transmit = transmit; - res = cfcnfg_add_phy_layer(cfg, - dev, - &caifd->layer, - pref, - link_support, - caifdev->use_fcs, - head_room); - mutex_unlock(&caifdevs->lock); - if (rcv_func) - *rcv_func = receive; - return res; -} -EXPORT_SYMBOL(caif_enroll_dev); - -/* notify Caif of device events */ -static int caif_device_notify(struct notifier_block *me, unsigned long what, - void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct caif_device_entry *caifd = NULL; - struct caif_dev_common *caifdev; - struct cfcnfg *cfg; - struct cflayer *layer, *link_support; - int head_room = 0; - struct caif_device_entry_list *caifdevs; - int res; - - cfg = get_cfcnfg(dev_net(dev)); - caifdevs = caif_device_list(dev_net(dev)); - - caifd = caif_get(dev); - if (caifd == NULL && dev->type != ARPHRD_CAIF) - return 0; - - switch (what) { - case NETDEV_REGISTER: - if (caifd != NULL) - break; - - caifdev = netdev_priv(dev); - - link_support = NULL; - if (caifdev->use_frag) { - head_room = 1; - link_support = cfserl_create(dev->ifindex, - caifdev->use_stx); - if (!link_support) { - pr_warn("Out of memory\n"); - break; - } - } - res = caif_enroll_dev(dev, caifdev, link_support, head_room, - &layer, NULL); - if (res) - cfserl_release(link_support); - caifdev->flowctrl = dev_flowctrl; - break; - - case NETDEV_UP: - rcu_read_lock(); - - caifd = caif_get(dev); - if (caifd == NULL) { - rcu_read_unlock(); - break; - } - - caifd->xoff = false; - cfcnfg_set_phy_state(cfg, &caifd->layer, true); - rcu_read_unlock(); - - break; - - case NETDEV_DOWN: - rcu_read_lock(); - - caifd = caif_get(dev); - if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) { - rcu_read_unlock(); - return -EINVAL; - } - - cfcnfg_set_phy_state(cfg, &caifd->layer, false); - caifd_hold(caifd); - rcu_read_unlock(); - - caifd->layer.up->ctrlcmd(caifd->layer.up, - _CAIF_CTRLCMD_PHYIF_DOWN_IND, - caifd->layer.id); - - spin_lock_bh(&caifd->flow_lock); - - /* - * Replace our xoff-destructor with original destructor. - * We trust that skb->destructor *always* is called before - * the skb reference is invalid. The hijacked SKB destructor - * takes the flow_lock so manipulating the skb->destructor here - * should be safe. - */ - if (caifd->xoff_skb_dtor != NULL && caifd->xoff_skb != NULL) - caifd->xoff_skb->destructor = caifd->xoff_skb_dtor; - - caifd->xoff = false; - caifd->xoff_skb_dtor = NULL; - caifd->xoff_skb = NULL; - - spin_unlock_bh(&caifd->flow_lock); - caifd_put(caifd); - break; - - case NETDEV_UNREGISTER: - mutex_lock(&caifdevs->lock); - - caifd = caif_get(dev); - if (caifd == NULL) { - mutex_unlock(&caifdevs->lock); - break; - } - list_del_rcu(&caifd->list); - - /* - * NETDEV_UNREGISTER is called repeatedly until all reference - * counts for the net-device are released. If references to - * caifd is taken, simply ignore NETDEV_UNREGISTER and wait for - * the next call to NETDEV_UNREGISTER. - * - * If any packets are in flight down the CAIF Stack, - * cfcnfg_del_phy_layer will return nonzero. - * If no packets are in flight, the CAIF Stack associated - * with the net-device un-registering is freed. - */ - - if (caifd_refcnt_read(caifd) != 0 || - cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0) { - - pr_info("Wait for device inuse\n"); - /* Enrole device if CAIF Stack is still in use */ - list_add_rcu(&caifd->list, &caifdevs->list); - mutex_unlock(&caifdevs->lock); - break; - } - - synchronize_rcu(); - dev_put(caifd->netdev); - free_percpu(caifd->pcpu_refcnt); - kfree(caifd); - - mutex_unlock(&caifdevs->lock); - break; - } - return 0; -} - -static struct notifier_block caif_device_notifier = { - .notifier_call = caif_device_notify, - .priority = 0, -}; - -/* Per-namespace Caif devices handling */ -static int caif_init_net(struct net *net) -{ - struct caif_net *caifn = net_generic(net, caif_net_id); - INIT_LIST_HEAD(&caifn->caifdevs.list); - mutex_init(&caifn->caifdevs.lock); - - caifn->cfg = cfcnfg_create(); - if (!caifn->cfg) - return -ENOMEM; - - return 0; -} - -static void caif_exit_net(struct net *net) -{ - struct caif_device_entry *caifd, *tmp; - struct caif_device_entry_list *caifdevs = - caif_device_list(net); - struct cfcnfg *cfg = get_cfcnfg(net); - - rtnl_lock(); - mutex_lock(&caifdevs->lock); - - list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) { - int i = 0; - list_del_rcu(&caifd->list); - cfcnfg_set_phy_state(cfg, &caifd->layer, false); - - while (i < 10 && - (caifd_refcnt_read(caifd) != 0 || - cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0)) { - - pr_info("Wait for device inuse\n"); - msleep(250); - i++; - } - synchronize_rcu(); - dev_put(caifd->netdev); - free_percpu(caifd->pcpu_refcnt); - kfree(caifd); - } - cfcnfg_remove(cfg); - - mutex_unlock(&caifdevs->lock); - rtnl_unlock(); -} - -static struct pernet_operations caif_net_ops = { - .init = caif_init_net, - .exit = caif_exit_net, - .id = &caif_net_id, - .size = sizeof(struct caif_net), -}; - -/* Initialize Caif devices list */ -static int __init caif_device_init(void) -{ - int result; - - result = register_pernet_subsys(&caif_net_ops); - - if (result) - return result; - - register_netdevice_notifier(&caif_device_notifier); - dev_add_pack(&caif_packet_type); - - return result; -} - -static void __exit caif_device_exit(void) -{ - unregister_netdevice_notifier(&caif_device_notifier); - dev_remove_pack(&caif_packet_type); - unregister_pernet_subsys(&caif_net_ops); -} - -module_init(caif_device_init); -module_exit(caif_device_exit); diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c deleted file mode 100644 index af218742af5a..000000000000 --- a/net/caif/caif_socket.c +++ /dev/null @@ -1,1114 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#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 -#include -#include - -MODULE_DESCRIPTION("ST-Ericsson CAIF modem protocol socket support (AF_CAIF)"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NETPROTO(AF_CAIF); - -/* - * CAIF state is re-using the TCP socket states. - * caif_states stored in sk_state reflect the state as reported by - * the CAIF stack, while sk_socket->state is the state of the socket. - */ -enum caif_states { - CAIF_CONNECTED = TCP_ESTABLISHED, - CAIF_CONNECTING = TCP_SYN_SENT, - CAIF_DISCONNECTED = TCP_CLOSE -}; - -#define TX_FLOW_ON_BIT 1 -#define RX_FLOW_ON_BIT 2 - -struct caifsock { - struct sock sk; /* must be first member */ - struct cflayer layer; - unsigned long flow_state; - struct caif_connect_request conn_req; - struct mutex readlock; - struct dentry *debugfs_socket_dir; - int headroom, tailroom, maxframe; -}; - -static int rx_flow_is_on(struct caifsock *cf_sk) -{ - return test_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state); -} - -static int tx_flow_is_on(struct caifsock *cf_sk) -{ - return test_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state); -} - -static void set_rx_flow_off(struct caifsock *cf_sk) -{ - clear_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state); -} - -static void set_rx_flow_on(struct caifsock *cf_sk) -{ - set_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state); -} - -static void set_tx_flow_off(struct caifsock *cf_sk) -{ - clear_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state); -} - -static void set_tx_flow_on(struct caifsock *cf_sk) -{ - set_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state); -} - -static void caif_read_lock(struct sock *sk) -{ - struct caifsock *cf_sk; - cf_sk = container_of(sk, struct caifsock, sk); - mutex_lock(&cf_sk->readlock); -} - -static void caif_read_unlock(struct sock *sk) -{ - struct caifsock *cf_sk; - cf_sk = container_of(sk, struct caifsock, sk); - mutex_unlock(&cf_sk->readlock); -} - -static int sk_rcvbuf_lowwater(struct caifsock *cf_sk) -{ - /* A quarter of full buffer is used a low water mark */ - return cf_sk->sk.sk_rcvbuf / 4; -} - -static void caif_flow_ctrl(struct sock *sk, int mode) -{ - struct caifsock *cf_sk; - cf_sk = container_of(sk, struct caifsock, sk); - if (cf_sk->layer.dn && cf_sk->layer.dn->modemcmd) - cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode); -} - -/* - * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are - * not dropped, but CAIF is sending flow off instead. - */ -static void caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - int err; - unsigned long flags; - struct sk_buff_head *list = &sk->sk_receive_queue; - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - bool queued = false; - - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned int)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) { - net_dbg_ratelimited("sending flow OFF (queue len = %d %d)\n", - atomic_read(&cf_sk->sk.sk_rmem_alloc), - sk_rcvbuf_lowwater(cf_sk)); - set_rx_flow_off(cf_sk); - caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); - } - - err = sk_filter(sk, skb); - if (err) - goto out; - - if (!sk_rmem_schedule(sk, skb, skb->truesize) && rx_flow_is_on(cf_sk)) { - set_rx_flow_off(cf_sk); - net_dbg_ratelimited("sending flow OFF due to rmem_schedule\n"); - caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); - } - skb->dev = NULL; - skb_set_owner_r(skb, sk); - spin_lock_irqsave(&list->lock, flags); - queued = !sock_flag(sk, SOCK_DEAD); - if (queued) - __skb_queue_tail(list, skb); - spin_unlock_irqrestore(&list->lock, flags); -out: - if (queued) - sk->sk_data_ready(sk); - else - kfree_skb(skb); -} - -/* Packet Receive Callback function called from CAIF Stack */ -static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt) -{ - struct caifsock *cf_sk; - struct sk_buff *skb; - - cf_sk = container_of(layr, struct caifsock, layer); - skb = cfpkt_tonative(pkt); - - if (unlikely(cf_sk->sk.sk_state != CAIF_CONNECTED)) { - kfree_skb(skb); - return 0; - } - caif_queue_rcv_skb(&cf_sk->sk, skb); - return 0; -} - -static void cfsk_hold(struct cflayer *layr) -{ - struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); - sock_hold(&cf_sk->sk); -} - -static void cfsk_put(struct cflayer *layr) -{ - struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); - sock_put(&cf_sk->sk); -} - -/* Packet Control Callback function called from CAIF */ -static void caif_ctrl_cb(struct cflayer *layr, - enum caif_ctrlcmd flow, - int phyid) -{ - struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); - switch (flow) { - case CAIF_CTRLCMD_FLOW_ON_IND: - /* OK from modem to start sending again */ - set_tx_flow_on(cf_sk); - cf_sk->sk.sk_state_change(&cf_sk->sk); - break; - - case CAIF_CTRLCMD_FLOW_OFF_IND: - /* Modem asks us to shut up */ - set_tx_flow_off(cf_sk); - cf_sk->sk.sk_state_change(&cf_sk->sk); - break; - - case CAIF_CTRLCMD_INIT_RSP: - /* We're now connected */ - caif_client_register_refcnt(&cf_sk->layer, - cfsk_hold, cfsk_put); - cf_sk->sk.sk_state = CAIF_CONNECTED; - set_tx_flow_on(cf_sk); - cf_sk->sk.sk_shutdown = 0; - cf_sk->sk.sk_state_change(&cf_sk->sk); - break; - - case CAIF_CTRLCMD_DEINIT_RSP: - /* We're now disconnected */ - cf_sk->sk.sk_state = CAIF_DISCONNECTED; - cf_sk->sk.sk_state_change(&cf_sk->sk); - break; - - case CAIF_CTRLCMD_INIT_FAIL_RSP: - /* Connect request failed */ - cf_sk->sk.sk_err = ECONNREFUSED; - cf_sk->sk.sk_state = CAIF_DISCONNECTED; - cf_sk->sk.sk_shutdown = SHUTDOWN_MASK; - /* - * Socket "standards" seems to require POLLOUT to - * be set at connect failure. - */ - set_tx_flow_on(cf_sk); - cf_sk->sk.sk_state_change(&cf_sk->sk); - break; - - case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND: - /* Modem has closed this connection, or device is down. */ - cf_sk->sk.sk_shutdown = SHUTDOWN_MASK; - cf_sk->sk.sk_err = ECONNRESET; - set_rx_flow_on(cf_sk); - sk_error_report(&cf_sk->sk); - break; - - default: - pr_debug("Unexpected flow command %d\n", flow); - } -} - -static void caif_check_flow_release(struct sock *sk) -{ - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - - if (rx_flow_is_on(cf_sk)) - return; - - if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) { - set_rx_flow_on(cf_sk); - caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ); - } -} - -/* - * Copied from unix_dgram_recvmsg, but removed credit checks, - * changed locking, address handling and added MSG_TRUNC. - */ -static int caif_seqpkt_recvmsg(struct socket *sock, struct msghdr *m, - size_t len, int flags) - -{ - struct sock *sk = sock->sk; - struct sk_buff *skb; - int ret; - int copylen; - - ret = -EOPNOTSUPP; - if (flags & MSG_OOB) - goto read_error; - - skb = skb_recv_datagram(sk, flags, &ret); - if (!skb) - goto read_error; - copylen = skb->len; - if (len < copylen) { - m->msg_flags |= MSG_TRUNC; - copylen = len; - } - - ret = skb_copy_datagram_msg(skb, 0, m, copylen); - if (ret) - goto out_free; - - ret = (flags & MSG_TRUNC) ? skb->len : copylen; -out_free: - skb_free_datagram(sk, skb); - caif_check_flow_release(sk); - return ret; - -read_error: - return ret; -} - - -/* Copied from unix_stream_wait_data, identical except for lock call. */ -static long caif_stream_data_wait(struct sock *sk, long timeo) -{ - DEFINE_WAIT(wait); - lock_sock(sk); - - for (;;) { - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - if (!skb_queue_empty(&sk->sk_receive_queue) || - sk->sk_err || - sk->sk_state != CAIF_CONNECTED || - sock_flag(sk, SOCK_DEAD) || - (sk->sk_shutdown & RCV_SHUTDOWN) || - signal_pending(current) || - !timeo) - break; - - sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); - release_sock(sk); - timeo = schedule_timeout(timeo); - lock_sock(sk); - - if (sock_flag(sk, SOCK_DEAD)) - break; - - sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); - } - - finish_wait(sk_sleep(sk), &wait); - release_sock(sk); - return timeo; -} - - -/* - * Copied from unix_stream_recvmsg, but removed credit checks, - * changed locking calls, changed address handling. - */ -static int caif_stream_recvmsg(struct socket *sock, struct msghdr *msg, - size_t size, int flags) -{ - struct sock *sk = sock->sk; - int copied = 0; - int target; - int err = 0; - long timeo; - - err = -EOPNOTSUPP; - if (flags&MSG_OOB) - goto out; - - /* - * Lock the socket to prevent queue disordering - * while sleeps in memcpy_tomsg - */ - err = -EAGAIN; - if (sk->sk_state == CAIF_CONNECTING) - goto out; - - caif_read_lock(sk); - target = sock_rcvlowat(sk, flags&MSG_WAITALL, size); - timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT); - - do { - int chunk; - struct sk_buff *skb; - - lock_sock(sk); - if (sock_flag(sk, SOCK_DEAD)) { - err = -ECONNRESET; - goto unlock; - } - skb = skb_dequeue(&sk->sk_receive_queue); - caif_check_flow_release(sk); - - if (skb == NULL) { - if (copied >= target) - goto unlock; - /* - * POSIX 1003.1g mandates this order. - */ - err = sock_error(sk); - if (err) - goto unlock; - err = -ECONNRESET; - if (sk->sk_shutdown & RCV_SHUTDOWN) - goto unlock; - - err = -EPIPE; - if (sk->sk_state != CAIF_CONNECTED) - goto unlock; - if (sock_flag(sk, SOCK_DEAD)) - goto unlock; - - release_sock(sk); - - err = -EAGAIN; - if (!timeo) - break; - - caif_read_unlock(sk); - - timeo = caif_stream_data_wait(sk, timeo); - - if (signal_pending(current)) { - err = sock_intr_errno(timeo); - goto out; - } - caif_read_lock(sk); - continue; -unlock: - release_sock(sk); - break; - } - release_sock(sk); - chunk = min_t(unsigned int, skb->len, size); - if (memcpy_to_msg(msg, skb->data, chunk)) { - skb_queue_head(&sk->sk_receive_queue, skb); - if (copied == 0) - copied = -EFAULT; - break; - } - copied += chunk; - size -= chunk; - - /* Mark read part of skb as used */ - if (!(flags & MSG_PEEK)) { - skb_pull(skb, chunk); - - /* put the skb back if we didn't use it up. */ - if (skb->len) { - skb_queue_head(&sk->sk_receive_queue, skb); - break; - } - kfree_skb(skb); - - } else { - /* - * It is questionable, see note in unix_dgram_recvmsg. - */ - /* put message back and return */ - skb_queue_head(&sk->sk_receive_queue, skb); - break; - } - } while (size); - caif_read_unlock(sk); - -out: - return copied ? : err; -} - -/* - * Copied from sock.c:sock_wait_for_wmem, but change to wait for - * CAIF flow-on and sock_writable. - */ -static long caif_wait_for_flow_on(struct caifsock *cf_sk, - int wait_writeable, long timeo, int *err) -{ - struct sock *sk = &cf_sk->sk; - DEFINE_WAIT(wait); - for (;;) { - *err = 0; - if (tx_flow_is_on(cf_sk) && - (!wait_writeable || sock_writeable(&cf_sk->sk))) - break; - *err = -ETIMEDOUT; - if (!timeo) - break; - *err = -ERESTARTSYS; - if (signal_pending(current)) - break; - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - *err = -ECONNRESET; - if (sk->sk_shutdown & SHUTDOWN_MASK) - break; - *err = -sk->sk_err; - if (sk->sk_err) - break; - *err = -EPIPE; - if (cf_sk->sk.sk_state != CAIF_CONNECTED) - break; - timeo = schedule_timeout(timeo); - } - finish_wait(sk_sleep(sk), &wait); - return timeo; -} - -/* - * Transmit a SKB. The device may temporarily request re-transmission - * by returning EAGAIN. - */ -static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk, - int noblock, long timeo) -{ - struct cfpkt *pkt; - - pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb); - memset(skb->cb, 0, sizeof(struct caif_payload_info)); - cfpkt_set_prio(pkt, cf_sk->sk.sk_priority); - - if (cf_sk->layer.dn == NULL) { - kfree_skb(skb); - return -EINVAL; - } - - return cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt); -} - -/* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */ -static int caif_seqpkt_sendmsg(struct socket *sock, struct msghdr *msg, - size_t len) -{ - struct sock *sk = sock->sk; - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - int buffer_size; - int ret = 0; - struct sk_buff *skb = NULL; - int noblock; - long timeo; - caif_assert(cf_sk); - ret = sock_error(sk); - if (ret) - goto err; - - ret = -EOPNOTSUPP; - if (msg->msg_flags&MSG_OOB) - goto err; - - ret = -EOPNOTSUPP; - if (msg->msg_namelen) - goto err; - - noblock = msg->msg_flags & MSG_DONTWAIT; - - timeo = sock_sndtimeo(sk, noblock); - timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk), - 1, timeo, &ret); - - if (ret) - goto err; - ret = -EPIPE; - if (cf_sk->sk.sk_state != CAIF_CONNECTED || - sock_flag(sk, SOCK_DEAD) || - (sk->sk_shutdown & RCV_SHUTDOWN)) - goto err; - - /* Error if trying to write more than maximum frame size. */ - ret = -EMSGSIZE; - if (len > cf_sk->maxframe && cf_sk->sk.sk_protocol != CAIFPROTO_RFM) - goto err; - - buffer_size = len + cf_sk->headroom + cf_sk->tailroom; - - ret = -ENOMEM; - skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret); - - if (!skb || skb_tailroom(skb) < buffer_size) - goto err; - - skb_reserve(skb, cf_sk->headroom); - - ret = memcpy_from_msg(skb_put(skb, len), msg, len); - - if (ret) - goto err; - ret = transmit_skb(skb, cf_sk, noblock, timeo); - if (ret < 0) - /* skb is already freed */ - return ret; - - return len; -err: - kfree_skb(skb); - return ret; -} - -/* - * Copied from unix_stream_sendmsg and adapted to CAIF: - * Changed removed permission handling and added waiting for flow on - * and other minor adaptations. - */ -static int caif_stream_sendmsg(struct socket *sock, struct msghdr *msg, - size_t len) -{ - struct sock *sk = sock->sk; - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - int err, size; - struct sk_buff *skb; - int sent = 0; - long timeo; - - err = -EOPNOTSUPP; - if (unlikely(msg->msg_flags&MSG_OOB)) - goto out_err; - - if (unlikely(msg->msg_namelen)) - goto out_err; - - timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); - timeo = caif_wait_for_flow_on(cf_sk, 1, timeo, &err); - - if (unlikely(sk->sk_shutdown & SEND_SHUTDOWN)) - goto pipe_err; - - while (sent < len) { - - size = len-sent; - - if (size > cf_sk->maxframe) - size = cf_sk->maxframe; - - /* If size is more than half of sndbuf, chop up message */ - if (size > ((sk->sk_sndbuf >> 1) - 64)) - size = (sk->sk_sndbuf >> 1) - 64; - - if (size > SKB_MAX_ALLOC) - size = SKB_MAX_ALLOC; - - skb = sock_alloc_send_skb(sk, - size + cf_sk->headroom + - cf_sk->tailroom, - msg->msg_flags&MSG_DONTWAIT, - &err); - if (skb == NULL) - goto out_err; - - skb_reserve(skb, cf_sk->headroom); - /* - * If you pass two values to the sock_alloc_send_skb - * it tries to grab the large buffer with GFP_NOFS - * (which can fail easily), and if it fails grab the - * fallback size buffer which is under a page and will - * succeed. [Alan] - */ - size = min_t(int, size, skb_tailroom(skb)); - - err = memcpy_from_msg(skb_put(skb, size), msg, size); - if (err) { - kfree_skb(skb); - goto out_err; - } - err = transmit_skb(skb, cf_sk, - msg->msg_flags&MSG_DONTWAIT, timeo); - if (err < 0) - /* skb is already freed */ - goto pipe_err; - - sent += size; - } - - return sent; - -pipe_err: - if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - err = -EPIPE; -out_err: - return sent ? : err; -} - -static int setsockopt(struct socket *sock, int lvl, int opt, sockptr_t ov, - unsigned int ol) -{ - struct sock *sk = sock->sk; - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - int linksel; - - if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED) - return -ENOPROTOOPT; - - switch (opt) { - case CAIFSO_LINK_SELECT: - if (ol < sizeof(int)) - return -EINVAL; - if (lvl != SOL_CAIF) - goto bad_sol; - if (copy_from_sockptr(&linksel, ov, sizeof(int))) - return -EINVAL; - lock_sock(&(cf_sk->sk)); - cf_sk->conn_req.link_selector = linksel; - release_sock(&cf_sk->sk); - return 0; - - case CAIFSO_REQ_PARAM: - if (lvl != SOL_CAIF) - goto bad_sol; - if (cf_sk->sk.sk_protocol != CAIFPROTO_UTIL) - return -ENOPROTOOPT; - lock_sock(&(cf_sk->sk)); - if (ol > sizeof(cf_sk->conn_req.param.data) || - copy_from_sockptr(&cf_sk->conn_req.param.data, ov, ol)) { - release_sock(&cf_sk->sk); - return -EINVAL; - } - cf_sk->conn_req.param.size = ol; - release_sock(&cf_sk->sk); - return 0; - - default: - return -ENOPROTOOPT; - } - - return 0; -bad_sol: - return -ENOPROTOOPT; - -} - -/* - * caif_connect() - Connect a CAIF Socket - * Copied and modified af_irda.c:irda_connect(). - * - * Note : by consulting "errno", the user space caller may learn the cause - * of the failure. Most of them are visible in the function, others may come - * from subroutines called and are listed here : - * o -EAFNOSUPPORT: bad socket family or type. - * o -ESOCKTNOSUPPORT: bad socket type or protocol - * o -EINVAL: bad socket address, or CAIF link type - * o -ECONNREFUSED: remote end refused the connection. - * o -EINPROGRESS: connect request sent but timed out (or non-blocking) - * o -EISCONN: already connected. - * o -ETIMEDOUT: Connection timed out (send timeout) - * o -ENODEV: No link layer to send request - * o -ECONNRESET: Received Shutdown indication or lost link layer - * o -ENOMEM: Out of memory - * - * State Strategy: - * o sk_state: holds the CAIF_* protocol state, it's updated by - * caif_ctrl_cb. - * o sock->state: holds the SS_* socket state and is updated by connect and - * disconnect. - */ -static int caif_connect(struct socket *sock, struct sockaddr_unsized *uaddr, - int addr_len, int flags) -{ - struct sock *sk = sock->sk; - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - long timeo; - int err; - int ifindex, headroom, tailroom; - unsigned int mtu; - struct net_device *dev; - - lock_sock(sk); - - err = -EINVAL; - if (addr_len < offsetofend(struct sockaddr, sa_family)) - goto out; - - err = -EAFNOSUPPORT; - if (uaddr->sa_family != AF_CAIF) - goto out; - - switch (sock->state) { - case SS_UNCONNECTED: - /* Normal case, a fresh connect */ - caif_assert(sk->sk_state == CAIF_DISCONNECTED); - break; - case SS_CONNECTING: - switch (sk->sk_state) { - case CAIF_CONNECTED: - sock->state = SS_CONNECTED; - err = -EISCONN; - goto out; - case CAIF_DISCONNECTED: - /* Reconnect allowed */ - break; - case CAIF_CONNECTING: - err = -EALREADY; - if (flags & O_NONBLOCK) - goto out; - goto wait_connect; - } - break; - case SS_CONNECTED: - caif_assert(sk->sk_state == CAIF_CONNECTED || - sk->sk_state == CAIF_DISCONNECTED); - if (sk->sk_shutdown & SHUTDOWN_MASK) { - /* Allow re-connect after SHUTDOWN_IND */ - caif_disconnect_client(sock_net(sk), &cf_sk->layer); - caif_free_client(&cf_sk->layer); - break; - } - /* No reconnect on a seqpacket socket */ - err = -EISCONN; - goto out; - case SS_DISCONNECTING: - case SS_FREE: - caif_assert(1); /*Should never happen */ - break; - } - sk->sk_state = CAIF_DISCONNECTED; - sock->state = SS_UNCONNECTED; - sk_stream_kill_queues(&cf_sk->sk); - - err = -EINVAL; - if (addr_len != sizeof(struct sockaddr_caif)) - goto out; - - memcpy(&cf_sk->conn_req.sockaddr, uaddr, - sizeof(struct sockaddr_caif)); - - /* Move to connecting socket, start sending Connect Requests */ - sock->state = SS_CONNECTING; - sk->sk_state = CAIF_CONNECTING; - - /* Check priority value comming from socket */ - /* if priority value is out of range it will be ajusted */ - if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX) - cf_sk->conn_req.priority = CAIF_PRIO_MAX; - else if (cf_sk->sk.sk_priority < CAIF_PRIO_MIN) - cf_sk->conn_req.priority = CAIF_PRIO_MIN; - else - cf_sk->conn_req.priority = cf_sk->sk.sk_priority; - - /*ifindex = id of the interface.*/ - cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if; - - cf_sk->layer.receive = caif_sktrecv_cb; - - err = caif_connect_client(sock_net(sk), &cf_sk->conn_req, - &cf_sk->layer, &ifindex, &headroom, &tailroom); - - if (err < 0) { - cf_sk->sk.sk_socket->state = SS_UNCONNECTED; - cf_sk->sk.sk_state = CAIF_DISCONNECTED; - goto out; - } - - err = -ENODEV; - rcu_read_lock(); - dev = dev_get_by_index_rcu(sock_net(sk), ifindex); - if (!dev) { - rcu_read_unlock(); - goto out; - } - cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom); - mtu = dev->mtu; - rcu_read_unlock(); - - cf_sk->tailroom = tailroom; - cf_sk->maxframe = mtu - (headroom + tailroom); - if (cf_sk->maxframe < 1) { - pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu); - err = -ENODEV; - goto out; - } - - err = -EINPROGRESS; -wait_connect: - - if (sk->sk_state != CAIF_CONNECTED && (flags & O_NONBLOCK)) - goto out; - - timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); - - release_sock(sk); - err = -ERESTARTSYS; - timeo = wait_event_interruptible_timeout(*sk_sleep(sk), - sk->sk_state != CAIF_CONNECTING, - timeo); - lock_sock(sk); - if (timeo < 0) - goto out; /* -ERESTARTSYS */ - - err = -ETIMEDOUT; - if (timeo == 0 && sk->sk_state != CAIF_CONNECTED) - goto out; - if (sk->sk_state != CAIF_CONNECTED) { - sock->state = SS_UNCONNECTED; - err = sock_error(sk); - if (!err) - err = -ECONNREFUSED; - goto out; - } - sock->state = SS_CONNECTED; - err = 0; -out: - release_sock(sk); - return err; -} - -/* - * caif_release() - Disconnect a CAIF Socket - * Copied and modified af_irda.c:irda_release(). - */ -static int caif_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - - if (!sk) - return 0; - - set_tx_flow_off(cf_sk); - - /* - * Ensure that packets are not queued after this point in time. - * caif_queue_rcv_skb checks SOCK_DEAD holding the queue lock, - * this ensures no packets when sock is dead. - */ - spin_lock_bh(&sk->sk_receive_queue.lock); - sock_set_flag(sk, SOCK_DEAD); - spin_unlock_bh(&sk->sk_receive_queue.lock); - sock->sk = NULL; - - WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir)); - debugfs_remove_recursive(cf_sk->debugfs_socket_dir); - - lock_sock(&(cf_sk->sk)); - sk->sk_state = CAIF_DISCONNECTED; - sk->sk_shutdown = SHUTDOWN_MASK; - - caif_disconnect_client(sock_net(sk), &cf_sk->layer); - cf_sk->sk.sk_socket->state = SS_DISCONNECTING; - wake_up_interruptible_poll(sk_sleep(sk), EPOLLERR|EPOLLHUP); - - sock_orphan(sk); - sk_stream_kill_queues(&cf_sk->sk); - release_sock(sk); - sock_put(sk); - return 0; -} - -/* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */ -static __poll_t caif_poll(struct file *file, - struct socket *sock, poll_table *wait) -{ - struct sock *sk = sock->sk; - __poll_t mask; - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - - sock_poll_wait(file, sock, wait); - mask = 0; - - /* exceptional events? */ - if (sk->sk_err) - mask |= EPOLLERR; - if (sk->sk_shutdown == SHUTDOWN_MASK) - mask |= EPOLLHUP; - if (sk->sk_shutdown & RCV_SHUTDOWN) - mask |= EPOLLRDHUP; - - /* readable? */ - if (!skb_queue_empty_lockless(&sk->sk_receive_queue) || - (sk->sk_shutdown & RCV_SHUTDOWN)) - mask |= EPOLLIN | EPOLLRDNORM; - - /* - * we set writable also when the other side has shut down the - * connection. This prevents stuck sockets. - */ - if (sock_writeable(sk) && tx_flow_is_on(cf_sk)) - mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; - - return mask; -} - -static const struct proto_ops caif_seqpacket_ops = { - .family = PF_CAIF, - .owner = THIS_MODULE, - .release = caif_release, - .bind = sock_no_bind, - .connect = caif_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = sock_no_getname, - .poll = caif_poll, - .ioctl = sock_no_ioctl, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = setsockopt, - .sendmsg = caif_seqpkt_sendmsg, - .recvmsg = caif_seqpkt_recvmsg, - .mmap = sock_no_mmap, -}; - -static const struct proto_ops caif_stream_ops = { - .family = PF_CAIF, - .owner = THIS_MODULE, - .release = caif_release, - .bind = sock_no_bind, - .connect = caif_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = sock_no_getname, - .poll = caif_poll, - .ioctl = sock_no_ioctl, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = setsockopt, - .sendmsg = caif_stream_sendmsg, - .recvmsg = caif_stream_recvmsg, - .mmap = sock_no_mmap, -}; - -/* This function is called when a socket is finally destroyed. */ -static void caif_sock_destructor(struct sock *sk) -{ - struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - caif_assert(!refcount_read(&sk->sk_wmem_alloc)); - caif_assert(sk_unhashed(sk)); - caif_assert(!sk->sk_socket); - if (!sock_flag(sk, SOCK_DEAD)) { - pr_debug("Attempt to release alive CAIF socket: %p\n", sk); - return; - } - sk_stream_kill_queues(&cf_sk->sk); - WARN_ON_ONCE(sk->sk_forward_alloc); - caif_free_client(&cf_sk->layer); -} - -static int caif_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct sock *sk = NULL; - struct caifsock *cf_sk = NULL; - static struct proto prot = {.name = "PF_CAIF", - .owner = THIS_MODULE, - .obj_size = sizeof(struct caifsock), - .useroffset = offsetof(struct caifsock, conn_req.param), - .usersize = sizeof_field(struct caifsock, conn_req.param) - }; - - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_NET_ADMIN)) - return -EPERM; - /* - * The sock->type specifies the socket type to use. - * The CAIF socket is a packet stream in the sense - * that it is packet based. CAIF trusts the reliability - * of the link, no resending is implemented. - */ - if (sock->type == SOCK_SEQPACKET) - sock->ops = &caif_seqpacket_ops; - else if (sock->type == SOCK_STREAM) - sock->ops = &caif_stream_ops; - else - return -ESOCKTNOSUPPORT; - - if (protocol < 0 || protocol >= CAIFPROTO_MAX) - return -EPROTONOSUPPORT; - /* - * Set the socket state to unconnected. The socket state - * is really not used at all in the net/core or socket.c but the - * initialization makes sure that sock->state is not uninitialized. - */ - sk = sk_alloc(net, PF_CAIF, GFP_KERNEL, &prot, kern); - if (!sk) - return -ENOMEM; - - cf_sk = container_of(sk, struct caifsock, sk); - - /* Store the protocol */ - sk->sk_protocol = (unsigned char) protocol; - - /* Initialize default priority for well-known cases */ - switch (protocol) { - case CAIFPROTO_AT: - sk->sk_priority = TC_PRIO_CONTROL; - break; - case CAIFPROTO_RFM: - sk->sk_priority = TC_PRIO_INTERACTIVE_BULK; - break; - default: - sk->sk_priority = TC_PRIO_BESTEFFORT; - } - - /* - * Lock in order to try to stop someone from opening the socket - * too early. - */ - lock_sock(&(cf_sk->sk)); - - /* Initialize the nozero default sock structure data. */ - sock_init_data(sock, sk); - sk->sk_destruct = caif_sock_destructor; - - mutex_init(&cf_sk->readlock); /* single task reading lock */ - cf_sk->layer.ctrlcmd = caif_ctrl_cb; - cf_sk->sk.sk_socket->state = SS_UNCONNECTED; - cf_sk->sk.sk_state = CAIF_DISCONNECTED; - - set_tx_flow_off(cf_sk); - set_rx_flow_on(cf_sk); - - /* Set default options on configuration */ - cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY; - cf_sk->conn_req.protocol = protocol; - release_sock(&cf_sk->sk); - return 0; -} - - -static const struct net_proto_family caif_family_ops = { - .family = PF_CAIF, - .create = caif_create, - .owner = THIS_MODULE, -}; - -static int __init caif_sktinit_module(void) -{ - return sock_register(&caif_family_ops); -} - -static void __exit caif_sktexit_module(void) -{ - sock_unregister(PF_CAIF); -} -module_init(caif_sktinit_module); -module_exit(caif_sktexit_module); diff --git a/net/caif/caif_usb.c b/net/caif/caif_usb.c deleted file mode 100644 index 4d44960d4c2f..000000000000 --- a/net/caif/caif_usb.c +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * CAIF USB handler - * Copyright (C) ST-Ericsson AB 2011 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("ST-Ericsson CAIF modem protocol USB support"); -MODULE_LICENSE("GPL"); - -#define CFUSB_PAD_DESCR_SZ 1 /* Alignment descriptor length */ -#define CFUSB_ALIGNMENT 4 /* Number of bytes to align. */ -#define CFUSB_MAX_HEADLEN (CFUSB_PAD_DESCR_SZ + CFUSB_ALIGNMENT-1) -#define STE_USB_VID 0x04cc /* USB Product ID for ST-Ericsson */ -#define STE_USB_PID_CAIF 0x230f /* Product id for CAIF Modems */ - -struct cfusbl { - struct cflayer layer; - u8 tx_eth_hdr[ETH_HLEN]; -}; - -static bool pack_added; - -static int cfusbl_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 hpad; - - /* Remove padding. */ - cfpkt_extr_head(pkt, &hpad, 1); - cfpkt_extr_head(pkt, NULL, hpad); - return layr->up->receive(layr->up, pkt); -} - -static int cfusbl_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - struct caif_payload_info *info; - u8 hpad; - u8 zeros[CFUSB_ALIGNMENT]; - struct sk_buff *skb; - struct cfusbl *usbl = container_of(layr, struct cfusbl, layer); - - skb = cfpkt_tonative(pkt); - - skb_reset_network_header(skb); - skb->protocol = htons(ETH_P_IP); - - info = cfpkt_info(pkt); - hpad = (info->hdr_len + CFUSB_PAD_DESCR_SZ) & (CFUSB_ALIGNMENT - 1); - - if (skb_headroom(skb) < ETH_HLEN + CFUSB_PAD_DESCR_SZ + hpad) { - pr_warn("Headroom too small\n"); - kfree_skb(skb); - return -EIO; - } - memset(zeros, 0, hpad); - - cfpkt_add_head(pkt, zeros, hpad); - cfpkt_add_head(pkt, &hpad, 1); - cfpkt_add_head(pkt, usbl->tx_eth_hdr, sizeof(usbl->tx_eth_hdr)); - return layr->dn->transmit(layr->dn, pkt); -} - -static void cfusbl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid) -{ - if (layr->up && layr->up->ctrlcmd) - layr->up->ctrlcmd(layr->up, ctrl, layr->id); -} - -static struct cflayer *cfusbl_create(int phyid, const u8 ethaddr[ETH_ALEN], - u8 braddr[ETH_ALEN]) -{ - struct cfusbl *this = kmalloc_obj(struct cfusbl, GFP_ATOMIC); - - if (!this) - return NULL; - - caif_assert(offsetof(struct cfusbl, layer) == 0); - - memset(&this->layer, 0, sizeof(this->layer)); - this->layer.receive = cfusbl_receive; - this->layer.transmit = cfusbl_transmit; - this->layer.ctrlcmd = cfusbl_ctrlcmd; - snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "usb%d", phyid); - this->layer.id = phyid; - - /* - * Construct TX ethernet header: - * 0-5 destination address - * 5-11 source address - * 12-13 protocol type - */ - ether_addr_copy(&this->tx_eth_hdr[ETH_ALEN], braddr); - ether_addr_copy(&this->tx_eth_hdr[ETH_ALEN], ethaddr); - this->tx_eth_hdr[12] = cpu_to_be16(ETH_P_802_EX1) & 0xff; - this->tx_eth_hdr[13] = (cpu_to_be16(ETH_P_802_EX1) >> 8) & 0xff; - pr_debug("caif ethernet TX-header dst:%pM src:%pM type:%02x%02x\n", - this->tx_eth_hdr, this->tx_eth_hdr + ETH_ALEN, - this->tx_eth_hdr[12], this->tx_eth_hdr[13]); - - return (struct cflayer *) this; -} - -static void cfusbl_release(struct cflayer *layer) -{ - kfree(layer); -} - -static struct packet_type caif_usb_type __read_mostly = { - .type = cpu_to_be16(ETH_P_802_EX1), -}; - -static int cfusbl_device_notify(struct notifier_block *me, unsigned long what, - void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct caif_dev_common common; - struct cflayer *layer, *link_support; - struct usbnet *usbnet; - struct usb_device *usbdev; - int res; - - if (what == NETDEV_UNREGISTER && dev->reg_state >= NETREG_UNREGISTERED) - return 0; - - /* Check whether we have a NCM device, and find its VID/PID. */ - if (!(dev->dev.parent && dev->dev.parent->driver && - strcmp(dev->dev.parent->driver->name, "cdc_ncm") == 0)) - return 0; - - usbnet = netdev_priv(dev); - usbdev = usbnet->udev; - - pr_debug("USB CDC NCM device VID:0x%4x PID:0x%4x\n", - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct)); - - /* Check for VID/PID that supports CAIF */ - if (!(le16_to_cpu(usbdev->descriptor.idVendor) == STE_USB_VID && - le16_to_cpu(usbdev->descriptor.idProduct) == STE_USB_PID_CAIF)) - return 0; - - if (what == NETDEV_UNREGISTER) - module_put(THIS_MODULE); - - if (what != NETDEV_REGISTER) - return 0; - - __module_get(THIS_MODULE); - - memset(&common, 0, sizeof(common)); - common.use_frag = false; - common.use_fcs = false; - common.use_stx = false; - common.link_select = CAIF_LINK_HIGH_BANDW; - common.flowctrl = NULL; - - link_support = cfusbl_create(dev->ifindex, dev->dev_addr, - dev->broadcast); - - if (!link_support) - return -ENOMEM; - - if (dev->num_tx_queues > 1) - pr_warn("USB device uses more than one tx queue\n"); - - res = caif_enroll_dev(dev, &common, link_support, CFUSB_MAX_HEADLEN, - &layer, &caif_usb_type.func); - if (res) - goto err; - - if (!pack_added) - dev_add_pack(&caif_usb_type); - pack_added = true; - - strscpy(layer->name, dev->name, sizeof(layer->name)); - - return 0; -err: - cfusbl_release(link_support); - return res; -} - -static struct notifier_block caif_device_notifier = { - .notifier_call = cfusbl_device_notify, - .priority = 0, -}; - -static int __init cfusbl_init(void) -{ - return register_netdevice_notifier(&caif_device_notifier); -} - -static void __exit cfusbl_exit(void) -{ - unregister_netdevice_notifier(&caif_device_notifier); - dev_remove_pack(&caif_usb_type); -} - -module_init(cfusbl_init); -module_exit(cfusbl_exit); diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c deleted file mode 100644 index 8a80914783e8..000000000000 --- a/net/caif/cfcnfg.c +++ /dev/null @@ -1,612 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) container_of(layr, struct cfcnfg, layer) - -/* Information about CAIF physical interfaces held by Config Module in order - * to manage physical interfaces - */ -struct cfcnfg_phyinfo { - struct list_head node; - bool up; - - /* Pointer to the layer below the MUX (framing layer) */ - struct cflayer *frm_layer; - /* Pointer to the lowest actual physical layer */ - struct cflayer *phy_layer; - /* Unique identifier of the physical interface */ - unsigned int id; - /* Preference of the physical in interface */ - enum cfcnfg_phy_preference pref; - - /* Information about the physical device */ - struct dev_info dev_info; - - /* Interface index */ - int ifindex; - - /* Protocol head room added for CAIF link layer */ - int head_room; - - /* Use Start of frame checksum */ - bool use_fcs; -}; - -struct cfcnfg { - struct cflayer layer; - struct cflayer *ctrl; - struct cflayer *mux; - struct list_head phys; - struct mutex lock; -}; - -static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, - enum cfctrl_srv serv, u8 phyid, - struct cflayer *adapt_layer); -static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id); -static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, - struct cflayer *adapt_layer); -static void cfctrl_resp_func(void); -static void cfctrl_enum_resp(void); - -struct cfcnfg *cfcnfg_create(void) -{ - struct cfcnfg *this; - struct cfctrl_rsp *resp; - - might_sleep(); - - /* Initiate this layer */ - this = kzalloc_obj(struct cfcnfg, GFP_ATOMIC); - if (!this) - return NULL; - this->mux = cfmuxl_create(); - if (!this->mux) - goto out_of_mem; - this->ctrl = cfctrl_create(); - if (!this->ctrl) - goto out_of_mem; - /* Initiate response functions */ - resp = cfctrl_get_respfuncs(this->ctrl); - resp->enum_rsp = cfctrl_enum_resp; - resp->linkerror_ind = cfctrl_resp_func; - resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp; - resp->sleep_rsp = cfctrl_resp_func; - resp->wake_rsp = cfctrl_resp_func; - resp->restart_rsp = cfctrl_resp_func; - resp->radioset_rsp = cfctrl_resp_func; - resp->linksetup_rsp = cfcnfg_linkup_rsp; - resp->reject_rsp = cfcnfg_reject_rsp; - INIT_LIST_HEAD(&this->phys); - - cfmuxl_set_uplayer(this->mux, this->ctrl, 0); - layer_set_dn(this->ctrl, this->mux); - layer_set_up(this->ctrl, this); - mutex_init(&this->lock); - - return this; -out_of_mem: - synchronize_rcu(); - - kfree(this->mux); - kfree(this->ctrl); - kfree(this); - return NULL; -} - -void cfcnfg_remove(struct cfcnfg *cfg) -{ - might_sleep(); - if (cfg) { - synchronize_rcu(); - - kfree(cfg->mux); - cfctrl_remove(cfg->ctrl); - kfree(cfg); - } -} - -static void cfctrl_resp_func(void) -{ -} - -static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg, - u8 phyid) -{ - struct cfcnfg_phyinfo *phy; - - list_for_each_entry_rcu(phy, &cnfg->phys, node) - if (phy->id == phyid) - return phy; - return NULL; -} - -static void cfctrl_enum_resp(void) -{ -} - -static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, - enum cfcnfg_phy_preference phy_pref) -{ - /* Try to match with specified preference */ - struct cfcnfg_phyinfo *phy; - - list_for_each_entry_rcu(phy, &cnfg->phys, node) { - if (phy->up && phy->pref == phy_pref && - phy->frm_layer != NULL) - - return &phy->dev_info; - } - - /* Otherwise just return something */ - list_for_each_entry_rcu(phy, &cnfg->phys, node) - if (phy->up) - return &phy->dev_info; - - return NULL; -} - -static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) -{ - struct cfcnfg_phyinfo *phy; - - list_for_each_entry_rcu(phy, &cnfg->phys, node) - if (phy->ifindex == ifi && phy->up) - return phy->id; - return -ENODEV; -} - -int caif_disconnect_client(struct net *net, struct cflayer *adap_layer) -{ - u8 channel_id; - struct cfcnfg *cfg = get_cfcnfg(net); - - caif_assert(adap_layer != NULL); - cfctrl_cancel_req(cfg->ctrl, adap_layer); - channel_id = adap_layer->id; - if (channel_id != 0) { - struct cflayer *servl; - servl = cfmuxl_remove_uplayer(cfg->mux, channel_id); - cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer); - if (servl != NULL) - layer_set_up(servl, NULL); - } else - pr_debug("nothing to disconnect\n"); - - /* Do RCU sync before initiating cleanup */ - synchronize_rcu(); - if (adap_layer->ctrlcmd != NULL) - adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); - return 0; - -} -EXPORT_SYMBOL(caif_disconnect_client); - -static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) -{ -} - -static const int protohead[CFCTRL_SRV_MASK] = { - [CFCTRL_SRV_VEI] = 4, - [CFCTRL_SRV_DATAGRAM] = 7, - [CFCTRL_SRV_UTIL] = 4, - [CFCTRL_SRV_RFM] = 3, - [CFCTRL_SRV_DBG] = 3, -}; - - -static int caif_connect_req_to_link_param(struct cfcnfg *cnfg, - struct caif_connect_request *s, - struct cfctrl_link_param *l) -{ - struct dev_info *dev_info; - enum cfcnfg_phy_preference pref; - int res; - - memset(l, 0, sizeof(*l)); - /* In caif protocol low value is high priority */ - l->priority = CAIF_PRIO_MAX - s->priority + 1; - - if (s->ifindex != 0) { - res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex); - if (res < 0) - return res; - l->phyid = res; - } else { - switch (s->link_selector) { - case CAIF_LINK_HIGH_BANDW: - pref = CFPHYPREF_HIGH_BW; - break; - case CAIF_LINK_LOW_LATENCY: - pref = CFPHYPREF_LOW_LAT; - break; - default: - return -EINVAL; - } - dev_info = cfcnfg_get_phyid(cnfg, pref); - if (dev_info == NULL) - return -ENODEV; - l->phyid = dev_info->id; - } - switch (s->protocol) { - case CAIFPROTO_AT: - l->linktype = CFCTRL_SRV_VEI; - l->endpoint = (s->sockaddr.u.at.type >> 2) & 0x3; - l->chtype = s->sockaddr.u.at.type & 0x3; - break; - case CAIFPROTO_DATAGRAM: - l->linktype = CFCTRL_SRV_DATAGRAM; - l->chtype = 0x00; - l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; - break; - case CAIFPROTO_DATAGRAM_LOOP: - l->linktype = CFCTRL_SRV_DATAGRAM; - l->chtype = 0x03; - l->endpoint = 0x00; - l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; - break; - case CAIFPROTO_RFM: - l->linktype = CFCTRL_SRV_RFM; - l->u.datagram.connid = s->sockaddr.u.rfm.connection_id; - strscpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, - sizeof(l->u.rfm.volume)); - break; - case CAIFPROTO_UTIL: - l->linktype = CFCTRL_SRV_UTIL; - l->endpoint = 0x00; - l->chtype = 0x00; - strscpy(l->u.utility.name, s->sockaddr.u.util.service, - sizeof(l->u.utility.name)); - caif_assert(sizeof(l->u.utility.name) > 10); - l->u.utility.paramlen = s->param.size; - if (l->u.utility.paramlen > sizeof(l->u.utility.params)) - l->u.utility.paramlen = sizeof(l->u.utility.params); - - memcpy(l->u.utility.params, s->param.data, - l->u.utility.paramlen); - - break; - case CAIFPROTO_DEBUG: - l->linktype = CFCTRL_SRV_DBG; - l->endpoint = s->sockaddr.u.dbg.service; - l->chtype = s->sockaddr.u.dbg.type; - break; - default: - return -EINVAL; - } - return 0; -} - -int caif_connect_client(struct net *net, struct caif_connect_request *conn_req, - struct cflayer *adap_layer, int *ifindex, - int *proto_head, int *proto_tail) -{ - struct cflayer *frml; - struct cfcnfg_phyinfo *phy; - int err; - struct cfctrl_link_param param; - struct cfcnfg *cfg = get_cfcnfg(net); - - rcu_read_lock(); - err = caif_connect_req_to_link_param(cfg, conn_req, ¶m); - if (err) - goto unlock; - - phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid); - if (!phy) { - err = -ENODEV; - goto unlock; - } - err = -EINVAL; - - if (adap_layer == NULL) { - pr_err("adap_layer is zero\n"); - goto unlock; - } - if (adap_layer->receive == NULL) { - pr_err("adap_layer->receive is NULL\n"); - goto unlock; - } - if (adap_layer->ctrlcmd == NULL) { - pr_err("adap_layer->ctrlcmd == NULL\n"); - goto unlock; - } - - err = -ENODEV; - frml = phy->frm_layer; - if (frml == NULL) { - pr_err("Specified PHY type does not exist!\n"); - goto unlock; - } - caif_assert(param.phyid == phy->id); - caif_assert(phy->frm_layer->id == - param.phyid); - caif_assert(phy->phy_layer->id == - param.phyid); - - *ifindex = phy->ifindex; - *proto_tail = 2; - *proto_head = protohead[param.linktype] + phy->head_room; - - rcu_read_unlock(); - - /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ - cfctrl_enum_req(cfg->ctrl, param.phyid); - return cfctrl_linkup_request(cfg->ctrl, ¶m, adap_layer); - -unlock: - rcu_read_unlock(); - return err; -} -EXPORT_SYMBOL(caif_connect_client); - -static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, - struct cflayer *adapt_layer) -{ - if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL) - adapt_layer->ctrlcmd(adapt_layer, - CAIF_CTRLCMD_INIT_FAIL_RSP, 0); -} - -static void -cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, - u8 phyid, struct cflayer *adapt_layer) -{ - struct cfcnfg *cnfg = container_obj(layer); - struct cflayer *servicel = NULL; - struct cfcnfg_phyinfo *phyinfo; - struct net_device *netdev; - - if (channel_id == 0) { - pr_warn("received channel_id zero\n"); - if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL) - adapt_layer->ctrlcmd(adapt_layer, - CAIF_CTRLCMD_INIT_FAIL_RSP, 0); - return; - } - - rcu_read_lock(); - - if (adapt_layer == NULL) { - pr_debug("link setup response but no client exist, send linkdown back\n"); - cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL); - goto unlock; - } - - caif_assert(cnfg != NULL); - caif_assert(phyid != 0); - - phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); - if (phyinfo == NULL) { - pr_err("ERROR: Link Layer Device disappeared while connecting\n"); - goto unlock; - } - - caif_assert(phyinfo != NULL); - caif_assert(phyinfo->id == phyid); - caif_assert(phyinfo->phy_layer != NULL); - caif_assert(phyinfo->phy_layer->id == phyid); - - adapt_layer->id = channel_id; - - switch (serv) { - case CFCTRL_SRV_VEI: - servicel = cfvei_create(channel_id, &phyinfo->dev_info); - break; - case CFCTRL_SRV_DATAGRAM: - servicel = cfdgml_create(channel_id, - &phyinfo->dev_info); - break; - case CFCTRL_SRV_RFM: - netdev = phyinfo->dev_info.dev; - servicel = cfrfml_create(channel_id, &phyinfo->dev_info, - netdev->mtu); - break; - case CFCTRL_SRV_UTIL: - servicel = cfutill_create(channel_id, &phyinfo->dev_info); - break; - case CFCTRL_SRV_VIDEO: - servicel = cfvidl_create(channel_id, &phyinfo->dev_info); - break; - case CFCTRL_SRV_DBG: - servicel = cfdbgl_create(channel_id, &phyinfo->dev_info); - break; - default: - pr_err("Protocol error. Link setup response - unknown channel type\n"); - goto unlock; - } - if (!servicel) - goto unlock; - layer_set_dn(servicel, cnfg->mux); - cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); - layer_set_up(servicel, adapt_layer); - layer_set_dn(adapt_layer, servicel); - - rcu_read_unlock(); - - servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); - return; -unlock: - rcu_read_unlock(); -} - -int -cfcnfg_add_phy_layer(struct cfcnfg *cnfg, - struct net_device *dev, struct cflayer *phy_layer, - enum cfcnfg_phy_preference pref, - struct cflayer *link_support, - bool fcs, int head_room) -{ - struct cflayer *frml; - struct cfcnfg_phyinfo *phyinfo = NULL; - int i, res = 0; - u8 phyid; - - mutex_lock(&cnfg->lock); - - /* CAIF protocol allow maximum 6 link-layers */ - for (i = 0; i < 7; i++) { - phyid = (dev->ifindex + i) & 0x7; - if (phyid == 0) - continue; - if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL) - goto got_phyid; - } - pr_warn("Too many CAIF Link Layers (max 6)\n"); - res = -EEXIST; - goto out; - -got_phyid: - phyinfo = kzalloc_obj(struct cfcnfg_phyinfo, GFP_ATOMIC); - if (!phyinfo) { - res = -ENOMEM; - goto out; - } - - phy_layer->id = phyid; - phyinfo->pref = pref; - phyinfo->id = phyid; - phyinfo->dev_info.id = phyid; - phyinfo->dev_info.dev = dev; - phyinfo->phy_layer = phy_layer; - phyinfo->ifindex = dev->ifindex; - phyinfo->head_room = head_room; - phyinfo->use_fcs = fcs; - - frml = cffrml_create(phyid, fcs); - - if (!frml) { - res = -ENOMEM; - goto out_err; - } - phyinfo->frm_layer = frml; - layer_set_up(frml, cnfg->mux); - - if (link_support != NULL) { - link_support->id = phyid; - layer_set_dn(frml, link_support); - layer_set_up(link_support, frml); - layer_set_dn(link_support, phy_layer); - layer_set_up(phy_layer, link_support); - } else { - layer_set_dn(frml, phy_layer); - layer_set_up(phy_layer, frml); - } - - list_add_rcu(&phyinfo->node, &cnfg->phys); -out: - mutex_unlock(&cnfg->lock); - return res; - -out_err: - kfree(phyinfo); - mutex_unlock(&cnfg->lock); - return res; -} -EXPORT_SYMBOL(cfcnfg_add_phy_layer); - -int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer, - bool up) -{ - struct cfcnfg_phyinfo *phyinfo; - - rcu_read_lock(); - phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id); - if (phyinfo == NULL) { - rcu_read_unlock(); - return -ENODEV; - } - - if (phyinfo->up == up) { - rcu_read_unlock(); - return 0; - } - phyinfo->up = up; - - if (up) { - cffrml_hold(phyinfo->frm_layer); - cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer, - phy_layer->id); - } else { - cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id); - cffrml_put(phyinfo->frm_layer); - } - - rcu_read_unlock(); - return 0; -} -EXPORT_SYMBOL(cfcnfg_set_phy_state); - -int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) -{ - struct cflayer *frml, *frml_dn; - u16 phyid; - struct cfcnfg_phyinfo *phyinfo; - - might_sleep(); - - mutex_lock(&cnfg->lock); - - phyid = phy_layer->id; - phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); - - if (phyinfo == NULL) { - mutex_unlock(&cnfg->lock); - return 0; - } - caif_assert(phyid == phyinfo->id); - caif_assert(phy_layer == phyinfo->phy_layer); - caif_assert(phy_layer->id == phyid); - caif_assert(phyinfo->frm_layer->id == phyid); - - list_del_rcu(&phyinfo->node); - synchronize_rcu(); - - /* Fail if reference count is not zero */ - if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { - pr_info("Wait for device inuse\n"); - list_add_rcu(&phyinfo->node, &cnfg->phys); - mutex_unlock(&cnfg->lock); - return -EAGAIN; - } - - frml = phyinfo->frm_layer; - frml_dn = frml->dn; - cffrml_set_uplayer(frml, NULL); - cffrml_set_dnlayer(frml, NULL); - if (phy_layer != frml_dn) { - layer_set_up(frml_dn, NULL); - layer_set_dn(frml_dn, NULL); - } - layer_set_up(phy_layer, NULL); - - if (phyinfo->phy_layer != frml_dn) - kfree(frml_dn); - - cffrml_free(frml); - kfree(phyinfo); - mutex_unlock(&cnfg->lock); - - return 0; -} -EXPORT_SYMBOL(cfcnfg_del_phy_layer); diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c deleted file mode 100644 index c6cc2bfed65d..000000000000 --- a/net/caif/cfctrl.c +++ /dev/null @@ -1,631 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) container_of(layr, struct cfctrl, serv.layer) -#define UTILITY_NAME_LENGTH 16 -#define CFPKT_CTRL_PKT_LEN 20 - -#ifdef CAIF_NO_LOOP -static int handle_loop(struct cfctrl *ctrl, - int cmd, struct cfpkt *pkt){ - return -1; -} -#else -static int handle_loop(struct cfctrl *ctrl, - int cmd, struct cfpkt *pkt); -#endif -static int cfctrl_recv(struct cflayer *layr, struct cfpkt *pkt); -static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid); - - -struct cflayer *cfctrl_create(void) -{ - struct dev_info dev_info; - struct cfctrl *this = - kzalloc_obj(struct cfctrl, GFP_ATOMIC); - if (!this) - return NULL; - caif_assert(offsetof(struct cfctrl, serv.layer) == 0); - memset(&dev_info, 0, sizeof(dev_info)); - dev_info.id = 0xff; - cfsrvl_init(&this->serv, 0, &dev_info, false); - atomic_set(&this->req_seq_no, 1); - atomic_set(&this->rsp_seq_no, 1); - this->serv.layer.receive = cfctrl_recv; - sprintf(this->serv.layer.name, "ctrl"); - this->serv.layer.ctrlcmd = cfctrl_ctrlcmd; -#ifndef CAIF_NO_LOOP - spin_lock_init(&this->loop_linkid_lock); - this->loop_linkid = 1; -#endif - spin_lock_init(&this->info_list_lock); - INIT_LIST_HEAD(&this->list); - return &this->serv.layer; -} - -void cfctrl_remove(struct cflayer *layer) -{ - struct cfctrl_request_info *p, *tmp; - struct cfctrl *ctrl = container_obj(layer); - - spin_lock_bh(&ctrl->info_list_lock); - list_for_each_entry_safe(p, tmp, &ctrl->list, list) { - list_del(&p->list); - kfree(p); - } - spin_unlock_bh(&ctrl->info_list_lock); - kfree(layer); -} - -static bool param_eq(const struct cfctrl_link_param *p1, - const struct cfctrl_link_param *p2) -{ - bool eq = - p1->linktype == p2->linktype && - p1->priority == p2->priority && - p1->phyid == p2->phyid && - p1->endpoint == p2->endpoint && p1->chtype == p2->chtype; - - if (!eq) - return false; - - switch (p1->linktype) { - case CFCTRL_SRV_VEI: - return true; - case CFCTRL_SRV_DATAGRAM: - return p1->u.datagram.connid == p2->u.datagram.connid; - case CFCTRL_SRV_RFM: - return - p1->u.rfm.connid == p2->u.rfm.connid && - strcmp(p1->u.rfm.volume, p2->u.rfm.volume) == 0; - case CFCTRL_SRV_UTIL: - return - p1->u.utility.fifosize_kb == p2->u.utility.fifosize_kb - && p1->u.utility.fifosize_bufs == - p2->u.utility.fifosize_bufs - && strcmp(p1->u.utility.name, p2->u.utility.name) == 0 - && p1->u.utility.paramlen == p2->u.utility.paramlen - && memcmp(p1->u.utility.params, p2->u.utility.params, - p1->u.utility.paramlen) == 0; - - case CFCTRL_SRV_VIDEO: - return p1->u.video.connid == p2->u.video.connid; - case CFCTRL_SRV_DBG: - return true; - case CFCTRL_SRV_DECM: - return false; - default: - return false; - } - return false; -} - -static bool cfctrl_req_eq(const struct cfctrl_request_info *r1, - const struct cfctrl_request_info *r2) -{ - if (r1->cmd != r2->cmd) - return false; - if (r1->cmd == CFCTRL_CMD_LINK_SETUP) - return param_eq(&r1->param, &r2->param); - else - return r1->channel_id == r2->channel_id; -} - -/* Insert request at the end */ -static void cfctrl_insert_req(struct cfctrl *ctrl, - struct cfctrl_request_info *req) -{ - spin_lock_bh(&ctrl->info_list_lock); - atomic_inc(&ctrl->req_seq_no); - req->sequence_no = atomic_read(&ctrl->req_seq_no); - list_add_tail(&req->list, &ctrl->list); - spin_unlock_bh(&ctrl->info_list_lock); -} - -/* Compare and remove request */ -static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, - struct cfctrl_request_info *req) -{ - struct cfctrl_request_info *p, *tmp, *first; - - first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list); - - list_for_each_entry_safe(p, tmp, &ctrl->list, list) { - if (cfctrl_req_eq(req, p)) { - if (p != first) - pr_warn("Requests are not received in order\n"); - - atomic_set(&ctrl->rsp_seq_no, - p->sequence_no); - list_del(&p->list); - goto out; - } - } - p = NULL; -out: - return p; -} - -struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer) -{ - struct cfctrl *this = container_obj(layer); - return &this->res; -} - -static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl) -{ - info->hdr_len = 0; - info->channel_id = cfctrl->serv.layer.id; - info->dev_info = &cfctrl->serv.dev_info; -} - -void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid) -{ - struct cfpkt *pkt; - struct cfctrl *cfctrl = container_obj(layer); - struct cflayer *dn = cfctrl->serv.layer.dn; - - if (!dn) { - pr_debug("not able to send enum request\n"); - return; - } - pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); - if (!pkt) - return; - caif_assert(offsetof(struct cfctrl, serv.layer) == 0); - init_info(cfpkt_info(pkt), cfctrl); - cfpkt_info(pkt)->dev_info->id = physlinkid; - cfctrl->serv.dev_info.id = physlinkid; - cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM); - cfpkt_addbdy(pkt, physlinkid); - cfpkt_set_prio(pkt, TC_PRIO_CONTROL); - dn->transmit(dn, pkt); -} - -int cfctrl_linkup_request(struct cflayer *layer, - struct cfctrl_link_param *param, - struct cflayer *user_layer) -{ - struct cfctrl *cfctrl = container_obj(layer); - struct cflayer *dn = cfctrl->serv.layer.dn; - char utility_name[UTILITY_NAME_LENGTH]; - struct cfctrl_request_info *req; - struct cfpkt *pkt; - u32 tmp32; - u16 tmp16; - u8 tmp8; - int ret; - - if (!dn) { - pr_debug("not able to send linkup request\n"); - return -ENODEV; - } - - if (cfctrl_cancel_req(layer, user_layer) > 0) { - /* Slight Paranoia, check if already connecting */ - pr_err("Duplicate connect request for same client\n"); - WARN_ON(1); - return -EALREADY; - } - - pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); - if (!pkt) - return -ENOMEM; - cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP); - cfpkt_addbdy(pkt, (param->chtype << 4) | param->linktype); - cfpkt_addbdy(pkt, (param->priority << 3) | param->phyid); - cfpkt_addbdy(pkt, param->endpoint & 0x03); - - switch (param->linktype) { - case CFCTRL_SRV_VEI: - break; - case CFCTRL_SRV_VIDEO: - cfpkt_addbdy(pkt, (u8) param->u.video.connid); - break; - case CFCTRL_SRV_DBG: - break; - case CFCTRL_SRV_DATAGRAM: - tmp32 = cpu_to_le32(param->u.datagram.connid); - cfpkt_add_body(pkt, &tmp32, 4); - break; - case CFCTRL_SRV_RFM: - /* Construct a frame, convert DatagramConnectionID to network - * format long and copy it out... - */ - tmp32 = cpu_to_le32(param->u.rfm.connid); - cfpkt_add_body(pkt, &tmp32, 4); - /* Add volume name, including zero termination... */ - cfpkt_add_body(pkt, param->u.rfm.volume, - strlen(param->u.rfm.volume) + 1); - break; - case CFCTRL_SRV_UTIL: - tmp16 = cpu_to_le16(param->u.utility.fifosize_kb); - cfpkt_add_body(pkt, &tmp16, 2); - tmp16 = cpu_to_le16(param->u.utility.fifosize_bufs); - cfpkt_add_body(pkt, &tmp16, 2); - strscpy_pad(utility_name, param->u.utility.name); - cfpkt_add_body(pkt, utility_name, UTILITY_NAME_LENGTH); - tmp8 = param->u.utility.paramlen; - cfpkt_add_body(pkt, &tmp8, 1); - cfpkt_add_body(pkt, param->u.utility.params, - param->u.utility.paramlen); - break; - default: - pr_warn("Request setup of bad link type = %d\n", - param->linktype); - cfpkt_destroy(pkt); - return -EINVAL; - } - req = kzalloc_obj(*req); - if (!req) { - cfpkt_destroy(pkt); - return -ENOMEM; - } - - req->client_layer = user_layer; - req->cmd = CFCTRL_CMD_LINK_SETUP; - req->param = *param; - cfctrl_insert_req(cfctrl, req); - init_info(cfpkt_info(pkt), cfctrl); - /* - * NOTE:Always send linkup and linkdown request on the same - * device as the payload. Otherwise old queued up payload - * might arrive with the newly allocated channel ID. - */ - cfpkt_info(pkt)->dev_info->id = param->phyid; - cfpkt_set_prio(pkt, TC_PRIO_CONTROL); - ret = - dn->transmit(dn, pkt); - if (ret < 0) { - int count; - - count = cfctrl_cancel_req(&cfctrl->serv.layer, - user_layer); - if (count != 1) { - pr_err("Could not remove request (%d)", count); - return -ENODEV; - } - } - return 0; -} - -int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid, - struct cflayer *client) -{ - int ret; - struct cfpkt *pkt; - struct cfctrl *cfctrl = container_obj(layer); - struct cflayer *dn = cfctrl->serv.layer.dn; - - if (!dn) { - pr_debug("not able to send link-down request\n"); - return -ENODEV; - } - pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); - if (!pkt) - return -ENOMEM; - cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY); - cfpkt_addbdy(pkt, channelid); - init_info(cfpkt_info(pkt), cfctrl); - cfpkt_set_prio(pkt, TC_PRIO_CONTROL); - ret = - dn->transmit(dn, pkt); -#ifndef CAIF_NO_LOOP - cfctrl->loop_linkused[channelid] = 0; -#endif - return ret; -} - -int cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) -{ - struct cfctrl_request_info *p, *tmp; - struct cfctrl *ctrl = container_obj(layr); - int found = 0; - spin_lock_bh(&ctrl->info_list_lock); - - list_for_each_entry_safe(p, tmp, &ctrl->list, list) { - if (p->client_layer == adap_layer) { - list_del(&p->list); - kfree(p); - found++; - } - } - - spin_unlock_bh(&ctrl->info_list_lock); - return found; -} - -static int cfctrl_link_setup(struct cfctrl *cfctrl, struct cfpkt *pkt, u8 cmdrsp) -{ - u8 len; - u8 linkid = 0; - enum cfctrl_srv serv; - enum cfctrl_srv servtype; - u8 endpoint; - u8 physlinkid; - u8 prio; - u8 tmp; - u8 *cp; - int i; - struct cfctrl_link_param linkparam; - struct cfctrl_request_info rsp, *req; - - memset(&linkparam, 0, sizeof(linkparam)); - - tmp = cfpkt_extr_head_u8(pkt); - - serv = tmp & CFCTRL_SRV_MASK; - linkparam.linktype = serv; - - servtype = tmp >> 4; - linkparam.chtype = servtype; - - tmp = cfpkt_extr_head_u8(pkt); - physlinkid = tmp & 0x07; - prio = tmp >> 3; - - linkparam.priority = prio; - linkparam.phyid = physlinkid; - endpoint = cfpkt_extr_head_u8(pkt); - linkparam.endpoint = endpoint & 0x03; - - switch (serv) { - case CFCTRL_SRV_VEI: - case CFCTRL_SRV_DBG: - if (CFCTRL_ERR_BIT & cmdrsp) - break; - /* Link ID */ - linkid = cfpkt_extr_head_u8(pkt); - break; - case CFCTRL_SRV_VIDEO: - tmp = cfpkt_extr_head_u8(pkt); - linkparam.u.video.connid = tmp; - if (CFCTRL_ERR_BIT & cmdrsp) - break; - /* Link ID */ - linkid = cfpkt_extr_head_u8(pkt); - break; - - case CFCTRL_SRV_DATAGRAM: - linkparam.u.datagram.connid = cfpkt_extr_head_u32(pkt); - if (CFCTRL_ERR_BIT & cmdrsp) - break; - /* Link ID */ - linkid = cfpkt_extr_head_u8(pkt); - break; - case CFCTRL_SRV_RFM: - /* Construct a frame, convert - * DatagramConnectionID - * to network format long and copy it out... - */ - linkparam.u.rfm.connid = cfpkt_extr_head_u32(pkt); - cp = (u8 *) linkparam.u.rfm.volume; - for (tmp = cfpkt_extr_head_u8(pkt); - cfpkt_more(pkt) && tmp != '\0'; - tmp = cfpkt_extr_head_u8(pkt)) - *cp++ = tmp; - *cp = '\0'; - - if (CFCTRL_ERR_BIT & cmdrsp) - break; - /* Link ID */ - linkid = cfpkt_extr_head_u8(pkt); - - break; - case CFCTRL_SRV_UTIL: - /* Construct a frame, convert - * DatagramConnectionID - * to network format long and copy it out... - */ - /* Fifosize KB */ - linkparam.u.utility.fifosize_kb = cfpkt_extr_head_u16(pkt); - /* Fifosize bufs */ - linkparam.u.utility.fifosize_bufs = cfpkt_extr_head_u16(pkt); - /* name */ - cp = (u8 *) linkparam.u.utility.name; - caif_assert(sizeof(linkparam.u.utility.name) - >= UTILITY_NAME_LENGTH); - for (i = 0; i < UTILITY_NAME_LENGTH && cfpkt_more(pkt); i++) { - tmp = cfpkt_extr_head_u8(pkt); - *cp++ = tmp; - } - /* Length */ - len = cfpkt_extr_head_u8(pkt); - linkparam.u.utility.paramlen = len; - /* Param Data */ - cp = linkparam.u.utility.params; - while (cfpkt_more(pkt) && len--) { - tmp = cfpkt_extr_head_u8(pkt); - *cp++ = tmp; - } - if (CFCTRL_ERR_BIT & cmdrsp) - break; - /* Link ID */ - linkid = cfpkt_extr_head_u8(pkt); - /* Length */ - len = cfpkt_extr_head_u8(pkt); - /* Param Data */ - cfpkt_extr_head(pkt, NULL, len); - break; - default: - pr_warn("Request setup, invalid type (%d)\n", serv); - return -1; - } - - rsp.cmd = CFCTRL_CMD_LINK_SETUP; - rsp.param = linkparam; - spin_lock_bh(&cfctrl->info_list_lock); - req = cfctrl_remove_req(cfctrl, &rsp); - - if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) || - cfpkt_erroneous(pkt)) { - pr_err("Invalid O/E bit or parse error " - "on CAIF control channel\n"); - cfctrl->res.reject_rsp(cfctrl->serv.layer.up, 0, - req ? req->client_layer : NULL); - } else { - cfctrl->res.linksetup_rsp(cfctrl->serv.layer.up, linkid, - serv, physlinkid, - req ? req->client_layer : NULL); - } - - kfree(req); - - spin_unlock_bh(&cfctrl->info_list_lock); - - return 0; -} - -static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) -{ - u8 cmdrsp; - u8 cmd; - int ret = 0; - u8 linkid = 0; - struct cfctrl *cfctrl = container_obj(layer); - - cmdrsp = cfpkt_extr_head_u8(pkt); - cmd = cmdrsp & CFCTRL_CMD_MASK; - if (cmd != CFCTRL_CMD_LINK_ERR - && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp) - && CFCTRL_ERR_BIT != (CFCTRL_ERR_BIT & cmdrsp)) { - if (handle_loop(cfctrl, cmd, pkt) != 0) - cmdrsp |= CFCTRL_ERR_BIT; - } - - switch (cmd) { - case CFCTRL_CMD_LINK_SETUP: - ret = cfctrl_link_setup(cfctrl, pkt, cmdrsp); - break; - case CFCTRL_CMD_LINK_DESTROY: - linkid = cfpkt_extr_head_u8(pkt); - cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid); - break; - case CFCTRL_CMD_LINK_ERR: - pr_err("Frame Error Indication received\n"); - cfctrl->res.linkerror_ind(); - break; - case CFCTRL_CMD_ENUM: - cfctrl->res.enum_rsp(); - break; - case CFCTRL_CMD_SLEEP: - cfctrl->res.sleep_rsp(); - break; - case CFCTRL_CMD_WAKE: - cfctrl->res.wake_rsp(); - break; - case CFCTRL_CMD_LINK_RECONF: - cfctrl->res.restart_rsp(); - break; - case CFCTRL_CMD_RADIO_SET: - cfctrl->res.radioset_rsp(); - break; - default: - pr_err("Unrecognized Control Frame\n"); - ret = -1; - goto error; - } -error: - cfpkt_destroy(pkt); - return ret; -} - -static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid) -{ - struct cfctrl *this = container_obj(layr); - switch (ctrl) { - case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: - case CAIF_CTRLCMD_FLOW_OFF_IND: - spin_lock_bh(&this->info_list_lock); - if (!list_empty(&this->list)) - pr_debug("Received flow off in control layer\n"); - spin_unlock_bh(&this->info_list_lock); - break; - case _CAIF_CTRLCMD_PHYIF_DOWN_IND: { - struct cfctrl_request_info *p, *tmp; - - /* Find all connect request and report failure */ - spin_lock_bh(&this->info_list_lock); - list_for_each_entry_safe(p, tmp, &this->list, list) { - if (p->param.phyid == phyid) { - list_del(&p->list); - p->client_layer->ctrlcmd(p->client_layer, - CAIF_CTRLCMD_INIT_FAIL_RSP, - phyid); - kfree(p); - } - } - spin_unlock_bh(&this->info_list_lock); - break; - } - default: - break; - } -} - -#ifndef CAIF_NO_LOOP -static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt) -{ - static int last_linkid; - static int dec; - u8 linkid, linktype, tmp; - switch (cmd) { - case CFCTRL_CMD_LINK_SETUP: - spin_lock_bh(&ctrl->loop_linkid_lock); - if (!dec) { - for (linkid = last_linkid + 1; linkid < 254; linkid++) - if (!ctrl->loop_linkused[linkid]) - goto found; - } - dec = 1; - for (linkid = last_linkid - 1; linkid > 1; linkid--) - if (!ctrl->loop_linkused[linkid]) - goto found; - spin_unlock_bh(&ctrl->loop_linkid_lock); - return -1; -found: - if (linkid < 10) - dec = 0; - - if (!ctrl->loop_linkused[linkid]) - ctrl->loop_linkused[linkid] = 1; - - last_linkid = linkid; - - cfpkt_add_trail(pkt, &linkid, 1); - spin_unlock_bh(&ctrl->loop_linkid_lock); - cfpkt_peek_head(pkt, &linktype, 1); - if (linktype == CFCTRL_SRV_UTIL) { - tmp = 0x01; - cfpkt_add_trail(pkt, &tmp, 1); - cfpkt_add_trail(pkt, &tmp, 1); - } - break; - - case CFCTRL_CMD_LINK_DESTROY: - spin_lock_bh(&ctrl->loop_linkid_lock); - cfpkt_peek_head(pkt, &linkid, 1); - ctrl->loop_linkused[linkid] = 0; - spin_unlock_bh(&ctrl->loop_linkid_lock); - break; - default: - break; - } - return 0; -} -#endif diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c deleted file mode 100644 index 57ad3f82e004..000000000000 --- a/net/caif/cfdbgl.c +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include - -#define container_obj(layr) ((struct cfsrvl *) layr) - -static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt); - -struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info) -{ - struct cfsrvl *dbg = kzalloc_obj(struct cfsrvl, GFP_ATOMIC); - if (!dbg) - return NULL; - caif_assert(offsetof(struct cfsrvl, layer) == 0); - cfsrvl_init(dbg, channel_id, dev_info, false); - dbg->layer.receive = cfdbgl_receive; - dbg->layer.transmit = cfdbgl_transmit; - snprintf(dbg->layer.name, CAIF_LAYER_NAME_SZ, "dbg%d", channel_id); - return &dbg->layer; -} - -static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - return layr->up->receive(layr->up, pkt); -} - -static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - struct cfsrvl *service = container_obj(layr); - struct caif_payload_info *info; - int ret; - - if (!cfsrvl_ready(service, &ret)) { - cfpkt_destroy(pkt); - return ret; - } - - /* Add info for MUX-layer to route the packet out */ - info = cfpkt_info(pkt); - info->channel_id = service->layer.id; - info->dev_info = &service->dev_info; - - return layr->dn->transmit(layr->dn, pkt); -} diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c deleted file mode 100644 index c451ddd155a7..000000000000 --- a/net/caif/cfdgml.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include - - -#define container_obj(layr) ((struct cfsrvl *) layr) - -#define DGM_CMD_BIT 0x80 -#define DGM_FLOW_OFF 0x81 -#define DGM_FLOW_ON 0x80 -#define DGM_MTU 1500 - -static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt); - -struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info) -{ - struct cfsrvl *dgm = kzalloc_obj(struct cfsrvl, GFP_ATOMIC); - if (!dgm) - return NULL; - caif_assert(offsetof(struct cfsrvl, layer) == 0); - cfsrvl_init(dgm, channel_id, dev_info, true); - dgm->layer.receive = cfdgml_receive; - dgm->layer.transmit = cfdgml_transmit; - snprintf(dgm->layer.name, CAIF_LAYER_NAME_SZ, "dgm%d", channel_id); - return &dgm->layer; -} - -static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 cmd = -1; - u8 dgmhdr[3]; - int ret; - caif_assert(layr->up != NULL); - caif_assert(layr->receive != NULL); - caif_assert(layr->ctrlcmd != NULL); - - if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - - if ((cmd & DGM_CMD_BIT) == 0) { - if (cfpkt_extr_head(pkt, &dgmhdr, 3) < 0) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - ret = layr->up->receive(layr->up, pkt); - return ret; - } - - switch (cmd) { - case DGM_FLOW_OFF: /* FLOW OFF */ - layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0); - cfpkt_destroy(pkt); - return 0; - case DGM_FLOW_ON: /* FLOW ON */ - layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0); - cfpkt_destroy(pkt); - return 0; - default: - cfpkt_destroy(pkt); - pr_info("Unknown datagram control %d (0x%x)\n", cmd, cmd); - return -EPROTO; - } -} - -static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 packet_type; - u32 zero = 0; - struct caif_payload_info *info; - struct cfsrvl *service = container_obj(layr); - int ret; - - if (!cfsrvl_ready(service, &ret)) { - cfpkt_destroy(pkt); - return ret; - } - - /* STE Modem cannot handle more than 1500 bytes datagrams */ - if (cfpkt_getlen(pkt) > DGM_MTU) { - cfpkt_destroy(pkt); - return -EMSGSIZE; - } - - cfpkt_add_head(pkt, &zero, 3); - packet_type = 0x08; /* B9 set - UNCLASSIFIED */ - cfpkt_add_head(pkt, &packet_type, 1); - - /* Add info for MUX-layer to route the packet out. */ - info = cfpkt_info(pkt); - info->channel_id = service->layer.id; - /* To optimize alignment, we add up the size of CAIF header - * before payload. - */ - info->hdr_len = 4; - info->dev_info = &service->dev_info; - return layr->dn->transmit(layr->dn, pkt); -} diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c deleted file mode 100644 index 0f4979d89fcb..000000000000 --- a/net/caif/cffrml.c +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * CAIF Framing Layer. - * - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) container_of(layr, struct cffrml, layer) - -struct cffrml { - struct cflayer layer; - bool dofcs; /* !< FCS active */ - int __percpu *pcpu_refcnt; -}; - -static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt); -static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid); - -static u32 cffrml_rcv_error; -static u32 cffrml_rcv_checsum_error; -struct cflayer *cffrml_create(u16 phyid, bool use_fcs) -{ - struct cffrml *this = kzalloc_obj(struct cffrml, GFP_ATOMIC); - if (!this) - return NULL; - this->pcpu_refcnt = alloc_percpu(int); - if (this->pcpu_refcnt == NULL) { - kfree(this); - return NULL; - } - - caif_assert(offsetof(struct cffrml, layer) == 0); - - this->layer.receive = cffrml_receive; - this->layer.transmit = cffrml_transmit; - this->layer.ctrlcmd = cffrml_ctrlcmd; - snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "frm%d", phyid); - this->dofcs = use_fcs; - this->layer.id = phyid; - return (struct cflayer *) this; -} - -void cffrml_free(struct cflayer *layer) -{ - struct cffrml *this = container_obj(layer); - free_percpu(this->pcpu_refcnt); - kfree(layer); -} - -void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) -{ - this->up = up; -} - -void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn) -{ - this->dn = dn; -} - -static u16 cffrml_checksum(u16 chks, void *buf, u16 len) -{ - /* FIXME: FCS should be moved to glue in order to use OS-Specific - * solutions - */ - return crc_ccitt(chks, buf, len); -} - -static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - u16 tmp; - u16 len; - u16 hdrchks; - int pktchks; - struct cffrml *this; - this = container_obj(layr); - - cfpkt_extr_head(pkt, &tmp, 2); - len = le16_to_cpu(tmp); - - /* Subtract for FCS on length if FCS is not used. */ - if (!this->dofcs) { - if (len < 2) { - ++cffrml_rcv_error; - pr_err("Invalid frame length (%d)\n", len); - cfpkt_destroy(pkt); - return -EPROTO; - } - len -= 2; - } - - if (cfpkt_setlen(pkt, len) < 0) { - ++cffrml_rcv_error; - pr_err("Framing length error (%d)\n", len); - cfpkt_destroy(pkt); - return -EPROTO; - } - /* - * Don't do extract if FCS is false, rather do setlen - then we don't - * get a cache-miss. - */ - if (this->dofcs) { - cfpkt_extr_trail(pkt, &tmp, 2); - hdrchks = le16_to_cpu(tmp); - pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); - if (pktchks != hdrchks) { - cfpkt_add_trail(pkt, &tmp, 2); - ++cffrml_rcv_error; - ++cffrml_rcv_checsum_error; - pr_info("Frame checksum error (0x%x != 0x%x)\n", - hdrchks, pktchks); - return -EILSEQ; - } - } - if (cfpkt_erroneous(pkt)) { - ++cffrml_rcv_error; - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - - if (layr->up == NULL) { - pr_err("Layr up is missing!\n"); - cfpkt_destroy(pkt); - return -EINVAL; - } - - return layr->up->receive(layr->up, pkt); -} - -static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - u16 chks; - u16 len; - __le16 data; - - struct cffrml *this = container_obj(layr); - if (this->dofcs) { - chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); - data = cpu_to_le16(chks); - cfpkt_add_trail(pkt, &data, 2); - } else { - cfpkt_pad_trail(pkt, 2); - } - len = cfpkt_getlen(pkt); - data = cpu_to_le16(len); - cfpkt_add_head(pkt, &data, 2); - cfpkt_info(pkt)->hdr_len += 2; - if (cfpkt_erroneous(pkt)) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - - if (layr->dn == NULL) { - cfpkt_destroy(pkt); - return -ENODEV; - - } - return layr->dn->transmit(layr->dn, pkt); -} - -static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid) -{ - if (layr->up && layr->up->ctrlcmd) - layr->up->ctrlcmd(layr->up, ctrl, layr->id); -} - -void cffrml_put(struct cflayer *layr) -{ - struct cffrml *this = container_obj(layr); - if (layr != NULL && this->pcpu_refcnt != NULL) - this_cpu_dec(*this->pcpu_refcnt); -} - -void cffrml_hold(struct cflayer *layr) -{ - struct cffrml *this = container_obj(layr); - if (layr != NULL && this->pcpu_refcnt != NULL) - this_cpu_inc(*this->pcpu_refcnt); -} - -int cffrml_refcnt_read(struct cflayer *layr) -{ - int i, refcnt = 0; - struct cffrml *this = container_obj(layr); - for_each_possible_cpu(i) - refcnt += *per_cpu_ptr(this->pcpu_refcnt, i); - return refcnt; -} diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c deleted file mode 100644 index 77a1f31639b7..000000000000 --- a/net/caif/cfmuxl.c +++ /dev/null @@ -1,267 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) container_of(layr, struct cfmuxl, layer) - -#define CAIF_CTRL_CHANNEL 0 -#define UP_CACHE_SIZE 8 -#define DN_CACHE_SIZE 8 - -struct cfmuxl { - struct cflayer layer; - struct list_head srvl_list; - struct list_head frml_list; - struct cflayer *up_cache[UP_CACHE_SIZE]; - struct cflayer *dn_cache[DN_CACHE_SIZE]; - /* - * Set when inserting or removing downwards layers. - */ - spinlock_t transmit_lock; - - /* - * Set when inserting or removing upwards layers. - */ - spinlock_t receive_lock; - -}; - -static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt); -static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid); -static struct cflayer *get_up(struct cfmuxl *muxl, u16 id); - -struct cflayer *cfmuxl_create(void) -{ - struct cfmuxl *this = kzalloc_obj(struct cfmuxl, GFP_ATOMIC); - - if (!this) - return NULL; - this->layer.receive = cfmuxl_receive; - this->layer.transmit = cfmuxl_transmit; - this->layer.ctrlcmd = cfmuxl_ctrlcmd; - INIT_LIST_HEAD(&this->srvl_list); - INIT_LIST_HEAD(&this->frml_list); - spin_lock_init(&this->transmit_lock); - spin_lock_init(&this->receive_lock); - snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "mux"); - return &this->layer; -} - -int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid) -{ - struct cfmuxl *muxl = (struct cfmuxl *) layr; - - spin_lock_bh(&muxl->transmit_lock); - list_add_rcu(&dn->node, &muxl->frml_list); - spin_unlock_bh(&muxl->transmit_lock); - return 0; -} - -static struct cflayer *get_from_id(struct list_head *list, u16 id) -{ - struct cflayer *lyr; - list_for_each_entry_rcu(lyr, list, node) { - if (lyr->id == id) - return lyr; - } - - return NULL; -} - -int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid) -{ - struct cfmuxl *muxl = container_obj(layr); - struct cflayer *old; - - spin_lock_bh(&muxl->receive_lock); - - /* Two entries with same id is wrong, so remove old layer from mux */ - old = get_from_id(&muxl->srvl_list, linkid); - if (old != NULL) - list_del_rcu(&old->node); - - list_add_rcu(&up->node, &muxl->srvl_list); - spin_unlock_bh(&muxl->receive_lock); - - return 0; -} - -struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid) -{ - struct cfmuxl *muxl = container_obj(layr); - struct cflayer *dn; - int idx = phyid % DN_CACHE_SIZE; - - spin_lock_bh(&muxl->transmit_lock); - RCU_INIT_POINTER(muxl->dn_cache[idx], NULL); - dn = get_from_id(&muxl->frml_list, phyid); - if (dn == NULL) - goto out; - - list_del_rcu(&dn->node); - caif_assert(dn != NULL); -out: - spin_unlock_bh(&muxl->transmit_lock); - return dn; -} - -static struct cflayer *get_up(struct cfmuxl *muxl, u16 id) -{ - struct cflayer *up; - int idx = id % UP_CACHE_SIZE; - up = rcu_dereference(muxl->up_cache[idx]); - if (up == NULL || up->id != id) { - spin_lock_bh(&muxl->receive_lock); - up = get_from_id(&muxl->srvl_list, id); - rcu_assign_pointer(muxl->up_cache[idx], up); - spin_unlock_bh(&muxl->receive_lock); - } - return up; -} - -static struct cflayer *get_dn(struct cfmuxl *muxl, struct dev_info *dev_info) -{ - struct cflayer *dn; - int idx = dev_info->id % DN_CACHE_SIZE; - dn = rcu_dereference(muxl->dn_cache[idx]); - if (dn == NULL || dn->id != dev_info->id) { - spin_lock_bh(&muxl->transmit_lock); - dn = get_from_id(&muxl->frml_list, dev_info->id); - rcu_assign_pointer(muxl->dn_cache[idx], dn); - spin_unlock_bh(&muxl->transmit_lock); - } - return dn; -} - -struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id) -{ - struct cflayer *up; - struct cfmuxl *muxl = container_obj(layr); - int idx = id % UP_CACHE_SIZE; - - if (id == 0) { - pr_warn("Trying to remove control layer\n"); - return NULL; - } - - spin_lock_bh(&muxl->receive_lock); - up = get_from_id(&muxl->srvl_list, id); - if (up == NULL) - goto out; - - RCU_INIT_POINTER(muxl->up_cache[idx], NULL); - list_del_rcu(&up->node); -out: - spin_unlock_bh(&muxl->receive_lock); - return up; -} - -static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - int ret; - struct cfmuxl *muxl = container_obj(layr); - u8 id; - struct cflayer *up; - if (cfpkt_extr_head(pkt, &id, 1) < 0) { - pr_err("erroneous Caif Packet\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - rcu_read_lock(); - up = get_up(muxl, id); - - if (up == NULL) { - pr_debug("Received data on unknown link ID = %d (0x%x)" - " up == NULL", id, id); - cfpkt_destroy(pkt); - /* - * Don't return ERROR, since modem misbehaves and sends out - * flow on before linksetup response. - */ - - rcu_read_unlock(); - return /* CFGLU_EPROT; */ 0; - } - - /* We can't hold rcu_lock during receive, so take a ref count instead */ - cfsrvl_get(up); - rcu_read_unlock(); - - ret = up->receive(up, pkt); - - cfsrvl_put(up); - return ret; -} - -static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - struct cfmuxl *muxl = container_obj(layr); - int err; - u8 linkid; - struct cflayer *dn; - struct caif_payload_info *info = cfpkt_info(pkt); - BUG_ON(!info); - - rcu_read_lock(); - - dn = get_dn(muxl, info->dev_info); - if (dn == NULL) { - pr_debug("Send data on unknown phy ID = %d (0x%x)\n", - info->dev_info->id, info->dev_info->id); - rcu_read_unlock(); - cfpkt_destroy(pkt); - return -ENOTCONN; - } - - info->hdr_len += 1; - linkid = info->channel_id; - cfpkt_add_head(pkt, &linkid, 1); - - /* We can't hold rcu_lock during receive, so take a ref count instead */ - cffrml_hold(dn); - - rcu_read_unlock(); - - err = dn->transmit(dn, pkt); - - cffrml_put(dn); - return err; -} - -static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid) -{ - struct cfmuxl *muxl = container_obj(layr); - struct cflayer *layer; - - rcu_read_lock(); - list_for_each_entry_rcu(layer, &muxl->srvl_list, node) { - - if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd) { - - if ((ctrl == _CAIF_CTRLCMD_PHYIF_DOWN_IND || - ctrl == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND) && - layer->id != 0) - cfmuxl_remove_uplayer(layr, layer->id); - - /* NOTE: ctrlcmd is not allowed to block */ - layer->ctrlcmd(layer, ctrl, phyid); - } - } - rcu_read_unlock(); -} diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c deleted file mode 100644 index 96236d21b18e..000000000000 --- a/net/caif/cfpkt_skbuff.c +++ /dev/null @@ -1,373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include - -#define PKT_PREFIX 48 -#define PKT_POSTFIX 2 -#define PKT_LEN_WHEN_EXTENDING 128 -#define PKT_ERROR(pkt, errmsg) \ -do { \ - cfpkt_priv(pkt)->erronous = true; \ - skb_reset_tail_pointer(&pkt->skb); \ - pr_warn(errmsg); \ -} while (0) - -/* - * net/caif/ is generic and does not - * understand SKB, so we do this typecast - */ -struct cfpkt { - struct sk_buff skb; -}; - -/* Private data inside SKB */ -struct cfpkt_priv_data { - struct dev_info dev_info; - bool erronous; -}; - -static inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt) -{ - return (struct cfpkt_priv_data *) pkt->skb.cb; -} - -static inline bool is_erronous(struct cfpkt *pkt) -{ - return cfpkt_priv(pkt)->erronous; -} - -static inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt) -{ - return &pkt->skb; -} - -static inline struct cfpkt *skb_to_pkt(struct sk_buff *skb) -{ - return (struct cfpkt *) skb; -} - -struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt) -{ - struct cfpkt *pkt = skb_to_pkt(nativepkt); - cfpkt_priv(pkt)->erronous = false; - return pkt; -} -EXPORT_SYMBOL(cfpkt_fromnative); - -void *cfpkt_tonative(struct cfpkt *pkt) -{ - return (void *) pkt; -} -EXPORT_SYMBOL(cfpkt_tonative); - -static struct cfpkt *cfpkt_create_pfx(u16 len, u16 pfx) -{ - struct sk_buff *skb; - - skb = alloc_skb(len + pfx, GFP_ATOMIC); - if (unlikely(skb == NULL)) - return NULL; - - skb_reserve(skb, pfx); - return skb_to_pkt(skb); -} - -inline struct cfpkt *cfpkt_create(u16 len) -{ - return cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); -} - -void cfpkt_destroy(struct cfpkt *pkt) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - kfree_skb(skb); -} - -inline bool cfpkt_more(struct cfpkt *pkt) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - return skb->len > 0; -} - -int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - if (skb_headlen(skb) >= len) { - memcpy(data, skb->data, len); - return 0; - } - return !cfpkt_extr_head(pkt, data, len) && - !cfpkt_add_head(pkt, data, len); -} - -int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - u8 *from; - if (unlikely(is_erronous(pkt))) - return -EPROTO; - - if (unlikely(len > skb->len)) { - PKT_ERROR(pkt, "read beyond end of packet\n"); - return -EPROTO; - } - - if (unlikely(len > skb_headlen(skb))) { - if (unlikely(skb_linearize(skb) != 0)) { - PKT_ERROR(pkt, "linearize failed\n"); - return -EPROTO; - } - } - from = skb_pull(skb, len); - from -= len; - if (data) - memcpy(data, from, len); - return 0; -} -EXPORT_SYMBOL(cfpkt_extr_head); - -int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - u8 *data = dta; - u8 *from; - if (unlikely(is_erronous(pkt))) - return -EPROTO; - - if (unlikely(skb_linearize(skb) != 0)) { - PKT_ERROR(pkt, "linearize failed\n"); - return -EPROTO; - } - if (unlikely(skb->data + len > skb_tail_pointer(skb))) { - PKT_ERROR(pkt, "read beyond end of packet\n"); - return -EPROTO; - } - from = skb_tail_pointer(skb) - len; - skb_trim(skb, skb->len - len); - memcpy(data, from, len); - return 0; -} - -int cfpkt_pad_trail(struct cfpkt *pkt, u16 len) -{ - return cfpkt_add_body(pkt, NULL, len); -} - -int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - struct sk_buff *lastskb; - u8 *to; - u16 addlen = 0; - - - if (unlikely(is_erronous(pkt))) - return -EPROTO; - - lastskb = skb; - - /* Check whether we need to add space at the tail */ - if (unlikely(skb_tailroom(skb) < len)) { - if (likely(len < PKT_LEN_WHEN_EXTENDING)) - addlen = PKT_LEN_WHEN_EXTENDING; - else - addlen = len; - } - - /* Check whether we need to change the SKB before writing to the tail */ - if (unlikely((addlen > 0) || skb_cloned(skb) || skb_shared(skb))) { - - /* Make sure data is writable */ - if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) { - PKT_ERROR(pkt, "cow failed\n"); - return -EPROTO; - } - } - - /* All set to put the last SKB and optionally write data there. */ - to = pskb_put(skb, lastskb, len); - if (likely(data)) - memcpy(to, data, len); - return 0; -} - -inline int cfpkt_addbdy(struct cfpkt *pkt, u8 data) -{ - return cfpkt_add_body(pkt, &data, 1); -} - -int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - struct sk_buff *lastskb; - u8 *to; - const u8 *data = data2; - int ret; - if (unlikely(is_erronous(pkt))) - return -EPROTO; - if (unlikely(skb_headroom(skb) < len)) { - PKT_ERROR(pkt, "no headroom\n"); - return -EPROTO; - } - - /* Make sure data is writable */ - ret = skb_cow_data(skb, 0, &lastskb); - if (unlikely(ret < 0)) { - PKT_ERROR(pkt, "cow failed\n"); - return ret; - } - - to = skb_push(skb, len); - memcpy(to, data, len); - return 0; -} -EXPORT_SYMBOL(cfpkt_add_head); - -inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len) -{ - return cfpkt_add_body(pkt, data, len); -} - -inline u16 cfpkt_getlen(struct cfpkt *pkt) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - return skb->len; -} - -int cfpkt_iterate(struct cfpkt *pkt, - u16 (*iter_func)(u16, void *, u16), - u16 data) -{ - /* - * Don't care about the performance hit of linearizing, - * Checksum should not be used on high-speed interfaces anyway. - */ - if (unlikely(is_erronous(pkt))) - return -EPROTO; - if (unlikely(skb_linearize(&pkt->skb) != 0)) { - PKT_ERROR(pkt, "linearize failed\n"); - return -EPROTO; - } - return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt)); -} - -int cfpkt_setlen(struct cfpkt *pkt, u16 len) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - - - if (unlikely(is_erronous(pkt))) - return -EPROTO; - - if (likely(len <= skb->len)) { - if (unlikely(skb->data_len)) - ___pskb_trim(skb, len); - else - skb_trim(skb, len); - - return cfpkt_getlen(pkt); - } - - /* Need to expand SKB */ - if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len))) - PKT_ERROR(pkt, "skb_pad_trail failed\n"); - - return cfpkt_getlen(pkt); -} - -struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, - struct cfpkt *addpkt, - u16 expectlen) -{ - struct sk_buff *dst = pkt_to_skb(dstpkt); - struct sk_buff *add = pkt_to_skb(addpkt); - u16 addlen = skb_headlen(add); - u16 neededtailspace; - struct sk_buff *tmp; - u16 dstlen; - u16 createlen; - if (unlikely(is_erronous(dstpkt) || is_erronous(addpkt))) { - return dstpkt; - } - - neededtailspace = max(expectlen, addlen); - - if (dst->tail + neededtailspace > dst->end) { - /* Create a dumplicate of 'dst' with more tail space */ - struct cfpkt *tmppkt; - dstlen = skb_headlen(dst); - createlen = dstlen + neededtailspace; - tmppkt = cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX); - if (tmppkt == NULL) - return NULL; - tmp = pkt_to_skb(tmppkt); - skb_put_data(tmp, dst->data, dstlen); - cfpkt_destroy(dstpkt); - dst = tmp; - } - skb_put_data(dst, add->data, skb_headlen(add)); - cfpkt_destroy(addpkt); - return skb_to_pkt(dst); -} - -struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) -{ - struct sk_buff *skb2; - struct sk_buff *skb = pkt_to_skb(pkt); - struct cfpkt *tmppkt; - u8 *split = skb->data + pos; - u16 len2nd = skb_tail_pointer(skb) - split; - - if (unlikely(is_erronous(pkt))) - return NULL; - - if (skb->data + pos > skb_tail_pointer(skb)) { - PKT_ERROR(pkt, "trying to split beyond end of packet\n"); - return NULL; - } - - /* Create a new packet for the second part of the data */ - tmppkt = cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX, - PKT_PREFIX); - if (tmppkt == NULL) - return NULL; - skb2 = pkt_to_skb(tmppkt); - - - if (skb2 == NULL) - return NULL; - - skb_put_data(skb2, split, len2nd); - - /* Reduce the length of the original packet */ - skb_trim(skb, pos); - - skb2->priority = skb->priority; - return skb_to_pkt(skb2); -} - -bool cfpkt_erroneous(struct cfpkt *pkt) -{ - return cfpkt_priv(pkt)->erronous; -} - -struct caif_payload_info *cfpkt_info(struct cfpkt *pkt) -{ - return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb; -} -EXPORT_SYMBOL(cfpkt_info); - -void cfpkt_set_prio(struct cfpkt *pkt, int prio) -{ - pkt_to_skb(pkt)->priority = prio; -} -EXPORT_SYMBOL(cfpkt_set_prio); diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c deleted file mode 100644 index 93732ebbd1e2..000000000000 --- a/net/caif/cfrfml.c +++ /dev/null @@ -1,299 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) container_of(layr, struct cfrfml, serv.layer) -#define RFM_SEGMENTATION_BIT 0x01 -#define RFM_HEAD_SIZE 7 - -static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt); - -struct cfrfml { - struct cfsrvl serv; - struct cfpkt *incomplete_frm; - int fragment_size; - u8 seghead[6]; - u16 pdu_size; - /* Protects serialized processing of packets */ - spinlock_t sync; -}; - -static void cfrfml_release(struct cflayer *layer) -{ - struct cfsrvl *srvl = container_of(layer, struct cfsrvl, layer); - struct cfrfml *rfml = container_obj(&srvl->layer); - - if (rfml->incomplete_frm) - cfpkt_destroy(rfml->incomplete_frm); - - kfree(srvl); -} - -struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info, - int mtu_size) -{ - int tmp; - struct cfrfml *this = kzalloc_obj(struct cfrfml, GFP_ATOMIC); - - if (!this) - return NULL; - - cfsrvl_init(&this->serv, channel_id, dev_info, false); - this->serv.release = cfrfml_release; - this->serv.layer.receive = cfrfml_receive; - this->serv.layer.transmit = cfrfml_transmit; - - /* Round down to closest multiple of 16 */ - tmp = (mtu_size - RFM_HEAD_SIZE - 6) / 16; - tmp *= 16; - - this->fragment_size = tmp; - spin_lock_init(&this->sync); - snprintf(this->serv.layer.name, CAIF_LAYER_NAME_SZ, - "rfm%d", channel_id); - - return &this->serv.layer; -} - -static struct cfpkt *rfm_append(struct cfrfml *rfml, char *seghead, - struct cfpkt *pkt, int *err) -{ - struct cfpkt *tmppkt; - *err = -EPROTO; - /* n-th but not last segment */ - - if (cfpkt_extr_head(pkt, seghead, 6) < 0) - return NULL; - - /* Verify correct header */ - if (memcmp(seghead, rfml->seghead, 6) != 0) - return NULL; - - tmppkt = cfpkt_append(rfml->incomplete_frm, pkt, - rfml->pdu_size + RFM_HEAD_SIZE); - - /* If cfpkt_append failes input pkts are not freed */ - *err = -ENOMEM; - if (tmppkt == NULL) - return NULL; - - *err = 0; - return tmppkt; -} - -static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 tmp; - bool segmented; - int err; - u8 seghead[6]; - struct cfrfml *rfml; - struct cfpkt *tmppkt = NULL; - - caif_assert(layr->up != NULL); - caif_assert(layr->receive != NULL); - rfml = container_obj(layr); - spin_lock(&rfml->sync); - - err = -EPROTO; - if (cfpkt_extr_head(pkt, &tmp, 1) < 0) - goto out; - segmented = tmp & RFM_SEGMENTATION_BIT; - - if (segmented) { - if (rfml->incomplete_frm == NULL) { - /* Initial Segment */ - if (cfpkt_peek_head(pkt, rfml->seghead, 6) != 0) - goto out; - - rfml->pdu_size = get_unaligned_le16(rfml->seghead+4); - - if (cfpkt_erroneous(pkt)) - goto out; - rfml->incomplete_frm = pkt; - pkt = NULL; - } else { - - tmppkt = rfm_append(rfml, seghead, pkt, &err); - if (tmppkt == NULL) - goto out; - - if (cfpkt_erroneous(tmppkt)) - goto out; - - rfml->incomplete_frm = tmppkt; - - - if (cfpkt_erroneous(tmppkt)) - goto out; - } - err = 0; - goto out; - } - - if (rfml->incomplete_frm) { - - /* Last Segment */ - tmppkt = rfm_append(rfml, seghead, pkt, &err); - if (tmppkt == NULL) - goto out; - - if (cfpkt_erroneous(tmppkt)) - goto out; - - rfml->incomplete_frm = NULL; - pkt = tmppkt; - tmppkt = NULL; - - /* Verify that length is correct */ - err = -EPROTO; - if (rfml->pdu_size != cfpkt_getlen(pkt) - RFM_HEAD_SIZE + 1) - goto out; - } - - err = rfml->serv.layer.up->receive(rfml->serv.layer.up, pkt); - -out: - - if (err != 0) { - if (tmppkt) - cfpkt_destroy(tmppkt); - if (pkt) - cfpkt_destroy(pkt); - if (rfml->incomplete_frm) - cfpkt_destroy(rfml->incomplete_frm); - rfml->incomplete_frm = NULL; - - pr_info("Connection error %d triggered on RFM link\n", err); - - /* Trigger connection error upon failure.*/ - layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, - rfml->serv.dev_info.id); - } - spin_unlock(&rfml->sync); - - if (unlikely(err == -EAGAIN)) - /* It is not possible to recover after drop of a fragment */ - err = -EIO; - - return err; -} - - -static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt) -{ - caif_assert(cfpkt_getlen(pkt) < rfml->fragment_size + RFM_HEAD_SIZE); - - /* Add info for MUX-layer to route the packet out. */ - cfpkt_info(pkt)->channel_id = rfml->serv.layer.id; - - /* - * To optimize alignment, we add up the size of CAIF header before - * payload. - */ - cfpkt_info(pkt)->hdr_len = RFM_HEAD_SIZE; - cfpkt_info(pkt)->dev_info = &rfml->serv.dev_info; - - return rfml->serv.layer.dn->transmit(rfml->serv.layer.dn, pkt); -} - -static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - int err; - u8 seg; - u8 head[6]; - struct cfpkt *rearpkt = NULL; - struct cfpkt *frontpkt = pkt; - struct cfrfml *rfml = container_obj(layr); - - caif_assert(layr->dn != NULL); - caif_assert(layr->dn->transmit != NULL); - - if (!cfsrvl_ready(&rfml->serv, &err)) - goto out; - - err = -EPROTO; - if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1) - goto out; - - err = 0; - if (cfpkt_getlen(pkt) > rfml->fragment_size + RFM_HEAD_SIZE) - err = cfpkt_peek_head(pkt, head, 6); - - if (err != 0) - goto out; - - while (cfpkt_getlen(frontpkt) > rfml->fragment_size + RFM_HEAD_SIZE) { - - seg = 1; - err = -EPROTO; - - if (cfpkt_add_head(frontpkt, &seg, 1) < 0) - goto out; - /* - * On OOM error cfpkt_split returns NULL. - * - * NOTE: Segmented pdu is not correctly aligned. - * This has negative performance impact. - */ - - rearpkt = cfpkt_split(frontpkt, rfml->fragment_size); - if (rearpkt == NULL) - goto out; - - err = cfrfml_transmit_segment(rfml, frontpkt); - - if (err != 0) { - frontpkt = NULL; - goto out; - } - - frontpkt = rearpkt; - rearpkt = NULL; - - err = -EPROTO; - if (cfpkt_add_head(frontpkt, head, 6) < 0) - goto out; - - } - - seg = 0; - err = -EPROTO; - - if (cfpkt_add_head(frontpkt, &seg, 1) < 0) - goto out; - - err = cfrfml_transmit_segment(rfml, frontpkt); - - frontpkt = NULL; -out: - - if (err != 0) { - pr_info("Connection error %d triggered on RFM link\n", err); - /* Trigger connection error upon failure.*/ - - layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, - rfml->serv.dev_info.id); - - if (rearpkt) - cfpkt_destroy(rearpkt); - - if (frontpkt) - cfpkt_destroy(frontpkt); - } - - return err; -} diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c deleted file mode 100644 index faf78fb754e2..000000000000 --- a/net/caif/cfserl.c +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) ((struct cfserl *) layr) - -#define CFSERL_STX 0x02 -#define SERIAL_MINIUM_PACKET_SIZE 4 -#define SERIAL_MAX_FRAMESIZE 4096 -struct cfserl { - struct cflayer layer; - struct cfpkt *incomplete_frm; - /* Protects parallel processing of incoming packets */ - spinlock_t sync; - bool usestx; -}; - -static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt); -static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid); - -void cfserl_release(struct cflayer *layer) -{ - kfree(layer); -} - -struct cflayer *cfserl_create(int instance, bool use_stx) -{ - struct cfserl *this = kzalloc_obj(struct cfserl, GFP_ATOMIC); - if (!this) - return NULL; - caif_assert(offsetof(struct cfserl, layer) == 0); - this->layer.receive = cfserl_receive; - this->layer.transmit = cfserl_transmit; - this->layer.ctrlcmd = cfserl_ctrlcmd; - this->usestx = use_stx; - spin_lock_init(&this->sync); - snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "ser1"); - return &this->layer; -} - -static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) -{ - struct cfserl *layr = container_obj(l); - u16 pkt_len; - struct cfpkt *pkt = NULL; - struct cfpkt *tail_pkt = NULL; - u8 tmp8; - u16 tmp; - u8 stx = CFSERL_STX; - int ret; - u16 expectlen = 0; - - caif_assert(newpkt != NULL); - spin_lock(&layr->sync); - - if (layr->incomplete_frm != NULL) { - layr->incomplete_frm = - cfpkt_append(layr->incomplete_frm, newpkt, expectlen); - pkt = layr->incomplete_frm; - if (pkt == NULL) { - spin_unlock(&layr->sync); - return -ENOMEM; - } - } else { - pkt = newpkt; - } - layr->incomplete_frm = NULL; - - do { - /* Search for STX at start of pkt if STX is used */ - if (layr->usestx) { - cfpkt_extr_head(pkt, &tmp8, 1); - if (tmp8 != CFSERL_STX) { - while (cfpkt_more(pkt) - && tmp8 != CFSERL_STX) { - cfpkt_extr_head(pkt, &tmp8, 1); - } - if (!cfpkt_more(pkt)) { - cfpkt_destroy(pkt); - layr->incomplete_frm = NULL; - spin_unlock(&layr->sync); - return -EPROTO; - } - } - } - - pkt_len = cfpkt_getlen(pkt); - - /* - * pkt_len is the accumulated length of the packet data - * we have received so far. - * Exit if frame doesn't hold length. - */ - - if (pkt_len < 2) { - if (layr->usestx) - cfpkt_add_head(pkt, &stx, 1); - layr->incomplete_frm = pkt; - spin_unlock(&layr->sync); - return 0; - } - - /* - * Find length of frame. - * expectlen is the length we need for a full frame. - */ - cfpkt_peek_head(pkt, &tmp, 2); - expectlen = le16_to_cpu(tmp) + 2; - /* - * Frame error handling - */ - if (expectlen < SERIAL_MINIUM_PACKET_SIZE - || expectlen > SERIAL_MAX_FRAMESIZE) { - if (!layr->usestx) { - if (pkt != NULL) - cfpkt_destroy(pkt); - layr->incomplete_frm = NULL; - spin_unlock(&layr->sync); - return -EPROTO; - } - continue; - } - - if (pkt_len < expectlen) { - /* Too little received data */ - if (layr->usestx) - cfpkt_add_head(pkt, &stx, 1); - layr->incomplete_frm = pkt; - spin_unlock(&layr->sync); - return 0; - } - - /* - * Enough data for at least one frame. - * Split the frame, if too long - */ - if (pkt_len > expectlen) - tail_pkt = cfpkt_split(pkt, expectlen); - else - tail_pkt = NULL; - - /* Send the first part of packet upwards.*/ - spin_unlock(&layr->sync); - ret = layr->layer.up->receive(layr->layer.up, pkt); - spin_lock(&layr->sync); - if (ret == -EILSEQ) { - if (layr->usestx) { - if (tail_pkt != NULL) - pkt = cfpkt_append(pkt, tail_pkt, 0); - /* Start search for next STX if frame failed */ - continue; - } else { - cfpkt_destroy(pkt); - pkt = NULL; - } - } - - pkt = tail_pkt; - - } while (pkt != NULL); - - spin_unlock(&layr->sync); - return 0; -} - -static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt) -{ - struct cfserl *layr = container_obj(layer); - u8 tmp8 = CFSERL_STX; - if (layr->usestx) - cfpkt_add_head(newpkt, &tmp8, 1); - return layer->dn->transmit(layer->dn, newpkt); -} - -static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid) -{ - layr->up->ctrlcmd(layr->up, ctrl, phyid); -} diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c deleted file mode 100644 index d687fd0b4ed3..000000000000 --- a/net/caif/cfsrvl.c +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SRVL_CTRL_PKT_SIZE 1 -#define SRVL_FLOW_OFF 0x81 -#define SRVL_FLOW_ON 0x80 -#define SRVL_SET_PIN 0x82 - -#define container_obj(layr) container_of(layr, struct cfsrvl, layer) - -static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, - int phyid) -{ - struct cfsrvl *service = container_obj(layr); - - if (layr->up == NULL || layr->up->ctrlcmd == NULL) - return; - - switch (ctrl) { - case CAIF_CTRLCMD_INIT_RSP: - service->open = true; - layr->up->ctrlcmd(layr->up, ctrl, phyid); - break; - case CAIF_CTRLCMD_DEINIT_RSP: - case CAIF_CTRLCMD_INIT_FAIL_RSP: - service->open = false; - layr->up->ctrlcmd(layr->up, ctrl, phyid); - break; - case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: - if (phyid != service->dev_info.id) - break; - if (service->modem_flow_on) - layr->up->ctrlcmd(layr->up, - CAIF_CTRLCMD_FLOW_OFF_IND, phyid); - service->phy_flow_on = false; - break; - case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND: - if (phyid != service->dev_info.id) - return; - if (service->modem_flow_on) { - layr->up->ctrlcmd(layr->up, - CAIF_CTRLCMD_FLOW_ON_IND, - phyid); - } - service->phy_flow_on = true; - break; - case CAIF_CTRLCMD_FLOW_OFF_IND: - if (service->phy_flow_on) { - layr->up->ctrlcmd(layr->up, - CAIF_CTRLCMD_FLOW_OFF_IND, phyid); - } - service->modem_flow_on = false; - break; - case CAIF_CTRLCMD_FLOW_ON_IND: - if (service->phy_flow_on) { - layr->up->ctrlcmd(layr->up, - CAIF_CTRLCMD_FLOW_ON_IND, phyid); - } - service->modem_flow_on = true; - break; - case _CAIF_CTRLCMD_PHYIF_DOWN_IND: - /* In case interface is down, let's fake a remove shutdown */ - layr->up->ctrlcmd(layr->up, - CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid); - break; - case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND: - layr->up->ctrlcmd(layr->up, ctrl, phyid); - break; - default: - pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl); - /* We have both modem and phy flow on, send flow on */ - layr->up->ctrlcmd(layr->up, ctrl, phyid); - service->phy_flow_on = true; - break; - } -} - -static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) -{ - struct cfsrvl *service = container_obj(layr); - - caif_assert(layr != NULL); - caif_assert(layr->dn != NULL); - caif_assert(layr->dn->transmit != NULL); - - if (!service->supports_flowctrl) - return 0; - - switch (ctrl) { - case CAIF_MODEMCMD_FLOW_ON_REQ: - { - struct cfpkt *pkt; - struct caif_payload_info *info; - u8 flow_on = SRVL_FLOW_ON; - pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE); - if (!pkt) - return -ENOMEM; - - if (cfpkt_add_head(pkt, &flow_on, 1) < 0) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - info = cfpkt_info(pkt); - info->channel_id = service->layer.id; - info->hdr_len = 1; - info->dev_info = &service->dev_info; - cfpkt_set_prio(pkt, TC_PRIO_CONTROL); - return layr->dn->transmit(layr->dn, pkt); - } - case CAIF_MODEMCMD_FLOW_OFF_REQ: - { - struct cfpkt *pkt; - struct caif_payload_info *info; - u8 flow_off = SRVL_FLOW_OFF; - pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE); - if (!pkt) - return -ENOMEM; - - if (cfpkt_add_head(pkt, &flow_off, 1) < 0) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - info = cfpkt_info(pkt); - info->channel_id = service->layer.id; - info->hdr_len = 1; - info->dev_info = &service->dev_info; - cfpkt_set_prio(pkt, TC_PRIO_CONTROL); - return layr->dn->transmit(layr->dn, pkt); - } - default: - break; - } - return -EINVAL; -} - -static void cfsrvl_release(struct cflayer *layer) -{ - struct cfsrvl *service = container_of(layer, struct cfsrvl, layer); - kfree(service); -} - -void cfsrvl_init(struct cfsrvl *service, - u8 channel_id, - struct dev_info *dev_info, - bool supports_flowctrl) -{ - caif_assert(offsetof(struct cfsrvl, layer) == 0); - service->open = false; - service->modem_flow_on = true; - service->phy_flow_on = true; - service->layer.id = channel_id; - service->layer.ctrlcmd = cfservl_ctrlcmd; - service->layer.modemcmd = cfservl_modemcmd; - service->dev_info = *dev_info; - service->supports_flowctrl = supports_flowctrl; - service->release = cfsrvl_release; -} - -bool cfsrvl_ready(struct cfsrvl *service, int *err) -{ - if (!service->open) { - *err = -ENOTCONN; - return false; - } - return true; -} - -bool cfsrvl_phyid_match(struct cflayer *layer, int phyid) -{ - struct cfsrvl *servl = container_obj(layer); - return servl->dev_info.id == phyid; -} - -void caif_free_client(struct cflayer *adap_layer) -{ - struct cflayer *serv_layer; - struct cfsrvl *servl; - - if (!adap_layer) - return; - - serv_layer = adap_layer->dn; - if (!serv_layer) - return; - - layer_set_dn(adap_layer, NULL); - layer_set_up(serv_layer, NULL); - - servl = container_obj(serv_layer); - servl->release(&servl->layer); -} -EXPORT_SYMBOL(caif_free_client); - -void caif_client_register_refcnt(struct cflayer *adapt_layer, - void (*hold)(struct cflayer *lyr), - void (*put)(struct cflayer *lyr)) -{ - struct cfsrvl *service; - - if (WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL)) - return; - service = container_of(adapt_layer->dn, struct cfsrvl, layer); - service->hold = hold; - service->put = put; -} -EXPORT_SYMBOL(caif_client_register_refcnt); diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c deleted file mode 100644 index 5111090bb2c0..000000000000 --- a/net/caif/cfutill.c +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) ((struct cfsrvl *) layr) -#define UTIL_PAYLOAD 0x00 -#define UTIL_CMD_BIT 0x80 -#define UTIL_REMOTE_SHUTDOWN 0x82 -#define UTIL_FLOW_OFF 0x81 -#define UTIL_FLOW_ON 0x80 - -static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt); - -struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info) -{ - struct cfsrvl *util = kzalloc_obj(struct cfsrvl, GFP_ATOMIC); - if (!util) - return NULL; - caif_assert(offsetof(struct cfsrvl, layer) == 0); - cfsrvl_init(util, channel_id, dev_info, true); - util->layer.receive = cfutill_receive; - util->layer.transmit = cfutill_transmit; - snprintf(util->layer.name, CAIF_LAYER_NAME_SZ, "util1"); - return &util->layer; -} - -static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 cmd = -1; - struct cfsrvl *service = container_obj(layr); - caif_assert(layr != NULL); - caif_assert(layr->up != NULL); - caif_assert(layr->up->receive != NULL); - caif_assert(layr->up->ctrlcmd != NULL); - if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - - switch (cmd) { - case UTIL_PAYLOAD: - return layr->up->receive(layr->up, pkt); - case UTIL_FLOW_OFF: - layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0); - cfpkt_destroy(pkt); - return 0; - case UTIL_FLOW_ON: - layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0); - cfpkt_destroy(pkt); - return 0; - case UTIL_REMOTE_SHUTDOWN: /* Remote Shutdown Request */ - pr_err("REMOTE SHUTDOWN REQUEST RECEIVED\n"); - layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0); - service->open = false; - cfpkt_destroy(pkt); - return 0; - default: - cfpkt_destroy(pkt); - pr_warn("Unknown service control %d (0x%x)\n", cmd, cmd); - return -EPROTO; - } -} - -static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 zero = 0; - struct caif_payload_info *info; - int ret; - struct cfsrvl *service = container_obj(layr); - caif_assert(layr != NULL); - caif_assert(layr->dn != NULL); - caif_assert(layr->dn->transmit != NULL); - - if (!cfsrvl_ready(service, &ret)) { - cfpkt_destroy(pkt); - return ret; - } - - cfpkt_add_head(pkt, &zero, 1); - /* Add info for MUX-layer to route the packet out. */ - info = cfpkt_info(pkt); - info->channel_id = service->layer.id; - /* - * To optimize alignment, we add up the size of CAIF header before - * payload. - */ - info->hdr_len = 1; - info->dev_info = &service->dev_info; - return layr->dn->transmit(layr->dn, pkt); -} diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c deleted file mode 100644 index 53f844c49bbb..000000000000 --- a/net/caif/cfveil.c +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include - -#define VEI_PAYLOAD 0x00 -#define VEI_CMD_BIT 0x80 -#define VEI_FLOW_OFF 0x81 -#define VEI_FLOW_ON 0x80 -#define VEI_SET_PIN 0x82 - -#define container_obj(layr) container_of(layr, struct cfsrvl, layer) - -static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt); - -struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info) -{ - struct cfsrvl *vei = kzalloc_obj(struct cfsrvl, GFP_ATOMIC); - if (!vei) - return NULL; - caif_assert(offsetof(struct cfsrvl, layer) == 0); - cfsrvl_init(vei, channel_id, dev_info, true); - vei->layer.receive = cfvei_receive; - vei->layer.transmit = cfvei_transmit; - snprintf(vei->layer.name, CAIF_LAYER_NAME_SZ, "vei%d", channel_id); - return &vei->layer; -} - -static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 cmd; - int ret; - caif_assert(layr->up != NULL); - caif_assert(layr->receive != NULL); - caif_assert(layr->ctrlcmd != NULL); - - - if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - switch (cmd) { - case VEI_PAYLOAD: - ret = layr->up->receive(layr->up, pkt); - return ret; - case VEI_FLOW_OFF: - layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0); - cfpkt_destroy(pkt); - return 0; - case VEI_FLOW_ON: - layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0); - cfpkt_destroy(pkt); - return 0; - case VEI_SET_PIN: /* SET RS232 PIN */ - cfpkt_destroy(pkt); - return 0; - default: /* SET RS232 PIN */ - pr_warn("Unknown VEI control packet %d (0x%x)!\n", cmd, cmd); - cfpkt_destroy(pkt); - return -EPROTO; - } -} - -static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - u8 tmp = 0; - struct caif_payload_info *info; - int ret; - struct cfsrvl *service = container_obj(layr); - if (!cfsrvl_ready(service, &ret)) - goto err; - caif_assert(layr->dn != NULL); - caif_assert(layr->dn->transmit != NULL); - - if (cfpkt_add_head(pkt, &tmp, 1) < 0) { - pr_err("Packet is erroneous!\n"); - ret = -EPROTO; - goto err; - } - - /* Add info-> for MUX-layer to route the packet out. */ - info = cfpkt_info(pkt); - info->channel_id = service->layer.id; - info->hdr_len = 1; - info->dev_info = &service->dev_info; - return layr->dn->transmit(layr->dn, pkt); -err: - cfpkt_destroy(pkt); - return ret; -} diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c deleted file mode 100644 index 39e075b0a259..000000000000 --- a/net/caif/cfvidl.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include - -#define container_obj(layr) ((struct cfsrvl *) layr) - -static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt); -static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt); - -struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info) -{ - struct cfsrvl *vid = kzalloc_obj(struct cfsrvl, GFP_ATOMIC); - if (!vid) - return NULL; - caif_assert(offsetof(struct cfsrvl, layer) == 0); - - cfsrvl_init(vid, channel_id, dev_info, false); - vid->layer.receive = cfvidl_receive; - vid->layer.transmit = cfvidl_transmit; - snprintf(vid->layer.name, CAIF_LAYER_NAME_SZ, "vid1"); - return &vid->layer; -} - -static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt) -{ - u32 videoheader; - if (cfpkt_extr_head(pkt, &videoheader, 4) < 0) { - pr_err("Packet is erroneous!\n"); - cfpkt_destroy(pkt); - return -EPROTO; - } - return layr->up->receive(layr->up, pkt); -} - -static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt) -{ - struct cfsrvl *service = container_obj(layr); - struct caif_payload_info *info; - u32 videoheader = 0; - int ret; - - if (!cfsrvl_ready(service, &ret)) { - cfpkt_destroy(pkt); - return ret; - } - - cfpkt_add_head(pkt, &videoheader, 4); - /* Add info for MUX-layer to route the packet out */ - info = cfpkt_info(pkt); - info->channel_id = service->layer.id; - info->dev_info = &service->dev_info; - return layr->dn->transmit(layr->dn, pkt); -} diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c deleted file mode 100644 index fa6a3c2634a8..000000000000 --- a/net/caif/chnl_net.c +++ /dev/null @@ -1,531 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson AB 2010 - * Authors: Sjur Brendeland - * Daniel Martensson - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* GPRS PDP connection has MTU to 1500 */ -#define GPRS_PDP_MTU 1500 -/* 5 sec. connect timeout */ -#define CONNECT_TIMEOUT (5 * HZ) -#define CAIF_NET_DEFAULT_QUEUE_LEN 500 -#define UNDEF_CONNID 0xffffffff - -/*This list is protected by the rtnl lock. */ -static LIST_HEAD(chnl_net_list); - -MODULE_DESCRIPTION("ST-Ericsson CAIF modem protocol GPRS network device"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_RTNL_LINK("caif"); - -enum caif_states { - CAIF_CONNECTED = 1, - CAIF_CONNECTING, - CAIF_DISCONNECTED, - CAIF_SHUTDOWN -}; - -struct chnl_net { - struct cflayer chnl; - struct caif_connect_request conn_req; - struct list_head list_field; - struct net_device *netdev; - wait_queue_head_t netmgmt_wq; - /* Flow status to remember and control the transmission. */ - bool flowenabled; - enum caif_states state; -}; - -static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) -{ - struct sk_buff *skb; - struct chnl_net *priv; - int pktlen; - const u8 *ip_version; - u8 buf; - - priv = container_of(layr, struct chnl_net, chnl); - - skb = (struct sk_buff *) cfpkt_tonative(pkt); - - /* Get length of CAIF packet. */ - pktlen = skb->len; - - /* Pass some minimum information and - * send the packet to the net stack. - */ - skb->dev = priv->netdev; - - /* check the version of IP */ - ip_version = skb_header_pointer(skb, 0, 1, &buf); - if (!ip_version) { - kfree_skb(skb); - return -EINVAL; - } - - switch (*ip_version >> 4) { - case 4: - skb->protocol = htons(ETH_P_IP); - break; - case 6: - skb->protocol = htons(ETH_P_IPV6); - break; - default: - kfree_skb(skb); - priv->netdev->stats.rx_errors++; - return -EINVAL; - } - - /* If we change the header in loop mode, the checksum is corrupted. */ - if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; - - netif_rx(skb); - - /* Update statistics. */ - priv->netdev->stats.rx_packets++; - priv->netdev->stats.rx_bytes += pktlen; - - return 0; -} - -static int delete_device(struct chnl_net *dev) -{ - ASSERT_RTNL(); - if (dev->netdev) - unregister_netdevice(dev->netdev); - return 0; -} - -static void close_work(struct work_struct *work) -{ - struct chnl_net *dev = NULL; - struct list_head *list_node; - struct list_head *_tmp; - - rtnl_lock(); - list_for_each_safe(list_node, _tmp, &chnl_net_list) { - dev = list_entry(list_node, struct chnl_net, list_field); - if (dev->state == CAIF_SHUTDOWN) - dev_close(dev->netdev); - } - rtnl_unlock(); -} -static DECLARE_WORK(close_worker, close_work); - -static void chnl_hold(struct cflayer *lyr) -{ - struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); - dev_hold(priv->netdev); -} - -static void chnl_put(struct cflayer *lyr) -{ - struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); - dev_put(priv->netdev); -} - -static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, - int phyid) -{ - struct chnl_net *priv = container_of(layr, struct chnl_net, chnl); - pr_debug("NET flowctrl func called flow: %s\n", - flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" : - flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" : - flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" : - flow == CAIF_CTRLCMD_DEINIT_RSP ? "CLOSE/DEINIT" : - flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "OPEN_FAIL" : - flow == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ? - "REMOTE_SHUTDOWN" : "UNKNOWN CTRL COMMAND"); - - - - switch (flow) { - case CAIF_CTRLCMD_FLOW_OFF_IND: - priv->flowenabled = false; - netif_stop_queue(priv->netdev); - break; - case CAIF_CTRLCMD_DEINIT_RSP: - priv->state = CAIF_DISCONNECTED; - break; - case CAIF_CTRLCMD_INIT_FAIL_RSP: - priv->state = CAIF_DISCONNECTED; - wake_up_interruptible(&priv->netmgmt_wq); - break; - case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND: - priv->state = CAIF_SHUTDOWN; - netif_tx_disable(priv->netdev); - schedule_work(&close_worker); - break; - case CAIF_CTRLCMD_FLOW_ON_IND: - priv->flowenabled = true; - netif_wake_queue(priv->netdev); - break; - case CAIF_CTRLCMD_INIT_RSP: - caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put); - priv->state = CAIF_CONNECTED; - priv->flowenabled = true; - netif_wake_queue(priv->netdev); - wake_up_interruptible(&priv->netmgmt_wq); - break; - default: - break; - } -} - -static netdev_tx_t chnl_net_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct chnl_net *priv; - struct cfpkt *pkt = NULL; - int len; - int result = -1; - /* Get our private data. */ - priv = netdev_priv(dev); - - if (skb->len > priv->netdev->mtu) { - pr_warn("Size of skb exceeded MTU\n"); - kfree_skb(skb); - dev->stats.tx_errors++; - return NETDEV_TX_OK; - } - - if (!priv->flowenabled) { - pr_debug("dropping packets flow off\n"); - kfree_skb(skb); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP) - swap(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr); - - /* Store original SKB length. */ - len = skb->len; - - pkt = cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb); - - /* Send the packet down the stack. */ - result = priv->chnl.dn->transmit(priv->chnl.dn, pkt); - if (result) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - /* Update statistics. */ - dev->stats.tx_packets++; - dev->stats.tx_bytes += len; - - return NETDEV_TX_OK; -} - -static int chnl_net_open(struct net_device *dev) -{ - struct chnl_net *priv = NULL; - int result = -1; - int llifindex, headroom, tailroom, mtu; - struct net_device *lldev; - ASSERT_RTNL(); - priv = netdev_priv(dev); - if (!priv) { - pr_debug("chnl_net_open: no priv\n"); - return -ENODEV; - } - - if (priv->state != CAIF_CONNECTING) { - priv->state = CAIF_CONNECTING; - result = caif_connect_client(dev_net(dev), &priv->conn_req, - &priv->chnl, &llifindex, - &headroom, &tailroom); - if (result != 0) { - pr_debug("err: " - "Unable to register and open device," - " Err:%d\n", - result); - goto error; - } - - lldev = __dev_get_by_index(dev_net(dev), llifindex); - - if (lldev == NULL) { - pr_debug("no interface?\n"); - result = -ENODEV; - goto error; - } - - dev->needed_tailroom = tailroom + lldev->needed_tailroom; - dev->hard_header_len = headroom + lldev->hard_header_len + - lldev->needed_tailroom; - - /* - * MTU, head-room etc is not know before we have a - * CAIF link layer device available. MTU calculation may - * override initial RTNL configuration. - * MTU is minimum of current mtu, link layer mtu pluss - * CAIF head and tail, and PDP GPRS contexts max MTU. - */ - mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom)); - mtu = min_t(int, GPRS_PDP_MTU, mtu); - dev_set_mtu(dev, mtu); - - if (mtu < 100) { - pr_warn("CAIF Interface MTU too small (%d)\n", mtu); - result = -ENODEV; - goto error; - } - } - - rtnl_unlock(); /* Release RTNL lock during connect wait */ - - result = wait_event_interruptible_timeout(priv->netmgmt_wq, - priv->state != CAIF_CONNECTING, - CONNECT_TIMEOUT); - - rtnl_lock(); - - if (result == -ERESTARTSYS) { - pr_debug("wait_event_interruptible woken by a signal\n"); - result = -ERESTARTSYS; - goto error; - } - - if (result == 0) { - pr_debug("connect timeout\n"); - result = -ETIMEDOUT; - goto error; - } - - if (priv->state != CAIF_CONNECTED) { - pr_debug("connect failed\n"); - result = -ECONNREFUSED; - goto error; - } - pr_debug("CAIF Netdevice connected\n"); - return 0; - -error: - caif_disconnect_client(dev_net(dev), &priv->chnl); - priv->state = CAIF_DISCONNECTED; - pr_debug("state disconnected\n"); - return result; - -} - -static int chnl_net_stop(struct net_device *dev) -{ - struct chnl_net *priv; - - ASSERT_RTNL(); - priv = netdev_priv(dev); - priv->state = CAIF_DISCONNECTED; - caif_disconnect_client(dev_net(dev), &priv->chnl); - return 0; -} - -static int chnl_net_init(struct net_device *dev) -{ - struct chnl_net *priv; - ASSERT_RTNL(); - priv = netdev_priv(dev); - INIT_LIST_HEAD(&priv->list_field); - return 0; -} - -static void chnl_net_uninit(struct net_device *dev) -{ - struct chnl_net *priv; - ASSERT_RTNL(); - priv = netdev_priv(dev); - list_del_init(&priv->list_field); -} - -static const struct net_device_ops netdev_ops = { - .ndo_open = chnl_net_open, - .ndo_stop = chnl_net_stop, - .ndo_init = chnl_net_init, - .ndo_uninit = chnl_net_uninit, - .ndo_start_xmit = chnl_net_start_xmit, -}; - -static void chnl_net_destructor(struct net_device *dev) -{ - struct chnl_net *priv = netdev_priv(dev); - caif_free_client(&priv->chnl); -} - -static void ipcaif_net_setup(struct net_device *dev) -{ - struct chnl_net *priv; - dev->netdev_ops = &netdev_ops; - dev->needs_free_netdev = true; - dev->priv_destructor = chnl_net_destructor; - dev->flags |= IFF_NOARP; - dev->flags |= IFF_POINTOPOINT; - dev->mtu = GPRS_PDP_MTU; - dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN; - - priv = netdev_priv(dev); - priv->chnl.receive = chnl_recv_cb; - priv->chnl.ctrlcmd = chnl_flowctrl_cb; - priv->netdev = dev; - priv->conn_req.protocol = CAIFPROTO_DATAGRAM; - priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW; - priv->conn_req.priority = CAIF_PRIO_LOW; - /* Insert illegal value */ - priv->conn_req.sockaddr.u.dgm.connection_id = UNDEF_CONNID; - priv->flowenabled = false; - - init_waitqueue_head(&priv->netmgmt_wq); -} - - -static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev) -{ - struct chnl_net *priv; - u8 loop; - priv = netdev_priv(dev); - if (nla_put_u32(skb, IFLA_CAIF_IPV4_CONNID, - priv->conn_req.sockaddr.u.dgm.connection_id) || - nla_put_u32(skb, IFLA_CAIF_IPV6_CONNID, - priv->conn_req.sockaddr.u.dgm.connection_id)) - goto nla_put_failure; - loop = priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP; - if (nla_put_u8(skb, IFLA_CAIF_LOOPBACK, loop)) - goto nla_put_failure; - return 0; -nla_put_failure: - return -EMSGSIZE; - -} - -static void caif_netlink_parms(struct nlattr *data[], - struct caif_connect_request *conn_req) -{ - if (!data) { - pr_warn("no params data found\n"); - return; - } - if (data[IFLA_CAIF_IPV4_CONNID]) - conn_req->sockaddr.u.dgm.connection_id = - nla_get_u32(data[IFLA_CAIF_IPV4_CONNID]); - if (data[IFLA_CAIF_IPV6_CONNID]) - conn_req->sockaddr.u.dgm.connection_id = - nla_get_u32(data[IFLA_CAIF_IPV6_CONNID]); - if (data[IFLA_CAIF_LOOPBACK]) { - if (nla_get_u8(data[IFLA_CAIF_LOOPBACK])) - conn_req->protocol = CAIFPROTO_DATAGRAM_LOOP; - else - conn_req->protocol = CAIFPROTO_DATAGRAM; - } -} - -static int ipcaif_newlink(struct net_device *dev, - struct rtnl_newlink_params *params, - struct netlink_ext_ack *extack) -{ - struct nlattr **data = params->data; - int ret; - struct chnl_net *caifdev; - ASSERT_RTNL(); - caifdev = netdev_priv(dev); - caif_netlink_parms(data, &caifdev->conn_req); - - ret = register_netdevice(dev); - if (ret) - pr_warn("device rtml registration failed\n"); - else - list_add(&caifdev->list_field, &chnl_net_list); - - /* Use ifindex as connection id, and use loopback channel default. */ - if (caifdev->conn_req.sockaddr.u.dgm.connection_id == UNDEF_CONNID) { - caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex; - caifdev->conn_req.protocol = CAIFPROTO_DATAGRAM_LOOP; - } - return ret; -} - -static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[], - struct nlattr *data[], - struct netlink_ext_ack *extack) -{ - struct chnl_net *caifdev; - ASSERT_RTNL(); - caifdev = netdev_priv(dev); - caif_netlink_parms(data, &caifdev->conn_req); - netdev_state_change(dev); - return 0; -} - -static size_t ipcaif_get_size(const struct net_device *dev) -{ - return - /* IFLA_CAIF_IPV4_CONNID */ - nla_total_size(4) + - /* IFLA_CAIF_IPV6_CONNID */ - nla_total_size(4) + - /* IFLA_CAIF_LOOPBACK */ - nla_total_size(2) + - 0; -} - -static const struct nla_policy ipcaif_policy[IFLA_CAIF_MAX + 1] = { - [IFLA_CAIF_IPV4_CONNID] = { .type = NLA_U32 }, - [IFLA_CAIF_IPV6_CONNID] = { .type = NLA_U32 }, - [IFLA_CAIF_LOOPBACK] = { .type = NLA_U8 } -}; - - -static struct rtnl_link_ops ipcaif_link_ops __read_mostly = { - .kind = "caif", - .priv_size = sizeof(struct chnl_net), - .setup = ipcaif_net_setup, - .maxtype = IFLA_CAIF_MAX, - .policy = ipcaif_policy, - .newlink = ipcaif_newlink, - .changelink = ipcaif_changelink, - .get_size = ipcaif_get_size, - .fill_info = ipcaif_fill_info, - -}; - -static int __init chnl_init_module(void) -{ - return rtnl_link_register(&ipcaif_link_ops); -} - -static void __exit chnl_exit_module(void) -{ - struct chnl_net *dev = NULL; - struct list_head *list_node; - struct list_head *_tmp; - rtnl_link_unregister(&ipcaif_link_ops); - rtnl_lock(); - list_for_each_safe(list_node, _tmp, &chnl_net_list) { - dev = list_entry(list_node, struct chnl_net, list_field); - list_del_init(list_node); - delete_device(dev); - } - rtnl_unlock(); -} - -module_init(chnl_init_module); -module_exit(chnl_exit_module); diff --git a/net/core/dev.c b/net/core/dev.c index d426c1beeb76..06c195906231 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/net/ipv4/arp.c b/net/ipv4/arp.c index 51d70180e1cc..d409f606aec0 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -109,7 +109,6 @@ #include #include #include -#include #include #include diff --git a/net/netrom/Makefile b/net/netrom/Makefile deleted file mode 100644 index 603e36c9af2e..000000000000 --- a/net/netrom/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the Linux NET/ROM layer. -# - -obj-$(CONFIG_NETROM) += netrom.o - -netrom-y := af_netrom.o nr_dev.o nr_in.o nr_loopback.o \ - nr_out.o nr_route.o nr_subr.o nr_timer.o -netrom-$(CONFIG_SYSCTL) += sysctl_net_netrom.o diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c deleted file mode 100644 index 5fc54836dfa8..000000000000 --- a/net/netrom/af_netrom.c +++ /dev/null @@ -1,1536 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk) - */ -#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 /* For TIOCINQ/OUTQ */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int nr_ndevs = 4; - -int sysctl_netrom_default_path_quality = NR_DEFAULT_QUAL; -int sysctl_netrom_obsolescence_count_initialiser = NR_DEFAULT_OBS; -int sysctl_netrom_network_ttl_initialiser = NR_DEFAULT_TTL; -int sysctl_netrom_transport_timeout = NR_DEFAULT_T1; -int sysctl_netrom_transport_maximum_tries = NR_DEFAULT_N2; -int sysctl_netrom_transport_acknowledge_delay = NR_DEFAULT_T2; -int sysctl_netrom_transport_busy_delay = NR_DEFAULT_T4; -int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW; -int sysctl_netrom_transport_no_activity_timeout = NR_DEFAULT_IDLE; -int sysctl_netrom_routing_control = NR_DEFAULT_ROUTING; -int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS; -int sysctl_netrom_reset_circuit = NR_DEFAULT_RESET; - -static unsigned short circuit = 0x101; - -static HLIST_HEAD(nr_list); -static DEFINE_SPINLOCK(nr_list_lock); - -static const struct proto_ops nr_proto_ops; - -/* - * NETROM network devices are virtual network devices encapsulating NETROM - * frames into AX.25 which will be sent through an AX.25 device, so form a - * special "super class" of normal net devices; split their locks off into a - * separate class since they always nest. - */ -static struct lock_class_key nr_netdev_xmit_lock_key; -static struct lock_class_key nr_netdev_addr_lock_key; - -static void nr_set_lockdep_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, &nr_netdev_xmit_lock_key); -} - -static void nr_set_lockdep_key(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, &nr_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL); -} - -/* - * Socket removal during an interrupt is now safe. - */ -static void nr_remove_socket(struct sock *sk) -{ - spin_lock_bh(&nr_list_lock); - sk_del_node_init(sk); - spin_unlock_bh(&nr_list_lock); -} - -/* - * Kill all bound sockets on a dropped device. - */ -static void nr_kill_by_device(struct net_device *dev) -{ - struct sock *s; - - spin_lock_bh(&nr_list_lock); - sk_for_each(s, &nr_list) - if (nr_sk(s)->device == dev) - nr_disconnect(s, ENETUNREACH); - spin_unlock_bh(&nr_list_lock); -} - -/* - * Handle device status changes. - */ -static int nr_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_DOWN) - return NOTIFY_DONE; - - nr_kill_by_device(dev); - nr_rt_device_down(dev); - - return NOTIFY_DONE; -} - -/* - * Add a socket to the bound sockets list. - */ -static void nr_insert_socket(struct sock *sk) -{ - spin_lock_bh(&nr_list_lock); - sk_add_node(sk, &nr_list); - spin_unlock_bh(&nr_list_lock); -} - -/* - * Find a socket that wants to accept the Connect Request we just - * received. - */ -static struct sock *nr_find_listener(ax25_address *addr) -{ - struct sock *s; - - spin_lock_bh(&nr_list_lock); - sk_for_each(s, &nr_list) - if (!ax25cmp(&nr_sk(s)->source_addr, addr) && - s->sk_state == TCP_LISTEN) { - sock_hold(s); - goto found; - } - s = NULL; -found: - spin_unlock_bh(&nr_list_lock); - return s; -} - -/* - * Find a connected NET/ROM socket given my circuit IDs. - */ -static struct sock *nr_find_socket(unsigned char index, unsigned char id) -{ - struct sock *s; - - spin_lock_bh(&nr_list_lock); - sk_for_each(s, &nr_list) { - struct nr_sock *nr = nr_sk(s); - - if (nr->my_index == index && nr->my_id == id) { - sock_hold(s); - goto found; - } - } - s = NULL; -found: - spin_unlock_bh(&nr_list_lock); - return s; -} - -/* - * Find a connected NET/ROM socket given their circuit IDs. - */ -static struct sock *nr_find_peer(unsigned char index, unsigned char id, - ax25_address *dest) -{ - struct sock *s; - - spin_lock_bh(&nr_list_lock); - sk_for_each(s, &nr_list) { - struct nr_sock *nr = nr_sk(s); - - if (nr->your_index == index && nr->your_id == id && - !ax25cmp(&nr->dest_addr, dest)) { - sock_hold(s); - goto found; - } - } - s = NULL; -found: - spin_unlock_bh(&nr_list_lock); - return s; -} - -/* - * Find next free circuit ID. - */ -static unsigned short nr_find_next_circuit(void) -{ - unsigned short id = circuit; - unsigned char i, j; - struct sock *sk; - - for (;;) { - i = id / 256; - j = id % 256; - - if (i != 0 && j != 0) { - if ((sk=nr_find_socket(i, j)) == NULL) - break; - sock_put(sk); - } - - id++; - } - - return id; -} - -/* - * Deferred destroy. - */ -void nr_destroy_socket(struct sock *); - -/* - * Handler for deferred kills. - */ -static void nr_destroy_timer(struct timer_list *t) -{ - struct sock *sk = timer_container_of(sk, t, sk_timer); - bh_lock_sock(sk); - sock_hold(sk); - nr_destroy_socket(sk); - bh_unlock_sock(sk); - sock_put(sk); -} - -/* - * This is called from user mode and the timers. Thus it protects itself - * against interrupt users but doesn't worry about being called during - * work. Once it is removed from the queue no interrupt or bottom half - * will touch it and we are (fairly 8-) ) safe. - */ -void nr_destroy_socket(struct sock *sk) -{ - struct sk_buff *skb; - - nr_remove_socket(sk); - - nr_stop_heartbeat(sk); - nr_stop_t1timer(sk); - nr_stop_t2timer(sk); - nr_stop_t4timer(sk); - nr_stop_idletimer(sk); - - nr_clear_queues(sk); /* Flush the queues */ - - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { - if (skb->sk != sk) { /* A pending connection */ - /* Queue the unaccepted socket for death */ - sock_set_flag(skb->sk, SOCK_DEAD); - nr_start_heartbeat(skb->sk); - nr_sk(skb->sk)->state = NR_STATE_0; - } - - kfree_skb(skb); - } - - if (sk_has_allocations(sk)) { - /* Defer: outstanding buffers */ - sk->sk_timer.function = nr_destroy_timer; - sk->sk_timer.expires = jiffies + 2 * HZ; - add_timer(&sk->sk_timer); - } else - sock_put(sk); -} - -/* - * Handling for system calls applied via the various interfaces to a - * NET/ROM socket object. - */ - -static int nr_setsockopt(struct socket *sock, int level, int optname, - sockptr_t optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - struct nr_sock *nr = nr_sk(sk); - unsigned int opt; - - if (level != SOL_NETROM) - return -ENOPROTOOPT; - - if (optlen < sizeof(unsigned int)) - return -EINVAL; - - if (copy_from_sockptr(&opt, optval, sizeof(opt))) - return -EFAULT; - - switch (optname) { - case NETROM_T1: - if (opt < 1 || opt > UINT_MAX / HZ) - return -EINVAL; - nr->t1 = opt * HZ; - return 0; - - case NETROM_T2: - if (opt < 1 || opt > UINT_MAX / HZ) - return -EINVAL; - nr->t2 = opt * HZ; - return 0; - - case NETROM_N2: - if (opt < 1 || opt > 31) - return -EINVAL; - nr->n2 = opt; - return 0; - - case NETROM_T4: - if (opt < 1 || opt > UINT_MAX / HZ) - return -EINVAL; - nr->t4 = opt * HZ; - return 0; - - case NETROM_IDLE: - if (opt > UINT_MAX / (60 * HZ)) - return -EINVAL; - nr->idle = opt * 60 * HZ; - return 0; - - default: - return -ENOPROTOOPT; - } -} - -static int nr_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - struct nr_sock *nr = nr_sk(sk); - int val = 0; - int len; - - if (level != SOL_NETROM) - return -ENOPROTOOPT; - - if (get_user(len, optlen)) - return -EFAULT; - - if (len < 0) - return -EINVAL; - - switch (optname) { - case NETROM_T1: - val = nr->t1 / HZ; - break; - - case NETROM_T2: - val = nr->t2 / HZ; - break; - - case NETROM_N2: - val = nr->n2; - break; - - case NETROM_T4: - val = nr->t4 / HZ; - break; - - case NETROM_IDLE: - val = nr->idle / (60 * HZ); - break; - - default: - return -ENOPROTOOPT; - } - - len = min_t(unsigned int, len, sizeof(int)); - - if (put_user(len, optlen)) - return -EFAULT; - - return copy_to_user(optval, &val, len) ? -EFAULT : 0; -} - -static int nr_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - - lock_sock(sk); - if (sock->state != SS_UNCONNECTED) { - release_sock(sk); - return -EINVAL; - } - - if (sk->sk_state != TCP_LISTEN) { - memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN); - sk->sk_max_ack_backlog = backlog; - sk->sk_state = TCP_LISTEN; - release_sock(sk); - return 0; - } - release_sock(sk); - - return -EOPNOTSUPP; -} - -static struct proto nr_proto = { - .name = "NETROM", - .owner = THIS_MODULE, - .obj_size = sizeof(struct nr_sock), -}; - -static int nr_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct sock *sk; - struct nr_sock *nr; - - if (!net_eq(net, &init_net)) - return -EAFNOSUPPORT; - - if (sock->type != SOCK_SEQPACKET || protocol != 0) - return -ESOCKTNOSUPPORT; - - sk = sk_alloc(net, PF_NETROM, GFP_ATOMIC, &nr_proto, kern); - if (sk == NULL) - return -ENOMEM; - - nr = nr_sk(sk); - - sock_init_data(sock, sk); - - sock->ops = &nr_proto_ops; - sk->sk_protocol = protocol; - - skb_queue_head_init(&nr->ack_queue); - skb_queue_head_init(&nr->reseq_queue); - skb_queue_head_init(&nr->frag_queue); - - nr_init_timers(sk); - - nr->t1 = - msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_timeout)); - nr->t2 = - msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_acknowledge_delay)); - nr->n2 = - msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_maximum_tries)); - nr->t4 = - msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_busy_delay)); - nr->idle = - msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_no_activity_timeout)); - nr->window = READ_ONCE(sysctl_netrom_transport_requested_window_size); - - nr->bpqext = 1; - nr->state = NR_STATE_0; - - return 0; -} - -static struct sock *nr_make_new(struct sock *osk) -{ - struct sock *sk; - struct nr_sock *nr, *onr; - - if (osk->sk_type != SOCK_SEQPACKET) - return NULL; - - sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot, 0); - if (sk == NULL) - return NULL; - - nr = nr_sk(sk); - - sock_init_data(NULL, sk); - - sk->sk_type = osk->sk_type; - sk->sk_priority = READ_ONCE(osk->sk_priority); - sk->sk_protocol = osk->sk_protocol; - sk->sk_rcvbuf = osk->sk_rcvbuf; - sk->sk_sndbuf = osk->sk_sndbuf; - sk->sk_state = TCP_ESTABLISHED; - sock_copy_flags(sk, osk); - - skb_queue_head_init(&nr->ack_queue); - skb_queue_head_init(&nr->reseq_queue); - skb_queue_head_init(&nr->frag_queue); - - nr_init_timers(sk); - - onr = nr_sk(osk); - - nr->t1 = onr->t1; - nr->t2 = onr->t2; - nr->n2 = onr->n2; - nr->t4 = onr->t4; - nr->idle = onr->idle; - nr->window = onr->window; - - nr->device = onr->device; - nr->bpqext = onr->bpqext; - - return sk; -} - -static int nr_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct nr_sock *nr; - - if (sk == NULL) return 0; - - sock_hold(sk); - sock_orphan(sk); - lock_sock(sk); - nr = nr_sk(sk); - - switch (nr->state) { - case NR_STATE_0: - case NR_STATE_1: - case NR_STATE_2: - nr_disconnect(sk, 0); - nr_destroy_socket(sk); - break; - - case NR_STATE_3: - nr_clear_queues(sk); - nr->n2count = 0; - nr_write_internal(sk, NR_DISCREQ); - nr_start_t1timer(sk); - nr_stop_t2timer(sk); - nr_stop_t4timer(sk); - nr_stop_idletimer(sk); - nr->state = NR_STATE_2; - sk->sk_state = TCP_CLOSE; - sk->sk_shutdown |= SEND_SHUTDOWN; - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DESTROY); - break; - - default: - break; - } - - sock->sk = NULL; - release_sock(sk); - sock_put(sk); - - return 0; -} - -static int nr_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len) -{ - struct sock *sk = sock->sk; - struct nr_sock *nr = nr_sk(sk); - struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; - struct net_device *dev; - ax25_uid_assoc *user; - ax25_address *source; - - lock_sock(sk); - if (!sock_flag(sk, SOCK_ZAPPED)) { - release_sock(sk); - return -EINVAL; - } - if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) { - release_sock(sk); - return -EINVAL; - } - if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) { - release_sock(sk); - return -EINVAL; - } - if (addr->fsa_ax25.sax25_family != AF_NETROM) { - release_sock(sk); - return -EINVAL; - } - if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) { - release_sock(sk); - return -EADDRNOTAVAIL; - } - - /* - * Only the super user can set an arbitrary user callsign. - */ - if (addr->fsa_ax25.sax25_ndigis == 1) { - if (!capable(CAP_NET_BIND_SERVICE)) { - dev_put(dev); - release_sock(sk); - return -EPERM; - } - nr->user_addr = addr->fsa_digipeater[0]; - nr->source_addr = addr->fsa_ax25.sax25_call; - } else { - source = &addr->fsa_ax25.sax25_call; - - user = ax25_findbyuid(current_euid()); - if (user) { - nr->user_addr = user->call; - ax25_uid_put(user); - } else { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { - release_sock(sk); - dev_put(dev); - return -EPERM; - } - nr->user_addr = *source; - } - - nr->source_addr = *source; - } - - nr->device = dev; - nr_insert_socket(sk); - - sock_reset_flag(sk, SOCK_ZAPPED); - dev_put(dev); - release_sock(sk); - - return 0; -} - -static int nr_connect(struct socket *sock, struct sockaddr_unsized *uaddr, - int addr_len, int flags) -{ - struct sock *sk = sock->sk; - struct nr_sock *nr = nr_sk(sk); - struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr; - const ax25_address *source = NULL; - ax25_uid_assoc *user; - struct net_device *dev; - int err = 0; - - lock_sock(sk); - if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { - sock->state = SS_CONNECTED; - goto out_release; /* Connect completed during a ERESTARTSYS event */ - } - - if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { - sock->state = SS_UNCONNECTED; - err = -ECONNREFUSED; - goto out_release; - } - - if (sk->sk_state == TCP_ESTABLISHED) { - err = -EISCONN; /* No reconnect on a seqpacket socket */ - goto out_release; - } - - if (sock->state == SS_CONNECTING) { - err = -EALREADY; - goto out_release; - } - - sk->sk_state = TCP_CLOSE; - sock->state = SS_UNCONNECTED; - - if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) { - err = -EINVAL; - goto out_release; - } - if (addr->sax25_family != AF_NETROM) { - err = -EINVAL; - goto out_release; - } - if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */ - sock_reset_flag(sk, SOCK_ZAPPED); - - if ((dev = nr_dev_first()) == NULL) { - err = -ENETUNREACH; - goto out_release; - } - source = (const ax25_address *)dev->dev_addr; - - user = ax25_findbyuid(current_euid()); - if (user) { - nr->user_addr = user->call; - ax25_uid_put(user); - } else { - if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) { - dev_put(dev); - err = -EPERM; - goto out_release; - } - nr->user_addr = *source; - } - - nr->source_addr = *source; - nr->device = dev; - - dev_put(dev); - nr_insert_socket(sk); /* Finish the bind */ - } - - nr->dest_addr = addr->sax25_call; - - release_sock(sk); - circuit = nr_find_next_circuit(); - lock_sock(sk); - - nr->my_index = circuit / 256; - nr->my_id = circuit % 256; - - circuit++; - - /* Move to connecting socket, start sending Connect Requests */ - sock->state = SS_CONNECTING; - sk->sk_state = TCP_SYN_SENT; - - nr_establish_data_link(sk); - - nr->state = NR_STATE_1; - - nr_start_heartbeat(sk); - - /* Now the loop */ - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { - err = -EINPROGRESS; - goto out_release; - } - - /* - * A Connect Ack with Choke or timeout or failed routing will go to - * closed. - */ - if (sk->sk_state == TCP_SYN_SENT) { - DEFINE_WAIT(wait); - - for (;;) { - prepare_to_wait(sk_sleep(sk), &wait, - TASK_INTERRUPTIBLE); - if (sk->sk_state != TCP_SYN_SENT) - break; - if (!signal_pending(current)) { - release_sock(sk); - schedule(); - lock_sock(sk); - continue; - } - err = -ERESTARTSYS; - break; - } - finish_wait(sk_sleep(sk), &wait); - if (err) - goto out_release; - } - - if (sk->sk_state != TCP_ESTABLISHED) { - sock->state = SS_UNCONNECTED; - err = sock_error(sk); /* Always set at this point */ - goto out_release; - } - - sock->state = SS_CONNECTED; - -out_release: - release_sock(sk); - - return err; -} - -static int nr_accept(struct socket *sock, struct socket *newsock, - struct proto_accept_arg *arg) -{ - struct sk_buff *skb; - struct sock *newsk; - DEFINE_WAIT(wait); - struct sock *sk; - int err = 0; - - if ((sk = sock->sk) == NULL) - return -EINVAL; - - lock_sock(sk); - if (sk->sk_type != SOCK_SEQPACKET) { - err = -EOPNOTSUPP; - goto out_release; - } - - if (sk->sk_state != TCP_LISTEN) { - err = -EINVAL; - goto out_release; - } - - /* - * The write queue this time is holding sockets ready to use - * hooked into the SABM we saved - */ - for (;;) { - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - skb = skb_dequeue(&sk->sk_receive_queue); - if (skb) - break; - - if (arg->flags & O_NONBLOCK) { - err = -EWOULDBLOCK; - break; - } - if (!signal_pending(current)) { - release_sock(sk); - schedule(); - lock_sock(sk); - continue; - } - err = -ERESTARTSYS; - break; - } - finish_wait(sk_sleep(sk), &wait); - if (err) - goto out_release; - - newsk = skb->sk; - sock_graft(newsk, newsock); - - /* Now attach up the new socket */ - kfree_skb(skb); - sk_acceptq_removed(sk); - -out_release: - release_sock(sk); - - return err; -} - -static int nr_getname(struct socket *sock, struct sockaddr *uaddr, - int peer) -{ - struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr; - struct sock *sk = sock->sk; - struct nr_sock *nr = nr_sk(sk); - int uaddr_len; - - memset(&sax->fsa_ax25, 0, sizeof(struct sockaddr_ax25)); - - lock_sock(sk); - if (peer != 0) { - if (sk->sk_state != TCP_ESTABLISHED) { - release_sock(sk); - return -ENOTCONN; - } - sax->fsa_ax25.sax25_family = AF_NETROM; - sax->fsa_ax25.sax25_ndigis = 1; - sax->fsa_ax25.sax25_call = nr->user_addr; - memset(sax->fsa_digipeater, 0, sizeof(sax->fsa_digipeater)); - sax->fsa_digipeater[0] = nr->dest_addr; - uaddr_len = sizeof(struct full_sockaddr_ax25); - } else { - sax->fsa_ax25.sax25_family = AF_NETROM; - sax->fsa_ax25.sax25_ndigis = 0; - sax->fsa_ax25.sax25_call = nr->source_addr; - uaddr_len = sizeof(struct sockaddr_ax25); - } - release_sock(sk); - - return uaddr_len; -} - -int nr_rx_frame(struct sk_buff *skb, struct net_device *dev) -{ - struct sock *sk; - struct sock *make; - struct nr_sock *nr_make; - ax25_address *src, *dest, *user; - unsigned short circuit_index, circuit_id; - unsigned short peer_circuit_index, peer_circuit_id; - unsigned short frametype, flags, window, timeout; - int ret; - - skb_orphan(skb); - - /* - * skb->data points to the netrom frame start - */ - - src = (ax25_address *)(skb->data + 0); - dest = (ax25_address *)(skb->data + 7); - - circuit_index = skb->data[15]; - circuit_id = skb->data[16]; - peer_circuit_index = skb->data[17]; - peer_circuit_id = skb->data[18]; - frametype = skb->data[19] & 0x0F; - flags = skb->data[19] & 0xF0; - - /* - * Check for an incoming IP over NET/ROM frame. - */ - if (frametype == NR_PROTOEXT && - circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) { - skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); - skb_reset_transport_header(skb); - - return nr_rx_ip(skb, dev); - } - - /* - * Find an existing socket connection, based on circuit ID, if it's - * a Connect Request base it on their circuit ID. - * - * Circuit ID 0/0 is not valid but it could still be a "reset" for a - * circuit that no longer exists at the other end ... - */ - - sk = NULL; - - if (circuit_index == 0 && circuit_id == 0) { - if (frametype == NR_CONNACK && flags == NR_CHOKE_FLAG) - sk = nr_find_peer(peer_circuit_index, peer_circuit_id, src); - } else { - if (frametype == NR_CONNREQ) - sk = nr_find_peer(circuit_index, circuit_id, src); - else - sk = nr_find_socket(circuit_index, circuit_id); - } - - if (sk != NULL) { - bh_lock_sock(sk); - skb_reset_transport_header(skb); - - if (frametype == NR_CONNACK && skb->len == 22) - nr_sk(sk)->bpqext = 1; - else - nr_sk(sk)->bpqext = 0; - - ret = nr_process_rx_frame(sk, skb); - bh_unlock_sock(sk); - sock_put(sk); - return ret; - } - - /* - * Now it should be a CONNREQ. - */ - if (frametype != NR_CONNREQ) { - /* - * Here it would be nice to be able to send a reset but - * NET/ROM doesn't have one. We've tried to extend the protocol - * by sending NR_CONNACK | NR_CHOKE_FLAGS replies but that - * apparently kills BPQ boxes... :-( - * So now we try to follow the established behaviour of - * G8PZT's Xrouter which is sending packets with command type 7 - * as an extension of the protocol. - */ - if (READ_ONCE(sysctl_netrom_reset_circuit) && - (frametype != NR_RESET || flags != 0)) - nr_transmit_reset(skb, 1); - - return 0; - } - - sk = nr_find_listener(dest); - - user = (ax25_address *)(skb->data + 21); - - if (sk == NULL || sk_acceptq_is_full(sk) || - (make = nr_make_new(sk)) == NULL) { - nr_transmit_refusal(skb, 0); - if (sk) - sock_put(sk); - return 0; - } - - bh_lock_sock(sk); - - window = skb->data[20]; - - sock_hold(make); - skb->sk = make; - skb->destructor = sock_efree; - make->sk_state = TCP_ESTABLISHED; - - /* Fill in his circuit details */ - nr_make = nr_sk(make); - nr_make->source_addr = *dest; - nr_make->dest_addr = *src; - nr_make->user_addr = *user; - - nr_make->your_index = circuit_index; - nr_make->your_id = circuit_id; - - bh_unlock_sock(sk); - circuit = nr_find_next_circuit(); - bh_lock_sock(sk); - - nr_make->my_index = circuit / 256; - nr_make->my_id = circuit % 256; - - circuit++; - - /* Window negotiation */ - if (window < nr_make->window) - nr_make->window = window; - - /* L4 timeout negotiation */ - if (skb->len == 37) { - timeout = skb->data[36] * 256 + skb->data[35]; - if (timeout * HZ < nr_make->t1) - nr_make->t1 = timeout * HZ; - nr_make->bpqext = 1; - } else { - nr_make->bpqext = 0; - } - - nr_write_internal(make, NR_CONNACK); - - nr_make->condition = 0x00; - nr_make->vs = 0; - nr_make->va = 0; - nr_make->vr = 0; - nr_make->vl = 0; - nr_make->state = NR_STATE_3; - sk_acceptq_added(sk); - skb_queue_head(&sk->sk_receive_queue, skb); - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); - - bh_unlock_sock(sk); - sock_put(sk); - - nr_insert_socket(make); - - nr_start_heartbeat(make); - nr_start_idletimer(make); - - return 1; -} - -static int nr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) -{ - struct sock *sk = sock->sk; - struct nr_sock *nr = nr_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name); - int err; - struct sockaddr_ax25 sax; - struct sk_buff *skb; - unsigned char *asmptr; - int size; - - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) - return -EINVAL; - - lock_sock(sk); - if (sock_flag(sk, SOCK_ZAPPED)) { - err = -EADDRNOTAVAIL; - goto out; - } - - if (sk->sk_shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 0); - err = -EPIPE; - goto out; - } - - if (nr->device == NULL) { - err = -ENETUNREACH; - goto out; - } - - if (usax) { - if (msg->msg_namelen < sizeof(sax)) { - err = -EINVAL; - goto out; - } - sax = *usax; - if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) { - err = -EISCONN; - goto out; - } - if (sax.sax25_family != AF_NETROM) { - err = -EINVAL; - goto out; - } - } else { - if (sk->sk_state != TCP_ESTABLISHED) { - err = -ENOTCONN; - goto out; - } - sax.sax25_family = AF_NETROM; - sax.sax25_call = nr->dest_addr; - } - - /* Build a packet - the conventional user limit is 236 bytes. We can - do ludicrously large NetROM frames but must not overflow */ - if (len > 65536) { - err = -EMSGSIZE; - goto out; - } - - size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; - - if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) - goto out; - - skb_reserve(skb, size - len); - skb_reset_transport_header(skb); - - /* - * Push down the NET/ROM header - */ - - asmptr = skb_push(skb, NR_TRANSPORT_LEN); - - /* Build a NET/ROM Transport header */ - - *asmptr++ = nr->your_index; - *asmptr++ = nr->your_id; - *asmptr++ = 0; /* To be filled in later */ - *asmptr++ = 0; /* Ditto */ - *asmptr++ = NR_INFO; - - /* - * Put the data on the end - */ - skb_put(skb, len); - - /* User data follows immediately after the NET/ROM transport header */ - if (memcpy_from_msg(skb_transport_header(skb), msg, len)) { - kfree_skb(skb); - err = -EFAULT; - goto out; - } - - if (sk->sk_state != TCP_ESTABLISHED) { - kfree_skb(skb); - err = -ENOTCONN; - goto out; - } - - nr_output(sk, skb); /* Shove it onto the queue */ - - err = len; -out: - release_sock(sk); - return err; -} - -static int nr_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, - int flags) -{ - struct sock *sk = sock->sk; - DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name); - size_t copied; - struct sk_buff *skb; - int er; - - /* - * This works for seqpacket too. The receiver has ordered the queue for - * us! We do one quick check first though - */ - - lock_sock(sk); - if (sk->sk_state != TCP_ESTABLISHED) { - release_sock(sk); - return -ENOTCONN; - } - - /* Now we can treat all alike */ - skb = skb_recv_datagram(sk, flags, &er); - if (!skb) { - release_sock(sk); - return er; - } - - skb_reset_transport_header(skb); - copied = skb->len; - - if (copied > size) { - copied = size; - msg->msg_flags |= MSG_TRUNC; - } - - er = skb_copy_datagram_msg(skb, 0, msg, copied); - if (er < 0) { - skb_free_datagram(sk, skb); - release_sock(sk); - return er; - } - - if (sax != NULL) { - memset(sax, 0, sizeof(*sax)); - sax->sax25_family = AF_NETROM; - skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call, - AX25_ADDR_LEN); - msg->msg_namelen = sizeof(*sax); - } - - skb_free_datagram(sk, skb); - - release_sock(sk); - return copied; -} - - -static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; - - switch (cmd) { - case TIOCOUTQ: { - long amount; - - lock_sock(sk); - amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); - if (amount < 0) - amount = 0; - release_sock(sk); - return put_user(amount, (int __user *)argp); - } - - case TIOCINQ: { - struct sk_buff *skb; - long amount = 0L; - - lock_sock(sk); - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) - amount = skb->len; - release_sock(sk); - return put_user(amount, (int __user *)argp); - } - - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - return -EINVAL; - - case SIOCADDRT: - case SIOCDELRT: - case SIOCNRDECOBS: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - return nr_rt_ioctl(cmd, argp); - - default: - return -ENOIOCTLCMD; - } - - return 0; -} - -#ifdef CONFIG_PROC_FS - -static void *nr_info_start(struct seq_file *seq, loff_t *pos) - __acquires(&nr_list_lock) -{ - spin_lock_bh(&nr_list_lock); - return seq_hlist_start_head(&nr_list, *pos); -} - -static void *nr_info_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_hlist_next(v, &nr_list, pos); -} - -static void nr_info_stop(struct seq_file *seq, void *v) - __releases(&nr_list_lock) -{ - spin_unlock_bh(&nr_list_lock); -} - -static int nr_info_show(struct seq_file *seq, void *v) -{ - struct sock *s = sk_entry(v); - struct net_device *dev; - struct nr_sock *nr; - const char *devname; - char buf[11]; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, -"user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n"); - - else { - - bh_lock_sock(s); - nr = nr_sk(s); - - if ((dev = nr->device) == NULL) - devname = "???"; - else - devname = dev->name; - - seq_printf(seq, "%-9s ", ax2asc(buf, &nr->user_addr)); - seq_printf(seq, "%-9s ", ax2asc(buf, &nr->dest_addr)); - seq_printf(seq, -"%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %llu\n", - ax2asc(buf, &nr->source_addr), - devname, - nr->my_index, - nr->my_id, - nr->your_index, - nr->your_id, - nr->state, - nr->vs, - nr->vr, - nr->va, - ax25_display_timer(&nr->t1timer) / HZ, - nr->t1 / HZ, - ax25_display_timer(&nr->t2timer) / HZ, - nr->t2 / HZ, - ax25_display_timer(&nr->t4timer) / HZ, - nr->t4 / HZ, - ax25_display_timer(&nr->idletimer) / (60 * HZ), - nr->idle / (60 * HZ), - nr->n2count, - nr->n2, - nr->window, - sk_wmem_alloc_get(s), - sk_rmem_alloc_get(s), - s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : (u64)0); - - bh_unlock_sock(s); - } - return 0; -} - -static const struct seq_operations nr_info_seqops = { - .start = nr_info_start, - .next = nr_info_next, - .stop = nr_info_stop, - .show = nr_info_show, -}; -#endif /* CONFIG_PROC_FS */ - -static const struct net_proto_family nr_family_ops = { - .family = PF_NETROM, - .create = nr_create, - .owner = THIS_MODULE, -}; - -static const struct proto_ops nr_proto_ops = { - .family = PF_NETROM, - .owner = THIS_MODULE, - .release = nr_release, - .bind = nr_bind, - .connect = nr_connect, - .socketpair = sock_no_socketpair, - .accept = nr_accept, - .getname = nr_getname, - .poll = datagram_poll, - .ioctl = nr_ioctl, - .gettstamp = sock_gettstamp, - .listen = nr_listen, - .shutdown = sock_no_shutdown, - .setsockopt = nr_setsockopt, - .getsockopt = nr_getsockopt, - .sendmsg = nr_sendmsg, - .recvmsg = nr_recvmsg, - .mmap = sock_no_mmap, -}; - -static struct notifier_block nr_dev_notifier = { - .notifier_call = nr_device_event, -}; - -static struct net_device **dev_nr; - -static struct ax25_protocol nr_pid = { - .pid = AX25_P_NETROM, - .func = nr_route_frame -}; - -static struct ax25_linkfail nr_linkfail_notifier = { - .func = nr_link_failed, -}; - -static int __init nr_proto_init(void) -{ - int i; - int rc = proto_register(&nr_proto, 0); - - if (rc) - return rc; - - if (nr_ndevs > 0x7fffffff/sizeof(struct net_device *)) { - pr_err("NET/ROM: %s - nr_ndevs parameter too large\n", - __func__); - rc = -EINVAL; - goto unregister_proto; - } - - dev_nr = kzalloc_objs(struct net_device *, nr_ndevs); - if (!dev_nr) { - pr_err("NET/ROM: %s - unable to allocate device array\n", - __func__); - rc = -ENOMEM; - goto unregister_proto; - } - - for (i = 0; i < nr_ndevs; i++) { - char name[IFNAMSIZ]; - struct net_device *dev; - - sprintf(name, "nr%d", i); - dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, nr_setup); - if (!dev) { - rc = -ENOMEM; - goto fail; - } - - dev->base_addr = i; - rc = register_netdev(dev); - if (rc) { - free_netdev(dev); - goto fail; - } - nr_set_lockdep_key(dev); - dev_nr[i] = dev; - } - - rc = sock_register(&nr_family_ops); - if (rc) - goto fail; - - rc = register_netdevice_notifier(&nr_dev_notifier); - if (rc) - goto out_sock; - - ax25_register_pid(&nr_pid); - ax25_linkfail_register(&nr_linkfail_notifier); - -#ifdef CONFIG_SYSCTL - rc = nr_register_sysctl(); - if (rc) - goto out_sysctl; -#endif - - nr_loopback_init(); - - rc = -ENOMEM; - if (!proc_create_seq("nr", 0444, init_net.proc_net, &nr_info_seqops)) - goto proc_remove1; - if (!proc_create_seq("nr_neigh", 0444, init_net.proc_net, - &nr_neigh_seqops)) - goto proc_remove2; - if (!proc_create_seq("nr_nodes", 0444, init_net.proc_net, - &nr_node_seqops)) - goto proc_remove3; - - return 0; - -proc_remove3: - remove_proc_entry("nr_neigh", init_net.proc_net); -proc_remove2: - remove_proc_entry("nr", init_net.proc_net); -proc_remove1: - - nr_loopback_clear(); - nr_rt_free(); - -#ifdef CONFIG_SYSCTL - nr_unregister_sysctl(); -out_sysctl: -#endif - ax25_linkfail_release(&nr_linkfail_notifier); - ax25_protocol_release(AX25_P_NETROM); - unregister_netdevice_notifier(&nr_dev_notifier); -out_sock: - sock_unregister(PF_NETROM); -fail: - while (--i >= 0) { - unregister_netdev(dev_nr[i]); - free_netdev(dev_nr[i]); - } - kfree(dev_nr); -unregister_proto: - proto_unregister(&nr_proto); - return rc; -} - -module_init(nr_proto_init); - -module_param(nr_ndevs, int, 0); -MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices"); - -MODULE_AUTHOR("Jonathan Naylor G4KLX "); -MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NETPROTO(PF_NETROM); - -static void __exit nr_exit(void) -{ - int i; - - remove_proc_entry("nr", init_net.proc_net); - remove_proc_entry("nr_neigh", init_net.proc_net); - remove_proc_entry("nr_nodes", init_net.proc_net); - nr_loopback_clear(); - - nr_rt_free(); - -#ifdef CONFIG_SYSCTL - nr_unregister_sysctl(); -#endif - - ax25_linkfail_release(&nr_linkfail_notifier); - ax25_protocol_release(AX25_P_NETROM); - - unregister_netdevice_notifier(&nr_dev_notifier); - - sock_unregister(PF_NETROM); - - for (i = 0; i < nr_ndevs; i++) { - struct net_device *dev = dev_nr[i]; - if (dev) { - unregister_netdev(dev); - free_netdev(dev); - } - } - - kfree(dev_nr); - proto_unregister(&nr_proto); -} -module_exit(nr_exit); diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c deleted file mode 100644 index 2c34389c3ce6..000000000000 --- a/net/netrom/nr_dev.c +++ /dev/null @@ -1,178 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For the statistics structure. */ -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -/* - * Only allow IP over NET/ROM frames through if the netrom device is up. - */ - -int nr_rx_ip(struct sk_buff *skb, struct net_device *dev) -{ - struct net_device_stats *stats = &dev->stats; - - if (!netif_running(dev)) { - stats->rx_dropped++; - return 0; - } - - stats->rx_packets++; - stats->rx_bytes += skb->len; - - skb->protocol = htons(ETH_P_IP); - - /* Spoof incoming device */ - skb->dev = dev; - skb->mac_header = skb->network_header; - skb_reset_network_header(skb); - skb->pkt_type = PACKET_HOST; - - netif_rx(skb); - - return 1; -} - -static int nr_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned int len) -{ - unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); - - memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len); - buff[6] &= ~AX25_CBIT; - buff[6] &= ~AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - if (daddr != NULL) - memcpy(buff, daddr, dev->addr_len); - buff[6] &= ~AX25_CBIT; - buff[6] |= AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - *buff++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser); - - *buff++ = NR_PROTO_IP; - *buff++ = NR_PROTO_IP; - *buff++ = 0; - *buff++ = 0; - *buff++ = NR_PROTOEXT; - - if (daddr != NULL) - return 37; - - return -37; -} - -static int __must_check nr_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = addr; - int err; - - if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) - return 0; - - if (dev->flags & IFF_UP) { - err = ax25_listen_register((ax25_address *)sa->sa_data, NULL); - if (err) - return err; - - ax25_listen_release((const ax25_address *)dev->dev_addr, NULL); - } - - dev_addr_set(dev, sa->sa_data); - - return 0; -} - -static int nr_open(struct net_device *dev) -{ - int err; - - err = ax25_listen_register((const ax25_address *)dev->dev_addr, NULL); - if (err) - return err; - - netif_start_queue(dev); - - return 0; -} - -static int nr_close(struct net_device *dev) -{ - ax25_listen_release((const ax25_address *)dev->dev_addr, NULL); - netif_stop_queue(dev); - return 0; -} - -static netdev_tx_t nr_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct net_device_stats *stats = &dev->stats; - unsigned int len = skb->len; - - if (!nr_route_frame(skb, NULL)) { - kfree_skb(skb); - stats->tx_errors++; - return NETDEV_TX_OK; - } - - stats->tx_packets++; - stats->tx_bytes += len; - - return NETDEV_TX_OK; -} - -static const struct header_ops nr_header_ops = { - .create = nr_header, -}; - -static const struct net_device_ops nr_netdev_ops = { - .ndo_open = nr_open, - .ndo_stop = nr_close, - .ndo_start_xmit = nr_xmit, - .ndo_set_mac_address = nr_set_mac_address, -}; - -void nr_setup(struct net_device *dev) -{ - dev->mtu = NR_MAX_PACKET_SIZE; - dev->netdev_ops = &nr_netdev_ops; - dev->header_ops = &nr_header_ops; - dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; - dev->addr_len = AX25_ADDR_LEN; - dev->type = ARPHRD_NETROM; - - /* New-style flags. */ - dev->flags = IFF_NOARP; -} diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c deleted file mode 100644 index 97944db6b5ac..000000000000 --- a/net/netrom/nr_in.c +++ /dev/null @@ -1,301 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) -{ - struct sk_buff *skbo, *skbn = skb; - struct nr_sock *nr = nr_sk(sk); - - skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); - - nr_start_idletimer(sk); - - if (more) { - nr->fraglen += skb->len; - skb_queue_tail(&nr->frag_queue, skb); - return 0; - } - - if (!more && nr->fraglen > 0) { /* End of fragment */ - nr->fraglen += skb->len; - skb_queue_tail(&nr->frag_queue, skb); - - if ((skbn = alloc_skb(nr->fraglen, GFP_ATOMIC)) == NULL) - return 1; - - skb_reset_transport_header(skbn); - - while ((skbo = skb_dequeue(&nr->frag_queue)) != NULL) { - skb_copy_from_linear_data(skbo, - skb_put(skbn, skbo->len), - skbo->len); - kfree_skb(skbo); - } - - nr->fraglen = 0; - } - - return sock_queue_rcv_skb(sk, skbn); -} - -/* - * State machine for state 1, Awaiting Connection State. - * The handling of the timer(s) is in file nr_timer.c. - * Handling of state 0 and connection release is in netrom.c. - */ -static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, - int frametype) -{ - switch (frametype) { - case NR_CONNACK: { - struct nr_sock *nr = nr_sk(sk); - - nr_stop_t1timer(sk); - nr_start_idletimer(sk); - nr->your_index = skb->data[17]; - nr->your_id = skb->data[18]; - nr->vs = 0; - nr->va = 0; - nr->vr = 0; - nr->vl = 0; - nr->state = NR_STATE_3; - nr->n2count = 0; - nr->window = skb->data[20]; - sk->sk_state = TCP_ESTABLISHED; - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_state_change(sk); - break; - } - - case NR_CONNACK | NR_CHOKE_FLAG: - nr_disconnect(sk, ECONNREFUSED); - break; - - case NR_RESET: - if (READ_ONCE(sysctl_netrom_reset_circuit)) - nr_disconnect(sk, ECONNRESET); - break; - - default: - break; - } - return 0; -} - -/* - * State machine for state 2, Awaiting Release State. - * The handling of the timer(s) is in file nr_timer.c - * Handling of state 0 and connection release is in netrom.c. - */ -static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, - int frametype) -{ - switch (frametype) { - case NR_CONNACK | NR_CHOKE_FLAG: - nr_disconnect(sk, ECONNRESET); - break; - - case NR_DISCREQ: - nr_write_internal(sk, NR_DISCACK); - fallthrough; - case NR_DISCACK: - nr_disconnect(sk, 0); - break; - - case NR_RESET: - if (READ_ONCE(sysctl_netrom_reset_circuit)) - nr_disconnect(sk, ECONNRESET); - break; - - default: - break; - } - return 0; -} - -/* - * State machine for state 3, Connected State. - * The handling of the timer(s) is in file nr_timer.c - * Handling of state 0 and connection release is in netrom.c. - */ -static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype) -{ - struct nr_sock *nrom = nr_sk(sk); - struct sk_buff_head temp_queue; - struct sk_buff *skbn; - unsigned short save_vr; - unsigned short nr, ns; - int queued = 0; - - nr = skb->data[18]; - - switch (frametype) { - case NR_CONNREQ: - nr_write_internal(sk, NR_CONNACK); - break; - - case NR_DISCREQ: - nr_write_internal(sk, NR_DISCACK); - nr_disconnect(sk, 0); - break; - - case NR_CONNACK | NR_CHOKE_FLAG: - case NR_DISCACK: - nr_disconnect(sk, ECONNRESET); - break; - - case NR_INFOACK: - case NR_INFOACK | NR_CHOKE_FLAG: - case NR_INFOACK | NR_NAK_FLAG: - case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG: - if (frametype & NR_CHOKE_FLAG) { - nrom->condition |= NR_COND_PEER_RX_BUSY; - nr_start_t4timer(sk); - } else { - nrom->condition &= ~NR_COND_PEER_RX_BUSY; - nr_stop_t4timer(sk); - } - if (!nr_validate_nr(sk, nr)) { - break; - } - if (frametype & NR_NAK_FLAG) { - nr_frames_acked(sk, nr); - nr_send_nak_frame(sk); - } else { - if (nrom->condition & NR_COND_PEER_RX_BUSY) { - nr_frames_acked(sk, nr); - } else { - nr_check_iframes_acked(sk, nr); - } - } - break; - - case NR_INFO: - case NR_INFO | NR_NAK_FLAG: - case NR_INFO | NR_CHOKE_FLAG: - case NR_INFO | NR_MORE_FLAG: - case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG: - case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG: - case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG: - case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG: - if (frametype & NR_CHOKE_FLAG) { - nrom->condition |= NR_COND_PEER_RX_BUSY; - nr_start_t4timer(sk); - } else { - nrom->condition &= ~NR_COND_PEER_RX_BUSY; - nr_stop_t4timer(sk); - } - if (nr_validate_nr(sk, nr)) { - if (frametype & NR_NAK_FLAG) { - nr_frames_acked(sk, nr); - nr_send_nak_frame(sk); - } else { - if (nrom->condition & NR_COND_PEER_RX_BUSY) { - nr_frames_acked(sk, nr); - } else { - nr_check_iframes_acked(sk, nr); - } - } - } - queued = 1; - skb_queue_head(&nrom->reseq_queue, skb); - if (nrom->condition & NR_COND_OWN_RX_BUSY) - break; - skb_queue_head_init(&temp_queue); - do { - save_vr = nrom->vr; - while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) { - ns = skbn->data[17]; - if (ns == nrom->vr) { - if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) { - nrom->vr = (nrom->vr + 1) % NR_MODULUS; - } else { - nrom->condition |= NR_COND_OWN_RX_BUSY; - skb_queue_tail(&temp_queue, skbn); - } - } else if (nr_in_rx_window(sk, ns)) { - skb_queue_tail(&temp_queue, skbn); - } else { - kfree_skb(skbn); - } - } - while ((skbn = skb_dequeue(&temp_queue)) != NULL) { - skb_queue_tail(&nrom->reseq_queue, skbn); - } - } while (save_vr != nrom->vr); - /* - * Window is full, ack it immediately. - */ - if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) { - nr_enquiry_response(sk); - } else { - if (!(nrom->condition & NR_COND_ACK_PENDING)) { - nrom->condition |= NR_COND_ACK_PENDING; - nr_start_t2timer(sk); - } - } - break; - - case NR_RESET: - if (READ_ONCE(sysctl_netrom_reset_circuit)) - nr_disconnect(sk, ECONNRESET); - break; - - default: - break; - } - return queued; -} - -/* Higher level upcall for a LAPB frame - called with sk locked */ -int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb) -{ - struct nr_sock *nr = nr_sk(sk); - int queued = 0, frametype; - - if (nr->state == NR_STATE_0) - return 0; - - frametype = skb->data[19]; - - switch (nr->state) { - case NR_STATE_1: - queued = nr_state1_machine(sk, skb, frametype); - break; - case NR_STATE_2: - queued = nr_state2_machine(sk, skb, frametype); - break; - case NR_STATE_3: - queued = nr_state3_machine(sk, skb, frametype); - break; - } - - nr_kick(sk); - - return queued; -} diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c deleted file mode 100644 index 7a9d765b30c0..000000000000 --- a/net/netrom/nr_loopback.c +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi) - */ -#include -#include -#include -#include -#include -#include -#include -#include - -static void nr_loopback_timer(struct timer_list *); - -static struct sk_buff_head loopback_queue; -static DEFINE_TIMER(loopback_timer, nr_loopback_timer); - -void __init nr_loopback_init(void) -{ - skb_queue_head_init(&loopback_queue); -} - -static inline int nr_loopback_running(void) -{ - return timer_pending(&loopback_timer); -} - -int nr_loopback_queue(struct sk_buff *skb) -{ - struct sk_buff *skbn; - - if ((skbn = alloc_skb(skb->len, GFP_ATOMIC)) != NULL) { - skb_copy_from_linear_data(skb, skb_put(skbn, skb->len), skb->len); - skb_reset_transport_header(skbn); - - skb_queue_tail(&loopback_queue, skbn); - - if (!nr_loopback_running()) - mod_timer(&loopback_timer, jiffies + 10); - } - - kfree_skb(skb); - return 1; -} - -static void nr_loopback_timer(struct timer_list *unused) -{ - struct sk_buff *skb; - ax25_address *nr_dest; - struct net_device *dev; - - if ((skb = skb_dequeue(&loopback_queue)) != NULL) { - nr_dest = (ax25_address *)(skb->data + 7); - - dev = nr_dev_get(nr_dest); - - if (dev == NULL || nr_rx_frame(skb, dev) == 0) - kfree_skb(skb); - - dev_put(dev); - - if (!skb_queue_empty(&loopback_queue) && !nr_loopback_running()) - mod_timer(&loopback_timer, jiffies + 10); - } -} - -void nr_loopback_clear(void) -{ - timer_delete_sync(&loopback_timer); - skb_queue_purge(&loopback_queue); -} diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c deleted file mode 100644 index 2b3cbceb0b52..000000000000 --- a/net/netrom/nr_out.c +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This is where all NET/ROM frames pass, except for IP-over-NET/ROM which - * cannot be fragmented in this manner. - */ -void nr_output(struct sock *sk, struct sk_buff *skb) -{ - struct sk_buff *skbn; - unsigned char transport[NR_TRANSPORT_LEN]; - int err, frontlen, len; - - if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) { - /* Save a copy of the Transport Header */ - skb_copy_from_linear_data(skb, transport, NR_TRANSPORT_LEN); - skb_pull(skb, NR_TRANSPORT_LEN); - - frontlen = skb_headroom(skb); - - while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL) { - kfree_skb(skb); - return; - } - - skb_reserve(skbn, frontlen); - - len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE; - - /* Copy the user data */ - skb_copy_from_linear_data(skb, skb_put(skbn, len), len); - skb_pull(skb, len); - - /* Duplicate the Transport Header */ - skb_push(skbn, NR_TRANSPORT_LEN); - skb_copy_to_linear_data(skbn, transport, - NR_TRANSPORT_LEN); - if (skb->len > 0) - skbn->data[4] |= NR_MORE_FLAG; - - skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */ - } - - kfree_skb(skb); - } else { - skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */ - } - - nr_kick(sk); -} - -/* - * This procedure is passed a buffer descriptor for an iframe. It builds - * the rest of the control part of the frame and then writes it out. - */ -static void nr_send_iframe(struct sock *sk, struct sk_buff *skb) -{ - struct nr_sock *nr = nr_sk(sk); - - if (skb == NULL) - return; - - skb->data[2] = nr->vs; - skb->data[3] = nr->vr; - - if (nr->condition & NR_COND_OWN_RX_BUSY) - skb->data[4] |= NR_CHOKE_FLAG; - - nr_start_idletimer(sk); - - nr_transmit_buffer(sk, skb); -} - -void nr_send_nak_frame(struct sock *sk) -{ - struct sk_buff *skb, *skbn; - struct nr_sock *nr = nr_sk(sk); - - if ((skb = skb_peek(&nr->ack_queue)) == NULL) - return; - - if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) - return; - - skbn->data[2] = nr->va; - skbn->data[3] = nr->vr; - - if (nr->condition & NR_COND_OWN_RX_BUSY) - skbn->data[4] |= NR_CHOKE_FLAG; - - nr_transmit_buffer(sk, skbn); - - nr->condition &= ~NR_COND_ACK_PENDING; - nr->vl = nr->vr; - - nr_stop_t1timer(sk); -} - -void nr_kick(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - struct sk_buff *skb, *skbn; - unsigned short start, end; - - if (nr->state != NR_STATE_3) - return; - - if (nr->condition & NR_COND_PEER_RX_BUSY) - return; - - if (!skb_peek(&sk->sk_write_queue)) - return; - - start = (skb_peek(&nr->ack_queue) == NULL) ? nr->va : nr->vs; - end = (nr->va + nr->window) % NR_MODULUS; - - if (start == end) - return; - - nr->vs = start; - - /* - * Transmit data until either we're out of data to send or - * the window is full. - */ - - /* - * Dequeue the frame and copy it. - */ - skb = skb_dequeue(&sk->sk_write_queue); - - do { - if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - skb_queue_head(&sk->sk_write_queue, skb); - break; - } - - skb_set_owner_w(skbn, sk); - - /* - * Transmit the frame copy. - */ - nr_send_iframe(sk, skbn); - - nr->vs = (nr->vs + 1) % NR_MODULUS; - - /* - * Requeue the original data frame. - */ - skb_queue_tail(&nr->ack_queue, skb); - - } while (nr->vs != end && - (skb = skb_dequeue(&sk->sk_write_queue)) != NULL); - - nr->vl = nr->vr; - nr->condition &= ~NR_COND_ACK_PENDING; - - if (!nr_t1timer_running(sk)) - nr_start_t1timer(sk); -} - -void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) -{ - struct nr_sock *nr = nr_sk(sk); - unsigned char *dptr; - - /* - * Add the protocol byte and network header. - */ - dptr = skb_push(skb, NR_NETWORK_LEN); - - memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] &= ~AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - - memcpy(dptr, &nr->dest_addr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] |= AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - - *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser); - - if (!nr_route_frame(skb, NULL)) { - kfree_skb(skb); - nr_disconnect(sk, ENETUNREACH); - } -} - -/* - * The following routines are taken from page 170 of the 7th ARRL Computer - * Networking Conference paper, as is the whole state machine. - */ - -void nr_establish_data_link(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - - nr->condition = 0x00; - nr->n2count = 0; - - nr_write_internal(sk, NR_CONNREQ); - - nr_stop_t2timer(sk); - nr_stop_t4timer(sk); - nr_stop_idletimer(sk); - nr_start_t1timer(sk); -} - -/* - * Never send a NAK when we are CHOKEd. - */ -void nr_enquiry_response(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - int frametype = NR_INFOACK; - - if (nr->condition & NR_COND_OWN_RX_BUSY) { - frametype |= NR_CHOKE_FLAG; - } else { - if (skb_peek(&nr->reseq_queue) != NULL) - frametype |= NR_NAK_FLAG; - } - - nr_write_internal(sk, frametype); - - nr->vl = nr->vr; - nr->condition &= ~NR_COND_ACK_PENDING; -} - -void nr_check_iframes_acked(struct sock *sk, unsigned short nr) -{ - struct nr_sock *nrom = nr_sk(sk); - - if (nrom->vs == nr) { - nr_frames_acked(sk, nr); - nr_stop_t1timer(sk); - nrom->n2count = 0; - } else { - if (nrom->va != nr) { - nr_frames_acked(sk, nr); - nr_start_t1timer(sk); - } - } -} diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c deleted file mode 100644 index 9cc29ae85b06..000000000000 --- a/net/netrom/nr_route.c +++ /dev/null @@ -1,989 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For TIOCINQ/OUTQ */ -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned int nr_neigh_no = 1; - -static HLIST_HEAD(nr_node_list); -static DEFINE_SPINLOCK(nr_node_list_lock); -static HLIST_HEAD(nr_neigh_list); -static DEFINE_SPINLOCK(nr_neigh_list_lock); - -static struct nr_node *nr_node_get(ax25_address *callsign) -{ - struct nr_node *found = NULL; - struct nr_node *nr_node; - - spin_lock_bh(&nr_node_list_lock); - nr_node_for_each(nr_node, &nr_node_list) - if (ax25cmp(callsign, &nr_node->callsign) == 0) { - nr_node_hold(nr_node); - found = nr_node; - break; - } - spin_unlock_bh(&nr_node_list_lock); - return found; -} - -static struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign, - struct net_device *dev) -{ - struct nr_neigh *found = NULL; - struct nr_neigh *nr_neigh; - - spin_lock_bh(&nr_neigh_list_lock); - nr_neigh_for_each(nr_neigh, &nr_neigh_list) - if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && - nr_neigh->dev == dev) { - nr_neigh_hold(nr_neigh); - found = nr_neigh; - break; - } - spin_unlock_bh(&nr_neigh_list_lock); - return found; -} - -static void nr_remove_neigh(struct nr_neigh *); - -/* re-sort the routes in quality order. */ -static void re_sort_routes(struct nr_node *nr_node, int x, int y) -{ - if (nr_node->routes[y].quality > nr_node->routes[x].quality) { - if (nr_node->which == x) - nr_node->which = y; - else if (nr_node->which == y) - nr_node->which = x; - - swap(nr_node->routes[x], nr_node->routes[y]); - } -} - -/* - * Add a new route to a node, and in the process add the node and the - * neighbour if it is new. - */ -static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic, - ax25_address *ax25, ax25_digi *ax25_digi, struct net_device *dev, - int quality, int obs_count) -{ - struct nr_node *nr_node; - struct nr_neigh *nr_neigh; - int i, found; - struct net_device *odev; - - if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */ - dev_put(odev); - return -EINVAL; - } - - nr_node = nr_node_get(nr); - - nr_neigh = nr_neigh_get_dev(ax25, dev); - - /* - * The L2 link to a neighbour has failed in the past - * and now a frame comes from this neighbour. We assume - * it was a temporary trouble with the link and reset the - * routes now (and not wait for a node broadcast). - */ - if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) { - struct nr_node *nr_nodet; - - spin_lock_bh(&nr_node_list_lock); - nr_node_for_each(nr_nodet, &nr_node_list) { - nr_node_lock(nr_nodet); - for (i = 0; i < nr_nodet->count; i++) - if (nr_nodet->routes[i].neighbour == nr_neigh) - if (i < nr_nodet->which) - nr_nodet->which = i; - nr_node_unlock(nr_nodet); - } - spin_unlock_bh(&nr_node_list_lock); - } - - if (nr_neigh != NULL) - nr_neigh->failed = 0; - - if (quality == 0 && nr_neigh != NULL && nr_node != NULL) { - nr_neigh_put(nr_neigh); - nr_node_put(nr_node); - return 0; - } - - if (nr_neigh == NULL) { - if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) { - if (nr_node) - nr_node_put(nr_node); - return -ENOMEM; - } - - nr_neigh->callsign = *ax25; - nr_neigh->digipeat = NULL; - nr_neigh->ax25 = NULL; - nr_neigh->dev = dev; - nr_neigh->quality = READ_ONCE(sysctl_netrom_default_path_quality); - nr_neigh->locked = 0; - nr_neigh->count = 0; - nr_neigh->number = nr_neigh_no++; - nr_neigh->failed = 0; - refcount_set(&nr_neigh->refcount, 1); - - if (ax25_digi != NULL && ax25_digi->ndigi > 0) { - nr_neigh->digipeat = kmemdup(ax25_digi, - sizeof(*ax25_digi), - GFP_KERNEL); - if (nr_neigh->digipeat == NULL) { - kfree(nr_neigh); - if (nr_node) - nr_node_put(nr_node); - return -ENOMEM; - } - } - - spin_lock_bh(&nr_neigh_list_lock); - hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list); - nr_neigh_hold(nr_neigh); - spin_unlock_bh(&nr_neigh_list_lock); - } - - if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked) - nr_neigh->quality = quality; - - if (nr_node == NULL) { - if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) { - if (nr_neigh) - nr_neigh_put(nr_neigh); - return -ENOMEM; - } - - nr_node->callsign = *nr; - strscpy(nr_node->mnemonic, mnemonic); - - nr_node->which = 0; - nr_node->count = 1; - refcount_set(&nr_node->refcount, 1); - spin_lock_init(&nr_node->node_lock); - - nr_node->routes[0].quality = quality; - nr_node->routes[0].obs_count = obs_count; - nr_node->routes[0].neighbour = nr_neigh; - - nr_neigh_hold(nr_neigh); - nr_neigh->count++; - - spin_lock_bh(&nr_node_list_lock); - hlist_add_head(&nr_node->node_node, &nr_node_list); - /* refcount initialized at 1 */ - spin_unlock_bh(&nr_node_list_lock); - - nr_neigh_put(nr_neigh); - return 0; - } - nr_node_lock(nr_node); - - if (quality != 0) - strscpy(nr_node->mnemonic, mnemonic); - - for (found = 0, i = 0; i < nr_node->count; i++) { - if (nr_node->routes[i].neighbour == nr_neigh) { - nr_node->routes[i].quality = quality; - nr_node->routes[i].obs_count = obs_count; - found = 1; - break; - } - } - - if (!found) { - /* We have space at the bottom, slot it in */ - if (nr_node->count < 3) { - nr_node->routes[2] = nr_node->routes[1]; - nr_node->routes[1] = nr_node->routes[0]; - - nr_node->routes[0].quality = quality; - nr_node->routes[0].obs_count = obs_count; - nr_node->routes[0].neighbour = nr_neigh; - - nr_node->which++; - nr_node->count++; - nr_neigh_hold(nr_neigh); - nr_neigh->count++; - } else { - /* It must be better than the worst */ - if (quality > nr_node->routes[2].quality) { - nr_node->routes[2].neighbour->count--; - nr_neigh_put(nr_node->routes[2].neighbour); - - if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked) - nr_remove_neigh(nr_node->routes[2].neighbour); - - nr_node->routes[2].quality = quality; - nr_node->routes[2].obs_count = obs_count; - nr_node->routes[2].neighbour = nr_neigh; - - nr_neigh_hold(nr_neigh); - nr_neigh->count++; - } - } - } - - /* Now re-sort the routes in quality order */ - switch (nr_node->count) { - case 3: - re_sort_routes(nr_node, 0, 1); - re_sort_routes(nr_node, 1, 2); - fallthrough; - case 2: - re_sort_routes(nr_node, 0, 1); - break; - case 1: - break; - } - - for (i = 0; i < nr_node->count; i++) { - if (nr_node->routes[i].neighbour == nr_neigh) { - if (i < nr_node->which) - nr_node->which = i; - break; - } - } - - nr_neigh_put(nr_neigh); - nr_node_unlock(nr_node); - nr_node_put(nr_node); - return 0; -} - -static void nr_remove_node_locked(struct nr_node *nr_node) -{ - lockdep_assert_held(&nr_node_list_lock); - - hlist_del_init(&nr_node->node_node); - nr_node_put(nr_node); -} - -static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh) -{ - hlist_del_init(&nr_neigh->neigh_node); - nr_neigh_put(nr_neigh); -} - -#define nr_remove_neigh_locked(__neigh) \ - __nr_remove_neigh(__neigh) - -static void nr_remove_neigh(struct nr_neigh *nr_neigh) -{ - spin_lock_bh(&nr_neigh_list_lock); - __nr_remove_neigh(nr_neigh); - spin_unlock_bh(&nr_neigh_list_lock); -} - -/* - * "Delete" a node. Strictly speaking remove a route to a node. The node - * is only deleted if no routes are left to it. - */ -static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev) -{ - struct nr_node *nr_node; - struct nr_neigh *nr_neigh; - int i; - - nr_node = nr_node_get(callsign); - - if (nr_node == NULL) - return -EINVAL; - - nr_neigh = nr_neigh_get_dev(neighbour, dev); - - if (nr_neigh == NULL) { - nr_node_put(nr_node); - return -EINVAL; - } - - spin_lock_bh(&nr_node_list_lock); - nr_node_lock(nr_node); - for (i = 0; i < nr_node->count; i++) { - if (nr_node->routes[i].neighbour == nr_neigh) { - nr_neigh->count--; - nr_neigh_put(nr_neigh); - - if (nr_neigh->count == 0 && !nr_neigh->locked) - nr_remove_neigh(nr_neigh); - nr_neigh_put(nr_neigh); - - nr_node->count--; - - if (nr_node->count == 0) { - nr_remove_node_locked(nr_node); - } else { - switch (i) { - case 0: - nr_node->routes[0] = nr_node->routes[1]; - fallthrough; - case 1: - nr_node->routes[1] = nr_node->routes[2]; - fallthrough; - case 2: - break; - } - nr_node_put(nr_node); - } - nr_node_unlock(nr_node); - spin_unlock_bh(&nr_node_list_lock); - - return 0; - } - } - nr_neigh_put(nr_neigh); - nr_node_unlock(nr_node); - spin_unlock_bh(&nr_node_list_lock); - nr_node_put(nr_node); - - return -EINVAL; -} - -/* - * Lock a neighbour with a quality. - */ -static int __must_check nr_add_neigh(ax25_address *callsign, - ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality) -{ - struct nr_neigh *nr_neigh; - - nr_neigh = nr_neigh_get_dev(callsign, dev); - if (nr_neigh) { - nr_neigh->quality = quality; - nr_neigh->locked = 1; - nr_neigh_put(nr_neigh); - return 0; - } - - if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) - return -ENOMEM; - - nr_neigh->callsign = *callsign; - nr_neigh->digipeat = NULL; - nr_neigh->ax25 = NULL; - nr_neigh->dev = dev; - nr_neigh->quality = quality; - nr_neigh->locked = 1; - nr_neigh->count = 0; - nr_neigh->number = nr_neigh_no++; - nr_neigh->failed = 0; - refcount_set(&nr_neigh->refcount, 1); - - if (ax25_digi != NULL && ax25_digi->ndigi > 0) { - nr_neigh->digipeat = kmemdup(ax25_digi, sizeof(*ax25_digi), - GFP_KERNEL); - if (nr_neigh->digipeat == NULL) { - kfree(nr_neigh); - return -ENOMEM; - } - } - - spin_lock_bh(&nr_neigh_list_lock); - hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list); - /* refcount is initialized at 1 */ - spin_unlock_bh(&nr_neigh_list_lock); - - return 0; -} - -/* - * "Delete" a neighbour. The neighbour is only removed if the number - * of nodes that may use it is zero. - */ -static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality) -{ - struct nr_neigh *nr_neigh; - - nr_neigh = nr_neigh_get_dev(callsign, dev); - - if (nr_neigh == NULL) return -EINVAL; - - nr_neigh->quality = quality; - nr_neigh->locked = 0; - - if (nr_neigh->count == 0) - nr_remove_neigh(nr_neigh); - nr_neigh_put(nr_neigh); - - return 0; -} - -/* - * Decrement the obsolescence count by one. If a route is reduced to a - * count of zero, remove it. Also remove any unlocked neighbours with - * zero nodes routing via it. - */ -static int nr_dec_obs(void) -{ - struct nr_neigh *nr_neigh; - struct nr_node *s; - struct hlist_node *nodet; - int i; - - spin_lock_bh(&nr_node_list_lock); - nr_node_for_each_safe(s, nodet, &nr_node_list) { - nr_node_lock(s); - for (i = 0; i < s->count; i++) { - switch (s->routes[i].obs_count) { - case 0: /* A locked entry */ - break; - - case 1: /* From 1 -> 0 */ - nr_neigh = s->routes[i].neighbour; - - nr_neigh->count--; - nr_neigh_put(nr_neigh); - - if (nr_neigh->count == 0 && !nr_neigh->locked) - nr_remove_neigh(nr_neigh); - - s->count--; - - switch (i) { - case 0: - s->routes[0] = s->routes[1]; - fallthrough; - case 1: - s->routes[1] = s->routes[2]; - break; - case 2: - break; - } - break; - - default: - s->routes[i].obs_count--; - break; - - } - } - - if (s->count <= 0) - nr_remove_node_locked(s); - nr_node_unlock(s); - } - spin_unlock_bh(&nr_node_list_lock); - - return 0; -} - -/* - * A device has been removed. Remove its routes and neighbours. - */ -void nr_rt_device_down(struct net_device *dev) -{ - struct nr_neigh *s; - struct hlist_node *nodet, *node2t; - struct nr_node *t; - int i; - - spin_lock_bh(&nr_neigh_list_lock); - nr_neigh_for_each_safe(s, nodet, &nr_neigh_list) { - if (s->dev == dev) { - spin_lock_bh(&nr_node_list_lock); - nr_node_for_each_safe(t, node2t, &nr_node_list) { - nr_node_lock(t); - for (i = 0; i < t->count; i++) { - if (t->routes[i].neighbour == s) { - t->count--; - - switch (i) { - case 0: - t->routes[0] = t->routes[1]; - fallthrough; - case 1: - t->routes[1] = t->routes[2]; - break; - case 2: - break; - } - } - } - - if (t->count <= 0) - nr_remove_node_locked(t); - nr_node_unlock(t); - } - spin_unlock_bh(&nr_node_list_lock); - - nr_remove_neigh_locked(s); - } - } - spin_unlock_bh(&nr_neigh_list_lock); -} - -/* - * Check that the device given is a valid AX.25 interface that is "up". - * Or a valid ethernet interface with an AX.25 callsign binding. - */ -static struct net_device *nr_ax25_dev_get(char *devname) -{ - struct net_device *dev; - - if ((dev = dev_get_by_name(&init_net, devname)) == NULL) - return NULL; - - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) - return dev; - - dev_put(dev); - return NULL; -} - -/* - * Find the first active NET/ROM device, usually "nr0". - */ -struct net_device *nr_dev_first(void) -{ - struct net_device *dev, *first = NULL; - - rcu_read_lock(); - for_each_netdev_rcu(&init_net, dev) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM) - if (first == NULL || strncmp(dev->name, first->name, 3) < 0) - first = dev; - } - dev_hold(first); - rcu_read_unlock(); - - return first; -} - -/* - * Find the NET/ROM device for the given callsign. - */ -struct net_device *nr_dev_get(ax25_address *addr) -{ - struct net_device *dev; - - rcu_read_lock(); - for_each_netdev_rcu(&init_net, dev) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && - ax25cmp(addr, (const ax25_address *)dev->dev_addr) == 0) { - dev_hold(dev); - goto out; - } - } - dev = NULL; -out: - rcu_read_unlock(); - return dev; -} - -static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis, - ax25_address *digipeaters) -{ - int i; - - if (ndigis == 0) - return NULL; - - for (i = 0; i < ndigis; i++) { - digi->calls[i] = digipeaters[i]; - digi->repeated[i] = 0; - } - - digi->ndigi = ndigis; - digi->lastrepeat = -1; - - return digi; -} - -/* - * Handle the ioctls that control the routing functions. - */ -int nr_rt_ioctl(unsigned int cmd, void __user *arg) -{ - struct nr_route_struct nr_route; - struct net_device *dev; - ax25_digi digi; - int ret; - - switch (cmd) { - case SIOCADDRT: - if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) - return -EFAULT; - if (nr_route.ndigis > AX25_MAX_DIGIS) - return -EINVAL; - if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) - return -EINVAL; - switch (nr_route.type) { - case NETROM_NODE: - if (strnlen(nr_route.mnemonic, 7) == 7) { - ret = -EINVAL; - break; - } - - ret = nr_add_node(&nr_route.callsign, - nr_route.mnemonic, - &nr_route.neighbour, - nr_call_to_digi(&digi, nr_route.ndigis, - nr_route.digipeaters), - dev, nr_route.quality, - nr_route.obs_count); - break; - case NETROM_NEIGH: - ret = nr_add_neigh(&nr_route.callsign, - nr_call_to_digi(&digi, nr_route.ndigis, - nr_route.digipeaters), - dev, nr_route.quality); - break; - default: - ret = -EINVAL; - } - dev_put(dev); - return ret; - - case SIOCDELRT: - if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) - return -EFAULT; - if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) - return -EINVAL; - switch (nr_route.type) { - case NETROM_NODE: - ret = nr_del_node(&nr_route.callsign, - &nr_route.neighbour, dev); - break; - case NETROM_NEIGH: - ret = nr_del_neigh(&nr_route.callsign, - dev, nr_route.quality); - break; - default: - ret = -EINVAL; - } - dev_put(dev); - return ret; - - case SIOCNRDECOBS: - return nr_dec_obs(); - - default: - return -EINVAL; - } - - return 0; -} - -/* - * A level 2 link has timed out, therefore it appears to be a poor link, - * then don't use that neighbour until it is reset. - */ -void nr_link_failed(ax25_cb *ax25, int reason) -{ - struct nr_neigh *s, *nr_neigh = NULL; - struct nr_node *nr_node = NULL; - - spin_lock_bh(&nr_neigh_list_lock); - nr_neigh_for_each(s, &nr_neigh_list) { - if (s->ax25 == ax25) { - nr_neigh_hold(s); - nr_neigh = s; - break; - } - } - spin_unlock_bh(&nr_neigh_list_lock); - - if (nr_neigh == NULL) - return; - - nr_neigh->ax25 = NULL; - ax25_cb_put(ax25); - - if (++nr_neigh->failed < READ_ONCE(sysctl_netrom_link_fails_count)) { - nr_neigh_put(nr_neigh); - return; - } - spin_lock_bh(&nr_node_list_lock); - nr_node_for_each(nr_node, &nr_node_list) { - nr_node_lock(nr_node); - if (nr_node->which < nr_node->count && - nr_node->routes[nr_node->which].neighbour == nr_neigh) - nr_node->which++; - nr_node_unlock(nr_node); - } - spin_unlock_bh(&nr_node_list_lock); - nr_neigh_put(nr_neigh); -} - -/* - * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb - * indicates an internally generated frame. - */ -int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) -{ - ax25_address *nr_src, *nr_dest; - struct nr_neigh *nr_neigh; - struct nr_node *nr_node; - struct net_device *dev; - unsigned char *dptr; - ax25_cb *ax25s; - int ret; - struct sk_buff *nskb, *oskb; - - /* - * Reject malformed packets early. Check that it contains at least 2 - * addresses and 1 byte more for Time-To-Live - */ - if (skb->len < 2 * sizeof(ax25_address) + 1) - return 0; - - nr_src = (ax25_address *)(skb->data + 0); - nr_dest = (ax25_address *)(skb->data + 7); - - if (ax25 != NULL) { - ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, - ax25->ax25_dev->dev, 0, - READ_ONCE(sysctl_netrom_obsolescence_count_initialiser)); - if (ret) - return ret; - } - - if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */ - if (ax25 == NULL) /* Its from me */ - ret = nr_loopback_queue(skb); - else - ret = nr_rx_frame(skb, dev); - dev_put(dev); - return ret; - } - - if (!READ_ONCE(sysctl_netrom_routing_control) && ax25 != NULL) - return 0; - - /* Its Time-To-Live has expired */ - if (skb->data[14] == 1) { - return 0; - } - - nr_node = nr_node_get(nr_dest); - if (nr_node == NULL) - return 0; - nr_node_lock(nr_node); - - if (nr_node->which >= nr_node->count) { - nr_node_unlock(nr_node); - nr_node_put(nr_node); - return 0; - } - - nr_neigh = nr_node->routes[nr_node->which].neighbour; - - if ((dev = nr_dev_first()) == NULL) { - nr_node_unlock(nr_node); - nr_node_put(nr_node); - return 0; - } - - /* We are going to change the netrom headers so we should get our - own skb, we also did not know until now how much header space - we had to reserve... - RXQ */ - nskb = skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC); - - if (!nskb) { - nr_node_unlock(nr_node); - nr_node_put(nr_node); - dev_put(dev); - return 0; - } - oskb = skb; - skb = nskb; - skb->data[14]--; - - dptr = skb_push(skb, 1); - *dptr = AX25_P_NETROM; - - ax25s = nr_neigh->ax25; - nr_neigh->ax25 = ax25_send_frame(skb, 256, - (const ax25_address *)dev->dev_addr, - &nr_neigh->callsign, - nr_neigh->digipeat, nr_neigh->dev); - if (ax25s) - ax25_cb_put(ax25s); - - dev_put(dev); - ret = (nr_neigh->ax25 != NULL); - nr_node_unlock(nr_node); - nr_node_put(nr_node); - - if (ret) - kfree_skb(oskb); - - return ret; -} - -#ifdef CONFIG_PROC_FS - -static void *nr_node_start(struct seq_file *seq, loff_t *pos) - __acquires(&nr_node_list_lock) -{ - spin_lock_bh(&nr_node_list_lock); - return seq_hlist_start_head(&nr_node_list, *pos); -} - -static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_hlist_next(v, &nr_node_list, pos); -} - -static void nr_node_stop(struct seq_file *seq, void *v) - __releases(&nr_node_list_lock) -{ - spin_unlock_bh(&nr_node_list_lock); -} - -static int nr_node_show(struct seq_file *seq, void *v) -{ - char buf[11]; - int i; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, - "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); - else { - struct nr_node *nr_node = hlist_entry(v, struct nr_node, - node_node); - - nr_node_lock(nr_node); - seq_printf(seq, "%-9s %-7s %d %d", - ax2asc(buf, &nr_node->callsign), - (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic, - nr_node->which + 1, - nr_node->count); - - for (i = 0; i < nr_node->count; i++) { - seq_printf(seq, " %3d %d %05d", - nr_node->routes[i].quality, - nr_node->routes[i].obs_count, - nr_node->routes[i].neighbour->number); - } - nr_node_unlock(nr_node); - - seq_puts(seq, "\n"); - } - return 0; -} - -const struct seq_operations nr_node_seqops = { - .start = nr_node_start, - .next = nr_node_next, - .stop = nr_node_stop, - .show = nr_node_show, -}; - -static void *nr_neigh_start(struct seq_file *seq, loff_t *pos) - __acquires(&nr_neigh_list_lock) -{ - spin_lock_bh(&nr_neigh_list_lock); - return seq_hlist_start_head(&nr_neigh_list, *pos); -} - -static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_hlist_next(v, &nr_neigh_list, pos); -} - -static void nr_neigh_stop(struct seq_file *seq, void *v) - __releases(&nr_neigh_list_lock) -{ - spin_unlock_bh(&nr_neigh_list_lock); -} - -static int nr_neigh_show(struct seq_file *seq, void *v) -{ - char buf[11]; - int i; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n"); - else { - struct nr_neigh *nr_neigh; - - nr_neigh = hlist_entry(v, struct nr_neigh, neigh_node); - seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d", - nr_neigh->number, - ax2asc(buf, &nr_neigh->callsign), - nr_neigh->dev ? nr_neigh->dev->name : "???", - nr_neigh->quality, - nr_neigh->locked, - nr_neigh->count, - nr_neigh->failed); - - if (nr_neigh->digipeat != NULL) { - for (i = 0; i < nr_neigh->digipeat->ndigi; i++) - seq_printf(seq, " %s", - ax2asc(buf, &nr_neigh->digipeat->calls[i])); - } - - seq_puts(seq, "\n"); - } - return 0; -} - -const struct seq_operations nr_neigh_seqops = { - .start = nr_neigh_start, - .next = nr_neigh_next, - .stop = nr_neigh_stop, - .show = nr_neigh_show, -}; -#endif - -/* - * Free all memory associated with the nodes and routes lists. - */ -void nr_rt_free(void) -{ - struct nr_neigh *s = NULL; - struct nr_node *t = NULL; - struct hlist_node *nodet; - - spin_lock_bh(&nr_neigh_list_lock); - spin_lock_bh(&nr_node_list_lock); - nr_node_for_each_safe(t, nodet, &nr_node_list) { - nr_node_lock(t); - nr_remove_node_locked(t); - nr_node_unlock(t); - } - nr_neigh_for_each_safe(s, nodet, &nr_neigh_list) { - while(s->count) { - s->count--; - nr_neigh_put(s); - } - nr_remove_neigh_locked(s); - } - spin_unlock_bh(&nr_node_list_lock); - spin_unlock_bh(&nr_neigh_list_lock); -} diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c deleted file mode 100644 index c3bbd5880850..000000000000 --- a/net/netrom/nr_subr.c +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This routine purges all of the queues of frames. - */ -void nr_clear_queues(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - - skb_queue_purge(&sk->sk_write_queue); - skb_queue_purge(&nr->ack_queue); - skb_queue_purge(&nr->reseq_queue); - skb_queue_purge(&nr->frag_queue); -} - -/* - * This routine purges the input queue of those frames that have been - * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the - * SDL diagram. - */ -void nr_frames_acked(struct sock *sk, unsigned short nr) -{ - struct nr_sock *nrom = nr_sk(sk); - struct sk_buff *skb; - - /* - * Remove all the ack-ed frames from the ack queue. - */ - if (nrom->va != nr) { - while (skb_peek(&nrom->ack_queue) != NULL && nrom->va != nr) { - skb = skb_dequeue(&nrom->ack_queue); - kfree_skb(skb); - nrom->va = (nrom->va + 1) % NR_MODULUS; - } - } -} - -/* - * Requeue all the un-ack-ed frames on the output queue to be picked - * up by nr_kick called from the timer. This arrangement handles the - * possibility of an empty output queue. - */ -void nr_requeue_frames(struct sock *sk) -{ - struct sk_buff *skb, *skb_prev = NULL; - - while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) { - if (skb_prev == NULL) - skb_queue_head(&sk->sk_write_queue, skb); - else - skb_append(skb_prev, skb, &sk->sk_write_queue); - skb_prev = skb; - } -} - -/* - * Validate that the value of nr is between va and vs. Return true or - * false for testing. - */ -int nr_validate_nr(struct sock *sk, unsigned short nr) -{ - struct nr_sock *nrom = nr_sk(sk); - unsigned short vc = nrom->va; - - while (vc != nrom->vs) { - if (nr == vc) return 1; - vc = (vc + 1) % NR_MODULUS; - } - - return nr == nrom->vs; -} - -/* - * Check that ns is within the receive window. - */ -int nr_in_rx_window(struct sock *sk, unsigned short ns) -{ - struct nr_sock *nr = nr_sk(sk); - unsigned short vc = nr->vr; - unsigned short vt = (nr->vl + nr->window) % NR_MODULUS; - - while (vc != vt) { - if (ns == vc) return 1; - vc = (vc + 1) % NR_MODULUS; - } - - return 0; -} - -/* - * This routine is called when the HDLC layer internally generates a - * control frame. - */ -void nr_write_internal(struct sock *sk, int frametype) -{ - struct nr_sock *nr = nr_sk(sk); - struct sk_buff *skb; - unsigned char *dptr; - int len, timeout; - - len = NR_TRANSPORT_LEN; - - switch (frametype & 0x0F) { - case NR_CONNREQ: - len += 17; - break; - case NR_CONNACK: - len += (nr->bpqext) ? 2 : 1; - break; - case NR_DISCREQ: - case NR_DISCACK: - case NR_INFOACK: - break; - default: - printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype); - return; - } - - skb = alloc_skb(NR_NETWORK_LEN + len, GFP_ATOMIC); - if (!skb) - return; - - /* - * Space for AX.25 and NET/ROM network header - */ - skb_reserve(skb, NR_NETWORK_LEN); - - dptr = skb_put(skb, len); - - switch (frametype & 0x0F) { - case NR_CONNREQ: - timeout = nr->t1 / HZ; - *dptr++ = nr->my_index; - *dptr++ = nr->my_id; - *dptr++ = 0; - *dptr++ = 0; - *dptr++ = frametype; - *dptr++ = nr->window; - memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] &= ~AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] &= ~AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - *dptr++ = timeout % 256; - *dptr++ = timeout / 256; - break; - - case NR_CONNACK: - *dptr++ = nr->your_index; - *dptr++ = nr->your_id; - *dptr++ = nr->my_index; - *dptr++ = nr->my_id; - *dptr++ = frametype; - *dptr++ = nr->window; - if (nr->bpqext) - *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser); - break; - - case NR_DISCREQ: - case NR_DISCACK: - *dptr++ = nr->your_index; - *dptr++ = nr->your_id; - *dptr++ = 0; - *dptr++ = 0; - *dptr++ = frametype; - break; - - case NR_INFOACK: - *dptr++ = nr->your_index; - *dptr++ = nr->your_id; - *dptr++ = 0; - *dptr++ = nr->vr; - *dptr++ = frametype; - break; - } - - nr_transmit_buffer(sk, skb); -} - -/* - * This routine is called to send an error reply. - */ -void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags) -{ - struct sk_buff *skbn; - unsigned char *dptr; - int len; - - len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; - - if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL) - return; - - skb_reserve(skbn, 0); - - dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN); - - skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] &= ~AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - - skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN); - dptr[6] &= ~AX25_CBIT; - dptr[6] |= AX25_EBIT; - dptr[6] |= AX25_SSSID_SPARE; - dptr += AX25_ADDR_LEN; - - *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser); - - if (mine) { - *dptr++ = 0; - *dptr++ = 0; - *dptr++ = skb->data[15]; - *dptr++ = skb->data[16]; - } else { - *dptr++ = skb->data[15]; - *dptr++ = skb->data[16]; - *dptr++ = 0; - *dptr++ = 0; - } - - *dptr++ = cmdflags; - *dptr++ = 0; - - if (!nr_route_frame(skbn, NULL)) - kfree_skb(skbn); -} - -void nr_disconnect(struct sock *sk, int reason) -{ - nr_stop_t1timer(sk); - nr_stop_t2timer(sk); - nr_stop_t4timer(sk); - nr_stop_idletimer(sk); - - nr_clear_queues(sk); - - nr_sk(sk)->state = NR_STATE_0; - - sk->sk_state = TCP_CLOSE; - sk->sk_err = reason; - sk->sk_shutdown |= SEND_SHUTDOWN; - - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DEAD); - } -} diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c deleted file mode 100644 index b3a62b1f3a09..000000000000 --- a/net/netrom/nr_timer.c +++ /dev/null @@ -1,249 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void nr_heartbeat_expiry(struct timer_list *); -static void nr_t1timer_expiry(struct timer_list *); -static void nr_t2timer_expiry(struct timer_list *); -static void nr_t4timer_expiry(struct timer_list *); -static void nr_idletimer_expiry(struct timer_list *); - -void nr_init_timers(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - - timer_setup(&nr->t1timer, nr_t1timer_expiry, 0); - timer_setup(&nr->t2timer, nr_t2timer_expiry, 0); - timer_setup(&nr->t4timer, nr_t4timer_expiry, 0); - timer_setup(&nr->idletimer, nr_idletimer_expiry, 0); - - /* initialized by sock_init_data */ - sk->sk_timer.function = nr_heartbeat_expiry; -} - -void nr_start_t1timer(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - - sk_reset_timer(sk, &nr->t1timer, jiffies + nr->t1); -} - -void nr_start_t2timer(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - - sk_reset_timer(sk, &nr->t2timer, jiffies + nr->t2); -} - -void nr_start_t4timer(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - - sk_reset_timer(sk, &nr->t4timer, jiffies + nr->t4); -} - -void nr_start_idletimer(struct sock *sk) -{ - struct nr_sock *nr = nr_sk(sk); - - if (nr->idle > 0) - sk_reset_timer(sk, &nr->idletimer, jiffies + nr->idle); -} - -void nr_start_heartbeat(struct sock *sk) -{ - sk_reset_timer(sk, &sk->sk_timer, jiffies + 5 * HZ); -} - -void nr_stop_t1timer(struct sock *sk) -{ - sk_stop_timer(sk, &nr_sk(sk)->t1timer); -} - -void nr_stop_t2timer(struct sock *sk) -{ - sk_stop_timer(sk, &nr_sk(sk)->t2timer); -} - -void nr_stop_t4timer(struct sock *sk) -{ - sk_stop_timer(sk, &nr_sk(sk)->t4timer); -} - -void nr_stop_idletimer(struct sock *sk) -{ - sk_stop_timer(sk, &nr_sk(sk)->idletimer); -} - -void nr_stop_heartbeat(struct sock *sk) -{ - sk_stop_timer(sk, &sk->sk_timer); -} - -int nr_t1timer_running(struct sock *sk) -{ - return timer_pending(&nr_sk(sk)->t1timer); -} - -static void nr_heartbeat_expiry(struct timer_list *t) -{ - struct sock *sk = timer_container_of(sk, t, sk_timer); - struct nr_sock *nr = nr_sk(sk); - - bh_lock_sock(sk); - switch (nr->state) { - case NR_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (sock_flag(sk, SOCK_DESTROY) || - (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { - if (sk->sk_state == TCP_LISTEN) - sock_hold(sk); - bh_unlock_sock(sk); - nr_destroy_socket(sk); - goto out; - } - break; - - case NR_STATE_3: - /* - * Check for the state of the receive buffer. - */ - if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) && - (nr->condition & NR_COND_OWN_RX_BUSY)) { - nr->condition &= ~NR_COND_OWN_RX_BUSY; - nr->condition &= ~NR_COND_ACK_PENDING; - nr->vl = nr->vr; - nr_write_internal(sk, NR_INFOACK); - break; - } - break; - } - - nr_start_heartbeat(sk); - bh_unlock_sock(sk); -out: - sock_put(sk); -} - -static void nr_t2timer_expiry(struct timer_list *t) -{ - struct nr_sock *nr = timer_container_of(nr, t, t2timer); - struct sock *sk = &nr->sock; - - bh_lock_sock(sk); - if (nr->condition & NR_COND_ACK_PENDING) { - nr->condition &= ~NR_COND_ACK_PENDING; - nr_enquiry_response(sk); - } - bh_unlock_sock(sk); - sock_put(sk); -} - -static void nr_t4timer_expiry(struct timer_list *t) -{ - struct nr_sock *nr = timer_container_of(nr, t, t4timer); - struct sock *sk = &nr->sock; - - bh_lock_sock(sk); - nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY; - bh_unlock_sock(sk); - sock_put(sk); -} - -static void nr_idletimer_expiry(struct timer_list *t) -{ - struct nr_sock *nr = timer_container_of(nr, t, idletimer); - struct sock *sk = &nr->sock; - - bh_lock_sock(sk); - - nr_clear_queues(sk); - - nr->n2count = 0; - nr_write_internal(sk, NR_DISCREQ); - nr->state = NR_STATE_2; - - nr_start_t1timer(sk); - nr_stop_t2timer(sk); - nr_stop_t4timer(sk); - - sk->sk_state = TCP_CLOSE; - sk->sk_err = 0; - sk->sk_shutdown |= SEND_SHUTDOWN; - - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DEAD); - } - bh_unlock_sock(sk); - sock_put(sk); -} - -static void nr_t1timer_expiry(struct timer_list *t) -{ - struct nr_sock *nr = timer_container_of(nr, t, t1timer); - struct sock *sk = &nr->sock; - - bh_lock_sock(sk); - switch (nr->state) { - case NR_STATE_1: - if (nr->n2count == nr->n2) { - nr_disconnect(sk, ETIMEDOUT); - goto out; - } else { - nr->n2count++; - nr_write_internal(sk, NR_CONNREQ); - } - break; - - case NR_STATE_2: - if (nr->n2count == nr->n2) { - nr_disconnect(sk, ETIMEDOUT); - goto out; - } else { - nr->n2count++; - nr_write_internal(sk, NR_DISCREQ); - } - break; - - case NR_STATE_3: - if (nr->n2count == nr->n2) { - nr_disconnect(sk, ETIMEDOUT); - goto out; - } else { - nr->n2count++; - nr_requeue_frames(sk); - } - break; - } - - nr_start_t1timer(sk); -out: - bh_unlock_sock(sk); - sock_put(sk); -} diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c deleted file mode 100644 index 7dc0fa628f2e..000000000000 --- a/net/netrom/sysctl_net_netrom.c +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com) - */ -#include -#include -#include -#include -#include - -/* - * Values taken from NET/ROM documentation. - */ -static int min_quality[] = {0}, max_quality[] = {255}; -static int min_obs[] = {0}, max_obs[] = {255}; -static int min_ttl[] = {0}, max_ttl[] = {255}; -static int min_t1[] = {5 * HZ}; -static int max_t1[] = {600 * HZ}; -static int min_n2[] = {2}, max_n2[] = {127}; -static int min_t2[] = {1 * HZ}; -static int max_t2[] = {60 * HZ}; -static int min_t4[] = {1 * HZ}; -static int max_t4[] = {1000 * HZ}; -static int min_window[] = {1}, max_window[] = {127}; -static int min_idle[] = {0 * HZ}; -static int max_idle[] = {65535 * HZ}; -static int min_route[] = {0}, max_route[] = {1}; -static int min_fails[] = {1}, max_fails[] = {10}; -static int min_reset[] = {0}, max_reset[] = {1}; - -static struct ctl_table_header *nr_table_header; - -static struct ctl_table nr_table[] = { - { - .procname = "default_path_quality", - .data = &sysctl_netrom_default_path_quality, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_quality, - .extra2 = &max_quality - }, - { - .procname = "obsolescence_count_initialiser", - .data = &sysctl_netrom_obsolescence_count_initialiser, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_obs, - .extra2 = &max_obs - }, - { - .procname = "network_ttl_initialiser", - .data = &sysctl_netrom_network_ttl_initialiser, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_ttl, - .extra2 = &max_ttl - }, - { - .procname = "transport_timeout", - .data = &sysctl_netrom_transport_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_t1, - .extra2 = &max_t1 - }, - { - .procname = "transport_maximum_tries", - .data = &sysctl_netrom_transport_maximum_tries, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_n2, - .extra2 = &max_n2 - }, - { - .procname = "transport_acknowledge_delay", - .data = &sysctl_netrom_transport_acknowledge_delay, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_t2, - .extra2 = &max_t2 - }, - { - .procname = "transport_busy_delay", - .data = &sysctl_netrom_transport_busy_delay, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_t4, - .extra2 = &max_t4 - }, - { - .procname = "transport_requested_window_size", - .data = &sysctl_netrom_transport_requested_window_size, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_window, - .extra2 = &max_window - }, - { - .procname = "transport_no_activity_timeout", - .data = &sysctl_netrom_transport_no_activity_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_idle, - .extra2 = &max_idle - }, - { - .procname = "routing_control", - .data = &sysctl_netrom_routing_control, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_route, - .extra2 = &max_route - }, - { - .procname = "link_fails_count", - .data = &sysctl_netrom_link_fails_count, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_fails, - .extra2 = &max_fails - }, - { - .procname = "reset", - .data = &sysctl_netrom_reset_circuit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_reset, - .extra2 = &max_reset - }, -}; - -int __init nr_register_sysctl(void) -{ - nr_table_header = register_net_sysctl(&init_net, "net/netrom", nr_table); - if (!nr_table_header) - return -ENOMEM; - return 0; -} - -void nr_unregister_sysctl(void) -{ - unregister_net_sysctl_table(nr_table_header); -} diff --git a/net/rose/Makefile b/net/rose/Makefile deleted file mode 100644 index 3e6638f5ba57..000000000000 --- a/net/rose/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the Linux Rose (X.25 PLP) layer. -# - -obj-$(CONFIG_ROSE) += rose.o - -rose-y := af_rose.o rose_dev.o rose_in.o rose_link.o rose_loopback.o \ - rose_out.o rose_route.o rose_subr.o rose_timer.o -rose-$(CONFIG_SYSCTL) += sysctl_net_rose.o diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c deleted file mode 100644 index d5032840ee48..000000000000 --- a/net/rose/af_rose.c +++ /dev/null @@ -1,1687 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) - * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net) - * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi) - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int rose_ndevs = 10; - -int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0; -int sysctl_rose_call_request_timeout = ROSE_DEFAULT_T1; -int sysctl_rose_reset_request_timeout = ROSE_DEFAULT_T2; -int sysctl_rose_clear_request_timeout = ROSE_DEFAULT_T3; -int sysctl_rose_no_activity_timeout = ROSE_DEFAULT_IDLE; -int sysctl_rose_ack_hold_back_timeout = ROSE_DEFAULT_HB; -int sysctl_rose_routing_control = ROSE_DEFAULT_ROUTING; -int sysctl_rose_link_fail_timeout = ROSE_DEFAULT_FAIL_TIMEOUT; -int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC; -int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE; - -static HLIST_HEAD(rose_list); -static DEFINE_SPINLOCK(rose_list_lock); - -static const struct proto_ops rose_proto_ops; - -ax25_address rose_callsign; - -/* - * ROSE network devices are virtual network devices encapsulating ROSE - * frames into AX.25 which will be sent through an AX.25 device, so form a - * special "super class" of normal net devices; split their locks off into a - * separate class since they always nest. - */ -static struct lock_class_key rose_netdev_xmit_lock_key; -static struct lock_class_key rose_netdev_addr_lock_key; - -static void rose_set_lockdep_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, &rose_netdev_xmit_lock_key); -} - -static void rose_set_lockdep_key(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, &rose_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL); -} - -/* - * Convert a ROSE address into text. - */ -char *rose2asc(char *buf, const rose_address *addr) -{ - if (addr->rose_addr[0] == 0x00 && addr->rose_addr[1] == 0x00 && - addr->rose_addr[2] == 0x00 && addr->rose_addr[3] == 0x00 && - addr->rose_addr[4] == 0x00) { - strcpy(buf, "*"); - } else { - sprintf(buf, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF, - addr->rose_addr[1] & 0xFF, - addr->rose_addr[2] & 0xFF, - addr->rose_addr[3] & 0xFF, - addr->rose_addr[4] & 0xFF); - } - - return buf; -} - -/* - * Compare two ROSE addresses, 0 == equal. - */ -int rosecmp(const rose_address *addr1, const rose_address *addr2) -{ - int i; - - for (i = 0; i < 5; i++) - if (addr1->rose_addr[i] != addr2->rose_addr[i]) - return 1; - - return 0; -} - -/* - * Compare two ROSE addresses for only mask digits, 0 == equal. - */ -int rosecmpm(const rose_address *addr1, const rose_address *addr2, - unsigned short mask) -{ - unsigned int i, j; - - if (mask > 10) - return 1; - - for (i = 0; i < mask; i++) { - j = i / 2; - - if ((i % 2) != 0) { - if ((addr1->rose_addr[j] & 0x0F) != (addr2->rose_addr[j] & 0x0F)) - return 1; - } else { - if ((addr1->rose_addr[j] & 0xF0) != (addr2->rose_addr[j] & 0xF0)) - return 1; - } - } - - return 0; -} - -/* - * Socket removal during an interrupt is now safe. - */ -static void rose_remove_socket(struct sock *sk) -{ - spin_lock_bh(&rose_list_lock); - sk_del_node_init(sk); - spin_unlock_bh(&rose_list_lock); -} - -/* - * Kill all bound sockets on a broken link layer connection to a - * particular neighbour. - */ -void rose_kill_by_neigh(struct rose_neigh *neigh) -{ - struct sock *s; - - spin_lock_bh(&rose_list_lock); - sk_for_each(s, &rose_list) { - struct rose_sock *rose = rose_sk(s); - - if (rose->neighbour == neigh) { - rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); - rose_neigh_put(rose->neighbour); - rose->neighbour = NULL; - } - } - spin_unlock_bh(&rose_list_lock); -} - -/* - * Kill all bound sockets on a dropped device. - */ -static void rose_kill_by_device(struct net_device *dev) -{ - struct sock *sk, *array[16]; - struct rose_sock *rose; - bool rescan; - int i, cnt; - -start: - rescan = false; - cnt = 0; - spin_lock_bh(&rose_list_lock); - sk_for_each(sk, &rose_list) { - rose = rose_sk(sk); - if (rose->device == dev) { - if (cnt == ARRAY_SIZE(array)) { - rescan = true; - break; - } - sock_hold(sk); - array[cnt++] = sk; - } - } - spin_unlock_bh(&rose_list_lock); - - for (i = 0; i < cnt; i++) { - sk = array[i]; - rose = rose_sk(sk); - lock_sock(sk); - spin_lock_bh(&rose_list_lock); - if (rose->device == dev) { - rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); - if (rose->neighbour) - rose_neigh_put(rose->neighbour); - netdev_put(rose->device, &rose->dev_tracker); - rose->device = NULL; - } - spin_unlock_bh(&rose_list_lock); - release_sock(sk); - sock_put(sk); - cond_resched(); - } - if (rescan) - goto start; -} - -/* - * Handle device status changes. - */ -static int rose_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_DOWN) - return NOTIFY_DONE; - - switch (dev->type) { - case ARPHRD_ROSE: - rose_kill_by_device(dev); - break; - case ARPHRD_AX25: - rose_link_device_down(dev); - rose_rt_device_down(dev); - break; - } - - return NOTIFY_DONE; -} - -/* - * Add a socket to the bound sockets list. - */ -static void rose_insert_socket(struct sock *sk) -{ - - spin_lock_bh(&rose_list_lock); - sk_add_node(sk, &rose_list); - spin_unlock_bh(&rose_list_lock); -} - -/* - * Find a socket that wants to accept the Call Request we just - * received. - */ -static struct sock *rose_find_listener(rose_address *addr, ax25_address *call) -{ - struct sock *s; - - spin_lock_bh(&rose_list_lock); - sk_for_each(s, &rose_list) { - struct rose_sock *rose = rose_sk(s); - - if (!rosecmp(&rose->source_addr, addr) && - !ax25cmp(&rose->source_call, call) && - !rose->source_ndigis && s->sk_state == TCP_LISTEN) - goto found; - } - - sk_for_each(s, &rose_list) { - struct rose_sock *rose = rose_sk(s); - - if (!rosecmp(&rose->source_addr, addr) && - !ax25cmp(&rose->source_call, &null_ax25_address) && - s->sk_state == TCP_LISTEN) - goto found; - } - s = NULL; -found: - spin_unlock_bh(&rose_list_lock); - return s; -} - -/* - * Find a connected ROSE socket given my LCI and device. - */ -struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh) -{ - struct sock *s; - - spin_lock_bh(&rose_list_lock); - sk_for_each(s, &rose_list) { - struct rose_sock *rose = rose_sk(s); - - if (rose->lci == lci && rose->neighbour == neigh) - goto found; - } - s = NULL; -found: - spin_unlock_bh(&rose_list_lock); - return s; -} - -/* - * Find a unique LCI for a given device. - */ -unsigned int rose_new_lci(struct rose_neigh *neigh) -{ - int lci; - - if (neigh->dce_mode) { - for (lci = 1; lci <= sysctl_rose_maximum_vcs; lci++) - if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL) - return lci; - } else { - for (lci = sysctl_rose_maximum_vcs; lci > 0; lci--) - if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL) - return lci; - } - - return 0; -} - -/* - * Deferred destroy. - */ -void rose_destroy_socket(struct sock *); - -/* - * Handler for deferred kills. - */ -static void rose_destroy_timer(struct timer_list *t) -{ - struct sock *sk = timer_container_of(sk, t, sk_timer); - - rose_destroy_socket(sk); -} - -/* - * This is called from user mode and the timers. Thus it protects itself - * against interrupt users but doesn't worry about being called during - * work. Once it is removed from the queue no interrupt or bottom half - * will touch it and we are (fairly 8-) ) safe. - */ -void rose_destroy_socket(struct sock *sk) -{ - struct sk_buff *skb; - - rose_remove_socket(sk); - rose_stop_heartbeat(sk); - rose_stop_idletimer(sk); - rose_stop_timer(sk); - - rose_clear_queues(sk); /* Flush the queues */ - - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { - if (skb->sk != sk) { /* A pending connection */ - /* Queue the unaccepted socket for death */ - sock_set_flag(skb->sk, SOCK_DEAD); - rose_start_heartbeat(skb->sk); - rose_sk(skb->sk)->state = ROSE_STATE_0; - } - - kfree_skb(skb); - } - - if (sk_has_allocations(sk)) { - /* Defer: outstanding buffers */ - timer_setup(&sk->sk_timer, rose_destroy_timer, 0); - sk->sk_timer.expires = jiffies + 10 * HZ; - add_timer(&sk->sk_timer); - } else - sock_put(sk); -} - -/* - * Handling for system calls applied via the various interfaces to a - * ROSE socket object. - */ - -static int rose_setsockopt(struct socket *sock, int level, int optname, - sockptr_t optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - unsigned int opt; - - if (level != SOL_ROSE) - return -ENOPROTOOPT; - - if (optlen < sizeof(unsigned int)) - return -EINVAL; - - if (copy_from_sockptr(&opt, optval, sizeof(unsigned int))) - return -EFAULT; - - switch (optname) { - case ROSE_DEFER: - rose->defer = opt ? 1 : 0; - return 0; - - case ROSE_T1: - if (opt < 1 || opt > UINT_MAX / HZ) - return -EINVAL; - rose->t1 = opt * HZ; - return 0; - - case ROSE_T2: - if (opt < 1 || opt > UINT_MAX / HZ) - return -EINVAL; - rose->t2 = opt * HZ; - return 0; - - case ROSE_T3: - if (opt < 1 || opt > UINT_MAX / HZ) - return -EINVAL; - rose->t3 = opt * HZ; - return 0; - - case ROSE_HOLDBACK: - if (opt < 1 || opt > UINT_MAX / HZ) - return -EINVAL; - rose->hb = opt * HZ; - return 0; - - case ROSE_IDLE: - if (opt > UINT_MAX / (60 * HZ)) - return -EINVAL; - rose->idle = opt * 60 * HZ; - return 0; - - case ROSE_QBITINCL: - rose->qbitincl = opt ? 1 : 0; - return 0; - - default: - return -ENOPROTOOPT; - } -} - -static int rose_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - int val = 0; - int len; - - if (level != SOL_ROSE) - return -ENOPROTOOPT; - - if (get_user(len, optlen)) - return -EFAULT; - - if (len < 0) - return -EINVAL; - - switch (optname) { - case ROSE_DEFER: - val = rose->defer; - break; - - case ROSE_T1: - val = rose->t1 / HZ; - break; - - case ROSE_T2: - val = rose->t2 / HZ; - break; - - case ROSE_T3: - val = rose->t3 / HZ; - break; - - case ROSE_HOLDBACK: - val = rose->hb / HZ; - break; - - case ROSE_IDLE: - val = rose->idle / (60 * HZ); - break; - - case ROSE_QBITINCL: - val = rose->qbitincl; - break; - - default: - return -ENOPROTOOPT; - } - - len = min_t(unsigned int, len, sizeof(int)); - - if (put_user(len, optlen)) - return -EFAULT; - - return copy_to_user(optval, &val, len) ? -EFAULT : 0; -} - -static int rose_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - - lock_sock(sk); - if (sock->state != SS_UNCONNECTED) { - release_sock(sk); - return -EINVAL; - } - - if (sk->sk_state != TCP_LISTEN) { - struct rose_sock *rose = rose_sk(sk); - - rose->dest_ndigis = 0; - memset(&rose->dest_addr, 0, ROSE_ADDR_LEN); - memset(&rose->dest_call, 0, AX25_ADDR_LEN); - memset(rose->dest_digis, 0, AX25_ADDR_LEN * ROSE_MAX_DIGIS); - sk->sk_max_ack_backlog = backlog; - sk->sk_state = TCP_LISTEN; - release_sock(sk); - return 0; - } - release_sock(sk); - - return -EOPNOTSUPP; -} - -static struct proto rose_proto = { - .name = "ROSE", - .owner = THIS_MODULE, - .obj_size = sizeof(struct rose_sock), -}; - -static int rose_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct sock *sk; - struct rose_sock *rose; - - if (!net_eq(net, &init_net)) - return -EAFNOSUPPORT; - - if (sock->type != SOCK_SEQPACKET || protocol != 0) - return -ESOCKTNOSUPPORT; - - sk = sk_alloc(net, PF_ROSE, GFP_ATOMIC, &rose_proto, kern); - if (sk == NULL) - return -ENOMEM; - - rose = rose_sk(sk); - - sock_init_data(sock, sk); - - skb_queue_head_init(&rose->ack_queue); -#ifdef M_BIT - skb_queue_head_init(&rose->frag_queue); - rose->fraglen = 0; -#endif - - sock->ops = &rose_proto_ops; - sk->sk_protocol = protocol; - - timer_setup(&rose->timer, NULL, 0); - timer_setup(&rose->idletimer, NULL, 0); - - rose->t1 = msecs_to_jiffies(sysctl_rose_call_request_timeout); - rose->t2 = msecs_to_jiffies(sysctl_rose_reset_request_timeout); - rose->t3 = msecs_to_jiffies(sysctl_rose_clear_request_timeout); - rose->hb = msecs_to_jiffies(sysctl_rose_ack_hold_back_timeout); - rose->idle = msecs_to_jiffies(sysctl_rose_no_activity_timeout); - - rose->state = ROSE_STATE_0; - - return 0; -} - -static struct sock *rose_make_new(struct sock *osk) -{ - struct sock *sk; - struct rose_sock *rose, *orose; - - if (osk->sk_type != SOCK_SEQPACKET) - return NULL; - - sk = sk_alloc(sock_net(osk), PF_ROSE, GFP_ATOMIC, &rose_proto, 0); - if (sk == NULL) - return NULL; - - rose = rose_sk(sk); - - sock_init_data(NULL, sk); - - skb_queue_head_init(&rose->ack_queue); -#ifdef M_BIT - skb_queue_head_init(&rose->frag_queue); - rose->fraglen = 0; -#endif - - sk->sk_type = osk->sk_type; - sk->sk_priority = READ_ONCE(osk->sk_priority); - sk->sk_protocol = osk->sk_protocol; - sk->sk_rcvbuf = osk->sk_rcvbuf; - sk->sk_sndbuf = osk->sk_sndbuf; - sk->sk_state = TCP_ESTABLISHED; - sock_copy_flags(sk, osk); - - timer_setup(&rose->timer, NULL, 0); - timer_setup(&rose->idletimer, NULL, 0); - - orose = rose_sk(osk); - rose->t1 = orose->t1; - rose->t2 = orose->t2; - rose->t3 = orose->t3; - rose->hb = orose->hb; - rose->idle = orose->idle; - rose->defer = orose->defer; - rose->device = orose->device; - if (rose->device) - netdev_hold(rose->device, &rose->dev_tracker, GFP_ATOMIC); - rose->qbitincl = orose->qbitincl; - - return sk; -} - -static int rose_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose; - - if (sk == NULL) return 0; - - sock_hold(sk); - sock_orphan(sk); - lock_sock(sk); - rose = rose_sk(sk); - - switch (rose->state) { - case ROSE_STATE_0: - release_sock(sk); - rose_disconnect(sk, 0, -1, -1); - lock_sock(sk); - rose_destroy_socket(sk); - break; - - case ROSE_STATE_2: - rose_neigh_put(rose->neighbour); - release_sock(sk); - rose_disconnect(sk, 0, -1, -1); - lock_sock(sk); - rose_destroy_socket(sk); - break; - - case ROSE_STATE_1: - case ROSE_STATE_3: - case ROSE_STATE_4: - case ROSE_STATE_5: - rose_clear_queues(sk); - rose_stop_idletimer(sk); - rose_write_internal(sk, ROSE_CLEAR_REQUEST); - rose_start_t3timer(sk); - rose->state = ROSE_STATE_2; - sk->sk_state = TCP_CLOSE; - sk->sk_shutdown |= SEND_SHUTDOWN; - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DEAD); - sock_set_flag(sk, SOCK_DESTROY); - break; - - default: - break; - } - - spin_lock_bh(&rose_list_lock); - netdev_put(rose->device, &rose->dev_tracker); - rose->device = NULL; - spin_unlock_bh(&rose_list_lock); - sock->sk = NULL; - release_sock(sk); - sock_put(sk); - - return 0; -} - -static int rose_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; - struct net_device *dev; - ax25_address *source; - ax25_uid_assoc *user; - int err = -EINVAL; - int n; - - if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) - return -EINVAL; - - if (addr->srose_family != AF_ROSE) - return -EINVAL; - - if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1) - return -EINVAL; - - if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS) - return -EINVAL; - - lock_sock(sk); - - if (!sock_flag(sk, SOCK_ZAPPED)) - goto out_release; - - err = -EADDRNOTAVAIL; - dev = rose_dev_get(&addr->srose_addr); - if (!dev) - goto out_release; - - source = &addr->srose_call; - - user = ax25_findbyuid(current_euid()); - if (user) { - rose->source_call = user->call; - ax25_uid_put(user); - } else { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { - dev_put(dev); - err = -EACCES; - goto out_release; - } - rose->source_call = *source; - } - - rose->source_addr = addr->srose_addr; - rose->device = dev; - netdev_tracker_alloc(rose->device, &rose->dev_tracker, GFP_KERNEL); - rose->source_ndigis = addr->srose_ndigis; - - if (addr_len == sizeof(struct full_sockaddr_rose)) { - struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr; - for (n = 0 ; n < addr->srose_ndigis ; n++) - rose->source_digis[n] = full_addr->srose_digis[n]; - } else { - if (rose->source_ndigis == 1) { - rose->source_digis[0] = addr->srose_digi; - } - } - - rose_insert_socket(sk); - - sock_reset_flag(sk, SOCK_ZAPPED); - err = 0; -out_release: - release_sock(sk); - return err; -} - -static int rose_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len, - int flags) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; - unsigned char cause, diagnostic; - ax25_uid_assoc *user; - int n, err = 0; - - if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) - return -EINVAL; - - if (addr->srose_family != AF_ROSE) - return -EINVAL; - - if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1) - return -EINVAL; - - if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS) - return -EINVAL; - - /* Source + Destination digis should not exceed ROSE_MAX_DIGIS */ - if ((rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS) - return -EINVAL; - - lock_sock(sk); - - if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { - /* Connect completed during a ERESTARTSYS event */ - sock->state = SS_CONNECTED; - goto out_release; - } - - if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { - sock->state = SS_UNCONNECTED; - err = -ECONNREFUSED; - goto out_release; - } - - if (sk->sk_state == TCP_ESTABLISHED) { - /* No reconnect on a seqpacket socket */ - err = -EISCONN; - goto out_release; - } - - if (sk->sk_state == TCP_SYN_SENT) { - err = -EALREADY; - goto out_release; - } - - sk->sk_state = TCP_CLOSE; - sock->state = SS_UNCONNECTED; - - rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, - &diagnostic, 0); - if (!rose->neighbour) { - err = -ENETUNREACH; - goto out_release; - } - - rose->lci = rose_new_lci(rose->neighbour); - if (!rose->lci) { - err = -ENETUNREACH; - rose_neigh_put(rose->neighbour); - goto out_release; - } - - if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */ - struct net_device *dev; - - sock_reset_flag(sk, SOCK_ZAPPED); - - dev = rose_dev_first(); - if (!dev) { - err = -ENETUNREACH; - rose_neigh_put(rose->neighbour); - goto out_release; - } - - user = ax25_findbyuid(current_euid()); - if (!user) { - err = -EINVAL; - rose_neigh_put(rose->neighbour); - dev_put(dev); - goto out_release; - } - - memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); - rose->source_call = user->call; - rose->device = dev; - netdev_tracker_alloc(rose->device, &rose->dev_tracker, - GFP_KERNEL); - ax25_uid_put(user); - - rose_insert_socket(sk); /* Finish the bind */ - } - rose->dest_addr = addr->srose_addr; - rose->dest_call = addr->srose_call; - rose->rand = ((long)rose & 0xFFFF) + rose->lci; - rose->dest_ndigis = addr->srose_ndigis; - - if (addr_len == sizeof(struct full_sockaddr_rose)) { - struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr; - for (n = 0 ; n < addr->srose_ndigis ; n++) - rose->dest_digis[n] = full_addr->srose_digis[n]; - } else { - if (rose->dest_ndigis == 1) { - rose->dest_digis[0] = addr->srose_digi; - } - } - - /* Move to connecting socket, start sending Connect Requests */ - sock->state = SS_CONNECTING; - sk->sk_state = TCP_SYN_SENT; - - rose->state = ROSE_STATE_1; - - rose_write_internal(sk, ROSE_CALL_REQUEST); - rose_start_heartbeat(sk); - rose_start_t1timer(sk); - - /* Now the loop */ - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { - err = -EINPROGRESS; - goto out_release; - } - - /* - * A Connect Ack with Choke or timeout or failed routing will go to - * closed. - */ - if (sk->sk_state == TCP_SYN_SENT) { - DEFINE_WAIT(wait); - - for (;;) { - prepare_to_wait(sk_sleep(sk), &wait, - TASK_INTERRUPTIBLE); - if (sk->sk_state != TCP_SYN_SENT) - break; - if (!signal_pending(current)) { - release_sock(sk); - schedule(); - lock_sock(sk); - continue; - } - err = -ERESTARTSYS; - break; - } - finish_wait(sk_sleep(sk), &wait); - - if (err) - goto out_release; - } - - if (sk->sk_state != TCP_ESTABLISHED) { - sock->state = SS_UNCONNECTED; - err = sock_error(sk); /* Always set at this point */ - goto out_release; - } - - sock->state = SS_CONNECTED; - -out_release: - release_sock(sk); - - return err; -} - -static int rose_accept(struct socket *sock, struct socket *newsock, - struct proto_accept_arg *arg) -{ - struct sk_buff *skb; - struct sock *newsk; - DEFINE_WAIT(wait); - struct sock *sk; - int err = 0; - - if ((sk = sock->sk) == NULL) - return -EINVAL; - - lock_sock(sk); - if (sk->sk_type != SOCK_SEQPACKET) { - err = -EOPNOTSUPP; - goto out_release; - } - - if (sk->sk_state != TCP_LISTEN) { - err = -EINVAL; - goto out_release; - } - - /* - * The write queue this time is holding sockets ready to use - * hooked into the SABM we saved - */ - for (;;) { - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - skb = skb_dequeue(&sk->sk_receive_queue); - if (skb) - break; - - if (arg->flags & O_NONBLOCK) { - err = -EWOULDBLOCK; - break; - } - if (!signal_pending(current)) { - release_sock(sk); - schedule(); - lock_sock(sk); - continue; - } - err = -ERESTARTSYS; - break; - } - finish_wait(sk_sleep(sk), &wait); - if (err) - goto out_release; - - newsk = skb->sk; - sock_graft(newsk, newsock); - - /* Now attach up the new socket */ - skb->sk = NULL; - kfree_skb(skb); - sk_acceptq_removed(sk); - -out_release: - release_sock(sk); - - return err; -} - -static int rose_getname(struct socket *sock, struct sockaddr *uaddr, - int peer) -{ - struct full_sockaddr_rose *srose = (struct full_sockaddr_rose *)uaddr; - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - int n; - - memset(srose, 0, sizeof(*srose)); - if (peer != 0) { - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; - srose->srose_family = AF_ROSE; - srose->srose_addr = rose->dest_addr; - srose->srose_call = rose->dest_call; - srose->srose_ndigis = rose->dest_ndigis; - for (n = 0; n < rose->dest_ndigis; n++) - srose->srose_digis[n] = rose->dest_digis[n]; - } else { - srose->srose_family = AF_ROSE; - srose->srose_addr = rose->source_addr; - srose->srose_call = rose->source_call; - srose->srose_ndigis = rose->source_ndigis; - for (n = 0; n < rose->source_ndigis; n++) - srose->srose_digis[n] = rose->source_digis[n]; - } - - return sizeof(struct full_sockaddr_rose); -} - -int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct rose_neigh *neigh, unsigned int lci) -{ - struct sock *sk; - struct sock *make; - struct rose_sock *make_rose; - struct rose_facilities_struct facilities; - int n; - - skb->sk = NULL; /* Initially we don't know who it's for */ - - /* - * skb->data points to the rose frame start - */ - memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); - - if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF, - skb->len - ROSE_CALL_REQ_FACILITIES_OFF, - &facilities)) { - rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76); - return 0; - } - - sk = rose_find_listener(&facilities.source_addr, &facilities.source_call); - - /* - * We can't accept the Call Request. - */ - if (sk == NULL || sk_acceptq_is_full(sk) || - (make = rose_make_new(sk)) == NULL) { - rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120); - return 0; - } - - skb->sk = make; - make->sk_state = TCP_ESTABLISHED; - make_rose = rose_sk(make); - - make_rose->lci = lci; - make_rose->dest_addr = facilities.dest_addr; - make_rose->dest_call = facilities.dest_call; - make_rose->dest_ndigis = facilities.dest_ndigis; - for (n = 0 ; n < facilities.dest_ndigis ; n++) - make_rose->dest_digis[n] = facilities.dest_digis[n]; - make_rose->source_addr = facilities.source_addr; - make_rose->source_call = facilities.source_call; - make_rose->source_ndigis = facilities.source_ndigis; - for (n = 0 ; n < facilities.source_ndigis ; n++) - make_rose->source_digis[n] = facilities.source_digis[n]; - make_rose->neighbour = neigh; - make_rose->device = dev; - /* Caller got a reference for us. */ - netdev_tracker_alloc(make_rose->device, &make_rose->dev_tracker, - GFP_ATOMIC); - make_rose->facilities = facilities; - - rose_neigh_hold(make_rose->neighbour); - - if (rose_sk(sk)->defer) { - make_rose->state = ROSE_STATE_5; - } else { - rose_write_internal(make, ROSE_CALL_ACCEPTED); - make_rose->state = ROSE_STATE_3; - rose_start_idletimer(make); - } - - make_rose->condition = 0x00; - make_rose->vs = 0; - make_rose->va = 0; - make_rose->vr = 0; - make_rose->vl = 0; - sk_acceptq_added(sk); - - rose_insert_socket(make); - - skb_queue_head(&sk->sk_receive_queue, skb); - - rose_start_heartbeat(make); - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); - - return 1; -} - -static int rose_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_rose *, usrose, msg->msg_name); - int err; - struct full_sockaddr_rose srose; - struct sk_buff *skb; - unsigned char *asmptr; - int n, size, qbit = 0; - - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) - return -EINVAL; - - if (sock_flag(sk, SOCK_ZAPPED)) - return -EADDRNOTAVAIL; - - if (sk->sk_shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 0); - return -EPIPE; - } - - if (rose->neighbour == NULL || rose->device == NULL) - return -ENETUNREACH; - - if (usrose != NULL) { - if (msg->msg_namelen != sizeof(struct sockaddr_rose) && msg->msg_namelen != sizeof(struct full_sockaddr_rose)) - return -EINVAL; - memset(&srose, 0, sizeof(struct full_sockaddr_rose)); - memcpy(&srose, usrose, msg->msg_namelen); - if (rosecmp(&rose->dest_addr, &srose.srose_addr) != 0 || - ax25cmp(&rose->dest_call, &srose.srose_call) != 0) - return -EISCONN; - if (srose.srose_ndigis != rose->dest_ndigis) - return -EISCONN; - if (srose.srose_ndigis == rose->dest_ndigis) { - for (n = 0 ; n < srose.srose_ndigis ; n++) - if (ax25cmp(&rose->dest_digis[n], - &srose.srose_digis[n])) - return -EISCONN; - } - if (srose.srose_family != AF_ROSE) - return -EINVAL; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; - - srose.srose_family = AF_ROSE; - srose.srose_addr = rose->dest_addr; - srose.srose_call = rose->dest_call; - srose.srose_ndigis = rose->dest_ndigis; - for (n = 0 ; n < rose->dest_ndigis ; n++) - srose.srose_digis[n] = rose->dest_digis[n]; - } - - /* Build a packet */ - /* Sanity check the packet size */ - if (len > 65535) - return -EMSGSIZE; - - size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; - - if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) - return err; - - skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN); - - /* - * Put the data on the end - */ - - skb_reset_transport_header(skb); - skb_put(skb, len); - - err = memcpy_from_msg(skb_transport_header(skb), msg, len); - if (err) { - kfree_skb(skb); - return err; - } - - /* - * If the Q BIT Include socket option is in force, the first - * byte of the user data is the logical value of the Q Bit. - */ - if (rose->qbitincl) { - qbit = skb->data[0]; - skb_pull(skb, 1); - } - - /* - * Push down the ROSE header - */ - asmptr = skb_push(skb, ROSE_MIN_LEN); - - /* Build a ROSE Network header */ - asmptr[0] = ((rose->lci >> 8) & 0x0F) | ROSE_GFI; - asmptr[1] = (rose->lci >> 0) & 0xFF; - asmptr[2] = ROSE_DATA; - - if (qbit) - asmptr[0] |= ROSE_Q_BIT; - - if (sk->sk_state != TCP_ESTABLISHED) { - kfree_skb(skb); - return -ENOTCONN; - } - -#ifdef M_BIT -#define ROSE_PACLEN (256-ROSE_MIN_LEN) - if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) { - unsigned char header[ROSE_MIN_LEN]; - struct sk_buff *skbn; - int frontlen; - int lg; - - /* Save a copy of the Header */ - skb_copy_from_linear_data(skb, header, ROSE_MIN_LEN); - skb_pull(skb, ROSE_MIN_LEN); - - frontlen = skb_headroom(skb); - - while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, &err)) == NULL) { - kfree_skb(skb); - return err; - } - - skbn->sk = sk; - skbn->free = 1; - skbn->arp = 1; - - skb_reserve(skbn, frontlen); - - lg = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN; - - /* Copy the user data */ - skb_copy_from_linear_data(skb, skb_put(skbn, lg), lg); - skb_pull(skb, lg); - - /* Duplicate the Header */ - skb_push(skbn, ROSE_MIN_LEN); - skb_copy_to_linear_data(skbn, header, ROSE_MIN_LEN); - - if (skb->len > 0) - skbn->data[2] |= M_BIT; - - skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */ - } - - skb->free = 1; - kfree_skb(skb); - } else { - skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */ - } -#else - skb_queue_tail(&sk->sk_write_queue, skb); /* Shove it onto the queue */ -#endif - - rose_kick(sk); - - return len; -} - - -static int rose_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, - int flags) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - size_t copied; - unsigned char *asmptr; - struct sk_buff *skb; - int n, er, qbit; - - /* - * This works for seqpacket too. The receiver has ordered the queue for - * us! We do one quick check first though - */ - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; - - /* Now we can treat all alike */ - skb = skb_recv_datagram(sk, flags, &er); - if (!skb) - return er; - - qbit = (skb->data[0] & ROSE_Q_BIT) == ROSE_Q_BIT; - - skb_pull(skb, ROSE_MIN_LEN); - - if (rose->qbitincl) { - asmptr = skb_push(skb, 1); - *asmptr = qbit; - } - - skb_reset_transport_header(skb); - copied = skb->len; - - if (copied > size) { - copied = size; - msg->msg_flags |= MSG_TRUNC; - } - - skb_copy_datagram_msg(skb, 0, msg, copied); - - if (msg->msg_name) { - struct sockaddr_rose *srose; - DECLARE_SOCKADDR(struct full_sockaddr_rose *, full_srose, - msg->msg_name); - - memset(msg->msg_name, 0, sizeof(struct full_sockaddr_rose)); - srose = msg->msg_name; - srose->srose_family = AF_ROSE; - srose->srose_addr = rose->dest_addr; - srose->srose_call = rose->dest_call; - srose->srose_ndigis = rose->dest_ndigis; - for (n = 0 ; n < rose->dest_ndigis ; n++) - full_srose->srose_digis[n] = rose->dest_digis[n]; - msg->msg_namelen = sizeof(struct full_sockaddr_rose); - } - - skb_free_datagram(sk, skb); - - return copied; -} - - -static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - struct rose_sock *rose = rose_sk(sk); - void __user *argp = (void __user *)arg; - - switch (cmd) { - case TIOCOUTQ: { - long amount; - - amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); - if (amount < 0) - amount = 0; - return put_user(amount, (unsigned int __user *) argp); - } - - case TIOCINQ: { - struct sk_buff *skb; - long amount = 0L; - - spin_lock_irq(&sk->sk_receive_queue.lock); - if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) - amount = skb->len; - spin_unlock_irq(&sk->sk_receive_queue.lock); - return put_user(amount, (unsigned int __user *) argp); - } - - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - return -EINVAL; - - case SIOCADDRT: - case SIOCDELRT: - case SIOCRSCLRRT: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - return rose_rt_ioctl(cmd, argp); - - case SIOCRSGCAUSE: { - struct rose_cause_struct rose_cause; - rose_cause.cause = rose->cause; - rose_cause.diagnostic = rose->diagnostic; - return copy_to_user(argp, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0; - } - - case SIOCRSSCAUSE: { - struct rose_cause_struct rose_cause; - if (copy_from_user(&rose_cause, argp, sizeof(struct rose_cause_struct))) - return -EFAULT; - rose->cause = rose_cause.cause; - rose->diagnostic = rose_cause.diagnostic; - return 0; - } - - case SIOCRSSL2CALL: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) - ax25_listen_release(&rose_callsign, NULL); - if (copy_from_user(&rose_callsign, argp, sizeof(ax25_address))) - return -EFAULT; - if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) - return ax25_listen_register(&rose_callsign, NULL); - - return 0; - - case SIOCRSGL2CALL: - return copy_to_user(argp, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0; - - case SIOCRSACCEPT: - if (rose->state == ROSE_STATE_5) { - rose_write_internal(sk, ROSE_CALL_ACCEPTED); - rose_start_idletimer(sk); - rose->condition = 0x00; - rose->vs = 0; - rose->va = 0; - rose->vr = 0; - rose->vl = 0; - rose->state = ROSE_STATE_3; - } - return 0; - - default: - return -ENOIOCTLCMD; - } - - return 0; -} - -#ifdef CONFIG_PROC_FS -static void *rose_info_start(struct seq_file *seq, loff_t *pos) - __acquires(rose_list_lock) -{ - spin_lock_bh(&rose_list_lock); - return seq_hlist_start_head(&rose_list, *pos); -} - -static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_hlist_next(v, &rose_list, pos); -} - -static void rose_info_stop(struct seq_file *seq, void *v) - __releases(rose_list_lock) -{ - spin_unlock_bh(&rose_list_lock); -} - -static int rose_info_show(struct seq_file *seq, void *v) -{ - char buf[11], rsbuf[11]; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, - "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); - - else { - struct sock *s = sk_entry(v); - struct rose_sock *rose = rose_sk(s); - const char *devname, *callsign; - const struct net_device *dev = rose->device; - - if (!dev) - devname = "???"; - else - devname = dev->name; - - seq_printf(seq, "%-10s %-9s ", - rose2asc(rsbuf, &rose->dest_addr), - ax2asc(buf, &rose->dest_call)); - - if (ax25cmp(&rose->source_call, &null_ax25_address) == 0) - callsign = "??????-?"; - else - callsign = ax2asc(buf, &rose->source_call); - - seq_printf(seq, - "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %llu\n", - rose2asc(rsbuf, &rose->source_addr), - callsign, - devname, - rose->lci & 0x0FFF, - (rose->neighbour) ? rose->neighbour->number : 0, - rose->state, - rose->vs, - rose->vr, - rose->va, - ax25_display_timer(&rose->timer) / HZ, - rose->t1 / HZ, - rose->t2 / HZ, - rose->t3 / HZ, - rose->hb / HZ, - ax25_display_timer(&rose->idletimer) / (60 * HZ), - rose->idle / (60 * HZ), - sk_wmem_alloc_get(s), - sk_rmem_alloc_get(s), - s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : (u64)0); - } - - return 0; -} - -static const struct seq_operations rose_info_seqops = { - .start = rose_info_start, - .next = rose_info_next, - .stop = rose_info_stop, - .show = rose_info_show, -}; -#endif /* CONFIG_PROC_FS */ - -static const struct net_proto_family rose_family_ops = { - .family = PF_ROSE, - .create = rose_create, - .owner = THIS_MODULE, -}; - -static const struct proto_ops rose_proto_ops = { - .family = PF_ROSE, - .owner = THIS_MODULE, - .release = rose_release, - .bind = rose_bind, - .connect = rose_connect, - .socketpair = sock_no_socketpair, - .accept = rose_accept, - .getname = rose_getname, - .poll = datagram_poll, - .ioctl = rose_ioctl, - .gettstamp = sock_gettstamp, - .listen = rose_listen, - .shutdown = sock_no_shutdown, - .setsockopt = rose_setsockopt, - .getsockopt = rose_getsockopt, - .sendmsg = rose_sendmsg, - .recvmsg = rose_recvmsg, - .mmap = sock_no_mmap, -}; - -static struct notifier_block rose_dev_notifier = { - .notifier_call = rose_device_event, -}; - -static struct net_device **dev_rose; - -static struct ax25_protocol rose_pid = { - .pid = AX25_P_ROSE, - .func = rose_route_frame -}; - -static struct ax25_linkfail rose_linkfail_notifier = { - .func = rose_link_failed -}; - -static int __init rose_proto_init(void) -{ - int i; - int rc; - - if (rose_ndevs > 0x7FFFFFFF/sizeof(struct net_device *)) { - printk(KERN_ERR "ROSE: rose_proto_init - rose_ndevs parameter too large\n"); - rc = -EINVAL; - goto out; - } - - rc = proto_register(&rose_proto, 0); - if (rc != 0) - goto out; - - rose_callsign = null_ax25_address; - - dev_rose = kzalloc_objs(struct net_device *, rose_ndevs); - if (dev_rose == NULL) { - printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n"); - rc = -ENOMEM; - goto out_proto_unregister; - } - - for (i = 0; i < rose_ndevs; i++) { - struct net_device *dev; - char name[IFNAMSIZ]; - - sprintf(name, "rose%d", i); - dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, rose_setup); - if (!dev) { - printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n"); - rc = -ENOMEM; - goto fail; - } - rc = register_netdev(dev); - if (rc) { - printk(KERN_ERR "ROSE: netdevice registration failed\n"); - free_netdev(dev); - goto fail; - } - rose_set_lockdep_key(dev); - dev_rose[i] = dev; - } - - sock_register(&rose_family_ops); - register_netdevice_notifier(&rose_dev_notifier); - - ax25_register_pid(&rose_pid); - ax25_linkfail_register(&rose_linkfail_notifier); - -#ifdef CONFIG_SYSCTL - rose_register_sysctl(); -#endif - rose_loopback_init(); - - rose_add_loopback_neigh(); - - proc_create_seq("rose", 0444, init_net.proc_net, &rose_info_seqops); - proc_create_seq("rose_neigh", 0444, init_net.proc_net, - &rose_neigh_seqops); - proc_create_seq("rose_nodes", 0444, init_net.proc_net, - &rose_node_seqops); - proc_create_seq("rose_routes", 0444, init_net.proc_net, - &rose_route_seqops); -out: - return rc; -fail: - while (--i >= 0) { - unregister_netdev(dev_rose[i]); - free_netdev(dev_rose[i]); - } - kfree(dev_rose); -out_proto_unregister: - proto_unregister(&rose_proto); - goto out; -} -module_init(rose_proto_init); - -module_param(rose_ndevs, int, 0); -MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices"); - -MODULE_AUTHOR("Jonathan Naylor G4KLX "); -MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NETPROTO(PF_ROSE); - -static void __exit rose_exit(void) -{ - int i; - - remove_proc_entry("rose", init_net.proc_net); - remove_proc_entry("rose_neigh", init_net.proc_net); - remove_proc_entry("rose_nodes", init_net.proc_net); - remove_proc_entry("rose_routes", init_net.proc_net); - rose_loopback_clear(); - - rose_rt_free(); - - ax25_protocol_release(AX25_P_ROSE); - ax25_linkfail_release(&rose_linkfail_notifier); - - if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) - ax25_listen_release(&rose_callsign, NULL); - -#ifdef CONFIG_SYSCTL - rose_unregister_sysctl(); -#endif - unregister_netdevice_notifier(&rose_dev_notifier); - - sock_unregister(PF_ROSE); - - for (i = 0; i < rose_ndevs; i++) { - struct net_device *dev = dev_rose[i]; - - if (dev) { - unregister_netdev(dev); - free_netdev(dev); - } - } - - kfree(dev_rose); - proto_unregister(&rose_proto); -} - -module_exit(rose_exit); diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c deleted file mode 100644 index f1a76a5820f1..000000000000 --- a/net/rose/rose_dev.c +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -static int rose_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned int len) -{ - unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2); - - if (daddr) - memcpy(buff + 7, daddr, dev->addr_len); - - *buff++ = ROSE_GFI | ROSE_Q_BIT; - *buff++ = 0x00; - *buff++ = ROSE_DATA; - *buff++ = 0x7F; - *buff++ = AX25_P_IP; - - if (daddr != NULL) - return 37; - - return -37; -} - -static int rose_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *sa = addr; - int err; - - if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) - return 0; - - if (dev->flags & IFF_UP) { - err = rose_add_loopback_node((rose_address *)sa->sa_data); - if (err) - return err; - - rose_del_loopback_node((const rose_address *)dev->dev_addr); - } - - dev_addr_set(dev, sa->sa_data); - - return 0; -} - -static int rose_open(struct net_device *dev) -{ - int err; - - err = rose_add_loopback_node((const rose_address *)dev->dev_addr); - if (err) - return err; - - netif_start_queue(dev); - - return 0; -} - -static int rose_close(struct net_device *dev) -{ - netif_stop_queue(dev); - rose_del_loopback_node((const rose_address *)dev->dev_addr); - return 0; -} - -static netdev_tx_t rose_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct net_device_stats *stats = &dev->stats; - unsigned int len = skb->len; - - if (!netif_running(dev)) { - printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); - return NETDEV_TX_BUSY; - } - - if (!rose_route_frame(skb, NULL)) { - dev_kfree_skb(skb); - stats->tx_errors++; - return NETDEV_TX_OK; - } - - stats->tx_packets++; - stats->tx_bytes += len; - return NETDEV_TX_OK; -} - -static const struct header_ops rose_header_ops = { - .create = rose_header, -}; - -static const struct net_device_ops rose_netdev_ops = { - .ndo_open = rose_open, - .ndo_stop = rose_close, - .ndo_start_xmit = rose_xmit, - .ndo_set_mac_address = rose_set_mac_address, -}; - -void rose_setup(struct net_device *dev) -{ - dev->mtu = ROSE_MAX_PACKET_SIZE - 2; - dev->netdev_ops = &rose_netdev_ops; - - dev->header_ops = &rose_header_ops; - dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; - dev->addr_len = ROSE_ADDR_LEN; - dev->type = ARPHRD_ROSE; - - /* New-style flags. */ - dev->flags = IFF_NOARP; -} diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c deleted file mode 100644 index ca4f217ef3d3..000000000000 --- a/net/rose/rose_in.c +++ /dev/null @@ -1,301 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * - * Most of this code is based on the SDL diagrams published in the 7th ARRL - * Computer Networking Conference papers. The diagrams have mistakes in them, - * but are mostly correct. Before you modify the code could you read the SDL - * diagrams as the code is not obvious and probably very easy to break. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * State machine for state 1, Awaiting Call Accepted State. - * The handling of the timer(s) is in file rose_timer.c. - * Handling of state 0 and connection release is in af_rose.c. - */ -static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) -{ - struct rose_sock *rose = rose_sk(sk); - - switch (frametype) { - case ROSE_CALL_ACCEPTED: - rose_stop_timer(sk); - rose_start_idletimer(sk); - rose->condition = 0x00; - rose->vs = 0; - rose->va = 0; - rose->vr = 0; - rose->vl = 0; - rose->state = ROSE_STATE_3; - sk->sk_state = TCP_ESTABLISHED; - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_state_change(sk); - break; - - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); - rose_neigh_put(rose->neighbour); - break; - - default: - break; - } - - return 0; -} - -/* - * State machine for state 2, Awaiting Clear Confirmation State. - * The handling of the timer(s) is in file rose_timer.c - * Handling of state 0 and connection release is in af_rose.c. - */ -static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) -{ - struct rose_sock *rose = rose_sk(sk); - - switch (frametype) { - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose_neigh_put(rose->neighbour); - break; - - case ROSE_CLEAR_CONFIRMATION: - rose_disconnect(sk, 0, -1, -1); - rose_neigh_put(rose->neighbour); - break; - - default: - break; - } - - return 0; -} - -/* - * State machine for state 3, Connected State. - * The handling of the timer(s) is in file rose_timer.c - * Handling of state 0 and connection release is in af_rose.c. - */ -static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) -{ - struct rose_sock *rose = rose_sk(sk); - int queued = 0; - - switch (frametype) { - case ROSE_RESET_REQUEST: - rose_stop_timer(sk); - rose_start_idletimer(sk); - rose_write_internal(sk, ROSE_RESET_CONFIRMATION); - rose->condition = 0x00; - rose->vs = 0; - rose->vr = 0; - rose->va = 0; - rose->vl = 0; - rose_requeue_frames(sk); - break; - - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose_neigh_put(rose->neighbour); - break; - - case ROSE_RR: - case ROSE_RNR: - if (!rose_validate_nr(sk, nr)) { - rose_write_internal(sk, ROSE_RESET_REQUEST); - rose->condition = 0x00; - rose->vs = 0; - rose->vr = 0; - rose->va = 0; - rose->vl = 0; - rose->state = ROSE_STATE_4; - rose_start_t2timer(sk); - rose_stop_idletimer(sk); - } else { - rose_frames_acked(sk, nr); - if (frametype == ROSE_RNR) { - rose->condition |= ROSE_COND_PEER_RX_BUSY; - } else { - rose->condition &= ~ROSE_COND_PEER_RX_BUSY; - } - } - break; - - case ROSE_DATA: /* XXX */ - rose->condition &= ~ROSE_COND_PEER_RX_BUSY; - if (!rose_validate_nr(sk, nr)) { - rose_write_internal(sk, ROSE_RESET_REQUEST); - rose->condition = 0x00; - rose->vs = 0; - rose->vr = 0; - rose->va = 0; - rose->vl = 0; - rose->state = ROSE_STATE_4; - rose_start_t2timer(sk); - rose_stop_idletimer(sk); - break; - } - rose_frames_acked(sk, nr); - if (ns == rose->vr) { - rose_start_idletimer(sk); - if (!sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) && - __sock_queue_rcv_skb(sk, skb) == 0) { - rose->vr = (rose->vr + 1) % ROSE_MODULUS; - queued = 1; - } else { - /* Should never happen ! */ - rose_write_internal(sk, ROSE_RESET_REQUEST); - rose->condition = 0x00; - rose->vs = 0; - rose->vr = 0; - rose->va = 0; - rose->vl = 0; - rose->state = ROSE_STATE_4; - rose_start_t2timer(sk); - rose_stop_idletimer(sk); - break; - } - if (atomic_read(&sk->sk_rmem_alloc) > - (sk->sk_rcvbuf >> 1)) - rose->condition |= ROSE_COND_OWN_RX_BUSY; - } - /* - * If the window is full, ack the frame, else start the - * acknowledge hold back timer. - */ - if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) { - rose->condition &= ~ROSE_COND_ACK_PENDING; - rose_stop_timer(sk); - rose_enquiry_response(sk); - } else { - rose->condition |= ROSE_COND_ACK_PENDING; - rose_start_hbtimer(sk); - } - break; - - default: - printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype); - break; - } - - return queued; -} - -/* - * State machine for state 4, Awaiting Reset Confirmation State. - * The handling of the timer(s) is in file rose_timer.c - * Handling of state 0 and connection release is in af_rose.c. - */ -static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) -{ - struct rose_sock *rose = rose_sk(sk); - - switch (frametype) { - case ROSE_RESET_REQUEST: - rose_write_internal(sk, ROSE_RESET_CONFIRMATION); - fallthrough; - case ROSE_RESET_CONFIRMATION: - rose_stop_timer(sk); - rose_start_idletimer(sk); - rose->condition = 0x00; - rose->va = 0; - rose->vr = 0; - rose->vs = 0; - rose->vl = 0; - rose->state = ROSE_STATE_3; - rose_requeue_frames(sk); - break; - - case ROSE_CLEAR_REQUEST: - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose_neigh_put(rose->neighbour); - break; - - default: - break; - } - - return 0; -} - -/* - * State machine for state 5, Awaiting Call Acceptance State. - * The handling of the timer(s) is in file rose_timer.c - * Handling of state 0 and connection release is in af_rose.c. - */ -static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype) -{ - if (frametype == ROSE_CLEAR_REQUEST) { - rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose_neigh_put(rose_sk(sk)->neighbour); - } - - return 0; -} - -/* Higher level upcall for a LAPB frame */ -int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) -{ - struct rose_sock *rose = rose_sk(sk); - int queued = 0, frametype, ns, nr, q, d, m; - - if (rose->state == ROSE_STATE_0) - return 0; - - frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); - - /* - * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. - * Reject a malformed frame that is too short to contain them. - */ - if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) - return 0; - - switch (rose->state) { - case ROSE_STATE_1: - queued = rose_state1_machine(sk, skb, frametype); - break; - case ROSE_STATE_2: - queued = rose_state2_machine(sk, skb, frametype); - break; - case ROSE_STATE_3: - queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m); - break; - case ROSE_STATE_4: - queued = rose_state4_machine(sk, skb, frametype); - break; - case ROSE_STATE_5: - queued = rose_state5_machine(sk, skb, frametype); - break; - } - - rose_kick(sk); - - return queued; -} diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c deleted file mode 100644 index 7746229fdc8c..000000000000 --- a/net/rose/rose_link.c +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void rose_ftimer_expiry(struct timer_list *); -static void rose_t0timer_expiry(struct timer_list *); - -static void rose_transmit_restart_confirmation(struct rose_neigh *neigh); -static void rose_transmit_restart_request(struct rose_neigh *neigh); - -void rose_start_ftimer(struct rose_neigh *neigh) -{ - timer_delete(&neigh->ftimer); - - neigh->ftimer.function = rose_ftimer_expiry; - neigh->ftimer.expires = - jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout); - - add_timer(&neigh->ftimer); -} - -static void rose_start_t0timer(struct rose_neigh *neigh) -{ - timer_delete(&neigh->t0timer); - - neigh->t0timer.function = rose_t0timer_expiry; - neigh->t0timer.expires = - jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout); - - add_timer(&neigh->t0timer); -} - -void rose_stop_ftimer(struct rose_neigh *neigh) -{ - timer_delete(&neigh->ftimer); -} - -void rose_stop_t0timer(struct rose_neigh *neigh) -{ - timer_delete(&neigh->t0timer); -} - -int rose_ftimer_running(struct rose_neigh *neigh) -{ - return timer_pending(&neigh->ftimer); -} - -static int rose_t0timer_running(struct rose_neigh *neigh) -{ - return timer_pending(&neigh->t0timer); -} - -static void rose_ftimer_expiry(struct timer_list *t) -{ -} - -static void rose_t0timer_expiry(struct timer_list *t) -{ - struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); - - rose_transmit_restart_request(neigh); - - neigh->dce_mode = 0; - - rose_start_t0timer(neigh); -} - -/* - * Interface to ax25_send_frame. Changes my level 2 callsign depending - * on whether we have a global ROSE callsign or use the default port - * callsign. - */ -static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh) -{ - const ax25_address *rose_call; - ax25_cb *ax25s; - - if (ax25cmp(&rose_callsign, &null_ax25_address) == 0) - rose_call = (const ax25_address *)neigh->dev->dev_addr; - else - rose_call = &rose_callsign; - - ax25s = neigh->ax25; - neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); - if (ax25s) - ax25_cb_put(ax25s); - - return neigh->ax25 != NULL; -} - -/* - * Interface to ax25_link_up. Changes my level 2 callsign depending - * on whether we have a global ROSE callsign or use the default port - * callsign. - */ -static int rose_link_up(struct rose_neigh *neigh) -{ - const ax25_address *rose_call; - ax25_cb *ax25s; - - if (ax25cmp(&rose_callsign, &null_ax25_address) == 0) - rose_call = (const ax25_address *)neigh->dev->dev_addr; - else - rose_call = &rose_callsign; - - ax25s = neigh->ax25; - neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); - if (ax25s) - ax25_cb_put(ax25s); - - return neigh->ax25 != NULL; -} - -/* - * This handles all restart and diagnostic frames. - */ -void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype) -{ - struct sk_buff *skbn; - - switch (frametype) { - case ROSE_RESTART_REQUEST: - rose_stop_t0timer(neigh); - neigh->restarted = 1; - neigh->dce_mode = (skb->data[3] == ROSE_DTE_ORIGINATED); - rose_transmit_restart_confirmation(neigh); - break; - - case ROSE_RESTART_CONFIRMATION: - rose_stop_t0timer(neigh); - neigh->restarted = 1; - break; - - case ROSE_DIAGNOSTIC: - pr_warn("ROSE: received diagnostic #%d - %3ph\n", skb->data[3], - skb->data + 4); - break; - - default: - printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype); - break; - } - - if (neigh->restarted) { - while ((skbn = skb_dequeue(&neigh->queue)) != NULL) - if (!rose_send_frame(skbn, neigh)) - kfree_skb(skbn); - } -} - -/* - * This routine is called when a Restart Request is needed - */ -static void rose_transmit_restart_request(struct rose_neigh *neigh) -{ - struct sk_buff *skb; - unsigned char *dptr; - int len; - - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3; - - if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) - return; - - skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN); - - dptr = skb_put(skb, ROSE_MIN_LEN + 3); - - *dptr++ = AX25_P_ROSE; - *dptr++ = ROSE_GFI; - *dptr++ = 0x00; - *dptr++ = ROSE_RESTART_REQUEST; - *dptr++ = ROSE_DTE_ORIGINATED; - *dptr++ = 0; - - if (!rose_send_frame(skb, neigh)) - kfree_skb(skb); -} - -/* - * This routine is called when a Restart Confirmation is needed - */ -static void rose_transmit_restart_confirmation(struct rose_neigh *neigh) -{ - struct sk_buff *skb; - unsigned char *dptr; - int len; - - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1; - - if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) - return; - - skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN); - - dptr = skb_put(skb, ROSE_MIN_LEN + 1); - - *dptr++ = AX25_P_ROSE; - *dptr++ = ROSE_GFI; - *dptr++ = 0x00; - *dptr++ = ROSE_RESTART_CONFIRMATION; - - if (!rose_send_frame(skb, neigh)) - kfree_skb(skb); -} - -/* - * This routine is called when a Clear Request is needed outside of the context - * of a connected socket. - */ -void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic) -{ - struct sk_buff *skb; - unsigned char *dptr; - int len; - - if (!neigh->dev) - return; - - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3; - - if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) - return; - - skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN); - - dptr = skb_put(skb, ROSE_MIN_LEN + 3); - - *dptr++ = AX25_P_ROSE; - *dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI; - *dptr++ = ((lci >> 0) & 0xFF); - *dptr++ = ROSE_CLEAR_REQUEST; - *dptr++ = cause; - *dptr++ = diagnostic; - - if (!rose_send_frame(skb, neigh)) - kfree_skb(skb); -} - -void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh) -{ - unsigned char *dptr; - - if (neigh->loopback) { - rose_loopback_queue(skb, neigh); - return; - } - - if (!rose_link_up(neigh)) - neigh->restarted = 0; - - dptr = skb_push(skb, 1); - *dptr++ = AX25_P_ROSE; - - if (neigh->restarted) { - if (!rose_send_frame(skb, neigh)) - kfree_skb(skb); - } else { - skb_queue_tail(&neigh->queue, skb); - - if (!rose_t0timer_running(neigh)) { - rose_transmit_restart_request(neigh); - neigh->dce_mode = 0; - rose_start_t0timer(neigh); - } - } -} diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c deleted file mode 100644 index b538e39b3df5..000000000000 --- a/net/rose/rose_loopback.c +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include - -static struct sk_buff_head loopback_queue; -#define ROSE_LOOPBACK_LIMIT 1000 -static struct timer_list loopback_timer; - -static void rose_set_loopback_timer(void); -static void rose_loopback_timer(struct timer_list *unused); - -void rose_loopback_init(void) -{ - skb_queue_head_init(&loopback_queue); - - timer_setup(&loopback_timer, rose_loopback_timer, 0); -} - -static int rose_loopback_running(void) -{ - return timer_pending(&loopback_timer); -} - -int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh) -{ - struct sk_buff *skbn = NULL; - - if (skb_queue_len(&loopback_queue) < ROSE_LOOPBACK_LIMIT) - skbn = skb_clone(skb, GFP_ATOMIC); - - if (skbn) { - consume_skb(skb); - skb_queue_tail(&loopback_queue, skbn); - - if (!rose_loopback_running()) - rose_set_loopback_timer(); - } else { - kfree_skb(skb); - } - - return 1; -} - -static void rose_set_loopback_timer(void) -{ - mod_timer(&loopback_timer, jiffies + 10); -} - -static void rose_loopback_timer(struct timer_list *unused) -{ - struct sk_buff *skb; - struct net_device *dev; - rose_address *dest; - struct sock *sk; - unsigned short frametype; - unsigned int lci_i, lci_o; - int count; - - for (count = 0; count < ROSE_LOOPBACK_LIMIT; count++) { - skb = skb_dequeue(&loopback_queue); - if (!skb) - return; - if (skb->len < ROSE_MIN_LEN) { - kfree_skb(skb); - continue; - } - lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); - frametype = skb->data[2]; - if (frametype == ROSE_CALL_REQUEST && - (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF || - skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] != - ROSE_CALL_REQ_ADDR_LEN_VAL)) { - kfree_skb(skb); - continue; - } - dest = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF); - lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; - - skb_reset_transport_header(skb); - - sk = rose_find_socket(lci_o, rose_loopback_neigh); - if (sk) { - if (rose_process_rx_frame(sk, skb) == 0) - kfree_skb(skb); - continue; - } - - if (frametype == ROSE_CALL_REQUEST) { - if (!rose_loopback_neigh->dev && - !rose_loopback_neigh->loopback) { - kfree_skb(skb); - continue; - } - - dev = rose_dev_get(dest); - if (!dev) { - kfree_skb(skb); - continue; - } - - if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) { - dev_put(dev); - kfree_skb(skb); - } - } else { - kfree_skb(skb); - } - } - if (!skb_queue_empty(&loopback_queue)) - mod_timer(&loopback_timer, jiffies + 1); -} - -void __exit rose_loopback_clear(void) -{ - struct sk_buff *skb; - - timer_delete(&loopback_timer); - - while ((skb = skb_dequeue(&loopback_queue)) != NULL) { - skb->sk = NULL; - kfree_skb(skb); - } -} diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c deleted file mode 100644 index 9050e33c9604..000000000000 --- a/net/rose/rose_out.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This procedure is passed a buffer descriptor for an iframe. It builds - * the rest of the control part of the frame and then writes it out. - */ -static void rose_send_iframe(struct sock *sk, struct sk_buff *skb) -{ - struct rose_sock *rose = rose_sk(sk); - - if (skb == NULL) - return; - - skb->data[2] |= (rose->vr << 5) & 0xE0; - skb->data[2] |= (rose->vs << 1) & 0x0E; - - rose_start_idletimer(sk); - - rose_transmit_link(skb, rose->neighbour); -} - -void rose_kick(struct sock *sk) -{ - struct rose_sock *rose = rose_sk(sk); - struct sk_buff *skb, *skbn; - unsigned short start, end; - - if (rose->state != ROSE_STATE_3) - return; - - if (rose->condition & ROSE_COND_PEER_RX_BUSY) - return; - - if (!skb_peek(&sk->sk_write_queue)) - return; - - start = (skb_peek(&rose->ack_queue) == NULL) ? rose->va : rose->vs; - end = (rose->va + sysctl_rose_window_size) % ROSE_MODULUS; - - if (start == end) - return; - - rose->vs = start; - - /* - * Transmit data until either we're out of data to send or - * the window is full. - */ - - skb = skb_dequeue(&sk->sk_write_queue); - - do { - if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - skb_queue_head(&sk->sk_write_queue, skb); - break; - } - - skb_set_owner_w(skbn, sk); - - /* - * Transmit the frame copy. - */ - rose_send_iframe(sk, skbn); - - rose->vs = (rose->vs + 1) % ROSE_MODULUS; - - /* - * Requeue the original data frame. - */ - skb_queue_tail(&rose->ack_queue, skb); - - } while (rose->vs != end && - (skb = skb_dequeue(&sk->sk_write_queue)) != NULL); - - rose->vl = rose->vr; - rose->condition &= ~ROSE_COND_ACK_PENDING; - - rose_stop_timer(sk); -} - -/* - * The following routines are taken from page 170 of the 7th ARRL Computer - * Networking Conference paper, as is the whole state machine. - */ - -void rose_enquiry_response(struct sock *sk) -{ - struct rose_sock *rose = rose_sk(sk); - - if (rose->condition & ROSE_COND_OWN_RX_BUSY) - rose_write_internal(sk, ROSE_RNR); - else - rose_write_internal(sk, ROSE_RR); - - rose->vl = rose->vr; - rose->condition &= ~ROSE_COND_ACK_PENDING; - - rose_stop_timer(sk); -} diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c deleted file mode 100644 index e31842e6b3c8..000000000000 --- a/net/rose/rose_route.c +++ /dev/null @@ -1,1333 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For TIOCINQ/OUTQ */ -#include -#include -#include -#include -#include -#include -#include - -static unsigned int rose_neigh_no = 1; - -static struct rose_node *rose_node_list; -static DEFINE_SPINLOCK(rose_node_list_lock); -static struct rose_neigh *rose_neigh_list; -static DEFINE_SPINLOCK(rose_neigh_list_lock); -static struct rose_route *rose_route_list; -static DEFINE_SPINLOCK(rose_route_list_lock); - -struct rose_neigh *rose_loopback_neigh; - -/* - * Add a new route to a node, and in the process add the node and the - * neighbour if it is new. - */ -static int __must_check rose_add_node(struct rose_route_struct *rose_route, - struct net_device *dev) -{ - struct rose_node *rose_node, *rose_tmpn, *rose_tmpp; - struct rose_neigh *rose_neigh; - int i, res = 0; - - spin_lock_bh(&rose_node_list_lock); - spin_lock_bh(&rose_neigh_list_lock); - - rose_node = rose_node_list; - while (rose_node != NULL) { - if ((rose_node->mask == rose_route->mask) && - (rosecmpm(&rose_route->address, &rose_node->address, - rose_route->mask) == 0)) - break; - rose_node = rose_node->next; - } - - if (rose_node != NULL && rose_node->loopback) { - res = -EINVAL; - goto out; - } - - rose_neigh = rose_neigh_list; - while (rose_neigh != NULL) { - if (ax25cmp(&rose_route->neighbour, - &rose_neigh->callsign) == 0 && - rose_neigh->dev == dev) - break; - rose_neigh = rose_neigh->next; - } - - if (rose_neigh == NULL) { - rose_neigh = kmalloc_obj(*rose_neigh, GFP_ATOMIC); - if (rose_neigh == NULL) { - res = -ENOMEM; - goto out; - } - - rose_neigh->callsign = rose_route->neighbour; - rose_neigh->digipeat = NULL; - rose_neigh->ax25 = NULL; - rose_neigh->dev = dev; - rose_neigh->count = 0; - rose_neigh->dce_mode = 0; - rose_neigh->loopback = 0; - rose_neigh->number = rose_neigh_no++; - rose_neigh->restarted = 0; - refcount_set(&rose_neigh->use, 1); - - skb_queue_head_init(&rose_neigh->queue); - - timer_setup(&rose_neigh->ftimer, NULL, 0); - timer_setup(&rose_neigh->t0timer, NULL, 0); - - if (rose_route->ndigis != 0) { - rose_neigh->digipeat = - kmalloc_obj(ax25_digi, GFP_ATOMIC); - if (rose_neigh->digipeat == NULL) { - kfree(rose_neigh); - res = -ENOMEM; - goto out; - } - - rose_neigh->digipeat->ndigi = rose_route->ndigis; - rose_neigh->digipeat->lastrepeat = -1; - - for (i = 0; i < rose_route->ndigis; i++) { - rose_neigh->digipeat->calls[i] = - rose_route->digipeaters[i]; - rose_neigh->digipeat->repeated[i] = 0; - } - } - - rose_neigh->next = rose_neigh_list; - rose_neigh_list = rose_neigh; - } - - /* - * This is a new node to be inserted into the list. Find where it needs - * to be inserted into the list, and insert it. We want to be sure - * to order the list in descending order of mask size to ensure that - * later when we are searching this list the first match will be the - * best match. - */ - if (rose_node == NULL) { - rose_tmpn = rose_node_list; - rose_tmpp = NULL; - - while (rose_tmpn != NULL) { - if (rose_tmpn->mask > rose_route->mask) { - rose_tmpp = rose_tmpn; - rose_tmpn = rose_tmpn->next; - } else { - break; - } - } - - /* create new node */ - rose_node = kmalloc_obj(*rose_node, GFP_ATOMIC); - if (rose_node == NULL) { - res = -ENOMEM; - goto out; - } - - rose_node->address = rose_route->address; - rose_node->mask = rose_route->mask; - rose_node->count = 1; - rose_node->loopback = 0; - rose_node->neighbour[0] = rose_neigh; - - if (rose_tmpn == NULL) { - if (rose_tmpp == NULL) { /* Empty list */ - rose_node_list = rose_node; - rose_node->next = NULL; - } else { - rose_tmpp->next = rose_node; - rose_node->next = NULL; - } - } else { - if (rose_tmpp == NULL) { /* 1st node */ - rose_node->next = rose_node_list; - rose_node_list = rose_node; - } else { - rose_tmpp->next = rose_node; - rose_node->next = rose_tmpn; - } - } - rose_neigh->count++; - rose_neigh_hold(rose_neigh); - - goto out; - } - - /* We have space, slot it in */ - if (rose_node->count < 3) { - rose_node->neighbour[rose_node->count] = rose_neigh; - rose_node->count++; - rose_neigh->count++; - rose_neigh_hold(rose_neigh); - } - -out: - spin_unlock_bh(&rose_neigh_list_lock); - spin_unlock_bh(&rose_node_list_lock); - - return res; -} - -/* - * Caller is holding rose_node_list_lock. - */ -static void rose_remove_node(struct rose_node *rose_node) -{ - struct rose_node *s; - - if ((s = rose_node_list) == rose_node) { - rose_node_list = rose_node->next; - kfree(rose_node); - return; - } - - while (s != NULL && s->next != NULL) { - if (s->next == rose_node) { - s->next = rose_node->next; - kfree(rose_node); - return; - } - - s = s->next; - } -} - -/* - * Caller is holding rose_neigh_list_lock. - */ -static void rose_remove_neigh(struct rose_neigh *rose_neigh) -{ - struct rose_neigh *s; - - timer_delete_sync(&rose_neigh->ftimer); - timer_delete_sync(&rose_neigh->t0timer); - - skb_queue_purge(&rose_neigh->queue); - - if ((s = rose_neigh_list) == rose_neigh) { - rose_neigh_list = rose_neigh->next; - return; - } - - while (s != NULL && s->next != NULL) { - if (s->next == rose_neigh) { - s->next = rose_neigh->next; - return; - } - - s = s->next; - } -} - -/* - * Caller is holding rose_route_list_lock. - */ -static void rose_remove_route(struct rose_route *rose_route) -{ - struct rose_route *s; - - if (rose_route->neigh1 != NULL) - rose_neigh_put(rose_route->neigh1); - - if (rose_route->neigh2 != NULL) - rose_neigh_put(rose_route->neigh2); - - if ((s = rose_route_list) == rose_route) { - rose_route_list = rose_route->next; - kfree(rose_route); - return; - } - - while (s != NULL && s->next != NULL) { - if (s->next == rose_route) { - s->next = rose_route->next; - kfree(rose_route); - return; - } - - s = s->next; - } -} - -/* - * "Delete" a node. Strictly speaking remove a route to a node. The node - * is only deleted if no routes are left to it. - */ -static int rose_del_node(struct rose_route_struct *rose_route, - struct net_device *dev) -{ - struct rose_node *rose_node; - struct rose_neigh *rose_neigh; - int i, err = 0; - - spin_lock_bh(&rose_node_list_lock); - spin_lock_bh(&rose_neigh_list_lock); - - rose_node = rose_node_list; - while (rose_node != NULL) { - if ((rose_node->mask == rose_route->mask) && - (rosecmpm(&rose_route->address, &rose_node->address, - rose_route->mask) == 0)) - break; - rose_node = rose_node->next; - } - - if (rose_node == NULL || rose_node->loopback) { - err = -EINVAL; - goto out; - } - - rose_neigh = rose_neigh_list; - while (rose_neigh != NULL) { - if (ax25cmp(&rose_route->neighbour, - &rose_neigh->callsign) == 0 && - rose_neigh->dev == dev) - break; - rose_neigh = rose_neigh->next; - } - - if (rose_neigh == NULL) { - err = -EINVAL; - goto out; - } - - for (i = 0; i < rose_node->count; i++) { - if (rose_node->neighbour[i] == rose_neigh) { - rose_neigh->count--; - rose_neigh_put(rose_neigh); - - if (rose_neigh->count == 0) { - rose_remove_neigh(rose_neigh); - rose_neigh_put(rose_neigh); - } - - rose_node->count--; - - if (rose_node->count == 0) { - rose_remove_node(rose_node); - } else { - switch (i) { - case 0: - rose_node->neighbour[0] = - rose_node->neighbour[1]; - fallthrough; - case 1: - rose_node->neighbour[1] = - rose_node->neighbour[2]; - break; - case 2: - break; - } - } - goto out; - } - } - err = -EINVAL; - -out: - spin_unlock_bh(&rose_neigh_list_lock); - spin_unlock_bh(&rose_node_list_lock); - - return err; -} - -/* - * Add the loopback neighbour. - */ -void rose_add_loopback_neigh(void) -{ - struct rose_neigh *sn; - - rose_loopback_neigh = kmalloc_obj(struct rose_neigh); - if (!rose_loopback_neigh) - return; - sn = rose_loopback_neigh; - - sn->callsign = null_ax25_address; - sn->digipeat = NULL; - sn->ax25 = NULL; - sn->dev = NULL; - sn->count = 0; - sn->dce_mode = 1; - sn->loopback = 1; - sn->number = rose_neigh_no++; - sn->restarted = 1; - refcount_set(&sn->use, 1); - - skb_queue_head_init(&sn->queue); - - timer_setup(&sn->ftimer, NULL, 0); - timer_setup(&sn->t0timer, NULL, 0); - - spin_lock_bh(&rose_neigh_list_lock); - sn->next = rose_neigh_list; - rose_neigh_list = sn; - spin_unlock_bh(&rose_neigh_list_lock); -} - -/* - * Add a loopback node. - */ -int rose_add_loopback_node(const rose_address *address) -{ - struct rose_node *rose_node; - int err = 0; - - spin_lock_bh(&rose_node_list_lock); - - rose_node = rose_node_list; - while (rose_node != NULL) { - if ((rose_node->mask == 10) && - (rosecmpm(address, &rose_node->address, 10) == 0) && - rose_node->loopback) - break; - rose_node = rose_node->next; - } - - if (rose_node != NULL) - goto out; - - if ((rose_node = kmalloc_obj(*rose_node, GFP_ATOMIC)) == NULL) { - err = -ENOMEM; - goto out; - } - - rose_node->address = *address; - rose_node->mask = 10; - rose_node->count = 1; - rose_node->loopback = 1; - rose_node->neighbour[0] = rose_loopback_neigh; - - /* Insert at the head of list. Address is always mask=10 */ - rose_node->next = rose_node_list; - rose_node_list = rose_node; - - rose_loopback_neigh->count++; - rose_neigh_hold(rose_loopback_neigh); - -out: - spin_unlock_bh(&rose_node_list_lock); - - return err; -} - -/* - * Delete a loopback node. - */ -void rose_del_loopback_node(const rose_address *address) -{ - struct rose_node *rose_node; - - spin_lock_bh(&rose_node_list_lock); - - rose_node = rose_node_list; - while (rose_node != NULL) { - if ((rose_node->mask == 10) && - (rosecmpm(address, &rose_node->address, 10) == 0) && - rose_node->loopback) - break; - rose_node = rose_node->next; - } - - if (rose_node == NULL) - goto out; - - rose_remove_node(rose_node); - - rose_loopback_neigh->count--; - rose_neigh_put(rose_loopback_neigh); - -out: - spin_unlock_bh(&rose_node_list_lock); -} - -/* - * A device has been removed. Remove its routes and neighbours. - */ -void rose_rt_device_down(struct net_device *dev) -{ - struct rose_neigh *s, *rose_neigh; - struct rose_node *t, *rose_node; - int i; - - spin_lock_bh(&rose_node_list_lock); - spin_lock_bh(&rose_neigh_list_lock); - rose_neigh = rose_neigh_list; - while (rose_neigh != NULL) { - s = rose_neigh; - rose_neigh = rose_neigh->next; - - if (s->dev != dev) - continue; - - rose_node = rose_node_list; - - while (rose_node != NULL) { - t = rose_node; - rose_node = rose_node->next; - - for (i = t->count - 1; i >= 0; i--) { - if (t->neighbour[i] != s) - continue; - - t->count--; - - memmove(&t->neighbour[i], &t->neighbour[i + 1], - sizeof(t->neighbour[0]) * - (t->count - i)); - rose_neigh_put(s); - } - - if (t->count <= 0) - rose_remove_node(t); - } - - rose_remove_neigh(s); - rose_neigh_put(s); - } - spin_unlock_bh(&rose_neigh_list_lock); - spin_unlock_bh(&rose_node_list_lock); -} - -#if 0 /* Currently unused */ -/* - * A device has been removed. Remove its links. - */ -void rose_route_device_down(struct net_device *dev) -{ - struct rose_route *s, *rose_route; - - spin_lock_bh(&rose_route_list_lock); - rose_route = rose_route_list; - while (rose_route != NULL) { - s = rose_route; - rose_route = rose_route->next; - - if (s->neigh1->dev == dev || s->neigh2->dev == dev) - rose_remove_route(s); - } - spin_unlock_bh(&rose_route_list_lock); -} -#endif - -/* - * Clear all nodes and neighbours out, except for neighbours with - * active connections going through them. - * Do not clear loopback neighbour and nodes. - */ -static int rose_clear_routes(void) -{ - struct rose_neigh *s, *rose_neigh; - struct rose_node *t, *rose_node; - int i; - - spin_lock_bh(&rose_node_list_lock); - spin_lock_bh(&rose_neigh_list_lock); - - rose_neigh = rose_neigh_list; - rose_node = rose_node_list; - - while (rose_node != NULL) { - t = rose_node; - rose_node = rose_node->next; - - if (!t->loopback) { - for (i = 0; i < t->count; i++) - rose_neigh_put(t->neighbour[i]); - rose_remove_node(t); - } - } - - while (rose_neigh != NULL) { - s = rose_neigh; - rose_neigh = rose_neigh->next; - - if (!s->loopback) { - rose_remove_neigh(s); - rose_neigh_put(s); - } - } - - spin_unlock_bh(&rose_neigh_list_lock); - spin_unlock_bh(&rose_node_list_lock); - - return 0; -} - -/* - * Check that the device given is a valid AX.25 interface that is "up". - * called with RTNL - */ -static struct net_device *rose_ax25_dev_find(char *devname) -{ - struct net_device *dev; - - if ((dev = __dev_get_by_name(&init_net, devname)) == NULL) - return NULL; - - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) - return dev; - - return NULL; -} - -/* - * Find the first active ROSE device, usually "rose0". - */ -struct net_device *rose_dev_first(void) -{ - struct net_device *dev, *first = NULL; - - rcu_read_lock(); - for_each_netdev_rcu(&init_net, dev) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE) - if (first == NULL || strncmp(dev->name, first->name, 3) < 0) - first = dev; - } - if (first) - dev_hold(first); - rcu_read_unlock(); - - return first; -} - -/* - * Find the ROSE device for the given address. - */ -struct net_device *rose_dev_get(rose_address *addr) -{ - struct net_device *dev; - - rcu_read_lock(); - for_each_netdev_rcu(&init_net, dev) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && - rosecmp(addr, (const rose_address *)dev->dev_addr) == 0) { - dev_hold(dev); - goto out; - } - } - dev = NULL; -out: - rcu_read_unlock(); - return dev; -} - -static int rose_dev_exists(rose_address *addr) -{ - struct net_device *dev; - - rcu_read_lock(); - for_each_netdev_rcu(&init_net, dev) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && - rosecmp(addr, (const rose_address *)dev->dev_addr) == 0) - goto out; - } - dev = NULL; -out: - rcu_read_unlock(); - return dev != NULL; -} - - - - -struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neigh) -{ - struct rose_route *rose_route; - - for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) - if ((rose_route->neigh1 == neigh && rose_route->lci1 == lci) || - (rose_route->neigh2 == neigh && rose_route->lci2 == lci)) - return rose_route; - - return NULL; -} - -/* - * Find a neighbour or a route given a ROSE address. - */ -struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, - unsigned char *diagnostic, int route_frame) -{ - struct rose_neigh *res = NULL; - struct rose_node *node; - int failed = 0; - int i; - - if (!route_frame) spin_lock_bh(&rose_node_list_lock); - for (node = rose_node_list; node != NULL; node = node->next) { - if (rosecmpm(addr, &node->address, node->mask) == 0) { - for (i = 0; i < node->count; i++) { - if (node->neighbour[i]->restarted) { - res = node->neighbour[i]; - rose_neigh_hold(node->neighbour[i]); - goto out; - } - } - } - } - if (!route_frame) { /* connect request */ - for (node = rose_node_list; node != NULL; node = node->next) { - if (rosecmpm(addr, &node->address, node->mask) == 0) { - for (i = 0; i < node->count; i++) { - if (!rose_ftimer_running(node->neighbour[i])) { - res = node->neighbour[i]; - rose_neigh_hold(node->neighbour[i]); - goto out; - } - failed = 1; - } - } - } - } - - if (failed) { - *cause = ROSE_OUT_OF_ORDER; - *diagnostic = 0; - } else { - *cause = ROSE_NOT_OBTAINABLE; - *diagnostic = 0; - } - -out: - if (!route_frame) spin_unlock_bh(&rose_node_list_lock); - return res; -} - -/* - * Handle the ioctls that control the routing functions. - */ -int rose_rt_ioctl(unsigned int cmd, void __user *arg) -{ - struct rose_route_struct rose_route; - struct net_device *dev; - int err; - - switch (cmd) { - case SIOCADDRT: - if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) - return -EFAULT; - if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) - return -EINVAL; - if (rose_dev_exists(&rose_route.address)) /* Can't add routes to ourself */ - return -EINVAL; - if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ - return -EINVAL; - if (rose_route.ndigis > AX25_MAX_DIGIS) - return -EINVAL; - err = rose_add_node(&rose_route, dev); - return err; - - case SIOCDELRT: - if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) - return -EFAULT; - if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) - return -EINVAL; - err = rose_del_node(&rose_route, dev); - return err; - - case SIOCRSCLRRT: - return rose_clear_routes(); - - default: - return -EINVAL; - } - - return 0; -} - -static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh) -{ - struct rose_route *rose_route, *s; - - rose_neigh->restarted = 0; - - rose_stop_t0timer(rose_neigh); - rose_start_ftimer(rose_neigh); - - skb_queue_purge(&rose_neigh->queue); - - spin_lock_bh(&rose_route_list_lock); - - rose_route = rose_route_list; - - while (rose_route != NULL) { - if ((rose_route->neigh1 == rose_neigh && rose_route->neigh2 == rose_neigh) || - (rose_route->neigh1 == rose_neigh && rose_route->neigh2 == NULL) || - (rose_route->neigh2 == rose_neigh && rose_route->neigh1 == NULL)) { - s = rose_route->next; - rose_remove_route(rose_route); - rose_route = s; - continue; - } - - if (rose_route->neigh1 == rose_neigh) { - rose_neigh_put(rose_route->neigh1); - rose_route->neigh1 = NULL; - rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0); - } - - if (rose_route->neigh2 == rose_neigh) { - rose_neigh_put(rose_route->neigh2); - rose_route->neigh2 = NULL; - rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0); - } - - rose_route = rose_route->next; - } - spin_unlock_bh(&rose_route_list_lock); -} - -/* - * A level 2 link has timed out, therefore it appears to be a poor link, - * then don't use that neighbour until it is reset. Blow away all through - * routes and connections using this route. - */ -void rose_link_failed(ax25_cb *ax25, int reason) -{ - struct rose_neigh *rose_neigh; - - spin_lock_bh(&rose_neigh_list_lock); - rose_neigh = rose_neigh_list; - while (rose_neigh != NULL) { - if (rose_neigh->ax25 == ax25) - break; - rose_neigh = rose_neigh->next; - } - - if (rose_neigh != NULL) { - rose_neigh->ax25 = NULL; - ax25_cb_put(ax25); - - rose_del_route_by_neigh(rose_neigh); - rose_kill_by_neigh(rose_neigh); - } - spin_unlock_bh(&rose_neigh_list_lock); -} - -/* - * A device has been "downed" remove its link status. Blow away all - * through routes and connections that use this device. - */ -void rose_link_device_down(struct net_device *dev) -{ - struct rose_neigh *rose_neigh; - - for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) { - if (rose_neigh->dev == dev) { - rose_del_route_by_neigh(rose_neigh); - rose_kill_by_neigh(rose_neigh); - } - } -} - -/* - * Route a frame to an appropriate AX.25 connection. - * A NULL ax25_cb indicates an internally generated frame. - */ -int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) -{ - struct rose_neigh *rose_neigh, *new_neigh; - struct rose_route *rose_route; - struct rose_facilities_struct facilities; - rose_address *src_addr, *dest_addr; - struct sock *sk; - unsigned short frametype; - unsigned int lci, new_lci; - unsigned char cause, diagnostic; - struct net_device *dev; - int res = 0; - char buf[11]; - - if (skb->len < ROSE_MIN_LEN) - return res; - - if (!ax25) - return rose_loopback_queue(skb, NULL); - - frametype = skb->data[2]; - lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); - if (frametype == ROSE_CALL_REQUEST && - (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF || - skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] != - ROSE_CALL_REQ_ADDR_LEN_VAL)) - return res; - src_addr = (rose_address *)(skb->data + ROSE_CALL_REQ_SRC_ADDR_OFF); - dest_addr = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF); - - spin_lock_bh(&rose_neigh_list_lock); - spin_lock_bh(&rose_route_list_lock); - - rose_neigh = rose_neigh_list; - while (rose_neigh != NULL) { - if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && - ax25->ax25_dev->dev == rose_neigh->dev) - break; - rose_neigh = rose_neigh->next; - } - - if (rose_neigh == NULL) { - printk("rose_route : unknown neighbour or device %s\n", - ax2asc(buf, &ax25->dest_addr)); - goto out; - } - - /* - * Obviously the link is working, halt the ftimer. - */ - rose_stop_ftimer(rose_neigh); - - /* - * LCI of zero is always for us, and its always a restart - * frame. - */ - if (lci == 0) { - rose_link_rx_restart(skb, rose_neigh, frametype); - goto out; - } - - /* - * Find an existing socket. - */ - if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) { - if (frametype == ROSE_CALL_REQUEST) { - struct rose_sock *rose = rose_sk(sk); - - /* Remove an existing unused socket */ - rose_clear_queues(sk); - rose->cause = ROSE_NETWORK_CONGESTION; - rose->diagnostic = 0; - rose_neigh_put(rose->neighbour); - rose->neighbour = NULL; - rose->lci = 0; - rose->state = ROSE_STATE_0; - sk->sk_state = TCP_CLOSE; - sk->sk_err = 0; - sk->sk_shutdown |= SEND_SHUTDOWN; - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DEAD); - } - } - else { - skb_reset_transport_header(skb); - res = rose_process_rx_frame(sk, skb); - goto out; - } - } - - /* - * Is is a Call Request and is it for us ? - */ - if (frametype == ROSE_CALL_REQUEST) - if ((dev = rose_dev_get(dest_addr)) != NULL) { - res = rose_rx_call_request(skb, dev, rose_neigh, lci); - dev_put(dev); - goto out; - } - - if (!sysctl_rose_routing_control) { - rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0); - goto out; - } - - /* - * Route it to the next in line if we have an entry for it. - */ - rose_route = rose_route_list; - while (rose_route != NULL) { - if (rose_route->lci1 == lci && - rose_route->neigh1 == rose_neigh) { - if (frametype == ROSE_CALL_REQUEST) { - /* F6FBB - Remove an existing unused route */ - rose_remove_route(rose_route); - break; - } else if (rose_route->neigh2 != NULL) { - skb->data[0] &= 0xF0; - skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F; - skb->data[1] = (rose_route->lci2 >> 0) & 0xFF; - rose_transmit_link(skb, rose_route->neigh2); - if (frametype == ROSE_CLEAR_CONFIRMATION) - rose_remove_route(rose_route); - res = 1; - goto out; - } else { - if (frametype == ROSE_CLEAR_CONFIRMATION) - rose_remove_route(rose_route); - goto out; - } - } - if (rose_route->lci2 == lci && - rose_route->neigh2 == rose_neigh) { - if (frametype == ROSE_CALL_REQUEST) { - /* F6FBB - Remove an existing unused route */ - rose_remove_route(rose_route); - break; - } else if (rose_route->neigh1 != NULL) { - skb->data[0] &= 0xF0; - skb->data[0] |= (rose_route->lci1 >> 8) & 0x0F; - skb->data[1] = (rose_route->lci1 >> 0) & 0xFF; - rose_transmit_link(skb, rose_route->neigh1); - if (frametype == ROSE_CLEAR_CONFIRMATION) - rose_remove_route(rose_route); - res = 1; - goto out; - } else { - if (frametype == ROSE_CLEAR_CONFIRMATION) - rose_remove_route(rose_route); - goto out; - } - } - rose_route = rose_route->next; - } - - /* - * We know that: - * 1. The frame isn't for us, - * 2. It isn't "owned" by any existing route. - */ - if (frametype != ROSE_CALL_REQUEST) { /* XXX */ - res = 0; - goto out; - } - - memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); - - if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF, - skb->len - ROSE_CALL_REQ_FACILITIES_OFF, - &facilities)) { - rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76); - goto out; - } - - /* - * Check for routing loops. - */ - rose_route = rose_route_list; - while (rose_route != NULL) { - if (rose_route->rand == facilities.rand && - rosecmp(src_addr, &rose_route->src_addr) == 0 && - ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 && - ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) { - rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120); - goto out; - } - rose_route = rose_route->next; - } - - if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic, 1)) == NULL) { - rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic); - goto out; - } - - if ((new_lci = rose_new_lci(new_neigh)) == 0) { - rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71); - goto put_neigh; - } - - if ((rose_route = kmalloc_obj(*rose_route, GFP_ATOMIC)) == NULL) { - rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120); - goto put_neigh; - } - - rose_route->lci1 = lci; - rose_route->src_addr = *src_addr; - rose_route->dest_addr = *dest_addr; - rose_route->src_call = facilities.dest_call; - rose_route->dest_call = facilities.source_call; - rose_route->rand = facilities.rand; - rose_route->neigh1 = rose_neigh; - rose_route->lci2 = new_lci; - rose_route->neigh2 = new_neigh; - - rose_neigh_hold(rose_route->neigh1); - rose_neigh_hold(rose_route->neigh2); - - rose_route->next = rose_route_list; - rose_route_list = rose_route; - - skb->data[0] &= 0xF0; - skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F; - skb->data[1] = (rose_route->lci2 >> 0) & 0xFF; - - rose_transmit_link(skb, rose_route->neigh2); - res = 1; - -put_neigh: - rose_neigh_put(new_neigh); -out: - spin_unlock_bh(&rose_route_list_lock); - spin_unlock_bh(&rose_neigh_list_lock); - - return res; -} - -#ifdef CONFIG_PROC_FS - -static void *rose_node_start(struct seq_file *seq, loff_t *pos) - __acquires(rose_node_list_lock) -{ - struct rose_node *rose_node; - int i = 1; - - spin_lock_bh(&rose_node_list_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - for (rose_node = rose_node_list; rose_node && i < *pos; - rose_node = rose_node->next, ++i); - - return (i == *pos) ? rose_node : NULL; -} - -static void *rose_node_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - - return (v == SEQ_START_TOKEN) ? rose_node_list - : ((struct rose_node *)v)->next; -} - -static void rose_node_stop(struct seq_file *seq, void *v) - __releases(rose_node_list_lock) -{ - spin_unlock_bh(&rose_node_list_lock); -} - -static int rose_node_show(struct seq_file *seq, void *v) -{ - char rsbuf[11]; - int i; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, "address mask n neigh neigh neigh\n"); - else { - const struct rose_node *rose_node = v; - seq_printf(seq, "%-10s %04d %d", - rose2asc(rsbuf, &rose_node->address), - rose_node->mask, - rose_node->count); - - for (i = 0; i < rose_node->count; i++) - seq_printf(seq, " %05d", rose_node->neighbour[i]->number); - - seq_puts(seq, "\n"); - } - return 0; -} - -const struct seq_operations rose_node_seqops = { - .start = rose_node_start, - .next = rose_node_next, - .stop = rose_node_stop, - .show = rose_node_show, -}; - -static void *rose_neigh_start(struct seq_file *seq, loff_t *pos) - __acquires(rose_neigh_list_lock) -{ - struct rose_neigh *rose_neigh; - int i = 1; - - spin_lock_bh(&rose_neigh_list_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - for (rose_neigh = rose_neigh_list; rose_neigh && i < *pos; - rose_neigh = rose_neigh->next, ++i); - - return (i == *pos) ? rose_neigh : NULL; -} - -static void *rose_neigh_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - - return (v == SEQ_START_TOKEN) ? rose_neigh_list - : ((struct rose_neigh *)v)->next; -} - -static void rose_neigh_stop(struct seq_file *seq, void *v) - __releases(rose_neigh_list_lock) -{ - spin_unlock_bh(&rose_neigh_list_lock); -} - -static int rose_neigh_show(struct seq_file *seq, void *v) -{ - char buf[11]; - int i; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, - "addr callsign dev count use mode restart t0 tf digipeaters\n"); - else { - struct rose_neigh *rose_neigh = v; - - /* if (!rose_neigh->loopback) { */ - seq_printf(seq, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu", - rose_neigh->number, - (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign), - rose_neigh->dev ? rose_neigh->dev->name : "???", - rose_neigh->count, - refcount_read(&rose_neigh->use) - rose_neigh->count - 1, - (rose_neigh->dce_mode) ? "DCE" : "DTE", - (rose_neigh->restarted) ? "yes" : "no", - ax25_display_timer(&rose_neigh->t0timer) / HZ, - ax25_display_timer(&rose_neigh->ftimer) / HZ); - - if (rose_neigh->digipeat != NULL) { - for (i = 0; i < rose_neigh->digipeat->ndigi; i++) - seq_printf(seq, " %s", ax2asc(buf, &rose_neigh->digipeat->calls[i])); - } - - seq_puts(seq, "\n"); - } - return 0; -} - - -const struct seq_operations rose_neigh_seqops = { - .start = rose_neigh_start, - .next = rose_neigh_next, - .stop = rose_neigh_stop, - .show = rose_neigh_show, -}; - -static void *rose_route_start(struct seq_file *seq, loff_t *pos) - __acquires(rose_route_list_lock) -{ - struct rose_route *rose_route; - int i = 1; - - spin_lock_bh(&rose_route_list_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - for (rose_route = rose_route_list; rose_route && i < *pos; - rose_route = rose_route->next, ++i); - - return (i == *pos) ? rose_route : NULL; -} - -static void *rose_route_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - - return (v == SEQ_START_TOKEN) ? rose_route_list - : ((struct rose_route *)v)->next; -} - -static void rose_route_stop(struct seq_file *seq, void *v) - __releases(rose_route_list_lock) -{ - spin_unlock_bh(&rose_route_list_lock); -} - -static int rose_route_show(struct seq_file *seq, void *v) -{ - char buf[11], rsbuf[11]; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, - "lci address callsign neigh <-> lci address callsign neigh\n"); - else { - struct rose_route *rose_route = v; - - if (rose_route->neigh1) - seq_printf(seq, - "%3.3X %-10s %-9s %05d ", - rose_route->lci1, - rose2asc(rsbuf, &rose_route->src_addr), - ax2asc(buf, &rose_route->src_call), - rose_route->neigh1->number); - else - seq_puts(seq, - "000 * * 00000 "); - - if (rose_route->neigh2) - seq_printf(seq, - "%3.3X %-10s %-9s %05d\n", - rose_route->lci2, - rose2asc(rsbuf, &rose_route->dest_addr), - ax2asc(buf, &rose_route->dest_call), - rose_route->neigh2->number); - else - seq_puts(seq, - "000 * * 00000\n"); - } - return 0; -} - -struct seq_operations rose_route_seqops = { - .start = rose_route_start, - .next = rose_route_next, - .stop = rose_route_stop, - .show = rose_route_show, -}; -#endif /* CONFIG_PROC_FS */ - -/* - * Release all memory associated with ROSE routing structures. - */ -void __exit rose_rt_free(void) -{ - struct rose_neigh *s, *rose_neigh = rose_neigh_list; - struct rose_node *t, *rose_node = rose_node_list; - struct rose_route *u, *rose_route = rose_route_list; - int i; - - while (rose_neigh != NULL) { - s = rose_neigh; - rose_neigh = rose_neigh->next; - - rose_remove_neigh(s); - rose_neigh_put(s); - } - - while (rose_node != NULL) { - t = rose_node; - rose_node = rose_node->next; - - for (i = 0; i < t->count; i++) - rose_neigh_put(t->neighbour[i]); - rose_remove_node(t); - } - - while (rose_route != NULL) { - u = rose_route; - rose_route = rose_route->next; - - rose_remove_route(u); - } -} diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c deleted file mode 100644 index 4dbc437a9e22..000000000000 --- a/net/rose/rose_subr.c +++ /dev/null @@ -1,556 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose); - -/* - * This routine purges all of the queues of frames. - */ -void rose_clear_queues(struct sock *sk) -{ - skb_queue_purge(&sk->sk_write_queue); - skb_queue_purge(&rose_sk(sk)->ack_queue); -} - -/* - * This routine purges the input queue of those frames that have been - * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the - * SDL diagram. - */ -void rose_frames_acked(struct sock *sk, unsigned short nr) -{ - struct sk_buff *skb; - struct rose_sock *rose = rose_sk(sk); - - /* - * Remove all the ack-ed frames from the ack queue. - */ - if (rose->va != nr) { - while (skb_peek(&rose->ack_queue) != NULL && rose->va != nr) { - skb = skb_dequeue(&rose->ack_queue); - kfree_skb(skb); - rose->va = (rose->va + 1) % ROSE_MODULUS; - } - } -} - -void rose_requeue_frames(struct sock *sk) -{ - struct sk_buff *skb, *skb_prev = NULL; - - /* - * Requeue all the un-ack-ed frames on the output queue to be picked - * up by rose_kick. This arrangement handles the possibility of an - * empty output queue. - */ - while ((skb = skb_dequeue(&rose_sk(sk)->ack_queue)) != NULL) { - if (skb_prev == NULL) - skb_queue_head(&sk->sk_write_queue, skb); - else - skb_append(skb_prev, skb, &sk->sk_write_queue); - skb_prev = skb; - } -} - -/* - * Validate that the value of nr is between va and vs. Return true or - * false for testing. - */ -int rose_validate_nr(struct sock *sk, unsigned short nr) -{ - struct rose_sock *rose = rose_sk(sk); - unsigned short vc = rose->va; - - while (vc != rose->vs) { - if (nr == vc) return 1; - vc = (vc + 1) % ROSE_MODULUS; - } - - return nr == rose->vs; -} - -/* - * This routine is called when the packet layer internally generates a - * control frame. - */ -void rose_write_internal(struct sock *sk, int frametype) -{ - struct rose_sock *rose = rose_sk(sk); - struct sk_buff *skb; - unsigned char *dptr; - unsigned char lci1, lci2; - int maxfaclen = 0; - int len, faclen; - int reserve; - - reserve = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1; - len = ROSE_MIN_LEN; - - switch (frametype) { - case ROSE_CALL_REQUEST: - len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN; - maxfaclen = 256; - break; - case ROSE_CALL_ACCEPTED: - case ROSE_CLEAR_REQUEST: - case ROSE_RESET_REQUEST: - len += 2; - break; - } - - skb = alloc_skb(reserve + len + maxfaclen, GFP_ATOMIC); - if (!skb) - return; - - /* - * Space for AX.25 header and PID. - */ - skb_reserve(skb, reserve); - - dptr = skb_put(skb, len); - - lci1 = (rose->lci >> 8) & 0x0F; - lci2 = (rose->lci >> 0) & 0xFF; - - switch (frametype) { - case ROSE_CALL_REQUEST: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = ROSE_CALL_REQ_ADDR_LEN_VAL; - memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); - dptr += ROSE_ADDR_LEN; - memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); - dptr += ROSE_ADDR_LEN; - faclen = rose_create_facilities(dptr, rose); - skb_put(skb, faclen); - dptr += faclen; - break; - - case ROSE_CALL_ACCEPTED: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = 0x00; /* Address length */ - *dptr++ = 0; /* Facilities length */ - break; - - case ROSE_CLEAR_REQUEST: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = rose->cause; - *dptr++ = rose->diagnostic; - break; - - case ROSE_RESET_REQUEST: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - *dptr++ = ROSE_DTE_ORIGINATED; - *dptr++ = 0; - break; - - case ROSE_RR: - case ROSE_RNR: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr = frametype; - *dptr++ |= (rose->vr << 5) & 0xE0; - break; - - case ROSE_CLEAR_CONFIRMATION: - case ROSE_RESET_CONFIRMATION: - *dptr++ = ROSE_GFI | lci1; - *dptr++ = lci2; - *dptr++ = frametype; - break; - - default: - printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype); - kfree_skb(skb); - return; - } - - rose_transmit_link(skb, rose->neighbour); -} - -int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m) -{ - unsigned char *frame; - - frame = skb->data; - - *ns = *nr = *q = *d = *m = 0; - - switch (frame[2]) { - case ROSE_CALL_REQUEST: - case ROSE_CALL_ACCEPTED: - case ROSE_CLEAR_REQUEST: - case ROSE_CLEAR_CONFIRMATION: - case ROSE_RESET_REQUEST: - case ROSE_RESET_CONFIRMATION: - return frame[2]; - default: - break; - } - - if ((frame[2] & 0x1F) == ROSE_RR || - (frame[2] & 0x1F) == ROSE_RNR) { - *nr = (frame[2] >> 5) & 0x07; - return frame[2] & 0x1F; - } - - if ((frame[2] & 0x01) == ROSE_DATA) { - *q = (frame[0] & ROSE_Q_BIT) == ROSE_Q_BIT; - *d = (frame[0] & ROSE_D_BIT) == ROSE_D_BIT; - *m = (frame[2] & ROSE_M_BIT) == ROSE_M_BIT; - *nr = (frame[2] >> 5) & 0x07; - *ns = (frame[2] >> 1) & 0x07; - return ROSE_DATA; - } - - return ROSE_ILLEGAL; -} - -static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len) -{ - unsigned char *pt; - unsigned char l, lg, n = 0; - int fac_national_digis_received = 0; - - do { - switch (*p & 0xC0) { - case 0x00: - if (len < 2) - return -1; - p += 2; - n += 2; - len -= 2; - break; - - case 0x40: - if (len < 3) - return -1; - if (*p == FAC_NATIONAL_RAND) - facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); - p += 3; - n += 3; - len -= 3; - break; - - case 0x80: - if (len < 4) - return -1; - p += 4; - n += 4; - len -= 4; - break; - - case 0xC0: - if (len < 2) - return -1; - l = p[1]; - if (len < 2 + l) - return -1; - if (*p == FAC_NATIONAL_DEST_DIGI) { - if (!fac_national_digis_received) { - if (l < AX25_ADDR_LEN) - return -1; - memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); - facilities->source_ndigis = 1; - } - } - else if (*p == FAC_NATIONAL_SRC_DIGI) { - if (!fac_national_digis_received) { - if (l < AX25_ADDR_LEN) - return -1; - memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); - facilities->dest_ndigis = 1; - } - } - else if (*p == FAC_NATIONAL_FAIL_CALL) { - if (l < AX25_ADDR_LEN) - return -1; - memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); - } - else if (*p == FAC_NATIONAL_FAIL_ADD) { - if (l < 1 + ROSE_ADDR_LEN) - return -1; - memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); - } - else if (*p == FAC_NATIONAL_DIGIS) { - if (l % AX25_ADDR_LEN) - return -1; - fac_national_digis_received = 1; - facilities->source_ndigis = 0; - facilities->dest_ndigis = 0; - for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { - if (pt[6] & AX25_HBIT) { - if (facilities->dest_ndigis >= ROSE_MAX_DIGIS) - return -1; - memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); - } else { - if (facilities->source_ndigis >= ROSE_MAX_DIGIS) - return -1; - memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); - } - } - } - p += l + 2; - n += l + 2; - len -= l + 2; - break; - } - } while (*p != 0x00 && len > 0); - - return n; -} - -static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len) -{ - unsigned char l, n = 0; - char callsign[11]; - - do { - switch (*p & 0xC0) { - case 0x00: - if (len < 2) - return -1; - p += 2; - n += 2; - len -= 2; - break; - - case 0x40: - if (len < 3) - return -1; - p += 3; - n += 3; - len -= 3; - break; - - case 0x80: - if (len < 4) - return -1; - p += 4; - n += 4; - len -= 4; - break; - - case 0xC0: - if (len < 2) - return -1; - l = p[1]; - - /* Prevent overflows*/ - if (l < 10 || l > 20) - return -1; - - if (*p == FAC_CCITT_DEST_NSAP) { - memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); - memcpy(callsign, p + 12, l - 10); - callsign[l - 10] = '\0'; - asc2ax(&facilities->source_call, callsign); - } - if (*p == FAC_CCITT_SRC_NSAP) { - memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN); - memcpy(callsign, p + 12, l - 10); - callsign[l - 10] = '\0'; - asc2ax(&facilities->dest_call, callsign); - } - p += l + 2; - n += l + 2; - len -= l + 2; - break; - } - } while (*p != 0x00 && len > 0); - - return n; -} - -int rose_parse_facilities(unsigned char *p, unsigned packet_len, - struct rose_facilities_struct *facilities) -{ - int facilities_len, len; - - facilities_len = *p++; - - if (facilities_len == 0 || (unsigned int)facilities_len > packet_len) - return 0; - - while (facilities_len >= 3 && *p == 0x00) { - facilities_len--; - p++; - - switch (*p) { - case FAC_NATIONAL: /* National */ - len = rose_parse_national(p + 1, facilities, facilities_len - 1); - break; - - case FAC_CCITT: /* CCITT */ - len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); - break; - - default: - printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); - len = 1; - break; - } - - if (len < 0) - return 0; - if (WARN_ON(len >= facilities_len)) - return 0; - facilities_len -= len + 1; - p += len + 1; - } - - return facilities_len == 0; -} - -static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) -{ - unsigned char *p = buffer + 1; - char *callsign; - char buf[11]; - int len, nb; - - /* National Facilities */ - if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) { - *p++ = 0x00; - *p++ = FAC_NATIONAL; - - if (rose->rand != 0) { - *p++ = FAC_NATIONAL_RAND; - *p++ = (rose->rand >> 8) & 0xFF; - *p++ = (rose->rand >> 0) & 0xFF; - } - - /* Sent before older facilities */ - if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) { - int maxdigi = 0; - *p++ = FAC_NATIONAL_DIGIS; - *p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis); - for (nb = 0 ; nb < rose->source_ndigis ; nb++) { - if (++maxdigi >= ROSE_MAX_DIGIS) - break; - memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN); - p[6] |= AX25_HBIT; - p += AX25_ADDR_LEN; - } - for (nb = 0 ; nb < rose->dest_ndigis ; nb++) { - if (++maxdigi >= ROSE_MAX_DIGIS) - break; - memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN); - p[6] &= ~AX25_HBIT; - p += AX25_ADDR_LEN; - } - } - - /* For compatibility */ - if (rose->source_ndigis > 0) { - *p++ = FAC_NATIONAL_SRC_DIGI; - *p++ = AX25_ADDR_LEN; - memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN); - p += AX25_ADDR_LEN; - } - - /* For compatibility */ - if (rose->dest_ndigis > 0) { - *p++ = FAC_NATIONAL_DEST_DIGI; - *p++ = AX25_ADDR_LEN; - memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN); - p += AX25_ADDR_LEN; - } - } - - *p++ = 0x00; - *p++ = FAC_CCITT; - - *p++ = FAC_CCITT_DEST_NSAP; - - callsign = ax2asc(buf, &rose->dest_call); - - *p++ = strlen(callsign) + 10; - *p++ = (strlen(callsign) + 9) * 2; /* ??? */ - - *p++ = 0x47; *p++ = 0x00; *p++ = 0x11; - *p++ = ROSE_ADDR_LEN * 2; - memcpy(p, &rose->dest_addr, ROSE_ADDR_LEN); - p += ROSE_ADDR_LEN; - - memcpy(p, callsign, strlen(callsign)); - p += strlen(callsign); - - *p++ = FAC_CCITT_SRC_NSAP; - - callsign = ax2asc(buf, &rose->source_call); - - *p++ = strlen(callsign) + 10; - *p++ = (strlen(callsign) + 9) * 2; /* ??? */ - - *p++ = 0x47; *p++ = 0x00; *p++ = 0x11; - *p++ = ROSE_ADDR_LEN * 2; - memcpy(p, &rose->source_addr, ROSE_ADDR_LEN); - p += ROSE_ADDR_LEN; - - memcpy(p, callsign, strlen(callsign)); - p += strlen(callsign); - - len = p - buffer; - buffer[0] = len - 1; - - return len; -} - -void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic) -{ - struct rose_sock *rose = rose_sk(sk); - - rose_stop_timer(sk); - rose_stop_idletimer(sk); - - rose_clear_queues(sk); - - rose->lci = 0; - rose->state = ROSE_STATE_0; - - if (cause != -1) - rose->cause = cause; - - if (diagnostic != -1) - rose->diagnostic = diagnostic; - - sk->sk_state = TCP_CLOSE; - sk->sk_err = reason; - sk->sk_shutdown |= SEND_SHUTDOWN; - - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DEAD); - } -} diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c deleted file mode 100644 index bb60a1654d61..000000000000 --- a/net/rose/rose_timer.c +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) - * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void rose_heartbeat_expiry(struct timer_list *t); -static void rose_timer_expiry(struct timer_list *); -static void rose_idletimer_expiry(struct timer_list *); - -void rose_start_heartbeat(struct sock *sk) -{ - sk_stop_timer(sk, &sk->sk_timer); - - sk->sk_timer.function = rose_heartbeat_expiry; - sk->sk_timer.expires = jiffies + 5 * HZ; - - sk_reset_timer(sk, &sk->sk_timer, sk->sk_timer.expires); -} - -void rose_start_t1timer(struct sock *sk) -{ - struct rose_sock *rose = rose_sk(sk); - - sk_stop_timer(sk, &rose->timer); - - rose->timer.function = rose_timer_expiry; - rose->timer.expires = jiffies + rose->t1; - - sk_reset_timer(sk, &rose->timer, rose->timer.expires); -} - -void rose_start_t2timer(struct sock *sk) -{ - struct rose_sock *rose = rose_sk(sk); - - sk_stop_timer(sk, &rose->timer); - - rose->timer.function = rose_timer_expiry; - rose->timer.expires = jiffies + rose->t2; - - sk_reset_timer(sk, &rose->timer, rose->timer.expires); -} - -void rose_start_t3timer(struct sock *sk) -{ - struct rose_sock *rose = rose_sk(sk); - - sk_stop_timer(sk, &rose->timer); - - rose->timer.function = rose_timer_expiry; - rose->timer.expires = jiffies + rose->t3; - - sk_reset_timer(sk, &rose->timer, rose->timer.expires); -} - -void rose_start_hbtimer(struct sock *sk) -{ - struct rose_sock *rose = rose_sk(sk); - - sk_stop_timer(sk, &rose->timer); - - rose->timer.function = rose_timer_expiry; - rose->timer.expires = jiffies + rose->hb; - - sk_reset_timer(sk, &rose->timer, rose->timer.expires); -} - -void rose_start_idletimer(struct sock *sk) -{ - struct rose_sock *rose = rose_sk(sk); - - sk_stop_timer(sk, &rose->idletimer); - - if (rose->idle > 0) { - rose->idletimer.function = rose_idletimer_expiry; - rose->idletimer.expires = jiffies + rose->idle; - - sk_reset_timer(sk, &rose->idletimer, rose->idletimer.expires); - } -} - -void rose_stop_heartbeat(struct sock *sk) -{ - sk_stop_timer(sk, &sk->sk_timer); -} - -void rose_stop_timer(struct sock *sk) -{ - sk_stop_timer(sk, &rose_sk(sk)->timer); -} - -void rose_stop_idletimer(struct sock *sk) -{ - sk_stop_timer(sk, &rose_sk(sk)->idletimer); -} - -static void rose_heartbeat_expiry(struct timer_list *t) -{ - struct sock *sk = timer_container_of(sk, t, sk_timer); - struct rose_sock *rose = rose_sk(sk); - - bh_lock_sock(sk); - if (sock_owned_by_user(sk)) { - sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ/20); - goto out; - } - switch (rose->state) { - case ROSE_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (sock_flag(sk, SOCK_DESTROY) || - (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { - bh_unlock_sock(sk); - rose_destroy_socket(sk); - sock_put(sk); - return; - } - break; - - case ROSE_STATE_3: - /* - * Check for the state of the receive buffer. - */ - if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) && - (rose->condition & ROSE_COND_OWN_RX_BUSY)) { - rose->condition &= ~ROSE_COND_OWN_RX_BUSY; - rose->condition &= ~ROSE_COND_ACK_PENDING; - rose->vl = rose->vr; - rose_write_internal(sk, ROSE_RR); - rose_stop_timer(sk); /* HB */ - break; - } - break; - } - - rose_start_heartbeat(sk); -out: - bh_unlock_sock(sk); - sock_put(sk); -} - -static void rose_timer_expiry(struct timer_list *t) -{ - struct rose_sock *rose = timer_container_of(rose, t, timer); - struct sock *sk = &rose->sock; - - bh_lock_sock(sk); - if (sock_owned_by_user(sk)) { - sk_reset_timer(sk, &rose->timer, jiffies + HZ/20); - goto out; - } - switch (rose->state) { - case ROSE_STATE_1: /* T1 */ - case ROSE_STATE_4: /* T2 */ - rose_write_internal(sk, ROSE_CLEAR_REQUEST); - rose->state = ROSE_STATE_2; - rose_start_t3timer(sk); - break; - - case ROSE_STATE_2: /* T3 */ - rose_neigh_put(rose->neighbour); - rose_disconnect(sk, ETIMEDOUT, -1, -1); - break; - - case ROSE_STATE_3: /* HB */ - if (rose->condition & ROSE_COND_ACK_PENDING) { - rose->condition &= ~ROSE_COND_ACK_PENDING; - rose_enquiry_response(sk); - } - break; - } -out: - bh_unlock_sock(sk); - sock_put(sk); -} - -static void rose_idletimer_expiry(struct timer_list *t) -{ - struct rose_sock *rose = timer_container_of(rose, t, idletimer); - struct sock *sk = &rose->sock; - - bh_lock_sock(sk); - if (sock_owned_by_user(sk)) { - sk_reset_timer(sk, &rose->idletimer, jiffies + HZ/20); - goto out; - } - rose_clear_queues(sk); - - rose_write_internal(sk, ROSE_CLEAR_REQUEST); - rose_sk(sk)->state = ROSE_STATE_2; - - rose_start_t3timer(sk); - - sk->sk_state = TCP_CLOSE; - sk->sk_err = 0; - sk->sk_shutdown |= SEND_SHUTDOWN; - - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - sock_set_flag(sk, SOCK_DEAD); - } -out: - bh_unlock_sock(sk); - sock_put(sk); -} diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c deleted file mode 100644 index d801315b7083..000000000000 --- a/net/rose/sysctl_net_rose.c +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com) - */ -#include -#include -#include -#include -#include - -static int min_timer[] = {1 * HZ}; -static int max_timer[] = {300 * HZ}; -static int min_idle[] = {0 * HZ}; -static int max_idle[] = {65535 * HZ}; -static int min_route[1], max_route[] = {1}; -static int min_ftimer[] = {60 * HZ}; -static int max_ftimer[] = {600 * HZ}; -static int min_maxvcs[] = {1}, max_maxvcs[] = {254}; -static int min_window[] = {1}, max_window[] = {7}; - -static struct ctl_table_header *rose_table_header; - -static struct ctl_table rose_table[] = { - { - .procname = "restart_request_timeout", - .data = &sysctl_rose_restart_request_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_timer, - .extra2 = &max_timer - }, - { - .procname = "call_request_timeout", - .data = &sysctl_rose_call_request_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_timer, - .extra2 = &max_timer - }, - { - .procname = "reset_request_timeout", - .data = &sysctl_rose_reset_request_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_timer, - .extra2 = &max_timer - }, - { - .procname = "clear_request_timeout", - .data = &sysctl_rose_clear_request_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_timer, - .extra2 = &max_timer - }, - { - .procname = "no_activity_timeout", - .data = &sysctl_rose_no_activity_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_idle, - .extra2 = &max_idle - }, - { - .procname = "acknowledge_hold_back_timeout", - .data = &sysctl_rose_ack_hold_back_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_timer, - .extra2 = &max_timer - }, - { - .procname = "routing_control", - .data = &sysctl_rose_routing_control, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_route, - .extra2 = &max_route - }, - { - .procname = "link_fail_timeout", - .data = &sysctl_rose_link_fail_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_ftimer, - .extra2 = &max_ftimer - }, - { - .procname = "maximum_virtual_circuits", - .data = &sysctl_rose_maximum_vcs, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_maxvcs, - .extra2 = &max_maxvcs - }, - { - .procname = "window_size", - .data = &sysctl_rose_window_size, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_window, - .extra2 = &max_window - }, -}; - -void __init rose_register_sysctl(void) -{ - rose_table_header = register_net_sysctl(&init_net, "net/rose", rose_table); -} - -void rose_unregister_sysctl(void) -{ - unregister_net_sysctl_table(rose_table_header); -}