diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index c07dc0ee860e..9764d6edb189 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -1933,7 +1933,7 @@ ... 255= /dev/umem/d15p15 15th partition of 16th board. - 117 char COSA/SRP synchronous serial card + 117 char [REMOVED] COSA/SRP synchronous serial card 0 = /dev/cosa0c0 1st board, 1st channel 1 = /dev/cosa0c1 1st board, 2nd channel ... diff --git a/Documentation/networking/device_drivers/index.rst b/Documentation/networking/device_drivers/index.rst index 5f5cfdb2a300..601eacaf12f3 100644 --- a/Documentation/networking/device_drivers/index.rst +++ b/Documentation/networking/device_drivers/index.rst @@ -17,7 +17,6 @@ Contents: fddi/index hamradio/index qlogic/index - wan/index wifi/index wwan/index diff --git a/Documentation/networking/device_drivers/wan/index.rst b/Documentation/networking/device_drivers/wan/index.rst deleted file mode 100644 index 9d9ae94f00b4..000000000000 --- a/Documentation/networking/device_drivers/wan/index.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) - -Classic WAN Device Drivers -========================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - z8530book - -.. only:: subproject and html - - Indices - ======= - - * :ref:`genindex` diff --git a/Documentation/networking/device_drivers/wan/z8530book.rst b/Documentation/networking/device_drivers/wan/z8530book.rst deleted file mode 100644 index fea2c40e7973..000000000000 --- a/Documentation/networking/device_drivers/wan/z8530book.rst +++ /dev/null @@ -1,256 +0,0 @@ -======================= -Z8530 Programming Guide -======================= - -:Author: Alan Cox - -Introduction -============ - -The Z85x30 family synchronous/asynchronous controller chips are used on -a large number of cheap network interface cards. The kernel provides a -core interface layer that is designed to make it easy to provide WAN -services using this chip. - -The current driver only support synchronous operation. Merging the -asynchronous driver support into this code to allow any Z85x30 device to -be used as both a tty interface and as a synchronous controller is a -project for Linux post the 2.4 release - -Driver Modes -============ - -The Z85230 driver layer can drive Z8530, Z85C30 and Z85230 devices in -three different modes. Each mode can be applied to an individual channel -on the chip (each chip has two channels). - -The PIO synchronous mode supports the most common Z8530 wiring. Here the -chip is interface to the I/O and interrupt facilities of the host -machine but not to the DMA subsystem. When running PIO the Z8530 has -extremely tight timing requirements. Doing high speeds, even with a -Z85230 will be tricky. Typically you should expect to achieve at best -9600 baud with a Z8C530 and 64Kbits with a Z85230. - -The DMA mode supports the chip when it is configured to use dual DMA -channels on an ISA bus. The better cards tend to support this mode of -operation for a single channel. With DMA running the Z85230 tops out -when it starts to hit ISA DMA constraints at about 512Kbits. It is worth -noting here that many PC machines hang or crash when the chip is driven -fast enough to hold the ISA bus solid. - -Transmit DMA mode uses a single DMA channel. The DMA channel is used for -transmission as the transmit FIFO is smaller than the receive FIFO. it -gives better performance than pure PIO mode but is nowhere near as ideal -as pure DMA mode. - -Using the Z85230 driver -======================= - -The Z85230 driver provides the back end interface to your board. To -configure a Z8530 interface you need to detect the board and to identify -its ports and interrupt resources. It is also your problem to verify the -resources are available. - -Having identified the chip you need to fill in a struct z8530_dev, -which describes each chip. This object must exist until you finally -shutdown the board. Firstly zero the active field. This ensures nothing -goes off without you intending it. The irq field should be set to the -interrupt number of the chip. (Each chip has a single interrupt source -rather than each channel). You are responsible for allocating the -interrupt line. The interrupt handler should be set to -:c:func:`z8530_interrupt()`. The device id should be set to the -z8530_dev structure pointer. Whether the interrupt can be shared or not -is board dependent, and up to you to initialise. - -The structure holds two channel structures. Initialise chanA.ctrlio and -chanA.dataio with the address of the control and data ports. You can or -this with Z8530_PORT_SLEEP to indicate your interface needs the 5uS -delay for chip settling done in software. The PORT_SLEEP option is -architecture specific. Other flags may become available on future -platforms, eg for MMIO. Initialise the chanA.irqs to &z8530_nop to -start the chip up as disabled and discarding interrupt events. This -ensures that stray interrupts will be mopped up and not hang the bus. -Set chanA.dev to point to the device structure itself. The private and -name field you may use as you wish. The private field is unused by the -Z85230 layer. The name is used for error reporting and it may thus make -sense to make it match the network name. - -Repeat the same operation with the B channel if your chip has both -channels wired to something useful. This isn't always the case. If it is -not wired then the I/O values do not matter, but you must initialise -chanB.dev. - -If your board has DMA facilities then initialise the txdma and rxdma -fields for the relevant channels. You must also allocate the ISA DMA -channels and do any necessary board level initialisation to configure -them. The low level driver will do the Z8530 and DMA controller -programming but not board specific magic. - -Having initialised the device you can then call -:c:func:`z8530_init()`. This will probe the chip and reset it into -a known state. An identification sequence is then run to identify the -chip type. If the checks fail to pass the function returns a non zero -error code. Typically this indicates that the port given is not valid. -After this call the type field of the z8530_dev structure is -initialised to either Z8530, Z85C30 or Z85230 according to the chip -found. - -Once you have called z8530_init you can also make use of the utility -function :c:func:`z8530_describe()`. This provides a consistent -reporting format for the Z8530 devices, and allows all the drivers to -provide consistent reporting. - -Attaching Network Interfaces -============================ - -If you wish to use the network interface facilities of the driver, then -you need to attach a network device to each channel that is present and -in use. In addition to use the generic HDLC you need to follow some -additional plumbing rules. They may seem complex but a look at the -example hostess_sv11 driver should reassure you. - -The network device used for each channel should be pointed to by the -netdevice field of each channel. The hdlc-> priv field of the network -device points to your private data - you will need to be able to find -your private data from this. - -The way most drivers approach this particular problem is to create a -structure holding the Z8530 device definition and put that into the -private field of the network device. The network device fields of the -channels then point back to the network devices. - -If you wish to use the generic HDLC then you need to register the HDLC -device. - -Before you register your network device you will also need to provide -suitable handlers for most of the network device callbacks. See the -network device documentation for more details on this. - -Configuring And Activating The Port -=================================== - -The Z85230 driver provides helper functions and tables to load the port -registers on the Z8530 chips. When programming the register settings for -a channel be aware that the documentation recommends initialisation -orders. Strange things happen when these are not followed. - -:c:func:`z8530_channel_load()` takes an array of pairs of -initialisation values in an array of u8 type. The first value is the -Z8530 register number. Add 16 to indicate the alternate register bank on -the later chips. The array is terminated by a 255. - -The driver provides a pair of public tables. The z8530_hdlc_kilostream -table is for the UK 'Kilostream' service and also happens to cover most -other end host configurations. The z8530_hdlc_kilostream_85230 table -is the same configuration using the enhancements of the 85230 chip. The -configuration loaded is standard NRZ encoded synchronous data with HDLC -bitstuffing. All of the timing is taken from the other end of the link. - -When writing your own tables be aware that the driver internally tracks -register values. It may need to reload values. You should therefore be -sure to set registers 1-7, 9-11, 14 and 15 in all configurations. Where -the register settings depend on DMA selection the driver will update the -bits itself when you open or close. Loading a new table with the -interface open is not recommended. - -There are three standard configurations supported by the core code. In -PIO mode the interface is programmed up to use interrupt driven PIO. -This places high demands on the host processor to avoid latency. The -driver is written to take account of latency issues but it cannot avoid -latencies caused by other drivers, notably IDE in PIO mode. Because the -drivers allocate buffers you must also prevent MTU changes while the -port is open. - -Once the port is open it will call the rx_function of each channel -whenever a completed packet arrived. This is invoked from interrupt -context and passes you the channel and a network buffer (struct -sk_buff) holding the data. The data includes the CRC bytes so most -users will want to trim the last two bytes before processing the data. -This function is very timing critical. When you wish to simply discard -data the support code provides the function -:c:func:`z8530_null_rx()` to discard the data. - -To active PIO mode sending and receiving the ``z8530_sync_open`` is called. -This expects to be passed the network device and the channel. Typically -this is called from your network device open callback. On a failure a -non zero error status is returned. -The :c:func:`z8530_sync_close()` function shuts down a PIO -channel. This must be done before the channel is opened again and before -the driver shuts down and unloads. - -The ideal mode of operation is dual channel DMA mode. Here the kernel -driver will configure the board for DMA in both directions. The driver -also handles ISA DMA issues such as controller programming and the -memory range limit for you. This mode is activated by calling the -:c:func:`z8530_sync_dma_open()` function. On failure a non zero -error value is returned. Once this mode is activated it can be shut down -by calling the :c:func:`z8530_sync_dma_close()`. You must call -the close function matching the open mode you used. - -The final supported mode uses a single DMA channel to drive the transmit -side. As the Z85C30 has a larger FIFO on the receive channel this tends -to increase the maximum speed a little. This is activated by calling the -``z8530_sync_txdma_open``. This returns a non zero error code on failure. The -:c:func:`z8530_sync_txdma_close()` function closes down the Z8530 -interface from this mode. - -Network Layer Functions -======================= - -The Z8530 layer provides functions to queue packets for transmission. -The driver internally buffers the frame currently being transmitted and -one further frame (in order to keep back to back transmission running). -Any further buffering is up to the caller. - -The function :c:func:`z8530_queue_xmit()` takes a network buffer -in sk_buff format and queues it for transmission. The caller must -provide the entire packet with the exception of the bitstuffing and CRC. -This is normally done by the caller via the generic HDLC interface -layer. It returns 0 if the buffer has been queued and non zero values -for queue full. If the function accepts the buffer it becomes property -of the Z8530 layer and the caller should not free it. - -The function :c:func:`z8530_get_stats()` returns a pointer to an -internally maintained per interface statistics block. This provides most -of the interface code needed to implement the network layer get_stats -callback. - -Porting The Z8530 Driver -======================== - -The Z8530 driver is written to be portable. In DMA mode it makes -assumptions about the use of ISA DMA. These are probably warranted in -most cases as the Z85230 in particular was designed to glue to PC type -machines. The PIO mode makes no real assumptions. - -Should you need to retarget the Z8530 driver to another architecture the -only code that should need changing are the port I/O functions. At the -moment these assume PC I/O port accesses. This may not be appropriate -for all platforms. Replacing :c:func:`z8530_read_port()` and -``z8530_write_port`` is intended to be all that is required to port -this driver layer. - -Known Bugs And Assumptions -========================== - -Interrupt Locking - The locking in the driver is done via the global cli/sti lock. This - makes for relatively poor SMP performance. Switching this to use a - per device spin lock would probably materially improve performance. - -Occasional Failures - We have reports of occasional failures when run for very long - periods of time and the driver starts to receive junk frames. At the - moment the cause of this is not clear. - -Public Functions Provided -========================= - -.. kernel-doc:: drivers/net/wan/z85230.c - :export: - -Internal Functions -================== - -.. kernel-doc:: drivers/net/wan/z85230.c - :internal: diff --git a/MAINTAINERS b/MAINTAINERS index dd61684c2573..cc5559a7fb5c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5047,12 +5047,6 @@ S: Maintained F: Documentation/hwmon/corsair-psu.rst F: drivers/hwmon/corsair-psu.c -COSA/SRP SYNC SERIAL DRIVER -M: Jan "Yenya" Kasprzak -S: Maintained -W: http://www.fi.muni.cz/~kas/cosa/ -F: drivers/net/wan/cosa* - COUNTER SUBSYSTEM M: William Breathitt Gray L: linux-iio@vger.kernel.org @@ -8772,7 +8766,6 @@ F: kernel/time/timer_*.c HIGH-SPEED SCC DRIVER FOR AX.25 L: linux-hams@vger.kernel.org S: Orphan -F: drivers/net/hamradio/dmascc.c F: drivers/net/hamradio/scc.c HIGHPOINT ROCKETRAID 3xxx RAID DRIVER diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig index b0489437621a..d82f4ebf687f 100644 --- a/arch/mips/configs/gpr_defconfig +++ b/arch/mips/configs/gpr_defconfig @@ -178,11 +178,8 @@ CONFIG_NETCONSOLE=m CONFIG_ATM_TCP=m CONFIG_ATM_LANAI=m CONFIG_ATM_ENI=m -CONFIG_ATM_FIRESTREAM=m -CONFIG_ATM_ZATM=m CONFIG_ATM_NICSTAR=m CONFIG_ATM_IDT77252=m -CONFIG_ATM_HORIZON=m CONFIG_ATM_IA=m CONFIG_ATM_FORE200E=m CONFIG_ATM_HE=m diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index c98099f0b354..0cb4d9aa14d1 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -255,11 +255,8 @@ CONFIG_ARCNET_COM20020_CS=m CONFIG_ATM_TCP=m CONFIG_ATM_LANAI=m CONFIG_ATM_ENI=m -CONFIG_ATM_FIRESTREAM=m -CONFIG_ATM_ZATM=m CONFIG_ATM_NICSTAR=m CONFIG_ATM_IDT77252=m -CONFIG_ATM_HORIZON=m CONFIG_ATM_IA=m CONFIG_ATM_FORE200E=m CONFIG_ATM_HE=m diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index 7be08e24955c..63cdb46a3439 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -146,36 +146,6 @@ config ATM_ENI_BURST_RX_2W 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_FIRESTREAM - tristate "Fujitsu FireStream (FS50/FS155) " - depends on PCI && VIRT_TO_BUS - help - Driver for the Fujitsu FireStream 155 (MB86697) and - FireStream 50 (MB86695) ATM PCI chips. - - To compile this driver as a module, choose M here: the module will - be called firestream. - -config ATM_ZATM - tristate "ZeitNet ZN1221/ZN1225" - depends on PCI && VIRT_TO_BUS - help - Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM - adapters. - - To compile this driver as a module, choose M here: the module will - be called zatm. - -config ATM_ZATM_DEBUG - bool "Enable extended debugging" - depends on ATM_ZATM - 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_NICSTAR tristate "IDT 77201 (NICStAR) (ForeRunnerLE)" depends on PCI @@ -244,30 +214,6 @@ config ATM_IDT77252_USE_SUNI depends on ATM_IDT77252 default y -config ATM_HORIZON - tristate "Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)" - depends on PCI && VIRT_TO_BUS - help - This is a driver for the Horizon chipset ATM adapter cards once - produced by Madge Networks Ltd. Say Y (or M to compile as a module - named horizon) here if you have one of these cards. - -config ATM_HORIZON_DEBUG - bool "Enable debugging messages" - depends on ATM_HORIZON - 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 (not yet) or changed by sending the - string "Dxxxx" to VCI 1023 (where x is a hex digit). 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_IA tristate "Interphase ATM PCI x575/x525/x531" depends on PCI diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 99ecbc280643..c9eade92019b 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -5,9 +5,7 @@ fore_200e-y := fore200e.o -obj-$(CONFIG_ATM_ZATM) += zatm.o uPD98402.o obj-$(CONFIG_ATM_NICSTAR) += nicstar.o -obj-$(CONFIG_ATM_HORIZON) += horizon.o obj-$(CONFIG_ATM_IA) += iphase.o suni.o obj-$(CONFIG_ATM_FORE200E) += fore_200e.o obj-$(CONFIG_ATM_ENI) += eni.o suni.o @@ -26,7 +24,6 @@ endif obj-$(CONFIG_ATM_DUMMY) += adummy.o obj-$(CONFIG_ATM_TCP) += atmtcp.o -obj-$(CONFIG_ATM_FIRESTREAM) += firestream.o obj-$(CONFIG_ATM_LANAI) += lanai.o obj-$(CONFIG_ATM_HE) += he.o diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c deleted file mode 100644 index 4f67404fe64c..000000000000 --- a/drivers/atm/firestream.c +++ /dev/null @@ -1,2057 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -/* drivers/atm/firestream.c - FireStream 155 (MB86697) and - * FireStream 50 (MB86695) device driver - */ - -/* Written & (C) 2000 by R.E.Wolff@BitWizard.nl - * Copied snippets from zatm.c by Werner Almesberger, EPFL LRC/ICA - * and ambassador.c Copyright (C) 1995-1999 Madge Networks Ltd - */ - -/* -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for request_region */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "firestream.h" - -static int loopback = 0; -static int num=0x5a; - -/* According to measurements (but they look suspicious to me!) done in - * '97, 37% of the packets are one cell in size. So it pays to have - * buffers allocated at that size. A large jump in percentage of - * packets occurs at packets around 536 bytes in length. So it also - * pays to have those pre-allocated. Unfortunately, we can't fully - * take advantage of this as the majority of the packets is likely to - * be TCP/IP (As where obviously the measurement comes from) There the - * link would be opened with say a 1500 byte MTU, and we can't handle - * smaller buffers more efficiently than the larger ones. -- REW - */ - -/* Due to the way Linux memory management works, specifying "576" as - * an allocation size here isn't going to help. They are allocated - * from 1024-byte regions anyway. With the size of the sk_buffs (quite - * large), it doesn't pay to allocate the smallest size (64) -- REW */ - -/* This is all guesswork. Hard numbers to back this up or disprove this, - * are appreciated. -- REW */ - -/* The last entry should be about 64k. However, the "buffer size" is - * passed to the chip in a 16 bit field. I don't know how "65536" - * would be interpreted. -- REW */ - -#define NP FS_NR_FREE_POOLS -static int rx_buf_sizes[NP] = {128, 256, 512, 1024, 2048, 4096, 16384, 65520}; -/* log2: 7 8 9 10 11 12 14 16 */ - -#if 0 -static int rx_pool_sizes[NP] = {1024, 1024, 512, 256, 128, 64, 32, 32}; -#else -/* debug */ -static int rx_pool_sizes[NP] = {128, 128, 128, 64, 64, 64, 32, 32}; -#endif -/* log2: 10 10 9 8 7 6 5 5 */ -/* sumlog2: 17 18 18 18 18 18 19 21 */ -/* mem allocated: 128k 256k 256k 256k 256k 256k 512k 2M */ -/* tot mem: almost 4M */ - -/* NP is shorter, so that it fits on a single line. */ -#undef NP - - -/* Small hardware gotcha: - - The FS50 CAM (VP/VC match registers) always take the lowest channel - number that matches. This is not a problem. - - However, they also ignore whether the channel is enabled or - not. This means that if you allocate channel 0 to 1.2 and then - channel 1 to 0.0, then disabeling channel 0 and writing 0 to the - match channel for channel 0 will "steal" the traffic from channel - 1, even if you correctly disable channel 0. - - Workaround: - - - When disabling channels, write an invalid VP/VC value to the - match register. (We use 0xffffffff, which in the worst case - matches VP/VC = /, but I expect it not to match - anything as some "when not in use, program to 0" bits are now - programmed to 1...) - - - Don't initialize the match registers to 0, as 0.0 is a valid - channel. -*/ - - -/* Optimization hints and tips. - - The FireStream chips are very capable of reducing the amount of - "interrupt-traffic" for the CPU. This driver requests an interrupt on EVERY - action. You could try to minimize this a bit. - - Besides that, the userspace->kernel copy and the PCI bus are the - performance limiting issues for this driver. - - You could queue up a bunch of outgoing packets without telling the - FireStream. I'm not sure that's going to win you much though. The - Linux layer won't tell us in advance when it's not going to give us - any more packets in a while. So this is tricky to implement right without - introducing extra delays. - - -- REW - */ - - - - -/* The strings that define what the RX queue entry is all about. */ -/* Fujitsu: Please tell me which ones can have a pointer to a - freepool descriptor! */ -static char *res_strings[] = { - "RX OK: streaming not EOP", - "RX OK: streaming EOP", - "RX OK: Single buffer packet", - "RX OK: packet mode", - "RX OK: F4 OAM (end to end)", - "RX OK: F4 OAM (Segment)", - "RX OK: F5 OAM (end to end)", - "RX OK: F5 OAM (Segment)", - "RX OK: RM cell", - "RX OK: TRANSP cell", - "RX OK: TRANSPC cell", - "Unmatched cell", - "reserved 12", - "reserved 13", - "reserved 14", - "Unrecognized cell", - "reserved 16", - "reassembly abort: AAL5 abort", - "packet purged", - "packet ageing timeout", - "channel ageing timeout", - "calculated length error", - "programmed length limit error", - "aal5 crc32 error", - "oam transp or transpc crc10 error", - "reserved 25", - "reserved 26", - "reserved 27", - "reserved 28", - "reserved 29", - "reserved 30", /* FIXME: The strings between 30-40 might be wrong. */ - "reassembly abort: no buffers", - "receive buffer overflow", - "change in GFC", - "receive buffer full", - "low priority discard - no receive descriptor", - "low priority discard - missing end of packet", - "reserved 37", - "reserved 38", - "reserved 39", - "reserved 40", - "reserved 41", - "reserved 42", - "reserved 43", - "reserved 44", - "reserved 45", - "reserved 46", - "reserved 47", - "reserved 48", - "reserved 49", - "reserved 50", - "reserved 51", - "reserved 52", - "reserved 53", - "reserved 54", - "reserved 55", - "reserved 56", - "reserved 57", - "reserved 58", - "reserved 59", - "reserved 60", - "reserved 61", - "reserved 62", - "reserved 63", -}; - -static char *irq_bitname[] = { - "LPCO", - "DPCO", - "RBRQ0_W", - "RBRQ1_W", - "RBRQ2_W", - "RBRQ3_W", - "RBRQ0_NF", - "RBRQ1_NF", - "RBRQ2_NF", - "RBRQ3_NF", - "BFP_SC", - "INIT", - "INIT_ERR", - "USCEO", - "UPEC0", - "VPFCO", - "CRCCO", - "HECO", - "TBRQ_W", - "TBRQ_NF", - "CTPQ_E", - "GFC_C0", - "PCI_FTL", - "CSQ_W", - "CSQ_NF", - "EXT_INT", - "RXDMA_S" -}; - - -#define PHY_EOF -1 -#define PHY_CLEARALL -2 - -struct reginit_item { - int reg, val; -}; - - -static struct reginit_item PHY_NTC_INIT[] = { - { PHY_CLEARALL, 0x40 }, - { 0x12, 0x0001 }, - { 0x13, 0x7605 }, - { 0x1A, 0x0001 }, - { 0x1B, 0x0005 }, - { 0x38, 0x0003 }, - { 0x39, 0x0006 }, /* changed here to make loopback */ - { 0x01, 0x5262 }, - { 0x15, 0x0213 }, - { 0x00, 0x0003 }, - { PHY_EOF, 0}, /* -1 signals end of list */ -}; - - -/* Safetyfeature: If the card interrupts more than this number of times - in a jiffy (1/100th of a second) then we just disable the interrupt and - print a message. This prevents the system from hanging. - - 150000 packets per second is close to the limit a PC is going to have - anyway. We therefore have to disable this for production. -- REW */ -#undef IRQ_RATE_LIMIT // 100 - -/* Interrupts work now. Unlike serial cards, ATM cards don't work all - that great without interrupts. -- REW */ -#undef FS_POLL_FREQ // 100 - -/* - This driver can spew a whole lot of debugging output at you. If you - need maximum performance, you should disable the DEBUG define. To - aid in debugging in the field, I'm leaving the compile-time debug - features enabled, and disable them "runtime". That allows me to - instruct people with problems to enable debugging without requiring - them to recompile... -- REW -*/ -#define DEBUG - -#ifdef DEBUG -#define fs_dprintk(f, str...) if (fs_debug & f) printk (str) -#else -#define fs_dprintk(f, str...) /* nothing */ -#endif - - -static int fs_keystream = 0; - -#ifdef DEBUG -/* I didn't forget to set this to zero before shipping. Hit me with a stick - if you get this with the debug default not set to zero again. -- REW */ -static int fs_debug = 0; -#else -#define fs_debug 0 -#endif - -#ifdef MODULE -#ifdef DEBUG -module_param(fs_debug, int, 0644); -#endif -module_param(loopback, int, 0); -module_param(num, int, 0); -module_param(fs_keystream, int, 0); -/* XXX Add rx_buf_sizes, and rx_pool_sizes As per request Amar. -- REW */ -#endif - - -#define FS_DEBUG_FLOW 0x00000001 -#define FS_DEBUG_OPEN 0x00000002 -#define FS_DEBUG_QUEUE 0x00000004 -#define FS_DEBUG_IRQ 0x00000008 -#define FS_DEBUG_INIT 0x00000010 -#define FS_DEBUG_SEND 0x00000020 -#define FS_DEBUG_PHY 0x00000040 -#define FS_DEBUG_CLEANUP 0x00000080 -#define FS_DEBUG_QOS 0x00000100 -#define FS_DEBUG_TXQ 0x00000200 -#define FS_DEBUG_ALLOC 0x00000400 -#define FS_DEBUG_TXMEM 0x00000800 -#define FS_DEBUG_QSIZE 0x00001000 - - -#define func_enter() fs_dprintk(FS_DEBUG_FLOW, "fs: enter %s\n", __func__) -#define func_exit() fs_dprintk(FS_DEBUG_FLOW, "fs: exit %s\n", __func__) - - -static struct fs_dev *fs_boards = NULL; - -#ifdef DEBUG - -static void my_hd (void *addr, int len) -{ - int j, ch; - unsigned char *ptr = addr; - - while (len > 0) { - printk ("%p ", ptr); - for (j=0;j < ((len < 16)?len:16);j++) { - printk ("%02x %s", ptr[j], (j==7)?" ":""); - } - for ( ;j < 16;j++) { - printk (" %s", (j==7)?" ":""); - } - for (j=0;j < ((len < 16)?len:16);j++) { - ch = ptr[j]; - printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch)); - } - printk ("\n"); - ptr += 16; - len -= 16; - } -} -#else /* DEBUG */ -static void my_hd (void *addr, int len){} -#endif /* DEBUG */ - -/********** free an skb (as per ATM device driver documentation) **********/ - -/* Hmm. If this is ATM specific, why isn't there an ATM routine for this? - * I copied it over from the ambassador driver. -- REW */ - -static inline void fs_kfree_skb (struct sk_buff * skb) -{ - if (ATM_SKB(skb)->vcc->pop) - ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb); - else - dev_kfree_skb_any (skb); -} - - - - -/* It seems the ATM forum recommends this horribly complicated 16bit - * floating point format. Turns out the Ambassador uses the exact same - * encoding. I just copied it over. If Mitch agrees, I'll move it over - * to the atm_misc file or something like that. (and remove it from - * here and the ambassador driver) -- REW - */ - -/* The good thing about this format is that it is monotonic. So, - a conversion routine need not be very complicated. To be able to - round "nearest" we need to take along a few extra bits. Lets - put these after 16 bits, so that we can just return the top 16 - bits of the 32bit number as the result: - - int mr (unsigned int rate, int r) - { - int e = 16+9; - static int round[4]={0, 0, 0xffff, 0x8000}; - if (!rate) return 0; - while (rate & 0xfc000000) { - rate >>= 1; - e++; - } - while (! (rate & 0xfe000000)) { - rate <<= 1; - e--; - } - -// Now the mantissa is in positions bit 16-25. Excepf for the "hidden 1" that's in bit 26. - rate &= ~0x02000000; -// Next add in the exponent - rate |= e << (16+9); -// And perform the rounding: - return (rate + round[r]) >> 16; - } - - 14 lines-of-code. Compare that with the 120 that the Ambassador - guys needed. (would be 8 lines shorter if I'd try to really reduce - the number of lines: - - int mr (unsigned int rate, int r) - { - int e = 16+9; - static int round[4]={0, 0, 0xffff, 0x8000}; - if (!rate) return 0; - for (; rate & 0xfc000000 ;rate >>= 1, e++); - for (;!(rate & 0xfe000000);rate <<= 1, e--); - return ((rate & ~0x02000000) | (e << (16+9)) + round[r]) >> 16; - } - - Exercise for the reader: Remove one more line-of-code, without - cheating. (Just joining two lines is cheating). (I know it's - possible, don't think you've beat me if you found it... If you - manage to lose two lines or more, keep me updated! ;-) - - -- REW */ - - -#define ROUND_UP 1 -#define ROUND_DOWN 2 -#define ROUND_NEAREST 3 -/********** make rate (not quite as much fun as Horizon) **********/ - -static int make_rate(unsigned int rate, int r, - u16 *bits, unsigned int *actual) -{ - unsigned char exp = -1; /* hush gcc */ - unsigned int man = -1; /* hush gcc */ - - fs_dprintk (FS_DEBUG_QOS, "make_rate %u", rate); - - /* rates in cells per second, ITU format (nasty 16-bit floating-point) - given 5-bit e and 9-bit m: - rate = EITHER (1+m/2^9)*2^e OR 0 - bits = EITHER 1<<14 | e<<9 | m OR 0 - (bit 15 is "reserved", bit 14 "non-zero") - smallest rate is 0 (special representation) - largest rate is (1+511/512)*2^31 = 4290772992 (< 2^32-1) - smallest non-zero rate is (1+0/512)*2^0 = 1 (> 0) - simple algorithm: - find position of top bit, this gives e - remove top bit and shift (rounding if feeling clever) by 9-e - */ - /* Ambassador ucode bug: please don't set bit 14! so 0 rate not - representable. // This should move into the ambassador driver - when properly merged. -- REW */ - - if (rate > 0xffc00000U) { - /* larger than largest representable rate */ - - if (r == ROUND_UP) { - return -EINVAL; - } else { - exp = 31; - man = 511; - } - - } else if (rate) { - /* representable rate */ - - exp = 31; - man = rate; - - /* invariant: rate = man*2^(exp-31) */ - while (!(man & (1<<31))) { - exp = exp - 1; - man = man<<1; - } - - /* man has top bit set - rate = (2^31+(man-2^31))*2^(exp-31) - rate = (1+(man-2^31)/2^31)*2^exp - */ - man = man<<1; - man &= 0xffffffffU; /* a nop on 32-bit systems */ - /* rate = (1+man/2^32)*2^exp - - exp is in the range 0 to 31, man is in the range 0 to 2^32-1 - time to lose significance... we want m in the range 0 to 2^9-1 - rounding presents a minor problem... we first decide which way - we are rounding (based on given rounding direction and possibly - the bits of the mantissa that are to be discarded). - */ - - switch (r) { - case ROUND_DOWN: { - /* just truncate */ - man = man>>(32-9); - break; - } - case ROUND_UP: { - /* check all bits that we are discarding */ - if (man & (~0U>>9)) { - man = (man>>(32-9)) + 1; - if (man == (1<<9)) { - /* no need to check for round up outside of range */ - man = 0; - exp += 1; - } - } else { - man = (man>>(32-9)); - } - break; - } - case ROUND_NEAREST: { - /* check msb that we are discarding */ - if (man & (1<<(32-9-1))) { - man = (man>>(32-9)) + 1; - if (man == (1<<9)) { - /* no need to check for round up outside of range */ - man = 0; - exp += 1; - } - } else { - man = (man>>(32-9)); - } - break; - } - } - - } else { - /* zero rate - not representable */ - - if (r == ROUND_DOWN) { - return -EINVAL; - } else { - exp = 0; - man = 0; - } - } - - fs_dprintk (FS_DEBUG_QOS, "rate: man=%u, exp=%hu", man, exp); - - if (bits) - *bits = /* (1<<14) | */ (exp<<9) | man; - - if (actual) - *actual = (exp >= 9) - ? (1 << exp) + (man << (exp-9)) - : (1 << exp) + ((man + (1<<(9-exp-1))) >> (9-exp)); - - return 0; -} - - - - -/* FireStream access routines */ -/* For DEEP-DOWN debugging these can be rigged to intercept accesses to - certain registers or to just log all accesses. */ - -static inline void write_fs (struct fs_dev *dev, int offset, u32 val) -{ - writel (val, dev->base + offset); -} - - -static inline u32 read_fs (struct fs_dev *dev, int offset) -{ - return readl (dev->base + offset); -} - - - -static inline struct FS_QENTRY *get_qentry (struct fs_dev *dev, struct queue *q) -{ - return bus_to_virt (read_fs (dev, Q_WP(q->offset)) & Q_ADDR_MASK); -} - - -static void submit_qentry (struct fs_dev *dev, struct queue *q, struct FS_QENTRY *qe) -{ - u32 wp; - struct FS_QENTRY *cqe; - - /* XXX Sanity check: the write pointer can be checked to be - still the same as the value passed as qe... -- REW */ - /* udelay (5); */ - while ((wp = read_fs (dev, Q_WP (q->offset))) & Q_FULL) { - fs_dprintk (FS_DEBUG_TXQ, "Found queue at %x full. Waiting.\n", - q->offset); - schedule (); - } - - wp &= ~0xf; - cqe = bus_to_virt (wp); - if (qe != cqe) { - fs_dprintk (FS_DEBUG_TXQ, "q mismatch! %p %p\n", qe, cqe); - } - - write_fs (dev, Q_WP(q->offset), Q_INCWRAP); - - { - static int c; - if (!(c++ % 100)) - { - int rp, wp; - rp = read_fs (dev, Q_RP(q->offset)); - wp = read_fs (dev, Q_WP(q->offset)); - fs_dprintk (FS_DEBUG_TXQ, "q at %d: %x-%x: %x entries.\n", - q->offset, rp, wp, wp-rp); - } - } -} - -#ifdef DEBUG_EXTRA -static struct FS_QENTRY pq[60]; -static int qp; - -static struct FS_BPENTRY dq[60]; -static int qd; -static void *da[60]; -#endif - -static void submit_queue (struct fs_dev *dev, struct queue *q, - u32 cmd, u32 p1, u32 p2, u32 p3) -{ - struct FS_QENTRY *qe; - - qe = get_qentry (dev, q); - qe->cmd = cmd; - qe->p0 = p1; - qe->p1 = p2; - qe->p2 = p3; - submit_qentry (dev, q, qe); - -#ifdef DEBUG_EXTRA - pq[qp].cmd = cmd; - pq[qp].p0 = p1; - pq[qp].p1 = p2; - pq[qp].p2 = p3; - qp++; - if (qp >= 60) qp = 0; -#endif -} - -/* Test the "other" way one day... -- REW */ -#if 1 -#define submit_command submit_queue -#else - -static void submit_command (struct fs_dev *dev, struct queue *q, - u32 cmd, u32 p1, u32 p2, u32 p3) -{ - write_fs (dev, CMDR0, cmd); - write_fs (dev, CMDR1, p1); - write_fs (dev, CMDR2, p2); - write_fs (dev, CMDR3, p3); -} -#endif - - - -static void process_return_queue (struct fs_dev *dev, struct queue *q) -{ - long rq; - struct FS_QENTRY *qe; - void *tc; - - while (!((rq = read_fs (dev, Q_RP(q->offset))) & Q_EMPTY)) { - fs_dprintk (FS_DEBUG_QUEUE, "reaping return queue entry at %lx\n", rq); - qe = bus_to_virt (rq); - - fs_dprintk (FS_DEBUG_QUEUE, "queue entry: %08x %08x %08x %08x. (%d)\n", - qe->cmd, qe->p0, qe->p1, qe->p2, STATUS_CODE (qe)); - - switch (STATUS_CODE (qe)) { - case 5: - tc = bus_to_virt (qe->p0); - fs_dprintk (FS_DEBUG_ALLOC, "Free tc: %p\n", tc); - kfree (tc); - break; - } - - write_fs (dev, Q_RP(q->offset), Q_INCWRAP); - } -} - - -static void process_txdone_queue (struct fs_dev *dev, struct queue *q) -{ - long rq; - long tmp; - struct FS_QENTRY *qe; - struct sk_buff *skb; - struct FS_BPENTRY *td; - - while (!((rq = read_fs (dev, Q_RP(q->offset))) & Q_EMPTY)) { - fs_dprintk (FS_DEBUG_QUEUE, "reaping txdone entry at %lx\n", rq); - qe = bus_to_virt (rq); - - fs_dprintk (FS_DEBUG_QUEUE, "queue entry: %08x %08x %08x %08x: %d\n", - qe->cmd, qe->p0, qe->p1, qe->p2, STATUS_CODE (qe)); - - if (STATUS_CODE (qe) != 2) - fs_dprintk (FS_DEBUG_TXMEM, "queue entry: %08x %08x %08x %08x: %d\n", - qe->cmd, qe->p0, qe->p1, qe->p2, STATUS_CODE (qe)); - - - switch (STATUS_CODE (qe)) { - case 0x01: /* This is for AAL0 where we put the chip in streaming mode */ - fallthrough; - case 0x02: - /* Process a real txdone entry. */ - tmp = qe->p0; - if (tmp & 0x0f) - printk (KERN_WARNING "td not aligned: %ld\n", tmp); - tmp &= ~0x0f; - td = bus_to_virt (tmp); - - fs_dprintk (FS_DEBUG_QUEUE, "Pool entry: %08x %08x %08x %08x %p.\n", - td->flags, td->next, td->bsa, td->aal_bufsize, td->skb ); - - skb = td->skb; - if (skb == FS_VCC (ATM_SKB(skb)->vcc)->last_skb) { - FS_VCC (ATM_SKB(skb)->vcc)->last_skb = NULL; - wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait); - } - td->dev->ntxpckts--; - - { - static int c=0; - - if (!(c++ % 100)) { - fs_dprintk (FS_DEBUG_QSIZE, "[%d]", td->dev->ntxpckts); - } - } - - atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); - - fs_dprintk (FS_DEBUG_TXMEM, "i"); - fs_dprintk (FS_DEBUG_ALLOC, "Free t-skb: %p\n", skb); - fs_kfree_skb (skb); - - fs_dprintk (FS_DEBUG_ALLOC, "Free trans-d: %p\n", td); - memset (td, ATM_POISON_FREE, sizeof(struct FS_BPENTRY)); - kfree (td); - break; - default: - /* Here we get the tx purge inhibit command ... */ - /* Action, I believe, is "don't do anything". -- REW */ - ; - } - - write_fs (dev, Q_RP(q->offset), Q_INCWRAP); - } -} - - -static void process_incoming (struct fs_dev *dev, struct queue *q) -{ - long rq; - struct FS_QENTRY *qe; - struct FS_BPENTRY *pe; - struct sk_buff *skb; - unsigned int channo; - struct atm_vcc *atm_vcc; - - while (!((rq = read_fs (dev, Q_RP(q->offset))) & Q_EMPTY)) { - fs_dprintk (FS_DEBUG_QUEUE, "reaping incoming queue entry at %lx\n", rq); - qe = bus_to_virt (rq); - - fs_dprintk (FS_DEBUG_QUEUE, "queue entry: %08x %08x %08x %08x. ", - qe->cmd, qe->p0, qe->p1, qe->p2); - - fs_dprintk (FS_DEBUG_QUEUE, "-> %x: %s\n", - STATUS_CODE (qe), - res_strings[STATUS_CODE(qe)]); - - pe = bus_to_virt (qe->p0); - fs_dprintk (FS_DEBUG_QUEUE, "Pool entry: %08x %08x %08x %08x %p %p.\n", - pe->flags, pe->next, pe->bsa, pe->aal_bufsize, - pe->skb, pe->fp); - - channo = qe->cmd & 0xffff; - - if (channo < dev->nchannels) - atm_vcc = dev->atm_vccs[channo]; - else - atm_vcc = NULL; - - /* Single buffer packet */ - switch (STATUS_CODE (qe)) { - case 0x1: - /* Fall through for streaming mode */ - fallthrough; - case 0x2:/* Packet received OK.... */ - if (atm_vcc) { - skb = pe->skb; - pe->fp->n--; -#if 0 - fs_dprintk (FS_DEBUG_QUEUE, "Got skb: %p\n", skb); - if (FS_DEBUG_QUEUE & fs_debug) my_hd (bus_to_virt (pe->bsa), 0x20); -#endif - skb_put (skb, qe->p1 & 0xffff); - ATM_SKB(skb)->vcc = atm_vcc; - atomic_inc(&atm_vcc->stats->rx); - __net_timestamp(skb); - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p (pushed)\n", skb); - atm_vcc->push (atm_vcc, skb); - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", pe); - kfree (pe); - } else { - printk (KERN_ERR "Got a receive on a non-open channel %d.\n", channo); - } - break; - case 0x17:/* AAL 5 CRC32 error. IFF the length field is nonzero, a buffer - has been consumed and needs to be processed. -- REW */ - if (qe->p1 & 0xffff) { - pe = bus_to_virt (qe->p0); - pe->fp->n--; - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", pe->skb); - dev_kfree_skb_any (pe->skb); - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", pe); - kfree (pe); - } - if (atm_vcc) - atomic_inc(&atm_vcc->stats->rx_drop); - break; - case 0x1f: /* Reassembly abort: no buffers. */ - /* Silently increment error counter. */ - if (atm_vcc) - atomic_inc(&atm_vcc->stats->rx_drop); - break; - default: /* Hmm. Haven't written the code to handle the others yet... -- REW */ - printk (KERN_WARNING "Don't know what to do with RX status %x: %s.\n", - STATUS_CODE(qe), res_strings[STATUS_CODE (qe)]); - } - write_fs (dev, Q_RP(q->offset), Q_INCWRAP); - } -} - - - -#define DO_DIRECTION(tp) ((tp)->traffic_class != ATM_NONE) - -static int fs_open(struct atm_vcc *atm_vcc) -{ - struct fs_dev *dev; - struct fs_vcc *vcc; - struct fs_transmit_config *tc; - struct atm_trafprm * txtp; - struct atm_trafprm * rxtp; - /* struct fs_receive_config *rc;*/ - /* struct FS_QENTRY *qe; */ - int error; - int bfp; - int to; - unsigned short tmc0; - short vpi = atm_vcc->vpi; - int vci = atm_vcc->vci; - - func_enter (); - - dev = FS_DEV(atm_vcc->dev); - fs_dprintk (FS_DEBUG_OPEN, "fs: open on dev: %p, vcc at %p\n", - dev, atm_vcc); - - if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) - set_bit(ATM_VF_ADDR, &atm_vcc->flags); - - if ((atm_vcc->qos.aal != ATM_AAL5) && - (atm_vcc->qos.aal != ATM_AAL2)) - return -EINVAL; /* XXX AAL0 */ - - fs_dprintk (FS_DEBUG_OPEN, "fs: (itf %d): open %d.%d\n", - atm_vcc->dev->number, atm_vcc->vpi, atm_vcc->vci); - - /* XXX handle qos parameters (rate limiting) ? */ - - vcc = kmalloc(sizeof(struct fs_vcc), GFP_KERNEL); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc VCC: %p(%zd)\n", vcc, sizeof(struct fs_vcc)); - if (!vcc) { - clear_bit(ATM_VF_ADDR, &atm_vcc->flags); - return -ENOMEM; - } - - atm_vcc->dev_data = vcc; - vcc->last_skb = NULL; - - init_waitqueue_head (&vcc->close_wait); - - txtp = &atm_vcc->qos.txtp; - rxtp = &atm_vcc->qos.rxtp; - - if (!test_bit(ATM_VF_PARTIAL, &atm_vcc->flags)) { - if (IS_FS50(dev)) { - /* Increment the channel numer: take a free one next time. */ - for (to=33;to;to--, dev->channo++) { - /* We only have 32 channels */ - if (dev->channo >= 32) - dev->channo = 0; - /* If we need to do RX, AND the RX is inuse, try the next */ - if (DO_DIRECTION(rxtp) && dev->atm_vccs[dev->channo]) - continue; - /* If we need to do TX, AND the TX is inuse, try the next */ - if (DO_DIRECTION(txtp) && test_bit (dev->channo, dev->tx_inuse)) - continue; - /* Ok, both are free! (or not needed) */ - break; - } - if (!to) { - printk ("No more free channels for FS50..\n"); - kfree(vcc); - return -EBUSY; - } - vcc->channo = dev->channo; - dev->channo &= dev->channel_mask; - - } else { - vcc->channo = (vpi << FS155_VCI_BITS) | (vci); - if (((DO_DIRECTION(rxtp) && dev->atm_vccs[vcc->channo])) || - ( DO_DIRECTION(txtp) && test_bit (vcc->channo, dev->tx_inuse))) { - printk ("Channel is in use for FS155.\n"); - kfree(vcc); - return -EBUSY; - } - } - fs_dprintk (FS_DEBUG_OPEN, "OK. Allocated channel %x(%d).\n", - vcc->channo, vcc->channo); - } - - if (DO_DIRECTION (txtp)) { - tc = kmalloc (sizeof (struct fs_transmit_config), GFP_KERNEL); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc tc: %p(%zd)\n", - tc, sizeof (struct fs_transmit_config)); - if (!tc) { - fs_dprintk (FS_DEBUG_OPEN, "fs: can't alloc transmit_config.\n"); - kfree(vcc); - return -ENOMEM; - } - - /* Allocate the "open" entry from the high priority txq. This makes - it most likely that the chip will notice it. It also prevents us - from having to wait for completion. On the other hand, we may - need to wait for completion anyway, to see if it completed - successfully. */ - - switch (atm_vcc->qos.aal) { - case ATM_AAL2: - case ATM_AAL0: - tc->flags = 0 - | TC_FLAGS_TRANSPARENT_PAYLOAD - | TC_FLAGS_PACKET - | (1 << 28) - | TC_FLAGS_TYPE_UBR /* XXX Change to VBR -- PVDL */ - | TC_FLAGS_CAL0; - break; - case ATM_AAL5: - tc->flags = 0 - | TC_FLAGS_AAL5 - | TC_FLAGS_PACKET /* ??? */ - | TC_FLAGS_TYPE_CBR - | TC_FLAGS_CAL0; - break; - default: - printk ("Unknown aal: %d\n", atm_vcc->qos.aal); - tc->flags = 0; - } - /* Docs are vague about this atm_hdr field. By the way, the FS - * chip makes odd errors if lower bits are set.... -- REW */ - tc->atm_hdr = (vpi << 20) | (vci << 4); - tmc0 = 0; - { - int pcr = atm_pcr_goal (txtp); - - fs_dprintk (FS_DEBUG_OPEN, "pcr = %d.\n", pcr); - - /* XXX Hmm. officially we're only allowed to do this if rounding - is round_down -- REW */ - if (IS_FS50(dev)) { - if (pcr > 51840000/53/8) pcr = 51840000/53/8; - } else { - if (pcr > 155520000/53/8) pcr = 155520000/53/8; - } - if (!pcr) { - /* no rate cap */ - tmc0 = IS_FS50(dev)?0x61BE:0x64c9; /* Just copied over the bits from Fujitsu -- REW */ - } else { - int r; - if (pcr < 0) { - r = ROUND_DOWN; - pcr = -pcr; - } else { - r = ROUND_UP; - } - error = make_rate (pcr, r, &tmc0, NULL); - if (error) { - kfree(tc); - kfree(vcc); - return error; - } - } - fs_dprintk (FS_DEBUG_OPEN, "pcr = %d.\n", pcr); - } - - tc->TMC[0] = tmc0 | 0x4000; - tc->TMC[1] = 0; /* Unused */ - tc->TMC[2] = 0; /* Unused */ - tc->TMC[3] = 0; /* Unused */ - - tc->spec = 0; /* UTOPIA address, UDF, HEC: Unused -> 0 */ - tc->rtag[0] = 0; /* What should I do with routing tags??? - -- Not used -- AS -- Thanks -- REW*/ - tc->rtag[1] = 0; - tc->rtag[2] = 0; - - if (fs_debug & FS_DEBUG_OPEN) { - fs_dprintk (FS_DEBUG_OPEN, "TX config record:\n"); - my_hd (tc, sizeof (*tc)); - } - - /* We now use the "submit_command" function to submit commands to - the firestream. There is a define up near the definition of - that routine that switches this routine between immediate write - to the immediate command registers and queuing the commands in - the HPTXQ for execution. This last technique might be more - efficient if we know we're going to submit a whole lot of - commands in one go, but this driver is not setup to be able to - use such a construct. So it probably doen't matter much right - now. -- REW */ - - /* The command is IMMediate and INQueue. The parameters are out-of-line.. */ - submit_command (dev, &dev->hp_txq, - QE_CMD_CONFIG_TX | QE_CMD_IMM_INQ | vcc->channo, - virt_to_bus (tc), 0, 0); - - submit_command (dev, &dev->hp_txq, - QE_CMD_TX_EN | QE_CMD_IMM_INQ | vcc->channo, - 0, 0, 0); - set_bit (vcc->channo, dev->tx_inuse); - } - - if (DO_DIRECTION (rxtp)) { - dev->atm_vccs[vcc->channo] = atm_vcc; - - for (bfp = 0;bfp < FS_NR_FREE_POOLS; bfp++) - if (atm_vcc->qos.rxtp.max_sdu <= dev->rx_fp[bfp].bufsize) break; - if (bfp >= FS_NR_FREE_POOLS) { - fs_dprintk (FS_DEBUG_OPEN, "No free pool fits sdu: %d.\n", - atm_vcc->qos.rxtp.max_sdu); - /* XXX Cleanup? -- Would just calling fs_close work??? -- REW */ - - /* XXX clear tx inuse. Close TX part? */ - dev->atm_vccs[vcc->channo] = NULL; - kfree (vcc); - return -EINVAL; - } - - switch (atm_vcc->qos.aal) { - case ATM_AAL0: - case ATM_AAL2: - submit_command (dev, &dev->hp_txq, - QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, - RC_FLAGS_TRANSP | - RC_FLAGS_BFPS_BFP * bfp | - RC_FLAGS_RXBM_PSB, 0, 0); - break; - case ATM_AAL5: - submit_command (dev, &dev->hp_txq, - QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, - RC_FLAGS_AAL5 | - RC_FLAGS_BFPS_BFP * bfp | - RC_FLAGS_RXBM_PSB, 0, 0); - break; - } - if (IS_FS50 (dev)) { - submit_command (dev, &dev->hp_txq, - QE_CMD_REG_WR | QE_CMD_IMM_INQ, - 0x80 + vcc->channo, - (vpi << 16) | vci, 0 ); /* XXX -- Use defines. */ - } - submit_command (dev, &dev->hp_txq, - QE_CMD_RX_EN | QE_CMD_IMM_INQ | vcc->channo, - 0, 0, 0); - } - - /* Indicate we're done! */ - set_bit(ATM_VF_READY, &atm_vcc->flags); - - func_exit (); - return 0; -} - - -static void fs_close(struct atm_vcc *atm_vcc) -{ - struct fs_dev *dev = FS_DEV (atm_vcc->dev); - struct fs_vcc *vcc = FS_VCC (atm_vcc); - struct atm_trafprm * txtp; - struct atm_trafprm * rxtp; - - func_enter (); - - clear_bit(ATM_VF_READY, &atm_vcc->flags); - - fs_dprintk (FS_DEBUG_QSIZE, "--==**[%d]**==--", dev->ntxpckts); - if (vcc->last_skb) { - fs_dprintk (FS_DEBUG_QUEUE, "Waiting for skb %p to be sent.\n", - vcc->last_skb); - /* We're going to wait for the last packet to get sent on this VC. It would - be impolite not to send them don't you think? - XXX - We don't know which packets didn't get sent. So if we get interrupted in - this sleep_on, we'll lose any reference to these packets. Memory leak! - On the other hand, it's awfully convenient that we can abort a "close" that - is taking too long. Maybe just use non-interruptible sleep on? -- REW */ - wait_event_interruptible(vcc->close_wait, !vcc->last_skb); - } - - txtp = &atm_vcc->qos.txtp; - rxtp = &atm_vcc->qos.rxtp; - - - /* See App note XXX (Unpublished as of now) for the reason for the - removal of the "CMD_IMM_INQ" part of the TX_PURGE_INH... -- REW */ - - if (DO_DIRECTION (txtp)) { - submit_command (dev, &dev->hp_txq, - QE_CMD_TX_PURGE_INH | /*QE_CMD_IMM_INQ|*/ vcc->channo, 0,0,0); - clear_bit (vcc->channo, dev->tx_inuse); - } - - if (DO_DIRECTION (rxtp)) { - submit_command (dev, &dev->hp_txq, - QE_CMD_RX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0); - dev->atm_vccs [vcc->channo] = NULL; - - /* This means that this is configured as a receive channel */ - if (IS_FS50 (dev)) { - /* Disable the receive filter. Is 0/0 indeed an invalid receive - channel? -- REW. Yes it is. -- Hang. Ok. I'll use -1 - (0xfff...) -- REW */ - submit_command (dev, &dev->hp_txq, - QE_CMD_REG_WR | QE_CMD_IMM_INQ, - 0x80 + vcc->channo, -1, 0 ); - } - } - - fs_dprintk (FS_DEBUG_ALLOC, "Free vcc: %p\n", vcc); - kfree (vcc); - - func_exit (); -} - - -static int fs_send (struct atm_vcc *atm_vcc, struct sk_buff *skb) -{ - struct fs_dev *dev = FS_DEV (atm_vcc->dev); - struct fs_vcc *vcc = FS_VCC (atm_vcc); - struct FS_BPENTRY *td; - - func_enter (); - - fs_dprintk (FS_DEBUG_TXMEM, "I"); - fs_dprintk (FS_DEBUG_SEND, "Send: atm_vcc %p skb %p vcc %p dev %p\n", - atm_vcc, skb, vcc, dev); - - fs_dprintk (FS_DEBUG_ALLOC, "Alloc t-skb: %p (atm_send)\n", skb); - - ATM_SKB(skb)->vcc = atm_vcc; - - vcc->last_skb = skb; - - td = kmalloc (sizeof (struct FS_BPENTRY), GFP_ATOMIC); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc transd: %p(%zd)\n", td, sizeof (struct FS_BPENTRY)); - if (!td) { - /* Oops out of mem */ - return -ENOMEM; - } - - fs_dprintk (FS_DEBUG_SEND, "first word in buffer: %x\n", - *(int *) skb->data); - - td->flags = TD_EPI | TD_DATA | skb->len; - td->next = 0; - td->bsa = virt_to_bus (skb->data); - td->skb = skb; - td->dev = dev; - dev->ntxpckts++; - -#ifdef DEBUG_EXTRA - da[qd] = td; - dq[qd].flags = td->flags; - dq[qd].next = td->next; - dq[qd].bsa = td->bsa; - dq[qd].skb = td->skb; - dq[qd].dev = td->dev; - qd++; - if (qd >= 60) qd = 0; -#endif - - submit_queue (dev, &dev->hp_txq, - QE_TRANSMIT_DE | vcc->channo, - virt_to_bus (td), 0, - virt_to_bus (td)); - - fs_dprintk (FS_DEBUG_QUEUE, "in send: txq %d txrq %d\n", - read_fs (dev, Q_EA (dev->hp_txq.offset)) - - read_fs (dev, Q_SA (dev->hp_txq.offset)), - read_fs (dev, Q_EA (dev->tx_relq.offset)) - - read_fs (dev, Q_SA (dev->tx_relq.offset))); - - func_exit (); - return 0; -} - - -/* Some function placeholders for functions we don't yet support. */ - -#if 0 -static int fs_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) -{ - func_enter (); - func_exit (); - return -ENOIOCTLCMD; -} - - -static int fs_getsockopt(struct atm_vcc *vcc,int level,int optname, - void __user *optval,int optlen) -{ - func_enter (); - func_exit (); - return 0; -} - - -static int fs_setsockopt(struct atm_vcc *vcc,int level,int optname, - void __user *optval,unsigned int optlen) -{ - func_enter (); - func_exit (); - return 0; -} - - -static void fs_phy_put(struct atm_dev *dev,unsigned char value, - unsigned long addr) -{ - func_enter (); - func_exit (); -} - - -static unsigned char fs_phy_get(struct atm_dev *dev,unsigned long addr) -{ - func_enter (); - func_exit (); - return 0; -} - - -static int fs_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags) -{ - func_enter (); - func_exit (); - return 0; -}; - -#endif - - -static const struct atmdev_ops ops = { - .open = fs_open, - .close = fs_close, - .send = fs_send, - .owner = THIS_MODULE, - /* ioctl: fs_ioctl, */ - /* change_qos: fs_change_qos, */ - - /* For now implement these internally here... */ - /* phy_put: fs_phy_put, */ - /* phy_get: fs_phy_get, */ -}; - - -static void undocumented_pci_fix(struct pci_dev *pdev) -{ - u32 tint; - - /* The Windows driver says: */ - /* Switch off FireStream Retry Limit Threshold - */ - - /* The register at 0x28 is documented as "reserved", no further - comments. */ - - pci_read_config_dword (pdev, 0x28, &tint); - if (tint != 0x80) { - tint = 0x80; - pci_write_config_dword (pdev, 0x28, tint); - } -} - - - -/************************************************************************** - * PHY routines * - **************************************************************************/ - -static void write_phy(struct fs_dev *dev, int regnum, int val) -{ - submit_command (dev, &dev->hp_txq, QE_CMD_PRP_WR | QE_CMD_IMM_INQ, - regnum, val, 0); -} - -static int init_phy(struct fs_dev *dev, struct reginit_item *reginit) -{ - int i; - - func_enter (); - while (reginit->reg != PHY_EOF) { - if (reginit->reg == PHY_CLEARALL) { - /* "PHY_CLEARALL means clear all registers. Numregisters is in "val". */ - for (i=0;ival;i++) { - write_phy (dev, i, 0); - } - } else { - write_phy (dev, reginit->reg, reginit->val); - } - reginit++; - } - func_exit (); - return 0; -} - -static void reset_chip (struct fs_dev *dev) -{ - int i; - - write_fs (dev, SARMODE0, SARMODE0_SRTS0); - - /* Undocumented delay */ - udelay (128); - - /* The "internal registers are documented to all reset to zero, but - comments & code in the Windows driver indicates that the pools are - NOT reset. */ - for (i=0;i < FS_NR_FREE_POOLS;i++) { - write_fs (dev, FP_CNF (RXB_FP(i)), 0); - write_fs (dev, FP_SA (RXB_FP(i)), 0); - write_fs (dev, FP_EA (RXB_FP(i)), 0); - write_fs (dev, FP_CNT (RXB_FP(i)), 0); - write_fs (dev, FP_CTU (RXB_FP(i)), 0); - } - - /* The same goes for the match channel registers, although those are - NOT documented that way in the Windows driver. -- REW */ - /* The Windows driver DOES write 0 to these registers somewhere in - the init sequence. However, a small hardware-feature, will - prevent reception of data on VPI/VCI = 0/0 (Unless the channel - allocated happens to have no disabled channels that have a lower - number. -- REW */ - - /* Clear the match channel registers. */ - if (IS_FS50 (dev)) { - for (i=0;i 0x10 alignment not yet implemented (hard!)\n"); - return NULL; -} - -static int init_q(struct fs_dev *dev, struct queue *txq, int queue, - int nentries, int is_rq) -{ - int sz = nentries * sizeof (struct FS_QENTRY); - struct FS_QENTRY *p; - - func_enter (); - - fs_dprintk (FS_DEBUG_INIT, "Initializing queue at %x: %d entries:\n", - queue, nentries); - - p = aligned_kmalloc (sz, GFP_KERNEL, 0x10); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc queue: %p(%d)\n", p, sz); - - if (!p) return 0; - - write_fs (dev, Q_SA(queue), virt_to_bus(p)); - write_fs (dev, Q_EA(queue), virt_to_bus(p+nentries-1)); - write_fs (dev, Q_WP(queue), virt_to_bus(p)); - write_fs (dev, Q_RP(queue), virt_to_bus(p)); - if (is_rq) { - /* Configuration for the receive queue: 0: interrupt immediately, - no pre-warning to empty queues: We do our best to keep the - queue filled anyway. */ - write_fs (dev, Q_CNF(queue), 0 ); - } - - txq->sa = p; - txq->ea = p; - txq->offset = queue; - - func_exit (); - return 1; -} - - -static int init_fp(struct fs_dev *dev, struct freepool *fp, int queue, - int bufsize, int nr_buffers) -{ - func_enter (); - - fs_dprintk (FS_DEBUG_INIT, "Initializing free pool at %x:\n", queue); - - write_fs (dev, FP_CNF(queue), (bufsize * RBFP_RBS) | RBFP_RBSVAL | RBFP_CME); - write_fs (dev, FP_SA(queue), 0); - write_fs (dev, FP_EA(queue), 0); - write_fs (dev, FP_CTU(queue), 0); - write_fs (dev, FP_CNT(queue), 0); - - fp->offset = queue; - fp->bufsize = bufsize; - fp->nr_buffers = nr_buffers; - - func_exit (); - return 1; -} - - -static inline int nr_buffers_in_freepool (struct fs_dev *dev, struct freepool *fp) -{ -#if 0 - /* This seems to be unreliable.... */ - return read_fs (dev, FP_CNT (fp->offset)); -#else - return fp->n; -#endif -} - - -/* Check if this gets going again if a pool ever runs out. -- Yes, it - does. I've seen "receive abort: no buffers" and things started - working again after that... -- REW */ - -static void top_off_fp (struct fs_dev *dev, struct freepool *fp, - gfp_t gfp_flags) -{ - struct FS_BPENTRY *qe, *ne; - struct sk_buff *skb; - int n = 0; - u32 qe_tmp; - - fs_dprintk (FS_DEBUG_QUEUE, "Topping off queue at %x (%d-%d/%d)\n", - fp->offset, read_fs (dev, FP_CNT (fp->offset)), fp->n, - fp->nr_buffers); - while (nr_buffers_in_freepool(dev, fp) < fp->nr_buffers) { - - skb = alloc_skb (fp->bufsize, gfp_flags); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc rec-skb: %p(%d)\n", skb, fp->bufsize); - if (!skb) break; - ne = kmalloc (sizeof (struct FS_BPENTRY), gfp_flags); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc rec-d: %p(%zd)\n", ne, sizeof (struct FS_BPENTRY)); - if (!ne) { - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", skb); - dev_kfree_skb_any (skb); - break; - } - - fs_dprintk (FS_DEBUG_QUEUE, "Adding skb %p desc %p -> %p(%p) ", - skb, ne, skb->data, skb->head); - n++; - ne->flags = FP_FLAGS_EPI | fp->bufsize; - ne->next = virt_to_bus (NULL); - ne->bsa = virt_to_bus (skb->data); - ne->aal_bufsize = fp->bufsize; - ne->skb = skb; - ne->fp = fp; - - /* - * FIXME: following code encodes and decodes - * machine pointers (could be 64-bit) into a - * 32-bit register. - */ - - qe_tmp = read_fs (dev, FP_EA(fp->offset)); - fs_dprintk (FS_DEBUG_QUEUE, "link at %x\n", qe_tmp); - if (qe_tmp) { - qe = bus_to_virt ((long) qe_tmp); - qe->next = virt_to_bus(ne); - qe->flags &= ~FP_FLAGS_EPI; - } else - write_fs (dev, FP_SA(fp->offset), virt_to_bus(ne)); - - write_fs (dev, FP_EA(fp->offset), virt_to_bus (ne)); - fp->n++; /* XXX Atomic_inc? */ - write_fs (dev, FP_CTU(fp->offset), 1); - } - - fs_dprintk (FS_DEBUG_QUEUE, "Added %d entries. \n", n); -} - -static void free_queue(struct fs_dev *dev, struct queue *txq) -{ - func_enter (); - - write_fs (dev, Q_SA(txq->offset), 0); - write_fs (dev, Q_EA(txq->offset), 0); - write_fs (dev, Q_RP(txq->offset), 0); - write_fs (dev, Q_WP(txq->offset), 0); - /* Configuration ? */ - - fs_dprintk (FS_DEBUG_ALLOC, "Free queue: %p\n", txq->sa); - kfree (txq->sa); - - func_exit (); -} - -static void free_freepool(struct fs_dev *dev, struct freepool *fp) -{ - func_enter (); - - write_fs (dev, FP_CNF(fp->offset), 0); - write_fs (dev, FP_SA (fp->offset), 0); - write_fs (dev, FP_EA (fp->offset), 0); - write_fs (dev, FP_CNT(fp->offset), 0); - write_fs (dev, FP_CTU(fp->offset), 0); - - func_exit (); -} - - - -static irqreturn_t fs_irq (int irq, void *dev_id) -{ - int i; - u32 status; - struct fs_dev *dev = dev_id; - - status = read_fs (dev, ISR); - if (!status) - return IRQ_NONE; - - func_enter (); - -#ifdef IRQ_RATE_LIMIT - /* Aaargh! I'm ashamed. This costs more lines-of-code than the actual - interrupt routine!. (Well, used to when I wrote that comment) -- REW */ - { - static int lastjif; - static int nintr=0; - - if (lastjif == jiffies) { - if (++nintr > IRQ_RATE_LIMIT) { - free_irq (dev->irq, dev_id); - printk (KERN_ERR "fs: Too many interrupts. Turning off interrupt %d.\n", - dev->irq); - } - } else { - lastjif = jiffies; - nintr = 0; - } - } -#endif - fs_dprintk (FS_DEBUG_QUEUE, "in intr: txq %d txrq %d\n", - read_fs (dev, Q_EA (dev->hp_txq.offset)) - - read_fs (dev, Q_SA (dev->hp_txq.offset)), - read_fs (dev, Q_EA (dev->tx_relq.offset)) - - read_fs (dev, Q_SA (dev->tx_relq.offset))); - - /* print the bits in the ISR register. */ - if (fs_debug & FS_DEBUG_IRQ) { - /* The FS_DEBUG things are unnecessary here. But this way it is - clear for grep that these are debug prints. */ - fs_dprintk (FS_DEBUG_IRQ, "IRQ status:"); - for (i=0;i<27;i++) - if (status & (1 << i)) - fs_dprintk (FS_DEBUG_IRQ, " %s", irq_bitname[i]); - fs_dprintk (FS_DEBUG_IRQ, "\n"); - } - - if (status & ISR_RBRQ0_W) { - fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (0)!!!!\n"); - process_incoming (dev, &dev->rx_rq[0]); - /* items mentioned on RBRQ0 are from FP 0 or 1. */ - top_off_fp (dev, &dev->rx_fp[0], GFP_ATOMIC); - top_off_fp (dev, &dev->rx_fp[1], GFP_ATOMIC); - } - - if (status & ISR_RBRQ1_W) { - fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (1)!!!!\n"); - process_incoming (dev, &dev->rx_rq[1]); - top_off_fp (dev, &dev->rx_fp[2], GFP_ATOMIC); - top_off_fp (dev, &dev->rx_fp[3], GFP_ATOMIC); - } - - if (status & ISR_RBRQ2_W) { - fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (2)!!!!\n"); - process_incoming (dev, &dev->rx_rq[2]); - top_off_fp (dev, &dev->rx_fp[4], GFP_ATOMIC); - top_off_fp (dev, &dev->rx_fp[5], GFP_ATOMIC); - } - - if (status & ISR_RBRQ3_W) { - fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (3)!!!!\n"); - process_incoming (dev, &dev->rx_rq[3]); - top_off_fp (dev, &dev->rx_fp[6], GFP_ATOMIC); - top_off_fp (dev, &dev->rx_fp[7], GFP_ATOMIC); - } - - if (status & ISR_CSQ_W) { - fs_dprintk (FS_DEBUG_IRQ, "Command executed ok!\n"); - process_return_queue (dev, &dev->st_q); - } - - if (status & ISR_TBRQ_W) { - fs_dprintk (FS_DEBUG_IRQ, "Data transmitted!\n"); - process_txdone_queue (dev, &dev->tx_relq); - } - - func_exit (); - return IRQ_HANDLED; -} - - -#ifdef FS_POLL_FREQ -static void fs_poll (struct timer_list *t) -{ - struct fs_dev *dev = from_timer(dev, t, timer); - - fs_irq (0, dev); - dev->timer.expires = jiffies + FS_POLL_FREQ; - add_timer (&dev->timer); -} -#endif - -static int fs_init(struct fs_dev *dev) -{ - struct pci_dev *pci_dev; - int isr, to; - int i; - - func_enter (); - pci_dev = dev->pci_dev; - - printk (KERN_INFO "found a FireStream %d card, base %16llx, irq%d.\n", - IS_FS50(dev)?50:155, - (unsigned long long)pci_resource_start(pci_dev, 0), - dev->pci_dev->irq); - - if (fs_debug & FS_DEBUG_INIT) - my_hd ((unsigned char *) dev, sizeof (*dev)); - - undocumented_pci_fix (pci_dev); - - dev->hw_base = pci_resource_start(pci_dev, 0); - - dev->base = ioremap(dev->hw_base, 0x1000); - if (!dev->base) - return 1; - - reset_chip (dev); - - write_fs (dev, SARMODE0, 0 - | (0 * SARMODE0_SHADEN) /* We don't use shadow registers. */ - | (1 * SARMODE0_INTMODE_READCLEAR) - | (1 * SARMODE0_CWRE) - | (IS_FS50(dev) ? SARMODE0_PRPWT_FS50_5: - SARMODE0_PRPWT_FS155_3) - | (1 * SARMODE0_CALSUP_1) - | (IS_FS50(dev) ? (0 - | SARMODE0_RXVCS_32 - | SARMODE0_ABRVCS_32 - | SARMODE0_TXVCS_32): - (0 - | SARMODE0_RXVCS_1k - | SARMODE0_ABRVCS_1k - | SARMODE0_TXVCS_1k))); - - /* 10ms * 100 is 1 second. That should be enough, as AN3:9 says it takes - 1ms. */ - to = 100; - while (--to) { - isr = read_fs (dev, ISR); - - /* This bit is documented as "RESERVED" */ - if (isr & ISR_INIT_ERR) { - printk (KERN_ERR "Error initializing the FS... \n"); - goto unmap; - } - if (isr & ISR_INIT) { - fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n"); - break; - } - - /* Try again after 10ms. */ - msleep(10); - } - - if (!to) { - printk (KERN_ERR "timeout initializing the FS... \n"); - goto unmap; - } - - /* XXX fix for fs155 */ - dev->channel_mask = 0x1f; - dev->channo = 0; - - /* AN3: 10 */ - write_fs (dev, SARMODE1, 0 - | (fs_keystream * SARMODE1_DEFHEC) /* XXX PHY */ - | ((loopback == 1) * SARMODE1_TSTLP) /* XXX Loopback mode enable... */ - | (1 * SARMODE1_DCRM) - | (1 * SARMODE1_DCOAM) - | (0 * SARMODE1_OAMCRC) - | (0 * SARMODE1_DUMPE) - | (0 * SARMODE1_GPLEN) - | (0 * SARMODE1_GNAM) - | (0 * SARMODE1_GVAS) - | (0 * SARMODE1_GPAS) - | (1 * SARMODE1_GPRI) - | (0 * SARMODE1_PMS) - | (0 * SARMODE1_GFCR) - | (1 * SARMODE1_HECM2) - | (1 * SARMODE1_HECM1) - | (1 * SARMODE1_HECM0) - | (1 << 12) /* That's what hang's driver does. Program to 0 */ - | (0 * 0xff) /* XXX FS155 */); - - - /* Cal prescale etc */ - - /* AN3: 11 */ - write_fs (dev, TMCONF, 0x0000000f); - write_fs (dev, CALPRESCALE, 0x01010101 * num); - write_fs (dev, 0x80, 0x000F00E4); - - /* AN3: 12 */ - write_fs (dev, CELLOSCONF, 0 - | ( 0 * CELLOSCONF_CEN) - | ( CELLOSCONF_SC1) - | (0x80 * CELLOSCONF_COBS) - | (num * CELLOSCONF_COPK) /* Changed from 0xff to 0x5a */ - | (num * CELLOSCONF_COST));/* after a hint from Hang. - * performance jumped 50->70... */ - - /* Magic value by Hang */ - write_fs (dev, CELLOSCONF_COST, 0x0B809191); - - if (IS_FS50 (dev)) { - write_fs (dev, RAS0, RAS0_DCD_XHLT); - dev->atm_dev->ci_range.vpi_bits = 12; - dev->atm_dev->ci_range.vci_bits = 16; - dev->nchannels = FS50_NR_CHANNELS; - } else { - write_fs (dev, RAS0, RAS0_DCD_XHLT - | (((1 << FS155_VPI_BITS) - 1) * RAS0_VPSEL) - | (((1 << FS155_VCI_BITS) - 1) * RAS0_VCSEL)); - /* We can chose the split arbitrarily. We might be able to - support more. Whatever. This should do for now. */ - dev->atm_dev->ci_range.vpi_bits = FS155_VPI_BITS; - dev->atm_dev->ci_range.vci_bits = FS155_VCI_BITS; - - /* Address bits we can't use should be compared to 0. */ - write_fs (dev, RAC, 0); - - /* Manual (AN9, page 6) says ASF1=0 means compare Utopia address - * too. I can't find ASF1 anywhere. Anyway, we AND with just the - * other bits, then compare with 0, which is exactly what we - * want. */ - write_fs (dev, RAM, (1 << (28 - FS155_VPI_BITS - FS155_VCI_BITS)) - 1); - dev->nchannels = FS155_NR_CHANNELS; - } - dev->atm_vccs = kcalloc (dev->nchannels, sizeof (struct atm_vcc *), - GFP_KERNEL); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc atmvccs: %p(%zd)\n", - dev->atm_vccs, dev->nchannels * sizeof (struct atm_vcc *)); - - if (!dev->atm_vccs) { - printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n"); - /* XXX Clean up..... */ - goto unmap; - } - - dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc tx_inuse: %p(%d)\n", - dev->atm_vccs, dev->nchannels / 8); - - if (!dev->tx_inuse) { - printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n"); - /* XXX Clean up..... */ - goto unmap; - } - /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */ - /* -- RAS2 : FS50 only: Default is OK. */ - - /* DMAMODE, default should be OK. -- REW */ - write_fs (dev, DMAMR, DMAMR_TX_MODE_FULL); - - init_q (dev, &dev->hp_txq, TX_PQ(TXQ_HP), TXQ_NENTRIES, 0); - init_q (dev, &dev->lp_txq, TX_PQ(TXQ_LP), TXQ_NENTRIES, 0); - init_q (dev, &dev->tx_relq, TXB_RQ, TXQ_NENTRIES, 1); - init_q (dev, &dev->st_q, ST_Q, TXQ_NENTRIES, 1); - - for (i=0;i < FS_NR_FREE_POOLS;i++) { - init_fp (dev, &dev->rx_fp[i], RXB_FP(i), - rx_buf_sizes[i], rx_pool_sizes[i]); - top_off_fp (dev, &dev->rx_fp[i], GFP_KERNEL); - } - - - for (i=0;i < FS_NR_RX_QUEUES;i++) - init_q (dev, &dev->rx_rq[i], RXB_RQ(i), RXRQ_NENTRIES, 1); - - dev->irq = pci_dev->irq; - if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) { - printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq); - /* XXX undo all previous stuff... */ - goto unmap; - } - fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev); - - /* We want to be notified of most things. Just the statistics count - overflows are not interesting */ - write_fs (dev, IMR, 0 - | ISR_RBRQ0_W - | ISR_RBRQ1_W - | ISR_RBRQ2_W - | ISR_RBRQ3_W - | ISR_TBRQ_W - | ISR_CSQ_W); - - write_fs (dev, SARMODE0, 0 - | (0 * SARMODE0_SHADEN) /* We don't use shadow registers. */ - | (1 * SARMODE0_GINT) - | (1 * SARMODE0_INTMODE_READCLEAR) - | (0 * SARMODE0_CWRE) - | (IS_FS50(dev)?SARMODE0_PRPWT_FS50_5: - SARMODE0_PRPWT_FS155_3) - | (1 * SARMODE0_CALSUP_1) - | (IS_FS50 (dev)?(0 - | SARMODE0_RXVCS_32 - | SARMODE0_ABRVCS_32 - | SARMODE0_TXVCS_32): - (0 - | SARMODE0_RXVCS_1k - | SARMODE0_ABRVCS_1k - | SARMODE0_TXVCS_1k)) - | (1 * SARMODE0_RUN)); - - init_phy (dev, PHY_NTC_INIT); - - if (loopback == 2) { - write_phy (dev, 0x39, 0x000e); - } - -#ifdef FS_POLL_FREQ - timer_setup(&dev->timer, fs_poll, 0); - dev->timer.expires = jiffies + FS_POLL_FREQ; - add_timer (&dev->timer); -#endif - - dev->atm_dev->dev_data = dev; - - func_exit (); - return 0; -unmap: - iounmap(dev->base); - return 1; -} - -static int firestream_init_one(struct pci_dev *pci_dev, - const struct pci_device_id *ent) -{ - struct atm_dev *atm_dev; - struct fs_dev *fs_dev; - - if (pci_enable_device(pci_dev)) - goto err_out; - - fs_dev = kzalloc (sizeof (struct fs_dev), GFP_KERNEL); - fs_dprintk (FS_DEBUG_ALLOC, "Alloc fs-dev: %p(%zd)\n", - fs_dev, sizeof (struct fs_dev)); - if (!fs_dev) - goto err_out; - atm_dev = atm_dev_register("fs", &pci_dev->dev, &ops, -1, NULL); - if (!atm_dev) - goto err_out_free_fs_dev; - - fs_dev->pci_dev = pci_dev; - fs_dev->atm_dev = atm_dev; - fs_dev->flags = ent->driver_data; - - if (fs_init(fs_dev)) - goto err_out_free_atm_dev; - - fs_dev->next = fs_boards; - fs_boards = fs_dev; - return 0; - - err_out_free_atm_dev: - atm_dev_deregister(atm_dev); - err_out_free_fs_dev: - kfree(fs_dev); - err_out: - return -ENODEV; -} - -static void firestream_remove_one(struct pci_dev *pdev) -{ - int i; - struct fs_dev *dev, *nxtdev; - struct fs_vcc *vcc; - struct FS_BPENTRY *fp, *nxt; - - func_enter (); - -#if 0 - printk ("hptxq:\n"); - for (i=0;i<60;i++) { - printk ("%d: %08x %08x %08x %08x \n", - i, pq[qp].cmd, pq[qp].p0, pq[qp].p1, pq[qp].p2); - qp++; - if (qp >= 60) qp = 0; - } - - printk ("descriptors:\n"); - for (i=0;i<60;i++) { - printk ("%d: %p: %08x %08x %p %p\n", - i, da[qd], dq[qd].flags, dq[qd].bsa, dq[qd].skb, dq[qd].dev); - qd++; - if (qd >= 60) qd = 0; - } -#endif - - for (dev = fs_boards;dev != NULL;dev=nxtdev) { - fs_dprintk (FS_DEBUG_CLEANUP, "Releasing resources for dev at %p.\n", dev); - - /* XXX Hit all the tx channels too! */ - - for (i=0;i < dev->nchannels;i++) { - if (dev->atm_vccs[i]) { - vcc = FS_VCC (dev->atm_vccs[i]); - submit_command (dev, &dev->hp_txq, - QE_CMD_TX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0); - submit_command (dev, &dev->hp_txq, - QE_CMD_RX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0); - - } - } - - /* XXX Wait a while for the chip to release all buffers. */ - - for (i=0;i < FS_NR_FREE_POOLS;i++) { - for (fp=bus_to_virt (read_fs (dev, FP_SA(dev->rx_fp[i].offset))); - !(fp->flags & FP_FLAGS_EPI);fp = nxt) { - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", fp->skb); - dev_kfree_skb_any (fp->skb); - nxt = bus_to_virt (fp->next); - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", fp); - kfree (fp); - } - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", fp->skb); - dev_kfree_skb_any (fp->skb); - fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", fp); - kfree (fp); - } - - /* Hang the chip in "reset", prevent it clobbering memory that is - no longer ours. */ - reset_chip (dev); - - fs_dprintk (FS_DEBUG_CLEANUP, "Freeing irq%d.\n", dev->irq); - free_irq (dev->irq, dev); - del_timer_sync (&dev->timer); - - atm_dev_deregister(dev->atm_dev); - free_queue (dev, &dev->hp_txq); - free_queue (dev, &dev->lp_txq); - free_queue (dev, &dev->tx_relq); - free_queue (dev, &dev->st_q); - - fs_dprintk (FS_DEBUG_ALLOC, "Free atmvccs: %p\n", dev->atm_vccs); - kfree (dev->atm_vccs); - - for (i=0;i< FS_NR_FREE_POOLS;i++) - free_freepool (dev, &dev->rx_fp[i]); - - for (i=0;i < FS_NR_RX_QUEUES;i++) - free_queue (dev, &dev->rx_rq[i]); - - iounmap(dev->base); - fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev); - nxtdev = dev->next; - kfree (dev); - } - - func_exit (); -} - -static const struct pci_device_id firestream_pci_tbl[] = { - { PCI_VDEVICE(FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50), FS_IS50}, - { PCI_VDEVICE(FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155), FS_IS155}, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, firestream_pci_tbl); - -static struct pci_driver firestream_driver = { - .name = "firestream", - .id_table = firestream_pci_tbl, - .probe = firestream_init_one, - .remove = firestream_remove_one, -}; - -static int __init firestream_init_module (void) -{ - int error; - - func_enter (); - error = pci_register_driver(&firestream_driver); - func_exit (); - return error; -} - -static void __exit firestream_cleanup_module(void) -{ - pci_unregister_driver(&firestream_driver); -} - -module_init(firestream_init_module); -module_exit(firestream_cleanup_module); - -MODULE_LICENSE("GPL"); - - - diff --git a/drivers/atm/firestream.h b/drivers/atm/firestream.h deleted file mode 100644 index 6d684160808d..000000000000 --- a/drivers/atm/firestream.h +++ /dev/null @@ -1,502 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* drivers/atm/firestream.h - FireStream 155 (MB86697) and - * FireStream 50 (MB86695) device driver - */ - -/* Written & (C) 2000 by R.E.Wolff@BitWizard.nl - * Copied snippets from zatm.c by Werner Almesberger, EPFL LRC/ICA - * and ambassador.c Copyright (C) 1995-1999 Madge Networks Ltd - */ - -/* -*/ - - -/*********************************************************************** - * first the defines for the chip. * - ***********************************************************************/ - - -/********************* General chip parameters. ************************/ - -#define FS_NR_FREE_POOLS 8 -#define FS_NR_RX_QUEUES 4 - - -/********************* queues and queue access macros ******************/ - - -/* A queue entry. */ -struct FS_QENTRY { - u32 cmd; - u32 p0, p1, p2; -}; - - -/* A freepool entry. */ -struct FS_BPENTRY { - u32 flags; - u32 next; - u32 bsa; - u32 aal_bufsize; - - /* The hardware doesn't look at this, but we need the SKB somewhere... */ - struct sk_buff *skb; - struct freepool *fp; - struct fs_dev *dev; -}; - - -#define STATUS_CODE(qe) ((qe->cmd >> 22) & 0x3f) - - -/* OFFSETS against the base of a QUEUE... */ -#define QSA 0x00 -#define QEA 0x04 -#define QRP 0x08 -#define QWP 0x0c -#define QCNF 0x10 /* Only for Release queues! */ -/* Not for the transmit pending queue. */ - - -/* OFFSETS against the base of a FREE POOL... */ -#define FPCNF 0x00 -#define FPSA 0x04 -#define FPEA 0x08 -#define FPCNT 0x0c -#define FPCTU 0x10 - -#define Q_SA(b) (b + QSA ) -#define Q_EA(b) (b + QEA ) -#define Q_RP(b) (b + QRP ) -#define Q_WP(b) (b + QWP ) -#define Q_CNF(b) (b + QCNF) - -#define FP_CNF(b) (b + FPCNF) -#define FP_SA(b) (b + FPSA) -#define FP_EA(b) (b + FPEA) -#define FP_CNT(b) (b + FPCNT) -#define FP_CTU(b) (b + FPCTU) - -/* bits in a queue register. */ -#define Q_FULL 0x1 -#define Q_EMPTY 0x2 -#define Q_INCWRAP 0x4 -#define Q_ADDR_MASK 0xfffffff0 - -/* bits in a FreePool config register */ -#define RBFP_RBS (0x1 << 16) -#define RBFP_RBSVAL (0x1 << 15) -#define RBFP_CME (0x1 << 12) -#define RBFP_DLP (0x1 << 11) -#define RBFP_BFPWT (0x1 << 0) - - - - -/* FireStream commands. */ -#define QE_CMD_NULL (0x00 << 22) -#define QE_CMD_REG_RD (0x01 << 22) -#define QE_CMD_REG_RDM (0x02 << 22) -#define QE_CMD_REG_WR (0x03 << 22) -#define QE_CMD_REG_WRM (0x04 << 22) -#define QE_CMD_CONFIG_TX (0x05 << 22) -#define QE_CMD_CONFIG_RX (0x06 << 22) -#define QE_CMD_PRP_RD (0x07 << 22) -#define QE_CMD_PRP_RDM (0x2a << 22) -#define QE_CMD_PRP_WR (0x09 << 22) -#define QE_CMD_PRP_WRM (0x2b << 22) -#define QE_CMD_RX_EN (0x0a << 22) -#define QE_CMD_RX_PURGE (0x0b << 22) -#define QE_CMD_RX_PURGE_INH (0x0c << 22) -#define QE_CMD_TX_EN (0x0d << 22) -#define QE_CMD_TX_PURGE (0x0e << 22) -#define QE_CMD_TX_PURGE_INH (0x0f << 22) -#define QE_CMD_RST_CG (0x10 << 22) -#define QE_CMD_SET_CG (0x11 << 22) -#define QE_CMD_RST_CLP (0x12 << 22) -#define QE_CMD_SET_CLP (0x13 << 22) -#define QE_CMD_OVERRIDE (0x14 << 22) -#define QE_CMD_ADD_BFP (0x15 << 22) -#define QE_CMD_DUMP_TX (0x16 << 22) -#define QE_CMD_DUMP_RX (0x17 << 22) -#define QE_CMD_LRAM_RD (0x18 << 22) -#define QE_CMD_LRAM_RDM (0x28 << 22) -#define QE_CMD_LRAM_WR (0x19 << 22) -#define QE_CMD_LRAM_WRM (0x29 << 22) -#define QE_CMD_LRAM_BSET (0x1a << 22) -#define QE_CMD_LRAM_BCLR (0x1b << 22) -#define QE_CMD_CONFIG_SEGM (0x1c << 22) -#define QE_CMD_READ_SEGM (0x1d << 22) -#define QE_CMD_CONFIG_ROUT (0x1e << 22) -#define QE_CMD_READ_ROUT (0x1f << 22) -#define QE_CMD_CONFIG_TM (0x20 << 22) -#define QE_CMD_READ_TM (0x21 << 22) -#define QE_CMD_CONFIG_TXBM (0x22 << 22) -#define QE_CMD_READ_TXBM (0x23 << 22) -#define QE_CMD_CONFIG_RXBM (0x24 << 22) -#define QE_CMD_READ_RXBM (0x25 << 22) -#define QE_CMD_CONFIG_REAS (0x26 << 22) -#define QE_CMD_READ_REAS (0x27 << 22) - -#define QE_TRANSMIT_DE (0x0 << 30) -#define QE_CMD_LINKED (0x1 << 30) -#define QE_CMD_IMM (0x2 << 30) -#define QE_CMD_IMM_INQ (0x3 << 30) - -#define TD_EPI (0x1 << 27) -#define TD_COMMAND (0x1 << 28) - -#define TD_DATA (0x0 << 29) -#define TD_RM_CELL (0x1 << 29) -#define TD_OAM_CELL (0x2 << 29) -#define TD_OAM_CELL_SEGMENT (0x3 << 29) - -#define TD_BPI (0x1 << 20) - -#define FP_FLAGS_EPI (0x1 << 27) - - -#define TX_PQ(i) (0x00 + (i) * 0x10) -#define TXB_RQ (0x20) -#define ST_Q (0x48) -#define RXB_FP(i) (0x90 + (i) * 0x14) -#define RXB_RQ(i) (0x134 + (i) * 0x14) - - -#define TXQ_HP 0 -#define TXQ_LP 1 - -/* Phew. You don't want to know how many revisions these simple queue - * address macros went through before I got them nice and compact as - * they are now. -- REW - */ - - -/* And now for something completely different: - * The rest of the registers... */ - - -#define CMDR0 0x34 -#define CMDR1 0x38 -#define CMDR2 0x3c -#define CMDR3 0x40 - - -#define SARMODE0 0x5c - -#define SARMODE0_TXVCS_0 (0x0 << 0) -#define SARMODE0_TXVCS_1k (0x1 << 0) -#define SARMODE0_TXVCS_2k (0x2 << 0) -#define SARMODE0_TXVCS_4k (0x3 << 0) -#define SARMODE0_TXVCS_8k (0x4 << 0) -#define SARMODE0_TXVCS_16k (0x5 << 0) -#define SARMODE0_TXVCS_32k (0x6 << 0) -#define SARMODE0_TXVCS_64k (0x7 << 0) -#define SARMODE0_TXVCS_32 (0x8 << 0) - -#define SARMODE0_ABRVCS_0 (0x0 << 4) -#define SARMODE0_ABRVCS_512 (0x1 << 4) -#define SARMODE0_ABRVCS_1k (0x2 << 4) -#define SARMODE0_ABRVCS_2k (0x3 << 4) -#define SARMODE0_ABRVCS_4k (0x4 << 4) -#define SARMODE0_ABRVCS_8k (0x5 << 4) -#define SARMODE0_ABRVCS_16k (0x6 << 4) -#define SARMODE0_ABRVCS_32k (0x7 << 4) -#define SARMODE0_ABRVCS_32 (0x9 << 4) /* The others are "8", this one really has to - be 9. Tell me you don't believe me. -- REW */ - -#define SARMODE0_RXVCS_0 (0x0 << 8) -#define SARMODE0_RXVCS_1k (0x1 << 8) -#define SARMODE0_RXVCS_2k (0x2 << 8) -#define SARMODE0_RXVCS_4k (0x3 << 8) -#define SARMODE0_RXVCS_8k (0x4 << 8) -#define SARMODE0_RXVCS_16k (0x5 << 8) -#define SARMODE0_RXVCS_32k (0x6 << 8) -#define SARMODE0_RXVCS_64k (0x7 << 8) -#define SARMODE0_RXVCS_32 (0x8 << 8) - -#define SARMODE0_CALSUP_1 (0x0 << 12) -#define SARMODE0_CALSUP_2 (0x1 << 12) -#define SARMODE0_CALSUP_3 (0x2 << 12) -#define SARMODE0_CALSUP_4 (0x3 << 12) - -#define SARMODE0_PRPWT_FS50_0 (0x0 << 14) -#define SARMODE0_PRPWT_FS50_2 (0x1 << 14) -#define SARMODE0_PRPWT_FS50_5 (0x2 << 14) -#define SARMODE0_PRPWT_FS50_11 (0x3 << 14) - -#define SARMODE0_PRPWT_FS155_0 (0x0 << 14) -#define SARMODE0_PRPWT_FS155_1 (0x1 << 14) -#define SARMODE0_PRPWT_FS155_2 (0x2 << 14) -#define SARMODE0_PRPWT_FS155_3 (0x3 << 14) - -#define SARMODE0_SRTS0 (0x1 << 23) -#define SARMODE0_SRTS1 (0x1 << 24) - -#define SARMODE0_RUN (0x1 << 25) - -#define SARMODE0_UNLOCK (0x1 << 26) -#define SARMODE0_CWRE (0x1 << 27) - - -#define SARMODE0_INTMODE_READCLEAR (0x0 << 28) -#define SARMODE0_INTMODE_READNOCLEAR (0x1 << 28) -#define SARMODE0_INTMODE_READNOCLEARINHIBIT (0x2 << 28) -#define SARMODE0_INTMODE_READCLEARINHIBIT (0x3 << 28) /* Tell me you don't believe me. */ - -#define SARMODE0_GINT (0x1 << 30) -#define SARMODE0_SHADEN (0x1 << 31) - - -#define SARMODE1 0x60 - - -#define SARMODE1_TRTL_SHIFT 0 /* Program to 0 */ -#define SARMODE1_RRTL_SHIFT 4 /* Program to 0 */ - -#define SARMODE1_TAGM (0x1 << 8) /* Program to 0 */ - -#define SARMODE1_HECM0 (0x1 << 9) -#define SARMODE1_HECM1 (0x1 << 10) -#define SARMODE1_HECM2 (0x1 << 11) - -#define SARMODE1_GFCE (0x1 << 14) -#define SARMODE1_GFCR (0x1 << 15) -#define SARMODE1_PMS (0x1 << 18) -#define SARMODE1_GPRI (0x1 << 19) -#define SARMODE1_GPAS (0x1 << 20) -#define SARMODE1_GVAS (0x1 << 21) -#define SARMODE1_GNAM (0x1 << 22) -#define SARMODE1_GPLEN (0x1 << 23) -#define SARMODE1_DUMPE (0x1 << 24) -#define SARMODE1_OAMCRC (0x1 << 25) -#define SARMODE1_DCOAM (0x1 << 26) -#define SARMODE1_DCRM (0x1 << 27) -#define SARMODE1_TSTLP (0x1 << 28) -#define SARMODE1_DEFHEC (0x1 << 29) - - -#define ISR 0x64 -#define IUSR 0x68 -#define IMR 0x6c - -#define ISR_LPCO (0x1 << 0) -#define ISR_DPCO (0x1 << 1) -#define ISR_RBRQ0_W (0x1 << 2) -#define ISR_RBRQ1_W (0x1 << 3) -#define ISR_RBRQ2_W (0x1 << 4) -#define ISR_RBRQ3_W (0x1 << 5) -#define ISR_RBRQ0_NF (0x1 << 6) -#define ISR_RBRQ1_NF (0x1 << 7) -#define ISR_RBRQ2_NF (0x1 << 8) -#define ISR_RBRQ3_NF (0x1 << 9) -#define ISR_BFP_SC (0x1 << 10) -#define ISR_INIT (0x1 << 11) -#define ISR_INIT_ERR (0x1 << 12) /* Documented as "reserved" */ -#define ISR_USCEO (0x1 << 13) -#define ISR_UPEC0 (0x1 << 14) -#define ISR_VPFCO (0x1 << 15) -#define ISR_CRCCO (0x1 << 16) -#define ISR_HECO (0x1 << 17) -#define ISR_TBRQ_W (0x1 << 18) -#define ISR_TBRQ_NF (0x1 << 19) -#define ISR_CTPQ_E (0x1 << 20) -#define ISR_GFC_C0 (0x1 << 21) -#define ISR_PCI_FTL (0x1 << 22) -#define ISR_CSQ_W (0x1 << 23) -#define ISR_CSQ_NF (0x1 << 24) -#define ISR_EXT_INT (0x1 << 25) -#define ISR_RXDMA_S (0x1 << 26) - - -#define TMCONF 0x78 -/* Bits? */ - - -#define CALPRESCALE 0x7c -/* Bits? */ - -#define CELLOSCONF 0x84 -#define CELLOSCONF_COTS (0x1 << 28) -#define CELLOSCONF_CEN (0x1 << 27) -#define CELLOSCONF_SC8 (0x3 << 24) -#define CELLOSCONF_SC4 (0x2 << 24) -#define CELLOSCONF_SC2 (0x1 << 24) -#define CELLOSCONF_SC1 (0x0 << 24) - -#define CELLOSCONF_COBS (0x1 << 16) -#define CELLOSCONF_COPK (0x1 << 8) -#define CELLOSCONF_COST (0x1 << 0) -/* Bits? */ - -#define RAS0 0x1bc -#define RAS0_DCD_XHLT (0x1 << 31) - -#define RAS0_VPSEL (0x1 << 16) -#define RAS0_VCSEL (0x1 << 0) - -#define RAS1 0x1c0 -#define RAS1_UTREG (0x1 << 5) - - -#define DMAMR 0x1cc -#define DMAMR_TX_MODE_FULL (0x0 << 0) -#define DMAMR_TX_MODE_PART (0x1 << 0) -#define DMAMR_TX_MODE_NONE (0x2 << 0) /* And 3 */ - - - -#define RAS2 0x280 - -#define RAS2_NNI (0x1 << 0) -#define RAS2_USEL (0x1 << 1) -#define RAS2_UBS (0x1 << 2) - - - -struct fs_transmit_config { - u32 flags; - u32 atm_hdr; - u32 TMC[4]; - u32 spec; - u32 rtag[3]; -}; - -#define TC_FLAGS_AAL5 (0x0 << 29) -#define TC_FLAGS_TRANSPARENT_PAYLOAD (0x1 << 29) -#define TC_FLAGS_TRANSPARENT_CELL (0x2 << 29) -#define TC_FLAGS_STREAMING (0x1 << 28) -#define TC_FLAGS_PACKET (0x0) -#define TC_FLAGS_TYPE_ABR (0x0 << 22) -#define TC_FLAGS_TYPE_CBR (0x1 << 22) -#define TC_FLAGS_TYPE_VBR (0x2 << 22) -#define TC_FLAGS_TYPE_UBR (0x3 << 22) -#define TC_FLAGS_CAL0 (0x0 << 20) -#define TC_FLAGS_CAL1 (0x1 << 20) -#define TC_FLAGS_CAL2 (0x2 << 20) -#define TC_FLAGS_CAL3 (0x3 << 20) - - -#define RC_FLAGS_NAM (0x1 << 13) -#define RC_FLAGS_RXBM_PSB (0x0 << 14) -#define RC_FLAGS_RXBM_CIF (0x1 << 14) -#define RC_FLAGS_RXBM_PMB (0x2 << 14) -#define RC_FLAGS_RXBM_STR (0x4 << 14) -#define RC_FLAGS_RXBM_SAF (0x6 << 14) -#define RC_FLAGS_RXBM_POS (0x6 << 14) -#define RC_FLAGS_BFPS (0x1 << 17) - -#define RC_FLAGS_BFPS_BFP (0x1 << 17) - -#define RC_FLAGS_BFPS_BFP0 (0x0 << 17) -#define RC_FLAGS_BFPS_BFP1 (0x1 << 17) -#define RC_FLAGS_BFPS_BFP2 (0x2 << 17) -#define RC_FLAGS_BFPS_BFP3 (0x3 << 17) -#define RC_FLAGS_BFPS_BFP4 (0x4 << 17) -#define RC_FLAGS_BFPS_BFP5 (0x5 << 17) -#define RC_FLAGS_BFPS_BFP6 (0x6 << 17) -#define RC_FLAGS_BFPS_BFP7 (0x7 << 17) -#define RC_FLAGS_BFPS_BFP01 (0x8 << 17) -#define RC_FLAGS_BFPS_BFP23 (0x9 << 17) -#define RC_FLAGS_BFPS_BFP45 (0xa << 17) -#define RC_FLAGS_BFPS_BFP67 (0xb << 17) -#define RC_FLAGS_BFPS_BFP07 (0xc << 17) -#define RC_FLAGS_BFPS_BFP27 (0xd << 17) -#define RC_FLAGS_BFPS_BFP47 (0xe << 17) - -#define RC_FLAGS_BFPP (0x1 << 21) -#define RC_FLAGS_TEVC (0x1 << 22) -#define RC_FLAGS_TEP (0x1 << 23) -#define RC_FLAGS_AAL5 (0x0 << 24) -#define RC_FLAGS_TRANSP (0x1 << 24) -#define RC_FLAGS_TRANSC (0x2 << 24) -#define RC_FLAGS_ML (0x1 << 27) -#define RC_FLAGS_TRBRM (0x1 << 28) -#define RC_FLAGS_PRI (0x1 << 29) -#define RC_FLAGS_HOAM (0x1 << 30) -#define RC_FLAGS_CRC10 (0x1 << 31) - - -#define RAC 0x1c8 -#define RAM 0x1c4 - - - -/************************************************************************ - * Then the datastructures that the DRIVER uses. * - ************************************************************************/ - -#define TXQ_NENTRIES 32 -#define RXRQ_NENTRIES 1024 - - -struct fs_vcc { - int channo; - wait_queue_head_t close_wait; - struct sk_buff *last_skb; -}; - - -struct queue { - struct FS_QENTRY *sa, *ea; - int offset; -}; - -struct freepool { - int offset; - int bufsize; - int nr_buffers; - int n; -}; - - -struct fs_dev { - struct fs_dev *next; /* other FS devices */ - int flags; - - unsigned char irq; /* IRQ */ - struct pci_dev *pci_dev; /* PCI stuff */ - struct atm_dev *atm_dev; - struct timer_list timer; - - unsigned long hw_base; /* mem base address */ - void __iomem *base; /* Mapping of base address */ - int channo; - unsigned long channel_mask; - - struct queue hp_txq, lp_txq, tx_relq, st_q; - struct freepool rx_fp[FS_NR_FREE_POOLS]; - struct queue rx_rq[FS_NR_RX_QUEUES]; - - int nchannels; - struct atm_vcc **atm_vccs; - void *tx_inuse; - int ntxpckts; -}; - - - - -/* Number of channesl that the FS50 supports. */ -#define FS50_CHANNEL_BITS 5 -#define FS50_NR_CHANNELS (1 << FS50_CHANNEL_BITS) - - -#define FS_DEV(atm_dev) ((struct fs_dev *) (atm_dev)->dev_data) -#define FS_VCC(atm_vcc) ((struct fs_vcc *) (atm_vcc)->dev_data) - - -#define FS_IS50 0x1 -#define FS_IS155 0x2 - -#define IS_FS50(dev) (dev->flags & FS_IS50) -#define IS_FS155(dev) (dev->flags & FS_IS155) - -/* Within limits this is user-configurable. */ -/* Note: Currently the sum (10 -> 1k channels) is hardcoded in the driver. */ -#define FS155_VPI_BITS 4 -#define FS155_VCI_BITS 6 - -#define FS155_CHANNEL_BITS (FS155_VPI_BITS + FS155_VCI_BITS) -#define FS155_NR_CHANNELS (1 << FS155_CHANNEL_BITS) diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c deleted file mode 100644 index d0e67ec46216..000000000000 --- a/drivers/atm/horizon.c +++ /dev/null @@ -1,2853 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - Madge Horizon ATM Adapter driver. - Copyright (C) 1995-1999 Madge Networks Ltd. - -*/ - -/* - IMPORTANT NOTE: Madge Networks no longer makes the adapters - supported by this driver and makes no commitment to maintain it. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "horizon.h" - -#define maintainer_string "Giuliano Procida at Madge Networks " -#define description_string "Madge ATM Horizon [Ultra] driver" -#define version_string "1.2.1" - -static inline void __init show_version (void) { - printk ("%s version %s\n", description_string, version_string); -} - -/* - - CREDITS - - Driver and documentation by: - - Chris Aston Madge Networks - Giuliano Procida Madge Networks - Simon Benham Madge Networks - Simon Johnson Madge Networks - Various Others Madge Networks - - Some inspiration taken from other drivers by: - - Alexandru Cucos UTBv - Kari Mettinen University of Helsinki - Werner Almesberger EPFL LRC - - Theory of Operation - - I Hardware, detection, initialisation and shutdown. - - 1. Supported Hardware - - This driver should handle all variants of the PCI Madge ATM adapters - with the Horizon chipset. These are all PCI cards supporting PIO, BM - DMA and a form of MMIO (registers only, not internal RAM). - - The driver is only known to work with SONET and UTP Horizon Ultra - cards at 155Mb/s. However, code is in place to deal with both the - original Horizon and 25Mb/s operation. - - There are two revisions of the Horizon ASIC: the original and the - Ultra. Details of hardware bugs are in section III. - - The ASIC version can be distinguished by chip markings but is NOT - indicated by the PCI revision (all adapters seem to have PCI rev 1). - - I believe that: - - Horizon => Collage 25 PCI Adapter (UTP and STP) - Horizon Ultra => Collage 155 PCI Client (UTP or SONET) - Ambassador x => Collage 155 PCI Server (completely different) - - Horizon (25Mb/s) is fitted with UTP and STP connectors. It seems to - have a Madge B154 plus glue logic serializer. I have also found a - really ancient version of this with slightly different glue. It - comes with the revision 0 (140-025-01) ASIC. - - Horizon Ultra (155Mb/s) is fitted with either a Pulse Medialink - output (UTP) or an HP HFBR 5205 output (SONET). It has either - Madge's SAMBA framer or a SUNI-lite device (early versions). It - comes with the revision 1 (140-027-01) ASIC. - - 2. Detection - - All Horizon-based cards present with the same PCI Vendor and Device - IDs. The standard Linux 2.2 PCI API is used to locate any cards and - to enable bus-mastering (with appropriate latency). - - ATM_LAYER_STATUS in the control register distinguishes between the - two possible physical layers (25 and 155). It is not clear whether - the 155 cards can also operate at 25Mbps. We rely on the fact that a - card operates at 155 if and only if it has the newer Horizon Ultra - ASIC. - - For 155 cards the two possible framers are probed for and then set - up for loop-timing. - - 3. Initialisation - - The card is reset and then put into a known state. The physical - layer is configured for normal operation at the appropriate speed; - in the case of the 155 cards, the framer is initialised with - line-based timing; the internal RAM is zeroed and the allocation of - buffers for RX and TX is made; the Burnt In Address is read and - copied to the ATM ESI; various policy settings for RX (VPI bits, - unknown VCs, oam cells) are made. Ideally all policy items should be - configurable at module load (if not actually on-demand), however, - only the vpi vs vci bit allocation can be specified at insmod. - - 4. Shutdown - - This is in response to module_cleaup. No VCs are in use and the card - should be idle; it is reset. - - II Driver software (as it should be) - - 0. Traffic Parameters - - The traffic classes (not an enumeration) are currently: ATM_NONE (no - traffic), ATM_UBR, ATM_CBR, ATM_VBR and ATM_ABR, ATM_ANYCLASS - (compatible with everything). Together with (perhaps only some of) - the following items they make up the traffic specification. - - struct atm_trafprm { - unsigned char traffic_class; traffic class (ATM_UBR, ...) - int max_pcr; maximum PCR in cells per second - int pcr; desired PCR in cells per second - int min_pcr; minimum PCR in cells per second - int max_cdv; maximum CDV in microseconds - int max_sdu; maximum SDU in bytes - }; - - Note that these denote bandwidth available not bandwidth used; the - possibilities according to ATMF are: - - Real Time (cdv and max CDT given) - - CBR(pcr) pcr bandwidth always available - rtVBR(pcr,scr,mbs) scr bandwidth always available, up to pcr at mbs too - - Non Real Time - - nrtVBR(pcr,scr,mbs) scr bandwidth always available, up to pcr at mbs too - UBR() - ABR(mcr,pcr) mcr bandwidth always available, up to pcr (depending) too - - mbs is max burst size (bucket) - pcr and scr have associated cdvt values - mcr is like scr but has no cdtv - cdtv may differ at each hop - - Some of the above items are qos items (as opposed to traffic - parameters). We have nothing to do with qos. All except ABR can have - their traffic parameters converted to GCRA parameters. The GCRA may - be implemented as a (real-number) leaky bucket. The GCRA can be used - in complicated ways by switches and in simpler ways by end-stations. - It can be used both to filter incoming cells and shape out-going - cells. - - ATM Linux actually supports: - - ATM_NONE() (no traffic in this direction) - ATM_UBR(max_frame_size) - ATM_CBR(max/min_pcr, max_cdv, max_frame_size) - - 0 or ATM_MAX_PCR are used to indicate maximum available PCR - - A traffic specification consists of the AAL type and separate - traffic specifications for either direction. In ATM Linux it is: - - struct atm_qos { - struct atm_trafprm txtp; - struct atm_trafprm rxtp; - unsigned char aal; - }; - - AAL types are: - - ATM_NO_AAL AAL not specified - ATM_AAL0 "raw" ATM cells - ATM_AAL1 AAL1 (CBR) - ATM_AAL2 AAL2 (VBR) - ATM_AAL34 AAL3/4 (data) - ATM_AAL5 AAL5 (data) - ATM_SAAL signaling AAL - - The Horizon has support for AAL frame types: 0, 3/4 and 5. However, - it does not implement AAL 3/4 SAR and it has a different notion of - "raw cell" to ATM Linux's (48 bytes vs. 52 bytes) so neither are - supported by this driver. - - The Horizon has limited support for ABR (including UBR), VBR and - CBR. Each TX channel has a bucket (containing up to 31 cell units) - and two timers (PCR and SCR) associated with it that can be used to - govern cell emissions and host notification (in the case of ABR this - is presumably so that RM cells may be emitted at appropriate times). - The timers may either be disabled or may be set to any of 240 values - (determined by the clock crystal, a fixed (?) per-device divider, a - configurable divider and a configurable timer preload value). - - At the moment only UBR and CBR are supported by the driver. VBR will - be supported as soon as ATM for Linux supports it. ABR support is - very unlikely as RM cell handling is completely up to the driver. - - 1. TX (TX channel setup and TX transfer) - - The TX half of the driver owns the TX Horizon registers. The TX - component in the IRQ handler is the BM completion handler. This can - only be entered when tx_busy is true (enforced by hardware). The - other TX component can only be entered when tx_busy is false - (enforced by driver). So TX is single-threaded. - - Apart from a minor optimisation to not re-select the last channel, - the TX send component works as follows: - - Atomic test and set tx_busy until we succeed; we should implement - some sort of timeout so that tx_busy will never be stuck at true. - - If no TX channel is set up for this VC we wait for an idle one (if - necessary) and set it up. - - At this point we have a TX channel ready for use. We wait for enough - buffers to become available then start a TX transmit (set the TX - descriptor, schedule transfer, exit). - - The IRQ component handles TX completion (stats, free buffer, tx_busy - unset, exit). We also re-schedule further transfers for the same - frame if needed. - - TX setup in more detail: - - TX open is a nop, the relevant information is held in the hrz_vcc - (vcc->dev_data) structure and is "cached" on the card. - - TX close gets the TX lock and clears the channel from the "cache". - - 2. RX (Data Available and RX transfer) - - The RX half of the driver owns the RX registers. There are two RX - components in the IRQ handler: the data available handler deals with - fresh data that has arrived on the card, the BM completion handler - is very similar to the TX completion handler. The data available - handler grabs the rx_lock and it is only released once the data has - been discarded or completely transferred to the host. The BM - completion handler only runs when the lock is held; the data - available handler is locked out over the same period. - - Data available on the card triggers an interrupt. If the data is not - suitable for our existing RX channels or we cannot allocate a buffer - it is flushed. Otherwise an RX receive is scheduled. Multiple RX - transfers may be scheduled for the same frame. - - RX setup in more detail: - - RX open... - RX close... - - III Hardware Bugs - - 0. Byte vs Word addressing of adapter RAM. - - A design feature; see the .h file (especially the memory map). - - 1. Bus Master Data Transfers (original Horizon only, fixed in Ultra) - - The host must not start a transmit direction transfer at a - non-four-byte boundary in host memory. Instead the host should - perform a byte, or a two byte, or one byte followed by two byte - transfer in order to start the rest of the transfer on a four byte - boundary. RX is OK. - - Simultaneous transmit and receive direction bus master transfers are - not allowed. - - The simplest solution to these two is to always do PIO (never DMA) - in the TX direction on the original Horizon. More complicated - solutions are likely to hurt my brain. - - 2. Loss of buffer on close VC - - When a VC is being closed, the buffer associated with it is not - returned to the pool. The host must store the reference to this - buffer and when opening a new VC then give it to that new VC. - - The host intervention currently consists of stacking such a buffer - pointer at VC close and checking the stack at VC open. - - 3. Failure to close a VC - - If a VC is currently receiving a frame then closing the VC may fail - and the frame continues to be received. - - The solution is to make sure any received frames are flushed when - ready. This is currently done just before the solution to 2. - - 4. PCI bus (original Horizon only, fixed in Ultra) - - Reading from the data port prior to initialisation will hang the PCI - bus. Just don't do that then! We don't. - - IV To Do List - - . Timer code may be broken. - - . Allow users to specify buffer allocation split for TX and RX. - - . Deal once and for all with buggy VC close. - - . Handle interrupted and/or non-blocking operations. - - . Change some macros to functions and move from .h to .c. - - . Try to limit the number of TX frames each VC may have queued, in - order to reduce the chances of TX buffer exhaustion. - - . Implement VBR (bucket and timers not understood) and ABR (need to - do RM cells manually); also no Linux support for either. - - . Implement QoS changes on open VCs (involves extracting parts of VC open - and close into separate functions and using them to make changes). - -*/ - -/********** globals **********/ - -static void do_housekeeping (struct timer_list *t); - -static unsigned short debug = 0; -static unsigned short vpi_bits = 0; -static int max_tx_size = 9000; -static int max_rx_size = 9000; -static unsigned char pci_lat = 0; - -/********** access functions **********/ - -/* Read / Write Horizon registers */ -static inline void wr_regl (const hrz_dev * dev, unsigned char reg, u32 data) { - outl (cpu_to_le32 (data), dev->iobase + reg); -} - -static inline u32 rd_regl (const hrz_dev * dev, unsigned char reg) { - return le32_to_cpu (inl (dev->iobase + reg)); -} - -static inline void wr_regw (const hrz_dev * dev, unsigned char reg, u16 data) { - outw (cpu_to_le16 (data), dev->iobase + reg); -} - -static inline u16 rd_regw (const hrz_dev * dev, unsigned char reg) { - return le16_to_cpu (inw (dev->iobase + reg)); -} - -static inline void wrs_regb (const hrz_dev * dev, unsigned char reg, void * addr, u32 len) { - outsb (dev->iobase + reg, addr, len); -} - -static inline void rds_regb (const hrz_dev * dev, unsigned char reg, void * addr, u32 len) { - insb (dev->iobase + reg, addr, len); -} - -/* Read / Write to a given address in Horizon buffer memory. - Interrupts must be disabled between the address register and data - port accesses as these must form an atomic operation. */ -static inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) { - // wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr); - wr_regl (dev, MEM_WR_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); - wr_regl (dev, MEMORY_PORT_OFF, data); -} - -static inline u32 rd_mem (const hrz_dev * dev, HDW * addr) { - // wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr); - wr_regl (dev, MEM_RD_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); - return rd_regl (dev, MEMORY_PORT_OFF); -} - -static inline void wr_framer (const hrz_dev * dev, u32 addr, u32 data) { - wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr | 0x80000000); - wr_regl (dev, MEMORY_PORT_OFF, data); -} - -static inline u32 rd_framer (const hrz_dev * dev, u32 addr) { - wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr | 0x80000000); - return rd_regl (dev, MEMORY_PORT_OFF); -} - -/********** specialised access functions **********/ - -/* RX */ - -static inline void FLUSH_RX_CHANNEL (hrz_dev * dev, u16 channel) { - wr_regw (dev, RX_CHANNEL_PORT_OFF, FLUSH_CHANNEL | channel); - return; -} - -static void WAIT_FLUSH_RX_COMPLETE (hrz_dev * dev) { - while (rd_regw (dev, RX_CHANNEL_PORT_OFF) & FLUSH_CHANNEL) - ; - return; -} - -static inline void SELECT_RX_CHANNEL (hrz_dev * dev, u16 channel) { - wr_regw (dev, RX_CHANNEL_PORT_OFF, channel); - return; -} - -static void WAIT_UPDATE_COMPLETE (hrz_dev * dev) { - while (rd_regw (dev, RX_CHANNEL_PORT_OFF) & RX_CHANNEL_UPDATE_IN_PROGRESS) - ; - return; -} - -/* TX */ - -static inline void SELECT_TX_CHANNEL (hrz_dev * dev, u16 tx_channel) { - wr_regl (dev, TX_CHANNEL_PORT_OFF, tx_channel); - return; -} - -/* Update or query one configuration parameter of a particular channel. */ - -static inline void update_tx_channel_config (hrz_dev * dev, short chan, u8 mode, u16 value) { - wr_regw (dev, TX_CHANNEL_CONFIG_COMMAND_OFF, - chan * TX_CHANNEL_CONFIG_MULT | mode); - wr_regw (dev, TX_CHANNEL_CONFIG_DATA_OFF, value); - return; -} - -/********** dump functions **********/ - -static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * skb) { -#ifdef DEBUG_HORIZON - unsigned int i; - unsigned char * data = skb->data; - PRINTDB (DBG_DATA, "%s(%u) ", prefix, vc); - for (i=0; ilen && i < 256;i++) - PRINTDM (DBG_DATA, "%02x ", data[i]); - PRINTDE (DBG_DATA,""); -#else - (void) prefix; - (void) vc; - (void) skb; -#endif - return; -} - -static inline void dump_regs (hrz_dev * dev) { -#ifdef DEBUG_HORIZON - PRINTD (DBG_REGS, "CONTROL 0: %#x", rd_regl (dev, CONTROL_0_REG)); - PRINTD (DBG_REGS, "RX CONFIG: %#x", rd_regw (dev, RX_CONFIG_OFF)); - PRINTD (DBG_REGS, "TX CONFIG: %#x", rd_regw (dev, TX_CONFIG_OFF)); - PRINTD (DBG_REGS, "TX STATUS: %#x", rd_regw (dev, TX_STATUS_OFF)); - PRINTD (DBG_REGS, "IRQ ENBLE: %#x", rd_regl (dev, INT_ENABLE_REG_OFF)); - PRINTD (DBG_REGS, "IRQ SORCE: %#x", rd_regl (dev, INT_SOURCE_REG_OFF)); -#else - (void) dev; -#endif - return; -} - -static inline void dump_framer (hrz_dev * dev) { -#ifdef DEBUG_HORIZON - unsigned int i; - PRINTDB (DBG_REGS, "framer registers:"); - for (i = 0; i < 0x10; ++i) - PRINTDM (DBG_REGS, " %02x", rd_framer (dev, i)); - PRINTDE (DBG_REGS,""); -#else - (void) dev; -#endif - return; -} - -/********** VPI/VCI <-> (RX) channel conversions **********/ - -/* RX channels are 10 bit integers, these fns are quite paranoid */ - -static inline int vpivci_to_channel (u16 * channel, const short vpi, const int vci) { - unsigned short vci_bits = 10 - vpi_bits; - if (0 <= vpi && vpi < 1<>RX_Q_ENTRY_CHANNEL_SHIFT) & RX_CHANNEL_MASK; -} - -/* Cell Transmit Rate Values - * - * the cell transmit rate (cells per sec) can be set to a variety of - * different values by specifying two parameters: a timer preload from - * 1 to 16 (stored as 0 to 15) and a clock divider (2 to the power of - * an exponent from 0 to 14; the special value 15 disables the timer). - * - * cellrate = baserate / (preload * 2^divider) - * - * The maximum cell rate that can be specified is therefore just the - * base rate. Halving the preload is equivalent to adding 1 to the - * divider and so values 1 to 8 of the preload are redundant except - * in the case of a maximal divider (14). - * - * Given a desired cell rate, an algorithm to determine the preload - * and divider is: - * - * a) x = baserate / cellrate, want p * 2^d = x (as far as possible) - * b) if x > 16 * 2^14 then set p = 16, d = 14 (min rate), done - * if x <= 16 then set p = x, d = 0 (high rates), done - * c) now have 16 < x <= 2^18, or 1 < x/16 <= 2^14 and we want to - * know n such that 2^(n-1) < x/16 <= 2^n, so slide a bit until - * we find the range (n will be between 1 and 14), set d = n - * d) Also have 8 < x/2^n <= 16, so set p nearest x/2^n - * - * The algorithm used below is a minor variant of the above. - * - * The base rate is derived from the oscillator frequency (Hz) using a - * fixed divider: - * - * baserate = freq / 32 in the case of some Unknown Card - * baserate = freq / 8 in the case of the Horizon 25 - * baserate = freq / 8 in the case of the Horizon Ultra 155 - * - * The Horizon cards have oscillators and base rates as follows: - * - * Card Oscillator Base Rate - * Unknown Card 33 MHz 1.03125 MHz (33 MHz = PCI freq) - * Horizon 25 32 MHz 4 MHz - * Horizon Ultra 155 40 MHz 5 MHz - * - * The following defines give the base rates in Hz. These were - * previously a factor of 100 larger, no doubt someone was using - * cps*100. - */ - -#define BR_UKN 1031250l -#define BR_HRZ 4000000l -#define BR_ULT 5000000l - -// d is an exponent -#define CR_MIND 0 -#define CR_MAXD 14 - -// p ranges from 1 to a power of 2 -#define CR_MAXPEXP 4 - -static int make_rate (const hrz_dev * dev, u32 c, rounding r, - u16 * bits, unsigned int * actual) -{ - // note: rounding the rate down means rounding 'p' up - const unsigned long br = test_bit(ultra, &dev->flags) ? BR_ULT : BR_HRZ; - - u32 div = CR_MIND; - u32 pre; - - // br_exp and br_man are used to avoid overflowing (c*maxp*2^d) in - // the tests below. We could think harder about exact possibilities - // of failure... - - unsigned long br_man = br; - unsigned int br_exp = 0; - - PRINTD (DBG_QOS|DBG_FLOW, "make_rate b=%lu, c=%u, %s", br, c, - r == round_up ? "up" : r == round_down ? "down" : "nearest"); - - // avoid div by zero - if (!c) { - PRINTD (DBG_QOS|DBG_ERR, "zero rate is not allowed!"); - return -EINVAL; - } - - while (br_exp < CR_MAXPEXP + CR_MIND && (br_man % 2 == 0)) { - br_man = br_man >> 1; - ++br_exp; - } - // (br >>br_exp) < CR_MAXD || (!pre) || pre > 1<rx_descs[channel]; - - PRINTD (DBG_FLOW, "hrz_open_rx %x", channel); - - spin_lock_irqsave (&dev->mem_lock, flags); - channel_type = rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK; - spin_unlock_irqrestore (&dev->mem_lock, flags); - - // very serious error, should never occur - if (channel_type != RX_CHANNEL_DISABLED) { - PRINTD (DBG_ERR|DBG_VCC, "RX channel for VC already open"); - return -EBUSY; // clean up? - } - - // Give back spare buffer - if (dev->noof_spare_buffers) { - buf_ptr = dev->spare_buffers[--dev->noof_spare_buffers]; - PRINTD (DBG_VCC, "using a spare buffer: %u", buf_ptr); - // should never occur - if (buf_ptr == RX_CHANNEL_DISABLED || buf_ptr == RX_CHANNEL_IDLE) { - // but easy to recover from - PRINTD (DBG_ERR|DBG_VCC, "bad spare buffer pointer, using IDLE"); - buf_ptr = RX_CHANNEL_IDLE; - } - } else { - PRINTD (DBG_VCC, "using IDLE buffer pointer"); - } - - // Channel is currently disabled so change its status to idle - - // do we really need to save the flags again? - spin_lock_irqsave (&dev->mem_lock, flags); - - wr_mem (dev, &rx_desc->wr_buf_type, - buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME); - if (buf_ptr != RX_CHANNEL_IDLE) - wr_mem (dev, &rx_desc->rd_buf_type, buf_ptr); - - spin_unlock_irqrestore (&dev->mem_lock, flags); - - // rxer->rate = make_rate (qos->peak_cells); - - PRINTD (DBG_FLOW, "hrz_open_rx ok"); - - return 0; -} - -#if 0 -/********** change vc rate for a given vc **********/ - -static void hrz_change_vc_qos (ATM_RXER * rxer, MAAL_QOS * qos) { - rxer->rate = make_rate (qos->peak_cells); -} -#endif - -/********** free an skb (as per ATM device driver documentation) **********/ - -static void hrz_kfree_skb (struct sk_buff * skb) { - if (ATM_SKB(skb)->vcc->pop) { - ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb); - } else { - dev_kfree_skb_any (skb); - } -} - -/********** cancel listen on a VC **********/ - -static void hrz_close_rx (hrz_dev * dev, u16 vc) { - unsigned long flags; - - u32 value; - - u32 r1, r2; - - rx_ch_desc * rx_desc = &memmap->rx_descs[vc]; - - int was_idle = 0; - - spin_lock_irqsave (&dev->mem_lock, flags); - value = rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK; - spin_unlock_irqrestore (&dev->mem_lock, flags); - - if (value == RX_CHANNEL_DISABLED) { - // I suppose this could happen once we deal with _NONE traffic properly - PRINTD (DBG_VCC, "closing VC: RX channel %u already disabled", vc); - return; - } - if (value == RX_CHANNEL_IDLE) - was_idle = 1; - - spin_lock_irqsave (&dev->mem_lock, flags); - - for (;;) { - wr_mem (dev, &rx_desc->wr_buf_type, RX_CHANNEL_DISABLED); - - if ((rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK) == RX_CHANNEL_DISABLED) - break; - - was_idle = 0; - } - - if (was_idle) { - spin_unlock_irqrestore (&dev->mem_lock, flags); - return; - } - - WAIT_FLUSH_RX_COMPLETE(dev); - - // XXX Is this all really necessary? We can rely on the rx_data_av - // handler to discard frames that remain queued for delivery. If the - // worry is that immediately reopening the channel (perhaps by a - // different process) may cause some data to be mis-delivered then - // there may still be a simpler solution (such as busy-waiting on - // rx_busy once the channel is disabled or before a new one is - // opened - does this leave any holes?). Arguably setting up and - // tearing down the TX and RX halves of each virtual circuit could - // most safely be done within ?x_busy protected regions. - - // OK, current changes are that Simon's marker is disabled and we DO - // look for NULL rxer elsewhere. The code here seems flush frames - // and then remember the last dead cell belonging to the channel - // just disabled - the cell gets relinked at the next vc_open. - // However, when all VCs are closed or only a few opened there are a - // handful of buffers that are unusable. - - // Does anyone feel like documenting spare_buffers properly? - // Does anyone feel like fixing this in a nicer way? - - // Flush any data which is left in the channel - for (;;) { - // Change the rx channel port to something different to the RX - // channel we are trying to close to force Horizon to flush the rx - // channel read and write pointers. - - u16 other = vc^(RX_CHANS/2); - - SELECT_RX_CHANNEL (dev, other); - WAIT_UPDATE_COMPLETE (dev); - - r1 = rd_mem (dev, &rx_desc->rd_buf_type); - - // Select this RX channel. Flush doesn't seem to work unless we - // select an RX channel before hand - - SELECT_RX_CHANNEL (dev, vc); - WAIT_UPDATE_COMPLETE (dev); - - // Attempt to flush a frame on this RX channel - - FLUSH_RX_CHANNEL (dev, vc); - WAIT_FLUSH_RX_COMPLETE (dev); - - // Force Horizon to flush rx channel read and write pointers as before - - SELECT_RX_CHANNEL (dev, other); - WAIT_UPDATE_COMPLETE (dev); - - r2 = rd_mem (dev, &rx_desc->rd_buf_type); - - PRINTD (DBG_VCC|DBG_RX, "r1 = %u, r2 = %u", r1, r2); - - if (r1 == r2) { - dev->spare_buffers[dev->noof_spare_buffers++] = (u16)r1; - break; - } - } - -#if 0 - { - rx_q_entry * wr_ptr = &memmap->rx_q_entries[rd_regw (dev, RX_QUEUE_WR_PTR_OFF)]; - rx_q_entry * rd_ptr = dev->rx_q_entry; - - PRINTD (DBG_VCC|DBG_RX, "rd_ptr = %u, wr_ptr = %u", rd_ptr, wr_ptr); - - while (rd_ptr != wr_ptr) { - u32 x = rd_mem (dev, (HDW *) rd_ptr); - - if (vc == rx_q_entry_to_rx_channel (x)) { - x |= SIMONS_DODGEY_MARKER; - - PRINTD (DBG_RX|DBG_VCC|DBG_WARN, "marking a frame as dodgey"); - - wr_mem (dev, (HDW *) rd_ptr, x); - } - - if (rd_ptr == dev->rx_q_wrap) - rd_ptr = dev->rx_q_reset; - else - rd_ptr++; - } - } -#endif - - spin_unlock_irqrestore (&dev->mem_lock, flags); - - return; -} - -/********** schedule RX transfers **********/ - -// Note on tail recursion: a GCC developer said that it is not likely -// to be fixed soon, so do not define TAILRECUSRIONWORKS unless you -// are sure it does as you may otherwise overflow the kernel stack. - -// giving this fn a return value would help GCC, allegedly - -static void rx_schedule (hrz_dev * dev, int irq) { - unsigned int rx_bytes; - - int pio_instead = 0; -#ifndef TAILRECURSIONWORKS - pio_instead = 1; - while (pio_instead) { -#endif - // bytes waiting for RX transfer - rx_bytes = dev->rx_bytes; - -#if 0 - spin_count = 0; - while (rd_regl (dev, MASTER_RX_COUNT_REG_OFF)) { - PRINTD (DBG_RX|DBG_WARN, "RX error: other PCI Bus Master RX still in progress!"); - if (++spin_count > 10) { - PRINTD (DBG_RX|DBG_ERR, "spun out waiting PCI Bus Master RX completion"); - wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); - clear_bit (rx_busy, &dev->flags); - hrz_kfree_skb (dev->rx_skb); - return; - } - } -#endif - - // this code follows the TX code but (at the moment) there is only - // one region - the skb itself. I don't know if this will change, - // but it doesn't hurt to have the code here, disabled. - - if (rx_bytes) { - // start next transfer within same region - if (rx_bytes <= MAX_PIO_COUNT) { - PRINTD (DBG_RX|DBG_BUS, "(pio)"); - pio_instead = 1; - } - if (rx_bytes <= MAX_TRANSFER_COUNT) { - PRINTD (DBG_RX|DBG_BUS, "(simple or last multi)"); - dev->rx_bytes = 0; - } else { - PRINTD (DBG_RX|DBG_BUS, "(continuing multi)"); - dev->rx_bytes = rx_bytes - MAX_TRANSFER_COUNT; - rx_bytes = MAX_TRANSFER_COUNT; - } - } else { - // rx_bytes == 0 -- we're between regions - // regions remaining to transfer -#if 0 - unsigned int rx_regions = dev->rx_regions; -#else - unsigned int rx_regions = 0; -#endif - - if (rx_regions) { -#if 0 - // start a new region - dev->rx_addr = dev->rx_iovec->iov_base; - rx_bytes = dev->rx_iovec->iov_len; - ++dev->rx_iovec; - dev->rx_regions = rx_regions - 1; - - if (rx_bytes <= MAX_PIO_COUNT) { - PRINTD (DBG_RX|DBG_BUS, "(pio)"); - pio_instead = 1; - } - if (rx_bytes <= MAX_TRANSFER_COUNT) { - PRINTD (DBG_RX|DBG_BUS, "(full region)"); - dev->rx_bytes = 0; - } else { - PRINTD (DBG_RX|DBG_BUS, "(start multi region)"); - dev->rx_bytes = rx_bytes - MAX_TRANSFER_COUNT; - rx_bytes = MAX_TRANSFER_COUNT; - } -#endif - } else { - // rx_regions == 0 - // that's all folks - end of frame - struct sk_buff * skb = dev->rx_skb; - // dev->rx_iovec = 0; - - FLUSH_RX_CHANNEL (dev, dev->rx_channel); - - dump_skb ("<<<", dev->rx_channel, skb); - - PRINTD (DBG_RX|DBG_SKB, "push %p %u", skb->data, skb->len); - - { - struct atm_vcc * vcc = ATM_SKB(skb)->vcc; - // VC layer stats - atomic_inc(&vcc->stats->rx); - __net_timestamp(skb); - // end of our responsibility - vcc->push (vcc, skb); - } - } - } - - // note: writing RX_COUNT clears any interrupt condition - if (rx_bytes) { - if (pio_instead) { - if (irq) - wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); - rds_regb (dev, DATA_PORT_OFF, dev->rx_addr, rx_bytes); - } else { - wr_regl (dev, MASTER_RX_ADDR_REG_OFF, virt_to_bus (dev->rx_addr)); - wr_regl (dev, MASTER_RX_COUNT_REG_OFF, rx_bytes); - } - dev->rx_addr += rx_bytes; - } else { - if (irq) - wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); - // allow another RX thread to start - YELLOW_LED_ON(dev); - clear_bit (rx_busy, &dev->flags); - PRINTD (DBG_RX, "cleared rx_busy for dev %p", dev); - } - -#ifdef TAILRECURSIONWORKS - // and we all bless optimised tail calls - if (pio_instead) - return rx_schedule (dev, 0); - return; -#else - // grrrrrrr! - irq = 0; - } - return; -#endif -} - -/********** handle RX bus master complete events **********/ - -static void rx_bus_master_complete_handler (hrz_dev * dev) { - if (test_bit (rx_busy, &dev->flags)) { - rx_schedule (dev, 1); - } else { - PRINTD (DBG_RX|DBG_ERR, "unexpected RX bus master completion"); - // clear interrupt condition on adapter - wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); - } - return; -} - -/********** (queue to) become the next TX thread **********/ - -static int tx_hold (hrz_dev * dev) { - PRINTD (DBG_TX, "sleeping at tx lock %p %lu", dev, dev->flags); - wait_event_interruptible(dev->tx_queue, (!test_and_set_bit(tx_busy, &dev->flags))); - PRINTD (DBG_TX, "woken at tx lock %p %lu", dev, dev->flags); - if (signal_pending (current)) - return -1; - PRINTD (DBG_TX, "set tx_busy for dev %p", dev); - return 0; -} - -/********** allow another TX thread to start **********/ - -static inline void tx_release (hrz_dev * dev) { - clear_bit (tx_busy, &dev->flags); - PRINTD (DBG_TX, "cleared tx_busy for dev %p", dev); - wake_up_interruptible (&dev->tx_queue); -} - -/********** schedule TX transfers **********/ - -static void tx_schedule (hrz_dev * const dev, int irq) { - unsigned int tx_bytes; - - int append_desc = 0; - - int pio_instead = 0; -#ifndef TAILRECURSIONWORKS - pio_instead = 1; - while (pio_instead) { -#endif - // bytes in current region waiting for TX transfer - tx_bytes = dev->tx_bytes; - -#if 0 - spin_count = 0; - while (rd_regl (dev, MASTER_TX_COUNT_REG_OFF)) { - PRINTD (DBG_TX|DBG_WARN, "TX error: other PCI Bus Master TX still in progress!"); - if (++spin_count > 10) { - PRINTD (DBG_TX|DBG_ERR, "spun out waiting PCI Bus Master TX completion"); - wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); - tx_release (dev); - hrz_kfree_skb (dev->tx_skb); - return; - } - } -#endif - - if (tx_bytes) { - // start next transfer within same region - if (!test_bit (ultra, &dev->flags) || tx_bytes <= MAX_PIO_COUNT) { - PRINTD (DBG_TX|DBG_BUS, "(pio)"); - pio_instead = 1; - } - if (tx_bytes <= MAX_TRANSFER_COUNT) { - PRINTD (DBG_TX|DBG_BUS, "(simple or last multi)"); - if (!dev->tx_iovec) { - // end of last region - append_desc = 1; - } - dev->tx_bytes = 0; - } else { - PRINTD (DBG_TX|DBG_BUS, "(continuing multi)"); - dev->tx_bytes = tx_bytes - MAX_TRANSFER_COUNT; - tx_bytes = MAX_TRANSFER_COUNT; - } - } else { - // tx_bytes == 0 -- we're between regions - // regions remaining to transfer - unsigned int tx_regions = dev->tx_regions; - - if (tx_regions) { - // start a new region - dev->tx_addr = dev->tx_iovec->iov_base; - tx_bytes = dev->tx_iovec->iov_len; - ++dev->tx_iovec; - dev->tx_regions = tx_regions - 1; - - if (!test_bit (ultra, &dev->flags) || tx_bytes <= MAX_PIO_COUNT) { - PRINTD (DBG_TX|DBG_BUS, "(pio)"); - pio_instead = 1; - } - if (tx_bytes <= MAX_TRANSFER_COUNT) { - PRINTD (DBG_TX|DBG_BUS, "(full region)"); - dev->tx_bytes = 0; - } else { - PRINTD (DBG_TX|DBG_BUS, "(start multi region)"); - dev->tx_bytes = tx_bytes - MAX_TRANSFER_COUNT; - tx_bytes = MAX_TRANSFER_COUNT; - } - } else { - // tx_regions == 0 - // that's all folks - end of frame - struct sk_buff * skb = dev->tx_skb; - dev->tx_iovec = NULL; - - // VC layer stats - atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); - - // free the skb - hrz_kfree_skb (skb); - } - } - - // note: writing TX_COUNT clears any interrupt condition - if (tx_bytes) { - if (pio_instead) { - if (irq) - wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); - wrs_regb (dev, DATA_PORT_OFF, dev->tx_addr, tx_bytes); - if (append_desc) - wr_regl (dev, TX_DESCRIPTOR_PORT_OFF, cpu_to_be32 (dev->tx_skb->len)); - } else { - wr_regl (dev, MASTER_TX_ADDR_REG_OFF, virt_to_bus (dev->tx_addr)); - if (append_desc) - wr_regl (dev, TX_DESCRIPTOR_REG_OFF, cpu_to_be32 (dev->tx_skb->len)); - wr_regl (dev, MASTER_TX_COUNT_REG_OFF, - append_desc - ? tx_bytes | MASTER_TX_AUTO_APPEND_DESC - : tx_bytes); - } - dev->tx_addr += tx_bytes; - } else { - if (irq) - wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); - YELLOW_LED_ON(dev); - tx_release (dev); - } - -#ifdef TAILRECURSIONWORKS - // and we all bless optimised tail calls - if (pio_instead) - return tx_schedule (dev, 0); - return; -#else - // grrrrrrr! - irq = 0; - } - return; -#endif -} - -/********** handle TX bus master complete events **********/ - -static void tx_bus_master_complete_handler (hrz_dev * dev) { - if (test_bit (tx_busy, &dev->flags)) { - tx_schedule (dev, 1); - } else { - PRINTD (DBG_TX|DBG_ERR, "unexpected TX bus master completion"); - // clear interrupt condition on adapter - wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); - } - return; -} - -/********** move RX Q pointer to next item in circular buffer **********/ - -// called only from IRQ sub-handler -static u32 rx_queue_entry_next (hrz_dev * dev) { - u32 rx_queue_entry; - spin_lock (&dev->mem_lock); - rx_queue_entry = rd_mem (dev, &dev->rx_q_entry->entry); - if (dev->rx_q_entry == dev->rx_q_wrap) - dev->rx_q_entry = dev->rx_q_reset; - else - dev->rx_q_entry++; - wr_regw (dev, RX_QUEUE_RD_PTR_OFF, dev->rx_q_entry - dev->rx_q_reset); - spin_unlock (&dev->mem_lock); - return rx_queue_entry; -} - -/********** handle RX data received by device **********/ - -// called from IRQ handler -static void rx_data_av_handler (hrz_dev * dev) { - u32 rx_queue_entry; - u32 rx_queue_entry_flags; - u16 rx_len; - u16 rx_channel; - - PRINTD (DBG_FLOW, "hrz_data_av_handler"); - - // try to grab rx lock (not possible during RX bus mastering) - if (test_and_set_bit (rx_busy, &dev->flags)) { - PRINTD (DBG_RX, "locked out of rx lock"); - return; - } - PRINTD (DBG_RX, "set rx_busy for dev %p", dev); - // lock is cleared if we fail now, o/w after bus master completion - - YELLOW_LED_OFF(dev); - - rx_queue_entry = rx_queue_entry_next (dev); - - rx_len = rx_q_entry_to_length (rx_queue_entry); - rx_channel = rx_q_entry_to_rx_channel (rx_queue_entry); - - WAIT_FLUSH_RX_COMPLETE (dev); - - SELECT_RX_CHANNEL (dev, rx_channel); - - PRINTD (DBG_RX, "rx_queue_entry is: %#x", rx_queue_entry); - rx_queue_entry_flags = rx_queue_entry & (RX_CRC_32_OK|RX_COMPLETE_FRAME|SIMONS_DODGEY_MARKER); - - if (!rx_len) { - // (at least) bus-mastering breaks if we try to handle a - // zero-length frame, besides AAL5 does not support them - PRINTK (KERN_ERR, "zero-length frame!"); - rx_queue_entry_flags &= ~RX_COMPLETE_FRAME; - } - - if (rx_queue_entry_flags & SIMONS_DODGEY_MARKER) { - PRINTD (DBG_RX|DBG_ERR, "Simon's marker detected!"); - } - if (rx_queue_entry_flags == (RX_CRC_32_OK | RX_COMPLETE_FRAME)) { - struct atm_vcc * atm_vcc; - - PRINTD (DBG_RX, "got a frame on rx_channel %x len %u", rx_channel, rx_len); - - atm_vcc = dev->rxer[rx_channel]; - // if no vcc is assigned to this channel, we should drop the frame - // (is this what SIMONS etc. was trying to achieve?) - - if (atm_vcc) { - - if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { - - if (rx_len <= atm_vcc->qos.rxtp.max_sdu) { - - struct sk_buff * skb = atm_alloc_charge (atm_vcc, rx_len, GFP_ATOMIC); - if (skb) { - // remember this so we can push it later - dev->rx_skb = skb; - // remember this so we can flush it later - dev->rx_channel = rx_channel; - - // prepare socket buffer - skb_put (skb, rx_len); - ATM_SKB(skb)->vcc = atm_vcc; - - // simple transfer - // dev->rx_regions = 0; - // dev->rx_iovec = 0; - dev->rx_bytes = rx_len; - dev->rx_addr = skb->data; - PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)", - skb->data, rx_len); - - // do the business - rx_schedule (dev, 0); - return; - - } else { - PRINTD (DBG_SKB|DBG_WARN, "failed to get skb"); - } - - } else { - PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel); - // do we count this? - } - - } else { - PRINTK (KERN_WARNING, "dropped over-size frame"); - // do we count this? - } - - } else { - PRINTD (DBG_WARN|DBG_VCC|DBG_RX, "no VCC for this frame (VC closed)"); - // do we count this? - } - - } else { - // Wait update complete ? SPONG - } - - // RX was aborted - YELLOW_LED_ON(dev); - - FLUSH_RX_CHANNEL (dev,rx_channel); - clear_bit (rx_busy, &dev->flags); - - return; -} - -/********** interrupt handler **********/ - -static irqreturn_t interrupt_handler(int irq, void *dev_id) -{ - hrz_dev *dev = dev_id; - u32 int_source; - unsigned int irq_ok; - - PRINTD (DBG_FLOW, "interrupt_handler: %p", dev_id); - - // definitely for us - irq_ok = 0; - while ((int_source = rd_regl (dev, INT_SOURCE_REG_OFF) - & INTERESTING_INTERRUPTS)) { - // In the interests of fairness, the handlers below are - // called in sequence and without immediate return to the head of - // the while loop. This is only of issue for slow hosts (or when - // debugging messages are on). Really slow hosts may find a fast - // sender keeps them permanently in the IRQ handler. :( - - // (only an issue for slow hosts) RX completion goes before - // rx_data_av as the former implies rx_busy and so the latter - // would just abort. If it reschedules another transfer - // (continuing the same frame) then it will not clear rx_busy. - - // (only an issue for slow hosts) TX completion goes before RX - // data available as it is a much shorter routine - there is the - // chance that any further transfers it schedules will be complete - // by the time of the return to the head of the while loop - - if (int_source & RX_BUS_MASTER_COMPLETE) { - ++irq_ok; - PRINTD (DBG_IRQ|DBG_BUS|DBG_RX, "rx_bus_master_complete asserted"); - rx_bus_master_complete_handler (dev); - } - if (int_source & TX_BUS_MASTER_COMPLETE) { - ++irq_ok; - PRINTD (DBG_IRQ|DBG_BUS|DBG_TX, "tx_bus_master_complete asserted"); - tx_bus_master_complete_handler (dev); - } - if (int_source & RX_DATA_AV) { - ++irq_ok; - PRINTD (DBG_IRQ|DBG_RX, "rx_data_av asserted"); - rx_data_av_handler (dev); - } - } - if (irq_ok) { - PRINTD (DBG_IRQ, "work done: %u", irq_ok); - } else { - PRINTD (DBG_IRQ|DBG_WARN, "spurious interrupt source: %#x", int_source); - } - - PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id); - if (irq_ok) - return IRQ_HANDLED; - return IRQ_NONE; -} - -/********** housekeeping **********/ - -static void do_housekeeping (struct timer_list *t) { - // just stats at the moment - hrz_dev * dev = from_timer(dev, t, housekeeping); - - // collect device-specific (not driver/atm-linux) stats here - dev->tx_cell_count += rd_regw (dev, TX_CELL_COUNT_OFF); - dev->rx_cell_count += rd_regw (dev, RX_CELL_COUNT_OFF); - dev->hec_error_count += rd_regw (dev, HEC_ERROR_COUNT_OFF); - dev->unassigned_cell_count += rd_regw (dev, UNASSIGNED_CELL_COUNT_OFF); - - mod_timer (&dev->housekeeping, jiffies + HZ/10); - - return; -} - -/********** find an idle channel for TX and set it up **********/ - -// called with tx_busy set -static short setup_idle_tx_channel (hrz_dev * dev, hrz_vcc * vcc) { - unsigned short idle_channels; - short tx_channel = -1; - unsigned int spin_count; - PRINTD (DBG_FLOW|DBG_TX, "setup_idle_tx_channel %p", dev); - - // better would be to fail immediately, the caller can then decide whether - // to wait or drop (depending on whether this is UBR etc.) - spin_count = 0; - while (!(idle_channels = rd_regw (dev, TX_STATUS_OFF) & IDLE_CHANNELS_MASK)) { - PRINTD (DBG_TX|DBG_WARN, "waiting for idle TX channel"); - // delay a bit here - if (++spin_count > 100) { - PRINTD (DBG_TX|DBG_ERR, "spun out waiting for idle TX channel"); - return -EBUSY; - } - } - - // got an idle channel - { - // tx_idle ensures we look for idle channels in RR order - int chan = dev->tx_idle; - - int keep_going = 1; - while (keep_going) { - if (idle_channels & (1<tx_idle = chan; - } - - // set up the channel we found - { - // Initialise the cell header in the transmit channel descriptor - // a.k.a. prepare the channel and remember that we have done so. - - tx_ch_desc * tx_desc = &memmap->tx_descs[tx_channel]; - u32 rd_ptr; - u32 wr_ptr; - u16 channel = vcc->channel; - - unsigned long flags; - spin_lock_irqsave (&dev->mem_lock, flags); - - // Update the transmit channel record. - dev->tx_channel_record[tx_channel] = channel; - - // xBR channel - update_tx_channel_config (dev, tx_channel, RATE_TYPE_ACCESS, - vcc->tx_xbr_bits); - - // Update the PCR counter preload value etc. - update_tx_channel_config (dev, tx_channel, PCR_TIMER_ACCESS, - vcc->tx_pcr_bits); - -#if 0 - if (vcc->tx_xbr_bits == VBR_RATE_TYPE) { - // SCR timer - update_tx_channel_config (dev, tx_channel, SCR_TIMER_ACCESS, - vcc->tx_scr_bits); - - // Bucket size... - update_tx_channel_config (dev, tx_channel, BUCKET_CAPACITY_ACCESS, - vcc->tx_bucket_bits); - - // ... and fullness - update_tx_channel_config (dev, tx_channel, BUCKET_FULLNESS_ACCESS, - vcc->tx_bucket_bits); - } -#endif - - // Initialise the read and write buffer pointers - rd_ptr = rd_mem (dev, &tx_desc->rd_buf_type) & BUFFER_PTR_MASK; - wr_ptr = rd_mem (dev, &tx_desc->wr_buf_type) & BUFFER_PTR_MASK; - - // idle TX channels should have identical pointers - if (rd_ptr != wr_ptr) { - PRINTD (DBG_TX|DBG_ERR, "TX buffer pointers are broken!"); - // spin_unlock... return -E... - // I wonder if gcc would get rid of one of the pointer aliases - } - PRINTD (DBG_TX, "TX buffer pointers are: rd %x, wr %x.", - rd_ptr, wr_ptr); - - switch (vcc->aal) { - case aal0: - PRINTD (DBG_QOS|DBG_TX, "tx_channel: aal0"); - rd_ptr |= CHANNEL_TYPE_RAW_CELLS; - wr_ptr |= CHANNEL_TYPE_RAW_CELLS; - break; - case aal34: - PRINTD (DBG_QOS|DBG_TX, "tx_channel: aal34"); - rd_ptr |= CHANNEL_TYPE_AAL3_4; - wr_ptr |= CHANNEL_TYPE_AAL3_4; - break; - case aal5: - rd_ptr |= CHANNEL_TYPE_AAL5; - wr_ptr |= CHANNEL_TYPE_AAL5; - // Initialise the CRC - wr_mem (dev, &tx_desc->partial_crc, INITIAL_CRC); - break; - } - - wr_mem (dev, &tx_desc->rd_buf_type, rd_ptr); - wr_mem (dev, &tx_desc->wr_buf_type, wr_ptr); - - // Write the Cell Header - // Payload Type, CLP and GFC would go here if non-zero - wr_mem (dev, &tx_desc->cell_header, channel); - - spin_unlock_irqrestore (&dev->mem_lock, flags); - } - - return tx_channel; -} - -/********** send a frame **********/ - -static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { - unsigned int spin_count; - int free_buffers; - hrz_dev * dev = HRZ_DEV(atm_vcc->dev); - hrz_vcc * vcc = HRZ_VCC(atm_vcc); - u16 channel = vcc->channel; - - u32 buffers_required; - - /* signed for error return */ - short tx_channel; - - PRINTD (DBG_FLOW|DBG_TX, "hrz_send vc %x data %p len %u", - channel, skb->data, skb->len); - - dump_skb (">>>", channel, skb); - - if (atm_vcc->qos.txtp.traffic_class == ATM_NONE) { - PRINTK (KERN_ERR, "attempt to send on RX-only VC %x", channel); - hrz_kfree_skb (skb); - return -EIO; - } - - // don't understand this - ATM_SKB(skb)->vcc = atm_vcc; - - if (skb->len > atm_vcc->qos.txtp.max_sdu) { - PRINTK (KERN_ERR, "sk_buff length greater than agreed max_sdu, dropping..."); - hrz_kfree_skb (skb); - return -EIO; - } - - if (!channel) { - PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel"); - hrz_kfree_skb (skb); - return -EIO; - } - -#if 0 - { - // where would be a better place for this? housekeeping? - u16 status; - pci_read_config_word (dev->pci_dev, PCI_STATUS, &status); - if (status & PCI_STATUS_REC_MASTER_ABORT) { - PRINTD (DBG_BUS|DBG_ERR, "Clearing PCI Master Abort (and cleaning up)"); - status &= ~PCI_STATUS_REC_MASTER_ABORT; - pci_write_config_word (dev->pci_dev, PCI_STATUS, status); - if (test_bit (tx_busy, &dev->flags)) { - hrz_kfree_skb (dev->tx_skb); - tx_release (dev); - } - } - } -#endif - -#ifdef DEBUG_HORIZON - /* wey-hey! */ - if (channel == 1023) { - unsigned int i; - unsigned short d = 0; - char * s = skb->data; - if (*s++ == 'D') { - for (i = 0; i < 4; ++i) - d = (d << 4) | hex_to_bin(*s++); - PRINTK (KERN_INFO, "debug bitmap is now %hx", debug = d); - } - } -#endif - - // wait until TX is free and grab lock - if (tx_hold (dev)) { - hrz_kfree_skb (skb); - return -ERESTARTSYS; - } - - // Wait for enough space to be available in transmit buffer memory. - - // should be number of cells needed + 2 (according to hardware docs) - // = ((framelen+8)+47) / 48 + 2 - // = (framelen+7) / 48 + 3, hmm... faster to put addition inside XXX - buffers_required = (skb->len+(ATM_AAL5_TRAILER-1)) / ATM_CELL_PAYLOAD + 3; - - // replace with timer and sleep, add dev->tx_buffers_queue (max 1 entry) - spin_count = 0; - while ((free_buffers = rd_regw (dev, TX_FREE_BUFFER_COUNT_OFF)) < buffers_required) { - PRINTD (DBG_TX, "waiting for free TX buffers, got %d of %d", - free_buffers, buffers_required); - // what is the appropriate delay? implement a timeout? (depending on line speed?) - // mdelay (1); - // what happens if we kill (current_pid, SIGKILL) ? - schedule(); - if (++spin_count > 1000) { - PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d", - free_buffers, buffers_required); - tx_release (dev); - hrz_kfree_skb (skb); - return -ERESTARTSYS; - } - } - - // Select a channel to transmit the frame on. - if (channel == dev->last_vc) { - PRINTD (DBG_TX, "last vc hack: hit"); - tx_channel = dev->tx_last; - } else { - PRINTD (DBG_TX, "last vc hack: miss"); - // Are we currently transmitting this VC on one of the channels? - for (tx_channel = 0; tx_channel < TX_CHANS; ++tx_channel) - if (dev->tx_channel_record[tx_channel] == channel) { - PRINTD (DBG_TX, "vc already on channel: hit"); - break; - } - if (tx_channel == TX_CHANS) { - PRINTD (DBG_TX, "vc already on channel: miss"); - // Find and set up an idle channel. - tx_channel = setup_idle_tx_channel (dev, vcc); - if (tx_channel < 0) { - PRINTD (DBG_TX|DBG_ERR, "failed to get channel"); - tx_release (dev); - return tx_channel; - } - } - - PRINTD (DBG_TX, "got channel"); - SELECT_TX_CHANNEL(dev, tx_channel); - - dev->last_vc = channel; - dev->tx_last = tx_channel; - } - - PRINTD (DBG_TX, "using channel %u", tx_channel); - - YELLOW_LED_OFF(dev); - - // TX start transfer - - { - unsigned int tx_len = skb->len; - unsigned int tx_iovcnt = skb_shinfo(skb)->nr_frags; - // remember this so we can free it later - dev->tx_skb = skb; - - if (tx_iovcnt) { - // scatter gather transfer - dev->tx_regions = tx_iovcnt; - dev->tx_iovec = NULL; /* @@@ needs rewritten */ - dev->tx_bytes = 0; - PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)", - skb->data, tx_len); - tx_release (dev); - hrz_kfree_skb (skb); - return -EIO; - } else { - // simple transfer - dev->tx_regions = 0; - dev->tx_iovec = NULL; - dev->tx_bytes = tx_len; - dev->tx_addr = skb->data; - PRINTD (DBG_TX|DBG_BUS, "TX start simple transfer (addr %p, len %d)", - skb->data, tx_len); - } - - // and do the business - tx_schedule (dev, 0); - - } - - return 0; -} - -/********** reset a card **********/ - -static void hrz_reset (const hrz_dev * dev) { - u32 control_0_reg = rd_regl (dev, CONTROL_0_REG); - - // why not set RESET_HORIZON to one and wait for the card to - // reassert that bit as zero? Like so: - control_0_reg = control_0_reg & RESET_HORIZON; - wr_regl (dev, CONTROL_0_REG, control_0_reg); - while (control_0_reg & RESET_HORIZON) - control_0_reg = rd_regl (dev, CONTROL_0_REG); - - // old reset code retained: - wr_regl (dev, CONTROL_0_REG, control_0_reg | - RESET_ATM | RESET_RX | RESET_TX | RESET_HOST); - // just guessing here - udelay (1000); - - wr_regl (dev, CONTROL_0_REG, control_0_reg); -} - -/********** read the burnt in address **********/ - -static void WRITE_IT_WAIT (const hrz_dev *dev, u32 ctrl) -{ - wr_regl (dev, CONTROL_0_REG, ctrl); - udelay (5); -} - -static void CLOCK_IT (const hrz_dev *dev, u32 ctrl) -{ - // DI must be valid around rising SK edge - WRITE_IT_WAIT(dev, ctrl & ~SEEPROM_SK); - WRITE_IT_WAIT(dev, ctrl | SEEPROM_SK); -} - -static u16 read_bia(const hrz_dev *dev, u16 addr) -{ - u32 ctrl = rd_regl (dev, CONTROL_0_REG); - - const unsigned int addr_bits = 6; - const unsigned int data_bits = 16; - - unsigned int i; - - u16 res; - - ctrl &= ~(SEEPROM_CS | SEEPROM_SK | SEEPROM_DI); - WRITE_IT_WAIT(dev, ctrl); - - // wake Serial EEPROM and send 110 (READ) command - ctrl |= (SEEPROM_CS | SEEPROM_DI); - CLOCK_IT(dev, ctrl); - - ctrl |= SEEPROM_DI; - CLOCK_IT(dev, ctrl); - - ctrl &= ~SEEPROM_DI; - CLOCK_IT(dev, ctrl); - - for (i=0; i> 1; - - CLOCK_IT(dev, ctrl); - - if (rd_regl (dev, CONTROL_0_REG) & SEEPROM_DO) - res |= (1 << (data_bits-1)); - } - - ctrl &= ~(SEEPROM_SK | SEEPROM_CS); - WRITE_IT_WAIT(dev, ctrl); - - return res; -} - -/********** initialise a card **********/ - -static int hrz_init(hrz_dev *dev) -{ - int onefivefive; - - u16 chan; - - int buff_count; - - HDW * mem; - - cell_buf * tx_desc; - cell_buf * rx_desc; - - u32 ctrl; - - ctrl = rd_regl (dev, CONTROL_0_REG); - PRINTD (DBG_INFO, "ctrl0reg is %#x", ctrl); - onefivefive = ctrl & ATM_LAYER_STATUS; - - if (onefivefive) - printk (DEV_LABEL ": Horizon Ultra (at 155.52 MBps)"); - else - printk (DEV_LABEL ": Horizon (at 25 MBps)"); - - printk (":"); - // Reset the card to get everything in a known state - - printk (" reset"); - hrz_reset (dev); - - // Clear all the buffer memory - - printk (" clearing memory"); - - for (mem = (HDW *) memmap; mem < (HDW *) (memmap + 1); ++mem) - wr_mem (dev, mem, 0); - - printk (" tx channels"); - - // All transmit eight channels are set up as AAL5 ABR channels with - // a 16us cell spacing. Why? - - // Channel 0 gets the free buffer at 100h, channel 1 gets the free - // buffer at 110h etc. - - for (chan = 0; chan < TX_CHANS; ++chan) { - tx_ch_desc * tx_desc = &memmap->tx_descs[chan]; - cell_buf * buf = &memmap->inittxbufs[chan]; - - // initialise the read and write buffer pointers - wr_mem (dev, &tx_desc->rd_buf_type, BUF_PTR(buf)); - wr_mem (dev, &tx_desc->wr_buf_type, BUF_PTR(buf)); - - // set the status of the initial buffers to empty - wr_mem (dev, &buf->next, BUFF_STATUS_EMPTY); - } - - // Use space bufn3 at the moment for tx buffers - - printk (" tx buffers"); - - tx_desc = memmap->bufn3; - - wr_mem (dev, &memmap->txfreebufstart.next, BUF_PTR(tx_desc) | BUFF_STATUS_EMPTY); - - for (buff_count = 0; buff_count < BUFN3_SIZE-1; buff_count++) { - wr_mem (dev, &tx_desc->next, BUF_PTR(tx_desc+1) | BUFF_STATUS_EMPTY); - tx_desc++; - } - - wr_mem (dev, &tx_desc->next, BUF_PTR(&memmap->txfreebufend) | BUFF_STATUS_EMPTY); - - // Initialise the transmit free buffer count - wr_regw (dev, TX_FREE_BUFFER_COUNT_OFF, BUFN3_SIZE); - - printk (" rx channels"); - - // Initialise all of the receive channels to be AAL5 disabled with - // an interrupt threshold of 0 - - for (chan = 0; chan < RX_CHANS; ++chan) { - rx_ch_desc * rx_desc = &memmap->rx_descs[chan]; - - wr_mem (dev, &rx_desc->wr_buf_type, CHANNEL_TYPE_AAL5 | RX_CHANNEL_DISABLED); - } - - printk (" rx buffers"); - - // Use space bufn4 at the moment for rx buffers - - rx_desc = memmap->bufn4; - - wr_mem (dev, &memmap->rxfreebufstart.next, BUF_PTR(rx_desc) | BUFF_STATUS_EMPTY); - - for (buff_count = 0; buff_count < BUFN4_SIZE-1; buff_count++) { - wr_mem (dev, &rx_desc->next, BUF_PTR(rx_desc+1) | BUFF_STATUS_EMPTY); - - rx_desc++; - } - - wr_mem (dev, &rx_desc->next, BUF_PTR(&memmap->rxfreebufend) | BUFF_STATUS_EMPTY); - - // Initialise the receive free buffer count - wr_regw (dev, RX_FREE_BUFFER_COUNT_OFF, BUFN4_SIZE); - - // Initialize Horizons registers - - // TX config - wr_regw (dev, TX_CONFIG_OFF, - ABR_ROUND_ROBIN | TX_NORMAL_OPERATION | DRVR_DRVRBAR_ENABLE); - - // RX config. Use 10-x VC bits, x VP bits, non user cells in channel 0. - wr_regw (dev, RX_CONFIG_OFF, - DISCARD_UNUSED_VPI_VCI_BITS_SET | NON_USER_CELLS_IN_ONE_CHANNEL | vpi_bits); - - // RX line config - wr_regw (dev, RX_LINE_CONFIG_OFF, - LOCK_DETECT_ENABLE | FREQUENCY_DETECT_ENABLE | GXTALOUT_SELECT_DIV4); - - // Set the max AAL5 cell count to be just enough to contain the - // largest AAL5 frame that the user wants to receive - wr_regw (dev, MAX_AAL5_CELL_COUNT_OFF, - DIV_ROUND_UP(max_rx_size + ATM_AAL5_TRAILER, ATM_CELL_PAYLOAD)); - - // Enable receive - wr_regw (dev, RX_CONFIG_OFF, rd_regw (dev, RX_CONFIG_OFF) | RX_ENABLE); - - printk (" control"); - - // Drive the OE of the LEDs then turn the green LED on - ctrl |= GREEN_LED_OE | YELLOW_LED_OE | GREEN_LED | YELLOW_LED; - wr_regl (dev, CONTROL_0_REG, ctrl); - - // Test for a 155-capable card - - if (onefivefive) { - // Select 155 mode... make this a choice (or: how do we detect - // external line speed and switch?) - ctrl |= ATM_LAYER_SELECT; - wr_regl (dev, CONTROL_0_REG, ctrl); - - // test SUNI-lite vs SAMBA - - // Register 0x00 in the SUNI will have some of bits 3-7 set, and - // they will always be zero for the SAMBA. Ha! Bloody hardware - // engineers. It'll never work. - - if (rd_framer (dev, 0) & 0x00f0) { - // SUNI - printk (" SUNI"); - - // Reset, just in case - wr_framer (dev, 0x00, 0x0080); - wr_framer (dev, 0x00, 0x0000); - - // Configure transmit FIFO - wr_framer (dev, 0x63, rd_framer (dev, 0x63) | 0x0002); - - // Set line timed mode - wr_framer (dev, 0x05, rd_framer (dev, 0x05) | 0x0001); - } else { - // SAMBA - printk (" SAMBA"); - - // Reset, just in case - wr_framer (dev, 0, rd_framer (dev, 0) | 0x0001); - wr_framer (dev, 0, rd_framer (dev, 0) &~ 0x0001); - - // Turn off diagnostic loopback and enable line-timed mode - wr_framer (dev, 0, 0x0002); - - // Turn on transmit outputs - wr_framer (dev, 2, 0x0B80); - } - } else { - // Select 25 mode - ctrl &= ~ATM_LAYER_SELECT; - - // Madge B154 setup - // none required? - } - - printk (" LEDs"); - - GREEN_LED_ON(dev); - YELLOW_LED_ON(dev); - - printk (" ESI="); - - { - u16 b = 0; - int i; - u8 * esi = dev->atm_dev->esi; - - // in the card I have, EEPROM - // addresses 0, 1, 2 contain 0 - // addresess 5, 6 etc. contain ffff - // NB: Madge prefix is 00 00 f6 (which is 00 00 6f in Ethernet bit order) - // the read_bia routine gets the BIA in Ethernet bit order - - for (i=0; i < ESI_LEN; ++i) { - if (i % 2 == 0) - b = read_bia (dev, i/2 + 2); - else - b = b >> 8; - esi[i] = b & 0xFF; - printk ("%02x", esi[i]); - } - } - - // Enable RX_Q and ?X_COMPLETE interrupts only - wr_regl (dev, INT_ENABLE_REG_OFF, INTERESTING_INTERRUPTS); - printk (" IRQ on"); - - printk (".\n"); - - return onefivefive; -} - -/********** check max_sdu **********/ - -static int check_max_sdu (hrz_aal aal, struct atm_trafprm * tp, unsigned int max_frame_size) { - PRINTD (DBG_FLOW|DBG_QOS, "check_max_sdu"); - - switch (aal) { - case aal0: - if (!(tp->max_sdu)) { - PRINTD (DBG_QOS, "defaulting max_sdu"); - tp->max_sdu = ATM_AAL0_SDU; - } else if (tp->max_sdu != ATM_AAL0_SDU) { - PRINTD (DBG_QOS|DBG_ERR, "rejecting max_sdu"); - return -EINVAL; - } - break; - case aal34: - if (tp->max_sdu == 0 || tp->max_sdu > ATM_MAX_AAL34_PDU) { - PRINTD (DBG_QOS, "%sing max_sdu", tp->max_sdu ? "capp" : "default"); - tp->max_sdu = ATM_MAX_AAL34_PDU; - } - break; - case aal5: - if (tp->max_sdu == 0 || tp->max_sdu > max_frame_size) { - PRINTD (DBG_QOS, "%sing max_sdu", tp->max_sdu ? "capp" : "default"); - tp->max_sdu = max_frame_size; - } - break; - } - return 0; -} - -/********** check pcr **********/ - -// something like this should be part of ATM Linux -static int atm_pcr_check (struct atm_trafprm * tp, unsigned int pcr) { - // we are assuming non-UBR, and non-special values of pcr - if (tp->min_pcr == ATM_MAX_PCR) - PRINTD (DBG_QOS, "luser gave min_pcr = ATM_MAX_PCR"); - else if (tp->min_pcr < 0) - PRINTD (DBG_QOS, "luser gave negative min_pcr"); - else if (tp->min_pcr && tp->min_pcr > pcr) - PRINTD (DBG_QOS, "pcr less than min_pcr"); - else - // !! max_pcr = UNSPEC (0) is equivalent to max_pcr = MAX (-1) - // easier to #define ATM_MAX_PCR 0 and have all rates unsigned? - // [this would get rid of next two conditionals] - if ((0) && tp->max_pcr == ATM_MAX_PCR) - PRINTD (DBG_QOS, "luser gave max_pcr = ATM_MAX_PCR"); - else if ((tp->max_pcr != ATM_MAX_PCR) && tp->max_pcr < 0) - PRINTD (DBG_QOS, "luser gave negative max_pcr"); - else if (tp->max_pcr && tp->max_pcr != ATM_MAX_PCR && tp->max_pcr < pcr) - PRINTD (DBG_QOS, "pcr greater than max_pcr"); - else { - // each limit unspecified or not violated - PRINTD (DBG_QOS, "xBR(pcr) OK"); - return 0; - } - PRINTD (DBG_QOS, "pcr=%u, tp: min_pcr=%d, pcr=%d, max_pcr=%d", - pcr, tp->min_pcr, tp->pcr, tp->max_pcr); - return -EINVAL; -} - -/********** open VC **********/ - -static int hrz_open (struct atm_vcc *atm_vcc) -{ - int error; - u16 channel; - - struct atm_qos * qos; - struct atm_trafprm * txtp; - struct atm_trafprm * rxtp; - - hrz_dev * dev = HRZ_DEV(atm_vcc->dev); - hrz_vcc vcc; - hrz_vcc * vccp; // allocated late - short vpi = atm_vcc->vpi; - int vci = atm_vcc->vci; - PRINTD (DBG_FLOW|DBG_VCC, "hrz_open %x %x", vpi, vci); - -#ifdef ATM_VPI_UNSPEC - // UNSPEC is deprecated, remove this code eventually - if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) { - PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)"); - return -EINVAL; - } -#endif - - error = vpivci_to_channel (&channel, vpi, vci); - if (error) { - PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci); - return error; - } - - vcc.channel = channel; - // max speed for the moment - vcc.tx_rate = 0x0; - - qos = &atm_vcc->qos; - - // check AAL and remember it - switch (qos->aal) { - case ATM_AAL0: - // we would if it were 48 bytes and not 52! - PRINTD (DBG_QOS|DBG_VCC, "AAL0"); - vcc.aal = aal0; - break; - case ATM_AAL34: - // we would if I knew how do the SAR! - PRINTD (DBG_QOS|DBG_VCC, "AAL3/4"); - vcc.aal = aal34; - break; - case ATM_AAL5: - PRINTD (DBG_QOS|DBG_VCC, "AAL5"); - vcc.aal = aal5; - break; - default: - PRINTD (DBG_QOS|DBG_VCC, "Bad AAL!"); - return -EINVAL; - } - - // TX traffic parameters - - // there are two, interrelated problems here: 1. the reservation of - // PCR is not a binary choice, we are given bounds and/or a - // desirable value; 2. the device is only capable of certain values, - // most of which are not integers. It is almost certainly acceptable - // to be off by a maximum of 1 to 10 cps. - - // Pragmatic choice: always store an integral PCR as that which has - // been allocated, even if we allocate a little (or a lot) less, - // after rounding. The actual allocation depends on what we can - // manage with our rate selection algorithm. The rate selection - // algorithm is given an integral PCR and a tolerance and told - // whether it should round the value up or down if the tolerance is - // exceeded; it returns: a) the actual rate selected (rounded up to - // the nearest integer), b) a bit pattern to feed to the timer - // register, and c) a failure value if no applicable rate exists. - - // Part of the job is done by atm_pcr_goal which gives us a PCR - // specification which says: EITHER grab the maximum available PCR - // (and perhaps a lower bound which we must not pass), OR grab this - // amount, rounding down if you have to (and perhaps a lower bound - // which we must not pass) OR grab this amount, rounding up if you - // have to (and perhaps an upper bound which we must not pass). If any - // bounds ARE passed we fail. Note that rounding is only rounding to - // match device limitations, we do not round down to satisfy - // bandwidth availability even if this would not violate any given - // lower bound. - - // Note: telephony = 64kb/s = 48 byte cell payload @ 500/3 cells/s - // (say) so this is not even a binary fixpoint cell rate (but this - // device can do it). To avoid this sort of hassle we use a - // tolerance parameter (currently fixed at 10 cps). - - PRINTD (DBG_QOS, "TX:"); - - txtp = &qos->txtp; - - // set up defaults for no traffic - vcc.tx_rate = 0; - // who knows what would actually happen if you try and send on this? - vcc.tx_xbr_bits = IDLE_RATE_TYPE; - vcc.tx_pcr_bits = CLOCK_DISABLE; -#if 0 - vcc.tx_scr_bits = CLOCK_DISABLE; - vcc.tx_bucket_bits = 0; -#endif - - if (txtp->traffic_class != ATM_NONE) { - error = check_max_sdu (vcc.aal, txtp, max_tx_size); - if (error) { - PRINTD (DBG_QOS, "TX max_sdu check failed"); - return error; - } - - switch (txtp->traffic_class) { - case ATM_UBR: { - // we take "the PCR" as a rate-cap - // not reserved - vcc.tx_rate = 0; - make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, NULL); - vcc.tx_xbr_bits = ABR_RATE_TYPE; - break; - } -#if 0 - case ATM_ABR: { - // reserve min, allow up to max - vcc.tx_rate = 0; // ? - make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, 0); - vcc.tx_xbr_bits = ABR_RATE_TYPE; - break; - } -#endif - case ATM_CBR: { - int pcr = atm_pcr_goal (txtp); - rounding r; - if (!pcr) { - // down vs. up, remaining bandwidth vs. unlimited bandwidth!! - // should really have: once someone gets unlimited bandwidth - // that no more non-UBR channels can be opened until the - // unlimited one closes?? For the moment, round_down means - // greedy people actually get something and not nothing - r = round_down; - // slight race (no locking) here so we may get -EAGAIN - // later; the greedy bastards would deserve it :) - PRINTD (DBG_QOS, "snatching all remaining TX bandwidth"); - pcr = dev->tx_avail; - } else if (pcr < 0) { - r = round_down; - pcr = -pcr; - } else { - r = round_up; - } - error = make_rate_with_tolerance (dev, pcr, r, 10, - &vcc.tx_pcr_bits, &vcc.tx_rate); - if (error) { - PRINTD (DBG_QOS, "could not make rate from TX PCR"); - return error; - } - // not really clear what further checking is needed - error = atm_pcr_check (txtp, vcc.tx_rate); - if (error) { - PRINTD (DBG_QOS, "TX PCR failed consistency check"); - return error; - } - vcc.tx_xbr_bits = CBR_RATE_TYPE; - break; - } -#if 0 - case ATM_VBR: { - int pcr = atm_pcr_goal (txtp); - // int scr = atm_scr_goal (txtp); - int scr = pcr/2; // just for fun - unsigned int mbs = 60; // just for fun - rounding pr; - rounding sr; - unsigned int bucket; - if (!pcr) { - pr = round_nearest; - pcr = 1<<30; - } else if (pcr < 0) { - pr = round_down; - pcr = -pcr; - } else { - pr = round_up; - } - error = make_rate_with_tolerance (dev, pcr, pr, 10, - &vcc.tx_pcr_bits, 0); - if (!scr) { - // see comments for PCR with CBR above - sr = round_down; - // slight race (no locking) here so we may get -EAGAIN - // later; the greedy bastards would deserve it :) - PRINTD (DBG_QOS, "snatching all remaining TX bandwidth"); - scr = dev->tx_avail; - } else if (scr < 0) { - sr = round_down; - scr = -scr; - } else { - sr = round_up; - } - error = make_rate_with_tolerance (dev, scr, sr, 10, - &vcc.tx_scr_bits, &vcc.tx_rate); - if (error) { - PRINTD (DBG_QOS, "could not make rate from TX SCR"); - return error; - } - // not really clear what further checking is needed - // error = atm_scr_check (txtp, vcc.tx_rate); - if (error) { - PRINTD (DBG_QOS, "TX SCR failed consistency check"); - return error; - } - // bucket calculations (from a piece of paper...) cell bucket - // capacity must be largest integer smaller than m(p-s)/p + 1 - // where m = max burst size, p = pcr, s = scr - bucket = mbs*(pcr-scr)/pcr; - if (bucket*pcr != mbs*(pcr-scr)) - bucket += 1; - if (bucket > BUCKET_MAX_SIZE) { - PRINTD (DBG_QOS, "shrinking bucket from %u to %u", - bucket, BUCKET_MAX_SIZE); - bucket = BUCKET_MAX_SIZE; - } - vcc.tx_xbr_bits = VBR_RATE_TYPE; - vcc.tx_bucket_bits = bucket; - break; - } -#endif - default: { - PRINTD (DBG_QOS, "unsupported TX traffic class"); - return -EINVAL; - } - } - } - - // RX traffic parameters - - PRINTD (DBG_QOS, "RX:"); - - rxtp = &qos->rxtp; - - // set up defaults for no traffic - vcc.rx_rate = 0; - - if (rxtp->traffic_class != ATM_NONE) { - error = check_max_sdu (vcc.aal, rxtp, max_rx_size); - if (error) { - PRINTD (DBG_QOS, "RX max_sdu check failed"); - return error; - } - switch (rxtp->traffic_class) { - case ATM_UBR: { - // not reserved - break; - } -#if 0 - case ATM_ABR: { - // reserve min - vcc.rx_rate = 0; // ? - break; - } -#endif - case ATM_CBR: { - int pcr = atm_pcr_goal (rxtp); - if (!pcr) { - // slight race (no locking) here so we may get -EAGAIN - // later; the greedy bastards would deserve it :) - PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); - pcr = dev->rx_avail; - } else if (pcr < 0) { - pcr = -pcr; - } - vcc.rx_rate = pcr; - // not really clear what further checking is needed - error = atm_pcr_check (rxtp, vcc.rx_rate); - if (error) { - PRINTD (DBG_QOS, "RX PCR failed consistency check"); - return error; - } - break; - } -#if 0 - case ATM_VBR: { - // int scr = atm_scr_goal (rxtp); - int scr = 1<<16; // just for fun - if (!scr) { - // slight race (no locking) here so we may get -EAGAIN - // later; the greedy bastards would deserve it :) - PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); - scr = dev->rx_avail; - } else if (scr < 0) { - scr = -scr; - } - vcc.rx_rate = scr; - // not really clear what further checking is needed - // error = atm_scr_check (rxtp, vcc.rx_rate); - if (error) { - PRINTD (DBG_QOS, "RX SCR failed consistency check"); - return error; - } - break; - } -#endif - default: { - PRINTD (DBG_QOS, "unsupported RX traffic class"); - return -EINVAL; - } - } - } - - - // late abort useful for diagnostics - if (vcc.aal != aal5) { - PRINTD (DBG_QOS, "AAL not supported"); - return -EINVAL; - } - - // get space for our vcc stuff and copy parameters into it - vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL); - if (!vccp) { - PRINTK (KERN_ERR, "out of memory!"); - return -ENOMEM; - } - *vccp = vcc; - - // clear error and grab cell rate resource lock - error = 0; - spin_lock (&dev->rate_lock); - - if (vcc.tx_rate > dev->tx_avail) { - PRINTD (DBG_QOS, "not enough TX PCR left"); - error = -EAGAIN; - } - - if (vcc.rx_rate > dev->rx_avail) { - PRINTD (DBG_QOS, "not enough RX PCR left"); - error = -EAGAIN; - } - - if (!error) { - // really consume cell rates - dev->tx_avail -= vcc.tx_rate; - dev->rx_avail -= vcc.rx_rate; - PRINTD (DBG_QOS|DBG_VCC, "reserving %u TX PCR and %u RX PCR", - vcc.tx_rate, vcc.rx_rate); - } - - // release lock and exit on error - spin_unlock (&dev->rate_lock); - if (error) { - PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources"); - kfree (vccp); - return error; - } - - // this is "immediately before allocating the connection identifier - // in hardware" - so long as the next call does not fail :) - set_bit(ATM_VF_ADDR,&atm_vcc->flags); - - // any errors here are very serious and should never occur - - if (rxtp->traffic_class != ATM_NONE) { - if (dev->rxer[channel]) { - PRINTD (DBG_ERR|DBG_VCC, "VC already open for RX"); - error = -EBUSY; - } - if (!error) - error = hrz_open_rx (dev, channel); - if (error) { - kfree (vccp); - return error; - } - // this link allows RX frames through - dev->rxer[channel] = atm_vcc; - } - - // success, set elements of atm_vcc - atm_vcc->dev_data = (void *) vccp; - - // indicate readiness - set_bit(ATM_VF_READY,&atm_vcc->flags); - - return 0; -} - -/********** close VC **********/ - -static void hrz_close (struct atm_vcc * atm_vcc) { - hrz_dev * dev = HRZ_DEV(atm_vcc->dev); - hrz_vcc * vcc = HRZ_VCC(atm_vcc); - u16 channel = vcc->channel; - PRINTD (DBG_VCC|DBG_FLOW, "hrz_close"); - - // indicate unreadiness - clear_bit(ATM_VF_READY,&atm_vcc->flags); - - if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) { - unsigned int i; - - // let any TX on this channel that has started complete - // no restart, just keep trying - while (tx_hold (dev)) - ; - // remove record of any tx_channel having been setup for this channel - for (i = 0; i < TX_CHANS; ++i) - if (dev->tx_channel_record[i] == channel) { - dev->tx_channel_record[i] = -1; - break; - } - if (dev->last_vc == channel) - dev->tx_last = -1; - tx_release (dev); - } - - if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { - // disable RXing - it tries quite hard - hrz_close_rx (dev, channel); - // forget the vcc - no more skbs will be pushed - if (atm_vcc != dev->rxer[channel]) - PRINTK (KERN_ERR, "%s atm_vcc=%p rxer[channel]=%p", - "arghhh! we're going to die!", - atm_vcc, dev->rxer[channel]); - dev->rxer[channel] = NULL; - } - - // atomically release our rate reservation - spin_lock (&dev->rate_lock); - PRINTD (DBG_QOS|DBG_VCC, "releasing %u TX PCR and %u RX PCR", - vcc->tx_rate, vcc->rx_rate); - dev->tx_avail += vcc->tx_rate; - dev->rx_avail += vcc->rx_rate; - spin_unlock (&dev->rate_lock); - - // free our structure - kfree (vcc); - // say the VPI/VCI is free again - clear_bit(ATM_VF_ADDR,&atm_vcc->flags); -} - -#if 0 -static int hrz_ioctl (struct atm_dev * atm_dev, unsigned int cmd, void *arg) { - hrz_dev * dev = HRZ_DEV(atm_dev); - PRINTD (DBG_FLOW, "hrz_ioctl"); - return -1; -} - -unsigned char hrz_phy_get (struct atm_dev * atm_dev, unsigned long addr) { - hrz_dev * dev = HRZ_DEV(atm_dev); - PRINTD (DBG_FLOW, "hrz_phy_get"); - return 0; -} - -static void hrz_phy_put (struct atm_dev * atm_dev, unsigned char value, - unsigned long addr) { - hrz_dev * dev = HRZ_DEV(atm_dev); - PRINTD (DBG_FLOW, "hrz_phy_put"); -} - -static int hrz_change_qos (struct atm_vcc * atm_vcc, struct atm_qos *qos, int flgs) { - hrz_dev * dev = HRZ_DEV(vcc->dev); - PRINTD (DBG_FLOW, "hrz_change_qos"); - return -1; -} -#endif - -/********** proc file contents **********/ - -static int hrz_proc_read (struct atm_dev * atm_dev, loff_t * pos, char * page) { - hrz_dev * dev = HRZ_DEV(atm_dev); - int left = *pos; - PRINTD (DBG_FLOW, "hrz_proc_read"); - - /* more diagnostics here? */ - -#if 0 - if (!left--) { - unsigned int count = sprintf (page, "vbr buckets:"); - unsigned int i; - for (i = 0; i < TX_CHANS; ++i) - count += sprintf (page, " %u/%u", - query_tx_channel_config (dev, i, BUCKET_FULLNESS_ACCESS), - query_tx_channel_config (dev, i, BUCKET_CAPACITY_ACCESS)); - count += sprintf (page+count, ".\n"); - return count; - } -#endif - - if (!left--) - return sprintf (page, - "cells: TX %lu, RX %lu, HEC errors %lu, unassigned %lu.\n", - dev->tx_cell_count, dev->rx_cell_count, - dev->hec_error_count, dev->unassigned_cell_count); - - if (!left--) - return sprintf (page, - "free cell buffers: TX %hu, RX %hu+%hu.\n", - rd_regw (dev, TX_FREE_BUFFER_COUNT_OFF), - rd_regw (dev, RX_FREE_BUFFER_COUNT_OFF), - dev->noof_spare_buffers); - - if (!left--) - return sprintf (page, - "cps remaining: TX %u, RX %u\n", - dev->tx_avail, dev->rx_avail); - - return 0; -} - -static const struct atmdev_ops hrz_ops = { - .open = hrz_open, - .close = hrz_close, - .send = hrz_send, - .proc_read = hrz_proc_read, - .owner = THIS_MODULE, -}; - -static int hrz_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_ent) -{ - hrz_dev * dev; - int err = 0; - - // adapter slot free, read resources from PCI configuration space - u32 iobase = pci_resource_start (pci_dev, 0); - u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 1)); - unsigned int irq; - unsigned char lat; - - PRINTD (DBG_FLOW, "hrz_probe"); - - if (pci_enable_device(pci_dev)) - return -EINVAL; - - /* XXX DEV_LABEL is a guess */ - if (!request_region(iobase, HRZ_IO_EXTENT, DEV_LABEL)) { - err = -EINVAL; - goto out_disable; - } - - dev = kzalloc(sizeof(hrz_dev), GFP_KERNEL); - if (!dev) { - // perhaps we should be nice: deregister all adapters and abort? - PRINTD(DBG_ERR, "out of memory"); - err = -ENOMEM; - goto out_release; - } - - pci_set_drvdata(pci_dev, dev); - - // grab IRQ and install handler - move this someplace more sensible - irq = pci_dev->irq; - if (request_irq(irq, - interrupt_handler, - IRQF_SHARED, /* irqflags guess */ - DEV_LABEL, /* name guess */ - dev)) { - PRINTD(DBG_WARN, "request IRQ failed!"); - err = -EINVAL; - goto out_free; - } - - PRINTD(DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p", - iobase, irq, membase); - - dev->atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &hrz_ops, -1, - NULL); - if (!(dev->atm_dev)) { - PRINTD(DBG_ERR, "failed to register Madge ATM adapter"); - err = -EINVAL; - goto out_free_irq; - } - - PRINTD(DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", - dev->atm_dev->number, dev, dev->atm_dev); - dev->atm_dev->dev_data = (void *) dev; - dev->pci_dev = pci_dev; - - // enable bus master accesses - pci_set_master(pci_dev); - - // frobnicate latency (upwards, usually) - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat); - if (pci_lat) { - PRINTD(DBG_INFO, "%s PCI latency timer from %hu to %hu", - "changing", lat, pci_lat); - pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat); - } else if (lat < MIN_PCI_LATENCY) { - PRINTK(KERN_INFO, "%s PCI latency timer from %hu to %hu", - "increasing", lat, MIN_PCI_LATENCY); - pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); - } - - dev->iobase = iobase; - dev->irq = irq; - dev->membase = membase; - - dev->rx_q_entry = dev->rx_q_reset = &memmap->rx_q_entries[0]; - dev->rx_q_wrap = &memmap->rx_q_entries[RX_CHANS-1]; - - // these next three are performance hacks - dev->last_vc = -1; - dev->tx_last = -1; - dev->tx_idle = 0; - - dev->tx_regions = 0; - dev->tx_bytes = 0; - dev->tx_skb = NULL; - dev->tx_iovec = NULL; - - dev->tx_cell_count = 0; - dev->rx_cell_count = 0; - dev->hec_error_count = 0; - dev->unassigned_cell_count = 0; - - dev->noof_spare_buffers = 0; - - { - unsigned int i; - for (i = 0; i < TX_CHANS; ++i) - dev->tx_channel_record[i] = -1; - } - - dev->flags = 0; - - // Allocate cell rates and remember ASIC version - // Fibre: ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 - // Copper: (WRONG) we want 6 into the above, close to 25Mb/s - // Copper: (plagarise!) 25600000/8/270*260/53 - n/53 - - if (hrz_init(dev)) { - // to be really pedantic, this should be ATM_OC3c_PCR - dev->tx_avail = ATM_OC3_PCR; - dev->rx_avail = ATM_OC3_PCR; - set_bit(ultra, &dev->flags); // NOT "|= ultra" ! - } else { - dev->tx_avail = ((25600000/8)*26)/(27*53); - dev->rx_avail = ((25600000/8)*26)/(27*53); - PRINTD(DBG_WARN, "Buggy ASIC: no TX bus-mastering."); - } - - // rate changes spinlock - spin_lock_init(&dev->rate_lock); - - // on-board memory access spinlock; we want atomic reads and - // writes to adapter memory (handles IRQ and SMP) - spin_lock_init(&dev->mem_lock); - - init_waitqueue_head(&dev->tx_queue); - - // vpi in 0..4, vci in 6..10 - dev->atm_dev->ci_range.vpi_bits = vpi_bits; - dev->atm_dev->ci_range.vci_bits = 10-vpi_bits; - - timer_setup(&dev->housekeeping, do_housekeeping, 0); - mod_timer(&dev->housekeeping, jiffies); - -out: - return err; - -out_free_irq: - free_irq(irq, dev); -out_free: - kfree(dev); -out_release: - release_region(iobase, HRZ_IO_EXTENT); -out_disable: - pci_disable_device(pci_dev); - goto out; -} - -static void hrz_remove_one(struct pci_dev *pci_dev) -{ - hrz_dev *dev; - - dev = pci_get_drvdata(pci_dev); - - PRINTD(DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev); - del_timer_sync(&dev->housekeeping); - hrz_reset(dev); - atm_dev_deregister(dev->atm_dev); - free_irq(dev->irq, dev); - release_region(dev->iobase, HRZ_IO_EXTENT); - kfree(dev); - - pci_disable_device(pci_dev); -} - -static void __init hrz_check_args (void) { -#ifdef DEBUG_HORIZON - PRINTK (KERN_NOTICE, "debug bitmap is %hx", debug &= DBG_MASK); -#else - if (debug) - PRINTK (KERN_NOTICE, "no debug support in this image"); -#endif - - if (vpi_bits > HRZ_MAX_VPI) - PRINTK (KERN_ERR, "vpi_bits has been limited to %hu", - vpi_bits = HRZ_MAX_VPI); - - if (max_tx_size < 0 || max_tx_size > TX_AAL5_LIMIT) - PRINTK (KERN_NOTICE, "max_tx_size has been limited to %hu", - max_tx_size = TX_AAL5_LIMIT); - - if (max_rx_size < 0 || max_rx_size > RX_AAL5_LIMIT) - PRINTK (KERN_NOTICE, "max_rx_size has been limited to %hu", - max_rx_size = RX_AAL5_LIMIT); - - return; -} - -MODULE_AUTHOR(maintainer_string); -MODULE_DESCRIPTION(description_string); -MODULE_LICENSE("GPL"); -module_param(debug, ushort, 0644); -module_param(vpi_bits, ushort, 0); -module_param(max_tx_size, int, 0); -module_param(max_rx_size, int, 0); -module_param(pci_lat, byte, 0); -MODULE_PARM_DESC(debug, "debug bitmap, see .h file"); -MODULE_PARM_DESC(vpi_bits, "number of bits (0..4) to allocate to VPIs"); -MODULE_PARM_DESC(max_tx_size, "maximum size of TX AAL5 frames"); -MODULE_PARM_DESC(max_rx_size, "maximum size of RX AAL5 frames"); -MODULE_PARM_DESC(pci_lat, "PCI latency in bus cycles"); - -static const struct pci_device_id hrz_pci_tbl[] = { - { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, hrz_pci_tbl); - -static struct pci_driver hrz_driver = { - .name = "horizon", - .probe = hrz_probe, - .remove = hrz_remove_one, - .id_table = hrz_pci_tbl, -}; - -/********** module entry **********/ - -static int __init hrz_module_init (void) { - BUILD_BUG_ON(sizeof(struct MEMMAP) != 128*1024/4); - - show_version(); - - // check arguments - hrz_check_args(); - - // get the juice - return pci_register_driver(&hrz_driver); -} - -/********** module exit **********/ - -static void __exit hrz_module_exit (void) { - PRINTD (DBG_FLOW, "cleanup_module"); - - pci_unregister_driver(&hrz_driver); -} - -module_init(hrz_module_init); -module_exit(hrz_module_exit); diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h deleted file mode 100644 index 7523eba19bad..000000000000 --- a/drivers/atm/horizon.h +++ /dev/null @@ -1,492 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - Madge Horizon ATM Adapter driver. - Copyright (C) 1995-1999 Madge Networks Ltd. - -*/ - -/* - IMPORTANT NOTE: Madge Networks no longer makes the adapters - supported by this driver and makes no commitment to maintain it. -*/ - -/* too many macros - change to inline functions */ - -#ifndef DRIVER_ATM_HORIZON_H -#define DRIVER_ATM_HORIZON_H - - -#ifdef CONFIG_ATM_HORIZON_DEBUG -#define DEBUG_HORIZON -#endif - -#define DEV_LABEL "hrz" - -#ifndef PCI_VENDOR_ID_MADGE -#define PCI_VENDOR_ID_MADGE 0x10B6 -#endif -#ifndef PCI_DEVICE_ID_MADGE_HORIZON -#define PCI_DEVICE_ID_MADGE_HORIZON 0x1000 -#endif - -// diagnostic output - -#define PRINTK(severity,format,args...) \ - printk(severity DEV_LABEL ": " format "\n" , ## args) - -#ifdef DEBUG_HORIZON - -#define DBG_ERR 0x0001 -#define DBG_WARN 0x0002 -#define DBG_INFO 0x0004 -#define DBG_VCC 0x0008 -#define DBG_QOS 0x0010 -#define DBG_TX 0x0020 -#define DBG_RX 0x0040 -#define DBG_SKB 0x0080 -#define DBG_IRQ 0x0100 -#define DBG_FLOW 0x0200 -#define DBG_BUS 0x0400 -#define DBG_REGS 0x0800 -#define DBG_DATA 0x1000 -#define DBG_MASK 0x1fff - -/* the ## prevents the annoying double expansion of the macro arguments */ -/* KERN_INFO is used since KERN_DEBUG often does not make it to the console */ -#define PRINTDB(bits,format,args...) \ - ( (debug & (bits)) ? printk (KERN_INFO DEV_LABEL ": " format , ## args) : 1 ) -#define PRINTDM(bits,format,args...) \ - ( (debug & (bits)) ? printk (format , ## args) : 1 ) -#define PRINTDE(bits,format,args...) \ - ( (debug & (bits)) ? printk (format "\n" , ## args) : 1 ) -#define PRINTD(bits,format,args...) \ - ( (debug & (bits)) ? printk (KERN_INFO DEV_LABEL ": " format "\n" , ## args) : 1 ) - -#else - -#define PRINTD(bits,format,args...) -#define PRINTDB(bits,format,args...) -#define PRINTDM(bits,format,args...) -#define PRINTDE(bits,format,args...) - -#endif - -#define PRINTDD(sec,fmt,args...) -#define PRINTDDB(sec,fmt,args...) -#define PRINTDDM(sec,fmt,args...) -#define PRINTDDE(sec,fmt,args...) - -// fixed constants - -#define SPARE_BUFFER_POOL_SIZE MAX_VCS -#define HRZ_MAX_VPI 4 -#define MIN_PCI_LATENCY 48 // 24 IS TOO SMALL - -/* Horizon specific bits */ -/* Register offsets */ - -#define HRZ_IO_EXTENT 0x80 - -#define DATA_PORT_OFF 0x00 -#define TX_CHANNEL_PORT_OFF 0x04 -#define TX_DESCRIPTOR_PORT_OFF 0x08 -#define MEMORY_PORT_OFF 0x0C -#define MEM_WR_ADDR_REG_OFF 0x14 -#define MEM_RD_ADDR_REG_OFF 0x18 -#define CONTROL_0_REG 0x1C -#define INT_SOURCE_REG_OFF 0x20 -#define INT_ENABLE_REG_OFF 0x24 -#define MASTER_RX_ADDR_REG_OFF 0x28 -#define MASTER_RX_COUNT_REG_OFF 0x2C -#define MASTER_TX_ADDR_REG_OFF 0x30 -#define MASTER_TX_COUNT_REG_OFF 0x34 -#define TX_DESCRIPTOR_REG_OFF 0x38 -#define TX_CHANNEL_CONFIG_COMMAND_OFF 0x40 -#define TX_CHANNEL_CONFIG_DATA_OFF 0x44 -#define TX_FREE_BUFFER_COUNT_OFF 0x48 -#define RX_FREE_BUFFER_COUNT_OFF 0x4C -#define TX_CONFIG_OFF 0x50 -#define TX_STATUS_OFF 0x54 -#define RX_CONFIG_OFF 0x58 -#define RX_LINE_CONFIG_OFF 0x5C -#define RX_QUEUE_RD_PTR_OFF 0x60 -#define RX_QUEUE_WR_PTR_OFF 0x64 -#define MAX_AAL5_CELL_COUNT_OFF 0x68 -#define RX_CHANNEL_PORT_OFF 0x6C -#define TX_CELL_COUNT_OFF 0x70 -#define RX_CELL_COUNT_OFF 0x74 -#define HEC_ERROR_COUNT_OFF 0x78 -#define UNASSIGNED_CELL_COUNT_OFF 0x7C - -/* Register bit definitions */ - -/* Control 0 register */ - -#define SEEPROM_DO 0x00000001 -#define SEEPROM_DI 0x00000002 -#define SEEPROM_SK 0x00000004 -#define SEEPROM_CS 0x00000008 -#define DEBUG_BIT_0 0x00000010 -#define DEBUG_BIT_1 0x00000020 -#define DEBUG_BIT_2 0x00000040 -// RESERVED 0x00000080 -#define DEBUG_BIT_0_OE 0x00000100 -#define DEBUG_BIT_1_OE 0x00000200 -#define DEBUG_BIT_2_OE 0x00000400 -// RESERVED 0x00000800 -#define DEBUG_BIT_0_STATE 0x00001000 -#define DEBUG_BIT_1_STATE 0x00002000 -#define DEBUG_BIT_2_STATE 0x00004000 -// RESERVED 0x00008000 -#define GENERAL_BIT_0 0x00010000 -#define GENERAL_BIT_1 0x00020000 -#define GENERAL_BIT_2 0x00040000 -#define GENERAL_BIT_3 0x00080000 -#define RESET_HORIZON 0x00100000 -#define RESET_ATM 0x00200000 -#define RESET_RX 0x00400000 -#define RESET_TX 0x00800000 -#define RESET_HOST 0x01000000 -// RESERVED 0x02000000 -#define TARGET_RETRY_DISABLE 0x04000000 -#define ATM_LAYER_SELECT 0x08000000 -#define ATM_LAYER_STATUS 0x10000000 -// RESERVED 0xE0000000 - -/* Interrupt source and enable registers */ - -#define RX_DATA_AV 0x00000001 -#define RX_DISABLED 0x00000002 -#define TIMING_MARKER 0x00000004 -#define FORCED 0x00000008 -#define RX_BUS_MASTER_COMPLETE 0x00000010 -#define TX_BUS_MASTER_COMPLETE 0x00000020 -#define ABR_TX_CELL_COUNT_INT 0x00000040 -#define DEBUG_INT 0x00000080 -// RESERVED 0xFFFFFF00 - -/* PIO and Bus Mastering */ - -#define MAX_PIO_COUNT 0x000000ff // 255 - make tunable? -// 8188 is a hard limit for bus mastering -#define MAX_TRANSFER_COUNT 0x00001ffc // 8188 -#define MASTER_TX_AUTO_APPEND_DESC 0x80000000 - -/* TX channel config command port */ - -#define PCR_TIMER_ACCESS 0x0000 -#define SCR_TIMER_ACCESS 0x0001 -#define BUCKET_CAPACITY_ACCESS 0x0002 -#define BUCKET_FULLNESS_ACCESS 0x0003 -#define RATE_TYPE_ACCESS 0x0004 -// UNUSED 0x00F8 -#define TX_CHANNEL_CONFIG_MULT 0x0100 -// UNUSED 0xF800 -#define BUCKET_MAX_SIZE 0x003f - -/* TX channel config data port */ - -#define CLOCK_SELECT_SHIFT 4 -#define CLOCK_DISABLE 0x00ff - -#define IDLE_RATE_TYPE 0x0 -#define ABR_RATE_TYPE 0x1 -#define VBR_RATE_TYPE 0x2 -#define CBR_RATE_TYPE 0x3 - -/* TX config register */ - -#define DRVR_DRVRBAR_ENABLE 0x0001 -#define TXCLK_MUX_SELECT_RCLK 0x0002 -#define TRANSMIT_TIMING_MARKER 0x0004 -#define LOOPBACK_TIMING_MARKER 0x0008 -#define TX_TEST_MODE_16MHz 0x0000 -#define TX_TEST_MODE_8MHz 0x0010 -#define TX_TEST_MODE_5_33MHz 0x0020 -#define TX_TEST_MODE_4MHz 0x0030 -#define TX_TEST_MODE_3_2MHz 0x0040 -#define TX_TEST_MODE_2_66MHz 0x0050 -#define TX_TEST_MODE_2_29MHz 0x0060 -#define TX_NORMAL_OPERATION 0x0070 -#define ABR_ROUND_ROBIN 0x0080 - -/* TX status register */ - -#define IDLE_CHANNELS_MASK 0x00FF -#define ABR_CELL_COUNT_REACHED_MULT 0x0100 -#define ABR_CELL_COUNT_REACHED_MASK 0xFF - -/* RX config register */ - -#define NON_USER_CELLS_IN_ONE_CHANNEL 0x0008 -#define RX_ENABLE 0x0010 -#define IGNORE_UNUSED_VPI_VCI_BITS_SET 0x0000 -#define NON_USER_UNUSED_VPI_VCI_BITS_SET 0x0020 -#define DISCARD_UNUSED_VPI_VCI_BITS_SET 0x0040 - -/* RX line config register */ - -#define SIGNAL_LOSS 0x0001 -#define FREQUENCY_DETECT_ERROR 0x0002 -#define LOCK_DETECT_ERROR 0x0004 -#define SELECT_INTERNAL_LOOPBACK 0x0008 -#define LOCK_DETECT_ENABLE 0x0010 -#define FREQUENCY_DETECT_ENABLE 0x0020 -#define USER_FRAQ 0x0040 -#define GXTALOUT_SELECT_DIV4 0x0080 -#define GXTALOUT_SELECT_NO_GATING 0x0100 -#define TIMING_MARKER_RECEIVED 0x0200 - -/* RX channel port */ - -#define RX_CHANNEL_MASK 0x03FF -// UNUSED 0x3C00 -#define FLUSH_CHANNEL 0x4000 -#define RX_CHANNEL_UPDATE_IN_PROGRESS 0x8000 - -/* Receive queue entry */ - -#define RX_Q_ENTRY_LENGTH_MASK 0x0000FFFF -#define RX_Q_ENTRY_CHANNEL_SHIFT 16 -#define SIMONS_DODGEY_MARKER 0x08000000 -#define RX_CONGESTION_EXPERIENCED 0x10000000 -#define RX_CRC_10_OK 0x20000000 -#define RX_CRC_32_OK 0x40000000 -#define RX_COMPLETE_FRAME 0x80000000 - -/* Offsets and constants for use with the buffer memory */ - -/* Buffer pointers and channel types */ - -#define BUFFER_PTR_MASK 0x0000FFFF -#define RX_INT_THRESHOLD_MULT 0x00010000 -#define RX_INT_THRESHOLD_MASK 0x07FF -#define INT_EVERY_N_CELLS 0x08000000 -#define CONGESTION_EXPERIENCED 0x10000000 -#define FIRST_CELL_OF_AAL5_FRAME 0x20000000 -#define CHANNEL_TYPE_AAL5 0x00000000 -#define CHANNEL_TYPE_RAW_CELLS 0x40000000 -#define CHANNEL_TYPE_AAL3_4 0x80000000 - -/* Buffer status stuff */ - -#define BUFF_STATUS_MASK 0x00030000 -#define BUFF_STATUS_EMPTY 0x00000000 -#define BUFF_STATUS_CELL_AV 0x00010000 -#define BUFF_STATUS_LAST_CELL_AV 0x00020000 - -/* Transmit channel stuff */ - -/* Receive channel stuff */ - -#define RX_CHANNEL_DISABLED 0x00000000 -#define RX_CHANNEL_IDLE 0x00000001 - -/* General things */ - -#define INITIAL_CRC 0xFFFFFFFF - -// A Horizon u32, a byte! Really nasty. Horizon pointers are (32 bit) -// word addresses and so standard C pointer operations break (as they -// assume byte addresses); so we pretend that Horizon words (and word -// pointers) are bytes (and byte pointers) for the purposes of having -// a memory map that works. - -typedef u8 HDW; - -typedef struct cell_buf { - HDW payload[12]; - HDW next; - HDW cell_count; // AAL5 rx bufs - HDW res; - union { - HDW partial_crc; // AAL5 rx bufs - HDW cell_header; // RAW bufs - } u; -} cell_buf; - -typedef struct tx_ch_desc { - HDW rd_buf_type; - HDW wr_buf_type; - HDW partial_crc; - HDW cell_header; -} tx_ch_desc; - -typedef struct rx_ch_desc { - HDW wr_buf_type; - HDW rd_buf_type; -} rx_ch_desc; - -typedef struct rx_q_entry { - HDW entry; -} rx_q_entry; - -#define TX_CHANS 8 -#define RX_CHANS 1024 -#define RX_QS 1024 -#define MAX_VCS RX_CHANS - -/* Horizon buffer memory map */ - -// TX Channel Descriptors 2 -// TX Initial Buffers 8 // TX_CHANS -#define BUFN1_SIZE 118 // (126 - TX_CHANS) -// RX/TX Start/End Buffers 4 -#define BUFN2_SIZE 124 -// RX Queue Entries 64 -#define BUFN3_SIZE 192 -// RX Channel Descriptors 128 -#define BUFN4_SIZE 1408 -// TOTAL cell_buff chunks 2048 - -// cell_buf bufs[2048]; -// HDW dws[32768]; - -typedef struct MEMMAP { - tx_ch_desc tx_descs[TX_CHANS]; // 8 * 4 = 32 , 0x0020 - cell_buf inittxbufs[TX_CHANS]; // these are really - cell_buf bufn1[BUFN1_SIZE]; // part of this pool - cell_buf txfreebufstart; - cell_buf txfreebufend; - cell_buf rxfreebufstart; - cell_buf rxfreebufend; // 8+118+1+1+1+1+124 = 254 - cell_buf bufn2[BUFN2_SIZE]; // 16 * 254 = 4064 , 0x1000 - rx_q_entry rx_q_entries[RX_QS]; // 1 * 1024 = 1024 , 0x1400 - cell_buf bufn3[BUFN3_SIZE]; // 16 * 192 = 3072 , 0x2000 - rx_ch_desc rx_descs[MAX_VCS]; // 2 * 1024 = 2048 , 0x2800 - cell_buf bufn4[BUFN4_SIZE]; // 16 * 1408 = 22528 , 0x8000 -} MEMMAP; - -#define memmap ((MEMMAP *)0) - -/* end horizon specific bits */ - -typedef enum { - aal0, - aal34, - aal5 -} hrz_aal; - -typedef enum { - tx_busy, - rx_busy, - ultra -} hrz_flags; - -// a single struct pointed to by atm_vcc->dev_data - -typedef struct { - unsigned int tx_rate; - unsigned int rx_rate; - u16 channel; - u16 tx_xbr_bits; - u16 tx_pcr_bits; -#if 0 - u16 tx_scr_bits; - u16 tx_bucket_bits; -#endif - hrz_aal aal; -} hrz_vcc; - -struct hrz_dev { - - u32 iobase; - u32 * membase; - - struct sk_buff * rx_skb; // skb being RXed - unsigned int rx_bytes; // bytes remaining to RX within region - void * rx_addr; // addr to send bytes to (for PIO) - unsigned int rx_channel; // channel that the skb is going out on - - struct sk_buff * tx_skb; // skb being TXed - unsigned int tx_bytes; // bytes remaining to TX within region - void * tx_addr; // addr to send bytes from (for PIO) - struct iovec * tx_iovec; // remaining regions - unsigned int tx_regions; // number of remaining regions - - spinlock_t mem_lock; - wait_queue_head_t tx_queue; - - u8 irq; - unsigned long flags; - u8 tx_last; - u8 tx_idle; - - rx_q_entry * rx_q_reset; - rx_q_entry * rx_q_entry; - rx_q_entry * rx_q_wrap; - - struct atm_dev * atm_dev; - - u32 last_vc; - - int noof_spare_buffers; - u16 spare_buffers[SPARE_BUFFER_POOL_SIZE]; - - u16 tx_channel_record[TX_CHANS]; - - // this is what we follow when we get incoming data - u32 txer[MAX_VCS/32]; - struct atm_vcc * rxer[MAX_VCS]; - - // cell rate allocation - spinlock_t rate_lock; - unsigned int rx_avail; - unsigned int tx_avail; - - // dev stats - unsigned long tx_cell_count; - unsigned long rx_cell_count; - unsigned long hec_error_count; - unsigned long unassigned_cell_count; - - struct pci_dev * pci_dev; - struct timer_list housekeeping; -}; - -typedef struct hrz_dev hrz_dev; - -/* macros for use later */ - -#define BUF_PTR(cbptr) ((cbptr) - (cell_buf *) 0) - -#define INTERESTING_INTERRUPTS \ - (RX_DATA_AV | RX_DISABLED | TX_BUS_MASTER_COMPLETE | RX_BUS_MASTER_COMPLETE) - -// 190 cells by default (192 TX buffers - 2 elbow room, see docs) -#define TX_AAL5_LIMIT (190*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER) // 9112 - -// Have enough RX buffers (unless we allow other buffer splits) -#define RX_AAL5_LIMIT ATM_MAX_AAL5_PDU - -/* multi-statement macro protector */ -#define DW(x) do{ x } while(0) - -#define HRZ_DEV(atm_dev) ((hrz_dev *) (atm_dev)->dev_data) -#define HRZ_VCC(atm_vcc) ((hrz_vcc *) (atm_vcc)->dev_data) - -/* Turn the LEDs on and off */ -// The LEDs bits are upside down in that setting the bit in the debug -// register will turn the appropriate LED off. - -#define YELLOW_LED DEBUG_BIT_0 -#define GREEN_LED DEBUG_BIT_1 -#define YELLOW_LED_OE DEBUG_BIT_0_OE -#define GREEN_LED_OE DEBUG_BIT_1_OE - -#define GREEN_LED_OFF(dev) \ - wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) | GREEN_LED) -#define GREEN_LED_ON(dev) \ - wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) &~ GREEN_LED) -#define YELLOW_LED_OFF(dev) \ - wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) | YELLOW_LED) -#define YELLOW_LED_ON(dev) \ - wr_regl (dev, CONTROL_0_REG, rd_regl (dev, CONTROL_0_REG) &~ YELLOW_LED) - -typedef enum { - round_up, - round_down, - round_nearest -} rounding; - -#endif /* DRIVER_ATM_HORIZON_H */ diff --git a/drivers/atm/uPD98401.h b/drivers/atm/uPD98401.h deleted file mode 100644 index f766a5ef0c5d..000000000000 --- a/drivers/atm/uPD98401.h +++ /dev/null @@ -1,293 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/uPD98401.h - NEC uPD98401 (SAR) declarations */ - -/* Written 1995 by Werner Almesberger, EPFL LRC */ - - -#ifndef DRIVERS_ATM_uPD98401_H -#define DRIVERS_ATM_uPD98401_H - - -#define MAX_CRAM_SIZE (1 << 18) /* 2^18 words */ -#define RAM_INCREMENT 1024 /* check in 4 kB increments */ - -#define uPD98401_PORTS 0x24 /* probably more ? */ - - -/* - * Commands - */ - -#define uPD98401_OPEN_CHAN 0x20000000 /* open channel */ -#define uPD98401_CHAN_ADDR 0x0003fff8 /* channel address */ -#define uPD98401_CHAN_ADDR_SHIFT 3 -#define uPD98401_CLOSE_CHAN 0x24000000 /* close channel */ -#define uPD98401_CHAN_RT 0x02000000 /* RX/TX (0 TX, 1 RX) */ -#define uPD98401_DEACT_CHAN 0x28000000 /* deactivate channel */ -#define uPD98401_TX_READY 0x30000000 /* TX ready */ -#define uPD98401_ADD_BAT 0x34000000 /* add batches */ -#define uPD98401_POOL 0x000f0000 /* pool number */ -#define uPD98401_POOL_SHIFT 16 -#define uPD98401_POOL_NUMBAT 0x0000ffff /* number of batches */ -#define uPD98401_NOP 0x3f000000 /* NOP */ -#define uPD98401_IND_ACC 0x00000000 /* Indirect Access */ -#define uPD98401_IA_RW 0x10000000 /* Read/Write (0 W, 1 R) */ -#define uPD98401_IA_B3 0x08000000 /* Byte select, 1 enable */ -#define uPD98401_IA_B2 0x04000000 -#define uPD98401_IA_B1 0x02000000 -#define uPD98401_IA_B0 0x01000000 -#define uPD98401_IA_BALL 0x0f000000 /* whole longword */ -#define uPD98401_IA_TGT 0x000c0000 /* Target */ -#define uPD98401_IA_TGT_SHIFT 18 -#define uPD98401_IA_TGT_CM 0 /* - Control Memory */ -#define uPD98401_IA_TGT_SAR 1 /* - uPD98401 registers */ -#define uPD98401_IA_TGT_PHY 3 /* - PHY device */ -#define uPD98401_IA_ADDR 0x0003ffff - -/* - * Command Register Status - */ - -#define uPD98401_BUSY 0x80000000 /* SAR is busy */ -#define uPD98401_LOCKED 0x40000000 /* SAR is locked by other CPU */ - -/* - * Indications - */ - -/* Normal (AAL5) Receive Indication */ -#define uPD98401_AAL5_UINFO 0xffff0000 /* user-supplied information */ -#define uPD98401_AAL5_UINFO_SHIFT 16 -#define uPD98401_AAL5_SIZE 0x0000ffff /* PDU size (in _CELLS_ !!) */ -#define uPD98401_AAL5_CHAN 0x7fff0000 /* Channel number */ -#define uPD98401_AAL5_CHAN_SHIFT 16 -#define uPD98401_AAL5_ERR 0x00008000 /* Error indication */ -#define uPD98401_AAL5_CI 0x00004000 /* Congestion Indication */ -#define uPD98401_AAL5_CLP 0x00002000 /* CLP (>= 1 cell had CLP=1) */ -#define uPD98401_AAL5_ES 0x00000f00 /* Error Status */ -#define uPD98401_AAL5_ES_SHIFT 8 -#define uPD98401_AAL5_ES_NONE 0 /* No error */ -#define uPD98401_AAL5_ES_FREE 1 /* Receiver free buf underflow */ -#define uPD98401_AAL5_ES_FIFO 2 /* Receiver FIFO overrun */ -#define uPD98401_AAL5_ES_TOOBIG 3 /* Maximum length violation */ -#define uPD98401_AAL5_ES_CRC 4 /* CRC error */ -#define uPD98401_AAL5_ES_ABORT 5 /* User abort */ -#define uPD98401_AAL5_ES_LENGTH 6 /* Length violation */ -#define uPD98401_AAL5_ES_T1 7 /* T1 error (timeout) */ -#define uPD98401_AAL5_ES_DEACT 8 /* Deactivated with DEACT_CHAN */ -#define uPD98401_AAL5_POOL 0x0000001f /* Free buffer pool number */ - -/* Raw Cell Indication */ -#define uPD98401_RAW_UINFO uPD98401_AAL5_UINFO -#define uPD98401_RAW_UINFO_SHIFT uPD98401_AAL5_UINFO_SHIFT -#define uPD98401_RAW_HEC 0x000000ff /* HEC */ -#define uPD98401_RAW_CHAN uPD98401_AAL5_CHAN -#define uPD98401_RAW_CHAN_SHIFT uPD98401_AAL5_CHAN_SHIFT - -/* Transmit Indication */ -#define uPD98401_TXI_CONN 0x7fff0000 /* Connection Number */ -#define uPD98401_TXI_CONN_SHIFT 16 -#define uPD98401_TXI_ACTIVE 0x00008000 /* Channel remains active */ -#define uPD98401_TXI_PQP 0x00007fff /* Packet Queue Pointer */ - -/* - * Directly Addressable Registers - */ - -#define uPD98401_GMR 0x00 /* General Mode Register */ -#define uPD98401_GSR 0x01 /* General Status Register */ -#define uPD98401_IMR 0x02 /* Interrupt Mask Register */ -#define uPD98401_RQU 0x03 /* Receive Queue Underrun */ -#define uPD98401_RQA 0x04 /* Receive Queue Alert */ -#define uPD98401_ADDR 0x05 /* Last Burst Address */ -#define uPD98401_VER 0x06 /* Version Number */ -#define uPD98401_SWR 0x07 /* Software Reset */ -#define uPD98401_CMR 0x08 /* Command Register */ -#define uPD98401_CMR_L 0x09 /* Command Register and Lock/Unlock */ -#define uPD98401_CER 0x0a /* Command Extension Register */ -#define uPD98401_CER_L 0x0b /* Command Ext Reg and Lock/Unlock */ - -#define uPD98401_MSH(n) (0x10+(n)) /* Mailbox n Start Address High */ -#define uPD98401_MSL(n) (0x14+(n)) /* Mailbox n Start Address High */ -#define uPD98401_MBA(n) (0x18+(n)) /* Mailbox n Bottom Address */ -#define uPD98401_MTA(n) (0x1c+(n)) /* Mailbox n Tail Address */ -#define uPD98401_MWA(n) (0x20+(n)) /* Mailbox n Write Address */ - -/* GMR is at 0x00 */ -#define uPD98401_GMR_ONE 0x80000000 /* Must be set to one */ -#define uPD98401_GMR_SLM 0x40000000 /* Address mode (0 word, 1 byte) */ -#define uPD98401_GMR_CPE 0x00008000 /* Control Memory Parity Enable */ -#define uPD98401_GMR_LP 0x00004000 /* Loopback */ -#define uPD98401_GMR_WA 0x00002000 /* Early Bus Write Abort/RDY */ -#define uPD98401_GMR_RA 0x00001000 /* Early Read Abort/RDY */ -#define uPD98401_GMR_SZ 0x00000f00 /* Burst Size Enable */ -#define uPD98401_BURST16 0x00000800 /* 16-word burst */ -#define uPD98401_BURST8 0x00000400 /* 8-word burst */ -#define uPD98401_BURST4 0x00000200 /* 4-word burst */ -#define uPD98401_BURST2 0x00000100 /* 2-word burst */ -#define uPD98401_GMR_AD 0x00000080 /* Address (burst resolution) Disable */ -#define uPD98401_GMR_BO 0x00000040 /* Byte Order (0 little, 1 big) */ -#define uPD98401_GMR_PM 0x00000020 /* Bus Parity Mode (0 byte, 1 word)*/ -#define uPD98401_GMR_PC 0x00000010 /* Bus Parity Control (0even,1odd) */ -#define uPD98401_GMR_BPE 0x00000008 /* Bus Parity Enable */ -#define uPD98401_GMR_DR 0x00000004 /* Receive Drop Mode (0drop,1don't)*/ -#define uPD98401_GMR_SE 0x00000002 /* Shapers Enable */ -#define uPD98401_GMR_RE 0x00000001 /* Receiver Enable */ - -/* GSR is at 0x01, IMR is at 0x02 */ -#define uPD98401_INT_PI 0x80000000 /* PHY interrupt */ -#define uPD98401_INT_RQA 0x40000000 /* Receive Queue Alert */ -#define uPD98401_INT_RQU 0x20000000 /* Receive Queue Underrun */ -#define uPD98401_INT_RD 0x10000000 /* Receiver Deactivated */ -#define uPD98401_INT_SPE 0x08000000 /* System Parity Error */ -#define uPD98401_INT_CPE 0x04000000 /* Control Memory Parity Error */ -#define uPD98401_INT_SBE 0x02000000 /* System Bus Error */ -#define uPD98401_INT_IND 0x01000000 /* Initialization Done */ -#define uPD98401_INT_RCR 0x0000ff00 /* Raw Cell Received */ -#define uPD98401_INT_RCR_SHIFT 8 -#define uPD98401_INT_MF 0x000000f0 /* Mailbox Full */ -#define uPD98401_INT_MF_SHIFT 4 -#define uPD98401_INT_MM 0x0000000f /* Mailbox Modified */ - -/* VER is at 0x06 */ -#define uPD98401_MAJOR 0x0000ff00 /* Major revision */ -#define uPD98401_MAJOR_SHIFT 8 -#define uPD98401_MINOR 0x000000ff /* Minor revision */ - -/* - * Indirectly Addressable Registers - */ - -#define uPD98401_IM(n) (0x40000+(n)) /* Scheduler n I and M */ -#define uPD98401_X(n) (0x40010+(n)) /* Scheduler n X */ -#define uPD98401_Y(n) (0x40020+(n)) /* Scheduler n Y */ -#define uPD98401_PC(n) (0x40030+(n)) /* Scheduler n P, C, p and c */ -#define uPD98401_PS(n) (0x40040+(n)) /* Scheduler n priority and status */ - -/* IM contents */ -#define uPD98401_IM_I 0xff000000 /* I */ -#define uPD98401_IM_I_SHIFT 24 -#define uPD98401_IM_M 0x00ffffff /* M */ - -/* PC contents */ -#define uPD98401_PC_P 0xff000000 /* P */ -#define uPD98401_PC_P_SHIFT 24 -#define uPD98401_PC_C 0x00ff0000 /* C */ -#define uPD98401_PC_C_SHIFT 16 -#define uPD98401_PC_p 0x0000ff00 /* p */ -#define uPD98401_PC_p_SHIFT 8 -#define uPD98401_PC_c 0x000000ff /* c */ - -/* PS contents */ -#define uPD98401_PS_PRIO 0xf0 /* Priority level (0 high, 15 low) */ -#define uPD98401_PS_PRIO_SHIFT 4 -#define uPD98401_PS_S 0x08 /* Scan - must be 0 (internal) */ -#define uPD98401_PS_R 0x04 /* Round Robin (internal) */ -#define uPD98401_PS_A 0x02 /* Active (internal) */ -#define uPD98401_PS_E 0x01 /* Enabled */ - -#define uPD98401_TOS 0x40100 /* Top of Stack Control Memory Address */ -#define uPD98401_SMA 0x40200 /* Shapers Control Memory Start Address */ -#define uPD98401_PMA 0x40201 /* Receive Pool Control Memory Start Address */ -#define uPD98401_T1R 0x40300 /* T1 Register */ -#define uPD98401_VRR 0x40301 /* VPI/VCI Reduction Register/Recv. Shutdown */ -#define uPD98401_TSR 0x40302 /* Time-Stamp Register */ - -/* VRR is at 0x40301 */ -#define uPD98401_VRR_SDM 0x80000000 /* Shutdown Mode */ -#define uPD98401_VRR_SHIFT 0x000f0000 /* VPI/VCI Shift */ -#define uPD98401_VRR_SHIFT_SHIFT 16 -#define uPD98401_VRR_MASK 0x0000ffff /* VPI/VCI mask */ - -/* - * TX packet descriptor - */ - -#define uPD98401_TXPD_SIZE 16 /* descriptor size (in bytes) */ - -#define uPD98401_TXPD_V 0x80000000 /* Valid bit */ -#define uPD98401_TXPD_DP 0x40000000 /* Descriptor (1) or Pointer (0) */ -#define uPD98401_TXPD_SM 0x20000000 /* Single (1) or Multiple (0) */ -#define uPD98401_TXPD_CLPM 0x18000000 /* CLP mode */ -#define uPD98401_CLPM_0 0 /* 00 CLP = 0 */ -#define uPD98401_CLPM_1 3 /* 11 CLP = 1 */ -#define uPD98401_CLPM_LAST 1 /* 01 CLP unless last cell */ -#define uPD98401_TXPD_CLPM_SHIFT 27 -#define uPD98401_TXPD_PTI 0x07000000 /* PTI pattern */ -#define uPD98401_TXPD_PTI_SHIFT 24 -#define uPD98401_TXPD_GFC 0x00f00000 /* GFC pattern */ -#define uPD98401_TXPD_GFC_SHIFT 20 -#define uPD98401_TXPD_C10 0x00040000 /* insert CRC-10 */ -#define uPD98401_TXPD_AAL5 0x00020000 /* AAL5 processing */ -#define uPD98401_TXPD_MB 0x00010000 /* TX mailbox number */ -#define uPD98401_TXPD_UU 0x0000ff00 /* CPCS-UU */ -#define uPD98401_TXPD_UU_SHIFT 8 -#define uPD98401_TXPD_CPI 0x000000ff /* CPI */ - -/* - * TX buffer descriptor - */ - -#define uPD98401_TXBD_SIZE 8 /* descriptor size (in bytes) */ - -#define uPD98401_TXBD_LAST 0x80000000 /* last buffer in packet */ - -/* - * TX VC table - */ - -/* 1st word has the same structure as in a TX packet descriptor */ -#define uPD98401_TXVC_L 0x80000000 /* last buffer */ -#define uPD98401_TXVC_SHP 0x0f000000 /* shaper number */ -#define uPD98401_TXVC_SHP_SHIFT 24 -#define uPD98401_TXVC_VPI 0x00ff0000 /* VPI */ -#define uPD98401_TXVC_VPI_SHIFT 16 -#define uPD98401_TXVC_VCI 0x0000ffff /* VCI */ -#define uPD98401_TXVC_QRP 6 /* Queue Read Pointer is in word 6 */ - -/* - * RX free buffer pools descriptor - */ - -#define uPD98401_RXFP_ALERT 0x70000000 /* low water mark */ -#define uPD98401_RXFP_ALERT_SHIFT 28 -#define uPD98401_RXFP_BFSZ 0x0f000000 /* buffer size, 64*2^n */ -#define uPD98401_RXFP_BFSZ_SHIFT 24 -#define uPD98401_RXFP_BTSZ 0x00ff0000 /* batch size, n+1 */ -#define uPD98401_RXFP_BTSZ_SHIFT 16 -#define uPD98401_RXFP_REMAIN 0x0000ffff /* remaining batches in pool */ - -/* - * RX VC table - */ - -#define uPD98401_RXVC_BTSZ 0xff000000 /* remaining free buffers in batch */ -#define uPD98401_RXVC_BTSZ_SHIFT 24 -#define uPD98401_RXVC_MB 0x00200000 /* RX mailbox number */ -#define uPD98401_RXVC_POOL 0x001f0000 /* free buffer pool number */ -#define uPD98401_RXVC_POOL_SHIFT 16 -#define uPD98401_RXVC_UINFO 0x0000ffff /* user-supplied information */ -#define uPD98401_RXVC_T1 0xffff0000 /* T1 timestamp */ -#define uPD98401_RXVC_T1_SHIFT 16 -#define uPD98401_RXVC_PR 0x00008000 /* Packet Reception, 1 if busy */ -#define uPD98401_RXVC_DR 0x00004000 /* FIFO Drop */ -#define uPD98401_RXVC_OD 0x00001000 /* Drop OAM cells */ -#define uPD98401_RXVC_AR 0x00000800 /* AAL5 or raw cell; 1 if AAL5 */ -#define uPD98401_RXVC_MAXSEG 0x000007ff /* max number of segments per PDU */ -#define uPD98401_RXVC_REM 0xfffe0000 /* remaining words in curr buffer */ -#define uPD98401_RXVC_REM_SHIFT 17 -#define uPD98401_RXVC_CLP 0x00010000 /* CLP received */ -#define uPD98401_RXVC_BFA 0x00008000 /* Buffer Assigned */ -#define uPD98401_RXVC_BTA 0x00004000 /* Batch Assigned */ -#define uPD98401_RXVC_CI 0x00002000 /* Congestion Indication */ -#define uPD98401_RXVC_DD 0x00001000 /* Dropping incoming cells */ -#define uPD98401_RXVC_DP 0x00000800 /* like PR ? */ -#define uPD98401_RXVC_CURSEG 0x000007ff /* Current Segment count */ - -/* - * RX lookup table - */ - -#define uPD98401_RXLT_ENBL 0x8000 /* Enable */ - -#endif diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c deleted file mode 100644 index 239852d85558..000000000000 --- a/drivers/atm/uPD98402.c +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */ - -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "uPD98402.h" - - -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - - -struct uPD98402_priv { - struct k_sonet_stats sonet_stats;/* link diagnostics */ - unsigned char framing; /* SONET/SDH framing */ - int loop_mode; /* loopback mode */ - spinlock_t lock; -}; - - -#define PRIV(dev) ((struct uPD98402_priv *) dev->phy_data) - -#define PUT(val,reg) dev->ops->phy_put(dev,val,uPD98402_##reg) -#define GET(reg) dev->ops->phy_get(dev,uPD98402_##reg) - - -static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero) -{ - struct sonet_stats tmp; - int error = 0; - - atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs); - sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp); - if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); - if (zero && !error) { - /* unused fields are reported as -1, but we must not "adjust" - them */ - tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0; - sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp); - } - return error ? -EFAULT : 0; -} - - -static int set_framing(struct atm_dev *dev,unsigned char framing) -{ - static const unsigned char sonet[] = { 1,2,3,0 }; - static const unsigned char sdh[] = { 1,0,0,2 }; - const char *set; - unsigned long flags; - - switch (framing) { - case SONET_FRAME_SONET: - set = sonet; - break; - case SONET_FRAME_SDH: - set = sdh; - break; - default: - return -EINVAL; - } - spin_lock_irqsave(&PRIV(dev)->lock, flags); - PUT(set[0],C11T); - PUT(set[1],C12T); - PUT(set[2],C13T); - PUT((GET(MDR) & ~uPD98402_MDR_SS_MASK) | (set[3] << - uPD98402_MDR_SS_SHIFT),MDR); - spin_unlock_irqrestore(&PRIV(dev)->lock, flags); - return 0; -} - - -static int get_sense(struct atm_dev *dev,u8 __user *arg) -{ - unsigned long flags; - unsigned char s[3]; - - spin_lock_irqsave(&PRIV(dev)->lock, flags); - s[0] = GET(C11R); - s[1] = GET(C12R); - s[2] = GET(C13R); - spin_unlock_irqrestore(&PRIV(dev)->lock, flags); - return (put_user(s[0], arg) || put_user(s[1], arg+1) || - put_user(s[2], arg+2) || put_user(0xff, arg+3) || - put_user(0xff, arg+4) || put_user(0xff, arg+5)) ? -EFAULT : 0; -} - - -static int set_loopback(struct atm_dev *dev,int mode) -{ - unsigned char mode_reg; - - mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP | - uPD98402_MDR_RPLP); - switch (__ATM_LM_XTLOC(mode)) { - case __ATM_LM_NONE: - break; - case __ATM_LM_PHY: - mode_reg |= uPD98402_MDR_TPLP; - break; - case __ATM_LM_ATM: - mode_reg |= uPD98402_MDR_ALP; - break; - default: - return -EINVAL; - } - switch (__ATM_LM_XTRMT(mode)) { - case __ATM_LM_NONE: - break; - case __ATM_LM_PHY: - mode_reg |= uPD98402_MDR_RPLP; - break; - default: - return -EINVAL; - } - PUT(mode_reg,MDR); - PRIV(dev)->loop_mode = mode; - return 0; -} - - -static int uPD98402_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_SETFRAMING: - return set_framing(dev, (int)(unsigned long)arg); - case SONET_GETFRAMING: - return put_user(PRIV(dev)->framing,(int __user *)arg) ? - -EFAULT : 0; - case SONET_GETFRSENSE: - return get_sense(dev,arg); - 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_PHY | ATM_LM_LOC_ATM | - ATM_LM_RMT_PHY,(int __user *)arg) ? -EFAULT : 0; - default: - return -ENOIOCTLCMD; - } -} - - -#define ADD_LIMITED(s,v) \ - { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \ - if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \ - atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); } - - -static void stat_event(struct atm_dev *dev) -{ - unsigned char events; - - events = GET(PCR); - if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB); - if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT); - if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT); - if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT); - if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT); -} - - -#undef ADD_LIMITED - - -static void uPD98402_int(struct atm_dev *dev) -{ - static unsigned long silence = 0; - unsigned char reason; - - while ((reason = GET(PICR))) { - if (reason & uPD98402_INT_LOS) - printk(KERN_NOTICE "%s(itf %d): signal lost\n", - dev->type,dev->number); - if (reason & uPD98402_INT_PFM) stat_event(dev); - if (reason & uPD98402_INT_PCO) { - (void) GET(PCOCR); /* clear interrupt cause */ - atomic_add(GET(HECCT), - &PRIV(dev)->sonet_stats.uncorr_hcs); - } - if ((reason & uPD98402_INT_RFO) && - (time_after(jiffies, silence) || silence == 0)) { - printk(KERN_WARNING "%s(itf %d): uPD98402 receive " - "FIFO overflow\n",dev->type,dev->number); - silence = (jiffies+HZ/2)|1; - } - } -} - - -static int uPD98402_start(struct atm_dev *dev) -{ - DPRINTK("phy_start\n"); - if (!(dev->phy_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) - return -ENOMEM; - spin_lock_init(&PRIV(dev)->lock); - memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats)); - (void) GET(PCR); /* clear performance events */ - PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */ - (void) GET(PCOCR); /* clear overflows */ - PUT(~uPD98402_PCO_HECC,PCOMR); - (void) GET(PICR); /* clear interrupts */ - PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO | - uPD98402_INT_LOS),PIMR); /* enable them */ - (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ - atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1); - atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1); - atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1); - return 0; -} - - -static int uPD98402_stop(struct atm_dev *dev) -{ - /* let SAR driver worry about stopping interrupts */ - kfree(PRIV(dev)); - return 0; -} - - -static const struct atmphy_ops uPD98402_ops = { - .start = uPD98402_start, - .ioctl = uPD98402_ioctl, - .interrupt = uPD98402_int, - .stop = uPD98402_stop, -}; - - -int uPD98402_init(struct atm_dev *dev) -{ -DPRINTK("phy_init\n"); - dev->phy = &uPD98402_ops; - return 0; -} - - -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(uPD98402_init); - -static __init int uPD98402_module_init(void) -{ - return 0; -} -module_init(uPD98402_module_init); -/* module_exit not defined so not unloadable */ diff --git a/drivers/atm/uPD98402.h b/drivers/atm/uPD98402.h deleted file mode 100644 index 437cfaa20c96..000000000000 --- a/drivers/atm/uPD98402.h +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/uPD98402.h - NEC uPD98402 (PHY) declarations */ - -/* Written 1995 by Werner Almesberger, EPFL LRC */ - - -#ifndef DRIVERS_ATM_uPD98402_H -#define DRIVERS_ATM_uPD98402_H - -/* - * Registers - */ - -#define uPD98402_CMR 0x00 /* Command Register */ -#define uPD98402_MDR 0x01 /* Mode Register */ -#define uPD98402_PICR 0x02 /* PHY Interrupt Cause Register */ -#define uPD98402_PIMR 0x03 /* PHY Interrupt Mask Register */ -#define uPD98402_ACR 0x04 /* Alarm Cause Register */ -#define uPD98402_ACMR 0x05 /* Alarm Cause Mask Register */ -#define uPD98402_PCR 0x06 /* Performance Cause Register */ -#define uPD98402_PCMR 0x07 /* Performance Cause Mask Register */ -#define uPD98402_IACM 0x08 /* Internal Alarm Cause Mask Register */ -#define uPD98402_B1ECT 0x09 /* B1 Error Count Register */ -#define uPD98402_B2ECT 0x0a /* B2 Error Count Register */ -#define uPD98402_B3ECT 0x0b /* B3 Error Count Regster */ -#define uPD98402_PFECB 0x0c /* Path FEBE Count Register */ -#define uPD98402_LECCT 0x0d /* Line FEBE Count Register */ -#define uPD98402_HECCT 0x0e /* HEC Error Count Register */ -#define uPD98402_FJCT 0x0f /* Frequence Justification Count Reg */ -#define uPD98402_PCOCR 0x10 /* Perf. Counter Overflow Cause Reg */ -#define uPD98402_PCOMR 0x11 /* Perf. Counter Overflow Mask Reg */ -#define uPD98402_C11T 0x20 /* C11T Data Register */ -#define uPD98402_C12T 0x21 /* C12T Data Register */ -#define uPD98402_C13T 0x22 /* C13T Data Register */ -#define uPD98402_F1T 0x23 /* F1T Data Register */ -#define uPD98402_K2T 0x25 /* K2T Data Register */ -#define uPD98402_C2T 0x26 /* C2T Data Register */ -#define uPD98402_F2T 0x27 /* F2T Data Register */ -#define uPD98402_C11R 0x30 /* C11T Data Register */ -#define uPD98402_C12R 0x31 /* C12T Data Register */ -#define uPD98402_C13R 0x32 /* C13T Data Register */ -#define uPD98402_F1R 0x33 /* F1T Data Register */ -#define uPD98402_K2R 0x35 /* K2T Data Register */ -#define uPD98402_C2R 0x36 /* C2T Data Register */ -#define uPD98402_F2R 0x37 /* F2T Data Register */ - -/* CMR is at 0x00 */ -#define uPD98402_CMR_PFRF 0x01 /* Send path FERF */ -#define uPD98402_CMR_LFRF 0x02 /* Send line FERF */ -#define uPD98402_CMR_PAIS 0x04 /* Send path AIS */ -#define uPD98402_CMR_LAIS 0x08 /* Send line AIS */ - -/* MDR is at 0x01 */ -#define uPD98402_MDR_ALP 0x01 /* ATM layer loopback */ -#define uPD98402_MDR_TPLP 0x02 /* PMD loopback, to host */ -#define uPD98402_MDR_RPLP 0x04 /* PMD loopback, to network */ -#define uPD98402_MDR_SS0 0x08 /* SS0 */ -#define uPD98402_MDR_SS1 0x10 /* SS1 */ -#define uPD98402_MDR_SS_MASK 0x18 /* mask */ -#define uPD98402_MDR_SS_SHIFT 3 /* shift */ -#define uPD98402_MDR_HEC 0x20 /* disable HEC inbound processing */ -#define uPD98402_MDR_FSR 0x40 /* disable frame scrambler */ -#define uPD98402_MDR_CSR 0x80 /* disable cell scrambler */ - -/* PICR is at 0x02, PIMR is at 0x03 */ -#define uPD98402_INT_PFM 0x01 /* performance counter has changed */ -#define uPD98402_INT_ALM 0x02 /* line fault */ -#define uPD98402_INT_RFO 0x04 /* receive FIFO overflow */ -#define uPD98402_INT_PCO 0x08 /* performance counter overflow */ -#define uPD98402_INT_OTD 0x20 /* OTD has occurred */ -#define uPD98402_INT_LOS 0x40 /* Loss Of Signal */ -#define uPD98402_INT_LOF 0x80 /* Loss Of Frame */ - -/* ACR is as 0x04, ACMR is at 0x05 */ -#define uPD98402_ALM_PFRF 0x01 /* path FERF */ -#define uPD98402_ALM_LFRF 0x02 /* line FERF */ -#define uPD98402_ALM_PAIS 0x04 /* path AIS */ -#define uPD98402_ALM_LAIS 0x08 /* line AIS */ -#define uPD98402_ALM_LOD 0x10 /* loss of delineation */ -#define uPD98402_ALM_LOP 0x20 /* loss of pointer */ -#define uPD98402_ALM_OOF 0x40 /* out of frame */ - -/* PCR is at 0x06, PCMR is at 0x07 */ -#define uPD98402_PFM_PFEB 0x01 /* path FEBE */ -#define uPD98402_PFM_LFEB 0x02 /* line FEBE */ -#define uPD98402_PFM_B3E 0x04 /* B3 error */ -#define uPD98402_PFM_B2E 0x08 /* B2 error */ -#define uPD98402_PFM_B1E 0x10 /* B1 error */ -#define uPD98402_PFM_FJ 0x20 /* frequency justification */ - -/* IACM is at 0x08 */ -#define uPD98402_IACM_PFRF 0x01 /* don't generate path FERF */ -#define uPD98402_IACM_LFRF 0x02 /* don't generate line FERF */ - -/* PCOCR is at 0x010, PCOMR is at 0x11 */ -#define uPD98402_PCO_B1EC 0x01 /* B1ECT overflow */ -#define uPD98402_PCO_B2EC 0x02 /* B2ECT overflow */ -#define uPD98402_PCO_B3EC 0x04 /* B3ECT overflow */ -#define uPD98402_PCO_PFBC 0x08 /* PFEBC overflow */ -#define uPD98402_PCO_LFBC 0x10 /* LFEVC overflow */ -#define uPD98402_PCO_HECC 0x20 /* HECCT overflow */ -#define uPD98402_PCO_FJC 0x40 /* FJCT overflow */ - - -int uPD98402_init(struct atm_dev *dev); - -#endif diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c deleted file mode 100644 index cf5fffcf98a1..000000000000 --- a/drivers/atm/zatm.c +++ /dev/null @@ -1,1652 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* drivers/atm/zatm.c - ZeitNet ZN122x 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 -#include -#include -#include -#include - -#include "uPD98401.h" -#include "uPD98402.h" -#include "zeprom.h" -#include "zatm.h" - - -/* - * TODO: - * - * Minor features - * - support 64 kB SDUs (will have to use multibuffer batches then :-( ) - * - proper use of CDV, credit = max(1,CDVT*PCR) - * - AAL0 - * - better receive timestamps - * - OAM - */ - -#define ZATM_COPPER 1 - -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - -#ifndef CONFIG_ATM_ZATM_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%x\n", (int) (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; - - printk(KERN_NOTICE "----- event dump follows -----\n"); - 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]); - } - printk(KERN_NOTICE "----- event dump ends here -----\n"); -} - - -#endif /* CONFIG_ATM_ZATM_DEBUG */ - - -#define RING_BUSY 1 /* indication from do_tx that PDU has to be - backlogged */ - -static struct atm_dev *zatm_boards = NULL; -static unsigned long dummy[2] = {0,0}; - - -#define zin_n(r) inl(zatm_dev->base+r*4) -#define zin(r) inl(zatm_dev->base+uPD98401_##r*4) -#define zout(v,r) outl(v,zatm_dev->base+uPD98401_##r*4) -#define zwait() do {} while (zin(CMR) & uPD98401_BUSY) - -/* RX0, RX1, TX0, TX1 */ -static const int mbx_entries[NR_MBX] = { 1024,1024,1024,1024 }; -static const int mbx_esize[NR_MBX] = { 16,16,4,4 }; /* entry size in bytes */ - -#define MBX_SIZE(i) (mbx_entries[i]*mbx_esize[i]) - - -/*-------------------------------- utilities --------------------------------*/ - - -static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr) -{ - zwait(); - zout(value,CER); - zout(uPD98401_IND_ACC | uPD98401_IA_BALL | - (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); -} - - -static u32 zpeekl(struct zatm_dev *zatm_dev,u32 addr) -{ - zwait(); - zout(uPD98401_IND_ACC | uPD98401_IA_BALL | uPD98401_IA_RW | - (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); - zwait(); - return zin(CER); -} - - -/*------------------------------- free lists --------------------------------*/ - - -/* - * Free buffer head structure: - * [0] pointer to buffer (for SAR) - * [1] buffer descr link pointer (for SAR) - * [2] back pointer to skb (for poll_rx) - * [3] data - * ... - */ - -struct rx_buffer_head { - u32 buffer; /* pointer to buffer (for SAR) */ - u32 link; /* buffer descriptor link pointer (for SAR) */ - struct sk_buff *skb; /* back pointer to skb (for poll_rx) */ -}; - - -static void refill_pool(struct atm_dev *dev,int pool) -{ - struct zatm_dev *zatm_dev; - struct sk_buff *skb; - struct rx_buffer_head *first; - unsigned long flags; - int align,offset,free,count,size; - - EVENT("refill_pool\n",0,0); - zatm_dev = ZATM_DEV(dev); - size = (64 << (pool <= ZATM_AAL5_POOL_BASE ? 0 : - pool-ZATM_AAL5_POOL_BASE))+sizeof(struct rx_buffer_head); - if (size < PAGE_SIZE) { - align = 32; /* for 32 byte alignment */ - offset = sizeof(struct rx_buffer_head); - } - else { - align = 4096; - offset = zatm_dev->pool_info[pool].offset+ - sizeof(struct rx_buffer_head); - } - size += align; - spin_lock_irqsave(&zatm_dev->lock, flags); - free = zpeekl(zatm_dev,zatm_dev->pool_base+2*pool) & - uPD98401_RXFP_REMAIN; - spin_unlock_irqrestore(&zatm_dev->lock, flags); - if (free >= zatm_dev->pool_info[pool].low_water) return; - EVENT("starting ... POOL: 0x%x, 0x%x\n", - zpeekl(zatm_dev,zatm_dev->pool_base+2*pool), - zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1)); - EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); - count = 0; - first = NULL; - while (free < zatm_dev->pool_info[pool].high_water) { - struct rx_buffer_head *head; - - skb = alloc_skb(size,GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING DEV_LABEL "(Itf %d): got no new " - "skb (%d) with %d free\n",dev->number,size,free); - break; - } - skb_reserve(skb,(unsigned char *) ((((unsigned long) skb->data+ - align+offset-1) & ~(unsigned long) (align-1))-offset)- - skb->data); - head = (struct rx_buffer_head *) skb->data; - skb_reserve(skb,sizeof(struct rx_buffer_head)); - if (!first) first = head; - count++; - head->buffer = virt_to_bus(skb->data); - head->link = 0; - head->skb = skb; - EVENT("enq skb 0x%08lx/0x%08lx\n",(unsigned long) skb, - (unsigned long) head); - spin_lock_irqsave(&zatm_dev->lock, flags); - if (zatm_dev->last_free[pool]) - ((struct rx_buffer_head *) (zatm_dev->last_free[pool]-> - data))[-1].link = virt_to_bus(head); - zatm_dev->last_free[pool] = skb; - skb_queue_tail(&zatm_dev->pool[pool],skb); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - free++; - } - if (first) { - spin_lock_irqsave(&zatm_dev->lock, flags); - zwait(); - zout(virt_to_bus(first),CER); - zout(uPD98401_ADD_BAT | (pool << uPD98401_POOL_SHIFT) | count, - CMR); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - EVENT ("POOL: 0x%x, 0x%x\n", - zpeekl(zatm_dev,zatm_dev->pool_base+2*pool), - zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1)); - EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); - } -} - - -static void drain_free(struct atm_dev *dev,int pool) -{ - skb_queue_purge(&ZATM_DEV(dev)->pool[pool]); -} - - -static int pool_index(int max_pdu) -{ - int i; - - if (max_pdu % ATM_CELL_PAYLOAD) - printk(KERN_ERR DEV_LABEL ": driver error in pool_index: " - "max_pdu is %d\n",max_pdu); - if (max_pdu > 65536) return -1; - for (i = 0; (64 << i) < max_pdu; i++); - return i+ZATM_AAL5_POOL_BASE; -} - - -/* use_pool isn't reentrant */ - - -static void use_pool(struct atm_dev *dev,int pool) -{ - struct zatm_dev *zatm_dev; - unsigned long flags; - int size; - - zatm_dev = ZATM_DEV(dev); - if (!(zatm_dev->pool_info[pool].ref_count++)) { - skb_queue_head_init(&zatm_dev->pool[pool]); - size = pool-ZATM_AAL5_POOL_BASE; - if (size < 0) size = 0; /* 64B... */ - else if (size > 10) size = 10; /* ... 64kB */ - spin_lock_irqsave(&zatm_dev->lock, flags); - zpokel(zatm_dev,((zatm_dev->pool_info[pool].low_water/4) << - uPD98401_RXFP_ALERT_SHIFT) | - (1 << uPD98401_RXFP_BTSZ_SHIFT) | - (size << uPD98401_RXFP_BFSZ_SHIFT), - zatm_dev->pool_base+pool*2); - zpokel(zatm_dev,(unsigned long) dummy,zatm_dev->pool_base+ - pool*2+1); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - zatm_dev->last_free[pool] = NULL; - refill_pool(dev,pool); - } - DPRINTK("pool %d: %d\n",pool,zatm_dev->pool_info[pool].ref_count); -} - - -static void unuse_pool(struct atm_dev *dev,int pool) -{ - if (!(--ZATM_DEV(dev)->pool_info[pool].ref_count)) - drain_free(dev,pool); -} - -/*----------------------------------- RX ------------------------------------*/ - - -#if 0 -static void exception(struct atm_vcc *vcc) -{ - static int count = 0; - struct zatm_dev *zatm_dev = ZATM_DEV(vcc->dev); - struct zatm_vcc *zatm_vcc = ZATM_VCC(vcc); - unsigned long *qrp; - int i; - - if (count++ > 2) return; - for (i = 0; i < 8; i++) - printk("TX%d: 0x%08lx\n",i, - zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+i)); - for (i = 0; i < 5; i++) - printk("SH%d: 0x%08lx\n",i, - zpeekl(zatm_dev,uPD98401_IM(zatm_vcc->shaper)+16*i)); - qrp = (unsigned long *) zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+ - uPD98401_TXVC_QRP); - printk("qrp=0x%08lx\n",(unsigned long) qrp); - for (i = 0; i < 4; i++) printk("QRP[%d]: 0x%08lx",i,qrp[i]); -} -#endif - - -static const char *err_txt[] = { - "No error", - "RX buf underflow", - "RX FIFO overrun", - "Maximum len violation", - "CRC error", - "User abort", - "Length violation", - "T1 error", - "Deactivated", - "???", - "???", - "???", - "???", - "???", - "???", - "???" -}; - - -static void poll_rx(struct atm_dev *dev,int mbx) -{ - struct zatm_dev *zatm_dev; - unsigned long pos; - u32 x; - int error; - - EVENT("poll_rx\n",0,0); - zatm_dev = ZATM_DEV(dev); - pos = (zatm_dev->mbx_start[mbx] & ~0xffffUL) | zin(MTA(mbx)); - while (x = zin(MWA(mbx)), (pos & 0xffff) != x) { - u32 *here; - struct sk_buff *skb; - struct atm_vcc *vcc; - int cells,size,chan; - - EVENT("MBX: host 0x%lx, nic 0x%x\n",pos,x); - here = (u32 *) pos; - if (((pos += 16) & 0xffff) == zatm_dev->mbx_end[mbx]) - pos = zatm_dev->mbx_start[mbx]; - cells = here[0] & uPD98401_AAL5_SIZE; -#if 0 -printk("RX IND: 0x%x, 0x%x, 0x%x, 0x%x\n",here[0],here[1],here[2],here[3]); -{ -unsigned long *x; - printk("POOL: 0x%08x, 0x%08x\n",zpeekl(zatm_dev, - zatm_dev->pool_base), - zpeekl(zatm_dev,zatm_dev->pool_base+1)); - x = (unsigned long *) here[2]; - printk("[0..3] = 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n", - x[0],x[1],x[2],x[3]); -} -#endif - error = 0; - if (here[3] & uPD98401_AAL5_ERR) { - error = (here[3] & uPD98401_AAL5_ES) >> - uPD98401_AAL5_ES_SHIFT; - if (error == uPD98401_AAL5_ES_DEACT || - error == uPD98401_AAL5_ES_FREE) continue; - } -EVENT("error code 0x%x/0x%x\n",(here[3] & uPD98401_AAL5_ES) >> - uPD98401_AAL5_ES_SHIFT,error); - skb = ((struct rx_buffer_head *) bus_to_virt(here[2]))->skb; - __net_timestamp(skb); -#if 0 -printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3], - ((unsigned *) skb->data)[-2],((unsigned *) skb->data)[-1], - ((unsigned *) skb->data)[0]); -#endif - EVENT("skb 0x%lx, here 0x%lx\n",(unsigned long) skb, - (unsigned long) here); -#if 0 -printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); -#endif - size = error ? 0 : ntohs(((__be16 *) skb->data)[cells* - ATM_CELL_PAYLOAD/sizeof(u16)-3]); - EVENT("got skb 0x%lx, size %d\n",(unsigned long) skb,size); - chan = (here[3] & uPD98401_AAL5_CHAN) >> - uPD98401_AAL5_CHAN_SHIFT; - if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) { - int pos; - vcc = zatm_dev->rx_map[chan]; - pos = ZATM_VCC(vcc)->pool; - if (skb == zatm_dev->last_free[pos]) - zatm_dev->last_free[pos] = NULL; - skb_unlink(skb, zatm_dev->pool + pos); - } - else { - printk(KERN_ERR DEV_LABEL "(itf %d): RX indication " - "for non-existing channel\n",dev->number); - size = 0; - vcc = NULL; - event_dump(); - } - if (error) { - static unsigned long silence = 0; - static int last_error = 0; - - if (error != last_error || - time_after(jiffies, silence) || silence == 0){ - printk(KERN_WARNING DEV_LABEL "(itf %d): " - "chan %d error %s\n",dev->number,chan, - err_txt[error]); - last_error = error; - silence = (jiffies+2*HZ)|1; - } - size = 0; - } - if (size && (size > cells*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER || - size <= (cells-1)*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER)) { - printk(KERN_ERR DEV_LABEL "(itf %d): size %d with %d " - "cells\n",dev->number,size,cells); - size = 0; - event_dump(); - } - if (size > ATM_MAX_AAL5_PDU) { - printk(KERN_ERR DEV_LABEL "(itf %d): size too big " - "(%d)\n",dev->number,size); - size = 0; - event_dump(); - } - if (!size) { - dev_kfree_skb_irq(skb); - if (vcc) atomic_inc(&vcc->stats->rx_err); - continue; - } - if (!atm_charge(vcc,skb->truesize)) { - dev_kfree_skb_irq(skb); - continue; - } - skb->len = size; - ATM_SKB(skb)->vcc = vcc; - vcc->push(vcc,skb); - atomic_inc(&vcc->stats->rx); - } - zout(pos & 0xffff,MTA(mbx)); -#if 0 /* probably a stupid idea */ - refill_pool(dev,zatm_vcc->pool); - /* maybe this saves us a few interrupts */ -#endif -} - - -static int open_rx_first(struct atm_vcc *vcc) -{ - struct zatm_dev *zatm_dev; - struct zatm_vcc *zatm_vcc; - unsigned long flags; - unsigned short chan; - int cells; - - DPRINTK("open_rx_first (0x%x)\n",inb_p(0xc053)); - zatm_dev = ZATM_DEV(vcc->dev); - zatm_vcc = ZATM_VCC(vcc); - zatm_vcc->rx_chan = 0; - if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; - if (vcc->qos.aal == ATM_AAL5) { - if (vcc->qos.rxtp.max_sdu > 65464) - vcc->qos.rxtp.max_sdu = 65464; - /* fix this - we may want to receive 64kB SDUs - later */ - cells = DIV_ROUND_UP(vcc->qos.rxtp.max_sdu + ATM_AAL5_TRAILER, - ATM_CELL_PAYLOAD); - zatm_vcc->pool = pool_index(cells*ATM_CELL_PAYLOAD); - } - else { - cells = 1; - zatm_vcc->pool = ZATM_AAL0_POOL; - } - if (zatm_vcc->pool < 0) return -EMSGSIZE; - spin_lock_irqsave(&zatm_dev->lock, flags); - zwait(); - zout(uPD98401_OPEN_CHAN,CMR); - zwait(); - DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); - chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; - spin_unlock_irqrestore(&zatm_dev->lock, flags); - DPRINTK("chan is %d\n",chan); - if (!chan) return -EAGAIN; - use_pool(vcc->dev,zatm_vcc->pool); - DPRINTK("pool %d\n",zatm_vcc->pool); - /* set up VC descriptor */ - spin_lock_irqsave(&zatm_dev->lock, flags); - zpokel(zatm_dev,zatm_vcc->pool << uPD98401_RXVC_POOL_SHIFT, - chan*VC_SIZE/4); - zpokel(zatm_dev,uPD98401_RXVC_OD | (vcc->qos.aal == ATM_AAL5 ? - uPD98401_RXVC_AR : 0) | cells,chan*VC_SIZE/4+1); - zpokel(zatm_dev,0,chan*VC_SIZE/4+2); - zatm_vcc->rx_chan = chan; - zatm_dev->rx_map[chan] = vcc; - spin_unlock_irqrestore(&zatm_dev->lock, flags); - return 0; -} - - -static int open_rx_second(struct atm_vcc *vcc) -{ - struct zatm_dev *zatm_dev; - struct zatm_vcc *zatm_vcc; - unsigned long flags; - int pos,shift; - - DPRINTK("open_rx_second (0x%x)\n",inb_p(0xc053)); - zatm_dev = ZATM_DEV(vcc->dev); - zatm_vcc = ZATM_VCC(vcc); - if (!zatm_vcc->rx_chan) return 0; - spin_lock_irqsave(&zatm_dev->lock, flags); - /* should also handle VPI @@@ */ - pos = vcc->vci >> 1; - shift = (1-(vcc->vci & 1)) << 4; - zpokel(zatm_dev,(zpeekl(zatm_dev,pos) & ~(0xffff << shift)) | - ((zatm_vcc->rx_chan | uPD98401_RXLT_ENBL) << shift),pos); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - return 0; -} - - -static void close_rx(struct atm_vcc *vcc) -{ - struct zatm_dev *zatm_dev; - struct zatm_vcc *zatm_vcc; - unsigned long flags; - int pos,shift; - - zatm_vcc = ZATM_VCC(vcc); - zatm_dev = ZATM_DEV(vcc->dev); - if (!zatm_vcc->rx_chan) return; - DPRINTK("close_rx\n"); - /* disable receiver */ - if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) { - spin_lock_irqsave(&zatm_dev->lock, flags); - pos = vcc->vci >> 1; - shift = (1-(vcc->vci & 1)) << 4; - zpokel(zatm_dev,zpeekl(zatm_dev,pos) & ~(0xffff << shift),pos); - zwait(); - zout(uPD98401_NOP,CMR); - zwait(); - zout(uPD98401_NOP,CMR); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - } - spin_lock_irqsave(&zatm_dev->lock, flags); - zwait(); - zout(uPD98401_DEACT_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << - uPD98401_CHAN_ADDR_SHIFT),CMR); - zwait(); - udelay(10); /* why oh why ... ? */ - zout(uPD98401_CLOSE_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << - uPD98401_CHAN_ADDR_SHIFT),CMR); - zwait(); - if (!(zin(CMR) & uPD98401_CHAN_ADDR)) - printk(KERN_CRIT DEV_LABEL "(itf %d): can't close RX channel " - "%d\n",vcc->dev->number,zatm_vcc->rx_chan); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - zatm_dev->rx_map[zatm_vcc->rx_chan] = NULL; - zatm_vcc->rx_chan = 0; - unuse_pool(vcc->dev,zatm_vcc->pool); -} - - -static int start_rx(struct atm_dev *dev) -{ - struct zatm_dev *zatm_dev; - int i; - - DPRINTK("start_rx\n"); - zatm_dev = ZATM_DEV(dev); - zatm_dev->rx_map = kcalloc(zatm_dev->chans, - sizeof(*zatm_dev->rx_map), - GFP_KERNEL); - if (!zatm_dev->rx_map) return -ENOMEM; - /* set VPI/VCI split (use all VCIs and give what's left to VPIs) */ - zpokel(zatm_dev,(1 << dev->ci_range.vci_bits)-1,uPD98401_VRR); - /* prepare free buffer pools */ - for (i = 0; i <= ZATM_LAST_POOL; i++) { - zatm_dev->pool_info[i].ref_count = 0; - zatm_dev->pool_info[i].rqa_count = 0; - zatm_dev->pool_info[i].rqu_count = 0; - zatm_dev->pool_info[i].low_water = LOW_MARK; - zatm_dev->pool_info[i].high_water = HIGH_MARK; - zatm_dev->pool_info[i].offset = 0; - zatm_dev->pool_info[i].next_off = 0; - zatm_dev->pool_info[i].next_cnt = 0; - zatm_dev->pool_info[i].next_thres = OFF_CNG_THRES; - } - return 0; -} - - -/*----------------------------------- TX ------------------------------------*/ - - -static int do_tx(struct sk_buff *skb) -{ - struct atm_vcc *vcc; - struct zatm_dev *zatm_dev; - struct zatm_vcc *zatm_vcc; - u32 *dsc; - unsigned long flags; - - EVENT("do_tx\n",0,0); - DPRINTK("sending skb %p\n",skb); - vcc = ATM_SKB(skb)->vcc; - zatm_dev = ZATM_DEV(vcc->dev); - zatm_vcc = ZATM_VCC(vcc); - EVENT("iovcnt=%d\n",skb_shinfo(skb)->nr_frags,0); - spin_lock_irqsave(&zatm_dev->lock, flags); - if (!skb_shinfo(skb)->nr_frags) { - if (zatm_vcc->txing == RING_ENTRIES-1) { - spin_unlock_irqrestore(&zatm_dev->lock, flags); - return RING_BUSY; - } - zatm_vcc->txing++; - dsc = zatm_vcc->ring+zatm_vcc->ring_curr; - zatm_vcc->ring_curr = (zatm_vcc->ring_curr+RING_WORDS) & - (RING_ENTRIES*RING_WORDS-1); - dsc[1] = 0; - dsc[2] = skb->len; - dsc[3] = virt_to_bus(skb->data); - mb(); - dsc[0] = uPD98401_TXPD_V | uPD98401_TXPD_DP | uPD98401_TXPD_SM - | (vcc->qos.aal == ATM_AAL5 ? uPD98401_TXPD_AAL5 : 0 | - (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? - uPD98401_CLPM_1 : uPD98401_CLPM_0)); - EVENT("dsc (0x%lx)\n",(unsigned long) dsc,0); - } - else { -printk("NONONONOO!!!!\n"); - dsc = NULL; -#if 0 - u32 *put; - int i; - - dsc = kmalloc(uPD98401_TXPD_SIZE * 2 + - uPD98401_TXBD_SIZE * ATM_SKB(skb)->iovcnt, GFP_ATOMIC); - if (!dsc) { - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_irq(skb); - return -EAGAIN; - } - /* @@@ should check alignment */ - put = dsc+8; - dsc[0] = uPD98401_TXPD_V | uPD98401_TXPD_DP | - (vcc->aal == ATM_AAL5 ? uPD98401_TXPD_AAL5 : 0 | - (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? - uPD98401_CLPM_1 : uPD98401_CLPM_0)); - dsc[1] = 0; - dsc[2] = ATM_SKB(skb)->iovcnt * uPD98401_TXBD_SIZE; - dsc[3] = virt_to_bus(put); - for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) { - *put++ = ((struct iovec *) skb->data)[i].iov_len; - *put++ = virt_to_bus(((struct iovec *) - skb->data)[i].iov_base); - } - put[-2] |= uPD98401_TXBD_LAST; -#endif - } - ZATM_PRV_DSC(skb) = dsc; - skb_queue_tail(&zatm_vcc->tx_queue,skb); - DPRINTK("QRP=0x%08lx\n",zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+ - uPD98401_TXVC_QRP)); - zwait(); - zout(uPD98401_TX_READY | (zatm_vcc->tx_chan << - uPD98401_CHAN_ADDR_SHIFT),CMR); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - EVENT("done\n",0,0); - return 0; -} - - -static inline void dequeue_tx(struct atm_vcc *vcc) -{ - struct zatm_vcc *zatm_vcc; - struct sk_buff *skb; - - EVENT("dequeue_tx\n",0,0); - zatm_vcc = ZATM_VCC(vcc); - skb = skb_dequeue(&zatm_vcc->tx_queue); - if (!skb) { - printk(KERN_CRIT DEV_LABEL "(itf %d): dequeue_tx but not " - "txing\n",vcc->dev->number); - return; - } -#if 0 /* @@@ would fail on CLP */ -if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP | - uPD98401_TXPD_SM | uPD98401_TXPD_AAL5)) printk("@#*$!!!! (%08x)\n", - *ZATM_PRV_DSC(skb)); -#endif - *ZATM_PRV_DSC(skb) = 0; /* mark as invalid */ - zatm_vcc->txing--; - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb_irq(skb); - while ((skb = skb_dequeue(&zatm_vcc->backlog))) - if (do_tx(skb) == RING_BUSY) { - skb_queue_head(&zatm_vcc->backlog,skb); - break; - } - atomic_inc(&vcc->stats->tx); - wake_up(&zatm_vcc->tx_wait); -} - - -static void poll_tx(struct atm_dev *dev,int mbx) -{ - struct zatm_dev *zatm_dev; - unsigned long pos; - u32 x; - - EVENT("poll_tx\n",0,0); - zatm_dev = ZATM_DEV(dev); - pos = (zatm_dev->mbx_start[mbx] & ~0xffffUL) | zin(MTA(mbx)); - while (x = zin(MWA(mbx)), (pos & 0xffff) != x) { - int chan; - -#if 1 - u32 data,*addr; - - EVENT("MBX: host 0x%lx, nic 0x%x\n",pos,x); - addr = (u32 *) pos; - data = *addr; - chan = (data & uPD98401_TXI_CONN) >> uPD98401_TXI_CONN_SHIFT; - EVENT("addr = 0x%lx, data = 0x%08x,",(unsigned long) addr, - data); - EVENT("chan = %d\n",chan,0); -#else -NO ! - chan = (zatm_dev->mbx_start[mbx][pos >> 2] & uPD98401_TXI_CONN) - >> uPD98401_TXI_CONN_SHIFT; -#endif - if (chan < zatm_dev->chans && zatm_dev->tx_map[chan]) - dequeue_tx(zatm_dev->tx_map[chan]); - else { - printk(KERN_CRIT DEV_LABEL "(itf %d): TX indication " - "for non-existing channel %d\n",dev->number,chan); - event_dump(); - } - if (((pos += 4) & 0xffff) == zatm_dev->mbx_end[mbx]) - pos = zatm_dev->mbx_start[mbx]; - } - zout(pos & 0xffff,MTA(mbx)); -} - - -/* - * BUG BUG BUG: Doesn't handle "new-style" rate specification yet. - */ - -static int alloc_shaper(struct atm_dev *dev,int *pcr,int min,int max,int ubr) -{ - struct zatm_dev *zatm_dev; - unsigned long flags; - unsigned long i,m,c; - int shaper; - - DPRINTK("alloc_shaper (min = %d, max = %d)\n",min,max); - zatm_dev = ZATM_DEV(dev); - if (!zatm_dev->free_shapers) return -EAGAIN; - for (shaper = 0; !((zatm_dev->free_shapers >> shaper) & 1); shaper++); - zatm_dev->free_shapers &= ~1 << shaper; - if (ubr) { - c = 5; - i = m = 1; - zatm_dev->ubr_ref_cnt++; - zatm_dev->ubr = shaper; - *pcr = 0; - } - else { - if (min) { - if (min <= 255) { - i = min; - m = ATM_OC3_PCR; - } - else { - i = 255; - m = ATM_OC3_PCR*255/min; - } - } - else { - if (max > zatm_dev->tx_bw) max = zatm_dev->tx_bw; - if (max <= 255) { - i = max; - m = ATM_OC3_PCR; - } - else { - i = 255; - m = DIV_ROUND_UP(ATM_OC3_PCR*255, max); - } - } - if (i > m) { - printk(KERN_CRIT DEV_LABEL "shaper algorithm botched " - "[%d,%d] -> i=%ld,m=%ld\n",min,max,i,m); - m = i; - } - *pcr = i*ATM_OC3_PCR/m; - c = 20; /* @@@ should use max_cdv ! */ - if ((min && *pcr < min) || (max && *pcr > max)) return -EINVAL; - if (zatm_dev->tx_bw < *pcr) return -EAGAIN; - zatm_dev->tx_bw -= *pcr; - } - spin_lock_irqsave(&zatm_dev->lock, flags); - DPRINTK("i = %d, m = %d, PCR = %d\n",i,m,*pcr); - zpokel(zatm_dev,(i << uPD98401_IM_I_SHIFT) | m,uPD98401_IM(shaper)); - zpokel(zatm_dev,c << uPD98401_PC_C_SHIFT,uPD98401_PC(shaper)); - zpokel(zatm_dev,0,uPD98401_X(shaper)); - zpokel(zatm_dev,0,uPD98401_Y(shaper)); - zpokel(zatm_dev,uPD98401_PS_E,uPD98401_PS(shaper)); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - return shaper; -} - - -static void dealloc_shaper(struct atm_dev *dev,int shaper) -{ - struct zatm_dev *zatm_dev; - unsigned long flags; - - zatm_dev = ZATM_DEV(dev); - if (shaper == zatm_dev->ubr) { - if (--zatm_dev->ubr_ref_cnt) return; - zatm_dev->ubr = -1; - } - spin_lock_irqsave(&zatm_dev->lock, flags); - zpokel(zatm_dev,zpeekl(zatm_dev,uPD98401_PS(shaper)) & ~uPD98401_PS_E, - uPD98401_PS(shaper)); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - zatm_dev->free_shapers |= 1 << shaper; -} - - -static void close_tx(struct atm_vcc *vcc) -{ - struct zatm_dev *zatm_dev; - struct zatm_vcc *zatm_vcc; - unsigned long flags; - int chan; - - zatm_vcc = ZATM_VCC(vcc); - zatm_dev = ZATM_DEV(vcc->dev); - chan = zatm_vcc->tx_chan; - if (!chan) return; - DPRINTK("close_tx\n"); - if (skb_peek(&zatm_vcc->backlog)) { - printk("waiting for backlog to drain ...\n"); - event_dump(); - wait_event(zatm_vcc->tx_wait, !skb_peek(&zatm_vcc->backlog)); - } - if (skb_peek(&zatm_vcc->tx_queue)) { - printk("waiting for TX queue to drain ...\n"); - event_dump(); - wait_event(zatm_vcc->tx_wait, !skb_peek(&zatm_vcc->tx_queue)); - } - spin_lock_irqsave(&zatm_dev->lock, flags); -#if 0 - zwait(); - zout(uPD98401_DEACT_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); -#endif - zwait(); - zout(uPD98401_CLOSE_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); - zwait(); - if (!(zin(CMR) & uPD98401_CHAN_ADDR)) - printk(KERN_CRIT DEV_LABEL "(itf %d): can't close TX channel " - "%d\n",vcc->dev->number,chan); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - zatm_vcc->tx_chan = 0; - zatm_dev->tx_map[chan] = NULL; - if (zatm_vcc->shaper != zatm_dev->ubr) { - zatm_dev->tx_bw += vcc->qos.txtp.min_pcr; - dealloc_shaper(vcc->dev,zatm_vcc->shaper); - } - kfree(zatm_vcc->ring); -} - - -static int open_tx_first(struct atm_vcc *vcc) -{ - struct zatm_dev *zatm_dev; - struct zatm_vcc *zatm_vcc; - unsigned long flags; - u32 *loop; - unsigned short chan; - int unlimited; - - DPRINTK("open_tx_first\n"); - zatm_dev = ZATM_DEV(vcc->dev); - zatm_vcc = ZATM_VCC(vcc); - zatm_vcc->tx_chan = 0; - if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; - spin_lock_irqsave(&zatm_dev->lock, flags); - zwait(); - zout(uPD98401_OPEN_CHAN,CMR); - zwait(); - DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); - chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; - spin_unlock_irqrestore(&zatm_dev->lock, flags); - DPRINTK("chan is %d\n",chan); - if (!chan) return -EAGAIN; - unlimited = vcc->qos.txtp.traffic_class == ATM_UBR && - (!vcc->qos.txtp.max_pcr || vcc->qos.txtp.max_pcr == ATM_MAX_PCR || - vcc->qos.txtp.max_pcr >= ATM_OC3_PCR); - if (unlimited && zatm_dev->ubr != -1) zatm_vcc->shaper = zatm_dev->ubr; - else { - int pcr; - - if (unlimited) vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU; - if ((zatm_vcc->shaper = alloc_shaper(vcc->dev,&pcr, - vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,unlimited)) - < 0) { - close_tx(vcc); - return zatm_vcc->shaper; - } - if (pcr > ATM_OC3_PCR) pcr = ATM_OC3_PCR; - vcc->qos.txtp.min_pcr = vcc->qos.txtp.max_pcr = pcr; - } - zatm_vcc->tx_chan = chan; - skb_queue_head_init(&zatm_vcc->tx_queue); - init_waitqueue_head(&zatm_vcc->tx_wait); - /* initialize ring */ - zatm_vcc->ring = kzalloc(RING_SIZE,GFP_KERNEL); - if (!zatm_vcc->ring) return -ENOMEM; - loop = zatm_vcc->ring+RING_ENTRIES*RING_WORDS; - loop[0] = uPD98401_TXPD_V; - loop[1] = loop[2] = 0; - loop[3] = virt_to_bus(zatm_vcc->ring); - zatm_vcc->ring_curr = 0; - zatm_vcc->txing = 0; - skb_queue_head_init(&zatm_vcc->backlog); - zpokel(zatm_dev,virt_to_bus(zatm_vcc->ring), - chan*VC_SIZE/4+uPD98401_TXVC_QRP); - return 0; -} - - -static int open_tx_second(struct atm_vcc *vcc) -{ - struct zatm_dev *zatm_dev; - struct zatm_vcc *zatm_vcc; - unsigned long flags; - - DPRINTK("open_tx_second\n"); - zatm_dev = ZATM_DEV(vcc->dev); - zatm_vcc = ZATM_VCC(vcc); - if (!zatm_vcc->tx_chan) return 0; - /* set up VC descriptor */ - spin_lock_irqsave(&zatm_dev->lock, flags); - zpokel(zatm_dev,0,zatm_vcc->tx_chan*VC_SIZE/4); - zpokel(zatm_dev,uPD98401_TXVC_L | (zatm_vcc->shaper << - uPD98401_TXVC_SHP_SHIFT) | (vcc->vpi << uPD98401_TXVC_VPI_SHIFT) | - vcc->vci,zatm_vcc->tx_chan*VC_SIZE/4+1); - zpokel(zatm_dev,0,zatm_vcc->tx_chan*VC_SIZE/4+2); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - zatm_dev->tx_map[zatm_vcc->tx_chan] = vcc; - return 0; -} - - -static int start_tx(struct atm_dev *dev) -{ - struct zatm_dev *zatm_dev; - int i; - - DPRINTK("start_tx\n"); - zatm_dev = ZATM_DEV(dev); - zatm_dev->tx_map = kmalloc_array(zatm_dev->chans, - sizeof(*zatm_dev->tx_map), - GFP_KERNEL); - if (!zatm_dev->tx_map) return -ENOMEM; - zatm_dev->tx_bw = ATM_OC3_PCR; - zatm_dev->free_shapers = (1 << NR_SHAPERS)-1; - zatm_dev->ubr = -1; - zatm_dev->ubr_ref_cnt = 0; - /* initialize shapers */ - for (i = 0; i < NR_SHAPERS; i++) zpokel(zatm_dev,0,uPD98401_PS(i)); - return 0; -} - - -/*------------------------------- interrupts --------------------------------*/ - - -static irqreturn_t zatm_int(int irq,void *dev_id) -{ - struct atm_dev *dev; - struct zatm_dev *zatm_dev; - u32 reason; - int handled = 0; - - dev = dev_id; - zatm_dev = ZATM_DEV(dev); - while ((reason = zin(GSR))) { - handled = 1; - EVENT("reason 0x%x\n",reason,0); - if (reason & uPD98401_INT_PI) { - EVENT("PHY int\n",0,0); - dev->phy->interrupt(dev); - } - if (reason & uPD98401_INT_RQA) { - unsigned long pools; - int i; - - pools = zin(RQA); - EVENT("RQA (0x%08x)\n",pools,0); - for (i = 0; pools; i++) { - if (pools & 1) { - refill_pool(dev,i); - zatm_dev->pool_info[i].rqa_count++; - } - pools >>= 1; - } - } - if (reason & uPD98401_INT_RQU) { - unsigned long pools; - int i; - pools = zin(RQU); - printk(KERN_WARNING DEV_LABEL "(itf %d): RQU 0x%08lx\n", - dev->number,pools); - event_dump(); - for (i = 0; pools; i++) { - if (pools & 1) { - refill_pool(dev,i); - zatm_dev->pool_info[i].rqu_count++; - } - pools >>= 1; - } - } - /* don't handle RD */ - if (reason & uPD98401_INT_SPE) - printk(KERN_ALERT DEV_LABEL "(itf %d): system parity " - "error at 0x%08x\n",dev->number,zin(ADDR)); - if (reason & uPD98401_INT_CPE) - printk(KERN_ALERT DEV_LABEL "(itf %d): control memory " - "parity error at 0x%08x\n",dev->number,zin(ADDR)); - if (reason & uPD98401_INT_SBE) { - printk(KERN_ALERT DEV_LABEL "(itf %d): system bus " - "error at 0x%08x\n",dev->number,zin(ADDR)); - event_dump(); - } - /* don't handle IND */ - if (reason & uPD98401_INT_MF) { - printk(KERN_CRIT DEV_LABEL "(itf %d): mailbox full " - "(0x%x)\n",dev->number,(reason & uPD98401_INT_MF) - >> uPD98401_INT_MF_SHIFT); - event_dump(); - /* @@@ should try to recover */ - } - if (reason & uPD98401_INT_MM) { - if (reason & 1) poll_rx(dev,0); - if (reason & 2) poll_rx(dev,1); - if (reason & 4) poll_tx(dev,2); - if (reason & 8) poll_tx(dev,3); - } - /* @@@ handle RCRn */ - } - return IRQ_RETVAL(handled); -} - - -/*----------------------------- (E)EPROM access -----------------------------*/ - - -static void eprom_set(struct zatm_dev *zatm_dev, unsigned long value, - unsigned short cmd) -{ - int error; - - if ((error = pci_write_config_dword(zatm_dev->pci_dev,cmd,value))) - printk(KERN_ERR DEV_LABEL ": PCI write failed (0x%02x)\n", - error); -} - - -static unsigned long eprom_get(struct zatm_dev *zatm_dev, unsigned short cmd) -{ - unsigned int value; - int error; - - if ((error = pci_read_config_dword(zatm_dev->pci_dev,cmd,&value))) - printk(KERN_ERR DEV_LABEL ": PCI read failed (0x%02x)\n", - error); - return value; -} - - -static void eprom_put_bits(struct zatm_dev *zatm_dev, unsigned long data, - int bits, unsigned short cmd) -{ - unsigned long value; - int i; - - for (i = bits-1; i >= 0; i--) { - value = ZEPROM_CS | (((data >> i) & 1) ? ZEPROM_DI : 0); - eprom_set(zatm_dev,value,cmd); - eprom_set(zatm_dev,value | ZEPROM_SK,cmd); - eprom_set(zatm_dev,value,cmd); - } -} - - -static void eprom_get_byte(struct zatm_dev *zatm_dev, unsigned char *byte, - unsigned short cmd) -{ - int i; - - *byte = 0; - for (i = 8; i; i--) { - eprom_set(zatm_dev,ZEPROM_CS,cmd); - eprom_set(zatm_dev,ZEPROM_CS | ZEPROM_SK,cmd); - *byte <<= 1; - if (eprom_get(zatm_dev,cmd) & ZEPROM_DO) *byte |= 1; - eprom_set(zatm_dev,ZEPROM_CS,cmd); - } -} - - -static int eprom_try_esi(struct atm_dev *dev, unsigned short cmd, int offset, - int swap) -{ - unsigned char buf[ZEPROM_SIZE]; - struct zatm_dev *zatm_dev; - int i; - - zatm_dev = ZATM_DEV(dev); - for (i = 0; i < ZEPROM_SIZE; i += 2) { - eprom_set(zatm_dev,ZEPROM_CS,cmd); /* select EPROM */ - eprom_put_bits(zatm_dev,ZEPROM_CMD_READ,ZEPROM_CMD_LEN,cmd); - eprom_put_bits(zatm_dev,i >> 1,ZEPROM_ADDR_LEN,cmd); - eprom_get_byte(zatm_dev,buf+i+swap,cmd); - eprom_get_byte(zatm_dev,buf+i+1-swap,cmd); - eprom_set(zatm_dev,0,cmd); /* deselect EPROM */ - } - memcpy(dev->esi,buf+offset,ESI_LEN); - return memcmp(dev->esi,"\0\0\0\0\0",ESI_LEN); /* assumes ESI_LEN == 6 */ -} - - -static void eprom_get_esi(struct atm_dev *dev) -{ - if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return; - (void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0); -} - - -/*--------------------------------- entries ---------------------------------*/ - - -static int zatm_init(struct atm_dev *dev) -{ - struct zatm_dev *zatm_dev; - struct pci_dev *pci_dev; - unsigned short command; - int error,i,last; - unsigned long t0,t1,t2; - - DPRINTK(">zatm_init\n"); - zatm_dev = ZATM_DEV(dev); - spin_lock_init(&zatm_dev->lock); - pci_dev = zatm_dev->pci_dev; - zatm_dev->base = pci_resource_start(pci_dev, 0); - zatm_dev->irq = pci_dev->irq; - if ((error = pci_read_config_word(pci_dev,PCI_COMMAND,&command))) { - printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%02x\n", - dev->number,error); - return -EINVAL; - } - if ((error = pci_write_config_word(pci_dev,PCI_COMMAND, - command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) { - printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (0x%02x)" - "\n",dev->number,error); - return -EIO; - } - eprom_get_esi(dev); - printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", - dev->number,pci_dev->revision,zatm_dev->base,zatm_dev->irq); - /* reset uPD98401 */ - zout(0,SWR); - while (!(zin(GSR) & uPD98401_INT_IND)); - zout(uPD98401_GMR_ONE /*uPD98401_BURST4*/,GMR); - last = MAX_CRAM_SIZE; - for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) { - zpokel(zatm_dev,0x55555555,i); - if (zpeekl(zatm_dev,i) != 0x55555555) last = i; - else { - zpokel(zatm_dev,0xAAAAAAAA,i); - if (zpeekl(zatm_dev,i) != 0xAAAAAAAA) last = i; - else zpokel(zatm_dev,i,i); - } - } - for (i = 0; i < last; i += RAM_INCREMENT) - if (zpeekl(zatm_dev,i) != i) break; - zatm_dev->mem = i << 2; - while (i) zpokel(zatm_dev,0,--i); - /* reset again to rebuild memory pointers */ - zout(0,SWR); - while (!(zin(GSR) & uPD98401_INT_IND)); - zout(uPD98401_GMR_ONE | uPD98401_BURST8 | uPD98401_BURST4 | - uPD98401_BURST2 | uPD98401_GMR_PM | uPD98401_GMR_DR,GMR); - /* TODO: should shrink allocation now */ - printk("mem=%dkB,%s (",zatm_dev->mem >> 10,zatm_dev->copper ? "UTP" : - "MMF"); - for (i = 0; i < ESI_LEN; i++) - printk("%02X%s",dev->esi[i],i == ESI_LEN-1 ? ")\n" : "-"); - do { - unsigned long flags; - - spin_lock_irqsave(&zatm_dev->lock, flags); - t0 = zpeekl(zatm_dev,uPD98401_TSR); - udelay(10); - t1 = zpeekl(zatm_dev,uPD98401_TSR); - udelay(1010); - t2 = zpeekl(zatm_dev,uPD98401_TSR); - spin_unlock_irqrestore(&zatm_dev->lock, flags); - } - while (t0 > t1 || t1 > t2); /* loop if wrapping ... */ - zatm_dev->khz = t2-2*t1+t0; - printk(KERN_NOTICE DEV_LABEL "(itf %d): uPD98401 %d.%d at %d.%03d " - "MHz\n",dev->number, - (zin(VER) & uPD98401_MAJOR) >> uPD98401_MAJOR_SHIFT, - zin(VER) & uPD98401_MINOR,zatm_dev->khz/1000,zatm_dev->khz % 1000); - return uPD98402_init(dev); -} - - -static int zatm_start(struct atm_dev *dev) -{ - struct zatm_dev *zatm_dev = ZATM_DEV(dev); - struct pci_dev *pdev = zatm_dev->pci_dev; - unsigned long curr; - int pools,vccs,rx; - int error, i, ld; - - DPRINTK("zatm_start\n"); - zatm_dev->rx_map = zatm_dev->tx_map = NULL; - for (i = 0; i < NR_MBX; i++) - zatm_dev->mbx_start[i] = 0; - error = request_irq(zatm_dev->irq, zatm_int, IRQF_SHARED, DEV_LABEL, dev); - if (error < 0) { - printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", - dev->number,zatm_dev->irq); - goto done; - } - /* define memory regions */ - pools = NR_POOLS; - if (NR_SHAPERS*SHAPER_SIZE > pools*POOL_SIZE) - pools = NR_SHAPERS*SHAPER_SIZE/POOL_SIZE; - vccs = (zatm_dev->mem-NR_SHAPERS*SHAPER_SIZE-pools*POOL_SIZE)/ - (2*VC_SIZE+RX_SIZE); - ld = -1; - for (rx = 1; rx < vccs; rx <<= 1) ld++; - dev->ci_range.vpi_bits = 0; /* @@@ no VPI for now */ - dev->ci_range.vci_bits = ld; - dev->link_rate = ATM_OC3_PCR; - zatm_dev->chans = vccs; /* ??? */ - curr = rx*RX_SIZE/4; - DPRINTK("RX pool 0x%08lx\n",curr); - zpokel(zatm_dev,curr,uPD98401_PMA); /* receive pool */ - zatm_dev->pool_base = curr; - curr += pools*POOL_SIZE/4; - DPRINTK("Shapers 0x%08lx\n",curr); - zpokel(zatm_dev,curr,uPD98401_SMA); /* shapers */ - curr += NR_SHAPERS*SHAPER_SIZE/4; - DPRINTK("Free 0x%08lx\n",curr); - zpokel(zatm_dev,curr,uPD98401_TOS); /* free pool */ - printk(KERN_INFO DEV_LABEL "(itf %d): %d shapers, %d pools, %d RX, " - "%ld VCs\n",dev->number,NR_SHAPERS,pools,rx, - (zatm_dev->mem-curr*4)/VC_SIZE); - /* create mailboxes */ - for (i = 0; i < NR_MBX; i++) { - void *mbx; - dma_addr_t mbx_dma; - - if (!mbx_entries[i]) - continue; - mbx = dma_alloc_coherent(&pdev->dev, - 2 * MBX_SIZE(i), &mbx_dma, GFP_KERNEL); - if (!mbx) { - error = -ENOMEM; - goto out; - } - /* - * Alignment provided by dma_alloc_coherent() isn't enough - * for this device. - */ - if (((unsigned long)mbx ^ mbx_dma) & 0xffff) { - printk(KERN_ERR DEV_LABEL "(itf %d): system " - "bus incompatible with driver\n", dev->number); - dma_free_coherent(&pdev->dev, 2*MBX_SIZE(i), mbx, mbx_dma); - error = -ENODEV; - goto out; - } - DPRINTK("mbx@0x%08lx-0x%08lx\n", mbx, mbx + MBX_SIZE(i)); - zatm_dev->mbx_start[i] = (unsigned long)mbx; - zatm_dev->mbx_dma[i] = mbx_dma; - zatm_dev->mbx_end[i] = (zatm_dev->mbx_start[i] + MBX_SIZE(i)) & - 0xffff; - zout(mbx_dma >> 16, MSH(i)); - zout(mbx_dma, MSL(i)); - zout(zatm_dev->mbx_end[i], MBA(i)); - zout((unsigned long)mbx & 0xffff, MTA(i)); - zout((unsigned long)mbx & 0xffff, MWA(i)); - } - error = start_tx(dev); - if (error) - goto out; - error = start_rx(dev); - if (error) - goto out_tx; - error = dev->phy->start(dev); - if (error) - goto out_rx; - zout(0xffffffff,IMR); /* enable interrupts */ - /* enable TX & RX */ - zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR); -done: - return error; - -out_rx: - kfree(zatm_dev->rx_map); -out_tx: - kfree(zatm_dev->tx_map); -out: - while (i-- > 0) { - dma_free_coherent(&pdev->dev, 2 * MBX_SIZE(i), - (void *)zatm_dev->mbx_start[i], - zatm_dev->mbx_dma[i]); - } - free_irq(zatm_dev->irq, dev); - goto done; -} - - -static void zatm_close(struct atm_vcc *vcc) -{ - DPRINTK(">zatm_close\n"); - if (!ZATM_VCC(vcc)) return; - clear_bit(ATM_VF_READY,&vcc->flags); - close_rx(vcc); - EVENT("close_tx\n",0,0); - close_tx(vcc); - DPRINTK("zatm_close: done waiting\n"); - /* deallocate memory */ - kfree(ZATM_VCC(vcc)); - vcc->dev_data = NULL; - clear_bit(ATM_VF_ADDR,&vcc->flags); -} - - -static int zatm_open(struct atm_vcc *vcc) -{ - struct zatm_vcc *zatm_vcc; - short vpi = vcc->vpi; - int vci = vcc->vci; - int error; - - DPRINTK(">zatm_open\n"); - 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_AAL5) return -EINVAL; /* @@@ AAL0 */ - DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, - vcc->vci); - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { - zatm_vcc = kmalloc(sizeof(*zatm_vcc), GFP_KERNEL); - if (!zatm_vcc) { - clear_bit(ATM_VF_ADDR,&vcc->flags); - return -ENOMEM; - } - vcc->dev_data = zatm_vcc; - ZATM_VCC(vcc)->tx_chan = 0; /* for zatm_close after open_rx */ - if ((error = open_rx_first(vcc))) { - zatm_close(vcc); - return error; - } - if ((error = open_tx_first(vcc))) { - zatm_close(vcc); - return error; - } - } - if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return 0; - if ((error = open_rx_second(vcc))) { - zatm_close(vcc); - return error; - } - if ((error = open_tx_second(vcc))) { - zatm_close(vcc); - return error; - } - set_bit(ATM_VF_READY,&vcc->flags); - return 0; -} - - -static int zatm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags) -{ - printk("Not yet implemented\n"); - return -ENOSYS; - /* @@@ */ -} - - -static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) -{ - struct zatm_dev *zatm_dev; - unsigned long flags; - - zatm_dev = ZATM_DEV(dev); - switch (cmd) { - case ZATM_GETPOOLZ: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - fallthrough; - case ZATM_GETPOOL: - { - struct zatm_pool_info info; - int pool; - - if (get_user(pool, - &((struct zatm_pool_req __user *) arg)->pool_num)) - return -EFAULT; - if (pool < 0 || pool > ZATM_LAST_POOL) - return -EINVAL; - pool = array_index_nospec(pool, - ZATM_LAST_POOL + 1); - spin_lock_irqsave(&zatm_dev->lock, flags); - info = zatm_dev->pool_info[pool]; - if (cmd == ZATM_GETPOOLZ) { - zatm_dev->pool_info[pool].rqa_count = 0; - zatm_dev->pool_info[pool].rqu_count = 0; - } - spin_unlock_irqrestore(&zatm_dev->lock, flags); - return copy_to_user( - &((struct zatm_pool_req __user *) arg)->info, - &info,sizeof(info)) ? -EFAULT : 0; - } - case ZATM_SETPOOL: - { - struct zatm_pool_info info; - int pool; - - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (get_user(pool, - &((struct zatm_pool_req __user *) arg)->pool_num)) - return -EFAULT; - if (pool < 0 || pool > ZATM_LAST_POOL) - return -EINVAL; - pool = array_index_nospec(pool, - ZATM_LAST_POOL + 1); - if (copy_from_user(&info, - &((struct zatm_pool_req __user *) arg)->info, - sizeof(info))) return -EFAULT; - if (!info.low_water) - info.low_water = zatm_dev-> - pool_info[pool].low_water; - if (!info.high_water) - info.high_water = zatm_dev-> - pool_info[pool].high_water; - if (!info.next_thres) - info.next_thres = zatm_dev-> - pool_info[pool].next_thres; - if (info.low_water >= info.high_water || - info.low_water < 0) - return -EINVAL; - spin_lock_irqsave(&zatm_dev->lock, flags); - zatm_dev->pool_info[pool].low_water = - info.low_water; - zatm_dev->pool_info[pool].high_water = - info.high_water; - zatm_dev->pool_info[pool].next_thres = - info.next_thres; - spin_unlock_irqrestore(&zatm_dev->lock, flags); - return 0; - } - default: - if (!dev->phy->ioctl) return -ENOIOCTLCMD; - return dev->phy->ioctl(dev,cmd,arg); - } -} - -static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb) -{ - int error; - - EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0); - if (!ZATM_VCC(vcc)->tx_chan || !test_bit(ATM_VF_READY,&vcc->flags)) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - return -EINVAL; - } - if (!skb) { - printk(KERN_CRIT "!skb in zatm_send ?\n"); - if (vcc->pop) vcc->pop(vcc,skb); - return -EINVAL; - } - ATM_SKB(skb)->vcc = vcc; - error = do_tx(skb); - if (error != RING_BUSY) return error; - skb_queue_tail(&ZATM_VCC(vcc)->backlog,skb); - return 0; -} - - -static void zatm_phy_put(struct atm_dev *dev,unsigned char value, - unsigned long addr) -{ - struct zatm_dev *zatm_dev; - - zatm_dev = ZATM_DEV(dev); - zwait(); - zout(value,CER); - zout(uPD98401_IND_ACC | uPD98401_IA_B0 | - (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); -} - - -static unsigned char zatm_phy_get(struct atm_dev *dev,unsigned long addr) -{ - struct zatm_dev *zatm_dev; - - zatm_dev = ZATM_DEV(dev); - zwait(); - zout(uPD98401_IND_ACC | uPD98401_IA_B0 | uPD98401_IA_RW | - (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); - zwait(); - return zin(CER) & 0xff; -} - - -static const struct atmdev_ops ops = { - .open = zatm_open, - .close = zatm_close, - .ioctl = zatm_ioctl, - .send = zatm_send, - .phy_put = zatm_phy_put, - .phy_get = zatm_phy_get, - .change_qos = zatm_change_qos, -}; - -static int zatm_init_one(struct pci_dev *pci_dev, - const struct pci_device_id *ent) -{ - struct atm_dev *dev; - struct zatm_dev *zatm_dev; - int ret = -ENOMEM; - - zatm_dev = kmalloc(sizeof(*zatm_dev), GFP_KERNEL); - if (!zatm_dev) { - printk(KERN_EMERG "%s: memory shortage\n", DEV_LABEL); - goto out; - } - - dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL); - if (!dev) - goto out_free; - - ret = pci_enable_device(pci_dev); - if (ret < 0) - goto out_deregister; - - ret = pci_request_regions(pci_dev, DEV_LABEL); - if (ret < 0) - goto out_disable; - - ret = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)); - if (ret < 0) - goto out_release; - - zatm_dev->pci_dev = pci_dev; - dev->dev_data = zatm_dev; - zatm_dev->copper = (int)ent->driver_data; - if ((ret = zatm_init(dev)) || (ret = zatm_start(dev))) - goto out_release; - - pci_set_drvdata(pci_dev, dev); - zatm_dev->more = zatm_boards; - zatm_boards = dev; - ret = 0; -out: - return ret; - -out_release: - pci_release_regions(pci_dev); -out_disable: - pci_disable_device(pci_dev); -out_deregister: - atm_dev_deregister(dev); -out_free: - kfree(zatm_dev); - goto out; -} - - -MODULE_LICENSE("GPL"); - -static const struct pci_device_id zatm_pci_tbl[] = { - { PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1221), ZATM_COPPER }, - { PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1225), 0 }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, zatm_pci_tbl); - -static struct pci_driver zatm_driver = { - .name = DEV_LABEL, - .id_table = zatm_pci_tbl, - .probe = zatm_init_one, -}; - -static int __init zatm_init_module(void) -{ - return pci_register_driver(&zatm_driver); -} - -module_init(zatm_init_module); -/* module_exit not defined so not unloadable */ diff --git a/drivers/atm/zatm.h b/drivers/atm/zatm.h deleted file mode 100644 index 8204369fe825..000000000000 --- a/drivers/atm/zatm.h +++ /dev/null @@ -1,104 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/zatm.h - ZeitNet ZN122x device driver declarations */ - -/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ - - -#ifndef DRIVER_ATM_ZATM_H -#define DRIVER_ATM_ZATM_H - -#include -#include -#include -#include -#include - - -#define DEV_LABEL "zatm" - -#define MAX_AAL5_PDU 10240 /* allocate for AAL5 PDUs of this size */ -#define MAX_RX_SIZE_LD 14 /* ceil(log2((MAX_AAL5_PDU+47)/48)) */ - -#define LOW_MARK 12 /* start adding new buffers if less than 12 */ -#define HIGH_MARK 30 /* stop adding buffers after reaching 30 */ -#define OFF_CNG_THRES 5 /* threshold for offset changes */ - -#define RX_SIZE 2 /* RX lookup entry size (in bytes) */ -#define NR_POOLS 32 /* number of free buffer pointers */ -#define POOL_SIZE 8 /* buffer entry size (in bytes) */ -#define NR_SHAPERS 16 /* number of shapers */ -#define SHAPER_SIZE 4 /* shaper entry size (in bytes) */ -#define VC_SIZE 32 /* VC dsc (TX or RX) size (in bytes) */ - -#define RING_ENTRIES 32 /* ring entries (without back pointer) */ -#define RING_WORDS 4 /* ring element size */ -#define RING_SIZE (sizeof(unsigned long)*(RING_ENTRIES+1)*RING_WORDS) - -#define NR_MBX 4 /* four mailboxes */ -#define MBX_RX_0 0 /* mailbox indices */ -#define MBX_RX_1 1 -#define MBX_TX_0 2 -#define MBX_TX_1 3 - -struct zatm_vcc { - /*-------------------------------- RX part */ - int rx_chan; /* RX channel, 0 if none */ - int pool; /* free buffer pool */ - /*-------------------------------- TX part */ - int tx_chan; /* TX channel, 0 if none */ - int shaper; /* shaper, <0 if none */ - struct sk_buff_head tx_queue; /* list of buffers in transit */ - wait_queue_head_t tx_wait; /* for close */ - u32 *ring; /* transmit ring */ - int ring_curr; /* current write position */ - int txing; /* number of transmits in progress */ - struct sk_buff_head backlog; /* list of buffers waiting for ring */ -}; - -struct zatm_dev { - /*-------------------------------- TX part */ - int tx_bw; /* remaining bandwidth */ - u32 free_shapers; /* bit set */ - int ubr; /* UBR shaper; -1 if none */ - int ubr_ref_cnt; /* number of VCs using UBR shaper */ - /*-------------------------------- RX part */ - int pool_ref[NR_POOLS]; /* free buffer pool usage counters */ - volatile struct sk_buff *last_free[NR_POOLS]; - /* last entry in respective pool */ - struct sk_buff_head pool[NR_POOLS];/* free buffer pools */ - struct zatm_pool_info pool_info[NR_POOLS]; /* pool information */ - /*-------------------------------- maps */ - struct atm_vcc **tx_map; /* TX VCCs */ - struct atm_vcc **rx_map; /* RX VCCs */ - int chans; /* map size, must be 2^n */ - /*-------------------------------- mailboxes */ - unsigned long mbx_start[NR_MBX];/* start addresses */ - dma_addr_t mbx_dma[NR_MBX]; - u16 mbx_end[NR_MBX]; /* end offset (in bytes) */ - /*-------------------------------- other pointers */ - u32 pool_base; /* Free buffer pool dsc (word addr) */ - /*-------------------------------- ZATM links */ - struct atm_dev *more; /* other ZATM devices */ - /*-------------------------------- general information */ - int mem; /* RAM on board (in bytes) */ - int khz; /* timer clock */ - int copper; /* PHY type */ - unsigned char irq; /* IRQ */ - unsigned int base; /* IO base address */ - struct pci_dev *pci_dev; /* PCI stuff */ - spinlock_t lock; -}; - - -#define ZATM_DEV(d) ((struct zatm_dev *) (d)->dev_data) -#define ZATM_VCC(d) ((struct zatm_vcc *) (d)->dev_data) - - -struct zatm_skb_prv { - struct atm_skb_data _; /* reserved */ - u32 *dsc; /* pointer to skb's descriptor */ -}; - -#define ZATM_PRV_DSC(skb) (((struct zatm_skb_prv *) (skb)->cb)->dsc) - -#endif diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index 441da03c23ee..a9c44f08199d 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -45,40 +45,6 @@ config BPQETHER useful if some other computer on your local network has a direct amateur radio connection. -config DMASCC - tristate "High-speed (DMA) SCC driver for AX.25" - depends on ISA && AX25 && BROKEN_ON_SMP && ISA_DMA_API - depends on VIRT_TO_BUS - help - This is a driver for high-speed SCC boards, i.e. those supporting - DMA on one port. You usually use those boards to connect your - computer to an amateur radio modem (such as the WA4DSY 56kbps - modem), in order to send and receive AX.25 packet radio network - traffic. - - Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis - PackeTwin, and S5SCC/DMA boards. They are detected automatically. - If you have one of these cards, say Y here and read the AX25-HOWTO, - available from . - - This driver can operate multiple boards simultaneously. If you - compile it as a module (by saying M instead of Y), it will be called - dmascc. If you don't pass any parameter to the driver, all - possible I/O addresses are probed. This could irritate other devices - that are currently not in use. You may specify the list of addresses - to be probed by "dmascc.io=addr1,addr2,..." (when compiled into the - kernel image) or "io=addr1,addr2,..." (when loaded as a module). The - network interfaces will be called dmascc0 and dmascc1 for the board - detected first, dmascc2 and dmascc3 for the second one, and so on. - - Before you configure each interface with ifconfig, you MUST set - certain parameters, such as channel access timing, clock mode, and - DMA channel. This is accomplished with a small utility program, - dmascc_cfg, available at - . Please be sure to - get at least version 1.27 of dmascc_cfg, as older versions will not - work with the current driver. - config SCC tristate "Z8530 SCC driver" depends on ISA && AX25 && ISA_DMA_API diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile index 7a1518d763e3..25fc400369ba 100644 --- a/drivers/net/hamradio/Makefile +++ b/drivers/net/hamradio/Makefile @@ -11,7 +11,6 @@ # Christoph Hellwig # -obj-$(CONFIG_DMASCC) += dmascc.o obj-$(CONFIG_SCC) += scc.o obj-$(CONFIG_MKISS) += mkiss.o obj-$(CONFIG_6PACK) += 6pack.o diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c deleted file mode 100644 index a2a12208e3ad..000000000000 --- a/drivers/net/hamradio/dmascc.c +++ /dev/null @@ -1,1450 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Driver for high-speed SCC boards (those with DMA support) - * Copyright (C) 1997-2000 Klaus Kudielka - * - * S5SCC/DMA support by Janko Koleznik S52HI - */ - - -#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" - - -/* Number of buffers per channel */ - -#define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (min. 2 recommended) */ -#define NUM_RX_BUF 6 /* NUM_RX_BUF >= 1 (min. 2 recommended) */ -#define BUF_SIZE 1576 /* BUF_SIZE >= mtu + hard_header_len */ - - -/* Cards supported */ - -#define HW_PI { "Ottawa PI", 0x300, 0x20, 0x10, 8, \ - 0, 8, 1843200, 3686400 } -#define HW_PI2 { "Ottawa PI2", 0x300, 0x20, 0x10, 8, \ - 0, 8, 3686400, 7372800 } -#define HW_TWIN { "Gracilis PackeTwin", 0x200, 0x10, 0x10, 32, \ - 0, 4, 6144000, 6144000 } -#define HW_S5 { "S5SCC/DMA", 0x200, 0x10, 0x10, 32, \ - 0, 8, 4915200, 9830400 } - -#define HARDWARE { HW_PI, HW_PI2, HW_TWIN, HW_S5 } - -#define TMR_0_HZ 25600 /* Frequency of timer 0 */ - -#define TYPE_PI 0 -#define TYPE_PI2 1 -#define TYPE_TWIN 2 -#define TYPE_S5 3 -#define NUM_TYPES 4 - -#define MAX_NUM_DEVS 32 - - -/* SCC chips supported */ - -#define Z8530 0 -#define Z85C30 1 -#define Z85230 2 - -#define CHIPNAMES { "Z8530", "Z85C30", "Z85230" } - - -/* I/O registers */ - -/* 8530 registers relative to card base */ -#define SCCB_CMD 0x00 -#define SCCB_DATA 0x01 -#define SCCA_CMD 0x02 -#define SCCA_DATA 0x03 - -/* 8253/8254 registers relative to card base */ -#define TMR_CNT0 0x00 -#define TMR_CNT1 0x01 -#define TMR_CNT2 0x02 -#define TMR_CTRL 0x03 - -/* Additional PI/PI2 registers relative to card base */ -#define PI_DREQ_MASK 0x04 - -/* Additional PackeTwin registers relative to card base */ -#define TWIN_INT_REG 0x08 -#define TWIN_CLR_TMR1 0x09 -#define TWIN_CLR_TMR2 0x0a -#define TWIN_SPARE_1 0x0b -#define TWIN_DMA_CFG 0x08 -#define TWIN_SERIAL_CFG 0x09 -#define TWIN_DMA_CLR_FF 0x0a -#define TWIN_SPARE_2 0x0b - - -/* PackeTwin I/O register values */ - -/* INT_REG */ -#define TWIN_SCC_MSK 0x01 -#define TWIN_TMR1_MSK 0x02 -#define TWIN_TMR2_MSK 0x04 -#define TWIN_INT_MSK 0x07 - -/* SERIAL_CFG */ -#define TWIN_DTRA_ON 0x01 -#define TWIN_DTRB_ON 0x02 -#define TWIN_EXTCLKA 0x04 -#define TWIN_EXTCLKB 0x08 -#define TWIN_LOOPA_ON 0x10 -#define TWIN_LOOPB_ON 0x20 -#define TWIN_EI 0x80 - -/* DMA_CFG */ -#define TWIN_DMA_HDX_T1 0x08 -#define TWIN_DMA_HDX_R1 0x0a -#define TWIN_DMA_HDX_T3 0x14 -#define TWIN_DMA_HDX_R3 0x16 -#define TWIN_DMA_FDX_T3R1 0x1b -#define TWIN_DMA_FDX_T1R3 0x1d - - -/* Status values */ - -#define IDLE 0 -#define TX_HEAD 1 -#define TX_DATA 2 -#define TX_PAUSE 3 -#define TX_TAIL 4 -#define RTS_OFF 5 -#define WAIT 6 -#define DCD_ON 7 -#define RX_ON 8 -#define DCD_OFF 9 - - -/* Ioctls */ - -#define SIOCGSCCPARAM SIOCDEVPRIVATE -#define SIOCSSCCPARAM (SIOCDEVPRIVATE+1) - - -/* Data types */ - -struct scc_param { - int pclk_hz; /* frequency of BRG input (don't change) */ - int brg_tc; /* BRG terminal count; BRG disabled if < 0 */ - int nrzi; /* 0 (nrz), 1 (nrzi) */ - int clocks; /* see dmascc_cfg documentation */ - int txdelay; /* [1/TMR_0_HZ] */ - int txtimeout; /* [1/HZ] */ - int txtail; /* [1/TMR_0_HZ] */ - int waittime; /* [1/TMR_0_HZ] */ - int slottime; /* [1/TMR_0_HZ] */ - int persist; /* 1 ... 256 */ - int dma; /* -1 (disable), 0, 1, 3 */ - int txpause; /* [1/TMR_0_HZ] */ - int rtsoff; /* [1/TMR_0_HZ] */ - int dcdon; /* [1/TMR_0_HZ] */ - int dcdoff; /* [1/TMR_0_HZ] */ -}; - -struct scc_hardware { - char *name; - int io_region; - int io_delta; - int io_size; - int num_devs; - int scc_offset; - int tmr_offset; - int tmr_hz; - int pclk_hz; -}; - -struct scc_priv { - int type; - int chip; - struct net_device *dev; - struct scc_info *info; - - int channel; - int card_base, scc_cmd, scc_data; - int tmr_cnt, tmr_ctrl, tmr_mode; - struct scc_param param; - char rx_buf[NUM_RX_BUF][BUF_SIZE]; - int rx_len[NUM_RX_BUF]; - int rx_ptr; - struct work_struct rx_work; - int rx_head, rx_tail, rx_count; - int rx_over; - char tx_buf[NUM_TX_BUF][BUF_SIZE]; - int tx_len[NUM_TX_BUF]; - int tx_ptr; - int tx_head, tx_tail, tx_count; - int state; - unsigned long tx_start; - int rr0; - spinlock_t *register_lock; /* Per scc_info */ - spinlock_t ring_lock; -}; - -struct scc_info { - int irq_used; - int twin_serial_cfg; - struct net_device *dev[2]; - struct scc_priv priv[2]; - struct scc_info *next; - spinlock_t register_lock; /* Per device register lock */ -}; - - -/* Function declarations */ -static int setup_adapter(int card_base, int type, int n) __init; - -static void write_scc(struct scc_priv *priv, int reg, int val); -static void write_scc_data(struct scc_priv *priv, int val, int fast); -static int read_scc(struct scc_priv *priv, int reg); -static int read_scc_data(struct scc_priv *priv); - -static int scc_open(struct net_device *dev); -static int scc_close(struct net_device *dev); -static int scc_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd); -static int scc_send_packet(struct sk_buff *skb, struct net_device *dev); -static int scc_set_mac_address(struct net_device *dev, void *sa); - -static inline void tx_on(struct scc_priv *priv); -static inline void rx_on(struct scc_priv *priv); -static inline void rx_off(struct scc_priv *priv); -static void start_timer(struct scc_priv *priv, int t, int r15); -static inline unsigned char random(void); - -static inline void z8530_isr(struct scc_info *info); -static irqreturn_t scc_isr(int irq, void *dev_id); -static void rx_isr(struct scc_priv *priv); -static void special_condition(struct scc_priv *priv, int rc); -static void rx_bh(struct work_struct *); -static void tx_isr(struct scc_priv *priv); -static void es_isr(struct scc_priv *priv); -static void tm_isr(struct scc_priv *priv); - - -/* Initialization variables */ - -static int io[MAX_NUM_DEVS] __initdata = { 0, }; - -/* Beware! hw[] is also used in dmascc_exit(). */ -static struct scc_hardware hw[NUM_TYPES] = HARDWARE; - - -/* Global variables */ - -static struct scc_info *first; -static unsigned long rand; - - -MODULE_AUTHOR("Klaus Kudielka"); -MODULE_DESCRIPTION("Driver for high-speed SCC boards"); -module_param_hw_array(io, int, ioport, NULL, 0); -MODULE_LICENSE("GPL"); - -static void __exit dmascc_exit(void) -{ - int i; - struct scc_info *info; - - while (first) { - info = first; - - /* Unregister devices */ - for (i = 0; i < 2; i++) - unregister_netdev(info->dev[i]); - - /* Reset board */ - if (info->priv[0].type == TYPE_TWIN) - outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); - write_scc(&info->priv[0], R9, FHWRES); - release_region(info->dev[0]->base_addr, - hw[info->priv[0].type].io_size); - - for (i = 0; i < 2; i++) - free_netdev(info->dev[i]); - - /* Free memory */ - first = info->next; - kfree(info); - } -} - -static int __init dmascc_init(void) -{ - int h, i, j, n; - int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], - t1[MAX_NUM_DEVS]; - unsigned t_val; - unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS], - counting[MAX_NUM_DEVS]; - - /* Initialize random number generator */ - rand = jiffies; - /* Cards found = 0 */ - n = 0; - /* Warning message */ - if (!io[0]) - printk(KERN_INFO "dmascc: autoprobing (dangerous)\n"); - - /* Run autodetection for each card type */ - for (h = 0; h < NUM_TYPES; h++) { - - if (io[0]) { - /* User-specified I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) - base[i] = 0; - for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) { - j = (io[i] - - hw[h].io_region) / hw[h].io_delta; - if (j >= 0 && j < hw[h].num_devs && - hw[h].io_region + - j * hw[h].io_delta == io[i]) { - base[j] = io[i]; - } - } - } else { - /* Default I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) { - base[i] = - hw[h].io_region + i * hw[h].io_delta; - } - } - - /* Check valid I/O address regions */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - if (!request_region - (base[i], hw[h].io_size, "dmascc")) - base[i] = 0; - else { - tcmd[i] = - base[i] + hw[h].tmr_offset + - TMR_CTRL; - t0[i] = - base[i] + hw[h].tmr_offset + - TMR_CNT0; - t1[i] = - base[i] + hw[h].tmr_offset + - TMR_CNT1; - } - } - - /* Start timers */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */ - outb(0x36, tcmd[i]); - outb((hw[h].tmr_hz / TMR_0_HZ) & 0xFF, - t0[i]); - outb((hw[h].tmr_hz / TMR_0_HZ) >> 8, - t0[i]); - /* Timer 1: LSB+MSB, Mode 0, HZ/10 */ - outb(0x70, tcmd[i]); - outb((TMR_0_HZ / HZ * 10) & 0xFF, t1[i]); - outb((TMR_0_HZ / HZ * 10) >> 8, t1[i]); - start[i] = jiffies; - delay[i] = 0; - counting[i] = 1; - /* Timer 2: LSB+MSB, Mode 0 */ - outb(0xb0, tcmd[i]); - } - time = jiffies; - /* Wait until counter registers are loaded */ - udelay(2000000 / TMR_0_HZ); - - /* Timing loop */ - while (time_is_after_jiffies(time + 13)) { - for (i = 0; i < hw[h].num_devs; i++) - if (base[i] && counting[i]) { - /* Read back Timer 1: latch; read LSB; read MSB */ - outb(0x40, tcmd[i]); - t_val = - inb(t1[i]) + (inb(t1[i]) << 8); - /* Also check whether counter did wrap */ - if (t_val == 0 || - t_val > TMR_0_HZ / HZ * 10) - counting[i] = 0; - delay[i] = jiffies - start[i]; - } - } - - /* Evaluate measurements */ - for (i = 0; i < hw[h].num_devs; i++) - if (base[i]) { - if ((delay[i] >= 9 && delay[i] <= 11) && - /* Ok, we have found an adapter */ - (setup_adapter(base[i], h, n) == 0)) - n++; - else - release_region(base[i], - hw[h].io_size); - } - - } /* NUM_TYPES */ - - /* If any adapter was successfully initialized, return ok */ - if (n) - return 0; - - /* If no adapter found, return error */ - printk(KERN_INFO "dmascc: no adapters found\n"); - return -EIO; -} - -module_init(dmascc_init); -module_exit(dmascc_exit); - -static void __init dev_setup(struct net_device *dev) -{ - dev->type = ARPHRD_AX25; - dev->hard_header_len = AX25_MAX_HEADER_LEN; - dev->mtu = 1500; - dev->addr_len = AX25_ADDR_LEN; - dev->tx_queue_len = 64; - memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); - dev_addr_set(dev, (u8 *)&ax25_defaddr); -} - -static const struct net_device_ops scc_netdev_ops = { - .ndo_open = scc_open, - .ndo_stop = scc_close, - .ndo_start_xmit = scc_send_packet, - .ndo_siocdevprivate = scc_siocdevprivate, - .ndo_set_mac_address = scc_set_mac_address, -}; - -static int __init setup_adapter(int card_base, int type, int n) -{ - int i, irq, chip, err; - struct scc_info *info; - struct net_device *dev; - struct scc_priv *priv; - unsigned long time; - unsigned int irqs; - int tmr_base = card_base + hw[type].tmr_offset; - int scc_base = card_base + hw[type].scc_offset; - char *chipnames[] = CHIPNAMES; - - /* Initialize what is necessary for write_scc and write_scc_data */ - info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); - if (!info) { - err = -ENOMEM; - goto out; - } - - info->dev[0] = alloc_netdev(0, "", NET_NAME_UNKNOWN, dev_setup); - if (!info->dev[0]) { - printk(KERN_ERR "dmascc: " - "could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); - err = -ENOMEM; - goto out1; - } - - info->dev[1] = alloc_netdev(0, "", NET_NAME_UNKNOWN, dev_setup); - if (!info->dev[1]) { - printk(KERN_ERR "dmascc: " - "could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); - err = -ENOMEM; - goto out2; - } - spin_lock_init(&info->register_lock); - - priv = &info->priv[0]; - priv->type = type; - priv->card_base = card_base; - priv->scc_cmd = scc_base + SCCA_CMD; - priv->scc_data = scc_base + SCCA_DATA; - priv->register_lock = &info->register_lock; - - /* Reset SCC */ - write_scc(priv, R9, FHWRES | MIE | NV); - - /* Determine type of chip by enabling SDLC/HDLC enhancements */ - write_scc(priv, R15, SHDLCE); - if (!read_scc(priv, R15)) { - /* WR7' not present. This is an ordinary Z8530 SCC. */ - chip = Z8530; - } else { - /* Put one character in TX FIFO */ - write_scc_data(priv, 0, 0); - if (read_scc(priv, R0) & Tx_BUF_EMP) { - /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ - chip = Z85230; - } else { - /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ - chip = Z85C30; - } - } - write_scc(priv, R15, 0); - - /* Start IRQ auto-detection */ - irqs = probe_irq_on(); - - /* Enable interrupts */ - if (type == TYPE_TWIN) { - outb(0, card_base + TWIN_DMA_CFG); - inb(card_base + TWIN_CLR_TMR1); - inb(card_base + TWIN_CLR_TMR2); - info->twin_serial_cfg = TWIN_EI; - outb(info->twin_serial_cfg, card_base + TWIN_SERIAL_CFG); - } else { - write_scc(priv, R15, CTSIE); - write_scc(priv, R0, RES_EXT_INT); - write_scc(priv, R1, EXT_INT_ENAB); - } - - /* Start timer */ - outb(1, tmr_base + TMR_CNT1); - outb(0, tmr_base + TMR_CNT1); - - /* Wait and detect IRQ */ - time = jiffies; - while (time_is_after_jiffies(time + 2 + HZ / TMR_0_HZ)); - irq = probe_irq_off(irqs); - - /* Clear pending interrupt, disable interrupts */ - if (type == TYPE_TWIN) { - inb(card_base + TWIN_CLR_TMR1); - } else { - write_scc(priv, R1, 0); - write_scc(priv, R15, 0); - write_scc(priv, R0, RES_EXT_INT); - } - - if (irq <= 0) { - printk(KERN_ERR - "dmascc: could not find irq of %s at %#3x (irq=%d)\n", - hw[type].name, card_base, irq); - err = -ENODEV; - goto out3; - } - - /* Set up data structures */ - for (i = 0; i < 2; i++) { - dev = info->dev[i]; - priv = &info->priv[i]; - priv->type = type; - priv->chip = chip; - priv->dev = dev; - priv->info = info; - priv->channel = i; - spin_lock_init(&priv->ring_lock); - priv->register_lock = &info->register_lock; - priv->card_base = card_base; - priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); - priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); - priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); - priv->tmr_ctrl = tmr_base + TMR_CTRL; - priv->tmr_mode = i ? 0xb0 : 0x70; - priv->param.pclk_hz = hw[type].pclk_hz; - priv->param.brg_tc = -1; - priv->param.clocks = TCTRxCP | RCRTxCP; - priv->param.persist = 256; - priv->param.dma = -1; - INIT_WORK(&priv->rx_work, rx_bh); - dev->ml_priv = priv; - snprintf(dev->name, sizeof(dev->name), "dmascc%i", 2 * n + i); - dev->base_addr = card_base; - dev->irq = irq; - dev->netdev_ops = &scc_netdev_ops; - dev->header_ops = &ax25_header_ops; - } - if (register_netdev(info->dev[0])) { - printk(KERN_ERR "dmascc: could not register %s\n", - info->dev[0]->name); - err = -ENODEV; - goto out3; - } - if (register_netdev(info->dev[1])) { - printk(KERN_ERR "dmascc: could not register %s\n", - info->dev[1]->name); - err = -ENODEV; - goto out4; - } - - - info->next = first; - first = info; - printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", - hw[type].name, chipnames[chip], card_base, irq); - return 0; - - out4: - unregister_netdev(info->dev[0]); - out3: - if (info->priv[0].type == TYPE_TWIN) - outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); - write_scc(&info->priv[0], R9, FHWRES); - free_netdev(info->dev[1]); - out2: - free_netdev(info->dev[0]); - out1: - kfree(info); - out: - return err; -} - - -/* Driver functions */ - -static void write_scc(struct scc_priv *priv, int reg, int val) -{ - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - if (reg) - outb(reg, priv->scc_cmd); - outb(val, priv->scc_cmd); - return; - case TYPE_TWIN: - if (reg) - outb_p(reg, priv->scc_cmd); - outb_p(val, priv->scc_cmd); - return; - default: - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - if (reg) - outb_p(reg, priv->scc_cmd); - outb_p(val, priv->scc_cmd); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - return; - } -} - - -static void write_scc_data(struct scc_priv *priv, int val, int fast) -{ - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - outb(val, priv->scc_data); - return; - case TYPE_TWIN: - outb_p(val, priv->scc_data); - return; - default: - if (fast) - outb_p(val, priv->scc_data); - else { - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - outb_p(val, priv->scc_data); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - } - return; - } -} - - -static int read_scc(struct scc_priv *priv, int reg) -{ - int rc; - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - if (reg) - outb(reg, priv->scc_cmd); - return inb(priv->scc_cmd); - case TYPE_TWIN: - if (reg) - outb_p(reg, priv->scc_cmd); - return inb_p(priv->scc_cmd); - default: - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - if (reg) - outb_p(reg, priv->scc_cmd); - rc = inb_p(priv->scc_cmd); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - return rc; - } -} - - -static int read_scc_data(struct scc_priv *priv) -{ - int rc; - unsigned long flags; - switch (priv->type) { - case TYPE_S5: - return inb(priv->scc_data); - case TYPE_TWIN: - return inb_p(priv->scc_data); - default: - spin_lock_irqsave(priv->register_lock, flags); - outb_p(0, priv->card_base + PI_DREQ_MASK); - rc = inb_p(priv->scc_data); - outb(1, priv->card_base + PI_DREQ_MASK); - spin_unlock_irqrestore(priv->register_lock, flags); - return rc; - } -} - - -static int scc_open(struct net_device *dev) -{ - struct scc_priv *priv = dev->ml_priv; - struct scc_info *info = priv->info; - int card_base = priv->card_base; - - /* Request IRQ if not already used by other channel */ - if (!info->irq_used) { - if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) { - return -EAGAIN; - } - } - info->irq_used++; - - /* Request DMA if required */ - if (priv->param.dma >= 0) { - if (request_dma(priv->param.dma, "dmascc")) { - if (--info->irq_used == 0) - free_irq(dev->irq, info); - return -EAGAIN; - } else { - unsigned long flags = claim_dma_lock(); - clear_dma_ff(priv->param.dma); - release_dma_lock(flags); - } - } - - /* Initialize local variables */ - priv->rx_ptr = 0; - priv->rx_over = 0; - priv->rx_head = priv->rx_tail = priv->rx_count = 0; - priv->state = IDLE; - priv->tx_head = priv->tx_tail = priv->tx_count = 0; - priv->tx_ptr = 0; - - /* Reset channel */ - write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); - /* X1 clock, SDLC mode */ - write_scc(priv, R4, SDLC | X1CLK); - /* DMA */ - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - /* 8 bit RX char, RX disable */ - write_scc(priv, R3, Rx8); - /* 8 bit TX char, TX disable */ - write_scc(priv, R5, Tx8); - /* SDLC address field */ - write_scc(priv, R6, 0); - /* SDLC flag */ - write_scc(priv, R7, FLAG); - switch (priv->chip) { - case Z85C30: - /* Select WR7' */ - write_scc(priv, R15, SHDLCE); - /* Auto EOM reset */ - write_scc(priv, R7, AUTOEOM); - write_scc(priv, R15, 0); - break; - case Z85230: - /* Select WR7' */ - write_scc(priv, R15, SHDLCE); - /* The following bits are set (see 2.5.2.1): - - Automatic EOM reset - - Interrupt request if RX FIFO is half full - This bit should be ignored in DMA mode (according to the - documentation), but actually isn't. The receiver doesn't work if - it is set. Thus, we have to clear it in DMA mode. - - Interrupt/DMA request if TX FIFO is completely empty - a) If set, the ESCC behaves as if it had no TX FIFO (Z85C30 - compatibility). - b) If cleared, DMA requests may follow each other very quickly, - filling up the TX FIFO. - Advantage: TX works even in case of high bus latency. - Disadvantage: Edge-triggered DMA request circuitry may miss - a request. No more data is delivered, resulting - in a TX FIFO underrun. - Both PI2 and S5SCC/DMA seem to work fine with TXFIFOE cleared. - The PackeTwin doesn't. I don't know about the PI, but let's - assume it behaves like the PI2. - */ - if (priv->param.dma >= 0) { - if (priv->type == TYPE_TWIN) - write_scc(priv, R7, AUTOEOM | TXFIFOE); - else - write_scc(priv, R7, AUTOEOM); - } else { - write_scc(priv, R7, AUTOEOM | RXFIFOH); - } - write_scc(priv, R15, 0); - break; - } - /* Preset CRC, NRZ(I) encoding */ - write_scc(priv, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ)); - - /* Configure baud rate generator */ - if (priv->param.brg_tc >= 0) { - /* Program BR generator */ - write_scc(priv, R12, priv->param.brg_tc & 0xFF); - write_scc(priv, R13, (priv->param.brg_tc >> 8) & 0xFF); - /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by - PackeTwin, not connected on the PI2); set DPLL source to BRG */ - write_scc(priv, R14, SSBR | DTRREQ | BRSRC | BRENABL); - /* Enable DPLL */ - write_scc(priv, R14, SEARCH | DTRREQ | BRSRC | BRENABL); - } else { - /* Disable BR generator */ - write_scc(priv, R14, DTRREQ | BRSRC); - } - - /* Configure clocks */ - if (priv->type == TYPE_TWIN) { - /* Disable external TX clock receiver */ - outb((info->twin_serial_cfg &= - ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), - card_base + TWIN_SERIAL_CFG); - } - write_scc(priv, R11, priv->param.clocks); - if ((priv->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) { - /* Enable external TX clock receiver */ - outb((info->twin_serial_cfg |= - (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), - card_base + TWIN_SERIAL_CFG); - } - - /* Configure PackeTwin */ - if (priv->type == TYPE_TWIN) { - /* Assert DTR, enable interrupts */ - outb((info->twin_serial_cfg |= TWIN_EI | - (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)), - card_base + TWIN_SERIAL_CFG); - } - - /* Read current status */ - priv->rr0 = read_scc(priv, R0); - /* Enable DCD interrupt */ - write_scc(priv, R15, DCDIE); - - netif_start_queue(dev); - - return 0; -} - - -static int scc_close(struct net_device *dev) -{ - struct scc_priv *priv = dev->ml_priv; - struct scc_info *info = priv->info; - int card_base = priv->card_base; - - netif_stop_queue(dev); - - if (priv->type == TYPE_TWIN) { - /* Drop DTR */ - outb((info->twin_serial_cfg &= - (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)), - card_base + TWIN_SERIAL_CFG); - } - - /* Reset channel, free DMA and IRQ */ - write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); - if (priv->param.dma >= 0) { - if (priv->type == TYPE_TWIN) - outb(0, card_base + TWIN_DMA_CFG); - free_dma(priv->param.dma); - } - if (--info->irq_used == 0) - free_irq(dev->irq, info); - - return 0; -} - - -static int scc_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void __user *data, int cmd) -{ - struct scc_priv *priv = dev->ml_priv; - - switch (cmd) { - case SIOCGSCCPARAM: - if (copy_to_user(data, &priv->param, sizeof(struct scc_param))) - return -EFAULT; - return 0; - case SIOCSSCCPARAM: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (netif_running(dev)) - return -EAGAIN; - if (copy_from_user(&priv->param, data, - sizeof(struct scc_param))) - return -EFAULT; - return 0; - default: - return -EOPNOTSUPP; - } -} - - -static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct scc_priv *priv = dev->ml_priv; - unsigned long flags; - int i; - - if (skb->protocol == htons(ETH_P_IP)) - return ax25_ip_xmit(skb); - - /* Temporarily stop the scheduler feeding us packets */ - netif_stop_queue(dev); - - /* Transfer data to DMA buffer */ - i = priv->tx_head; - skb_copy_from_linear_data_offset(skb, 1, priv->tx_buf[i], skb->len - 1); - priv->tx_len[i] = skb->len - 1; - - /* Clear interrupts while we touch our circular buffers */ - - spin_lock_irqsave(&priv->ring_lock, flags); - /* Move the ring buffer's head */ - priv->tx_head = (i + 1) % NUM_TX_BUF; - priv->tx_count++; - - /* If we just filled up the last buffer, leave queue stopped. - The higher layers must wait until we have a DMA buffer - to accept the data. */ - if (priv->tx_count < NUM_TX_BUF) - netif_wake_queue(dev); - - /* Set new TX state */ - if (priv->state == IDLE) { - /* Assert RTS, start timer */ - priv->state = TX_HEAD; - priv->tx_start = jiffies; - write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); - write_scc(priv, R15, 0); - start_timer(priv, priv->param.txdelay, 0); - } - - /* Turn interrupts back on and free buffer */ - spin_unlock_irqrestore(&priv->ring_lock, flags); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - - -static int scc_set_mac_address(struct net_device *dev, void *sa) -{ - dev_addr_set(dev, ((struct sockaddr *)sa)->sa_data); - return 0; -} - - -static inline void tx_on(struct scc_priv *priv) -{ - int i, n; - unsigned long flags; - - if (priv->param.dma >= 0) { - n = (priv->chip == Z85230) ? 3 : 1; - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_WRITE); - set_dma_addr(priv->param.dma, - virt_to_bus(priv->tx_buf[priv->tx_tail]) + n); - set_dma_count(priv->param.dma, - priv->tx_len[priv->tx_tail] - n); - release_dma_lock(flags); - /* Enable TX underrun interrupt */ - write_scc(priv, R15, TxUIE); - /* Configure DREQ */ - if (priv->type == TYPE_TWIN) - outb((priv->param.dma == - 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, - priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, - EXT_INT_ENAB | WT_FN_RDYFN | - WT_RDY_ENAB); - /* Write first byte(s) */ - spin_lock_irqsave(priv->register_lock, flags); - for (i = 0; i < n; i++) - write_scc_data(priv, - priv->tx_buf[priv->tx_tail][i], 1); - enable_dma(priv->param.dma); - spin_unlock_irqrestore(priv->register_lock, flags); - } else { - write_scc(priv, R15, TxUIE); - write_scc(priv, R1, - EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); - tx_isr(priv); - } - /* Reset EOM latch if we do not have the AUTOEOM feature */ - if (priv->chip == Z8530) - write_scc(priv, R0, RES_EOM_L); -} - - -static inline void rx_on(struct scc_priv *priv) -{ - unsigned long flags; - - /* Clear RX FIFO */ - while (read_scc(priv, R0) & Rx_CH_AV) - read_scc_data(priv); - priv->rx_over = 0; - if (priv->param.dma >= 0) { - /* Program DMA controller */ - flags = claim_dma_lock(); - set_dma_mode(priv->param.dma, DMA_MODE_READ); - set_dma_addr(priv->param.dma, - virt_to_bus(priv->rx_buf[priv->rx_head])); - set_dma_count(priv->param.dma, BUF_SIZE); - release_dma_lock(flags); - enable_dma(priv->param.dma); - /* Configure PackeTwin DMA */ - if (priv->type == TYPE_TWIN) { - outb((priv->param.dma == - 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, - priv->card_base + TWIN_DMA_CFG); - } - /* Sp. cond. intr. only, ext int enable, RX DMA enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | - WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); - } else { - /* Reset current frame */ - priv->rx_ptr = 0; - /* Intr. on all Rx characters and Sp. cond., ext int enable */ - write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | - WT_FN_RDYFN); - } - write_scc(priv, R0, ERR_RES); - write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); -} - - -static inline void rx_off(struct scc_priv *priv) -{ - /* Disable receiver */ - write_scc(priv, R3, Rx8); - /* Disable DREQ / RX interrupt */ - if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) - outb(0, priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - /* Disable DMA */ - if (priv->param.dma >= 0) - disable_dma(priv->param.dma); -} - - -static void start_timer(struct scc_priv *priv, int t, int r15) -{ - outb(priv->tmr_mode, priv->tmr_ctrl); - if (t == 0) { - tm_isr(priv); - } else if (t > 0) { - outb(t & 0xFF, priv->tmr_cnt); - outb((t >> 8) & 0xFF, priv->tmr_cnt); - if (priv->type != TYPE_TWIN) { - write_scc(priv, R15, r15 | CTSIE); - priv->rr0 |= CTS; - } - } -} - - -static inline unsigned char random(void) -{ - /* See "Numerical Recipes in C", second edition, p. 284 */ - rand = rand * 1664525L + 1013904223L; - return (unsigned char) (rand >> 24); -} - -static inline void z8530_isr(struct scc_info *info) -{ - int is, i = 100; - - while ((is = read_scc(&info->priv[0], R3)) && i--) { - if (is & CHARxIP) { - rx_isr(&info->priv[0]); - } else if (is & CHATxIP) { - tx_isr(&info->priv[0]); - } else if (is & CHAEXT) { - es_isr(&info->priv[0]); - } else if (is & CHBRxIP) { - rx_isr(&info->priv[1]); - } else if (is & CHBTxIP) { - tx_isr(&info->priv[1]); - } else { - es_isr(&info->priv[1]); - } - write_scc(&info->priv[0], R0, RES_H_IUS); - i++; - } - if (i < 0) { - printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n", - is); - } - /* Ok, no interrupts pending from this 8530. The INT line should - be inactive now. */ -} - - -static irqreturn_t scc_isr(int irq, void *dev_id) -{ - struct scc_info *info = dev_id; - - spin_lock(info->priv[0].register_lock); - /* At this point interrupts are enabled, and the interrupt under service - is already acknowledged, but masked off. - - Interrupt processing: We loop until we know that the IRQ line is - low. If another positive edge occurs afterwards during the ISR, - another interrupt will be triggered by the interrupt controller - as soon as the IRQ level is enabled again (see asm/irq.h). - - Bottom-half handlers will be processed after scc_isr(). This is - important, since we only have small ringbuffers and want new data - to be fetched/delivered immediately. */ - - if (info->priv[0].type == TYPE_TWIN) { - int is, card_base = info->priv[0].card_base; - while ((is = ~inb(card_base + TWIN_INT_REG)) & - TWIN_INT_MSK) { - if (is & TWIN_SCC_MSK) { - z8530_isr(info); - } else if (is & TWIN_TMR1_MSK) { - inb(card_base + TWIN_CLR_TMR1); - tm_isr(&info->priv[0]); - } else { - inb(card_base + TWIN_CLR_TMR2); - tm_isr(&info->priv[1]); - } - } - } else - z8530_isr(info); - spin_unlock(info->priv[0].register_lock); - return IRQ_HANDLED; -} - - -static void rx_isr(struct scc_priv *priv) -{ - if (priv->param.dma >= 0) { - /* Check special condition and perform error reset. See 2.4.7.5. */ - special_condition(priv, read_scc(priv, R1)); - write_scc(priv, R0, ERR_RES); - } else { - /* Check special condition for each character. Error reset not necessary. - Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */ - int rc; - while (read_scc(priv, R0) & Rx_CH_AV) { - rc = read_scc(priv, R1); - if (priv->rx_ptr < BUF_SIZE) - priv->rx_buf[priv->rx_head][priv-> - rx_ptr++] = - read_scc_data(priv); - else { - priv->rx_over = 2; - read_scc_data(priv); - } - special_condition(priv, rc); - } - } -} - - -static void special_condition(struct scc_priv *priv, int rc) -{ - int cb; - unsigned long flags; - - /* See Figure 2-15. Only overrun and EOF need to be checked. */ - - if (rc & Rx_OVR) { - /* Receiver overrun */ - priv->rx_over = 1; - if (priv->param.dma < 0) - write_scc(priv, R0, ERR_RES); - } else if (rc & END_FR) { - /* End of frame. Get byte count */ - if (priv->param.dma >= 0) { - flags = claim_dma_lock(); - cb = BUF_SIZE - get_dma_residue(priv->param.dma) - - 2; - release_dma_lock(flags); - } else { - cb = priv->rx_ptr - 2; - } - if (priv->rx_over) { - /* We had an overrun */ - priv->dev->stats.rx_errors++; - if (priv->rx_over == 2) - priv->dev->stats.rx_length_errors++; - else - priv->dev->stats.rx_fifo_errors++; - priv->rx_over = 0; - } else if (rc & CRC_ERR) { - /* Count invalid CRC only if packet length >= minimum */ - if (cb >= 15) { - priv->dev->stats.rx_errors++; - priv->dev->stats.rx_crc_errors++; - } - } else { - if (cb >= 15) { - if (priv->rx_count < NUM_RX_BUF - 1) { - /* Put good frame in FIFO */ - priv->rx_len[priv->rx_head] = cb; - priv->rx_head = - (priv->rx_head + - 1) % NUM_RX_BUF; - priv->rx_count++; - schedule_work(&priv->rx_work); - } else { - priv->dev->stats.rx_errors++; - priv->dev->stats.rx_over_errors++; - } - } - } - /* Get ready for new frame */ - if (priv->param.dma >= 0) { - flags = claim_dma_lock(); - set_dma_addr(priv->param.dma, - virt_to_bus(priv->rx_buf[priv->rx_head])); - set_dma_count(priv->param.dma, BUF_SIZE); - release_dma_lock(flags); - } else { - priv->rx_ptr = 0; - } - } -} - - -static void rx_bh(struct work_struct *ugli_api) -{ - struct scc_priv *priv = container_of(ugli_api, struct scc_priv, rx_work); - int i = priv->rx_tail; - int cb; - unsigned long flags; - struct sk_buff *skb; - unsigned char *data; - - spin_lock_irqsave(&priv->ring_lock, flags); - while (priv->rx_count) { - spin_unlock_irqrestore(&priv->ring_lock, flags); - cb = priv->rx_len[i]; - /* Allocate buffer */ - skb = dev_alloc_skb(cb + 1); - if (skb == NULL) { - /* Drop packet */ - priv->dev->stats.rx_dropped++; - } else { - /* Fill buffer */ - data = skb_put(skb, cb + 1); - data[0] = 0; - memcpy(&data[1], priv->rx_buf[i], cb); - skb->protocol = ax25_type_trans(skb, priv->dev); - netif_rx(skb); - priv->dev->stats.rx_packets++; - priv->dev->stats.rx_bytes += cb; - } - spin_lock_irqsave(&priv->ring_lock, flags); - /* Move tail */ - priv->rx_tail = i = (i + 1) % NUM_RX_BUF; - priv->rx_count--; - } - spin_unlock_irqrestore(&priv->ring_lock, flags); -} - - -static void tx_isr(struct scc_priv *priv) -{ - int i = priv->tx_tail, p = priv->tx_ptr; - - /* Suspend TX interrupts if we don't want to send anything. - See Figure 2-22. */ - if (p == priv->tx_len[i]) { - write_scc(priv, R0, RES_Tx_P); - return; - } - - /* Write characters */ - while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) { - write_scc_data(priv, priv->tx_buf[i][p++], 0); - } - - /* Reset EOM latch of Z8530 */ - if (!priv->tx_ptr && p && priv->chip == Z8530) - write_scc(priv, R0, RES_EOM_L); - - priv->tx_ptr = p; -} - - -static void es_isr(struct scc_priv *priv) -{ - int i, rr0, drr0, res; - unsigned long flags; - - /* Read status, reset interrupt bit (open latches) */ - rr0 = read_scc(priv, R0); - write_scc(priv, R0, RES_EXT_INT); - drr0 = priv->rr0 ^ rr0; - priv->rr0 = rr0; - - /* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since - it might have already been cleared again by AUTOEOM. */ - if (priv->state == TX_DATA) { - /* Get remaining bytes */ - i = priv->tx_tail; - if (priv->param.dma >= 0) { - disable_dma(priv->param.dma); - flags = claim_dma_lock(); - res = get_dma_residue(priv->param.dma); - release_dma_lock(flags); - } else { - res = priv->tx_len[i] - priv->tx_ptr; - priv->tx_ptr = 0; - } - /* Disable DREQ / TX interrupt */ - if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) - outb(0, priv->card_base + TWIN_DMA_CFG); - else - write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); - if (res) { - /* Update packet statistics */ - priv->dev->stats.tx_errors++; - priv->dev->stats.tx_fifo_errors++; - /* Other underrun interrupts may already be waiting */ - write_scc(priv, R0, RES_EXT_INT); - write_scc(priv, R0, RES_EXT_INT); - } else { - /* Update packet statistics */ - priv->dev->stats.tx_packets++; - priv->dev->stats.tx_bytes += priv->tx_len[i]; - /* Remove frame from FIFO */ - priv->tx_tail = (i + 1) % NUM_TX_BUF; - priv->tx_count--; - /* Inform upper layers */ - netif_wake_queue(priv->dev); - } - /* Switch state */ - write_scc(priv, R15, 0); - if (priv->tx_count && - time_is_after_jiffies(priv->tx_start + priv->param.txtimeout)) { - priv->state = TX_PAUSE; - start_timer(priv, priv->param.txpause, 0); - } else { - priv->state = TX_TAIL; - start_timer(priv, priv->param.txtail, 0); - } - } - - /* DCD transition */ - if (drr0 & DCD) { - if (rr0 & DCD) { - switch (priv->state) { - case IDLE: - case WAIT: - priv->state = DCD_ON; - write_scc(priv, R15, 0); - start_timer(priv, priv->param.dcdon, 0); - } - } else { - switch (priv->state) { - case RX_ON: - rx_off(priv); - priv->state = DCD_OFF; - write_scc(priv, R15, 0); - start_timer(priv, priv->param.dcdoff, 0); - } - } - } - - /* CTS transition */ - if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN) - tm_isr(priv); - -} - - -static void tm_isr(struct scc_priv *priv) -{ - switch (priv->state) { - case TX_HEAD: - case TX_PAUSE: - tx_on(priv); - priv->state = TX_DATA; - break; - case TX_TAIL: - write_scc(priv, R5, TxCRC_ENAB | Tx8); - priv->state = RTS_OFF; - if (priv->type != TYPE_TWIN) - write_scc(priv, R15, 0); - start_timer(priv, priv->param.rtsoff, 0); - break; - case RTS_OFF: - write_scc(priv, R15, DCDIE); - priv->rr0 = read_scc(priv, R0); - if (priv->rr0 & DCD) { - priv->dev->stats.collisions++; - rx_on(priv); - priv->state = RX_ON; - } else { - priv->state = WAIT; - start_timer(priv, priv->param.waittime, DCDIE); - } - break; - case WAIT: - if (priv->tx_count) { - priv->state = TX_HEAD; - priv->tx_start = jiffies; - write_scc(priv, R5, - TxCRC_ENAB | RTS | TxENAB | Tx8); - write_scc(priv, R15, 0); - start_timer(priv, priv->param.txdelay, 0); - } else { - priv->state = IDLE; - if (priv->type != TYPE_TWIN) - write_scc(priv, R15, DCDIE); - } - break; - case DCD_ON: - case DCD_OFF: - write_scc(priv, R15, DCDIE); - priv->rr0 = read_scc(priv, R0); - if (priv->rr0 & DCD) { - rx_on(priv); - priv->state = RX_ON; - } else { - priv->state = WAIT; - start_timer(priv, - random() / priv->param.persist * - priv->param.slottime, DCDIE); - } - break; - } -} diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 588b2333cdb8..dcb069dde66b 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -23,50 +23,6 @@ menuconfig WAN if WAN -# There is no way to detect a comtrol sv11 - force it modular for now. -config HOSTESS_SV11 - tristate "Comtrol Hostess SV-11 support" - depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS - help - Driver for Comtrol Hostess SV-11 network card which - operates on low speed synchronous serial links at up to - 256Kbps, supporting PPP and Cisco HDLC. - - The driver will be compiled as a module: the - module will be called hostess_sv11. - -# The COSA/SRP driver has not been tested as non-modular yet. -config COSA - tristate "COSA/SRP sync serial boards support" - depends on ISA && m && ISA_DMA_API && HDLC && VIRT_TO_BUS - help - Driver for COSA and SRP synchronous serial boards. - - These boards allow to connect synchronous serial devices (for example - base-band modems, or any other device with the X.21, V.24, V.35 or - V.36 interface) to your Linux box. The cards can work as the - character device, synchronous PPP network device, or the Cisco HDLC - network device. - - You will need user-space utilities COSA or SRP boards for downloading - the firmware to the cards and to set them up. Look at the - for more information. You can also - read the comment at the top of the for - details about the cards and the driver itself. - - The driver will be compiled as a module: the - module will be called cosa. - -# There is no way to detect a Sealevel board. Force it modular -config SEALEVEL_4021 - tristate "Sealevel Systems 4021 support" - depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS - help - This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. - - The driver will be compiled as a module: the - module will be called sealevel. - # Generic HDLC config HDLC tristate "Generic HDLC layer" diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 1cd42147b34f..5bec8fae47f8 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -14,9 +14,6 @@ obj-$(CONFIG_HDLC_FR) += hdlc_fr.o obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o obj-$(CONFIG_HDLC_X25) += hdlc_x25.o -obj-$(CONFIG_HOSTESS_SV11) += z85230.o hostess_sv11.o -obj-$(CONFIG_SEALEVEL_4021) += z85230.o sealevel.o -obj-$(CONFIG_COSA) += cosa.o obj-$(CONFIG_FARSYNC) += farsync.o obj-$(CONFIG_LAPBETHER) += lapbether.o diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c deleted file mode 100644 index 23d2954d9747..000000000000 --- a/drivers/net/wan/cosa.c +++ /dev/null @@ -1,2052 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* $Id: cosa.c,v 1.31 2000/03/08 17:47:16 kas Exp $ */ - -/* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak - * Generic HDLC port Copyright (C) 2008 Krzysztof Halasa - */ - -/* The driver for the SRP and COSA synchronous serial cards. - * - * HARDWARE INFO - * - * Both cards are developed at the Institute of Computer Science, - * Masaryk University (https://www.ics.muni.cz/). The hardware is - * developed by Jiri Novotny . More information - * and the photo of both cards is available at - * http://www.pavoucek.cz/cosa.html. The card documentation, firmwares - * and other goods can be downloaded from ftp://ftp.ics.muni.cz/pub/cosa/. - * For Linux-specific utilities, see below in the "Software info" section. - * If you want to order the card, contact Jiri Novotny. - * - * The SRP (serial port?, the Czech word "srp" means "sickle") card - * is a 2-port intelligent (with its own 8-bit CPU) synchronous serial card - * with V.24 interfaces up to 80kb/s each. - * - * The COSA (communication serial adapter?, the Czech word "kosa" means - * "scythe") is a next-generation sync/async board with two interfaces - * - currently any of V.24, X.21, V.35 and V.36 can be selected. - * It has a 16-bit SAB80166 CPU and can do up to 10 Mb/s per channel. - * The 8-channels version is in development. - * - * Both types have downloadable firmware and communicate via ISA DMA. - * COSA can be also a bus-mastering device. - * - * SOFTWARE INFO - * - * The homepage of the Linux driver is at https://www.fi.muni.cz/~kas/cosa/. - * The CVS tree of Linux driver can be viewed there, as well as the - * firmware binaries and user-space utilities for downloading the firmware - * into the card and setting up the card. - * - * The Linux driver (unlike the present *BSD drivers :-) can work even - * for the COSA and SRP in one computer and allows each channel to work - * in one of the two modes (character or network device). - * - * AUTHOR - * - * The Linux driver was written by Jan "Yenya" Kasprzak . - * - * You can mail me bugfixes and even success reports. I am especially - * interested in the SMP and/or muliti-channel success/failure reports - * (I wonder if I did the locking properly :-). - * - * THE AUTHOR USED THE FOLLOWING SOURCES WHEN PROGRAMMING THE DRIVER - * - * The COSA/SRP NetBSD driver by Zdenek Salvet and Ivos Cernohlavek - * The skeleton.c by Donald Becker - * The SDL Riscom/N2 driver by Mike Natale - * The Comtrol Hostess SV11 driver by Alan Cox - * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox - */ - -#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 - -#undef COSA_SLOW_IO /* for testing purposes only */ - -#include "cosa.h" - -/* Maximum length of the identification string. */ -#define COSA_MAX_ID_STRING 128 - -/* Maximum length of the channel name */ -#define COSA_MAX_NAME (sizeof("cosaXXXcXXX") + 1) - -/* Per-channel data structure */ - -struct channel_data { - int usage; /* Usage count; >0 for chrdev, -1 for netdev */ - int num; /* Number of the channel */ - struct cosa_data *cosa; /* Pointer to the per-card structure */ - int txsize; /* Size of transmitted data */ - char *txbuf; /* Transmit buffer */ - char name[COSA_MAX_NAME]; /* channel name */ - - /* The HW layer interface */ - /* routine called from the RX interrupt */ - char *(*setup_rx)(struct channel_data *channel, int size); - /* routine called when the RX is done (from the EOT interrupt) */ - int (*rx_done)(struct channel_data *channel); - /* routine called when the TX is done (from the EOT interrupt) */ - int (*tx_done)(struct channel_data *channel, int size); - - /* Character device parts */ - struct mutex rlock; - struct semaphore wsem; - char *rxdata; - int rxsize; - wait_queue_head_t txwaitq, rxwaitq; - int tx_status, rx_status; - - /* generic HDLC device parts */ - struct net_device *netdev; - struct sk_buff *rx_skb, *tx_skb; -}; - -/* cosa->firmware_status bits */ -#define COSA_FW_RESET BIT(0) /* Is the ROM monitor active? */ -#define COSA_FW_DOWNLOAD BIT(1) /* Is the microcode downloaded? */ -#define COSA_FW_START BIT(2) /* Is the microcode running? */ - -struct cosa_data { - int num; /* Card number */ - char name[COSA_MAX_NAME]; /* Card name - e.g "cosa0" */ - unsigned int datareg, statusreg; /* I/O ports */ - unsigned short irq, dma; /* IRQ and DMA number */ - unsigned short startaddr; /* Firmware start address */ - unsigned short busmaster; /* Use busmastering? */ - int nchannels; /* # of channels on this card */ - int driver_status; /* For communicating with firmware */ - int firmware_status; /* Downloaded, reseted, etc. */ - unsigned long rxbitmap, txbitmap;/* Bitmap of channels who are willing to send/receive data */ - unsigned long rxtx; /* RX or TX in progress? */ - int enabled; - int usage; /* usage count */ - int txchan, txsize, rxsize; - struct channel_data *rxchan; - char *bouncebuf; - char *txbuf, *rxbuf; - struct channel_data *chan; - spinlock_t lock; /* For exclusive operations on this structure */ - char id_string[COSA_MAX_ID_STRING]; /* ROM monitor ID string */ - char *type; /* card type */ -}; - -/* Define this if you want all the possible ports to be autoprobed. - * It is here but it probably is not a good idea to use this. - */ -/* #define COSA_ISA_AUTOPROBE 1*/ - -/* Character device major number. 117 was allocated for us. - * The value of 0 means to allocate a first free one. - */ -static DEFINE_MUTEX(cosa_chardev_mutex); -static int cosa_major = 117; - -/* Encoding of the minor numbers: - * The lowest CARD_MINOR_BITS bits means the channel on the single card, - * the highest bits means the card number. - */ -#define CARD_MINOR_BITS 4 /* How many bits in minor number are reserved - * for the single card - */ -/* The following depends on CARD_MINOR_BITS. Unfortunately, the "MODULE_STRING" - * macro doesn't like anything other than the raw number as an argument :-( - */ -#define MAX_CARDS 16 -/* #define MAX_CARDS (1 << (8-CARD_MINOR_BITS)) */ - -#define DRIVER_RX_READY 0x0001 -#define DRIVER_TX_READY 0x0002 -#define DRIVER_TXMAP_SHIFT 2 -#define DRIVER_TXMAP_MASK 0x0c /* FIXME: 0xfc for 8-channel version */ - -/* for cosa->rxtx - indicates whether either transmit or receive is - * in progress. These values are mean number of the bit. - */ -#define TXBIT 0 -#define RXBIT 1 -#define IRQBIT 2 - -#define COSA_MTU 2000 /* FIXME: I don't know this exactly */ - -#undef DEBUG_DATA //1 /* Dump the data read or written to the channel */ -#undef DEBUG_IRQS //1 /* Print the message when the IRQ is received */ -#undef DEBUG_IO //1 /* Dump the I/O traffic */ - -#define TX_TIMEOUT (5 * HZ) - -/* Maybe the following should be allocated dynamically */ -static struct cosa_data cosa_cards[MAX_CARDS]; -static int nr_cards; - -#ifdef COSA_ISA_AUTOPROBE -static int io[MAX_CARDS + 1] = {0x220, 0x228, 0x210, 0x218, 0,}; -/* NOTE: DMA is not autoprobed!!! */ -static int dma[MAX_CARDS + 1] = {1, 7, 1, 7, 1, 7, 1, 7, 0,}; -#else -static int io[MAX_CARDS + 1]; -static int dma[MAX_CARDS + 1]; -#endif -/* IRQ can be safely autoprobed */ -static int irq[MAX_CARDS + 1] = {-1, -1, -1, -1, -1, -1, 0,}; - -/* for class stuff*/ -static struct class *cosa_class; - -#ifdef MODULE -module_param_hw_array(io, int, ioport, NULL, 0); -MODULE_PARM_DESC(io, "The I/O bases of the COSA or SRP cards"); -module_param_hw_array(irq, int, irq, NULL, 0); -MODULE_PARM_DESC(irq, "The IRQ lines of the COSA or SRP cards"); -module_param_hw_array(dma, int, dma, NULL, 0); -MODULE_PARM_DESC(dma, "The DMA channels of the COSA or SRP cards"); - -MODULE_AUTHOR("Jan \"Yenya\" Kasprzak, "); -MODULE_DESCRIPTION("Modular driver for the COSA or SRP synchronous card"); -MODULE_LICENSE("GPL"); -#endif - -/* I use this mainly for testing purposes */ -#ifdef COSA_SLOW_IO -#define cosa_outb outb_p -#define cosa_outw outw_p -#define cosa_inb inb_p -#define cosa_inw inw_p -#else -#define cosa_outb outb -#define cosa_outw outw -#define cosa_inb inb -#define cosa_inw inw -#endif - -#define is_8bit(cosa) (!((cosa)->datareg & 0x08)) - -#define cosa_getstatus(cosa) (cosa_inb((cosa)->statusreg)) -#define cosa_putstatus(cosa, stat) (cosa_outb(stat, (cosa)->statusreg)) -#define cosa_getdata16(cosa) (cosa_inw((cosa)->datareg)) -#define cosa_getdata8(cosa) (cosa_inb((cosa)->datareg)) -#define cosa_putdata16(cosa, dt) (cosa_outw(dt, (cosa)->datareg)) -#define cosa_putdata8(cosa, dt) (cosa_outb(dt, (cosa)->datareg)) - -/* Initialization stuff */ -static int cosa_probe(int ioaddr, int irq, int dma); - -/* HW interface */ -static void cosa_enable_rx(struct channel_data *chan); -static void cosa_disable_rx(struct channel_data *chan); -static int cosa_start_tx(struct channel_data *channel, char *buf, int size); -static void cosa_kick(struct cosa_data *cosa); -static int cosa_dma_able(struct channel_data *chan, char *buf, int data); - -/* Network device stuff */ -static int cosa_net_attach(struct net_device *dev, unsigned short encoding, - unsigned short parity); -static int cosa_net_open(struct net_device *d); -static int cosa_net_close(struct net_device *d); -static void cosa_net_timeout(struct net_device *d, unsigned int txqueue); -static netdev_tx_t cosa_net_tx(struct sk_buff *skb, struct net_device *d); -static char *cosa_net_setup_rx(struct channel_data *channel, int size); -static int cosa_net_rx_done(struct channel_data *channel); -static int cosa_net_tx_done(struct channel_data *channel, int size); - -/* Character device */ -static char *chrdev_setup_rx(struct channel_data *channel, int size); -static int chrdev_rx_done(struct channel_data *channel); -static int chrdev_tx_done(struct channel_data *channel, int size); -static ssize_t cosa_read(struct file *file, - char __user *buf, size_t count, loff_t *ppos); -static ssize_t cosa_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static unsigned int cosa_poll(struct file *file, poll_table *poll); -static int cosa_open(struct inode *inode, struct file *file); -static int cosa_release(struct inode *inode, struct file *file); -static long cosa_chardev_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -#ifdef COSA_FASYNC_WORKING -static int cosa_fasync(struct inode *inode, struct file *file, int on); -#endif - -static const struct file_operations cosa_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cosa_read, - .write = cosa_write, - .poll = cosa_poll, - .unlocked_ioctl = cosa_chardev_ioctl, - .open = cosa_open, - .release = cosa_release, -#ifdef COSA_FASYNC_WORKING - .fasync = cosa_fasync, -#endif -}; - -/* Ioctls */ -static int cosa_start(struct cosa_data *cosa, int address); -static int cosa_reset(struct cosa_data *cosa); -static int cosa_download(struct cosa_data *cosa, void __user *a); -static int cosa_readmem(struct cosa_data *cosa, void __user *a); - -/* COSA/SRP ROM monitor */ -static int download(struct cosa_data *cosa, const char __user *data, int addr, int len); -static int startmicrocode(struct cosa_data *cosa, int address); -static int readmem(struct cosa_data *cosa, char __user *data, int addr, int len); -static int cosa_reset_and_read_id(struct cosa_data *cosa, char *id); - -/* Auxiliary functions */ -static int get_wait_data(struct cosa_data *cosa); -static int put_wait_data(struct cosa_data *cosa, int data); -static int puthexnumber(struct cosa_data *cosa, int number); -static void put_driver_status(struct cosa_data *cosa); -static void put_driver_status_nolock(struct cosa_data *cosa); - -/* Interrupt handling */ -static irqreturn_t cosa_interrupt(int irq, void *cosa); - -/* I/O ops debugging */ -#ifdef DEBUG_IO -static void debug_data_in(struct cosa_data *cosa, int data); -static void debug_data_out(struct cosa_data *cosa, int data); -static void debug_data_cmd(struct cosa_data *cosa, int data); -static void debug_status_in(struct cosa_data *cosa, int status); -static void debug_status_out(struct cosa_data *cosa, int status); -#endif - -static inline struct channel_data *dev_to_chan(struct net_device *dev) -{ - return (struct channel_data *)dev_to_hdlc(dev)->priv; -} - -/* ---------- Initialization stuff ---------- */ - -static int __init cosa_init(void) -{ - int i, err = 0; - - if (cosa_major > 0) { - if (register_chrdev(cosa_major, "cosa", &cosa_fops)) { - pr_warn("unable to get major %d\n", cosa_major); - err = -EIO; - goto out; - } - } else { - cosa_major = register_chrdev(0, "cosa", &cosa_fops); - if (!cosa_major) { - pr_warn("unable to register chardev\n"); - err = -EIO; - goto out; - } - } - for (i = 0; i < MAX_CARDS; i++) - cosa_cards[i].num = -1; - for (i = 0; io[i] != 0 && i < MAX_CARDS; i++) - cosa_probe(io[i], irq[i], dma[i]); - if (!nr_cards) { - pr_warn("no devices found\n"); - unregister_chrdev(cosa_major, "cosa"); - err = -ENODEV; - goto out; - } - cosa_class = class_create(THIS_MODULE, "cosa"); - if (IS_ERR(cosa_class)) { - err = PTR_ERR(cosa_class); - goto out_chrdev; - } - for (i = 0; i < nr_cards; i++) - device_create(cosa_class, NULL, MKDEV(cosa_major, i), NULL, - "cosa%d", i); - err = 0; - goto out; - -out_chrdev: - unregister_chrdev(cosa_major, "cosa"); -out: - return err; -} -module_init(cosa_init); - -static void __exit cosa_exit(void) -{ - struct cosa_data *cosa; - int i; - - for (i = 0; i < nr_cards; i++) - device_destroy(cosa_class, MKDEV(cosa_major, i)); - class_destroy(cosa_class); - - for (cosa = cosa_cards; nr_cards--; cosa++) { - /* Clean up the per-channel data */ - for (i = 0; i < cosa->nchannels; i++) { - /* Chardev driver has no alloc'd per-channel data */ - unregister_hdlc_device(cosa->chan[i].netdev); - free_netdev(cosa->chan[i].netdev); - } - /* Clean up the per-card data */ - kfree(cosa->chan); - kfree(cosa->bouncebuf); - free_irq(cosa->irq, cosa); - free_dma(cosa->dma); - release_region(cosa->datareg, is_8bit(cosa) ? 2 : 4); - } - unregister_chrdev(cosa_major, "cosa"); -} -module_exit(cosa_exit); - -static const struct net_device_ops cosa_ops = { - .ndo_open = cosa_net_open, - .ndo_stop = cosa_net_close, - .ndo_start_xmit = hdlc_start_xmit, - .ndo_siocwandev = hdlc_ioctl, - .ndo_tx_timeout = cosa_net_timeout, -}; - -static int cosa_probe(int base, int irq, int dma) -{ - struct cosa_data *cosa = cosa_cards + nr_cards; - int i, err = 0; - - memset(cosa, 0, sizeof(struct cosa_data)); - - /* Checking validity of parameters: */ - /* IRQ should be 2-7 or 10-15; negative IRQ means autoprobe */ - if ((irq >= 0 && irq < 2) || irq > 15 || (irq < 10 && irq > 7)) { - pr_info("invalid IRQ %d\n", irq); - return -1; - } - /* I/O address should be between 0x100 and 0x3ff and should be - * multiple of 8. - */ - if (base < 0x100 || base > 0x3ff || base & 0x7) { - pr_info("invalid I/O address 0x%x\n", base); - return -1; - } - /* DMA should be 0,1 or 3-7 */ - if (dma < 0 || dma == 4 || dma > 7) { - pr_info("invalid DMA %d\n", dma); - return -1; - } - /* and finally, on 16-bit COSA DMA should be 4-7 and - * I/O base should not be multiple of 0x10 - */ - if (((base & 0x8) && dma < 4) || (!(base & 0x8) && dma > 3)) { - pr_info("8/16 bit base and DMA mismatch (base=0x%x, dma=%d)\n", - base, dma); - return -1; - } - - cosa->dma = dma; - cosa->datareg = base; - cosa->statusreg = is_8bit(cosa) ? base + 1 : base + 2; - spin_lock_init(&cosa->lock); - - if (!request_region(base, is_8bit(cosa) ? 2 : 4, "cosa")) - return -1; - - if (cosa_reset_and_read_id(cosa, cosa->id_string) < 0) { - printk(KERN_DEBUG "probe at 0x%x failed.\n", base); - err = -1; - goto err_out; - } - - /* Test the validity of identification string */ - if (!strncmp(cosa->id_string, "SRP", 3)) { - cosa->type = "srp"; - } else if (!strncmp(cosa->id_string, "COSA", 4)) { - cosa->type = is_8bit(cosa) ? "cosa8" : "cosa16"; - } else { -/* Print a warning only if we are not autoprobing */ -#ifndef COSA_ISA_AUTOPROBE - pr_info("valid signature not found at 0x%x\n", base); -#endif - err = -1; - goto err_out; - } - /* Update the name of the region now we know the type of card */ - release_region(base, is_8bit(cosa) ? 2 : 4); - if (!request_region(base, is_8bit(cosa) ? 2 : 4, cosa->type)) { - printk(KERN_DEBUG "changing name at 0x%x failed.\n", base); - return -1; - } - - /* Now do IRQ autoprobe */ - if (irq < 0) { - unsigned long irqs; -/* pr_info("IRQ autoprobe\n"); */ - irqs = probe_irq_on(); - /* Enable interrupt on tx buffer empty (it sure is) - * really sure ? - * FIXME: When this code is not used as module, we should - * probably call udelay() instead of the interruptible sleep. - */ - set_current_state(TASK_INTERRUPTIBLE); - cosa_putstatus(cosa, SR_TX_INT_ENA); - schedule_timeout(msecs_to_jiffies(300)); - irq = probe_irq_off(irqs); - /* Disable all IRQs from the card */ - cosa_putstatus(cosa, 0); - /* Empty the received data register */ - cosa_getdata8(cosa); - - if (irq < 0) { - pr_info("multiple interrupts obtained (%d, board at 0x%x)\n", - irq, cosa->datareg); - err = -1; - goto err_out; - } - if (irq == 0) { - pr_info("no interrupt obtained (board at 0x%x)\n", - cosa->datareg); - /* return -1; */ - } - } - - cosa->irq = irq; - cosa->num = nr_cards; - cosa->usage = 0; - cosa->nchannels = 2; /* FIXME: how to determine this? */ - - if (request_irq(cosa->irq, cosa_interrupt, 0, cosa->type, cosa)) { - err = -1; - goto err_out; - } - if (request_dma(cosa->dma, cosa->type)) { - err = -1; - goto err_out1; - } - - cosa->bouncebuf = kmalloc(COSA_MTU, GFP_KERNEL | GFP_DMA); - if (!cosa->bouncebuf) { - err = -ENOMEM; - goto err_out2; - } - sprintf(cosa->name, "cosa%d", cosa->num); - - /* Initialize the per-channel data */ - cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL); - if (!cosa->chan) { - err = -ENOMEM; - goto err_out3; - } - - for (i = 0; i < cosa->nchannels; i++) { - struct channel_data *chan = &cosa->chan[i]; - - chan->cosa = cosa; - chan->num = i; - sprintf(chan->name, "cosa%dc%d", chan->cosa->num, i); - - /* Initialize the chardev data structures */ - mutex_init(&chan->rlock); - sema_init(&chan->wsem, 1); - - /* Register the network interface */ - chan->netdev = alloc_hdlcdev(chan); - if (!chan->netdev) { - pr_warn("%s: alloc_hdlcdev failed\n", chan->name); - err = -ENOMEM; - goto err_hdlcdev; - } - dev_to_hdlc(chan->netdev)->attach = cosa_net_attach; - dev_to_hdlc(chan->netdev)->xmit = cosa_net_tx; - chan->netdev->netdev_ops = &cosa_ops; - chan->netdev->watchdog_timeo = TX_TIMEOUT; - chan->netdev->base_addr = chan->cosa->datareg; - chan->netdev->irq = chan->cosa->irq; - chan->netdev->dma = chan->cosa->dma; - err = register_hdlc_device(chan->netdev); - if (err) { - netdev_warn(chan->netdev, - "register_hdlc_device() failed\n"); - free_netdev(chan->netdev); - goto err_hdlcdev; - } - } - - pr_info("cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n", - cosa->num, cosa->id_string, cosa->type, - cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels); - - return nr_cards++; - -err_hdlcdev: - while (i-- > 0) { - unregister_hdlc_device(cosa->chan[i].netdev); - free_netdev(cosa->chan[i].netdev); - } - kfree(cosa->chan); -err_out3: - kfree(cosa->bouncebuf); -err_out2: - free_dma(cosa->dma); -err_out1: - free_irq(cosa->irq, cosa); -err_out: - release_region(cosa->datareg, is_8bit(cosa) ? 2 : 4); - pr_notice("cosa%d: allocating resources failed\n", cosa->num); - return err; -} - -/*---------- network device ---------- */ - -static int cosa_net_attach(struct net_device *dev, unsigned short encoding, - unsigned short parity) -{ - if (encoding == ENCODING_NRZ && parity == PARITY_CRC16_PR1_CCITT) - return 0; - return -EINVAL; -} - -static int cosa_net_open(struct net_device *dev) -{ - struct channel_data *chan = dev_to_chan(dev); - int err; - unsigned long flags; - - if (!(chan->cosa->firmware_status & COSA_FW_START)) { - pr_notice("%s: start the firmware first (status %d)\n", - chan->cosa->name, chan->cosa->firmware_status); - return -EPERM; - } - spin_lock_irqsave(&chan->cosa->lock, flags); - if (chan->usage != 0) { - pr_warn("%s: cosa_net_open called with usage count %d\n", - chan->name, chan->usage); - spin_unlock_irqrestore(&chan->cosa->lock, flags); - return -EBUSY; - } - chan->setup_rx = cosa_net_setup_rx; - chan->tx_done = cosa_net_tx_done; - chan->rx_done = cosa_net_rx_done; - chan->usage = -1; - chan->cosa->usage++; - spin_unlock_irqrestore(&chan->cosa->lock, flags); - - err = hdlc_open(dev); - if (err) { - spin_lock_irqsave(&chan->cosa->lock, flags); - chan->usage = 0; - chan->cosa->usage--; - spin_unlock_irqrestore(&chan->cosa->lock, flags); - return err; - } - - netif_start_queue(dev); - cosa_enable_rx(chan); - return 0; -} - -static netdev_tx_t cosa_net_tx(struct sk_buff *skb, - struct net_device *dev) -{ - struct channel_data *chan = dev_to_chan(dev); - - netif_stop_queue(dev); - - chan->tx_skb = skb; - cosa_start_tx(chan, skb->data, skb->len); - return NETDEV_TX_OK; -} - -static void cosa_net_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct channel_data *chan = dev_to_chan(dev); - - if (test_bit(RXBIT, &chan->cosa->rxtx)) { - chan->netdev->stats.rx_errors++; - chan->netdev->stats.rx_missed_errors++; - } else { - chan->netdev->stats.tx_errors++; - chan->netdev->stats.tx_aborted_errors++; - } - cosa_kick(chan->cosa); - if (chan->tx_skb) { - dev_kfree_skb(chan->tx_skb); - chan->tx_skb = NULL; - } - netif_wake_queue(dev); -} - -static int cosa_net_close(struct net_device *dev) -{ - struct channel_data *chan = dev_to_chan(dev); - unsigned long flags; - - netif_stop_queue(dev); - hdlc_close(dev); - cosa_disable_rx(chan); - spin_lock_irqsave(&chan->cosa->lock, flags); - if (chan->rx_skb) { - kfree_skb(chan->rx_skb); - chan->rx_skb = NULL; - } - if (chan->tx_skb) { - kfree_skb(chan->tx_skb); - chan->tx_skb = NULL; - } - chan->usage = 0; - chan->cosa->usage--; - spin_unlock_irqrestore(&chan->cosa->lock, flags); - return 0; -} - -static char *cosa_net_setup_rx(struct channel_data *chan, int size) -{ - /* We can safely fall back to non-dma-able memory, because we have - * the cosa->bouncebuf pre-allocated. - */ - kfree_skb(chan->rx_skb); - chan->rx_skb = dev_alloc_skb(size); - if (!chan->rx_skb) { - pr_notice("%s: Memory squeeze, dropping packet\n", chan->name); - chan->netdev->stats.rx_dropped++; - return NULL; - } - netif_trans_update(chan->netdev); - return skb_put(chan->rx_skb, size); -} - -static int cosa_net_rx_done(struct channel_data *chan) -{ - if (!chan->rx_skb) { - pr_warn("%s: rx_done with empty skb!\n", chan->name); - chan->netdev->stats.rx_errors++; - chan->netdev->stats.rx_frame_errors++; - return 0; - } - chan->rx_skb->protocol = hdlc_type_trans(chan->rx_skb, chan->netdev); - chan->rx_skb->dev = chan->netdev; - skb_reset_mac_header(chan->rx_skb); - chan->netdev->stats.rx_packets++; - chan->netdev->stats.rx_bytes += chan->cosa->rxsize; - netif_rx(chan->rx_skb); - chan->rx_skb = NULL; - return 0; -} - -/* ARGSUSED */ -static int cosa_net_tx_done(struct channel_data *chan, int size) -{ - if (!chan->tx_skb) { - pr_warn("%s: tx_done with empty skb!\n", chan->name); - chan->netdev->stats.tx_errors++; - chan->netdev->stats.tx_aborted_errors++; - return 1; - } - dev_consume_skb_irq(chan->tx_skb); - chan->tx_skb = NULL; - chan->netdev->stats.tx_packets++; - chan->netdev->stats.tx_bytes += size; - netif_wake_queue(chan->netdev); - return 1; -} - -/*---------- Character device ---------- */ - -static ssize_t cosa_read(struct file *file, - char __user *buf, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct channel_data *chan = file->private_data; - struct cosa_data *cosa = chan->cosa; - char *kbuf; - - if (!(cosa->firmware_status & COSA_FW_START)) { - pr_notice("%s: start the firmware first (status %d)\n", - cosa->name, cosa->firmware_status); - return -EPERM; - } - if (mutex_lock_interruptible(&chan->rlock)) - return -ERESTARTSYS; - - chan->rxdata = kmalloc(COSA_MTU, GFP_DMA | GFP_KERNEL); - if (!chan->rxdata) { - mutex_unlock(&chan->rlock); - return -ENOMEM; - } - - chan->rx_status = 0; - cosa_enable_rx(chan); - spin_lock_irqsave(&cosa->lock, flags); - add_wait_queue(&chan->rxwaitq, &wait); - while (!chan->rx_status) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&cosa->lock, flags); - schedule(); - spin_lock_irqsave(&cosa->lock, flags); - if (signal_pending(current) && chan->rx_status == 0) { - chan->rx_status = 1; - remove_wait_queue(&chan->rxwaitq, &wait); - __set_current_state(TASK_RUNNING); - spin_unlock_irqrestore(&cosa->lock, flags); - mutex_unlock(&chan->rlock); - return -ERESTARTSYS; - } - } - remove_wait_queue(&chan->rxwaitq, &wait); - __set_current_state(TASK_RUNNING); - kbuf = chan->rxdata; - count = chan->rxsize; - spin_unlock_irqrestore(&cosa->lock, flags); - mutex_unlock(&chan->rlock); - - if (copy_to_user(buf, kbuf, count)) { - kfree(kbuf); - return -EFAULT; - } - kfree(kbuf); - return count; -} - -static char *chrdev_setup_rx(struct channel_data *chan, int size) -{ - /* Expect size <= COSA_MTU */ - chan->rxsize = size; - return chan->rxdata; -} - -static int chrdev_rx_done(struct channel_data *chan) -{ - if (chan->rx_status) { /* Reader has died */ - kfree(chan->rxdata); - up(&chan->wsem); - } - chan->rx_status = 1; - wake_up_interruptible(&chan->rxwaitq); - return 1; -} - -static ssize_t cosa_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - struct channel_data *chan = file->private_data; - struct cosa_data *cosa = chan->cosa; - unsigned long flags; - char *kbuf; - - if (!(cosa->firmware_status & COSA_FW_START)) { - pr_notice("%s: start the firmware first (status %d)\n", - cosa->name, cosa->firmware_status); - return -EPERM; - } - if (down_interruptible(&chan->wsem)) - return -ERESTARTSYS; - - if (count > COSA_MTU) - count = COSA_MTU; - - /* Allocate the buffer */ - kbuf = kmalloc(count, GFP_KERNEL | GFP_DMA); - if (!kbuf) { - up(&chan->wsem); - return -ENOMEM; - } - if (copy_from_user(kbuf, buf, count)) { - up(&chan->wsem); - kfree(kbuf); - return -EFAULT; - } - chan->tx_status = 0; - cosa_start_tx(chan, kbuf, count); - - spin_lock_irqsave(&cosa->lock, flags); - add_wait_queue(&chan->txwaitq, &wait); - while (!chan->tx_status) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&cosa->lock, flags); - schedule(); - spin_lock_irqsave(&cosa->lock, flags); - if (signal_pending(current) && chan->tx_status == 0) { - chan->tx_status = 1; - remove_wait_queue(&chan->txwaitq, &wait); - __set_current_state(TASK_RUNNING); - chan->tx_status = 1; - spin_unlock_irqrestore(&cosa->lock, flags); - up(&chan->wsem); - kfree(kbuf); - return -ERESTARTSYS; - } - } - remove_wait_queue(&chan->txwaitq, &wait); - __set_current_state(TASK_RUNNING); - up(&chan->wsem); - spin_unlock_irqrestore(&cosa->lock, flags); - kfree(kbuf); - return count; -} - -static int chrdev_tx_done(struct channel_data *chan, int size) -{ - if (chan->tx_status) { /* Writer was interrupted */ - kfree(chan->txbuf); - up(&chan->wsem); - } - chan->tx_status = 1; - wake_up_interruptible(&chan->txwaitq); - return 1; -} - -static __poll_t cosa_poll(struct file *file, poll_table *poll) -{ - pr_info("cosa_poll is here\n"); - return 0; -} - -static int cosa_open(struct inode *inode, struct file *file) -{ - struct cosa_data *cosa; - struct channel_data *chan; - unsigned long flags; - int n; - int ret = 0; - - mutex_lock(&cosa_chardev_mutex); - n = iminor(file_inode(file)) >> CARD_MINOR_BITS; - if (n >= nr_cards) { - ret = -ENODEV; - goto out; - } - cosa = cosa_cards + n; - - n = iminor(file_inode(file)) & ((1 << CARD_MINOR_BITS) - 1); - if (n >= cosa->nchannels) { - ret = -ENODEV; - goto out; - } - chan = cosa->chan + n; - - file->private_data = chan; - - spin_lock_irqsave(&cosa->lock, flags); - - if (chan->usage < 0) { /* in netdev mode */ - spin_unlock_irqrestore(&cosa->lock, flags); - ret = -EBUSY; - goto out; - } - cosa->usage++; - chan->usage++; - - chan->tx_done = chrdev_tx_done; - chan->setup_rx = chrdev_setup_rx; - chan->rx_done = chrdev_rx_done; - spin_unlock_irqrestore(&cosa->lock, flags); -out: - mutex_unlock(&cosa_chardev_mutex); - return ret; -} - -static int cosa_release(struct inode *inode, struct file *file) -{ - struct channel_data *channel = file->private_data; - struct cosa_data *cosa; - unsigned long flags; - - cosa = channel->cosa; - spin_lock_irqsave(&cosa->lock, flags); - cosa->usage--; - channel->usage--; - spin_unlock_irqrestore(&cosa->lock, flags); - return 0; -} - -#ifdef COSA_FASYNC_WORKING -static struct fasync_struct *fasync[256] = { NULL, }; - -/* To be done ... */ -static int cosa_fasync(struct inode *inode, struct file *file, int on) -{ - int port = iminor(inode); - - return fasync_helper(inode, file, on, &fasync[port]); -} -#endif - -/* ---------- Ioctls ---------- */ - -/* Ioctl subroutines can safely be made inline, because they are called - * only from cosa_ioctl(). - */ -static inline int cosa_reset(struct cosa_data *cosa) -{ - char idstring[COSA_MAX_ID_STRING]; - - if (cosa->usage > 1) - pr_info("cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->num, cosa->usage); - cosa->firmware_status &= ~(COSA_FW_RESET | COSA_FW_START); - if (cosa_reset_and_read_id(cosa, idstring) < 0) { - pr_notice("cosa%d: reset failed\n", cosa->num); - return -EIO; - } - pr_info("cosa%d: resetting device: %s\n", cosa->num, idstring); - cosa->firmware_status |= COSA_FW_RESET; - return 0; -} - -/* High-level function to download data into COSA memory. Calls download() */ -static inline int cosa_download(struct cosa_data *cosa, void __user *arg) -{ - struct cosa_download d; - int i; - - if (cosa->usage > 1) - pr_info("%s: WARNING: download of microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->name, cosa->usage); - if (!(cosa->firmware_status & COSA_FW_RESET)) { - pr_notice("%s: reset the card first (status %d)\n", - cosa->name, cosa->firmware_status); - return -EPERM; - } - - if (copy_from_user(&d, arg, sizeof(d))) - return -EFAULT; - - if (d.addr < 0 || d.addr > COSA_MAX_FIRMWARE_SIZE) - return -EINVAL; - if (d.len < 0 || d.len > COSA_MAX_FIRMWARE_SIZE) - return -EINVAL; - - /* If something fails, force the user to reset the card */ - cosa->firmware_status &= ~(COSA_FW_RESET | COSA_FW_DOWNLOAD); - - i = download(cosa, d.code, d.len, d.addr); - if (i < 0) { - pr_notice("cosa%d: microcode download failed: %d\n", - cosa->num, i); - return -EIO; - } - pr_info("cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n", - cosa->num, d.len, d.addr); - cosa->firmware_status |= COSA_FW_RESET | COSA_FW_DOWNLOAD; - return 0; -} - -/* High-level function to read COSA memory. Calls readmem() */ -static inline int cosa_readmem(struct cosa_data *cosa, void __user *arg) -{ - struct cosa_download d; - int i; - - if (cosa->usage > 1) - pr_info("cosa%d: WARNING: readmem requested with cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->num, cosa->usage); - if (!(cosa->firmware_status & COSA_FW_RESET)) { - pr_notice("%s: reset the card first (status %d)\n", - cosa->name, cosa->firmware_status); - return -EPERM; - } - - if (copy_from_user(&d, arg, sizeof(d))) - return -EFAULT; - - /* If something fails, force the user to reset the card */ - cosa->firmware_status &= ~COSA_FW_RESET; - - i = readmem(cosa, d.code, d.len, d.addr); - if (i < 0) { - pr_notice("cosa%d: reading memory failed: %d\n", cosa->num, i); - return -EIO; - } - pr_info("cosa%d: reading card memory - 0x%04x bytes at 0x%04x\n", - cosa->num, d.len, d.addr); - cosa->firmware_status |= COSA_FW_RESET; - return 0; -} - -/* High-level function to start microcode. Calls startmicrocode(). */ -static inline int cosa_start(struct cosa_data *cosa, int address) -{ - int i; - - if (cosa->usage > 1) - pr_info("cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n", - cosa->num, cosa->usage); - - if ((cosa->firmware_status & (COSA_FW_RESET | COSA_FW_DOWNLOAD)) - != (COSA_FW_RESET | COSA_FW_DOWNLOAD)) { - pr_notice("%s: download the microcode and/or reset the card first (status %d)\n", - cosa->name, cosa->firmware_status); - return -EPERM; - } - cosa->firmware_status &= ~COSA_FW_RESET; - i = startmicrocode(cosa, address); - if (i < 0) { - pr_notice("cosa%d: start microcode at 0x%04x failed: %d\n", - cosa->num, address, i); - return -EIO; - } - pr_info("cosa%d: starting microcode at 0x%04x\n", cosa->num, address); - cosa->startaddr = address; - cosa->firmware_status |= COSA_FW_START; - return 0; -} - -/* Buffer of size at least COSA_MAX_ID_STRING is expected */ -static inline int cosa_getidstr(struct cosa_data *cosa, char __user *string) -{ - int l = strlen(cosa->id_string) + 1; - - if (copy_to_user(string, cosa->id_string, l)) - return -EFAULT; - return l; -} - -/* Buffer of size at least COSA_MAX_ID_STRING is expected */ -static inline int cosa_gettype(struct cosa_data *cosa, char __user *string) -{ - int l = strlen(cosa->type) + 1; - - if (copy_to_user(string, cosa->type, l)) - return -EFAULT; - return l; -} - -static int cosa_ioctl_common(struct cosa_data *cosa, - struct channel_data *channel, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - - switch (cmd) { - case COSAIORSET: /* Reset the device */ - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - return cosa_reset(cosa); - case COSAIOSTRT: /* Start the firmware */ - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return cosa_start(cosa, arg); - case COSAIODOWNLD: /* Download the firmware */ - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - - return cosa_download(cosa, argp); - case COSAIORMEM: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return cosa_readmem(cosa, argp); - case COSAIORTYPE: - return cosa_gettype(cosa, argp); - case COSAIORIDSTR: - return cosa_getidstr(cosa, argp); - case COSAIONRCARDS: - return nr_cards; - case COSAIONRCHANS: - return cosa->nchannels; - case COSAIOBMSET: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - if (is_8bit(cosa)) - return -EINVAL; - if (arg != COSA_BM_OFF && arg != COSA_BM_ON) - return -EINVAL; - cosa->busmaster = arg; - return 0; - case COSAIOBMGET: - return cosa->busmaster; - } - return -ENOIOCTLCMD; -} - -static long cosa_chardev_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct channel_data *channel = file->private_data; - struct cosa_data *cosa; - long ret; - - mutex_lock(&cosa_chardev_mutex); - cosa = channel->cosa; - ret = cosa_ioctl_common(cosa, channel, cmd, arg); - mutex_unlock(&cosa_chardev_mutex); - return ret; -} - -/*---------- HW layer interface ---------- */ - -/* The higher layer can bind itself to the HW layer by setting the callbacks - * in the channel_data structure and by using these routines. - */ -static void cosa_enable_rx(struct channel_data *chan) -{ - struct cosa_data *cosa = chan->cosa; - - if (!test_and_set_bit(chan->num, &cosa->rxbitmap)) - put_driver_status(cosa); -} - -static void cosa_disable_rx(struct channel_data *chan) -{ - struct cosa_data *cosa = chan->cosa; - - if (test_and_clear_bit(chan->num, &cosa->rxbitmap)) - put_driver_status(cosa); -} - -/* FIXME: This routine probably should check for cosa_start_tx() called when - * the previous transmit is still unfinished. In this case the non-zero - * return value should indicate to the caller that the queuing(sp?) up - * the transmit has failed. - */ -static int cosa_start_tx(struct channel_data *chan, char *buf, int len) -{ - struct cosa_data *cosa = chan->cosa; - unsigned long flags; -#ifdef DEBUG_DATA - int i; - - pr_info("cosa%dc%d: starting tx(0x%x)", - chan->cosa->num, chan->num, len); - for (i = 0; i < len; i++) - pr_cont(" %02x", buf[i]&0xff); - pr_cont("\n"); -#endif - spin_lock_irqsave(&cosa->lock, flags); - chan->txbuf = buf; - chan->txsize = len; - if (len > COSA_MTU) - chan->txsize = COSA_MTU; - spin_unlock_irqrestore(&cosa->lock, flags); - - /* Tell the firmware we are ready */ - set_bit(chan->num, &cosa->txbitmap); - put_driver_status(cosa); - - return 0; -} - -static void put_driver_status(struct cosa_data *cosa) -{ - unsigned long flags; - int status; - - spin_lock_irqsave(&cosa->lock, flags); - - status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) - | (cosa->txbitmap ? DRIVER_TX_READY : 0) - | (cosa->txbitmap ? ~(cosa->txbitmap << DRIVER_TXMAP_SHIFT) - & DRIVER_TXMAP_MASK : 0); - if (!cosa->rxtx) { - if (cosa->rxbitmap | cosa->txbitmap) { - if (!cosa->enabled) { - cosa_putstatus(cosa, SR_RX_INT_ENA); -#ifdef DEBUG_IO - debug_status_out(cosa, SR_RX_INT_ENA); -#endif - cosa->enabled = 1; - } - } else if (cosa->enabled) { - cosa->enabled = 0; - cosa_putstatus(cosa, 0); -#ifdef DEBUG_IO - debug_status_out(cosa, 0); -#endif - } - cosa_putdata8(cosa, status); -#ifdef DEBUG_IO - debug_data_cmd(cosa, status); -#endif - } - spin_unlock_irqrestore(&cosa->lock, flags); -} - -static void put_driver_status_nolock(struct cosa_data *cosa) -{ - int status; - - status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) - | (cosa->txbitmap ? DRIVER_TX_READY : 0) - | (cosa->txbitmap ? ~(cosa->txbitmap << DRIVER_TXMAP_SHIFT) - & DRIVER_TXMAP_MASK : 0); - - if (cosa->rxbitmap | cosa->txbitmap) { - cosa_putstatus(cosa, SR_RX_INT_ENA); -#ifdef DEBUG_IO - debug_status_out(cosa, SR_RX_INT_ENA); -#endif - cosa->enabled = 1; - } else { - cosa_putstatus(cosa, 0); -#ifdef DEBUG_IO - debug_status_out(cosa, 0); -#endif - cosa->enabled = 0; - } - cosa_putdata8(cosa, status); -#ifdef DEBUG_IO - debug_data_cmd(cosa, status); -#endif -} - -/* The "kickme" function: When the DMA times out, this is called to - * clean up the driver status. - * FIXME: Preliminary support, the interface is probably wrong. - */ -static void cosa_kick(struct cosa_data *cosa) -{ - unsigned long flags, flags1; - char *s = "(probably) IRQ"; - - if (test_bit(RXBIT, &cosa->rxtx)) - s = "RX DMA"; - if (test_bit(TXBIT, &cosa->rxtx)) - s = "TX DMA"; - - pr_info("%s: %s timeout - restarting\n", cosa->name, s); - spin_lock_irqsave(&cosa->lock, flags); - cosa->rxtx = 0; - - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - release_dma_lock(flags1); - - /* FIXME: Anything else? */ - udelay(100); - cosa_putstatus(cosa, 0); - udelay(100); - (void)cosa_getdata8(cosa); - udelay(100); - cosa_putdata8(cosa, 0); - udelay(100); - put_driver_status_nolock(cosa); - spin_unlock_irqrestore(&cosa->lock, flags); -} - -/* Check if the whole buffer is DMA-able. It means it is below the 16M of - * physical memory and doesn't span the 64k boundary. For now it seems - * SKB's never do this, but we'll check this anyway. - */ -static int cosa_dma_able(struct channel_data *chan, char *buf, int len) -{ - static int count; - unsigned long b = (unsigned long)buf; - - if (b + len >= MAX_DMA_ADDRESS) - return 0; - if ((b ^ (b + len)) & 0x10000) { - if (count++ < 5) - pr_info("%s: packet spanning a 64k boundary\n", - chan->name); - return 0; - } - return 1; -} - -/* ---------- The SRP/COSA ROM monitor functions ---------- */ - -/* Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=", - * drivers need to say 4-digit hex number meaning start address of the microcode - * separated by a single space. Monitor replies by saying " =". Now driver - * has to write 4-digit hex number meaning the last byte address ended - * by a single space. Monitor has to reply with a space. Now the download - * begins. After the download monitor replies with "\r\n." (CR LF dot). - */ -static int download(struct cosa_data *cosa, const char __user *microcode, int length, int address) -{ - int i; - - if (put_wait_data(cosa, 'w') == -1) - return -1; - if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;} - if (get_wait_data(cosa) != '=') - return -3; - - if (puthexnumber(cosa, address) < 0) - return -4; - if (put_wait_data(cosa, ' ') == -1) - return -10; - if (get_wait_data(cosa) != ' ') - return -11; - if (get_wait_data(cosa) != '=') - return -12; - - if (puthexnumber(cosa, address + length - 1) < 0) - return -13; - if (put_wait_data(cosa, ' ') == -1) - return -18; - if (get_wait_data(cosa) != ' ') - return -19; - - while (length--) { - char c; -#ifndef SRP_DOWNLOAD_AT_BOOT - if (get_user(c, microcode)) - return -23; /* ??? */ -#else - c = *microcode; -#endif - if (put_wait_data(cosa, c) == -1) - return -20; - microcode++; - } - - if (get_wait_data(cosa) != '\r') - return -21; - if (get_wait_data(cosa) != '\n') - return -22; - if (get_wait_data(cosa) != '.') - return -23; -#if 0 - printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num); -#endif - return 0; -} - -/* Starting microcode is done via the "g" command of the SRP monitor. - * The chat should be the following: "g" "g=" "" - * "". - */ -static int startmicrocode(struct cosa_data *cosa, int address) -{ - if (put_wait_data(cosa, 'g') == -1) - return -1; - if (get_wait_data(cosa) != 'g') - return -2; - if (get_wait_data(cosa) != '=') - return -3; - - if (puthexnumber(cosa, address) < 0) - return -4; - if (put_wait_data(cosa, '\r') == -1) - return -5; - - if (get_wait_data(cosa) != '\r') - return -6; - if (get_wait_data(cosa) != '\r') - return -7; - if (get_wait_data(cosa) != '\n') - return -8; - if (get_wait_data(cosa) != '\r') - return -9; - if (get_wait_data(cosa) != '\n') - return -10; -#if 0 - printk(KERN_DEBUG "cosa%d: microcode started\n", cosa->num); -#endif - return 0; -} - -/* Reading memory is done via the "r" command of the SRP monitor. - * The chat is the following "r" "r=" " " " =" " " " " - * Then driver can read the data and the conversation is finished - * by SRP monitor sending "." (dot at the end). - * - * This routine is not needed during the normal operation and serves - * for debugging purposes only. - */ -static int readmem(struct cosa_data *cosa, char __user *microcode, int length, int address) -{ - if (put_wait_data(cosa, 'r') == -1) - return -1; - if ((get_wait_data(cosa)) != 'r') - return -2; - if ((get_wait_data(cosa)) != '=') - return -3; - - if (puthexnumber(cosa, address) < 0) - return -4; - if (put_wait_data(cosa, ' ') == -1) - return -5; - if (get_wait_data(cosa) != ' ') - return -6; - if (get_wait_data(cosa) != '=') - return -7; - - if (puthexnumber(cosa, address + length - 1) < 0) - return -8; - if (put_wait_data(cosa, ' ') == -1) - return -9; - if (get_wait_data(cosa) != ' ') - return -10; - - while (length--) { - char c; - int i; - - i = get_wait_data(cosa); - if (i == -1) { - pr_info("0x%04x bytes remaining\n", length); - return -11; - } - c = i; -#if 1 - if (put_user(c, microcode)) - return -23; /* ??? */ -#else - *microcode = c; -#endif - microcode++; - } - - if (get_wait_data(cosa) != '\r') - return -21; - if (get_wait_data(cosa) != '\n') - return -22; - if (get_wait_data(cosa) != '.') - return -23; -#if 0 - printk(KERN_DEBUG "cosa%d: readmem completed.\n", cosa->num); -#endif - return 0; -} - -/* This function resets the device and reads the initial prompt - * of the device's ROM monitor. - */ -static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring) -{ - int i = 0, id = 0, prev = 0, curr = 0; - - /* Reset the card ... */ - cosa_putstatus(cosa, 0); - cosa_getdata8(cosa); - cosa_putstatus(cosa, SR_RST); - msleep(500); - /* Disable all IRQs from the card */ - cosa_putstatus(cosa, 0); - - /* Try to read the ID string. The card then prints out the - * identification string ended by the "\n\x2e". - * - * The following loop is indexed through i (instead of id) - * to avoid looping forever when for any reason - * the port returns '\r', '\n' or '\x2e' permanently. - */ - for (i = 0; i < COSA_MAX_ID_STRING - 1; i++, prev = curr) { - curr = get_wait_data(cosa); - if (curr == -1) - return -1; - - curr &= 0xff; - if (curr != '\r' && curr != '\n' && curr != 0x2e) - idstring[id++] = curr; - if (curr == 0x2e && prev == '\n') - break; - } - /* Perhaps we should fail when i==COSA_MAX_ID_STRING-1 ? */ - idstring[id] = '\0'; - return id; -} - -/* ---------- Auxiliary routines for COSA/SRP monitor ---------- */ - -/* This routine gets the data byte from the card waiting for the SR_RX_RDY - * bit to be set in a loop. It should be used in the exceptional cases - * only (for example when resetting the card or downloading the firmware. - */ -static int get_wait_data(struct cosa_data *cosa) -{ - int retries = 1000; - - while (--retries) { - /* read data and return them */ - if (cosa_getstatus(cosa) & SR_RX_RDY) { - short r; - - r = cosa_getdata8(cosa); -#if 0 - pr_info("get_wait_data returning after %d retries\n", - 999 - retries); -#endif - return r; - } - /* sleep if not ready to read */ - schedule_timeout_interruptible(1); - } - pr_info("timeout in get_wait_data (status 0x%x)\n", - cosa_getstatus(cosa)); - return -1; -} - -/* This routine puts the data byte to the card waiting for the SR_TX_RDY - * bit to be set in a loop. It should be used in the exceptional cases - * only (for example when resetting the card or downloading the firmware). - */ -static int put_wait_data(struct cosa_data *cosa, int data) -{ - int retries = 1000; - - while (--retries) { - /* read data and return them */ - if (cosa_getstatus(cosa) & SR_TX_RDY) { - cosa_putdata8(cosa, data); -#if 0 - pr_info("Putdata: %d retries\n", 999 - retries); -#endif - return 0; - } -#if 0 - /* sleep if not ready to read */ - schedule_timeout_interruptible(1); -#endif - } - pr_info("cosa%d: timeout in put_wait_data (status 0x%x)\n", - cosa->num, cosa_getstatus(cosa)); - return -1; -} - -/* The following routine puts the hexadecimal number into the SRP monitor - * and verifies the proper echo of the sent bytes. Returns 0 on success, - * negative number on failure (-1,-3,-5,-7) means that put_wait_data() failed, - * (-2,-4,-6,-8) means that reading echo failed. - */ -static int puthexnumber(struct cosa_data *cosa, int number) -{ - char temp[5]; - int i; - - /* Well, I should probably replace this by something faster. */ - sprintf(temp, "%04X", number); - for (i = 0; i < 4; i++) { - if (put_wait_data(cosa, temp[i]) == -1) { - pr_notice("cosa%d: puthexnumber failed to write byte %d\n", - cosa->num, i); - return -1 - 2 * i; - } - if (get_wait_data(cosa) != temp[i]) { - pr_notice("cosa%d: puthexhumber failed to read echo of byte %d\n", - cosa->num, i); - return -2 - 2 * i; - } - } - return 0; -} - -/* ---------- Interrupt routines ---------- */ - -/* There are three types of interrupt: - * At the beginning of transmit - this handled is in tx_interrupt(), - * at the beginning of receive - it is in rx_interrupt() and - * at the end of transmit/receive - it is the eot_interrupt() function. - * These functions are multiplexed by cosa_interrupt() according to the - * COSA status byte. I have moved the rx/tx/eot interrupt handling into - * separate functions to make it more readable. These functions are inline, - * so there should be no overhead of function call. - * - * In the COSA bus-master mode, we need to tell the card the address of a - * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait. - * It's time to use the bottom half :-( - */ - -/* Transmit interrupt routine - called when COSA is willing to obtain - * data from the OS. The most tricky part of the routine is selection - * of channel we (OS) want to send packet for. For SRP we should probably - * use the round-robin approach. The newer COSA firmwares have a simple - * flow-control - in the status word has bits 2 and 3 set to 1 means that the - * channel 0 or 1 doesn't want to receive data. - * - * It seems there is a bug in COSA firmware (need to trace it further): - * When the driver status says that the kernel has no more data for transmit - * (e.g. at the end of TX DMA) and then the kernel changes its mind - * (e.g. new packet is queued to hard_start_xmit()), the card issues - * the TX interrupt but does not mark the channel as ready-to-transmit. - * The fix seems to be to push the packet to COSA despite its request. - * We first try to obey the card's opinion, and then fall back to forced TX. - */ -static inline void tx_interrupt(struct cosa_data *cosa, int status) -{ - unsigned long flags, flags1; -#ifdef DEBUG_IRQS - pr_info("cosa%d: SR_DOWN_REQUEST status=0x%04x\n", cosa->num, status); -#endif - spin_lock_irqsave(&cosa->lock, flags); - set_bit(TXBIT, &cosa->rxtx); - if (!test_bit(IRQBIT, &cosa->rxtx)) { - /* flow control, see the comment above */ - int i = 0; - - if (!cosa->txbitmap) { - pr_warn("%s: No channel wants data in TX IRQ. Expect DMA timeout.\n", - cosa->name); - put_driver_status_nolock(cosa); - clear_bit(TXBIT, &cosa->rxtx); - spin_unlock_irqrestore(&cosa->lock, flags); - return; - } - while (1) { - cosa->txchan++; - i++; - if (cosa->txchan >= cosa->nchannels) - cosa->txchan = 0; - if (!(cosa->txbitmap & (1 << cosa->txchan))) - continue; - if (~status & - (1 << (cosa->txchan + DRIVER_TXMAP_SHIFT))) - break; - /* in second pass, accept first ready-to-TX channel */ - if (i > cosa->nchannels) { - /* Can be safely ignored */ -#ifdef DEBUG_IRQS - printk(KERN_DEBUG "%s: Forcing TX " - "to not-ready channel %d\n", - cosa->name, cosa->txchan); -#endif - break; - } - } - - cosa->txsize = cosa->chan[cosa->txchan].txsize; - if (cosa_dma_able(cosa->chan + cosa->txchan, - cosa->chan[cosa->txchan].txbuf, - cosa->txsize)) { - cosa->txbuf = cosa->chan[cosa->txchan].txbuf; - } else { - memcpy(cosa->bouncebuf, cosa->chan[cosa->txchan].txbuf, - cosa->txsize); - cosa->txbuf = cosa->bouncebuf; - } - } - - if (is_8bit(cosa)) { - if (!test_bit(IRQBIT, &cosa->rxtx)) { - cosa_putstatus(cosa, SR_TX_INT_ENA); - cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0) | - ((cosa->txsize >> 8) & 0x1f)); -#ifdef DEBUG_IO - debug_status_out(cosa, SR_TX_INT_ENA); - debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0) | - ((cosa->txsize >> 8) & 0x1f)); - debug_data_in(cosa, cosa_getdata8(cosa)); -#else - cosa_getdata8(cosa); -#endif - set_bit(IRQBIT, &cosa->rxtx); - spin_unlock_irqrestore(&cosa->lock, flags); - return; - } else { - clear_bit(IRQBIT, &cosa->rxtx); - cosa_putstatus(cosa, 0); - cosa_putdata8(cosa, cosa->txsize & 0xff); -#ifdef DEBUG_IO - debug_status_out(cosa, 0); - debug_data_out(cosa, cosa->txsize & 0xff); -#endif - } - } else { - cosa_putstatus(cosa, SR_TX_INT_ENA); - cosa_putdata16(cosa, ((cosa->txchan << 13) & 0xe000) - | (cosa->txsize & 0x1fff)); -#ifdef DEBUG_IO - debug_status_out(cosa, SR_TX_INT_ENA); - debug_data_out(cosa, ((cosa->txchan << 13) & 0xe000) | - (cosa->txsize & 0x1fff)); - debug_data_in(cosa, cosa_getdata8(cosa)); - debug_status_out(cosa, 0); -#else - cosa_getdata8(cosa); -#endif - cosa_putstatus(cosa, 0); - } - - if (cosa->busmaster) { - unsigned long addr = virt_to_bus(cosa->txbuf); - int count = 0; - - pr_info("busmaster IRQ\n"); - while (!(cosa_getstatus(cosa) & SR_TX_RDY)) { - count++; - udelay(10); - if (count > 1000) - break; - } - pr_info("status %x\n", cosa_getstatus(cosa)); - pr_info("ready after %d loops\n", count); - cosa_putdata16(cosa, (addr >> 16) & 0xffff); - - count = 0; - while (!(cosa_getstatus(cosa) & SR_TX_RDY)) { - count++; - if (count > 1000) - break; - udelay(10); - } - pr_info("ready after %d loops\n", count); - cosa_putdata16(cosa, addr & 0xffff); - flags1 = claim_dma_lock(); - set_dma_mode(cosa->dma, DMA_MODE_CASCADE); - enable_dma(cosa->dma); - release_dma_lock(flags1); - } else { - /* start the DMA */ - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - set_dma_mode(cosa->dma, DMA_MODE_WRITE); - set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf)); - set_dma_count(cosa->dma, cosa->txsize); - enable_dma(cosa->dma); - release_dma_lock(flags1); - } - cosa_putstatus(cosa, SR_TX_DMA_ENA | SR_USR_INT_ENA); -#ifdef DEBUG_IO - debug_status_out(cosa, SR_TX_DMA_ENA | SR_USR_INT_ENA); -#endif - spin_unlock_irqrestore(&cosa->lock, flags); -} - -static inline void rx_interrupt(struct cosa_data *cosa, int status) -{ - unsigned long flags; -#ifdef DEBUG_IRQS - pr_info("cosa%d: SR_UP_REQUEST\n", cosa->num); -#endif - - spin_lock_irqsave(&cosa->lock, flags); - set_bit(RXBIT, &cosa->rxtx); - - if (is_8bit(cosa)) { - if (!test_bit(IRQBIT, &cosa->rxtx)) { - set_bit(IRQBIT, &cosa->rxtx); - put_driver_status_nolock(cosa); - cosa->rxsize = cosa_getdata8(cosa) << 8; -#ifdef DEBUG_IO - debug_data_in(cosa, cosa->rxsize >> 8); -#endif - spin_unlock_irqrestore(&cosa->lock, flags); - return; - } else { - clear_bit(IRQBIT, &cosa->rxtx); - cosa->rxsize |= cosa_getdata8(cosa) & 0xff; -#ifdef DEBUG_IO - debug_data_in(cosa, cosa->rxsize & 0xff); -#endif -#if 0 - pr_info("cosa%d: receive rxsize = (0x%04x)\n", - cosa->num, cosa->rxsize); -#endif - } - } else { - cosa->rxsize = cosa_getdata16(cosa); -#ifdef DEBUG_IO - debug_data_in(cosa, cosa->rxsize); -#endif -#if 0 - pr_info("cosa%d: receive rxsize = (0x%04x)\n", - cosa->num, cosa->rxsize); -#endif - } - if (((cosa->rxsize & 0xe000) >> 13) >= cosa->nchannels) { - pr_warn("%s: rx for unknown channel (0x%04x)\n", - cosa->name, cosa->rxsize); - spin_unlock_irqrestore(&cosa->lock, flags); - goto reject; - } - cosa->rxchan = cosa->chan + ((cosa->rxsize & 0xe000) >> 13); - cosa->rxsize &= 0x1fff; - spin_unlock_irqrestore(&cosa->lock, flags); - - cosa->rxbuf = NULL; - if (cosa->rxchan->setup_rx) - cosa->rxbuf = cosa->rxchan->setup_rx(cosa->rxchan, cosa->rxsize); - - if (!cosa->rxbuf) { -reject: /* Reject the packet */ - pr_info("cosa%d: rejecting packet on channel %d\n", - cosa->num, cosa->rxchan->num); - cosa->rxbuf = cosa->bouncebuf; - } - - /* start the DMA */ - flags = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - set_dma_mode(cosa->dma, DMA_MODE_READ); - if (cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize & 0x1fff)) - set_dma_addr(cosa->dma, virt_to_bus(cosa->rxbuf)); - else - set_dma_addr(cosa->dma, virt_to_bus(cosa->bouncebuf)); - - set_dma_count(cosa->dma, (cosa->rxsize & 0x1fff)); - enable_dma(cosa->dma); - release_dma_lock(flags); - spin_lock_irqsave(&cosa->lock, flags); - cosa_putstatus(cosa, SR_RX_DMA_ENA | SR_USR_INT_ENA); - if (!is_8bit(cosa) && (status & SR_TX_RDY)) - cosa_putdata8(cosa, DRIVER_RX_READY); -#ifdef DEBUG_IO - debug_status_out(cosa, SR_RX_DMA_ENA | SR_USR_INT_ENA); - if (!is_8bit(cosa) && (status & SR_TX_RDY)) - debug_data_cmd(cosa, DRIVER_RX_READY); -#endif - spin_unlock_irqrestore(&cosa->lock, flags); -} - -static inline void eot_interrupt(struct cosa_data *cosa, int status) -{ - unsigned long flags, flags1; - - spin_lock_irqsave(&cosa->lock, flags); - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - release_dma_lock(flags1); - if (test_bit(TXBIT, &cosa->rxtx)) { - struct channel_data *chan = cosa->chan + cosa->txchan; - - if (chan->tx_done) - if (chan->tx_done(chan, cosa->txsize)) - clear_bit(chan->num, &cosa->txbitmap); - } else if (test_bit(RXBIT, &cosa->rxtx)) { -#ifdef DEBUG_DATA - { - int i; - - pr_info("cosa%dc%d: done rx(0x%x)", - cosa->num, cosa->rxchan->num, cosa->rxsize); - for (i = 0; i < cosa->rxsize; i++) - pr_cont(" %02x", cosa->rxbuf[i]&0xff); - pr_cont("\n"); - } -#endif - /* Packet for unknown channel? */ - if (cosa->rxbuf == cosa->bouncebuf) - goto out; - if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize)) - memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize); - if (cosa->rxchan->rx_done) - if (cosa->rxchan->rx_done(cosa->rxchan)) - clear_bit(cosa->rxchan->num, &cosa->rxbitmap); - } else { - pr_notice("cosa%d: unexpected EOT interrupt\n", cosa->num); - } - /* Clear the RXBIT, TXBIT and IRQBIT (the latest should be - * cleared anyway). We should do it as soon as possible - * so that we can tell the COSA we are done and to give it a time - * for recovery. - */ -out: - cosa->rxtx = 0; - put_driver_status_nolock(cosa); - spin_unlock_irqrestore(&cosa->lock, flags); -} - -static irqreturn_t cosa_interrupt(int irq, void *cosa_) -{ - unsigned status; - int count = 0; - struct cosa_data *cosa = cosa_; -again: - status = cosa_getstatus(cosa); -#ifdef DEBUG_IRQS - pr_info("cosa%d: got IRQ, status 0x%02x\n", cosa->num, status & 0xff); -#endif -#ifdef DEBUG_IO - debug_status_in(cosa, status); -#endif - switch (status & SR_CMD_FROM_SRP_MASK) { - case SR_DOWN_REQUEST: - tx_interrupt(cosa, status); - break; - case SR_UP_REQUEST: - rx_interrupt(cosa, status); - break; - case SR_END_OF_TRANSFER: - eot_interrupt(cosa, status); - break; - default: - /* We may be too fast for SRP. Try to wait a bit more. */ - if (count++ < 100) { - udelay(100); - goto again; - } - pr_info("cosa%d: unknown status 0x%02x in IRQ after %d retries\n", - cosa->num, status & 0xff, count); - } -#ifdef DEBUG_IRQS - if (count) - pr_info("%s: %d-times got unknown status in IRQ\n", - cosa->name, count); - else - pr_info("%s: returning from IRQ\n", cosa->name); -#endif - return IRQ_HANDLED; -} - -/* ---------- I/O debugging routines ---------- */ -/* These routines can be used to monitor COSA/SRP I/O and to printk() - * the data being transferred on the data and status I/O port in a - * readable way. - */ - -#ifdef DEBUG_IO -static void debug_status_in(struct cosa_data *cosa, int status) -{ - char *s; - - switch (status & SR_CMD_FROM_SRP_MASK) { - case SR_UP_REQUEST: - s = "RX_REQ"; - break; - case SR_DOWN_REQUEST: - s = "TX_REQ"; - break; - case SR_END_OF_TRANSFER: - s = "ET_REQ"; - break; - default: - s = "NO_REQ"; - break; - } - pr_info("%s: IO: status -> 0x%02x (%s%s%s%s)\n", - cosa->name, - status, - status & SR_USR_RQ ? "USR_RQ|" : "", - status & SR_TX_RDY ? "TX_RDY|" : "", - status & SR_RX_RDY ? "RX_RDY|" : "", - s); -} - -static void debug_status_out(struct cosa_data *cosa, int status) -{ - pr_info("%s: IO: status <- 0x%02x (%s%s%s%s%s%s)\n", - cosa->name, - status, - status & SR_RX_DMA_ENA ? "RXDMA|" : "!rxdma|", - status & SR_TX_DMA_ENA ? "TXDMA|" : "!txdma|", - status & SR_RST ? "RESET|" : "", - status & SR_USR_INT_ENA ? "USRINT|" : "!usrint|", - status & SR_TX_INT_ENA ? "TXINT|" : "!txint|", - status & SR_RX_INT_ENA ? "RXINT" : "!rxint"); -} - -static void debug_data_in(struct cosa_data *cosa, int data) -{ - pr_info("%s: IO: data -> 0x%04x\n", cosa->name, data); -} - -static void debug_data_out(struct cosa_data *cosa, int data) -{ - pr_info("%s: IO: data <- 0x%04x\n", cosa->name, data); -} - -static void debug_data_cmd(struct cosa_data *cosa, int data) -{ - pr_info("%s: IO: data <- 0x%04x (%s|%s)\n", - cosa->name, data, - data & SR_RDY_RCV ? "RX_RDY" : "!rx_rdy", - data & SR_RDY_SND ? "TX_RDY" : "!tx_rdy"); -} -#endif - -/* EOF -- this file has not been truncated */ diff --git a/drivers/net/wan/cosa.h b/drivers/net/wan/cosa.h deleted file mode 100644 index f57e0af9d56a..000000000000 --- a/drivers/net/wan/cosa.h +++ /dev/null @@ -1,104 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* $Id: cosa.h,v 1.6 1999/01/06 14:02:44 kas Exp $ */ - -/* - * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak - */ - -#ifndef COSA_H__ -#define COSA_H__ - -#include - -#ifdef __KERNEL__ -/* status register - output bits */ -#define SR_RX_DMA_ENA 0x04 /* receiver DMA enable bit */ -#define SR_TX_DMA_ENA 0x08 /* transmitter DMA enable bit */ -#define SR_RST 0x10 /* SRP reset */ -#define SR_USR_INT_ENA 0x20 /* user interrupt enable bit */ -#define SR_TX_INT_ENA 0x40 /* transmitter interrupt enable bit */ -#define SR_RX_INT_ENA 0x80 /* receiver interrupt enable bit */ - -/* status register - input bits */ -#define SR_USR_RQ 0x20 /* user interrupt request pending */ -#define SR_TX_RDY 0x40 /* transmitter empty (ready) */ -#define SR_RX_RDY 0x80 /* receiver data ready */ - -#define SR_UP_REQUEST 0x02 /* request from SRP to transfer data - up to PC */ -#define SR_DOWN_REQUEST 0x01 /* SRP is able to transfer data down - from PC to SRP */ -#define SR_END_OF_TRANSFER 0x03 /* SRP signalize end of - transfer (up or down) */ - -#define SR_CMD_FROM_SRP_MASK 0x03 /* mask to get SRP command */ - -/* bits in driver status byte definitions : */ -#define SR_RDY_RCV 0x01 /* ready to receive packet */ -#define SR_RDY_SND 0x02 /* ready to send packet */ -#define SR_CMD_PND 0x04 /* command pending */ /* not currently used */ - -/* ???? */ -#define SR_PKT_UP 0x01 /* transfer of packet up in progress */ -#define SR_PKT_DOWN 0x02 /* transfer of packet down in progress */ - -#endif /* __KERNEL__ */ - -#define SR_LOAD_ADDR 0x4400 /* SRP microcode load address */ -#define SR_START_ADDR 0x4400 /* SRP microcode start address */ - -#define COSA_LOAD_ADDR 0x400 /* SRP microcode load address */ -#define COSA_MAX_FIRMWARE_SIZE 0x10000 - -/* ioctls */ -struct cosa_download { - int addr, len; - char __user *code; -}; - -/* Reset the device */ -#define COSAIORSET _IO('C',0xf0) - -/* Start microcode at given address */ -#define COSAIOSTRT _IOW('C',0xf1, int) - -/* Read the block from the device memory */ -#define COSAIORMEM _IOWR('C',0xf2, struct cosa_download *) - /* actually the struct cosa_download itself; this is to keep - * the ioctl number same as in 2.4 in order to keep the user-space - * utils compatible. */ - -/* Write the block to the device memory (i.e. download the microcode) */ -#define COSAIODOWNLD _IOW('C',0xf2, struct cosa_download *) - /* actually the struct cosa_download itself; this is to keep - * the ioctl number same as in 2.4 in order to keep the user-space - * utils compatible. */ - -/* Read the device type (one of "srp", "cosa", and "cosa8" for now) */ -#define COSAIORTYPE _IOR('C',0xf3, char *) - -/* Read the device identification string */ -#define COSAIORIDSTR _IOR('C',0xf4, char *) -/* Maximum length of the identification string. */ -#define COSA_MAX_ID_STRING 128 - -/* Increment/decrement the module usage count :-) */ -/* #define COSAIOMINC _IO('C',0xf5) */ -/* #define COSAIOMDEC _IO('C',0xf6) */ - -/* Get the total number of cards installed */ -#define COSAIONRCARDS _IO('C',0xf7) - -/* Get the number of channels on this card */ -#define COSAIONRCHANS _IO('C',0xf8) - -/* Set the driver for the bus-master operations */ -#define COSAIOBMSET _IOW('C', 0xf9, unsigned short) - -#define COSA_BM_OFF 0 /* Bus-mastering off - use ISA DMA (default) */ -#define COSA_BM_ON 1 /* Bus-mastering on - faster but untested */ - -/* Gets the busmaster status */ -#define COSAIOBMGET _IO('C', 0xfa) - -#endif /* !COSA_H__ */ diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c deleted file mode 100644 index e985e54ba75d..000000000000 --- a/drivers/net/wan/hostess_sv11.c +++ /dev/null @@ -1,336 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Comtrol SV11 card driver - * - * This is a slightly odd Z85230 synchronous driver. All you need to - * know basically is - * - * Its a genuine Z85230 - * - * It supports DMA using two DMA channels in SYNC mode. The driver doesn't - * use these facilities - * - * The control port is at io+1, the data at io+3 and turning off the DMA - * is done by writing 0 to io+4 - * - * The hardware does the bus handling to avoid the need for delays between - * touching control registers. - * - * Port B isn't wired (why - beats me) - * - * Generic HDLC port Copyright (C) 2008 Krzysztof Halasa - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "z85230.h" - -static int dma; - -/* Network driver support routines - */ - -static inline struct z8530_dev *dev_to_sv(struct net_device *dev) -{ - return (struct z8530_dev *)dev_to_hdlc(dev)->priv; -} - -/* Frame receive. Simple for our card as we do HDLC and there - * is no funny garbage involved - */ - -static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) -{ - /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ - skb_trim(skb, skb->len - 2); - skb->protocol = hdlc_type_trans(skb, c->netdevice); - skb_reset_mac_header(skb); - skb->dev = c->netdevice; - /* Send it to the PPP layer. We don't have time to process - * it right now. - */ - netif_rx(skb); -} - -/* We've been placed in the UP state - */ - -static int hostess_open(struct net_device *d) -{ - struct z8530_dev *sv11 = dev_to_sv(d); - int err = -1; - - /* Link layer up - */ - switch (dma) { - case 0: - err = z8530_sync_open(d, &sv11->chanA); - break; - case 1: - err = z8530_sync_dma_open(d, &sv11->chanA); - break; - case 2: - err = z8530_sync_txdma_open(d, &sv11->chanA); - break; - } - - if (err) - return err; - - err = hdlc_open(d); - if (err) { - switch (dma) { - case 0: - z8530_sync_close(d, &sv11->chanA); - break; - case 1: - z8530_sync_dma_close(d, &sv11->chanA); - break; - case 2: - z8530_sync_txdma_close(d, &sv11->chanA); - break; - } - return err; - } - sv11->chanA.rx_function = hostess_input; - - /* - * Go go go - */ - - netif_start_queue(d); - return 0; -} - -static int hostess_close(struct net_device *d) -{ - struct z8530_dev *sv11 = dev_to_sv(d); - /* Discard new frames - */ - sv11->chanA.rx_function = z8530_null_rx; - - hdlc_close(d); - netif_stop_queue(d); - - switch (dma) { - case 0: - z8530_sync_close(d, &sv11->chanA); - break; - case 1: - z8530_sync_dma_close(d, &sv11->chanA); - break; - case 2: - z8530_sync_txdma_close(d, &sv11->chanA); - break; - } - return 0; -} - -/* Passed network frames, fire them downwind. - */ - -static netdev_tx_t hostess_queue_xmit(struct sk_buff *skb, - struct net_device *d) -{ - return z8530_queue_xmit(&dev_to_sv(d)->chanA, skb); -} - -static int hostess_attach(struct net_device *dev, unsigned short encoding, - unsigned short parity) -{ - if (encoding == ENCODING_NRZ && parity == PARITY_CRC16_PR1_CCITT) - return 0; - return -EINVAL; -} - -/* Description block for a Comtrol Hostess SV11 card - */ - -static const struct net_device_ops hostess_ops = { - .ndo_open = hostess_open, - .ndo_stop = hostess_close, - .ndo_start_xmit = hdlc_start_xmit, - .ndo_siocwandev = hdlc_ioctl, -}; - -static struct z8530_dev *sv11_init(int iobase, int irq) -{ - struct z8530_dev *sv; - struct net_device *netdev; - /* Get the needed I/O space - */ - - if (!request_region(iobase, 8, "Comtrol SV11")) { - pr_warn("I/O 0x%X already in use\n", iobase); - return NULL; - } - - sv = kzalloc(sizeof(struct z8530_dev), GFP_KERNEL); - if (!sv) - goto err_kzalloc; - - /* Stuff in the I/O addressing - */ - - sv->active = 0; - - sv->chanA.ctrlio = iobase + 1; - sv->chanA.dataio = iobase + 3; - sv->chanB.ctrlio = -1; - sv->chanB.dataio = -1; - sv->chanA.irqs = &z8530_nop; - sv->chanB.irqs = &z8530_nop; - - outb(0, iobase + 4); /* DMA off */ - - /* We want a fast IRQ for this device. Actually we'd like an even faster - * IRQ ;) - This is one driver RtLinux is made for - */ - - if (request_irq(irq, z8530_interrupt, 0, - "Hostess SV11", sv) < 0) { - pr_warn("IRQ %d already in use\n", irq); - goto err_irq; - } - - sv->irq = irq; - sv->chanA.private = sv; - sv->chanA.dev = sv; - sv->chanB.dev = sv; - - if (dma) { - /* You can have DMA off or 1 and 3 thats the lot - * on the Comtrol. - */ - sv->chanA.txdma = 3; - sv->chanA.rxdma = 1; - outb(0x03 | 0x08, iobase + 4); /* DMA on */ - if (request_dma(sv->chanA.txdma, "Hostess SV/11 (TX)")) - goto err_txdma; - - if (dma == 1) - if (request_dma(sv->chanA.rxdma, "Hostess SV/11 (RX)")) - goto err_rxdma; - } - - /* Kill our private IRQ line the hostess can end up chattering - * until the configuration is set - */ - disable_irq(irq); - - /* Begin normal initialise - */ - - if (z8530_init(sv)) { - pr_err("Z8530 series device not found\n"); - enable_irq(irq); - goto free_dma; - } - z8530_channel_load(&sv->chanB, z8530_dead_port); - if (sv->type == Z85C30) - z8530_channel_load(&sv->chanA, z8530_hdlc_kilostream); - else - z8530_channel_load(&sv->chanA, z8530_hdlc_kilostream_85230); - - enable_irq(irq); - - /* Now we can take the IRQ - */ - - sv->chanA.netdevice = netdev = alloc_hdlcdev(sv); - if (!netdev) - goto free_dma; - - dev_to_hdlc(netdev)->attach = hostess_attach; - dev_to_hdlc(netdev)->xmit = hostess_queue_xmit; - netdev->netdev_ops = &hostess_ops; - netdev->base_addr = iobase; - netdev->irq = irq; - - if (register_hdlc_device(netdev)) { - pr_err("unable to register HDLC device\n"); - free_netdev(netdev); - goto free_dma; - } - - z8530_describe(sv, "I/O", iobase); - sv->active = 1; - return sv; - -free_dma: - if (dma == 1) - free_dma(sv->chanA.rxdma); -err_rxdma: - if (dma) - free_dma(sv->chanA.txdma); -err_txdma: - free_irq(irq, sv); -err_irq: - kfree(sv); -err_kzalloc: - release_region(iobase, 8); - return NULL; -} - -static void sv11_shutdown(struct z8530_dev *dev) -{ - unregister_hdlc_device(dev->chanA.netdevice); - z8530_shutdown(dev); - free_irq(dev->irq, dev); - if (dma) { - if (dma == 1) - free_dma(dev->chanA.rxdma); - free_dma(dev->chanA.txdma); - } - release_region(dev->chanA.ctrlio - 1, 8); - free_netdev(dev->chanA.netdevice); - kfree(dev); -} - -static int io = 0x200; -static int irq = 9; - -module_param_hw(io, int, ioport, 0); -MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card"); -module_param_hw(dma, int, dma, 0); -MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX"); -module_param_hw(irq, int, irq, 0); -MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card"); - -MODULE_AUTHOR("Alan Cox"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11"); - -static struct z8530_dev *sv11_unit; - -static int sv11_module_init(void) -{ - sv11_unit = sv11_init(io, irq); - if (!sv11_unit) - return -ENODEV; - return 0; -} -module_init(sv11_module_init); - -static void sv11_module_cleanup(void) -{ - if (sv11_unit) - sv11_shutdown(sv11_unit); -} -module_exit(sv11_module_cleanup); diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c deleted file mode 100644 index eddd20aab691..000000000000 --- a/drivers/net/wan/sealevel.c +++ /dev/null @@ -1,352 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* Sealevel Systems 4021 driver. - * - * (c) Copyright 1999, 2001 Alan Cox - * (c) Copyright 2001 Red Hat Inc. - * Generic HDLC port Copyright (C) 2008 Krzysztof Halasa - */ - -#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 "z85230.h" - -struct slvl_device { - struct z8530_channel *chan; - int channel; -}; - -struct slvl_board { - struct slvl_device dev[2]; - struct z8530_dev board; - int iobase; -}; - - /* Network driver support routines */ - -static inline struct slvl_device *dev_to_chan(struct net_device *dev) -{ - return (struct slvl_device *)dev_to_hdlc(dev)->priv; -} - -/* Frame receive. Simple for our card as we do HDLC and there - * is no funny garbage involved - */ - -static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) -{ - /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ - skb_trim(skb, skb->len - 2); - skb->protocol = hdlc_type_trans(skb, c->netdevice); - skb_reset_mac_header(skb); - skb->dev = c->netdevice; - netif_rx(skb); -} - - /* We've been placed in the UP state */ - -static int sealevel_open(struct net_device *d) -{ - struct slvl_device *slvl = dev_to_chan(d); - int err = -1; - int unit = slvl->channel; - - /* Link layer up. */ - - switch (unit) { - case 0: - err = z8530_sync_dma_open(d, slvl->chan); - break; - case 1: - err = z8530_sync_open(d, slvl->chan); - break; - } - - if (err) - return err; - - err = hdlc_open(d); - if (err) { - switch (unit) { - case 0: - z8530_sync_dma_close(d, slvl->chan); - break; - case 1: - z8530_sync_close(d, slvl->chan); - break; - } - return err; - } - - slvl->chan->rx_function = sealevel_input; - - netif_start_queue(d); - return 0; -} - -static int sealevel_close(struct net_device *d) -{ - struct slvl_device *slvl = dev_to_chan(d); - int unit = slvl->channel; - - /* Discard new frames */ - - slvl->chan->rx_function = z8530_null_rx; - - hdlc_close(d); - netif_stop_queue(d); - - switch (unit) { - case 0: - z8530_sync_dma_close(d, slvl->chan); - break; - case 1: - z8530_sync_close(d, slvl->chan); - break; - } - return 0; -} - -/* Passed network frames, fire them downwind. */ - -static netdev_tx_t sealevel_queue_xmit(struct sk_buff *skb, - struct net_device *d) -{ - return z8530_queue_xmit(dev_to_chan(d)->chan, skb); -} - -static int sealevel_attach(struct net_device *dev, unsigned short encoding, - unsigned short parity) -{ - if (encoding == ENCODING_NRZ && parity == PARITY_CRC16_PR1_CCITT) - return 0; - return -EINVAL; -} - -static const struct net_device_ops sealevel_ops = { - .ndo_open = sealevel_open, - .ndo_stop = sealevel_close, - .ndo_start_xmit = hdlc_start_xmit, - .ndo_siocwandev = hdlc_ioctl, -}; - -static int slvl_setup(struct slvl_device *sv, int iobase, int irq) -{ - struct net_device *dev = alloc_hdlcdev(sv); - - if (!dev) - return -1; - - dev_to_hdlc(dev)->attach = sealevel_attach; - dev_to_hdlc(dev)->xmit = sealevel_queue_xmit; - dev->netdev_ops = &sealevel_ops; - dev->base_addr = iobase; - dev->irq = irq; - - if (register_hdlc_device(dev)) { - pr_err("unable to register HDLC device\n"); - free_netdev(dev); - return -1; - } - - sv->chan->netdevice = dev; - return 0; -} - -/* Allocate and setup Sealevel board. */ - -static __init struct slvl_board *slvl_init(int iobase, int irq, - int txdma, int rxdma, int slow) -{ - struct z8530_dev *dev; - struct slvl_board *b; - - /* Get the needed I/O space */ - - if (!request_region(iobase, 8, "Sealevel 4021")) { - pr_warn("I/O 0x%X already in use\n", iobase); - return NULL; - } - - b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL); - if (!b) - goto err_kzalloc; - - b->dev[0].chan = &b->board.chanA; - b->dev[0].channel = 0; - - b->dev[1].chan = &b->board.chanB; - b->dev[1].channel = 1; - - dev = &b->board; - - /* Stuff in the I/O addressing */ - - dev->active = 0; - - b->iobase = iobase; - - /* Select 8530 delays for the old board */ - - if (slow) - iobase |= Z8530_PORT_SLEEP; - - dev->chanA.ctrlio = iobase + 1; - dev->chanA.dataio = iobase; - dev->chanB.ctrlio = iobase + 3; - dev->chanB.dataio = iobase + 2; - - dev->chanA.irqs = &z8530_nop; - dev->chanB.irqs = &z8530_nop; - - /* Assert DTR enable DMA */ - - outb(3 | (1 << 7), b->iobase + 4); - - /* We want a fast IRQ for this device. Actually we'd like an even faster - * IRQ ;) - This is one driver RtLinux is made for - */ - - if (request_irq(irq, z8530_interrupt, 0, - "SeaLevel", dev) < 0) { - pr_warn("IRQ %d already in use\n", irq); - goto err_request_irq; - } - - dev->irq = irq; - dev->chanA.private = &b->dev[0]; - dev->chanB.private = &b->dev[1]; - dev->chanA.dev = dev; - dev->chanB.dev = dev; - - dev->chanA.txdma = 3; - dev->chanA.rxdma = 1; - if (request_dma(dev->chanA.txdma, "SeaLevel (TX)")) - goto err_dma_tx; - - if (request_dma(dev->chanA.rxdma, "SeaLevel (RX)")) - goto err_dma_rx; - - disable_irq(irq); - - /* Begin normal initialise */ - - if (z8530_init(dev) != 0) { - pr_err("Z8530 series device not found\n"); - enable_irq(irq); - goto free_hw; - } - if (dev->type == Z85C30) { - z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); - z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); - } else { - z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); - z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); - } - - /* Now we can take the IRQ */ - - enable_irq(irq); - - if (slvl_setup(&b->dev[0], iobase, irq)) - goto free_hw; - if (slvl_setup(&b->dev[1], iobase, irq)) - goto free_netdev0; - - z8530_describe(dev, "I/O", iobase); - dev->active = 1; - return b; - -free_netdev0: - unregister_hdlc_device(b->dev[0].chan->netdevice); - free_netdev(b->dev[0].chan->netdevice); -free_hw: - free_dma(dev->chanA.rxdma); -err_dma_rx: - free_dma(dev->chanA.txdma); -err_dma_tx: - free_irq(irq, dev); -err_request_irq: - kfree(b); -err_kzalloc: - release_region(iobase, 8); - return NULL; -} - -static void __exit slvl_shutdown(struct slvl_board *b) -{ - int u; - - z8530_shutdown(&b->board); - - for (u = 0; u < 2; u++) { - struct net_device *d = b->dev[u].chan->netdevice; - - unregister_hdlc_device(d); - free_netdev(d); - } - - free_irq(b->board.irq, &b->board); - free_dma(b->board.chanA.rxdma); - free_dma(b->board.chanA.txdma); - /* DMA off on the card, drop DTR */ - outb(0, b->iobase); - release_region(b->iobase, 8); - kfree(b); -} - -static int io = 0x238; -static int txdma = 1; -static int rxdma = 3; -static int irq = 5; -static bool slow; - -module_param_hw(io, int, ioport, 0); -MODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); -module_param_hw(txdma, int, dma, 0); -MODULE_PARM_DESC(txdma, "Transmit DMA channel"); -module_param_hw(rxdma, int, dma, 0); -MODULE_PARM_DESC(rxdma, "Receive DMA channel"); -module_param_hw(irq, int, irq, 0); -MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); -module_param(slow, bool, 0); -MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); - -MODULE_AUTHOR("Alan Cox"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); - -static struct slvl_board *slvl_unit; - -static int __init slvl_init_module(void) -{ - slvl_unit = slvl_init(io, irq, txdma, rxdma, slow); - - return slvl_unit ? 0 : -ENODEV; -} - -static void __exit slvl_cleanup_module(void) -{ - if (slvl_unit) - slvl_shutdown(slvl_unit); -} - -module_init(slvl_init_module); -module_exit(slvl_cleanup_module); diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c deleted file mode 100644 index 982a03488a00..000000000000 --- a/drivers/net/wan/z85230.c +++ /dev/null @@ -1,1641 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* (c) Copyright 1998 Alan Cox - * (c) Copyright 2000, 2001 Red Hat Inc - * - * Development of this driver was funded by Equiinet Ltd - * http://www.equiinet.com - * - * ChangeLog: - * - * Asynchronous mode dropped for 2.2. For 2.5 we will attempt the - * unification of all the Z85x30 asynchronous drivers for real. - * - * DMA now uses get_free_page as kmalloc buffers may span a 64K - * boundary. - * - * Modified for SMP safety and SMP locking by Alan Cox - * - * - * Performance - * - * Z85230: - * Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud - * X.25 is not unrealistic on all machines. DMA mode can in theory - * handle T1/E1 quite nicely. In practice the limit seems to be about - * 512Kbit->1Mbit depending on motherboard. - * - * Z85C30: - * 64K will take DMA, 9600 baud X.25 should be ok. - * - * Z8530: - * Synchronous mode without DMA is unlikely to pass about 2400 baud. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define RT_LOCK -#define RT_UNLOCK -#include - -#include "z85230.h" - -/** - * z8530_read_port - Architecture specific interface function - * @p: port to read - * - * Provided port access methods. The Comtrol SV11 requires no delays - * between accesses and uses PC I/O. Some drivers may need a 5uS delay - * - * In the longer term this should become an architecture specific - * section so that this can become a generic driver interface for all - * platforms. For now we only handle PC I/O ports with or without the - * dread 5uS sanity delay. - * - * The caller must hold sufficient locks to avoid violating the horrible - * 5uS delay rule. - */ - -static inline int z8530_read_port(unsigned long p) -{ - u8 r = inb(Z8530_PORT_OF(p)); - - if (p & Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */ - udelay(5); - return r; -} - -/** - * z8530_write_port - Architecture specific interface function - * @p: port to write - * @d: value to write - * - * Write a value to a port with delays if need be. Note that the - * caller must hold locks to avoid read/writes from other contexts - * violating the 5uS rule - * - * In the longer term this should become an architecture specific - * section so that this can become a generic driver interface for all - * platforms. For now we only handle PC I/O ports with or without the - * dread 5uS sanity delay. - */ - -static inline void z8530_write_port(unsigned long p, u8 d) -{ - outb(d, Z8530_PORT_OF(p)); - if (p & Z8530_PORT_SLEEP) - udelay(5); -} - -static void z8530_rx_done(struct z8530_channel *c); -static void z8530_tx_done(struct z8530_channel *c); - -/** - * read_zsreg - Read a register from a Z85230 - * @c: Z8530 channel to read from (2 per chip) - * @reg: Register to read - * FIXME: Use a spinlock. - * - * Most of the Z8530 registers are indexed off the control registers. - * A read is done by writing to the control register and reading the - * register back. The caller must hold the lock - */ - -static inline u8 read_zsreg(struct z8530_channel *c, u8 reg) -{ - if (reg) - z8530_write_port(c->ctrlio, reg); - return z8530_read_port(c->ctrlio); -} - -/** - * read_zsdata - Read the data port of a Z8530 channel - * @c: The Z8530 channel to read the data port from - * - * The data port provides fast access to some things. We still - * have all the 5uS delays to worry about. - */ - -static inline u8 read_zsdata(struct z8530_channel *c) -{ - u8 r; - - r = z8530_read_port(c->dataio); - return r; -} - -/** - * write_zsreg - Write to a Z8530 channel register - * @c: The Z8530 channel - * @reg: Register number - * @val: Value to write - * - * Write a value to an indexed register. The caller must hold the lock - * to honour the irritating delay rules. We know about register 0 - * being fast to access. - * - * Assumes c->lock is held. - */ -static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) -{ - if (reg) - z8530_write_port(c->ctrlio, reg); - z8530_write_port(c->ctrlio, val); -} - -/** - * write_zsctrl - Write to a Z8530 control register - * @c: The Z8530 channel - * @val: Value to write - * - * Write directly to the control register on the Z8530 - */ - -static inline void write_zsctrl(struct z8530_channel *c, u8 val) -{ - z8530_write_port(c->ctrlio, val); -} - -/** - * write_zsdata - Write to a Z8530 control register - * @c: The Z8530 channel - * @val: Value to write - * - * Write directly to the data register on the Z8530 - */ -static inline void write_zsdata(struct z8530_channel *c, u8 val) -{ - z8530_write_port(c->dataio, val); -} - -/* Register loading parameters for a dead port - */ - -u8 z8530_dead_port[] = { - 255 -}; -EXPORT_SYMBOL(z8530_dead_port); - -/* Register loading parameters for currently supported circuit types - */ - -/* Data clocked by telco end. This is the correct data for the UK - * "kilostream" service, and most other similar services. - */ - -u8 z8530_hdlc_kilostream[] = { - 4, SYNC_ENAB | SDLC | X1CLK, - 2, 0, /* No vector */ - 1, 0, - 3, ENT_HM | RxCRC_ENAB | Rx8, - 5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR, - 9, 0, /* Disable interrupts */ - 6, 0xFF, - 7, FLAG, - 10, ABUNDER | NRZ | CRCPS,/*MARKIDLE ??*/ - 11, TCTRxCP, - 14, DISDPLL, - 15, DCDIE | SYNCIE | CTSIE | TxUIE | BRKIE, - 1, EXT_INT_ENAB | TxINT_ENAB | INT_ALL_Rx, - 9, NV | MIE | NORESET, - 255 -}; -EXPORT_SYMBOL(z8530_hdlc_kilostream); - -/* As above but for enhanced chips. - */ - -u8 z8530_hdlc_kilostream_85230[] = { - 4, SYNC_ENAB | SDLC | X1CLK, - 2, 0, /* No vector */ - 1, 0, - 3, ENT_HM | RxCRC_ENAB | Rx8, - 5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR, - 9, 0, /* Disable interrupts */ - 6, 0xFF, - 7, FLAG, - 10, ABUNDER | NRZ | CRCPS, /* MARKIDLE?? */ - 11, TCTRxCP, - 14, DISDPLL, - 15, DCDIE | SYNCIE | CTSIE | TxUIE | BRKIE, - 1, EXT_INT_ENAB | TxINT_ENAB | INT_ALL_Rx, - 9, NV | MIE | NORESET, - 23, 3, /* Extended mode AUTO TX and EOM*/ - - 255 -}; -EXPORT_SYMBOL(z8530_hdlc_kilostream_85230); - -/** - * z8530_flush_fifo - Flush on chip RX FIFO - * @c: Channel to flush - * - * Flush the receive FIFO. There is no specific option for this, we - * blindly read bytes and discard them. Reading when there is no data - * is harmless. The 8530 has a 4 byte FIFO, the 85230 has 8 bytes. - * - * All locking is handled for the caller. On return data may still be - * present if it arrived during the flush. - */ - -static void z8530_flush_fifo(struct z8530_channel *c) -{ - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - if (c->dev->type == Z85230) { - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - read_zsreg(c, R1); - } -} - -/** - * z8530_rtsdtr - Control the outgoing DTS/RTS line - * @c: The Z8530 channel to control; - * @set: 1 to set, 0 to clear - * - * Sets or clears DTR/RTS on the requested line. All locking is handled - * by the caller. For now we assume all boards use the actual RTS/DTR - * on the chip. Apparently one or two don't. We'll scream about them - * later. - */ - -static void z8530_rtsdtr(struct z8530_channel *c, int set) -{ - if (set) - c->regs[5] |= (RTS | DTR); - else - c->regs[5] &= ~(RTS | DTR); - write_zsreg(c, R5, c->regs[5]); -} - -/** - * z8530_rx - Handle a PIO receive event - * @c: Z8530 channel to process - * - * Receive handler for receiving in PIO mode. This is much like the - * async one but not quite the same or as complex - * - * Note: Its intended that this handler can easily be separated from - * the main code to run realtime. That'll be needed for some machines - * (eg to ever clock 64kbits on a sparc ;)). - * - * The RT_LOCK macros don't do anything now. Keep the code covered - * by them as short as possible in all circumstances - clocks cost - * baud. The interrupt handler is assumed to be atomic w.r.t. to - * other code - this is true in the RT case too. - * - * We only cover the sync cases for this. If you want 2Mbit async - * do it yourself but consider medical assistance first. This non DMA - * synchronous mode is portable code. The DMA mode assumes PCI like - * ISA DMA - * - * Called with the device lock held - */ - -static void z8530_rx(struct z8530_channel *c) -{ - u8 ch, stat; - - while (1) { - /* FIFO empty ? */ - if (!(read_zsreg(c, R0) & 1)) - break; - ch = read_zsdata(c); - stat = read_zsreg(c, R1); - - /* Overrun ? - */ - if (c->count < c->max) { - *c->dptr++ = ch; - c->count++; - } - - if (stat & END_FR) { - /* Error ? - */ - if (stat & (Rx_OVR | CRC_ERR)) { - /* Rewind the buffer and return */ - if (c->skb) - c->dptr = c->skb->data; - c->count = 0; - if (stat & Rx_OVR) { - pr_warn("%s: overrun\n", c->dev->name); - c->rx_overrun++; - } - if (stat & CRC_ERR) { - c->rx_crc_err++; - /* printk("crc error\n"); */ - } - /* Shove the frame upstream */ - } else { - /* Drop the lock for RX processing, or - * there are deadlocks - */ - z8530_rx_done(c); - write_zsctrl(c, RES_Rx_CRC); - } - } - } - /* Clear irq - */ - write_zsctrl(c, ERR_RES); - write_zsctrl(c, RES_H_IUS); -} - -/** - * z8530_tx - Handle a PIO transmit event - * @c: Z8530 channel to process - * - * Z8530 transmit interrupt handler for the PIO mode. The basic - * idea is to attempt to keep the FIFO fed. We fill as many bytes - * in as possible, its quite possible that we won't keep up with the - * data rate otherwise. - */ - -static void z8530_tx(struct z8530_channel *c) -{ - while (c->txcount) { - /* FIFO full ? */ - if (!(read_zsreg(c, R0) & 4)) - return; - c->txcount--; - /* Shovel out the byte - */ - write_zsreg(c, R8, *c->tx_ptr++); - write_zsctrl(c, RES_H_IUS); - /* We are about to underflow */ - if (c->txcount == 0) { - write_zsctrl(c, RES_EOM_L); - write_zsreg(c, R10, c->regs[10] & ~ABUNDER); - } - } - - /* End of frame TX - fire another one - */ - - write_zsctrl(c, RES_Tx_P); - - z8530_tx_done(c); - write_zsctrl(c, RES_H_IUS); -} - -/** - * z8530_status - Handle a PIO status exception - * @chan: Z8530 channel to process - * - * A status event occurred in PIO synchronous mode. There are several - * reasons the chip will bother us here. A transmit underrun means we - * failed to feed the chip fast enough and just broke a packet. A DCD - * change is a line up or down. - */ - -static void z8530_status(struct z8530_channel *chan) -{ - u8 status, altered; - - status = read_zsreg(chan, R0); - altered = chan->status ^ status; - - chan->status = status; - - if (status & TxEOM) { -/* printk("%s: Tx underrun.\n", chan->dev->name); */ - chan->netdevice->stats.tx_fifo_errors++; - write_zsctrl(chan, ERR_RES); - z8530_tx_done(chan); - } - - if (altered & chan->dcdcheck) { - if (status & chan->dcdcheck) { - pr_info("%s: DCD raised\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3] | RxENABLE); - if (chan->netdevice) - netif_carrier_on(chan->netdevice); - } else { - pr_info("%s: DCD lost\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3] & ~RxENABLE); - z8530_flush_fifo(chan); - if (chan->netdevice) - netif_carrier_off(chan->netdevice); - } - } - write_zsctrl(chan, RES_EXT_INT); - write_zsctrl(chan, RES_H_IUS); -} - -struct z8530_irqhandler z8530_sync = { - .rx = z8530_rx, - .tx = z8530_tx, - .status = z8530_status, -}; -EXPORT_SYMBOL(z8530_sync); - -/** - * z8530_dma_rx - Handle a DMA RX event - * @chan: Channel to handle - * - * Non bus mastering DMA interfaces for the Z8x30 devices. This - * is really pretty PC specific. The DMA mode means that most receive - * events are handled by the DMA hardware. We get a kick here only if - * a frame ended. - */ - -static void z8530_dma_rx(struct z8530_channel *chan) -{ - if (chan->rxdma_on) { - /* Special condition check only */ - u8 status; - - read_zsreg(chan, R7); - read_zsreg(chan, R6); - - status = read_zsreg(chan, R1); - - if (status & END_FR) - z8530_rx_done(chan); /* Fire up the next one */ - - write_zsctrl(chan, ERR_RES); - write_zsctrl(chan, RES_H_IUS); - } else { - /* DMA is off right now, drain the slow way */ - z8530_rx(chan); - } -} - -/** - * z8530_dma_tx - Handle a DMA TX event - * @chan: The Z8530 channel to handle - * - * We have received an interrupt while doing DMA transmissions. It - * shouldn't happen. Scream loudly if it does. - */ -static void z8530_dma_tx(struct z8530_channel *chan) -{ - if (!chan->dma_tx) { - pr_warn("Hey who turned the DMA off?\n"); - z8530_tx(chan); - return; - } - /* This shouldn't occur in DMA mode */ - pr_err("DMA tx - bogus event!\n"); - z8530_tx(chan); -} - -/** - * z8530_dma_status - Handle a DMA status exception - * @chan: Z8530 channel to process - * - * A status event occurred on the Z8530. We receive these for two reasons - * when in DMA mode. Firstly if we finished a packet transfer we get one - * and kick the next packet out. Secondly we may see a DCD change. - * - */ -static void z8530_dma_status(struct z8530_channel *chan) -{ - u8 status, altered; - - status = read_zsreg(chan, R0); - altered = chan->status ^ status; - - chan->status = status; - - if (chan->dma_tx) { - if (status & TxEOM) { - unsigned long flags; - - flags = claim_dma_lock(); - disable_dma(chan->txdma); - clear_dma_ff(chan->txdma); - chan->txdma_on = 0; - release_dma_lock(flags); - z8530_tx_done(chan); - } - } - - if (altered & chan->dcdcheck) { - if (status & chan->dcdcheck) { - pr_info("%s: DCD raised\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3] | RxENABLE); - if (chan->netdevice) - netif_carrier_on(chan->netdevice); - } else { - pr_info("%s: DCD lost\n", chan->dev->name); - write_zsreg(chan, R3, chan->regs[3] & ~RxENABLE); - z8530_flush_fifo(chan); - if (chan->netdevice) - netif_carrier_off(chan->netdevice); - } - } - - write_zsctrl(chan, RES_EXT_INT); - write_zsctrl(chan, RES_H_IUS); -} - -static struct z8530_irqhandler z8530_dma_sync = { - .rx = z8530_dma_rx, - .tx = z8530_dma_tx, - .status = z8530_dma_status, -}; - -static struct z8530_irqhandler z8530_txdma_sync = { - .rx = z8530_rx, - .tx = z8530_dma_tx, - .status = z8530_dma_status, -}; - -/** - * z8530_rx_clear - Handle RX events from a stopped chip - * @c: Z8530 channel to shut up - * - * Receive interrupt vectors for a Z8530 that is in 'parked' mode. - * For machines with PCI Z85x30 cards, or level triggered interrupts - * (eg the MacII) we must clear the interrupt cause or die. - */ - -static void z8530_rx_clear(struct z8530_channel *c) -{ - /* Data and status bytes - */ - u8 stat; - - read_zsdata(c); - stat = read_zsreg(c, R1); - - if (stat & END_FR) - write_zsctrl(c, RES_Rx_CRC); - /* Clear irq - */ - write_zsctrl(c, ERR_RES); - write_zsctrl(c, RES_H_IUS); -} - -/** - * z8530_tx_clear - Handle TX events from a stopped chip - * @c: Z8530 channel to shut up - * - * Transmit interrupt vectors for a Z8530 that is in 'parked' mode. - * For machines with PCI Z85x30 cards, or level triggered interrupts - * (eg the MacII) we must clear the interrupt cause or die. - */ - -static void z8530_tx_clear(struct z8530_channel *c) -{ - write_zsctrl(c, RES_Tx_P); - write_zsctrl(c, RES_H_IUS); -} - -/** - * z8530_status_clear - Handle status events from a stopped chip - * @chan: Z8530 channel to shut up - * - * Status interrupt vectors for a Z8530 that is in 'parked' mode. - * For machines with PCI Z85x30 cards, or level triggered interrupts - * (eg the MacII) we must clear the interrupt cause or die. - */ - -static void z8530_status_clear(struct z8530_channel *chan) -{ - u8 status = read_zsreg(chan, R0); - - if (status & TxEOM) - write_zsctrl(chan, ERR_RES); - write_zsctrl(chan, RES_EXT_INT); - write_zsctrl(chan, RES_H_IUS); -} - -struct z8530_irqhandler z8530_nop = { - .rx = z8530_rx_clear, - .tx = z8530_tx_clear, - .status = z8530_status_clear, -}; -EXPORT_SYMBOL(z8530_nop); - -/** - * z8530_interrupt - Handle an interrupt from a Z8530 - * @irq: Interrupt number - * @dev_id: The Z8530 device that is interrupting. - * - * A Z85[2]30 device has stuck its hand in the air for attention. - * We scan both the channels on the chip for events and then call - * the channel specific call backs for each channel that has events. - * We have to use callback functions because the two channels can be - * in different modes. - * - * Locking is done for the handlers. Note that locking is done - * at the chip level (the 5uS delay issue is per chip not per - * channel). c->lock for both channels points to dev->lock - */ - -irqreturn_t z8530_interrupt(int irq, void *dev_id) -{ - struct z8530_dev *dev = dev_id; - u8 intr; - static volatile int locker=0; - int work = 0; - struct z8530_irqhandler *irqs; - - if (locker) { - pr_err("IRQ re-enter\n"); - return IRQ_NONE; - } - locker = 1; - - spin_lock(&dev->lock); - - while (++work < 5000) { - intr = read_zsreg(&dev->chanA, R3); - if (!(intr & - (CHARxIP | CHATxIP | CHAEXT | CHBRxIP | CHBTxIP | CHBEXT))) - break; - - /* This holds the IRQ status. On the 8530 you must read it - * from chan A even though it applies to the whole chip - */ - - /* Now walk the chip and see what it is wanting - it may be - * an IRQ for someone else remember - */ - - irqs = dev->chanA.irqs; - - if (intr & (CHARxIP | CHATxIP | CHAEXT)) { - if (intr & CHARxIP) - irqs->rx(&dev->chanA); - if (intr & CHATxIP) - irqs->tx(&dev->chanA); - if (intr & CHAEXT) - irqs->status(&dev->chanA); - } - - irqs = dev->chanB.irqs; - - if (intr & (CHBRxIP | CHBTxIP | CHBEXT)) { - if (intr & CHBRxIP) - irqs->rx(&dev->chanB); - if (intr & CHBTxIP) - irqs->tx(&dev->chanB); - if (intr & CHBEXT) - irqs->status(&dev->chanB); - } - } - spin_unlock(&dev->lock); - if (work == 5000) - pr_err("%s: interrupt jammed - abort(0x%X)!\n", - dev->name, intr); - /* Ok all done */ - locker = 0; - return IRQ_HANDLED; -} -EXPORT_SYMBOL(z8530_interrupt); - -static const u8 reg_init[16] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0x55, 0, 0, 0 -}; - -/** - * z8530_sync_open - Open a Z8530 channel for PIO - * @dev: The network interface we are using - * @c: The Z8530 channel to open in synchronous PIO mode - * - * Switch a Z8530 into synchronous mode without DMA assist. We - * raise the RTS/DTR and commence network operation. - */ -int z8530_sync_open(struct net_device *dev, struct z8530_channel *c) -{ - unsigned long flags; - - spin_lock_irqsave(c->lock, flags); - - c->sync = 1; - c->mtu = dev->mtu + 64; - c->count = 0; - c->skb = NULL; - c->skb2 = NULL; - c->irqs = &z8530_sync; - - /* This loads the double buffer up */ - z8530_rx_done(c); /* Load the frame ring */ - z8530_rx_done(c); /* Load the backup frame */ - z8530_rtsdtr(c, 1); - c->dma_tx = 0; - c->regs[R1] |= TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - write_zsreg(c, R3, c->regs[R3] | RxENABLE); - - spin_unlock_irqrestore(c->lock, flags); - return 0; -} -EXPORT_SYMBOL(z8530_sync_open); - -/** - * z8530_sync_close - Close a PIO Z8530 channel - * @dev: Network device to close - * @c: Z8530 channel to disassociate and move to idle - * - * Close down a Z8530 interface and switch its interrupt handlers - * to discard future events. - */ -int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) -{ - u8 chk; - unsigned long flags; - - spin_lock_irqsave(c->lock, flags); - c->irqs = &z8530_nop; - c->max = 0; - c->sync = 0; - - chk = read_zsreg(c, R0); - write_zsreg(c, R3, c->regs[R3]); - z8530_rtsdtr(c, 0); - - spin_unlock_irqrestore(c->lock, flags); - return 0; -} -EXPORT_SYMBOL(z8530_sync_close); - -/** - * z8530_sync_dma_open - Open a Z8530 for DMA I/O - * @dev: The network device to attach - * @c: The Z8530 channel to configure in sync DMA mode. - * - * Set up a Z85x30 device for synchronous DMA in both directions. Two - * ISA DMA channels must be available for this to work. We assume ISA - * DMA driven I/O and PC limits on access. - */ -int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c) -{ - unsigned long cflags, dflags; - - c->sync = 1; - c->mtu = dev->mtu + 64; - c->count = 0; - c->skb = NULL; - c->skb2 = NULL; - - /* Load the DMA interfaces up - */ - c->rxdma_on = 0; - c->txdma_on = 0; - - /* Allocate the DMA flip buffers. Limit by page size. - * Everyone runs 1500 mtu or less on wan links so this - * should be fine. - */ - - if (c->mtu > PAGE_SIZE / 2) - return -EMSGSIZE; - - c->rx_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!c->rx_buf[0]) - return -ENOBUFS; - c->rx_buf[1] = c->rx_buf[0] + PAGE_SIZE / 2; - - c->tx_dma_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!c->tx_dma_buf[0]) { - free_page((unsigned long)c->rx_buf[0]); - c->rx_buf[0] = NULL; - return -ENOBUFS; - } - c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE / 2; - - c->tx_dma_used = 0; - c->dma_tx = 1; - c->dma_num = 0; - c->dma_ready = 1; - - /* Enable DMA control mode - */ - - spin_lock_irqsave(c->lock, cflags); - - /* TX DMA via DIR/REQ - */ - - c->regs[R14] |= DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - c->regs[R1] &= ~TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - - /* RX DMA via W/Req - */ - - c->regs[R1] |= WT_FN_RDYFN; - c->regs[R1] |= WT_RDY_RT; - c->regs[R1] |= INT_ERR_Rx; - c->regs[R1] &= ~TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R1] |= WT_RDY_ENAB; - write_zsreg(c, R1, c->regs[R1]); - - /* DMA interrupts - */ - - /* Set up the DMA configuration - */ - - dflags = claim_dma_lock(); - - disable_dma(c->rxdma); - clear_dma_ff(c->rxdma); - set_dma_mode(c->rxdma, DMA_MODE_READ | 0x10); - set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0])); - set_dma_count(c->rxdma, c->mtu); - enable_dma(c->rxdma); - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - set_dma_mode(c->txdma, DMA_MODE_WRITE); - disable_dma(c->txdma); - - release_dma_lock(dflags); - - /* Select the DMA interrupt handlers - */ - - c->rxdma_on = 1; - c->txdma_on = 1; - c->tx_dma_used = 1; - - c->irqs = &z8530_dma_sync; - z8530_rtsdtr(c, 1); - write_zsreg(c, R3, c->regs[R3] | RxENABLE); - - spin_unlock_irqrestore(c->lock, cflags); - - return 0; -} -EXPORT_SYMBOL(z8530_sync_dma_open); - -/** - * z8530_sync_dma_close - Close down DMA I/O - * @dev: Network device to detach - * @c: Z8530 channel to move into discard mode - * - * Shut down a DMA mode synchronous interface. Halt the DMA, and - * free the buffers. - */ -int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c) -{ - u8 chk; - unsigned long flags; - - c->irqs = &z8530_nop; - c->max = 0; - c->sync = 0; - - /* Disable the PC DMA channels - */ - - flags = claim_dma_lock(); - disable_dma(c->rxdma); - clear_dma_ff(c->rxdma); - - c->rxdma_on = 0; - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - release_dma_lock(flags); - - c->txdma_on = 0; - c->tx_dma_used = 0; - - spin_lock_irqsave(c->lock, flags); - - /* Disable DMA control mode - */ - - c->regs[R1] &= ~WT_RDY_ENAB; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R1] &= ~(WT_RDY_RT | WT_FN_RDYFN | INT_ERR_Rx); - c->regs[R1] |= INT_ALL_Rx; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R14] &= ~DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - if (c->rx_buf[0]) { - free_page((unsigned long)c->rx_buf[0]); - c->rx_buf[0] = NULL; - } - if (c->tx_dma_buf[0]) { - free_page((unsigned long)c->tx_dma_buf[0]); - c->tx_dma_buf[0] = NULL; - } - chk = read_zsreg(c, R0); - write_zsreg(c, R3, c->regs[R3]); - z8530_rtsdtr(c, 0); - - spin_unlock_irqrestore(c->lock, flags); - - return 0; -} -EXPORT_SYMBOL(z8530_sync_dma_close); - -/** - * z8530_sync_txdma_open - Open a Z8530 for TX driven DMA - * @dev: The network device to attach - * @c: The Z8530 channel to configure in sync DMA mode. - * - * Set up a Z85x30 device for synchronous DMA transmission. One - * ISA DMA channel must be available for this to work. The receive - * side is run in PIO mode, but then it has the bigger FIFO. - */ - -int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c) -{ - unsigned long cflags, dflags; - - printk("Opening sync interface for TX-DMA\n"); - c->sync = 1; - c->mtu = dev->mtu + 64; - c->count = 0; - c->skb = NULL; - c->skb2 = NULL; - - /* Allocate the DMA flip buffers. Limit by page size. - * Everyone runs 1500 mtu or less on wan links so this - * should be fine. - */ - - if (c->mtu > PAGE_SIZE / 2) - return -EMSGSIZE; - - c->tx_dma_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!c->tx_dma_buf[0]) - return -ENOBUFS; - - c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE / 2; - - spin_lock_irqsave(c->lock, cflags); - - /* Load the PIO receive ring - */ - - z8530_rx_done(c); - z8530_rx_done(c); - - /* Load the DMA interfaces up - */ - - c->rxdma_on = 0; - c->txdma_on = 0; - - c->tx_dma_used = 0; - c->dma_num = 0; - c->dma_ready = 1; - c->dma_tx = 1; - - /* Enable DMA control mode - */ - - /* TX DMA via DIR/REQ - */ - c->regs[R14] |= DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - c->regs[R1] &= ~TxINT_ENAB; - write_zsreg(c, R1, c->regs[R1]); - - /* Set up the DMA configuration - */ - - dflags = claim_dma_lock(); - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - set_dma_mode(c->txdma, DMA_MODE_WRITE); - disable_dma(c->txdma); - - release_dma_lock(dflags); - - /* Select the DMA interrupt handlers - */ - - c->rxdma_on = 0; - c->txdma_on = 1; - c->tx_dma_used = 1; - - c->irqs = &z8530_txdma_sync; - z8530_rtsdtr(c, 1); - write_zsreg(c, R3, c->regs[R3] | RxENABLE); - spin_unlock_irqrestore(c->lock, cflags); - - return 0; -} -EXPORT_SYMBOL(z8530_sync_txdma_open); - -/** - * z8530_sync_txdma_close - Close down a TX driven DMA channel - * @dev: Network device to detach - * @c: Z8530 channel to move into discard mode - * - * Shut down a DMA/PIO split mode synchronous interface. Halt the DMA, - * and free the buffers. - */ - -int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c) -{ - unsigned long dflags, cflags; - u8 chk; - - spin_lock_irqsave(c->lock, cflags); - - c->irqs = &z8530_nop; - c->max = 0; - c->sync = 0; - - /* Disable the PC DMA channels - */ - - dflags = claim_dma_lock(); - - disable_dma(c->txdma); - clear_dma_ff(c->txdma); - c->txdma_on = 0; - c->tx_dma_used = 0; - - release_dma_lock(dflags); - - /* Disable DMA control mode - */ - - c->regs[R1] &= ~WT_RDY_ENAB; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R1] &= ~(WT_RDY_RT | WT_FN_RDYFN | INT_ERR_Rx); - c->regs[R1] |= INT_ALL_Rx; - write_zsreg(c, R1, c->regs[R1]); - c->regs[R14] &= ~DTRREQ; - write_zsreg(c, R14, c->regs[R14]); - - if (c->tx_dma_buf[0]) { - free_page((unsigned long)c->tx_dma_buf[0]); - c->tx_dma_buf[0] = NULL; - } - chk = read_zsreg(c, R0); - write_zsreg(c, R3, c->regs[R3]); - z8530_rtsdtr(c, 0); - - spin_unlock_irqrestore(c->lock, cflags); - return 0; -} -EXPORT_SYMBOL(z8530_sync_txdma_close); - -/* Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny - * it exists... - */ -static const char * const z8530_type_name[] = { - "Z8530", - "Z85C30", - "Z85230" -}; - -/** - * z8530_describe - Uniformly describe a Z8530 port - * @dev: Z8530 device to describe - * @mapping: string holding mapping type (eg "I/O" or "Mem") - * @io: the port value in question - * - * Describe a Z8530 in a standard format. We must pass the I/O as - * the port offset isn't predictable. The main reason for this function - * is to try and get a common format of report. - */ - -void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io) -{ - pr_info("%s: %s found at %s 0x%lX, IRQ %d\n", - dev->name, - z8530_type_name[dev->type], - mapping, - Z8530_PORT_OF(io), - dev->irq); -} -EXPORT_SYMBOL(z8530_describe); - -/* Locked operation part of the z8530 init code - */ -static inline int do_z8530_init(struct z8530_dev *dev) -{ - /* NOP the interrupt handlers first - we might get a - * floating IRQ transition when we reset the chip - */ - dev->chanA.irqs = &z8530_nop; - dev->chanB.irqs = &z8530_nop; - dev->chanA.dcdcheck = DCD; - dev->chanB.dcdcheck = DCD; - - /* Reset the chip */ - write_zsreg(&dev->chanA, R9, 0xC0); - udelay(200); - /* Now check its valid */ - write_zsreg(&dev->chanA, R12, 0xAA); - if (read_zsreg(&dev->chanA, R12) != 0xAA) - return -ENODEV; - write_zsreg(&dev->chanA, R12, 0x55); - if (read_zsreg(&dev->chanA, R12) != 0x55) - return -ENODEV; - - dev->type = Z8530; - - /* See the application note. - */ - - write_zsreg(&dev->chanA, R15, 0x01); - - /* If we can set the low bit of R15 then - * the chip is enhanced. - */ - - if (read_zsreg(&dev->chanA, R15) == 0x01) { - /* This C30 versus 230 detect is from Klaus Kudielka's dmascc */ - /* Put a char in the fifo */ - write_zsreg(&dev->chanA, R8, 0); - if (read_zsreg(&dev->chanA, R0) & Tx_BUF_EMP) - dev->type = Z85230; /* Has a FIFO */ - else - dev->type = Z85C30; /* Z85C30, 1 byte FIFO */ - } - - /* The code assumes R7' and friends are - * off. Use write_zsext() for these and keep - * this bit clear. - */ - - write_zsreg(&dev->chanA, R15, 0); - - /* At this point it looks like the chip is behaving - */ - - memcpy(dev->chanA.regs, reg_init, 16); - memcpy(dev->chanB.regs, reg_init, 16); - - return 0; -} - -/** - * z8530_init - Initialise a Z8530 device - * @dev: Z8530 device to initialise. - * - * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device - * is present, identify the type and then program it to hopefully - * keep quite and behave. This matters a lot, a Z8530 in the wrong - * state will sometimes get into stupid modes generating 10Khz - * interrupt streams and the like. - * - * We set the interrupt handler up to discard any events, in case - * we get them during reset or setp. - * - * Return 0 for success, or a negative value indicating the problem - * in errno form. - */ - -int z8530_init(struct z8530_dev *dev) -{ - unsigned long flags; - int ret; - - /* Set up the chip level lock */ - spin_lock_init(&dev->lock); - dev->chanA.lock = &dev->lock; - dev->chanB.lock = &dev->lock; - - spin_lock_irqsave(&dev->lock, flags); - ret = do_z8530_init(dev); - spin_unlock_irqrestore(&dev->lock, flags); - - return ret; -} -EXPORT_SYMBOL(z8530_init); - -/** - * z8530_shutdown - Shutdown a Z8530 device - * @dev: The Z8530 chip to shutdown - * - * We set the interrupt handlers to silence any interrupts. We then - * reset the chip and wait 100uS to be sure the reset completed. Just - * in case the caller then tries to do stuff. - * - * This is called without the lock held - */ -int z8530_shutdown(struct z8530_dev *dev) -{ - unsigned long flags; - /* Reset the chip */ - - spin_lock_irqsave(&dev->lock, flags); - dev->chanA.irqs = &z8530_nop; - dev->chanB.irqs = &z8530_nop; - write_zsreg(&dev->chanA, R9, 0xC0); - /* We must lock the udelay, the chip is offlimits here */ - udelay(100); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; -} -EXPORT_SYMBOL(z8530_shutdown); - -/** - * z8530_channel_load - Load channel data - * @c: Z8530 channel to configure - * @rtable: table of register, value pairs - * FIXME: ioctl to allow user uploaded tables - * - * Load a Z8530 channel up from the system data. We use +16 to - * indicate the "prime" registers. The value 255 terminates the - * table. - */ - -int z8530_channel_load(struct z8530_channel *c, u8 *rtable) -{ - unsigned long flags; - - spin_lock_irqsave(c->lock, flags); - - while (*rtable != 255) { - int reg = *rtable++; - - if (reg > 0x0F) - write_zsreg(c, R15, c->regs[15] | 1); - write_zsreg(c, reg & 0x0F, *rtable); - if (reg > 0x0F) - write_zsreg(c, R15, c->regs[15] & ~1); - c->regs[reg] = *rtable++; - } - c->rx_function = z8530_null_rx; - c->skb = NULL; - c->tx_skb = NULL; - c->tx_next_skb = NULL; - c->mtu = 1500; - c->max = 0; - c->count = 0; - c->status = read_zsreg(c, R0); - c->sync = 1; - write_zsreg(c, R3, c->regs[R3] | RxENABLE); - - spin_unlock_irqrestore(c->lock, flags); - return 0; -} -EXPORT_SYMBOL(z8530_channel_load); - -/** - * z8530_tx_begin - Begin packet transmission - * @c: The Z8530 channel to kick - * - * This is the speed sensitive side of transmission. If we are called - * and no buffer is being transmitted we commence the next buffer. If - * nothing is queued we idle the sync. - * - * Note: We are handling this code path in the interrupt path, keep it - * fast or bad things will happen. - * - * Called with the lock held. - */ - -static void z8530_tx_begin(struct z8530_channel *c) -{ - unsigned long flags; - - if (c->tx_skb) - return; - - c->tx_skb = c->tx_next_skb; - c->tx_next_skb = NULL; - c->tx_ptr = c->tx_next_ptr; - - if (!c->tx_skb) { - /* Idle on */ - if (c->dma_tx) { - flags = claim_dma_lock(); - disable_dma(c->txdma); - /* Check if we crapped out. - */ - if (get_dma_residue(c->txdma)) { - c->netdevice->stats.tx_dropped++; - c->netdevice->stats.tx_fifo_errors++; - } - release_dma_lock(flags); - } - c->txcount = 0; - } else { - c->txcount = c->tx_skb->len; - - if (c->dma_tx) { - /* FIXME. DMA is broken for the original 8530, - * on the older parts we need to set a flag and - * wait for a further TX interrupt to fire this - * stage off - */ - - flags = claim_dma_lock(); - disable_dma(c->txdma); - - /* These two are needed by the 8530/85C30 - * and must be issued when idling. - */ - if (c->dev->type != Z85230) { - write_zsctrl(c, RES_Tx_CRC); - write_zsctrl(c, RES_EOM_L); - } - write_zsreg(c, R10, c->regs[10] & ~ABUNDER); - clear_dma_ff(c->txdma); - set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr)); - set_dma_count(c->txdma, c->txcount); - enable_dma(c->txdma); - release_dma_lock(flags); - write_zsctrl(c, RES_EOM_L); - write_zsreg(c, R5, c->regs[R5] | TxENAB); - } else { - /* ABUNDER off */ - write_zsreg(c, R10, c->regs[10]); - write_zsctrl(c, RES_Tx_CRC); - - while (c->txcount && (read_zsreg(c, R0) & Tx_BUF_EMP)) { - write_zsreg(c, R8, *c->tx_ptr++); - c->txcount--; - } - } - } - /* Since we emptied tx_skb we can ask for more - */ - netif_wake_queue(c->netdevice); -} - -/** - * z8530_tx_done - TX complete callback - * @c: The channel that completed a transmit. - * - * This is called when we complete a packet send. We wake the queue, - * start the next packet going and then free the buffer of the existing - * packet. This code is fairly timing sensitive. - * - * Called with the register lock held. - */ - -static void z8530_tx_done(struct z8530_channel *c) -{ - struct sk_buff *skb; - - /* Actually this can happen.*/ - if (!c->tx_skb) - return; - - skb = c->tx_skb; - c->tx_skb = NULL; - z8530_tx_begin(c); - c->netdevice->stats.tx_packets++; - c->netdevice->stats.tx_bytes += skb->len; - dev_consume_skb_irq(skb); -} - -/** - * z8530_null_rx - Discard a packet - * @c: The channel the packet arrived on - * @skb: The buffer - * - * We point the receive handler at this function when idle. Instead - * of processing the frames we get to throw them away. - */ -void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb) -{ - dev_kfree_skb_any(skb); -} -EXPORT_SYMBOL(z8530_null_rx); - -/** - * z8530_rx_done - Receive completion callback - * @c: The channel that completed a receive - * - * A new packet is complete. Our goal here is to get back into receive - * mode as fast as possible. On the Z85230 we could change to using - * ESCC mode, but on the older chips we have no choice. We flip to the - * new buffer immediately in DMA mode so that the DMA of the next - * frame can occur while we are copying the previous buffer to an sk_buff - * - * Called with the lock held - */ -static void z8530_rx_done(struct z8530_channel *c) -{ - struct sk_buff *skb; - int ct; - - /* Is our receive engine in DMA mode - */ - if (c->rxdma_on) { - /* Save the ready state and the buffer currently - * being used as the DMA target - */ - int ready = c->dma_ready; - unsigned char *rxb = c->rx_buf[c->dma_num]; - unsigned long flags; - - /* Complete this DMA. Necessary to find the length - */ - flags = claim_dma_lock(); - - disable_dma(c->rxdma); - clear_dma_ff(c->rxdma); - c->rxdma_on = 0; - ct = c->mtu - get_dma_residue(c->rxdma); - if (ct < 0) - ct = 2; /* Shit happens.. */ - c->dma_ready = 0; - - /* Normal case: the other slot is free, start the next DMA - * into it immediately. - */ - - if (ready) { - c->dma_num ^= 1; - set_dma_mode(c->rxdma, DMA_MODE_READ | 0x10); - set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num])); - set_dma_count(c->rxdma, c->mtu); - c->rxdma_on = 1; - enable_dma(c->rxdma); - /* Stop any frames that we missed the head of - * from passing - */ - write_zsreg(c, R0, RES_Rx_CRC); - } else { - /* Can't occur as we dont reenable the DMA irq until - * after the flip is done - */ - netdev_warn(c->netdevice, "DMA flip overrun!\n"); - } - - release_dma_lock(flags); - - /* Shove the old buffer into an sk_buff. We can't DMA - * directly into one on a PC - it might be above the 16Mb - * boundary. Optimisation - we could check to see if we - * can avoid the copy. Optimisation 2 - make the memcpy - * a copychecksum. - */ - - skb = dev_alloc_skb(ct); - if (!skb) { - c->netdevice->stats.rx_dropped++; - netdev_warn(c->netdevice, "Memory squeeze\n"); - } else { - skb_put(skb, ct); - skb_copy_to_linear_data(skb, rxb, ct); - c->netdevice->stats.rx_packets++; - c->netdevice->stats.rx_bytes += ct; - } - c->dma_ready = 1; - } else { - RT_LOCK; - skb = c->skb; - - /* The game we play for non DMA is similar. We want to - * get the controller set up for the next packet as fast - * as possible. We potentially only have one byte + the - * fifo length for this. Thus we want to flip to the new - * buffer and then mess around copying and allocating - * things. For the current case it doesn't matter but - * if you build a system where the sync irq isn't blocked - * by the kernel IRQ disable then you need only block the - * sync IRQ for the RT_LOCK area. - * - */ - ct = c->count; - - c->skb = c->skb2; - c->count = 0; - c->max = c->mtu; - if (c->skb) { - c->dptr = c->skb->data; - c->max = c->mtu; - } else { - c->count = 0; - c->max = 0; - } - RT_UNLOCK; - - c->skb2 = dev_alloc_skb(c->mtu); - if (c->skb2) - skb_put(c->skb2, c->mtu); - - c->netdevice->stats.rx_packets++; - c->netdevice->stats.rx_bytes += ct; - } - /* If we received a frame we must now process it. - */ - if (skb) { - skb_trim(skb, ct); - c->rx_function(c, skb); - } else { - c->netdevice->stats.rx_dropped++; - netdev_err(c->netdevice, "Lost a frame\n"); - } -} - -/** - * spans_boundary - Check a packet can be ISA DMA'd - * @skb: The buffer to check - * - * Returns true if the buffer cross a DMA boundary on a PC. The poor - * thing can only DMA within a 64K block not across the edges of it. - */ - -static inline int spans_boundary(struct sk_buff *skb) -{ - unsigned long a = (unsigned long)skb->data; - - a ^= (a + skb->len); - if (a & 0x00010000) /* If the 64K bit is different.. */ - return 1; - return 0; -} - -/** - * z8530_queue_xmit - Queue a packet - * @c: The channel to use - * @skb: The packet to kick down the channel - * - * Queue a packet for transmission. Because we have rather - * hard to hit interrupt latencies for the Z85230 per packet - * even in DMA mode we do the flip to DMA buffer if needed here - * not in the IRQ. - * - * Called from the network code. The lock is not held at this - * point. - */ -netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) -{ - unsigned long flags; - - netif_stop_queue(c->netdevice); - if (c->tx_next_skb) - return NETDEV_TX_BUSY; - - /* PC SPECIFIC - DMA limits */ - /* If we will DMA the transmit and its gone over the ISA bus - * limit, then copy to the flip buffer - */ - - if (c->dma_tx && - ((unsigned long)(virt_to_bus(skb->data + skb->len)) >= - 16 * 1024 * 1024 || spans_boundary(skb))) { - /* Send the flip buffer, and flip the flippy bit. - * We don't care which is used when just so long as - * we never use the same buffer twice in a row. Since - * only one buffer can be going out at a time the other - * has to be safe. - */ - c->tx_next_ptr = c->tx_dma_buf[c->tx_dma_used]; - c->tx_dma_used ^= 1; /* Flip temp buffer */ - skb_copy_from_linear_data(skb, c->tx_next_ptr, skb->len); - } else { - c->tx_next_ptr = skb->data; - } - RT_LOCK; - c->tx_next_skb = skb; - RT_UNLOCK; - - spin_lock_irqsave(c->lock, flags); - z8530_tx_begin(c); - spin_unlock_irqrestore(c->lock, flags); - - return NETDEV_TX_OK; -} -EXPORT_SYMBOL(z8530_queue_xmit); - -/* Module support - */ -static const char banner[] __initconst = - KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"; - -static int __init z85230_init_driver(void) -{ - printk(banner); - return 0; -} -module_init(z85230_init_driver); - -static void __exit z85230_cleanup_driver(void) -{ -} -module_exit(z85230_cleanup_driver); - -MODULE_AUTHOR("Red Hat Inc."); -MODULE_DESCRIPTION("Z85x30 synchronous driver core"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h deleted file mode 100644 index 462cb620bc5d..000000000000 --- a/drivers/net/wan/z85230.h +++ /dev/null @@ -1,407 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Description of Z8530 Z85C30 and Z85230 communications chips - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 Alan Cox - */ - -#ifndef _Z8530_H -#define _Z8530_H - -#include -#include - -/* Conversion routines to/from brg time constants from/to bits - * per second. - */ -#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -/* The Zilog register set */ - -#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 RPRIME 16 /* Indicate a prime register access on 230 */ - -#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 PRIME 1 /* R5' etc register access (Z85C30/230 only) */ -#define ZCIE 2 /* Zero count IE */ -#define FIFOE 4 /* Z85230 only */ -#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) */ - - -/* - * Interrupt handling functions for this SCC - */ - -struct z8530_channel; - -struct z8530_irqhandler -{ - void (*rx)(struct z8530_channel *); - void (*tx)(struct z8530_channel *); - void (*status)(struct z8530_channel *); -}; - -/* - * A channel of the Z8530 - */ - -struct z8530_channel -{ - struct z8530_irqhandler *irqs; /* IRQ handlers */ - /* - * Synchronous - */ - u16 count; /* Buyes received */ - u16 max; /* Most we can receive this frame */ - u16 mtu; /* MTU of the device */ - u8 *dptr; /* Pointer into rx buffer */ - struct sk_buff *skb; /* Buffer dptr points into */ - struct sk_buff *skb2; /* Pending buffer */ - u8 status; /* Current DCD */ - u8 dcdcheck; /* which bit to check for line */ - u8 sync; /* Set if in sync mode */ - - u8 regs[32]; /* Register map for the chip */ - u8 pendregs[32]; /* Pending register values */ - - struct sk_buff *tx_skb; /* Buffer being transmitted */ - struct sk_buff *tx_next_skb; /* Next transmit buffer */ - u8 *tx_ptr; /* Byte pointer into the buffer */ - u8 *tx_next_ptr; /* Next pointer to use */ - u8 *tx_dma_buf[2]; /* TX flip buffers for DMA */ - u8 tx_dma_used; /* Flip buffer usage toggler */ - u16 txcount; /* Count of bytes to transmit */ - - void (*rx_function)(struct z8530_channel *, struct sk_buff *); - - /* - * Sync DMA - */ - - u8 rxdma; /* DMA channels */ - u8 txdma; - u8 rxdma_on; /* DMA active if flag set */ - u8 txdma_on; - u8 dma_num; /* Buffer we are DMAing into */ - u8 dma_ready; /* Is the other buffer free */ - u8 dma_tx; /* TX is to use DMA */ - u8 *rx_buf[2]; /* The flip buffers */ - - /* - * System - */ - - struct z8530_dev *dev; /* Z85230 chip instance we are from */ - unsigned long ctrlio; /* I/O ports */ - unsigned long dataio; - - /* - * For PC we encode this way. - */ -#define Z8530_PORT_SLEEP 0x80000000 -#define Z8530_PORT_OF(x) ((x)&0xFFFF) - - u32 rx_overrun; /* Overruns - not done yet */ - u32 rx_crc_err; - - /* - * Bound device pointers - */ - - void *private; /* For our owner */ - struct net_device *netdevice; /* Network layer device */ - - spinlock_t *lock; /* Device lock */ -}; - -/* - * Each Z853x0 device. - */ - -struct z8530_dev -{ - char *name; /* Device instance name */ - struct z8530_channel chanA; /* SCC channel A */ - struct z8530_channel chanB; /* SCC channel B */ - int type; -#define Z8530 0 /* NMOS dinosaur */ -#define Z85C30 1 /* CMOS - better */ -#define Z85230 2 /* CMOS with real FIFO */ - int irq; /* Interrupt for the device */ - int active; /* Soft interrupt enable - the Mac doesn't - always have a hard disable on its 8530s... */ - spinlock_t lock; -}; - - -/* - * Functions - */ - -extern u8 z8530_dead_port[]; -extern u8 z8530_hdlc_kilostream_85230[]; -extern u8 z8530_hdlc_kilostream[]; -irqreturn_t z8530_interrupt(int, void *); -void z8530_describe(struct z8530_dev *, char *mapping, unsigned long io); -int z8530_init(struct z8530_dev *); -int z8530_shutdown(struct z8530_dev *); -int z8530_sync_open(struct net_device *, struct z8530_channel *); -int z8530_sync_close(struct net_device *, struct z8530_channel *); -int z8530_sync_dma_open(struct net_device *, struct z8530_channel *); -int z8530_sync_dma_close(struct net_device *, struct z8530_channel *); -int z8530_sync_txdma_open(struct net_device *, struct z8530_channel *); -int z8530_sync_txdma_close(struct net_device *, struct z8530_channel *); -int z8530_channel_load(struct z8530_channel *, u8 *); -netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb); -void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb); - - -/* - * Standard interrupt vector sets - */ - -extern struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop; - -/* - * Asynchronous Interfacing - */ - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ - -#define SERIAL_XMIT_SIZE 4096 -#define WAKEUP_CHARS 256 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ -#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -#endif /* !(_Z8530_H) */ diff --git a/include/uapi/linux/atm_zatm.h b/include/uapi/linux/atm_zatm.h deleted file mode 100644 index 5135027b93c1..000000000000 --- a/include/uapi/linux/atm_zatm.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* atm_zatm.h - Driver-specific declarations of the ZATM driver (for use by - driver-specific utilities) */ - -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ - - -#ifndef LINUX_ATM_ZATM_H -#define LINUX_ATM_ZATM_H - -/* - * Note: non-kernel programs including this file must also include - * sys/types.h for struct timeval - */ - -#include -#include - -#define ZATM_GETPOOL _IOW('a',ATMIOC_SARPRV+1,struct atmif_sioc) - /* get pool statistics */ -#define ZATM_GETPOOLZ _IOW('a',ATMIOC_SARPRV+2,struct atmif_sioc) - /* get statistics and zero */ -#define ZATM_SETPOOL _IOW('a',ATMIOC_SARPRV+3,struct atmif_sioc) - /* set pool parameters */ - -struct zatm_pool_info { - int ref_count; /* free buffer pool usage counters */ - int low_water,high_water; /* refill parameters */ - int rqa_count,rqu_count; /* queue condition counters */ - int offset,next_off; /* alignment optimizations: offset */ - int next_cnt,next_thres; /* repetition counter and threshold */ -}; - -struct zatm_pool_req { - int pool_num; /* pool number */ - struct zatm_pool_info info; /* actual information */ -}; - -#define ZATM_OAM_POOL 0 /* free buffer pool for OAM cells */ -#define ZATM_AAL0_POOL 1 /* free buffer pool for AAL0 cells */ -#define ZATM_AAL5_POOL_BASE 2 /* first AAL5 free buffer pool */ -#define ZATM_LAST_POOL ZATM_AAL5_POOL_BASE+10 /* max. 64 kB */ - -#define ZATM_TIMER_HISTORY_SIZE 16 /* number of timer adjustments to - record; must be 2^n */ - -#endif