Netdev List
 help / color / mirror / Atom feed
* [PATCH net 12/18] drivers: net: cirrus: mac89x0: Remove this driver
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

The mac89x0 was written by Russell Nelson in 1996. It is an MAC
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/cirrus/Kconfig   |  10 -
 drivers/net/ethernet/cirrus/Makefile  |   1 -
 drivers/net/ethernet/cirrus/cs89x0.h  | 461 ---------------------------
 drivers/net/ethernet/cirrus/mac89x0.c | 577 ----------------------------------
 4 files changed, 1049 deletions(-)

diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 1a0c7b3bfcd6..786d379e79fe 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -25,14 +25,4 @@ config EP93XX_ETH
 	  This is a driver for the ethernet hardware included in EP93xx CPUs.
 	  Say Y if you are building a kernel for EP93xx based devices.
 
-config MAC89x0
-	tristate "Macintosh CS89x0 based ethernet cards"
-	depends on MAC
-	help
-	  Support for CS89x0 chipset based Ethernet cards.  If you have a
-	  Nubus or LC-PDS network (Ethernet) card of this type, say Y here.
-
-	  To compile this driver as a module, choose M here. This module will
-	  be called mac89x0.
-
 endif # NET_VENDOR_CIRRUS
diff --git a/drivers/net/ethernet/cirrus/Makefile b/drivers/net/ethernet/cirrus/Makefile
index cb740939d976..03800af0f0e1 100644
--- a/drivers/net/ethernet/cirrus/Makefile
+++ b/drivers/net/ethernet/cirrus/Makefile
@@ -4,4 +4,3 @@
 #
 
 obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
-obj-$(CONFIG_MAC89x0) += mac89x0.o
diff --git a/drivers/net/ethernet/cirrus/cs89x0.h b/drivers/net/ethernet/cirrus/cs89x0.h
deleted file mode 100644
index 210f9ec9af4b..000000000000
--- a/drivers/net/ethernet/cirrus/cs89x0.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*  Copyright, 1988-1992, Russell Nelson, Crynwr Software
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, version 1.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-   */
-
-
-#define PP_ChipID 0x0000	/* offset   0h -> Corp -ID              */
-				/* offset   2h -> Model/Product Number  */
-				/* offset   3h -> Chip Revision Number  */
-
-#define PP_ISAIOB 0x0020	/*  IO base address */
-#define PP_CS8900_ISAINT 0x0022	/*  ISA interrupt select */
-#define PP_CS8920_ISAINT 0x0370	/*  ISA interrupt select */
-#define PP_CS8900_ISADMA 0x0024	/*  ISA Rec DMA channel */
-#define PP_CS8920_ISADMA 0x0374	/*  ISA Rec DMA channel */
-#define PP_ISASOF 0x0026	/*  ISA DMA offset */
-#define PP_DmaFrameCnt 0x0028	/*  ISA DMA Frame count */
-#define PP_DmaByteCnt 0x002A	/*  ISA DMA Byte count */
-#define PP_CS8900_ISAMemB 0x002C	/*  Memory base */
-#define PP_CS8920_ISAMemB 0x0348 /*  */
-
-#define PP_ISABootBase 0x0030	/*  Boot Prom base  */
-#define PP_ISABootMask 0x0034	/*  Boot Prom Mask */
-
-/* EEPROM data and command registers */
-#define PP_EECMD 0x0040		/*  NVR Interface Command register */
-#define PP_EEData 0x0042	/*  NVR Interface Data Register */
-#define PP_DebugReg 0x0044	/*  Debug Register */
-
-#define PP_RxCFG 0x0102		/*  Rx Bus config */
-#define PP_RxCTL 0x0104		/*  Receive Control Register */
-#define PP_TxCFG 0x0106		/*  Transmit Config Register */
-#define PP_TxCMD 0x0108		/*  Transmit Command Register */
-#define PP_BufCFG 0x010A	/*  Bus configuration Register */
-#define PP_LineCTL 0x0112	/*  Line Config Register */
-#define PP_SelfCTL 0x0114	/*  Self Command Register */
-#define PP_BusCTL 0x0116	/*  ISA bus control Register */
-#define PP_TestCTL 0x0118	/*  Test Register */
-#define PP_AutoNegCTL 0x011C	/*  Auto Negotiation Ctrl */
-
-#define PP_ISQ 0x0120		/*  Interrupt Status */
-#define PP_RxEvent 0x0124	/*  Rx Event Register */
-#define PP_TxEvent 0x0128	/*  Tx Event Register */
-#define PP_BufEvent 0x012C	/*  Bus Event Register */
-#define PP_RxMiss 0x0130	/*  Receive Miss Count */
-#define PP_TxCol 0x0132		/*  Transmit Collision Count */
-#define PP_LineST 0x0134	/*  Line State Register */
-#define PP_SelfST 0x0136	/*  Self State register */
-#define PP_BusST 0x0138		/*  Bus Status */
-#define PP_TDR 0x013C		/*  Time Domain Reflectometry */
-#define PP_AutoNegST 0x013E	/*  Auto Neg Status */
-#define PP_TxCommand 0x0144	/*  Tx Command */
-#define PP_TxLength 0x0146	/*  Tx Length */
-#define PP_LAF 0x0150		/*  Hash Table */
-#define PP_IA 0x0158		/*  Physical Address Register */
-
-#define PP_RxStatus 0x0400	/*  Receive start of frame */
-#define PP_RxLength 0x0402	/*  Receive Length of frame */
-#define PP_RxFrame 0x0404	/*  Receive frame pointer */
-#define PP_TxFrame 0x0A00	/*  Transmit frame pointer */
-
-/*  Primary I/O Base Address. If no I/O base is supplied by the user, then this */
-/*  can be used as the default I/O base to access the PacketPage Area. */
-#define DEFAULTIOBASE 0x0300
-#define FIRST_IO 0x020C		/*  First I/O port to check */
-#define LAST_IO 0x037C		/*  Last I/O port to check (+10h) */
-#define ADD_MASK 0x3000		/*  Mask it use of the ADD_PORT register */
-#define ADD_SIG 0x3000		/*  Expected ID signature */
-
-/* On Macs, we only need use the ISA I/O stuff until we do MEMORY_ON */
-#ifdef CONFIG_MAC
-#define LCSLOTBASE 0xfee00000
-#define MMIOBASE 0x40000
-#endif
-
-#define CHIP_EISA_ID_SIG 0x630E   /*  Product ID Code for Crystal Chip (CS8900 spec 4.3) */
-#define CHIP_EISA_ID_SIG_STR "0x630E"
-
-#ifdef IBMEIPKT
-#define EISA_ID_SIG 0x4D24	/*  IBM */
-#define PART_NO_SIG 0x1010	/*  IBM */
-#define MONGOOSE_BIT 0x0000	/*  IBM */
-#else
-#define EISA_ID_SIG 0x630E	/*  PnP Vendor ID (same as chip id for Crystal board) */
-#define PART_NO_SIG 0x4000	/*  ID code CS8920 board (PnP Vendor Product code) */
-#define MONGOOSE_BIT 0x2000	/*  PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */
-#endif
-
-#define PRODUCT_ID_ADD 0x0002   /*  Address of product ID */
-
-/*  Mask to find out the types of  registers */
-#define REG_TYPE_MASK 0x001F
-
-/*  Eeprom Commands */
-#define ERSE_WR_ENBL 0x00F0
-#define ERSE_WR_DISABLE 0x0000
-
-/*  Defines Control/Config register quintuplet numbers */
-#define RX_BUF_CFG 0x0003
-#define RX_CONTROL 0x0005
-#define TX_CFG 0x0007
-#define TX_COMMAND 0x0009
-#define BUF_CFG 0x000B
-#define LINE_CONTROL 0x0013
-#define SELF_CONTROL 0x0015
-#define BUS_CONTROL 0x0017
-#define TEST_CONTROL 0x0019
-
-/*  Defines Status/Count registers quintuplet numbers */
-#define RX_EVENT 0x0004
-#define TX_EVENT 0x0008
-#define BUF_EVENT 0x000C
-#define RX_MISS_COUNT 0x0010
-#define TX_COL_COUNT 0x0012
-#define LINE_STATUS 0x0014
-#define SELF_STATUS 0x0016
-#define BUS_STATUS 0x0018
-#define TDR 0x001C
-
-/* PP_RxCFG - Receive  Configuration and Interrupt Mask bit definition -  Read/write */
-#define SKIP_1 0x0040
-#define RX_STREAM_ENBL 0x0080
-#define RX_OK_ENBL 0x0100
-#define RX_DMA_ONLY 0x0200
-#define AUTO_RX_DMA 0x0400
-#define BUFFER_CRC 0x0800
-#define RX_CRC_ERROR_ENBL 0x1000
-#define RX_RUNT_ENBL 0x2000
-#define RX_EXTRA_DATA_ENBL 0x4000
-
-/* PP_RxCTL - Receive Control bit definition - Read/write */
-#define RX_IA_HASH_ACCEPT 0x0040
-#define RX_PROM_ACCEPT 0x0080
-#define RX_OK_ACCEPT 0x0100
-#define RX_MULTCAST_ACCEPT 0x0200
-#define RX_IA_ACCEPT 0x0400
-#define RX_BROADCAST_ACCEPT 0x0800
-#define RX_BAD_CRC_ACCEPT 0x1000
-#define RX_RUNT_ACCEPT 0x2000
-#define RX_EXTRA_DATA_ACCEPT 0x4000
-#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT)
-/*  Default receive mode - individually addressed, broadcast, and error free */
-#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT)
-
-/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */
-#define TX_LOST_CRS_ENBL 0x0040
-#define TX_SQE_ERROR_ENBL 0x0080
-#define TX_OK_ENBL 0x0100
-#define TX_LATE_COL_ENBL 0x0200
-#define TX_JBR_ENBL 0x0400
-#define TX_ANY_COL_ENBL 0x0800
-#define TX_16_COL_ENBL 0x8000
-
-/* PP_TxCMD - Transmit Command bit definition - Read-only */
-#define TX_START_4_BYTES 0x0000
-#define TX_START_64_BYTES 0x0040
-#define TX_START_128_BYTES 0x0080
-#define TX_START_ALL_BYTES 0x00C0
-#define TX_FORCE 0x0100
-#define TX_ONE_COL 0x0200
-#define TX_TWO_PART_DEFF_DISABLE 0x0400
-#define TX_NO_CRC 0x1000
-#define TX_RUNT 0x2000
-
-/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */
-#define GENERATE_SW_INTERRUPT 0x0040
-#define RX_DMA_ENBL 0x0080
-#define READY_FOR_TX_ENBL 0x0100
-#define TX_UNDERRUN_ENBL 0x0200
-#define RX_MISS_ENBL 0x0400
-#define RX_128_BYTE_ENBL 0x0800
-#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000
-#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000
-#define RX_DEST_MATCH_ENBL 0x8000
-
-/* PP_LineCTL - Line Control bit definition - Read/write */
-#define SERIAL_RX_ON 0x0040
-#define SERIAL_TX_ON 0x0080
-#define AUI_ONLY 0x0100
-#define AUTO_AUI_10BASET 0x0200
-#define MODIFIED_BACKOFF 0x0800
-#define NO_AUTO_POLARITY 0x1000
-#define TWO_PART_DEFDIS 0x2000
-#define LOW_RX_SQUELCH 0x4000
-
-/* PP_SelfCTL - Software Self Control bit definition - Read/write */
-#define POWER_ON_RESET 0x0040
-#define SW_STOP 0x0100
-#define SLEEP_ON 0x0200
-#define AUTO_WAKEUP 0x0400
-#define HCB0_ENBL 0x1000
-#define HCB1_ENBL 0x2000
-#define HCB0 0x4000
-#define HCB1 0x8000
-
-/* PP_BusCTL - ISA Bus Control bit definition - Read/write */
-#define RESET_RX_DMA 0x0040
-#define MEMORY_ON 0x0400
-#define DMA_BURST_MODE 0x0800
-#define IO_CHANNEL_READY_ON 0x1000
-#define RX_DMA_SIZE_64K 0x2000
-#define ENABLE_IRQ 0x8000
-
-/* PP_TestCTL - Test Control bit definition - Read/write */
-#define LINK_OFF 0x0080
-#define ENDEC_LOOPBACK 0x0200
-#define AUI_LOOPBACK 0x0400
-#define BACKOFF_OFF 0x0800
-#define FDX_8900 0x4000
-#define FAST_TEST 0x8000
-
-/* PP_RxEvent - Receive Event Bit definition - Read-only */
-#define RX_IA_HASHED 0x0040
-#define RX_DRIBBLE 0x0080
-#define RX_OK 0x0100
-#define RX_HASHED 0x0200
-#define RX_IA 0x0400
-#define RX_BROADCAST 0x0800
-#define RX_CRC_ERROR 0x1000
-#define RX_RUNT 0x2000
-#define RX_EXTRA_DATA 0x4000
-
-#define HASH_INDEX_MASK 0x0FC00
-
-/* PP_TxEvent - Transmit Event Bit definition - Read-only */
-#define TX_LOST_CRS 0x0040
-#define TX_SQE_ERROR 0x0080
-#define TX_OK 0x0100
-#define TX_LATE_COL 0x0200
-#define TX_JBR 0x0400
-#define TX_16_COL 0x8000
-#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS)
-#define TX_COL_COUNT_MASK 0x7800
-
-/* PP_BufEvent - Buffer Event Bit definition - Read-only */
-#define SW_INTERRUPT 0x0040
-#define RX_DMA 0x0080
-#define READY_FOR_TX 0x0100
-#define TX_UNDERRUN 0x0200
-#define RX_MISS 0x0400
-#define RX_128_BYTE 0x0800
-#define TX_COL_OVRFLW 0x1000
-#define RX_MISS_OVRFLW 0x2000
-#define RX_DEST_MATCH 0x8000
-
-/* PP_LineST - Ethernet Line Status bit definition - Read-only */
-#define LINK_OK 0x0080
-#define AUI_ON 0x0100
-#define TENBASET_ON 0x0200
-#define POLARITY_OK 0x1000
-#define CRS_OK 0x4000
-
-/* PP_SelfST - Chip Software Status bit definition */
-#define ACTIVE_33V 0x0040
-#define INIT_DONE 0x0080
-#define SI_BUSY 0x0100
-#define EEPROM_PRESENT 0x0200
-#define EEPROM_OK 0x0400
-#define EL_PRESENT 0x0800
-#define EE_SIZE_64 0x1000
-
-/* PP_BusST - ISA Bus Status bit definition */
-#define TX_BID_ERROR 0x0080
-#define READY_FOR_TX_NOW 0x0100
-
-/* PP_AutoNegCTL - Auto Negotiation Control bit definition */
-#define RE_NEG_NOW 0x0040
-#define ALLOW_FDX 0x0080
-#define AUTO_NEG_ENABLE 0x0100
-#define NLP_ENABLE 0x0200
-#define FORCE_FDX 0x8000
-#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE)
-#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW)
-
-/* PP_AutoNegST - Auto Negotiation Status bit definition */
-#define AUTO_NEG_BUSY 0x0080
-#define FLP_LINK 0x0100
-#define FLP_LINK_GOOD 0x0800
-#define LINK_FAULT 0x1000
-#define HDX_ACTIVE 0x4000
-#define FDX_ACTIVE 0x8000
-
-/*  The following block defines the ISQ event types */
-#define ISQ_RECEIVER_EVENT 0x04
-#define ISQ_TRANSMITTER_EVENT 0x08
-#define ISQ_BUFFER_EVENT 0x0c
-#define ISQ_RX_MISS_EVENT 0x10
-#define ISQ_TX_COL_EVENT 0x12
-
-#define ISQ_EVENT_MASK 0x003F   /*  ISQ mask to find out type of event */
-#define ISQ_HIST 16		/*  small history buffer */
-#define AUTOINCREMENT 0x8000	/*  Bit mask to set bit-15 for autoincrement */
-
-#define TXRXBUFSIZE 0x0600
-#define RXDMABUFSIZE 0x8000
-#define RXDMASIZE 0x4000
-#define TXRX_LENGTH_MASK 0x07FF
-
-/*  rx options bits */
-#define RCV_WITH_RXON	1       /*  Set SerRx ON */
-#define RCV_COUNTS	2       /*  Use Framecnt1 */
-#define RCV_PONG	4       /*  Pong respondent */
-#define RCV_DONG	8       /*  Dong operation */
-#define RCV_POLLING	0x10	/*  Poll RxEvent */
-#define RCV_ISQ		0x20	/*  Use ISQ, int */
-#define RCV_AUTO_DMA	0x100	/*  Set AutoRxDMAE */
-#define RCV_DMA		0x200	/*  Set RxDMA only */
-#define RCV_DMA_ALL	0x400	/*  Copy all DMA'ed */
-#define RCV_FIXED_DATA	0x800	/*  Every frame same */
-#define RCV_IO		0x1000	/*  Use ISA IO only */
-#define RCV_MEMORY	0x2000	/*  Use ISA Memory */
-
-#define RAM_SIZE	0x1000       /*  The card has 4k bytes or RAM */
-#define PKT_START PP_TxFrame  /*  Start of packet RAM */
-
-#define RX_FRAME_PORT	0x0000
-#define TX_FRAME_PORT RX_FRAME_PORT
-#define TX_CMD_PORT	0x0004
-#define TX_NOW		0x0000       /*  Tx packet after   5 bytes copied */
-#define TX_AFTER_381	0x0040       /*  Tx packet after 381 bytes copied */
-#define TX_AFTER_ALL	0x00c0       /*  Tx packet after all bytes copied */
-#define TX_LEN_PORT	0x0006
-#define ISQ_PORT	0x0008
-#define ADD_PORT	0x000A
-#define DATA_PORT	0x000C
-
-#define EEPROM_WRITE_EN		0x00F0
-#define EEPROM_WRITE_DIS	0x0000
-#define EEPROM_WRITE_CMD	0x0100
-#define EEPROM_READ_CMD		0x0200
-
-/*  Receive Header */
-/*  Description of header of each packet in receive area of memory */
-#define RBUF_EVENT_LOW	0   /*  Low byte of RxEvent - status of received frame */
-#define RBUF_EVENT_HIGH	1   /*  High byte of RxEvent - status of received frame */
-#define RBUF_LEN_LOW	2   /*  Length of received data - low byte */
-#define RBUF_LEN_HI	3   /*  Length of received data - high byte */
-#define RBUF_HEAD_LEN	4   /*  Length of this header */
-
-#define CHIP_READ 0x1   /*  Used to mark state of the repins code (chip or dma) */
-#define DMA_READ 0x2   /*  Used to mark state of the repins code (chip or dma) */
-
-/*  for bios scan */
-/*  */
-#ifdef CSDEBUG
-/*  use these values for debugging bios scan */
-#define BIOS_START_SEG 0x00000
-#define BIOS_OFFSET_INC 0x0010
-#else
-#define BIOS_START_SEG 0x0c000
-#define BIOS_OFFSET_INC 0x0200
-#endif
-
-#define BIOS_LAST_OFFSET 0x0fc00
-
-/*  Byte offsets into the EEPROM configuration buffer */
-#define ISA_CNF_OFFSET 0x6
-#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8)			/*  8900 eeprom */
-#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8)		/*  8920 eeprom */
-
-  /*  the assumption here is that the bits in the eeprom are generally  */
-  /*  in the same position as those in the autonegctl register. */
-  /*  Of course the IMM bit is not in that register so it must be  */
-  /*  masked out */
-#define EE_FORCE_FDX  0x8000
-#define EE_NLP_ENABLE 0x0200
-#define EE_AUTO_NEG_ENABLE 0x0100
-#define EE_ALLOW_FDX 0x0080
-#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX)
-
-#define IMM_BIT 0x0040		/*  ignore missing media	 */
-
-#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2)
-#define A_CNF_10B_T 0x0001
-#define A_CNF_AUI 0x0002
-#define A_CNF_10B_2 0x0004
-#define A_CNF_MEDIA_TYPE 0x0070
-#define A_CNF_MEDIA_AUTO 0x0070
-#define A_CNF_MEDIA_10B_T 0x0020
-#define A_CNF_MEDIA_AUI 0x0040
-#define A_CNF_MEDIA_10B_2 0x0010
-#define A_CNF_DC_DC_POLARITY 0x0080
-#define A_CNF_NO_AUTO_POLARITY 0x2000
-#define A_CNF_LOW_RX_SQUELCH 0x4000
-#define A_CNF_EXTND_10B_2 0x8000
-
-#define PACKET_PAGE_OFFSET 0x8
-
-/*  Bit definitions for the ISA configuration word from the EEPROM */
-#define INT_NO_MASK 0x000F
-#define DMA_NO_MASK 0x0070
-#define ISA_DMA_SIZE 0x0200
-#define ISA_AUTO_RxDMA 0x0400
-#define ISA_RxDMA 0x0800
-#define DMA_BURST 0x1000
-#define STREAM_TRANSFER 0x2000
-#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA)
-
-/*  DMA controller registers */
-#define DMA_BASE 0x00     /*  DMA controller base */
-#define DMA_BASE_2 0x0C0    /*  DMA controller base */
-
-#define DMA_STAT 0x0D0    /*  DMA controller status register */
-#define DMA_MASK 0x0D4    /*  DMA controller mask register */
-#define DMA_MODE 0x0D6    /*  DMA controller mode register */
-#define DMA_RESETFF 0x0D8    /*  DMA controller first/last flip flop */
-
-/*  DMA data */
-#define DMA_DISABLE 0x04     /*  Disable channel n */
-#define DMA_ENABLE 0x00     /*  Enable channel n */
-/*  Demand transfers, incr. address, auto init, writes, ch. n */
-#define DMA_RX_MODE 0x14
-/*  Demand transfers, incr. address, auto init, reads, ch. n */
-#define DMA_TX_MODE 0x18
-
-#define DMA_SIZE (16*1024) /*  Size of dma buffer - 16k */
-
-#define CS8900 0x0000
-#define CS8920 0x4000
-#define CS8920M 0x6000
-#define REVISON_BITS 0x1F00
-#define EEVER_NUMBER 0x12
-#define CHKSUM_LEN 0x14
-#define CHKSUM_VAL 0x0000
-#define START_EEPROM_DATA 0x001c /*  Offset into eeprom for start of data */
-#define IRQ_MAP_EEPROM_DATA 0x0046 /*  Offset into eeprom for the IRQ map */
-#define IRQ_MAP_LEN 0x0004 /*  No of bytes to read for the IRQ map */
-#define PNP_IRQ_FRMT 0x0022 /*  PNP small item IRQ format */
-#define CS8900_IRQ_MAP 0x1c20 /*  This IRQ map is fixed */
-
-#define CS8920_NO_INTS 0x0F   /*  Max CS8920 interrupt select # */
-
-#define PNP_ADD_PORT 0x0279
-#define PNP_WRITE_PORT 0x0A79
-
-#define GET_PNP_ISA_STRUCT 0x40
-#define PNP_ISA_STRUCT_LEN 0x06
-#define PNP_CSN_CNT_OFF 0x01
-#define PNP_RD_PORT_OFF 0x02
-#define PNP_FUNCTION_OK 0x00
-#define PNP_WAKE 0x03
-#define PNP_RSRC_DATA 0x04
-#define PNP_RSRC_READY 0x01
-#define PNP_STATUS 0x05
-#define PNP_ACTIVATE 0x30
-#define PNP_CNF_IO_H 0x60
-#define PNP_CNF_IO_L 0x61
-#define PNP_CNF_INT 0x70
-#define PNP_CNF_DMA 0x74
-#define PNP_CNF_MEM 0x48
diff --git a/drivers/net/ethernet/cirrus/mac89x0.c b/drivers/net/ethernet/cirrus/mac89x0.c
deleted file mode 100644
index 6723df9b65d9..000000000000
--- a/drivers/net/ethernet/cirrus/mac89x0.c
+++ /dev/null
@@ -1,577 +0,0 @@
-/* mac89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
-/*
-	Written 1996 by Russell Nelson, with reference to skeleton.c
-	written 1993-1994 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached at nelson@crynwr.com, Crynwr
-	Software, 11 Grant St., Potsdam, NY 13676
-
-  Changelog:
-
-  Mike Cruse        : mcruse@cti-ltd.com
-                    : Changes for Linux 2.0 compatibility.
-                    : Added dev_id parameter in net_interrupt(),
-                    : request_irq() and free_irq(). Just NULL for now.
-
-  Mike Cruse        : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
-                    : in net_open() and net_close() so kerneld would know
-                    : that the module is in use and wouldn't eject the
-                    : driver prematurely.
-
-  Mike Cruse        : Rewrote init_module() and cleanup_module using 8390.c
-                    : as an example. Disabled autoprobing in init_module(),
-                    : not a good thing to do to other devices while Linux
-                    : is running from all accounts.
-
-  Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
-
-  David Huggins-Daines <dhd@debian.org>
-
-  Split this off into mac89x0.c, and gutted it of all parts which are
-  not relevant to the existing CS8900 cards on the Macintosh
-  (i.e. basically the Daynaport CS and LC cards).  To be precise:
-
-    * Removed all the media-detection stuff, because these cards are
-    TP-only.
-
-    * Lobotomized the ISA interrupt bogosity, because these cards use
-    a hardwired NuBus interrupt and a magic ISAIRQ value in the card.
-
-    * Basically eliminated everything not relevant to getting the
-    cards minimally functioning on the Macintosh.
-
-  I might add that these cards are badly designed even from the Mac
-  standpoint, in that Dayna, in their infinite wisdom, used NuBus slot
-  I/O space and NuBus interrupts for these cards, but neglected to
-  provide anything even remotely resembling a NuBus ROM.  Therefore we
-  have to probe for them in a brain-damaged ISA-like fashion.
-
-  Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
-  check kmalloc and release the allocated memory on failure in
-  mac89x0_probe and in init_module
-  use local_irq_{save,restore}(flags) in net_get_stat, not just
-  local_irq_{dis,en}able()
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-static const char version[] =
-"cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
-
-#include <linux/module.h>
-
-/*
-  Sources:
-
-	Crynwr packet driver epktisa.
-
-	Crystal Semiconductor data sheets.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/nubus.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/platform_device.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/hwtest.h>
-#include <asm/macints.h>
-
-#include "cs89x0.h"
-
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "debug message level");
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	int msg_enable;
-	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
-	char chip_revision;	/* revision letter of the chip ('A'...) */
-	int send_cmd;		/* the propercommand used to send a packet. */
-	int rx_mode;
-	int curr_rx_cfg;
-        int send_underrun;      /* keep track of how many underruns in a row we get */
-};
-
-/* Index to functions, as function prototypes. */
-static int net_open(struct net_device *dev);
-static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id);
-static void set_multicast_list(struct net_device *dev);
-static void net_rx(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
-static int set_mac_address(struct net_device *dev, void *addr);
-
-/* For reading/writing registers ISA-style */
-static inline int
-readreg_io(struct net_device *dev, int portno)
-{
-	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
-	return swab16(nubus_readw(dev->base_addr + DATA_PORT));
-}
-
-static inline void
-writereg_io(struct net_device *dev, int portno, int value)
-{
-	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
-	nubus_writew(swab16(value), dev->base_addr + DATA_PORT);
-}
-
-/* These are for reading/writing registers in shared memory */
-static inline int
-readreg(struct net_device *dev, int portno)
-{
-	return swab16(nubus_readw(dev->mem_start + portno));
-}
-
-static inline void
-writereg(struct net_device *dev, int portno, int value)
-{
-	nubus_writew(swab16(value), dev->mem_start + portno);
-}
-
-static const struct net_device_ops mac89x0_netdev_ops = {
-	.ndo_open		= net_open,
-	.ndo_stop		= net_close,
-	.ndo_start_xmit		= net_send_packet,
-	.ndo_get_stats		= net_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address	= set_mac_address,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/* Probe for the CS8900 card in slot E.  We won't bother looking
-   anywhere else until we have a really good reason to do so. */
-static int mac89x0_device_probe(struct platform_device *pdev)
-{
-	struct net_device *dev;
-	struct net_local *lp;
-	int i, slot;
-	unsigned rev_type = 0;
-	unsigned long ioaddr;
-	unsigned short sig;
-	int err = -ENODEV;
-	struct nubus_rsrc *fres;
-
-	dev = alloc_etherdev(sizeof(struct net_local));
-	if (!dev)
-		return -ENOMEM;
-
-	/* We might have to parameterize this later */
-	slot = 0xE;
-	/* Get out now if there's a real NuBus card in slot E */
-	for_each_func_rsrc(fres)
-		if (fres->board->slot == slot)
-			goto out;
-
-	/* The pseudo-ISA bits always live at offset 0x300 (gee,
-           wonder why...) */
-	ioaddr = (unsigned long)
-		nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
-	{
-		int card_present;
-
-		card_present = (hwreg_present((void *)ioaddr + 4) &&
-				hwreg_present((void *)ioaddr + DATA_PORT));
-		if (!card_present)
-			goto out;
-	}
-
-	nubus_writew(0, ioaddr + ADD_PORT);
-	sig = nubus_readw(ioaddr + DATA_PORT);
-	if (sig != swab16(CHIP_EISA_ID_SIG))
-		goto out;
-
-	SET_NETDEV_DEV(dev, &pdev->dev);
-
-	/* Initialize the net_device structure. */
-	lp = netdev_priv(dev);
-
-	lp->msg_enable = netif_msg_init(debug, 0);
-
-	/* Fill in the 'dev' fields. */
-	dev->base_addr = ioaddr;
-	dev->mem_start = (unsigned long)
-		nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
-	dev->mem_end = dev->mem_start + 0x1000;
-
-	/* Turn on shared memory */
-	writereg_io(dev, PP_BusCTL, MEMORY_ON);
-
-	/* get the chip type */
-	rev_type = readreg(dev, PRODUCT_ID_ADD);
-	lp->chip_type = rev_type &~ REVISON_BITS;
-	lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
-
-	/* Check the chip type and revision in order to set the correct send command
-	CS8920 revision C and CS8900 revision F can use the faster send. */
-	lp->send_cmd = TX_AFTER_381;
-	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
-		lp->send_cmd = TX_NOW;
-	if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
-		lp->send_cmd = TX_NOW;
-
-	netif_dbg(lp, drv, dev, "%s", version);
-
-	pr_info("cs89%c0%s rev %c found at %#8lx\n",
-		lp->chip_type == CS8900 ? '0' : '2',
-		lp->chip_type == CS8920M ? "M" : "",
-		lp->chip_revision, dev->base_addr);
-
-	/* Try to read the MAC address */
-	if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
-		pr_info("No EEPROM, giving up now.\n");
-		goto out1;
-        } else {
-		u8 addr[ETH_ALEN];
-
-                for (i = 0; i < ETH_ALEN; i += 2) {
-			/* Big-endian (why??!) */
-			unsigned short s = readreg(dev, PP_IA + i);
-			addr[i] = s >> 8;
-			addr[i+1] = s & 0xff;
-                }
-		eth_hw_addr_set(dev, addr);
-        }
-
-	dev->irq = SLOT2IRQ(slot);
-
-	/* print the IRQ and ethernet address. */
-
-	pr_info("MAC %pM, IRQ %d\n", dev->dev_addr, dev->irq);
-
-	dev->netdev_ops		= &mac89x0_netdev_ops;
-
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-
-	platform_set_drvdata(pdev, dev);
-	return 0;
-out1:
-	nubus_writew(0, dev->base_addr + ADD_PORT);
-out:
-	free_netdev(dev);
-	return err;
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-   */
-static int
-net_open(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int i;
-
-	/* Disable the interrupt for now */
-	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);
-
-	/* Grab the interrupt */
-	if (request_irq(dev->irq, net_interrupt, 0, "cs89x0", dev))
-		return -EAGAIN;
-
-	/* Set up the IRQ - Apparently magic */
-	if (lp->chip_type == CS8900)
-		writereg(dev, PP_CS8900_ISAINT, 0);
-	else
-		writereg(dev, PP_CS8920_ISAINT, 0);
-
-	/* set the Ethernet address */
-	for (i=0; i < ETH_ALEN/2; i++)
-		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
-
-	/* Turn on both receive and transmit operations */
-	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
-
-	/* Receive only error free packets addressed to this card */
-	lp->rx_mode = 0;
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
-
-	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
-
-	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
-
-	writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
-	       TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
-
-	writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
-		 TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
-
-	/* now that we've got our act together, enable everything */
-	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
-	netif_start_queue(dev);
-	return 0;
-}
-
-static netdev_tx_t
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	netif_dbg(lp, tx_queued, dev, "sent %d byte packet of type %x\n",
-		  skb->len, skb->data[ETH_ALEN + ETH_ALEN] << 8 |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]);
-
-	/* keep the upload from being interrupted, since we
-	   ask the chip to start transmitting before the
-	   whole packet has been completely uploaded. */
-	local_irq_save(flags);
-	netif_stop_queue(dev);
-
-	/* initiate a transmit sequence */
-	writereg(dev, PP_TxCMD, lp->send_cmd);
-	writereg(dev, PP_TxLength, skb->len);
-
-	/* Test to see if the chip has allocated memory for the packet */
-	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
-		/* Gasp!  It hasn't.  But that shouldn't happen since
-		   we're waiting for TxOk, so return 1 and requeue this packet. */
-		local_irq_restore(flags);
-		return NETDEV_TX_BUSY;
-	}
-
-	/* Write the contents of the packet */
-	skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame),
-				  skb->len+1);
-
-	local_irq_restore(flags);
-	dev_kfree_skb (skb);
-
-	return NETDEV_TX_OK;
-}
-
-/* The typical workload of the driver:
-   Handle the network interface interrupts. */
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int ioaddr, status;
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-
-	/* we MUST read all the events out of the ISQ, otherwise we'll never
-           get interrupted again.  As a consequence, we can't have any limit
-           on the number of times we loop in the interrupt handler.  The
-           hardware guarantees that eventually we'll run out of events.  Of
-           course, if you're on a slow machine, and packets are arriving
-           faster than you can read them off, you're screwed.  Hasta la
-           vista, baby!  */
-	while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) {
-		netif_dbg(lp, intr, dev, "status=%04x\n", status);
-		switch(status & ISQ_EVENT_MASK) {
-		case ISQ_RECEIVER_EVENT:
-			/* Got a packet(s). */
-			net_rx(dev);
-			break;
-		case ISQ_TRANSMITTER_EVENT:
-			dev->stats.tx_packets++;
-			netif_wake_queue(dev);
-			if ((status & TX_OK) == 0)
-				dev->stats.tx_errors++;
-			if (status & TX_LOST_CRS)
-				dev->stats.tx_carrier_errors++;
-			if (status & TX_SQE_ERROR)
-				dev->stats.tx_heartbeat_errors++;
-			if (status & TX_LATE_COL)
-				dev->stats.tx_window_errors++;
-			if (status & TX_16_COL)
-				dev->stats.tx_aborted_errors++;
-			break;
-		case ISQ_BUFFER_EVENT:
-			if (status & READY_FOR_TX) {
-				/* we tried to transmit a packet earlier,
-                                   but inexplicably ran out of buffers.
-                                   That shouldn't happen since we only ever
-                                   load one packet.  Shrug.  Do the right
-                                   thing anyway. */
-				netif_wake_queue(dev);
-			}
-			if (status & TX_UNDERRUN) {
-				netif_dbg(lp, tx_err, dev, "transmit underrun\n");
-                                lp->send_underrun++;
-                                if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
-                                else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
-                        }
-			break;
-		case ISQ_RX_MISS_EVENT:
-			dev->stats.rx_missed_errors += (status >> 6);
-			break;
-		case ISQ_TX_COL_EVENT:
-			dev->stats.collisions += (status >> 6);
-			break;
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	struct sk_buff *skb;
-	int status, length;
-
-	status = readreg(dev, PP_RxStatus);
-	if ((status & RX_OK) == 0) {
-		dev->stats.rx_errors++;
-		if (status & RX_RUNT)
-				dev->stats.rx_length_errors++;
-		if (status & RX_EXTRA_DATA)
-				dev->stats.rx_length_errors++;
-		if ((status & RX_CRC_ERROR) &&
-		    !(status & (RX_EXTRA_DATA|RX_RUNT)))
-			/* per str 172 */
-			dev->stats.rx_crc_errors++;
-		if (status & RX_DRIBBLE)
-				dev->stats.rx_frame_errors++;
-		return;
-	}
-
-	length = readreg(dev, PP_RxLength);
-	/* Malloc up new buffer. */
-	skb = alloc_skb(length, GFP_ATOMIC);
-	if (skb == NULL) {
-		dev->stats.rx_dropped++;
-		return;
-	}
-	skb_put(skb, length);
-
-	skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame),
-				length);
-
-	netif_dbg(lp, rx_status, dev, "received %d byte packet of type %x\n",
-		  length, skb->data[ETH_ALEN + ETH_ALEN] << 8 |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]);
-
-        skb->protocol=eth_type_trans(skb,dev);
-	netif_rx(skb);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += length;
-}
-
-/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
-{
-
-	writereg(dev, PP_RxCFG, 0);
-	writereg(dev, PP_TxCFG, 0);
-	writereg(dev, PP_BufCFG, 0);
-	writereg(dev, PP_BusCTL, 0);
-
-	netif_stop_queue(dev);
-
-	free_irq(dev->irq, dev);
-
-	/* Update the statistics here. */
-
-	return 0;
-
-}
-
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	/* Update the statistics from the device registers. */
-	dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
-	dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
-	local_irq_restore(flags);
-
-	return &dev->stats;
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	if(dev->flags&IFF_PROMISC)
-	{
-		lp->rx_mode = RX_ALL_ACCEPT;
-	} else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
-		/* The multicast-accept list is initialized to accept-all, and we
-		   rely on higher-level filtering for now. */
-		lp->rx_mode = RX_MULTCAST_ACCEPT;
-	}
-	else
-		lp->rx_mode = 0;
-
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
-
-	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
-	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
-	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
-}
-
-
-static int set_mac_address(struct net_device *dev, void *addr)
-{
-	struct sockaddr *saddr = addr;
-	int i;
-
-	if (!is_valid_ether_addr(saddr->sa_data))
-		return -EADDRNOTAVAIL;
-
-	eth_hw_addr_set(dev, saddr->sa_data);
-	netdev_info(dev, "Setting MAC address to %pM\n", dev->dev_addr);
-
-	/* set the Ethernet address */
-	for (i=0; i < ETH_ALEN/2; i++)
-		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
-
-	return 0;
-}
-
-MODULE_DESCRIPTION("Macintosh CS89x0-based Ethernet driver");
-MODULE_LICENSE("GPL");
-
-static void mac89x0_device_remove(struct platform_device *pdev)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-
-	unregister_netdev(dev);
-	nubus_writew(0, dev->base_addr + ADD_PORT);
-	free_netdev(dev);
-}
-
-static struct platform_driver mac89x0_platform_driver = {
-	.probe = mac89x0_device_probe,
-	.remove = mac89x0_device_remove,
-	.driver = {
-		.name = "mac89x0",
-	},
-};
-
-module_platform_driver(mac89x0_platform_driver);

-- 
2.53.0


^ permalink raw reply related

* [PATCH net 14/18] drivers: net: xircom: xirc2ps: Remove this driver
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

The xirc2ps was written by Werner Koch in 1997. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/Kconfig             |    1 -
 drivers/net/ethernet/xircom/Kconfig      |   30 -
 drivers/net/ethernet/xircom/Makefile     |    6 -
 drivers/net/ethernet/xircom/xirc2ps_cs.c | 1794 ------------------------------
 4 files changed, 1831 deletions(-)

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index c94e8f27af94..5171d9046ea4 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -188,6 +188,5 @@ source "drivers/net/ethernet/via/Kconfig"
 source "drivers/net/ethernet/wangxun/Kconfig"
 source "drivers/net/ethernet/wiznet/Kconfig"
 source "drivers/net/ethernet/xilinx/Kconfig"
-source "drivers/net/ethernet/xircom/Kconfig"
 
 endif # ETHERNET
diff --git a/drivers/net/ethernet/xircom/Kconfig b/drivers/net/ethernet/xircom/Kconfig
deleted file mode 100644
index bfbdcf758afb..000000000000
--- a/drivers/net/ethernet/xircom/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Xircom network device configuration
-#
-
-config NET_VENDOR_XIRCOM
-	bool "Xircom devices"
-	default y
-	depends on PCMCIA
-	help
-	  If you have a network (Ethernet) card belonging to this class, say Y.
-
-	  Note that the answer to this question doesn't directly affect the
-	  kernel: saying N will just cause the configurator to skip all
-	  the questions about Xircom cards. If you say Y, you will be asked for
-	  your specific card in the following questions.
-
-if NET_VENDOR_XIRCOM
-
-config PCMCIA_XIRC2PS
-	tristate "Xircom 16-bit PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	help
-	  Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card)
-	  Ethernet or Fast Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called xirc2ps_cs.  If unsure, say N.
-
-endif # NET_VENDOR_XIRCOM
diff --git a/drivers/net/ethernet/xircom/Makefile b/drivers/net/ethernet/xircom/Makefile
deleted file mode 100644
index 07667fefafc2..000000000000
--- a/drivers/net/ethernet/xircom/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Xircom network device drivers.
-#
-
-obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
deleted file mode 100644
index 97e88886253f..000000000000
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ /dev/null
@@ -1,1794 +0,0 @@
-/* [xirc2ps_cs.c wk 03.11.99] (1.40 1999/11/18 00:06:03)
- * Xircom CreditCard Ethernet Adapter IIps driver
- * Xircom Realport 10/100 (RE-100) driver 
- *
- * This driver supports various Xircom CreditCard Ethernet adapters
- * including the CE2, CE IIps, RE-10, CEM28, CEM33, CE33, CEM56,
- * CE3-100, CE3B, RE-100, REM10BT, and REM56G-100.
- *
- * 2000-09-24 <psheer@icon.co.za> The Xircom CE3B-100 may not
- * autodetect the media properly. In this case use the
- * if_port=1 (for 10BaseT) or if_port=4 (for 100BaseT) options
- * to force the media type.
- * 
- * Written originally by Werner Koch based on David Hinds' skeleton of the
- * PCMCIA driver.
- *
- * Copyright (c) 1997,1998 Werner Koch (dd9jn)
- *
- * This driver is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * It is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * ALTERNATIVELY, this driver may be distributed under the terms of
- * the following license, in which case the provisions of this license
- * are required INSTEAD OF the GNU General Public License.  (This clause
- * is necessary due to a potential bad interaction between the GPL and
- * the restrictions contained in a BSD-style copyright.)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, and the entire permission notice in its entirety,
- *    including the disclaimer of warranties.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/bitops.h>
-#include <linux/mii.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-
-#include <asm/io.h>
-#include <linux/uaccess.h>
-
-#ifndef MANFID_COMPAQ
-  #define MANFID_COMPAQ 	   0x0138
-  #define MANFID_COMPAQ2	   0x0183  /* is this correct? */
-#endif
-
-#include <pcmcia/ds.h>
-
-/* Time in jiffies before concluding Tx hung */
-#define TX_TIMEOUT	((400*HZ)/1000)
-
-/****************
- * Some constants used to access the hardware
- */
-
-/* Register offsets and value constans */
-#define XIRCREG_CR  0	/* Command register (wr) */
-enum xirc_cr {
-    TransmitPacket = 0x01,
-    SoftReset = 0x02,
-    EnableIntr = 0x04,
-    ForceIntr  = 0x08,
-    ClearTxFIFO = 0x10,
-    ClearRxOvrun = 0x20,
-    RestartTx	 = 0x40
-};
-#define XIRCREG_ESR 0	/* Ethernet status register (rd) */
-enum xirc_esr {
-    FullPktRcvd = 0x01, /* full packet in receive buffer */
-    PktRejected = 0x04, /* a packet has been rejected */
-    TxPktPend = 0x08,	/* TX Packet Pending */
-    IncorPolarity = 0x10,
-    MediaSelect = 0x20	/* set if TP, clear if AUI */
-};
-#define XIRCREG_PR  1	/* Page Register select */
-#define XIRCREG_EDP 4	/* Ethernet Data Port Register */
-#define XIRCREG_ISR 6	/* Ethernet Interrupt Status Register */
-enum xirc_isr {
-    TxBufOvr = 0x01,	/* TX Buffer Overflow */
-    PktTxed  = 0x02,	/* Packet Transmitted */
-    MACIntr  = 0x04,	/* MAC Interrupt occurred */
-    TxResGrant = 0x08,	/* Tx Reservation Granted */
-    RxFullPkt = 0x20,	/* Rx Full Packet */
-    RxPktRej  = 0x40,	/* Rx Packet Rejected */
-    ForcedIntr= 0x80	/* Forced Interrupt */
-};
-#define XIRCREG1_IMR0 12 /* Ethernet Interrupt Mask Register (on page 1)*/
-#define XIRCREG1_IMR1 13
-#define XIRCREG0_TSO  8  /* Transmit Space Open Register (on page 0)*/
-#define XIRCREG0_TRS  10 /* Transmit reservation Size Register (page 0)*/
-#define XIRCREG0_DO   12 /* Data Offset Register (page 0) (wr) */
-#define XIRCREG0_RSR  12 /* Receive Status Register (page 0) (rd) */
-enum xirc_rsr {
-    PhyPkt = 0x01,	/* set:physical packet, clear: multicast packet */
-    BrdcstPkt = 0x02,	/* set if it is a broadcast packet */
-    PktTooLong = 0x04,	/* set if packet length > 1518 */
-    AlignErr = 0x10,	/* incorrect CRC and last octet not complete */
-    CRCErr = 0x20,	/* incorrect CRC and last octet is complete */
-    PktRxOk = 0x80	/* received ok */
-};
-#define XIRCREG0_PTR 13 /* packets transmitted register (rd) */
-#define XIRCREG0_RBC 14 /* receive byte count regsister (rd) */
-#define XIRCREG1_ECR 14 /* ethernet configurationn register */
-enum xirc_ecr {
-    FullDuplex = 0x04,	/* enable full duplex mode */
-    LongTPMode = 0x08,	/* adjust for longer lengths of TP cable */
-    DisablePolCor = 0x10,/* disable auto polarity correction */
-    DisableLinkPulse = 0x20, /* disable link pulse generation */
-    DisableAutoTx = 0x40, /* disable auto-transmit */
-};
-#define XIRCREG2_RBS 8	/* receive buffer start register */
-#define XIRCREG2_LED 10 /* LED Configuration register */
-/* values for the leds:    Bits 2-0 for led 1
- *  0 disabled		   Bits 5-3 for led 2
- *  1 collision
- *  2 noncollision
- *  3 link_detected
- *  4 incor_polarity
- *  5 jabber
- *  6 auto_assertion
- *  7 rx_tx_activity
- */
-#define XIRCREG2_MSR 12 /* Mohawk specific register */
-
-#define XIRCREG4_GPR0 8 /* General Purpose Register 0 */
-#define XIRCREG4_GPR1 9 /* General Purpose Register 1 */
-#define XIRCREG2_GPR2 13 /* General Purpose Register 2 (page2!)*/
-#define XIRCREG4_BOV 10 /* Bonding Version Register */
-#define XIRCREG4_LMA 12 /* Local Memory Address Register */
-#define XIRCREG4_LMD 14 /* Local Memory Data Port */
-/* MAC register can only by accessed with 8 bit operations */
-#define XIRCREG40_CMD0 8    /* Command Register (wr) */
-enum xirc_cmd { 	    /* Commands */
-    Transmit = 0x01,
-    EnableRecv = 0x04,
-    DisableRecv = 0x08,
-    Abort = 0x10,
-    Online = 0x20,
-    IntrAck = 0x40,
-    Offline = 0x80
-};
-#define XIRCREG5_RHSA0	10  /* Rx Host Start Address */
-#define XIRCREG40_RXST0 9   /* Receive Status Register */
-#define XIRCREG40_TXST0 11  /* Transmit Status Register 0 */
-#define XIRCREG40_TXST1 12  /* Transmit Status Register 10 */
-#define XIRCREG40_RMASK0 13  /* Receive Mask Register */
-#define XIRCREG40_TMASK0 14  /* Transmit Mask Register 0 */
-#define XIRCREG40_TMASK1 15  /* Transmit Mask Register 0 */
-#define XIRCREG42_SWC0	8   /* Software Configuration 0 */
-#define XIRCREG42_SWC1	9   /* Software Configuration 1 */
-#define XIRCREG42_BOC	10  /* Back-Off Configuration */
-#define XIRCREG44_TDR0	8   /* Time Domain Reflectometry 0 */
-#define XIRCREG44_TDR1	9   /* Time Domain Reflectometry 1 */
-#define XIRCREG44_RXBC_LO 10 /* Rx Byte Count 0 (rd) */
-#define XIRCREG44_RXBC_HI 11 /* Rx Byte Count 1 (rd) */
-#define XIRCREG45_REV	 15 /* Revision Register (rd) */
-#define XIRCREG50_IA	8   /* Individual Address (8-13) */
-
-static const char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" };
-
-/* card types */
-#define XIR_UNKNOWN  0	/* unknown: not supported */
-#define XIR_CE	     1	/* (prodid 1) different hardware: not supported */
-#define XIR_CE2      2	/* (prodid 2) */
-#define XIR_CE3      3	/* (prodid 3) */
-#define XIR_CEM      4	/* (prodid 1) different hardware: not supported */
-#define XIR_CEM2     5	/* (prodid 2) */
-#define XIR_CEM3     6	/* (prodid 3) */
-#define XIR_CEM33    7	/* (prodid 4) */
-#define XIR_CEM56M   8	/* (prodid 5) */
-#define XIR_CEM56    9	/* (prodid 6) */
-#define XIR_CM28    10	/* (prodid 3) modem only: not supported here */
-#define XIR_CM33    11	/* (prodid 4) modem only: not supported here */
-#define XIR_CM56    12	/* (prodid 5) modem only: not supported here */
-#define XIR_CG	    13	/* (prodid 1) GSM modem only: not supported */
-#define XIR_CBE     14	/* (prodid 1) cardbus ethernet: not supported */
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_DESCRIPTION("Xircom PCMCIA ethernet driver");
-MODULE_LICENSE("Dual MPL/GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-INT_MODULE_PARM(if_port,	0);
-INT_MODULE_PARM(full_duplex,	0);
-INT_MODULE_PARM(do_sound, 	1);
-INT_MODULE_PARM(lockup_hack,	0);  /* anti lockup hack */
-
-/*====================================================================*/
-
-/* We do not process more than these number of bytes during one
- * interrupt. (Of course we receive complete packets, so this is not
- * an exact value).
- * Something between 2000..22000; first value gives best interrupt latency,
- * the second enables the usage of the complete on-chip buffer. We use the
- * high value as the initial value.
- */
-static unsigned maxrx_bytes = 22000;
-
-/* MII management prototypes */
-static void mii_idle(unsigned int ioaddr);
-static void mii_putbit(unsigned int ioaddr, unsigned data);
-static int  mii_getbit(unsigned int ioaddr);
-static void mii_wbits(unsigned int ioaddr, unsigned data, int len);
-static unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg);
-static void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg,
-		   unsigned data, int len);
-
-static int has_ce2_string(struct pcmcia_device * link);
-static int xirc2ps_config(struct pcmcia_device * link);
-static void xirc2ps_release(struct pcmcia_device * link);
-static void xirc2ps_detach(struct pcmcia_device *p_dev);
-
-static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id);
-
-struct local_info {
-	struct net_device	*dev;
-	struct pcmcia_device	*p_dev;
-
-    int card_type;
-    int probe_port;
-    int silicon; /* silicon revision. 0=old CE2, 1=Scipper, 4=Mohawk */
-    int mohawk;  /* a CE3 type card */
-    int dingo;	 /* a CEM56 type card */
-    int new_mii; /* has full 10baseT/100baseT MII */
-    int modem;	 /* is a multi function card (i.e with a modem) */
-    void __iomem *dingo_ccr; /* only used for CEM56 cards */
-    unsigned last_ptr_value; /* last packets transmitted value */
-    const char *manf_str;
-    struct work_struct tx_timeout_task;
-};
-
-/****************
- * Some more prototypes
- */
-static netdev_tx_t do_start_xmit(struct sk_buff *skb,
-				       struct net_device *dev);
-static void xirc_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static void xirc2ps_tx_timeout_task(struct work_struct *work);
-static void set_addresses(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static int set_card_type(struct pcmcia_device *link);
-static int do_config(struct net_device *dev, struct ifmap *map);
-static int do_open(struct net_device *dev);
-static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops netdev_ethtool_ops;
-static void hardreset(struct net_device *dev);
-static void do_reset(struct net_device *dev, int full);
-static int init_mii(struct net_device *dev);
-static void do_powerdown(struct net_device *dev);
-static int do_stop(struct net_device *dev);
-
-/*=============== Helper functions =========================*/
-#define SelectPage(pgnr)   outb((pgnr), ioaddr + XIRCREG_PR)
-#define GetByte(reg)	   ((unsigned)inb(ioaddr + (reg)))
-#define GetWord(reg)	   ((unsigned)inw(ioaddr + (reg)))
-#define PutByte(reg,value) outb((value), ioaddr+(reg))
-#define PutWord(reg,value) outw((value), ioaddr+(reg))
-
-/*====== Functions used for debugging =================================*/
-#if 0 /* reading regs may change system status */
-static void
-PrintRegisters(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-
-    if (pc_debug > 1) {
-	int i, page;
-
-	printk(KERN_DEBUG pr_fmt("Register  common: "));
-	for (i = 0; i < 8; i++)
-	    pr_cont(" %2.2x", GetByte(i));
-	pr_cont("\n");
-	for (page = 0; page <= 8; page++) {
-	    printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
-	    SelectPage(page);
-	    for (i = 8; i < 16; i++)
-		pr_cont(" %2.2x", GetByte(i));
-	    pr_cont("\n");
-	}
-	for (page=0x40 ; page <= 0x5f; page++) {
-		if (page == 0x43 || (page >= 0x46 && page <= 0x4f) ||
-		    (page >= 0x51 && page <=0x5e))
-			continue;
-	    printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
-	    SelectPage(page);
-	    for (i = 8; i < 16; i++)
-		pr_cont(" %2.2x", GetByte(i));
-	    pr_cont("\n");
-	}
-    }
-}
-#endif /* 0 */
-
-/*============== MII Management functions ===============*/
-
-/****************
- * Turn around for read
- */
-static void
-mii_idle(unsigned int ioaddr)
-{
-    PutByte(XIRCREG2_GPR2, 0x04|0); /* drive MDCK low */
-    udelay(1);
-    PutByte(XIRCREG2_GPR2, 0x04|1); /* and drive MDCK high */
-    udelay(1);
-}
-
-/****************
- * Write a bit to MDI/O
- */
-static void
-mii_putbit(unsigned int ioaddr, unsigned data)
-{
-  #if 1
-    if (data) {
-	PutByte(XIRCREG2_GPR2, 0x0c|2|0); /* set MDIO */
-	udelay(1);
-	PutByte(XIRCREG2_GPR2, 0x0c|2|1); /* and drive MDCK high */
-	udelay(1);
-    } else {
-	PutByte(XIRCREG2_GPR2, 0x0c|0|0); /* clear MDIO */
-	udelay(1);
-	PutByte(XIRCREG2_GPR2, 0x0c|0|1); /* and drive MDCK high */
-	udelay(1);
-    }
-  #else
-    if (data) {
-	PutWord(XIRCREG2_GPR2-1, 0x0e0e);
-	udelay(1);
-	PutWord(XIRCREG2_GPR2-1, 0x0f0f);
-	udelay(1);
-    } else {
-	PutWord(XIRCREG2_GPR2-1, 0x0c0c);
-	udelay(1);
-	PutWord(XIRCREG2_GPR2-1, 0x0d0d);
-	udelay(1);
-    }
-  #endif
-}
-
-/****************
- * Get a bit from MDI/O
- */
-static int
-mii_getbit(unsigned int ioaddr)
-{
-    unsigned d;
-
-    PutByte(XIRCREG2_GPR2, 4|0); /* drive MDCK low */
-    udelay(1);
-    d = GetByte(XIRCREG2_GPR2); /* read MDIO */
-    PutByte(XIRCREG2_GPR2, 4|1); /* drive MDCK high again */
-    udelay(1);
-    return d & 0x20; /* read MDIO */
-}
-
-static void
-mii_wbits(unsigned int ioaddr, unsigned data, int len)
-{
-    unsigned m = 1 << (len-1);
-    for (; m; m >>= 1)
-	mii_putbit(ioaddr, data & m);
-}
-
-static unsigned
-mii_rd(unsigned int ioaddr,	u_char phyaddr, u_char phyreg)
-{
-    int i;
-    unsigned data=0, m;
-
-    SelectPage(2);
-    for (i=0; i < 32; i++)		/* 32 bit preamble */
-	mii_putbit(ioaddr, 1);
-    mii_wbits(ioaddr, 0x06, 4); 	/* Start and opcode for read */
-    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
-    mii_wbits(ioaddr, phyreg, 5);	/* PHY register to read */
-    mii_idle(ioaddr);			/* turn around */
-    mii_getbit(ioaddr);
-
-    for (m = 1<<15; m; m >>= 1)
-	if (mii_getbit(ioaddr))
-	    data |= m;
-    mii_idle(ioaddr);
-    return data;
-}
-
-static void
-mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data,
-       int len)
-{
-    int i;
-
-    SelectPage(2);
-    for (i=0; i < 32; i++)		/* 32 bit preamble */
-	mii_putbit(ioaddr, 1);
-    mii_wbits(ioaddr, 0x05, 4); 	/* Start and opcode for write */
-    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
-    mii_wbits(ioaddr, phyreg, 5);	/* PHY Register to write */
-    mii_putbit(ioaddr, 1);		/* turn around */
-    mii_putbit(ioaddr, 0);
-    mii_wbits(ioaddr, data, len);	/* And write the data */
-    mii_idle(ioaddr);
-}
-
-/*============= Main bulk of functions	=========================*/
-
-static const struct net_device_ops netdev_ops = {
-	.ndo_open		= do_open,
-	.ndo_stop		= do_stop,
-	.ndo_start_xmit		= do_start_xmit,
-	.ndo_tx_timeout 	= xirc_tx_timeout,
-	.ndo_set_config		= do_config,
-	.ndo_eth_ioctl		= do_ioctl,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int
-xirc2ps_probe(struct pcmcia_device *link)
-{
-    struct net_device *dev;
-    struct local_info *local;
-
-    dev_dbg(&link->dev, "attach()\n");
-
-    /* Allocate the device structure */
-    dev = alloc_etherdev(sizeof(struct local_info));
-    if (!dev)
-	    return -ENOMEM;
-    local = netdev_priv(dev);
-    local->dev = dev;
-    local->p_dev = link;
-    link->priv = dev;
-
-    /* General socket configuration */
-    link->config_index = 1;
-
-    /* Fill in card specific entries */
-    dev->netdev_ops = &netdev_ops;
-    dev->ethtool_ops = &netdev_ethtool_ops;
-    dev->watchdog_timeo = TX_TIMEOUT;
-    INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task);
-
-    return xirc2ps_config(link);
-} /* xirc2ps_attach */
-
-static void
-xirc2ps_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *local = netdev_priv(dev);
-
-    netif_carrier_off(dev);
-    netif_tx_disable(dev);
-    cancel_work_sync(&local->tx_timeout_task);
-
-    dev_dbg(&link->dev, "detach\n");
-
-    unregister_netdev(dev);
-
-    xirc2ps_release(link);
-
-    free_netdev(dev);
-} /* xirc2ps_detach */
-
-/****************
- * Detect the type of the card. s is the buffer with the data of tuple 0x20
- * Returns: 0 := not supported
- *		       mediaid=11 and prodid=47
- * Media-Id bits:
- *  Ethernet	    0x01
- *  Tokenring	    0x02
- *  Arcnet	    0x04
- *  Wireless	    0x08
- *  Modem	    0x10
- *  GSM only	    0x20
- * Prod-Id bits:
- *  Pocket	    0x10
- *  External	    0x20
- *  Creditcard	    0x40
- *  Cardbus	    0x80
- *
- */
-static int
-set_card_type(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *local = netdev_priv(dev);
-    u8 *buf;
-    unsigned int cisrev, mediaid, prodid;
-    size_t len;
-
-    len = pcmcia_get_tuple(link, CISTPL_MANFID, &buf);
-    if (len < 5) {
-	    dev_err(&link->dev, "invalid CIS -- sorry\n");
-	    return 0;
-    }
-
-    cisrev = buf[2];
-    mediaid = buf[3];
-    prodid = buf[4];
-
-    dev_dbg(&link->dev, "cisrev=%02x mediaid=%02x prodid=%02x\n",
-	  cisrev, mediaid, prodid);
-
-    local->mohawk = 0;
-    local->dingo = 0;
-    local->modem = 0;
-    local->card_type = XIR_UNKNOWN;
-    if (!(prodid & 0x40)) {
-	pr_notice("Oops: Not a creditcard\n");
-	return 0;
-    }
-    if (!(mediaid & 0x01)) {
-	pr_notice("Not an Ethernet card\n");
-	return 0;
-    }
-    if (mediaid & 0x10) {
-	local->modem = 1;
-	switch(prodid & 15) {
-	  case 1: local->card_type = XIR_CEM   ; break;
-	  case 2: local->card_type = XIR_CEM2  ; break;
-	  case 3: local->card_type = XIR_CEM3  ; break;
-	  case 4: local->card_type = XIR_CEM33 ; break;
-	  case 5: local->card_type = XIR_CEM56M;
-		  local->mohawk = 1;
-		  break;
-	  case 6:
-	  case 7: /* 7 is the RealPort 10/56 */
-		  local->card_type = XIR_CEM56 ;
-		  local->mohawk = 1;
-		  local->dingo = 1;
-		  break;
-	}
-    } else {
-	switch(prodid & 15) {
-	  case 1: local->card_type = has_ce2_string(link)? XIR_CE2 : XIR_CE ;
-		  break;
-	  case 2: local->card_type = XIR_CE2; break;
-	  case 3: local->card_type = XIR_CE3;
-		  local->mohawk = 1;
-		  break;
-	}
-    }
-    if (local->card_type == XIR_CE || local->card_type == XIR_CEM) {
-	pr_notice("Sorry, this is an old CE card\n");
-	return 0;
-    }
-    if (local->card_type == XIR_UNKNOWN)
-	pr_notice("unknown card (mediaid=%02x prodid=%02x)\n", mediaid, prodid);
-
-    return 1;
-}
-
-/****************
- * There are some CE2 cards out which claim to be a CE card.
- * This function looks for a "CE2" in the 3rd version field.
- * Returns: true if this is a CE2
- */
-static int
-has_ce2_string(struct pcmcia_device * p_dev)
-{
-	if (p_dev->prod_id[2] && strstr(p_dev->prod_id[2], "CE2"))
-		return 1;
-	return 0;
-}
-
-static int
-xirc2ps_config_modem(struct pcmcia_device *p_dev, void *priv_data)
-{
-	unsigned int ioaddr;
-
-	if ((p_dev->resource[0]->start & 0xf) == 8)
-		return -ENODEV;
-
-	p_dev->resource[0]->end = 16;
-	p_dev->resource[1]->end = 8;
-	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-	p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	p_dev->io_lines = 10;
-
-	p_dev->resource[1]->start = p_dev->resource[0]->start;
-	for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
-		p_dev->resource[0]->start = ioaddr;
-		if (!pcmcia_request_io(p_dev))
-			return 0;
-	}
-	return -ENODEV;
-}
-
-static int
-xirc2ps_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-	int *pass = priv_data;
-	resource_size_t tmp = p_dev->resource[1]->start;
-
-	tmp += (*pass ? (p_dev->config_index & 0x20 ? -24 : 8)
-		: (p_dev->config_index & 0x20 ?   8 : -24));
-
-	if ((p_dev->resource[0]->start & 0xf) == 8)
-		return -ENODEV;
-
-	p_dev->resource[0]->end = 18;
-	p_dev->resource[1]->end = 8;
-	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-	p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	p_dev->io_lines = 10;
-
-	p_dev->resource[1]->start = p_dev->resource[0]->start;
-	p_dev->resource[0]->start = tmp;
-	return pcmcia_request_io(p_dev);
-}
-
-
-static int pcmcia_get_mac_ce(struct pcmcia_device *p_dev,
-			     tuple_t *tuple,
-			     void *priv)
-{
-	struct net_device *dev = priv;
-
-	if (tuple->TupleDataLen != 13)
-		return -EINVAL;
-	if ((tuple->TupleData[0] != 2) || (tuple->TupleData[1] != 1) ||
-		(tuple->TupleData[2] != 6))
-		return -EINVAL;
-	/* another try	(James Lehmer's CE2 version 4.1)*/
-	dev_addr_mod(dev, 2, &tuple->TupleData[2], 4);
-	return 0;
-};
-
-
-static int
-xirc2ps_config(struct pcmcia_device * link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr;
-    int err;
-    u8 *buf;
-    size_t len;
-
-    local->dingo_ccr = NULL;
-
-    dev_dbg(&link->dev, "config\n");
-
-    /* Is this a valid	card */
-    if (link->has_manf_id == 0) {
-	pr_notice("manfid not found in CIS\n");
-	goto failure;
-    }
-
-    switch (link->manf_id) {
-      case MANFID_XIRCOM:
-	local->manf_str = "Xircom";
-	break;
-      case MANFID_ACCTON:
-	local->manf_str = "Accton";
-	break;
-      case MANFID_COMPAQ:
-      case MANFID_COMPAQ2:
-	local->manf_str = "Compaq";
-	break;
-      case MANFID_INTEL:
-	local->manf_str = "Intel";
-	break;
-      case MANFID_TOSHIBA:
-	local->manf_str = "Toshiba";
-	break;
-      default:
-	pr_notice("Unknown Card Manufacturer ID: 0x%04x\n",
-		  (unsigned)link->manf_id);
-	goto failure;
-    }
-    dev_dbg(&link->dev, "found %s card\n", local->manf_str);
-
-    if (!set_card_type(link)) {
-	pr_notice("this card is not supported\n");
-	goto failure;
-    }
-
-    /* get the ethernet address from the CIS */
-    err = pcmcia_get_mac_from_cis(link, dev);
-
-    /* not found: try to get the node-id from tuple 0x89 */
-    if (err) {
-	    len = pcmcia_get_tuple(link, 0x89, &buf);
-	    /* data layout looks like tuple 0x22 */
-	    if (buf && len == 8) {
-		    if (*buf == CISTPL_FUNCE_LAN_NODE_ID)
-			    dev_addr_mod(dev, 2, &buf[2], 4);
-		    else
-			    err = -1;
-	    }
-	    kfree(buf);
-    }
-
-    if (err)
-	err = pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev);
-
-    if (err) {
-	pr_notice("node-id not found in CIS\n");
-	goto failure;
-    }
-
-    if (local->modem) {
-	int pass;
-	link->config_flags |= CONF_AUTO_SET_IO;
-
-	if (local->dingo) {
-	    /* Take the Modem IO port from the CIS and scan for a free
-	     * Ethernet port */
-	    if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL))
-		    goto port_found;
-	} else {
-	    /* We do 2 passes here: The first one uses the regular mapping and
-	     * the second tries again, thereby considering that the 32 ports are
-	     * mirrored every 32 bytes. Actually we use a mirrored port for
-	     * the Mako if (on the first pass) the COR bit 5 is set.
-	     */
-	    for (pass=0; pass < 2; pass++)
-		    if (!pcmcia_loop_config(link, xirc2ps_config_check,
-						    &pass))
-			    goto port_found;
-	    /* if special option:
-	     * try to configure as Ethernet only.
-	     * .... */
-	}
-	pr_notice("no ports available\n");
-    } else {
-	link->io_lines = 10;
-	link->resource[0]->end = 16;
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-	for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
-	    link->resource[0]->start = ioaddr;
-	    if (!(err = pcmcia_request_io(link)))
-		goto port_found;
-	}
-	link->resource[0]->start = 0; /* let CS decide */
-	if ((err = pcmcia_request_io(link)))
-	    goto config_error;
-    }
-  port_found:
-
-    /****************
-     * Now allocate an interrupt line.	Note that this does not
-     * actually assign a handler to the interrupt.
-     */
-    if ((err=pcmcia_request_irq(link, xirc2ps_interrupt)))
-	goto config_error;
-
-    link->config_flags |= CONF_ENABLE_IRQ;
-    if (do_sound)
-	    link->config_flags |= CONF_ENABLE_SPKR;
-
-    if ((err = pcmcia_enable_device(link)))
-	goto config_error;
-
-    if (local->dingo) {
-	/* Reset the modem's BAR to the correct value
-	 * This is necessary because in the RequestConfiguration call,
-	 * the base address of the ethernet port (BasePort1) is written
-	 * to the BAR registers of the modem.
-	 */
-	err = pcmcia_write_config_byte(link, CISREG_IOBASE_0, (u8)
-				link->resource[1]->start & 0xff);
-	if (err)
-	    goto config_error;
-
-	err = pcmcia_write_config_byte(link, CISREG_IOBASE_1,
-				(link->resource[1]->start >> 8) & 0xff);
-	if (err)
-	    goto config_error;
-
-	/* There is no config entry for the Ethernet part which
-	 * is at 0x0800. So we allocate a window into the attribute
-	 * memory and write direct to the CIS registers
-	 */
-	link->resource[2]->flags = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM |
-					WIN_ENABLE;
-	link->resource[2]->start = link->resource[2]->end = 0;
-	if ((err = pcmcia_request_window(link, link->resource[2], 0)))
-	    goto config_error;
-
-	local->dingo_ccr = ioremap(link->resource[2]->start, 0x1000) + 0x0800;
-	if ((err = pcmcia_map_mem_page(link, link->resource[2], 0)))
-	    goto config_error;
-
-	/* Setup the CCRs; there are no infos in the CIS about the Ethernet
-	 * part.
-	 */
-	writeb(0x47, local->dingo_ccr + CISREG_COR);
-	ioaddr = link->resource[0]->start;
-	writeb(ioaddr & 0xff	  , local->dingo_ccr + CISREG_IOBASE_0);
-	writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1);
-
-      #if 0
-	{
-	    u_char tmp;
-	    pr_info("ECOR:");
-	    for (i=0; i < 7; i++) {
-		tmp = readb(local->dingo_ccr + i*2);
-		pr_cont(" %02x", tmp);
-	    }
-	    pr_cont("\n");
-	    pr_info("DCOR:");
-	    for (i=0; i < 4; i++) {
-		tmp = readb(local->dingo_ccr + 0x20 + i*2);
-		pr_cont(" %02x", tmp);
-	    }
-	    pr_cont("\n");
-	    pr_info("SCOR:");
-	    for (i=0; i < 10; i++) {
-		tmp = readb(local->dingo_ccr + 0x40 + i*2);
-		pr_cont(" %02x", tmp);
-	    }
-	    pr_cont("\n");
-	}
-      #endif
-
-	writeb(0x01, local->dingo_ccr + 0x20);
-	writeb(0x0c, local->dingo_ccr + 0x22);
-	writeb(0x00, local->dingo_ccr + 0x24);
-	writeb(0x00, local->dingo_ccr + 0x26);
-	writeb(0x00, local->dingo_ccr + 0x28);
-    }
-
-    /* The if_port symbol can be set when the module is loaded */
-    local->probe_port=0;
-    if (!if_port) {
-	local->probe_port = dev->if_port = 1;
-    } else if ((if_port >= 1 && if_port <= 2) ||
-	       (local->mohawk && if_port==4))
-	dev->if_port = if_port;
-    else
-	pr_notice("invalid if_port requested\n");
-
-    /* we can now register the device with the net subsystem */
-    dev->irq = link->irq;
-    dev->base_addr = link->resource[0]->start;
-
-    if (local->dingo)
-	do_reset(dev, 1); /* a kludge to make the cem56 work */
-
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if ((err=register_netdev(dev))) {
-	pr_notice("register_netdev() failed\n");
-	goto config_error;
-    }
-
-    /* give some infos about the hardware */
-    netdev_info(dev, "%s: port %#3lx, irq %d, hwaddr %pM\n",
-		local->manf_str, (u_long)dev->base_addr, (int)dev->irq,
-		dev->dev_addr);
-
-    return 0;
-
-  config_error:
-    xirc2ps_release(link);
-    return -ENODEV;
-
-  failure:
-    return -ENODEV;
-} /* xirc2ps_config */
-
-static void
-xirc2ps_release(struct pcmcia_device *link)
-{
-	dev_dbg(&link->dev, "release\n");
-
-	if (link->resource[2]->end) {
-		struct net_device *dev = link->priv;
-		struct local_info *local = netdev_priv(dev);
-		if (local->dingo)
-			iounmap(local->dingo_ccr - 0x0800);
-	}
-	pcmcia_disable_device(link);
-} /* xirc2ps_release */
-
-/*====================================================================*/
-
-
-static int xirc2ps_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		netif_device_detach(dev);
-		do_powerdown(dev);
-	}
-
-	return 0;
-}
-
-static int xirc2ps_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		do_reset(dev,1);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/*====================================================================*/
-
-/****************
- * This is the Interrupt service route.
- */
-static irqreturn_t
-xirc2ps_interrupt(int irq, void *dev_id)
-{
-    struct net_device *dev = (struct net_device *)dev_id;
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr;
-    u_char saved_page;
-    unsigned bytes_rcvd;
-    unsigned int_status, eth_status, rx_status, tx_status;
-    unsigned rsr, pktlen;
-    ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days
-				  * is this something to worry about?
-				  * -- on a laptop?
-				  */
-
-    if (!netif_device_present(dev))
-	return IRQ_HANDLED;
-
-    ioaddr = dev->base_addr;
-    if (lp->mohawk) { /* must disable the interrupt */
-	PutByte(XIRCREG_CR, 0);
-    }
-
-    pr_debug("%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr);
-
-    saved_page = GetByte(XIRCREG_PR);
-    /* Read the ISR to see whats the cause for the interrupt.
-     * This also clears the interrupt flags on CE2 cards
-     */
-    int_status = GetByte(XIRCREG_ISR);
-    bytes_rcvd = 0;
-  loop_entry:
-    if (int_status == 0xff) { /* card may be ejected */
-	pr_debug("%s: interrupt %d for dead card\n", dev->name, irq);
-	goto leave;
-    }
-    eth_status = GetByte(XIRCREG_ESR);
-
-    SelectPage(0x40);
-    rx_status  = GetByte(XIRCREG40_RXST0);
-    PutByte(XIRCREG40_RXST0, (~rx_status & 0xff));
-    tx_status = GetByte(XIRCREG40_TXST0);
-    tx_status |= GetByte(XIRCREG40_TXST1) << 8;
-    PutByte(XIRCREG40_TXST0, 0);
-    PutByte(XIRCREG40_TXST1, 0);
-
-    pr_debug("%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n",
-	  dev->name, int_status, eth_status, rx_status, tx_status);
-
-    /***** receive section ******/
-    SelectPage(0);
-    while (eth_status & FullPktRcvd) {
-	rsr = GetByte(XIRCREG0_RSR);
-	if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) {
-	    /* too many bytes received during this int, drop the rest of the
-	     * packets */
-	    dev->stats.rx_dropped++;
-	    pr_debug("%s: RX drop, too much done\n", dev->name);
-	} else if (rsr & PktRxOk) {
-	    struct sk_buff *skb;
-
-	    pktlen = GetWord(XIRCREG0_RBC);
-	    bytes_rcvd += pktlen;
-
-	    pr_debug("rsr=%#02x packet_length=%u\n", rsr, pktlen);
-
-	    /* 1 extra so we can use insw */
-	    skb = netdev_alloc_skb(dev, pktlen + 3);
-	    if (!skb) {
-		dev->stats.rx_dropped++;
-	    } else { /* okay get the packet */
-		skb_reserve(skb, 2);
-		if (lp->silicon == 0 ) { /* work around a hardware bug */
-		    unsigned rhsa; /* receive start address */
-
-		    SelectPage(5);
-		    rhsa = GetWord(XIRCREG5_RHSA0);
-		    SelectPage(0);
-		    rhsa += 3; /* skip control infos */
-		    if (rhsa >= 0x8000)
-			rhsa = 0;
-		    if (rhsa + pktlen > 0x8000) {
-			unsigned i;
-			u_char *buf = skb_put(skb, pktlen);
-			for (i=0; i < pktlen ; i++, rhsa++) {
-			    buf[i] = GetByte(XIRCREG_EDP);
-			    if (rhsa == 0x8000) {
-				rhsa = 0;
-				i--;
-			    }
-			}
-		    } else {
-			insw(ioaddr+XIRCREG_EDP,
-				skb_put(skb, pktlen), (pktlen+1)>>1);
-		    }
-		}
-	      #if 0
-		else if (lp->mohawk) {
-		    /* To use this 32 bit access we should use
-		     * a manual optimized loop
-		     * Also the words are swapped, we can get more
-		     * performance by using 32 bit access and swapping
-		     * the words in a register. Will need this for cardbus
-		     *
-		     * Note: don't forget to change the ALLOC_SKB to .. +3
-		     */
-		    unsigned i;
-		    u_long *p = skb_put(skb, pktlen);
-		    register u_long a;
-		    unsigned int edpreg = ioaddr+XIRCREG_EDP-2;
-		    for (i=0; i < len ; i += 4, p++) {
-			a = inl(edpreg);
-			__asm__("rorl $16,%0\n\t"
-				:"=q" (a)
-				: "0" (a));
-			*p = a;
-		    }
-		}
-	      #endif
-		else {
-		    insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen),
-			    (pktlen+1)>>1);
-		}
-		skb->protocol = eth_type_trans(skb, dev);
-		netif_rx(skb);
-		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += pktlen;
-		if (!(rsr & PhyPkt))
-		    dev->stats.multicast++;
-	    }
-	} else { /* bad packet */
-	    pr_debug("rsr=%#02x\n", rsr);
-	}
-	if (rsr & PktTooLong) {
-	    dev->stats.rx_frame_errors++;
-	    pr_debug("%s: Packet too long\n", dev->name);
-	}
-	if (rsr & CRCErr) {
-	    dev->stats.rx_crc_errors++;
-	    pr_debug("%s: CRC error\n", dev->name);
-	}
-	if (rsr & AlignErr) {
-	    dev->stats.rx_fifo_errors++; /* okay ? */
-	    pr_debug("%s: Alignment error\n", dev->name);
-	}
-
-	/* clear the received/dropped/error packet */
-	PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
-
-	/* get the new ethernet status */
-	eth_status = GetByte(XIRCREG_ESR);
-    }
-    if (rx_status & 0x10) { /* Receive overrun */
-	dev->stats.rx_over_errors++;
-	PutByte(XIRCREG_CR, ClearRxOvrun);
-	pr_debug("receive overrun cleared\n");
-    }
-
-    /***** transmit section ******/
-    if (int_status & PktTxed) {
-	unsigned n, nn;
-
-	n = lp->last_ptr_value;
-	nn = GetByte(XIRCREG0_PTR);
-	lp->last_ptr_value = nn;
-	if (nn < n) /* rollover */
-	    dev->stats.tx_packets += 256 - n;
-	else if (n == nn) { /* happens sometimes - don't know why */
-	    pr_debug("PTR not changed?\n");
-	} else
-	    dev->stats.tx_packets += lp->last_ptr_value - n;
-	netif_wake_queue(dev);
-    }
-    if (tx_status & 0x0002) {	/* Excessive collisions */
-	pr_debug("tx restarted due to excessive collisions\n");
-	PutByte(XIRCREG_CR, RestartTx);  /* restart transmitter process */
-    }
-    if (tx_status & 0x0040)
-	dev->stats.tx_aborted_errors++;
-
-    /* recalculate our work chunk so that we limit the duration of this
-     * ISR to about 1/10 of a second.
-     * Calculate only if we received a reasonable amount of bytes.
-     */
-    if (bytes_rcvd > 1000) {
-	u_long duration = jiffies - start_ticks;
-
-	if (duration >= HZ/10) { /* if more than about 1/10 second */
-	    maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration;
-	    if (maxrx_bytes < 2000)
-		maxrx_bytes = 2000;
-	    else if (maxrx_bytes > 22000)
-		maxrx_bytes = 22000;
-	    pr_debug("set maxrx=%u (rcvd=%u ticks=%lu)\n",
-		  maxrx_bytes, bytes_rcvd, duration);
-	} else if (!duration && maxrx_bytes < 22000) {
-	    /* now much faster */
-	    maxrx_bytes += 2000;
-	    if (maxrx_bytes > 22000)
-		maxrx_bytes = 22000;
-	    pr_debug("set maxrx=%u\n", maxrx_bytes);
-	}
-    }
-
-  leave:
-    if (lockup_hack) {
-	if (int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0)
-	    goto loop_entry;
-    }
-    SelectPage(saved_page);
-    PutByte(XIRCREG_CR, EnableIntr);  /* re-enable interrupts */
-    /* Instead of dropping packets during a receive, we could
-     * force an interrupt with this command:
-     *	  PutByte(XIRCREG_CR, EnableIntr|ForceIntr);
-     */
-    return IRQ_HANDLED;
-} /* xirc2ps_interrupt */
-
-/*====================================================================*/
-
-static void
-xirc2ps_tx_timeout_task(struct work_struct *work)
-{
-	struct local_info *local =
-		container_of(work, struct local_info, tx_timeout_task);
-	struct net_device *dev = local->dev;
-    /* reset the card */
-    do_reset(dev,1);
-    netif_trans_update(dev); /* prevent tx timeout */
-    netif_wake_queue(dev);
-}
-
-static void
-xirc_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-    struct local_info *lp = netdev_priv(dev);
-    dev->stats.tx_errors++;
-    netdev_notice(dev, "transmit timed out\n");
-    schedule_work(&lp->tx_timeout_task);
-}
-
-static netdev_tx_t
-do_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    int okay;
-    unsigned freespace;
-    unsigned pktlen = skb->len;
-
-    pr_debug("do_start_xmit(skb=%p, dev=%p) len=%u\n",
-	  skb, dev, pktlen);
-
-
-    /* adjust the packet length to min. required
-     * and hope that the buffer is large enough
-     * to provide some random data.
-     * fixme: For Mohawk we can change this by sending
-     * a larger packetlen than we actually have; the chip will
-     * pad this in his buffer with random bytes
-     */
-    if (pktlen < ETH_ZLEN)
-    {
-        if (skb_padto(skb, ETH_ZLEN))
-		return NETDEV_TX_OK;
-	pktlen = ETH_ZLEN;
-    }
-
-    netif_stop_queue(dev);
-    SelectPage(0);
-    PutWord(XIRCREG0_TRS, (u_short)pktlen+2);
-    freespace = GetWord(XIRCREG0_TSO) & 0x7fff;
-    /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */
-    okay = pktlen +2 < freespace;
-    pr_debug("%s: avail. tx space=%u%s\n",
-	  dev->name, freespace, okay ? " (okay)":" (not enough)");
-    if (!okay) { /* not enough space */
-	return NETDEV_TX_BUSY;  /* upper layer may decide to requeue this packet */
-    }
-    /* send the packet */
-    PutWord(XIRCREG_EDP, (u_short)pktlen);
-    outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1);
-    if (pktlen & 1)
-	PutByte(XIRCREG_EDP, skb->data[pktlen-1]);
-
-    if (lp->mohawk)
-	PutByte(XIRCREG_CR, TransmitPacket|EnableIntr);
-
-    dev_kfree_skb (skb);
-    dev->stats.tx_bytes += pktlen;
-    netif_start_queue(dev);
-    return NETDEV_TX_OK;
-}
-
-struct set_address_info {
-	int reg_nr;
-	int page_nr;
-	int mohawk;
-	unsigned int ioaddr;
-};
-
-static void set_address(struct set_address_info *sa_info, const char *addr)
-{
-	unsigned int ioaddr = sa_info->ioaddr;
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		if (sa_info->reg_nr > 15) {
-			sa_info->reg_nr = 8;
-			sa_info->page_nr++;
-			SelectPage(sa_info->page_nr);
-		}
-		if (sa_info->mohawk)
-			PutByte(sa_info->reg_nr++, addr[5 - i]);
-		else
-			PutByte(sa_info->reg_nr++, addr[i]);
-	}
-}
-
-/****************
- * Set all addresses: This first one is the individual address,
- * the next 9 addresses are taken from the multicast list and
- * the rest is filled with the individual address.
- */
-static void set_addresses(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	struct local_info *lp = netdev_priv(dev);
-	struct netdev_hw_addr *ha;
-	struct set_address_info sa_info;
-	int i;
-
-	/*
-	 * Setup the info structure so that by first set_address call it will do
-	 * SelectPage with the right page number. Hence these ones here.
-	 */
-	sa_info.reg_nr = 15 + 1;
-	sa_info.page_nr = 0x50 - 1;
-	sa_info.mohawk = lp->mohawk;
-	sa_info.ioaddr = ioaddr;
-
-	set_address(&sa_info, dev->dev_addr);
-	i = 0;
-	netdev_for_each_mc_addr(ha, dev) {
-		if (i++ == 9)
-			break;
-		set_address(&sa_info, ha->addr);
-	}
-	while (i++ < 9)
-		set_address(&sa_info, dev->dev_addr);
-	SelectPage(0);
-}
-
-/****************
- * Set or clear the multicast filter for this adaptor.
- * We can filter up to 9 addresses, if more are requested we set
- * multicast promiscuous mode.
- */
-
-static void
-set_multicast_list(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    unsigned value;
-
-    SelectPage(0x42);
-    value = GetByte(XIRCREG42_SWC1) & 0xC0;
-
-    if (dev->flags & IFF_PROMISC) { /* snoop */
-	PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */
-    } else if (netdev_mc_count(dev) > 9 || (dev->flags & IFF_ALLMULTI)) {
-	PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */
-    } else if (!netdev_mc_empty(dev)) {
-	/* the chip can filter 9 addresses perfectly */
-	PutByte(XIRCREG42_SWC1, value | 0x01);
-	SelectPage(0x40);
-	PutByte(XIRCREG40_CMD0, Offline);
-	set_addresses(dev);
-	SelectPage(0x40);
-	PutByte(XIRCREG40_CMD0, EnableRecv | Online);
-    } else { /* standard usage */
-	PutByte(XIRCREG42_SWC1, value | 0x00);
-    }
-    SelectPage(0);
-}
-
-static int
-do_config(struct net_device *dev, struct ifmap *map)
-{
-    struct local_info *local = netdev_priv(dev);
-
-    pr_debug("do_config(%p)\n", dev);
-    if (map->port != 255 && map->port != dev->if_port) {
-	if (map->port > 4)
-	    return -EINVAL;
-	if (!map->port) {
-	    local->probe_port = 1;
-	    WRITE_ONCE(dev->if_port, 1);
-	} else {
-	    local->probe_port = 0;
-	    WRITE_ONCE(dev->if_port, map->port);
-	}
-	netdev_info(dev, "switching to %s port\n", if_names[dev->if_port]);
-	do_reset(dev,1);  /* not the fine way :-) */
-    }
-    return 0;
-}
-
-/****************
- * Open the driver
- */
-static int
-do_open(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-
-    dev_dbg(&link->dev, "do_open(%p)\n", dev);
-
-    /* Check that the PCMCIA card is still here. */
-    /* Physical device present signature. */
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-
-    /* okay */
-    link->open++;
-
-    netif_start_queue(dev);
-    do_reset(dev,1);
-
-    return 0;
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, "xirc2ps_cs", sizeof(info->driver));
-	snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx",
-		 dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-};
-
-static int
-do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    struct mii_ioctl_data *data = if_mii(rq);
-
-    pr_debug("%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n",
-	  dev->name, rq->ifr_ifrn.ifrn_name, cmd,
-	  data->phy_id, data->reg_num, data->val_in, data->val_out);
-
-    if (!local->mohawk)
-	return -EOPNOTSUPP;
-
-    switch(cmd) {
-      case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
-	data->phy_id = 0;	/* we have only this address */
-	fallthrough;
-      case SIOCGMIIREG:		/* Read the specified MII register. */
-	data->val_out = mii_rd(ioaddr, data->phy_id & 0x1f,
-			       data->reg_num & 0x1f);
-	break;
-      case SIOCSMIIREG:		/* Write the specified MII register */
-	mii_wr(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in,
-	       16);
-	break;
-      default:
-	return -EOPNOTSUPP;
-    }
-    return 0;
-}
-
-static void
-hardreset(struct net_device *dev)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-
-    SelectPage(4);
-    udelay(1);
-    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
-    msleep(40);				     /* wait 40 msec */
-    if (local->mohawk)
-	PutByte(XIRCREG4_GPR1, 1);	 /* set bit 0: power up */
-    else
-	PutByte(XIRCREG4_GPR1, 1 | 4);	 /* set bit 0: power up, bit 2: AIC */
-    msleep(20);			     /* wait 20 msec */
-}
-
-static void
-do_reset(struct net_device *dev, int full)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    unsigned value;
-
-    pr_debug("%s: do_reset(%p,%d)\n", dev->name, dev, full);
-
-    hardreset(dev);
-    PutByte(XIRCREG_CR, SoftReset); /* set */
-    msleep(20);			     /* wait 20 msec */
-    PutByte(XIRCREG_CR, 0);	     /* clear */
-    msleep(40);			     /* wait 40 msec */
-    if (local->mohawk) {
-	SelectPage(4);
-	/* set pin GP1 and GP2 to output  (0x0c)
-	 * set GP1 to low to power up the ML6692 (0x00)
-	 * set GP2 to high to power up the 10Mhz chip  (0x02)
-	 */
-	PutByte(XIRCREG4_GPR0, 0x0e);
-    }
-
-    /* give the circuits some time to power up */
-    msleep(500);			/* about 500ms */
-
-    local->last_ptr_value = 0;
-    local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4
-				   : (GetByte(XIRCREG4_BOV) & 0x30) >> 4;
-
-    if (local->probe_port) {
-	if (!local->mohawk) {
-	    SelectPage(4);
-	    PutByte(XIRCREG4_GPR0, 4);
-	    local->probe_port = 0;
-	}
-    } else if (dev->if_port == 2) { /* enable 10Base2 */
-	SelectPage(0x42);
-	PutByte(XIRCREG42_SWC1, 0xC0);
-    } else { /* enable 10BaseT */
-	SelectPage(0x42);
-	PutByte(XIRCREG42_SWC1, 0x80);
-    }
-    msleep(40);			     /* wait 40 msec to let it complete */
-
-  #if 0
-    {
-	SelectPage(0);
-	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
-	pr_debug("%s: ESR is: %#02x\n", dev->name, value);
-    }
-  #endif
-
-    /* setup the ECR */
-    SelectPage(1);
-    PutByte(XIRCREG1_IMR0, 0xff); /* allow all ints */
-    PutByte(XIRCREG1_IMR1, 1	); /* and Set TxUnderrunDetect */
-    value = GetByte(XIRCREG1_ECR);
-  #if 0
-    if (local->mohawk)
-	value |= DisableLinkPulse;
-    PutByte(XIRCREG1_ECR, value);
-  #endif
-    pr_debug("%s: ECR is: %#02x\n", dev->name, value);
-
-    SelectPage(0x42);
-    PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */
-
-    if (local->silicon != 1) {
-	/* set the local memory dividing line.
-	 * The comments in the sample code say that this is only
-	 * settable with the scipper version 2 which is revision 0.
-	 * Always for CE3 cards
-	 */
-	SelectPage(2);
-	PutWord(XIRCREG2_RBS, 0x2000);
-    }
-
-    if (full)
-	set_addresses(dev);
-
-    /* Hardware workaround:
-     * The receive byte pointer after reset is off by 1 so we need
-     * to move the offset pointer back to 0.
-     */
-    SelectPage(0);
-    PutWord(XIRCREG0_DO, 0x2000); /* change offset command, off=0 */
-
-    /* setup MAC IMRs and clear status registers */
-    SelectPage(0x40);		     /* Bit 7 ... bit 0 */
-    PutByte(XIRCREG40_RMASK0, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, MP */
-    PutByte(XIRCREG40_TMASK0, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
-    PutByte(XIRCREG40_TMASK1, 0xb0); /* rsv, rsv, PTD, EXT, rsv,rsv,rsv, rsv*/
-    PutByte(XIRCREG40_RXST0,  0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, MP */
-    PutByte(XIRCREG40_TXST0,  0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
-    PutByte(XIRCREG40_TXST1,  0x00); /* TEN, rsv, PTD, EXT, retry_counter:4  */
-
-    if (full && local->mohawk && init_mii(dev)) {
-	if (dev->if_port == 4 || local->dingo || local->new_mii) {
-	    netdev_info(dev, "MII selected\n");
-	    SelectPage(2);
-	    PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08);
-	    msleep(20);
-	} else {
-	    netdev_info(dev, "MII detected; using 10mbs\n");
-	    SelectPage(0x42);
-	    if (dev->if_port == 2) /* enable 10Base2 */
-		PutByte(XIRCREG42_SWC1, 0xC0);
-	    else  /* enable 10BaseT */
-		PutByte(XIRCREG42_SWC1, 0x80);
-	    msleep(40);			/* wait 40 msec to let it complete */
-	}
-	if (full_duplex)
-	    PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR) | FullDuplex);
-    } else {  /* No MII */
-	SelectPage(0);
-	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
-	dev->if_port = (value & MediaSelect) ? 1 : 2;
-    }
-
-    /* configure the LEDs */
-    SelectPage(2);
-    if (dev->if_port == 1 || dev->if_port == 4) /* TP: Link and Activity */
-	PutByte(XIRCREG2_LED, 0x3b);
-    else			      /* Coax: Not-Collision and Activity */
-	PutByte(XIRCREG2_LED, 0x3a);
-
-    if (local->dingo)
-	PutByte(0x0b, 0x04); /* 100 Mbit LED */
-
-    /* enable receiver and put the mac online */
-    if (full) {
-	set_multicast_list(dev);
-	SelectPage(0x40);
-	PutByte(XIRCREG40_CMD0, EnableRecv | Online);
-    }
-
-    /* setup Ethernet IMR and enable interrupts */
-    SelectPage(1);
-    PutByte(XIRCREG1_IMR0, 0xff);
-    udelay(1);
-    SelectPage(0);
-    PutByte(XIRCREG_CR, EnableIntr);
-    if (local->modem && !local->dingo) { /* do some magic */
-	if (!(GetByte(0x10) & 0x01))
-	    PutByte(0x10, 0x11); /* unmask master-int bit */
-    }
-
-    if (full)
-	netdev_info(dev, "media %s, silicon revision %d\n",
-		    if_names[dev->if_port], local->silicon);
-    /* We should switch back to page 0 to avoid a bug in revision 0
-     * where regs with offset below 8 can't be read after an access
-     * to the MAC registers */
-    SelectPage(0);
-}
-
-/****************
- * Initialize the Media-Independent-Interface
- * Returns: True if we have a good MII
- */
-static int
-init_mii(struct net_device *dev)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    unsigned control, status, linkpartner;
-    int i;
-
-    if (if_port == 4 || if_port == 1) { /* force 100BaseT or 10BaseT */
-	dev->if_port = if_port;
-	local->probe_port = 0;
-	return 1;
-    }
-
-    status = mii_rd(ioaddr,  0, 1);
-    if ((status & 0xff00) != 0x7800)
-	return 0; /* No MII */
-
-    local->new_mii = (mii_rd(ioaddr, 0, 2) != 0xffff);
-    
-    if (local->probe_port)
-	control = 0x1000; /* auto neg */
-    else if (dev->if_port == 4)
-	control = 0x2000; /* no auto neg, 100mbs mode */
-    else
-	control = 0x0000; /* no auto neg, 10mbs mode */
-    mii_wr(ioaddr,  0, 0, control, 16);
-    udelay(100);
-    control = mii_rd(ioaddr, 0, 0);
-
-    if (control & 0x0400) {
-	netdev_notice(dev, "can't take PHY out of isolation mode\n");
-	local->probe_port = 0;
-	return 0;
-    }
-
-    if (local->probe_port) {
-	/* according to the DP83840A specs the auto negotiation process
-	 * may take up to 3.5 sec, so we use this also for our ML6692
-	 * Fixme: Better to use a timer here!
-	 */
-	for (i=0; i < 35; i++) {
-	    msleep(100);	 /* wait 100 msec */
-	    status = mii_rd(ioaddr,  0, 1);
-	    if ((status & 0x0020) && (status & 0x0004))
-		break;
-	}
-
-	if (!(status & 0x0020)) {
-	    netdev_info(dev, "autonegotiation failed; using 10mbs\n");
-	    if (!local->new_mii) {
-		control = 0x0000;
-		mii_wr(ioaddr,  0, 0, control, 16);
-		udelay(100);
-		SelectPage(0);
-		dev->if_port = (GetByte(XIRCREG_ESR) & MediaSelect) ? 1 : 2;
-	    }
-	} else {
-	    linkpartner = mii_rd(ioaddr, 0, 5);
-	    netdev_info(dev, "MII link partner: %04x\n", linkpartner);
-	    if (linkpartner & 0x0080) {
-		dev->if_port = 4;
-	    } else
-		dev->if_port = 1;
-	}
-    }
-
-    return 1;
-}
-
-static void
-do_powerdown(struct net_device *dev)
-{
-
-    unsigned int ioaddr = dev->base_addr;
-
-    pr_debug("do_powerdown(%p)\n", dev);
-
-    SelectPage(4);
-    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
-    SelectPage(0);
-}
-
-static int
-do_stop(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-
-    dev_dbg(&link->dev, "do_stop(%p)\n", dev);
-
-    if (!link)
-	return -ENODEV;
-
-    netif_stop_queue(dev);
-
-    SelectPage(0);
-    PutByte(XIRCREG_CR, 0);  /* disable interrupts */
-    SelectPage(0x01);
-    PutByte(XIRCREG1_IMR0, 0x00); /* forbid all ints */
-    SelectPage(4);
-    PutByte(XIRCREG4_GPR1, 0);	/* clear bit 0: power down */
-    SelectPage(0);
-
-    link->open--;
-    return 0;
-}
-
-static const struct pcmcia_device_id xirc2ps_ids[] = {
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
-	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a),
-	PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b94fe, 0xf381c1a2),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "PS-CE2-10", 0x2e3ee845, 0x947d9073),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "R2E-100BTX", 0x2e3ee845, 0x2464a6e3),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "RE-10", 0x2e3ee845, 0x3e08d609),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "XE2000", 0x2e3ee845, 0xf7188e46),
-	PCMCIA_DEVICE_PROD_ID12("Compaq", "Ethernet LAN Card", 0x54f7c49c, 0x9fd2f0a2),
-	PCMCIA_DEVICE_PROD_ID12("Compaq", "Netelligent 10/100 PC Card", 0x54f7c49c, 0xefe96769),
-	PCMCIA_DEVICE_PROD_ID12("Intel", "EtherExpress(TM) PRO/100 PC Card Mobile Adapter16", 0x816cc815, 0x174397db),
-	PCMCIA_DEVICE_PROD_ID12("Toshiba", "10/100 Ethernet PC Card", 0x44a09d9c, 0xb44deecf),
-	/* also matches CFE-10 cards! */
-	/* PCMCIA_DEVICE_MANF_CARD(0x0105, 0x010a), */
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids);
-
-
-static struct pcmcia_driver xirc2ps_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "xirc2ps_cs",
-	.probe		= xirc2ps_probe,
-	.remove		= xirc2ps_detach,
-	.id_table       = xirc2ps_ids,
-	.suspend	= xirc2ps_suspend,
-	.resume		= xirc2ps_resume,
-};
-module_pcmcia_driver(xirc2ps_cs_driver);
-
-#ifndef MODULE
-static int __init setup_xirc2ps_cs(char *str)
-{
-	/* if_port, full_duplex, do_sound, lockup_hack
-	 */
-	int ints[10] = { -1 };
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-#define MAYBE_SET(X,Y) if (ints[0] >= Y && ints[Y] != -1) { X = ints[Y]; }
-	MAYBE_SET(if_port, 3);
-	MAYBE_SET(full_duplex, 4);
-	MAYBE_SET(do_sound, 5);
-	MAYBE_SET(lockup_hack, 6);
-#undef  MAYBE_SET
-
-	return 1;
-}
-
-__setup("xirc2ps_cs=", setup_xirc2ps_cs);
-#endif

-- 
2.53.0


^ permalink raw reply related

* [PATCH net 15/18] drivers: net: 8390: AX88190: Remove this driver
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

The ax88190 was written by David A. Hindsh in 2001. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/8390/Kconfig    |   12 -
 drivers/net/ethernet/8390/Makefile   |    1 -
 drivers/net/ethernet/8390/axnet_cs.c | 1707 ----------------------------------
 3 files changed, 1720 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 345f250781c6..3dea042cc2eb 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -17,18 +17,6 @@ config NET_VENDOR_8390
 
 if NET_VENDOR_8390
 
-config PCMCIA_AXNET
-	tristate "Asix AX88190 PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	help
-	  Say Y here if you intend to attach an Asix AX88190-based PCMCIA
-	  (PC-card) Fast Ethernet card to your computer.  These cards are
-	  nearly NE2000 compatible but need a separate driver due to a few
-	  misfeatures.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called axnet_cs.  If unsure, say N.
-
 config AX88796
 	tristate "ASIX AX88796 NE2000 clone support" if !ZORRO
 	depends on (ARM || MIPS || SUPERH || ZORRO || COMPILE_TEST)
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index 85c83c566ec6..60220484b382 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_MCF8390) += mcf8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
deleted file mode 100644
index 7c8213011b5c..000000000000
--- a/drivers/net/ethernet/8390/axnet_cs.c
+++ /dev/null
@@ -1,1707 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-
-/*======================================================================
-
-    A PCMCIA ethernet driver for Asix AX88190-based cards
-
-    The Asix AX88190 is a NS8390-derived chipset with a few nasty
-    idiosyncracies that make it very inconvenient to support with a
-    standard 8390 driver.  This driver is based on pcnet_cs, with the
-    tweaked 8390 code grafted on the end.  Much of what I did was to
-    clean up and update a similar driver supplied by Asix, which was
-    adapted by William Lee, william@asix.com.tw.
-
-    Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
-
-    axnet_cs.c 1.28 2002/06/29 06:27:37
-
-    The network driver code is based on Donald Becker's NE2000 code:
-
-    Written 1992,1993 by Donald Becker.
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.
-    Donald Becker may be reached at becker@scyld.com
-
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include "8390.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#define AXNET_CMD	0x00
-#define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
-#define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
-#define AXNET_MII_EEP	0x14	/* Offset of MII access port */
-#define AXNET_TEST	0x15	/* Offset of TEST Register port */
-#define AXNET_GPIO	0x17	/* Offset of General Purpose Register Port */
-
-#define AXNET_START_PG	0x40	/* First page of TX buffer */
-#define AXNET_STOP_PG	0x80	/* Last page +1 of RX ring */
-
-#define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
-
-#define IS_AX88190	0x0001
-#define IS_AX88790	0x0002
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-static int axnet_config(struct pcmcia_device *link);
-static void axnet_release(struct pcmcia_device *link);
-static int axnet_open(struct net_device *dev);
-static int axnet_close(struct net_device *dev);
-static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
-					  struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
-static void ei_watchdog(struct timer_list *t);
-static void axnet_reset_8390(struct net_device *dev);
-
-static int mdio_read(unsigned int addr, int phy_id, int loc);
-static void mdio_write(unsigned int addr, int phy_id, int loc, int value);
-
-static void get_8390_hdr(struct net_device *,
-			 struct e8390_pkt_hdr *, int);
-static void block_input(struct net_device *dev, int count,
-			struct sk_buff *skb, int ring_offset);
-static void block_output(struct net_device *dev, int count,
-			 const u_char *buf, const int start_page);
-
-static void axnet_detach(struct pcmcia_device *p_dev);
-
-static void AX88190_init(struct net_device *dev, int startp);
-static int ax_open(struct net_device *dev);
-static int ax_close(struct net_device *dev);
-static irqreturn_t ax_interrupt(int irq, void *dev_id);
-
-/*====================================================================*/
-
-struct axnet_dev {
-	struct pcmcia_device	*p_dev;
-	caddr_t	base;
-	struct timer_list	watchdog;
-	int	stale, fast_poll;
-	u_short	link_status;
-	u_char	duplex_flag;
-	int	phy_id;
-	int	flags;
-	int	active_low;
-};
-
-static inline struct axnet_dev *PRIV(struct net_device *dev)
-{
-	void *p = (char *)netdev_priv(dev) + sizeof(struct ei_device);
-	return p;
-}
-
-static const struct net_device_ops axnet_netdev_ops = {
-	.ndo_open 		= axnet_open,
-	.ndo_stop		= axnet_close,
-	.ndo_eth_ioctl		= axnet_ioctl,
-	.ndo_start_xmit		= axnet_start_xmit,
-	.ndo_tx_timeout		= axnet_tx_timeout,
-	.ndo_get_stats		= get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int axnet_probe(struct pcmcia_device *link)
-{
-    struct axnet_dev *info;
-    struct net_device *dev;
-    struct ei_device *ei_local;
-
-    dev_dbg(&link->dev, "axnet_attach()\n");
-
-    dev = alloc_etherdev(sizeof(struct ei_device) + sizeof(struct axnet_dev));
-    if (!dev)
-	return -ENOMEM;
-
-    ei_local = netdev_priv(dev);
-    spin_lock_init(&ei_local->page_lock);
-
-    info = PRIV(dev);
-    info->p_dev = link;
-    link->priv = dev;
-    link->config_flags |= CONF_ENABLE_IRQ;
-
-    dev->netdev_ops = &axnet_netdev_ops;
-
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    return axnet_config(link);
-} /* axnet_attach */
-
-static void axnet_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    dev_dbg(&link->dev, "axnet_detach(0x%p)\n", link);
-
-    unregister_netdev(dev);
-
-    axnet_release(link);
-
-    free_netdev(dev);
-} /* axnet_detach */
-
-/*======================================================================
-
-    This probes for a card's hardware address by reading the PROM.
-
-======================================================================*/
-
-static int get_prom(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    u8 addr[ETH_ALEN];
-    int i, j;
-
-    /* This is based on drivers/net/ethernet/8390/ne.c */
-    struct {
-	u_char value, offset;
-    } program_seq[] = {
-	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
-	{0x01,	EN0_DCFG},	/* Set word-wide access. */
-	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_IMR},	/* Mask completion irq. */
-	{0xFF,	EN0_ISR},
-	{E8390_RXOFF|0x40, EN0_RXCR},	/* 0x60  Set to monitor */
-	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
-	{0x10,	EN0_RCNTLO},
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0400. */
-	{0x04,	EN0_RSARHI},
-	{E8390_RREAD+E8390_START, E8390_CMD},
-    };
-
-    /* Not much of a test, but the alternatives are messy */
-    if (link->config_base != 0x03c0)
-	return 0;
-
-    axnet_reset_8390(dev);
-    mdelay(10);
-
-    for (i = 0; i < ARRAY_SIZE(program_seq); i++)
-	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
-
-    for (i = 0; i < 6; i += 2) {
-	j = inw(ioaddr + AXNET_DATAPORT);
-	addr[i] = j & 0xff;
-	addr[i+1] = j >> 8;
-    }
-    eth_hw_addr_set(dev, addr);
-
-    return 1;
-} /* get_prom */
-
-static int try_io_port(struct pcmcia_device *link)
-{
-    int j, ret;
-    link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-    link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-    if (link->resource[0]->end == 32) {
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-	/* for master/slave multifunction cards */
-	if (link->resource[1]->end > 0)
-	    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    } else {
-	/* This should be two 16-port windows */
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
-    }
-    if (link->resource[0]->start == 0) {
-	for (j = 0; j < 0x400; j += 0x20) {
-	    link->resource[0]->start = j ^ 0x300;
-	    link->resource[1]->start = (j ^ 0x300) + 0x10;
-	    link->io_lines = 16;
-	    ret = pcmcia_request_io(link);
-	    if (ret == 0)
-		    return ret;
-	}
-	return ret;
-    } else {
-	return pcmcia_request_io(link);
-    }
-}
-
-static int axnet_configcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
-	if (p_dev->config_index == 0)
-		return -EINVAL;
-
-	p_dev->config_index = 0x05;
-	if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
-		return -ENODEV;
-
-	return try_io_port(p_dev);
-}
-
-static int axnet_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct axnet_dev *info = PRIV(dev);
-    int i, j, j2, ret;
-
-    dev_dbg(&link->dev, "axnet_config(0x%p)\n", link);
-
-    /* don't trust the CIS on this; Linksys got it wrong */
-    link->config_regs = 0x63;
-    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-    ret = pcmcia_loop_config(link, axnet_configcheck, NULL);
-    if (ret != 0)
-	goto failed;
-
-    if (!link->irq)
-	    goto failed;
-
-    if (resource_size(link->resource[1]) == 8)
-	link->config_flags |= CONF_ENABLE_SPKR;
-    
-    ret = pcmcia_enable_device(link);
-    if (ret)
-	    goto failed;
-
-    dev->irq = link->irq;
-    dev->base_addr = link->resource[0]->start;
-
-    if (!get_prom(link)) {
-	pr_notice("this is not an AX88190 card!\n");
-	pr_notice("use pcnet_cs instead.\n");
-	goto failed;
-    }
-
-    ei_status.name = "AX88190";
-    ei_status.word16 = 1;
-    ei_status.tx_start_page = AXNET_START_PG;
-    ei_status.rx_start_page = AXNET_START_PG + TX_PAGES;
-    ei_status.stop_page = AXNET_STOP_PG;
-    ei_status.reset_8390 = axnet_reset_8390;
-    ei_status.get_8390_hdr = get_8390_hdr;
-    ei_status.block_input = block_input;
-    ei_status.block_output = block_output;
-
-    if (inb(dev->base_addr + AXNET_TEST) != 0)
-	info->flags |= IS_AX88790;
-    else
-	info->flags |= IS_AX88190;
-
-    if (info->flags & IS_AX88790)
-	outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
-
-    info->active_low = 0;
-
-    for (i = 0; i < 32; i++) {
-	j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
-	j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
-	if (j == j2) continue;
-	if ((j != 0) && (j != 0xffff)) break;
-    }
-
-    if (i == 32) {
-	/* Maybe PHY is in power down mode. (PPD_SET = 1)
-	   Bit 2 of CCSR is active low. */
-	pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
-	for (i = 0; i < 32; i++) {
-	    j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
-	    j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
-	    if (j == j2) continue;
-	    if ((j != 0) && (j != 0xffff)) {
-		info->active_low = 1;
-		break;
-	    }
-	}
-    }
-
-    info->phy_id = (i < 32) ? i : -1;
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-	pr_notice("register_netdev() failed\n");
-	goto failed;
-    }
-
-    netdev_info(dev, "Asix AX88%d90: io %#3lx, irq %d, hw_addr %pM\n",
-		((info->flags & IS_AX88790) ? 7 : 1),
-		dev->base_addr, dev->irq, dev->dev_addr);
-    if (info->phy_id != -1) {
-	netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
-		   info->phy_id, j);
-    } else {
-	netdev_notice(dev, "  No MII transceivers found!\n");
-    }
-    return 0;
-
-failed:
-    axnet_release(link);
-    return -ENODEV;
-} /* axnet_config */
-
-static void axnet_release(struct pcmcia_device *link)
-{
-	pcmcia_disable_device(link);
-}
-
-static int axnet_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int axnet_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-	struct axnet_dev *info = PRIV(dev);
-
-	if (link->open) {
-		if (info->active_low == 1)
-			pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
-
-		axnet_reset_8390(dev);
-		AX88190_init(dev, 1);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/*======================================================================
-
-    MII interface support
-
-======================================================================*/
-
-#define MDIO_SHIFT_CLK		0x01
-#define MDIO_DATA_WRITE0	0x00
-#define MDIO_DATA_WRITE1	0x08
-#define MDIO_DATA_READ		0x04
-#define MDIO_MASK		0x0f
-#define MDIO_ENB_IN		0x02
-
-static void mdio_sync(unsigned int addr)
-{
-    int bits;
-    for (bits = 0; bits < 32; bits++) {
-	outb_p(MDIO_DATA_WRITE1, addr);
-	outb_p(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-static int mdio_read(unsigned int addr, int phy_id, int loc)
-{
-    u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
-    int i, retval = 0;
-
-    mdio_sync(addr);
-    for (i = 14; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb_p(dat, addr);
-	outb_p(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 19; i > 0; i--) {
-	outb_p(MDIO_ENB_IN, addr);
-	retval = (retval << 1) | ((inb_p(addr) & MDIO_DATA_READ) != 0);
-	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
-    }
-    return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
-{
-    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
-    int i;
-
-    mdio_sync(addr);
-    for (i = 31; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb_p(dat, addr);
-	outb_p(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 1; i >= 0; i--) {
-	outb_p(MDIO_ENB_IN, addr);
-	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-/*====================================================================*/
-
-static int axnet_open(struct net_device *dev)
-{
-    int ret;
-    struct axnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-    unsigned int nic_base = dev->base_addr;
-    
-    dev_dbg(&link->dev, "axnet_open('%s')\n", dev->name);
-
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-
-    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
-    ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
-    if (ret)
-	    return ret;
-
-    link->open++;
-
-    info->link_status = 0x00;
-    timer_setup(&info->watchdog, ei_watchdog, 0);
-    mod_timer(&info->watchdog, jiffies + HZ);
-
-    return ax_open(dev);
-} /* axnet_open */
-
-/*====================================================================*/
-
-static int axnet_close(struct net_device *dev)
-{
-    struct axnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-
-    dev_dbg(&link->dev, "axnet_close('%s')\n", dev->name);
-
-    ax_close(dev);
-    free_irq(dev->irq, dev);
-    
-    link->open--;
-    netif_stop_queue(dev);
-    timer_delete_sync(&info->watchdog);
-
-    return 0;
-} /* axnet_close */
-
-/*======================================================================
-
-    Hard reset the card.  This used to pause for the same period that
-    a 8390 reset command required, but that shouldn't be necessary.
-
-======================================================================*/
-
-static void axnet_reset_8390(struct net_device *dev)
-{
-    unsigned int nic_base = dev->base_addr;
-    int i;
-
-    ei_status.txing = ei_status.dmaing = 0;
-
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
-
-    outb(inb(nic_base + AXNET_RESET), nic_base + AXNET_RESET);
-
-    for (i = 0; i < 100; i++) {
-	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
-	    break;
-	udelay(100);
-    }
-    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
-    
-    if (i == 100)
-	netdev_err(dev, "axnet_reset_8390() did not complete\n");
-    
-} /* axnet_reset_8390 */
-
-/*====================================================================*/
-
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    PRIV(dev)->stale = 0;
-    return ax_interrupt(irq, dev_id);
-}
-
-static void ei_watchdog(struct timer_list *t)
-{
-    struct axnet_dev *info = timer_container_of(info, t, watchdog);
-    struct net_device *dev = info->p_dev->priv;
-    unsigned int nic_base = dev->base_addr;
-    unsigned int mii_addr = nic_base + AXNET_MII_EEP;
-    u_short link;
-
-    if (!netif_device_present(dev)) goto reschedule;
-
-    /* Check for pending interrupt with expired latency timer: with
-       this, we can limp along even if the interrupt is blocked */
-    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
-	if (!info->fast_poll)
-	    netdev_info(dev, "interrupt(s) dropped!\n");
-	ei_irq_wrapper(dev->irq, dev);
-	info->fast_poll = HZ;
-    }
-    if (info->fast_poll) {
-	info->fast_poll--;
-	info->watchdog.expires = jiffies + 1;
-	add_timer(&info->watchdog);
-	return;
-    }
-
-    if (info->phy_id < 0)
-	goto reschedule;
-    link = mdio_read(mii_addr, info->phy_id, 1);
-    if (!link || (link == 0xffff)) {
-	netdev_info(dev, "MII is missing!\n");
-	info->phy_id = -1;
-	goto reschedule;
-    }
-
-    link &= 0x0004;
-    if (link != info->link_status) {
-	u_short p = mdio_read(mii_addr, info->phy_id, 5);
-	netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
-	if (link) {
-	    info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00;
-	    if (p)
-		netdev_info(dev, "autonegotiation complete: %dbaseT-%cD selected\n",
-			    (p & 0x0180) ? 100 : 10, (p & 0x0140) ? 'F' : 'H');
-	    else
-		netdev_info(dev, "link partner did not autonegotiate\n");
-	    AX88190_init(dev, 1);
-	}
-	info->link_status = link;
-    }
-
-reschedule:
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
-}
-
-/*====================================================================*/
-
-static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    struct axnet_dev *info = PRIV(dev);
-    struct mii_ioctl_data *data = if_mii(rq);
-    unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP;
-    switch (cmd) {
-    case SIOCGMIIPHY:
-	data->phy_id = info->phy_id;
-	fallthrough;
-    case SIOCGMIIREG:		/* Read MII PHY register. */
-	data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
-	return 0;
-    case SIOCSMIIREG:		/* Write MII PHY register. */
-	mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in);
-	return 0;
-    }
-    return -EOPNOTSUPP;
-}
-
-/*====================================================================*/
-
-static void get_8390_hdr(struct net_device *dev,
-			 struct e8390_pkt_hdr *hdr,
-			 int ring_page)
-{
-    unsigned int nic_base = dev->base_addr;
-
-    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
-    outb_p(ring_page, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
-
-    insw(nic_base + AXNET_DATAPORT, hdr,
-	    sizeof(struct e8390_pkt_hdr)>>1);
-    /* Fix for big endian systems */
-    hdr->count = le16_to_cpu(hdr->count);
-
-}
-
-/*====================================================================*/
-
-static void block_input(struct net_device *dev, int count,
-			struct sk_buff *skb, int ring_offset)
-{
-    unsigned int nic_base = dev->base_addr;
-    struct ei_device *ei_local = netdev_priv(dev);
-    char *buf = skb->data;
-
-    if ((netif_msg_rx_status(ei_local)) && (count != 4))
-	netdev_dbg(dev, "[bi=%d]\n", count+4);
-    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
-    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
-
-    insw(nic_base + AXNET_DATAPORT,buf,count>>1);
-    if (count & 0x01) {
-	buf[count-1] = inb(nic_base + AXNET_DATAPORT);
-    }
-}
-
-/*====================================================================*/
-
-static void block_output(struct net_device *dev, int count,
-			 const u_char *buf, const int start_page)
-{
-    unsigned int nic_base = dev->base_addr;
-
-    pr_debug("%s: [bo=%d]\n", dev->name, count);
-
-    /* Round the count up for word writes.  Do we need to do this?
-       What effect will an odd byte count have on the 8390?
-       I should check someday. */
-    if (count & 0x01)
-	count++;
-
-    outb_p(0x00, nic_base + EN0_RSARLO);
-    outb_p(start_page, nic_base + EN0_RSARHI);
-    outb_p(E8390_RWRITE+E8390_START, nic_base + AXNET_CMD);
-    outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
-}
-
-static const struct pcmcia_device_id axnet_ids[] = {
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
-	PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
-	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
-	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
-	PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
-	PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), 
-	PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
-	PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
-	PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
-	PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
-	PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
-	PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXM", 0x5261440f, 0x3abbd061),
-	PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
-	PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
-	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
-	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
-	PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6,  0xab9be5ef),
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
-
-static struct pcmcia_driver axnet_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "axnet_cs",
-	.probe		= axnet_probe,
-	.remove		= axnet_detach,
-	.id_table       = axnet_ids,
-	.suspend	= axnet_suspend,
-	.resume		= axnet_resume,
-};
-module_pcmcia_driver(axnet_cs_driver);
-
-/*====================================================================*/
-
-/* 8390.c: A general NS8390 ethernet driver core for linux. */
-/*
-	Written 1992-94 by Donald Becker.
-  
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-  This is the chip-specific code for many 8390-based ethernet adaptors.
-  This is not a complete driver, it must be combined with board-specific
-  code such as ne.c, wd.c, 3c503.c, etc.
-
-  Seeing how at least eight drivers use this code, (not counting the
-  PCMCIA ones either) it is easy to break some card by what seems like
-  a simple innocent change. Please contact me or Donald if you think
-  you have found something that needs changing. -- PG
-
-  Changelog:
-
-  Paul Gortmaker	: remove set_bit lock, other cleanups.
-  Paul Gortmaker	: add ei_get_8390_hdr() so we can pass skb's to 
-			  ei_block_input() for eth_io_copy_and_sum().
-  Paul Gortmaker	: exchange static int ei_pingpong for a #define,
-			  also add better Tx error handling.
-  Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.
-  Alexey Kuznetsov	: use the 8390's six bit hash multicast filter.
-  Paul Gortmaker	: tweak ANK's above multicast changes a bit.
-  Paul Gortmaker	: update packet statistics for v2.1.x
-  Alan Cox		: support arbitrary stupid port mappings on the
-			  68K Macintosh. Support >16bit I/O spaces
-  Paul Gortmaker	: add kmod support for auto-loading of the 8390
-			  module by all drivers that require it.
-  Alan Cox		: Spinlocking work, added 'BUG_83C690'
-  Paul Gortmaker	: Separate out Tx timeout code from Tx path.
-
-  Sources:
-  The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
-
-  */
-
-#include <linux/bitops.h>
-#include <asm/irq.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/interrupt.h>
-
-#define BUG_83C690
-
-/* These are the operational function interfaces to board-specific
-   routines.
-	void reset_8390(struct net_device *dev)
-		Resets the board associated with DEV, including a hardware reset of
-		the 8390.  This is only called when there is a transmit timeout, and
-		it is always followed by 8390_init().
-	void block_output(struct net_device *dev, int count, const unsigned char *buf,
-					  int start_page)
-		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
-		"page" value uses the 8390's 256-byte pages.
-	void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
-		Read the 4 byte, page aligned 8390 header. *If* there is a
-		subsequent read, it will be of the rest of the packet.
-	void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-		Read COUNT bytes from the packet buffer into the skb data area. Start 
-		reading from RING_OFFSET, the address as the 8390 sees it.  This will always
-		follow the read of the 8390 header. 
-*/
-#define ei_reset_8390 (ei_local->reset_8390)
-#define ei_block_output (ei_local->block_output)
-#define ei_block_input (ei_local->block_input)
-#define ei_get_8390_hdr (ei_local->get_8390_hdr)
-
-/* Index to functions. */
-static void ei_tx_intr(struct net_device *dev);
-static void ei_tx_err(struct net_device *dev);
-static void ei_receive(struct net_device *dev);
-static void ei_rx_overrun(struct net_device *dev);
-
-/* Routines generic to NS8390-based boards. */
-static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
-								int start_page);
-static void do_set_multicast_list(struct net_device *dev);
-
-/*
- *	SMP and the 8390 setup.
- *
- *	The 8390 isn't exactly designed to be multithreaded on RX/TX. There is
- *	a page register that controls bank and packet buffer access. We guard
- *	this with ei_local->page_lock. Nobody should assume or set the page other
- *	than zero when the lock is not held. Lock holders must restore page 0
- *	before unlocking. Even pure readers must take the lock to protect in 
- *	page 0.
- *
- *	To make life difficult the chip can also be very slow. We therefore can't
- *	just use spinlocks. For the longer lockups we disable the irq the device
- *	sits on and hold the lock. We must hold the lock because there is a dual
- *	processor case other than interrupts (get stats/set multicast list in
- *	parallel with each other and transmit).
- *
- *	Note: in theory we can just disable the irq on the card _but_ there is
- *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
- *	enter lock, take the queued irq. So we waddle instead of flying.
- *
- *	Finally by special arrangement for the purpose of being generally 
- *	annoying the transmit function is called bh atomic. That places
- *	restrictions on the user context callers as disable_irq won't save
- *	them.
- */
- 
-/**
- * ax_open - Open/initialize the board.
- * @dev: network device to initialize
- *
- * This routine goes all-out, setting everything
- * up anew at each open, even though many of these registers should only
- * need to be set once at boot.
- */
-static int ax_open(struct net_device *dev)
-{
-	unsigned long flags;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	/*
-	 *	Grab the page lock so we own the register set, then call
-	 *	the init function.
-	 */
-      
-      	spin_lock_irqsave(&ei_local->page_lock, flags);
-	AX88190_init(dev, 1);
-	/* Set the flag before we drop the lock, That way the IRQ arrives
-	   after its set and we get no silly warnings */
-	netif_start_queue(dev);
-      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	ei_local->irqlock = 0;
-	return 0;
-}
-
-#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock)
-
-/**
- * ax_close - shut down network device
- * @dev: network device to close
- *
- * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
- */
-static int ax_close(struct net_device *dev)
-{
-	unsigned long flags;
-
-	/*
-	 *      Hold the page lock during close
-	 */
-
-	spin_lock_irqsave(&dev_lock(dev), flags);
-	AX88190_init(dev, 0);
-	spin_unlock_irqrestore(&dev_lock(dev), flags);
-	netif_stop_queue(dev);
-	return 0;
-}
-
-/**
- * axnet_tx_timeout - handle transmit time out condition
- * @dev: network device which has apparently fallen asleep
- * @txqueue: unused
- *
- * Called by kernel when device never acknowledges a transmit has
- * completed (or failed) - i.e. never posted a Tx related interrupt.
- */
-
-static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int txsr, isr, tickssofar = jiffies - dev_trans_start(dev);
-	unsigned long flags;
-
-	dev->stats.tx_errors++;
-
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-	txsr = inb(e8390_base+EN0_TSR);
-	isr = inb(e8390_base+EN0_ISR);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-
-	netdev_dbg(dev, "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
-		   (txsr & ENTSR_ABT) ? "excess collisions." :
-		   (isr) ? "lost interrupt?" : "cable problem?",
-		   txsr, isr, tickssofar);
-
-	if (!isr && !dev->stats.tx_packets) 
-	{
-		/* The 8390 probably hasn't gotten on the cable yet. */
-		ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
-	}
-
-	/* Ugly but a reset can be slow, yet must be protected */
-		
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-		
-	/* Try to restart the card.  Perhaps the user has fixed something. */
-	ei_reset_8390(dev);
-	AX88190_init(dev, 1);
-		
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	netif_wake_queue(dev);
-}
-    
-/**
- * axnet_start_xmit - begin packet transmission
- * @skb: packet to be sent
- * @dev: network device to which packet is sent
- *
- * Sends a packet to an 8390 network device.
- */
- 
-static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
-					  struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int length, send_length, output_page;
-	unsigned long flags;
-	u8 packet[ETH_ZLEN];
-	
-	netif_stop_queue(dev);
-
-	length = skb->len;
-
-	/* Mask interrupts from the ethercard. 
-	   SMP: We have to grab the lock here otherwise the IRQ handler
-	   on another CPU can flip window and race the IRQ mask set. We end
-	   up trashing the mcast filter not disabling irqs if we don't lock */
-	   
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-	outb_p(0x00, e8390_base + EN0_IMR);
-	
-	/*
-	 *	Slow phase with lock held.
-	 */
-	 
-	ei_local->irqlock = 1;
-
-	send_length = max(length, ETH_ZLEN);
-
-	/*
-	 * We have two Tx slots available for use. Find the first free
-	 * slot, and then perform some sanity checks. With two Tx bufs,
-	 * you get very close to transmitting back-to-back packets. With
-	 * only one Tx buf, the transmitter sits idle while you reload the
-	 * card, leaving a substantial gap between each transmitted packet.
-	 */
-
-	if (ei_local->tx1 == 0) 
-	{
-		output_page = ei_local->tx_start_page;
-		ei_local->tx1 = send_length;
-		if ((netif_msg_tx_queued(ei_local)) &&
-		    ei_local->tx2 > 0)
-			netdev_dbg(dev,
-				   "idle transmitter tx2=%d, lasttx=%d, txing=%d\n",
-				   ei_local->tx2, ei_local->lasttx,
-				   ei_local->txing);
-	}
-	else if (ei_local->tx2 == 0) 
-	{
-		output_page = ei_local->tx_start_page + TX_PAGES/2;
-		ei_local->tx2 = send_length;
-		if ((netif_msg_tx_queued(ei_local)) &&
-		    ei_local->tx1 > 0)
-			netdev_dbg(dev,
-				   "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n",
-				   ei_local->tx1, ei_local->lasttx,
-				   ei_local->txing);
-	}
-	else
-	{	/* We should never get here. */
-		netif_dbg(ei_local, tx_err, dev,
-			  "No Tx buffers free! tx1=%d tx2=%d last=%d\n",
-			  ei_local->tx1, ei_local->tx2,
-			  ei_local->lasttx);
-		ei_local->irqlock = 0;
-		netif_stop_queue(dev);
-		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-		spin_unlock_irqrestore(&ei_local->page_lock, flags);
-		dev->stats.tx_errors++;
-		return NETDEV_TX_BUSY;
-	}
-
-	/*
-	 * Okay, now upload the packet and trigger a send if the transmitter
-	 * isn't already sending. If it is busy, the interrupt handler will
-	 * trigger the send later, upon receiving a Tx done interrupt.
-	 */
-
-	if (length == skb->len)
-		ei_block_output(dev, length, skb->data, output_page);
-	else {
-		memset(packet, 0, ETH_ZLEN);
-		skb_copy_from_linear_data(skb, packet, skb->len);
-		ei_block_output(dev, length, packet, output_page);
-	}
-	
-	if (! ei_local->txing) 
-	{
-		ei_local->txing = 1;
-		NS8390_trigger_send(dev, send_length, output_page);
-		netif_trans_update(dev);
-		if (output_page == ei_local->tx_start_page) 
-		{
-			ei_local->tx1 = -1;
-			ei_local->lasttx = -1;
-		}
-		else 
-		{
-			ei_local->tx2 = -1;
-			ei_local->lasttx = -2;
-		}
-	}
-	else ei_local->txqueue++;
-
-	if (ei_local->tx1  &&  ei_local->tx2)
-		netif_stop_queue(dev);
-	else
-		netif_start_queue(dev);
-
-	/* Turn 8390 interrupts back on. */
-	ei_local->irqlock = 0;
-	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-	
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-
-	dev_kfree_skb (skb);
-	dev->stats.tx_bytes += send_length;
-    
-	return NETDEV_TX_OK;
-}
-
-/**
- * ax_interrupt - handle the interrupts from an 8390
- * @irq: interrupt number
- * @dev_id: a pointer to the net_device
- *
- * Handle the ether interface interrupts. We pull packets from
- * the 8390 via the card specific functions and fire them at the networking
- * stack. We also handle transmit completions and wake the transmit path if
- * necessary. We also update the counters and do other housekeeping as
- * needed.
- */
-
-static irqreturn_t ax_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	long e8390_base;
-	int interrupts, nr_serviced = 0, i;
-	struct ei_device *ei_local;
-	int handled = 0;
-	unsigned long flags;
-
-	e8390_base = dev->base_addr;
-	ei_local = netdev_priv(dev);
-
-	/*
-	 *	Protect the irq test too.
-	 */
-	 
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-
-	if (ei_local->irqlock) {
-#if 1 /* This might just be an interrupt for a PCI device sharing this line */
-		const char *msg;
-		/* The "irqlock" check is only for testing. */
-		if (ei_local->irqlock)
-			msg = "Interrupted while interrupts are masked!";
-		else
-			msg = "Reentering the interrupt handler!";
-		netdev_info(dev, "%s, isr=%#2x imr=%#2x\n",
-			    msg,
-			    inb_p(e8390_base + EN0_ISR),
-			    inb_p(e8390_base + EN0_IMR));
-#endif
-		spin_unlock_irqrestore(&ei_local->page_lock, flags);
-		return IRQ_NONE;
-	}
-
-	netif_dbg(ei_local, intr, dev, "interrupt(isr=%#2.2x)\n",
-		  inb_p(e8390_base + EN0_ISR));
-
-	outb_p(0x00, e8390_base + EN0_ISR);
-	ei_local->irqlock = 1;
-   
-	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */
-	while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 &&
-	       ++nr_serviced < MAX_SERVICE)
-	{
-		if (!netif_running(dev) || (interrupts == 0xff)) {
-			netif_warn(ei_local, intr, dev,
-				   "interrupt from stopped card\n");
-			outb_p(interrupts, e8390_base + EN0_ISR);
-			interrupts = 0;
-			break;
-		}
-		handled = 1;
-
-		/* AX88190 bug fix. */
-		outb_p(interrupts, e8390_base + EN0_ISR);
-		for (i = 0; i < 10; i++) {
-			if (!(inb(e8390_base + EN0_ISR) & interrupts))
-				break;
-			outb_p(0, e8390_base + EN0_ISR);
-			outb_p(interrupts, e8390_base + EN0_ISR);
-		}
-		if (interrupts & ENISR_OVER) 
-			ei_rx_overrun(dev);
-		else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) 
-		{
-			/* Got a good (?) packet. */
-			ei_receive(dev);
-		}
-		/* Push the next to-transmit packet through. */
-		if (interrupts & ENISR_TX)
-			ei_tx_intr(dev);
-		else if (interrupts & ENISR_TX_ERR)
-			ei_tx_err(dev);
-
-		if (interrupts & ENISR_COUNTERS) 
-		{
-			dev->stats.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
-			dev->stats.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
-			dev->stats.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
-		}
-	}
-    
-	if (interrupts && (netif_msg_intr(ei_local)))
-	{
-		handled = 1;
-		if (nr_serviced >= MAX_SERVICE) 
-		{
-			/* 0xFF is valid for a card removal */
-			if (interrupts != 0xFF)
-				netdev_warn(dev,
-					    "Too much work at interrupt, status %#2.2x\n",
-					    interrupts);
-			outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
-		} else {
-			netdev_warn(dev, "unknown interrupt %#2x\n",
-				    interrupts);
-			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
-		}
-	}
-
-	/* Turn 8390 interrupts back on. */
-	ei_local->irqlock = 0;
-	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	return IRQ_RETVAL(handled);
-}
-
-/**
- * ei_tx_err - handle transmitter error
- * @dev: network device which threw the exception
- *
- * A transmitter error has happened. Most likely excess collisions (which
- * is a fairly normal condition). If the error is one where the Tx will
- * have been aborted, we try and send another one right away, instead of
- * letting the failed packet sit and collect dust in the Tx buffer. This
- * is a much better solution as it avoids kernel based Tx timeouts, and
- * an unnecessary card reset.
- *
- * Called with lock held.
- */
-
-static void ei_tx_err(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	unsigned char txsr = inb_p(e8390_base+EN0_TSR);
-	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
-
-#ifdef VERBOSE_ERROR_DUMP
-	netdev_dbg(dev, "transmitter error (%#2x):", txsr);
-	if (txsr & ENTSR_ABT)
-		pr_cont(" excess-collisions");
-	if (txsr & ENTSR_ND)
-		pr_cont(" non-deferral");
-	if (txsr & ENTSR_CRS)
-		pr_cont(" lost-carrier");
-	if (txsr & ENTSR_FU)
-		pr_cont(" FIFO-underrun");
-	if (txsr & ENTSR_CDH)
-		pr_cont(" lost-heartbeat");
-	pr_cont("\n");
-#endif
-
-	if (tx_was_aborted)
-		ei_tx_intr(dev);
-	else 
-	{
-		dev->stats.tx_errors++;
-		if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++;
-		if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++;
-		if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++;
-	}
-}
-
-/**
- * ei_tx_intr - transmit interrupt handler
- * @dev: network device for which tx intr is handled
- *
- * We have finished a transmit: check for errors and then trigger the next
- * packet to be sent. Called with lock held.
- */
-
-static void ei_tx_intr(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int status = inb(e8390_base + EN0_TSR);
-    
-	/*
-	 * There are two Tx buffers, see which one finished, and trigger
-	 * the send of another one if it exists.
-	 */
-	ei_local->txqueue--;
-
-	if (ei_local->tx1 < 0) 
-	{
-		if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
-			netdev_err(dev, "%s: bogus last_tx_buffer %d, tx1=%d\n",
-				   ei_local->name, ei_local->lasttx,
-				   ei_local->tx1);
-		ei_local->tx1 = 0;
-		if (ei_local->tx2 > 0) 
-		{
-			ei_local->txing = 1;
-			NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
-			netif_trans_update(dev);
-			ei_local->tx2 = -1;
-			ei_local->lasttx = 2;
-		} else {
-			ei_local->lasttx = 20;
-			ei_local->txing = 0;
-		}
-	}
-	else if (ei_local->tx2 < 0) 
-	{
-		if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
-			netdev_err(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n",
-				   ei_local->name, ei_local->lasttx,
-				   ei_local->tx2);
-		ei_local->tx2 = 0;
-		if (ei_local->tx1 > 0) 
-		{
-			ei_local->txing = 1;
-			NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
-			netif_trans_update(dev);
-			ei_local->tx1 = -1;
-			ei_local->lasttx = 1;
-		} else {
-			ei_local->lasttx = 10;
-			ei_local->txing = 0;
-		}
-	}
-//	else
-//		netdev_warn(dev, "unexpected TX-done interrupt, lasttx=%d\n",
-//			    ei_local->lasttx);
-
-	/* Minimize Tx latency: update the statistics after we restart TXing. */
-	if (status & ENTSR_COL)
-		dev->stats.collisions++;
-	if (status & ENTSR_PTX)
-		dev->stats.tx_packets++;
-	else 
-	{
-		dev->stats.tx_errors++;
-		if (status & ENTSR_ABT) 
-		{
-			dev->stats.tx_aborted_errors++;
-			dev->stats.collisions += 16;
-		}
-		if (status & ENTSR_CRS) 
-			dev->stats.tx_carrier_errors++;
-		if (status & ENTSR_FU) 
-			dev->stats.tx_fifo_errors++;
-		if (status & ENTSR_CDH)
-			dev->stats.tx_heartbeat_errors++;
-		if (status & ENTSR_OWC)
-			dev->stats.tx_window_errors++;
-	}
-	netif_wake_queue(dev);
-}
-
-/**
- * ei_receive - receive some packets
- * @dev: network device with which receive will be run
- *
- * We have a good packet(s), get it/them out of the buffers. 
- * Called with lock held.
- */
-
-static void ei_receive(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	unsigned char rxing_page, this_frame, next_frame;
-	unsigned short current_offset;
-	int rx_pkt_count = 0;
-	struct e8390_pkt_hdr rx_frame;
-    
-	while (++rx_pkt_count < 10) 
-	{
-		int pkt_len, pkt_stat;
-		
-		/* Get the rx page (incoming packet pointer). */
-		rxing_page = inb_p(e8390_base + EN1_CURPAG -1);
-		
-		/* Remove one frame from the ring.  Boundary is always a page behind. */
-		this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
-		if (this_frame >= ei_local->stop_page)
-			this_frame = ei_local->rx_start_page;
-		
-		/* Someday we'll omit the previous, iff we never get this message.
-		   (There is at least one clone claimed to have a problem.)  
-		   
-		   Keep quiet if it looks like a card removal. One problem here
-		   is that some clones crash in roughly the same way.
-		 */
-		if ((netif_msg_rx_err(ei_local)) &&
-		    this_frame != ei_local->current_page &&
-		    (this_frame != 0x0 || rxing_page != 0xFF))
-			netdev_err(dev, "mismatched read page pointers %2x vs %2x\n",
-				   this_frame, ei_local->current_page);
-		
-		if (this_frame == rxing_page)	/* Read all the frames? */
-			break;				/* Done for now */
-		
-		current_offset = this_frame << 8;
-		ei_get_8390_hdr(dev, &rx_frame, this_frame);
-		
-		pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
-		pkt_stat = rx_frame.status;
-		
-		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
-		
-		if (pkt_len < 60  ||  pkt_len > 1518) 
-		{
-			netif_err(ei_local, rx_err, dev,
-				  "bogus packet size: %d, status=%#2x nxpg=%#2x\n",
-				  rx_frame.count, rx_frame.status,
-				  rx_frame.next);
-			dev->stats.rx_errors++;
-			dev->stats.rx_length_errors++;
-		}
-		 else if ((pkt_stat & 0x0F) == ENRSR_RXOK) 
-		{
-			struct sk_buff *skb;
-			
-			skb = netdev_alloc_skb(dev, pkt_len + 2);
-			if (skb == NULL) 
-			{
-				netif_err(ei_local, rx_err, dev,
-					  "Couldn't allocate a sk_buff of size %d\n",
-					  pkt_len);
-				dev->stats.rx_dropped++;
-				break;
-			}
-			else
-			{
-				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
-				skb_put(skb, pkt_len);	/* Make room */
-				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
-				skb->protocol=eth_type_trans(skb,dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += pkt_len;
-				if (pkt_stat & ENRSR_PHY)
-					dev->stats.multicast++;
-			}
-		} 
-		else 
-		{
-			netif_err(ei_local, rx_err, dev,
-				  "bogus packet: status=%#2x nxpg=%#2x size=%d\n",
-				  rx_frame.status, rx_frame.next,
-				  rx_frame.count);
-			dev->stats.rx_errors++;
-			/* NB: The NIC counts CRC, frame and missed errors. */
-			if (pkt_stat & ENRSR_FO)
-				dev->stats.rx_fifo_errors++;
-		}
-		next_frame = rx_frame.next;
-		
-		/* This _should_ never happen: it's here for avoiding bad clones. */
-		if (next_frame >= ei_local->stop_page) {
-			netdev_info(dev, "next frame inconsistency, %#2x\n",
-				    next_frame);
-			next_frame = ei_local->rx_start_page;
-		}
-		ei_local->current_page = next_frame;
-		outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
-	}
-}
-
-/**
- * ei_rx_overrun - handle receiver overrun
- * @dev: network device which threw exception
- *
- * We have a receiver overrun: we have to kick the 8390 to get it started
- * again. Problem is that you have to kick it exactly as NS prescribes in
- * the updated datasheets, or "the NIC may act in an unpredictable manner."
- * This includes causing "the NIC to defer indefinitely when it is stopped
- * on a busy network."  Ugh.
- * Called with lock held. Don't call this with the interrupts off or your
- * computer will hate you - it takes 10ms or so. 
- */
-
-static void ei_rx_overrun(struct net_device *dev)
-{
-	struct axnet_dev *info = PRIV(dev);
-	long e8390_base = dev->base_addr;
-	unsigned char was_txing, must_resend = 0;
-	struct ei_device *ei_local = netdev_priv(dev);
-    
-	/*
-	 * Record whether a Tx was in progress and then issue the
-	 * stop command.
-	 */
-	was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-
-	netif_dbg(ei_local, rx_err, dev, "Receiver overrun\n");
-	dev->stats.rx_over_errors++;
-    
-	/* 
-	 * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
-	 * We wait at least 2ms.
-	 */
-
-	mdelay(2);
-
-	/*
-	 * Reset RBCR[01] back to zero as per magic incantation.
-	 */
-	outb_p(0x00, e8390_base+EN0_RCNTLO);
-	outb_p(0x00, e8390_base+EN0_RCNTHI);
-
-	/*
-	 * See if any Tx was interrupted or not. According to NS, this
-	 * step is vital, and skipping it will cause no end of havoc.
-	 */
-
-	if (was_txing)
-	{ 
-		unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
-		if (!tx_completed)
-			must_resend = 1;
-	}
-
-	/*
-	 * Have to enter loopback mode and then restart the NIC before
-	 * you are allowed to slurp packets up off the ring.
-	 */
-	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
-	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
-
-	/*
-	 * Clear the Rx ring of all the debris, and ack the interrupt.
-	 */
-	ei_receive(dev);
-
-	/*
-	 * Leave loopback mode, and resend any packet that got stopped.
-	 */
-	outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); 
-	if (must_resend)
-    		outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
-}
-
-/*
- *	Collect the stats. This is called unlocked and from several contexts.
- */
- 
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	unsigned long flags;
-    
-	/* If the card is stopped, just return the present stats. */
-	if (!netif_running(dev))
-		return &dev->stats;
-
-	spin_lock_irqsave(&ei_local->page_lock,flags);
-	/* Read the counter registers, assuming we are in page 0. */
-	dev->stats.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
-	dev->stats.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
-	dev->stats.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-    
-	return &dev->stats;
-}
-
-/*
- * Form the 64 bit 8390 multicast table from the linked list of addresses
- * associated with this dev structure.
- */
- 
-static inline void make_mc_bits(u8 *bits, struct net_device *dev)
-{
-	struct netdev_hw_addr *ha;
-	u32 crc;
-
-	netdev_for_each_mc_addr(ha, dev) {
-		crc = ether_crc(ETH_ALEN, ha->addr);
-		/* 
-		 * The 8390 uses the 6 most significant bits of the
-		 * CRC to index the multicast table.
-		 */
-		bits[crc>>29] |= (1<<((crc>>26)&7));
-	}
-}
-
-/**
- * do_set_multicast_list - set/clear multicast filter
- * @dev: net device for which multicast filter is adjusted
- *
- *	Set or clear the multicast filter for this adaptor.
- *	Must be called with lock held. 
- */
- 
-static void do_set_multicast_list(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	int i;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
-		memset(ei_local->mcfilter, 0, 8);
-		if (!netdev_mc_empty(dev))
-			make_mc_bits(ei_local->mcfilter, dev);
-	} else {
-		/* set to accept-all */
-		memset(ei_local->mcfilter, 0xFF, 8);
-	}
-
-	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
-	for(i = 0; i < 8; i++) 
-	{
-		outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
-	}
-	outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
-
-	if(dev->flags&IFF_PROMISC)
-		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
-	else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev))
-		outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
-	else
-		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
-
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
-}
-
-/*
- *	Called without lock held. This is invoked from user context and may
- *	be parallel to just about everything else. Its also fairly quick and
- *	not called too often. Must protect against both bh and irq users
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_lock(dev), flags);
-	do_set_multicast_list(dev);
-	spin_unlock_irqrestore(&dev_lock(dev), flags);
-}	
-
-/* This page of functions should be 8390 generic */
-/* Follow National Semi's recommendations for initializing the "NIC". */
-
-/**
- * AX88190_init - initialize 8390 hardware
- * @dev: network device to initialize
- * @startp: boolean.  non-zero value to initiate chip processing
- *
- *	Must be called with lock held.
- */
-
-static void AX88190_init(struct net_device *dev, int startp)
-{
-	struct axnet_dev *info = PRIV(dev);
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int i;
-	int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
-    
-	if(sizeof(struct e8390_pkt_hdr)!=4)
-    		panic("8390.c: header struct mispacked\n");    
-	/* Follow National Semi's recommendations for initing the DP83902. */
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
-	outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */
-	/* Clear the remote byte count registers. */
-	outb_p(0x00,  e8390_base + EN0_RCNTLO);
-	outb_p(0x00,  e8390_base + EN0_RCNTHI);
-	/* Set to monitor and loopback mode -- this is vital!. */
-	outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */
-	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
-	/* Set the transmit page and receive ring. */
-	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
-	ei_local->tx1 = ei_local->tx2 = 0;
-	outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
-	outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY);	/* 3c503 says 0x3f,NS0x26*/
-	ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */
-	outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
-	/* Clear the pending interrupts and mask. */
-	outb_p(0xFF, e8390_base + EN0_ISR);
-	outb_p(0x00,  e8390_base + EN0_IMR);
-    
-	/* Copy the station address into the DS8390 registers. */
-
-	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
-	for(i = 0; i < 6; i++) 
-	{
-		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
-		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
-			netdev_err(dev, "Hw. address read/write mismap %d\n", i);
-	}
-
-	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-
-	netif_start_queue(dev);
-	ei_local->tx1 = ei_local->tx2 = 0;
-	ei_local->txing = 0;
-
-	if (info->flags & IS_AX88790)	/* select Internal PHY */
-		outb(0x10, e8390_base + AXNET_GPIO);
-
-	if (startp) 
-	{
-		outb_p(0xff,  e8390_base + EN0_ISR);
-		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
-		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
-		outb_p(E8390_TXCONFIG | info->duplex_flag,
-		       e8390_base + EN0_TXCR); /* xmit on. */
-		/* 3c503 TechMan says rxconfig only after the NIC is started. */
-		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */
-		do_set_multicast_list(dev);	/* (re)load the mcast table */
-	}
-}
-
-/* Trigger a transmit start, assuming the length is valid. 
-   Always called with the page lock held */
-   
-static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
-								int start_page)
-{
-	long e8390_base = dev->base_addr;
- 	struct ei_device *ei_local __attribute((unused)) = netdev_priv(dev);
-    
-	if (inb_p(e8390_base) & E8390_TRANS) 
-	{
-		netdev_warn(dev, "trigger_send() called with the transmitter busy\n");
-		return;
-	}
-	outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
-	outb_p(length >> 8, e8390_base + EN0_TCNTHI);
-	outb_p(start_page, e8390_base + EN0_TPSR);
-	outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
-}

-- 
2.53.0


^ permalink raw reply related

* [PATCH net 17/18] drivers: net: 8390: ultra: Remove this driver
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

The ultra was written by Donald Becker 1993 to 1998. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/8390/Kconfig     |  18 -
 drivers/net/ethernet/8390/Makefile    |   1 -
 drivers/net/ethernet/8390/smc-ultra.c | 630 ----------------------------------
 3 files changed, 649 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 3e56806471a3..dd066b0a39d5 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -144,24 +144,6 @@ config STNIC
 
 	  If unsure, say N.
 
-config ULTRA
-	tristate "SMC Ultra support"
-	depends on ISA
-	select NETDEV_LEGACY_INIT
-	select CRC32
-	help
-	  If you have a network (Ethernet) card of this type, say Y here.
-
-	  Important: There have been many reports that, with some motherboards
-	  mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
-	  such as some BusLogic models) causes corruption problems with many
-	  operating systems. The Linux smc-ultra driver has a work-around for
-	  this but keep it in mind if you have such a SCSI card and have
-	  problems.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called smc-ultra.
-
 config WD80x3
 	tristate "WD80*3 support"
 	depends on ISA
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index b215136a603b..0afdccddda58 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_MCF8390) += mcf8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
-obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_XSURF100) += xsurf100.o
 obj-$(CONFIG_ZORRO8390) += zorro8390.o
diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c
deleted file mode 100644
index 22ca804b2e95..000000000000
--- a/drivers/net/ethernet/8390/smc-ultra.c
+++ /dev/null
@@ -1,630 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-/* smc-ultra.c: A SMC Ultra ethernet driver for linux. */
-/*
-	This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards.
-
-	Written 1993-1998 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	This driver uses the cards in the 8390-compatible mode.
-	Most of the run-time complexity is handled by the generic code in
-	8390.c.  The code in this file is responsible for
-
-		ultra_probe()	 	Detecting and initializing the card.
-		ultra_probe1()
-		ultra_probe_isapnp()
-
-		ultra_open()		The card-specific details of starting, stopping
-		ultra_reset_8390()	and resetting the 8390 NIC core.
-		ultra_close()
-
-		ultra_block_input()		Routines for reading and writing blocks of
-		ultra_block_output()	packet buffer memory.
-		ultra_pio_input()
-		ultra_pio_output()
-
-	This driver enables the shared memory only when doing the actual data
-	transfers to avoid a bug in early version of the card that corrupted
-	data transferred by a AHA1542.
-
-	This driver now supports the programmed-I/O (PIO) data transfer mode of
-	the EtherEZ. It does not use the non-8390-compatible "Altego" mode.
-	That support (if available) is in smc-ez.c.
-
-	Changelog:
-
-	Paul Gortmaker	: multiple card support for module users.
-	Donald Becker	: 4/17/96 PIO support, minor potential problems avoided.
-	Donald Becker	: 6/6/96 correctly set auto-wrap bit.
-	Alexander Sotirov : 1/20/01 Added support for ISAPnP cards
-
-	Note about the ISA PnP support:
-
-	This driver can not autoprobe for more than one SMC EtherEZ PnP card.
-	You have to configure the second card manually through the /proc/isapnp
-	interface and then load the module with an explicit io=0x___ option.
-*/
-
-static const char version[] =
-	"smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/isapnp.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <net/Space.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "8390.h"
-
-#define DRV_NAME "smc-ultra"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int ultra_portlist[] __initdata =
-{0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0};
-
-static int ultra_probe1(struct net_device *dev, int ioaddr);
-
-#ifdef __ISAPNP__
-static int ultra_probe_isapnp(struct net_device *dev);
-#endif
-
-static int ultra_open(struct net_device *dev);
-static void ultra_reset_8390(struct net_device *dev);
-static void ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void ultra_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void ultra_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, const int start_page);
-static void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void ultra_pio_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void ultra_pio_output(struct net_device *dev, int count,
-							 const unsigned char *buf, const int start_page);
-static int ultra_close_card(struct net_device *dev);
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id ultra_device_ids[] __initdata = {
-        {       ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416),
-                ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416),
-                (long) "SMC EtherEZ (8416)" },
-        { }	/* terminate list */
-};
-
-MODULE_DEVICE_TABLE(isapnp, ultra_device_ids);
-#endif
-
-static u32 ultra_msg_enable;
-
-#define START_PG		0x00	/* First page of TX buffer */
-
-#define ULTRA_CMDREG	0		/* Offset to ASIC command register. */
-#define	 ULTRA_RESET	0x80	/* Board reset, in ULTRA_CMDREG. */
-#define	 ULTRA_MEMENB	0x40	/* Enable the shared memory. */
-#define IOPD	0x02			/* I/O Pipe Data (16 bits), PIO operation. */
-#define IOPA	0x07			/* I/O Pipe Address for PIO operation. */
-#define ULTRA_NIC_OFFSET  16	/* NIC register offset from the base_addr. */
-#define ULTRA_IO_EXTENT 32
-#define EN0_ERWCNT		0x08	/* Early receive warning count. */
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void ultra_poll(struct net_device *dev)
-{
-	disable_irq(dev->irq);
-	ei_interrupt(dev->irq, dev);
-	enable_irq(dev->irq);
-}
-#endif
-/*	Probe for the Ultra.  This looks like a 8013 with the station
-	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
-	following.
-*/
-
-static int __init do_ultra_probe(struct net_device *dev)
-{
-	int i;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return ultra_probe1(dev, base_addr);
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-#ifdef __ISAPNP__
-	/* Look for any installed ISAPnP cards */
-	if (isapnp_present() && (ultra_probe_isapnp(dev) == 0))
-		return 0;
-#endif
-
-	for (i = 0; ultra_portlist[i]; i++) {
-		dev->irq = irq;
-		if (ultra_probe1(dev, ultra_portlist[i]) == 0)
-			return 0;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init ultra_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_ultra_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops ultra_netdev_ops = {
-	.ndo_open		= ultra_open,
-	.ndo_stop		= ultra_close_card,
-
-	.ndo_start_xmit		= ei_start_xmit,
-	.ndo_tx_timeout		= ei_tx_timeout,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= ultra_poll,
-#endif
-};
-
-static int __init ultra_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, retval;
-	int checksum = 0;
-	u8 macaddr[ETH_ALEN];
-	const char *model_name;
-	unsigned char eeprom_irq = 0;
-	static unsigned version_printed;
-	/* Values from various config regs. */
-	unsigned char num_pages, irqreg, addr, piomode;
-	unsigned char idreg = inb(ioaddr + 7);
-	unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	/* Check the ID nibble. */
-	if ((idreg & 0xF0) != 0x20 			/* SMC Ultra */
-		&& (idreg & 0xF0) != 0x40) {		/* SMC EtherEZ */
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/* Select the station address register set. */
-	outb(reg4, ioaddr + 4);
-
-	for (i = 0; i < 8; i++)
-		checksum += inb(ioaddr + 8 + i);
-	if ((checksum & 0xff) != 0xFF) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	if ((ultra_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
-		netdev_info(dev, version);
-
-	model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ";
-
-	for (i = 0; i < 6; i++)
-		macaddr[i] = inb(ioaddr + 8 + i);
-	eth_hw_addr_set(dev, macaddr);
-
-	netdev_info(dev, "%s at %#3x, %pM", model_name,
-		    ioaddr, dev->dev_addr);
-
-	/* Switch from the station address to the alternate register set and
-	   read the useful registers there. */
-	outb(0x80 | reg4, ioaddr + 4);
-
-	/* Enabled FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
-	outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
-	piomode = inb(ioaddr + 0x8);
-	addr = inb(ioaddr + 0xb);
-	irqreg = inb(ioaddr + 0xd);
-
-	/* Switch back to the station address register set so that the MS-DOS driver
-	   can find the card after a warm boot. */
-	outb(reg4, ioaddr + 4);
-
-	if (dev->irq < 2) {
-		unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
-		int irq;
-
-		/* The IRQ bits are split. */
-		irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)];
-
-		if (irq == 0) {
-			pr_cont(", failed to detect IRQ line.\n");
-			retval =  -EAGAIN;
-			goto out;
-		}
-		dev->irq = irq;
-		eeprom_irq = 1;
-	}
-
-	/* The 8390 isn't at the base address, so fake the offset */
-	dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
-
-	{
-		static const int addr_tbl[4] = {
-			0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000
-		};
-		static const short num_pages_tbl[4] = {
-			0x20, 0x40, 0x80, 0xff
-		};
-
-		dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ;
-		num_pages = num_pages_tbl[(addr >> 4) & 3];
-	}
-
-	ei_status.name = model_name;
-	ei_status.word16 = 1;
-	ei_status.tx_start_page = START_PG;
-	ei_status.rx_start_page = START_PG + TX_PAGES;
-	ei_status.stop_page = num_pages;
-
-	ei_status.mem = ioremap(dev->mem_start, (ei_status.stop_page - START_PG)*256);
-	if (!ei_status.mem) {
-		pr_cont(", failed to ioremap.\n");
-		retval =  -ENOMEM;
-		goto out;
-	}
-
-	dev->mem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256;
-
-	if (piomode) {
-		pr_cont(", %s IRQ %d programmed-I/O mode.\n",
-			eeprom_irq ? "EEPROM" : "assigned ", dev->irq);
-		ei_status.block_input = &ultra_pio_input;
-		ei_status.block_output = &ultra_pio_output;
-		ei_status.get_8390_hdr = &ultra_pio_get_hdr;
-	} else {
-		pr_cont(", %s IRQ %d memory %#lx-%#lx.\n",
-			eeprom_irq ? "" : "assigned ", dev->irq, dev->mem_start,
-			dev->mem_end-1);
-		ei_status.block_input = &ultra_block_input;
-		ei_status.block_output = &ultra_block_output;
-		ei_status.get_8390_hdr = &ultra_get_8390_hdr;
-	}
-	ei_status.reset_8390 = &ultra_reset_8390;
-
-	dev->netdev_ops = &ultra_netdev_ops;
-	NS8390_init(dev, 0);
-	ei_local->msg_enable = ultra_msg_enable;
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out;
-	return 0;
-out:
-	release_region(ioaddr, ULTRA_IO_EXTENT);
-	return retval;
-}
-
-#ifdef __ISAPNP__
-static int __init ultra_probe_isapnp(struct net_device *dev)
-{
-        int i;
-
-        for (i = 0; ultra_device_ids[i].vendor != 0; i++) {
-		struct pnp_dev *idev = NULL;
-
-                while ((idev = pnp_find_dev(NULL,
-                                            ultra_device_ids[i].vendor,
-                                            ultra_device_ids[i].function,
-                                            idev))) {
-                        /* Avoid already found cards from previous calls */
-                        if (pnp_device_attach(idev) < 0)
-				continue;
-                        if (pnp_activate_dev(idev) < 0) {
-                              __again:
-				pnp_device_detach(idev);
-				continue;
-                        }
-			/* if no io and irq, search for next */
-			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0))
-				goto __again;
-                        /* found it */
-			dev->base_addr = pnp_port_start(idev, 0);
-			dev->irq = pnp_irq(idev, 0);
-			netdev_info(dev,
-				    "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
-				    (char *) ultra_device_ids[i].driver_data,
-				    dev->base_addr, dev->irq);
-                        if (ultra_probe1(dev, dev->base_addr) != 0) {      /* Shouldn't happen. */
-				netdev_err(dev,
-					   "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n",
-					   dev->base_addr);
-				pnp_device_detach(idev);
-				return -ENXIO;
-                        }
-                        ei_status.priv = (unsigned long)idev;
-                        break;
-                }
-                if (!idev)
-                        continue;
-                return 0;
-        }
-
-        return -ENODEV;
-}
-#endif
-
-static int
-ultra_open(struct net_device *dev)
-{
-	int retval;
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-	unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40,
-				   0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, };
-
-	retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
-	if (retval)
-		return retval;
-
-	outb(0x00, ioaddr);	/* Disable shared memory for safety. */
-	outb(0x80, ioaddr + 5);
-	/* Set the IRQ line. */
-	outb(inb(ioaddr + 4) | 0x80, ioaddr + 4);
-	outb((inb(ioaddr + 13) & ~0x4C) | irq2reg[dev->irq], ioaddr + 13);
-	outb(inb(ioaddr + 4) & 0x7f, ioaddr + 4);
-
-	if (ei_status.block_input == &ultra_pio_input) {
-		outb(0x11, ioaddr + 6);		/* Enable interrupts and PIO. */
-		outb(0x01, ioaddr + 0x19);  	/* Enable ring read auto-wrap. */
-	} else
-		outb(0x01, ioaddr + 6);		/* Enable interrupts and memory. */
-	/* Set the early receive warning level in window 0 high enough not
-	   to receive ERW interrupts. */
-	outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
-	outb(0xff, dev->base_addr + EN0_ERWCNT);
-	ei_open(dev);
-	return 0;
-}
-
-static void
-ultra_reset_8390(struct net_device *dev)
-{
-	int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	outb(ULTRA_RESET, cmd_port);
-	netif_dbg(ei_local, hw, dev, "resetting Ultra, t=%ld...\n", jiffies);
-	ei_status.txing = 0;
-
-	outb(0x00, cmd_port);	/* Disable shared memory for safety. */
-	outb(0x80, cmd_port + 5);
-	if (ei_status.block_input == &ultra_pio_input)
-		outb(0x11, cmd_port + 6);		/* Enable interrupts and PIO. */
-	else
-		outb(0x01, cmd_port + 6);		/* Enable interrupts and memory. */
-
-	netif_dbg(ei_local, hw, dev, "reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void
-ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - START_PG)<<8);
-
-	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);	/* shmem on */
-#ifdef __BIG_ENDIAN
-	/* Officially this is what we are doing, but the readl() is faster */
-	/* unfortunately it isn't endian aware of the struct               */
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = le16_to_cpu(hdr->count);
-#else
-	((unsigned int*)hdr)[0] = readl(hdr_start);
-#endif
-	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */
-}
-
-/* Block input and output are easy on shared memory ethercards, the only
-   complication is when the ring buffer wraps. */
-
-static void
-ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	void __iomem *xfer_start = ei_status.mem + ring_offset - (START_PG<<8);
-
-	/* Enable shared memory. */
-	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
-
-	if (ring_offset + count > ei_status.stop_page*256) {
-		/* We must wrap the input move. */
-		int semi_count = ei_status.stop_page*256 - ring_offset;
-		memcpy_fromio(skb->data, xfer_start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
-	} else {
-		memcpy_fromio(skb->data, xfer_start, count);
-	}
-
-	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET);	/* Disable memory. */
-}
-
-static void
-ultra_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	void __iomem *shmem = ei_status.mem + ((start_page - START_PG)<<8);
-
-	/* Enable shared memory. */
-	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
-
-	memcpy_toio(shmem, buf, count);
-
-	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
-}
-
-/* The identical operations for programmed I/O cards.
-   The PIO model is trivial to use: the 16 bit start address is written
-   byte-sequentially to IOPA, with no intervening I/O operations, and the
-   data is read or written to the IOPD data port.
-   The only potential complication is that the address register is shared
-   and must be always be rewritten between each read/write direction change.
-   This is no problem for us, as the 8390 code ensures that we are single
-   threaded. */
-static void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-	outb(0x00, ioaddr + IOPA);	/* Set the address, LSB first. */
-	outb(ring_page, ioaddr + IOPA);
-	insw(ioaddr + IOPD, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-}
-
-static void ultra_pio_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-    char *buf = skb->data;
-
-	/* For now set the address again, although it should already be correct. */
-	outb(ring_offset, ioaddr + IOPA);	/* Set the address, LSB first. */
-	outb(ring_offset >> 8, ioaddr + IOPA);
-	/* We know skbuffs are padded to at least word alignment. */
-	insw(ioaddr + IOPD, buf, (count+1)>>1);
-}
-static void ultra_pio_output(struct net_device *dev, int count,
-							const unsigned char *buf, const int start_page)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-	outb(0x00, ioaddr + IOPA);	/* Set the address, LSB first. */
-	outb(start_page, ioaddr + IOPA);
-	/* An extra odd byte is OK here as well. */
-	outsw(ioaddr + IOPD, buf, (count+1)>>1);
-}
-
-static int
-ultra_close_card(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	netif_stop_queue(dev);
-
-	netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n");
-
-	outb(0x00, ioaddr + 6);		/* Disable interrupts. */
-	free_irq(dev->irq, dev);
-
-	NS8390_init(dev, 0);
-
-	/* We should someday disable shared memory and change to 8-bit mode
-	   "just in case"... */
-
-	return 0;
-}
-
-
-#ifdef MODULE
-#define MAX_ULTRA_CARDS	4	/* Max number of Ultra cards per module */
-static struct net_device *dev_ultra[MAX_ULTRA_CARDS];
-static int io[MAX_ULTRA_CARDS];
-static int irq[MAX_ULTRA_CARDS];
-
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param_named(msg_enable, ultra_msg_enable, uint, 0444);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
-MODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-static int __init ultra_init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		if (do_ultra_probe(dev) == 0) {
-			dev_ultra[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-module_init(ultra_init_module);
-
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: ultra_close_card() does free_irq */
-#ifdef __ISAPNP__
-	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
-	if (idev)
-		pnp_device_detach(idev);
-#endif
-	release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-static void __exit ultra_cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
-		struct net_device *dev = dev_ultra[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-module_exit(ultra_cleanup_module);
-#endif /* MODULE */

-- 
2.53.0


^ permalink raw reply related

* [PATCH net 11/18] drivers: net: cirrus: cs89x0: Remove this driver
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

The cs89x0 was written by Bonald Becker 1993 to 1994. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/cirrus/Kconfig  |   30 -
 drivers/net/ethernet/cirrus/Makefile |    1 -
 drivers/net/ethernet/cirrus/cs89x0.c | 1915 ----------------------------------
 3 files changed, 1946 deletions(-)

diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 5bdf731d9503..1a0c7b3bfcd6 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -17,36 +17,6 @@ config NET_VENDOR_CIRRUS
 
 if NET_VENDOR_CIRRUS
 
-config CS89x0
-	tristate
-
-config CS89x0_ISA
-	tristate "CS89x0 ISA driver support"
-	depends on HAS_IOPORT_MAP
-	depends on ISA
-	depends on !PPC32
-	depends on CS89x0_PLATFORM=n
-	select NETDEV_LEGACY_INIT
-	select CS89x0
-	help
-	  Support for CS89x0 chipset based Ethernet cards. If you have a
-	  network (Ethernet) card of this type, say Y and read the file
-	  <file:Documentation/networking/device_drivers/ethernet/cirrus/cs89x0.rst>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called cs89x0.
-
-config CS89x0_PLATFORM
-	tristate "CS89x0 platform driver support"
-	depends on ARM || (COMPILE_TEST && !PPC)
-	select CS89x0
-	help
-	  Say Y to compile the cs89x0 platform driver. This makes this driver
-	  suitable for use on certain evaluation boards such as the iMX21ADS.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called cs89x0.
-
 config EP93XX_ETH
 	tristate "EP93xx Ethernet support"
 	depends on (ARM && ARCH_EP93XX) || COMPILE_TEST
diff --git a/drivers/net/ethernet/cirrus/Makefile b/drivers/net/ethernet/cirrus/Makefile
index 84865e593788..cb740939d976 100644
--- a/drivers/net/ethernet/cirrus/Makefile
+++ b/drivers/net/ethernet/cirrus/Makefile
@@ -3,6 +3,5 @@
 # Makefile for the Cirrus network device drivers.
 #
 
-obj-$(CONFIG_CS89x0) += cs89x0.o
 obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
deleted file mode 100644
index fa5857923db4..000000000000
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ /dev/null
@@ -1,1915 +0,0 @@
-/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0
- *           driver for linux.
- * Written 1996 by Russell Nelson, with reference to skeleton.c
- * written 1993-1994 by Donald Becker.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * The author may be reached at nelson@crynwr.com, Crynwr
- * Software, 521 Pleasant Valley Rd., Potsdam, NY 13676
- *
- * Other contributors:
- * Mike Cruse        : mcruse@cti-ltd.com
- * Russ Nelson
- * Melody Lee        : ethernet@crystal.cirrus.com
- * Alan Cox
- * Andrew Morton
- * Oskar Schirmer    : oskar@scara.com
- * Deepak Saxena     : dsaxena@plexity.net
- * Dmitry Pervushin  : dpervushin@ru.mvista.com
- * Deepak Saxena     : dsaxena@plexity.net
- * Domenico Andreoli : cavokz@gmail.com
- */
-
-
-/*
- * Set this to zero to disable DMA code
- *
- * Note that even if DMA is turned off we still support the 'dma' and  'use_dma'
- * module options so we don't break any startup scripts.
- */
-#ifndef CONFIG_ISA_DMA_API
-#define ALLOW_DMA	0
-#else
-#define ALLOW_DMA	1
-#endif
-
-/*
- * Set this to zero to remove all the debug statements via
- * dead code elimination
- */
-#define DEBUGGING	1
-
-/* Sources:
- *	Crynwr packet driver epktisa.
- *	Crystal Semiconductor data sheets.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/printk.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/jiffies.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-#include <linux/io.h>
-
-#include <net/Space.h>
-
-#include <asm/irq.h>
-#include <linux/atomic.h>
-#if ALLOW_DMA
-#include <asm/dma.h>
-#endif
-
-#include "cs89x0.h"
-
-#define cs89_dbg(val, level, fmt, ...)				\
-do {								\
-	if (val <= net_debug)					\
-		pr_##level(fmt, ##__VA_ARGS__);			\
-} while (0)
-
-static char version[] __initdata =
-	"v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton";
-
-#define DRV_NAME "cs89x0"
-
-/* First, a few definitions that the brave might change.
- * A zero-terminated list of I/O addresses to be probed. Some special flags..
- * Addr & 1 = Read back the address port, look for signature and reset
- * the page window before probing
- * Addr & 3 = Reset the page window and probe
- * The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
- * but it is possible that a Cirrus board could be plugged into the ISA
- * slots.
- */
-/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
- * them to system IRQ numbers. This mapping is card specific and is set to
- * the configuration of the Cirrus Eval board for this chip.
- */
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-static unsigned int netcard_portlist[] __used __initdata = {
-	0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240,
-	0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0
-};
-static unsigned int cs8900_irq_map[] = {
-	10, 11, 12, 5
-};
-#endif
-
-#if DEBUGGING
-static unsigned int net_debug = DEBUGGING;
-#else
-#define net_debug 0	/* gcc will remove all the debug code for us */
-#endif
-
-/* The number of low I/O ports used by the ethercard. */
-#define NETCARD_IO_EXTENT	16
-
-/* we allow the user to override various values normally set in the EEPROM */
-#define FORCE_RJ45	0x0001    /* pick one of these three */
-#define FORCE_AUI	0x0002
-#define FORCE_BNC	0x0004
-
-#define FORCE_AUTO	0x0010    /* pick one of these three */
-#define FORCE_HALF	0x0020
-#define FORCE_FULL	0x0030
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
-	char chip_revision;	/* revision letter of the chip ('A'...) */
-	int send_cmd;		/* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */
-	int auto_neg_cnf;	/* auto-negotiation word from EEPROM */
-	int adapter_cnf;	/* adapter configuration from EEPROM */
-	int isa_config;		/* ISA configuration from EEPROM */
-	int irq_map;		/* IRQ map from EEPROM */
-	int rx_mode;		/* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */
-	int curr_rx_cfg;	/* a copy of PP_RxCFG */
-	int linectl;		/* either 0 or LOW_RX_SQUELCH, depending on configuration. */
-	int send_underrun;	/* keep track of how many underruns in a row we get */
-	int force;		/* force various values; see FORCE* above. */
-	spinlock_t lock;
-	void __iomem *virt_addr;/* CS89x0 virtual address. */
-#if ALLOW_DMA
-	int use_dma;		/* Flag: we're using dma */
-	int dma;		/* DMA channel */
-	int dmasize;		/* 16 or 64 */
-	unsigned char *dma_buff;	/* points to the beginning of the buffer */
-	unsigned char *end_dma_buff;	/* points to the end of the buffer */
-	unsigned char *rx_dma_ptr;	/* points to the next packet  */
-#endif
-};
-
-/* Example routines you must write ;->. */
-#define tx_done(dev) 1
-
-/*
- * Permit 'cs89x0_dma=N' in the kernel boot environment
- */
-#if !defined(MODULE)
-#if ALLOW_DMA
-static int g_cs89x0_dma;
-
-static int __init dma_fn(char *str)
-{
-	g_cs89x0_dma = simple_strtol(str, NULL, 0);
-	return 1;
-}
-
-__setup("cs89x0_dma=", dma_fn);
-#endif	/* ALLOW_DMA */
-
-static int g_cs89x0_media__force;
-
-static int __init media_fn(char *str)
-{
-	if (!strcmp(str, "rj45"))
-		g_cs89x0_media__force = FORCE_RJ45;
-	else if (!strcmp(str, "aui"))
-		g_cs89x0_media__force = FORCE_AUI;
-	else if (!strcmp(str, "bnc"))
-		g_cs89x0_media__force = FORCE_BNC;
-
-	return 1;
-}
-
-__setup("cs89x0_media=", media_fn);
-#endif
-
-static void readwords(struct net_local *lp, int portno, void *buf, int length)
-{
-	u8 *buf8 = (u8 *)buf;
-
-	do {
-		u16 tmp16;
-
-		tmp16 = ioread16(lp->virt_addr + portno);
-		*buf8++ = (u8)tmp16;
-		*buf8++ = (u8)(tmp16 >> 8);
-	} while (--length);
-}
-
-static void writewords(struct net_local *lp, int portno, void *buf, int length)
-{
-	u8 *buf8 = (u8 *)buf;
-
-	do {
-		u16 tmp16;
-
-		tmp16 = *buf8++;
-		tmp16 |= (*buf8++) << 8;
-		iowrite16(tmp16, lp->virt_addr + portno);
-	} while (--length);
-}
-
-static u16
-readreg(struct net_device *dev, u16 regno)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	iowrite16(regno, lp->virt_addr + ADD_PORT);
-	return ioread16(lp->virt_addr + DATA_PORT);
-}
-
-static void
-writereg(struct net_device *dev, u16 regno, u16 value)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	iowrite16(regno, lp->virt_addr + ADD_PORT);
-	iowrite16(value, lp->virt_addr + DATA_PORT);
-}
-
-static int __init
-wait_eeprom_ready(struct net_device *dev)
-{
-	unsigned long timeout = jiffies;
-	/* check to see if the EEPROM is ready,
-	 * a timeout is used just in case EEPROM is ready when
-	 * SI_BUSY in the PP_SelfST is clear
-	 */
-	while (readreg(dev, PP_SelfST) & SI_BUSY)
-		if (time_after_eq(jiffies, timeout + 40))
-			return -1;
-	return 0;
-}
-
-static int __init
-get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
-{
-	int i;
-
-	cs89_dbg(3, info, "EEPROM data from %x for %x:", off, len);
-	for (i = 0; i < len; i++) {
-		if (wait_eeprom_ready(dev) < 0)
-			return -1;
-		/* Now send the EEPROM read command and EEPROM location to read */
-		writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD);
-		if (wait_eeprom_ready(dev) < 0)
-			return -1;
-		buffer[i] = readreg(dev, PP_EEData);
-		cs89_dbg(3, cont, " %04x", buffer[i]);
-	}
-	cs89_dbg(3, cont, "\n");
-	return 0;
-}
-
-static int  __init
-get_eeprom_cksum(int off, int len, int *buffer)
-{
-	int i, cksum;
-
-	cksum = 0;
-	for (i = 0; i < len; i++)
-		cksum += buffer[i];
-	cksum &= 0xffff;
-	if (cksum == 0)
-		return 0;
-	return -1;
-}
-
-static void
-write_irq(struct net_device *dev, int chip_type, int irq)
-{
-	int i;
-
-	if (chip_type == CS8900) {
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-		/* Search the mapping table for the corresponding IRQ pin. */
-		for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
-			if (cs8900_irq_map[i] == irq)
-				break;
-		/* Not found */
-		if (i == ARRAY_SIZE(cs8900_irq_map))
-			i = 3;
-#else
-		/* INTRQ0 pin is used for interrupt generation. */
-		i = 0;
-#endif
-		writereg(dev, PP_CS8900_ISAINT, i);
-	} else {
-		writereg(dev, PP_CS8920_ISAINT, irq);
-	}
-}
-
-static void
-count_rx_errors(int status, struct net_device *dev)
-{
-	dev->stats.rx_errors++;
-	if (status & RX_RUNT)
-		dev->stats.rx_length_errors++;
-	if (status & RX_EXTRA_DATA)
-		dev->stats.rx_length_errors++;
-	if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA | RX_RUNT)))
-		/* per str 172 */
-		dev->stats.rx_crc_errors++;
-	if (status & RX_DRIBBLE)
-		dev->stats.rx_frame_errors++;
-}
-
-/*********************************
- * This page contains DMA routines
- *********************************/
-
-#if ALLOW_DMA
-
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1) >> 17 == (long)(ptr2) >> 17)
-
-static void
-get_dma_channel(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	if (lp->dma) {
-		dev->dma = lp->dma;
-		lp->isa_config |= ISA_RxDMA;
-	} else {
-		if ((lp->isa_config & ANY_ISA_DMA) == 0)
-			return;
-		dev->dma = lp->isa_config & DMA_NO_MASK;
-		if (lp->chip_type == CS8900)
-			dev->dma += 5;
-		if (dev->dma < 5 || dev->dma > 7) {
-			lp->isa_config &= ~ANY_ISA_DMA;
-			return;
-		}
-	}
-}
-
-static void
-write_dma(struct net_device *dev, int chip_type, int dma)
-{
-	struct net_local *lp = netdev_priv(dev);
-	if ((lp->isa_config & ANY_ISA_DMA) == 0)
-		return;
-	if (chip_type == CS8900)
-		writereg(dev, PP_CS8900_ISADMA, dma - 5);
-	else
-		writereg(dev, PP_CS8920_ISADMA, dma);
-}
-
-static void
-set_dma_cfg(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	if (lp->use_dma) {
-		if ((lp->isa_config & ANY_ISA_DMA) == 0) {
-			cs89_dbg(3, err, "set_dma_cfg(): no DMA\n");
-			return;
-		}
-		if (lp->isa_config & ISA_RxDMA) {
-			lp->curr_rx_cfg |= RX_DMA_ONLY;
-			cs89_dbg(3, info, "set_dma_cfg(): RX_DMA_ONLY\n");
-		} else {
-			lp->curr_rx_cfg |= AUTO_RX_DMA;	/* not that we support it... */
-			cs89_dbg(3, info, "set_dma_cfg(): AUTO_RX_DMA\n");
-		}
-	}
-}
-
-static int
-dma_bufcfg(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	if (lp->use_dma)
-		return (lp->isa_config & ANY_ISA_DMA) ? RX_DMA_ENBL : 0;
-	else
-		return 0;
-}
-
-static int
-dma_busctl(struct net_device *dev)
-{
-	int retval = 0;
-	struct net_local *lp = netdev_priv(dev);
-	if (lp->use_dma) {
-		if (lp->isa_config & ANY_ISA_DMA)
-			retval |= RESET_RX_DMA; /* Reset the DMA pointer */
-		if (lp->isa_config & DMA_BURST)
-			retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */
-		if (lp->dmasize == 64)
-			retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */
-		retval |= MEMORY_ON;	/* we need memory enabled to use DMA. */
-	}
-	return retval;
-}
-
-static void
-dma_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	struct sk_buff *skb;
-	int status, length;
-	unsigned char *bp = lp->rx_dma_ptr;
-
-	status = bp[0] + (bp[1] << 8);
-	length = bp[2] + (bp[3] << 8);
-	bp += 4;
-
-	cs89_dbg(5, debug, "%s: receiving DMA packet at %lx, status %x, length %x\n",
-		 dev->name, (unsigned long)bp, status, length);
-
-	if ((status & RX_OK) == 0) {
-		count_rx_errors(status, dev);
-		goto skip_this_frame;
-	}
-
-	/* Malloc up new buffer. */
-	skb = netdev_alloc_skb(dev, length + 2);
-	if (skb == NULL) {
-		dev->stats.rx_dropped++;
-
-		/* AKPM: advance bp to the next frame */
-skip_this_frame:
-		bp += (length + 3) & ~3;
-		if (bp >= lp->end_dma_buff)
-			bp -= lp->dmasize * 1024;
-		lp->rx_dma_ptr = bp;
-		return;
-	}
-	skb_reserve(skb, 2);	/* longword align L3 header */
-
-	if (bp + length > lp->end_dma_buff) {
-		int semi_cnt = lp->end_dma_buff - bp;
-		skb_put_data(skb, bp, semi_cnt);
-		skb_put_data(skb, lp->dma_buff, length - semi_cnt);
-	} else {
-		skb_put_data(skb, bp, length);
-	}
-	bp += (length + 3) & ~3;
-	if (bp >= lp->end_dma_buff)
-		bp -= lp->dmasize*1024;
-	lp->rx_dma_ptr = bp;
-
-	cs89_dbg(3, info, "%s: received %d byte DMA packet of type %x\n",
-		 dev->name, length,
-		 ((skb->data[ETH_ALEN + ETH_ALEN] << 8) |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]));
-
-	skb->protocol = eth_type_trans(skb, dev);
-	netif_rx(skb);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += length;
-}
-
-static void release_dma_buff(struct net_local *lp)
-{
-	if (lp->dma_buff) {
-		free_pages((unsigned long)(lp->dma_buff),
-			   get_order(lp->dmasize * 1024));
-		lp->dma_buff = NULL;
-	}
-}
-
-#endif	/* ALLOW_DMA */
-
-static void
-control_dc_dc(struct net_device *dev, int on_not_off)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned int selfcontrol;
-	unsigned long timenow = jiffies;
-	/* control the DC to DC convertor in the SelfControl register.
-	 * Note: This is hooked up to a general purpose pin, might not
-	 * always be a DC to DC convertor.
-	 */
-
-	selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
-	if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
-		selfcontrol |= HCB1;
-	else
-		selfcontrol &= ~HCB1;
-	writereg(dev, PP_SelfCTL, selfcontrol);
-
-	/* Wait for the DC/DC converter to power up - 500ms */
-	while (time_before(jiffies, timenow + HZ))
-		;
-}
-
-/* send a test packet - return true if carrier bits are ok */
-static int
-send_test_pkt(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	char test_packet[] = {
-		0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0,
-		0, 46,		/* A 46 in network order */
-		0, 0,		/* DSAP=0 & SSAP=0 fields */
-		0xf3, 0		/* Control (Test Req + P bit set) */
-	};
-	unsigned long timenow = jiffies;
-
-	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);
-
-	memcpy(test_packet,            dev->dev_addr, ETH_ALEN);
-	memcpy(test_packet + ETH_ALEN, dev->dev_addr, ETH_ALEN);
-
-	iowrite16(TX_AFTER_ALL, lp->virt_addr + TX_CMD_PORT);
-	iowrite16(ETH_ZLEN, lp->virt_addr + TX_LEN_PORT);
-
-	/* Test to see if the chip has allocated memory for the packet */
-	while (time_before(jiffies, timenow + 5))
-		if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)
-			break;
-	if (time_after_eq(jiffies, timenow + 5))
-		return 0;	/* this shouldn't happen */
-
-	/* Write the contents of the packet */
-	writewords(lp, TX_FRAME_PORT, test_packet, (ETH_ZLEN + 1) >> 1);
-
-	cs89_dbg(1, debug, "Sending test packet ");
-	/* wait a couple of jiffies for packet to be received */
-	for (timenow = jiffies; time_before(jiffies, timenow + 3);)
-		;
-	if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
-		cs89_dbg(1, cont, "succeeded\n");
-		return 1;
-	}
-	cs89_dbg(1, cont, "failed\n");
-	return 0;
-}
-
-#define DETECTED_NONE  0
-#define DETECTED_RJ45H 1
-#define DETECTED_RJ45F 2
-#define DETECTED_AUI   3
-#define DETECTED_BNC   4
-
-static int
-detect_tp(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long timenow = jiffies;
-	int fdx;
-
-	cs89_dbg(1, debug, "%s: Attempting TP\n", dev->name);
-
-	/* If connected to another full duplex capable 10-Base-T card
-	 * the link pulses seem to be lost when the auto detect bit in
-	 * the LineCTL is set.  To overcome this the auto detect bit will
-	 * be cleared whilst testing the 10-Base-T interface.  This would
-	 * not be necessary for the sparrow chip but is simpler to do it
-	 * anyway.
-	 */
-	writereg(dev, PP_LineCTL, lp->linectl & ~AUI_ONLY);
-	control_dc_dc(dev, 0);
-
-	/* Delay for the hardware to work out if the TP cable is present
-	 * - 150ms
-	 */
-	for (timenow = jiffies; time_before(jiffies, timenow + 15);)
-		;
-	if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
-		return DETECTED_NONE;
-
-	if (lp->chip_type == CS8900) {
-		switch (lp->force & 0xf0) {
-#if 0
-		case FORCE_AUTO:
-			pr_info("%s: cs8900 doesn't autonegotiate\n",
-				dev->name);
-			return DETECTED_NONE;
-#endif
-			/* CS8900 doesn't support AUTO, change to HALF*/
-		case FORCE_AUTO:
-			lp->force &= ~FORCE_AUTO;
-			lp->force |= FORCE_HALF;
-			break;
-		case FORCE_HALF:
-			break;
-		case FORCE_FULL:
-			writereg(dev, PP_TestCTL,
-				 readreg(dev, PP_TestCTL) | FDX_8900);
-			break;
-		}
-		fdx = readreg(dev, PP_TestCTL) & FDX_8900;
-	} else {
-		switch (lp->force & 0xf0) {
-		case FORCE_AUTO:
-			lp->auto_neg_cnf = AUTO_NEG_ENABLE;
-			break;
-		case FORCE_HALF:
-			lp->auto_neg_cnf = 0;
-			break;
-		case FORCE_FULL:
-			lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX;
-			break;
-		}
-
-		writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK);
-
-		if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
-			pr_info("%s: negotiating duplex...\n", dev->name);
-			while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {
-				if (time_after(jiffies, timenow + 4000)) {
-					pr_err("**** Full / half duplex auto-negotiation timed out ****\n");
-					break;
-				}
-			}
-		}
-		fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE;
-	}
-	if (fdx)
-		return DETECTED_RJ45F;
-	else
-		return DETECTED_RJ45H;
-}
-
-static int
-detect_bnc(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	cs89_dbg(1, debug, "%s: Attempting BNC\n", dev->name);
-	control_dc_dc(dev, 1);
-
-	writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
-
-	if (send_test_pkt(dev))
-		return DETECTED_BNC;
-	else
-		return DETECTED_NONE;
-}
-
-static int
-detect_aui(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	cs89_dbg(1, debug, "%s: Attempting AUI\n", dev->name);
-	control_dc_dc(dev, 0);
-
-	writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
-
-	if (send_test_pkt(dev))
-		return DETECTED_AUI;
-	else
-		return DETECTED_NONE;
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	struct sk_buff *skb;
-	int status, length;
-
-	status = ioread16(lp->virt_addr + RX_FRAME_PORT);
-	length = ioread16(lp->virt_addr + RX_FRAME_PORT);
-
-	if ((status & RX_OK) == 0) {
-		count_rx_errors(status, dev);
-		return;
-	}
-
-	/* Malloc up new buffer. */
-	skb = netdev_alloc_skb(dev, length + 2);
-	if (skb == NULL) {
-		dev->stats.rx_dropped++;
-		return;
-	}
-	skb_reserve(skb, 2);	/* longword align L3 header */
-
-	readwords(lp, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
-	if (length & 1)
-		skb->data[length-1] = ioread16(lp->virt_addr + RX_FRAME_PORT);
-
-	cs89_dbg(3, debug, "%s: received %d byte packet of type %x\n",
-		 dev->name, length,
-		 (skb->data[ETH_ALEN + ETH_ALEN] << 8) |
-		 skb->data[ETH_ALEN + ETH_ALEN + 1]);
-
-	skb->protocol = eth_type_trans(skb, dev);
-	netif_rx(skb);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += length;
-}
-
-/* The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int status;
-	int handled = 0;
-
-	lp = netdev_priv(dev);
-
-	/* we MUST read all the events out of the ISQ, otherwise we'll never
-	 * get interrupted again.  As a consequence, we can't have any limit
-	 * on the number of times we loop in the interrupt handler.  The
-	 * hardware guarantees that eventually we'll run out of events.  Of
-	 * course, if you're on a slow machine, and packets are arriving
-	 * faster than you can read them off, you're screwed.  Hasta la
-	 * vista, baby!
-	 */
-	while ((status = ioread16(lp->virt_addr + ISQ_PORT))) {
-		cs89_dbg(4, debug, "%s: event=%04x\n", dev->name, status);
-		handled = 1;
-		switch (status & ISQ_EVENT_MASK) {
-		case ISQ_RECEIVER_EVENT:
-			/* Got a packet(s). */
-			net_rx(dev);
-			break;
-		case ISQ_TRANSMITTER_EVENT:
-			dev->stats.tx_packets++;
-			netif_wake_queue(dev);	/* Inform upper layers. */
-			if ((status & (TX_OK |
-				       TX_LOST_CRS |
-				       TX_SQE_ERROR |
-				       TX_LATE_COL |
-				       TX_16_COL)) != TX_OK) {
-				if ((status & TX_OK) == 0)
-					dev->stats.tx_errors++;
-				if (status & TX_LOST_CRS)
-					dev->stats.tx_carrier_errors++;
-				if (status & TX_SQE_ERROR)
-					dev->stats.tx_heartbeat_errors++;
-				if (status & TX_LATE_COL)
-					dev->stats.tx_window_errors++;
-				if (status & TX_16_COL)
-					dev->stats.tx_aborted_errors++;
-			}
-			break;
-		case ISQ_BUFFER_EVENT:
-			if (status & READY_FOR_TX) {
-				/* we tried to transmit a packet earlier,
-				 * but inexplicably ran out of buffers.
-				 * That shouldn't happen since we only ever
-				 * load one packet.  Shrug.  Do the right
-				 * thing anyway.
-				 */
-				netif_wake_queue(dev);	/* Inform upper layers. */
-			}
-			if (status & TX_UNDERRUN) {
-				cs89_dbg(0, err, "%s: transmit underrun\n",
-					 dev->name);
-				lp->send_underrun++;
-				if (lp->send_underrun == 3)
-					lp->send_cmd = TX_AFTER_381;
-				else if (lp->send_underrun == 6)
-					lp->send_cmd = TX_AFTER_ALL;
-				/* transmit cycle is done, although
-				 * frame wasn't transmitted - this
-				 * avoids having to wait for the upper
-				 * layers to timeout on us, in the
-				 * event of a tx underrun
-				 */
-				netif_wake_queue(dev);	/* Inform upper layers. */
-			}
-#if ALLOW_DMA
-			if (lp->use_dma && (status & RX_DMA)) {
-				int count = readreg(dev, PP_DmaFrameCnt);
-				while (count) {
-					cs89_dbg(5, debug,
-						 "%s: receiving %d DMA frames\n",
-						 dev->name, count);
-					if (count > 1)
-						cs89_dbg(2, debug,
-							 "%s: receiving %d DMA frames\n",
-							 dev->name, count);
-					dma_rx(dev);
-					if (--count == 0)
-						count = readreg(dev, PP_DmaFrameCnt);
-					if (count > 0)
-						cs89_dbg(2, debug,
-							 "%s: continuing with %d DMA frames\n",
-							 dev->name, count);
-				}
-			}
-#endif
-			break;
-		case ISQ_RX_MISS_EVENT:
-			dev->stats.rx_missed_errors += (status >> 6);
-			break;
-		case ISQ_TX_COL_EVENT:
-			dev->stats.collisions += (status >> 6);
-			break;
-		}
-	}
-	return IRQ_RETVAL(handled);
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-*/
-
-/* AKPM: do we need to do any locking here? */
-
-static int
-net_open(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int result = 0;
-	int i;
-	int ret;
-
-	if (dev->irq < 2) {
-		/* Allow interrupts to be generated by the chip */
-/* Cirrus' release had this: */
-#if 0
-		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
-#endif
-/* And 2.3.47 had this: */
-		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
-
-		for (i = 2; i < CS8920_NO_INTS; i++) {
-			if ((1 << i) & lp->irq_map) {
-				if (request_irq(i, net_interrupt, 0, dev->name,
-						dev) == 0) {
-					dev->irq = i;
-					write_irq(dev, lp->chip_type, i);
-					/* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */
-					break;
-				}
-			}
-		}
-
-		if (i >= CS8920_NO_INTS) {
-			writereg(dev, PP_BusCTL, 0);	/* disable interrupts. */
-			pr_err("can't get an interrupt\n");
-			ret = -EAGAIN;
-			goto bad_out;
-		}
-	} else {
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-		if (((1 << dev->irq) & lp->irq_map) == 0) {
-			pr_err("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
-			       dev->name, dev->irq, lp->irq_map);
-			ret = -EAGAIN;
-			goto bad_out;
-		}
-#endif
-/* FIXME: Cirrus' release had this: */
-		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ);
-/* And 2.3.47 had this: */
-#if 0
-		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
-#endif
-		write_irq(dev, lp->chip_type, dev->irq);
-		ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev);
-		if (ret) {
-			pr_err("request_irq(%d) failed\n", dev->irq);
-			goto bad_out;
-		}
-	}
-
-#if ALLOW_DMA
-	if (lp->use_dma && (lp->isa_config & ANY_ISA_DMA)) {
-		unsigned long flags;
-		lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,
-								get_order(lp->dmasize * 1024));
-		if (!lp->dma_buff) {
-			pr_err("%s: cannot get %dK memory for DMA\n",
-			       dev->name, lp->dmasize);
-			goto release_irq;
-		}
-		cs89_dbg(1, debug, "%s: dma %lx %lx\n",
-			 dev->name,
-			 (unsigned long)lp->dma_buff,
-			 (unsigned long)isa_virt_to_bus(lp->dma_buff));
-		if ((unsigned long)lp->dma_buff >= MAX_DMA_ADDRESS ||
-		    !dma_page_eq(lp->dma_buff,
-				 lp->dma_buff + lp->dmasize * 1024 - 1)) {
-			pr_err("%s: not usable as DMA buffer\n", dev->name);
-			goto release_irq;
-		}
-		memset(lp->dma_buff, 0, lp->dmasize * 1024);	/* Why? */
-		if (request_dma(dev->dma, dev->name)) {
-			pr_err("%s: cannot get dma channel %d\n",
-			       dev->name, dev->dma);
-			goto release_irq;
-		}
-		write_dma(dev, lp->chip_type, dev->dma);
-		lp->rx_dma_ptr = lp->dma_buff;
-		lp->end_dma_buff = lp->dma_buff + lp->dmasize * 1024;
-		spin_lock_irqsave(&lp->lock, flags);
-		disable_dma(dev->dma);
-		clear_dma_ff(dev->dma);
-		set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
-		set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
-		set_dma_count(dev->dma, lp->dmasize * 1024);
-		enable_dma(dev->dma);
-		spin_unlock_irqrestore(&lp->lock, flags);
-	}
-#endif	/* ALLOW_DMA */
-
-	/* set the Ethernet address */
-	for (i = 0; i < ETH_ALEN / 2; i++)
-		writereg(dev, PP_IA + i * 2,
-			 (dev->dev_addr[i * 2] |
-			  (dev->dev_addr[i * 2 + 1] << 8)));
-
-	/* while we're testing the interface, leave interrupts disabled */
-	writereg(dev, PP_BusCTL, MEMORY_ON);
-
-	/* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */
-	if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) &&
-	    (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
-		lp->linectl = LOW_RX_SQUELCH;
-	else
-		lp->linectl = 0;
-
-	/* check to make sure that they have the "right" hardware available */
-	switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
-	case A_CNF_MEDIA_10B_T:
-		result = lp->adapter_cnf & A_CNF_10B_T;
-		break;
-	case A_CNF_MEDIA_AUI:
-		result = lp->adapter_cnf & A_CNF_AUI;
-		break;
-	case A_CNF_MEDIA_10B_2:
-		result = lp->adapter_cnf & A_CNF_10B_2;
-		break;
-	default:
-		result = lp->adapter_cnf & (A_CNF_10B_T |
-					    A_CNF_AUI |
-					    A_CNF_10B_2);
-	}
-	if (!result) {
-		pr_err("%s: EEPROM is configured for unavailable media\n",
-		       dev->name);
-release_dma:
-#if ALLOW_DMA
-		free_dma(dev->dma);
-release_irq:
-		release_dma_buff(lp);
-#endif
-		writereg(dev, PP_LineCTL,
-			 readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
-		free_irq(dev->irq, dev);
-		ret = -EAGAIN;
-		goto bad_out;
-	}
-
-	/* set the hardware to the configured choice */
-	switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
-	case A_CNF_MEDIA_10B_T:
-		result = detect_tp(dev);
-		if (result == DETECTED_NONE) {
-			pr_warn("%s: 10Base-T (RJ-45) has no cable\n",
-				dev->name);
-			if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-				result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */
-		}
-		break;
-	case A_CNF_MEDIA_AUI:
-		result = detect_aui(dev);
-		if (result == DETECTED_NONE) {
-			pr_warn("%s: 10Base-5 (AUI) has no cable\n", dev->name);
-			if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-				result = DETECTED_AUI; /* Yes! I don't care if I see a carrier */
-		}
-		break;
-	case A_CNF_MEDIA_10B_2:
-		result = detect_bnc(dev);
-		if (result == DETECTED_NONE) {
-			pr_warn("%s: 10Base-2 (BNC) has no cable\n", dev->name);
-			if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-				result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */
-		}
-		break;
-	case A_CNF_MEDIA_AUTO:
-		writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);
-		if (lp->adapter_cnf & A_CNF_10B_T) {
-			result = detect_tp(dev);
-			if (result != DETECTED_NONE)
-				break;
-		}
-		if (lp->adapter_cnf & A_CNF_AUI) {
-			result = detect_aui(dev);
-			if (result != DETECTED_NONE)
-				break;
-		}
-		if (lp->adapter_cnf & A_CNF_10B_2) {
-			result = detect_bnc(dev);
-			if (result != DETECTED_NONE)
-				break;
-		}
-		pr_err("%s: no media detected\n", dev->name);
-		goto release_dma;
-	}
-	switch (result) {
-	case DETECTED_NONE:
-		pr_err("%s: no network cable attached to configured media\n",
-		       dev->name);
-		goto release_dma;
-	case DETECTED_RJ45H:
-		pr_info("%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);
-		break;
-	case DETECTED_RJ45F:
-		pr_info("%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);
-		break;
-	case DETECTED_AUI:
-		pr_info("%s: using 10Base-5 (AUI)\n", dev->name);
-		break;
-	case DETECTED_BNC:
-		pr_info("%s: using 10Base-2 (BNC)\n", dev->name);
-		break;
-	}
-
-	/* Turn on both receive and transmit operations */
-	writereg(dev, PP_LineCTL,
-		 readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
-
-	/* Receive only error free packets addressed to this card */
-	lp->rx_mode = 0;
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
-
-	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
-
-	if (lp->isa_config & STREAM_TRANSFER)
-		lp->curr_rx_cfg |= RX_STREAM_ENBL;
-#if ALLOW_DMA
-	set_dma_cfg(dev);
-#endif
-	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
-
-	writereg(dev, PP_TxCFG, (TX_LOST_CRS_ENBL |
-				 TX_SQE_ERROR_ENBL |
-				 TX_OK_ENBL |
-				 TX_LATE_COL_ENBL |
-				 TX_JBR_ENBL |
-				 TX_ANY_COL_ENBL |
-				 TX_16_COL_ENBL));
-
-	writereg(dev, PP_BufCFG, (READY_FOR_TX_ENBL |
-				  RX_MISS_COUNT_OVRFLOW_ENBL |
-#if ALLOW_DMA
-				  dma_bufcfg(dev) |
-#endif
-				  TX_COL_COUNT_OVRFLOW_ENBL |
-				  TX_UNDERRUN_ENBL));
-
-	/* now that we've got our act together, enable everything */
-	writereg(dev, PP_BusCTL, (ENABLE_IRQ
-				  | (dev->mem_start ? MEMORY_ON : 0) /* turn memory on */
-#if ALLOW_DMA
-				  | dma_busctl(dev)
-#endif
-			 ));
-	netif_start_queue(dev);
-	cs89_dbg(1, debug, "net_open() succeeded\n");
-	return 0;
-bad_out:
-	return ret;
-}
-
-/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
-{
-#if ALLOW_DMA
-	struct net_local *lp = netdev_priv(dev);
-#endif
-
-	netif_stop_queue(dev);
-
-	writereg(dev, PP_RxCFG, 0);
-	writereg(dev, PP_TxCFG, 0);
-	writereg(dev, PP_BufCFG, 0);
-	writereg(dev, PP_BusCTL, 0);
-
-	free_irq(dev->irq, dev);
-
-#if ALLOW_DMA
-	if (lp->use_dma && lp->dma) {
-		free_dma(dev->dma);
-		release_dma_buff(lp);
-	}
-#endif
-
-	/* Update the statistics here. */
-	return 0;
-}
-
-/* Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	/* Update the statistics from the device registers. */
-	dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
-	dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	return &dev->stats;
-}
-
-static void net_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	/* If we get here, some higher level has decided we are broken.
-	   There should really be a "kick me" function call instead. */
-	cs89_dbg(0, err, "%s: transmit timed out, %s?\n",
-		 dev->name,
-		 tx_done(dev) ? "IRQ conflict" : "network cable problem");
-	/* Try to restart the adaptor. */
-	netif_wake_queue(dev);
-}
-
-static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	cs89_dbg(3, debug, "%s: sent %d byte packet of type %x\n",
-		 dev->name, skb->len,
-		 ((skb->data[ETH_ALEN + ETH_ALEN] << 8) |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]));
-
-	/* keep the upload from being interrupted, since we
-	 * ask the chip to start transmitting before the
-	 * whole packet has been completely uploaded.
-	 */
-
-	spin_lock_irqsave(&lp->lock, flags);
-	netif_stop_queue(dev);
-
-	/* initiate a transmit sequence */
-	iowrite16(lp->send_cmd, lp->virt_addr + TX_CMD_PORT);
-	iowrite16(skb->len, lp->virt_addr + TX_LEN_PORT);
-
-	/* Test to see if the chip has allocated memory for the packet */
-	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
-		/* Gasp!  It hasn't.  But that shouldn't happen since
-		 * we're waiting for TxOk, so return 1 and requeue this packet.
-		 */
-
-		spin_unlock_irqrestore(&lp->lock, flags);
-		cs89_dbg(0, err, "Tx buffer not free!\n");
-		return NETDEV_TX_BUSY;
-	}
-	/* Write the contents of the packet */
-	writewords(lp, TX_FRAME_PORT, skb->data, (skb->len + 1) >> 1);
-	spin_unlock_irqrestore(&lp->lock, flags);
-	dev->stats.tx_bytes += skb->len;
-	dev_consume_skb_any(skb);
-
-	/* We DO NOT call netif_wake_queue() here.
-	 * We also DO NOT call netif_start_queue().
-	 *
-	 * Either of these would cause another bottom half run through
-	 * net_send_packet() before this packet has fully gone out.
-	 * That causes us to hit the "Gasp!" above and the send is rescheduled.
-	 * it runs like a dog.  We just return and wait for the Tx completion
-	 * interrupt handler to restart the netdevice layer
-	 */
-
-	return NETDEV_TX_OK;
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-	u16 cfg;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	if (dev->flags & IFF_PROMISC)
-		lp->rx_mode = RX_ALL_ACCEPT;
-	else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
-		/* The multicast-accept list is initialized to accept-all,
-		 * and we rely on higher-level filtering for now.
-		 */
-		lp->rx_mode = RX_MULTCAST_ACCEPT;
-	else
-		lp->rx_mode = 0;
-
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
-
-	/* in promiscuous mode, we accept errored packets,
-	 * so we have to enable interrupts on them also
-	 */
-	cfg = lp->curr_rx_cfg;
-	if (lp->rx_mode == RX_ALL_ACCEPT)
-		cfg |= RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL;
-	writereg(dev, PP_RxCFG, cfg);
-	spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-static int set_mac_address(struct net_device *dev, void *p)
-{
-	int i;
-	struct sockaddr *addr = p;
-
-	if (netif_running(dev))
-		return -EBUSY;
-
-	eth_hw_addr_set(dev, addr->sa_data);
-
-	cs89_dbg(0, debug, "%s: Setting MAC address to %pM\n",
-		 dev->name, dev->dev_addr);
-
-	/* set the Ethernet address */
-	for (i = 0; i < ETH_ALEN / 2; i++)
-		writereg(dev, PP_IA + i * 2,
-			 (dev->dev_addr[i * 2] |
-			  (dev->dev_addr[i * 2 + 1] << 8)));
-
-	return 0;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void net_poll_controller(struct net_device *dev)
-{
-	disable_irq(dev->irq);
-	net_interrupt(dev->irq, dev);
-	enable_irq(dev->irq);
-}
-#endif
-
-static const struct net_device_ops net_ops = {
-	.ndo_open		= net_open,
-	.ndo_stop		= net_close,
-	.ndo_tx_timeout		= net_timeout,
-	.ndo_start_xmit		= net_send_packet,
-	.ndo_get_stats		= net_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address	= set_mac_address,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= net_poll_controller,
-#endif
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static void __init reset_chip(struct net_device *dev)
-{
-#if !defined(CONFIG_MACH_MX31ADS)
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long reset_start_time;
-
-	writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
-
-	/* wait 30 ms */
-	msleep(30);
-
-	if (lp->chip_type != CS8900) {
-		/* Hardware problem requires PNP registers to be reconfigured after a reset */
-		iowrite16(PP_CS8920_ISAINT, lp->virt_addr + ADD_PORT);
-		iowrite8(dev->irq, lp->virt_addr + DATA_PORT);
-		iowrite8(0, lp->virt_addr + DATA_PORT + 1);
-
-		iowrite16(PP_CS8920_ISAMemB, lp->virt_addr + ADD_PORT);
-		iowrite8((dev->mem_start >> 16) & 0xff,
-			 lp->virt_addr + DATA_PORT);
-		iowrite8((dev->mem_start >> 8) & 0xff,
-			 lp->virt_addr + DATA_PORT + 1);
-	}
-
-	/* Wait until the chip is reset */
-	reset_start_time = jiffies;
-	while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 &&
-	       time_before(jiffies, reset_start_time + 2))
-		;
-#endif /* !CONFIG_MACH_MX31ADS */
-}
-
-/* This is the real probe routine.
- * Linux has a history of friendly device probes on the ISA bus.
- * A good device probes avoids doing writes, and
- * verifies that the correct device exists and functions.
- * Return 0 on success.
- */
-static int __init
-cs89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int i;
-	int tmp;
-	unsigned rev_type = 0;
-	int eeprom_buff[CHKSUM_LEN];
-	u8 addr[ETH_ALEN];
-	int retval;
-
-	/* Initialize the device structure. */
-	if (!modular) {
-		memset(lp, 0, sizeof(*lp));
-		spin_lock_init(&lp->lock);
-#ifndef MODULE
-#if ALLOW_DMA
-		if (g_cs89x0_dma) {
-			lp->use_dma = 1;
-			lp->dma = g_cs89x0_dma;
-			lp->dmasize = 16;	/* Could make this an option... */
-		}
-#endif
-		lp->force = g_cs89x0_media__force;
-#endif
-	}
-
-	pr_debug("PP_addr at %p[%x]: 0x%x\n",
-		 ioaddr, ADD_PORT, ioread16(ioaddr + ADD_PORT));
-	iowrite16(PP_ChipID, ioaddr + ADD_PORT);
-
-	tmp = ioread16(ioaddr + DATA_PORT);
-	if (tmp != CHIP_EISA_ID_SIG) {
-		pr_debug("%s: incorrect signature at %p[%x]: 0x%x!="
-			 CHIP_EISA_ID_SIG_STR "\n",
-			 dev->name, ioaddr, DATA_PORT, tmp);
-		retval = -ENODEV;
-		goto out1;
-	}
-
-	lp->virt_addr = ioaddr;
-
-	/* get the chip type */
-	rev_type = readreg(dev, PRODUCT_ID_ADD);
-	lp->chip_type = rev_type & ~REVISON_BITS;
-	lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
-
-	/* Check the chip type and revision in order to set the correct
-	 * send command.  CS8920 revision C and CS8900 revision F can use
-	 * the faster send.
-	 */
-	lp->send_cmd = TX_AFTER_381;
-	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
-		lp->send_cmd = TX_NOW;
-	if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
-		lp->send_cmd = TX_NOW;
-
-	pr_info_once("%s\n", version);
-
-	pr_info("%s: cs89%c0%s rev %c found at %p ",
-		dev->name,
-		lp->chip_type == CS8900  ? '0' : '2',
-		lp->chip_type == CS8920M ? "M" : "",
-		lp->chip_revision,
-		lp->virt_addr);
-
-	reset_chip(dev);
-
-	/* Here we read the current configuration of the chip.
-	 * If there is no Extended EEPROM then the idea is to not disturb
-	 * the chip configuration, it should have been correctly setup by
-	 * automatic EEPROM read on reset. So, if the chip says it read
-	 * the EEPROM the driver will always do *something* instead of
-	 * complain that adapter_cnf is 0.
-	 */
-
-	if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
-	    (EEPROM_OK | EEPROM_PRESENT)) {
-		/* Load the MAC. */
-		for (i = 0; i < ETH_ALEN / 2; i++) {
-			unsigned int Addr;
-			Addr = readreg(dev, PP_IA + i * 2);
-			addr[i * 2] = Addr & 0xFF;
-			addr[i * 2 + 1] = Addr >> 8;
-		}
-		eth_hw_addr_set(dev, addr);
-
-		/* Load the Adapter Configuration.
-		 * Note:  Barring any more specific information from some
-		 * other source (ie EEPROM+Schematics), we would not know
-		 * how to operate a 10Base2 interface on the AUI port.
-		 * However, since we  do read the status of HCB1 and use
-		 * settings that always result in calls to control_dc_dc(dev,0)
-		 * a BNC interface should work if the enable pin
-		 * (dc/dc converter) is on HCB1.
-		 * It will be called AUI however.
-		 */
-
-		lp->adapter_cnf = 0;
-		i = readreg(dev, PP_LineCTL);
-		/* Preserve the setting of the HCB1 pin. */
-		if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL))
-			lp->adapter_cnf |= A_CNF_DC_DC_POLARITY;
-		/* Save the sqelch bit */
-		if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH)
-			lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH;
-		/* Check if the card is in 10Base-t only mode */
-		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0)
-			lp->adapter_cnf |=  A_CNF_10B_T | A_CNF_MEDIA_10B_T;
-		/* Check if the card is in AUI only mode */
-		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY)
-			lp->adapter_cnf |=  A_CNF_AUI | A_CNF_MEDIA_AUI;
-		/* Check if the card is in Auto mode. */
-		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
-			lp->adapter_cnf |=  A_CNF_AUI | A_CNF_10B_T |
-				A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
-
-		cs89_dbg(1, info, "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
-			 dev->name, i, lp->adapter_cnf);
-
-		/* IRQ. Other chips already probe, see below. */
-		if (lp->chip_type == CS8900)
-			lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
-
-		pr_cont("[Cirrus EEPROM] ");
-	}
-
-	pr_cont("\n");
-
-	/* First check to see if an EEPROM is attached. */
-
-	if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
-		pr_warn("No EEPROM, relying on command line....\n");
-	else if (get_eeprom_data(dev, START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) {
-		pr_warn("EEPROM read failed, relying on command line\n");
-	} else if (get_eeprom_cksum(START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) {
-		/* Check if the chip was able to read its own configuration starting
-		   at 0 in the EEPROM*/
-		if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
-		    (EEPROM_OK | EEPROM_PRESENT))
-			pr_warn("Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
-
-	} else {
-		/* This reads an extended EEPROM that is not documented
-		 * in the CS8900 datasheet.
-		 */
-
-		/* get transmission control word  but keep the autonegotiation bits */
-		if (!lp->auto_neg_cnf)
-			lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET / 2];
-		/* Store adapter configuration */
-		if (!lp->adapter_cnf)
-			lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET / 2];
-		/* Store ISA configuration */
-		lp->isa_config = eeprom_buff[ISA_CNF_OFFSET / 2];
-		dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET / 2] << 8;
-
-		/* eeprom_buff has 32-bit ints, so we can't just memcpy it */
-		/* store the initial memory base address */
-		for (i = 0; i < ETH_ALEN / 2; i++) {
-			addr[i * 2] = eeprom_buff[i];
-			addr[i * 2 + 1] = eeprom_buff[i] >> 8;
-		}
-		eth_hw_addr_set(dev, addr);
-		cs89_dbg(1, debug, "%s: new adapter_cnf: 0x%x\n",
-			 dev->name, lp->adapter_cnf);
-	}
-
-	/* allow them to force multiple transceivers.  If they force multiple, autosense */
-	{
-		int count = 0;
-		if (lp->force & FORCE_RJ45) {
-			lp->adapter_cnf |= A_CNF_10B_T;
-			count++;
-		}
-		if (lp->force & FORCE_AUI) {
-			lp->adapter_cnf |= A_CNF_AUI;
-			count++;
-		}
-		if (lp->force & FORCE_BNC) {
-			lp->adapter_cnf |= A_CNF_10B_2;
-			count++;
-		}
-		if (count > 1)
-			lp->adapter_cnf |= A_CNF_MEDIA_AUTO;
-		else if (lp->force & FORCE_RJ45)
-			lp->adapter_cnf |= A_CNF_MEDIA_10B_T;
-		else if (lp->force & FORCE_AUI)
-			lp->adapter_cnf |= A_CNF_MEDIA_AUI;
-		else if (lp->force & FORCE_BNC)
-			lp->adapter_cnf |= A_CNF_MEDIA_10B_2;
-	}
-
-	cs89_dbg(1, debug, "%s: after force 0x%x, adapter_cnf=0x%x\n",
-		 dev->name, lp->force, lp->adapter_cnf);
-
-	/* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
-
-	/* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
-
-	/* FIXME: we don't set the Ethernet address on the command line.  Use
-	 * ifconfig IFACE hw ether AABBCCDDEEFF
-	 */
-
-	pr_info("media %s%s%s",
-		(lp->adapter_cnf & A_CNF_10B_T) ? "RJ-45," : "",
-		(lp->adapter_cnf & A_CNF_AUI) ? "AUI," : "",
-		(lp->adapter_cnf & A_CNF_10B_2) ? "BNC," : "");
-
-	lp->irq_map = 0xffff;
-
-	/* If this is a CS8900 then no pnp soft */
-	if (lp->chip_type != CS8900 &&
-	    /* Check if the ISA IRQ has been set  */
-	    (i = readreg(dev, PP_CS8920_ISAINT) & 0xff,
-	     (i != 0 && i < CS8920_NO_INTS))) {
-		if (!dev->irq)
-			dev->irq = i;
-	} else {
-		i = lp->isa_config & INT_NO_MASK;
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-		if (lp->chip_type == CS8900) {
-			/* Translate the IRQ using the IRQ mapping table. */
-			if (i >= ARRAY_SIZE(cs8900_irq_map))
-				pr_err("invalid ISA interrupt number %d\n", i);
-			else
-				i = cs8900_irq_map[i];
-
-			lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
-		} else {
-			int irq_map_buff[IRQ_MAP_LEN/2];
-
-			if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA,
-					    IRQ_MAP_LEN / 2,
-					    irq_map_buff) >= 0) {
-				if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT)
-					lp->irq_map = ((irq_map_buff[0] >> 8) |
-						       (irq_map_buff[1] << 8));
-			}
-		}
-#endif
-		if (!dev->irq)
-			dev->irq = i;
-	}
-
-	pr_cont(" IRQ %d", dev->irq);
-
-#if ALLOW_DMA
-	if (lp->use_dma) {
-		get_dma_channel(dev);
-		pr_cont(", DMA %d", dev->dma);
-	} else
-#endif
-		pr_cont(", programmed I/O");
-
-	/* print the ethernet address. */
-	pr_cont(", MAC %pM\n", dev->dev_addr);
-
-	dev->netdev_ops	= &net_ops;
-	dev->watchdog_timeo = HZ;
-
-	cs89_dbg(0, info, "cs89x0_probe1() successful\n");
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out2;
-	return 0;
-out2:
-	iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT);
-out1:
-	return retval;
-}
-
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-/*
- * This function converts the I/O port address used by the cs89x0_probe() and
- * init_module() functions to the I/O memory address used by the
- * cs89x0_probe1() function.
- */
-static int __init
-cs89x0_ioport_probe(struct net_device *dev, unsigned long ioport, int modular)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ret;
-	void __iomem *io_mem;
-
-	if (!lp)
-		return -ENOMEM;
-
-	dev->base_addr = ioport;
-
-	if (!request_region(ioport, NETCARD_IO_EXTENT, DRV_NAME)) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	io_mem = ioport_map(ioport & ~3, NETCARD_IO_EXTENT);
-	if (!io_mem) {
-		ret = -ENOMEM;
-		goto release;
-	}
-
-	/* if they give us an odd I/O address, then do ONE write to
-	 * the address port, to get it back to address zero, where we
-	 * expect to find the EISA signature word. An IO with a base of 0x3
-	 * will skip the test for the ADD_PORT.
-	 */
-	if (ioport & 1) {
-		cs89_dbg(1, info, "%s: odd ioaddr 0x%lx\n", dev->name, ioport);
-		if ((ioport & 2) != 2) {
-			if ((ioread16(io_mem + ADD_PORT) & ADD_MASK) !=
-			    ADD_SIG) {
-				pr_err("%s: bad signature 0x%x\n",
-				       dev->name, ioread16(io_mem + ADD_PORT));
-				ret = -ENODEV;
-				goto unmap;
-			}
-		}
-	}
-
-	ret = cs89x0_probe1(dev, io_mem, modular);
-	if (!ret)
-		goto out;
-unmap:
-	ioport_unmap(io_mem);
-release:
-	release_region(ioport, NETCARD_IO_EXTENT);
-out:
-	return ret;
-}
-
-#ifndef MODULE
-/* Check for a network adaptor of this type, and return '0' iff one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
- * Return 0 on success.
- */
-
-struct net_device * __init cs89x0_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	unsigned *port;
-	int err = 0;
-	int irq;
-	int io;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-	io = dev->base_addr;
-	irq = dev->irq;
-
-	cs89_dbg(0, info, "cs89x0_probe(0x%x)\n", io);
-
-	if (io > 0x1ff)	{	/* Check a single specified location. */
-		err = cs89x0_ioport_probe(dev, io, 0);
-	} else if (io != 0) {	/* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (port = netcard_portlist; *port; port++) {
-			if (cs89x0_ioport_probe(dev, *port, 0) == 0)
-				break;
-			dev->irq = irq;
-		}
-		if (!*port)
-			err = -ENODEV;
-	}
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	pr_warn("no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
-	return ERR_PTR(err);
-}
-#else
-static struct net_device *dev_cs89x0;
-
-/* Support the 'debug' module parm even if we're compiled for non-debug to
- * avoid breaking someone's startup scripts
- */
-
-static int io;
-static int irq;
-static int debug;
-static char media[8];
-static int duplex = -1;
-
-static int use_dma;			/* These generate unused var warnings if ALLOW_DMA = 0 */
-static int dma;
-static int dmasize = 16;		/* or 64 */
-
-module_param_hw(io, int, ioport, 0);
-module_param_hw(irq, int, irq, 0);
-module_param(debug, int, 0);
-module_param_string(media, media, sizeof(media), 0);
-module_param(duplex, int, 0);
-module_param_hw(dma , int, dma, 0);
-module_param(dmasize , int, 0);
-module_param(use_dma , int, 0);
-MODULE_PARM_DESC(io, "cs89x0 I/O base address");
-MODULE_PARM_DESC(irq, "cs89x0 IRQ number");
-#if DEBUGGING
-MODULE_PARM_DESC(debug, "cs89x0 debug level (0-6)");
-#else
-MODULE_PARM_DESC(debug, "(ignored)");
-#endif
-MODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui)");
-/* No other value than -1 for duplex seems to be currently interpreted */
-MODULE_PARM_DESC(duplex, "(ignored)");
-#if ALLOW_DMA
-MODULE_PARM_DESC(dma , "cs89x0 ISA DMA channel; ignored if use_dma=0");
-MODULE_PARM_DESC(dmasize , "cs89x0 DMA size in kB (16,64); ignored if use_dma=0");
-MODULE_PARM_DESC(use_dma , "cs89x0 using DMA (0-1)");
-#else
-MODULE_PARM_DESC(dma , "(ignored)");
-MODULE_PARM_DESC(dmasize , "(ignored)");
-MODULE_PARM_DESC(use_dma , "(ignored)");
-#endif
-
-MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton");
-MODULE_LICENSE("GPL");
-
-/*
- * media=t             - specify media type
- * or media=2
- * or media=aui
- * or medai=auto
- * duplex=0            - specify forced half/full/autonegotiate duplex
- * debug=#             - debug level
- *
- * Default Chip Configuration:
- * DMA Burst = enabled
- * IOCHRDY Enabled = enabled
- * UseSA = enabled
- * CS8900 defaults to half-duplex if not specified on command-line
- * CS8920 defaults to autoneg if not specified on command-line
- * Use reset defaults for other config parameters
- *
- * Assumptions:
- * media type specified is supported (circuitry is present)
- * if memory address is > 1MB, then required mem decode hw is present
- * if 10B-2, then agent other than driver will enable DC/DC converter
- * (hw or software util)
- */
-
-static int __init cs89x0_isa_init_module(void)
-{
-	struct net_device *dev;
-	struct net_local *lp;
-	int ret = 0;
-
-#if DEBUGGING
-	net_debug = debug;
-#else
-	debug = 0;
-#endif
-	dev = alloc_etherdev(sizeof(struct net_local));
-	if (!dev)
-		return -ENOMEM;
-
-	dev->irq = irq;
-	dev->base_addr = io;
-	lp = netdev_priv(dev);
-
-#if ALLOW_DMA
-	if (use_dma) {
-		lp->use_dma = use_dma;
-		lp->dma = dma;
-		lp->dmasize = dmasize;
-	}
-#endif
-
-	spin_lock_init(&lp->lock);
-
-	/* boy, they'd better get these right */
-	if (!strcmp(media, "rj45"))
-		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
-	else if (!strcmp(media, "aui"))
-		lp->adapter_cnf = A_CNF_MEDIA_AUI   | A_CNF_AUI;
-	else if (!strcmp(media, "bnc"))
-		lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2;
-	else
-		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
-
-	if (duplex == -1)
-		lp->auto_neg_cnf = AUTO_NEG_ENABLE;
-
-	if (io == 0) {
-		pr_err("Module autoprobing not allowed\n");
-		pr_err("Append io=0xNNN\n");
-		ret = -EPERM;
-		goto out;
-	} else if (io <= 0x1ff) {
-		ret = -ENXIO;
-		goto out;
-	}
-
-#if ALLOW_DMA
-	if (use_dma && dmasize != 16 && dmasize != 64) {
-		pr_err("dma size must be either 16K or 64K, not %dK\n",
-		       dmasize);
-		ret = -EPERM;
-		goto out;
-	}
-#endif
-	ret = cs89x0_ioport_probe(dev, io, 1);
-	if (ret)
-		goto out;
-
-	dev_cs89x0 = dev;
-	return 0;
-out:
-	free_netdev(dev);
-	return ret;
-}
-module_init(cs89x0_isa_init_module);
-
-static void __exit cs89x0_isa_cleanup_module(void)
-{
-	struct net_local *lp = netdev_priv(dev_cs89x0);
-
-	unregister_netdev(dev_cs89x0);
-	iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT);
-	ioport_unmap(lp->virt_addr);
-	release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
-	free_netdev(dev_cs89x0);
-}
-module_exit(cs89x0_isa_cleanup_module);
-#endif /* MODULE */
-#endif /* CONFIG_CS89x0_ISA */
-
-#if IS_ENABLED(CONFIG_CS89x0_PLATFORM)
-static int __init cs89x0_platform_probe(struct platform_device *pdev)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	void __iomem *virt_addr;
-	int err;
-
-	if (!dev)
-		return -ENOMEM;
-
-	dev->irq = platform_get_irq(pdev, 0);
-	if (dev->irq < 0) {
-		err = dev->irq;
-		goto free;
-	}
-
-	virt_addr = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(virt_addr)) {
-		err = PTR_ERR(virt_addr);
-		goto free;
-	}
-
-	err = cs89x0_probe1(dev, virt_addr, 0);
-	if (err) {
-		dev_warn(&dev->dev, "no cs8900 or cs8920 detected\n");
-		goto free;
-	}
-
-	platform_set_drvdata(pdev, dev);
-	return 0;
-
-free:
-	free_netdev(dev);
-	return err;
-}
-
-static void cs89x0_platform_remove(struct platform_device *pdev)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-
-	/* This platform_get_resource() call will not return NULL, because
-	 * the same call in cs89x0_platform_probe() has returned a non NULL
-	 * value.
-	 */
-	unregister_netdev(dev);
-	free_netdev(dev);
-}
-
-static const struct of_device_id __maybe_unused cs89x0_match[] = {
-	{ .compatible = "cirrus,cs8900", },
-	{ .compatible = "cirrus,cs8920", },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, cs89x0_match);
-
-static struct platform_driver cs89x0_driver = {
-	.driver	= {
-		.name		= DRV_NAME,
-		.of_match_table	= of_match_ptr(cs89x0_match),
-	},
-	.remove = cs89x0_platform_remove,
-};
-
-module_platform_driver_probe(cs89x0_driver, cs89x0_platform_probe);
-
-#endif /* CONFIG_CS89x0_PLATFORM */
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 network driver");
-MODULE_AUTHOR("Russell Nelson <nelson@crynwr.com>");

-- 
2.53.0


^ permalink raw reply related

* [PATCH] dt-bindings: Fix phandle-array constraints, again
From: Rob Herring (Arm) @ 2026-04-21 19:55 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson, Stephan Gerhold, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Johannes Berg, Jeff Johnson, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Andersson,
	Mathieu Poirier, Sylwester Nawrocki, Mark Brown, Maxime Coquelin,
	Greg Kroah-Hartman, Yang Xiwen, Alex Elder, Chaitanya Chundru,
	Sibi Sankar, Rao Mandadapu, Patrice Chotard, Xu Yang, Peng Fan,
	Thomas Zimmermann
  Cc: devicetree, linux-kernel, linux-mmc, linux-arm-msm, netdev,
	linux-wireless, ath10k, ath11k, linux-pci, linux-remoteproc,
	linux-sound, linux-spi, linux-usb

The unfortunately named 'phandle-array' property type is really a matrix
with phandle and fixed arg cells entries. A matrix property should have 2
levels of items constraints.

Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
Can someone from QCom provide some descriptions for 'qcom,smem-states'
properties.
---
 .../display/rockchip/rockchip,rk3399-cdn-dp.yaml         | 2 ++
 .../bindings/mmc/hisilicon,hi3798cv200-dw-mshc.yaml      | 7 ++++---
 Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml | 6 ++++++
 Documentation/devicetree/bindings/net/qcom,ipa.yaml      | 6 ++++++
 .../devicetree/bindings/net/wireless/qcom,ath10k.yaml    | 5 ++++-
 .../devicetree/bindings/net/wireless/qcom,ath11k.yaml    | 5 ++++-
 .../bindings/net/wireless/qcom,ipq5332-wifi.yaml         | 9 +++++++++
 .../devicetree/bindings/pci/toshiba,tc9563.yaml          | 5 +++--
 .../bindings/remoteproc/qcom,msm8916-mss-pil.yaml        | 3 +++
 .../bindings/remoteproc/qcom,msm8996-mss-pil.yaml        | 3 +++
 .../devicetree/bindings/remoteproc/qcom,pas-common.yaml  | 4 ++++
 .../bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml        | 4 ++++
 .../bindings/remoteproc/qcom,sc7180-mss-pil.yaml         | 3 +++
 .../bindings/remoteproc/qcom,sc7280-adsp-pil.yaml        | 3 +++
 .../bindings/remoteproc/qcom,sc7280-mss-pil.yaml         | 3 +++
 .../bindings/remoteproc/qcom,sc7280-wpss-pil.yaml        | 3 +++
 .../bindings/remoteproc/qcom,sdm845-adsp-pil.yaml        | 3 +++
 .../devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml   | 3 +++
 Documentation/devicetree/bindings/sound/samsung,tm2.yaml | 2 ++
 .../devicetree/bindings/spi/st,stm32mp25-ospi.yaml       | 5 +++--
 .../devicetree/bindings/usb/chipidea,usb2-common.yaml    | 2 ++
 Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml  | 7 ++++---
 22 files changed, 81 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3399-cdn-dp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3399-cdn-dp.yaml
index 1a33128e77f5..195f665970bf 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3399-cdn-dp.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3399-cdn-dp.yaml
@@ -41,7 +41,9 @@ properties:
     minItems: 1
     items:
       - description: Extcon device providing the cable state for DP PHY device 0
+        maxItems: 1
       - description: Extcon device providing the cable state for DP PHY device 1
+        maxItems: 1
     description:
       List of phandle to the extcon device providing the cable state for the DP PHY.
 
diff --git a/Documentation/devicetree/bindings/mmc/hisilicon,hi3798cv200-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/hisilicon,hi3798cv200-dw-mshc.yaml
index 41c9b22523e7..e447579e0f22 100644
--- a/Documentation/devicetree/bindings/mmc/hisilicon,hi3798cv200-dw-mshc.yaml
+++ b/Documentation/devicetree/bindings/mmc/hisilicon,hi3798cv200-dw-mshc.yaml
@@ -39,10 +39,11 @@ properties:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: |
       DWMMC core on Hi3798MV2x SoCs has a delay-locked-loop(DLL) attached to card data input path.
-      It is integrated into CRG core on the SoC and has to be controlled during tuning.
+      It is integrated into CRG core on the SoC and has to be controlled during tuning
     items:
-      - description: A phandle pointed to the CRG syscon node
-      - description: Sample DLL register offset in CRG address space
+      - items:
+          - description: A phandle pointed to the CRG syscon node
+          - description: Sample DLL register offset in CRG address space
 
 required:
   - compatible
diff --git a/Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml b/Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml
index b30544410d09..e47e1e09300a 100644
--- a/Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml
+++ b/Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml
@@ -42,7 +42,13 @@ properties:
     description: State bits used by the AP to signal the modem.
     items:
       - description: Power control
+        items:
+          - description: Phandle to ???
+          - description: ???
       - description: Power control acknowledgment
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: Names for the state bits used by the AP to signal the modem.
diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml
index c7f5f2ef7452..c53f63068b77 100644
--- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml
+++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml
@@ -123,7 +123,13 @@ properties:
     description: State bits used in by the AP to signal the modem.
     items:
       - description: Whether the "ipa-clock-enabled" state bit is valid
+        items:
+          - description: Phandle to ???
+          - description: ???
       - description: Whether the IPA clock is enabled (if valid)
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
index f2440d39b7eb..5c580bc7df08 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
@@ -158,7 +158,10 @@ properties:
     description: State bits used by the AP to signal the WLAN Q6.
     items:
       - description: Signal bits used to enable/disable low power mode
-                     on WCN in the case of WoW (Wake on Wireless).
+          on WCN in the case of WoW (Wake on Wireless).
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output.
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
index 0cc1dbf2beef..326c1a94a1a0 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
@@ -80,7 +80,10 @@ properties:
     description: State bits used by the AP to signal the WLAN Q6.
     items:
       - description: Signal bits used to enable/disable low power mode
-                     on WCN6750 in the case of WoW (Wake on Wireless).
+          on WCN6750 in the case of WoW (Wake on Wireless).
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output.
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml
index 363a0ecb6ad9..ea8df6890478 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml
@@ -167,8 +167,17 @@ properties:
     description: States used by the AP to signal the remote processor
     items:
       - description: Shutdown WCSS pd
+        items:
+          - description: Phandle to ???
+          - description: ???
       - description: Stop WCSS pd
+        items:
+          - description: Phandle to ???
+          - description: ???
       - description: Spawn WCSS pd
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description:
diff --git a/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml b/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml
index fae466064780..b3ad05d90201 100644
--- a/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml
+++ b/Documentation/devicetree/bindings/pci/toshiba,tc9563.yaml
@@ -49,8 +49,9 @@ properties:
       A phandle to the parent I2C node and the slave address of the device
       used to configure tc9563 to change FTS, tx amplitude etc.
     items:
-      - description: Phandle to the I2C controller node
-      - description: I2C slave address
+      - items:
+          - description: Phandle to the I2C controller node
+          - description: I2C slave address
 
 patternProperties:
   "^pcie@[1-3],0$":
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,msm8916-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,msm8916-mss-pil.yaml
index c179b560572b..3c614cb7ce88 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,msm8916-mss-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,msm8916-mss-pil.yaml
@@ -104,6 +104,9 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: Names of the states used by the AP to signal the Hexagon core
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml
index 4d2055f283ac..d459296df0c2 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml
@@ -101,6 +101,9 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: Names of the states used by the AP to signal the Hexagon core
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
index 68c17bf18987..6260f77b7e4b 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml
@@ -60,6 +60,10 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
+
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml
index bca59394aef4..3e410cbd45cf 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml
@@ -92,6 +92,10 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
+
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-mss-pil.yaml
index b1402bef0ebe..f0bee69baf0d 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-mss-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-mss-pil.yaml
@@ -134,6 +134,9 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-adsp-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-adsp-pil.yaml
index 94ca7a0cc203..3ea83207ae32 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-adsp-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-adsp-pil.yaml
@@ -91,6 +91,9 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-mss-pil.yaml
index 005cb21732af..1f1d73610510 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-mss-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-mss-pil.yaml
@@ -148,6 +148,9 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml
index f4118b2da5f6..0111384d55d5 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml
@@ -104,6 +104,9 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml
index a3c74871457f..b9325967b8a3 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml
@@ -92,6 +92,9 @@ properties:
     description: States used by the AP to signal the Hexagon core
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml
index 117fb4d0c4ad..e009f8ed9e8c 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml
@@ -84,6 +84,9 @@ properties:
       States used by the AP to signal the WCNSS core that it should shutdown
     items:
       - description: Stop the modem
+        items:
+          - description: Phandle to ???
+          - description: ???
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output
diff --git a/Documentation/devicetree/bindings/sound/samsung,tm2.yaml b/Documentation/devicetree/bindings/sound/samsung,tm2.yaml
index 67586ba3e0a0..c752e4874e7f 100644
--- a/Documentation/devicetree/bindings/sound/samsung,tm2.yaml
+++ b/Documentation/devicetree/bindings/sound/samsung,tm2.yaml
@@ -46,7 +46,9 @@ properties:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     items:
       - description: Phandle to I2S0.
+        maxItems: 1
       - description: Phandle to I2S1.
+        maxItems: 1
 
   mic-bias-gpios:
     description: GPIO pin that enables the Main Mic bias regulator.
diff --git a/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
index 272bc308726b..b6be47f67fcb 100644
--- a/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
+++ b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
@@ -49,8 +49,9 @@ properties:
     description: configure OCTOSPI delay block.
     $ref: /schemas/types.yaml#/definitions/phandle-array
     items:
-      - description: phandle to syscfg
-      - description: register offset within syscfg
+      - items:
+          - description: phandle to syscfg
+          - description: register offset within syscfg
 
   access-controllers:
     description: phandle to the rifsc device to check access right
diff --git a/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml b/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml
index 10020af15afc..e6a5e79df348 100644
--- a/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml
+++ b/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml
@@ -97,7 +97,9 @@ properties:
     minItems: 1
     items:
       - description: vbus extcon
+        maxItems: 1
       - description: id extcon
+        maxItems: 1
 
   phy-clkgate-delay-us:
     description:
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
index 691d6cf02c27..fec04702f530 100644
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
+++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
@@ -61,9 +61,10 @@ properties:
       offset, and phy index
     $ref: /schemas/types.yaml#/definitions/phandle-array
     items:
-      - description: phandle to TCSR node
-      - description: register offset
-      - description: phy index
+      - items:
+          - description: phandle to TCSR node
+          - description: register offset
+          - description: phy index
 
   nvidia,phy:
     description: phandle of usb phy that connects to the port. Use "phys" instead.
-- 
2.53.0


^ permalink raw reply related

* [PATCH net 10/18] drivers: net: smsc: smc91c92: Remove this driver
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

The smc91c92 was written by David A Hinds in 1999. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/smsc/Kconfig       |   12 -
 drivers/net/ethernet/smsc/Makefile      |    1 -
 drivers/net/ethernet/smsc/smc91c92_cs.c | 2059 -------------------------------
 3 files changed, 2072 deletions(-)

diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index d25bbcc98854..66bca803b19c 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -37,18 +37,6 @@ config SMC91X
 	  The module will be called smc91x.  If you want to compile it as a
 	  module, say M here and read <file:Documentation/kbuild/modules.rst>.
 
-config PCMCIA_SMC91C92
-	tristate "SMC 91Cxx PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	select CRC32
-	select MII
-	help
-	  Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
-	  (PC-card) Ethernet or Fast Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called smc91c92_cs.  If unsure, say N.
-
 config EPIC100
 	tristate "SMC EtherPower II"
 	depends on PCI
diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc/Makefile
index afea0b94c2a4..ab6f03f7ba17 100644
--- a/drivers/net/ethernet/smsc/Makefile
+++ b/drivers/net/ethernet/smsc/Makefile
@@ -4,7 +4,6 @@
 #
 
 obj-$(CONFIG_SMC91X) += smc91x.o
-obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o
 obj-$(CONFIG_EPIC100) += epic100.o
 obj-$(CONFIG_SMSC9420) += smsc9420.o
 obj-$(CONFIG_SMSC911X) += smsc911x.o
diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c
deleted file mode 100644
index cc0c75694351..000000000000
--- a/drivers/net/ethernet/smsc/smc91c92_cs.c
+++ /dev/null
@@ -1,2059 +0,0 @@
-/*======================================================================
-
-    A PCMCIA ethernet driver for SMC91c92-based cards.
-
-    This driver supports Megahertz PCMCIA ethernet cards; and
-    Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem
-    multifunction cards.
-
-    Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
-
-    smc91c92_cs.c 1.122 2002/10/25 06:26:39
-
-    This driver contains code written by Donald Becker
-    (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
-    David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
-    (erik@vt.edu).  Donald wrote the SMC 91c92 code using parts of
-    Erik's SMC 91c94 driver.  Rowan wrote a similar driver, and I've
-    incorporated some parts of his driver here.  I (Dave) wrote most
-    of the PCMCIA glue code, and the Ositech support code.  Kelly
-    Stephens (kstephen@holli.com) added support for the Motorola
-    Mariner, with help from Allen Brost.
-
-    This software may be used and distributed according to the terms of
-    the GNU General Public License, incorporated herein by reference.
-
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/jiffies.h>
-#include <linux/firmware.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/ss.h>
-
-#include <asm/io.h>
-#include <linux/uaccess.h>
-
-/*====================================================================*/
-
-static const char *if_names[] = { "auto", "10baseT", "10base2"};
-
-/* Firmware name */
-#define FIRMWARE_NAME		"ositech/Xilinx7OD.bin"
-
-/* Module parameters */
-
-MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FIRMWARE_NAME);
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/*
-  Transceiver/media type.
-   0 = auto
-   1 = 10baseT (and autoselect if #define AUTOSELECT),
-   2 = AUI/10base2,
-*/
-INT_MODULE_PARM(if_port, 0);
-
-
-#define DRV_NAME	"smc91c92_cs"
-#define DRV_VERSION	"1.123"
-
-/*====================================================================*/
-
-/* Operational parameter that usually are not changed. */
-
-/* Time in jiffies before concluding Tx hung */
-#define TX_TIMEOUT		((400*HZ)/1000)
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-#define INTR_WORK		4
-
-/* Times to check the check the chip before concluding that it doesn't
-   currently have room for another Tx packet. */
-#define MEMORY_WAIT_TIME       	8
-
-struct smc_private {
-	struct pcmcia_device	*p_dev;
-    spinlock_t			lock;
-    u_short			manfid;
-    u_short			cardid;
-
-    struct sk_buff		*saved_skb;
-    int				packets_waiting;
-    void			__iomem *base;
-    u_short			cfg;
-    struct timer_list		media;
-    int				watchdog, tx_err;
-    u_short			media_status;
-    u_short			fast_poll;
-    u_short			link_status;
-    struct mii_if_info		mii_if;
-    int				duplex;
-    int				rx_ovrn;
-    unsigned long		last_rx;
-};
-
-/* Special definitions for Megahertz multifunction cards */
-#define MEGAHERTZ_ISR		0x0380
-
-/* Special function registers for Motorola Mariner */
-#define MOT_LAN			0x0000
-#define MOT_UART		0x0020
-#define MOT_EEPROM		0x20
-
-#define MOT_NORMAL \
-(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)
-
-/* Special function registers for Ositech cards */
-#define OSITECH_AUI_CTL		0x0c
-#define OSITECH_PWRDOWN		0x0d
-#define OSITECH_RESET		0x0e
-#define OSITECH_ISR		0x0f
-#define OSITECH_AUI_PWR		0x0c
-#define OSITECH_RESET_ISR	0x0e
-
-#define OSI_AUI_PWR		0x40
-#define OSI_LAN_PWRDOWN		0x02
-#define OSI_MODEM_PWRDOWN	0x01
-#define OSI_LAN_RESET		0x02
-#define OSI_MODEM_RESET		0x01
-
-/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
-#define	BANK_SELECT		14		/* Window select register. */
-#define SMC_SELECT_BANK(x)  { outw(x, ioaddr + BANK_SELECT); }
-
-/* Bank 0 registers. */
-#define	TCR 		0	/* transmit control register */
-#define	 TCR_CLEAR	0	/* do NOTHING */
-#define  TCR_ENABLE	0x0001	/* if this is 1, we can transmit */
-#define	 TCR_PAD_EN	0x0080	/* pads short packets to 64 bytes */
-#define  TCR_MONCSN	0x0400  /* Monitor Carrier. */
-#define  TCR_FDUPLX	0x0800  /* Full duplex mode. */
-#define	 TCR_NORMAL TCR_ENABLE | TCR_PAD_EN
-
-#define EPH		2	/* Ethernet Protocol Handler report. */
-#define  EPH_TX_SUC	0x0001
-#define  EPH_SNGLCOL	0x0002
-#define  EPH_MULCOL	0x0004
-#define  EPH_LTX_MULT	0x0008
-#define  EPH_16COL	0x0010
-#define  EPH_SQET	0x0020
-#define  EPH_LTX_BRD	0x0040
-#define  EPH_TX_DEFR	0x0080
-#define  EPH_LAT_COL	0x0200
-#define  EPH_LOST_CAR	0x0400
-#define  EPH_EXC_DEF	0x0800
-#define  EPH_CTR_ROL	0x1000
-#define  EPH_RX_OVRN	0x2000
-#define  EPH_LINK_OK	0x4000
-#define  EPH_TX_UNRN	0x8000
-#define MEMINFO		8	/* Memory Information Register */
-#define MEMCFG		10	/* Memory Configuration Register */
-
-/* Bank 1 registers. */
-#define CONFIG			0
-#define  CFG_MII_SELECT		0x8000	/* 91C100 only */
-#define  CFG_NO_WAIT		0x1000
-#define  CFG_FULL_STEP		0x0400
-#define  CFG_SET_SQLCH		0x0200
-#define  CFG_AUI_SELECT	 	0x0100
-#define  CFG_16BIT		0x0080
-#define  CFG_DIS_LINK		0x0040
-#define  CFG_STATIC		0x0030
-#define  CFG_IRQ_SEL_1		0x0004
-#define  CFG_IRQ_SEL_0		0x0002
-#define BASE_ADDR		2
-#define	ADDR0			4
-#define	GENERAL			10
-#define	CONTROL			12
-#define  CTL_STORE		0x0001
-#define  CTL_RELOAD		0x0002
-#define  CTL_EE_SELECT		0x0004
-#define  CTL_TE_ENABLE		0x0020
-#define  CTL_CR_ENABLE		0x0040
-#define  CTL_LE_ENABLE		0x0080
-#define  CTL_AUTO_RELEASE	0x0800
-#define	 CTL_POWERDOWN		0x2000
-
-/* Bank 2 registers. */
-#define MMU_CMD		0
-#define	 MC_ALLOC	0x20  	/* or with number of 256 byte packets */
-#define	 MC_RESET	0x40
-#define  MC_RELEASE  	0x80  	/* remove and release the current rx packet */
-#define  MC_FREEPKT  	0xA0  	/* Release packet in PNR register */
-#define  MC_ENQUEUE	0xC0 	/* Enqueue the packet for transmit */
-#define	PNR_ARR		2
-#define FIFO_PORTS	4
-#define  FP_RXEMPTY	0x8000
-#define	POINTER		6
-#define  PTR_AUTO_INC	0x0040
-#define  PTR_READ	0x2000
-#define	 PTR_AUTOINC 	0x4000
-#define	 PTR_RCV	0x8000
-#define	DATA_1		8
-#define	INTERRUPT	12
-#define  IM_RCV_INT		0x1
-#define	 IM_TX_INT		0x2
-#define	 IM_TX_EMPTY_INT	0x4
-#define	 IM_ALLOC_INT		0x8
-#define	 IM_RX_OVRN_INT		0x10
-#define	 IM_EPH_INT		0x20
-
-#define	RCR		4
-enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
-	     RxEnable = 0x0100, RxStripCRC = 0x0200};
-#define  RCR_SOFTRESET	0x8000 	/* resets the chip */
-#define	 RCR_STRIP_CRC	0x200	/* strips CRC */
-#define  RCR_ENABLE	0x100	/* IFF this is set, we can receive packets */
-#define  RCR_ALMUL	0x4 	/* receive all multicast packets */
-#define	 RCR_PROMISC	0x2	/* enable promiscuous mode */
-
-/* the normal settings for the RCR register : */
-#define	 RCR_NORMAL	(RCR_STRIP_CRC | RCR_ENABLE)
-#define  RCR_CLEAR	0x0		/* set it to a base state */
-#define	COUNTER		6
-
-/* BANK 3 -- not the same values as in smc9194! */
-#define	MULTICAST0	0
-#define	MULTICAST2	2
-#define	MULTICAST4	4
-#define	MULTICAST6	6
-#define MGMT    	8
-#define REVISION	0x0a
-
-/* Transmit status bits. */
-#define TS_SUCCESS 0x0001
-#define TS_16COL   0x0010
-#define TS_LATCOL  0x0200
-#define TS_LOSTCAR 0x0400
-
-/* Receive status bits. */
-#define RS_ALGNERR	0x8000
-#define RS_BADCRC	0x2000
-#define RS_ODDFRAME	0x1000
-#define RS_TOOLONG	0x0800
-#define RS_TOOSHORT	0x0400
-#define RS_MULTICAST	0x0001
-#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
-
-#define set_bits(v, p) outw(inw(p)|(v), (p))
-#define mask_bits(v, p) outw(inw(p)&(v), (p))
-
-/*====================================================================*/
-
-static void smc91c92_detach(struct pcmcia_device *p_dev);
-static int smc91c92_config(struct pcmcia_device *link);
-static void smc91c92_release(struct pcmcia_device *link);
-
-static int smc_open(struct net_device *dev);
-static int smc_close(struct net_device *dev);
-static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
-					struct net_device *dev);
-static irqreturn_t smc_interrupt(int irq, void *dev_id);
-static void smc_rx(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static int s9k_config(struct net_device *dev, struct ifmap *map);
-static void smc_set_xcvr(struct net_device *dev, int if_port);
-static void smc_reset(struct net_device *dev);
-static void media_check(struct timer_list *t);
-static void mdio_sync(unsigned int addr);
-static int mdio_read(struct net_device *dev, int phy_id, int loc);
-static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
-static int smc_link_ok(struct net_device *dev);
-static const struct ethtool_ops ethtool_ops;
-
-static const struct net_device_ops smc_netdev_ops = {
-	.ndo_open		= smc_open,
-	.ndo_stop		= smc_close,
-	.ndo_start_xmit		= smc_start_xmit,
-	.ndo_tx_timeout 	= smc_tx_timeout,
-	.ndo_set_config 	= s9k_config,
-	.ndo_set_rx_mode	= set_rx_mode,
-	.ndo_eth_ioctl		= smc_ioctl,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int smc91c92_probe(struct pcmcia_device *link)
-{
-    struct smc_private *smc;
-    struct net_device *dev;
-
-    dev_dbg(&link->dev, "smc91c92_attach()\n");
-
-    /* Create new ethernet device */
-    dev = alloc_etherdev(sizeof(struct smc_private));
-    if (!dev)
-	return -ENOMEM;
-    smc = netdev_priv(dev);
-    smc->p_dev = link;
-    link->priv = dev;
-
-    spin_lock_init(&smc->lock);
-
-    /* The SMC91c92-specific entries in the device structure. */
-    dev->netdev_ops = &smc_netdev_ops;
-    dev->ethtool_ops = &ethtool_ops;
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    smc->mii_if.dev = dev;
-    smc->mii_if.mdio_read = mdio_read;
-    smc->mii_if.mdio_write = mdio_write;
-    smc->mii_if.phy_id_mask = 0x1f;
-    smc->mii_if.reg_num_mask = 0x1f;
-
-    return smc91c92_config(link);
-} /* smc91c92_attach */
-
-static void smc91c92_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    dev_dbg(&link->dev, "smc91c92_detach\n");
-
-    unregister_netdev(dev);
-
-    smc91c92_release(link);
-
-    free_netdev(dev);
-} /* smc91c92_detach */
-
-/*====================================================================*/
-
-static int cvt_ascii_address(struct net_device *dev, char *s)
-{
-    u8 mac[ETH_ALEN];
-    int i, j, da, c;
-
-    if (strlen(s) != 12)
-	return -1;
-    for (i = 0; i < 6; i++) {
-	da = 0;
-	for (j = 0; j < 2; j++) {
-	    c = *s++;
-	    da <<= 4;
-	    da += ((c >= '0') && (c <= '9')) ?
-		(c - '0') : ((c & 0x0f) + 9);
-	}
-	mac[i] = da;
-    }
-    eth_hw_addr_set(dev, mac);
-    return 0;
-}
-
-/*====================================================================
-
-    Configuration stuff for Megahertz cards
-
-    mhz_3288_power() is used to power up a 3288's ethernet chip.
-    mhz_mfc_config() handles socket setup for multifunction (1144
-    and 3288) cards.  mhz_setup() gets a card's hardware ethernet
-    address.
-
-======================================================================*/
-
-static int mhz_3288_power(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    u_char tmp;
-
-    /* Read the ISR twice... */
-    readb(smc->base+MEGAHERTZ_ISR);
-    udelay(5);
-    readb(smc->base+MEGAHERTZ_ISR);
-
-    /* Pause 200ms... */
-    mdelay(200);
-
-    /* Now read and write the COR... */
-    tmp = readb(smc->base + link->config_base + CISREG_COR);
-    udelay(5);
-    writeb(tmp, smc->base + link->config_base + CISREG_COR);
-
-    return 0;
-}
-
-static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-	int k;
-	p_dev->io_lines = 16;
-	p_dev->resource[1]->start = p_dev->resource[0]->start;
-	p_dev->resource[1]->end = 8;
-	p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	p_dev->resource[0]->end = 16;
-	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-	for (k = 0; k < 0x400; k += 0x10) {
-		if (k & 0x80)
-			continue;
-		p_dev->resource[0]->start = k ^ 0x300;
-		if (!pcmcia_request_io(p_dev))
-			return 0;
-	}
-	return -ENODEV;
-}
-
-static int mhz_mfc_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int offset;
-    int i;
-
-    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ |
-	    CONF_AUTO_SET_IO;
-
-    /* The Megahertz combo cards have modem-like CIS entries, so
-       we have to explicitly try a bunch of port combinations. */
-    if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
-	    return -ENODEV;
-
-    dev->base_addr = link->resource[0]->start;
-
-    /* Allocate a memory window, for accessing the ISR */
-    link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[2]->start = link->resource[2]->end = 0;
-    i = pcmcia_request_window(link, link->resource[2], 0);
-    if (i != 0)
-	    return -ENODEV;
-
-    smc->base = ioremap(link->resource[2]->start,
-		    resource_size(link->resource[2]));
-    offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0;
-    i = pcmcia_map_mem_page(link, link->resource[2], offset);
-    if ((i == 0) &&
-	(smc->manfid == MANFID_MEGAHERTZ) &&
-	(smc->cardid == PRODID_MEGAHERTZ_EM3288))
-	    mhz_3288_power(link);
-
-    return 0;
-}
-
-static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
-			      tuple_t *tuple,
-			      void *priv)
-{
-	struct net_device *dev = priv;
-	cisparse_t parse;
-	u8 *buf;
-
-	if (pcmcia_parse_tuple(tuple, &parse))
-		return -EINVAL;
-
-	buf = parse.version_1.str + parse.version_1.ofs[3];
-
-	if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0))
-		return 0;
-
-	return -EINVAL;
-};
-
-static int mhz_setup(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    size_t len;
-    u8 *buf;
-    int rc;
-
-    /* Read the station address from the CIS.  It is stored as the last
-       (fourth) string in the Version 1 Version/ID tuple. */
-    if ((link->prod_id[3]) &&
-	(cvt_ascii_address(dev, link->prod_id[3]) == 0))
-	    return 0;
-
-    /* Workarounds for broken cards start here. */
-    /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
-    if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
-	    return 0;
-
-    /* Another possibility: for the EM3288, in a special tuple */
-    rc = -1;
-    len = pcmcia_get_tuple(link, 0x81, &buf);
-    if (buf && len >= 13) {
-	    buf[12] = '\0';
-	    if (cvt_ascii_address(dev, buf) == 0)
-		    rc = 0;
-    }
-    kfree(buf);
-
-    return rc;
-};
-
-/*======================================================================
-
-    Configuration stuff for the Motorola Mariner
-
-    mot_config() writes directly to the Mariner configuration
-    registers because the CIS is just bogus.
-
-======================================================================*/
-
-static void mot_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    unsigned int iouart = link->resource[1]->start;
-
-    /* Set UART base address and force map with COR bit 1 */
-    writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
-    writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
-    writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);
-
-    /* Set SMC base address and force map with COR bit 1 */
-    writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
-    writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
-    writeb(MOT_NORMAL,           smc->base + MOT_LAN + CISREG_COR);
-
-    /* Wait for things to settle down */
-    mdelay(100);
-}
-
-static int mot_setup(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    int i, wait, loop;
-    u8 mac[ETH_ALEN];
-    u_int addr;
-
-    /* Read Ethernet address from Serial EEPROM */
-
-    for (i = 0; i < 3; i++) {
-	SMC_SELECT_BANK(2);
-	outw(MOT_EEPROM + i, ioaddr + POINTER);
-	SMC_SELECT_BANK(1);
-	outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
-
-	for (loop = wait = 0; loop < 200; loop++) {
-	    udelay(10);
-	    wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
-	    if (wait == 0) break;
-	}
-	
-	if (wait)
-	    return -1;
-	
-	addr = inw(ioaddr + GENERAL);
-	mac[2*i]   = addr & 0xff;
-	mac[2*i+1] = (addr >> 8) & 0xff;
-    }
-    eth_hw_addr_set(dev, mac);
-
-    return 0;
-}
-
-/*====================================================================*/
-
-static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
-	p_dev->resource[0]->end = 16;
-	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
-	return pcmcia_request_io(p_dev);
-}
-
-static int smc_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    int i;
-
-    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
-    i = pcmcia_loop_config(link, smc_configcheck, NULL);
-    if (!i)
-	    dev->base_addr = link->resource[0]->start;
-
-    return i;
-}
-
-
-static int smc_setup(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    /* Check for a LAN function extension tuple */
-    if (!pcmcia_get_mac_from_cis(link, dev))
-	    return 0;
-
-    /* Try the third string in the Version 1 Version/ID tuple. */
-    if (link->prod_id[2]) {
-	    if (cvt_ascii_address(dev, link->prod_id[2]) == 0)
-		    return 0;
-    }
-    return -1;
-}
-
-/*====================================================================*/
-
-static int osi_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
-    int i, j;
-
-    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ;
-    link->resource[0]->end = 64;
-    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    link->resource[1]->end = 8;
-
-    /* Enable Hard Decode, LAN, Modem */
-    link->io_lines = 16;
-    link->config_index = 0x23;
-
-    for (i = j = 0; j < 4; j++) {
-	link->resource[1]->start = com[j];
-	i = pcmcia_request_io(link);
-	if (i == 0)
-		break;
-    }
-    if (i != 0) {
-	/* Fallback: turn off hard decode */
-	link->config_index = 0x03;
-	link->resource[1]->end = 0;
-	i = pcmcia_request_io(link);
-    }
-    dev->base_addr = link->resource[0]->start + 0x10;
-    return i;
-}
-
-static int osi_load_firmware(struct pcmcia_device *link)
-{
-	const struct firmware *fw;
-	int i, err;
-
-	err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
-	if (err) {
-		pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
-		return err;
-	}
-
-	/* Download the Seven of Diamonds firmware */
-	for (i = 0; i < fw->size; i++) {
-	    outb(fw->data[i], link->resource[0]->start + 2);
-	    udelay(50);
-	}
-	release_firmware(fw);
-	return err;
-}
-
-static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
-			  tuple_t *tuple,
-			  void *priv)
-{
-	struct net_device *dev = priv;
-
-	if (tuple->TupleDataLen < 8)
-		return -EINVAL;
-	if (tuple->TupleData[0] != 0x04)
-		return -EINVAL;
-
-	eth_hw_addr_set(dev, &tuple->TupleData[2]);
-	return 0;
-};
-
-
-static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
-{
-    struct net_device *dev = link->priv;
-    int rc;
-
-    /* Read the station address from tuple 0x90, subtuple 0x04 */
-    if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev))
-	    return -1;
-
-    if (((manfid == MANFID_OSITECH) &&
-	 (cardid == PRODID_OSITECH_SEVEN)) ||
-	((manfid == MANFID_PSION) &&
-	 (cardid == PRODID_PSION_NET100))) {
-	rc = osi_load_firmware(link);
-	if (rc)
-		return rc;
-    } else if (manfid == MANFID_OSITECH) {
-	/* Make sure both functions are powered up */
-	set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR);
-	/* Now, turn on the interrupt for both card functions */
-	set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR);
-	dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
-	      inw(link->resource[0]->start + OSITECH_AUI_PWR),
-	      inw(link->resource[0]->start + OSITECH_RESET_ISR));
-    }
-    return 0;
-}
-
-static int smc91c92_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int smc91c92_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-	struct smc_private *smc = netdev_priv(dev);
-	int i;
-
-	if ((smc->manfid == MANFID_MEGAHERTZ) &&
-	    (smc->cardid == PRODID_MEGAHERTZ_EM3288))
-		mhz_3288_power(link);
-	if (smc->manfid == MANFID_MOTOROLA)
-		mot_config(link);
-	if ((smc->manfid == MANFID_OSITECH) &&
-	    (smc->cardid != PRODID_OSITECH_SEVEN)) {
-		/* Power up the card and enable interrupts */
-		set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
-		set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
-	}
-	if (((smc->manfid == MANFID_OSITECH) &&
-	     (smc->cardid == PRODID_OSITECH_SEVEN)) ||
-	    ((smc->manfid == MANFID_PSION) &&
-	     (smc->cardid == PRODID_PSION_NET100))) {
-		i = osi_load_firmware(link);
-		if (i) {
-			netdev_err(dev, "Failed to load firmware\n");
-			return i;
-		}
-	}
-	if (link->open) {
-		smc_reset(dev);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/*======================================================================
-
-    This verifies that the chip is some SMC91cXX variant, and returns
-    the revision code if successful.  Otherwise, it returns -ENODEV.
-
-======================================================================*/
-
-static int check_sig(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    int width;
-    u_short s;
-
-    SMC_SELECT_BANK(1);
-    if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
-	/* Try powering up the chip */
-	outw(0, ioaddr + CONTROL);
-	mdelay(55);
-    }
-
-    /* Try setting bus width */
-    width = (link->resource[0]->flags == IO_DATA_PATH_WIDTH_AUTO);
-    s = inb(ioaddr + CONFIG);
-    if (width)
-	s |= CFG_16BIT;
-    else
-	s &= ~CFG_16BIT;
-    outb(s, ioaddr + CONFIG);
-
-    /* Check Base Address Register to make sure bus width is OK */
-    s = inw(ioaddr + BASE_ADDR);
-    if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
-	((s >> 8) != (s & 0xff))) {
-	SMC_SELECT_BANK(3);
-	s = inw(ioaddr + REVISION);
-	return s & 0xff;
-    }
-
-    if (width) {
-	    netdev_info(dev, "using 8-bit IO window\n");
-
-	    smc91c92_suspend(link);
-	    pcmcia_fixup_iowidth(link);
-	    smc91c92_resume(link);
-	    return check_sig(link);
-    }
-    return -ENODEV;
-}
-
-static int smc91c92_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    char *name;
-    int i, rev, j = 0;
-    unsigned int ioaddr;
-    u_long mir;
-
-    dev_dbg(&link->dev, "smc91c92_config\n");
-
-    smc->manfid = link->manf_id;
-    smc->cardid = link->card_id;
-
-    if ((smc->manfid == MANFID_OSITECH) &&
-	(smc->cardid != PRODID_OSITECH_SEVEN)) {
-	i = osi_config(link);
-    } else if ((smc->manfid == MANFID_MOTOROLA) ||
-	       ((smc->manfid == MANFID_MEGAHERTZ) &&
-		((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
-		 (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
-	i = mhz_mfc_config(link);
-    } else {
-	i = smc_config(link);
-    }
-    if (i)
-	    goto config_failed;
-
-    i = pcmcia_request_irq(link, smc_interrupt);
-    if (i)
-	    goto config_failed;
-    i = pcmcia_enable_device(link);
-    if (i)
-	    goto config_failed;
-
-    if (smc->manfid == MANFID_MOTOROLA)
-	mot_config(link);
-
-    dev->irq = link->irq;
-
-    if ((if_port >= 0) && (if_port <= 2))
-	dev->if_port = if_port;
-    else
-	dev_notice(&link->dev, "invalid if_port requested\n");
-
-    switch (smc->manfid) {
-    case MANFID_OSITECH:
-    case MANFID_PSION:
-	i = osi_setup(link, smc->manfid, smc->cardid); break;
-    case MANFID_SMC:
-    case MANFID_NEW_MEDIA:
-	i = smc_setup(link); break;
-    case 0x128: /* For broken Megahertz cards */
-    case MANFID_MEGAHERTZ:
-	i = mhz_setup(link); break;
-    case MANFID_MOTOROLA:
-    default: /* get the hw address from EEPROM */
-	i = mot_setup(link); break;
-    }
-
-    if (i != 0) {
-	dev_notice(&link->dev, "Unable to find hardware address.\n");
-	goto config_failed;
-    }
-
-    smc->duplex = 0;
-    smc->rx_ovrn = 0;
-
-    rev = check_sig(link);
-    name = "???";
-    if (rev > 0)
-	switch (rev >> 4) {
-	case 3: name = "92"; break;
-	case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
-	case 5: name = "95"; break;
-	case 7: name = "100"; break;
-	case 8: name = "100-FD"; break;
-	case 9: name = "110"; break;
-	}
-
-    ioaddr = dev->base_addr;
-    if (rev > 0) {
-	u_long mcr;
-	SMC_SELECT_BANK(0);
-	mir = inw(ioaddr + MEMINFO) & 0xff;
-	if (mir == 0xff) mir++;
-	/* Get scale factor for memory size */
-	mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
-	mir *= 128 * (1<<((mcr >> 9) & 7));
-	SMC_SELECT_BANK(1);
-	smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
-	smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;
-	if (smc->manfid == MANFID_OSITECH)
-	    smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;
-	if ((rev >> 4) >= 7)
-	    smc->cfg |= CFG_MII_SELECT;
-    } else
-	mir = 0;
-
-    if (smc->cfg & CFG_MII_SELECT) {
-	SMC_SELECT_BANK(3);
-
-	for (i = 0; i < 32; i++) {
-	    j = mdio_read(dev, i, 1);
-	    if ((j != 0) && (j != 0xffff)) break;
-	}
-	smc->mii_if.phy_id = (i < 32) ? i : -1;
-
-	SMC_SELECT_BANK(0);
-    }
-
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-	dev_err(&link->dev, "register_netdev() failed\n");
-	goto config_undo;
-    }
-
-    netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n",
-		name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr);
-
-    if (rev > 0) {
-	if (mir & 0x3ff)
-	    netdev_info(dev, "  %lu byte", mir);
-	else
-	    netdev_info(dev, "  %lu kb", mir>>10);
-	pr_cont(" buffer, %s xcvr\n",
-		(smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]);
-    }
-
-    if (smc->cfg & CFG_MII_SELECT) {
-	if (smc->mii_if.phy_id != -1) {
-	    netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
-		       smc->mii_if.phy_id, j);
-	} else {
-	    netdev_notice(dev, "  No MII transceivers found!\n");
-	}
-    }
-    return 0;
-
-config_undo:
-    unregister_netdev(dev);
-config_failed:
-    smc91c92_release(link);
-    free_netdev(dev);
-    return -ENODEV;
-} /* smc91c92_config */
-
-static void smc91c92_release(struct pcmcia_device *link)
-{
-	dev_dbg(&link->dev, "smc91c92_release\n");
-	if (link->resource[2]->end) {
-		struct net_device *dev = link->priv;
-		struct smc_private *smc = netdev_priv(dev);
-		iounmap(smc->base);
-	}
-	pcmcia_disable_device(link);
-}
-
-/*======================================================================
-
-    MII interface support for SMC91cXX based cards
-======================================================================*/
-
-#define MDIO_SHIFT_CLK		0x04
-#define MDIO_DATA_OUT		0x01
-#define MDIO_DIR_WRITE		0x08
-#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
-#define MDIO_DATA_READ		0x02
-
-static void mdio_sync(unsigned int addr)
-{
-    int bits;
-    for (bits = 0; bits < 32; bits++) {
-	outb(MDIO_DATA_WRITE1, addr);
-	outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-static int mdio_read(struct net_device *dev, int phy_id, int loc)
-{
-    unsigned int addr = dev->base_addr + MGMT;
-    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
-    int i, retval = 0;
-
-    mdio_sync(addr);
-    for (i = 13; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb(dat, addr);
-	outb(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 19; i > 0; i--) {
-	outb(0, addr);
-	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
-	outb(MDIO_SHIFT_CLK, addr);
-    }
-    return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
-{
-    unsigned int addr = dev->base_addr + MGMT;
-    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
-    int i;
-
-    mdio_sync(addr);
-    for (i = 31; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb(dat, addr);
-	outb(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 1; i >= 0; i--) {
-	outb(0, addr);
-	outb(MDIO_SHIFT_CLK, addr);
-    }
-}
-
-/*======================================================================
-
-    The driver core code, most of which should be common with a
-    non-PCMCIA implementation.
-
-======================================================================*/
-
-#ifdef PCMCIA_DEBUG
-static void smc_dump(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    u_short i, w, save;
-    save = inw(ioaddr + BANK_SELECT);
-    for (w = 0; w < 4; w++) {
-	SMC_SELECT_BANK(w);
-	netdev_dbg(dev, "bank %d: ", w);
-	for (i = 0; i < 14; i += 2)
-	    pr_cont(" %04x", inw(ioaddr + i));
-	pr_cont("\n");
-    }
-    outw(save, ioaddr + BANK_SELECT);
-}
-#endif
-
-static int smc_open(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    struct pcmcia_device *link = smc->p_dev;
-
-    dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n",
-	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));
-#ifdef PCMCIA_DEBUG
-    smc_dump(dev);
-#endif
-
-    /* Check that the PCMCIA card is still here. */
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-    /* Physical device present signature. */
-    if (check_sig(link) < 0) {
-	netdev_info(dev, "Yikes!  Bad chip signature!\n");
-	return -ENODEV;
-    }
-    link->open++;
-
-    netif_start_queue(dev);
-    smc->saved_skb = NULL;
-    smc->packets_waiting = 0;
-
-    smc_reset(dev);
-    timer_setup(&smc->media, media_check, 0);
-    mod_timer(&smc->media, jiffies + HZ);
-
-    return 0;
-} /* smc_open */
-
-/*====================================================================*/
-
-static int smc_close(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    struct pcmcia_device *link = smc->p_dev;
-    unsigned int ioaddr = dev->base_addr;
-
-    dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n",
-	  dev->name, inw(ioaddr + BANK_SELECT));
-
-    netif_stop_queue(dev);
-
-    /* Shut off all interrupts, and turn off the Tx and Rx sections.
-       Don't bother to check for chip present. */
-    SMC_SELECT_BANK(2);	/* Nominally paranoia, but do no assume... */
-    outw(0, ioaddr + INTERRUPT);
-    SMC_SELECT_BANK(0);
-    mask_bits(0xff00, ioaddr + RCR);
-    mask_bits(0xff00, ioaddr + TCR);
-
-    /* Put the chip into power-down mode. */
-    SMC_SELECT_BANK(1);
-    outw(CTL_POWERDOWN, ioaddr + CONTROL );
-
-    link->open--;
-    timer_delete_sync(&smc->media);
-
-    return 0;
-} /* smc_close */
-
-/*======================================================================
-
-   Transfer a packet to the hardware and trigger the packet send.
-   This may be called at either from either the Tx queue code
-   or the interrupt handler.
-
-======================================================================*/
-
-static void smc_hardware_send_packet(struct net_device * dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    struct sk_buff *skb = smc->saved_skb;
-    unsigned int ioaddr = dev->base_addr;
-    u_char packet_no;
-
-    if (!skb) {
-	netdev_err(dev, "In XMIT with no packet to send\n");
-	return;
-    }
-
-    /* There should be a packet slot waiting. */
-    packet_no = inw(ioaddr + PNR_ARR) >> 8;
-    if (packet_no & 0x80) {
-	/* If not, there is a hardware problem!  Likely an ejected card. */
-	netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n",
-		    packet_no);
-	dev_kfree_skb_irq(skb);
-	smc->saved_skb = NULL;
-	netif_start_queue(dev);
-	return;
-    }
-
-    dev->stats.tx_bytes += skb->len;
-    /* The card should use the just-allocated buffer. */
-    outw(packet_no, ioaddr + PNR_ARR);
-    /* point to the beginning of the packet */
-    outw(PTR_AUTOINC , ioaddr + POINTER);
-
-    /* Send the packet length (+6 for status, length and ctl byte)
-       and the status word (set to zeros). */
-    {
-	u_char *buf = skb->data;
-	u_int length = skb->len; /* The chip will pad to ethernet min. */
-
-	netdev_dbg(dev, "Trying to xmit packet of length %d\n", length);
-	
-	/* send the packet length: +6 for status word, length, and ctl */
-	outw(0, ioaddr + DATA_1);
-	outw(length + 6, ioaddr + DATA_1);
-	outsw(ioaddr + DATA_1, buf, length >> 1);
-	
-	/* The odd last byte, if there is one, goes in the control word. */
-	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
-    }
-
-    /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
-    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
-	 (inw(ioaddr + INTERRUPT) & 0xff00),
-	 ioaddr + INTERRUPT);
-
-    /* The chip does the rest of the work. */
-    outw(MC_ENQUEUE , ioaddr + MMU_CMD);
-
-    smc->saved_skb = NULL;
-    dev_kfree_skb_irq(skb);
-    netif_trans_update(dev);
-    netif_start_queue(dev);
-}
-
-/*====================================================================*/
-
-static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-
-    netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\n",
-		  inw(ioaddr)&0xff, inw(ioaddr + 2));
-    dev->stats.tx_errors++;
-    smc_reset(dev);
-    netif_trans_update(dev); /* prevent tx timeout */
-    smc->saved_skb = NULL;
-    netif_wake_queue(dev);
-}
-
-static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
-					struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u_short num_pages;
-    short time_out, ir;
-    unsigned long flags;
-
-    netif_stop_queue(dev);
-
-    netdev_dbg(dev, "smc_start_xmit(length = %d) called, status %04x\n",
-	       skb->len, inw(ioaddr + 2));
-
-    if (smc->saved_skb) {
-	/* THIS SHOULD NEVER HAPPEN. */
-	dev->stats.tx_aborted_errors++;
-	netdev_dbg(dev, "Internal error -- sent packet while busy\n");
-	return NETDEV_TX_BUSY;
-    }
-    smc->saved_skb = skb;
-
-    num_pages = skb->len >> 8;
-
-    if (num_pages > 7) {
-	netdev_err(dev, "Far too big packet error: %d pages\n", num_pages);
-	dev_kfree_skb (skb);
-	smc->saved_skb = NULL;
-	dev->stats.tx_dropped++;
-	return NETDEV_TX_OK;		/* Do not re-queue this packet. */
-    }
-    /* A packet is now waiting. */
-    smc->packets_waiting++;
-
-    spin_lock_irqsave(&smc->lock, flags);
-    SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */
-
-    /* need MC_RESET to keep the memory consistent. errata? */
-    if (smc->rx_ovrn) {
-	outw(MC_RESET, ioaddr + MMU_CMD);
-	smc->rx_ovrn = 0;
-    }
-
-    /* Allocate the memory; send the packet now if we win. */
-    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
-    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
-	ir = inw(ioaddr+INTERRUPT);
-	if (ir & IM_ALLOC_INT) {
-	    /* Acknowledge the interrupt, send the packet. */
-	    outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
-	    smc_hardware_send_packet(dev);	/* Send the packet now.. */
-	    spin_unlock_irqrestore(&smc->lock, flags);
-	    return NETDEV_TX_OK;
-	}
-    }
-
-    /* Otherwise defer until the Tx-space-allocated interrupt. */
-    netdev_dbg(dev, "memory allocation deferred.\n");
-    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
-    spin_unlock_irqrestore(&smc->lock, flags);
-
-    return NETDEV_TX_OK;
-}
-
-/*======================================================================
-
-    Handle a Tx anomalous event.  Entered while in Window 2.
-
-======================================================================*/
-
-static void smc_tx_err(struct net_device * dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
-    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
-    int tx_status;
-
-    /* select this as the packet to read from */
-    outw(packet_no, ioaddr + PNR_ARR);
-
-    /* read the first word from this packet */
-    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
-
-    tx_status = inw(ioaddr + DATA_1);
-
-    dev->stats.tx_errors++;
-    if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
-    if (tx_status & TS_LATCOL)  dev->stats.tx_window_errors++;
-    if (tx_status & TS_16COL) {
-	dev->stats.tx_aborted_errors++;
-	smc->tx_err++;
-    }
-
-    if (tx_status & TS_SUCCESS) {
-	netdev_notice(dev, "Successful packet caused error interrupt?\n");
-    }
-    /* re-enable transmit */
-    SMC_SELECT_BANK(0);
-    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
-    SMC_SELECT_BANK(2);
-
-    outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */
-
-    /* one less packet waiting for me */
-    smc->packets_waiting--;
-
-    outw(saved_packet, ioaddr + PNR_ARR);
-}
-
-/*====================================================================*/
-
-static void smc_eph_irq(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u_short card_stats, ephs;
-
-    SMC_SELECT_BANK(0);
-    ephs = inw(ioaddr + EPH);
-    netdev_dbg(dev, "Ethernet protocol handler interrupt, status %4.4x.\n",
-	       ephs);
-    /* Could be a counter roll-over warning: update stats. */
-    card_stats = inw(ioaddr + COUNTER);
-    /* single collisions */
-    dev->stats.collisions += card_stats & 0xF;
-    card_stats >>= 4;
-    /* multiple collisions */
-    dev->stats.collisions += card_stats & 0xF;
-#if 0 		/* These are for when linux supports these statistics */
-    card_stats >>= 4;			/* deferred */
-    card_stats >>= 4;			/* excess deferred */
-#endif
-    /* If we had a transmit error we must re-enable the transmitter. */
-    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
-
-    /* Clear a link error interrupt. */
-    SMC_SELECT_BANK(1);
-    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
-    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
-	 ioaddr + CONTROL);
-    SMC_SELECT_BANK(2);
-}
-
-/*====================================================================*/
-
-static irqreturn_t smc_interrupt(int irq, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr;
-    u_short saved_bank, saved_pointer, mask, status;
-    unsigned int handled = 1;
-    char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */
-
-    if (!netif_device_present(dev))
-	return IRQ_NONE;
-
-    ioaddr = dev->base_addr;
-
-    netdev_dbg(dev, "SMC91c92 interrupt %d at %#x.\n",
-	       irq, ioaddr);
-
-    spin_lock(&smc->lock);
-    smc->watchdog = 0;
-    saved_bank = inw(ioaddr + BANK_SELECT);
-    if ((saved_bank & 0xff00) != 0x3300) {
-	/* The device does not exist -- the card could be off-line, or
-	   maybe it has been ejected. */
-	netdev_dbg(dev, "SMC91c92 interrupt %d for non-existent/ejected device.\n",
-		   irq);
-	handled = 0;
-	goto irq_done;
-    }
-
-    SMC_SELECT_BANK(2);
-    saved_pointer = inw(ioaddr + POINTER);
-    mask = inw(ioaddr + INTERRUPT) >> 8;
-    /* clear all interrupts */
-    outw(0, ioaddr + INTERRUPT);
-
-    do { /* read the status flag, and mask it */
-	status = inw(ioaddr + INTERRUPT) & 0xff;
-	netdev_dbg(dev, "Status is %#2.2x (mask %#2.2x).\n",
-		   status, mask);
-	if ((status & mask) == 0) {
-	    if (bogus_cnt == INTR_WORK)
-		handled = 0;
-	    break;
-	}
-	if (status & IM_RCV_INT) {
-	    /* Got a packet(s). */
-	    smc_rx(dev);
-	}
-	if (status & IM_TX_INT) {
-	    smc_tx_err(dev);
-	    outw(IM_TX_INT, ioaddr + INTERRUPT);
-	}
-	status &= mask;
-	if (status & IM_TX_EMPTY_INT) {
-	    outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
-	    mask &= ~IM_TX_EMPTY_INT;
-	    dev->stats.tx_packets += smc->packets_waiting;
-	    smc->packets_waiting = 0;
-	}
-	if (status & IM_ALLOC_INT) {
-	    /* Clear this interrupt so it doesn't happen again */
-	    mask &= ~IM_ALLOC_INT;
-	
-	    smc_hardware_send_packet(dev);
-	
-	    /* enable xmit interrupts based on this */
-	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
-	
-	    /* and let the card send more packets to me */
-	    netif_wake_queue(dev);
-	}
-	if (status & IM_RX_OVRN_INT) {
-	    dev->stats.rx_errors++;
-	    dev->stats.rx_fifo_errors++;
-	    if (smc->duplex)
-		smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
-	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
-	}
-	if (status & IM_EPH_INT)
-	    smc_eph_irq(dev);
-    } while (--bogus_cnt);
-
-    netdev_dbg(dev, "  Restoring saved registers mask %2.2x bank %4.4x pointer %4.4x.\n",
-	       mask, saved_bank, saved_pointer);
-
-    /* restore state register */
-    outw((mask<<8), ioaddr + INTERRUPT);
-    outw(saved_pointer, ioaddr + POINTER);
-    SMC_SELECT_BANK(saved_bank);
-
-    netdev_dbg(dev, "Exiting interrupt IRQ%d.\n", irq);
-
-irq_done:
-
-    if ((smc->manfid == MANFID_OSITECH) &&
-	(smc->cardid != PRODID_OSITECH_SEVEN)) {
-	/* Retrigger interrupt if needed */
-	mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
-	set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
-    }
-    if (smc->manfid == MANFID_MOTOROLA) {
-	u_char cor;
-	cor = readb(smc->base + MOT_UART + CISREG_COR);
-	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
-	writeb(cor, smc->base + MOT_UART + CISREG_COR);
-	cor = readb(smc->base + MOT_LAN + CISREG_COR);
-	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
-	writeb(cor, smc->base + MOT_LAN + CISREG_COR);
-    }
-
-    if ((smc->base != NULL) &&  /* Megahertz MFC's */
-	(smc->manfid == MANFID_MEGAHERTZ) &&
-	(smc->cardid == PRODID_MEGAHERTZ_EM3288)) {
-
-	u_char tmp;
-	tmp = readb(smc->base+MEGAHERTZ_ISR);
-	tmp = readb(smc->base+MEGAHERTZ_ISR);
-
-	/* Retrigger interrupt if needed */
-	writeb(tmp, smc->base + MEGAHERTZ_ISR);
-	writeb(tmp, smc->base + MEGAHERTZ_ISR);
-    }
-
-    spin_unlock(&smc->lock);
-    return IRQ_RETVAL(handled);
-}
-
-/*====================================================================*/
-
-static void smc_rx(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    int rx_status;
-    int packet_length;	/* Caution: not frame length, rather words
-			   to transfer from the chip. */
-
-    /* Assertion: we are in Window 2. */
-
-    if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
-	netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n");
-	return;
-    }
-
-    /*  Reset the read pointer, and read the status and packet length. */
-    outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
-    rx_status = inw(ioaddr + DATA_1);
-    packet_length = inw(ioaddr + DATA_1) & 0x07ff;
-
-    netdev_dbg(dev, "Receive status %4.4x length %d.\n",
-	       rx_status, packet_length);
-
-    if (!(rx_status & RS_ERRORS)) {
-	/* do stuff to make a new packet */
-	struct sk_buff *skb;
-	struct smc_private *smc = netdev_priv(dev);
-	
-	/* Note: packet_length adds 5 or 6 extra bytes here! */
-	skb = netdev_alloc_skb(dev, packet_length+2);
-	
-	if (skb == NULL) {
-	    netdev_dbg(dev, "Low memory, packet dropped.\n");
-	    dev->stats.rx_dropped++;
-	    outw(MC_RELEASE, ioaddr + MMU_CMD);
-	    return;
-	}
-	
-	packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
-	skb_reserve(skb, 2);
-	insw(ioaddr+DATA_1, skb_put(skb, packet_length),
-	     (packet_length+1)>>1);
-	skb->protocol = eth_type_trans(skb, dev);
-	
-	netif_rx(skb);
-	smc->last_rx = jiffies;
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += packet_length;
-	if (rx_status & RS_MULTICAST)
-	    dev->stats.multicast++;
-    } else {
-	/* error ... */
-	dev->stats.rx_errors++;
-	
-	if (rx_status & RS_ALGNERR)  dev->stats.rx_frame_errors++;
-	if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
-	    dev->stats.rx_length_errors++;
-	if (rx_status & RS_BADCRC)	dev->stats.rx_crc_errors++;
-    }
-    /* Let the MMU free the memory of this packet. */
-    outw(MC_RELEASE, ioaddr + MMU_CMD);
-}
-
-/*======================================================================
-
-    Set the receive mode.
-
-    This routine is used by both the protocol level to notify us of
-    promiscuous/multicast mode changes, and by the open/reset code to
-    initialize the Rx registers.  We always set the multicast list and
-    leave the receiver running.
-
-======================================================================*/
-
-static void set_rx_mode(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned char multicast_table[8];
-    unsigned long flags;
-    u_short rx_cfg_setting;
-    int i;
-
-    memset(multicast_table, 0, sizeof(multicast_table));
-
-    if (dev->flags & IFF_PROMISC) {
-	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
-    } else if (dev->flags & IFF_ALLMULTI)
-	rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
-    else {
-	if (!netdev_mc_empty(dev)) {
-	    struct netdev_hw_addr *ha;
-
-	    netdev_for_each_mc_addr(ha, dev) {
-		u_int position = ether_crc(6, ha->addr);
-		multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
-	    }
-	}
-	rx_cfg_setting = RxStripCRC | RxEnable;
-    }
-
-    /* Load MC table and Rx setting into the chip without interrupts. */
-    spin_lock_irqsave(&smc->lock, flags);
-    SMC_SELECT_BANK(3);
-    for (i = 0; i < 8; i++)
-	outb(multicast_table[i], ioaddr + MULTICAST0 + i);
-    SMC_SELECT_BANK(0);
-    outw(rx_cfg_setting, ioaddr + RCR);
-    SMC_SELECT_BANK(2);
-    spin_unlock_irqrestore(&smc->lock, flags);
-}
-
-/*======================================================================
-
-    Senses when a card's config changes. Here, it's coax or TP.
-
-======================================================================*/
-
-static int s9k_config(struct net_device *dev, struct ifmap *map)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-	if (smc->cfg & CFG_MII_SELECT)
-	    return -EOPNOTSUPP;
-	else if (map->port > 2)
-	    return -EINVAL;
-	WRITE_ONCE(dev->if_port, map->port);
-	netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
-	smc_reset(dev);
-    }
-    return 0;
-}
-
-/*======================================================================
-
-    Reset the chip, reloading every register that might be corrupted.
-
-======================================================================*/
-
-/*
-  Set transceiver type, perhaps to something other than what the user
-  specified in dev->if_port.
-*/
-static void smc_set_xcvr(struct net_device *dev, int if_port)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u_short saved_bank;
-
-    saved_bank = inw(ioaddr + BANK_SELECT);
-    SMC_SELECT_BANK(1);
-    if (if_port == 2) {
-	outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
-	if ((smc->manfid == MANFID_OSITECH) &&
-	    (smc->cardid != PRODID_OSITECH_SEVEN))
-	    set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
-	smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
-    } else {
-	outw(smc->cfg, ioaddr + CONFIG);
-	if ((smc->manfid == MANFID_OSITECH) &&
-	    (smc->cardid != PRODID_OSITECH_SEVEN))
-	    mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
-	smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
-    }
-    SMC_SELECT_BANK(saved_bank);
-}
-
-static void smc_reset(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct smc_private *smc = netdev_priv(dev);
-    int i;
-
-    netdev_dbg(dev, "smc91c92 reset called.\n");
-
-    /* The first interaction must be a write to bring the chip out
-       of sleep mode. */
-    SMC_SELECT_BANK(0);
-    /* Reset the chip. */
-    outw(RCR_SOFTRESET, ioaddr + RCR);
-    udelay(10);
-
-    /* Clear the transmit and receive configuration registers. */
-    outw(RCR_CLEAR, ioaddr + RCR);
-    outw(TCR_CLEAR, ioaddr + TCR);
-
-    /* Set the Window 1 control, configuration and station addr registers.
-       No point in writing the I/O base register ;-> */
-    SMC_SELECT_BANK(1);
-    /* Automatically release successfully transmitted packets,
-       Accept link errors, counter and Tx error interrupts. */
-    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
-	 ioaddr + CONTROL);
-    smc_set_xcvr(dev, dev->if_port);
-    if ((smc->manfid == MANFID_OSITECH) &&
-	(smc->cardid != PRODID_OSITECH_SEVEN))
-	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
-	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
-	     ioaddr - 0x10 + OSITECH_AUI_PWR);
-
-    /* Fill in the physical address.  The databook is wrong about the order! */
-    for (i = 0; i < 6; i += 2)
-	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
-	     ioaddr + ADDR0 + i);
-
-    /* Reset the MMU */
-    SMC_SELECT_BANK(2);
-    outw(MC_RESET, ioaddr + MMU_CMD);
-    outw(0, ioaddr + INTERRUPT);
-
-    /* Re-enable the chip. */
-    SMC_SELECT_BANK(0);
-    outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
-	 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
-    set_rx_mode(dev);
-
-    if (smc->cfg & CFG_MII_SELECT) {
-	SMC_SELECT_BANK(3);
-
-	/* Reset MII */
-	mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
-
-	/* Advertise 100F, 100H, 10F, 10H */
-	mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
-
-	/* Restart MII autonegotiation */
-	mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
-	mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
-    }
-
-    /* Enable interrupts. */
-    SMC_SELECT_BANK(2);
-    outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
-	 ioaddr + INTERRUPT);
-}
-
-/*======================================================================
-
-    Media selection timer routine
-
-======================================================================*/
-
-static void media_check(struct timer_list *t)
-{
-    struct smc_private *smc = timer_container_of(smc, t, media);
-    struct net_device *dev = smc->mii_if.dev;
-    unsigned int ioaddr = dev->base_addr;
-    u_short i, media, saved_bank;
-    u_short link;
-    unsigned long flags;
-
-    spin_lock_irqsave(&smc->lock, flags);
-
-    saved_bank = inw(ioaddr + BANK_SELECT);
-
-    if (!netif_device_present(dev))
-	goto reschedule;
-
-    SMC_SELECT_BANK(2);
-
-    /* need MC_RESET to keep the memory consistent. errata? */
-    if (smc->rx_ovrn) {
-	outw(MC_RESET, ioaddr + MMU_CMD);
-	smc->rx_ovrn = 0;
-    }
-    i = inw(ioaddr + INTERRUPT);
-    SMC_SELECT_BANK(0);
-    media = inw(ioaddr + EPH) & EPH_LINK_OK;
-    SMC_SELECT_BANK(1);
-    media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
-
-    SMC_SELECT_BANK(saved_bank);
-    spin_unlock_irqrestore(&smc->lock, flags);
-
-    /* Check for pending interrupt with watchdog flag set: with
-       this, we can limp along even if the interrupt is blocked */
-    if (smc->watchdog++ && ((i>>8) & i)) {
-	if (!smc->fast_poll)
-	    netdev_info(dev, "interrupt(s) dropped!\n");
-	local_irq_save(flags);
-	smc_interrupt(dev->irq, dev);
-	local_irq_restore(flags);
-	smc->fast_poll = HZ;
-    }
-    if (smc->fast_poll) {
-	smc->fast_poll--;
-	smc->media.expires = jiffies + HZ/100;
-	add_timer(&smc->media);
-	return;
-    }
-
-    spin_lock_irqsave(&smc->lock, flags);
-
-    saved_bank = inw(ioaddr + BANK_SELECT);
-
-    if (smc->cfg & CFG_MII_SELECT) {
-	if (smc->mii_if.phy_id < 0)
-	    goto reschedule;
-
-	SMC_SELECT_BANK(3);
-	link = mdio_read(dev, smc->mii_if.phy_id, 1);
-	if (!link || (link == 0xffff)) {
-	    netdev_info(dev, "MII is missing!\n");
-	    smc->mii_if.phy_id = -1;
-	    goto reschedule;
-	}
-
-	link &= 0x0004;
-	if (link != smc->link_status) {
-	    u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
-	    netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
-	    smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
-			   ? TCR_FDUPLX : 0);
-	    if (link) {
-		netdev_info(dev, "autonegotiation complete: "
-			    "%dbaseT-%cD selected\n",
-			    (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H');
-	    }
-	    SMC_SELECT_BANK(0);
-	    outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
-	    smc->link_status = link;
-	}
-	goto reschedule;
-    }
-
-    /* Ignore collisions unless we've had no rx's recently */
-    if (time_after(jiffies, smc->last_rx + HZ)) {
-	if (smc->tx_err || (smc->media_status & EPH_16COL))
-	    media |= EPH_16COL;
-    }
-    smc->tx_err = 0;
-
-    if (media != smc->media_status) {
-	if ((media & smc->media_status & 1) &&
-	    ((smc->media_status ^ media) & EPH_LINK_OK))
-	    netdev_info(dev, "%s link beat\n",
-			smc->media_status & EPH_LINK_OK ? "lost" : "found");
-	else if ((media & smc->media_status & 2) &&
-		 ((smc->media_status ^ media) & EPH_16COL))
-	    netdev_info(dev, "coax cable %s\n",
-			media & EPH_16COL ? "problem" : "ok");
-	if (dev->if_port == 0) {
-	    if (media & 1) {
-		if (media & EPH_LINK_OK)
-		    netdev_info(dev, "flipped to 10baseT\n");
-		else
-		    smc_set_xcvr(dev, 2);
-	    } else {
-		if (media & EPH_16COL)
-		    smc_set_xcvr(dev, 1);
-		else
-		    netdev_info(dev, "flipped to 10base2\n");
-	    }
-	}
-	smc->media_status = media;
-    }
-
-reschedule:
-    smc->media.expires = jiffies + HZ;
-    add_timer(&smc->media);
-    SMC_SELECT_BANK(saved_bank);
-    spin_unlock_irqrestore(&smc->lock, flags);
-}
-
-static int smc_link_ok(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct smc_private *smc = netdev_priv(dev);
-
-    if (smc->cfg & CFG_MII_SELECT) {
-	return mii_link_ok(&smc->mii_if);
-    } else {
-        SMC_SELECT_BANK(0);
-	return inw(ioaddr + EPH) & EPH_LINK_OK;
-    }
-}
-
-static void smc_netdev_get_ecmd(struct net_device *dev,
-				struct ethtool_link_ksettings *ecmd)
-{
-	u16 tmp;
-	unsigned int ioaddr = dev->base_addr;
-	u32 supported;
-
-	supported = (SUPPORTED_TP | SUPPORTED_AUI |
-		     SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
-
-	SMC_SELECT_BANK(1);
-	tmp = inw(ioaddr + CONFIG);
-	ecmd->base.port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
-	ecmd->base.speed = SPEED_10;
-	ecmd->base.phy_address = ioaddr + MGMT;
-
-	SMC_SELECT_BANK(0);
-	tmp = inw(ioaddr + TCR);
-	ecmd->base.duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
-
-	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
-						supported);
-}
-
-static int smc_netdev_set_ecmd(struct net_device *dev,
-			       const struct ethtool_link_ksettings *ecmd)
-{
-	u16 tmp;
-	unsigned int ioaddr = dev->base_addr;
-
-	if (ecmd->base.speed != SPEED_10)
-		return -EINVAL;
-	if (ecmd->base.duplex != DUPLEX_HALF &&
-	    ecmd->base.duplex != DUPLEX_FULL)
-		return -EINVAL;
-	if (ecmd->base.port != PORT_TP && ecmd->base.port != PORT_AUI)
-		return -EINVAL;
-
-	if (ecmd->base.port == PORT_AUI)
-		smc_set_xcvr(dev, 1);
-	else
-		smc_set_xcvr(dev, 0);
-
-	SMC_SELECT_BANK(0);
-	tmp = inw(ioaddr + TCR);
-	if (ecmd->base.duplex == DUPLEX_FULL)
-		tmp |= TCR_FDUPLX;
-	else
-		tmp &= ~TCR_FDUPLX;
-	outw(tmp, ioaddr + TCR);
-
-	return 0;
-}
-
-static int check_if_running(struct net_device *dev)
-{
-	if (!netif_running(dev))
-		return -EINVAL;
-	return 0;
-}
-
-static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	strscpy(info->version, DRV_VERSION, sizeof(info->version));
-}
-
-static int smc_get_link_ksettings(struct net_device *dev,
-				  struct ethtool_link_ksettings *ecmd)
-{
-	struct smc_private *smc = netdev_priv(dev);
-	unsigned int ioaddr = dev->base_addr;
-	u16 saved_bank = inw(ioaddr + BANK_SELECT);
-	unsigned long flags;
-
-	spin_lock_irqsave(&smc->lock, flags);
-	SMC_SELECT_BANK(3);
-	if (smc->cfg & CFG_MII_SELECT)
-		mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd);
-	else
-		smc_netdev_get_ecmd(dev, ecmd);
-	SMC_SELECT_BANK(saved_bank);
-	spin_unlock_irqrestore(&smc->lock, flags);
-	return 0;
-}
-
-static int smc_set_link_ksettings(struct net_device *dev,
-				  const struct ethtool_link_ksettings *ecmd)
-{
-	struct smc_private *smc = netdev_priv(dev);
-	unsigned int ioaddr = dev->base_addr;
-	u16 saved_bank = inw(ioaddr + BANK_SELECT);
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&smc->lock, flags);
-	SMC_SELECT_BANK(3);
-	if (smc->cfg & CFG_MII_SELECT)
-		ret = mii_ethtool_set_link_ksettings(&smc->mii_if, ecmd);
-	else
-		ret = smc_netdev_set_ecmd(dev, ecmd);
-	SMC_SELECT_BANK(saved_bank);
-	spin_unlock_irqrestore(&smc->lock, flags);
-	return ret;
-}
-
-static u32 smc_get_link(struct net_device *dev)
-{
-	struct smc_private *smc = netdev_priv(dev);
-	unsigned int ioaddr = dev->base_addr;
-	u16 saved_bank = inw(ioaddr + BANK_SELECT);
-	u32 ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&smc->lock, flags);
-	SMC_SELECT_BANK(3);
-	ret = smc_link_ok(dev);
-	SMC_SELECT_BANK(saved_bank);
-	spin_unlock_irqrestore(&smc->lock, flags);
-	return ret;
-}
-
-static int smc_nway_reset(struct net_device *dev)
-{
-	struct smc_private *smc = netdev_priv(dev);
-	if (smc->cfg & CFG_MII_SELECT) {
-		unsigned int ioaddr = dev->base_addr;
-		u16 saved_bank = inw(ioaddr + BANK_SELECT);
-		int res;
-
-		SMC_SELECT_BANK(3);
-		res = mii_nway_restart(&smc->mii_if);
-		SMC_SELECT_BANK(saved_bank);
-
-		return res;
-	} else
-		return -EOPNOTSUPP;
-}
-
-static const struct ethtool_ops ethtool_ops = {
-	.begin = check_if_running,
-	.get_drvinfo = smc_get_drvinfo,
-	.get_link = smc_get_link,
-	.nway_reset = smc_nway_reset,
-	.get_link_ksettings = smc_get_link_ksettings,
-	.set_link_ksettings = smc_set_link_ksettings,
-};
-
-static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct smc_private *smc = netdev_priv(dev);
-	struct mii_ioctl_data *mii = if_mii(rq);
-	int rc = 0;
-	u16 saved_bank;
-	unsigned int ioaddr = dev->base_addr;
-	unsigned long flags;
-
-	if (!netif_running(dev))
-		return -EINVAL;
-
-	spin_lock_irqsave(&smc->lock, flags);
-	saved_bank = inw(ioaddr + BANK_SELECT);
-	SMC_SELECT_BANK(3);
-	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
-	SMC_SELECT_BANK(saved_bank);
-	spin_unlock_irqrestore(&smc->lock, flags);
-	return rc;
-}
-
-static const struct pcmcia_device_id smc91c92_ids[] = {
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
-	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
-	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
-	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
-	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
-	PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
-	PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
-	PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
-	PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
-	PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
-	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
-	PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
-	PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
-	PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
-	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
-	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
-	PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
-	PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
-	/* These conflict with other cards! */
-	/* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
-	/* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
-
-static struct pcmcia_driver smc91c92_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "smc91c92_cs",
-	.probe		= smc91c92_probe,
-	.remove		= smc91c92_detach,
-	.id_table       = smc91c92_ids,
-	.suspend	= smc91c92_suspend,
-	.resume		= smc91c92_resume,
-};
-module_pcmcia_driver(smc91c92_cs_driver);

-- 
2.53.0


^ permalink raw reply related

* [PATCH net 16/18] drivers: net: 8390: pcnet: Remove this driver
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

The pcnet was written by David A. Hindsh in 1999. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/8390/Kconfig    |   11 -
 drivers/net/ethernet/8390/Makefile   |    1 -
 drivers/net/ethernet/8390/pcnet_cs.c | 1717 ----------------------------------
 3 files changed, 1729 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 3dea042cc2eb..3e56806471a3 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -132,17 +132,6 @@ config APNE
 	  To compile this driver as a module, choose M here: the module
 	  will be called apne.
 
-config PCMCIA_PCNET
-	tristate "NE2000 compatible PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	select CRC32
-	help
-	  Say Y here if you intend to attach an NE2000 compatible PCMCIA
-	  (PC-card) Ethernet or Fast Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called pcnet_cs.  If unsure, say N.
-
 config STNIC
 	tristate "National DP83902AV  support"
 	depends on SUPERH
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index 60220484b382..b215136a603b 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_MCF8390) += mcf8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
deleted file mode 100644
index 19f9c5db3f3b..000000000000
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ /dev/null
@@ -1,1717 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-/*======================================================================
-
-    A PCMCIA ethernet driver for NS8390-based cards
-
-    This driver supports the D-Link DE-650 and Linksys EthernetCard
-    cards, the newer D-Link and Linksys combo cards, Accton EN2212
-    cards, the RPTI EP400, and the PreMax PE-200 in non-shared-memory
-    mode, and the IBM Credit Card Adapter, the NE4100, the Thomas
-    Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory
-    mode.  It will also handle the Socket EA card in either mode.
-
-    Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
-
-    pcnet_cs.c 1.153 2003/11/09 18:53:09
-
-    The network driver code is based on Donald Becker's NE2000 code:
-
-    Written 1992,1993 by Donald Becker.
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.
-    Donald Becker may be reached at becker@scyld.com
-
-    Based also on Keith Moore's changes to Don Becker's code, for IBM
-    CCAE support.  Drivers merged back together, and shared-memory
-    Socket EA support added, by Ken Raeburn, September 1995.
-
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/log2.h>
-#include <linux/etherdevice.h>
-#include <linux/mii.h>
-#include "8390.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#define PCNET_CMD	0x00
-#define PCNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
-#define PCNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
-#define PCNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
-
-#define PCNET_START_PG	0x40	/* First page of TX buffer */
-#define PCNET_STOP_PG	0x80	/* Last page +1 of RX ring */
-
-/* Socket EA cards have a larger packet buffer */
-#define SOCKET_START_PG	0x01
-#define SOCKET_STOP_PG	0xff
-
-#define PCNET_RDC_TIMEOUT (2*HZ/100)	/* Max wait in jiffies for Tx RDC */
-
-static const char *if_names[] = { "auto", "10baseT", "10base2"};
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("NE2000 compatible PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-INT_MODULE_PARM(if_port,	1);	/* Transceiver type */
-INT_MODULE_PARM(use_big_buf,	1);	/* use 64K packet buffer? */
-INT_MODULE_PARM(mem_speed,	0);	/* shared mem speed, in ns */
-INT_MODULE_PARM(delay_output,	0);	/* pause after xmit? */
-INT_MODULE_PARM(delay_time,	4);	/* in usec */
-INT_MODULE_PARM(use_shmem,	-1);	/* use shared memory? */
-INT_MODULE_PARM(full_duplex,	0);	/* full duplex? */
-
-/* Ugh!  Let the user hardwire the hardware address for queer cards */
-static int hw_addr[6] = { 0, /* ... */ };
-module_param_array(hw_addr, int, NULL, 0);
-
-/*====================================================================*/
-
-static void mii_phy_probe(struct net_device *dev);
-static int pcnet_config(struct pcmcia_device *link);
-static void pcnet_release(struct pcmcia_device *link);
-static int pcnet_open(struct net_device *dev);
-static int pcnet_close(struct net_device *dev);
-static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
-static void ei_watchdog(struct timer_list *t);
-static void pcnet_reset_8390(struct net_device *dev);
-static int set_config(struct net_device *dev, struct ifmap *map);
-static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
-			      int stop_pg, int cm_offset);
-static int setup_dma_config(struct pcmcia_device *link, int start_pg,
-			    int stop_pg);
-
-static void pcnet_detach(struct pcmcia_device *p_dev);
-
-/*====================================================================*/
-
-struct hw_info {
-    u_int	offset;
-    u_char	a0, a1, a2;
-    u_int	flags;
-};
-
-#define DELAY_OUTPUT	0x01
-#define HAS_MISC_REG	0x02
-#define USE_BIG_BUF	0x04
-#define HAS_IBM_MISC	0x08
-#define IS_DL10019	0x10
-#define IS_DL10022	0x20
-#define HAS_MII		0x40
-#define USE_SHMEM	0x80	/* autodetected */
-
-#define AM79C9XX_HOME_PHY	0x00006B90  /* HomePNA PHY */
-#define AM79C9XX_ETH_PHY	0x00006B70  /* 10baseT PHY */
-#define MII_PHYID_REV_MASK	0xfffffff0
-#define MII_PHYID_REG1		0x02
-#define MII_PHYID_REG2		0x03
-
-static struct hw_info hw_info[] = {
-    { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
-    { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
-    { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
-    { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
-      DELAY_OUTPUT | HAS_IBM_MISC },
-    { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
-    { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
-    { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
-    { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
-    { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
-    { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
-    { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
-    { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
-    { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
-    { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
-    { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
-    { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
-    { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
-    { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
-    { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
-    { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
-    { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
-    { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
-      DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
-    { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
-    { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
-    { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
-    { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
-    { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
-};
-
-#define NR_INFO		ARRAY_SIZE(hw_info)
-
-static struct hw_info default_info = { 0, 0, 0, 0, 0 };
-static struct hw_info dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
-static struct hw_info dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII };
-
-struct pcnet_dev {
-	struct pcmcia_device	*p_dev;
-    u_int		flags;
-    void		__iomem *base;
-    struct timer_list	watchdog;
-    int			stale, fast_poll;
-    u_char		phy_id;
-    u_char		eth_phy, pna_phy;
-    u_short		link_status;
-    u_long		mii_reset;
-};
-
-static inline struct pcnet_dev *PRIV(struct net_device *dev)
-{
-	char *p = netdev_priv(dev);
-	return (struct pcnet_dev *)(p + sizeof(struct ei_device));
-}
-
-static const struct net_device_ops pcnet_netdev_ops = {
-	.ndo_open		= pcnet_open,
-	.ndo_stop		= pcnet_close,
-	.ndo_set_config		= set_config,
-	.ndo_start_xmit 	= ei_start_xmit,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_eth_ioctl		= ei_ioctl,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_tx_timeout 	= ei_tx_timeout,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= ei_poll,
-#endif
-};
-
-static int pcnet_probe(struct pcmcia_device *link)
-{
-    struct pcnet_dev *info;
-    struct net_device *dev;
-
-    dev_dbg(&link->dev, "pcnet_attach()\n");
-
-    /* Create new ethernet device */
-    dev = __alloc_ei_netdev(sizeof(struct pcnet_dev));
-    if (!dev) return -ENOMEM;
-    info = PRIV(dev);
-    info->p_dev = link;
-    link->priv = dev;
-
-    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
-    dev->netdev_ops = &pcnet_netdev_ops;
-
-    return pcnet_config(link);
-} /* pcnet_attach */
-
-static void pcnet_detach(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	dev_dbg(&link->dev, "pcnet_detach\n");
-
-	unregister_netdev(dev);
-
-	pcnet_release(link);
-
-	free_netdev(dev);
-} /* pcnet_detach */
-
-/*======================================================================
-
-    This probes for a card's hardware address, for card types that
-    encode this information in their CIS.
-
-======================================================================*/
-
-static struct hw_info *get_hwinfo(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    u_char __iomem *base, *virt;
-    u8 addr[ETH_ALEN];
-    int i, j;
-
-    /* Allocate a small memory window */
-    link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[2]->start = 0; link->resource[2]->end = 0;
-    i = pcmcia_request_window(link, link->resource[2], 0);
-    if (i != 0)
-	return NULL;
-
-    virt = ioremap(link->resource[2]->start,
-	    resource_size(link->resource[2]));
-    if (unlikely(!virt)) {
-	    pcmcia_release_window(link, link->resource[2]);
-	    return NULL;
-    }
-
-    for (i = 0; i < NR_INFO; i++) {
-	pcmcia_map_mem_page(link, link->resource[2],
-		hw_info[i].offset & ~(resource_size(link->resource[2])-1));
-	base = &virt[hw_info[i].offset & (resource_size(link->resource[2])-1)];
-	if ((readb(base+0) == hw_info[i].a0) &&
-	    (readb(base+2) == hw_info[i].a1) &&
-	    (readb(base+4) == hw_info[i].a2)) {
-		for (j = 0; j < 6; j++)
-			addr[j] = readb(base + (j<<1));
-		eth_hw_addr_set(dev, addr);
-		break;
-	}
-    }
-
-    iounmap(virt);
-    j = pcmcia_release_window(link, link->resource[2]);
-    return (i < NR_INFO) ? hw_info+i : NULL;
-} /* get_hwinfo */
-
-/*======================================================================
-
-    This probes for a card's hardware address by reading the PROM.
-    It checks the address against a list of known types, then falls
-    back to a simple NE2000 clone signature check.
-
-======================================================================*/
-
-static struct hw_info *get_prom(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    u8 addr[ETH_ALEN];
-    u_char prom[32];
-    int i, j;
-
-    /* This is lifted straight from drivers/net/ethernet/8390/ne.c */
-    struct {
-	u_char value, offset;
-    } program_seq[] = {
-	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
-	{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
-	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_IMR},	/* Mask completion irq. */
-	{0xFF,	EN0_ISR},
-	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
-	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
-	{32,	EN0_RCNTLO},
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
-	{0x00,	EN0_RSARHI},
-	{E8390_RREAD+E8390_START, E8390_CMD},
-    };
-
-    pcnet_reset_8390(dev);
-    mdelay(10);
-
-    for (i = 0; i < ARRAY_SIZE(program_seq); i++)
-	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
-
-    for (i = 0; i < 32; i++)
-	prom[i] = inb(ioaddr + PCNET_DATAPORT);
-    for (i = 0; i < NR_INFO; i++) {
-	if ((prom[0] == hw_info[i].a0) &&
-	    (prom[2] == hw_info[i].a1) &&
-	    (prom[4] == hw_info[i].a2))
-	    break;
-    }
-    if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
-	for (j = 0; j < 6; j++)
-	    addr[j] = prom[j<<1];
-	eth_hw_addr_set(dev, addr);
-	return (i < NR_INFO) ? hw_info+i : &default_info;
-    }
-    return NULL;
-} /* get_prom */
-
-/*======================================================================
-
-    For DL10019 based cards, like the Linksys EtherFast
-
-======================================================================*/
-
-static struct hw_info *get_dl10019(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    u8 addr[ETH_ALEN];
-    int i;
-    u_char sum;
-
-    for (sum = 0, i = 0x14; i < 0x1c; i++)
-	sum += inb_p(dev->base_addr + i);
-    if (sum != 0xff)
-	return NULL;
-    for (i = 0; i < 6; i++)
-	addr[i] = inb_p(dev->base_addr + 0x14 + i);
-    eth_hw_addr_set(dev, addr);
-    i = inb(dev->base_addr + 0x1f);
-    return ((i == 0x91)||(i == 0x99)) ? &dl10022_info : &dl10019_info;
-}
-
-/*======================================================================
-
-    For Asix AX88190 based cards
-
-======================================================================*/
-
-static struct hw_info *get_ax88190(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    u8 addr[ETH_ALEN];
-    int i, j;
-
-    /* Not much of a test, but the alternatives are messy */
-    if (link->config_base != 0x03c0)
-	return NULL;
-
-    outb_p(0x01, ioaddr + EN0_DCFG);	/* Set word-wide access. */
-    outb_p(0x00, ioaddr + EN0_RSARLO);	/* DMA starting at 0x0400. */
-    outb_p(0x04, ioaddr + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, ioaddr + E8390_CMD);
-
-    for (i = 0; i < 6; i += 2) {
-	j = inw(ioaddr + PCNET_DATAPORT);
-	addr[i] = j & 0xff;
-	addr[i+1] = j >> 8;
-    }
-    eth_hw_addr_set(dev, addr);
-    return NULL;
-}
-
-/*======================================================================
-
-    This should be totally unnecessary... but when we can't figure
-    out the hardware address any other way, we'll let the user hard
-    wire it when the module is initialized.
-
-======================================================================*/
-
-static struct hw_info *get_hwired(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    u8 addr[ETH_ALEN];
-    int i;
-
-    for (i = 0; i < 6; i++)
-	if (hw_addr[i] != 0) break;
-    if (i == 6)
-	return NULL;
-
-    for (i = 0; i < 6; i++)
-	addr[i] = hw_addr[i];
-    eth_hw_addr_set(dev, addr);
-
-    return &default_info;
-} /* get_hwired */
-
-static int try_io_port(struct pcmcia_device *link)
-{
-    int j, ret;
-    link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-    link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-    if (link->resource[0]->end == 32) {
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-	if (link->resource[1]->end > 0) {
-	    /* for master/slave multifunction cards */
-	    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	}
-    } else {
-	/* This should be two 16-port windows */
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
-    }
-    if (link->resource[0]->start == 0) {
-	for (j = 0; j < 0x400; j += 0x20) {
-	    link->resource[0]->start = j ^ 0x300;
-	    link->resource[1]->start = (j ^ 0x300) + 0x10;
-	    link->io_lines = 16;
-	    ret = pcmcia_request_io(link);
-	    if (ret == 0)
-		    return ret;
-	}
-	return ret;
-    } else {
-	return pcmcia_request_io(link);
-    }
-}
-
-static int pcnet_confcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
-	int *priv = priv_data;
-	int try = (*priv & 0x1);
-
-	*priv &= (p_dev->resource[2]->end >= 0x4000) ? 0x10 : ~0x10;
-
-	if (p_dev->config_index == 0)
-		return -EINVAL;
-
-	if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
-		return -EINVAL;
-
-	if (try)
-		p_dev->io_lines = 16;
-	return try_io_port(p_dev);
-}
-
-static struct hw_info *pcnet_try_config(struct pcmcia_device *link,
-					int *has_shmem, int try)
-{
-	struct net_device *dev = link->priv;
-	struct hw_info *local_hw_info;
-	struct pcnet_dev *info = PRIV(dev);
-	int priv = try;
-	int ret;
-
-	ret = pcmcia_loop_config(link, pcnet_confcheck, &priv);
-	if (ret) {
-		dev_warn(&link->dev, "no useable port range found\n");
-		return NULL;
-	}
-	*has_shmem = (priv & 0x10);
-
-	if (!link->irq)
-		return NULL;
-
-	if (resource_size(link->resource[1]) == 8)
-		link->config_flags |= CONF_ENABLE_SPKR;
-
-	if ((link->manf_id == MANFID_IBM) &&
-	    (link->card_id == PRODID_IBM_HOME_AND_AWAY))
-		link->config_index |= 0x10;
-
-	ret = pcmcia_enable_device(link);
-	if (ret)
-		return NULL;
-
-	dev->irq = link->irq;
-	dev->base_addr = link->resource[0]->start;
-
-	if (info->flags & HAS_MISC_REG) {
-		if ((if_port == 1) || (if_port == 2))
-			dev->if_port = if_port;
-		else
-			dev_notice(&link->dev, "invalid if_port requested\n");
-	} else
-		dev->if_port = 0;
-
-	if ((link->config_base == 0x03c0) &&
-	    (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
-		dev_info(&link->dev,
-			"this is an AX88190 card - use axnet_cs instead.\n");
-		return NULL;
-	}
-
-	local_hw_info = get_hwinfo(link);
-	if (!local_hw_info)
-		local_hw_info = get_prom(link);
-	if (!local_hw_info)
-		local_hw_info = get_dl10019(link);
-	if (!local_hw_info)
-		local_hw_info = get_ax88190(link);
-	if (!local_hw_info)
-		local_hw_info = get_hwired(link);
-
-	return local_hw_info;
-}
-
-static int pcnet_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct pcnet_dev *info = PRIV(dev);
-    int start_pg, stop_pg, cm_offset;
-    int has_shmem = 0;
-    struct hw_info *local_hw_info;
-
-    dev_dbg(&link->dev, "pcnet_config\n");
-
-    local_hw_info = pcnet_try_config(link, &has_shmem, 0);
-    if (!local_hw_info) {
-	    /* check whether forcing io_lines to 16 helps... */
-	    pcmcia_disable_device(link);
-	    local_hw_info = pcnet_try_config(link, &has_shmem, 1);
-	    if (local_hw_info == NULL) {
-		    dev_notice(&link->dev, "unable to read hardware net"
-			    " address for io base %#3lx\n", dev->base_addr);
-		    goto failed;
-	    }
-    }
-
-    info->flags = local_hw_info->flags;
-    /* Check for user overrides */
-    info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
-    if ((link->manf_id == MANFID_SOCKET) &&
-	((link->card_id == PRODID_SOCKET_LPE) ||
-	 (link->card_id == PRODID_SOCKET_LPE_CF) ||
-	 (link->card_id == PRODID_SOCKET_EIO)))
-	info->flags &= ~USE_BIG_BUF;
-    if (!use_big_buf)
-	info->flags &= ~USE_BIG_BUF;
-
-    if (info->flags & USE_BIG_BUF) {
-	start_pg = SOCKET_START_PG;
-	stop_pg = SOCKET_STOP_PG;
-	cm_offset = 0x10000;
-    } else {
-	start_pg = PCNET_START_PG;
-	stop_pg = PCNET_STOP_PG;
-	cm_offset = 0;
-    }
-
-    /* has_shmem is ignored if use_shmem != -1 */
-    if ((use_shmem == 0) || (!has_shmem && (use_shmem == -1)) ||
-	(setup_shmem_window(link, start_pg, stop_pg, cm_offset) != 0))
-	setup_dma_config(link, start_pg, stop_pg);
-
-    ei_status.name = "NE2000";
-    ei_status.word16 = 1;
-    ei_status.reset_8390 = pcnet_reset_8390;
-
-    if (info->flags & (IS_DL10019|IS_DL10022))
-	mii_phy_probe(dev);
-
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-	pr_notice("register_netdev() failed\n");
-	goto failed;
-    }
-
-    if (info->flags & (IS_DL10019|IS_DL10022)) {
-	u_char id = inb(dev->base_addr + 0x1a);
-	netdev_info(dev, "NE2000 (DL100%d rev %02x): ",
-		    (info->flags & IS_DL10022) ? 22 : 19, id);
-	if (info->pna_phy)
-	    pr_cont("PNA, ");
-    } else {
-	netdev_info(dev, "NE2000 Compatible: ");
-    }
-    pr_cont("io %#3lx, irq %d,", dev->base_addr, dev->irq);
-    if (info->flags & USE_SHMEM)
-	pr_cont(" mem %#5lx,", dev->mem_start);
-    if (info->flags & HAS_MISC_REG)
-	pr_cont(" %s xcvr,", if_names[dev->if_port]);
-    pr_cont(" hw_addr %pM\n", dev->dev_addr);
-    return 0;
-
-failed:
-    pcnet_release(link);
-    return -ENODEV;
-} /* pcnet_config */
-
-static void pcnet_release(struct pcmcia_device *link)
-{
-	struct pcnet_dev *info = PRIV(link->priv);
-
-	dev_dbg(&link->dev, "pcnet_release\n");
-
-	if (info->flags & USE_SHMEM)
-		iounmap(info->base);
-
-	pcmcia_disable_device(link);
-}
-
-static int pcnet_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int pcnet_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		pcnet_reset_8390(dev);
-		NS8390_init(dev, 1);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/*======================================================================
-
-    MII interface support for DL10019 and DL10022 based cards
-
-    On the DL10019, the MII IO direction bit is 0x10; on the DL10022
-    it is 0x20.  Setting both bits seems to work on both card types.
-
-======================================================================*/
-
-#define DLINK_GPIO		0x1c
-#define DLINK_DIAG		0x1d
-#define DLINK_EEPROM		0x1e
-
-#define MDIO_SHIFT_CLK		0x80
-#define MDIO_DATA_OUT		0x40
-#define MDIO_DIR_WRITE		0x30
-#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
-#define MDIO_DATA_READ		0x10
-#define MDIO_MASK		0x0f
-
-static void mdio_sync(unsigned int addr)
-{
-    int bits, mask = inb(addr) & MDIO_MASK;
-    for (bits = 0; bits < 32; bits++) {
-	outb(mask | MDIO_DATA_WRITE1, addr);
-	outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-static int mdio_read(unsigned int addr, int phy_id, int loc)
-{
-    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
-    int i, retval = 0, mask = inb(addr) & MDIO_MASK;
-
-    mdio_sync(addr);
-    for (i = 13; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb(mask | dat, addr);
-	outb(mask | dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 19; i > 0; i--) {
-	outb(mask, addr);
-	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
-	outb(mask | MDIO_SHIFT_CLK, addr);
-    }
-    return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
-{
-    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
-    int i, mask = inb(addr) & MDIO_MASK;
-
-    mdio_sync(addr);
-    for (i = 31; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb(mask | dat, addr);
-	outb(mask | dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 1; i >= 0; i--) {
-	outb(mask, addr);
-	outb(mask | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-/*======================================================================
-
-    EEPROM access routines for DL10019 and DL10022 based cards
-
-======================================================================*/
-
-#define EE_EEP		0x40
-#define EE_ASIC		0x10
-#define EE_CS		0x08
-#define EE_CK		0x04
-#define EE_DO		0x02
-#define EE_DI		0x01
-#define EE_ADOT		0x01	/* DataOut for ASIC */
-#define EE_READ_CMD	0x06
-
-#define DL19FDUPLX	0x0400	/* DL10019 Full duplex mode */
-
-static int read_eeprom(unsigned int ioaddr, int location)
-{
-    int i, retval = 0;
-    unsigned int ee_addr = ioaddr + DLINK_EEPROM;
-    int read_cmd = location | (EE_READ_CMD << 8);
-
-    outb(0, ee_addr);
-    outb(EE_EEP|EE_CS, ee_addr);
-
-    /* Shift the read command bits out. */
-    for (i = 10; i >= 0; i--) {
-	short dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
-	outb_p(EE_EEP|EE_CS|dataval, ee_addr);
-	outb_p(EE_EEP|EE_CS|dataval|EE_CK, ee_addr);
-    }
-    outb(EE_EEP|EE_CS, ee_addr);
-
-    for (i = 16; i > 0; i--) {
-	outb_p(EE_EEP|EE_CS | EE_CK, ee_addr);
-	retval = (retval << 1) | ((inb(ee_addr) & EE_DI) ? 1 : 0);
-	outb_p(EE_EEP|EE_CS, ee_addr);
-    }
-
-    /* Terminate the EEPROM access. */
-    outb(0, ee_addr);
-    return retval;
-}
-
-/*
-    The internal ASIC registers can be changed by EEPROM READ access
-    with EE_ASIC bit set.
-    In ASIC mode, EE_ADOT is used to output the data to the ASIC.
-*/
-
-static void write_asic(unsigned int ioaddr, int location, short asic_data)
-{
-	int i;
-	unsigned int ee_addr = ioaddr + DLINK_EEPROM;
-	short dataval;
-	int read_cmd = location | (EE_READ_CMD << 8);
-
-	asic_data |= read_eeprom(ioaddr, location);
-
-	outb(0, ee_addr);
-	outb(EE_ASIC|EE_CS|EE_DI, ee_addr);
-
-	read_cmd = read_cmd >> 1;
-
-	/* Shift the read command bits out. */
-	for (i = 9; i >= 0; i--) {
-		dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
-		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
-		outb_p(EE_ASIC|EE_CS|EE_DI|dataval|EE_CK, ee_addr);
-		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
-	}
-	// sync
-	outb(EE_ASIC|EE_CS, ee_addr);
-	outb(EE_ASIC|EE_CS|EE_CK, ee_addr);
-	outb(EE_ASIC|EE_CS, ee_addr);
-
-	for (i = 15; i >= 0; i--) {
-		dataval = (asic_data & (1 << i)) ? EE_ADOT : 0;
-		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
-		outb_p(EE_ASIC|EE_CS|dataval|EE_CK, ee_addr);
-		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
-	}
-
-	/* Terminate the ASIC access. */
-	outb(EE_ASIC|EE_DI, ee_addr);
-	outb(EE_ASIC|EE_DI| EE_CK, ee_addr);
-	outb(EE_ASIC|EE_DI, ee_addr);
-
-	outb(0, ee_addr);
-}
-
-/*====================================================================*/
-
-static void set_misc_reg(struct net_device *dev)
-{
-    unsigned int nic_base = dev->base_addr;
-    struct pcnet_dev *info = PRIV(dev);
-    u_char tmp;
-
-    if (info->flags & HAS_MISC_REG) {
-	tmp = inb_p(nic_base + PCNET_MISC) & ~3;
-	if (dev->if_port == 2)
-	    tmp |= 1;
-	if (info->flags & USE_BIG_BUF)
-	    tmp |= 2;
-	if (info->flags & HAS_IBM_MISC)
-	    tmp |= 8;
-	outb_p(tmp, nic_base + PCNET_MISC);
-    }
-    if (info->flags & IS_DL10022) {
-	if (info->flags & HAS_MII) {
-	    /* Advertise 100F, 100H, 10F, 10H */
-	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
-	    /* Restart MII autonegotiation */
-	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
-	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
-	    info->mii_reset = jiffies;
-	} else {
-	    outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG);
-	}
-    } else if (info->flags & IS_DL10019) {
-	/* Advertise 100F, 100H, 10F, 10H */
-	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
-	/* Restart MII autonegotiation */
-	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
-	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
-    }
-}
-
-/*====================================================================*/
-
-static void mii_phy_probe(struct net_device *dev)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
-    int i;
-    u_int tmp, phyid;
-
-    for (i = 31; i >= 0; i--) {
-	tmp = mdio_read(mii_addr, i, 1);
-	if ((tmp == 0) || (tmp == 0xffff))
-	    continue;
-	tmp = mdio_read(mii_addr, i, MII_PHYID_REG1);
-	phyid = tmp << 16;
-	phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2);
-	phyid &= MII_PHYID_REV_MASK;
-	netdev_dbg(dev, "MII at %d is 0x%08x\n", i, phyid);
-	if (phyid == AM79C9XX_HOME_PHY) {
-	    info->pna_phy = i;
-	} else if (phyid != AM79C9XX_ETH_PHY) {
-	    info->eth_phy = i;
-	}
-    }
-}
-
-static int pcnet_open(struct net_device *dev)
-{
-    int ret;
-    struct pcnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-    unsigned int nic_base = dev->base_addr;
-
-    dev_dbg(&link->dev, "pcnet_open('%s')\n", dev->name);
-
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-
-    set_misc_reg(dev);
-
-    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
-    ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev->name, dev);
-    if (ret)
-	    return ret;
-
-    link->open++;
-
-    info->phy_id = info->eth_phy;
-    info->link_status = 0x00;
-    timer_setup(&info->watchdog, ei_watchdog, 0);
-    mod_timer(&info->watchdog, jiffies + HZ);
-
-    return ei_open(dev);
-} /* pcnet_open */
-
-/*====================================================================*/
-
-static int pcnet_close(struct net_device *dev)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-
-    dev_dbg(&link->dev, "pcnet_close('%s')\n", dev->name);
-
-    ei_close(dev);
-    free_irq(dev->irq, dev);
-
-    link->open--;
-    netif_stop_queue(dev);
-    timer_delete_sync(&info->watchdog);
-
-    return 0;
-} /* pcnet_close */
-
-/*======================================================================
-
-    Hard reset the card.  This used to pause for the same period that
-    a 8390 reset command required, but that shouldn't be necessary.
-
-======================================================================*/
-
-static void pcnet_reset_8390(struct net_device *dev)
-{
-    unsigned int nic_base = dev->base_addr;
-    int i;
-
-    ei_status.txing = ei_status.dmaing = 0;
-
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
-
-    outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);
-
-    for (i = 0; i < 100; i++) {
-	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
-	    break;
-	udelay(100);
-    }
-    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
-
-    if (i == 100)
-	netdev_err(dev, "pcnet_reset_8390() did not complete.\n");
-
-    set_misc_reg(dev);
-
-} /* pcnet_reset_8390 */
-
-/*====================================================================*/
-
-static int set_config(struct net_device *dev, struct ifmap *map)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-	if (!(info->flags & HAS_MISC_REG))
-	    return -EOPNOTSUPP;
-	else if ((map->port < 1) || (map->port > 2))
-	    return -EINVAL;
-	WRITE_ONCE(dev->if_port, map->port);
-	netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
-	NS8390_init(dev, 1);
-    }
-    return 0;
-}
-
-/*====================================================================*/
-
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    struct pcnet_dev *info;
-    irqreturn_t ret = ei_interrupt(irq, dev_id);
-
-    if (ret == IRQ_HANDLED) {
-	    info = PRIV(dev);
-	    info->stale = 0;
-    }
-    return ret;
-}
-
-static void ei_watchdog(struct timer_list *t)
-{
-    struct pcnet_dev *info = timer_container_of(info, t, watchdog);
-    struct net_device *dev = info->p_dev->priv;
-    unsigned int nic_base = dev->base_addr;
-    unsigned int mii_addr = nic_base + DLINK_GPIO;
-    u_short link;
-
-    if (!netif_device_present(dev)) goto reschedule;
-
-    /* Check for pending interrupt with expired latency timer: with
-       this, we can limp along even if the interrupt is blocked */
-    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
-	if (!info->fast_poll)
-	    netdev_info(dev, "interrupt(s) dropped!\n");
-	ei_irq_wrapper(dev->irq, dev);
-	info->fast_poll = HZ;
-    }
-    if (info->fast_poll) {
-	info->fast_poll--;
-	info->watchdog.expires = jiffies + 1;
-	add_timer(&info->watchdog);
-	return;
-    }
-
-    if (!(info->flags & HAS_MII))
-	goto reschedule;
-
-    mdio_read(mii_addr, info->phy_id, 1);
-    link = mdio_read(mii_addr, info->phy_id, 1);
-    if (!link || (link == 0xffff)) {
-	if (info->eth_phy) {
-	    info->phy_id = info->eth_phy = 0;
-	} else {
-	    netdev_info(dev, "MII is missing!\n");
-	    info->flags &= ~HAS_MII;
-	}
-	goto reschedule;
-    }
-
-    link &= 0x0004;
-    if (link != info->link_status) {
-	u_short p = mdio_read(mii_addr, info->phy_id, 5);
-	netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
-	if (link && (info->flags & IS_DL10022)) {
-	    /* Disable collision detection on full duplex links */
-	    outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);
-	} else if (link && (info->flags & IS_DL10019)) {
-	    /* Disable collision detection on full duplex links */
-	    write_asic(dev->base_addr, 4, (p & 0x140) ? DL19FDUPLX : 0);
-	}
-	if (link) {
-	    if (info->phy_id == info->eth_phy) {
-		if (p)
-		    netdev_info(dev, "autonegotiation complete: "
-				"%sbaseT-%cD selected\n",
-				((p & 0x0180) ? "100" : "10"),
-				((p & 0x0140) ? 'F' : 'H'));
-		else
-		    netdev_info(dev, "link partner did not autonegotiate\n");
-	    }
-	    NS8390_init(dev, 1);
-	}
-	info->link_status = link;
-    }
-    if (info->pna_phy && time_after(jiffies, info->mii_reset + 6*HZ)) {
-	link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004;
-	if (((info->phy_id == info->pna_phy) && link) ||
-	    ((info->phy_id != info->pna_phy) && !link)) {
-	    /* isolate this MII and try flipping to the other one */
-	    mdio_write(mii_addr, info->phy_id, 0, 0x0400);
-	    info->phy_id ^= info->pna_phy ^ info->eth_phy;
-	    netdev_info(dev, "switched to %s transceiver\n",
-			(info->phy_id == info->eth_phy) ? "ethernet" : "PNA");
-	    mdio_write(mii_addr, info->phy_id, 0,
-		       (info->phy_id == info->eth_phy) ? 0x1000 : 0);
-	    info->link_status = 0;
-	    info->mii_reset = jiffies;
-	}
-    }
-
-reschedule:
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
-}
-
-/*====================================================================*/
-
-
-static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    struct mii_ioctl_data *data = if_mii(rq);
-    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
-
-    if (!(info->flags & (IS_DL10019|IS_DL10022)))
-	return -EINVAL;
-
-    switch (cmd) {
-    case SIOCGMIIPHY:
-	data->phy_id = info->phy_id;
-	fallthrough;
-    case SIOCGMIIREG:		/* Read MII PHY register. */
-	data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
-	return 0;
-    case SIOCSMIIREG:		/* Write MII PHY register. */
-	mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in);
-	return 0;
-    }
-    return -EOPNOTSUPP;
-}
-
-/*====================================================================*/
-
-static void dma_get_8390_hdr(struct net_device *dev,
-			     struct e8390_pkt_hdr *hdr,
-			     int ring_page)
-{
-    unsigned int nic_base = dev->base_addr;
-
-    if (ei_status.dmaing) {
-	netdev_err(dev, "DMAing conflict in dma_block_input."
-		   "[DMAstat:%1x][irqlock:%1x]\n",
-		   ei_status.dmaing, ei_status.irqlock);
-	return;
-    }
-
-    ei_status.dmaing |= 0x01;
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
-    outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
-    outb_p(0, nic_base + EN0_RCNTHI);
-    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
-    outb_p(ring_page, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
-
-    insw(nic_base + PCNET_DATAPORT, hdr,
-	    sizeof(struct e8390_pkt_hdr)>>1);
-    /* Fix for big endian systems */
-    hdr->count = le16_to_cpu(hdr->count);
-
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
-    ei_status.dmaing &= ~0x01;
-}
-
-/*====================================================================*/
-
-static void dma_block_input(struct net_device *dev, int count,
-			    struct sk_buff *skb, int ring_offset)
-{
-    unsigned int nic_base = dev->base_addr;
-    int xfer_count = count;
-    char *buf = skb->data;
-    struct ei_device *ei_local = netdev_priv(dev);
-
-    if ((netif_msg_rx_status(ei_local)) && (count != 4))
-	netdev_dbg(dev, "[bi=%d]\n", count+4);
-    if (ei_status.dmaing) {
-	netdev_err(dev, "DMAing conflict in dma_block_input."
-		   "[DMAstat:%1x][irqlock:%1x]\n",
-		   ei_status.dmaing, ei_status.irqlock);
-	return;
-    }
-    ei_status.dmaing |= 0x01;
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
-    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-    outb_p(count >> 8, nic_base + EN0_RCNTHI);
-    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
-    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
-
-    insw(nic_base + PCNET_DATAPORT,buf,count>>1);
-    if (count & 0x01) {
-	buf[count-1] = inb(nic_base + PCNET_DATAPORT);
-	xfer_count++;
-    }
-
-    /* This was for the ALPHA version only, but enough people have been
-       encountering problems that it is still here. */
-#ifdef PCMCIA_DEBUG
-      /* DMA termination address check... */
-    if (netif_msg_rx_status(ei_local)) {
-	int addr, tries = 20;
-	do {
-	    /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
-	       -- it's broken for Rx on some cards! */
-	    int high = inb_p(nic_base + EN0_RSARHI);
-	    int low = inb_p(nic_base + EN0_RSARLO);
-	    addr = (high << 8) + low;
-	    if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff))
-		break;
-	} while (--tries > 0);
-	if (tries <= 0)
-	    netdev_notice(dev, "RX transfer address mismatch,"
-			  "%#4.4x (expected) vs. %#4.4x (actual).\n",
-			  ring_offset + xfer_count, addr);
-    }
-#endif
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
-    ei_status.dmaing &= ~0x01;
-} /* dma_block_input */
-
-/*====================================================================*/
-
-static void dma_block_output(struct net_device *dev, int count,
-			     const u_char *buf, const int start_page)
-{
-    unsigned int nic_base = dev->base_addr;
-    struct pcnet_dev *info = PRIV(dev);
-#ifdef PCMCIA_DEBUG
-    int retries = 0;
-    struct ei_device *ei_local = netdev_priv(dev);
-#endif
-    u_long dma_start;
-
-#ifdef PCMCIA_DEBUG
-    netif_dbg(ei_local, tx_queued, dev, "[bo=%d]\n", count);
-#endif
-
-    /* Round the count up for word writes.  Do we need to do this?
-       What effect will an odd byte count have on the 8390?
-       I should check someday. */
-    if (count & 0x01)
-	count++;
-    if (ei_status.dmaing) {
-	netdev_err(dev, "DMAing conflict in dma_block_output."
-		   "[DMAstat:%1x][irqlock:%1x]\n",
-		   ei_status.dmaing, ei_status.irqlock);
-	return;
-    }
-    ei_status.dmaing |= 0x01;
-    /* We should already be in page 0, but to be safe... */
-    outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD);
-
-#ifdef PCMCIA_DEBUG
-  retry:
-#endif
-
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);
-
-    /* Now the normal output. */
-    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-    outb_p(count >> 8,   nic_base + EN0_RCNTHI);
-    outb_p(0x00, nic_base + EN0_RSARLO);
-    outb_p(start_page, nic_base + EN0_RSARHI);
-
-    outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD);
-    outsw(nic_base + PCNET_DATAPORT, buf, count>>1);
-
-    dma_start = jiffies;
-
-#ifdef PCMCIA_DEBUG
-    /* This was for the ALPHA version only, but enough people have been
-       encountering problems that it is still here. */
-    /* DMA termination address check... */
-    if (netif_msg_tx_queued(ei_local)) {
-	int addr, tries = 20;
-	do {
-	    int high = inb_p(nic_base + EN0_RSARHI);
-	    int low = inb_p(nic_base + EN0_RSARLO);
-	    addr = (high << 8) + low;
-	    if ((start_page << 8) + count == addr)
-		break;
-	} while (--tries > 0);
-	if (tries <= 0) {
-	    netdev_notice(dev, "Tx packet transfer address mismatch,"
-			  "%#4.4x (expected) vs. %#4.4x (actual).\n",
-			  (start_page << 8) + count, addr);
-	    if (retries++ == 0)
-		goto retry;
-	}
-    }
-#endif
-
-    while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
-	if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) {
-		netdev_warn(dev, "timeout waiting for Tx RDC.\n");
-		pcnet_reset_8390(dev);
-		NS8390_init(dev, 1);
-		break;
-	}
-
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
-    if (info->flags & DELAY_OUTPUT)
-	udelay((long)delay_time);
-    ei_status.dmaing &= ~0x01;
-}
-
-/*====================================================================*/
-
-static int setup_dma_config(struct pcmcia_device *link, int start_pg,
-			    int stop_pg)
-{
-    struct net_device *dev = link->priv;
-
-    ei_status.tx_start_page = start_pg;
-    ei_status.rx_start_page = start_pg + TX_PAGES;
-    ei_status.stop_page = stop_pg;
-
-    /* set up block i/o functions */
-    ei_status.get_8390_hdr = dma_get_8390_hdr;
-    ei_status.block_input = dma_block_input;
-    ei_status.block_output = dma_block_output;
-
-    return 0;
-}
-
-/*====================================================================*/
-
-static void copyin(void *dest, void __iomem *src, int c)
-{
-    u_short *d = dest;
-    u_short __iomem *s = src;
-    int odd;
-
-    if (c <= 0)
-	return;
-    odd = (c & 1); c >>= 1;
-
-    if (c) {
-	do { *d++ = __raw_readw(s++); } while (--c);
-    }
-    /* get last byte by fetching a word and masking */
-    if (odd)
-	*((u_char *)d) = readw(s) & 0xff;
-}
-
-static void copyout(void __iomem *dest, const void *src, int c)
-{
-    u_short __iomem *d = dest;
-    const u_short *s = src;
-    int odd;
-
-    if (c <= 0)
-	return;
-    odd = (c & 1); c >>= 1;
-
-    if (c) {
-	do { __raw_writew(*s++, d++); } while (--c);
-    }
-    /* copy last byte doing a read-modify-write */
-    if (odd)
-	writew((readw(d) & 0xff00) | *(u_char *)s, d);
-}
-
-/*====================================================================*/
-
-static void shmem_get_8390_hdr(struct net_device *dev,
-			       struct e8390_pkt_hdr *hdr,
-			       int ring_page)
-{
-    void __iomem *xfer_start = ei_status.mem + (TX_PAGES<<8)
-				+ (ring_page << 8)
-				- (ei_status.rx_start_page << 8);
-
-    copyin(hdr, xfer_start, sizeof(struct e8390_pkt_hdr));
-    /* Fix for big endian systems */
-    hdr->count = le16_to_cpu(hdr->count);
-}
-
-/*====================================================================*/
-
-static void shmem_block_input(struct net_device *dev, int count,
-			      struct sk_buff *skb, int ring_offset)
-{
-    void __iomem *base = ei_status.mem;
-    unsigned long offset = (TX_PAGES<<8) + ring_offset
-				- (ei_status.rx_start_page << 8);
-    char *buf = skb->data;
-
-    if (offset + count > ei_status.priv) {
-	/* We must wrap the input move. */
-	int semi_count = ei_status.priv - offset;
-	copyin(buf, base + offset, semi_count);
-	buf += semi_count;
-	offset = TX_PAGES<<8;
-	count -= semi_count;
-    }
-    copyin(buf, base + offset, count);
-}
-
-/*====================================================================*/
-
-static void shmem_block_output(struct net_device *dev, int count,
-			       const u_char *buf, const int start_page)
-{
-    void __iomem *shmem = ei_status.mem + (start_page << 8);
-    shmem -= ei_status.tx_start_page << 8;
-    copyout(shmem, buf, count);
-}
-
-/*====================================================================*/
-
-static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
-			      int stop_pg, int cm_offset)
-{
-    struct net_device *dev = link->priv;
-    struct pcnet_dev *info = PRIV(dev);
-    int i, window_size, offset, ret;
-
-    window_size = (stop_pg - start_pg) << 8;
-    if (window_size > 32 * 1024)
-	window_size = 32 * 1024;
-
-    /* Make sure it's a power of two.  */
-    window_size = roundup_pow_of_two(window_size);
-
-    /* Allocate a memory window */
-    link->resource[3]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    link->resource[3]->flags |= WIN_USE_WAIT;
-    link->resource[3]->start = 0; link->resource[3]->end = window_size;
-    ret = pcmcia_request_window(link, link->resource[3], mem_speed);
-    if (ret)
-	    goto failed;
-
-    offset = (start_pg << 8) + cm_offset;
-    offset -= offset % window_size;
-    ret = pcmcia_map_mem_page(link, link->resource[3], offset);
-    if (ret)
-	    goto failed;
-
-    /* Try scribbling on the buffer */
-    info->base = ioremap(link->resource[3]->start,
-			resource_size(link->resource[3]));
-    if (unlikely(!info->base)) {
-	    ret = -ENOMEM;
-	    goto failed;
-    }
-
-    for (i = 0; i < (TX_PAGES<<8); i += 2)
-	__raw_writew((i>>1), info->base+offset+i);
-    udelay(100);
-    for (i = 0; i < (TX_PAGES<<8); i += 2)
-	if (__raw_readw(info->base+offset+i) != (i>>1)) break;
-    pcnet_reset_8390(dev);
-    if (i != (TX_PAGES<<8)) {
-	iounmap(info->base);
-	pcmcia_release_window(link, link->resource[3]);
-	info->base = NULL;
-	goto failed;
-    }
-
-    ei_status.mem = info->base + offset;
-    ei_status.priv = resource_size(link->resource[3]);
-    dev->mem_start = (u_long)ei_status.mem;
-    dev->mem_end = dev->mem_start + resource_size(link->resource[3]);
-
-    ei_status.tx_start_page = start_pg;
-    ei_status.rx_start_page = start_pg + TX_PAGES;
-    ei_status.stop_page = start_pg + (
-	    (resource_size(link->resource[3]) - offset) >> 8);
-
-    /* set up block i/o functions */
-    ei_status.get_8390_hdr = shmem_get_8390_hdr;
-    ei_status.block_input = shmem_block_input;
-    ei_status.block_output = shmem_block_output;
-
-    info->flags |= USE_SHMEM;
-    return 0;
-
-failed:
-    return 1;
-}
-
-/*====================================================================*/
-
-static const struct pcmcia_device_id pcnet_ids[] = {
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0x3341),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0xc0ab),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
-	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
-	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
-	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
-	PCMCIA_MFC_DEVICE_PROD_ID123(0, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
-	PCMCIA_MFC_DEVICE_PROD_ID2(0, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
-	PCMCIA_DEVICE_MANF_CARD(0x0057, 0x1004),
-	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x000d),
-	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0075),
-	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0145),
-	PCMCIA_DEVICE_MANF_CARD(0x0149, 0x0230),
-	PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
-	PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab),
-	PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
-	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
-	PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0307),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
-	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
-	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
-	PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0009),
-	PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID1234("Socket", "CF 10/100 Ethernet Card", "Revision B", "05/11/06", 0xb38bcc2e, 0x4de88352, 0xeaca6c8d, 0x7e57c22e),
-	PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("CNet  ", "CN30BC", "ETHERNET", 0x9fe55d3d, 0x85601198, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("Digital", "Ethernet", "Adapter", 0x9999ab35, 0x00b2e941, 0x4b0d829e),
-	PCMCIA_DEVICE_PROD_ID123("Edimax Technology Inc.", "PCMCIA", "Ethernet Card", 0x738a0019, 0x281f1c5d, 0x5e9d92c0),
-	PCMCIA_DEVICE_PROD_ID123("EFA   ", "EFA207", "ETHERNET", 0x3d294be4, 0xeb9aab6c, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("I-O DATA", "PCLA", "ETHERNET", 0x1d55d7ec, 0xe4c64d34, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCLATE", "ETHERNET", 0x547e66dc, 0x6b260753, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("KingMax Technology Inc.", "EN10-T2", "PCMCIA Ethernet Card", 0x932b7189, 0x699e4436, 0x6f6652e0),
-	PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216", 0x281f1c5d, 0xd4cd2f20, 0xb87add82),
-	PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2620", 0x281f1c5d, 0xd4cd2f20, 0x7d3d83a8),
-	PCMCIA_DEVICE_PROD_ID1("2412LAN", 0x67f236ab),
-	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2212", 0xdfc6b5b2, 0xcb112a11),
-	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002", 0x93b15570, 0x75ec3efb),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002T", 0x93b15570, 0x461c5247),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8010", 0x93b15570, 0x82f96e96),
-	PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet", 0x578ba6e7, 0x0a9888c1),
-	PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet 10/100", 0x578ba6e7, 0x939fedbd),
-	PCMCIA_DEVICE_PROD_ID12("AROWANA", "PCMCIA Ethernet LAN Card", 0x313adbc8, 0x08d9f190),
-	PCMCIA_DEVICE_PROD_ID12("ASANTE", "FriendlyNet PC Card", 0x3a7ade0f, 0x41c64504),
-	PCMCIA_DEVICE_PROD_ID12("Billionton", "LNT-10TB", 0x552ab682, 0xeeb1ba6a),
-	PCMCIA_DEVICE_PROD_ID12("CF", "10Base-Ethernet", 0x44ebf863, 0x93ae4d79),
-	PCMCIA_DEVICE_PROD_ID12("CNet", "CN40BC Ethernet", 0xbc477dde, 0xfba775a7),
-	PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "BASEline PCMCIA 10 MBit Ethernetadapter", 0xfa2e424d, 0xe9190d8a),
-	PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9),
-	PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
-	PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
-	PCMCIA_DEVICE_PROD_ID12("corega", "Ether CF-TD", 0x0a21501a, 0x6589340a),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether CF-TD LAN Card", 0x5261440f, 0x8797663b),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d),
-	PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-TD", 0x5261440f, 0x47d5ca83),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
-	PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
-	PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "(CG-LAPCCTXD)", 0x5261440f, 0x73ec0d88),
-	PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04),
-	PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d),
-	PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814),
-	PCMCIA_DEVICE_PROD_ID12("DataTrek.", "NetCard ", 0x5cd66d9d, 0x84697ce0),
-	PCMCIA_DEVICE_PROD_ID12("Dayna Communications, Inc.", "CommuniCard E", 0x0c629325, 0xb4e7dbaf),
-	PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100", 0x697403d8, 0xe160b995),
-	PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100 Dongless", 0x697403d8, 0xa6d3b233),
-	PCMCIA_DEVICE_PROD_ID12("DIGITAL", "DEPCM-XX", 0x69616cb3, 0xe600e76e),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-650", 0x1a424a1c, 0xf28c8398),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660", 0x1a424a1c, 0xd9a1d05b),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660+", 0x1a424a1c, 0x50dcd0ec),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DFE-650", 0x1a424a1c, 0x0f0073f9),
-	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 PC Card", 0x725b842d, 0xf1efee84),
-	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x725b842d, 0x2db1f8e9),
-	PCMCIA_DEVICE_PROD_ID12("Dynalink", "L10BC", 0x55632fd5, 0xdc65f2b1),
-	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10BC", 0x6a26d1cf, 0xdc65f2b1),
-	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10C", 0x6a26d1cf, 0xc4f84efb),
-	PCMCIA_DEVICE_PROD_ID12("E-CARD", "E-CARD", 0x6701da11, 0x6701da11),
-	PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet 10BaseT card", 0x53c864c6, 0xedd059f6),
-	PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet Combo card", 0x53c864c6, 0x929c486c),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet", "Adapter", 0x00b2e941, 0x4b0d829e),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet Adapter", "E2000 PCMCIA Ethernet", 0x96767301, 0x71fbbc61),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet PCMCIA adapter", "EP-210", 0x8dd86181, 0xf2b52517),
-	PCMCIA_DEVICE_PROD_ID12("Fast Ethernet", "Adapter", 0xb4be14e3, 0x4b0d829e),
-	PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2000", 0x2a151fac, 0xf00555cb),
-	PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2220", 0x2a151fac, 0xc1b7e327),
-	PCMCIA_DEVICE_PROD_ID12("GVC", "NIC-2000p", 0x76e171bd, 0x6eb1c947),
-	PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "Ethernet", 0xe3736c88, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("IC-CARD", "IC-CARD", 0x60cb09a6, 0x60cb09a6),
-	PCMCIA_DEVICE_PROD_ID12("IC-CARD+", "IC-CARD+", 0x93693494, 0x93693494),
-	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b),
-	PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0),
-	PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956),
-	PCMCIA_DEVICE_PROD_ID12("KENTRONICS", "KEP-230", 0xaf8144c9, 0x868f6616),
-	PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d3, 0x1eb88e64),
-	PCMCIA_DEVICE_PROD_ID12("KINGMAX", "EN10T2T", 0x7bcb459a, 0xa5c81fa5),
-	PCMCIA_DEVICE_PROD_ID12("Kingston", "KNE-PC2", 0x1128e633, 0xce2a89b3),
-	PCMCIA_DEVICE_PROD_ID12("Kingston Technology Corp.", "EtheRx PC Card Ethernet Adapter", 0x313c7be3, 0x0afb54a2),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-10/100CD", 0x1b7827b2, 0xcda71d1c),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
-	PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
-	PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100)", 0x0733cc81, 0x66c5a389),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline + 10/100 Network PC Card (PCM100H1)", 0x733cc81, 0x7a3e5c3a),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TE", 0x88fcdeda, 0x0e714bee),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN10TE", 0x88fcdeda, 0xc1e2521c),
-	PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
-	PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578),
-	PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307),
-	PCMCIA_DEVICE_PROD_ID12("Matsushita Electric Industrial Co.,LTD.", "CF-VEL211", 0x44445376, 0x8ded41d4),
-	PCMCIA_DEVICE_PROD_ID12("MAXTECH", "PCN2000", 0x78d64bc0, 0xca0ca4b8),
-	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-T", 0x481e0094, 0xa2eb0cf3),
-	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-TX", 0x481e0094, 0x41a6916c),
-	PCMCIA_DEVICE_PROD_ID12("Microcom C.E.", "Travel Card LAN 10/100", 0x4b91cec7, 0xe70220d6),
-	PCMCIA_DEVICE_PROD_ID12("Microdyne", "NE4200", 0x2e6da59b, 0x0478e472),
-	PCMCIA_DEVICE_PROD_ID12("MIDORI ELEC.", "LT-PCMT", 0x648d55c1, 0xbde526c7),
-	PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover 4100", 0x36e1191f, 0x60c229b9),
-	PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x36e1191f, 0xa6617ec8),
-	PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J12", 0x18df0ba0, 0xbc912d76),
-	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA410TX", 0x9aa79dc3, 0x60e5bc0e),
-	PCMCIA_DEVICE_PROD_ID12("Network Everywhere", "Fast Ethernet 10/100 PC Card", 0x820a67b6, 0x31ed1a5f),
-	PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050ef1),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100Mbps Ethernet Card", 0x281f1c5d, 0x6e41773b),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet", 0x281f1c5d, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET", 0x281f1c5d, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet 10BaseT Card", 0x281f1c5d, 0x4de2f6c8),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Card", 0x281f1c5d, 0x5e9d92c0),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Combo card", 0x281f1c5d, 0x929c486c),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET V1.0", 0x281f1c5d, 0x4d8817c8),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEthernet", 0x281f1c5d, 0xfe871eeb),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast-Ethernet", 0x281f1c5d, 0x45f1f3b4),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FAST ETHERNET CARD", 0x281f1c5d, 0xec5dbca7),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA LAN", "Ethernet", 0x7500e246, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "LNT-10TN", 0x281f1c5d, 0xe707f641),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "UE2212", 0x281f1c5d, 0xbf17199b),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "    Ethernet NE2000 Compatible", 0x281f1c5d, 0x42d5d7e1),
-	PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10baseT 3.3V", 0xebf91155, 0x30074c80),
-	PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50),
-	PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110),
-	PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("RIOS Systems Co.", "PC CARD3 ETHERNET", 0x7dd33481, 0x10b41826),
-	PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df),
-	PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0),
-	PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd),
-	PCMCIA_DEVICE_PROD_ID12("RPTI LTD.", "EP400", 0xc53ac515, 0x81e39388),
-	PCMCIA_DEVICE_PROD_ID12("SCM", "Ethernet Combo card", 0xbdc3b102, 0x929c486c),
-	PCMCIA_DEVICE_PROD_ID12("Seiko Epson Corp.", "Ethernet", 0x09928730, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("SMC", "EZCard-10-PCMCIA", 0xc4f8b18b, 0xfb21d265),
-	PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision D", 0xc70a4760, 0x2ade483e),
-	PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision E", 0xc70a4760, 0x5dd978a8),
-	PCMCIA_DEVICE_PROD_ID12("TDK", "LAK-CD031 for PCMCIA", 0x1eae9475, 0x0ed386fa),
-	PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE450T", 0x466b05f0, 0x8b74bc4f),
-	PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE550T", 0x466b05f0, 0x33c8db2a),
-	PCMCIA_DEVICE_PROD_ID13("Hypertec",  "EP401", 0x8787bec7, 0xf6e4a31e),
-	PCMCIA_DEVICE_PROD_ID13("KingMax Technology Inc.", "Ethernet Card", 0x932b7189, 0x5e9d92c0),
-	PCMCIA_DEVICE_PROD_ID13("LONGSHINE", "EP401", 0xf866b0b0, 0xf6e4a31e),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "CFE-10", 0x2e3ee845, 0x22a49f89),
-	PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
-	PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
-	PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
-	PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
-	PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
-	/* too generic! */
-	/* PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100 Ethernet Card", 0x281f1c5d, 0x11b0ffc0), */
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
-	PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
-	PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
-	PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("Allied Telesis,K.K", "Ethernet LAN Card", 0x2ad62f3c, 0x9fd2f0a2, "cis/LA-PCM.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "cis/PE520.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("PMX   ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "cis/PE-200.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "cis/tamarack.cis"),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet", "CF Size PC Card", 0x00b2e941, 0x43ac239b),
-	PCMCIA_DEVICE_PROD_ID123("Fast Ethernet", "CF Size PC Card", "1.0",
-		0xb4be14e3, 0x43ac239b, 0x0877b627),
-	PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, pcnet_ids);
-MODULE_FIRMWARE("cis/PCMLM28.cis");
-MODULE_FIRMWARE("cis/DP83903.cis");
-MODULE_FIRMWARE("cis/LA-PCM.cis");
-MODULE_FIRMWARE("cis/PE520.cis");
-MODULE_FIRMWARE("cis/NE2K.cis");
-MODULE_FIRMWARE("cis/PE-200.cis");
-MODULE_FIRMWARE("cis/tamarack.cis");
-
-static struct pcmcia_driver pcnet_driver = {
-	.name		= "pcnet_cs",
-	.probe		= pcnet_probe,
-	.remove		= pcnet_detach,
-	.owner		= THIS_MODULE,
-	.id_table	= pcnet_ids,
-	.suspend	= pcnet_suspend,
-	.resume		= pcnet_resume,
-};
-module_pcmcia_driver(pcnet_driver);

-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH] dt-bindings: Fix phandle-array constraints, again
From: Mark Brown @ 2026-04-21 20:00 UTC (permalink / raw)
  To: Rob Herring (Arm)
  Cc: Maarten Lankhorst, Maxime Ripard, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson, Stephan Gerhold, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Johannes Berg, Jeff Johnson, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Andersson,
	Mathieu Poirier, Sylwester Nawrocki, Maxime Coquelin,
	Greg Kroah-Hartman, Yang Xiwen, Alex Elder, Chaitanya Chundru,
	Sibi Sankar, Rao Mandadapu, Patrice Chotard, Xu Yang, Peng Fan,
	Thomas Zimmermann, devicetree, linux-kernel, linux-mmc,
	linux-arm-msm, netdev, linux-wireless, ath10k, ath11k, linux-pci,
	linux-remoteproc, linux-sound, linux-spi, linux-usb
In-Reply-To: <20260421195836.1547469-1-robh@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 292 bytes --]

On Tue, Apr 21, 2026 at 02:55:25PM -0500, Rob Herring (Arm) wrote:
> The unfortunately named 'phandle-array' property type is really a matrix
> with phandle and fixed arg cells entries. A matrix property should have 2
> levels of items constraints.

Acked-by: Mark Brown <broonie@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH v11 4/4] stmmac: s32: enable support for Multi-IRQ mode
From: Jared Kangas @ 2026-04-21 20:02 UTC (permalink / raw)
  To: jan.petrous
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Maxime Coquelin, Alexandre Torgue, Chester Lin,
	Matthias Brugger, Ghennadi Procopciuc, NXP S32 Linux Team,
	Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li, netdev,
	linux-stm32, linux-arm-kernel, linux-kernel, imx, devicetree,
	rmk+kernel, vladimir.oltean, boon.khai.ng
In-Reply-To: <20260312-dwmac_multi_irq-v11-4-09621ccb040b@oss.nxp.com>

Hi Jan,

On Thu, Mar 12, 2026 at 09:55:30AM +0100, Jan Petrous via B4 Relay wrote:
> From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
> 
> Based on previous changes in platform driver, the vendor
> glue driver can enable Multi-IRQ mode, if needed.
> 
> [...]
> 
> If those prerequisites are met, the driver switches to Multi-IRQ mode,
> using per-queue IRQs for rx/tx data pathr:
> 
> [    1.387045] s32-dwmac 4033c000.ethernet: Multi-IRQ mode (per queue IRQs) selected
> 
> Now the driver owns all queues IRQs:
> 
> root@s32g399aevb3:~# grep eth /proc/interrupts
>  29:    0    0    0    0    0    0    0    0    GICv3  89 Level   eth0:mac
>  30:    0    0    0    0    0    0    0    0    GICv3  91 Level   eth0:rx-0
>  31:    0    0    0    0    0    0    0    0    GICv3  93 Level   eth0:rx-1
>  32:    0    0    0    0    0    0    0    0    GICv3  95 Level   eth0:rx-2
>  33:    0    0    0    0    0    0    0    0    GICv3  97 Level   eth0:rx-3
>  34:    0    0    0    0    0    0    0    0    GICv3  99 Level   eth0:rx-4
>  35:    0    0    0    0    0    0    0    0    GICv3  90 Level   eth0:tx-0
>  36:    0    0    0    0    0    0    0    0    GICv3  92 Level   eth0:tx-1
>  37:    0    0    0    0    0    0    0    0    GICv3  94 Level   eth0:tx-2
>  38:    0    0    0    0    0    0    0    0    GICv3  96 Level   eth0:tx-3
>  39:    0    0    0    0    0    0    0    0    GICv3  98 Level   eth0:tx-4

I ran this series' changes on an NXP S32G-VNP-RDB3 (dwmac-s32) and
confirmed multichannel TX by doing a basic iperf3 throughput test:

    # dmesg | grep Multi-IRQ
    [   37.463467] s32-dwmac 4033c000.ethernet: Multi-IRQ mode (per queue IRQs) selected
    # iperf3 -s
    [connection logs snipped]
    # grep end0 /proc/interrupts | column -t
    29:  0      0  0  0  0  0  0  0  GICv3  89  Level  end0:mac
    30:  968    0  0  0  0  0  0  0  GICv3  90  Level  end0:tx-0
    31:  0      3  0  0  0  0  0  0  GICv3  92  Level  end0:tx-1
    32:  0      0  3  0  0  0  0  0  GICv3  94  Level  end0:tx-2
    33:  0      0  0  3  0  0  0  0  GICv3  96  Level  end0:tx-3
    34:  0      0  0  0  3  0  0  0  GICv3  98  Level  end0:tx-4
    35:  67302  0  0  0  0  0  0  0  GICv3  91  Level  end0:rx-0
    36:  0      0  0  0  0  0  0  0  GICv3  93  Level  end0:rx-1
    37:  0      0  0  0  0  0  0  0  GICv3  95  Level  end0:rx-2
    38:  0      0  0  0  0  0  0  0  GICv3  97  Level  end0:rx-3
    39:  0      0  0  0  0  0  0  0  GICv3  99  Level  end0:rx-4

Also tried out multichannel RX by adding 'snps,route-multi-broad' to
rx-queues-config/queue2 in the devicetree, which showed activity on
the corresponding rx-2 entry:

    # grep end0 /proc/interrupts | column -t
    29:  0   0  0   0  0  0  0  0  GICv3  89  Level  end0:mac
    30:  4   0  0   0  0  0  0  0  GICv3  90  Level  end0:tx-0
    31:  0   1  0   0  0  0  0  0  GICv3  92  Level  end0:tx-1
    32:  0   0  1   0  0  0  0  0  GICv3  94  Level  end0:tx-2
    33:  0   0  0   0  0  0  0  0  GICv3  96  Level  end0:tx-3
    34:  0   0  0   0  1  0  0  0  GICv3  98  Level  end0:tx-4
    35:  68  0  0   0  0  0  0  0  GICv3  91  Level  end0:rx-0
    36:  0   0  0   0  0  0  0  0  GICv3  93  Level  end0:rx-1
    37:  0   0  91  0  0  0  0  0  GICv3  95  Level  end0:rx-2
    38:  0   0  0   0  0  0  0  0  GICv3  97  Level  end0:rx-3
    39:  0   0  0   0  0  0  0  0  GICv3  99  Level  end0:rx-4

I didn't see any regressions with light network usage, and both TX/RX
appear to function as expected.

Tested-by: Jared Kangas <jkangas@redhat.com>


^ permalink raw reply

* Re: [PATCH] net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit()
From: Michal Pecio @ 2026-04-21 20:05 UTC (permalink / raw)
  To: Morduan Zang
  Cc: petkan, davem, edumazet, kuba, pabeni, andrew+netdev, linux-usb,
	netdev, linux-kernel, syzkaller-bugs, Zhan Jun,
	syzbot+3f46c095ac0ca048cb71
In-Reply-To: <73ACB7391A6DE033+20260421110412.14795-1-zhangdandan@uniontech.com>

On Tue, 21 Apr 2026 19:04:12 +0800, Morduan Zang wrote:
> From: Zhan Jun <zhanjun@uniontech.com>
> 
> syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit()
> when accessing skb->len for tx statistics after usb_submit_urb() has
> been called:
> 
>   BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760
>     drivers/net/usb/rtl8150.c:712
>   Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226
> 
> The URB completion handler write_bulk_callback() frees the skb via
> dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU
> in softirq context before usb_submit_urb() returns in the submitter,
> so by the time the submitter reads skb->len the skb has already been
> queued to the per-CPU completion_queue and freed by net_tx_action():
> 
>   CPU A (xmit)                      CPU B (USB completion softirq)
>   ------------                      ------------------------------
>   dev->tx_skb = skb;
>   usb_submit_urb()      --+
>                           |-------> write_bulk_callback()
>                           |           dev_kfree_skb_irq(dev->tx_skb)
>                           |         net_tx_action()
>                           |           napi_skb_cache_put()   <-- free
>   netdev->stats.tx_bytes  |
>     += skb->len;          <-- UAF read
> 
> Fix it by caching skb->len before submitting the URB and using the
> cached value when updating the tx_bytes counter.

Question:
Is it correct that ETH_ZLEN padding isn't counted in tx_bytes?

> This mirrors the fix pattern used by other USB network drivers.

Which ones? I looked at a few and they either:

- appear to have the same bug (kaweth)
- update stats on URB completion, right before freeing skb
- copy data out of skb, update stats, free skb before URB completion

Regards,
Michal

^ permalink raw reply

* Re: [PATCH v11 2/4] arm64: dts: s32: set Ethernet channel irqs
From: Jared Kangas @ 2026-04-21 20:07 UTC (permalink / raw)
  To: jan.petrous
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Maxime Coquelin, Alexandre Torgue, Chester Lin,
	Matthias Brugger, Ghennadi Procopciuc, NXP S32 Linux Team,
	Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li, netdev,
	linux-stm32, linux-arm-kernel, linux-kernel, imx, devicetree,
	rmk+kernel, vladimir.oltean, boon.khai.ng
In-Reply-To: <20260312-dwmac_multi_irq-v11-2-09621ccb040b@oss.nxp.com>

On Thu, Mar 12, 2026 at 09:55:28AM +0100, Jan Petrous via B4 Relay wrote:
> From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
> 
> The GMAC Ethernet controller found on S32G2/S32G3 and S32R45
> contains up to 5 RX and 5 TX channels.
> It can operate in two interrupt modes:
> 
>   1) Sharing IRQ mode: only MAC IRQ line is used
>      for all channels.
> 
>   2) Multiple IRQ mode: every channel uses two IRQ lines,
>      one for RX and second for TX.
> 
> Specify all IRQ twins for all channels.
> 
> Reviewed-by: Matthias Brugger <mbrugger@suse.com>
> Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
> ---

Tested the new channels on an S32G-VNP-RDB3 while testing patch 4/4.

Tested-by: Jared Kangas <jkangas@redhat.com>


^ permalink raw reply

* [PATCH iproute2] lib: add input validation for time, rate, and size parsing functions
From: Stephen Hemminger @ 2026-04-21 20:23 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger

The parsing functions get_time(), get_time64(), get_rate(), get_rate64(),
and get_size64() use strtod() to convert user input but don't validate
the parsed values. This allows negative numbers and overflow values to
be passed through, which can cause unexpected behavior or security issues
when these values reach the kernel as unsigned integers.

Add validation to reject:
- Negative values (which make no sense for time, rate, or size)
- Overflow conditions (when strtod() returns HUGE_VAL with ERANGE)
- Empty strings (already checked, but now with explicit comments)

This prevents potential issues and provides clearer error reporting.
Fixing it in iproute2 does not mean that the kernel is off the hook
for handling negative values. Checks are still needed.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/utils.c      | 16 ++++++++++++++--
 lib/utils_math.c | 25 ++++++++++++++++++++++---
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/lib/utils.c b/lib/utils.c
index 1215fe31..50602e59 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -1647,7 +1647,13 @@ int get_time(unsigned int *time, const char *str)
 
 	t = strtod(str, &p);
 	if (p == str)
-		return -1;
+		return -1;	/* empty string */
+
+	if (t < 0)
+		return -1;	/* negative value */
+
+	if (t == HUGE_VAL && errno == ERANGE)
+		return -1;	/* out of range */
 
 	if (*p) {
 		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec") == 0 ||
@@ -1693,7 +1699,13 @@ int get_time64(__s64 *time, const char *str)
 
 	nsec = strtod(str, &p);
 	if (p == str)
-		return -1;
+		return -1;	/* empty string */
+
+	if (nsec < 0)
+		return -1;	/* negative value */
+
+	if (nsec == HUGE_VAL && errno == ERANGE)
+		return -1;	/* out of range */
 
 	if (*p) {
 		if (strcasecmp(p, "s") == 0 ||
diff --git a/lib/utils_math.c b/lib/utils_math.c
index fd2ddc7c..4b0ac266 100644
--- a/lib/utils_math.c
+++ b/lib/utils_math.c
@@ -5,6 +5,7 @@
 #include <string.h>
 #include <math.h>
 #include <limits.h>
+#include <errno.h>
 #include <asm/types.h>
 
 #include "utils.h"
@@ -42,7 +43,13 @@ int get_rate(unsigned int *rate, const char *str)
 	const struct rate_suffix *s;
 
 	if (p == str)
-		return -1;
+		return -1;	/* empty string */
+
+	if (bps < 0)
+		return -1;	/* negative */
+
+	if (bps == HUGE_VAL && errno == ERANGE)
+		return -1;	/* out of range */
 
 	for (s = suffixes; s->name; ++s) {
 		if (strcasecmp(s->name, p) == 0) {
@@ -70,7 +77,13 @@ int get_rate64(__u64 *rate, const char *str)
 	const struct rate_suffix *s;
 
 	if (p == str)
-		return -1;
+		return -1;	/* empty string */
+
+	if (bps < 0)
+		return -1;	/* negative */
+
+	if (bps == HUGE_VAL && errno == ERANGE)
+		return -1;	/* out of range */
 
 	for (s = suffixes; s->name; ++s) {
 		if (strcasecmp(s->name, p) == 0) {
@@ -95,7 +108,13 @@ int get_size64(__u64 *size, const char *str)
 
 	sz = strtod(str, &p);
 	if (p == str)
-		return -1;
+		return -1;	/* empty string */
+
+	if (sz < 0)
+		return -1;	/* negative */
+
+	if (sz == HUGE_VAL && errno == ERANGE)
+		return -1;	/* out of range */
 
 	if (*p) {
 		if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k") == 0)
-- 
2.53.0


^ permalink raw reply related

* [PATCH net v3] ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim
From: Daniel Borkmann @ 2026-04-21 20:24 UTC (permalink / raw)
  To: kuba
  Cc: edumazet, dsahern, tom, willemdebruijn.kernel, idosch,
	justin.iurman, pabeni, netdev

Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and
Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len}
and applied them in ip6_parse_tlv(), the generic TLV walker
invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts().

ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv();
it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST
branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner
loop is bounded only by optlen, which can be up to 2048 bytes.
Stuffing the Destination Options header with 2046 Pad1 (type=0)
entries advances the scanner a single byte at a time, yielding
~2000 TLV iterations per extension header.

Reusing max_dst_opts_cnt to bound the TLV iterations, matching
the semantics from 47d3d7ac656a, would require duplicating
ip6_parse_tlv() to also validate Pad1/PadN payload. It would
also mandate enforcing max_dst_opts_len, since otherwise an
attacker shifts the axis to few options with a giant PadN and
recovers the original DoS. Allowing up to 8 options before the
tunnel encapsulation limit TLV is liberal enough; in practice
encap limit is the first TLV. Thus, go with a hard-coded limit
IP6_TUNNEL_MAX_DEST_TLVS (8).

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
  v2->v3:
   - Hard code limit of 8 instead of max_dst_opts_cnt (Ido)
  v1->v2:
   - Use abs() given max_dst_opts_cnt's negative meaning (Justin)
   - Remove unlikely (Justin)

 net/ipv6/ip6_tunnel.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 907c6a2af331..4546a60942ab 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -62,6 +62,8 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("ip6tnl");
 MODULE_ALIAS_NETDEV("ip6tnl0");
 
+#define IP6_TUNNEL_MAX_DEST_TLVS    8
+
 #define IP6_TUNNEL_HASH_SIZE_SHIFT  5
 #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT)
 
@@ -430,11 +432,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
 				break;
 		}
 		if (nexthdr == NEXTHDR_DEST) {
+			int tlv_cnt = 0;
 			u16 i = 2;
 
 			while (1) {
 				struct ipv6_tlv_tnl_enc_lim *tel;
 
+				if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS))
+					break;
+
 				/* No more room for encapsulation limit */
 				if (i + sizeof(*tel) > optlen)
 					break;
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net 1/4] rxrpc: Fix memory leaks in rxkad_verify_response()
From: Simon Horman @ 2026-04-21 20:32 UTC (permalink / raw)
  To: David Howells
  Cc: netdev, Marc Dionne, Jakub Kicinski, David S. Miller,
	Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
	Jeffrey Altman, stable
In-Reply-To: <20260420145900.1223732-2-dhowells@redhat.com>

On Mon, Apr 20, 2026 at 03:58:54PM +0100, David Howells wrote:
> Fix rxkad_verify_response() to free ticket by using a __free() construct
> rather than explicitly freeing it.
> 
> Also fix rxkad_verify_response() to free the server key by using a __free()
> construct.
> 
> Fixes: 57af281e5389 ("rxrpc: Tidy up abort generation infrastructure")
> Fixes: ec832bd06d6f ("rxrpc: Don't retain the server key in the connection")
> Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com
> Signed-off-by: David Howells <dhowells@redhat.com>

...

> index eb7f2769d2b1..0acdc46f42c2 100644
> --- a/net/rxrpc/rxkad.c
> +++ b/net/rxrpc/rxkad.c

...

> @@ -1160,16 +1159,15 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
>  	}
>  
>  	ret = -ENOMEM;
> -	response = kzalloc_obj(struct rxkad_response, GFP_NOFS);
> +	struct rxkad_response *response __free(kfree) =
> +		kzalloc_obj(struct rxkad_response, GFP_NOFS);
>  	if (!response)
>  		goto temporary_error;
>  

Hi David,

This goto, combined with the use of __free in the declaration
of ticket below results in a compile error for x86_64 allmodconfig
with clang 21.1.8.

  net/rxrpc/rxkad.c:1165:3: error: cannot jump from this goto statement to its label
   1165 |                 goto temporary_error;
        |                 ^
  net/rxrpc/rxkad.c:1192:8: note: jump bypasses initialization of variable with __attribute__((cleanup))
   1192 |         void *ticket __free(kfree) = kmalloc(ticket_len, GFP_NOFS);
        |               ^

Moreover, the use of this construct is discouraged in Networking code:

  1.7.3. Using device-managed and cleanup.h constructs¶

  Netdev remains skeptical about promises of all “auto-cleanup” APIs,
  including even devm_ helpers, historically. They are not the preferred
  style of implementation, merely an acceptable one.

  Use of guard() is discouraged within any function longer than 20 lines,
  scoped_guard() is considered more readable. Using normal lock/unlock is
  still (weakly) preferred.

  Low level cleanup constructs (such as __free()) can be used when building
  APIs and helpers, especially scoped iterators. However, direct use of
  __free() within networking core and drivers is discouraged. Similar
  guidance applies to declaring variables mid-function.

  https://docs.kernel.org/process/maintainer-netdev.html#using-device-managed-and-cleanup-h-constructs

And to round things out, Sashiko also points out problems with
the use of __free() in this patch.

...

>  
>  	/* extract the kerberos ticket and decrypt and decode it */
>  	ret = -ENOMEM;
> -	ticket = kmalloc(ticket_len, GFP_NOFS);
> +	void *ticket __free(kfree) = kmalloc(ticket_len, GFP_NOFS);
>  	if (!ticket)
> -		goto temporary_error_free_resp;
> +		goto temporary_error;

...

>  temporary_error:
>  	/* Ignore the response packet if we got a temporary error such as
>  	 * ENOMEM.  We just want to send the challenge again.  Note that we
>  	 * also come out this way if the ticket decryption fails.
>  	 */
> -	key_put(server_key);
>  	return ret;
>  }
>  
> 

-- 
pw-bot: changes-requested

^ permalink raw reply

* Re: [PATCH net 2/4] rxrpc: Fix conn-level packet handling to unshare RESPONSE packets
From: Simon Horman @ 2026-04-21 20:38 UTC (permalink / raw)
  To: dhowells
  Cc: 'Simon Horman', netdev, marc.dionne, kuba, davem,
	edumazet, pabeni, linux-afs, linux-kernel, jaltman, stable
In-Reply-To: <20260420145900.1223732-3-dhowells@redhat.com>

From: 'Simon Horman' <horms@kernel.org>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
Subject: rxrpc: Fix conn-level packet handling to unshare RESPONSE packets

This commit modifies the RxRPC connection-level packet processor to unshare
RESPONSE packets before decryption. It introduces a new rxrpc_unshare_skb()
helper to safely unshare skbuffs passed via a double pointer and replaces
direct calls to skb_unshare().

Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com

> diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
> index 9a41ec708aeb9..3d56a5d233697 100644
> --- a/net/rxrpc/conn_event.c
> +++ b/net/rxrpc/conn_event.c

[ ... ]

> @@ -371,7 +379,7 @@ static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
>  	 * connection that each one has when we've finished with it */
>  	while ((skb = skb_dequeue(&conn->rx_queue))) {
>  		rxrpc_see_skb(skb, rxrpc_skb_see_conn_work);
> -		ret = rxrpc_process_event(conn, skb);
> +		ret = rxrpc_process_event(conn, &skb);
>  		switch (ret) {
>  		case -ENOMEM:
>  		case -EAGAIN:

Looking at the code immediately following this hunk in
rxrpc_do_process_connection():

		switch (ret) {
		case -ENOMEM:
		case -EAGAIN:
			skb_queue_head(&conn->rx_queue, skb);
			rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work);
			break;

If rxrpc_process_event() fails with -ENOMEM because rxrpc_unshare_skb()
failed, rxrpc_unshare_skb() will have set *_skb = NULL.

Does this mean skb is NULL when we reach skb_queue_head()?

Since skb_queue_head() dereferences the skb parameter, this appears to
result in a NULL pointer dereference. Furthermore, since skb_unshare()
frees the original skb on allocation failure, the packet is already gone
and requeuing it wouldn't be possible anyway.

> diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c
> index 6979569319252..0592ce644fc3d 100644
> --- a/net/rxrpc/io_thread.c
> +++ b/net/rxrpc/io_thread.c

[ ... ]

> @@ -249,19 +249,10 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
>  		 * decryption.
>  		 */
>  		if (sp->hdr.securityIndex != 0) {
> -			skb = skb_unshare(skb, GFP_ATOMIC);
> -			if (!skb) {
> -				rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem);
> -				*_skb = NULL;
> +			skb = rxrpc_unshare_skb(_skb, GFP_ATOMIC);
> +			if (!skb)
>  				return just_discard;
> -			}

This isn't a new bug introduced by this patch, but since we are modifying
the unshare path here: when rxrpc_unshare_skb() fails, it sets *_skb = NULL
and returns just_discard.

Back in rxrpc_io_thread(), the packet is processed like this:

net/rxrpc/io_thread.c:rxrpc_io_thread() {
...
		while ((skb = __skb_dequeue(&rx_queue))) {
			struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
			switch (skb->mark) {
			case RXRPC_SKB_MARK_PACKET:
				skb->priority = 0;
				if (!rxrpc_input_packet(local, &skb))
					rxrpc_reject_packet(local, skb);
				trace_rxrpc_rx_done(skb->mark, skb->priority);
...

If rxrpc_input_packet() sets skb to NULL and returns false (just_discard),
does this cause a NULL pointer dereference when trace_rxrpc_rx_done() tries
to access skb->mark?

^ permalink raw reply

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
From: Byron Stanoszek @ 2026-04-21 20:44 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

On Tue, 21 Apr 2026, Andrew Lunn wrote:

> These old drivers have not been much of a Maintenance burden until
> recently. Now there are more newbies using AI and fuzzers finding
> issues, resulting in more work for Maintainers. Fixing these old
> drivers make little sense, if it is not clear they have users.
>
>      drivers: net: 3com: 3c59x: Remove this driver

Hi Andrew,

I happen to still use this driver on several hundred industrial PC
installations that were outfitted with 3com 3C905-B & CX cards 15+ years ago.
The old hardware still runs, therefore those cards haven't needed to be
replaced. I keep these systems up to date with the latest Linux kernel roughly
once per year.

I understand the maintenance burden, but I would be delighted to continue
receiving bug fixes for this driver via the mainline Linux kernel if you are
still willing to continue to support it.

Thanks and best regards,
  -Byron


^ permalink raw reply

* Re: [syzbot] [kvm?] [net?] [virt?] BUG: sleeping function called from invalid context in vhost_get_avail_idx
From: Michael S. Tsirkin @ 2026-04-21 20:54 UTC (permalink / raw)
  To: Kohei Enju; +Cc: syzbot, jasowang, linux-kernel, netdev, syzkaller-bugs
In-Reply-To: <aeerTzpq8B-WTKeC@x1>

On Wed, Apr 22, 2026 at 02:11:01AM +0900, Kohei Enju wrote:
> On 04/20 15:09, syzbot wrote:
> > Hello,
> > 
> > syzbot found the following issue on:
> > 
> > HEAD commit:    8541d8f725c6 Merge tag 'mtd/for-7.1' of git://git.kernel.o..
> > git tree:       upstream
> > console output: https://syzkaller.appspot.com/x/log.txt?x=136454ce580000
> > kernel config:  https://syzkaller.appspot.com/x/.config?x=7e54da1916e8d11f
> > dashboard link: https://syzkaller.appspot.com/bug?extid=6985cb8e543ea90ba8ee
> > compiler:       gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44
> > syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=15d264ce580000
> > C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=143ec1ba580000
> > 
> > Downloadable assets:
> > disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-8541d8f7.raw.xz
> > vmlinux: https://storage.googleapis.com/syzbot-assets/22dfea2c37c2/vmlinux-8541d8f7.xz
> > kernel image: https://storage.googleapis.com/syzbot-assets/e2f93ad68fe3/bzImage-8541d8f7.xz
> > 
> > IMPORTANT: if you fix the issue, please add the following tag to the commit:
> > Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com
> > 
> > BUG: sleeping function called from invalid context at drivers/vhost/vhost.c:1527
> > in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 6110, name: vhost-6109
> > preempt_count: 1, expected: 0
> > RCU nest depth: 0, expected: 0
> > 2 locks held by vhost-6109/6110:
> >  #0: ffff888055624cb0 (&vq->mutex/1){+.+.}-{4:4}, at: handle_tx+0x2d/0x160 drivers/vhost/net.c:971
> >  #1: ffff888055620248 (&vq->mutex){+.+.}-{4:4}, at: vhost_net_busy_poll+0x9c/0x730 drivers/vhost/net.c:554
> > Preemption disabled at:
> > [<ffffffff88f1a006>] vhost_net_busy_poll+0x1c6/0x730 drivers/vhost/net.c:563
> 
> I think the blamed commit may be commit 030881372460 ("vhost_net: basic
> polling support"), since it introduced preempt_{disable,enable}() around
> the busy-poll loop, which calls a sleepable function inside the loop.
> 
> Also, from the changelog of the series,
> 
> https://lore.kernel.org/netdev/1448435489-5949-4-git-send-email-jasowang@redhat.com/T/#u
> 
>   Changes from RFC V1:
>   ...
>   - Disable preemption during busy looping to make sure local_clock() was
>     correctly used.
> 
> So my understanding is that preempt_disable() was introduced to keep
> local_clock() based timeout accounting on a single CPU, rather than as a
> requirement of busy polling itself.
> 
> If my understanding is correct, migrate_disable() is sufficient here
> instead of preempt_disable(), avoiding sleepable accesses from a
> preempt-disabled context.
> 
> #syz test
> 
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index 80965181920c..c6536cad9c4f 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
>         busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
>                                      tvq->busyloop_timeout;
> 
> -       preempt_disable();
> +       migrate_disable();
>         endtime = busy_clock() + busyloop_timeout;
> 
>         while (vhost_can_busy_poll(endtime)) {
> @@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
>                 cpu_relax();
>         }
> 
> -       preempt_enable();
> +       migrate_enable();
> 
>         if (poll_rx || sock_has_rx_data(sock))
>                 vhost_net_busy_poll_try_queue(net, vq);



Makes sense but this stipped up the bot. Try again?

> 
> > CPU: 0 UID: 0 PID: 6110 Comm: vhost-6109 Not tainted syzkaller #0 PREEMPT(full) 
> > Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
> > Call Trace:
> >  <TASK>
> >  __dump_stack lib/dump_stack.c:94 [inline]
> >  dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120
> >  __might_resched.cold+0x1ec/0x232 kernel/sched/core.c:9162
> >  __might_fault+0x8b/0x140 mm/memory.c:7322
> >  vhost_get_avail_idx+0x31c/0x4f0 drivers/vhost/vhost.c:1527
> >  vhost_vq_avail_empty drivers/vhost/vhost.c:3206 [inline]
> >  vhost_vq_avail_empty+0xa9/0xe0 drivers/vhost/vhost.c:3199
> >  vhost_net_busy_poll+0x297/0x730 drivers/vhost/net.c:574
> >  vhost_net_tx_get_vq_desc drivers/vhost/net.c:610 [inline]
> >  get_tx_bufs.constprop.0+0x338/0x600 drivers/vhost/net.c:650
> >  handle_tx_copy+0x28c/0x12e0 drivers/vhost/net.c:778
> >  handle_tx+0x139/0x160 drivers/vhost/net.c:985
> >  vhost_run_work_list+0x183/0x220 drivers/vhost/vhost.c:454
> >  vhost_task_fn+0x156/0x430 kernel/vhost_task.c:49
> >  ret_from_fork+0x72b/0xd50 arch/x86/kernel/process.c:158
> >  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> >  </TASK>
> > 
> > 
> > ---
> > This report is generated by a bot. It may contain errors.
> > See https://goo.gl/tpsmEJ for more information about syzbot.
> > syzbot engineers can be reached at syzkaller@googlegroups.com.
> > 
> > syzbot will keep track of this issue. See:
> > https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
> > 
> > If the report is already addressed, let syzbot know by replying with:
> > #syz fix: exact-commit-title
> > 
> > If you want syzbot to run the reproducer, reply with:
> > #syz test: git://repo/address.git branch-or-commit-hash
> > If you attach or paste a git patch, syzbot will apply it before testing.
> > 
> > If you want to overwrite report's subsystems, reply with:
> > #syz set subsystems: new-subsystem
> > (See the list of subsystem names on the web dashboard)
> > 
> > If the report is a duplicate of another one, reply with:
> > #syz dup: exact-subject-of-another-report
> > 
> > If you want to undo deduplication, reply with:
> > #syz undup


^ permalink raw reply

* Re: [PATCH net 2/4] rxrpc: Fix conn-level packet handling to unshare RESPONSE packets
From: David Howells @ 2026-04-21 20:58 UTC (permalink / raw)
  To: Simon Horman
  Cc: dhowells, netdev, marc.dionne, kuba, davem, edumazet, pabeni,
	linux-afs, linux-kernel, jaltman, stable
In-Reply-To: <20260421203833.745240-1-horms@kernel.org>

Simon Horman <horms@kernel.org> wrote:

> This isn't a new bug introduced by this patch, but since we are modifying
> the unshare path here: when rxrpc_unshare_skb() fails, it sets *_skb = NULL
> and returns just_discard.

Is there a way to avoid having skb_unshare() eat your ref to the source skbuff
if it fails?

David


^ permalink raw reply

* Re: [PATCH] dt-bindings: Fix phandle-array constraints, again
From: Rob Herring (Arm) @ 2026-04-21 21:33 UTC (permalink / raw)
  To: Rob Herring (Arm)
  Cc: Sylwester Nawrocki, ath11k, devicetree, linux-pci,
	Mathieu Poirier, Conor Dooley, Xu Yang, Lorenzo Pieralisi,
	Andrew Lunn, linux-spi, Patrice Chotard, Rao Mandadapu,
	Mark Brown, linux-sound, Maarten Lankhorst, Bjorn Andersson,
	linux-remoteproc, Maxime Coquelin, Thomas Zimmermann, Sibi Sankar,
	linux-wireless, Johannes Berg, Yang Xiwen, Chaitanya Chundru,
	Alex Elder, Manivannan Sadhasivam, Ulf Hansson, Stephan Gerhold,
	linux-kernel, Eric Dumazet, Paolo Abeni, Jakub Kicinski,
	linux-arm-msm, linux-usb, Bjorn Helgaas, Jeff Johnson, linux-mmc,
	Krzysztof Wilczyński, Krzysztof Kozlowski, Peng Fan,
	David S. Miller, Greg Kroah-Hartman, ath10k, netdev,
	Maxime Ripard
In-Reply-To: <20260421195836.1547469-1-robh@kernel.org>


On Tue, 21 Apr 2026 14:55:25 -0500, Rob Herring (Arm) wrote:
> The unfortunately named 'phandle-array' property type is really a matrix
> with phandle and fixed arg cells entries. A matrix property should have 2
> levels of items constraints.
> 
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
> ---
> Can someone from QCom provide some descriptions for 'qcom,smem-states'
> properties.
> ---
>  .../display/rockchip/rockchip,rk3399-cdn-dp.yaml         | 2 ++
>  .../bindings/mmc/hisilicon,hi3798cv200-dw-mshc.yaml      | 7 ++++---
>  Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml | 6 ++++++
>  Documentation/devicetree/bindings/net/qcom,ipa.yaml      | 6 ++++++
>  .../devicetree/bindings/net/wireless/qcom,ath10k.yaml    | 5 ++++-
>  .../devicetree/bindings/net/wireless/qcom,ath11k.yaml    | 5 ++++-
>  .../bindings/net/wireless/qcom,ipq5332-wifi.yaml         | 9 +++++++++
>  .../devicetree/bindings/pci/toshiba,tc9563.yaml          | 5 +++--
>  .../bindings/remoteproc/qcom,msm8916-mss-pil.yaml        | 3 +++
>  .../bindings/remoteproc/qcom,msm8996-mss-pil.yaml        | 3 +++
>  .../devicetree/bindings/remoteproc/qcom,pas-common.yaml  | 4 ++++
>  .../bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml        | 4 ++++
>  .../bindings/remoteproc/qcom,sc7180-mss-pil.yaml         | 3 +++
>  .../bindings/remoteproc/qcom,sc7280-adsp-pil.yaml        | 3 +++
>  .../bindings/remoteproc/qcom,sc7280-mss-pil.yaml         | 3 +++
>  .../bindings/remoteproc/qcom,sc7280-wpss-pil.yaml        | 3 +++
>  .../bindings/remoteproc/qcom,sdm845-adsp-pil.yaml        | 3 +++
>  .../devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml   | 3 +++
>  Documentation/devicetree/bindings/sound/samsung,tm2.yaml | 2 ++
>  .../devicetree/bindings/spi/st,stm32mp25-ospi.yaml       | 5 +++--
>  .../devicetree/bindings/usb/chipidea,usb2-common.yaml    | 2 ++
>  Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml  | 7 ++++---
>  22 files changed, 81 insertions(+), 12 deletions(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml:99:1: [warning] too many blank lines (2 > 1) (empty-lines)
./Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml:67:1: [warning] too many blank lines (2 > 1) (empty-lines)

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.example.dtb: i2c-mux3 (i2c-demux-pinctrl): i2c-parent:0: [2, 3, 4] is too long
	from schema $id: http://devicetree.org/schemas/i2c/i2c-demux-pinctrl.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/sound/samsung,tm2.example.dtb: sound (samsung,tm2-audio): i2s-controller: [[4294967295], [0], [4294967295], [0]] is too long
	from schema $id: http://devicetree.org/schemas/sound/samsung,tm2.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20260421195836.1547469-1-robh@kernel.org

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* Re: [PATCH net 12/18] drivers: net: cirrus: mac89x0: Remove this driver
From: Daniel Palmer @ 2026-04-21 21:34 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-12-69517c689d1f@lunn.ch>

Hi Andrew,

On Wed, 22 Apr 2026 at 05:01, Andrew Lunn <andrew@lunn.ch> wrote:
>
> The mac89x0 was written by Russell Nelson in 1996. It is an MAC
> device, so unlikely to be used with modern kernels.
>
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>

I think I might be using this with a mac and I'm running mainline.
FWIW the m68k mac stuff still works perfectly fine with modern kernels
and there are people using it.

^ permalink raw reply

* Re: [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147
From: Daniel Palmer @ 2026-04-21 21:38 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-6-69517c689d1f@lunn.ch>

Hi Andrew,

On Wed, 22 Apr 2026 at 04:39, Andrew Lunn <andrew@lunn.ch> wrote:
>
> These drivers use the 7990 core with wrappers for the HP300 and
> Motorola MVME147 SBC circa 1998. It is unlikely they are used with a
> modern kernel.

I have an MVME147 blinking away running mainline using the mvme147 driver.
I think some of these need to be CC'd to the specific arch lists so
the few people using them get a chance to pipe up.
I think I'm the last person to have touched the mvme147, I don't mind
being a maintainer for it.

Cheers,

Daniel

^ permalink raw reply

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
From: Daniel Palmer @ 2026-04-21 22:03 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>

Hi Andrew,

On Wed, 22 Apr 2026 at 04:32, Andrew Lunn <andrew@lunn.ch> wrote:
>
> These old drivers have not been much of a Maintenance burden until
> recently. Now there are more newbies using AI and fuzzers finding
> issues, resulting in more work for Maintainers. Fixing these old
> drivers make little sense, if it is not clear they have users.
>
> These are all ISA and PCMCIA Ethernet devices, mostly from the last
> century, a couple from 2001 or 2002. It seems unlikely they are still
> used. However, remove them one patch at a time so they can be brought
> back if somebody still has the hardware, runs modern kernels and wants
> to take up the roll of driver Maintainer.
>
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>

I replied to the single patches for the ones I think I have off the
top of my head but maybe I have a few other these.
I think on x86 people running machines that have real ISA slots and a
modern kernel are going to be fairly rare but I think there is non-x86
hardware that has some of these and people are still using them.
I think the pcnet one is used in some PC emulators too?

This is just my opinion but I think it'd be good to give people a bit
more time before they get removed. I thought I was the only person
using the 68000 (a cpu from 1979) code in the m68k tree for years
until out of the blue a month or so ago someone popped up and asked if
I could fix a bug in it since I'd fixed a different bug in it
recently.

Maybe we could add a special thing in the maintainers for "this is
code only crazy people use" and have a rule to ignore untested AI
generated patches for it? :)

Thanks,

Daniel

^ permalink raw reply

* [PATCH bpf-next v3 0/9] Refactor verifier object relationship tracking
From: Amery Hung @ 2026-04-21 22:10 UTC (permalink / raw)
  To: bpf
  Cc: netdev, alexei.starovoitov, andrii, daniel, eddyz87, memxor,
	martin.lau, mykyta.yatsenko5, ameryhung, kernel-team

Hi all,

This patchset cleans up dynptr handling, refactors object relationship
tracking in the verifier by introducing parent_id, and fixes dynptr
use-after-free bugs where file/skb dynptrs are not invalidated when
the parent referenced object is freed.


* Motivation *

In BPF qdisc programs, an skb can be freed through kfuncs. However,
since dynptr does not track the parent referenced object (e.g., skb),
the verifier does not invalidate the dynptr after the skb is freed,
resulting in use-after-free. The same issue also affects file dynptr.

The figure below shows the current state of object tracking. The
verifier tracks objects using three fields: id for nullness tracking,
ref_obj_id for lifetime tracking, and dynptr_id for tracking the parent
dynptr of a slice (PTR_TO_MEM only). While dynptr_id links slices to
their parent dynptr, there is no field that links a dynptr back to its
parent skb. When the skb is freed via release_reference(ref_obj_id=1),
only objects with ref_obj_id=1 are invalidated. Since skb dynptr is
non-referenced (ref_obj_id=0), the dynptr and its derived slices remain
accessible.

Current: object (id, ref_obj_id, dynptr_id)
  id         = unique id of the object (for nullness tracking)
  ref_obj_id = id of the referenced object (for lifetime tracking)
  dynptr_id  = id of the parent dynptr (only for PTR_TO_MEM slices)

                      skb (0,1,0)
                             ^
                             ! No link from dynptr to skb
                             +-------------------------------+
                             |           bpf_dynptr_clone    |
                 dynptr A (2,0,0)                dynptr C (4,0,0)
                           ^                               ^
        bpf_dynptr_slice   |                               |
                           |                               |
              slice B (3,0,2)                 slice D (5,0,4)


* Why not simply use ref_obj_id to track the parent? *

A natural first approach is to link dynptr to its parent by sharing
the parent's ref_obj_id and propagating it to slices. Now, releasing
the skb via release_reference(ref_obj_id=1) correctly invalidates all
derived objects.

Attempted fix: share parent's ref_obj_id

                      skb (0,1,0)
                             ^
                             +-------------------------------+
                             |           bpf_dynptr_clone    |
                 dynptr A (2,1,0)                dynptr C (4,1,0)
                           ^                               ^
        bpf_dynptr_slice   |                               |
                           |                               |
              slice B (3,1,2)                 slice D (5,1,4)


However, this approach does not generalize to all dynptr types.
Referenced dynptrs such as file dynptr acquire their own ref_obj_id to
track the dynptr's lifetime. Since ref_obj_id is already
used for the dynptr's own reference, it cannot also be used to point to
the parent file object. While it is possible to add specialized handling
for individual dynptr types [0], it adds complexity and does not
generalize.

An alternative approach is to avoid introducing a new field and instead
repurpose ref_obj_id as parent_id by folding lifetime tracking into id
[1]. In this design, each object is represented as (id, ref_obj_id)
where id is used for both nullness and lifetime tracking, and ref_obj_id
tracks the parent object's id.

Attempted: object (id, ref_obj_id)
  id         = id of the object (for nullness and lifetime tracking)
  ref_obj_id = id of the parent object
  '          = id is referenced

                        skb (1',0)
                             ^
        bpf_dynptr_from_skb  +-------------------------------+
                             |      bpf_dynptr_clone(A, C)   |
                 dynptr A (2,1')                 dynptr C (4,1')
                           ^                               ^
        bpf_dynptr_slice   |                               |
                           |                               |
                slice B (3,2)                   slice D (5,4)

However, this design cannot express the relationship between referenced
socket pointers and their casted counterparts. After pointer casting,
the original and casted pointers need the same lifetime (same ref_obj_id
in the current design) but different nullness (different id). The casted
pointer may be NULL even if the original is valid. With id serving as
the only field for both nullness and lifetime, and ref_obj_id repurposed
as parent, there is no way to express "different identity, same
lifetime."

Referenced socket pointer (expressed using current design):

                                C = ptr_casting_function(A)
                ptr A (1,1,0)                     ptr C (2,1,0)
                         ^                                 ^
                         |                                 |
                        ptr C may be NULL even if ptr A is valid
                        but they have the same lifetime


* New Design: parent_id *

To track precise object relationships, u32 parent_id is added to
bpf_reg_state. A child object's parent_id points to the parent
object's id. This replaces the PTR_TO_MEM-specific dynptr_id, and
does not increase the size of bpf_reg_state on 64-bit machines as
there is existing padding.

After: object (id, ref_obj_id, parent_id)
  id         = unique id of the object (for nullness tracking)
  ref_obj_id = id of the referenced object; objects with the same
               ref_obj_id share the same lifetime
  parent_id  = id of the parent object; points to parent's id
               (for object relationship tracking)

                          skb (1,1,0)
                               ^
          bpf_dynptr_from_skb  +-------------------------------+
                               |      bpf_dynptr_clone(A, C)   |
                 dynptr A (2,0,1)               dynptr C (4,0,1)
                           ^                              ^
        bpf_dynptr_slice   |                              |
                           |                              |
              slice B (3,0,2)                slice D (5,0,4)
                       ^
  bpf_dynptr_from_mem  |
  (NOT allowed yet)    |
         dynptr E (6,0,3)

With parent_id, the verifier can precisely track object trees. When the
skb is freed, the verifier traverses the tree rooted at skb (id=1) and
invalidates all descendants — dynptr A, dynptr C, and their slices.
When dynptr A is destroyed by overwriting the stack slot, only dynptr A
and its children (slice B, dynptr E) are invalidated; skb, dynptr C,
and slice D remain valid.

For referenced dynptr (e.g., file dynptr), the original and its clones
share the same ref_obj_id so they are all invalidated together when any
one of them is released. For non-referenced dynptr (e.g., skb dynptr),
clones live independently since they have ref_obj_id=0.

To avoid recursive call chains when releasing objects (e.g.,
release_reference() -> unmark_stack_slots_dynptr() ->
release_reference()), release_reference() now uses stack-based DFS to
find and invalidate all registers and stack slots with matching id or
ref_obj_id and all descendants whose parent_id matches. Currently, it
skips id == 0, which could be a valid id (e.g., pkt pointer by reading
ctx). Future work may start assigning > 0 id to them. This does not
affect the current use cases where skb and file parents are both given
id > 0.


* Preserving reg->id after null-check *

For parent_id tracking to work, child objects need to refer to the
parent's id. This requires two preparatory changes: assigning reg->id
when reading referenced kptrs from program context (patch 2), and
preserving reg->id of pointer objects after null-check (patch 3).
Previously, null-check would clear reg->id, making it impossible for
children to reference the parent afterward. The latter causes a slight
increase in verified states for some programs. One selftest object
sees +19 states (+5.01%). For Meta BPF objects, the increase is
also minor, with the largest being +34 states (+3.63%).


* Object relationship in different scenarios (for reference) *

The figures below show how the new design handles all four combinations
of referenced/non-referenced dynptr with referenced/non-referenced
parent. The relationship between slices and dynptrs is omitted as it
is the same across all cases. The main difference is how cloned dynptrs
are represented. Since bpf_dynptr_clone() does not initialize a new
reference, clones of referenced dynptrs share the same ref_obj_id and
must be invalidated together. For non-referenced dynptrs, the original
and clones live independently.

(1) Non-referenced dynptr with referenced parent (e.g., skb in Qdisc):

                          skb (1,1,0)
                               ^
          bpf_dynptr_from_skb  +-------------------------------+
                               |      bpf_dynptr_clone(A, C)   |
                 dynptr A (2,0,1)                dynptr C (4,0,1)

(2) Non-referenced dynptr with non-referenced parent (e.g., skb in TC,
    always valid):

      bpf_dynptr_from_skb
                                  bpf_dynptr_clone(A, C)
             dynptr A (1,0,0)                  dynptr C (2,0,0)

                         dynptr A and C live independently

(3) Referenced dynptr with referenced parent:

                     file (1,1,0)
                           ^ ^
     bpf_dynptr_from_file  | +-------------------------------+
                           |       bpf_dynptr_clone(A, C)    |
             dynptr A (2,3,1)                  dynptr C (4,3,1)
                         ^                                 ^
                         |                                 |
                         dynptr A and C have the same lifetime

(4) Referenced dynptr with non-referenced parent:

 bpf_ringbuf_reserve_dynptr
                                  bpf_dynptr_clone(A, C)
             dynptr A (1,1,0)                  dynptr C (2,1,0)
                         ^                                 ^
                         |                                 |
                         dynptr A and C have the same lifetime


[0] https://lore.kernel.org/bpf/20250414161443.1146103-2-memxor@gmail.com/
[1] https://github.com/ameryhung/bpf/commits/obj_relationship_v2_no_parent_id/


Changelog:

v2 -> v3
  - Rebase to bpf-next/master
  - Update veristat numbers
  - Update commit msg to explain multiple dropped checks (Mykyta, Andrii)
  - Reuse idmap as idstack in release_reference() and check for
    duplicate id (Mykyta, Andrii)
  - Change to use RUN_TEST for qdisc dynptr selftest (Eduard) 
  Link: https://lore.kernel.org/bpf/20260307064439.3247440-1-ameryhung@gmail.com/  

v1 -> v2
  - Redesign: Use object (id, ref_obj_id, parent_id) instead of
    (id, ref_obj_id) as it cannot express ptr casting without
    introducing specialized code to handle the case
  - Use stack-based DFS to release objects to avoid recursion (Andrii)
  - Keep reg->id after null check
  - Add dynptr cleanup
  - Fix dynptr kfunc arg type determination
  - Add a file dynptr UAF selftest
  Link: https://lore.kernel.org/bpf/20260202214817.2853236-1-ameryhung@gmail.com/

---

Amery Hung (9):
  bpf: Unify dynptr handling in the verifier
  bpf: Assign reg->id when getting referenced kptr from ctx
  bpf: Preserve reg->id of pointer objects after null-check
  bpf: Refactor object relationship tracking and fix dynptr UAF bug
  bpf: Remove redundant dynptr arg check for helper
  selftests/bpf: Test creating dynptr from dynptr data and slice
  selftests/bpf: Test using dynptr after freeing the underlying object
  selftests/bpf: Test using slice after invalidating dynptr clone
  selftests/bpf: Test using file dynptr after the reference on file is
    dropped

 include/linux/bpf_verifier.h                  |  34 +-
 kernel/bpf/log.c                              |   4 +-
 kernel/bpf/states.c                           |   9 +-
 kernel/bpf/verifier.c                         | 461 ++++++------------
 .../selftests/bpf/prog_tests/bpf_qdisc.c      |   8 +
 ..._qdisc_dynptr_use_after_invalidate_clone.c |  75 +++
 .../progs/bpf_qdisc_fail__invalid_dynptr.c    |  68 +++
 ...f_qdisc_fail__invalid_dynptr_cross_frame.c |  74 +++
 .../bpf_qdisc_fail__invalid_dynptr_slice.c    |  70 +++
 .../testing/selftests/bpf/progs/dynptr_fail.c |  48 +-
 .../selftests/bpf/progs/file_reader_fail.c    |  60 +++
 .../selftests/bpf/progs/user_ringbuf_fail.c   |   4 +-
 12 files changed, 593 insertions(+), 322 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_qdisc_dynptr_use_after_invalidate_clone.c
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_qdisc_fail__invalid_dynptr.c
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_qdisc_fail__invalid_dynptr_cross_frame.c
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_qdisc_fail__invalid_dynptr_slice.c

-- 
2.52.0


^ permalink raw reply

* [PATCH bpf-next v3 1/9] bpf: Unify dynptr handling in the verifier
From: Amery Hung @ 2026-04-21 22:10 UTC (permalink / raw)
  To: bpf
  Cc: netdev, alexei.starovoitov, andrii, daniel, eddyz87, memxor,
	martin.lau, mykyta.yatsenko5, ameryhung, kernel-team
In-Reply-To: <20260421221016.2967924-1-ameryhung@gmail.com>

Simplify dynptr checking for helper and kfunc by unifying it. Remember
the initialized dynptr (i.e.,g !(arg_type |= MEM_UNINIT)) pass to a
dynptr kfunc during process_dynptr_func() so that we can easily
retrieve the information for verification later. By saving it in
meta->dynptr, there is no need to call dynptr helpers such as
dynptr_id(), dynptr_ref_obj_id() and dynptr_type() in check_func_arg().

Remove and open code the helpers in process_dynptr_func() when
saving id, ref_obj_id, and type. It is okay to drop spi < 0 check as
is_dynptr_reg_valid_init() has made sure the dynptr is valid.

Besides, since dynptr ref_obj_id information is now pass around in
meta->bpf_dynptr_desc, drop the check in helper_multiple_ref_obj_use.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Amery Hung <ameryhung@gmail.com>
---
 include/linux/bpf_verifier.h |  12 ++-
 kernel/bpf/verifier.c        | 178 +++++++----------------------------
 2 files changed, 41 insertions(+), 149 deletions(-)

diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index b148f816f25b..dc0cff59246d 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -1319,6 +1319,12 @@ struct bpf_map_desc {
 	int uid;
 };
 
+struct bpf_dynptr_desc {
+	enum bpf_dynptr_type type;
+	u32 id;
+	u32 ref_obj_id;
+};
+
 struct bpf_kfunc_call_arg_meta {
 	/* In parameters */
 	struct btf *btf;
@@ -1359,16 +1365,12 @@ struct bpf_kfunc_call_arg_meta {
 	struct {
 		struct btf_field *field;
 	} arg_rbtree_root;
-	struct {
-		enum bpf_dynptr_type type;
-		u32 id;
-		u32 ref_obj_id;
-	} initialized_dynptr;
 	struct {
 		u8 spi;
 		u8 frameno;
 	} iter;
 	struct bpf_map_desc map;
+	struct bpf_dynptr_desc dynptr;
 	u64 mem_size;
 };
 
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 185210b73385..41e4ea41c72e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -232,6 +232,7 @@ static void bpf_map_key_store(struct bpf_insn_aux_data *aux, u64 state)
 
 struct bpf_call_arg_meta {
 	struct bpf_map_desc map;
+	struct bpf_dynptr_desc dynptr;
 	bool raw_mode;
 	bool pkt_access;
 	u8 release_regno;
@@ -240,7 +241,6 @@ struct bpf_call_arg_meta {
 	int mem_size;
 	u64 msize_max_value;
 	int ref_obj_id;
-	int dynptr_id;
 	int func_id;
 	struct btf *btf;
 	u32 btf_id;
@@ -434,11 +434,6 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id)
 		func_id == BPF_FUNC_skc_to_tcp_request_sock;
 }
 
-static bool is_dynptr_ref_function(enum bpf_func_id func_id)
-{
-	return func_id == BPF_FUNC_dynptr_data;
-}
-
 static bool is_sync_callback_calling_kfunc(u32 btf_id);
 static bool is_async_callback_calling_kfunc(u32 btf_id);
 static bool is_callback_calling_kfunc(u32 btf_id);
@@ -507,8 +502,6 @@ static bool helper_multiple_ref_obj_use(enum bpf_func_id func_id,
 		ref_obj_uses++;
 	if (is_acquire_function(func_id, map))
 		ref_obj_uses++;
-	if (is_dynptr_ref_function(func_id))
-		ref_obj_uses++;
 
 	return ref_obj_uses > 1;
 }
@@ -7433,7 +7426,8 @@ static int process_kptr_func(struct bpf_verifier_env *env, int regno,
  * and checked dynamically during runtime.
  */
 static int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx,
-			       enum bpf_arg_type arg_type, int clone_ref_obj_id)
+			       enum bpf_arg_type arg_type, int clone_ref_obj_id,
+			       struct bpf_dynptr_desc *dynptr)
 {
 	struct bpf_reg_state *reg = reg_state(env, regno);
 	int err;
@@ -7499,6 +7493,20 @@ static int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn
 		}
 
 		err = mark_dynptr_read(env, reg);
+
+		if (dynptr) {
+			struct bpf_func_state *state = bpf_func(env, reg);
+			int spi;
+
+			if (reg->type != CONST_PTR_TO_DYNPTR) {
+				spi = dynptr_get_spi(env, reg);
+				reg = &state->stack[spi].spilled_ptr;
+			}
+
+			dynptr->id = reg->id;
+			dynptr->type = reg->dynptr.type;
+			dynptr->ref_obj_id = reg->ref_obj_id;
+		}
 	}
 	return err;
 }
@@ -8263,72 +8271,6 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env,
 	}
 }
 
-static struct bpf_reg_state *get_dynptr_arg_reg(struct bpf_verifier_env *env,
-						const struct bpf_func_proto *fn,
-						struct bpf_reg_state *regs)
-{
-	struct bpf_reg_state *state = NULL;
-	int i;
-
-	for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++)
-		if (arg_type_is_dynptr(fn->arg_type[i])) {
-			if (state) {
-				verbose(env, "verifier internal error: multiple dynptr args\n");
-				return NULL;
-			}
-			state = &regs[BPF_REG_1 + i];
-		}
-
-	if (!state)
-		verbose(env, "verifier internal error: no dynptr arg found\n");
-
-	return state;
-}
-
-static int dynptr_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg)
-{
-	struct bpf_func_state *state = bpf_func(env, reg);
-	int spi;
-
-	if (reg->type == CONST_PTR_TO_DYNPTR)
-		return reg->id;
-	spi = dynptr_get_spi(env, reg);
-	if (spi < 0)
-		return spi;
-	return state->stack[spi].spilled_ptr.id;
-}
-
-static int dynptr_ref_obj_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg)
-{
-	struct bpf_func_state *state = bpf_func(env, reg);
-	int spi;
-
-	if (reg->type == CONST_PTR_TO_DYNPTR)
-		return reg->ref_obj_id;
-	spi = dynptr_get_spi(env, reg);
-	if (spi < 0)
-		return spi;
-	return state->stack[spi].spilled_ptr.ref_obj_id;
-}
-
-static enum bpf_dynptr_type dynptr_get_type(struct bpf_verifier_env *env,
-					    struct bpf_reg_state *reg)
-{
-	struct bpf_func_state *state = bpf_func(env, reg);
-	int spi;
-
-	if (reg->type == CONST_PTR_TO_DYNPTR)
-		return reg->dynptr.type;
-
-	spi = bpf_get_spi(reg->var_off.value);
-	if (spi < 0) {
-		verbose(env, "verifier internal error: invalid spi when querying dynptr type\n");
-		return BPF_DYNPTR_TYPE_INVALID;
-	}
-
-	return state->stack[spi].spilled_ptr.dynptr.type;
-}
-
 static int check_reg_const_str(struct bpf_verifier_env *env,
 			       struct bpf_reg_state *reg, u32 regno)
 {
@@ -8683,7 +8625,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 					 true, meta);
 		break;
 	case ARG_PTR_TO_DYNPTR:
-		err = process_dynptr_func(env, regno, insn_idx, arg_type, 0);
+		err = process_dynptr_func(env, regno, insn_idx, arg_type, 0, &meta->dynptr);
 		if (err)
 			return err;
 		break;
@@ -9342,7 +9284,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
 			if (ret)
 				return ret;
 
-			ret = process_dynptr_func(env, regno, -1, arg->arg_type, 0);
+			ret = process_dynptr_func(env, regno, -1, arg->arg_type, 0, NULL);
 			if (ret)
 				return ret;
 		} else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) {
@@ -10429,52 +10371,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 			}
 		}
 		break;
-	case BPF_FUNC_dynptr_data:
-	{
-		struct bpf_reg_state *reg;
-		int id, ref_obj_id;
-
-		reg = get_dynptr_arg_reg(env, fn, regs);
-		if (!reg)
-			return -EFAULT;
-
-
-		if (meta.dynptr_id) {
-			verifier_bug(env, "meta.dynptr_id already set");
-			return -EFAULT;
-		}
-		if (meta.ref_obj_id) {
-			verifier_bug(env, "meta.ref_obj_id already set");
-			return -EFAULT;
-		}
-
-		id = dynptr_id(env, reg);
-		if (id < 0) {
-			verifier_bug(env, "failed to obtain dynptr id");
-			return id;
-		}
-
-		ref_obj_id = dynptr_ref_obj_id(env, reg);
-		if (ref_obj_id < 0) {
-			verifier_bug(env, "failed to obtain dynptr ref_obj_id");
-			return ref_obj_id;
-		}
-
-		meta.dynptr_id = id;
-		meta.ref_obj_id = ref_obj_id;
-
-		break;
-	}
 	case BPF_FUNC_dynptr_write:
 	{
-		enum bpf_dynptr_type dynptr_type;
-		struct bpf_reg_state *reg;
+		enum bpf_dynptr_type dynptr_type = meta.dynptr.type;
 
-		reg = get_dynptr_arg_reg(env, fn, regs);
-		if (!reg)
-			return -EFAULT;
-
-		dynptr_type = dynptr_get_type(env, reg);
 		if (dynptr_type == BPF_DYNPTR_TYPE_INVALID)
 			return -EFAULT;
 
@@ -10665,10 +10565,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 		return -EFAULT;
 	}
 
-	if (is_dynptr_ref_function(func_id))
-		regs[BPF_REG_0].dynptr_id = meta.dynptr_id;
-
-	if (is_ptr_cast_function(func_id) || is_dynptr_ref_function(func_id)) {
+	if (is_ptr_cast_function(func_id)) {
 		/* For release_reference() */
 		regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id;
 	} else if (is_acquire_function(func_id, meta.map.ptr)) {
@@ -10682,6 +10579,11 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 		regs[BPF_REG_0].ref_obj_id = id;
 	}
 
+	if (func_id == BPF_FUNC_dynptr_data) {
+		regs[BPF_REG_0].dynptr_id = meta.dynptr.id;
+		regs[BPF_REG_0].ref_obj_id = meta.dynptr.ref_obj_id;
+	}
+
 	err = do_refine_retval_range(env, regs, fn->ret_type, func_id, &meta);
 	if (err)
 		return err;
@@ -12260,7 +12162,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
 				meta->release_regno = regno;
 			} else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] &&
 				   (dynptr_arg_type & MEM_UNINIT)) {
-				enum bpf_dynptr_type parent_type = meta->initialized_dynptr.type;
+				enum bpf_dynptr_type parent_type = meta->dynptr.type;
 
 				if (parent_type == BPF_DYNPTR_TYPE_INVALID) {
 					verifier_bug(env, "no dynptr type for parent of clone");
@@ -12268,29 +12170,17 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
 				}
 
 				dynptr_arg_type |= (unsigned int)get_dynptr_type_flag(parent_type);
-				clone_ref_obj_id = meta->initialized_dynptr.ref_obj_id;
+				clone_ref_obj_id = meta->dynptr.ref_obj_id;
 				if (dynptr_type_refcounted(parent_type) && !clone_ref_obj_id) {
 					verifier_bug(env, "missing ref obj id for parent of clone");
 					return -EFAULT;
 				}
 			}
 
-			ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type, clone_ref_obj_id);
+			ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type, clone_ref_obj_id,
+						  &meta->dynptr);
 			if (ret < 0)
 				return ret;
-
-			if (!(dynptr_arg_type & MEM_UNINIT)) {
-				int id = dynptr_id(env, reg);
-
-				if (id < 0) {
-					verifier_bug(env, "failed to obtain dynptr id");
-					return id;
-				}
-				meta->initialized_dynptr.id = id;
-				meta->initialized_dynptr.type = dynptr_get_type(env, reg);
-				meta->initialized_dynptr.ref_obj_id = dynptr_ref_obj_id(env, reg);
-			}
-
 			break;
 		}
 		case KF_ARG_PTR_TO_ITER:
@@ -12894,7 +12784,7 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_ca
 		}
 	} else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice] ||
 		   meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice_rdwr]) {
-		enum bpf_type_flag type_flag = get_dynptr_type_flag(meta->initialized_dynptr.type);
+		enum bpf_type_flag type_flag = get_dynptr_type_flag(meta->dynptr.type);
 
 		mark_reg_known_zero(env, regs, BPF_REG_0);
 
@@ -12918,11 +12808,11 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_ca
 			}
 		}
 
-		if (!meta->initialized_dynptr.id) {
+		if (!meta->dynptr.id) {
 			verifier_bug(env, "no dynptr id");
 			return -EFAULT;
 		}
-		regs[BPF_REG_0].dynptr_id = meta->initialized_dynptr.id;
+		regs[BPF_REG_0].dynptr_id = meta->dynptr.id;
 
 		/* we don't need to set BPF_REG_0's ref obj id
 		 * because packet slices are not refcounted (see
@@ -13110,7 +13000,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 	if (meta.release_regno) {
 		struct bpf_reg_state *reg = &regs[meta.release_regno];
 
-		if (meta.initialized_dynptr.ref_obj_id) {
+		if (meta.dynptr.ref_obj_id) {
 			err = unmark_stack_slots_dynptr(env, reg);
 		} else {
 			err = release_reference(env, reg->ref_obj_id);
-- 
2.52.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox