netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus()
@ 2022-04-26 17:54 Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 1/6] net: atm: remove support for Fujitsu FireStream ATM devices Jakub Kicinski
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Jakub Kicinski @ 2022-04-26 17:54 UTC (permalink / raw)
  To: davem, pabeni; +Cc: netdev, Jakub Kicinski

Networking is currently the main offender in using virt_to_bus().
Frankly all the drivers which use it are super old and unlikely
to be used today. They are just an ongoing maintenance burden.

In other words this series is using virt_to_bus() as an excuse
to shed some old stuff. Having done the tree-wide dev_addr_set()
conversion recently I have limited sympathy for carrying dead
code.

Obviously please scream if any of these drivers _is_ in fact
still being used. Otherwise let's take the chance, we can always
apologize and revert if users show up later.

Also I should say thanks to everyone who contributed to this code!
The work continues to be appreciated although realistically in more
of a "history book" fashion...

Jakub Kicinski (6):
  net: atm: remove support for Fujitsu FireStream ATM devices
  net: atm: remove support for Madge Horizon ATM devices
  net: atm: remove support for ZeitNet ZN122x ATM devices
  net: wan: remove support for COSA and SRP synchronous serial boards
  net: wan: remove support for Z85230-based devices
  net: hamradio: remove support for DMA SCC devices

 Documentation/admin-guide/devices.txt         |    2 +-
 .../networking/device_drivers/index.rst       |    1 -
 .../networking/device_drivers/wan/index.rst   |   18 -
 .../device_drivers/wan/z8530book.rst          |  256 --
 MAINTAINERS                                   |    7 -
 arch/mips/configs/gpr_defconfig               |    3 -
 arch/mips/configs/mtx1_defconfig              |    3 -
 drivers/atm/Kconfig                           |   54 -
 drivers/atm/Makefile                          |    3 -
 drivers/atm/firestream.c                      | 2057 ------------
 drivers/atm/firestream.h                      |  502 ---
 drivers/atm/horizon.c                         | 2853 -----------------
 drivers/atm/horizon.h                         |  492 ---
 drivers/atm/uPD98401.h                        |  293 --
 drivers/atm/uPD98402.c                        |  266 --
 drivers/atm/uPD98402.h                        |  107 -
 drivers/atm/zatm.c                            | 1652 ----------
 drivers/atm/zatm.h                            |  104 -
 drivers/net/hamradio/Kconfig                  |   34 -
 drivers/net/hamradio/Makefile                 |    1 -
 drivers/net/hamradio/dmascc.c                 | 1450 ---------
 drivers/net/wan/Kconfig                       |   44 -
 drivers/net/wan/Makefile                      |    3 -
 drivers/net/wan/cosa.c                        | 2052 ------------
 drivers/net/wan/cosa.h                        |  104 -
 drivers/net/wan/hostess_sv11.c                |  336 --
 drivers/net/wan/sealevel.c                    |  352 --
 drivers/net/wan/z85230.c                      | 1641 ----------
 drivers/net/wan/z85230.h                      |  407 ---
 include/uapi/linux/atm_zatm.h                 |   47 -
 30 files changed, 1 insertion(+), 15143 deletions(-)
 delete mode 100644 Documentation/networking/device_drivers/wan/index.rst
 delete mode 100644 Documentation/networking/device_drivers/wan/z8530book.rst
 delete mode 100644 drivers/atm/firestream.c
 delete mode 100644 drivers/atm/firestream.h
 delete mode 100644 drivers/atm/horizon.c
 delete mode 100644 drivers/atm/horizon.h
 delete mode 100644 drivers/atm/uPD98401.h
 delete mode 100644 drivers/atm/uPD98402.c
 delete mode 100644 drivers/atm/uPD98402.h
 delete mode 100644 drivers/atm/zatm.c
 delete mode 100644 drivers/atm/zatm.h
 delete mode 100644 drivers/net/hamradio/dmascc.c
 delete mode 100644 drivers/net/wan/cosa.c
 delete mode 100644 drivers/net/wan/cosa.h
 delete mode 100644 drivers/net/wan/hostess_sv11.c
 delete mode 100644 drivers/net/wan/sealevel.c
 delete mode 100644 drivers/net/wan/z85230.c
 delete mode 100644 drivers/net/wan/z85230.h
 delete mode 100644 include/uapi/linux/atm_zatm.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH net-next 1/6] net: atm: remove support for Fujitsu FireStream ATM devices
  2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
@ 2022-04-26 17:54 ` Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 2/6] net: atm: remove support for Madge Horizon " Jakub Kicinski
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2022-04-26 17:54 UTC (permalink / raw)
  To: davem, pabeni
  Cc: netdev, Jakub Kicinski, Thomas Gleixner, Chas Williams,
	linux-atm-general, Thomas Bogendoerfer, linux-mips, arnd

This driver received nothing but automated fixes (mostly spelling
and compiler warnings) since git era begun. Since it's using
virt_to_bus it's unlikely to be used on any modern platform.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: Thomas Gleixner <tglx@linutronix.de>
CC: Chas Williams <3chas3@gmail.com>
CC: linux-atm-general@lists.sourceforge.net
CC: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
CC: linux-mips@vger.kernel.org
CC: arnd@arndb.de
---
 arch/mips/configs/gpr_defconfig  |    1 -
 arch/mips/configs/mtx1_defconfig |    1 -
 drivers/atm/Kconfig              |   10 -
 drivers/atm/Makefile             |    1 -
 drivers/atm/firestream.c         | 2057 ------------------------------
 drivers/atm/firestream.h         |  502 --------
 6 files changed, 2572 deletions(-)
 delete mode 100644 drivers/atm/firestream.c
 delete mode 100644 drivers/atm/firestream.h

diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
index b0489437621a..605e778dff74 100644
--- a/arch/mips/configs/gpr_defconfig
+++ b/arch/mips/configs/gpr_defconfig
@@ -178,7 +178,6 @@ 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
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index c98099f0b354..de95e7fe5a77 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -255,7 +255,6 @@ 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
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index 7be08e24955c..360c98ad29eb 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -146,16 +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
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index 99ecbc280643..7d38fdaddd09 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -26,7 +26,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 <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/poison.h>
-#include <linux/errno.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/sonet.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/ioport.h> /* for request_region */
-#include <linux/uio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/capability.h>
-#include <linux/bitops.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <asm/string.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-#include <linux/uaccess.h>
-#include <linux/wait.h>
-
-#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 = <maxVP>/<maxVC>, 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;i<reginit->val;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<FS50_NR_CHANNELS;i++) {
-			write_fs (dev, 0x200 + i * 4, -1);
-		}
-	}
-}
-
-static void *aligned_kmalloc(int size, gfp_t flags, int alignment)
-{
-	void  *t;
-
-	if (alignment <= 0x10) {
-		t = kmalloc (size, flags);
-		if ((unsigned long)t & (alignment-1)) {
-			printk ("Kmalloc doesn't align things correctly! %p\n", t);
-			kfree (t);
-			return aligned_kmalloc (size, flags, alignment * 4);
-		}
-		return t;
-	}
-	printk (KERN_ERR "Request for > 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)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH net-next 2/6] net: atm: remove support for Madge Horizon ATM devices
  2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 1/6] net: atm: remove support for Fujitsu FireStream ATM devices Jakub Kicinski
@ 2022-04-26 17:54 ` Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x " Jakub Kicinski
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2022-04-26 17:54 UTC (permalink / raw)
  To: davem, pabeni
  Cc: netdev, Jakub Kicinski, Jiri Slaby, Chas Williams,
	linux-atm-general, Thomas Bogendoerfer, linux-mips, arnd

This driver received nothing but automated fixes since git era begun.
Since it's using virt_to_bus it's unlikely to be used on any modern
platform.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: Jiri Slaby <jirislaby@kernel.org>
CC: Chas Williams <3chas3@gmail.com>
CC: linux-atm-general@lists.sourceforge.net
CC: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
CC: linux-mips@vger.kernel.org
CC: arnd@arndb.de
---
 arch/mips/configs/gpr_defconfig  |    1 -
 arch/mips/configs/mtx1_defconfig |    1 -
 drivers/atm/Kconfig              |   24 -
 drivers/atm/Makefile             |    1 -
 drivers/atm/horizon.c            | 2853 ------------------------------
 drivers/atm/horizon.h            |  492 ------
 6 files changed, 3372 deletions(-)
 delete mode 100644 drivers/atm/horizon.c
 delete mode 100644 drivers/atm/horizon.h

diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
index 605e778dff74..7ed202db9ef0 100644
--- a/arch/mips/configs/gpr_defconfig
+++ b/arch/mips/configs/gpr_defconfig
@@ -181,7 +181,6 @@ CONFIG_ATM_ENI=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 de95e7fe5a77..f46ad2e294fa 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -258,7 +258,6 @@ CONFIG_ATM_ENI=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 360c98ad29eb..9c778308722a 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -234,30 +234,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
-	  <file:drivers/atm/horizon.h> 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 7d38fdaddd09..1b6a8ddaf007 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -7,7 +7,6 @@ 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
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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/sonet.h>
-#include <linux/skbuff.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/uio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <linux/atomic.h>
-#include <linux/uaccess.h>
-#include <asm/string.h>
-#include <asm/byteorder.h>
-
-#include "horizon.h"
-
-#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
-#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; i<skb->len && 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<<vpi_bits && 0 <= vci && vci < 1<<vci_bits) {
-    *channel = vpi<<vci_bits | vci;
-    return *channel ? 0 : -EINVAL;
-  }
-  return -EINVAL;
-}
-
-/********** decode RX queue entries **********/
-
-static inline u16 rx_q_entry_to_length (u32 x) {
-  return x & RX_Q_ENTRY_LENGTH_MASK;
-}
-
-static inline u16 rx_q_entry_to_rx_channel (u32 x) {
-  return (x>>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) <<br_exp == br and
-	// br_exp <= CR_MAXPEXP+CR_MIND
-  
-	if (br_man <= (c << (CR_MAXPEXP+CR_MIND-br_exp))) {
-		// Equivalent to: B <= (c << (MAXPEXP+MIND))
-		// take care of rounding
-		switch (r) {
-			case round_down:
-				pre = DIV_ROUND_UP(br, c<<div);
-				// but p must be non-zero
-				if (!pre)
-					pre = 1;
-				break;
-			case round_nearest:
-				pre = DIV_ROUND_CLOSEST(br, c<<div);
-				// but p must be non-zero
-				if (!pre)
-					pre = 1;
-				break;
-			default:	/* round_up */
-				pre = br/(c<<div);
-				// but p must be non-zero
-				if (!pre)
-					return -EINVAL;
-		}
-		PRINTD (DBG_QOS, "A: p=%u, d=%u", pre, div);
-		goto got_it;
-	}
-  
-	// at this point we have
-	// d == MIND and (c << (MAXPEXP+MIND)) < B
-	while (div < CR_MAXD) {
-		div++;
-		if (br_man <= (c << (CR_MAXPEXP+div-br_exp))) {
-			// Equivalent to: B <= (c << (MAXPEXP+d))
-			// c << (MAXPEXP+d-1) < B <= c << (MAXPEXP+d)
-			// 1 << (MAXPEXP-1) < B/2^d/c <= 1 << MAXPEXP
-			// MAXP/2 < B/c2^d <= MAXP
-			// take care of rounding
-			switch (r) {
-				case round_down:
-					pre = DIV_ROUND_UP(br, c<<div);
-					break;
-				case round_nearest:
-					pre = DIV_ROUND_CLOSEST(br, c<<div);
-					break;
-				default: /* round_up */
-					pre = br/(c<<div);
-			}
-			PRINTD (DBG_QOS, "B: p=%u, d=%u", pre, div);
-			goto got_it;
-		}
-	}
-	// at this point we have
-	// d == MAXD and (c << (MAXPEXP+MAXD)) < B
-	// but we cannot go any higher
-	// take care of rounding
-	if (r == round_down)
-		return -EINVAL;
-	pre = 1 << CR_MAXPEXP;
-	PRINTD (DBG_QOS, "C: p=%u, d=%u", pre, div);
-got_it:
-	// paranoia
-	if (div > CR_MAXD || (!pre) || pre > 1<<CR_MAXPEXP) {
-		PRINTD (DBG_QOS, "set_cr internal failure: d=%u p=%u",
-			div, pre);
-		return -EINVAL;
-	} else {
-		if (bits)
-			*bits = (div<<CLOCK_SELECT_SHIFT) | (pre-1);
-		if (actual) {
-			*actual = DIV_ROUND_UP(br, pre<<div);
-			PRINTD (DBG_QOS, "actual rate: %u", *actual);
-		}
-		return 0;
-	}
-}
-
-static int make_rate_with_tolerance (const hrz_dev * dev, u32 c, rounding r, unsigned int tol,
-				     u16 * bit_pattern, unsigned int * actual) {
-  unsigned int my_actual;
-  
-  PRINTD (DBG_QOS|DBG_FLOW, "make_rate_with_tolerance c=%u, %s, tol=%u",
-	  c, (r == round_up) ? "up" : (r == round_down) ? "down" : "nearest", tol);
-  
-  if (!actual)
-    // actual rate is not returned
-    actual = &my_actual;
-  
-  if (make_rate (dev, c, round_nearest, bit_pattern, actual))
-    // should never happen as round_nearest always succeeds
-    return -1;
-  
-  if (c - tol <= *actual && *actual <= c + tol)
-    // within tolerance
-    return 0;
-  else
-    // intolerant, try rounding instead
-    return make_rate (dev, c, r, bit_pattern, actual);
-}
-
-/********** Listen on a VC **********/
-
-static int hrz_open_rx (hrz_dev * dev, u16 channel) {
-  // is there any guarantee that we don't get two simulataneous
-  // identical calls of this function from different processes? yes
-  // rate_lock
-  unsigned long flags;
-  u32 channel_type; // u16?
-  
-  u16 buf_ptr = RX_CHANNEL_IDLE;
-  
-  rx_ch_desc * rx_desc = &memmap->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<<chan)) {
-	tx_channel = chan;
-	keep_going = 0;
-      }
-      ++chan;
-      if (chan == TX_CHANS)
-	chan = 0;
-    }
-    
-    dev->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<addr_bits; i++) {
-    if (addr & (1 << (addr_bits-1)))
-      ctrl |= SEEPROM_DI;
-    else
-      ctrl &= ~SEEPROM_DI;
-    
-    CLOCK_IT(dev, ctrl);
-    
-    addr = addr << 1;
-  }
-  
-  // we could check that we have DO = 0 here
-  ctrl &= ~SEEPROM_DI;
-  
-  res = 0;
-  for (i=0;i<data_bits;i++) {
-    res = res >> 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 */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x ATM devices
  2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 1/6] net: atm: remove support for Fujitsu FireStream ATM devices Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 2/6] net: atm: remove support for Madge Horizon " Jakub Kicinski
@ 2022-04-26 17:54 ` Jakub Kicinski
  2022-08-10  7:36   ` Jiri Slaby
  2022-04-26 17:54 ` [PATCH net-next 4/6] net: wan: remove support for COSA and SRP synchronous serial boards Jakub Kicinski
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2022-04-26 17:54 UTC (permalink / raw)
  To: davem, pabeni
  Cc: netdev, Jakub Kicinski, Chas Williams, linux-atm-general,
	Thomas Bogendoerfer, linux-mips, arnd

This driver received nothing but automated fixes in the last 15 years.
Since it's using virt_to_bus it's unlikely to be used on any modern
platform.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: Chas Williams <3chas3@gmail.com>
CC: linux-atm-general@lists.sourceforge.net
CC: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
CC: linux-mips@vger.kernel.org
CC: arnd@arndb.de
---
 arch/mips/configs/gpr_defconfig  |    1 -
 arch/mips/configs/mtx1_defconfig |    1 -
 drivers/atm/Kconfig              |   20 -
 drivers/atm/Makefile             |    1 -
 drivers/atm/uPD98401.h           |  293 ------
 drivers/atm/uPD98402.c           |  266 -----
 drivers/atm/uPD98402.h           |  107 --
 drivers/atm/zatm.c               | 1652 ------------------------------
 drivers/atm/zatm.h               |  104 --
 include/uapi/linux/atm_zatm.h    |   47 -
 10 files changed, 2492 deletions(-)
 delete mode 100644 drivers/atm/uPD98401.h
 delete mode 100644 drivers/atm/uPD98402.c
 delete mode 100644 drivers/atm/uPD98402.h
 delete mode 100644 drivers/atm/zatm.c
 delete mode 100644 drivers/atm/zatm.h
 delete mode 100644 include/uapi/linux/atm_zatm.h

diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
index 7ed202db9ef0..d82f4ebf687f 100644
--- a/arch/mips/configs/gpr_defconfig
+++ b/arch/mips/configs/gpr_defconfig
@@ -178,7 +178,6 @@ CONFIG_NETCONSOLE=m
 CONFIG_ATM_TCP=m
 CONFIG_ATM_LANAI=m
 CONFIG_ATM_ENI=m
-CONFIG_ATM_ZATM=m
 CONFIG_ATM_NICSTAR=m
 CONFIG_ATM_IDT77252=m
 CONFIG_ATM_IA=m
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index f46ad2e294fa..0cb4d9aa14d1 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -255,7 +255,6 @@ CONFIG_ARCNET_COM20020_CS=m
 CONFIG_ATM_TCP=m
 CONFIG_ATM_LANAI=m
 CONFIG_ATM_ENI=m
-CONFIG_ATM_ZATM=m
 CONFIG_ATM_NICSTAR=m
 CONFIG_ATM_IDT77252=m
 CONFIG_ATM_IA=m
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index 9c778308722a..63cdb46a3439 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -146,26 +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_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
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index 1b6a8ddaf007..c9eade92019b 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -5,7 +5,6 @@
 
 fore_200e-y	:= fore200e.o
 
-obj-$(CONFIG_ATM_ZATM)		+= zatm.o uPD98402.o
 obj-$(CONFIG_ATM_NICSTAR)	+= nicstar.o
 obj-$(CONFIG_ATM_IA)		+= iphase.o suni.o
 obj-$(CONFIG_ATM_FORE200E)	+= fore_200e.o
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 <linux/module.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/atmdev.h>
-#include <linux/sonet.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/atomic.h>
-
-#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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/sonet.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/uio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/atm_zatm.h>
-#include <linux/capability.h>
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <asm/string.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-#include <linux/uaccess.h>
-#include <linux/nospec.h>
-
-#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 <linux/skbuff.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/sonet.h>
-#include <linux/pci.h>
-
-
-#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/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 <linux/atmapi.h>
-#include <linux/atmioc.h>
-
-#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
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH net-next 4/6] net: wan: remove support for COSA and SRP synchronous serial boards
  2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
                   ` (2 preceding siblings ...)
  2022-04-26 17:54 ` [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x " Jakub Kicinski
@ 2022-04-26 17:54 ` Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 5/6] net: wan: remove support for Z85230-based devices Jakub Kicinski
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2022-04-26 17:54 UTC (permalink / raw)
  To: davem, pabeni
  Cc: netdev, Jakub Kicinski, corbet, linux-doc, alexandre.ghiti,
	linus.walleij, juerg.haefliger, kilobyte, huangguangbin2,
	lipeng321, arnd

