Netdev List
 help / color / mirror / Atom feed
* [PATCH net v2 11/15] drivers: net: fujitsu: fmvj18x: Remove this driver
From: Andrew Lunn @ 2026-04-22 18:01 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: Geert Uytterhoeven, Michael Fritscher, Byron Stanoszek,
	Daniel Palmer, linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260422-v7-0-0-net-next-driver-removal-v1-v2-0-08a5b59784d5@lunn.ch>

The fmvj18x was written by Shingo Fujimoto in 2002. 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/fujitsu/Kconfig      |   30 -
 drivers/net/ethernet/fujitsu/Makefile     |    6 -
 drivers/net/ethernet/fujitsu/fmvj18x_cs.c | 1176 -----------------------------
 4 files changed, 1213 deletions(-)

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index bdc29d143160..c94e8f27af94 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -61,7 +61,6 @@ source "drivers/net/ethernet/engleder/Kconfig"
 source "drivers/net/ethernet/ezchip/Kconfig"
 source "drivers/net/ethernet/faraday/Kconfig"
 source "drivers/net/ethernet/freescale/Kconfig"
-source "drivers/net/ethernet/fujitsu/Kconfig"
 source "drivers/net/ethernet/fungible/Kconfig"
 source "drivers/net/ethernet/google/Kconfig"
 source "drivers/net/ethernet/hisilicon/Kconfig"
diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig
deleted file mode 100644
index 06a28bce5d27..000000000000
--- a/drivers/net/ethernet/fujitsu/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Fujitsu Network device configuration
-#
-
-config NET_VENDOR_FUJITSU
-	bool "Fujitsu devices"
-	default y
-	depends on PCMCIA
-	help
-	  If you have a network (Ethernet) card belonging to this class, say Y.
-
-	  Note that the answer to this question doesn't directly affect the
-	  the questions about Fujitsu cards. If you say Y, you will be asked for
-	  your specific card in the following questions.
-
-if NET_VENDOR_FUJITSU
-
-config PCMCIA_FMVJ18X
-	tristate "Fujitsu FMV-J18x PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	select CRC32
-	help
-	  Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible
-	  PCMCIA (PC-card) Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called fmvj18x_cs.  If unsure, say N.
-
-endif # NET_VENDOR_FUJITSU
diff --git a/drivers/net/ethernet/fujitsu/Makefile b/drivers/net/ethernet/fujitsu/Makefile
deleted file mode 100644
index 74feebbf4572..000000000000
--- a/drivers/net/ethernet/fujitsu/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Fujitsu network device drivers.
-#
-
-obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
deleted file mode 100644
index 4859493471db..000000000000
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ /dev/null
@@ -1,1176 +0,0 @@
-/*======================================================================
-    fmvj18x_cs.c 2.8 2002/03/23
-
-    A fmvj18x (and its compatibles) PCMCIA client driver
-
-    Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp
-
-    TDK LAK-CD021 and CONTEC C-NET(PC)C support added by 
-    Nobuhiro Katayama, kata-n@po.iijnet.or.jp
-
-    The PCMCIA client code is based on code written by David Hinds.
-    Network code is based on the "FMV-18x driver" by Yutaka TAMIYA
-    but is actually largely Donald Becker's AT1700 driver, which
-    carries the following attribution:
-
-    Written 1993-94 by Donald Becker.
-
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.
-    
-    This software may be used and distributed according to the terms
-    of the GNU General Public License, incorporated herein by reference.
-    
-    The author may be reached as becker@scyld.com, or C/O
-    Scyld Computing Corporation
-    410 Severn Ave., Suite 210
-    Annapolis MD 21403
-   
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define DRV_NAME	"fmvj18x_cs"
-#define DRV_VERSION	"2.9"
-
-#include <linux/module.h>
-#include <linux/kernel.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/crc32.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/* SRAM configuration */
-/* 0:4KB*2 TX buffer   else:8KB*2 TX buffer */
-INT_MODULE_PARM(sram_config, 0);
-
-
-/*====================================================================*/
-/*
-    PCMCIA event handlers
- */
-static int fmvj18x_config(struct pcmcia_device *link);
-static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id);
-static int fmvj18x_setup_mfc(struct pcmcia_device *link);
-static void fmvj18x_release(struct pcmcia_device *link);
-static void fmvj18x_detach(struct pcmcia_device *p_dev);
-
-/*
-    LAN controller(MBH86960A) specific routines
- */
-static int fjn_config(struct net_device *dev, struct ifmap *map);
-static int fjn_open(struct net_device *dev);
-static int fjn_close(struct net_device *dev);
-static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
-					struct net_device *dev);
-static irqreturn_t fjn_interrupt(int irq, void *dev_id);
-static void fjn_rx(struct net_device *dev);
-static void fjn_reset(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-/*
-    card type
- */
-enum cardtype { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN,
-	       XXX10304, NEC, KME
-};
-
-/*
-    driver specific data structure
-*/
-struct local_info {
-	struct pcmcia_device	*p_dev;
-    long open_time;
-    uint tx_started:1;
-    uint tx_queue;
-    u_short tx_queue_len;
-    enum cardtype cardtype;
-    u_short sent;
-    u_char __iomem *base;
-};
-
-#define MC_FILTERBREAK 64
-
-/*====================================================================*/
-/* 
-    ioport offset from the base address 
- */
-#define TX_STATUS               0 /* transmit status register */
-#define RX_STATUS               1 /* receive status register */
-#define TX_INTR                 2 /* transmit interrupt mask register */
-#define RX_INTR                 3 /* receive interrupt mask register */
-#define TX_MODE                 4 /* transmit mode register */
-#define RX_MODE                 5 /* receive mode register */
-#define CONFIG_0                6 /* configuration register 0 */
-#define CONFIG_1                7 /* configuration register 1 */
-
-#define NODE_ID                 8 /* node ID register            (bank 0) */
-#define MAR_ADR                 8 /* multicast address registers (bank 1) */
-
-#define DATAPORT                8 /* buffer mem port registers   (bank 2) */
-#define TX_START               10 /* transmit start register */
-#define COL_CTRL               11 /* 16 collision control register */
-#define BMPR12                 12 /* reserved */
-#define BMPR13                 13 /* reserved */
-#define RX_SKIP                14 /* skip received packet register */
-
-#define LAN_CTRL               16 /* LAN card control register */
-
-#define MAC_ID               0x1a /* hardware address */
-#define UNGERMANN_MAC_ID     0x18 /* UNGERMANN-BASS hardware address */
-
-/* 
-    control bits 
- */
-#define ENA_TMT_OK           0x80
-#define ENA_TMT_REC          0x20
-#define ENA_COL              0x04
-#define ENA_16_COL           0x02
-#define ENA_TBUS_ERR         0x01
-
-#define ENA_PKT_RDY          0x80
-#define ENA_BUS_ERR          0x40
-#define ENA_LEN_ERR          0x08
-#define ENA_ALG_ERR          0x04
-#define ENA_CRC_ERR          0x02
-#define ENA_OVR_FLO          0x01
-
-/* flags */
-#define F_TMT_RDY            0x80 /* can accept new packet */
-#define F_NET_BSY            0x40 /* carrier is detected */
-#define F_TMT_OK             0x20 /* send packet successfully */
-#define F_SRT_PKT            0x10 /* short packet error */
-#define F_COL_ERR            0x04 /* collision error */
-#define F_16_COL             0x02 /* 16 collision error */
-#define F_TBUS_ERR           0x01 /* bus read error */
-
-#define F_PKT_RDY            0x80 /* packet(s) in buffer */
-#define F_BUS_ERR            0x40 /* bus read error */
-#define F_LEN_ERR            0x08 /* short packet */
-#define F_ALG_ERR            0x04 /* frame error */
-#define F_CRC_ERR            0x02 /* CRC error */
-#define F_OVR_FLO            0x01 /* overflow error */
-
-#define F_BUF_EMP            0x40 /* receive buffer is empty */
-
-#define F_SKP_PKT            0x05 /* drop packet in buffer */
-
-/* default bitmaps */
-#define D_TX_INTR  ( ENA_TMT_OK )
-#define D_RX_INTR  ( ENA_PKT_RDY | ENA_LEN_ERR \
-		   | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO )
-#define TX_STAT_M  ( F_TMT_RDY )
-#define RX_STAT_M  ( F_PKT_RDY | F_LEN_ERR \
-                   | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO )
-
-/* commands */
-#define D_TX_MODE            0x06 /* no tests, detect carrier */
-#define ID_MATCHED           0x02 /* (RX_MODE) */
-#define RECV_ALL             0x03 /* (RX_MODE) */
-#define CONFIG0_DFL          0x5a /* 16bit bus, 4K x 2 Tx queues */
-#define CONFIG0_DFL_1        0x5e /* 16bit bus, 8K x 2 Tx queues */
-#define CONFIG0_RST          0xda /* Data Link Controller off (CONFIG_0) */
-#define CONFIG0_RST_1        0xde /* Data Link Controller off (CONFIG_0) */
-#define BANK_0               0xa0 /* bank 0 (CONFIG_1) */
-#define BANK_1               0xa4 /* bank 1 (CONFIG_1) */
-#define BANK_2               0xa8 /* bank 2 (CONFIG_1) */
-#define CHIP_OFF             0x80 /* contrl chip power off (CONFIG_1) */
-#define DO_TX                0x80 /* do transmit packet */
-#define SEND_PKT             0x81 /* send a packet */
-#define AUTO_MODE            0x07 /* Auto skip packet on 16 col detected */
-#define MANU_MODE            0x03 /* Stop and skip packet on 16 col */
-#define TDK_AUTO_MODE        0x47 /* Auto skip packet on 16 col detected */
-#define TDK_MANU_MODE        0x43 /* Stop and skip packet on 16 col */
-#define INTR_OFF             0x0d /* LAN controller ignores interrupts */
-#define INTR_ON              0x1d /* LAN controller will catch interrupts */
-
-#define TX_TIMEOUT		((400*HZ)/1000)
-
-#define BANK_0U              0x20 /* bank 0 (CONFIG_1) */
-#define BANK_1U              0x24 /* bank 1 (CONFIG_1) */
-#define BANK_2U              0x28 /* bank 2 (CONFIG_1) */
-
-static const struct net_device_ops fjn_netdev_ops = {
-	.ndo_open 		= fjn_open,
-	.ndo_stop		= fjn_close,
-	.ndo_start_xmit 	= fjn_start_xmit,
-	.ndo_tx_timeout 	= fjn_tx_timeout,
-	.ndo_set_config 	= fjn_config,
-	.ndo_set_rx_mode	= set_rx_mode,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int fmvj18x_probe(struct pcmcia_device *link)
-{
-    struct local_info *lp;
-    struct net_device *dev;
-
-    dev_dbg(&link->dev, "fmvj18x_attach()\n");
-
-    /* Make up a FMVJ18x specific data structure */
-    dev = alloc_etherdev(sizeof(struct local_info));
-    if (!dev)
-	return -ENOMEM;
-    lp = netdev_priv(dev);
-    link->priv = dev;
-    lp->p_dev = link;
-    lp->base = NULL;
-
-    /* The io structure describes IO port mapping */
-    link->resource[0]->end = 32;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
-    /* General socket configuration */
-    link->config_flags |= CONF_ENABLE_IRQ;
-
-    dev->netdev_ops = &fjn_netdev_ops;
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    dev->ethtool_ops = &netdev_ethtool_ops;
-
-    return fmvj18x_config(link);
-} /* fmvj18x_attach */
-
-/*====================================================================*/
-
-static void fmvj18x_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    dev_dbg(&link->dev, "fmvj18x_detach\n");
-
-    unregister_netdev(dev);
-
-    fmvj18x_release(link);
-
-    free_netdev(dev);
-} /* fmvj18x_detach */
-
-/*====================================================================*/
-
-static int mfc_try_io_port(struct pcmcia_device *link)
-{
-    int i, ret;
-    static const unsigned int serial_base[5] =
-	{ 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-
-    for (i = 0; i < 5; i++) {
-	link->resource[1]->start = serial_base[i];
-	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	if (link->resource[1]->start == 0) {
-	    link->resource[1]->end = 0;
-	    pr_notice("out of resource for serial\n");
-	}
-	ret = pcmcia_request_io(link);
-	if (ret == 0)
-		return ret;
-    }
-    return ret;
-}
-
-static int ungermann_try_io_port(struct pcmcia_device *link)
-{
-    int ret;
-    unsigned int ioaddr;
-    /*
-	Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
-	0x380,0x3c0 only for ioport.
-    */
-    for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
-	link->resource[0]->start = ioaddr;
-	ret = pcmcia_request_io(link);
-	if (ret == 0) {
-	    /* calculate ConfigIndex value */
-	    link->config_index =
-		((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
-	    return ret;
-	}
-    }
-    return ret;	/* RequestIO failed */
-}
-
-static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
-{
-	return 0; /* strange, but that's what the code did already before... */
-}
-
-static int fmvj18x_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *lp = netdev_priv(dev);
-    int i, ret;
-    unsigned int ioaddr;
-    enum cardtype cardtype;
-    char *card_name = "unknown";
-    u8 *buf;
-    size_t len;
-    u_char buggybuf[32];
-    u8 addr[ETH_ALEN];
-
-    dev_dbg(&link->dev, "fmvj18x_config\n");
-
-    link->io_lines = 5;
-
-    len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
-    kfree(buf);
-
-    if (len) {
-	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
-	ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL);
-	if (ret != 0)
-		goto failed;
-
-	switch (link->manf_id) {
-	case MANFID_TDK:
-	    cardtype = TDK;
-	    if (link->card_id == PRODID_TDK_GN3410 ||
-		link->card_id == PRODID_TDK_NP9610 ||
-		link->card_id == PRODID_TDK_MN3200) {
-		/* MultiFunction Card */
-		link->config_base = 0x800;
-		link->config_index = 0x47;
-		link->resource[1]->end = 8;
-	    }
-	    break;
-	case MANFID_NEC:
-	    cardtype = NEC; /* MultiFunction Card */
-	    link->config_base = 0x800;
-	    link->config_index = 0x47;
-	    link->resource[1]->end = 8;
-	    break;
-	case MANFID_KME:
-	    cardtype = KME; /* MultiFunction Card */
-	    link->config_base = 0x800;
-	    link->config_index = 0x47;
-	    link->resource[1]->end = 8;
-	    break;
-	case MANFID_CONTEC:
-	    cardtype = CONTEC;
-	    break;
-	case MANFID_FUJITSU:
-	    if (link->config_base == 0x0fe0)
-		cardtype = MBH10302;
-	    else if (link->card_id == PRODID_FUJITSU_MBH10302) 
-                /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
-                   but these are MBH10304 based card. */ 
-		cardtype = MBH10304;
-	    else if (link->card_id == PRODID_FUJITSU_MBH10304)
-		cardtype = MBH10304;
-	    else
-		cardtype = LA501;
-	    break;
-	default:
-	    cardtype = MBH10304;
-	}
-    } else {
-	/* old type card */
-	switch (link->manf_id) {
-	case MANFID_FUJITSU:
-	    if (link->card_id == PRODID_FUJITSU_MBH10304) {
-		cardtype = XXX10304;    /* MBH10304 with buggy CIS */
-		link->config_index = 0x20;
-	    } else {
-		cardtype = MBH10302;    /* NextCom NC5310, etc. */
-		link->config_index = 1;
-	    }
-	    break;
-	case MANFID_UNGERMANN:
-	    cardtype = UNGERMANN;
-	    break;
-	default:
-	    cardtype = MBH10302;
-	    link->config_index = 1;
-	}
-    }
-
-    if (link->resource[1]->end != 0) {
-	ret = mfc_try_io_port(link);
-	if (ret != 0) goto failed;
-    } else if (cardtype == UNGERMANN) {
-	ret = ungermann_try_io_port(link);
-	if (ret != 0) goto failed;
-    } else { 
-	    ret = pcmcia_request_io(link);
-	    if (ret)
-		    goto failed;
-    }
-    ret = pcmcia_request_irq(link, fjn_interrupt);
-    if (ret)
-	    goto failed;
-    ret = pcmcia_enable_device(link);
-    if (ret)
-	    goto failed;
-
-    dev->irq = link->irq;
-    dev->base_addr = link->resource[0]->start;
-
-    if (resource_size(link->resource[1]) != 0) {
-	ret = fmvj18x_setup_mfc(link);
-	if (ret != 0) goto failed;
-    }
-
-    ioaddr = dev->base_addr;
-
-    /* Reset controller */
-    if (sram_config == 0) 
-	outb(CONFIG0_RST, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
-
-    /* Power On chip and select bank 0 */
-    if (cardtype == MBH10302)
-	outb(BANK_0, ioaddr + CONFIG_1);
-    else
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    
-    /* Set hardware address */
-    switch (cardtype) {
-    case MBH10304:
-    case TDK:
-    case LA501:
-    case CONTEC:
-    case NEC:
-    case KME:
-	if (cardtype == MBH10304) {
-	    card_name = "FMV-J182";
-
-	    len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
-	    if (len < 11) {
-		    kfree(buf);
-		    goto failed;
-	    }
-	    /* Read MACID from CIS */
-	    eth_hw_addr_set(dev, &buf[5]);
-	    kfree(buf);
-	} else {
-	    if (pcmcia_get_mac_from_cis(link, dev))
-		goto failed;
-	    if( cardtype == TDK ) {
-		card_name = "TDK LAK-CD021";
-	    } else if( cardtype == LA501 ) {
-		card_name = "LA501";
-	    } else if( cardtype == NEC ) {
-		card_name = "PK-UG-J001";
-	    } else if( cardtype == KME ) {
-		card_name = "Panasonic";
-	    } else {
-		card_name = "C-NET(PC)C";
-	    }
-	}
-	break;
-    case UNGERMANN:
-	/* Read MACID from register */
-	for (i = 0; i < 6; i++) 
-	    addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i);
-	eth_hw_addr_set(dev, addr);
-	card_name = "Access/CARD";
-	break;
-    case XXX10304:
-	/* Read MACID from Buggy CIS */
-	if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
-	    pr_notice("unable to read hardware net address\n");
-	    goto failed;
-	}
-	eth_hw_addr_set(dev, buggybuf);
-	card_name = "FMV-J182";
-	break;
-    case MBH10302:
-    default:
-	/* Read MACID from register */
-	for (i = 0; i < 6; i++) 
-	    addr[i] = inb(ioaddr + MAC_ID + i);
-	eth_hw_addr_set(dev, addr);
-	card_name = "FMV-J181";
-	break;
-    }
-
-    lp->cardtype = cardtype;
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-	pr_notice("register_netdev() failed\n");
-	goto failed;
-    }
-
-    /* print current configuration */
-    netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n",
-		card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
-		dev->base_addr, dev->irq, dev->dev_addr);
-
-    return 0;
-    
-failed:
-    fmvj18x_release(link);
-    return -ENODEV;
-} /* fmvj18x_config */
-/*====================================================================*/
-
-static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
-{
-    u_char __iomem *base;
-    int i, j;
-
-    /* Allocate a small memory window */
-    link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[2]->start = 0; link->resource[2]->end = 0;
-    i = pcmcia_request_window(link, link->resource[2], 0);
-    if (i != 0)
-	return -1;
-
-    base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
-    if (!base) {
-	pcmcia_release_window(link, link->resource[2]);
-	return -1;
-    }
-
-    pcmcia_map_mem_page(link, link->resource[2], 0);
-
-    /*
-     *  MBH10304 CISTPL_FUNCE_LAN_NODE_ID format
-     *  22 0d xx xx xx 04 06 yy yy yy yy yy yy ff
-     *  'xx' is garbage.
-     *  'yy' is MAC address.
-    */ 
-    for (i = 0; i < 0x200; i++) {
-	if (readb(base+i*2) == 0x22) {	
-		if (readb(base+(i-1)*2) == 0xff &&
-		    readb(base+(i+5)*2) == 0x04 &&
-		    readb(base+(i+6)*2) == 0x06 &&
-		    readb(base+(i+13)*2) == 0xff)
-			break;
-	}
-    }
-
-    if (i != 0x200) {
-	for (j = 0 ; j < 6; j++,i++) {
-	    node_id[j] = readb(base+(i+7)*2);
-	}
-    }
-
-    iounmap(base);
-    j = pcmcia_release_window(link, link->resource[2]);
-    return (i != 0x200) ? 0 : -1;
-
-} /* fmvj18x_get_hwinfo */
-/*====================================================================*/
-
-static int fmvj18x_setup_mfc(struct pcmcia_device *link)
-{
-    int i;
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr;
-    struct local_info *lp = netdev_priv(dev);
-
-    /* Allocate a small memory window */
-    link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[3]->start = link->resource[3]->end = 0;
-    i = pcmcia_request_window(link, link->resource[3], 0);
-    if (i != 0)
-	return -1;
-
-    lp->base = ioremap(link->resource[3]->start,
-		       resource_size(link->resource[3]));
-    if (lp->base == NULL) {
-	netdev_notice(dev, "ioremap failed\n");
-	return -1;
-    }
-
-    i = pcmcia_map_mem_page(link, link->resource[3], 0);
-    if (i != 0) {
-	iounmap(lp->base);
-	lp->base = NULL;
-	return -1;
-    }
-    
-    ioaddr = dev->base_addr;
-    writeb(0x47, lp->base+0x800);	/* Config Option Register of LAN */
-    writeb(0x0,  lp->base+0x802);	/* Config and Status Register */
-
-    writeb(ioaddr & 0xff, lp->base+0x80a);	  /* I/O Base(Low) of LAN */
-    writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */
-   
-    writeb(0x45, lp->base+0x820);	/* Config Option Register of Modem */
-    writeb(0x8,  lp->base+0x822);	/* Config and Status Register */
-
-    return 0;
-
-}
-/*====================================================================*/
-
-static void fmvj18x_release(struct pcmcia_device *link)
-{
-
-    struct net_device *dev = link->priv;
-    struct local_info *lp = netdev_priv(dev);
-    u_char __iomem *tmp;
-
-    dev_dbg(&link->dev, "fmvj18x_release\n");
-
-    if (lp->base != NULL) {
-	tmp = lp->base;
-	lp->base = NULL;    /* set NULL before iounmap */
-	iounmap(tmp);
-    }
-
-    pcmcia_disable_device(link);
-
-}
-
-static int fmvj18x_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int fmvj18x_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		fjn_reset(dev);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-/*====================================================================*/
-
-static const struct pcmcia_device_id fmvj18x_ids[] = {
-	PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
-	PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
-	PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
-	PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922),
-	PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db),
-	PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e),
-	PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2),
-	PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4),
-	PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0       ", 0x8cef4d3a, 0x075fc7b6),
-	PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0        ", 0x8cef4d3a, 0xbccf43e6),
-	PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666),
-	PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70),
-	PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a),
-	PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2),
-	PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304  ES", 0x2599f454),
-	PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
-	PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
-
-static struct pcmcia_driver fmvj18x_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "fmvj18x_cs",
-	.probe		= fmvj18x_probe,
-	.remove		= fmvj18x_detach,
-	.id_table       = fmvj18x_ids,
-	.suspend	= fmvj18x_suspend,
-	.resume		= fmvj18x_resume,
-};
-module_pcmcia_driver(fmvj18x_cs_driver);
-
-/*====================================================================*/
-
-static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr;
-    unsigned short tx_stat, rx_stat;
-
-    ioaddr = dev->base_addr;
-
-    /* avoid multiple interrupts */
-    outw(0x0000, ioaddr + TX_INTR);
-
-    /* wait for a while */
-    udelay(1);
-
-    /* get status */
-    tx_stat = inb(ioaddr + TX_STATUS);
-    rx_stat = inb(ioaddr + RX_STATUS);
-
-    /* clear status */
-    outb(tx_stat, ioaddr + TX_STATUS);
-    outb(rx_stat, ioaddr + RX_STATUS);
-    
-    pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat);
-    pr_debug("               tx_status %02x.\n", tx_stat);
-    
-    if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
-	/* there is packet(s) in rx buffer */
-	fjn_rx(dev);
-    }
-    if (tx_stat & F_TMT_RDY) {
-	dev->stats.tx_packets += lp->sent ;
-        lp->sent = 0 ;
-	if (lp->tx_queue) {
-	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
-	    lp->sent = lp->tx_queue ;
-	    lp->tx_queue = 0;
-	    lp->tx_queue_len = 0;
-	    netif_trans_update(dev);
-	} else {
-	    lp->tx_started = 0;
-	}
-	netif_wake_queue(dev);
-    }
-    pr_debug("%s: exiting interrupt,\n", dev->name);
-    pr_debug("    tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
-
-    outb(D_TX_INTR, ioaddr + TX_INTR);
-    outb(D_RX_INTR, ioaddr + RX_INTR);
-
-    if (lp->base != NULL) {
-	/* Ack interrupt for multifunction card */
-	writeb(0x01, lp->base+0x802);
-	writeb(0x09, lp->base+0x822);
-    }
-
-    return IRQ_HANDLED;
-
-} /* fjn_interrupt */
-
-/*====================================================================*/
-
-static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-
-    netdev_notice(dev, "transmit timed out with status %04x, %s?\n",
-		  htons(inw(ioaddr + TX_STATUS)),
-		  inb(ioaddr + TX_STATUS) & F_TMT_RDY
-		  ? "IRQ conflict" : "network cable problem");
-    netdev_notice(dev, "timeout registers: %04x %04x %04x "
-		  "%04x %04x %04x %04x %04x.\n",
-		  htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)),
-		  htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)),
-		  htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)),
-		  htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14)));
-    dev->stats.tx_errors++;
-    /* ToDo: We should try to restart the adaptor... */
-    local_irq_disable();
-    fjn_reset(dev);
-
-    lp->tx_started = 0;
-    lp->tx_queue = 0;
-    lp->tx_queue_len = 0;
-    lp->sent = 0;
-    lp->open_time = jiffies;
-    local_irq_enable();
-    netif_wake_queue(dev);
-}
-
-static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
-					struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    short length = skb->len;
-    
-    if (length < ETH_ZLEN)
-    {
-	if (skb_padto(skb, ETH_ZLEN))
-		return NETDEV_TX_OK;
-	length = ETH_ZLEN;
-    }
-
-    netif_stop_queue(dev);
-
-    {
-	unsigned char *buf = skb->data;
-
-	if (length > ETH_FRAME_LEN) {
-	    netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n",
-			  length);
-	    return NETDEV_TX_BUSY;
-	}
-
-	netdev_dbg(dev, "Transmitting a packet of length %lu\n",
-		   (unsigned long)skb->len);
-	dev->stats.tx_bytes += skb->len;
-
-	/* Disable both interrupts. */
-	outw(0x0000, ioaddr + TX_INTR);
-
-	/* wait for a while */
-	udelay(1);
-
-	outw(length, ioaddr + DATAPORT);
-	outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-
-	lp->tx_queue++;
-	lp->tx_queue_len += ((length+3) & ~1);
-
-	if (lp->tx_started == 0) {
-	    /* If the Tx is idle, always trigger a transmit. */
-	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
-	    lp->sent = lp->tx_queue ;
-	    lp->tx_queue = 0;
-	    lp->tx_queue_len = 0;
-	    lp->tx_started = 1;
-	    netif_start_queue(dev);
-	} else {
-	    if( sram_config == 0 ) {
-		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
-		    /* Yes, there is room for one more packet. */
-		    netif_start_queue(dev);
-	    } else {
-		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 
-						lp->tx_queue < 127 )
-		    /* Yes, there is room for one more packet. */
-		    netif_start_queue(dev);
-	    }
-	}
-
-	/* Re-enable interrupts */
-	outb(D_TX_INTR, ioaddr + TX_INTR);
-	outb(D_RX_INTR, ioaddr + RX_INTR);
-    }
-    dev_kfree_skb (skb);
-
-    return NETDEV_TX_OK;
-} /* fjn_start_xmit */
-
-/*====================================================================*/
-
-static void fjn_reset(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    int i;
-
-    netdev_dbg(dev, "fjn_reset() called\n");
-
-    /* Reset controller */
-    if( sram_config == 0 ) 
-	outb(CONFIG0_RST, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
-
-    /* Power On chip and select bank 0 */
-    if (lp->cardtype == MBH10302)
-	outb(BANK_0, ioaddr + CONFIG_1);
-    else
-	outb(BANK_0U, ioaddr + CONFIG_1);
-
-    /* Set Tx modes */
-    outb(D_TX_MODE, ioaddr + TX_MODE);
-    /* set Rx modes */
-    outb(ID_MATCHED, ioaddr + RX_MODE);
-
-    /* Set hardware address */
-    for (i = 0; i < 6; i++) 
-        outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
-
-    /* (re)initialize the multicast table */
-    set_rx_mode(dev);
-
-    /* Switch to bank 2 (runtime mode) */
-    if (lp->cardtype == MBH10302)
-	outb(BANK_2, ioaddr + CONFIG_1);
-    else
-	outb(BANK_2U, ioaddr + CONFIG_1);
-
-    /* set 16col ctrl bits */
-    if( lp->cardtype == TDK || lp->cardtype == CONTEC) 
-        outb(TDK_AUTO_MODE, ioaddr + COL_CTRL);
-    else
-        outb(AUTO_MODE, ioaddr + COL_CTRL);
-
-    /* clear Reserved Regs */
-    outb(0x00, ioaddr + BMPR12);
-    outb(0x00, ioaddr + BMPR13);
-
-    /* reset Skip packet reg. */
-    outb(0x01, ioaddr + RX_SKIP);
-
-    /* Enable Tx and Rx */
-    if( sram_config == 0 )
-	outb(CONFIG0_DFL, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_DFL_1, ioaddr + CONFIG_0);
-
-    /* Init receive pointer ? */
-    inw(ioaddr + DATAPORT);
-    inw(ioaddr + DATAPORT);
-
-    /* Clear all status */
-    outb(0xff, ioaddr + TX_STATUS);
-    outb(0xff, ioaddr + RX_STATUS);
-
-    if (lp->cardtype == MBH10302)
-	outb(INTR_OFF, ioaddr + LAN_CTRL);
-
-    /* Turn on Rx interrupts */
-    outb(D_TX_INTR, ioaddr + TX_INTR);
-    outb(D_RX_INTR, ioaddr + RX_INTR);
-
-    /* Turn on interrupts from LAN card controller */
-    if (lp->cardtype == MBH10302)
-	outb(INTR_ON, ioaddr + LAN_CTRL);
-} /* fjn_reset */
-
-/*====================================================================*/
-
-static void fjn_rx(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    int boguscount = 10;	/* 5 -> 10: by agy 19940922 */
-
-    pr_debug("%s: in rx_packet(), rx_status %02x.\n",
-	  dev->name, inb(ioaddr + RX_STATUS));
-
-    while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
-	u_short status = inw(ioaddr + DATAPORT);
-
-	netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n",
-		   inb(ioaddr + RX_MODE), status);
-#ifndef final_version
-	if (status == 0) {
-	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
-	    break;
-	}
-#endif
-	if ((status & 0xF0) != 0x20) {	/* There was an error. */
-	    dev->stats.rx_errors++;
-	    if (status & F_LEN_ERR) dev->stats.rx_length_errors++;
-	    if (status & F_ALG_ERR) dev->stats.rx_frame_errors++;
-	    if (status & F_CRC_ERR) dev->stats.rx_crc_errors++;
-	    if (status & F_OVR_FLO) dev->stats.rx_over_errors++;
-	} else {
-	    u_short pkt_len = inw(ioaddr + DATAPORT);
-	    /* Malloc up new buffer. */
-	    struct sk_buff *skb;
-
-	    if (pkt_len > 1550) {
-		netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n",
-			      pkt_len);
-		outb(F_SKP_PKT, ioaddr + RX_SKIP);
-		dev->stats.rx_errors++;
-		break;
-	    }
-	    skb = netdev_alloc_skb(dev, pkt_len + 2);
-	    if (skb == NULL) {
-		outb(F_SKP_PKT, ioaddr + RX_SKIP);
-		dev->stats.rx_dropped++;
-		break;
-	    }
-
-	    skb_reserve(skb, 2);
-	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
-		 (pkt_len + 1) >> 1);
-	    skb->protocol = eth_type_trans(skb, dev);
-
-	    {
-		int i;
-		pr_debug("%s: Rxed packet of length %d: ",
-			dev->name, pkt_len);
-		for (i = 0; i < 14; i++)
-			pr_debug(" %02x", skb->data[i]);
-		pr_debug(".\n");
-	    }
-
-	    netif_rx(skb);
-	    dev->stats.rx_packets++;
-	    dev->stats.rx_bytes += pkt_len;
-	}
-	if (--boguscount <= 0)
-	    break;
-    }
-
-    /* If any worth-while packets have been received, dev_rint()
-	   has done a netif_wake_queue() for us and will work on them
-	   when we get to the bottom-half routine. */
-/*
-    if (lp->cardtype != TDK) {
-	int i;
-	for (i = 0; i < 20; i++) {
-	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
-		break;
-	    (void)inw(ioaddr + DATAPORT);  /+ dummy status read +/
-	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
-	}
-
-	if (i > 0)
-	    pr_debug("%s: Exint Rx packet with mode %02x after "
-		  "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
-    }
-*/
-} /* fjn_rx */
-
-/*====================================================================*/
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	strscpy(info->version, DRV_VERSION, sizeof(info->version));
-	snprintf(info->bus_info, sizeof(info->bus_info),
-		"PCMCIA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-};
-
-static int fjn_config(struct net_device *dev, struct ifmap *map){
-    return 0;
-}
-
-static int fjn_open(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-
-    pr_debug("fjn_open('%s').\n", dev->name);
-
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-    
-    link->open++;
-    
-    fjn_reset(dev);
-    
-    lp->tx_started = 0;
-    lp->tx_queue = 0;
-    lp->tx_queue_len = 0;
-    lp->open_time = jiffies;
-    netif_start_queue(dev);
-    
-    return 0;
-} /* fjn_open */
-
-/*====================================================================*/
-
-static int fjn_close(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-    unsigned int ioaddr = dev->base_addr;
-
-    pr_debug("fjn_close('%s').\n", dev->name);
-
-    lp->open_time = 0;
-    netif_stop_queue(dev);
-
-    /* Set configuration register 0 to disable Tx and Rx. */
-    if( sram_config == 0 ) 
-	outb(CONFIG0_RST ,ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0);
-
-    /* Update the statistics -- ToDo. */
-
-    /* Power-down the chip.  Green, green, green! */
-    outb(CHIP_OFF ,ioaddr + CONFIG_1);
-
-    /* Set the ethernet adaptor disable IRQ */
-    if (lp->cardtype == MBH10302)
-	outb(INTR_OFF, ioaddr + LAN_CTRL);
-
-    link->open--;
-
-    return 0;
-} /* fjn_close */
-
-/*====================================================================*/
-
-/*
-  Set the multicast/promiscuous mode for this adaptor.
-*/
-
-static void set_rx_mode(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    u_char mc_filter[8];		 /* Multicast hash filter */
-    u_long flags;
-    int i;
-    
-    int saved_bank;
-    int saved_config_0 = inb(ioaddr + CONFIG_0);
-     
-    local_irq_save(flags); 
-
-    /* Disable Tx and Rx */
-    if (sram_config == 0) 
-	outb(CONFIG0_RST, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
-
-    if (dev->flags & IFF_PROMISC) {
-	memset(mc_filter, 0xff, sizeof(mc_filter));
-	outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
-    } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
-	       (dev->flags & IFF_ALLMULTI)) {
-	/* Too many to filter perfectly -- accept all multicasts. */
-	memset(mc_filter, 0xff, sizeof(mc_filter));
-	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
-    } else if (netdev_mc_empty(dev)) {
-	memset(mc_filter, 0x00, sizeof(mc_filter));
-	outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
-    } else {
-	struct netdev_hw_addr *ha;
-
-	memset(mc_filter, 0, sizeof(mc_filter));
-	netdev_for_each_mc_addr(ha, dev) {
-	    unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26;
-	    mc_filter[bit >> 3] |= (1 << (bit & 7));
-	}
-	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
-    }
-
-    /* Switch to bank 1 and set the multicast table. */
-    saved_bank = inb(ioaddr + CONFIG_1);
-    outb(0xe4, ioaddr + CONFIG_1);
-
-    for (i = 0; i < 8; i++)
-	outb(mc_filter[i], ioaddr + MAR_ADR + i);
-    outb(saved_bank, ioaddr + CONFIG_1);
-
-    outb(saved_config_0, ioaddr + CONFIG_0);
-
-    local_irq_restore(flags);
-}

-- 
2.53.0


^ permalink raw reply related

* [PATCH net v2 10/15] drivers: net: cirrus: mac89x0: Remove this driver
From: Andrew Lunn @ 2026-04-22 18:01 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: Geert Uytterhoeven, Michael Fritscher, Byron Stanoszek,
	Daniel Palmer, linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260422-v7-0-0-net-next-driver-removal-v1-v2-0-08a5b59784d5@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 v2 13/15] drivers: net: 8390: pcnet: Remove this driver
From: Andrew Lunn @ 2026-04-22 18:01 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: Geert Uytterhoeven, Michael Fritscher, Byron Stanoszek,
	Daniel Palmer, linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260422-v7-0-0-net-next-driver-removal-v1-v2-0-08a5b59784d5@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

* [PATCH net v2 12/15] drivers: net: 8390: AX88190: Remove this driver
From: Andrew Lunn @ 2026-04-22 18:01 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: Geert Uytterhoeven, Michael Fritscher, Byron Stanoszek,
	Daniel Palmer, linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260422-v7-0-0-net-next-driver-removal-v1-v2-0-08a5b59784d5@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 v2 15/15] drivers: net: 8390: wd80x3: Remove this driver
From: Andrew Lunn @ 2026-04-22 18:01 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: Geert Uytterhoeven, Michael Fritscher, Byron Stanoszek,
	Daniel Palmer, linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260422-v7-0-0-net-next-driver-removal-v1-v2-0-08a5b59784d5@lunn.ch>

The wd80x3 was written by Donald 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/8390/Kconfig  |  11 -
 drivers/net/ethernet/8390/Makefile |   1 -
 drivers/net/ethernet/8390/wd.c     | 575 -------------------------------------
 3 files changed, 587 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index dd066b0a39d5..d2116d70ab5d 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -144,17 +144,6 @@ config STNIC
 
 	  If unsure, say N.
 
-config WD80x3
-	tristate "WD80*3 support"
-	depends on ISA
-	select NETDEV_LEGACY_INIT
-	select CRC32
-	help
-	  If you have a network (Ethernet) card of this type, say Y here.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called wd.
-
 config ZORRO8390
 	tristate "Zorro NS8390-based Ethernet support"
 	depends on ZORRO
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index 0afdccddda58..ad5145c30c85 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -12,6 +12,5 @@ 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_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_XSURF100) += xsurf100.o
 obj-$(CONFIG_ZORRO8390) += zorro8390.o
diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c
deleted file mode 100644
index ffd639477dfc..000000000000
--- a/drivers/net/ethernet/8390/wd.c
+++ /dev/null
@@ -1,575 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-/* wd.c: A WD80x3 ethernet driver for linux. */
-/*
-	Written 1993-94 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	This is a driver for WD8003 and WD8013 "compatible" ethercards.
-
-	Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
-
-	Changelog:
-
-	Paul Gortmaker	: multiple card support for module users, support
-			  for non-standard memory sizes.
-
-
-*/
-
-static const char version[] =
-	"wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <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/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <net/Space.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "wd"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int wd_portlist[] __initdata =
-{0x300, 0x280, 0x380, 0x240, 0};
-
-static int wd_probe1(struct net_device *dev, int ioaddr);
-
-static int wd_open(struct net_device *dev);
-static void wd_reset_8390(struct net_device *dev);
-static void wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void wd_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void wd_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, int start_page);
-static int wd_close(struct net_device *dev);
-
-static u32 wd_msg_enable;
-
-#define WD_START_PG		0x00	/* First page of TX buffer */
-#define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
-#define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
-
-#define WD_CMDREG		0		/* Offset to ASIC command register. */
-#define	 WD_RESET		0x80	/* Board reset, in WD_CMDREG. */
-#define	 WD_MEMENB		0x40	/* Enable the shared memory. */
-#define WD_CMDREG5		5		/* Offset to 16-bit-only ASIC register 5. */
-#define	 ISA16			0x80	/* Enable 16 bit access from the ISA bus. */
-#define	 NIC16			0x40	/* Enable 16 bit access from the 8390. */
-#define WD_NIC_OFFSET	16		/* Offset to the 8390 from the base_addr. */
-#define WD_IO_EXTENT	32
-
-
-/*	Probe for the WD8003 and WD8013.  These cards have the station
-	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
-	following. A Soundblaster can have the same checksum as an WDethercard,
-	so we have an extra exclusionary check for it.
-
-	The wd_probe1() routine initializes the card and fills the
-	station address field. */
-
-static int __init do_wd_probe(struct net_device *dev)
-{
-	int i;
-	struct resource *r;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-	int mem_start = dev->mem_start;
-	int mem_end = dev->mem_end;
-
-	if (base_addr > 0x1ff) {	/* Check a user specified location. */
-		r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
-		if ( r == NULL)
-			return -EBUSY;
-		i = wd_probe1(dev, base_addr);
-		if (i != 0)
-			release_region(base_addr, WD_IO_EXTENT);
-		else
-			r->name = dev->name;
-		return i;
-	}
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-	for (i = 0; wd_portlist[i]; i++) {
-		int ioaddr = wd_portlist[i];
-		r = request_region(ioaddr, WD_IO_EXTENT, "wd-probe");
-		if (r == NULL)
-			continue;
-		if (wd_probe1(dev, ioaddr) == 0) {
-			r->name = dev->name;
-			return 0;
-		}
-		release_region(ioaddr, WD_IO_EXTENT);
-		dev->irq = irq;
-		dev->mem_start = mem_start;
-		dev->mem_end = mem_end;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init wd_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_wd_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops wd_netdev_ops = {
-	.ndo_open		= wd_open,
-	.ndo_stop		= wd_close,
-	.ndo_start_xmit		= ei_start_xmit,
-	.ndo_tx_timeout		= ei_tx_timeout,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= ei_poll,
-#endif
-};
-
-static int __init wd_probe1(struct net_device *dev, int ioaddr)
-{
-	int i;
-	int err;
-	int checksum = 0;
-	int ancient = 0;			/* An old card without config registers. */
-	int word16 = 0;				/* 0 = 8 bit, 1 = 16 bit */
-	u8 addr[ETH_ALEN];
-	const char *model_name;
-	static unsigned version_printed;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	for (i = 0; i < 8; i++)
-		checksum += inb(ioaddr + 8 + i);
-	if (inb(ioaddr + 8) == 0xff 	/* Extra check to avoid soundcard. */
-		|| inb(ioaddr + 9) == 0xff
-		|| (checksum & 0xff) != 0xFF)
-		return -ENODEV;
-
-	/* Check for semi-valid mem_start/end values if supplied. */
-	if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) {
-		netdev_warn(dev,
-			    "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
-		dev->mem_start = 0;
-		dev->mem_end = 0;
-	}
-
-	if ((wd_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
-		netdev_info(dev, version);
-
-	for (i = 0; i < 6; i++)
-		addr[i] = inb(ioaddr + 8 + i);
-	eth_hw_addr_set(dev, addr);
-
-	netdev_info(dev, "WD80x3 at %#3x, %pM", ioaddr, dev->dev_addr);
-
-	/* The following PureData probe code was contributed by
-	   Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
-	   configuration differently from others so we have to check for them.
-	   This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
-	   */
-	if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
-		unsigned char reg5 = inb(ioaddr+5);
-
-		switch (inb(ioaddr+2)) {
-		case 0x03: word16 = 0; model_name = "PDI8023-8";	break;
-		case 0x05: word16 = 0; model_name = "PDUC8023";	break;
-		case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
-			/* Either 0x01 (dumb) or they've released a new version. */
-		default:	 word16 = 0; model_name = "PDI8023";	break;
-		}
-		dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
-		dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
-	} else {								/* End of PureData probe */
-		/* This method of checking for a 16-bit board is borrowed from the
-		   we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
-		   I'm comparing the two method in alpha test to make certain they
-		   return the same result. */
-		/* Check for the old 8 bit board - it has register 0/8 aliasing.
-		   Do NOT check i>=6 here -- it hangs the old 8003 boards! */
-		for (i = 0; i < 6; i++)
-			if (inb(ioaddr+i) != inb(ioaddr+8+i))
-				break;
-		if (i >= 6) {
-			ancient = 1;
-			model_name = "WD8003-old";
-			word16 = 0;
-		} else {
-			int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
-			outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
-			if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
-				&& (tmp & 0x01) == 0x01	) {				/* In a 16 slot. */
-				int asic_reg5 = inb(ioaddr+WD_CMDREG5);
-				/* Magic to set ASIC to word-wide mode. */
-				outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
-				outb(tmp, ioaddr+1);
-				model_name = "WD8013";
-				word16 = 1;		/* We have a 16bit board here! */
-			} else {
-				model_name = "WD8003";
-				word16 = 0;
-			}
-			outb(tmp, ioaddr+1);			/* Restore original reg1 value. */
-		}
-#ifndef final_version
-		if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
-			pr_cont("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
-				word16 ? 16 : 8,
-				(inb(ioaddr+1) & 0x01) ? 16 : 8);
-#endif
-	}
-
-#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
-	/* Allow a compile-time override.	 */
-	dev->mem_start = WD_SHMEM;
-#else
-	if (dev->mem_start == 0) {
-		/* Sanity and old 8003 check */
-		int reg0 = inb(ioaddr);
-		if (reg0 == 0xff || reg0 == 0) {
-			/* Future plan: this could check a few likely locations first. */
-			dev->mem_start = 0xd0000;
-			pr_cont(" assigning address %#lx", dev->mem_start);
-		} else {
-			int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
-			/* Some boards don't have the register 5 -- it returns 0xff. */
-			if (high_addr_bits == 0x1f || word16 == 0)
-				high_addr_bits = 0x01;
-			dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
-		}
-	}
-#endif
-
-	/* The 8390 isn't at the base address -- the ASIC regs are there! */
-	dev->base_addr = ioaddr+WD_NIC_OFFSET;
-
-	if (dev->irq < 2) {
-		static const int irqmap[] = {9, 3, 5, 7, 10, 11, 15, 4};
-		int reg1 = inb(ioaddr+1);
-		int reg4 = inb(ioaddr+4);
-		if (ancient || reg1 == 0xff) {	/* Ack!! No way to read the IRQ! */
-			short nic_addr = ioaddr+WD_NIC_OFFSET;
-			unsigned long irq_mask;
-
-			/* We have an old-style ethercard that doesn't report its IRQ
-			   line.  Do autoirq to find the IRQ line. Note that this IS NOT
-			   a reliable way to trigger an interrupt. */
-			outb_p(E8390_NODMA + E8390_STOP, nic_addr);
-			outb(0x00, nic_addr+EN0_IMR);	/* Disable all intrs. */
-
-			irq_mask = probe_irq_on();
-			outb_p(0xff, nic_addr + EN0_IMR);	/* Enable all interrupts. */
-			outb_p(0x00, nic_addr + EN0_RCNTLO);
-			outb_p(0x00, nic_addr + EN0_RCNTHI);
-			outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
-			mdelay(20);
-			dev->irq = probe_irq_off(irq_mask);
-
-			outb_p(0x00, nic_addr+EN0_IMR);	/* Mask all intrs. again. */
-
-			if (wd_msg_enable & NETIF_MSG_PROBE)
-				pr_cont(" autoirq is %d", dev->irq);
-			if (dev->irq < 2)
-				dev->irq = word16 ? 10 : 5;
-		} else
-			dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
-	} else if (dev->irq == 2)		/* Fixup bogosity: IRQ2 is really IRQ9 */
-		dev->irq = 9;
-
-	/* Snarf the interrupt now.  There's no point in waiting since we cannot
-	   share and the board will usually be enabled. */
-	i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
-	if (i) {
-		pr_cont(" unable to get IRQ %d.\n", dev->irq);
-		return i;
-	}
-
-	/* OK, were are certain this is going to work.  Setup the device. */
-	ei_status.name = model_name;
-	ei_status.word16 = word16;
-	ei_status.tx_start_page = WD_START_PG;
-	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
-
-	/* Don't map in the shared memory until the board is actually opened. */
-
-	/* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
-	if (dev->mem_end != 0) {
-		ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-		ei_status.priv = dev->mem_end - dev->mem_start;
-	} else {
-		ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
-		dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
-		ei_status.priv = (ei_status.stop_page - WD_START_PG)*256;
-	}
-
-	ei_status.mem = ioremap(dev->mem_start, ei_status.priv);
-	if (!ei_status.mem) {
-		free_irq(dev->irq, dev);
-		return -ENOMEM;
-	}
-
-	pr_cont(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
-		model_name, dev->irq, dev->mem_start, dev->mem_end-1);
-
-	ei_status.reset_8390 = wd_reset_8390;
-	ei_status.block_input = wd_block_input;
-	ei_status.block_output = wd_block_output;
-	ei_status.get_8390_hdr = wd_get_8390_hdr;
-
-	dev->netdev_ops = &wd_netdev_ops;
-	NS8390_init(dev, 0);
-	ei_local->msg_enable = wd_msg_enable;
-
-#if 1
-	/* Enable interrupt generation on softconfig cards -- M.U */
-	/* .. but possibly potentially unsafe - Donald */
-	if (inb(ioaddr+14) & 0x20)
-		outb(inb(ioaddr+4)|0x80, ioaddr+4);
-#endif
-
-	err = register_netdev(dev);
-	if (err) {
-		free_irq(dev->irq, dev);
-		iounmap(ei_status.mem);
-	}
-	return err;
-}
-
-static int
-wd_open(struct net_device *dev)
-{
-  int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-
-  /* Map in the shared memory. Always set register 0 last to remain
-	 compatible with very old boards. */
-  ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
-  ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
-
-  if (ei_status.word16)
-	  outb(ei_status.reg5, ioaddr+WD_CMDREG5);
-  outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
-
-  return ei_open(dev);
-}
-
-static void
-wd_reset_8390(struct net_device *dev)
-{
-	int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	outb(WD_RESET, wd_cmd_port);
-	netif_dbg(ei_local, hw, dev, "resetting the WD80x3 t=%lu...\n",
-		  jiffies);
-	ei_status.txing = 0;
-
-	/* Set up the ASIC registers, just in case something changed them. */
-	outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
-	if (ei_status.word16)
-		outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
-
-	netif_dbg(ei_local, hw, dev, "reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void
-wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - WD_START_PG)<<8);
-
-	/* We'll always get a 4 byte header read followed by a packet read, so
-	   we enable 16 bit mode before the header, and disable after the body. */
-	if (ei_status.word16)
-		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-
-#ifdef __BIG_ENDIAN
-	/* Officially this is what we are doing, but the readl() is faster */
-	/* unfortunately it isn't endian aware of the struct               */
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = le16_to_cpu(hdr->count);
-#else
-	((unsigned int*)hdr)[0] = readl(hdr_start);
-#endif
-}
-
-/* Block input and output are easy on shared memory ethercards, and trivial
-   on the Western digital card where there is no choice of how to do it.
-   The only complications are that the ring buffer wraps, and need to map
-   switch between 8- and 16-bit modes. */
-
-static void
-wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	unsigned long offset = ring_offset - (WD_START_PG<<8);
-	void __iomem *xfer_start = ei_status.mem + offset;
-
-	if (offset + count > ei_status.priv) {
-		/* We must wrap the input move. */
-		int semi_count = ei_status.priv - offset;
-		memcpy_fromio(skb->data, xfer_start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
-	} else {
-		/* Packet is in one chunk -- we can copy + cksum. */
-		memcpy_fromio(skb->data, xfer_start, count);
-	}
-
-	/* Turn off 16 bit access so that reboot works.	 ISA brain-damage */
-	if (ei_status.word16)
-		outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-}
-
-static void
-wd_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	void __iomem *shmem = ei_status.mem + ((start_page - WD_START_PG)<<8);
-
-
-	if (ei_status.word16) {
-		/* Turn on and off 16 bit access so that reboot works. */
-		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-		memcpy_toio(shmem, buf, count);
-		outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-	} else
-		memcpy_toio(shmem, buf, count);
-}
-
-
-static int
-wd_close(struct net_device *dev)
-{
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n");
-	ei_close(dev);
-
-	/* Change from 16-bit to 8-bit shared memory so reboot works. */
-	if (ei_status.word16)
-		outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
-
-	/* And disable the shared memory. */
-	outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
-
-	return 0;
-}
-
-
-#ifdef MODULE
-#define MAX_WD_CARDS	4	/* Max number of wd cards per module */
-static struct net_device *dev_wd[MAX_WD_CARDS];
-static int io[MAX_WD_CARDS];
-static int irq[MAX_WD_CARDS];
-static int mem[MAX_WD_CARDS];
-static int mem_end[MAX_WD_CARDS];	/* for non std. mem size */
-
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param_hw_array(mem, int, iomem, NULL, 0);
-module_param_hw_array(mem_end, int, iomem, NULL, 0);
-module_param_named(msg_enable, wd_msg_enable, uint, 0444);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
-MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)");
-MODULE_PARM_DESC(mem_end, "memory end address(es)");
-MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
-MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-
-static int __init wd_init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_start = mem[this_dev];
-		dev->mem_end = mem_end[this_dev];
-		if (do_wd_probe(dev) == 0) {
-			dev_wd[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-module_init(wd_init_module);
-
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-static void __exit wd_cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
-		struct net_device *dev = dev_wd[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-module_exit(wd_cleanup_module);
-#endif /* MODULE */

-- 
2.53.0


^ permalink raw reply related

* [PATCH net v2 14/15] drivers: net: 8390: ultra: Remove this driver
From: Andrew Lunn @ 2026-04-22 18:01 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: Geert Uytterhoeven, Michael Fritscher, Byron Stanoszek,
	Daniel Palmer, linux-kernel, netdev, linux-doc, Andrew Lunn
In-Reply-To: <20260422-v7-0-0-net-next-driver-removal-v1-v2-0-08a5b59784d5@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

* Re: [PATCH net 0/4] Intel Wired LAN Driver Updates 2026-04-20 (ice)
From: Jacob Keller @ 2026-04-22 18:59 UTC (permalink / raw)
  To: Simon Horman
  Cc: Przemek Kitszel, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, netdev, Grzegorz Nitka,
	Aleksandr Loktionov, Petr Oros, Sunitha Mekala, Timothy Miskell
In-Reply-To: <20260422092304.GJ651125@horms.kernel.org>

On 4/22/2026 2:23 AM, Simon Horman wrote:
> On Mon, Apr 20, 2026 at 05:51:24PM -0700, Jacob Keller wrote:
>> Since this is a set of related fixes for just the ice driver, Jake provides
>> the following description for the series:
> 
> Thanks for the excellent cover letter and patch descriptions.
> 
> Reviewed-by: Simon Horman <horms@kernel.org>
> 
> For completeness:
> 
> * I have looked over the AI generated review of patch 2/4 by Sashiko.
>   You may wish to too. But I do not believe that feedback warrants
>   holding up this series. Actually, I am skeptical those issues
>   should be addressed at all.
> 

Interestingly, the version posted to Intel Wired LAN did not receive any
feedback from Sashiko, and the code remains unchanged. As helpful as the
bots are, it is definitely frustrating that they remain somewhat
inconsistent.

To answer some of the questions, Sashiko says:

>> @@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay)
>>   * The following functions operate on devices with the ETH 56G PHY.
>>   */
>>  
>> +/**
>> + * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization
>> + * @hw: pointer to HW struct
>> + *
>> + * Perform E825C-specific PTP hardware clock initialization steps.
>> + *
>> + * Return: 0 on success, or a negative error value on failure.
>> + */
>> +static int ice_ptp_init_phc_e825c(struct ice_hw *hw)
>> +{
>> +	int err;
>> +
>> +	/* Soft reset all ports, to ensure everything is at a clean state */
>> +	for (int port = 0; port < hw->ptp.num_lports; port++) {
>> +		err = ice_ptp_phy_soft_reset_eth56g(hw, port);
> Could this sequence disrupt active secondary PFs?
> This loop iterates over all ports and performs a soft reset without acquiring
> the global hardware semaphore.
> If the primary PF is rebound or undergoes initialization while
> secondary PFs are already bound and active, this lockless reset
> will wipe the timer configurations and outstanding Tx timestamps of those
> active secondary PFs.
> Does this need coordination with the software state of secondary PFs or use of
> ice_ptp_lock() before executing the reset?

This function resets the PTP timer, but it is called within either the
initialization or reset flows and only by the clock owner. After calling
the init function, the driver will reconfigure all ports, so I do not
think there is an issue.


It also says:

>> @@ -2179,6 +2204,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
>>  	return 0;
>>  }
>>  
>> +/**
>> + * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G
>> + * @hw: pointer to the HW structure
>> + * @port: PHY port number
>> + *
>> + * Trigger a soft reset of the ETH56G PHY by toggling the soft reset
>> + * bit in the PHY global register. The reset sequence consists of:
>> + *   1. Clearing the soft reset bit
>> + *   2. Asserting the soft reset bit
>> + *   3. Clearing the soft reset bit again
>> + *
>> + * Short delays are inserted between each step to allow the hardware
>> + * to settle. This provides a controlled way to reinitialize the PHY
>> + * without requiring a full device reset.
>> + *
>> + * Return: 0 on success, or a negative error code on failure when
>> + *         reading or writing the PHY register.
>> + */
>> +int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port)
>> +{
>> +	u32 global_val;
>> +	int err;
>> +
>> +	err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val);
>> +	if (err) {
>> +		ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n",
>> +			  port, err);
>> +		return err;
>> +	}
>> +
>> +	global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M;
>> +	ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n",
>> +		  port, global_val);
>> +	err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
>> +	if (err) {
>> +		ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
>> +			  port, err);
>> +		return err;
>> +	}
>> +
>> +	usleep_range(5000, 6000);
>> +
>> +	global_val |= PHY_REG_GLOBAL_SOFT_RESET_M;
> Will this write clobber hardware state changes?
> The code reads the register into global_val once at the beginning, but modifies
> and writes it back three times, separated by sleep windows.
> If hardware or firmware modifies any other bits in this register during the
> sleep windows, the subsequent writes using the cached global_val will silently
> overwrite those updates.
> Should the register be re-read into global_val before each modification?

I do not think we need to re-read the value between these writes.
Neither the hardware or firmware update these values. If other software
is accessing and modifying the value for this register, we have a
different issue. Again, the only caller for the phy soft reset function
is the clock owning PF, so I don't see how another thread could cause an
issue here.

> * I have also looked over the AI generated review based on Chris Mason's
>   review prompts which is available at https://netdev-ai.bots.linux.dev
>   (if only it had a name!). It flags an potentially incorrect Fixes tag in
>   patch 4/4. However, the cover letter for the patch explains the
>   choice of Fixes tag, effectively rebutting the analysis generated by AI
>   (I guess it didn't take the commit message sufficiently into account.)
> 

Thanks for the review!

^ permalink raw reply

* Re: [PATCH net] net: txgbe: fix firmware version check
From: Jacob Keller @ 2026-04-22 19:01 UTC (permalink / raw)
  To: Jiawen Wu, netdev
  Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, stable
In-Reply-To: <C787AA5C07598B13+20260422071837.372731-1-jiawenwu@trustnetic.com>

On 4/22/2026 12:18 AM, Jiawen Wu wrote:
> For the device SP, the firmware version is a 32-bit value where the
> lower 20 bits represent the base version number. And the customized
> firmware version populates the upper 12 bits with a specific
> identification number.
> 
> For other devices AML 25G and 40G, the upper 12 bits of the firmware
> version is always non-zero, and they have other naming conventions.
> 
> Only SP devices need to check this to tell if XPCS will work properly.
> So the judgement of MAC type is added here.
> 
> And the original logic compared the entire 32-bit value against 0x20010,
> which caused the outdated base firmwares bypass the version check
> without a warning. Apply a mask 0xfffff to isolate the lower 20 bits for
> an accurate base version comparison.
> 
> Fixes: ab928c24e6cd ("net: txgbe: add FW version warning")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> ---
>  drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
> index ec32a5f422f2..8b7c3753bb6a 100644
> --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
> +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
> @@ -864,7 +864,8 @@ static int txgbe_probe(struct pci_dev *pdev,
>  			 "0x%08x", etrack_id);
>  	}
>  
> -	if (etrack_id < 0x20010)
> +	if (wx->mac.type == wx_mac_sp &&
> +	    ((etrack_id & 0xfffff) < 0x20010))
>  		dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
>  

Minor nit/comment, and I don't have any objection to merging as-is.
This might be more readable with a FIELD_GET() and an associated mask. I
guess the mask is fairly obvious, so it doesn't really warrant a v2 of
the fix.

Either way:

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

Thanks,
Jake

>  	err = txgbe_test_hostif(wx);


^ permalink raw reply

* Re: [PATCH iwl-net] ice: fix infinite recursion in ice_cfg_tx_topo via ice_init_dev_hw
From: Petr Oros @ 2026-04-22 19:17 UTC (permalink / raw)
  To: Simon Horman
  Cc: netdev, Tony Nguyen, Przemek Kitszel, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Aleksandr Loktionov, Nikolay Aleksandrov, Daniel Zahka,
	Paul Greenwalt, Dave Ertman, Michal Swiatkowski, jacob.e.keller,
	intel-wired-lan, linux-kernel
In-Reply-To: <20260415163003.GP772670@horms.kernel.org>


On 4/15/26 18:30, Simon Horman wrote:
> On Mon, Apr 13, 2026 at 09:14:20PM +0200, Petr Oros wrote:
>> On certain E810 configurations where firmware supports Tx scheduler
>> topology switching (tx_sched_topo_comp_mode_en), ice_cfg_tx_topo()
>> may need to apply a new 5-layer or 9-layer topology from the DDP
>> package. If the AQ command to set the topology fails (e.g. due to
>> invalid DDP data or firmware limitations), the global configuration
>> lock must still be cleared via a CORER reset.
>>
>> Commit 86aae43f21cf ("ice: don't leave device non-functional if Tx
>> scheduler config fails") correctly fixed this by refactoring
>> ice_cfg_tx_topo() to always trigger CORER after acquiring the global
>> lock and re-initialize hardware via ice_init_hw() afterwards.
>>
>> However, commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end
>> of deinit paths") later moved ice_init_dev_hw() into ice_init_hw(),
>> breaking the reinit path introduced by 86aae43f21cf. This creates an
>> infinite recursive call chain:
>>
>>    ice_init_hw()
>>      ice_init_dev_hw()
>>        ice_cfg_tx_topo()         # topology change needed
>>          ice_deinit_hw()
>>          ice_init_hw()           # reinit after CORER
>>            ice_init_dev_hw()     # recurse
>>              ice_cfg_tx_topo()
>>                ...               # stack overflow
>>
>> Fix by moving ice_init_dev_hw() back out of ice_init_hw() and calling
>> it explicitly from ice_probe() and ice_devlink_reinit_up(). The third
>> caller, ice_cfg_tx_topo(), intentionally does not need ice_init_dev_hw()
>> during its reinit, it only needs the core HW reinitialization. This
>> breaks the recursion cleanly without adding flags or guards.
>>
>> The deinit ordering changes from commit 8a37f9e2ff40 ("ice: move
>> ice_deinit_dev() to the end of deinit paths") which fixed slow rmmod
>> are preserved, only the init-side placement of ice_init_dev_hw() is
>> reverted.
>>
>> Fixes: 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths")
>> Signed-off-by: Petr Oros <poros@redhat.com>
> Hi Petr,
>
> I don't intended to delay this patch.
> But could you follow-up by looking over the AI generated
> review of this patch on sashiko.dev?
>
> Thanks!
>
Hi Simon,

Thanks, the sashiko.dev concern is valid. ice_init_dev_hw() swallowing
-ENODEV from the torn-down hw is a latent UAF independent of the
recursion fix here. I will send a follow-up patch that propagates
-ENODEV to abort probe cleanly.

Regards,
Petr


^ permalink raw reply

* RE: [PATCH net v2 11/12] idpf: fix xdp crash in soft reset error path
From: Hay, Joshua A @ 2026-04-22 19:26 UTC (permalink / raw)
  To: Jakub Kicinski, Keller, Jacob E
  Cc: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	pabeni@redhat.com, netdev@vger.kernel.org, Tantilov, Emil S,
	stable@vger.kernel.org, Loktionov, Aleksandr, Holda, Patryk
In-Reply-To: <20260418190019.194263-2-kuba@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.
> 
> Jakub: I'll drop this patch and apply the rest.
> ---
> idpf: fix xdp crash in soft reset error path
> 
> This commit fixes a NULL pointer dereference in idpf_vport_open() when
> soft reset fails by restoring vport->xdp_prog to the old value. It also
> updates the restart check to use IDPF_VPORT_UP instead of netif_running().
> 
> Cc: stable@vger.kernel.org
> 
> > diff --git a/drivers/net/ethernet/intel/idpf/xdp.c
> b/drivers/net/ethernet/intel/idpf/xdp.c
> > --- a/drivers/net/ethernet/intel/idpf/xdp.c
> > +++ b/drivers/net/ethernet/intel/idpf/xdp.c
> > @@ -488,6 +488,7 @@ static int idpf_xdp_setup_prog(struct idpf_vport
> *vport,
> >  				   "Could not reopen the vport after XDP
> setup");
> >
> >  		cfg->user_config.xdp_prog = old;
> > +		vport->xdp_prog = old;
> 
> Does this also need to roll back vport->num_xdp_txq?
> 
> Because idpf_initiate_soft_reset() overwrites the vport struct with the new
> queue configuration before failing, vport->num_xdp_txq might remain > 0
> while vport->xdp_prog is restored to NULL.
> 
> When the interface is brought up, idpf_xdpsqs_get() evaluates
> idpf_xdp_enabled(vport) as false and returns early without allocating the
> NAPI timers (xdpsq->timer).
> 
> Could another interface redirect XDP frames via ndo_xdp_xmit, bypassing the
> check because vport->num_xdp_txq > 0, and cause a NULL pointer
> dereference
> in libeth_xdpsq_queue_timer() during idpf_xdp_tx_finalize()?

Yes, that is possible. num_xdp_txq needs to be rolled back as well.
Will send a V3 to IWL.

> 
> >  		old = prog;
> >  	}
> 
> Is this old = prog assignment leading to a double-put of the BPF program?
> 
> If idpf_initiate_soft_reset() fails, this error path drops a reference to
> the newly provided prog when it calls bpf_prog_put(old) right after this
> block.
> 
> Since the function returns an error code to the core network stack, won't
> dev_xdp_install() in net/core/dev.c also explicitly call bpf_prog_put(prog)
> assuming ownership of the error cleanup?
> 
> Could this underflow the reference count and cause a use-after-free?

Will fix in V3.

> 
> [ ... ]
> 
> > diff --git a/drivers/net/ethernet/intel/idpf/xsk.c
> b/drivers/net/ethernet/intel/idpf/xsk.c
> > --- a/drivers/net/ethernet/intel/idpf/xsk.c
> > +++ b/drivers/net/ethernet/intel/idpf/xsk.c
> > @@ -568,7 +569,8 @@ int idpf_xsk_pool_setup(struct idpf_vport *vport,
> struct netdev_bpf *bpf)
> >  		return -EINVAL;
> >  	}
> >
> > -	restart = idpf_xdp_enabled(vport) && netif_running(vport->netdev);
> > +	restart = idpf_xdp_enabled(vport) &&
> > +		  test_bit(IDPF_VPORT_UP, np->state);
> >  	if (!restart)
> >  		goto pool;
> 
> Does this function leave the queue pair permanently disabled if the pool
> setup fails?
> 
> If restart is true, the queue pair is disabled via:
>     idpf_qp_switch(vport, qid, false);
> 
> If the subsequent call to libeth_xsk_setup_pool() fails, the function
> returns early:
> 
>     ret = libeth_xsk_setup_pool(vport->netdev, qid, pool);
>     if (ret) {
>         ...
>         return ret;
>     }
> 
> Does this early return bypass the idpf_qp_switch(vport, qid, true) call
> expected later, causing a permanent partial loss of connectivity until the
> interface is manually restarted?

This seems valid but not necessarily related to the soft reset issue. 
Will fix in a separate patch.

Thanks!
Josh


^ permalink raw reply

* Re: [PATCH v1 1/2] vfio: add callback to get tph info for dma-buf
From: Alex Williamson @ 2026-04-22 19:27 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Zhiping Zhang, Stanislav Fomichev, Keith Busch, Leon Romanovsky,
	Bjorn Helgaas, linux-rdma, linux-pci, netdev, dri-devel,
	Yochai Cohen, Yishai Hadas, alex
In-Reply-To: <20260422162928.GL3611611@ziepe.ca>

On Wed, 22 Apr 2026 13:29:28 -0300
Jason Gunthorpe <jgg@ziepe.ca> wrote:

> On Wed, Apr 22, 2026 at 09:23:27AM -0600, Alex Williamson wrote:
> > In general though, I'm really hoping that someone interested in
> > enabling TPH as an interface through vfio actually decides to take
> > resource targeting and revocation seriously.  There's no validation of
> > the steering tag here relative to what the user has access to and no
> > mechanism to revoke those tags if access changes.  In fact, there's not
> > even a proposed mechanism allowing the user to derive valid steering
> > tags.  Does the user implicitly know the value and the kernel just
> > allows it because... yolo?   
> 
> This is the steering tag that remote devices will send *INTO* the VFIO
> device.
> 
> IMHO it is entirely appropriate that the driver controlling the device
> decide what tags are sent into it and when, so that's the VFIO
> userspace.
> 
> There is no concept of access here since the entire device is captured
> by VFIO.
> 
> If the VFIO device catastrophically malfunctions when receiving
> certain steering tags then it is incompatible with VFIO and we should
> at least block this new API..
> 
> The only requirement is that the device limit the TPH to only the
> function that is perceiving them. If a device is really broken and
> doesn't meet that then it should be blocked off and it is probably not
> safe to be used with VMs at all.

Ok, if the vfio user is only suggesting steering tags for another
driver to use when accessing their own device through the dma-buf, and
the lifecycle is bound to that dma-buf, maybe I'm overreacting on the
security aspect.

I don't know how to qualify the statement in the last paragraph about
"[t]he only requirement is that the device limit the TPH to only the
function that is perceiving them", though.  Is that implicit in being
associated to the dma-buf for the user owned device, or is it a
property of the suggested steering tags, that we're not validating?

Steering tags can induce caching abuse, as interpreted in the
interconnect fabric, but maybe we've already conceded that as
fundamental aspect of TPH in general.

So why does vfio need to be involved in any of the sequence proposed
here?  It seems like it would be a much cleaner design, avoiding
overloading the existing vfio feature and questionable array semantics,
if there were a set-tph ioctl on the resulting dma-buf instead of
making some vfio specific interface bundling creation with tph hints.
Thanks,

Alex

^ permalink raw reply

* Re: [PATCH net v8 03/15] net: cache snapshot entries for ndo_set_rx_mode_async
From: Stanislav Fomichev @ 2026-04-22 19:48 UTC (permalink / raw)
  To: Paolo Abeni; +Cc: netdev, davem, edumazet, kuba
In-Reply-To: <27946411-c226-426c-9307-d2cf76b88b1f@redhat.com>

On 04/22, Paolo Abeni wrote:
> On 4/22/26 12:19 AM, Stanislav Fomichev wrote:
> > On 04/21, Paolo Abeni wrote:
> >> On 4/21/26 11:52 AM, Paolo Abeni wrote:
> >>> On 4/16/26 8:57 PM, Stanislav Fomichev wrote:
> >>>> Add a per-device netdev_hw_addr_list cache (rx_mode_addr_cache) that
> >>>> allows __hw_addr_list_snapshot() and __hw_addr_list_reconcile() to
> >>>> reuse previously allocated entries instead of hitting GFP_ATOMIC on
> >>>> every snapshot cycle.
> >>>>
> >>>> snapshot pops entries from the cache when available, falling back to
> >>>> __hw_addr_create(). reconcile splices both snapshot lists back into
> >>>> the cache via __hw_addr_splice(). The cache is flushed in
> >>>> free_netdev().
> >>>>
> >>>> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
> >>>> (cherry picked from commit ba3ab1832a511f660fdc6231245b14bf610c05bd)
> >>>
> >>> Are you backporting from 7.2 via time machine??? :-P
> >>>
> >>>> @@ -611,8 +633,8 @@ void __hw_addr_list_reconcile(struct netdev_hw_addr_list *real_list,
> >>>>  		}
> >>>>  	}
> >>>>  
> >>>> -	__hw_addr_flush(work);
> >>>> -	__hw_addr_flush(ref);
> >>>> +	__hw_addr_splice(cache, work);
> >>>> +	__hw_addr_splice(cache, ref);
> >>>
> >>> I think here sashiko has a point, with the cache size being unbounded. I
> >>> guess syzkaller or the like will find a way to make it grow too much.
> >>>
> >>> What about hard-limit it to some reasonable value?!?
> >>
> >> There are a few more remarks from sashiko at the driver level, but
> >> AFAICS are all pre-existing issues.
> >>
> >> I think even the above one it's better handled as a follow-up, so I'm
> >> applying the series as-is (I'll just drop the cherry-pick statement above).
> > 
> > I have a follow-up series to add retries here, but not sure it's the
> > right direction. I can send it once net-next opens just to opinions.
> 
> I'm not sure how you are going to use retries with cache access?!?
> Likely some code could clarify.
> 
> I was wondering about a dumb limit for such cache, possibly netns-wide,
> possibly with a paired sysctl.

Ah, you're more concerned about the cache growth. I'm more worried about
the failed allocations and failed sync :-/ Let me look into cache grown,
should be relatively easy to have some test that keeps adding mc
addresses..

^ permalink raw reply

* Re: [PATCH v3 10/15] drm/msm: Switch to generic PAS TZ APIs
From: Dmitry Baryshkov @ 2026-04-22 20:04 UTC (permalink / raw)
  To: Sumit Garg
  Cc: lumag, robin.clark, linux-arm-msm, devicetree, dri-devel,
	freedreno, linux-media, netdev, linux-wireless, ath12k,
	linux-remoteproc, andersson, konradybcio, robh, krzk+dt, conor+dt,
	sean, akhilpo, abhinav.kumar, jesszhan0024, marijn.suijten,
	airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
	elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
	mathieu.poirier, trilokkumar.soni, mukesh.ojha, pavan.kondeti,
	jorge.ramirez, tonyh, vignesh.viswanathan, srinivas.kandagatla,
	amirreza.zarrabi, jens.wiklander, op-tee, apurupa, skare,
	harshal.dev, linux-kernel, Sumit Garg
In-Reply-To: <aeduRrAMOAW4f5TU@sumit-xelite>

On Tue, Apr 21, 2026 at 06:02:06PM +0530, Sumit Garg wrote:
> Hey Rob, Dmitry,
> 
> On Fri, Mar 27, 2026 at 06:40:38PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > 
> > Switch drm/msm client drivers over to generic PAS TZ APIs. Generic PAS
> > TZ service allows to support multiple TZ implementation backends like QTEE
> > based SCM PAS service, OP-TEE based PAS service and any further future TZ
> > backend service.
> > 
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> >  drivers/gpu/drm/msm/Kconfig             |  1 +
> >  drivers/gpu/drm/msm/adreno/a5xx_gpu.c   |  4 ++--
> >  drivers/gpu/drm/msm/adreno/adreno_gpu.c | 11 ++++++-----
> >  3 files changed, 9 insertions(+), 7 deletions(-)
> > 
> 
> Can I get an ack from you on this change? I expect this complete
> patch-set to land via Qcom SoC tree.
> 

Acked-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH net v3 8/8] xsk: don't support AF_XDP on 32-bit architectures
From: David Laight @ 2026-04-22 20:27 UTC (permalink / raw)
  To: Jason Xing
  Cc: davem, edumazet, kuba, pabeni, bjorn, magnus.karlsson,
	maciej.fijalkowski, jonathan.lemon, sdf, ast, daniel, hawk,
	john.fastabend, bpf, netdev, Jason Xing
In-Reply-To: <20260422033650.68457-9-kerneljasonxing@gmail.com>

On Wed, 22 Apr 2026 11:36:50 +0800
Jason Xing <kerneljasonxing@gmail.com> wrote:

> From: Jason Xing <kernelxing@tencent.com>
> 
> In copy mode TX, xsk_skb_destructor_set_addr() stores the 64-bit
> descriptor address into skb_shinfo(skb)->destructor_arg (void *) via a
> uintptr_t cast:
> 
>     skb_shinfo(skb)->destructor_arg = (void *)((uintptr_t)addr | 0x1UL);
> 
> On 32-bit architectures uintptr_t is 32 bits, so the upper 32 bits of
> the descriptor address are silently dropped. In XDP_ZEROCOPY unaligned
> mode the chunk offset is encoded in bits 48-63 of the descriptor
> address (XSK_UNALIGNED_BUF_OFFSET_SHIFT = 48), meaning the offset is
> lost entirely. The completion queue then returns a truncated address to
> userspace, making buffer recycling impossible.

I had a look at how this is used.

I suspect that XSK_UNALIGNED_BUF_OFFSET_SHIFT can just be made smaller.
The 'addr' isn't really a normal address of any kind, it is a really
and offset into an array made up of pages of memory.
The actual address (kernel virtual of dma) is generated by:
	ptr->array[addr >> PAGE_SHIFT] + addr & ~PAGE_MASK
(after removing the unaligned chunk offset from 'addr').

It is actually quite likely that there are enough free high bits
even in 32bit mode.

	David

> 
> Since we hear no one is using AF_XDP on 32-bit arch, we decided to
> strictly stop supporting it at compile time.
> 
> Closes: https://lore.kernel.org/all/20260419045824.D9E5EC2BCAF@smtp.kernel.org/
> Fixes: 0ebc27a4c67d ("xsk: avoid data corruption on cq descriptor number")
> Suggested-by: Stanislav Fomichev <sdf@fomichev.me>
> Signed-off-by: Jason Xing <kernelxing@tencent.com>
> ---
>  net/xdp/Kconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/net/xdp/Kconfig b/net/xdp/Kconfig
> index 71af2febe72a..819aa5795f50 100644
> --- a/net/xdp/Kconfig
> +++ b/net/xdp/Kconfig
> @@ -1,7 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  config XDP_SOCKETS
>  	bool "XDP sockets"
> -	depends on BPF_SYSCALL
> +	depends on BPF_SYSCALL && 64BIT
>  	default n
>  	help
>  	  XDP sockets allows a channel between XDP programs and


^ permalink raw reply

* Re: [PATCH bpf-next v4 0/4] bpf: Reject TCP_NODELAY in TCP header option
From: patchwork-bot+netdevbpf @ 2026-04-22 20:36 UTC (permalink / raw)
  To: KaFai Wan
  Cc: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, memxor,
	song, yonghong.song, jolsa, sdf, davem, edumazet, kuba, pabeni,
	horms, dsahern, shuah, ihor.solodrai, jiayuan.chen, hoyeon.lee,
	ameryhung, bpf, linux-kernel, netdev, linux-kselftest
In-Reply-To: <20260421155804.135786-1-kafai.wan@linux.dev>

Hello:

This series was applied to bpf/bpf.git (master)
by Martin KaFai Lau <martin.lau@kernel.org>:

On Tue, 21 Apr 2026 23:58:00 +0800 you wrote:
> This small patchset is about avoid infinite recursion in TCP header option callbacks
> and bpf-tcp-cc callbacks via TCP_NODELAY setsockopt.
> 
> v4:
>  - Fix the test case for TCP header option callbacks (Martin and Jiayuan)
>  - Reject TCP_NODELAY in bpf-tcp-cc callbacks (AI and Martin)
>  - Add a test case for bpf-tcp-cc
> 
> [...]

Here is the summary with links:
  - [bpf-next,v4,1/4] bpf: Reject TCP_NODELAY in TCP header option callbacks
    https://git.kernel.org/bpf/bpf/c/846c76ecc029
  - [bpf-next,v4,2/4] bpf: Reject TCP_NODELAY in bpf-tcp-cc
    https://git.kernel.org/bpf/bpf/c/54377fcab51f
  - [bpf-next,v4,3/4] selftests/bpf: Test TCP_NODELAY in TCP hdr opt callbacks
    https://git.kernel.org/bpf/bpf/c/52b6b5334924
  - [bpf-next,v4,4/4] selftests/bpf: Verify bpf-tcp-cc rejects TCP_NODELAY
    https://git.kernel.org/bpf/bpf/c/2c7e33f1fc2e

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



^ permalink raw reply

* Re: [PATCH bpf v5 1/2] bpf: guard sock_ops rtt_min against non-locked tcp_sock
From: Martin KaFai Lau @ 2026-04-22 21:03 UTC (permalink / raw)
  To: Werner Kasselman
  Cc: bpf@vger.kernel.org, netdev@vger.kernel.org,
	stable@vger.kernel.org, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, John Fastabend,
	Stanislav Fomichev, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Lawrence Brakmo, open list
In-Reply-To: <20260420230030.2802408-2-werner@verivus.com>

On Mon, Apr 20, 2026 at 11:00:35PM +0000, Werner Kasselman wrote:
> sock_ops_convert_ctx_access() reads rtt_min without the is_locked_tcp_sock guard used for every other tcp_sock field. On request_sock-backed sock_ops callbacks, sk points at a tcp_request_sock and the converted load reads past the end of the allocation.
> 
> Extract the guarded tcp_sock field load sequence into SOCK_OPS_LOAD_TCP_SOCK_FIELD() and use it for the rtt_min access after computing the sub-field offset with offsetof(struct minmax_sample, v). Reusing the shared helper keeps rtt_min aligned with the other guarded tcp_sock field loads and preserves the dst_reg == src_reg failure path that zeros the destination register when the guard fails.

I think some formatting instruction was not given to the AI this time and
no human bothered to look at the formatting of the commit message
before posting?

^ permalink raw reply

* Re: [PATCH bpf v5 2/2] selftests/bpf: cover same-reg sock_ops rtt_min request_sock access
From: Martin KaFai Lau @ 2026-04-22 21:11 UTC (permalink / raw)
  To: Werner Kasselman
  Cc: bpf@vger.kernel.org, netdev@vger.kernel.org, Andrii Nakryiko,
	Eduard Zingerman, Alexei Starovoitov, Daniel Borkmann,
	Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa,
	Shuah Khan, open list:KERNEL SELFTEST FRAMEWORK, open list
In-Reply-To: <20260420230030.2802408-3-werner@verivus.com>

On Mon, Apr 20, 2026 at 11:00:37PM +0000, Werner Kasselman wrote:
> Add a tcpbpf sock_ops selftest that forces a same-register ctx->rtt_min read on request_sock-backed callbacks and verifies the observed value is zero.
> 
> This covers the dst_reg == src_reg path that the previous ctx_rewrite-only test did not exercise.

Same formatting issue.