Looks like all the changes to this driver had been automated
churn since git era begun. The driver is using virt_to_bus()
so it should be updated to a proper DMA API or removed. Given
the latest "news" entry on the website is from 1999 I'm opting
for the latter.

I'm marking the allocated char device major number as [REMOVED],
I reckon we can't reuse it in case some SW out there assumes its
COSA?

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: corbet@lwn.net
CC: linux-doc@vger.kernel.org
CC: alexandre.ghiti@canonical.com
CC: linus.walleij@linaro.org
CC: juerg.haefliger@canonical.com
CC: kilobyte@angband.pl
CC: huangguangbin2@huawei.com
CC: lipeng321@huawei.com
CC: arnd@arndb.de
CC: Jan "Yenya" Kasprzak <kas@fi.muni.cz>
---
 Documentation/admin-guide/devices.txt |    2 +-
 MAINTAINERS                           |    6 -
 drivers/net/wan/Kconfig               |   22 -
 drivers/net/wan/Makefile              |    1 -
 drivers/net/wan/cosa.c                | 2052 -------------------------
 drivers/net/wan/cosa.h                |  104 --
 6 files changed, 1 insertion(+), 2186 deletions(-)
 delete mode 100644 drivers/net/wan/cosa.c
 delete mode 100644 drivers/net/wan/cosa.h

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/MAINTAINERS b/MAINTAINERS
index dd61684c2573..9619058bb0b9 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 <kas@fi.muni.cz>
-S:	Maintained
-W:	http://www.fi.muni.cz/~kas/cosa/
-F:	drivers/net/wan/cosa*
-
 COUNTER SUBSYSTEM
 M:	William Breathitt Gray <vilhelm.gray@gmail.com>
 L:	linux-iio@vger.kernel.org
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 588b2333cdb8..12c5b6c67ab2 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -35,28 +35,6 @@ config HOSTESS_SV11
 	  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
-	  <http://www.fi.muni.cz/~kas/cosa/> for more information. You can also
-	  read the comment at the top of the <file:drivers/net/wan/cosa.c> 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"
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 1cd42147b34f..901a094c061c 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -16,7 +16,6 @@ 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 <kas@fi.muni.cz>
- *  Generic HDLC port Copyright (C) 2008 Krzysztof Halasa <khc@pm.waw.pl>
- */
-
-/* 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 <novotny@ics.muni.cz>. 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 <kas@fi.muni.cz>.
- *
- * 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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/hdlc.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#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, <kas@fi.muni.cz>");
-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=" "<addr><CR>"
- * "<CR><CR><LF><CR><LF>".
- */
-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=" "<addr> " " =" "<last_byte> " " "
- * Then driver can read the data and the conversation is finished
- * by SRP monitor sending "<CR><LF>." (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 <kas@fi.muni.cz>
- */
-
-#ifndef COSA_H__
-#define COSA_H__
-
-#include <linux/ioctl.h>
-
-#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__ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH net-next 5/6] net: wan: remove support for Z85230-based devices
  2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
                   ` (3 preceding siblings ...)
  2022-04-26 17:54 ` [PATCH net-next 4/6] net: wan: remove support for COSA and SRP synchronous serial boards Jakub Kicinski
@ 2022-04-26 17:54 ` Jakub Kicinski
  2022-04-26 17:54 ` [PATCH net-next 6/6] net: hamradio: remove support for DMA SCC devices Jakub Kicinski
  2022-04-27 11:30 ` [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() patchwork-bot+netdevbpf
  6 siblings, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2022-04-26 17:54 UTC (permalink / raw)
  To: davem, pabeni
  Cc: netdev, Jakub Kicinski, corbet, linux-doc, mkl, dario.binacchi,
	m.chetan.kumar, arnd, juerg.haefliger, linus.walleij, kilobyte,
	lipeng321, huangguangbin2, Alan Cox

Looks like all the changes to this driver had been automated
churn since git era begun. The driver is using virt_to_bus(),
it's just a maintenance burden unlikely to have any users.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: corbet@lwn.net
CC: linux-doc@vger.kernel.org
CC: mkl@pengutronix.de
CC: dario.binacchi@amarulasolutions.com
CC: m.chetan.kumar@intel.com
CC: arnd@arndb.de
CC: juerg.haefliger@canonical.com
CC: linus.walleij@linaro.org
CC: kilobyte@angband.pl
CC: lipeng321@huawei.com
CC: huangguangbin2@huawei.com
CC: Alan Cox <alan@linux.intel.com>
---
 .../networking/device_drivers/index.rst       |    1 -
 .../networking/device_drivers/wan/index.rst   |   18 -
 .../device_drivers/wan/z8530book.rst          |  256 ---
 drivers/net/wan/Kconfig                       |   22 -
 drivers/net/wan/Makefile                      |    2 -
 drivers/net/wan/hostess_sv11.c                |  336 ----
 drivers/net/wan/sealevel.c                    |  352 ----
 drivers/net/wan/z85230.c                      | 1641 -----------------
 drivers/net/wan/z85230.h                      |  407 ----
 9 files changed, 3035 deletions(-)
 delete mode 100644 Documentation/networking/device_drivers/wan/index.rst
 delete mode 100644 Documentation/networking/device_drivers/wan/z8530book.rst
 delete mode 100644 drivers/net/wan/hostess_sv11.c
 delete mode 100644 drivers/net/wan/sealevel.c
 delete mode 100644 drivers/net/wan/z85230.c
 delete mode 100644 drivers/net/wan/z85230.h

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 @@ Hardware Device Drivers
    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/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 12c5b6c67ab2..dcb069dde66b 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -23,28 +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.
-
-# 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 901a094c061c..5bec8fae47f8 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -14,8 +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_FARSYNC)		+= farsync.o
 
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
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 <khc@pm.waw.pl>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/hdlc.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-#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 <khc@pm.waw.pl>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/hdlc.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-#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 <alan@lxorguk.ukuu.org.uk>
- *	(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
- *					<alan@lxorguk.ukuu.org.uk>
- *
- *	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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/hdlc.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#define RT_LOCK
-#define RT_UNLOCK
-#include <linux/spinlock.h>
-
-#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 <alan@lxorguk.ukuu.org.uk>
- */
-
-#ifndef _Z8530_H
-#define _Z8530_H
-
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-
-/* 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) */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH net-next 6/6] net: hamradio: remove support for DMA SCC devices
  2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
                   ` (4 preceding siblings ...)
  2022-04-26 17:54 ` [PATCH net-next 5/6] net: wan: remove support for Z85230-based devices Jakub Kicinski
@ 2022-04-26 17:54 ` Jakub Kicinski
  2022-04-27 11:30 ` [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() patchwork-bot+netdevbpf
  6 siblings, 0 replies; 13+ messages in thread
From: Jakub Kicinski @ 2022-04-26 17:54 UTC (permalink / raw)
  To: davem, pabeni; +Cc: netdev, Jakub Kicinski, jreuter, arnd, linux-hams

Another incarnation of Z8530, looks like? Again, no real changes
in the git history, and it needs VIRT_TO_BUS. Unlikely to have
users, let's spend less time refactoring dead code...

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: jreuter@yaina.de
CC: arnd@arndb.de
CC: linux-hams@vger.kernel.org
---
 MAINTAINERS                   |    1 -
 drivers/net/hamradio/Kconfig  |   34 -
 drivers/net/hamradio/Makefile |    1 -
 drivers/net/hamradio/dmascc.c | 1450 ---------------------------------
 4 files changed, 1486 deletions(-)
 delete mode 100644 drivers/net/hamradio/dmascc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9619058bb0b9..cc5559a7fb5c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8766,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/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 <http://www.tldp.org/docs.html#howto>.
-
-	  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
-	  <http://www.linux-ax25.org/wiki/Ax25-tools>. 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 <hch@infradead.org>
 #
 
-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 <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/rtnetlink.h>
-#include <linux/sockios.h>
-#include <linux/workqueue.h>
-#include <linux/atomic.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <linux/jiffies.h>
-#include <net/ax25.h>
-#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;
-	}
-}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus()
  2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
                   ` (5 preceding siblings ...)
  2022-04-26 17:54 ` [PATCH net-next 6/6] net: hamradio: remove support for DMA SCC devices Jakub Kicinski
@ 2022-04-27 11:30 ` patchwork-bot+netdevbpf
  6 siblings, 0 replies; 13+ messages in thread
From: patchwork-bot+netdevbpf @ 2022-04-27 11:30 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, pabeni, netdev

Hello:

This series was applied to netdev/net-next.git (master)
by David S. Miller <davem@davemloft.net>:

On Tue, 26 Apr 2022 10:54:30 -0700 you wrote:
> Networking is currently the main offender in using virt_to_bus().
> Frankly all the drivers which use it are super old and unlikely
> to be used today. They are just an ongoing maintenance burden.
> 
> In other words this series is using virt_to_bus() as an excuse
> to shed some old stuff. Having done the tree-wide dev_addr_set()
> conversion recently I have limited sympathy for carrying dead
> code.
> 
> [...]

Here is the summary with links:
  - [net-next,1/6] net: atm: remove support for Fujitsu FireStream ATM devices
    https://git.kernel.org/netdev/net-next/c/41c335c82123
  - [net-next,2/6] net: atm: remove support for Madge Horizon ATM devices
    https://git.kernel.org/netdev/net-next/c/5b74a20d35ab
  - [net-next,3/6] net: atm: remove support for ZeitNet ZN122x ATM devices
    https://git.kernel.org/netdev/net-next/c/052e1f01bfae
  - [net-next,4/6] net: wan: remove support for COSA and SRP synchronous serial boards
    https://git.kernel.org/netdev/net-next/c/89fbca3307d4
  - [net-next,5/6] net: wan: remove support for Z85230-based devices
    https://git.kernel.org/netdev/net-next/c/bc6df26f1f78
  - [net-next,6/6] net: hamradio: remove support for DMA SCC devices
    https://git.kernel.org/netdev/net-next/c/865e2eb08f51

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x ATM devices
  2022-04-26 17:54 ` [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x " Jakub Kicinski
@ 2022-08-10  7:36   ` Jiri Slaby
  2022-08-10  9:11     ` Arnd Bergmann
  0 siblings, 1 reply; 13+ messages in thread
From: Jiri Slaby @ 2022-08-10  7:36 UTC (permalink / raw)
  To: Jakub Kicinski, davem, pabeni
  Cc: netdev, Chas Williams, linux-atm-general, Thomas Bogendoerfer,
	linux-mips, arnd

On 26. 04. 22, 19:54, Jakub Kicinski wrote:
> This driver received nothing but automated fixes in the last 15 years.
> Since it's using virt_to_bus it's unlikely to be used on any modern
> platform.
...
>   delete mode 100644 include/uapi/linux/atm_zatm.h

This unfortunately breaks linux-atm:
zntune.c:18:10: fatal error: linux/atm_zatm.h: No such file or directory

The source does also:
ioctl(s,ZATM_SETPOOL,&sioc)
ioctl(s,zero ? ZATM_GETPOOLZ : ZATM_GETPOOL,&sioc)
etc.

So we should likely revert the below:

> --- 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 <linux/atmapi.h>
> -#include <linux/atmioc.h>
> -
> -#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

thanks,
-- 
js
suse labs


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x ATM devices
  2022-08-10  7:36   ` Jiri Slaby
@ 2022-08-10  9:11     ` Arnd Bergmann
  2022-08-10 16:42       ` Jakub Kicinski
  0 siblings, 1 reply; 13+ messages in thread
From: Arnd Bergmann @ 2022-08-10  9:11 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Jakub Kicinski, davem, pabeni, netdev, Chas Williams,
	linux-atm-general, Thomas Bogendoerfer, linux-mips, arnd

On Wed, Aug 10, 2022 at 9:36 AM Jiri Slaby <jirislaby@kernel.org> wrote:
>
> On 26. 04. 22, 19:54, Jakub Kicinski wrote:
> > This driver received nothing but automated fixes in the last 15 years.
> > Since it's using virt_to_bus it's unlikely to be used on any modern
> > platform.
> ...
> >   delete mode 100644 include/uapi/linux/atm_zatm.h
>
> This unfortunately breaks linux-atm:
> zntune.c:18:10: fatal error: linux/atm_zatm.h: No such file or directory
>
> The source does also:
> ioctl(s,ZATM_SETPOOL,&sioc)
> ioctl(s,zero ? ZATM_GETPOOLZ : ZATM_GETPOOL,&sioc)
> etc.
>
> So we should likely revert the below:

I suppose there is no chance of also getting the linux-atm package updated
to not include those source files, right? The last release I found on
sourceforge
is 12 years old, but maybe I was looking in the wrong place.

          Arnd

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x ATM devices
  2022-08-10  9:11     ` Arnd Bergmann
@ 2022-08-10 16:42       ` Jakub Kicinski
  2022-08-11  5:19         ` Jiri Slaby
  0 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2022-08-10 16:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jiri Slaby, davem, pabeni, netdev, Chas Williams,
	linux-atm-general, Thomas Bogendoerfer, linux-mips

On Wed, 10 Aug 2022 11:11:32 +0200 Arnd Bergmann wrote:
> > This unfortunately breaks linux-atm:
> > zntune.c:18:10: fatal error: linux/atm_zatm.h: No such file or directory
> >
> > The source does also:
> > ioctl(s,ZATM_SETPOOL,&sioc)
> > ioctl(s,zero ? ZATM_GETPOOLZ : ZATM_GETPOOL,&sioc)
> > etc.
> >
> > So we should likely revert the below:  
> 
> I suppose there is no chance of also getting the linux-atm package updated
> to not include those source files, right? The last release I found on
> sourceforge
> is 12 years old, but maybe I was looking in the wrong place.

Is linux-atm used for something remotely modern? PPPoA? Maybe it's 
time to ditch it completely? I'll send the revert in any case.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x ATM devices
  2022-08-10 16:42       ` Jakub Kicinski
@ 2022-08-11  5:19         ` Jiri Slaby
  2022-08-11  9:18           ` Arnd Bergmann
  0 siblings, 1 reply; 13+ messages in thread
From: Jiri Slaby @ 2022-08-11  5:19 UTC (permalink / raw)
  To: Jakub Kicinski, Arnd Bergmann
  Cc: davem, pabeni, netdev, Chas Williams, linux-atm-general,
	Thomas Bogendoerfer, linux-mips

On 10. 08. 22, 18:42, Jakub Kicinski wrote:
> On Wed, 10 Aug 2022 11:11:32 +0200 Arnd Bergmann wrote:
>>> This unfortunately breaks linux-atm:
>>> zntune.c:18:10: fatal error: linux/atm_zatm.h: No such file or directory
>>>
>>> The source does also:
>>> ioctl(s,ZATM_SETPOOL,&sioc)
>>> ioctl(s,zero ? ZATM_GETPOOLZ : ZATM_GETPOOL,&sioc)
>>> etc.
>>>
>>> So we should likely revert the below:
>>
>> I suppose there is no chance of also getting the linux-atm package updated
>> to not include those source files, right? The last release I found on
>> sourceforge
>> is 12 years old, but maybe I was looking in the wrong place.
> 
> Is linux-atm used for something remotely modern? PPPoA? Maybe it's
> time to ditch it completely? I'll send the revert in any case.

Sorry, I have no idea. openSUSE is just a provider of an rpm -- if there 
any users? Who knows...

thanks,
-- 
js
suse labs


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x ATM devices
  2022-08-11  5:19         ` Jiri Slaby
@ 2022-08-11  9:18           ` Arnd Bergmann
  0 siblings, 0 replies; 13+ messages in thread
From: Arnd Bergmann @ 2022-08-11  9:18 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Jakub Kicinski, Arnd Bergmann, davem, pabeni, netdev,
	Chas Williams, linux-atm-general, Thomas Bogendoerfer,
	linux-mips

On Thu, Aug 11, 2022 at 7:19 AM Jiri Slaby <jirislaby@kernel.org> wrote:
> On 10. 08. 22, 18:42, Jakub Kicinski wrote:
> > On Wed, 10 Aug 2022 11:11:32 +0200 Arnd Bergmann wrote:
> >>> This unfortunately breaks linux-atm:
> >>> zntune.c:18:10: fatal error: linux/atm_zatm.h: No such file or directory
> >>>
> >>> The source does also:
> >>> ioctl(s,ZATM_SETPOOL,&sioc)
> >>> ioctl(s,zero ? ZATM_GETPOOLZ : ZATM_GETPOOL,&sioc)
> >>> etc.
> >>>
> >>> So we should likely revert the below:
> >>
> >> I suppose there is no chance of also getting the linux-atm package updated
> >> to not include those source files, right? The last release I found on
> >> sourceforge
> >> is 12 years old, but maybe I was looking in the wrong place.
> >
> > Is linux-atm used for something remotely modern? PPPoA? Maybe it's
> > time to ditch it completely? I'll send the revert in any case.
>
> Sorry, I have no idea. openSUSE is just a provider of an rpm -- if there
> any users? Who knows...

I think in theory this is the subsystem that DSL drivers would use, but
there is only one driver for the "Solos ADSL2+".

OpenWRT used to support the TI AR7 platform (later owned by Infineon,
Lantiq, and Intel, now Maxlinear) with the "sangam-atm" driver for DSL,
but that driver was never available in mainline Linux and is now gone
from OpenWRT as well.

It appears that the later hardware that is still supported uses a custom
atm driver implementation rather than the in-kernel subsystem, using
a different set of ioctls:
https://git.openwrt.org/?p=openwrt/openwrt.git;a=tree;f=package/kernel/lantiq/ltq-atm/src

There are also DSL SoCs from (at least) Broadcom, Realtek, Mediatek and
Qualcomm, but no open source drivers, so I guess they probably all
use their own kernel subsystems.

       Arnd

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-08-11  9:19 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-26 17:54 [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() Jakub Kicinski
2022-04-26 17:54 ` [PATCH net-next 1/6] net: atm: remove support for Fujitsu FireStream ATM devices Jakub Kicinski
2022-04-26 17:54 ` [PATCH net-next 2/6] net: atm: remove support for Madge Horizon " Jakub Kicinski
2022-04-26 17:54 ` [PATCH net-next 3/6] net: atm: remove support for ZeitNet ZN122x " Jakub Kicinski
2022-08-10  7:36   ` Jiri Slaby
2022-08-10  9:11     ` Arnd Bergmann
2022-08-10 16:42       ` Jakub Kicinski
2022-08-11  5:19         ` Jiri Slaby
2022-08-11  9:18           ` Arnd Bergmann
2022-04-26 17:54 ` [PATCH net-next 4/6] net: wan: remove support for COSA and SRP synchronous serial boards Jakub Kicinski
2022-04-26 17:54 ` [PATCH net-next 5/6] net: wan: remove support for Z85230-based devices Jakub Kicinski
2022-04-26 17:54 ` [PATCH net-next 6/6] net: hamradio: remove support for DMA SCC devices Jakub Kicinski
2022-04-27 11:30 ` [PATCH net-next 0/6] net: remove non-Ethernet drivers using virt_to_bus() patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).