> 
> Signed-off-by: Werner Kasselman <werner@verivus.com>
> ---
>  .../testing/selftests/bpf/prog_tests/tcpbpf_user.c |  4 ++++
>  .../testing/selftests/bpf/progs/test_tcpbpf_kern.c | 14 ++++++++++++++
>  tools/testing/selftests/bpf/test_tcpbpf.h          |  2 ++
>  3 files changed, 20 insertions(+)
> 
> diff --git a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c
> index 7e8fe1bad03f..1b08e49327d0 100644
> --- a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c
> +++ b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c
> @@ -42,6 +42,10 @@ static void verify_result(struct tcpbpf_globals *result)
>  	/* check getsockopt for window_clamp */
>  	ASSERT_EQ(result->window_clamp_client, 9216, "window_clamp_client");
>  	ASSERT_EQ(result->window_clamp_server, 9216, "window_clamp_server");
> +
> +	/* check same-reg rtt_min read on request_sock-backed callbacks */
> +	ASSERT_NEQ(result->rtt_min_req_seen, 0, "rtt_min_req_seen");
> +	ASSERT_EQ(result->rtt_min_req_nonzero, 0, "rtt_min_req_nonzero");
>  }
>  
>  static void run_test(struct tcpbpf_globals *result)
> diff --git a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c
> index 6935f32eeb8f..a488b282b5dd 100644
> --- a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c
> +++ b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c
> @@ -33,6 +33,7 @@ int bpf_testcb(struct bpf_sock_ops *skops)
>  {
>  	char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)];
>  	struct bpf_sock_ops *reuse = skops;
> +	long rtt_min = (long)skops;

It is overly smart to test the same dst_reg == src_reg.
A new test has just been added to test it in a cleaner way.

pw-bot: cr

You haven't spent time to take a look of the patches first.
Please don't post again. I will stop reviewing your patches from now.

^ permalink raw reply

* Re: [PATCH bpf-next v3 2/9] bpf: Assign reg->id when getting referenced kptr from ctx
From: Eduard Zingerman @ 2026-04-22 21:46 UTC (permalink / raw)
  To: Amery Hung, bpf
  Cc: netdev, alexei.starovoitov, andrii, daniel, memxor, martin.lau,
	mykyta.yatsenko5, kernel-team
In-Reply-To: <20260421221016.2967924-3-ameryhung@gmail.com>

On Tue, 2026-04-21 at 15:10 -0700, Amery Hung wrote:
> Assign reg->id when getting referenced kptr from read program context
> to be consistent with R0 of KF_ACQUIRE kfunc. skb dynptr will track the
> referenced skb in qdisc programs using a new field reg->parent_id in
> a later patch.
> 
> Signed-off-by: Amery Hung <ameryhung@gmail.com>
> ---
>  kernel/bpf/verifier.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 41e4ea41c72e..93003a2a96b0 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -6448,8 +6448,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
>  			} else {
>  				mark_reg_known_zero(env, regs,
>  						    value_regno);
> -				if (type_may_be_null(info.reg_type))
> -					regs[value_regno].id = ++env->id_gen;
>  				/* A load of ctx field could have different
>  				 * actual load size with the one encoded in the
>  				 * insn. When the dst is PTR, it is for sure not
> @@ -6459,8 +6457,11 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
>  				if (base_type(info.reg_type) == PTR_TO_BTF_ID) {
>  					regs[value_regno].btf = info.btf;
>  					regs[value_regno].btf_id = info.btf_id;
> +					regs[value_regno].id = info.ref_obj_id;
>  					regs[value_regno].ref_obj_id = info.ref_obj_id;
>  				}

Hi Amery,

Could you please help me double-check my understanding of this change?

It adds a new behavior, if struct_ops method parameter is annotated
with __ref, then if a field is read from such struct_ops context
the destination register would now have it's .id == ref_obj_id
allocated for the parameter at the beginning of do_check().
E.g. for `rB = *(T *)(rA + off)`, if `rA` is a pointer to struct_ops
context and parameter corresponding to `off` has `__ref` annotation
the `rB.id` will be assigned, contrary to old behavior, when it remained 0.

This change in behavior, however, becomes visible only after the
changes to release_reference() later in the series.
There the `rB.id` is used to initiate `mark_reg_invalid(env, reg)` for
the `rB`.

Are the above observations correct?

> +				if (type_may_be_null(info.reg_type) && !regs[value_regno].id)
> +					regs[value_regno].id = ++env->id_gen;
>  			}
>  			regs[value_regno].type = info.reg_type;
>  		}

^ permalink raw reply

* Re: [PATCH bpf-next v2 1/2] selftests/bpf: make btf_dump use xdp_dummy rather than xdping_kern
From: Paul Chaignon @ 2026-04-22 21:51 UTC (permalink / raw)
  To: Alexis Lothoré (eBPF Foundation)
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, David S. Miller,
	Jakub Kicinski, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, ebpf, Bastien Curutchet, Thomas Petazzoni,
	bpf, linux-kselftest, linux-kernel, netdev
In-Reply-To: <20260422-xdping-v2-1-c0f8ccedcf91@bootlin.com>

On Wed, Apr 22, 2026 at 06:20:24PM +0200, Alexis Lothoré (eBPF Foundation) wrote:
> In order to prepare xdping tool removal from the BPF selftests
> directory, make the btf_dump test use another BPF program for the btf
> datasec dump test. Use xdp_dummy.bpf.o, as it is already used by various
> other tests.
> 
> Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>

Acked-by: Paul Chaignon <paul.chaignon@gmail.com>

> ---
>  tools/testing/selftests/bpf/prog_tests/btf_dump.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dump.c b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
> index f1642794f70e..9f1b50e07a29 100644
> --- a/tools/testing/selftests/bpf/prog_tests/btf_dump.c
> +++ b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
> @@ -1027,8 +1027,8 @@ static void test_btf_dump_datasec_data(char *str)
>  	char license[4] = "GPL";
>  	struct btf_dump *d;
>  
> -	btf = btf__parse("xdping_kern.bpf.o", NULL);
> -	if (!ASSERT_OK_PTR(btf, "xdping_kern.bpf.o BTF not found"))
> +	btf = btf__parse("xdp_dummy.bpf.o", NULL);
> +	if (!ASSERT_OK_PTR(btf, "xdp_dummy.bpf.o BTF not found"))
>  		return;
>  
>  	d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
> 
> -- 
> 2.53.0
> 
> 

^ permalink raw reply

* Re: [PATCH bpf-next v2 2/2] selftests/bpf: drop xdping tool
From: Paul Chaignon @ 2026-04-22 21:53 UTC (permalink / raw)
  To: Alexis Lothoré (eBPF Foundation)
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, David S. Miller,
	Jakub Kicinski, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, ebpf, Bastien Curutchet, Thomas Petazzoni,
	bpf, linux-kselftest, linux-kernel, netdev, Alan Maguire
In-Reply-To: <20260422-xdping-v2-2-c0f8ccedcf91@bootlin.com>

On Wed, Apr 22, 2026 at 06:20:25PM +0200, Alexis Lothoré (eBPF Foundation) wrote:
> As part of a larger cleanup effort in the bpf selftests directory,
> tests and scripts are either being converted to the test_progs framework
> (so they are executed automatically in bpf CI), or removed if not
> relevant for such integration.
> 
> The test_xdping.sh script (with the associated xdping.c) acts as a RTT
> measurement tool, by attaching two small xdp programs to two interfaces.
> Converting this test to test_progs may not make much sense:
> - RTT measurement does not really fit in the scope of a functional test,
>   this is rather about measuring some performance level.
> - there are other existing tests in test_progs that actively validate
>   XDP features like program attachment, return value processing, packet
>   modification, etc
> 
> Drop test_xdping.sh, the corresponding xdping.c userspace part, the
> xdping_kern.c program, and the shared header, xdping.h
> 
> Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
> Reviewed-by: Alan Maguire <alan.maguire@oracle.com>

Acked-by: Paul Chaignon <paul.chaignon@gmail.com>

> ---
>  tools/testing/selftests/bpf/.gitignore          |   1 -
>  tools/testing/selftests/bpf/Makefile            |   3 -
>  tools/testing/selftests/bpf/progs/xdping_kern.c | 183 -----------------
>  tools/testing/selftests/bpf/test_xdping.sh      | 103 ----------
>  tools/testing/selftests/bpf/xdping.c            | 254 ------------------------
>  tools/testing/selftests/bpf/xdping.h            |  13 --
>  6 files changed, 557 deletions(-)
> 

[...]

^ permalink raw reply

* Re: [PATCH net-next v2 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning
From: Vadim Fedorenko @ 2026-04-22 21:54 UTC (permalink / raw)
  To: Junyang Han, netdev
  Cc: davem, andrew+netdev, edumazet, kuba, pabeni, ran.ming,
	han.chengfei, zhang.yanze
In-Reply-To: <20260422144901.2403456-4-han.junyang@zte.com.cn>

On 22.04.2026 15:49, Junyang Han wrote:
> Implement PCI configuration space access, BAR mapping, capability
> scanning (common/notify/device), and hardware queue register
> definitions for DingHai PF device.
> 
> Signed-off-by: Junyang Han <han.junyang@zte.com.cn>

[...]

> +
> +void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int32_t off,
> +				     size_t minlen, uint32_t align,
> +				     uint32_t start, uint32_t size,
> +				     size_t *len, resource_size_t *pa,
> +				     uint32_t *bar_off)
> +{
> +	struct pci_dev *pdev = dh_dev->pdev;
> +	uint8_t bar = 0;
> +	uint32_t offset = 0;
> +	uint32_t length = 0;
> +	void __iomem *p = NULL;

Even though the changelog says that variable declaration ordering is fixed, this
patch (as some others in the series) still has the problem.

Also, please avoid using user-space fixed size types, kernel space uses short
type names, like u32/u8 etc.

Try to avoid meaningless initialization as well.

These comments apply to the whole series, not only to this single patch

> +
> +	pci_read_config_byte(pdev, off + offsetof(struct zxdh_pf_pci_cap, bar), &bar);
> +	pci_read_config_dword(pdev, off + offsetof(struct zxdh_pf_pci_cap, offset), &offset);
> +	pci_read_config_dword(pdev, off + offsetof(struct zxdh_pf_pci_cap, length), &length);
> +
> +	if (bar_off)
> +		*bar_off = offset;
> +

^ permalink raw reply

* [PATCH 5.10.y] rxrpc: Fix recvmsg() unconditional requeue
From: Jay Wang @ 2026-04-22 22:24 UTC (permalink / raw)
  To: stable
  Cc: dhowells, marc.dionne, davem, edumazet, kuba, pabeni, netdev,
	linux-afs, jay.wang.upstream, Faith, Pumpkin Chang

From: David Howells <dhowells@redhat.com>

[ Upstream commit 2c28769a51deb6022d7fbd499987e237a01dd63a ]

If rxrpc_recvmsg() fails because MSG_DONTWAIT was specified but the call
at the front of the recvmsg queue already has its mutex locked, it
requeues the call - whether or not the call is already queued.  The call
may be on the queue because MSG_PEEK was also passed and so the call was
not dequeued or because the I/O thread requeued it.

The unconditional requeue may then corrupt the recvmsg queue, leading to
things like UAFs or refcount underruns.

Fix this by only requeuing the call if it isn't already on the queue -
and moving it to the front if it is already queued.  If we don't queue
it, we have to put the ref we obtained by dequeuing it.

Also, MSG_PEEK doesn't dequeue the call so shouldn't call
rxrpc_notify_socket() for the call if we didn't use up all the data on
the queue, so fix that also.

Fixes: 540b1c48c37a ("rxrpc: Fix deadlock between call creation and sendmsg/recvmsg")
Reported-by: Faith <faith@zellic.io>
Reported-by: Pumpkin Chang <pumpkin@devco.re>
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Cc: stable@vger.kernel.org
[Adapted to 5.10: use write_lock_bh/write_unlock_bh, trace_rxrpc_call
 directly for see-call tracing, 5.10 trace enum naming convention, and
 added entries to both plain enum and EM() macro list.]
Signed-off-by: Jay Wang <wanjay@amazon.com>
---
 include/trace/events/rxrpc.h | 8 ++++++++
 net/rxrpc/recvmsg.c          | 20 ++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -93,9 +93,13 @@ enum rxrpc_call_trace {
 	rxrpc_call_put_notimer,
 	rxrpc_call_put_timer,
 	rxrpc_call_put_userid,
+	rxrpc_call_put_recvmsg_peek_nowait,
 	rxrpc_call_queued,
 	rxrpc_call_queued_ref,
 	rxrpc_call_release,
+	rxrpc_call_see_recvmsg_requeue,
+	rxrpc_call_see_recvmsg_requeue_first,
+	rxrpc_call_see_recvmsg_requeue_move,
 	rxrpc_call_seen,
 };
 
@@ -291,9 +295,13 @@ enum rxrpc_tx_point {
 	EM(rxrpc_call_put_notimer,		"PnT") \
 	EM(rxrpc_call_put_timer,		"PTM") \
 	EM(rxrpc_call_put_userid,		"Pus") \
+	EM(rxrpc_call_put_recvmsg_peek_nowait,	"PpN") \
 	EM(rxrpc_call_queued,			"QUE") \
 	EM(rxrpc_call_queued_ref,		"QUR") \
 	EM(rxrpc_call_release,			"RLS") \
+	EM(rxrpc_call_see_recvmsg_requeue,	"SrQ") \
+	EM(rxrpc_call_see_recvmsg_requeue_first,"SrF") \
+	EM(rxrpc_call_see_recvmsg_requeue_move,	"SrM") \
 	E_(rxrpc_call_seen,			"SEE")
 
 #define rxrpc_transmit_traces \
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -607,7 +607,8 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
 		if (after(call->rx_top, call->rx_hard_ack) &&
 		    call->rxtx_buffer[(call->rx_hard_ack + 1) & RXRPC_RXTX_BUFF_MASK])
-			rxrpc_notify_socket(call);
+			if (!(flags & MSG_PEEK))
+				rxrpc_notify_socket(call);
 		break;
 	default:
 		ret = 0;
@@ -642,11 +643,24 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 error_requeue_call:
 	if (!(flags & MSG_PEEK)) {
 		write_lock_bh(&rx->recvmsg_lock);
-		list_add(&call->recvmsg_link, &rx->recvmsg_q);
-		write_unlock_bh(&rx->recvmsg_lock);
+		if (list_empty(&call->recvmsg_link)) {
+			list_add(&call->recvmsg_link, &rx->recvmsg_q);
+			trace_rxrpc_call(call->debug_id,
+					 rxrpc_call_see_recvmsg_requeue,
+					 refcount_read(&call->ref),
+					 __builtin_return_address(0), NULL);
+			write_unlock_bh(&rx->recvmsg_lock);
+		} else if (list_is_first(&call->recvmsg_link, &rx->recvmsg_q)) {
+			write_unlock_bh(&rx->recvmsg_lock);
+			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_first);
+		} else {
+			list_move(&call->recvmsg_link, &rx->recvmsg_q);
+			write_unlock_bh(&rx->recvmsg_lock);
+			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_move);
+		}
 		trace_rxrpc_recvmsg(call, rxrpc_recvmsg_requeue, 0, 0, 0, 0);
 	} else {
-		rxrpc_put_call(call, rxrpc_call_put);
+		rxrpc_put_call(call, rxrpc_call_put_recvmsg_peek_nowait);
 	}
 error_no_call:
 	release_sock(&rx->sk);
-- 
2.43.0


^ permalink raw reply

* [PATCH 6.1.y] rxrpc: Fix recvmsg() unconditional requeue
From: Jay Wang @ 2026-04-22 22:24 UTC (permalink / raw)
  To: stable
  Cc: dhowells, marc.dionne, davem, edumazet, kuba, pabeni, netdev,
	linux-afs, jay.wang.upstream, Faith, Pumpkin Chang

From: David Howells <dhowells@redhat.com>

[ Upstream commit 2c28769a51deb6022d7fbd499987e237a01dd63a ]

If rxrpc_recvmsg() fails because MSG_DONTWAIT was specified but the call
at the front of the recvmsg queue already has its mutex locked, it
requeues the call - whether or not the call is already queued.  The call
may be on the queue because MSG_PEEK was also passed and so the call was
not dequeued or because the I/O thread requeued it.

The unconditional requeue may then corrupt the recvmsg queue, leading to
things like UAFs or refcount underruns.

Fix this by only requeuing the call if it isn't already on the queue -
and moving it to the front if it is already queued.  If we don't queue
it, we have to put the ref we obtained by dequeuing it.

Also, MSG_PEEK doesn't dequeue the call so shouldn't call
rxrpc_notify_socket() for the call if we didn't use up all the data on
the queue, so fix that also.

Fixes: 540b1c48c37a ("rxrpc: Fix deadlock between call creation and sendmsg/recvmsg")
Reported-by: Faith <faith@zellic.io>
Reported-by: Pumpkin Chang <pumpkin@devco.re>
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Cc: stable@vger.kernel.org
[Adapted to 6.1: use write_lock_bh/write_unlock_bh, trace_rxrpc_call
 directly for see-call tracing, and 6.1 trace enum naming convention.]
Signed-off-by: Jay Wang <wanjay@amazon.com>
---
 include/trace/events/rxrpc.h |  4 ++++
 net/rxrpc/recvmsg.c          | 20 ++++++++++++++++----
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -82,9 +82,13 @@
 	EM(rxrpc_call_put_notimer,		"PnT") \
 	EM(rxrpc_call_put_timer,		"PTM") \
 	EM(rxrpc_call_put_userid,		"Pus") \
+	EM(rxrpc_call_put_recvmsg_peek_nowait,	"PpN") \
 	EM(rxrpc_call_queued,			"QUE") \
 	EM(rxrpc_call_queued_ref,		"QUR") \
 	EM(rxrpc_call_release,			"RLS") \
+	EM(rxrpc_call_see_recvmsg_requeue,	"SrQ") \
+	EM(rxrpc_call_see_recvmsg_requeue_first,"SrF") \
+	EM(rxrpc_call_see_recvmsg_requeue_move,	"SrM") \
 	E_(rxrpc_call_seen,			"SEE")
 
 #define rxrpc_transmit_traces \
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -607,7 +607,8 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
 		if (after(call->rx_top, call->rx_hard_ack) &&
 		    call->rxtx_buffer[(call->rx_hard_ack + 1) & RXRPC_RXTX_BUFF_MASK])
-			rxrpc_notify_socket(call);
+			if (!(flags & MSG_PEEK))
+				rxrpc_notify_socket(call);
 		break;
 	default:
 		ret = 0;
@@ -642,11 +643,24 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 error_requeue_call:
 	if (!(flags & MSG_PEEK)) {
 		write_lock_bh(&rx->recvmsg_lock);
-		list_add(&call->recvmsg_link, &rx->recvmsg_q);
-		write_unlock_bh(&rx->recvmsg_lock);
+		if (list_empty(&call->recvmsg_link)) {
+			list_add(&call->recvmsg_link, &rx->recvmsg_q);
+			trace_rxrpc_call(call->debug_id,
+					 rxrpc_call_see_recvmsg_requeue,
+					 refcount_read(&call->ref),
+					 __builtin_return_address(0), NULL);
+			write_unlock_bh(&rx->recvmsg_lock);
+		} else if (list_is_first(&call->recvmsg_link, &rx->recvmsg_q)) {
+			write_unlock_bh(&rx->recvmsg_lock);
+			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_first);
+		} else {
+			list_move(&call->recvmsg_link, &rx->recvmsg_q);
+			write_unlock_bh(&rx->recvmsg_lock);
+			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_move);
+		}
 		trace_rxrpc_recvmsg(call, rxrpc_recvmsg_requeue, 0, 0, 0, 0);
 	} else {
-		rxrpc_put_call(call, rxrpc_call_put);
+		rxrpc_put_call(call, rxrpc_call_put_recvmsg_peek_nowait);
 	}
 error_no_call:
 	release_sock(&rx->sk);
-- 
2.43.0


^ permalink raw reply

* [PATCH 5.15.y] rxrpc: Fix recvmsg() unconditional requeue
From: Jay Wang @ 2026-04-22 22:24 UTC (permalink / raw)
  To: stable
  Cc: dhowells, marc.dionne, davem, edumazet, kuba, pabeni, netdev,
	linux-afs, jay.wang.upstream, Faith, Pumpkin Chang

From: David Howells <dhowells@redhat.com>

[ Upstream commit 2c28769a51deb6022d7fbd499987e237a01dd63a ]

If rxrpc_recvmsg() fails because MSG_DONTWAIT was specified but the call
at the front of the recvmsg queue already has its mutex locked, it
requeues the call - whether or not the call is already queued.  The call
may be on the queue because MSG_PEEK was also passed and so the call was
not dequeued or because the I/O thread requeued it.

The unconditional requeue may then corrupt the recvmsg queue, leading to
things like UAFs or refcount underruns.

Fix this by only requeuing the call if it isn't already on the queue -
and moving it to the front if it is already queued.  If we don't queue
it, we have to put the ref we obtained by dequeuing it.

Also, MSG_PEEK doesn't dequeue the call so shouldn't call
rxrpc_notify_socket() for the call if we didn't use up all the data on
the queue, so fix that also.

Fixes: 540b1c48c37a ("rxrpc: Fix deadlock between call creation and sendmsg/recvmsg")
Reported-by: Faith <faith@zellic.io>
Reported-by: Pumpkin Chang <pumpkin@devco.re>
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Cc: stable@vger.kernel.org
[Adapted to 5.15: use write_lock_bh/write_unlock_bh, trace_rxrpc_call
 directly for see-call tracing, 5.15 trace enum naming convention, and
 added entries to both plain enum and EM() macro list.]
Signed-off-by: Jay Wang <wanjay@amazon.com>
---
 include/trace/events/rxrpc.h | 8 ++++++++
 net/rxrpc/recvmsg.c          | 20 ++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -93,9 +93,13 @@ enum rxrpc_call_trace {
 	rxrpc_call_put_notimer,
 	rxrpc_call_put_timer,
 	rxrpc_call_put_userid,
+	rxrpc_call_put_recvmsg_peek_nowait,
 	rxrpc_call_queued,
 	rxrpc_call_queued_ref,
 	rxrpc_call_release,
+	rxrpc_call_see_recvmsg_requeue,
+	rxrpc_call_see_recvmsg_requeue_first,
+	rxrpc_call_see_recvmsg_requeue_move,
 	rxrpc_call_seen,
 };
 
@@ -291,9 +295,13 @@ enum rxrpc_tx_point {
 	EM(rxrpc_call_put_notimer,		"PnT") \
 	EM(rxrpc_call_put_timer,		"PTM") \
 	EM(rxrpc_call_put_userid,		"Pus") \
+	EM(rxrpc_call_put_recvmsg_peek_nowait,	"PpN") \
 	EM(rxrpc_call_queued,			"QUE") \
 	EM(rxrpc_call_queued_ref,		"QUR") \
 	EM(rxrpc_call_release,			"RLS") \
+	EM(rxrpc_call_see_recvmsg_requeue,	"SrQ") \
+	EM(rxrpc_call_see_recvmsg_requeue_first,"SrF") \
+	EM(rxrpc_call_see_recvmsg_requeue_move,	"SrM") \
 	E_(rxrpc_call_seen,			"SEE")
 
 #define rxrpc_transmit_traces \
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -607,7 +607,8 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
 		if (after(call->rx_top, call->rx_hard_ack) &&
 		    call->rxtx_buffer[(call->rx_hard_ack + 1) & RXRPC_RXTX_BUFF_MASK])
-			rxrpc_notify_socket(call);
+			if (!(flags & MSG_PEEK))
+				rxrpc_notify_socket(call);
 		break;
 	default:
 		ret = 0;
@@ -642,11 +643,24 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 error_requeue_call:
 	if (!(flags & MSG_PEEK)) {
 		write_lock_bh(&rx->recvmsg_lock);
-		list_add(&call->recvmsg_link, &rx->recvmsg_q);
-		write_unlock_bh(&rx->recvmsg_lock);
+		if (list_empty(&call->recvmsg_link)) {
+			list_add(&call->recvmsg_link, &rx->recvmsg_q);
+			trace_rxrpc_call(call->debug_id,
+					 rxrpc_call_see_recvmsg_requeue,
+					 refcount_read(&call->ref),
+					 __builtin_return_address(0), NULL);
+			write_unlock_bh(&rx->recvmsg_lock);
+		} else if (list_is_first(&call->recvmsg_link, &rx->recvmsg_q)) {
+			write_unlock_bh(&rx->recvmsg_lock);
+			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_first);
+		} else {
+			list_move(&call->recvmsg_link, &rx->recvmsg_q);
+			write_unlock_bh(&rx->recvmsg_lock);
+			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_move);
+		}
 		trace_rxrpc_recvmsg(call, rxrpc_recvmsg_requeue, 0, 0, 0, 0);
 	} else {
-		rxrpc_put_call(call, rxrpc_call_put);
+		rxrpc_put_call(call, rxrpc_call_put_recvmsg_peek_nowait);
 	}
 error_no_call:
 	release_sock(&rx->sk);
-- 
2.43.0


^ permalink raw reply

* Re: [PATCH bpf-next v3 2/9] bpf: Assign reg->id when getting referenced kptr from ctx
From: Amery Hung @ 2026-04-22 22:45 UTC (permalink / raw)
  To: Eduard Zingerman
  Cc: bpf, netdev, alexei.starovoitov, andrii, daniel, memxor,
	martin.lau, mykyta.yatsenko5, kernel-team
In-Reply-To: <9237d7b35463c79863488e3f2180239aab679049.camel@gmail.com>

On Wed, Apr 22, 2026 at 2:46 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Tue, 2026-04-21 at 15:10 -0700, Amery Hung wrote:
> > Assign reg->id when getting referenced kptr from read program context
> > to be consistent with R0 of KF_ACQUIRE kfunc. skb dynptr will track the
> > referenced skb in qdisc programs using a new field reg->parent_id in
> > a later patch.
> >
> > Signed-off-by: Amery Hung <ameryhung@gmail.com>
> > ---
> >  kernel/bpf/verifier.c | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 41e4ea41c72e..93003a2a96b0 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -6448,8 +6448,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
> >                       } else {
> >                               mark_reg_known_zero(env, regs,
> >                                                   value_regno);
> > -                             if (type_may_be_null(info.reg_type))
> > -                                     regs[value_regno].id = ++env->id_gen;
> >                               /* A load of ctx field could have different
> >                                * actual load size with the one encoded in the
> >                                * insn. When the dst is PTR, it is for sure not
> > @@ -6459,8 +6457,11 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
> >                               if (base_type(info.reg_type) == PTR_TO_BTF_ID) {
> >                                       regs[value_regno].btf = info.btf;
> >                                       regs[value_regno].btf_id = info.btf_id;
> > +                                     regs[value_regno].id = info.ref_obj_id;
> >                                       regs[value_regno].ref_obj_id = info.ref_obj_id;
> >                               }
>
> Hi Amery,
>
> Could you please help me double-check my understanding of this change?
>
> It adds a new behavior, if struct_ops method parameter is annotated
> with __ref, then if a field is read from such struct_ops context
> the destination register would now have it's .id == ref_obj_id
> allocated for the parameter at the beginning of do_check().
> E.g. for `rB = *(T *)(rA + off)`, if `rA` is a pointer to struct_ops
> context and parameter corresponding to `off` has `__ref` annotation
> the `rB.id` will be assigned, contrary to old behavior, when it remained 0.
>

Right

> This change in behavior, however, becomes visible only after the
> changes to release_reference() later in the series.
> There the `rB.id` is used to initiate `mark_reg_invalid(env, reg)` for
> the `rB`.
>

I probably should mention it in the commit message. The purpose of the
patch is to make the implementation consistent with the design:
parent_id tracks the id of the parent objects.

Without this patch, it should still work since in this case ref_obj_id
always equals to id. When release_reference() is called on a
KF_RELEASE kfunc, the children objects will still be invalidated
correctly.

> Are the above observations correct?
>
> > +                             if (type_may_be_null(info.reg_type) && !regs[value_regno].id)
> > +                                     regs[value_regno].id = ++env->id_gen;
> >                       }
> >                       regs[value_regno].type = info.reg_type;
> >               }

^ permalink raw reply


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