From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1EB3D351C03; Tue, 21 Apr 2026 19:31:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799897; cv=none; b=crXTk5PVJ+jiAQjCKhG8V24JqtBV63OMCVhfa3VgvQuzP9TZWh464nEadiS3as+Zj/3szp+nKGX4iJsylH6eI2Uc6jkXyEaZcHTW4Ps+ne0TlLdFrpfOzs8KJwKYeFLOBw7rov9ndE8i2hxkLmLOaO8p0h40JXDdJEJIysqWeKk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799897; c=relaxed/simple; bh=7WxzJrU9WgaTu/tH5Gnb4WEdkRvE+e/Wn7qKm2ahc4g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pgIeTXMl3vcrEBjQEVU0LDpaUCmiokLB1xFvi04c6A+BoUIrnNnquOF0DN+AEnFolJrNxJ9HGfve7GCfGCL2+RuRzFE3TkCfNaefYlbLRfiB5ecoJuGexLouuZl59mbV+Bjbo29sTxPid1ag17hDf5jPbCaxijXspbmw42QOtYE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=bJF4WdD/; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="bJF4WdD/" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=OuenODQgi/IVQamyhIw5WSD4NPZBSp8tkODkAxLuMe0=; b=bJ F4WdD/HcG+grXEpQcKWqUx43MzV7XyL7+/0VkycOcsGz5+ederOu077cGK0NdsMD+wFIhh+d5W0gl 3tw23WkzHZMtXM77ZKND6gI0e5ThM0TVAGz5BR//DzR/E0a8e3MAlFVkB7B/IvPOsXraabFj577IF HWdGl+Rfm2e/DSk=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGoZ-00GwVc-FH; Tue, 21 Apr 2026 21:31:19 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:04 -0500 Subject: [PATCH net 01/18] drivers: net: 3com: 3c509: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-1-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=43916; i=andrew@lunn.ch; h=from:subject:message-id; bh=7WxzJrU9WgaTu/tH5Gnb4WEdkRvE+e/Wn7qKm2ahc4g=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CB/WEO90/8TElZGnsSuFvNxPGKmbQAKaK7F jG4HCK+bZqJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hNrhD/wLXhZASS35j81OgKkDlA+TQ9R0keXDbGjEAUs5tcjzOIVTRi9JKZwdsptKTldd3o3YjK4 8ruKshrHqxFix2jsku0BNgwlkGH00m459rpq0jrbmmLu0Yg3i/TEMocw+bmkIBxMAUfV9G0fngV Zj1c0Gun/348nJ5KeGwBgyy+mZ30AYQNAMvvQVQ9IgXd0gxDNFNa0PkTFvHILpcJkM5A0H+1mKr 0dMhXUmBPkTPkzF+lmAqGaMkVxUePDy/IoV1d6ZiI76JXc+R4x/3Vn9cJrdAl56KdRFS5+g0AgN PbfBG6tcu2CNf/mTyIGg594DxTd5a1sDYgjk/KwfZTUqu53KEMI5a9gfhgl8NM6q51e0UXn0ZVA oRFHxdw6KWi2xEnX0ko4qU6XPTCpJ0YlhQMMMIKJoAhM+41ZQeiQ9nLJCN86YD8V5zEsiG7Ev0F EFOmUYPH2Y84PYwcb/3v/n4sNAdwBZzUVEUvcM8oKP18C7HmlczamS8ZyOFUaaC/dZeG9mi8dlJ dZ8HYzvFCpdfFJTdhRFVhYoQLSV9XtKWtWOSuqefp+u+TtZgqK7Fxqy1ZwhNVeCt6sKKJIhTcBJ amsxyr82nKLQB4TEBjqTn8SirSFMNEEG4CdHYZ1S6sIYzCx2BDUgkripyKvu8yaTWwsl2m+CXNe 13M8wjpBnFFq06w== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The 3c509 was written by Donald Becker between 1993-2000. It is an ISA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/3com/3c509.c | 1448 --------------------------------= ---- drivers/net/ethernet/3com/Kconfig | 14 - drivers/net/ethernet/3com/Makefile | 1 - 3 files changed, 1463 deletions(-) diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/= 3c509.c deleted file mode 100644 index fb68339e1511..000000000000 --- a/drivers/net/ethernet/3com/3c509.c +++ /dev/null @@ -1,1448 +0,0 @@ -/* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ -/* - Written 1993-2000 by Donald Becker. - - Copyright 1994-2000 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may be used and - distributed according to the terms of the GNU General Public License, - incorporated herein by reference. - - This driver is for the 3Com EtherLinkIII series. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Known limitations: - Because of the way 3c509 ISA detection works it's difficult to predict - a priori which of several ISA-mode cards will be detected first. - - This driver does not use predictive interrupt mode, resulting in higher - packet latency but lower overhead. If interrupts are disabled for an - unusually long time it could also result in missed packets, but in - practice this rarely happens. - - - FIXES: - Alan Cox: Removed the 'Unexpected interrupt' bug. - Michael Meskes: Upgraded to Donald Becker's version 1.07. - Alan Cox: Increased the eeprom delay. Regardless of - what the docs say some people definitely - get problems with lower (but in card spec) - delays - v1.10 4/21/97 Fixed module code so that multiple cards may be detected, - other cleanups. -djb - Andrea Arcangeli: Upgraded to Donald Becker's version 1.12. - Rick Payne: Fixed SMP race condition - v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb - v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb - v1.15 1/31/98 Faster recovery for Tx errors. -djb - v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb - v1.18 12Mar2001 Andrew Morton - - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz) - - Reviewed against 1.18 from scyld.com - v1.18a 17Nov2001 Jeff Garzik - - ethtool support - v1.18b 1Mar2002 Zwane Mwaikambo - - Power Management support - v1.18c 1Mar2002 David Ruggiero - - Full duplex support - v1.19 16Oct2002 Zwane Mwaikambo - - Additional ethtool features - v1.19a 28Oct2002 Davud Ruggiero - - Increase *read_eeprom udelay to workaround oops with 2 cards. - v1.19b 08Nov2002 Marc Zyngier - - Introduce driver model for EISA cards. - v1.20 04Feb2008 Ondrej Zary - - convert to isa_driver and pnp_driver and some cleanups -*/ - -#define DRV_NAME "3c509" - -/* A few values that may be tweaked. */ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (400*HZ/1000) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for udelay() */ -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef EL3_DEBUG -static int el3_debug =3D EL3_DEBUG; -#else -static int el3_debug =3D 2; -#endif - -/* Used to do a global count of all the cards in the system. Must be - * a global variable so that the eisa probe routines can increment - * it */ -static int el3_cards =3D 0; -#define EL3_MAX_CARDS 8 - -/* To minimize the size of the driver source I only define operating - constants if they are used several times. You'll need the manual - anyway if you want to understand driver details. */ -/* Offsets from base I/O address. */ -#define EL3_DATA 0x00 -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e -#define EEPROM_READ 0x80 - -#define EL3_IO_EXTENT 16 - -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) - - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. */ -enum c509cmd { - TotalReset =3D 0<<11, SelectWindow =3D 1<<11, StartCoax =3D 2<<11, - RxDisable =3D 3<<11, RxEnable =3D 4<<11, RxReset =3D 5<<11, RxDiscard =3D= 8<<11, - TxEnable =3D 9<<11, TxDisable =3D 10<<11, TxReset =3D 11<<11, - FakeIntr =3D 12<<11, AckIntr =3D 13<<11, SetIntrEnb =3D 14<<11, - SetStatusEnb =3D 15<<11, SetRxFilter =3D 16<<11, SetRxThreshold =3D 17<<1= 1, - SetTxThreshold =3D 18<<11, SetTxStart =3D 19<<11, StatsEnable =3D 21<<11, - StatsDisable =3D 22<<11, StopCoax =3D 23<<11, PowerUp =3D 27<<11, - PowerDown =3D 28<<11, PowerAuto =3D 29<<11}; - -enum c509status { - IntLatch =3D 0x0001, AdapterFailure =3D 0x0002, TxComplete =3D 0x0004, - TxAvailable =3D 0x0008, RxComplete =3D 0x0010, RxEarly =3D 0x0020, - IntReq =3D 0x0040, StatsFull =3D 0x0080, CmdBusy =3D 0x1000, }; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation =3D 1, RxMulticast =3D 2, RxBroadcast =3D 4, RxProm =3D 8 }; - -/* Register window 1 offsets, the window used in normal operation. */ -#define TX_FIFO 0x00 -#define RX_FIFO 0x00 -#define RX_STATUS 0x08 -#define TX_STATUS 0x0B -#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ - -#define WN0_CONF_CTRL 0x04 /* Window 0: Configuration control register */ -#define WN0_ADDR_CONF 0x06 /* Window 0: Address configuration register */ -#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ -#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ -#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ -#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ - -/* - * Must be a power of two (we use a binary and in the - * circular queue) - */ -#define SKB_QUEUE_SIZE 64 - -enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_EISA }; - -struct el3_private { - spinlock_t lock; - /* skb send-queue */ - int head, size; - struct sk_buff *queue[SKB_QUEUE_SIZE]; - enum el3_cardtype type; -}; -static int id_port; -static int current_tag; -static struct net_device *el3_devs[EL3_MAX_CARDS]; - -/* Parameters that may be passed into the module. */ -static int debug =3D -1; -static int irq[] =3D {-1, -1, -1, -1, -1, -1, -1, -1}; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work =3D 10; -#ifdef CONFIG_PNP -static int nopnp; -#endif - -static int el3_common_init(struct net_device *dev); -static void el3_common_remove(struct net_device *dev); -static ushort id_read_eeprom(int index); -static ushort read_eeprom(int ioaddr, int index); -static int el3_open(struct net_device *dev); -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *= dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id); -static void update_stats(struct net_device *dev); -static struct net_device_stats *el3_get_stats(struct net_device *dev); -static int el3_rx(struct net_device *dev); -static int el3_close(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void el3_tx_timeout (struct net_device *dev, unsigned int txqueue); -static void el3_down(struct net_device *dev); -static void el3_up(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; -#ifdef CONFIG_PM -static int el3_suspend(struct device *, pm_message_t); -static int el3_resume(struct device *); -#else -#define el3_suspend NULL -#define el3_resume NULL -#endif - - -/* generic device remove for all device types */ -static int el3_device_remove (struct device *device); -#ifdef CONFIG_NET_POLL_CONTROLLER -static void el3_poll_controller(struct net_device *dev); -#endif - -/* Return 0 on success, 1 on error, 2 when found already detected PnP card= */ -static int el3_isa_id_sequence(__be16 *phys_addr) -{ - short lrs_state =3D 0xff; - int i; - - /* ISA boards are detected by sending the ID sequence to the - ID_PORT. We find cards past the first by setting the 'current_tag' - on cards as they are found. Cards with their tag set will not - respond to subsequent ID sequences. */ - - outb(0x00, id_port); - outb(0x00, id_port); - for (i =3D 0; i < 255; i++) { - outb(lrs_state, id_port); - lrs_state <<=3D 1; - lrs_state =3D lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; - } - /* For the first probe, clear all board's tag registers. */ - if (current_tag =3D=3D 0) - outb(0xd0, id_port); - else /* Otherwise kill off already-found boards. */ - outb(0xd8, id_port); - if (id_read_eeprom(7) !=3D 0x6d50) - return 1; - /* Read in EEPROM data, which does contention-select. - Only the lowest address board will stay "on-line". - 3Com got the byte order backwards. */ - for (i =3D 0; i < 3; i++) - phys_addr[i] =3D htons(id_read_eeprom(i)); -#ifdef CONFIG_PNP - if (!nopnp) { - /* The ISA PnP 3c509 cards respond to the ID sequence too. - This check is needed in order not to register them twice. */ - for (i =3D 0; i < el3_cards; i++) { - struct el3_private *lp =3D netdev_priv(el3_devs[i]); - if (lp->type =3D=3D EL3_PNP && - ether_addr_equal((u8 *)phys_addr, el3_devs[i]->dev_addr)) { - if (el3_debug > 3) - pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found = by ISAPnP\n", - phys_addr[0] & 0xff, phys_addr[0] >> 8, - phys_addr[1] & 0xff, phys_addr[1] >> 8, - phys_addr[2] & 0xff, phys_addr[2] >> 8); - /* Set the adaptor tag so that the next card can be found. */ - outb(0xd0 + ++current_tag, id_port); - return 2; - } - } - } -#endif /* CONFIG_PNP */ - return 0; - -} - -static void el3_dev_fill(struct net_device *dev, __be16 *phys_addr, int io= addr, - int irq, int if_port, enum el3_cardtype type) -{ - struct el3_private *lp =3D netdev_priv(dev); - - eth_hw_addr_set(dev, (u8 *)phys_addr); - dev->base_addr =3D ioaddr; - dev->irq =3D irq; - dev->if_port =3D if_port; - lp->type =3D type; -} - -static int el3_isa_match(struct device *pdev, unsigned int ndev) -{ - struct net_device *dev; - int ioaddr, isa_irq, if_port, err; - unsigned int iobase; - __be16 phys_addr[3]; - - while ((err =3D el3_isa_id_sequence(phys_addr)) =3D=3D 2) - ; /* Skip to next card when PnP card found */ - if (err =3D=3D 1) - return 0; - - iobase =3D id_read_eeprom(8); - if_port =3D iobase >> 14; - ioaddr =3D 0x200 + ((iobase & 0x1f) << 4); - if (irq[el3_cards] > 1 && irq[el3_cards] < 16) - isa_irq =3D irq[el3_cards]; - else - isa_irq =3D id_read_eeprom(9) >> 12; - - dev =3D alloc_etherdev(sizeof(struct el3_private)); - if (!dev) - return -ENOMEM; - - SET_NETDEV_DEV(dev, pdev); - - if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) { - free_netdev(dev); - return 0; - } - - /* Set the adaptor tag so that the next card can be found. */ - outb(0xd0 + ++current_tag, id_port); - - /* Activate the adaptor at the EEPROM location. */ - outb((ioaddr >> 4) | 0xe0, id_port); - - EL3WINDOW(0); - if (inw(ioaddr) !=3D 0x6d50) { - free_netdev(dev); - return 0; - } - - /* Free the interrupt so that some other card can use it. */ - outw(0x0f00, ioaddr + WN0_IRQ); - - el3_dev_fill(dev, phys_addr, ioaddr, isa_irq, if_port, EL3_ISA); - dev_set_drvdata(pdev, dev); - if (el3_common_init(dev)) { - free_netdev(dev); - return 0; - } - - el3_devs[el3_cards++] =3D dev; - return 1; -} - -static void el3_isa_remove(struct device *pdev, - unsigned int ndev) -{ - el3_device_remove(pdev); - dev_set_drvdata(pdev, NULL); -} - -#ifdef CONFIG_PM -static int el3_isa_suspend(struct device *dev, unsigned int n, - pm_message_t state) -{ - current_tag =3D 0; - return el3_suspend(dev, state); -} - -static int el3_isa_resume(struct device *dev, unsigned int n) -{ - struct net_device *ndev =3D dev_get_drvdata(dev); - int ioaddr =3D ndev->base_addr, err; - __be16 phys_addr[3]; - - while ((err =3D el3_isa_id_sequence(phys_addr)) =3D=3D 2) - ; /* Skip to next card when PnP card found */ - if (err =3D=3D 1) - return 0; - /* Set the adaptor tag so that the next card can be found. */ - outb(0xd0 + ++current_tag, id_port); - /* Enable the card */ - outb((ioaddr >> 4) | 0xe0, id_port); - EL3WINDOW(0); - if (inw(ioaddr) !=3D 0x6d50) - return 1; - /* Free the interrupt so that some other card can use it. */ - outw(0x0f00, ioaddr + WN0_IRQ); - return el3_resume(dev); -} -#endif - -static struct isa_driver el3_isa_driver =3D { - .match =3D el3_isa_match, - .remove =3D el3_isa_remove, -#ifdef CONFIG_PM - .suspend =3D el3_isa_suspend, - .resume =3D el3_isa_resume, -#endif - .driver =3D { - .name =3D "3c509" - }, -}; -static int isa_registered; - -#ifdef CONFIG_PNP -static const struct pnp_device_id el3_pnp_ids[] =3D { - { .id =3D "TCM5090" }, /* 3Com Etherlink III (TP) */ - { .id =3D "TCM5091" }, /* 3Com Etherlink III */ - { .id =3D "TCM5094" }, /* 3Com Etherlink III (combo) */ - { .id =3D "TCM5095" }, /* 3Com Etherlink III (TPO) */ - { .id =3D "TCM5098" }, /* 3Com Etherlink III (TPC) */ - { .id =3D "PNP80f7" }, /* 3Com Etherlink III compatible */ - { .id =3D "PNP80f8" }, /* 3Com Etherlink III compatible */ - { .id =3D "" } -}; -MODULE_DEVICE_TABLE(pnp, el3_pnp_ids); - -static int el3_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id = *id) -{ - short i; - int ioaddr, irq, if_port; - __be16 phys_addr[3]; - struct net_device *dev =3D NULL; - int err; - - ioaddr =3D pnp_port_start(pdev, 0); - if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-pnp")) - return -EBUSY; - irq =3D pnp_irq(pdev, 0); - EL3WINDOW(0); - for (i =3D 0; i < 3; i++) - phys_addr[i] =3D htons(read_eeprom(ioaddr, i)); - if_port =3D read_eeprom(ioaddr, 8) >> 14; - dev =3D alloc_etherdev(sizeof(struct el3_private)); - if (!dev) { - release_region(ioaddr, EL3_IO_EXTENT); - return -ENOMEM; - } - SET_NETDEV_DEV(dev, &pdev->dev); - - el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_PNP); - pnp_set_drvdata(pdev, dev); - err =3D el3_common_init(dev); - - if (err) { - pnp_set_drvdata(pdev, NULL); - free_netdev(dev); - return err; - } - - el3_devs[el3_cards++] =3D dev; - return 0; -} - -static void el3_pnp_remove(struct pnp_dev *pdev) -{ - el3_common_remove(pnp_get_drvdata(pdev)); - pnp_set_drvdata(pdev, NULL); -} - -#ifdef CONFIG_PM -static int el3_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) -{ - return el3_suspend(&pdev->dev, state); -} - -static int el3_pnp_resume(struct pnp_dev *pdev) -{ - return el3_resume(&pdev->dev); -} -#endif - -static struct pnp_driver el3_pnp_driver =3D { - .name =3D "3c509", - .id_table =3D el3_pnp_ids, - .probe =3D el3_pnp_probe, - .remove =3D el3_pnp_remove, -#ifdef CONFIG_PM - .suspend =3D el3_pnp_suspend, - .resume =3D el3_pnp_resume, -#endif -}; -static int pnp_registered; -#endif /* CONFIG_PNP */ - -#ifdef CONFIG_EISA -static const struct eisa_device_id el3_eisa_ids[] =3D { - { "TCM5090" }, - { "TCM5091" }, - { "TCM5092" }, - { "TCM5093" }, - { "TCM5094" }, - { "TCM5095" }, - { "TCM5098" }, - { "" } -}; -MODULE_DEVICE_TABLE(eisa, el3_eisa_ids); - -static int el3_eisa_probe (struct device *device); - -static struct eisa_driver el3_eisa_driver =3D { - .id_table =3D el3_eisa_ids, - .driver =3D { - .name =3D "3c579", - .probe =3D el3_eisa_probe, - .remove =3D el3_device_remove, - .suspend =3D el3_suspend, - .resume =3D el3_resume, - } -}; -static int eisa_registered; -#endif - -static const struct net_device_ops netdev_ops =3D { - .ndo_open =3D el3_open, - .ndo_stop =3D el3_close, - .ndo_start_xmit =3D el3_start_xmit, - .ndo_get_stats =3D el3_get_stats, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_tx_timeout =3D el3_tx_timeout, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D el3_poll_controller, -#endif -}; - -static int el3_common_init(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - int err; - static const char * const if_names[] =3D { - "10baseT", "AUI", "undefined", "BNC" - }; - - spin_lock_init(&lp->lock); - - if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ - dev->if_port =3D (dev->mem_start & 0x0f); - } else { /* xcvr codes 0/8 */ - /* use eeprom value, but save user's full-duplex selection */ - dev->if_port |=3D (dev->mem_start & 0x08); - } - - /* The EL3-specific entries in the device structure. */ - dev->netdev_ops =3D &netdev_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - dev->ethtool_ops =3D ðtool_ops; - - err =3D register_netdev(dev); - if (err) { - pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n", - dev->base_addr, dev->irq); - release_region(dev->base_addr, EL3_IO_EXTENT); - return err; - } - - pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n", - dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], - dev->dev_addr, dev->irq); - - return 0; - -} - -static void el3_common_remove (struct net_device *dev) -{ - unregister_netdev (dev); - release_region(dev->base_addr, EL3_IO_EXTENT); - free_netdev (dev); -} - -#ifdef CONFIG_EISA -static int el3_eisa_probe(struct device *device) -{ - short i; - int ioaddr, irq, if_port; - __be16 phys_addr[3]; - struct net_device *dev =3D NULL; - struct eisa_device *edev; - int err; - - /* Yeepee, The driver framework is calling us ! */ - edev =3D to_eisa_device (device); - ioaddr =3D edev->base_addr; - - if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa")) - return -EBUSY; - - /* Change the register set to the configuration window 0. */ - outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD); - - irq =3D inw(ioaddr + WN0_IRQ) >> 12; - if_port =3D inw(ioaddr + 6)>>14; - for (i =3D 0; i < 3; i++) - phys_addr[i] =3D htons(read_eeprom(ioaddr, i)); - - /* Restore the "Product ID" to the EEPROM read register. */ - read_eeprom(ioaddr, 3); - - dev =3D alloc_etherdev(sizeof (struct el3_private)); - if (dev =3D=3D NULL) { - release_region(ioaddr, EL3_IO_EXTENT); - return -ENOMEM; - } - - SET_NETDEV_DEV(dev, device); - - el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA); - eisa_set_drvdata (edev, dev); - err =3D el3_common_init(dev); - - if (err) { - eisa_set_drvdata (edev, NULL); - free_netdev(dev); - return err; - } - - el3_devs[el3_cards++] =3D dev; - return 0; -} -#endif - -/* This remove works for all device types. - * - * The net dev must be stored in the driver data field */ -static int el3_device_remove(struct device *device) -{ - struct net_device *dev; - - dev =3D dev_get_drvdata(device); - - el3_common_remove (dev); - return 0; -} - -/* Read a word from the EEPROM using the regular EEPROM access register. - Assume that we are in register window zero. - */ -static ushort read_eeprom(int ioaddr, int index) -{ - outw(EEPROM_READ + index, ioaddr + 10); - /* Pause for at least 162 us. for the read to take place. - Some chips seem to require much longer */ - mdelay(2); - return inw(ioaddr + 12); -} - -/* Read a word from the EEPROM when in the ISA ID probe state. */ -static ushort id_read_eeprom(int index) -{ - int bit, word =3D 0; - - /* Issue read command, and pause for at least 162 us. for it to complete. - Assume extra-fast 16Mhz bus. */ - outb(EEPROM_READ + index, id_port); - - /* Pause for at least 162 us. for the read to take place. */ - /* Some chips seem to require much longer */ - mdelay(4); - - for (bit =3D 15; bit >=3D 0; bit--) - word =3D (word << 1) + (inb(id_port) & 0x01); - - if (el3_debug > 3) - pr_debug(" 3c509 EEPROM word %d %#4.4x.\n", index, word); - - return word; -} - - -static int -el3_open(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - int i; - - outw(TxReset, ioaddr + EL3_CMD); - outw(RxReset, ioaddr + EL3_CMD); - outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - - i =3D request_irq(dev->irq, el3_interrupt, 0, dev->name, dev); - if (i) - return i; - - EL3WINDOW(0); - if (el3_debug > 3) - pr_debug("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, - dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS)); - - el3_up(dev); - - if (el3_debug > 3) - pr_debug("%s: Opened 3c509 IRQ %d status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + EL3_STATUS)); - - return 0; -} - -static void -el3_tx_timeout (struct net_device *dev, unsigned int txqueue) -{ - int ioaddr =3D dev->base_addr; - - /* Transmitter timeout, serious problems. */ - pr_warn("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO roo= m %d\n", - dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), - inw(ioaddr + TX_FREE)); - dev->stats.tx_errors++; - netif_trans_update(dev); /* prevent tx timeout */ - /* Issue TX_RESET and TX_START commands. */ - outw(TxReset, ioaddr + EL3_CMD); - outw(TxEnable, ioaddr + EL3_CMD); - netif_wake_queue(dev); -} - - -static netdev_tx_t -el3_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - int ioaddr =3D dev->base_addr; - unsigned long flags; - - netif_stop_queue (dev); - - dev->stats.tx_bytes +=3D skb->len; - - if (el3_debug > 4) { - pr_debug("%s: el3_start_xmit(length =3D %u) called, status %4.4x.\n", - dev->name, skb->len, inw(ioaddr + EL3_STATUS)); - } - /* - * We lock the driver against other processors. Note - * we don't need to lock versus the IRQ as we suspended - * that. This means that we lose the ability to take - * an RX during a TX upload. That sucks a bit with SMP - * on an original 3c509 (2K buffer) - * - * Using disable_irq stops us crapping on other - * time sensitive devices. - */ - - spin_lock_irqsave(&lp->lock, flags); - - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0x00, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - - if (inw(ioaddr + TX_FREE) > 1536) - netif_start_queue(dev); - else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); - - spin_unlock_irqrestore(&lp->lock, flags); - - dev_consume_skb_any (skb); - - /* Clear the Tx status stack. */ - { - short tx_status; - int i =3D 4; - - while (--i > 0 && (tx_status =3D inb(ioaddr + TX_STATUS)) > 0) { - if (tx_status & 0x38) dev->stats.tx_aborted_errors++; - if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); - if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); - outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ - } - } - return NETDEV_TX_OK; -} - -/* The EL3 interrupt handler. */ -static irqreturn_t -el3_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D dev_id; - struct el3_private *lp; - int ioaddr, status; - int i =3D max_interrupt_work; - - lp =3D netdev_priv(dev); - spin_lock(&lp->lock); - - ioaddr =3D dev->base_addr; - - if (el3_debug > 4) { - status =3D inw(ioaddr + EL3_STATUS); - pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status); - } - - while ((status =3D inw(ioaddr + EL3_STATUS)) & - (IntLatch | RxComplete | StatsFull)) { - - if (status & RxComplete) - el3_rx(dev); - - if (status & TxAvailable) { - if (el3_debug > 5) - pr_debug(" TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue (dev); - } - if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) { - /* Handle all uncommon interrupts. */ - if (status & StatsFull) /* Empty statistics. */ - update_stats(dev); - if (status & RxEarly) { /* Rx early is unused. */ - el3_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & TxComplete) { /* Really Tx error. */ - short tx_status; - int i =3D 4; - - while (--i>0 && (tx_status =3D inb(ioaddr + TX_STATUS)) > 0) { - if (tx_status & 0x38) dev->stats.tx_aborted_errors++; - if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); - if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); - outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ - } - } - if (status & AdapterFailure) { - /* Adapter failure requires Rx reset and reinit. */ - outw(RxReset, ioaddr + EL3_CMD); - /* Set the Rx filter to the current state. */ - outw(SetRxFilter | RxStation | RxBroadcast - | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0) - | (dev->flags & IFF_PROMISC ? RxProm : 0), - ioaddr + EL3_CMD); - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); - } - } - - if (--i < 0) { - pr_err("%s: Infinite loop in interrupt, status %4.4x.\n", - dev->name, status); - /* Clear all interrupts. */ - outw(AckIntr | 0xFF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */ - } - - if (el3_debug > 4) { - pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, - inw(ioaddr + EL3_STATUS)); - } - spin_unlock(&lp->lock); - return IRQ_HANDLED; -} - - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling receive - used by netconsole and other diagnostic tools - * to allow network i/o with interrupts disabled. - */ -static void el3_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - el3_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -static struct net_device_stats * -el3_get_stats(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - unsigned long flags; - - /* - * This is fast enough not to bother with disable IRQ - * stuff. - */ - - spin_lock_irqsave(&lp->lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->lock, flags); - return &dev->stats; -} - -/* Update statistics. We change to register window 6, so this should be = run - single-threaded if the device is active. This is expected to be a rare - operation, and it's simpler for the rest of the driver to assume that - window 1 is always valid rather than use a special window-state variable. - */ -static void update_stats(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - - if (el3_debug > 5) - pr_debug(" Updating the statistics.\n"); - /* Turn off statistics updates while reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors +=3D inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors +=3D inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - dev->stats.collisions +=3D inb(ioaddr + 3); - dev->stats.tx_window_errors +=3D inb(ioaddr + 4); - dev->stats.rx_fifo_errors +=3D inb(ioaddr + 5); - dev->stats.tx_packets +=3D inb(ioaddr + 6); - /* Rx packets */ inb(ioaddr + 7); - /* Tx deferrals */ inb(ioaddr + 8); - inw(ioaddr + 10); /* Total Rx and Tx octets. */ - inw(ioaddr + 12); - - /* Back to window 1, and turn statistics back on. */ - EL3WINDOW(1); - outw(StatsEnable, ioaddr + EL3_CMD); -} - -static int -el3_rx(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - short rx_status; - - if (el3_debug > 5) - pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); - while ((rx_status =3D inw(ioaddr + RX_STATUS)) > 0) { - if (rx_status & 0x4000) { /* Error, update stats. */ - short error =3D rx_status & 0x3800; - - outw(RxDiscard, ioaddr + EL3_CMD); - dev->stats.rx_errors++; - switch (error) { - case 0x0000: dev->stats.rx_over_errors++; break; - case 0x0800: dev->stats.rx_length_errors++; break; - case 0x1000: dev->stats.rx_frame_errors++; break; - case 0x1800: dev->stats.rx_length_errors++; break; - case 0x2000: dev->stats.rx_frame_errors++; break; - case 0x2800: dev->stats.rx_crc_errors++; break; - } - } else { - short pkt_len =3D rx_status & 0x7ff; - struct sk_buff *skb; - - skb =3D netdev_alloc_skb(dev, pkt_len + 5); - if (el3_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb !=3D NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte */ - - /* 'skb->data' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len), - (pkt_len + 3) >> 2); - - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ - skb->protocol =3D eth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_bytes +=3D pkt_len; - dev->stats.rx_packets++; - continue; - } - outw(RxDiscard, ioaddr + EL3_CMD); - dev->stats.rx_dropped++; - if (el3_debug) - pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", - dev->name, pkt_len); - } - inw(ioaddr + EL3_STATUS); /* Delay. */ - while (inw(ioaddr + EL3_STATUS) & 0x1000) - pr_debug(" Waiting for 3c509 to discard packet, status %x.\n", - inw(ioaddr + EL3_STATUS) ); - } - - return 0; -} - -/* - * Set or clear the multicast filter for this adaptor. - */ -static void -set_multicast_list(struct net_device *dev) -{ - unsigned long flags; - struct el3_private *lp =3D netdev_priv(dev); - int ioaddr =3D dev->base_addr; - int mc_count =3D netdev_mc_count(dev); - - if (el3_debug > 1) { - static int old; - if (old !=3D mc_count) { - old =3D mc_count; - pr_debug("%s: Setting Rx mode to %d addresses.\n", - dev->name, mc_count); - } - } - spin_lock_irqsave(&lp->lock, flags); - if (dev->flags&IFF_PROMISC) { - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, - ioaddr + EL3_CMD); - } - else if (mc_count || (dev->flags&IFF_ALLMULTI)) { - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_C= MD); - } - else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); - spin_unlock_irqrestore(&lp->lock, flags); -} - -static int -el3_close(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - struct el3_private *lp =3D netdev_priv(dev); - - if (el3_debug > 2) - pr_debug("%s: Shutting down ethercard.\n", dev->name); - - el3_down(dev); - - free_irq(dev->irq, dev); - /* Switching back to window 0 disables the IRQ. */ - EL3WINDOW(0); - if (lp->type !=3D EL3_EISA) { - /* But we explicitly zero the IRQ line select anyway. Don't do - * it on EISA cards, it prevents the module from getting an - * IRQ after unload+reload... */ - outw(0x0f00, ioaddr + WN0_IRQ); - } - - return 0; -} - -static int -el3_link_ok(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - u16 tmp; - - EL3WINDOW(4); - tmp =3D inw(ioaddr + WN4_MEDIA); - EL3WINDOW(1); - return tmp & (1<<11); -} - -static void -el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_link_ksettings = *cmd) -{ - u16 tmp; - int ioaddr =3D dev->base_addr; - u32 supported; - - EL3WINDOW(0); - /* obtain current transceiver via WN4_MEDIA? */ - tmp =3D inw(ioaddr + WN0_ADDR_CONF); - switch (tmp >> 14) { - case 0: - cmd->base.port =3D PORT_TP; - break; - case 1: - cmd->base.port =3D PORT_AUI; - break; - case 3: - cmd->base.port =3D PORT_BNC; - break; - default: - break; - } - - cmd->base.duplex =3D DUPLEX_HALF; - supported =3D 0; - tmp =3D inw(ioaddr + WN0_CONF_CTRL); - if (tmp & (1<<13)) - supported |=3D SUPPORTED_AUI; - if (tmp & (1<<12)) - supported |=3D SUPPORTED_BNC; - if (tmp & (1<<9)) { - supported |=3D SUPPORTED_TP | SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full; /* hmm... */ - EL3WINDOW(4); - tmp =3D inw(ioaddr + WN4_NETDIAG); - if (tmp & FD_ENABLE) - cmd->base.duplex =3D DUPLEX_FULL; - } - - ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, - supported); - cmd->base.speed =3D SPEED_10; - EL3WINDOW(1); -} - -static int -el3_netdev_set_ecmd(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - u16 tmp; - int ioaddr =3D dev->base_addr; - - if (cmd->base.speed !=3D SPEED_10) - return -EINVAL; - if ((cmd->base.duplex !=3D DUPLEX_HALF) && - (cmd->base.duplex !=3D DUPLEX_FULL)) - return -EINVAL; - - /* change XCVR type */ - EL3WINDOW(0); - tmp =3D inw(ioaddr + WN0_ADDR_CONF); - switch (cmd->base.port) { - case PORT_TP: - tmp &=3D ~(3<<14); - dev->if_port =3D 0; - break; - case PORT_AUI: - tmp |=3D (1<<14); - dev->if_port =3D 1; - break; - case PORT_BNC: - tmp |=3D (3<<14); - dev->if_port =3D 3; - break; - default: - return -EINVAL; - } - - outw(tmp, ioaddr + WN0_ADDR_CONF); - if (dev->if_port =3D=3D 3) { - /* fire up the DC-DC convertor if BNC gets enabled */ - tmp =3D inw(ioaddr + WN0_ADDR_CONF); - if (tmp & (3 << 14)) { - outw(StartCoax, ioaddr + EL3_CMD); - udelay(800); - } else - return -EIO; - } - - EL3WINDOW(4); - tmp =3D inw(ioaddr + WN4_NETDIAG); - if (cmd->base.duplex =3D=3D DUPLEX_FULL) - tmp |=3D FD_ENABLE; - else - tmp &=3D ~FD_ENABLE; - outw(tmp, ioaddr + WN4_NETDIAG); - EL3WINDOW(1); - - return 0; -} - -static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo= *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); -} - -static int el3_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct el3_private *lp =3D netdev_priv(dev); - - spin_lock_irq(&lp->lock); - el3_netdev_get_ecmd(dev, cmd); - spin_unlock_irq(&lp->lock); - return 0; -} - -static int el3_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct el3_private *lp =3D netdev_priv(dev); - int ret; - - spin_lock_irq(&lp->lock); - ret =3D el3_netdev_set_ecmd(dev, cmd); - spin_unlock_irq(&lp->lock); - return ret; -} - -static u32 el3_get_link(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - u32 ret; - - spin_lock_irq(&lp->lock); - ret =3D el3_link_ok(dev); - spin_unlock_irq(&lp->lock); - return ret; -} - -static u32 el3_get_msglevel(struct net_device *dev) -{ - return el3_debug; -} - -static void el3_set_msglevel(struct net_device *dev, u32 v) -{ - el3_debug =3D v; -} - -static const struct ethtool_ops ethtool_ops =3D { - .get_drvinfo =3D el3_get_drvinfo, - .get_link =3D el3_get_link, - .get_msglevel =3D el3_get_msglevel, - .set_msglevel =3D el3_set_msglevel, - .get_link_ksettings =3D el3_get_link_ksettings, - .set_link_ksettings =3D el3_set_link_ksettings, -}; - -static void -el3_down(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - - netif_stop_queue(dev); - - /* Turn off statistics ASAP. We update lp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port =3D=3D 3) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port =3D=3D 0) { - /* Disable link beat and jabber, if_port may change here next open(). */ - EL3WINDOW(4); - outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); - } - - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - - update_stats(dev); -} - -static void -el3_up(struct net_device *dev) -{ - int i, sw_info, net_diag; - int ioaddr =3D dev->base_addr; - - /* Activating the board required and does no harm otherwise */ - outw(0x0001, ioaddr + 4); - - /* Set the IRQ line. */ - outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ); - - /* Set the station address in window 2 each time opened. */ - EL3WINDOW(2); - - for (i =3D 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - - if ((dev->if_port & 0x03) =3D=3D 3) /* BNC interface */ - /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); - else if ((dev->if_port & 0x03) =3D=3D 0) { /* 10baseT interface */ - /* Combine secondary sw_info word (the adapter level) and primary - sw_info word (duplex setting plus other useless bits) */ - EL3WINDOW(0); - sw_info =3D (read_eeprom(ioaddr, 0x14) & 0x400f) | - (read_eeprom(ioaddr, 0x0d) & 0xBff0); - - EL3WINDOW(4); - net_diag =3D inw(ioaddr + WN4_NETDIAG); - net_diag =3D (net_diag | FD_ENABLE); /* temporarily assume full-duplex w= ill be set */ - pr_info("%s: ", dev->name); - switch (dev->if_port & 0x0c) { - case 12: - /* force full-duplex mode if 3c5x9b */ - if (sw_info & 0x000f) { - pr_cont("Forcing 3c5x9b full-duplex mode"); - break; - } - fallthrough; - case 8: - /* set full-duplex mode based on eeprom config setting */ - if ((sw_info & 0x000f) && (sw_info & 0x8000)) { - pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration b= it)"); - break; - } - fallthrough; - default: - /* xcvr=3D(0 || 4) OR user has an old 3c5x9 non "B" model */ - pr_cont("Setting 3c5x9/3c5x9B half-duplex mode"); - net_diag =3D (net_diag & ~FD_ENABLE); /* disable full duplex */ - } - - outw(net_diag, ioaddr + WN4_NETDIAG); - pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); - if (el3_debug > 3) - pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_dia= g); - /* Enable link beat and jabber check. */ - outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); - } - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i =3D 0; i < 9; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - - /* Switch to register set 1 for normal use. */ - EL3WINDOW(1); - - /* Accept b-case and phys addr only. */ - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull, - ioaddr + EL3_CMD); - - netif_start_queue(dev); -} - -/* Power Management support functions */ -#ifdef CONFIG_PM - -static int -el3_suspend(struct device *pdev, pm_message_t state) -{ - unsigned long flags; - struct net_device *dev; - struct el3_private *lp; - int ioaddr; - - dev =3D dev_get_drvdata(pdev); - lp =3D netdev_priv(dev); - ioaddr =3D dev->base_addr; - - spin_lock_irqsave(&lp->lock, flags); - - if (netif_running(dev)) - netif_device_detach(dev); - - el3_down(dev); - outw(PowerDown, ioaddr + EL3_CMD); - - spin_unlock_irqrestore(&lp->lock, flags); - return 0; -} - -static int -el3_resume(struct device *pdev) -{ - unsigned long flags; - struct net_device *dev; - struct el3_private *lp; - int ioaddr; - - dev =3D dev_get_drvdata(pdev); - lp =3D netdev_priv(dev); - ioaddr =3D dev->base_addr; - - spin_lock_irqsave(&lp->lock, flags); - - outw(PowerUp, ioaddr + EL3_CMD); - EL3WINDOW(0); - el3_up(dev); - - if (netif_running(dev)) - netif_device_attach(dev); - - spin_unlock_irqrestore(&lp->lock, flags); - return 0; -} - -#endif /* CONFIG_PM */ - -module_param(debug,int, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param(max_interrupt_work, int, 0); -MODULE_PARM_DESC(debug, "debug level (0-6)"); -MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); -MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt= "); -#ifdef CONFIG_PNP -module_param(nopnp, int, 0); -MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)"); -#endif /* CONFIG_PNP */ -MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ether= net driver"); -MODULE_LICENSE("GPL"); - -static int __init el3_init_module(void) -{ - int ret =3D 0; - - if (debug >=3D 0) - el3_debug =3D debug; - -#ifdef CONFIG_PNP - if (!nopnp) { - ret =3D pnp_register_driver(&el3_pnp_driver); - if (!ret) - pnp_registered =3D 1; - } -#endif - /* Select an open I/O location at 0x1*0 to do ISA contention select. */ - /* Start with 0x110 to avoid some sound cards.*/ - for (id_port =3D 0x110 ; id_port < 0x200; id_port +=3D 0x10) { - if (!request_region(id_port, 1, "3c509-control")) - continue; - outb(0x00, id_port); - outb(0xff, id_port); - if (inb(id_port) & 0x01) - break; - else - release_region(id_port, 1); - } - if (id_port >=3D 0x200) { - id_port =3D 0; - pr_err("No I/O port available for 3c509 activation.\n"); - } else { - ret =3D isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS); - if (!ret) - isa_registered =3D 1; - } -#ifdef CONFIG_EISA - ret =3D eisa_driver_register(&el3_eisa_driver); - if (!ret) - eisa_registered =3D 1; -#endif - -#ifdef CONFIG_PNP - if (pnp_registered) - ret =3D 0; -#endif - if (isa_registered) - ret =3D 0; -#ifdef CONFIG_EISA - if (eisa_registered) - ret =3D 0; -#endif - return ret; -} - -static void __exit el3_cleanup_module(void) -{ -#ifdef CONFIG_PNP - if (pnp_registered) - pnp_unregister_driver(&el3_pnp_driver); -#endif - if (isa_registered) - isa_unregister_driver(&el3_isa_driver); - if (id_port) - release_region(id_port, 1); -#ifdef CONFIG_EISA - if (eisa_registered) - eisa_driver_unregister(&el3_eisa_driver); -#endif -} - -module_init (el3_init_module); -module_exit (el3_cleanup_module); diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/= Kconfig index 1fbab79e2be4..c05a1b63c1c9 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -17,20 +17,6 @@ config NET_VENDOR_3COM =20 if NET_VENDOR_3COM =20 -config EL3 - tristate "3c509/3c579 \"EtherLink III\" support" - depends on (ISA || EISA) - help - If you have a network (Ethernet) card belonging to the 3Com - EtherLinkIII series, say Y here. - - If your card is not working you may need to use the DOS - setup disk to disable Plug & Play mode, and to select the default - media type. - - To compile this driver as a module, choose M here. The module - will be called 3c509. - config 3C515 tristate "3c515 ISA \"Fast EtherLink\"" depends on ISA && ISA_DMA_API && !PPC32 diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com= /Makefile index f8b73babc510..f7623fa2d441 100644 --- a/drivers/net/ethernet/3com/Makefile +++ b/drivers/net/ethernet/3com/Makefile @@ -3,7 +3,6 @@ # Makefile for the 3Com Ethernet device drivers # =20 -obj-$(CONFIG_EL3) +=3D 3c509.o obj-$(CONFIG_3C515) +=3D 3c515.o obj-$(CONFIG_PCMCIA_3C589) +=3D 3c589_cs.o obj-$(CONFIG_PCMCIA_3C574) +=3D 3c574_cs.o --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7EE833DCDBC; Tue, 21 Apr 2026 19:31:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799893; cv=none; b=sQTd5/OQHxpcVucxVaEl90o6h+A+Nh6FIqT33UBEeJ6AW0DGGLG9/Gk9pKUkDupqfhNdPee06Vc8xr4JBZ8AwKjGHbnHRpjNhqTjx+gbvwuFQ1QdCd3kINPdXQws3ltCsYvnzmbqQpXNe/8qQ1WRKBqEHSodVmjMusRFqejqQaU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799893; c=relaxed/simple; bh=UyaXHhWsVbEnJzFhshGS5ImAdmwEPyKQ5XTLvu4rCrc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YJjYTPqyDppaDyy9zJl7OKP4YYH4KoVCEkCrnEBKpso61JG6aP/5qqvWunlXY8P1DXYfmCfWbadkOSiVcHCNr2IcwOjP1TJ8/mtSaqnu0szLkabJjN4rvIub2h0QnmcGF67BOm1rIQl3xlUgz8dIlF97XFIpZSqOwYDagEDvcTk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=s0MsWJ41; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="s0MsWJ41" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=BxBYSj1YTrss5QpwzRXm/Y7o8QQj6x0oUHoFLHVKQ6o=; b=s0 MsWJ41B53ktZTft3ym2XHnGVoLF5RQ084groAoyx5uNQwBeJSwOVG1GTzew5qRTTiDirU0HPXCf8O 8OO4w6hhRsjjMlm1x8dIBVwhTysw7SGPNrYJX5FQ4BrWr/m9Kn5M+v0PBkKesH53pxdMpV+m1rtoG DFllB01drNA3FVI=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGoc-00GwVc-3g; Tue, 21 Apr 2026 21:31:22 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:05 -0500 Subject: [PATCH net 02/18] drivers: net: 3com: 3c515: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-2-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=54104; i=andrew@lunn.ch; h=from:subject:message-id; bh=UyaXHhWsVbEnJzFhshGS5ImAdmwEPyKQ5XTLvu4rCrc=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CBuv+QrExCaqwAkRsuTXnVVpFD/4LTazLjI JrNCe7efZiJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hHpZD/93V8R0Oie0hgA8B3+SaFlZdpsD1LRgnULkvy/s6wuEDPltEVgD72wYcs1/UNW70NsXWOb X2nko609lFAijOJz0htxEpjPMQfvbXqtwgPhS8pRuTgku1PC6dtVZetkUCfLMjrAB5mE4rbRsWb SBFQfIqhvqtMgm7NJyl/PbkrGGwLoj3/XVezIXwxXpoKBD9v64A8Xw2dxc4VazXkJAovRMLDUF+ DHC4oCPN5eqks//5+pjuFUueQ25ia1JlYzTFj0k+37b46W+W7ES+2Dtq4nhXmWJ8W32fsR7+4kr WmNVgNMDcwMTPEZxy546DUFreCOpV1vlvhNLR43EgPfz4ELHTxcT7+W3xFDI7Xc+wSnXV55yOK/ t+7G6E51WRHqdK8dDMX2PoYTby1Y1yfY6vMY1WJH4qLOi7oHYFzJ3ndEc0s0B44lzSq6SXVChWo c4MJiYo8/HbY3ZSQawIkx2XJK6QSU8RloVvbOKsZ2UtmCLDY2PaTsUgII+/RNeOxNCBN6FSFYvz MP4HMHX4mOW4CebfJOBodF6Nrm8euT7SBVUPvVBQRJxVHLksOlgiSpHZomLt+I3AZXz834tC6YW G2T0G4J/V2q1/jkKa1a1E2JpBENvfN1SzggP5Vvuif0KCeWbrfoVqAsru1ZIA2m4pipv+HzwWCr RUmpf/6XS/4BG0w== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The 3c515 was written by Donald Becker between 1997-1998. It is an ISA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/3com/3c515.c | 1566 --------------------------------= ---- drivers/net/ethernet/3com/Kconfig | 11 - drivers/net/ethernet/3com/Makefile | 1 - 3 files changed, 1578 deletions(-) diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/= 3c515.c deleted file mode 100644 index 2227c83a4862..000000000000 --- a/drivers/net/ethernet/3com/3c515.c +++ /dev/null @@ -1,1566 +0,0 @@ -/* - Written 1997-1998 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - This driver is for the 3Com ISA EtherLink XL "Corkscrew" 3c515 ethercard. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - - 2000/2/2- Added support for kernel-level ISAPnP - by Stephen Frost and Alessandro Zummo - Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox. - - 2001/11/17 - Added ethtool support (jgarzik) - - 2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk) - -*/ - -#define DRV_NAME "3c515" - -#define CORKSCREW 1 - -/* "Knobs" that adjust features and parameters. */ -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1512 effectively disables this feature. */ -static int rx_copybreak =3D 200; - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work =3D 20; - -/* Enable the automatic media selection code -- usually set. */ -#define AUTOMEDIA 1 - -/* Allow the use of fragment bus master transfers instead of only - programmed-I/O for Vortex cards. Full-bus-master transfers are always - enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined, - the feature may be turned on using 'options'. */ -#define VORTEX_BUS_MASTER - -/* A few values that may be tweaked. */ -/* Keep the ring sizes a power of two for efficiency. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 16 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#define NEW_MULTICAST -#include - -#define MAX_UNITS 8 - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver"); -MODULE_LICENSE("GPL"); - -/* "Knobs" for adjusting internal parameters. */ -/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs).= */ -#define DRIVER_DEBUG 1 -/* Some values here only for performance evaluation and path-coverage - debugging. */ -static int rx_nocopy, rx_copy, queued_packet; - -/* Number of times to check to see if the Tx FIFO has space, used in some - limited cases. */ -#define WAIT_TX_AVAIL 200 - -/* Operational parameter that usually are not changed. */ -#define TX_TIMEOUT ((4*HZ)/10) /* Time in jiffies before concluding Tx hu= ng */ - -/* The size here is somewhat misleading: the Corkscrew also uses the ISA - aliased registers at +0x400. - */ -#define CORKSCREW_TOTAL_SIZE 0x20 - -#ifdef DRIVER_DEBUG -static int corkscrew_debug =3D DRIVER_DEBUG; -#else -static int corkscrew_debug =3D 1; -#endif - -#define CORKSCREW_ID 10 - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the 3Com 3c515 ISA Fast EtherLink XL, -3Com's ISA bus adapter for Fast Ethernet. Due to the unique I/O port layo= ut, -it's not practical to integrate this driver with the other EtherLink drive= rs. - -II. Board-specific settings - -The Corkscrew has an EEPROM for configuration, but no special settings are -needed for Linux. - -III. Driver operation - -The 3c515 series use an interface that's very similar to the 3c900 "Boomer= ang" -PCI cards, with the bus master interface extensively modified to work with -the ISA bus. - -The card is capable of full-bus-master transfers with separate -lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet, -DEC Tulip and Intel Speedo3. - -This driver uses a "RX_COPYBREAK" scheme rather than a fixed intermediate -receive buffer. This scheme allocates full-sized skbuffs as receive -buffers. The value RX_COPYBREAK is used as the copying breakpoint: it is -chosen to trade-off the memory wasted by passing the full-sized skbuff to -the queue layer for all frames vs. the copying cost of copying a frame to a -correctly-sized skbuff. - - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the netif -layer. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -IV. Notes - -Thanks to Terry Murphy of 3Com for providing documentation and a developme= nt -board. - -The names "Vortex", "Boomerang" and "Corkscrew" are the internal 3Com -project names. I use these names to eliminate confusion -- 3Com product -numbers and names are very similar and often confused. - -The new chips support both ethernet (1.5K) and FDDI (4.5K) frame sizes! -This driver only supports ethernet frames because of the recent MTU limit -of 1.5K, but the changes to support 4.5K are minimal. -*/ - -/* Operational definitions. - These are not used by other compilation units and thus are not - exported in a ".h" file. - - First the windows. There are eight register windows, with the command - and status registers available in each. - */ -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. - Note that 11 parameters bits was fine for ethernet, but the new chips - can handle FDDI length frames (~4500 octets) and now parameters count - 32-bit 'Dwords' rather than octets. */ - -enum corkscrew_cmd { - TotalReset =3D 0 << 11, SelectWindow =3D 1 << 11, StartCoax =3D 2 << 11, - RxDisable =3D 3 << 11, RxEnable =3D 4 << 11, RxReset =3D 5 << 11, - UpStall =3D 6 << 11, UpUnstall =3D (6 << 11) + 1, DownStall =3D (6 << 11)= + 2, - DownUnstall =3D (6 << 11) + 3, RxDiscard =3D 8 << 11, TxEnable =3D 9 << 1= 1, - TxDisable =3D 10 << 11, TxReset =3D 11 << 11, FakeIntr =3D 12 << 11, - AckIntr =3D 13 << 11, SetIntrEnb =3D 14 << 11, SetStatusEnb =3D 15 << 11, - SetRxFilter =3D 16 << 11, SetRxThreshold =3D 17 << 11, - SetTxThreshold =3D 18 << 11, SetTxStart =3D 19 << 11, StartDMAUp =3D 20 <= < 11, - StartDMADown =3D (20 << 11) + 1, StatsEnable =3D 21 << 11, - StatsDisable =3D 22 << 11, StopCoax =3D 23 << 11, -}; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation =3D 1, RxMulticast =3D 2, RxBroadcast =3D 4, RxProm =3D 8 -}; - -/* Bits in the general status register. */ -enum corkscrew_status { - IntLatch =3D 0x0001, AdapterFailure =3D 0x0002, TxComplete =3D 0x0004, - TxAvailable =3D 0x0008, RxComplete =3D 0x0010, RxEarly =3D 0x0020, - IntReq =3D 0x0040, StatsFull =3D 0x0080, - DMADone =3D 1 << 8, DownComplete =3D 1 << 9, UpComplete =3D 1 << 10, - DMAInProgress =3D 1 << 11, /* DMA controller is still busy. */ - CmdInProgress =3D 1 << 12, /* EL3_CMD is still busy. */ -}; - -/* Register window 1 offsets, the window used in normal operation. - On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */ -enum Window1 { - TX_FIFO =3D 0x10, RX_FIFO =3D 0x10, RxErrors =3D 0x14, - RxStatus =3D 0x18, Timer =3D 0x1A, TxStatus =3D 0x1B, - TxFree =3D 0x1C, /* Remaining free bytes in Tx buffer. */ -}; -enum Window0 { - Wn0IRQ =3D 0x08, -#if defined(CORKSCREW) - Wn0EepromCmd =3D 0x200A, /* Corkscrew EEPROM command register. */ - Wn0EepromData =3D 0x200C, /* Corkscrew EEPROM results register. */ -#else - Wn0EepromCmd =3D 10, /* Window 0: EEPROM command register. */ - Wn0EepromData =3D 12, /* Window 0: EEPROM results register. */ -#endif -}; -enum Win0_EEPROM_bits { - EEPROM_Read =3D 0x80, EEPROM_WRITE =3D 0x40, EEPROM_ERASE =3D 0xC0, - EEPROM_EWENB =3D 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS =3D 0x00, /* Disable EWENB before 10 msec timeout. */ -}; - -/* EEPROM locations. */ -enum eeprom_offset { - PhysAddr01 =3D 0, PhysAddr23 =3D 1, PhysAddr45 =3D 2, ModelID =3D 3, - EtherLink3ID =3D 7, -}; - -enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config =3D 0, Wn3_MAC_Ctrl =3D 6, Wn3_Options =3D 8, -}; -enum wn3_config { - Ram_size =3D 7, - Ram_width =3D 8, - Ram_speed =3D 0x30, - Rom_size =3D 0xc0, - Ram_split_shift =3D 16, - Ram_split =3D 3 << Ram_split_shift, - Xcvr_shift =3D 20, - Xcvr =3D 7 << Xcvr_shift, - Autoselect =3D 0x1000000, -}; - -enum Window4 { - Wn4_NetDiag =3D 6, Wn4_Media =3D 10, /* Window 4: Xcvr/media bits. */ -}; -enum Win4_Media_bits { - Media_SQE =3D 0x0008, /* Enable SQE error counting for AUI. */ - Media_10TP =3D 0x00C0, /* Enable link beat and jabber for 10baseT. */ - Media_Lnk =3D 0x0080, /* Enable just link beat for 100TX/100FX. */ - Media_LnkBeat =3D 0x0800, -}; -enum Window7 { /* Window 7: Bus Master control. */ - Wn7_MasterAddr =3D 0, Wn7_MasterLen =3D 6, Wn7_MasterStatus =3D 12, -}; - -/* Boomerang-style bus master control registers. Note ISA aliases! */ -enum MasterCtrl { - PktStatus =3D 0x400, DownListPtr =3D 0x404, FragAddr =3D 0x408, FragLen = =3D - 0x40c, - TxFreeThreshold =3D 0x40f, UpPktStatus =3D 0x410, UpListPtr =3D 0x418, -}; - -/* The Rx and Tx descriptor lists. - Caution Alpha hackers: these types are 32 bits! Note also the 8 byte - alignment contraint on tx_ring[] and rx_ring[]. */ -struct boom_rx_desc { - u32 next; - s32 status; - u32 addr; - s32 length; -}; - -/* Values for the Rx status entry. */ -enum rx_desc_status { - RxDComplete =3D 0x00008000, RxDError =3D 0x4000, - /* See boomerang_rx() for actual error bits */ -}; - -struct boom_tx_desc { - u32 next; - s32 status; - u32 addr; - s32 length; -}; - -struct corkscrew_private { - const char *product_name; - struct list_head list; - struct net_device *our_dev; - /* The Rx and Tx rings are here to keep them quad-word-aligned. */ - struct boom_rx_desc rx_ring[RX_RING_SIZE]; - struct boom_tx_desc tx_ring[TX_RING_SIZE]; - /* The addresses of transmit- and receive-in-place skbuffs. */ - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */ - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ - struct timer_list timer; /* Media selection timer. */ - int capabilities ; /* Adapter capabilities word. */ - int options; /* User-settable misc. driver options. */ - int last_rx_packets; /* For media autoselection. */ - unsigned int available_media:8, /* From Wn3_Options */ - media_override:3, /* Passed-in media type. */ - default_media:3, /* Read from the EEPROM. */ - full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragm= ent bus-m. */ - full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */ - tx_full:1; - spinlock_t lock; - struct device *dev; -}; - -/* The action to take with a media selection timer tick. - Note that we deviate from the 3Com order by checking 10base2 before AUI. - */ -enum xcvr_types { - XCVR_10baseT =3D 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100bas= eTx, - XCVR_100baseFx, XCVR_MII =3D 6, XCVR_Default =3D 8, -}; - -static struct media_table { - char *name; - unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ - mask:8, /* The transceiver-present bit in Wn3_Config. */ - next:8; /* The media type to try next. */ - short wait; /* Time before we check media status. */ -} media_tbl[] =3D { - { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 }, - { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10}, - { "undefined", 0, 0x80, XCVR_10baseT, 10000}, - { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10}, - { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10}, - { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10}, - { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ}, - { "undefined", 0, 0x01, XCVR_10baseT, 10000}, - { "Default", 0, 0xFF, XCVR_10baseT, 10000}, -}; - -#ifdef __ISAPNP__ -static struct isapnp_device_id corkscrew_isapnp_adapters[] =3D { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), - (long) "3Com Fast EtherLink ISA" }, - { } /* terminate list */ -}; - -MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters); - -static int nopnp; -#endif /* __ISAPNP__ */ - -static struct net_device *corkscrew_scan(int unit); -static int corkscrew_setup(struct net_device *dev, int ioaddr, - struct pnp_dev *idev, int card_number); -static int corkscrew_open(struct net_device *dev); -static void corkscrew_timer(struct timer_list *t); -static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int corkscrew_rx(struct net_device *dev); -static void corkscrew_timeout(struct net_device *dev, unsigned int txqueue= ); -static int boomerang_rx(struct net_device *dev); -static irqreturn_t corkscrew_interrupt(int irq, void *dev_id); -static int corkscrew_close(struct net_device *dev); -static void update_stats(int addr, struct net_device *dev); -static struct net_device_stats *corkscrew_get_stats(struct net_device *dev= ); -static void set_rx_mode(struct net_device *dev); -static const struct ethtool_ops netdev_ethtool_ops; - - -/* - Unfortunately maximizing the shared code between the integrated and - module version of the driver results in a complicated set of initializa= tion - procedures. - init_module() -- modules / tc59x_init() -- built-in - The wrappers for corkscrew_scan() - corkscrew_scan() The common routine that scans for PCI and EISA car= ds - corkscrew_found_device() Allocate a device structure when we find a car= d. - Different versions exist for modules and built-in. - corkscrew_probe1() Fill in the device structure -- this is separated - so that the modules code can put it in dev->init. -*/ -/* This driver uses 'options' to pass the media type, full-duplex flag, et= c. */ -/* Note: this is the only limit on the number of cards supported!! */ -static int options[MAX_UNITS] =3D { -1, -1, -1, -1, -1, -1, -1, -1, }; - -#ifdef MODULE -static int debug =3D -1; - -module_param(debug, int, 0); -module_param_array(options, int, NULL, 0); -module_param(rx_copybreak, int, 0); -module_param(max_interrupt_work, int, 0); -MODULE_PARM_DESC(debug, "3c515 debug level (0-6)"); -MODULE_PARM_DESC(options, "3c515: Bits 0-2: media type, bit 3: full duplex= , bit 4: bus mastering"); -MODULE_PARM_DESC(rx_copybreak, "3c515 copy breakpoint for copy-only-tiny-f= rames"); -MODULE_PARM_DESC(max_interrupt_work, "3c515 maximum events handled per int= errupt"); - -/* A list of all installed Vortex devices, for removing the driver module.= */ -/* we will need locking (and refcounting) if we ever use it for more */ -static LIST_HEAD(root_corkscrew_dev); - -static int corkscrew_init_module(void) -{ - int found =3D 0; - if (debug >=3D 0) - corkscrew_debug =3D debug; - while (corkscrew_scan(-1)) - found++; - return found ? 0 : -ENODEV; -} -module_init(corkscrew_init_module); - -#else -struct net_device *tc515_probe(int unit) -{ - struct net_device *dev =3D corkscrew_scan(unit); - - if (!dev) - return ERR_PTR(-ENODEV); - - return dev; -} -#endif /* not MODULE */ - -static int check_device(unsigned ioaddr) -{ - int timer; - - if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515")) - return 0; - /* Check the resource configuration for a matching ioaddr. */ - if ((inw(ioaddr + 0x2002) & 0x1f0) !=3D (ioaddr & 0x1f0)) { - release_region(ioaddr, CORKSCREW_TOTAL_SIZE); - return 0; - } - /* Verify by reading the device ID from the EEPROM. */ - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer =3D 4; timer >=3D 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) =3D=3D 0) - break; - } - if (inw(ioaddr + Wn0EepromData) !=3D 0x6d50) { - release_region(ioaddr, CORKSCREW_TOTAL_SIZE); - return 0; - } - return 1; -} - -static void cleanup_card(struct net_device *dev) -{ - struct corkscrew_private *vp =3D netdev_priv(dev); - list_del_init(&vp->list); - if (dev->dma) - free_dma(dev->dma); - outw(TotalReset, dev->base_addr + EL3_CMD); - release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE); - if (vp->dev) - pnp_device_detach(to_pnp_dev(vp->dev)); -} - -static struct net_device *corkscrew_scan(int unit) -{ - struct net_device *dev; - static int cards_found =3D 0; - static int ioaddr; - int err; -#ifdef __ISAPNP__ - short i; - static int pnp_cards; -#endif - - dev =3D alloc_etherdev(sizeof(struct corkscrew_private)); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >=3D 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - -#ifdef __ISAPNP__ - if(nopnp =3D=3D 1) - goto no_pnp; - for(i=3D0; corkscrew_isapnp_adapters[i].vendor !=3D 0; i++) { - struct pnp_dev *idev =3D NULL; - int irq; - while((idev =3D pnp_find_dev(NULL, - corkscrew_isapnp_adapters[i].vendor, - corkscrew_isapnp_adapters[i].function, - idev))) { - - if (pnp_device_attach(idev) < 0) - continue; - if (pnp_activate_dev(idev) < 0) { - pr_warn("pnp activate failed (out of resources?)\n"); - pnp_device_detach(idev); - continue; - } - if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) { - pnp_device_detach(idev); - continue; - } - ioaddr =3D pnp_port_start(idev, 0); - irq =3D pnp_irq(idev, 0); - if (!check_device(ioaddr)) { - pnp_device_detach(idev); - continue; - } - if(corkscrew_debug) - pr_debug("ISAPNP reports %s at i/o 0x%x, irq %d\n", - (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); - pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", - inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - /* irq =3D inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ - SET_NETDEV_DEV(dev, &idev->dev); - pnp_cards++; - err =3D corkscrew_setup(dev, ioaddr, idev, cards_found++); - if (!err) - return dev; - cleanup_card(dev); - } - } -no_pnp: -#endif /* __ISAPNP__ */ - - /* Check all locations on the ISA bus -- evil! */ - for (ioaddr =3D 0x100; ioaddr < 0x400; ioaddr +=3D 0x20) { - if (!check_device(ioaddr)) - continue; - - pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", - inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - err =3D corkscrew_setup(dev, ioaddr, NULL, cards_found++); - if (!err) - return dev; - cleanup_card(dev); - } - free_netdev(dev); - return NULL; -} - - -static const struct net_device_ops netdev_ops =3D { - .ndo_open =3D corkscrew_open, - .ndo_stop =3D corkscrew_close, - .ndo_start_xmit =3D corkscrew_start_xmit, - .ndo_tx_timeout =3D corkscrew_timeout, - .ndo_get_stats =3D corkscrew_get_stats, - .ndo_set_rx_mode =3D set_rx_mode, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - - -static int corkscrew_setup(struct net_device *dev, int ioaddr, - struct pnp_dev *idev, int card_number) -{ - struct corkscrew_private *vp =3D netdev_priv(dev); - unsigned int eeprom[0x40], checksum =3D 0; /* EEPROM contents */ - __be16 addr[ETH_ALEN / 2]; - int i; - int irq; - -#ifdef __ISAPNP__ - if (idev) { - irq =3D pnp_irq(idev, 0); - vp->dev =3D &idev->dev; - } else { - irq =3D inw(ioaddr + 0x2002) & 15; - } -#else - irq =3D inw(ioaddr + 0x2002) & 15; -#endif - - dev->base_addr =3D ioaddr; - dev->irq =3D irq; - dev->dma =3D inw(ioaddr + 0x2000) & 7; - vp->product_name =3D "3c515"; - vp->options =3D dev->mem_start; - vp->our_dev =3D dev; - - if (!vp->options) { - if (card_number >=3D MAX_UNITS) - vp->options =3D -1; - else - vp->options =3D options[card_number]; - } - - if (vp->options >=3D 0) { - vp->media_override =3D vp->options & 7; - if (vp->media_override =3D=3D 2) - vp->media_override =3D 0; - vp->full_duplex =3D (vp->options & 8) ? 1 : 0; - vp->bus_master =3D (vp->options & 16) ? 1 : 0; - } else { - vp->media_override =3D 7; - vp->full_duplex =3D 0; - vp->bus_master =3D 0; - } -#ifdef MODULE - list_add(&vp->list, &root_corkscrew_dev); -#endif - - pr_info("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); - - spin_lock_init(&vp->lock); - - timer_setup(&vp->timer, corkscrew_timer, 0); - - /* Read the station address from the EEPROM. */ - EL3WINDOW(0); - for (i =3D 0; i < 0x18; i++) { - int timer; - outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer =3D 4; timer >=3D 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) =3D=3D 0) - break; - } - eeprom[i] =3D inw(ioaddr + Wn0EepromData); - checksum ^=3D eeprom[i]; - if (i < 3) - addr[i] =3D htons(eeprom[i]); - } - eth_hw_addr_set(dev, (u8 *)addr); - checksum =3D (checksum ^ (checksum >> 8)) & 0xff; - if (checksum !=3D 0x00) - pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); - pr_cont(" %pM", dev->dev_addr); - if (eeprom[16] =3D=3D 0x11c7) { /* Corkscrew */ - if (request_dma(dev->dma, "3c515")) { - pr_cont(", DMA %d allocation failed", dev->dma); - dev->dma =3D 0; - } else - pr_cont(", DMA %d", dev->dma); - } - pr_cont(", IRQ %d\n", dev->irq); - /* Tell them about an invalid IRQ. */ - if (corkscrew_debug && (dev->irq <=3D 0 || dev->irq > 15)) - pr_warn(" *** Warning: this IRQ is unlikely to work! ***\n"); - - { - static const char * const ram_split[] =3D { - "5:3", "3:1", "1:1", "3:5" - }; - __u32 config; - EL3WINDOW(3); - vp->available_media =3D inw(ioaddr + Wn3_Options); - config =3D inl(ioaddr + Wn3_Config); - if (corkscrew_debug > 1) - pr_info(" Internal config register is %4.4x, transceivers %#x.\n", - config, inw(ioaddr + Wn3_Options)); - pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << config & Ram_size, - config & Ram_width ? "word" : "byte", - ram_split[(config & Ram_split) >> Ram_split_shift], - config & Autoselect ? "autoselect/" : "", - media_tbl[(config & Xcvr) >> Xcvr_shift].name); - vp->default_media =3D (config & Xcvr) >> Xcvr_shift; - vp->autoselect =3D config & Autoselect ? 1 : 0; - dev->if_port =3D vp->default_media; - } - if (vp->media_override !=3D 7) { - pr_info(" Media override to transceiver type %d (%s).\n", - vp->media_override, - media_tbl[vp->media_override].name); - dev->if_port =3D vp->media_override; - } - - vp->capabilities =3D eeprom[16]; - vp->full_bus_master_tx =3D (vp->capabilities & 0x20) ? 1 : 0; - /* Rx is broken at 10mbps, so we always disable it. */ - /* vp->full_bus_master_rx =3D 0; */ - vp->full_bus_master_rx =3D (vp->capabilities & 0x20) ? 1 : 0; - - /* The 3c51x-specific entries in the device structure. */ - dev->netdev_ops =3D &netdev_ops; - dev->watchdog_timeo =3D (400 * HZ) / 1000; - dev->ethtool_ops =3D &netdev_ethtool_ops; - - return register_netdev(dev); -} - - -static int corkscrew_open(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - struct corkscrew_private *vp =3D netdev_priv(dev); - bool armtimer =3D false; - __u32 config; - int i; - - /* Before initializing select the active media port. */ - EL3WINDOW(3); - if (vp->full_duplex) - outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ - config =3D inl(ioaddr + Wn3_Config); - - if (vp->media_override !=3D 7) { - if (corkscrew_debug > 1) - pr_info("%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); - dev->if_port =3D vp->media_override; - } else if (vp->autoselect) { - /* Find first available media type, starting with 100baseTx. */ - dev->if_port =3D 4; - while (!(vp->available_media & media_tbl[dev->if_port].mask)) - dev->if_port =3D media_tbl[dev->if_port].next; - - if (corkscrew_debug > 1) - pr_debug("%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); - armtimer =3D true; - } else - dev->if_port =3D vp->default_media; - - config =3D (config & ~Xcvr) | (dev->if_port << Xcvr_shift); - outl(config, ioaddr + Wn3_Config); - - if (corkscrew_debug > 1) { - pr_debug("%s: corkscrew_open() InternalConfig %8.8x.\n", - dev->name, config); - } - - outw(TxReset, ioaddr + EL3_CMD); - for (i =3D 20; i >=3D 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - - outw(RxReset, ioaddr + EL3_CMD); - /* Wait a few ticks for the RxReset command to complete. */ - for (i =3D 20; i >=3D 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - - outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - - /* Use the now-standard shared IRQ implementation. */ - if (vp->capabilities =3D=3D 0x11c7) { - /* Corkscrew: Cannot share ISA resources. */ - if (dev->irq =3D=3D 0 || - dev->dma =3D=3D 0 || - request_irq(dev->irq, corkscrew_interrupt, 0, - vp->product_name, dev)) - return -EAGAIN; - enable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - } else if (request_irq(dev->irq, corkscrew_interrupt, IRQF_SHARED, - vp->product_name, dev)) { - return -EAGAIN; - } - - if (armtimer) - mod_timer(&vp->timer, jiffies + media_tbl[dev->if_port].wait); - - if (corkscrew_debug > 1) { - EL3WINDOW(4); - pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + Wn4_Media)); - } - - /* Set the station address and mask in window 2 each time opened. */ - EL3WINDOW(2); - for (i =3D 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - for (; i < 12; i +=3D 2) - outw(0, ioaddr + i); - - if (dev->if_port =3D=3D 3) - /* Start the thinnet transceiver. We should really wait 50ms... */ - outw(StartCoax, ioaddr + EL3_CMD); - EL3WINDOW(4); - outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i =3D 0; i < 10; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - /* New: On the Vortex we must also clear the BadSSD counter. */ - EL3WINDOW(4); - inb(ioaddr + 12); - /* ..and on the Boomerang we enable the extra statistics bits. */ - outw(0x0040, ioaddr + Wn4_NetDiag); - - /* Switch to register set 7 for normal use. */ - EL3WINDOW(7); - - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ - vp->cur_rx =3D vp->dirty_rx =3D 0; - if (corkscrew_debug > 2) - pr_debug("%s: Filling in the Rx ring.\n", dev->name); - for (i =3D 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - if (i < (RX_RING_SIZE - 1)) - vp->rx_ring[i].next =3D - isa_virt_to_bus(&vp->rx_ring[i + 1]); - else - vp->rx_ring[i].next =3D 0; - vp->rx_ring[i].status =3D 0; /* Clear complete bit. */ - vp->rx_ring[i].length =3D PKT_BUF_SZ | 0x80000000; - skb =3D netdev_alloc_skb(dev, PKT_BUF_SZ); - vp->rx_skbuff[i] =3D skb; - if (skb =3D=3D NULL) - break; /* Bad news! */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr =3D isa_virt_to_bus(skb->data); - } - if (i !=3D 0) - vp->rx_ring[i - 1].next =3D - isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ - outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); - } - if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ - vp->cur_tx =3D vp->dirty_tx =3D 0; - outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold); /* Room for a packet. */ - /* Clear the Tx ring. */ - for (i =3D 0; i < TX_RING_SIZE; i++) - vp->tx_skbuff[i] =3D NULL; - outl(0, ioaddr + DownListPtr); - } - /* Set receiver mode: presumably accept b-case and phys addr only. */ - set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - netif_start_queue(dev); - - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull | - (vp->full_bus_master_tx ? DownComplete : TxAvailable) | - (vp->full_bus_master_rx ? UpComplete : RxComplete) | - (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete, - ioaddr + EL3_CMD); - - return 0; -} - -static void corkscrew_timer(struct timer_list *t) -{ -#ifdef AUTOMEDIA - struct corkscrew_private *vp =3D timer_container_of(vp, t, timer); - struct net_device *dev =3D vp->our_dev; - int ioaddr =3D dev->base_addr; - unsigned long flags; - int ok =3D 0; - - if (corkscrew_debug > 1) - pr_debug("%s: Media selection timer tick happened, %s.\n", - dev->name, media_tbl[dev->if_port].name); - - spin_lock_irqsave(&vp->lock, flags); - - { - int old_window =3D inw(ioaddr + EL3_CMD) >> 13; - int media_status; - EL3WINDOW(4); - media_status =3D inw(ioaddr + Wn4_Media); - switch (dev->if_port) { - case 0: - case 4: - case 5: /* 10baseT, 100baseTX, 100baseFX */ - if (media_status & Media_LnkBeat) { - ok =3D 1; - if (corkscrew_debug > 1) - pr_debug("%s: Media %s has link beat, %x.\n", - dev->name, - media_tbl[dev->if_port].name, - media_status); - } else if (corkscrew_debug > 1) - pr_debug("%s: Media %s is has no link beat, %x.\n", - dev->name, - media_tbl[dev->if_port].name, - media_status); - - break; - default: /* Other media types handled by Tx timeouts. */ - if (corkscrew_debug > 1) - pr_debug("%s: Media %s is has no indication, %x.\n", - dev->name, - media_tbl[dev->if_port].name, - media_status); - ok =3D 1; - } - if (!ok) { - __u32 config; - - do { - dev->if_port =3D - media_tbl[dev->if_port].next; - } - while (!(vp->available_media & media_tbl[dev->if_port].mask)); - - if (dev->if_port =3D=3D 8) { /* Go back to default. */ - dev->if_port =3D vp->default_media; - if (corkscrew_debug > 1) - pr_debug("%s: Media selection failing, using default %s port.\n", - dev->name, - media_tbl[dev->if_port].name); - } else { - if (corkscrew_debug > 1) - pr_debug("%s: Media selection failed, now trying %s port.\n", - dev->name, - media_tbl[dev->if_port].name); - vp->timer.expires =3D jiffies + media_tbl[dev->if_port].wait; - add_timer(&vp->timer); - } - outw((media_status & ~(Media_10TP | Media_SQE)) | - media_tbl[dev->if_port].media_bits, - ioaddr + Wn4_Media); - - EL3WINDOW(3); - config =3D inl(ioaddr + Wn3_Config); - config =3D (config & ~Xcvr) | (dev->if_port << Xcvr_shift); - outl(config, ioaddr + Wn3_Config); - - outw(dev->if_port =3D=3D 3 ? StartCoax : StopCoax, - ioaddr + EL3_CMD); - } - EL3WINDOW(old_window); - } - - spin_unlock_irqrestore(&vp->lock, flags); - if (corkscrew_debug > 1) - pr_debug("%s: Media selection timer finished, %s.\n", - dev->name, media_tbl[dev->if_port].name); - -#endif /* AUTOMEDIA */ -} - -static void corkscrew_timeout(struct net_device *dev, unsigned int txqueue) -{ - int i; - struct corkscrew_private *vp =3D netdev_priv(dev); - int ioaddr =3D dev->base_addr; - - pr_warn("%s: transmit timed out, tx_status %2.2x status %4.4x\n", - dev->name, inb(ioaddr + TxStatus), - inw(ioaddr + EL3_STATUS)); - /* Slight code bloat to be user friendly. */ - if ((inb(ioaddr + TxStatus) & 0x88) =3D=3D 0x88) - pr_warn("%s: Transmitter encountered 16 collisions -- network cable prob= lem?\n", - dev->name); -#ifndef final_version - pr_debug(" Flags; bus-master %d, full %d; dirty %d current %d.\n", - vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, - vp->cur_tx); - pr_debug(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), - &vp->tx_ring[0]); - for (i =3D 0; i < TX_RING_SIZE; i++) { - pr_debug(" %d: %p length %8.8x status %8.8x\n", i, - &vp->tx_ring[i], - vp->tx_ring[i].length, vp->tx_ring[i].status); - } -#endif - /* Issue TX_RESET and TX_START commands. */ - outw(TxReset, ioaddr + EL3_CMD); - for (i =3D 20; i >=3D 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - outw(TxEnable, ioaddr + EL3_CMD); - netif_trans_update(dev); /* prevent tx timeout */ - dev->stats.tx_errors++; - dev->stats.tx_dropped++; - netif_wake_queue(dev); -} - -static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct corkscrew_private *vp =3D netdev_priv(dev); - int ioaddr =3D dev->base_addr; - - /* Block a timer-based transmit from overlapping. */ - - netif_stop_queue(dev); - - if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */ - /* Calculate the next Tx descriptor entry. */ - int entry =3D vp->cur_tx % TX_RING_SIZE; - struct boom_tx_desc *prev_entry; - unsigned long flags; - int i; - - if (vp->tx_full) /* No room to transmit with */ - return NETDEV_TX_BUSY; - if (vp->cur_tx !=3D 0) - prev_entry =3D &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE]; - else - prev_entry =3D NULL; - if (corkscrew_debug > 3) - pr_debug("%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); - /* vp->tx_full =3D 1; */ - vp->tx_skbuff[entry] =3D skb; - vp->tx_ring[entry].next =3D 0; - vp->tx_ring[entry].addr =3D isa_virt_to_bus(skb->data); - vp->tx_ring[entry].length =3D skb->len | 0x80000000; - vp->tx_ring[entry].status =3D skb->len | 0x80000000; - - spin_lock_irqsave(&vp->lock, flags); - outw(DownStall, ioaddr + EL3_CMD); - /* Wait for the stall to complete. */ - for (i =3D 20; i >=3D 0; i--) - if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) =3D=3D 0) - break; - if (prev_entry) - prev_entry->next =3D isa_virt_to_bus(&vp->tx_ring[entry]); - if (inl(ioaddr + DownListPtr) =3D=3D 0) { - outl(isa_virt_to_bus(&vp->tx_ring[entry]), - ioaddr + DownListPtr); - queued_packet++; - } - outw(DownUnstall, ioaddr + EL3_CMD); - spin_unlock_irqrestore(&vp->lock, flags); - - vp->cur_tx++; - if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) - vp->tx_full =3D 1; - else { /* Clear previous interrupt enable. */ - if (prev_entry) - prev_entry->status &=3D ~0x80000000; - netif_wake_queue(dev); - } - return NETDEV_TX_OK; - } - /* Put out the doubleword header... */ - outl(skb->len, ioaddr + TX_FIFO); - dev->stats.tx_bytes +=3D skb->len; -#ifdef VORTEX_BUS_MASTER - if (vp->bus_master) { - /* Set the bus-master controller to transfer the packet. */ - outl(isa_virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr); - outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); - vp->tx_skb =3D skb; - outw(StartDMADown, ioaddr + EL3_CMD); - /* queue will be woken at the DMADone interrupt. */ - } else { - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb(skb); - if (inw(ioaddr + TxFree) > 1536) { - netif_wake_queue(dev); - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536 >> 2), - ioaddr + EL3_CMD); - } -#else - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb(skb); - if (inw(ioaddr + TxFree) > 1536) { - netif_wake_queue(dev); - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD); -#endif /* bus master */ - - - /* Clear the Tx status stack. */ - { - short tx_status; - int i =3D 4; - - while (--i > 0 && (tx_status =3D inb(ioaddr + TxStatus)) > 0) { - if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ - if (corkscrew_debug > 2) - pr_debug("%s: Tx error, status %2.2x.\n", - dev->name, tx_status); - if (tx_status & 0x04) - dev->stats.tx_fifo_errors++; - if (tx_status & 0x38) - dev->stats.tx_aborted_errors++; - if (tx_status & 0x30) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j =3D 20; j >=3D 0; j--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - } - outw(TxEnable, ioaddr + EL3_CMD); - } - outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ - } - } - return NETDEV_TX_OK; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ - -static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) -{ - /* Use the now-standard shared IRQ implementation. */ - struct net_device *dev =3D dev_id; - struct corkscrew_private *lp =3D netdev_priv(dev); - int ioaddr, status; - int latency; - int i =3D max_interrupt_work; - - ioaddr =3D dev->base_addr; - latency =3D inb(ioaddr + Timer); - - spin_lock(&lp->lock); - - status =3D inw(ioaddr + EL3_STATUS); - - if (corkscrew_debug > 4) - pr_debug("%s: interrupt, status %4.4x, timer %d.\n", - dev->name, status, latency); - if ((status & 0xE000) !=3D 0xE000) { - static int donedidthis; - /* Some interrupt controllers store a bogus interrupt from boot-time. - Ignore a single early interrupt, but don't hang the machine for - other interrupt problems. */ - if (donedidthis++ > 100) { - pr_err("%s: Bogus interrupt, bailing. Status %4.4x, start=3D%d.\n", - dev->name, status, netif_running(dev)); - free_irq(dev->irq, dev); - dev->irq =3D -1; - } - } - - do { - if (corkscrew_debug > 5) - pr_debug("%s: In interrupt loop, status %4.4x.\n", - dev->name, status); - if (status & RxComplete) - corkscrew_rx(dev); - - if (status & TxAvailable) { - if (corkscrew_debug > 5) - pr_debug(" TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); - } - if (status & DownComplete) { - unsigned int dirty_tx =3D lp->dirty_tx; - - while (lp->cur_tx - dirty_tx > 0) { - int entry =3D dirty_tx % TX_RING_SIZE; - if (inl(ioaddr + DownListPtr) =3D=3D isa_virt_to_bus(&lp->tx_ring[entr= y])) - break; /* It still hasn't been processed. */ - if (lp->tx_skbuff[entry]) { - dev_consume_skb_irq(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] =3D NULL; - } - dirty_tx++; - } - lp->dirty_tx =3D dirty_tx; - outw(AckIntr | DownComplete, ioaddr + EL3_CMD); - if (lp->tx_full && (lp->cur_tx - dirty_tx <=3D TX_RING_SIZE - 1)) { - lp->tx_full =3D 0; - netif_wake_queue(dev); - } - } -#ifdef VORTEX_BUS_MASTER - if (status & DMADone) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - dev_consume_skb_irq(lp->tx_skb); /* Release the transferred buffer */ - netif_wake_queue(dev); - } -#endif - if (status & UpComplete) { - boomerang_rx(dev); - outw(AckIntr | UpComplete, ioaddr + EL3_CMD); - } - if (status & (AdapterFailure | RxEarly | StatsFull)) { - /* Handle all uncommon interrupts at once. */ - if (status & RxEarly) { /* Rx early is unused. */ - corkscrew_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & StatsFull) { /* Empty statistics. */ - static int DoneDidThat; - if (corkscrew_debug > 4) - pr_debug("%s: Updating stats.\n", dev->name); - update_stats(ioaddr, dev); - /* DEBUG HACK: Disable statistics as an interrupt source. */ - /* This occurs when we have the wrong media type! */ - if (DoneDidThat =3D=3D 0 && inw(ioaddr + EL3_STATUS) & StatsFull) { - int win, reg; - pr_notice("%s: Updating stats failed, disabling stats as an interrupt= source.\n", - dev->name); - for (win =3D 0; win < 8; win++) { - EL3WINDOW(win); - pr_notice("Vortex window %d:", win); - for (reg =3D 0; reg < 16; reg++) - pr_cont(" %2.2x", inb(ioaddr + reg)); - pr_cont("\n"); - } - EL3WINDOW(7); - outw(SetIntrEnb | TxAvailable | - RxComplete | AdapterFailure | - UpComplete | DownComplete | - TxComplete, ioaddr + EL3_CMD); - DoneDidThat++; - } - } - if (status & AdapterFailure) { - /* Adapter failure requires Rx reset and reinit. */ - outw(RxReset, ioaddr + EL3_CMD); - /* Set the Rx filter to the current state. */ - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | AdapterFailure, - ioaddr + EL3_CMD); - } - } - - if (--i < 0) { - pr_err("%s: Too much work in interrupt, status %4.4x. Disabling functio= ns (%4.4x).\n", - dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); - /* Disable all pending interrupts. */ - outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); - outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - - } while ((status =3D inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); - - spin_unlock(&lp->lock); - - if (corkscrew_debug > 4) - pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); - return IRQ_HANDLED; -} - -static int corkscrew_rx(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - int i; - short rx_status; - - if (corkscrew_debug > 5) - pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); - while ((rx_status =3D inw(ioaddr + RxStatus)) > 0) { - if (rx_status & 0x4000) { /* Error, update stats. */ - unsigned char rx_error =3D inb(ioaddr + RxErrors); - if (corkscrew_debug > 2) - pr_debug(" Rx error: status %2.2x.\n", - rx_error); - dev->stats.rx_errors++; - if (rx_error & 0x01) - dev->stats.rx_over_errors++; - if (rx_error & 0x02) - dev->stats.rx_length_errors++; - if (rx_error & 0x04) - dev->stats.rx_frame_errors++; - if (rx_error & 0x08) - dev->stats.rx_crc_errors++; - if (rx_error & 0x10) - dev->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - short pkt_len =3D rx_status & 0x1fff; - struct sk_buff *skb; - - skb =3D netdev_alloc_skb(dev, pkt_len + 5 + 2); - if (corkscrew_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb !=3D NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, - skb_put(skb, pkt_len), - (pkt_len + 3) >> 2); - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pkt_len; - /* Wait a limited time to go to next packet. */ - for (i =3D 200; i >=3D 0; i--) - if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - continue; - } else if (corkscrew_debug) - pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, p= kt_len); - } - outw(RxDiscard, ioaddr + EL3_CMD); - dev->stats.rx_dropped++; - /* Wait a limited time to skip this packet. */ - for (i =3D 200; i >=3D 0; i--) - if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - } - return 0; -} - -static int boomerang_rx(struct net_device *dev) -{ - struct corkscrew_private *vp =3D netdev_priv(dev); - int entry =3D vp->cur_rx % RX_RING_SIZE; - int ioaddr =3D dev->base_addr; - int rx_status; - - if (corkscrew_debug > 5) - pr_debug(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); - while ((rx_status =3D vp->rx_ring[entry].status) & RxDComplete) { - if (rx_status & RxDError) { /* Error, update stats. */ - unsigned char rx_error =3D rx_status >> 16; - if (corkscrew_debug > 2) - pr_debug(" Rx error: status %2.2x.\n", - rx_error); - dev->stats.rx_errors++; - if (rx_error & 0x01) - dev->stats.rx_over_errors++; - if (rx_error & 0x02) - dev->stats.rx_length_errors++; - if (rx_error & 0x04) - dev->stats.rx_frame_errors++; - if (rx_error & 0x08) - dev->stats.rx_crc_errors++; - if (rx_error & 0x10) - dev->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - short pkt_len =3D rx_status & 0x1fff; - struct sk_buff *skb; - - dev->stats.rx_bytes +=3D pkt_len; - if (corkscrew_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - - /* Check if the packet is long enough to just accept without - copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb =3D netdev_alloc_skb(dev, pkt_len + 4)) !=3D NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - skb_put_data(skb, - isa_bus_to_virt(vp->rx_ring[entry].addr), - pkt_len); - rx_copy++; - } else { - void *temp; - /* Pass up the skbuff already on the Rx ring. */ - skb =3D vp->rx_skbuff[entry]; - vp->rx_skbuff[entry] =3D NULL; - temp =3D skb_put(skb, pkt_len); - /* Remove this checking code for final release. */ - if (isa_bus_to_virt(vp->rx_ring[entry].addr) !=3D temp) - pr_warn("%s: Warning -- the skbuff addresses do not match in boomeran= g_rx: %p vs. %p / %p\n", - dev->name, - isa_bus_to_virt(vp->rx_ring[entry].addr), - skb->head, temp); - rx_nocopy++; - } - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - } - entry =3D (++vp->cur_rx) % RX_RING_SIZE; - } - /* Refill the Rx ring buffers. */ - for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) { - struct sk_buff *skb; - entry =3D vp->dirty_rx % RX_RING_SIZE; - if (vp->rx_skbuff[entry] =3D=3D NULL) { - skb =3D netdev_alloc_skb(dev, PKT_BUF_SZ); - if (skb =3D=3D NULL) - break; /* Bad news! */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr =3D isa_virt_to_bus(skb->data); - vp->rx_skbuff[entry] =3D skb; - } - vp->rx_ring[entry].status =3D 0; /* Clear complete bit. */ - } - return 0; -} - -static int corkscrew_close(struct net_device *dev) -{ - struct corkscrew_private *vp =3D netdev_priv(dev); - int ioaddr =3D dev->base_addr; - int i; - - netif_stop_queue(dev); - - if (corkscrew_debug > 1) { - pr_debug("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n", - dev->name, inw(ioaddr + EL3_STATUS), - inb(ioaddr + TxStatus)); - pr_debug("%s: corkscrew close stats: rx_nocopy %d rx_copy %d tx_queued %= d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet); - } - - timer_delete_sync(&vp->timer); - - /* Turn off statistics ASAP. We update lp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port =3D=3D XCVR_10base2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - - free_irq(dev->irq, dev); - - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - - update_stats(ioaddr, dev); - if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ - outl(0, ioaddr + UpListPtr); - for (i =3D 0; i < RX_RING_SIZE; i++) - if (vp->rx_skbuff[i]) { - dev_kfree_skb(vp->rx_skbuff[i]); - vp->rx_skbuff[i] =3D NULL; - } - } - if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - outl(0, ioaddr + DownListPtr); - for (i =3D 0; i < TX_RING_SIZE; i++) - if (vp->tx_skbuff[i]) { - dev_kfree_skb(vp->tx_skbuff[i]); - vp->tx_skbuff[i] =3D NULL; - } - } - - return 0; -} - -static struct net_device_stats *corkscrew_get_stats(struct net_device *dev) -{ - struct corkscrew_private *vp =3D netdev_priv(dev); - unsigned long flags; - - if (netif_running(dev)) { - spin_lock_irqsave(&vp->lock, flags); - update_stats(dev->base_addr, dev); - spin_unlock_irqrestore(&vp->lock, flags); - } - return &dev->stats; -} - -/* Update statistics. - Unlike with the EL3 we need not worry about interrupts changing - the window setting from underneath us, but we must still guard - against a race condition with a StatsUpdate interrupt updating the - table. This is done by checking that the ASM (!) code generated uses - atomic updates with '+=3D'. - */ -static void update_stats(int ioaddr, struct net_device *dev) -{ - /* Unlike the 3c5x9 we need not turn off stats updates while reading. */ - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors +=3D inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors +=3D inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - dev->stats.collisions +=3D inb(ioaddr + 3); - dev->stats.tx_window_errors +=3D inb(ioaddr + 4); - dev->stats.rx_fifo_errors +=3D inb(ioaddr + 5); - dev->stats.tx_packets +=3D inb(ioaddr + 6); - dev->stats.tx_packets +=3D (inb(ioaddr + 9) & 0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); - /* Must read to clear */ - /* Tx deferrals */ inb(ioaddr + 8); - /* Don't bother with register 9, an extension of registers 6&7. - If we do use the 6&7 values the atomic update assumption above - is invalid. */ - inw(ioaddr + 10); /* Total Rx and Tx octets. */ - inw(ioaddr + 12); - /* New: On the Vortex we must also clear the BadSSD counter. */ - EL3WINDOW(4); - inb(ioaddr + 12); - - /* We change back to window 7 (not 1) with the Vortex. */ - EL3WINDOW(7); -} - -/* This new version of set_rx_mode() supports v1.4 kernels. - The Vortex chip has no documented multicast filter, so the only - multicast setting is to receive all multicast frames. At least - the chip has a very clean way to set the mode, unlike many others. */ -static void set_rx_mode(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - unsigned short new_mode; - - if (dev->flags & IFF_PROMISC) { - if (corkscrew_debug > 3) - pr_debug("%s: Setting promiscuous mode.\n", - dev->name); - new_mode =3D SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxPro= m; - } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) { - new_mode =3D SetRxFilter | RxStation | RxMulticast | RxBroadcast; - } else - new_mode =3D SetRxFilter | RxStation | RxBroadcast; - - outw(new_mode, ioaddr + EL3_CMD); -} - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - snprintf(info->bus_info, sizeof(info->bus_info), "ISA 0x%lx", - dev->base_addr); -} - -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return corkscrew_debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 level) -{ - corkscrew_debug =3D level; -} - -static const struct ethtool_ops netdev_ethtool_ops =3D { - .get_drvinfo =3D netdev_get_drvinfo, - .get_msglevel =3D netdev_get_msglevel, - .set_msglevel =3D netdev_set_msglevel, -}; - -#ifdef MODULE -static void __exit corkscrew_exit_module(void) -{ - while (!list_empty(&root_corkscrew_dev)) { - struct net_device *dev; - struct corkscrew_private *vp; - - vp =3D list_entry(root_corkscrew_dev.next, - struct corkscrew_private, list); - dev =3D vp->our_dev; - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } -} -module_exit(corkscrew_exit_module); -#endif /* MODULE */ diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/= Kconfig index c05a1b63c1c9..3fd3202d9776 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -17,17 +17,6 @@ config NET_VENDOR_3COM =20 if NET_VENDOR_3COM =20 -config 3C515 - tristate "3c515 ISA \"Fast EtherLink\"" - depends on ISA && ISA_DMA_API && !PPC32 - select NETDEV_LEGACY_INIT - help - If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet - network card, say Y here. - - To compile this driver as a module, choose M here. The module - will be called 3c515. - config PCMCIA_3C574 tristate "3Com 3c574 PCMCIA support" depends on PCMCIA && HAS_IOPORT diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com= /Makefile index f7623fa2d441..babfd93d5d53 100644 --- a/drivers/net/ethernet/3com/Makefile +++ b/drivers/net/ethernet/3com/Makefile @@ -3,7 +3,6 @@ # Makefile for the 3Com Ethernet device drivers # =20 -obj-$(CONFIG_3C515) +=3D 3c515.o obj-$(CONFIG_PCMCIA_3C589) +=3D 3c589_cs.o obj-$(CONFIG_PCMCIA_3C574) +=3D 3c574_cs.o obj-$(CONFIG_VORTEX) +=3D 3c59x.o --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 936373233ED; Tue, 21 Apr 2026 19:31:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799899; cv=none; b=NcbFRvZ2cR9qadE/Fl7f1Z9RpuyAzlRbybJoidWz+plEl+ekhn2z+Xw9/wn6qua/tfXvYsbJ5SLosIcmpyl0QaJP+GA+9gLMT3NnoD5F6qa5HlH5vfrSXjOCq/vrKlYO5XeMpW0Xb+8Rj/FPEq5EUytZofa6Af9BUjQ4b5M+oMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799899; c=relaxed/simple; bh=hJkKR8T4Ja4ogSrxHXxI6VqOE+ELVVW0A5hz0S0B+Bg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eAGsEggL9GtHat3iVbMtUKZ69l1NBMNz7yvLCXglDbJ76Oth4zQ5RGHBBRR6zZWjaG272/H8rk3By7szCad41g70ErlsDcXbJeLHEzl1DfSy0lG2sHvWgjwzCkyibtPSbKngn9ORzhIPUsbaOEjWxMACrazUco2h4OohKSYW+gY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=OJDX1Fq7; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="OJDX1Fq7" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=tUayKS3mLOTKQTpTDfP8IG9gYrhahBM/lCBtLPKhmjA=; b=OJ DX1Fq7WkKyIZkjhZPwPcJgKStDk4uQ//IP4yfI+rB+IrXXfZesw0AonPmeMsF5niMTJAhqMVi8aCR fqG5gQ2PsT25ysYjydLvUmjBOEiRU6CrL2RBvf0neTGtYMHgY3A/5y7Ar9gHRy6DsJR2vvx6V8w/E up9sQj6S6wKb2JA=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGoe-00GwVc-HL; Tue, 21 Apr 2026 21:31:24 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:06 -0500 Subject: [PATCH net 03/18] drivers: net: 3com: 3c574: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-3-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=38013; i=andrew@lunn.ch; h=from:subject:message-id; bh=hJkKR8T4Ja4ogSrxHXxI6VqOE+ELVVW0A5hz0S0B+Bg=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CBWAZS/qhrlVhUVJ5HmryGyPivnXN4MIxl0 z8LlyXg/T2JAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hBj4EADJTUB6LO1RLG2mBKGVDIYQUs6v+ZKYSno66XxMCTcV86B6sqO73oWVVTMgq4k2bMTSvdY 3jEPzutLcbg5+ghFPa4T/WJ0cc/xIR4VEDQZwlVciyUtY9WQVqxryaPk0s9fcI2ip7ksVMy3bxE rJ9CHSzF0O2S0p+qVq6ataydim99Vus70VwVSkllBkJ45AIMIu8tc+5nqTqirnyMx1xqjygaH2Z KTfd5DkeaqJTUE1VklCBG9L+N6su2U7cpuPUWBRVqZ7V8kpuDeaExwq+gUqkSxsY/6+IUDvVBad 8Ma7qydAx/+H+HBMW6LutgysWNe+l+H3Rpbov8bQP2LXf6k+vk4cUgTrWTc+xifuhIYYm0TyJYb h89JEX/2U90OyL1BEkvNMqbQf0sZG3168A8FL/PQTrROIzTfaNY22nv0SaLF9OSif6YhaCi7RbM 42Q8Ua+wE876zzRv2gfvIx02SgSw05dHyXIfp4Oc0JAjl0VDEvuOEkpv4fz4cmntqzEW+8xLbs+ v5ApUMiMT4SDm3/Jcncz9nvtbSZu5bee3nt+Hh+tz3FS0ajMTnguun3xAKpbdXdBsX3oAP6tzNX V2+5kYvOLmzZLaqSWCJcnnpgUV7IzqDZpTmw15UJ7tA1iPf4/B6VmKmZE//XIpkSuOX3TpypUW9 kB6sAExNKPMBv3g== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The 3c574 was written by Donald Becker between 19973-1998. It is an PCMCIA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/3com/3c574_cs.c | 1164 ------------------------------= ---- drivers/net/ethernet/3com/Kconfig | 10 - drivers/net/ethernet/3com/Makefile | 1 - 3 files changed, 1175 deletions(-) diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3c= om/3c574_cs.c deleted file mode 100644 index 1f2070497a75..000000000000 --- a/drivers/net/ethernet/3com/3c574_cs.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner". - - Written 1993-1998 by - Donald Becker, becker@scyld.com, (driver core) and - David Hinds, dahinds@users.sourceforge.net (from his PC card code). - Locking fixes (C) Copyright 2003 Red Hat Inc - - This software may be used and distributed according to the terms of - the GNU General Public License, incorporated herein by reference. - - This driver derives from Donald Becker's 3c509 core, which has the - following copyright: - Copyright 1993 United States Government as represented by the - Director, National Security Agency. -=09 - -*/ - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the 3Com 3c574 PC card Fast Ethernet -Adapter. - -II. Board-specific settings - -None -- PC cards are autoconfigured. - -III. Driver operation - -The 3c574 uses a Boomerang-style interface, without the bus-master capabil= ity. -See the Boomerang driver and documentation for most details. - -IV. Notes and chip documentation. - -Two added registers are used to enhance PIO performance, RunnerRdCtrl and -RunnerWrCtrl. These are 11 bit down-counters that are preloaded with the -count of word (16 bits) reads or writes the driver is about to do to the Rx -or Tx FIFO. The chip is then able to hide the internal-PCI-bus to PC-card -translation latency by buffering the I/O operations with an 8 word FIFO. -Note: No other chip accesses are permitted when this buffer is used. - -A second enhancement is that both attribute and common memory space -0x0800-0x0fff can translated to the PIO FIFO. Thus memory operations (fas= ter -with *some* PCcard bridges) may be used instead of I/O operations. -This is enabled by setting the 0x10 bit in the PCMCIA LAN COR. - -Some slow PC card bridges work better if they never see a WAIT signal. -This is configured by setting the 0x20 bit in the PCMCIA LAN COR. -Only do this after testing that it is reliable and improves performance. - -The upper five bits of RunnerRdCtrl are used to window into PCcard -configuration space registers. Window 0 is the regular Boomerang/Odie -register set, 1-5 are various PC card control registers, and 16-31 are -the (reversed!) CIS table. - -A final note: writing the InternalConfig register in window 3 with an -invalid ramWidth is Very Bad. - -V. References - -http://www.scyld.com/expert/NWay.html -http://www.national.com/opf/DP/DP83840A.html - -Thanks to Terry Murphy of 3Com for providing development information for -earlier 3Com products. - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("3Com 3c574 series PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n =3D v; module_param(n, int, 0) - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -INT_MODULE_PARM(max_interrupt_work, 32); - -/* Force full duplex modes? */ -INT_MODULE_PARM(full_duplex, 0); - -/* Autodetect link polarity reversal? */ -INT_MODULE_PARM(auto_polarity, 1); - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((800*HZ)/1000) - -/* To minimize the size of the driver source and make the driver more - readable not all constants are symbolically defined. - You'll need the manual if you want to understand driver details anyway.= */ -/* Offsets from base I/O address. */ -#define EL3_DATA 0x00 -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. */ -enum el3_cmds { - TotalReset =3D 0<<11, SelectWindow =3D 1<<11, StartCoax =3D 2<<11, - RxDisable =3D 3<<11, RxEnable =3D 4<<11, RxReset =3D 5<<11, RxDiscard =3D= 8<<11, - TxEnable =3D 9<<11, TxDisable =3D 10<<11, TxReset =3D 11<<11, - FakeIntr =3D 12<<11, AckIntr =3D 13<<11, SetIntrEnb =3D 14<<11, - SetStatusEnb =3D 15<<11, SetRxFilter =3D 16<<11, SetRxThreshold =3D 17<<1= 1, - SetTxThreshold =3D 18<<11, SetTxStart =3D 19<<11, StatsEnable =3D 21<<11, - StatsDisable =3D 22<<11, StopCoax =3D 23<<11, -}; - -enum elxl_status { - IntLatch =3D 0x0001, AdapterFailure =3D 0x0002, TxComplete =3D 0x0004, - TxAvailable =3D 0x0008, RxComplete =3D 0x0010, RxEarly =3D 0x0020, - IntReq =3D 0x0040, StatsFull =3D 0x0080, CmdBusy =3D 0x1000 }; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation =3D 1, RxMulticast =3D 2, RxBroadcast =3D 4, RxProm =3D 8 -}; - -enum Window0 { - Wn0EepromCmd =3D 10, Wn0EepromData =3D 12, /* EEPROM command/address, dat= a. */ - IntrStatus=3D0x0E, /* Valid in all windows. */ -}; -/* These assumes the larger EEPROM. */ -enum Win0_EEPROM_cmds { - EEPROM_Read =3D 0x200, EEPROM_WRITE =3D 0x100, EEPROM_ERASE =3D 0x300, - EEPROM_EWENB =3D 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS =3D 0x00, /* Disable EWENB before 10 msec timeout. */ -}; - -/* Register window 1 offsets, the window used in normal operation. - On the "Odie" this window is always mapped at offsets 0x10-0x1f. - Except for TxFree, which is overlapped by RunnerWrCtrl. */ -enum Window1 { - TX_FIFO =3D 0x10, RX_FIFO =3D 0x10, RxErrors =3D 0x14, - RxStatus =3D 0x18, Timer=3D0x1A, TxStatus =3D 0x1B, - TxFree =3D 0x0C, /* Remaining free bytes in Tx buffer. */ - RunnerRdCtrl =3D 0x16, RunnerWrCtrl =3D 0x1c, -}; - -enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=3D0, Wn3_MAC_Ctrl=3D6, Wn3_Options=3D8, -}; -enum wn3_config { - Ram_size =3D 7, - Ram_width =3D 8, - Ram_speed =3D 0x30, - Rom_size =3D 0xc0, - Ram_split_shift =3D 16, - Ram_split =3D 3 << Ram_split_shift, - Xcvr_shift =3D 20, - Xcvr =3D 7 << Xcvr_shift, - Autoselect =3D 0x1000000, -}; - -enum Window4 { /* Window 4: Xcvr/media bits. */ - Wn4_FIFODiag =3D 4, Wn4_NetDiag =3D 6, Wn4_PhysicalMgmt=3D8, Wn4_Media = =3D 10, -}; - -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ - -struct el3_private { - struct pcmcia_device *p_dev; - u16 advertising, partner; /* NWay media advertisement */ - unsigned char phys; /* MII device address */ - unsigned int autoselect:1, default_media:3; /* Read from the EEPROM/Wn3_C= onfig. */ - /* for transceiver monitoring */ - struct timer_list media; - unsigned short media_status; - unsigned short fast_poll; - unsigned long last_irq; - spinlock_t window_lock; /* Guards the Window selection */ -}; - -/* Set iff a MII transceiver on any interface requires mdio preamble. - This only set with the original DP83840 on older 3c905 boards, so the e= xtra - code size of a per-interface flag is not worthwhile. */ -static char mii_preamble_required =3D 0; - -/* Index of functions. */ - -static int tc574_config(struct pcmcia_device *link); -static void tc574_release(struct pcmcia_device *link); - -static void mdio_sync(unsigned int ioaddr, int bits); -static int mdio_read(unsigned int ioaddr, int phy_id, int location); -static void mdio_write(unsigned int ioaddr, int phy_id, int location, - int value); -static unsigned short read_eeprom(unsigned int ioaddr, int index); -static void tc574_wait_for_completion(struct net_device *dev, int cmd); - -static void tc574_reset(struct net_device *dev); -static void media_check(struct timer_list *t); -static int el3_open(struct net_device *dev); -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id); -static void update_stats(struct net_device *dev); -static struct net_device_stats *el3_get_stats(struct net_device *dev); -static int el3_rx(struct net_device *dev, int worklimit); -static int el3_close(struct net_device *dev); -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue); -static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); - -static void tc574_detach(struct pcmcia_device *p_dev); - -/* - tc574_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. -*/ -static const struct net_device_ops el3_netdev_ops =3D { - .ndo_open =3D el3_open, - .ndo_stop =3D el3_close, - .ndo_start_xmit =3D el3_start_xmit, - .ndo_tx_timeout =3D el3_tx_timeout, - .ndo_get_stats =3D el3_get_stats, - .ndo_eth_ioctl =3D el3_ioctl, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - -static int tc574_probe(struct pcmcia_device *link) -{ - struct el3_private *lp; - struct net_device *dev; - - dev_dbg(&link->dev, "3c574_attach()\n"); - - /* Create the PC card device object. */ - dev =3D alloc_etherdev(sizeof(struct el3_private)); - if (!dev) - return -ENOMEM; - lp =3D netdev_priv(dev); - link->priv =3D dev; - lp->p_dev =3D link; - - spin_lock_init(&lp->window_lock); - link->resource[0]->end =3D 32; - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_16; - link->config_flags |=3D CONF_ENABLE_IRQ; - link->config_index =3D 1; - - dev->netdev_ops =3D &el3_netdev_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - - return tc574_config(link); -} - -static void tc574_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - dev_dbg(&link->dev, "3c574_detach()\n"); - - unregister_netdev(dev); - - tc574_release(link); - - free_netdev(dev); -} /* tc574_detach */ - -static const char *ram_split[] =3D {"5:3", "3:1", "1:1", "3:5"}; - -static int tc574_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct el3_private *lp =3D netdev_priv(dev); - int ret, i, j; - __be16 addr[ETH_ALEN / 2]; - unsigned int ioaddr; - char *cardname; - __u32 config; - u8 *buf; - size_t len; - - dev_dbg(&link->dev, "3c574_config()\n"); - - link->io_lines =3D 16; - - for (i =3D j =3D 0; j < 0x400; j +=3D 0x20) { - link->resource[0]->start =3D j ^ 0x300; - i =3D pcmcia_request_io(link); - if (i =3D=3D 0) - break; - } - if (i !=3D 0) - goto failed; - - ret =3D pcmcia_request_irq(link, el3_interrupt); - if (ret) - goto failed; - - ret =3D pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq =3D link->irq; - dev->base_addr =3D link->resource[0]->start; - - ioaddr =3D dev->base_addr; - - /* The 3c574 normally uses an EEPROM for configuration info, including - the hardware address. The future products may include a modem chip - and put the address in the CIS. */ - - len =3D pcmcia_get_tuple(link, 0x88, &buf); - if (buf && len >=3D 6) { - for (i =3D 0; i < 3; i++) - addr[i] =3D htons(le16_to_cpu(buf[i * 2])); - kfree(buf); - } else { - kfree(buf); /* 0 < len < 6 */ - EL3WINDOW(0); - for (i =3D 0; i < 3; i++) - addr[i] =3D htons(read_eeprom(ioaddr, i + 10)); - if (addr[0] =3D=3D htons(0x6060)) { - pr_notice("IO port conflict at 0x%03lx-0x%03lx\n", - dev->base_addr, dev->base_addr+15); - goto failed; - } - } - eth_hw_addr_set(dev, (u8 *)addr); - if (link->prod_id[1]) - cardname =3D link->prod_id[1]; - else - cardname =3D "3Com 3c574"; - - { - u_char mcr; - outw(2<<11, ioaddr + RunnerRdCtrl); - mcr =3D inb(ioaddr + 2); - outw(0<<11, ioaddr + RunnerRdCtrl); - pr_info(" ASIC rev %d,", mcr>>3); - EL3WINDOW(3); - config =3D inl(ioaddr + Wn3_Config); - lp->default_media =3D (config & Xcvr) >> Xcvr_shift; - lp->autoselect =3D config & Autoselect ? 1 : 0; - } - - timer_setup(&lp->media, media_check, 0); - - { - int phy; - =09 - /* Roadrunner only: Turn on the MII transceiver */ - outw(0x8040, ioaddr + Wn3_Options); - mdelay(1); - outw(0xc040, ioaddr + Wn3_Options); - tc574_wait_for_completion(dev, TxReset); - tc574_wait_for_completion(dev, RxReset); - mdelay(1); - outw(0x8040, ioaddr + Wn3_Options); - =09 - EL3WINDOW(4); - for (phy =3D 1; phy <=3D 32; phy++) { - int mii_status; - mdio_sync(ioaddr, 32); - mii_status =3D mdio_read(ioaddr, phy & 0x1f, 1); - if (mii_status !=3D 0xffff) { - lp->phys =3D phy & 0x1f; - dev_dbg(&link->dev, " MII transceiver at " - "index %d, status %x.\n", - phy, mii_status); - if ((mii_status & 0x0040) =3D=3D 0) - mii_preamble_required =3D 1; - break; - } - } - if (phy > 32) { - pr_notice(" No MII transceivers found!\n"); - goto failed; - } - i =3D mdio_read(ioaddr, lp->phys, 16) | 0x40; - mdio_write(ioaddr, lp->phys, 16, i); - lp->advertising =3D mdio_read(ioaddr, lp->phys, 4); - if (full_duplex) { - /* Only advertise the FD media types. */ - lp->advertising &=3D ~0x02a0; - mdio_write(ioaddr, lp->phys, 4, lp->advertising); - } - } - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) !=3D 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n", - cardname, dev->base_addr, dev->irq, dev->dev_addr); - netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n", - 8 << (config & Ram_size), - ram_split[(config & Ram_split) >> Ram_split_shift], - config & Autoselect ? "autoselect " : ""); - - return 0; - -failed: - tc574_release(link); - return -ENODEV; - -} /* tc574_config */ - -static void tc574_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int tc574_suspend(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int tc574_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) { - tc574_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -static void dump_status(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - EL3WINDOW(1); - netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x, tx f= ree %04x\n", - inw(ioaddr+EL3_STATUS), - inw(ioaddr+RxStatus), inb(ioaddr+TxStatus), - inw(ioaddr+TxFree)); - EL3WINDOW(4); - netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %= 04x\n", - inw(ioaddr+0x04), inw(ioaddr+0x06), - inw(ioaddr+0x08), inw(ioaddr+0x0a)); - EL3WINDOW(1); -} - -/* - Use this for commands that may take time to finish -*/ -static void tc574_wait_for_completion(struct net_device *dev, int cmd) -{ - int i =3D 1500; - outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; - if (i =3D=3D 0) - netdev_notice(dev, "command 0x%04x did not complete!\n", cmd); -} - -/* Read a word from the EEPROM using the regular EEPROM access register. - Assume that we are in register window zero. - */ -static unsigned short read_eeprom(unsigned int ioaddr, int index) -{ - int timer; - outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 usec for the read to take place. */ - for (timer =3D 1620; timer >=3D 0; timer--) { - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) =3D=3D 0) - break; - } - return inw(ioaddr + Wn0EepromData); -} - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. - The maxium data clock rate is 2.5 Mhz. The timing is easily met by the - slow PC card interface. */ - -#define MDIO_SHIFT_CLK 0x01 -#define MDIO_DIR_WRITE 0x04 -#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE) -#define MDIO_DATA_READ 0x02 -#define MDIO_ENB_IN 0x00 - -/* Generate the preamble required for initial synchronization and - a few older transceivers. */ -static void mdio_sync(unsigned int ioaddr, int bits) -{ - unsigned int mdio_addr =3D ioaddr + Wn4_PhysicalMgmt; - - /* Establish sync by sending at least 32 logic ones. */ - while (-- bits >=3D 0) { - outw(MDIO_DATA_WRITE1, mdio_addr); - outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - } -} - -static int mdio_read(unsigned int ioaddr, int phy_id, int location) -{ - int i; - int read_cmd =3D (0xf6 << 10) | (phy_id << 5) | location; - unsigned int retval =3D 0; - unsigned int mdio_addr =3D ioaddr + Wn4_PhysicalMgmt; - - if (mii_preamble_required) - mdio_sync(ioaddr, 32); - - /* Shift the read command bits out. */ - for (i =3D 14; i >=3D 0; i--) { - int dataval =3D (read_cmd&(1< 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); - retval =3D (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(unsigned int ioaddr, int phy_id, int location, int = value) -{ - int write_cmd =3D 0x50020000 | (phy_id << 23) | (location << 18) | value; - unsigned int mdio_addr =3D ioaddr + Wn4_PhysicalMgmt; - int i; - - if (mii_preamble_required) - mdio_sync(ioaddr, 32); - - /* Shift the command bits out. */ - for (i =3D 31; i >=3D 0; i--) { - int dataval =3D (write_cmd&(1<=3D 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - } -} - -/* Reset and restore all of the 3c574 registers. */ -static void tc574_reset(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - int i; - unsigned int ioaddr =3D dev->base_addr; - unsigned long flags; - - tc574_wait_for_completion(dev, TotalReset|0x10); - - spin_lock_irqsave(&lp->window_lock, flags); - /* Clear any transactions in progress. */ - outw(0, ioaddr + RunnerWrCtrl); - outw(0, ioaddr + RunnerRdCtrl); - - /* Set the station address and mask. */ - EL3WINDOW(2); - for (i =3D 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - for (; i < 12; i+=3D2) - outw(0, ioaddr + i); - - /* Reset config options */ - EL3WINDOW(3); - outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); - outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b, - ioaddr + Wn3_Config); - /* Roadrunner only: Turn on the MII transceiver. */ - outw(0x8040, ioaddr + Wn3_Options); - mdelay(1); - outw(0xc040, ioaddr + Wn3_Options); - EL3WINDOW(1); - spin_unlock_irqrestore(&lp->window_lock, flags); -=09 - tc574_wait_for_completion(dev, TxReset); - tc574_wait_for_completion(dev, RxReset); - mdelay(1); - spin_lock_irqsave(&lp->window_lock, flags); - EL3WINDOW(3); - outw(0x8040, ioaddr + Wn3_Options); - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i =3D 0; i < 10; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - EL3WINDOW(4); - inb(ioaddr + 12); - inb(ioaddr + 13); - - /* .. enable any extra statistics bits.. */ - outw(0x0040, ioaddr + Wn4_NetDiag); -=09 - EL3WINDOW(1); - spin_unlock_irqrestore(&lp->window_lock, flags); -=09 - /* .. re-sync MII and re-fill what NWay is advertising. */ - mdio_sync(ioaddr, 32); - mdio_write(ioaddr, lp->phys, 4, lp->advertising); - if (!auto_polarity) { - /* works for TDK 78Q2120 series MII's */ - i =3D mdio_read(ioaddr, lp->phys, 16) | 0x20; - mdio_write(ioaddr, lp->phys, 16, i); - } - - spin_lock_irqsave(&lp->window_lock, flags); - /* Switch to register set 1 for normal use, just for TxFree. */ - set_rx_mode(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | AdapterFailure | RxEarly, ioaddr + EL3_CMD); -} - -static int el3_open(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - if (!pcmcia_dev_present(link)) - return -ENODEV; -=09 - link->open++; - netif_start_queue(dev); -=09 - tc574_reset(dev); - lp->media.expires =3D jiffies + HZ; - add_timer(&lp->media); -=09 - dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", - dev->name, inw(dev->base_addr + EL3_STATUS)); -=09 - return 0; -} - -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - unsigned int ioaddr =3D dev->base_addr; -=09 - netdev_notice(dev, "Transmit timed out!\n"); - dump_status(dev); - dev->stats.tx_errors++; - netif_trans_update(dev); /* prevent tx timeout */ - /* Issue TX_RESET and TX_START commands. */ - tc574_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - netif_wake_queue(dev); -} - -static void pop_tx_status(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - int i; - =20 - /* Clear the Tx status stack. */ - for (i =3D 32; i > 0; i--) { - u_char tx_status =3D inb(ioaddr + TxStatus); - if (!(tx_status & 0x84)) - break; - /* reset transmitter on jabber error or underrun */ - if (tx_status & 0x30) - tc574_wait_for_completion(dev, TxReset); - if (tx_status & 0x38) { - pr_debug("%s: transmit error: status 0x%02x\n", - dev->name, tx_status); - outw(TxEnable, ioaddr + EL3_CMD); - dev->stats.tx_aborted_errors++; - } - outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ - } -} - -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct el3_private *lp =3D netdev_priv(dev); - unsigned long flags; - - pr_debug("%s: el3_start_xmit(length =3D %ld) called, " - "status %4.4x.\n", dev->name, (long)skb->len, - inw(ioaddr + EL3_STATUS)); - - spin_lock_irqsave(&lp->window_lock, flags); - - dev->stats.tx_bytes +=3D skb->len; - - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2); - - /* TxFree appears only in Window 1, not offset 0x1c. */ - if (inw(ioaddr + TxFree) <=3D 1536) { - netif_stop_queue(dev); - /* Interrupt us when the FIFO has room for max-sized packet.=20 - The threshold is in units of dwords. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - } - - pop_tx_status(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -/* The EL3 interrupt handler. */ -static irqreturn_t el3_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D (struct net_device *) dev_id; - struct el3_private *lp =3D netdev_priv(dev); - unsigned int ioaddr; - unsigned status; - int work_budget =3D max_interrupt_work; - int handled =3D 0; - - if (!netif_device_present(dev)) - return IRQ_NONE; - ioaddr =3D dev->base_addr; - - pr_debug("%s: interrupt, status %4.4x.\n", - dev->name, inw(ioaddr + EL3_STATUS)); - - spin_lock(&lp->window_lock); -=09 - while ((status =3D inw(ioaddr + EL3_STATUS)) & - (IntLatch | RxComplete | RxEarly | StatsFull)) { - if (!netif_device_present(dev) || - ((status & 0xe000) !=3D 0x2000)) { - pr_debug("%s: Interrupt from dead card\n", dev->name); - break; - } - - handled =3D 1; - - if (status & RxComplete) - work_budget =3D el3_rx(dev, work_budget); - - if (status & TxAvailable) { - pr_debug(" TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); - } - - if (status & TxComplete) - pop_tx_status(dev); - - if (status & (AdapterFailure | RxEarly | StatsFull)) { - /* Handle all uncommon interrupts. */ - if (status & StatsFull) - update_stats(dev); - if (status & RxEarly) { - work_budget =3D el3_rx(dev, work_budget); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & AdapterFailure) { - u16 fifo_diag; - EL3WINDOW(4); - fifo_diag =3D inw(ioaddr + Wn4_FIFODiag); - EL3WINDOW(1); - netdev_notice(dev, "adapter failure, FIFO diagnostic register %04x\n", - fifo_diag); - if (fifo_diag & 0x0400) { - /* Tx overrun */ - tc574_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - } - if (fifo_diag & 0x2000) { - /* Rx underrun */ - tc574_wait_for_completion(dev, RxReset); - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); - } - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); - } - } - - if (--work_budget < 0) { - pr_debug("%s: Too much work in interrupt, " - "status %4.4x.\n", dev->name, status); - /* Clear all interrupts */ - outw(AckIntr | 0xFF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } - - pr_debug("%s: exiting interrupt, status %4.4x.\n", - dev->name, inw(ioaddr + EL3_STATUS)); - =20 - spin_unlock(&lp->window_lock); - return IRQ_RETVAL(handled); -} - -/* - This timer serves two purposes: to check for missed interrupts - (and as a last resort, poll the NIC for events), and to monitor - the MII, reporting changes in cable status. -*/ -static void media_check(struct timer_list *t) -{ - struct el3_private *lp =3D timer_container_of(lp, t, media); - struct net_device *dev =3D lp->p_dev->priv; - unsigned int ioaddr =3D dev->base_addr; - unsigned long flags; - unsigned short /* cable, */ media, partner; - - if (!netif_device_present(dev)) - goto reschedule; -=09 - /* Check for pending interrupt with expired latency timer: with - this, we can limp along even if the interrupt is blocked */ - if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) =3D=3D = 0xff)) { - if (!lp->fast_poll) - netdev_info(dev, "interrupt(s) dropped!\n"); - - local_irq_save(flags); - el3_interrupt(dev->irq, dev); - local_irq_restore(flags); - - lp->fast_poll =3D HZ; - } - if (lp->fast_poll) { - lp->fast_poll--; - lp->media.expires =3D jiffies + 2*HZ/100; - add_timer(&lp->media); - return; - } - - spin_lock_irqsave(&lp->window_lock, flags); - EL3WINDOW(4); - media =3D mdio_read(ioaddr, lp->phys, 1); - partner =3D mdio_read(ioaddr, lp->phys, 5); - EL3WINDOW(1); -=09 - if (media !=3D lp->media_status) { - if ((media ^ lp->media_status) & 0x0004) - netdev_info(dev, "%s link beat\n", - (lp->media_status & 0x0004) ? "lost" : "found"); - if ((media ^ lp->media_status) & 0x0020) { - lp->partner =3D 0; - if (lp->media_status & 0x0020) { - netdev_info(dev, "autonegotiation restarted\n"); - } else if (partner) { - partner &=3D lp->advertising; - lp->partner =3D partner; - netdev_info(dev, "autonegotiation complete: " - "%dbaseT-%cD selected\n", - (partner & 0x0180) ? 100 : 10, - (partner & 0x0140) ? 'F' : 'H'); - } else { - netdev_info(dev, "link partner did not autonegotiate\n"); - } - - EL3WINDOW(3); - outb((partner & 0x0140 ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); - EL3WINDOW(1); - - } - if (media & 0x0010) - netdev_info(dev, "remote fault detected\n"); - if (media & 0x0002) - netdev_info(dev, "jabber detected\n"); - lp->media_status =3D media; - } - spin_unlock_irqrestore(&lp->window_lock, flags); - -reschedule: - lp->media.expires =3D jiffies + HZ; - add_timer(&lp->media); -} - -static struct net_device_stats *el3_get_stats(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - - if (netif_device_present(dev)) { - unsigned long flags; - spin_lock_irqsave(&lp->window_lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - } - return &dev->stats; -} - -/* Update statistics. - Surprisingly this need not be run single-threaded, but it effectively is. - The counters clear when read, so the adds must merely be atomic. - */ -static void update_stats(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - u8 up; - - pr_debug("%s: updating the statistics.\n", dev->name); - - if (inw(ioaddr+EL3_STATUS) =3D=3D 0xffff) /* No card. */ - return; - =09 - /* Unlike the 3c509 we need not turn off stats updates while reading. */ - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors +=3D inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors +=3D inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - dev->stats.collisions +=3D inb(ioaddr + 3); - dev->stats.tx_window_errors +=3D inb(ioaddr + 4); - dev->stats.rx_fifo_errors +=3D inb(ioaddr + 5); - dev->stats.tx_packets +=3D inb(ioaddr + 6); - up =3D inb(ioaddr + 9); - dev->stats.tx_packets +=3D (up&0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); - /* Tx deferrals */ inb(ioaddr + 8); - /* rx */ inw(ioaddr + 10); - /* tx */ inw(ioaddr + 12); - - EL3WINDOW(4); - /* BadSSD */ inb(ioaddr + 12); - up =3D inb(ioaddr + 13); - - EL3WINDOW(1); -} - -static int el3_rx(struct net_device *dev, int worklimit) -{ - unsigned int ioaddr =3D dev->base_addr; - short rx_status; -=09 - pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n", - dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); - while (!((rx_status =3D inw(ioaddr + RxStatus)) & 0x8000) && - worklimit > 0) { - worklimit--; - if (rx_status & 0x4000) { /* Error, update stats. */ - short error =3D rx_status & 0x3800; - dev->stats.rx_errors++; - switch (error) { - case 0x0000: dev->stats.rx_over_errors++; break; - case 0x0800: dev->stats.rx_length_errors++; break; - case 0x1000: dev->stats.rx_frame_errors++; break; - case 0x1800: dev->stats.rx_length_errors++; break; - case 0x2000: dev->stats.rx_frame_errors++; break; - case 0x2800: dev->stats.rx_crc_errors++; break; - } - } else { - short pkt_len =3D rx_status & 0x7ff; - struct sk_buff *skb; - - skb =3D netdev_alloc_skb(dev, pkt_len + 5); - - pr_debug(" Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb !=3D NULL) { - skb_reserve(skb, 2); - insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), - ((pkt_len+3)>>2)); - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pkt_len; - } else { - pr_debug("%s: couldn't allocate a sk_buff of" - " size %d.\n", dev->name, pkt_len); - dev->stats.rx_dropped++; - } - } - tc574_wait_for_completion(dev, RxDiscard); - } - - return worklimit; -} - -/* Provide ioctl() calls to examine the MII xcvr state. */ -static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct el3_private *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - struct mii_ioctl_data *data =3D if_mii(rq); - int phy =3D lp->phys & 0x1f; - - pr_debug("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", - dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data->phy_id, data->reg_num, data->val_in, data->val_out); - - switch(cmd) { - case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data->phy_id =3D phy; - fallthrough; - case SIOCGMIIREG: /* Read the specified MII register. */ - { - int saved_window; - unsigned long flags; - - spin_lock_irqsave(&lp->window_lock, flags); - saved_window =3D inw(ioaddr + EL3_CMD) >> 13; - EL3WINDOW(4); - data->val_out =3D mdio_read(ioaddr, data->phy_id & 0x1f, - data->reg_num & 0x1f); - EL3WINDOW(saved_window); - spin_unlock_irqrestore(&lp->window_lock, flags); - return 0; - } - case SIOCSMIIREG: /* Write the specified MII register */ - { - int saved_window; - unsigned long flags; - - spin_lock_irqsave(&lp->window_lock, flags); - saved_window =3D inw(ioaddr + EL3_CMD) >> 13; - EL3WINDOW(4); - mdio_write(ioaddr, data->phy_id & 0x1f, - data->reg_num & 0x1f, data->val_in); - EL3WINDOW(saved_window); - spin_unlock_irqrestore(&lp->window_lock, flags); - return 0; - } - default: - return -EOPNOTSUPP; - } -} - -/* The Odie chip has a 64 bin multicast filter, but the bit layout is not - documented. Until it is we revert to receiving all multicast frames wh= en - any multicast reception is desired. - Note: My other drivers emit a log message whenever promiscuous mode is - entered to help detect password sniffers. This is less desirable on - typical PC card machines, so we omit the message. - */ - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - - if (dev->flags & IFF_PROMISC) - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, - ioaddr + EL3_CMD); - else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) - outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); - else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); -} - -static void set_multicast_list(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&lp->window_lock, flags); - set_rx_mode(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); -} - -static int el3_close(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct el3_private *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); -=09 - if (pcmcia_dev_present(link)) { - unsigned long flags; - - /* Turn off statistics ASAP. We update lp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - =09 - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - =09 - /* Note: Switching to window 0 may disable the IRQ. */ - EL3WINDOW(0); - spin_lock_irqsave(&lp->window_lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->window_lock, flags); - - /* force interrupts off */ - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - } - - link->open--; - netif_stop_queue(dev); - timer_delete_sync(&lp->media); - - return 0; -} - -static const struct pcmcia_device_id tc574_ids[] =3D { - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, tc574_ids); - -static struct pcmcia_driver tc574_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "3c574_cs", - .probe =3D tc574_probe, - .remove =3D tc574_detach, - .id_table =3D tc574_ids, - .suspend =3D tc574_suspend, - .resume =3D tc574_resume, -}; -module_pcmcia_driver(tc574_driver); diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/= Kconfig index 3fd3202d9776..294403ad7141 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -17,16 +17,6 @@ config NET_VENDOR_3COM =20 if NET_VENDOR_3COM =20 -config PCMCIA_3C574 - tristate "3Com 3c574 PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA - (PC-card) Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called 3c574_cs. If unsure, say N. - config PCMCIA_3C589 tristate "3Com 3c589 PCMCIA support" depends on PCMCIA && HAS_IOPORT diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com= /Makefile index babfd93d5d53..45fb9af9b5c7 100644 --- a/drivers/net/ethernet/3com/Makefile +++ b/drivers/net/ethernet/3com/Makefile @@ -4,6 +4,5 @@ # =20 obj-$(CONFIG_PCMCIA_3C589) +=3D 3c589_cs.o -obj-$(CONFIG_PCMCIA_3C574) +=3D 3c574_cs.o obj-$(CONFIG_VORTEX) +=3D 3c59x.o obj-$(CONFIG_TYPHOON) +=3D typhoon.o --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1EBC237C937; Tue, 21 Apr 2026 19:31:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799899; cv=none; b=hdqWpRF2KHbM5nPCIQRrHf/wxLaDwRdnx2JkQDwlXVTDX4YpiQHOQmdmqILLVwMuxJiiOOE93zHfFfx7Jk5UW8HumbdAJnO+u9CBA7N6EV6DJDUzMZXroFdbT9g2Gtn/6e5un2i0THpXQ1PleBJ4ZHD7b8a3wA5jYcsYY4yrv74= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799899; c=relaxed/simple; bh=mFTIQ6cuxfewRADA9sCAD8EUjvtaRRMTEC4Yzf+QQZI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Q8SwqPn6VPNpI6rVr5MRA53gfBHAaYbTCfmSUye06MSpO0QHM18OtXFN5XTCdkMYRMfXPH72buvTFWIHDrgXuZGKgg6j+Mdn7ZbfJ+nlJn2n4pITSBG3Dro+Fw0JnwZU0hoCIwR5TS+eUorCg62CmNcSI3X9D2CvSapO0zHp3Hg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=YW1OzAfb; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="YW1OzAfb" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=oseksMDkV5xKYi7kdlkVt7Js5LhinwXICQS+kgUIHKA=; b=YW 1OzAfbOaWAuV7N4Ac1GASD/UdmZJBxpUyg4oqF6W3Y2t4w9pO3pn1OkcfyZgNANf07c85DjQ9fB20 sFDXF1pF0KXlhtdSnE383olVjWG1fnWXZalVZz2PpWzOUd+Es0CmovwkqbeYEJfqRxD2r42FoBciB IU9CoFYWAupJ7Ns=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGoh-00GwVc-0o; Tue, 21 Apr 2026 21:31:27 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:07 -0500 Subject: [PATCH net 04/18] drivers: net: 3com: 3c589: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-4-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=29772; i=andrew@lunn.ch; h=from:subject:message-id; bh=mFTIQ6cuxfewRADA9sCAD8EUjvtaRRMTEC4Yzf+QQZI=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CB/jgeml4pdzgAVnxfhzENYjXzYAU7eEKMO Tfw9laU/dqJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hJ2DEAC6lxrBwNRW9CqUEw4kHP8XKfqjuIXY2I6Xy81KHRRybAhG9QG5Th/L800SDIVYag6NrEj Wk/BuS74wK8j7RIO0G1za7+lp8Pleasky4AU1r1subBFvjVD+VJP+WFQX3v1rsjWlIiXp75w7Yl HqTCibCm3N+IngoChJtLTFZP/U9y+wmLqwvQECwKgV+SYYSyPV/wbdQini1p80uy7bQcleVEipA xg+L3XLKpR2eH1HUjanGeTD4T96gRwIrpLW2nJZEjSIV48Z46OlZVjs3ZZgRjGa4Llf4WrFT271 51lLRPmHbPZr/o54QF9+6mgdob6tRGlCemFqfRbYcb7NoFZUN7N3o4YJDuDh1jSOx6wq8cFcxIh nol1X+/WAVs3W2DD0nB3MkRaWbejBAv03tzS25YlgyRes+ggtYedP7N67w/M777Nbp5rbhlWZSd bSKF+88vLzghrOV7V0bC8k78YEwIz3sWU1AmqO3nYjH5ciywfeYdQFGvEncUlgaBhIynRBm9oS5 +9TO6G16BeXNmWseiM/fm+HGBXiFXSwPnYTDCKiub/pyFKbIqEuNiqoaPUW5hZpMvT22cPnhKFR P6AsvYBgqoJBYIpz8kesabrM02cot+vJYZeYJIvwdXHCJCF/HA2ML0KHA6dRWg6SnzExh+xPiVh ja3fef4JhAnnINQ== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The 3c589 was written by David A. Hinds 2001. It is an PCMCIA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/3com/3c589_cs.c | 974 -------------------------------= ---- drivers/net/ethernet/3com/Kconfig | 10 - drivers/net/ethernet/3com/Makefile | 1 - 3 files changed, 985 deletions(-) diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3c= om/3c589_cs.c deleted file mode 100644 index ea49be43b8c3..000000000000 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ /dev/null @@ -1,974 +0,0 @@ -/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - * - * A PCMCIA ethernet driver for the 3com 3c589 card. - * - * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - * - * 3c589_cs.c 1.162 2001/10/13 00:08:50 - * - * The network driver code is based on Donald Becker's 3c589 code: - * - * Written 1994 by Donald Becker. - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. This software may be used and - * distributed according to the terms of the GNU General Public License, - * incorporated herein by reference. - * Donald Becker may be reached at becker@scyld.com - * - * Updated for 2.5.x by Alan Cox - * - * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DRV_NAME "3c589_cs" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -/* To minimize the size of the driver source I only define operating - * constants if they are used several times. You'll need the manual - * if you want to understand driver details. - */ - -/* Offsets from base I/O address. */ -#define EL3_DATA 0x00 -#define EL3_TIMER 0x0a -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -#define EEPROM_READ 0x0080 -#define EEPROM_BUSY 0x8000 - -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) - -/* The top five bits written to EL3_CMD are a command, the lower - * 11 bits are the parameter, if applicable. - */ - -enum c509cmd { - TotalReset =3D 0<<11, - SelectWindow =3D 1<<11, - StartCoax =3D 2<<11, - RxDisable =3D 3<<11, - RxEnable =3D 4<<11, - RxReset =3D 5<<11, - RxDiscard =3D 8<<11, - TxEnable =3D 9<<11, - TxDisable =3D 10<<11, - TxReset =3D 11<<11, - FakeIntr =3D 12<<11, - AckIntr =3D 13<<11, - SetIntrEnb =3D 14<<11, - SetStatusEnb =3D 15<<11, - SetRxFilter =3D 16<<11, - SetRxThreshold =3D 17<<11, - SetTxThreshold =3D 18<<11, - SetTxStart =3D 19<<11, - StatsEnable =3D 21<<11, - StatsDisable =3D 22<<11, - StopCoax =3D 23<<11 -}; - -enum c509status { - IntLatch =3D 0x0001, - AdapterFailure =3D 0x0002, - TxComplete =3D 0x0004, - TxAvailable =3D 0x0008, - RxComplete =3D 0x0010, - RxEarly =3D 0x0020, - IntReq =3D 0x0040, - StatsFull =3D 0x0080, - CmdBusy =3D 0x1000 -}; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation =3D 1, - RxMulticast =3D 2, - RxBroadcast =3D 4, - RxProm =3D 8 -}; - -/* Register window 1 offsets, the window used in normal operation. */ -#define TX_FIFO 0x00 -#define RX_FIFO 0x00 -#define RX_STATUS 0x08 -#define TX_STATUS 0x0B -#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ - -#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ -#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ -#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ -#define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */ - -/* Time in jiffies before concluding Tx hung */ -#define TX_TIMEOUT ((400*HZ)/1000) - -struct el3_private { - struct pcmcia_device *p_dev; - /* For transceiver monitoring */ - struct timer_list media; - u16 media_status; - u16 fast_poll; - unsigned long last_irq; - spinlock_t lock; -}; - -static const char *if_names[] =3D { "auto", "10baseT", "10base2", "AUI" }; - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n =3D v; module_param(n, int, 0) - -/* Special hook for setting if_port when module is loaded */ -INT_MODULE_PARM(if_port, 0); - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int tc589_config(struct pcmcia_device *link); -static void tc589_release(struct pcmcia_device *link); - -static u16 read_eeprom(unsigned int ioaddr, int index); -static void tc589_reset(struct net_device *dev); -static void media_check(struct timer_list *t); -static int el3_config(struct net_device *dev, struct ifmap *map); -static int el3_open(struct net_device *dev); -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t el3_interrupt(int irq, void *dev_id); -static void update_stats(struct net_device *dev); -static struct net_device_stats *el3_get_stats(struct net_device *dev); -static int el3_rx(struct net_device *dev); -static int el3_close(struct net_device *dev); -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue); -static void set_rx_mode(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static const struct ethtool_ops netdev_ethtool_ops; - -static void tc589_detach(struct pcmcia_device *p_dev); - -static const struct net_device_ops el3_netdev_ops =3D { - .ndo_open =3D el3_open, - .ndo_stop =3D el3_close, - .ndo_start_xmit =3D el3_start_xmit, - .ndo_tx_timeout =3D el3_tx_timeout, - .ndo_set_config =3D el3_config, - .ndo_get_stats =3D el3_get_stats, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - -static int tc589_probe(struct pcmcia_device *link) -{ - struct el3_private *lp; - struct net_device *dev; - int ret; - - dev_dbg(&link->dev, "3c589_attach()\n"); - - /* Create new ethernet device */ - dev =3D alloc_etherdev(sizeof(struct el3_private)); - if (!dev) - return -ENOMEM; - lp =3D netdev_priv(dev); - link->priv =3D dev; - lp->p_dev =3D link; - - spin_lock_init(&lp->lock); - link->resource[0]->end =3D 16; - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_16; - - link->config_flags |=3D CONF_ENABLE_IRQ; - link->config_index =3D 1; - - dev->netdev_ops =3D &el3_netdev_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - - dev->ethtool_ops =3D &netdev_ethtool_ops; - - ret =3D tc589_config(link); - if (ret) - goto err_free_netdev; - - return 0; - -err_free_netdev: - free_netdev(dev); - return ret; -} - -static void tc589_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - dev_dbg(&link->dev, "3c589_detach\n"); - - unregister_netdev(dev); - - tc589_release(link); - - free_netdev(dev); -} /* tc589_detach */ - -static int tc589_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - int ret, i, j, multi =3D 0, fifo; - __be16 addr[ETH_ALEN / 2]; - unsigned int ioaddr; - static const char * const ram_split[] =3D {"5:3", "3:1", "1:1", "3:5"}; - u8 *buf; - size_t len; - - dev_dbg(&link->dev, "3c589_config\n"); - - /* Is this a 3c562? */ - if (link->manf_id !=3D MANFID_3COM) - dev_info(&link->dev, "hmmm, is this really a 3Com card??\n"); - multi =3D (link->card_id =3D=3D PRODID_3COM_3C562); - - link->io_lines =3D 16; - - /* For the 3c562, the base address must be xx00-xx7f */ - for (i =3D j =3D 0; j < 0x400; j +=3D 0x10) { - if (multi && (j & 0x80)) - continue; - link->resource[0]->start =3D j ^ 0x300; - i =3D pcmcia_request_io(link); - if (i =3D=3D 0) - break; - } - if (i !=3D 0) - goto failed; - - ret =3D pcmcia_request_irq(link, el3_interrupt); - if (ret) - goto failed; - - ret =3D pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq =3D link->irq; - dev->base_addr =3D link->resource[0]->start; - ioaddr =3D dev->base_addr; - EL3WINDOW(0); - - /* The 3c589 has an extra EEPROM for configuration info, including - * the hardware address. The 3c562 puts the address in the CIS. - */ - len =3D pcmcia_get_tuple(link, 0x88, &buf); - if (buf && len >=3D 6) { - for (i =3D 0; i < 3; i++) - addr[i] =3D htons(le16_to_cpu(buf[i*2])); - kfree(buf); - } else { - kfree(buf); /* 0 < len < 6 */ - for (i =3D 0; i < 3; i++) - addr[i] =3D htons(read_eeprom(ioaddr, i)); - if (addr[0] =3D=3D htons(0x6060)) { - dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n", - dev->base_addr, dev->base_addr+15); - goto failed; - } - } - eth_hw_addr_set(dev, (u8 *)addr); - - /* The address and resource configuration register aren't loaded from - * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. - */ - - outw(0x3f00, ioaddr + 8); - fifo =3D inl(ioaddr); - - /* The if_port symbol can be set when the module is loaded */ - if ((if_port >=3D 0) && (if_port <=3D 3)) - dev->if_port =3D if_port; - else - dev_err(&link->dev, "invalid if_port requested\n"); - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) !=3D 0) { - dev_err(&link->dev, "register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n", - (multi ? "562" : "589"), dev->base_addr, dev->irq, - dev->dev_addr); - netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n", - (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], - if_names[dev->if_port]); - return 0; - -failed: - tc589_release(link); - return -ENODEV; -} /* tc589_config */ - -static void tc589_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int tc589_suspend(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int tc589_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) { - tc589_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Use this for commands that may take time to finish */ - -static void tc589_wait_for_completion(struct net_device *dev, int cmd) -{ - int i =3D 100; - outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) - break; - if (i =3D=3D 0) - netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); -} - -/* Read a word from the EEPROM using the regular EEPROM access register. - * Assume that we are in register window zero. - */ - -static u16 read_eeprom(unsigned int ioaddr, int index) -{ - int i; - outw(EEPROM_READ + index, ioaddr + 10); - /* Reading the eeprom takes 162 us */ - for (i =3D 1620; i >=3D 0; i--) - if ((inw(ioaddr + 10) & EEPROM_BUSY) =3D=3D 0) - break; - return inw(ioaddr + 12); -} - -/* Set transceiver type, perhaps to something other than what the user - * specified in dev->if_port. - */ - -static void tc589_set_xcvr(struct net_device *dev, int if_port) -{ - struct el3_private *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - - EL3WINDOW(0); - switch (if_port) { - case 0: - case 1: - outw(0, ioaddr + 6); - break; - case 2: - outw(3<<14, ioaddr + 6); - break; - case 3: - outw(1<<14, ioaddr + 6); - break; - } - /* On PCMCIA, this just turns on the LED */ - outw((if_port =3D=3D 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); - /* 10baseT interface, enable link beat and jabber check. */ - EL3WINDOW(4); - outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); - EL3WINDOW(1); - if (if_port =3D=3D 2) - lp->media_status =3D ((dev->if_port =3D=3D 0) ? 0x8000 : 0x4000); - else - lp->media_status =3D ((dev->if_port =3D=3D 0) ? 0x4010 : 0x8800); -} - -static void dump_status(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - EL3WINDOW(1); - netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx f= ree %04x\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), - inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); - EL3WINDOW(4); - netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %= 04x\n", - inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), - inw(ioaddr+0x0a)); - EL3WINDOW(1); -} - -/* Reset and restore all of the 3c589 registers. */ -static void tc589_reset(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - int i; - - EL3WINDOW(0); - outw(0x0001, ioaddr + 4); /* Activate board. */ - outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ - - /* Set the station address in window 2. */ - EL3WINDOW(2); - for (i =3D 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - - tc589_set_xcvr(dev, dev->if_port); - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i =3D 0; i < 9; i++) - inb(ioaddr+i); - inw(ioaddr + 10); - inw(ioaddr + 12); - - /* Switch to register set 1 for normal use. */ - EL3WINDOW(1); - - set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | AdapterFailure, ioaddr + EL3_CMD); -} - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - snprintf(info->bus_info, sizeof(info->bus_info), - "PCMCIA 0x%lx", dev->base_addr); -} - -static const struct ethtool_ops netdev_ethtool_ops =3D { - .get_drvinfo =3D netdev_get_drvinfo, -}; - -static int el3_config(struct net_device *dev, struct ifmap *map) -{ - if ((map->port !=3D (u_char)(-1)) && (map->port !=3D dev->if_port)) { - if (map->port <=3D 3) { - WRITE_ONCE(dev->if_port, map->port); - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - tc589_set_xcvr(dev, dev->if_port); - } else { - return -EINVAL; - } - } - return 0; -} - -static int el3_open(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - link->open++; - netif_start_queue(dev); - - tc589_reset(dev); - timer_setup(&lp->media, media_check, 0); - mod_timer(&lp->media, jiffies + HZ); - - dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", - dev->name, inw(dev->base_addr + EL3_STATUS)); - - return 0; -} - -static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - unsigned int ioaddr =3D dev->base_addr; - - netdev_warn(dev, "Transmit timed out!\n"); - dump_status(dev); - dev->stats.tx_errors++; - netif_trans_update(dev); /* prevent tx timeout */ - /* Issue TX_RESET and TX_START commands. */ - tc589_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - netif_wake_queue(dev); -} - -static void pop_tx_status(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - int i; - - /* Clear the Tx status stack. */ - for (i =3D 32; i > 0; i--) { - u_char tx_status =3D inb(ioaddr + TX_STATUS); - if (!(tx_status & 0x84)) - break; - /* reset transmitter on jabber error or underrun */ - if (tx_status & 0x30) - tc589_wait_for_completion(dev, TxReset); - if (tx_status & 0x38) { - netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status); - outw(TxEnable, ioaddr + EL3_CMD); - dev->stats.tx_aborted_errors++; - } - outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ - } -} - -static netdev_tx_t el3_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct el3_private *priv =3D netdev_priv(dev); - unsigned long flags; - - netdev_dbg(dev, "el3_start_xmit(length =3D %ld) called, status %4.4x.\n", - (long)skb->len, inw(ioaddr + EL3_STATUS)); - - spin_lock_irqsave(&priv->lock, flags); - - dev->stats.tx_bytes +=3D skb->len; - - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0x00, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - - if (inw(ioaddr + TX_FREE) <=3D 1536) { - netif_stop_queue(dev); - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); - } - - pop_tx_status(dev); - spin_unlock_irqrestore(&priv->lock, flags); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -/* The EL3 interrupt handler. */ -static irqreturn_t el3_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D (struct net_device *) dev_id; - struct el3_private *lp =3D netdev_priv(dev); - unsigned int ioaddr; - __u16 status; - int i =3D 0, handled =3D 1; - - if (!netif_device_present(dev)) - return IRQ_NONE; - - ioaddr =3D dev->base_addr; - - netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); - - spin_lock(&lp->lock); - while ((status =3D inw(ioaddr + EL3_STATUS)) & - (IntLatch | RxComplete | StatsFull)) { - if ((status & 0xe000) !=3D 0x2000) { - netdev_dbg(dev, "interrupt from dead card\n"); - handled =3D 0; - break; - } - if (status & RxComplete) - el3_rx(dev); - if (status & TxAvailable) { - netdev_dbg(dev, " TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); - } - if (status & TxComplete) - pop_tx_status(dev); - if (status & (AdapterFailure | RxEarly | StatsFull)) { - /* Handle all uncommon interrupts. */ - if (status & StatsFull) /* Empty statistics. */ - update_stats(dev); - if (status & RxEarly) { - /* Rx early is unused. */ - el3_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & AdapterFailure) { - u16 fifo_diag; - EL3WINDOW(4); - fifo_diag =3D inw(ioaddr + 4); - EL3WINDOW(1); - netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", - fifo_diag); - if (fifo_diag & 0x0400) { - /* Tx overrun */ - tc589_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - } - if (fifo_diag & 0x2000) { - /* Rx underrun */ - tc589_wait_for_completion(dev, RxReset); - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); - } - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); - } - } - if (++i > 10) { - netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", - status); - /* Clear all interrupts */ - outw(AckIntr | 0xFF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } - lp->last_irq =3D jiffies; - spin_unlock(&lp->lock); - netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", - inw(ioaddr + EL3_STATUS)); - return IRQ_RETVAL(handled); -} - -static void media_check(struct timer_list *t) -{ - struct el3_private *lp =3D timer_container_of(lp, t, media); - struct net_device *dev =3D lp->p_dev->priv; - unsigned int ioaddr =3D dev->base_addr; - u16 media, errs; - unsigned long flags; - - if (!netif_device_present(dev)) - goto reschedule; - - /* Check for pending interrupt with expired latency timer: with - * this, we can limp along even if the interrupt is blocked - */ - if ((inw(ioaddr + EL3_STATUS) & IntLatch) && - (inb(ioaddr + EL3_TIMER) =3D=3D 0xff)) { - if (!lp->fast_poll) - netdev_warn(dev, "interrupt(s) dropped!\n"); - - local_irq_save(flags); - el3_interrupt(dev->irq, dev); - local_irq_restore(flags); - - lp->fast_poll =3D HZ; - } - if (lp->fast_poll) { - lp->fast_poll--; - lp->media.expires =3D jiffies + HZ/100; - add_timer(&lp->media); - return; - } - - /* lp->lock guards the EL3 window. Window should always be 1 except - * when the lock is held - */ - - spin_lock_irqsave(&lp->lock, flags); - EL3WINDOW(4); - media =3D inw(ioaddr+WN4_MEDIA) & 0xc810; - - /* Ignore collisions unless we've had no irq's recently */ - if (time_before(jiffies, lp->last_irq + HZ)) { - media &=3D ~0x0010; - } else { - /* Try harder to detect carrier errors */ - EL3WINDOW(6); - outw(StatsDisable, ioaddr + EL3_CMD); - errs =3D inb(ioaddr + 0); - outw(StatsEnable, ioaddr + EL3_CMD); - dev->stats.tx_carrier_errors +=3D errs; - if (errs || (lp->media_status & 0x0010)) - media |=3D 0x0010; - } - - if (media !=3D lp->media_status) { - if ((media & lp->media_status & 0x8000) && - ((lp->media_status ^ media) & 0x0800)) - netdev_info(dev, "%s link beat\n", - (lp->media_status & 0x0800 ? "lost" : "found")); - else if ((media & lp->media_status & 0x4000) && - ((lp->media_status ^ media) & 0x0010)) - netdev_info(dev, "coax cable %s\n", - (lp->media_status & 0x0010 ? "ok" : "problem")); - if (dev->if_port =3D=3D 0) { - if (media & 0x8000) { - if (media & 0x0800) - netdev_info(dev, "flipped to 10baseT\n"); - else - tc589_set_xcvr(dev, 2); - } else if (media & 0x4000) { - if (media & 0x0010) - tc589_set_xcvr(dev, 1); - else - netdev_info(dev, "flipped to 10base2\n"); - } - } - lp->media_status =3D media; - } - - EL3WINDOW(1); - spin_unlock_irqrestore(&lp->lock, flags); - -reschedule: - lp->media.expires =3D jiffies + HZ; - add_timer(&lp->media); -} - -static struct net_device_stats *el3_get_stats(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link =3D lp->p_dev; - - if (pcmcia_dev_present(link)) { - spin_lock_irqsave(&lp->lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->lock, flags); - } - return &dev->stats; -} - -/* Update statistics. We change to register window 6, so this should be r= un -* single-threaded if the device is active. This is expected to be a rare -* operation, and it's simpler for the rest of the driver to assume that -* window 1 is always valid rather than use a special window-state variable. -* -* Caller must hold the lock for this -*/ - -static void update_stats(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - - netdev_dbg(dev, "updating the statistics.\n"); - /* Turn off statistics updates while reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors +=3D inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors +=3D inb(ioaddr + 1); - /* Multiple collisions. */ - inb(ioaddr + 2); - dev->stats.collisions +=3D inb(ioaddr + 3); - dev->stats.tx_window_errors +=3D inb(ioaddr + 4); - dev->stats.rx_fifo_errors +=3D inb(ioaddr + 5); - dev->stats.tx_packets +=3D inb(ioaddr + 6); - /* Rx packets */ - inb(ioaddr + 7); - /* Tx deferrals */ - inb(ioaddr + 8); - /* Rx octets */ - inw(ioaddr + 10); - /* Tx octets */ - inw(ioaddr + 12); - - /* Back to window 1, and turn statistics back on. */ - EL3WINDOW(1); - outw(StatsEnable, ioaddr + EL3_CMD); -} - -static int el3_rx(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - int worklimit =3D 32; - short rx_status; - - netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); - while (!((rx_status =3D inw(ioaddr + RX_STATUS)) & 0x8000) && - worklimit > 0) { - worklimit--; - if (rx_status & 0x4000) { /* Error, update stats. */ - short error =3D rx_status & 0x3800; - dev->stats.rx_errors++; - switch (error) { - case 0x0000: - dev->stats.rx_over_errors++; - break; - case 0x0800: - dev->stats.rx_length_errors++; - break; - case 0x1000: - dev->stats.rx_frame_errors++; - break; - case 0x1800: - dev->stats.rx_length_errors++; - break; - case 0x2000: - dev->stats.rx_frame_errors++; - break; - case 0x2800: - dev->stats.rx_crc_errors++; - break; - } - } else { - short pkt_len =3D rx_status & 0x7ff; - struct sk_buff *skb; - - skb =3D netdev_alloc_skb(dev, pkt_len + 5); - - netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb !=3D NULL) { - skb_reserve(skb, 2); - insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), - (pkt_len+3)>>2); - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pkt_len; - } else { - netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n", - pkt_len); - dev->stats.rx_dropped++; - } - } - /* Pop the top of the Rx FIFO */ - tc589_wait_for_completion(dev, RxDiscard); - } - if (worklimit =3D=3D 0) - netdev_warn(dev, "too much work in el3_rx!\n"); - return 0; -} - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - u16 opts =3D SetRxFilter | RxStation | RxBroadcast; - - if (dev->flags & IFF_PROMISC) - opts |=3D RxMulticast | RxProm; - else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) - opts |=3D RxMulticast; - outw(opts, ioaddr + EL3_CMD); -} - -static void set_multicast_list(struct net_device *dev) -{ - struct el3_private *priv =3D netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - set_rx_mode(dev); - spin_unlock_irqrestore(&priv->lock, flags); -} - -static int el3_close(struct net_device *dev) -{ - struct el3_private *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - unsigned int ioaddr =3D dev->base_addr; - - dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); - - if (pcmcia_dev_present(link)) { - /* Turn off statistics ASAP. We update dev->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port =3D=3D 2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port =3D=3D 1) { - /* Disable link beat and jabber */ - EL3WINDOW(4); - outw(0, ioaddr + WN4_MEDIA); - } - - /* Switching back to window 0 disables the IRQ. */ - EL3WINDOW(0); - /* But we explicitly zero the IRQ line select anyway. */ - outw(0x0f00, ioaddr + WN0_IRQ); - - /* Check if the card still exists */ - if ((inw(ioaddr+EL3_STATUS) & 0xe000) =3D=3D 0x2000) - update_stats(dev); - } - - link->open--; - netif_stop_queue(dev); - timer_delete_sync(&lp->media); - - return 0; -} - -static const struct pcmcia_device_id tc589_ids[] =3D { - PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562), - PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77), - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589), - PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, tc589_ids); - -static struct pcmcia_driver tc589_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "3c589_cs", - .probe =3D tc589_probe, - .remove =3D tc589_detach, - .id_table =3D tc589_ids, - .suspend =3D tc589_suspend, - .resume =3D tc589_resume, -}; -module_pcmcia_driver(tc589_driver); diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/= Kconfig index 294403ad7141..399cb6c56198 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -17,16 +17,6 @@ config NET_VENDOR_3COM =20 if NET_VENDOR_3COM =20 -config PCMCIA_3C589 - tristate "3Com 3c589 PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA - (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called 3c589_cs. If unsure, say N. - config VORTEX tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support" depends on (PCI || EISA) && HAS_IOPORT_MAP diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com= /Makefile index 45fb9af9b5c7..5c4d07f1d456 100644 --- a/drivers/net/ethernet/3com/Makefile +++ b/drivers/net/ethernet/3com/Makefile @@ -3,6 +3,5 @@ # Makefile for the 3Com Ethernet device drivers # =20 -obj-$(CONFIG_PCMCIA_3C589) +=3D 3c589_cs.o obj-$(CONFIG_VORTEX) +=3D 3c59x.o obj-$(CONFIG_TYPHOON) +=3D typhoon.o --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 45A4A3DCDB9; Tue, 21 Apr 2026 19:31:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799906; cv=none; b=Y3wX1ZwlL7FwDYj1rv8aHcAJHvSXMg8ty4v1Maj+BwzAESmznbUieaXLtBjbsx8IJ/n7NBhnNE3LtIvL0aaSzjl0iwakBrXZ0SibkXNNrjZTaOYhcqUkT2q5rLW9z7kb6tsvJzbOu4c81u8rEHamH9lPQleKzlTbzeHIMG2sZNo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799906; c=relaxed/simple; bh=oTa4HwxdwHnXo6iH9VwBQOxSzRNgJH2ZwBa81Z5Q24U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KkPCFC2bV/qe2937pyg4L+bGq0JUSNCioFlixSGGr633QQkxdlOgTDPq9trFnmWTDJ7n2qMYWr+Rwdl7EmJwJ2ZTBr06XJmh/41eAc/57IPRmO2PHSzAiD/ByIKwJ/OPbqalubxy+dtBeaHmnDDpXjPpJ4OpzkoKTNFCyarJG0A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=r3fzcS7A; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="r3fzcS7A" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=gGvWYD6DOWbSDT8E5MCrANL/z20tiJ+c+AL0zJEjSrw=; b=r3 fzcS7ALhd27UqZwqJXEmZ4nT+bbZrKV7rzDnI9P/3lSCK0wezpo68vrhvwjurjBR1cLBK5CA6mNT1 7Tdn+P0Q5Z+MeYwINnc/NqN3/O8vTn5UsUBisFsNcGiGQ1lxDAgvUerp1DenLOfE6YSWTr3Xy/sFh Gygz9O+oU/HA0vE=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGoj-00GwVc-GH; Tue, 21 Apr 2026 21:31:29 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:08 -0500 Subject: [PATCH net 05/18] drivers: net: 3com: 3c59x: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-5-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=131054; i=andrew@lunn.ch; h=from:subject:message-id; bh=oTa4HwxdwHnXo6iH9VwBQOxSzRNgJH2ZwBa81Z5Q24U=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CBLpLmoh1f0vnfkdG07kBjIau5VEfeHUZlG xfq+3FPj5OJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hBRpD/0ew0+OnvGReVfSYS5gbdIeg+wqogQ6XsOdPTqjhQ72EjyhVzfRMXVxiXo3P4P0cakg2/H 2HyKF+CFIreFSCdx7TmM4lI9T1/pjM88cNYK9n28PdUQZ03KbdAvGULPQ693bDzsMXI5YVIERnz sTouT+S5gLxxhqM13WSQchP4KB+NSOuUD4gO+GXHplgFBTTkeoV/RRW5QBl2NZEFh1FeGjgftX7 bUueQ0HqZxu2Nqiv97z/lEfPXpRV29V8RkhU1D8DMRTE0+gEWm02OLUdw3ICxdbGqzDKN7m829O LQGtAHKj1ckCChwY66Z9AjGyQ2cHEKDN+wS/odh7vUfp1tCwVoZqBhOSy/tZ/hM7DCfzd2atzX4 Bm86mjeTDENojjxFeLYDjkFX/BEhuV7lStlXcn7Smav/LLS51s7EzTwVGWqIqybGaXA9bsva3aA Yrp6NrMIXwR9b62J9FOjH/VhFUuxW3Y33Vkvy+McqxjPlT6BCm3Jnzu+C/q36kquCWG0lZWC/kl fP3XZh66E+JszK4pDpRc2QzMjyxoRhEsMUbpuY6DT0+UZGTgT+BBOTxfBUj8jqRbDaXdhQkw6hi gAy/I3+W6WbOZvkZWHtJRsjtgKWCITxgrcNe4evaCxFkIyW41lcRgNy1g0AvNzaooRNTlsBnVIH hctItDIjjva3llQ== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The 3c59x was written by Donald Becker between 1996-1999. It is an EISA and PCI Fast Ethernet device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- .../device_drivers/ethernet/3com/vortex.rst | 459 --- MAINTAINERS | 7 - drivers/net/ethernet/3com/3c59x.c | 3357 ----------------= ---- drivers/net/ethernet/3com/Kconfig | 21 - drivers/net/ethernet/3com/Makefile | 1 - 5 files changed, 3845 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/3com/vortex.r= st b/Documentation/networking/device_drivers/ethernet/3com/vortex.rst deleted file mode 100644 index a060f84c4f96..000000000000 --- a/Documentation/networking/device_drivers/ethernet/3com/vortex.rst +++ /dev/null @@ -1,459 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D -3Com Vortex device driver -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D - -Andrew Morton - -30 April 2000 - - -This document describes the usage and errata of the 3Com "Vortex" device -driver for Linux, 3c59x.c. - -The driver was written by Donald Becker - -Don is no longer the prime maintainer of this version of the driver. -Please report problems to one or more of: - -- Andrew Morton -- Netdev mailing list -- Linux kernel mailing list - -Please note the 'Reporting and Diagnosing Problems' section at the end -of this file. - - -Since kernel 2.3.99-pre6, this driver incorporates the support for the -3c575-series Cardbus cards which used to be handled by 3c575_cb.c. - -This driver supports the following hardware: - - - 3c590 Vortex 10Mbps - - 3c592 EISA 10Mbps Demon/Vortex - - 3c597 EISA Fast Demon/Vortex - - 3c595 Vortex 100baseTx - - 3c595 Vortex 100baseT4 - - 3c595 Vortex 100base-MII - - 3c900 Boomerang 10baseT - - 3c900 Boomerang 10Mbps Combo - - 3c900 Cyclone 10Mbps TPO - - 3c900 Cyclone 10Mbps Combo - - 3c900 Cyclone 10Mbps TPC - - 3c900B-FL Cyclone 10base-FL - - 3c905 Boomerang 100baseTx - - 3c905 Boomerang 100baseT4 - - 3c905B Cyclone 100baseTx - - 3c905B Cyclone 10/100/BNC - - 3c905B-FX Cyclone 100baseFx - - 3c905C Tornado - - 3c920B-EMB-WNM (ATI Radeon 9100 IGP) - - 3c980 Cyclone - - 3c980C Python-T - - 3cSOHO100-TX Hurricane - - 3c555 Laptop Hurricane - - 3c556 Laptop Tornado - - 3c556B Laptop Hurricane - - 3c575 [Megahertz] 10/100 LAN CardBus - - 3c575 Boomerang CardBus - - 3CCFE575BT Cyclone CardBus - - 3CCFE575CT Tornado CardBus - - 3CCFE656 Cyclone CardBus - - 3CCFEM656B Cyclone+Winmodem CardBus - - 3CXFEM656C Tornado+Winmodem CardBus - - 3c450 HomePNA Tornado - - 3c920 Tornado - - 3c982 Hydra Dual Port A - - 3c982 Hydra Dual Port B - - 3c905B-T4 - - 3c920B-EMB-WNM Tornado - -Module parameters -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - -There are several parameters which may be provided to the driver when -its module is loaded. These are usually placed in ``/etc/modprobe.d/*.con= f`` -configuration files. Example:: - - options 3c59x debug=3D3 rx_copybreak=3D300 - -If you are using the PCMCIA tools (cardmgr) then the options may be -placed in /etc/pcmcia/config.opts:: - - module "3c59x" opts "debug=3D3 rx_copybreak=3D300" - - -The supported parameters are: - -debug=3DN - - Where N is a number from 0 to 7. Anything above 3 produces a lot - of output in your system logs. debug=3D1 is default. - -options=3DN1,N2,N3,... - - Each number in the list provides an option to the corresponding - network card. So if you have two 3c905's and you wish to provide - them with option 0x204 you would use:: - - options=3D0x204,0x204 - - The individual options are composed of a number of bitfields which - have the following meanings: - - Possible media type settings - - =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - 0 10baseT - 1 10Mbs AUI - 2 undefined - 3 10base2 (BNC) - 4 100base-TX - 5 100base-FX - 6 MII (Media Independent Interface) - 7 Use default setting from EEPROM - 8 Autonegotiate - 9 External MII - 10 Use default setting from EEPROM - =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - When generating a value for the 'options' setting, the above media - selection values may be OR'ed (or added to) the following: - - =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D - 0x8000 Set driver debugging level to 7 - 0x4000 Set driver debugging level to 2 - 0x0400 Enable Wake-on-LAN - 0x0200 Force full duplex mode. - 0x0010 Bus-master enable bit (Old Vortex cards only) - =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D - - For example:: - - insmod 3c59x options=3D0x204 - - will force full-duplex 100base-TX, rather than allowing the usual - autonegotiation. - -global_options=3DN - - Sets the ``options`` parameter for all 3c59x NICs in the machine. - Entries in the ``options`` array above will override any setting of - this. - -full_duplex=3DN1,N2,N3... - - Similar to bit 9 of 'options'. Forces the corresponding card into - full-duplex mode. Please use this in preference to the ``options`` - parameter. - - In fact, please don't use this at all! You're better off getting - autonegotiation working properly. - -global_full_duplex=3DN1 - - Sets full duplex mode for all 3c59x NICs in the machine. Entries - in the ``full_duplex`` array above will override any setting of this. - -flow_ctrl=3DN1,N2,N3... - - Use 802.3x MAC-layer flow control. The 3com cards only support the - PAUSE command, which means that they will stop sending packets for a - short period if they receive a PAUSE frame from the link partner. - - The driver only allows flow control on a link which is operating in - full duplex mode. - - This feature does not appear to work on the 3c905 - only 3c905B and - 3c905C have been tested. - - The 3com cards appear to only respond to PAUSE frames which are - sent to the reserved destination address of 01:80:c2:00:00:01. They - do not honour PAUSE frames which are sent to the station MAC address. - -rx_copybreak=3DM - - The driver preallocates 32 full-sized (1536 byte) network buffers - for receiving. When a packet arrives, the driver has to decide - whether to leave the packet in its full-sized buffer, or to allocate - a smaller buffer and copy the packet across into it. - - This is a speed/space tradeoff. - - The value of rx_copybreak is used to decide when to make the copy. - If the packet size is less than rx_copybreak, the packet is copied. - The default value for rx_copybreak is 200 bytes. - -max_interrupt_work=3DN - - The driver's interrupt service routine can handle many receive and - transmit packets in a single invocation. It does this in a loop. - The value of max_interrupt_work governs how many times the interrupt - service routine will loop. The default value is 32 loops. If this - is exceeded the interrupt service routine gives up and generates a - warning message "eth0: Too much work in interrupt". - -hw_checksums=3DN1,N2,N3,... - - Recent 3com NICs are able to generate IPv4, TCP and UDP checksums - in hardware. Linux has used the Rx checksumming for a long time. - The "zero copy" patch which is planned for the 2.4 kernel series - allows you to make use of the NIC's DMA scatter/gather and transmit - checksumming as well. - - The driver is set up so that, when the zerocopy patch is applied, - all Tornado and Cyclone devices will use S/G and Tx checksums. - - This module parameter has been provided so you can override this - decision. If you think that Tx checksums are causing a problem, you - may disable the feature with ``hw_checksums=3D0``. - - If you think your NIC should be performing Tx checksumming and the - driver isn't enabling it, you can force the use of hardware Tx - checksumming with ``hw_checksums=3D1``. - - The driver drops a message in the logfiles to indicate whether or - not it is using hardware scatter/gather and hardware Tx checksums. - - Scatter/gather and hardware checksums provide considerable - performance improvement for the sendfile() system call, but a small - decrease in throughput for send(). There is no effect upon receive - efficiency. - -compaq_ioaddr=3DN, -compaq_irq=3DN, -compaq_device_id=3DN - - "Variables to work-around the Compaq PCI BIOS32 problem".... - -watchdog=3DN - - Sets the time duration (in milliseconds) after which the kernel - decides that the transmitter has become stuck and needs to be reset. - This is mainly for debugging purposes, although it may be advantageous - to increase this value on LANs which have very high collision rates. - The default value is 5000 (5.0 seconds). - -enable_wol=3DN1,N2,N3,... - - Enable Wake-on-LAN support for the relevant interface. Donald - Becker's ``ether-wake`` application may be used to wake suspended - machines. - - Also enables the NIC's power management support. - -global_enable_wol=3DN - - Sets enable_wol mode for all 3c59x NICs in the machine. Entries in - the ``enable_wol`` array above will override any setting of this. - -Media selection ---------------- - -A number of the older NICs such as the 3c590 and 3c900 series have -10base2 and AUI interfaces. - -Prior to January, 2001 this driver would autoselect the 10base2 or AUI -port if it didn't detect activity on the 10baseT port. It would then -get stuck on the 10base2 port and a driver reload was necessary to -switch back to 10baseT. This behaviour could not be prevented with a -module option override. - -Later (current) versions of the driver _do_ support locking of the -media type. So if you load the driver module with - - modprobe 3c59x options=3D0 - -it will permanently select the 10baseT port. Automatic selection of -other media types does not occur. - - -Transmit error, Tx status register 82 -------------------------------------- - -This is a common error which is almost always caused by another host on -the same network being in full-duplex mode, while this host is in -half-duplex mode. You need to find that other host and make it run in -half-duplex mode or fix this host to run in full-duplex mode. - -As a last resort, you can force the 3c59x driver into full-duplex mode -with - - options 3c59x full_duplex=3D1 - -but this has to be viewed as a workaround for broken network gear and -should only really be used for equipment which cannot autonegotiate. - - -Additional resources --------------------- - -Details of the device driver implementation are at the top of the source f= ile. - -Additional documentation is available at Don Becker's Linux Drivers site: - - http://www.scyld.com/vortex.html - -Donald Becker's driver development site: - - http://www.scyld.com/network.html - -Donald's vortex-diag program is useful for inspecting the NIC's state: - - http://www.scyld.com/ethercard_diag.html - -Donald's mii-diag program may be used for inspecting and manipulating -the NIC's Media Independent Interface subsystem: - - http://www.scyld.com/ethercard_diag.html#mii-diag - -Donald's wake-on-LAN page: - - http://www.scyld.com/wakeonlan.html - -3Com's DOS-based application for setting up the NICs EEPROMs: - - ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe - - -Autonegotiation notes ---------------------- - - The driver uses a one-minute heartbeat for adapting to changes in - the external LAN environment if link is up and 5 seconds if link is down. - This means that when, for example, a machine is unplugged from a hubbed - 10baseT LAN plugged into a switched 100baseT LAN, the throughput - will be quite dreadful for up to sixty seconds. Be patient. - - Cisco interoperability note from Walter Wong : - - On a side note, adding HAS_NWAY seems to share a problem with the - Cisco 6509 switch. Specifically, you need to change the spanning - tree parameter for the port the machine is plugged into to 'portfast' - mode. Otherwise, the negotiation fails. This has been an issue - we've noticed for a while but haven't had the time to track down. - - Cisco switches (Jeff Busch ) - - My "standard config" for ports to which PC's/servers connect directly:: - - interface FastEthernet0/N - description machinename - load-interval 30 - spanning-tree portfast - - If autonegotiation is a problem, you may need to specify "speed - 100" and "duplex full" as well (or "speed 10" and "duplex half"). - - WARNING: DO NOT hook up hubs/switches/bridges to these - specially-configured ports! The switch will become very confused. - - -Reporting and diagnosing problems ---------------------------------- - -Maintainers find that accurate and complete problem reports are -invaluable in resolving driver problems. We are frequently not able to -reproduce problems and must rely on your patience and efforts to get to -the bottom of the problem. - -If you believe you have a driver problem here are some of the -steps you should take: - -- Is it really a driver problem? - - Eliminate some variables: try different cards, different - computers, different cables, different ports on the switch/hub, - different versions of the kernel or of the driver, etc. - -- OK, it's a driver problem. - - You need to generate a report. Typically this is an email to the - maintainer and/or netdev@vger.kernel.org. The maintainer's - email address will be in the driver source or in the MAINTAINERS file. - -- The contents of your report will vary a lot depending upon the - problem. If it's a kernel crash then you should refer to - 'Documentation/admin-guide/reporting-issues.rst'. - - But for most problems it is useful to provide the following: - - - Kernel version, driver version - - - A copy of the banner message which the driver generates when - it is initialised. For example: - - eth0: 3Com PCI 3c905C Tornado at 0xa400, 00:50:da:6a:88:f0, IRQ 19 - 8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface. - MII transceiver found at address 24, status 782d. - Enabling bus-master transmits and whole-frame receives. - - NOTE: You must provide the ``debug=3D2`` modprobe option to generate - a full detection message. Please do this:: - - modprobe 3c59x debug=3D2 - - - If it is a PCI device, the relevant output from 'lspci -vx', eg:: - - 00:09.0 Ethernet controller: 3Com Corporation 3c905C-TX [Fast Ether= link] (rev 74) - Subsystem: 3Com Corporation: Unknown device 9200 - Flags: bus master, medium devsel, latency 32, IRQ 19 - I/O ports at a400 [size=3D128] - Memory at db000000 (32-bit, non-prefetchable) [size=3D128] - Expansion ROM at [disabled] [size=3D128K] - Capabilities: [dc] Power Management version 2 - 00: b7 10 00 92 07 00 10 02 74 00 00 02 08 20 00 00 - 10: 01 a4 00 00 00 00 00 db 00 00 00 00 00 00 00 00 - 20: 00 00 00 00 00 00 00 00 00 00 00 00 b7 10 00 10 - 30: 00 00 00 00 dc 00 00 00 00 00 00 00 05 01 0a 0a - - - A description of the environment: 10baseT? 100baseT? - full/half duplex? switched or hubbed? - - - Any additional module parameters which you may be providing to the dr= iver. - - - Any kernel logs which are produced. The more the merrier. - If this is a large file and you are sending your report to a - mailing list, mention that you have the logfile, but don't send - it. If you're reporting direct to the maintainer then just send - it. - - To ensure that all kernel logs are available, add the - following line to /etc/syslog.conf:: - - kern.* /var/log/messages - - Then restart syslogd with:: - - /etc/rc.d/init.d/syslog restart - - (The above may vary, depending upon which Linux distribution you use). - - - If your problem is reproducible then that's great. Try the - following: - - 1) Increase the debug level. Usually this is done via: - - a) modprobe driver debug=3D7 - b) In /etc/modprobe.d/driver.conf: - options driver debug=3D7 - - 2) Recreate the problem with the higher debug level, - send all logs to the maintainer. - - 3) Download you card's diagnostic tool from Donald - Becker's website . - Download mii-diag.c as well. Build these. - - a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is - working correctly. Save the output. - - b) Run the above commands when the card is malfunctioning. Send - both sets of output. - -Finally, please be patient and be prepared to do some work. You may -end up working on this problem for a week or more as the maintainer -asks more questions, asks for more tests, asks for patches to be -applied, etc. At the end of it all, the problem may even remain -unresolved. diff --git a/MAINTAINERS b/MAINTAINERS index e7dc9e6fad2e..188b10f2c859 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -67,13 +67,6 @@ Maintainers List first. When adding to this list, please keep the entries in alphabetical order. =20 -3C59X NETWORK DRIVER -M: Steffen Klassert -L: netdev@vger.kernel.org -S: Odd Fixes -F: Documentation/networking/device_drivers/ethernet/3com/vortex.rst -F: drivers/net/ethernet/3com/3c59x.c - 3CR990 NETWORK DRIVER M: David Dillow L: netdev@vger.kernel.org diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/= 3c59x.c deleted file mode 100644 index 4fe4efdb3737..000000000000 --- a/drivers/net/ethernet/3com/3c59x.c +++ /dev/null @@ -1,3357 +0,0 @@ -/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ -/* - Written 1996-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - This driver is for the 3Com "Vortex" and "Boomerang" series ethercards. - Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597 - and the EtherLink XL 3c900 and 3c905 cards. - - Problem reports and questions should be directed to - vortex@scyld.com - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - -*/ - -/* - * FIXME: This driver _could_ support MTU changing, but doesn't. See Don'= s hamachi.c implementation - * as well as other drivers - * - * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) th= e driver shrinks by 2k - * due to dead code elimination. There will be some performance benefits = from this due to - * elimination of all the tests and reduced cache footprint. - */ - - -#define DRV_NAME "3c59x" - - - -/* A few values that may be tweaked. */ -/* Keep the ring sizes a power of two for efficiency. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ - -/* "Knobs" that adjust features and parameters. */ -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1512 effectively disables this feature. */ -#ifndef __arm__ -static int rx_copybreak =3D 200; -#else -/* ARM systems perform better by disregarding the bus-master - transfer capability of these cards. -- rmk */ -static int rx_copybreak =3D 1513; -#endif -/* Allow setting MTU to a larger size, bypassing the normal ethernet setup= . */ -static const int mtu =3D 1500; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work =3D 32; -/* Tx timeout interval (millisecs) */ -static int watchdog =3D 5000; - -/* Allow aggregation of Tx interrupts. Saves CPU load at the cost - * of possible Tx stalls if the system is blocking interrupts - * somewhere else. Undefine this to disable. - */ -#define tx_interrupt_mitigation 1 - -/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). = */ -#define vortex_debug debug -#ifdef VORTEX_DEBUG -static int vortex_debug =3D VORTEX_DEBUG; -#else -static int vortex_debug =3D 1; -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For nr_irqs only. */ -#include -#include - -/* Kernel compatibility defines, some common to David Hinds' PCMCIA packag= e. - This is only in the support-all-kernels source code. */ - -#define RUN_AT(x) (jiffies + (x)) - -#include - - -static const char version[] =3D - DRV_NAME ": Donald Becker and others.\n"; - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver "); -MODULE_LICENSE("GPL"); - - -/* Operational parameter that usually are not changed. */ - -/* The Vortex size is twice that of the original EtherLinkIII series: the - runtime register window, window 1, is now always mapped in. - The Boomerang size is twice as large as the Vortex -- it has additional - bus master control registers. */ -#define VORTEX_TOTAL_SIZE 0x20 -#define BOOMERANG_TOTAL_SIZE 0x40 - -/* Set iff a MII transceiver on any interface requires mdio preamble. - This only set with the original DP83840 on older 3c905 boards, so the e= xtra - code size of a per-interface flag is not worthwhile. */ -static char mii_preamble_required; - -#define PFX DRV_NAME ": " - - - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the 3Com FastEtherLink and FastEtherLink -XL, 3Com's PCI to 10/100baseT adapters. It also works with the 10Mbs -versions of the FastEtherLink cards. The supported product IDs are - 3c590, 3c592, 3c595, 3c597, 3c900, 3c905 - -The related ISA 3c515 is supported with a separate driver, 3c515.c, includ= ed -with the kernel source or available from - cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS should be set to assign the -PCI INTA signal to an otherwise unused system IRQ line. - -The EEPROM settings for media type and forced-full-duplex are observed. -The EEPROM media type should be left at the default "autoselect" unless us= ing -10base2 or AUI connections which cannot be reliably detected. - -III. Driver operation - -The 3c59x series use an interface that's very similar to the previous 3c5x9 -series. The primary interface is two programmed-I/O FIFOs, with an -alternate single-contiguous-region bus-master transfer (see next). - -The 3c900 "Boomerang" series uses a full-bus-master interface with separate -lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet, -DEC Tulip and Intel Speedo3. The first chip version retains a compatible -programmed-I/O interface that has been removed in 'B' and subsequent board -revisions. - -One extension that is advertised in a very large font is that the adapters -are capable of being bus masters. On the Vortex chip this capability was -only for a single contiguous region making it far less useful than the full -bus master capability. There is a significant performance impact of taking -an extra interrupt or polling for the completion of each transfer, as well -as difficulty sharing the single transfer engine between the transmit and -receive threads. Using DMA transfers is a win only with large blocks or -with the flawed versions of the Intel Orion motherboard PCI controller. - -The Boomerang chip's full-bus-master interface is useful, and has the -currently-unused advantages over other similar chips that queued transmit -packets may be reordered and receive buffer groups are associated with a -single frame. - -With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme. -Rather than a fixed intermediate receive buffer, this scheme allocates -full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as -the copying breakpoint: it is chosen to trade-off the memory wasted by -passing the full-sized skbuff to the queue layer for all frames vs. the -copying cost of copying a frame to a correctly-sized skbuff. - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is sing= le -threaded by the hardware and other software. - -IV. Notes - -Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing developme= nt -3c590, 3c595, and 3c900 boards. -The name "Vortex" is the internal 3Com project name for the PCI ASIC, and -the EISA version is called "Demon". According to Terry these names come -from rides at the local amusement park. - -The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes! -This driver only supports ethernet packets because of the skbuff allocation -limit of 4K. -*/ - -/* This table drives the PCI probe routines. It's mostly boilerplate in a= ll - of the drivers, and will likely be provided by some future kernel. -*/ -enum pci_flags_bit { - PCI_USES_MASTER=3D4, -}; - -enum { IS_VORTEX=3D1, IS_BOOMERANG=3D2, IS_CYCLONE=3D4, IS_TORNADO=3D8, - EEPROM_8BIT=3D0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM re= ads */ - HAS_PWR_CTRL=3D0x20, HAS_MII=3D0x40, HAS_NWAY=3D0x80, HAS_CB_FNS=3D0x100, - INVERT_MII_PWR=3D0x200, INVERT_LED_PWR=3D0x400, MAX_COLLISION_RESET=3D0x8= 00, - EEPROM_OFFSET=3D0x1000, HAS_HWCKSM=3D0x2000, WNO_XCVR_PWR=3D0x4000, - EXTRA_PREAMBLE=3D0x8000, EEPROM_RESET=3D0x10000, }; - -enum vortex_chips { - CH_3C590 =3D 0, - CH_3C592, - CH_3C597, - CH_3C595_1, - CH_3C595_2, - - CH_3C595_3, - CH_3C900_1, - CH_3C900_2, - CH_3C900_3, - CH_3C900_4, - - CH_3C900_5, - CH_3C900B_FL, - CH_3C905_1, - CH_3C905_2, - CH_3C905B_TX, - CH_3C905B_1, - - CH_3C905B_2, - CH_3C905B_FX, - CH_3C905C, - CH_3C9202, - CH_3C980, - CH_3C9805, - - CH_3CSOHO100_TX, - CH_3C555, - CH_3C556, - CH_3C556B, - CH_3C575, - - CH_3C575_1, - CH_3CCFE575, - CH_3CCFE575CT, - CH_3CCFE656, - CH_3CCFEM656, - - CH_3CCFEM656_1, - CH_3C450, - CH_3C920, - CH_3C982A, - CH_3C982B, - - CH_905BT4, - CH_920B_EMB_WNM, -}; - - -/* note: this array directly indexed by above enums, and MUST - * be kept in sync with both the enums above, and the PCI device - * table below - */ -static struct vortex_chip_info { - const char *name; - int flags; - int drv_flags; - int io_size; -} vortex_info_tbl[] =3D { - {"3c590 Vortex 10Mbps", - PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c592 EISA 10Mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.4= 9H */ - PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H= */ - PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c595 Vortex 100baseTx", - PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c595 Vortex 100baseT4", - PCI_USES_MASTER, IS_VORTEX, 32, }, - - {"3c595 Vortex 100base-MII", - PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c900 Boomerang 10baseT", - PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, - {"3c900 Boomerang 10Mbps Combo", - PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, - {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ - PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c900 Cyclone 10Mbps Combo", - PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - - {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ - PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c900B-FL Cyclone 10base-FL", - PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c905 Boomerang 100baseTx", - PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, - {"3c905 Boomerang 100baseT4", - PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, - {"3C905B-TX Fast Etherlink XL PCI", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, - {"3c905B Cyclone 100baseTx", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, - - {"3c905B Cyclone 10/100/BNC", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3c905B-FX Cyclone 100baseFx", - PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c905C Tornado", - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, - {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)", - PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, }, - {"3c980 Cyclone", - PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, - - {"3c980C Python-T", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3cSOHO100-TX Hurricane", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, - {"3c555 Laptop Hurricane", - PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, }, - {"3c556 Laptop Tornado", - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_P= WR| - HAS_HWCKSM, 128, }, - {"3c556B Laptop Hurricane", - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII= _PWR| - WNO_XCVR_PWR|HAS_HWCKSM, 128, }, - - {"3c575 [Megahertz] 10/100 LAN CardBus", - PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, - {"3c575 Boomerang CardBus", - PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, - {"3CCFE575BT Cyclone CardBus", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT| - INVERT_LED_PWR|HAS_HWCKSM, 128, }, - {"3CCFE575CT Tornado CardBus", - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_P= WR| - MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, - {"3CCFE656 Cyclone CardBus", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_P= WR| - INVERT_LED_PWR|HAS_HWCKSM, 128, }, - - {"3CCFEM656B Cyclone+Winmodem CardBus", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_P= WR| - INVERT_LED_PWR|HAS_HWCKSM, 128, }, - {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_P= WR| - MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, - {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3c920 Tornado", - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3c982 Hydra Dual Port A", - PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, }, - - {"3c982 Hydra Dual Port B", - PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, }, - {"3c905B-T4", - PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, - {"3c920B-EMB-WNM Tornado", - PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, - - {NULL,}, /* NULL terminated list. */ -}; - - -static const struct pci_device_id vortex_pci_tbl[] =3D { - { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 }, - { 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 }, - { 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 }, - { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 }, - { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 }, - - { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 }, - { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 }, - { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 }, - { 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 }, - { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 }, - - { 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 }, - { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL }, - { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 }, - { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 }, - { 0x10B7, 0x9054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_TX }, - { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 }, - - { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 }, - { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX }, - { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C }, - { 0x10B7, 0x9202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9202 }, - { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 }, - { 0x10B7, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9805 }, - - { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, - { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, - { 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 }, - { 0x10B7, 0x6056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556B }, - { 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 }, - - { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, - { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, - { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, - { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, - { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, - - { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 }, - { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, - { 0x10B7, 0x9201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C920 }, - { 0x10B7, 0x1201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982A }, - { 0x10B7, 0x1202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982B }, - - { 0x10B7, 0x9056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_905BT4 }, - { 0x10B7, 0x9210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_920B_EMB_WNM }, - - {0,} /* 0 terminated list. */ -}; -MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); - - -/* Operational definitions. - These are not used by other compilation units and thus are not - exported in a ".h" file. - - First the windows. There are eight register windows, with the command - and status registers available in each. - */ -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. - Note that 11 parameters bits was fine for ethernet, but the new chip - can handle FDDI length frames (~4500 octets) and now parameters count - 32-bit 'Dwords' rather than octets. */ - -enum vortex_cmd { - TotalReset =3D 0<<11, SelectWindow =3D 1<<11, StartCoax =3D 2<<11, - RxDisable =3D 3<<11, RxEnable =3D 4<<11, RxReset =3D 5<<11, - UpStall =3D 6<<11, UpUnstall =3D (6<<11)+1, - DownStall =3D (6<<11)+2, DownUnstall =3D (6<<11)+3, - RxDiscard =3D 8<<11, TxEnable =3D 9<<11, TxDisable =3D 10<<11, TxReset = =3D 11<<11, - FakeIntr =3D 12<<11, AckIntr =3D 13<<11, SetIntrEnb =3D 14<<11, - SetStatusEnb =3D 15<<11, SetRxFilter =3D 16<<11, SetRxThreshold =3D 17<<1= 1, - SetTxThreshold =3D 18<<11, SetTxStart =3D 19<<11, - StartDMAUp =3D 20<<11, StartDMADown =3D (20<<11)+1, StatsEnable =3D 21<<1= 1, - StatsDisable =3D 22<<11, StopCoax =3D 23<<11, SetFilterBit =3D 25<<11,}; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation =3D 1, RxMulticast =3D 2, RxBroadcast =3D 4, RxProm =3D 8 }; - -/* Bits in the general status register. */ -enum vortex_status { - IntLatch =3D 0x0001, HostError =3D 0x0002, TxComplete =3D 0x0004, - TxAvailable =3D 0x0008, RxComplete =3D 0x0010, RxEarly =3D 0x0020, - IntReq =3D 0x0040, StatsFull =3D 0x0080, - DMADone =3D 1<<8, DownComplete =3D 1<<9, UpComplete =3D 1<<10, - DMAInProgress =3D 1<<11, /* DMA controller is still busy.*/ - CmdInProgress =3D 1<<12, /* EL3_CMD is still busy.*/ -}; - -/* Register window 1 offsets, the window used in normal operation. - On the Vortex this window is always mapped at offsets 0x10-0x1f. */ -enum Window1 { - TX_FIFO =3D 0x10, RX_FIFO =3D 0x10, RxErrors =3D 0x14, - RxStatus =3D 0x18, Timer=3D0x1A, TxStatus =3D 0x1B, - TxFree =3D 0x1C, /* Remaining free bytes in Tx buffer. */ -}; -enum Window0 { - Wn0EepromCmd =3D 10, /* Window 0: EEPROM command register. */ - Wn0EepromData =3D 12, /* Window 0: EEPROM results register. */ - IntrStatus=3D0x0E, /* Valid in all windows. */ -}; -enum Win0_EEPROM_bits { - EEPROM_Read =3D 0x80, EEPROM_WRITE =3D 0x40, EEPROM_ERASE =3D 0xC0, - EEPROM_EWENB =3D 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS =3D 0x00, /* Disable EWENB before 10 msec timeout. */ -}; -/* EEPROM locations. */ -enum eeprom_offset { - PhysAddr01=3D0, PhysAddr23=3D1, PhysAddr45=3D2, ModelID=3D3, - EtherLink3ID=3D7, IFXcvrIO=3D8, IRQLine=3D9, - NodeAddr01=3D10, NodeAddr23=3D11, NodeAddr45=3D12, - DriverTune=3D13, Checksum=3D15}; - -enum Window2 { /* Window 2. */ - Wn2_ResetOptions=3D12, -}; -enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=3D0, Wn3_MaxPktSize=3D4, Wn3_MAC_Ctrl=3D6, Wn3_Options=3D8, -}; - -#define BFEXT(value, offset, bitcount) \ - ((((unsigned long)(value)) >> (offset)) & ((1 << (bitcount)) - 1)) - -#define BFINS(lhs, rhs, offset, bitcount) \ - (((lhs) & ~((((1 << (bitcount)) - 1)) << (offset))) | \ - (((rhs) & ((1 << (bitcount)) - 1)) << (offset))) - -#define RAM_SIZE(v) BFEXT(v, 0, 3) -#define RAM_WIDTH(v) BFEXT(v, 3, 1) -#define RAM_SPEED(v) BFEXT(v, 4, 2) -#define ROM_SIZE(v) BFEXT(v, 6, 2) -#define RAM_SPLIT(v) BFEXT(v, 16, 2) -#define XCVR(v) BFEXT(v, 20, 4) -#define AUTOSELECT(v) BFEXT(v, 24, 1) - -enum Window4 { /* Window 4: Xcvr/media bits. */ - Wn4_FIFODiag =3D 4, Wn4_NetDiag =3D 6, Wn4_PhysicalMgmt=3D8, Wn4_Media = =3D 10, -}; -enum Win4_Media_bits { - Media_SQE =3D 0x0008, /* Enable SQE error counting for AUI. */ - Media_10TP =3D 0x00C0, /* Enable link beat and jabber for 10baseT. */ - Media_Lnk =3D 0x0080, /* Enable just link beat for 100TX/100FX. */ - Media_LnkBeat =3D 0x0800, -}; -enum Window7 { /* Window 7: Bus Master control. */ - Wn7_MasterAddr =3D 0, Wn7_VlanEtherType=3D4, Wn7_MasterLen =3D 6, - Wn7_MasterStatus =3D 12, -}; -/* Boomerang bus master control registers. */ -enum MasterCtrl { - PktStatus =3D 0x20, DownListPtr =3D 0x24, FragAddr =3D 0x28, FragLen =3D = 0x2c, - TxFreeThreshold =3D 0x2f, UpPktStatus =3D 0x30, UpListPtr =3D 0x38, -}; - -/* The Rx and Tx descriptor lists. - Caution Alpha hackers: these types are 32 bits! Note also the 8 byte - alignment contraint on tx_ring[] and rx_ring[]. */ -#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ -#define DN_COMPLETE 0x00010000 /* This packet has been downloaded */ -struct boom_rx_desc { - __le32 next; /* Last entry points to 0. */ - __le32 status; - __le32 addr; /* Up to 63 addr/len pairs possible. */ - __le32 length; /* Set LAST_FRAG to indicate last pair. */ -}; -/* Values for the Rx status entry. */ -enum rx_desc_status { - RxDComplete=3D0x00008000, RxDError=3D0x4000, - /* See boomerang_rx() for actual error bits */ - IPChksumErr=3D1<<25, TCPChksumErr=3D1<<26, UDPChksumErr=3D1<<27, - IPChksumValid=3D1<<29, TCPChksumValid=3D1<<30, UDPChksumValid=3D1<<31, -}; - -#ifdef MAX_SKB_FRAGS -#define DO_ZEROCOPY 1 -#else -#define DO_ZEROCOPY 0 -#endif - -struct boom_tx_desc { - __le32 next; /* Last entry points to 0. */ - __le32 status; /* bits 0:12 length, others see below. */ -#if DO_ZEROCOPY - struct { - __le32 addr; - __le32 length; - } frag[1+MAX_SKB_FRAGS]; -#else - __le32 addr; - __le32 length; -#endif -}; - -/* Values for the Tx status entry. */ -enum tx_desc_status { - CRCDisable=3D0x2000, TxDComplete=3D0x8000, - AddIPChksum=3D0x02000000, AddTCPChksum=3D0x04000000, AddUDPChksum=3D0x080= 00000, - TxIntrUploaded=3D0x80000000, /* IRQ when in FIFO, but maybe not sent. */ -}; - -/* Chip features we care about in vp->capabilities, read from the EEPROM. = */ -enum ChipCaps { CapBusMaster=3D0x20, CapPwrMgmt=3D0x2000 }; - -struct vortex_extra_stats { - unsigned long tx_deferred; - unsigned long tx_max_collisions; - unsigned long tx_multiple_collisions; - unsigned long tx_single_collisions; - unsigned long rx_bad_ssd; -}; - -struct vortex_private { - /* The Rx and Tx rings should be quad-word-aligned. */ - struct boom_rx_desc* rx_ring; - struct boom_tx_desc* tx_ring; - dma_addr_t rx_ring_dma; - dma_addr_t tx_ring_dma; - /* The addresses of transmit- and receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_tx; /* The ring entries to be free()ed. */ - struct vortex_extra_stats xstats; /* NIC-specific extra stats */ - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ - dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DM= A. */ - - /* PCI configuration space information. */ - struct device *gendev; - void __iomem *ioaddr; /* IO address space */ - void __iomem *cb_fn_base; /* CardBus function status addr space. */ - - /* Some values here only for performance evaluation and path-coverage */ - int rx_nocopy, rx_copy, queued_packet, rx_csumhits; - int card_idx; - - /* The remainder are related to chip state, mostly media selection. */ - struct timer_list timer; /* Media selection timer. */ - int options; /* User-settable misc. driver options. */ - unsigned int media_override:4, /* Passed-in media type. */ - default_media:4, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ - full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ - partner_flow_ctrl:1, /* Partner supports flow control */ - has_nway:1, - enable_wol:1, /* Wake-on-LAN is enabled */ - pm_state_valid:1, /* pci_dev->saved_config_space has sane contents */ - open:1, - medialock:1, - large_frames:1, /* accept large frames */ - handling_irq:1; /* private in_irq indicator */ - /* {get|set}_wol operations are already serialized by rtnl. - * no additional locking is required for the enable_wol and acpi_set_WOL() - */ - int drv_flags; - u16 status_enable; - u16 intr_enable; - u16 available_media; /* From Wn3_Options. */ - u16 capabilities, info1, info2; /* Various, from EEPROM. */ - u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ - u16 deferred; /* Resend these interrupts when we - * bale from the ISR */ - u16 io_size; /* Size of PCI region (for release_region) */ - - /* Serialises access to hardware other than MII and variables below. - * The lock hierarchy is rtnl_lock > {lock, mii_lock} > window_lock. */ - spinlock_t lock; - - spinlock_t mii_lock; /* Serialises access to MII */ - struct mii_if_info mii; /* MII lib hooks/info */ - spinlock_t window_lock; /* Serialises access to windowed regs */ - int window; /* Register window */ -}; - -static void window_set(struct vortex_private *vp, int window) -{ - if (window !=3D vp->window) { - iowrite16(SelectWindow + window, vp->ioaddr + EL3_CMD); - vp->window =3D window; - } -} - -#define DEFINE_WINDOW_IO(size) \ -static u ## size \ -window_read ## size(struct vortex_private *vp, int window, int addr) \ -{ \ - unsigned long flags; \ - u ## size ret; \ - spin_lock_irqsave(&vp->window_lock, flags); \ - window_set(vp, window); \ - ret =3D ioread ## size(vp->ioaddr + addr); \ - spin_unlock_irqrestore(&vp->window_lock, flags); \ - return ret; \ -} \ -static void \ -window_write ## size(struct vortex_private *vp, u ## size value, \ - int window, int addr) \ -{ \ - unsigned long flags; \ - spin_lock_irqsave(&vp->window_lock, flags); \ - window_set(vp, window); \ - iowrite ## size(value, vp->ioaddr + addr); \ - spin_unlock_irqrestore(&vp->window_lock, flags); \ -} -DEFINE_WINDOW_IO(8) -DEFINE_WINDOW_IO(16) -DEFINE_WINDOW_IO(32) - -#ifdef CONFIG_PCI -#define DEVICE_PCI(dev) ((dev_is_pci(dev)) ? to_pci_dev((dev)) : NULL) -#else -#define DEVICE_PCI(dev) NULL -#endif - -#define VORTEX_PCI(vp) \ - ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL)) - -#ifdef CONFIG_EISA -#define DEVICE_EISA(dev) (((dev)->bus =3D=3D &eisa_bus_type) ? to_eisa_dev= ice((dev)) : NULL) -#else -#define DEVICE_EISA(dev) NULL -#endif - -#define VORTEX_EISA(vp) \ - ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NUL= L)) - -/* The action to take with a media selection timer tick. - Note that we deviate from the 3Com order by checking 10base2 before AUI. - */ -enum xcvr_types { - XCVR_10baseT=3D0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseT= x, - XCVR_100baseFx, XCVR_MII=3D6, XCVR_NWAY=3D8, XCVR_ExtMII=3D9, XCVR_Defaul= t=3D10, -}; - -static const struct media_table { - char *name; - unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ - mask:8, /* The transceiver-present bit in Wn3_Config.*/ - next:8; /* The media type to try next. */ - int wait; /* Time before we check media status. */ -} media_tbl[] =3D { - { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10}, - { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10}, - { "undefined", 0, 0x80, XCVR_10baseT, 10000}, - { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10}, - { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10}, - { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10}, - { "MII", 0, 0x41, XCVR_10baseT, 3*HZ }, - { "undefined", 0, 0x01, XCVR_10baseT, 10000}, - { "Autonegotiate", 0, 0x41, XCVR_10baseT, 3*HZ}, - { "MII-External", 0, 0x41, XCVR_10baseT, 3*HZ }, - { "Default", 0, 0xFF, XCVR_10baseT, 10000}, -}; - -static struct { - const char str[ETH_GSTRING_LEN]; -} ethtool_stats_keys[] =3D { - { "tx_deferred" }, - { "tx_max_collisions" }, - { "tx_multiple_collisions" }, - { "tx_single_collisions" }, - { "rx_bad_ssd" }, -}; - -/* number of ETHTOOL_GSTATS u64's */ -#define VORTEX_NUM_STATS 5 - -static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int = irq, - int chip_idx, int card_idx); -static int vortex_up(struct net_device *dev); -static void vortex_down(struct net_device *dev, int final); -static int vortex_open(struct net_device *dev); -static void mdio_sync(struct vortex_private *vp, int bits); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *vp, int phy_id, int location, in= t value); -static void vortex_timer(struct timer_list *t); -static netdev_tx_t vortex_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static netdev_tx_t boomerang_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int vortex_rx(struct net_device *dev); -static int boomerang_rx(struct net_device *dev); -static irqreturn_t vortex_boomerang_interrupt(int irq, void *dev_id); -static irqreturn_t _vortex_interrupt(int irq, struct net_device *dev); -static irqreturn_t _boomerang_interrupt(int irq, struct net_device *dev); -static int vortex_close(struct net_device *dev); -static void dump_tx_ring(struct net_device *dev); -static void update_stats(void __iomem *ioaddr, struct net_device *dev); -static struct net_device_stats *vortex_get_stats(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -#ifdef CONFIG_PCI -static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif -static void vortex_tx_timeout(struct net_device *dev, unsigned int txqueue= ); -static void acpi_set_WOL(struct net_device *dev); -static const struct ethtool_ops vortex_ethtool_ops; -static void set_8021q_mode(struct net_device *dev, int enable); - -/* This driver uses 'options' to pass the media type, full-duplex flag, et= c. */ -/* Option count limit only -- unlimited interfaces are supported. */ -#define MAX_UNITS 8 -static int options[MAX_UNITS] =3D { [0 ... MAX_UNITS-1] =3D -1 }; -static int full_duplex[MAX_UNITS] =3D {[0 ... MAX_UNITS-1] =3D -1 }; -static int hw_checksums[MAX_UNITS] =3D {[0 ... MAX_UNITS-1] =3D -1 }; -static int flow_ctrl[MAX_UNITS] =3D {[0 ... MAX_UNITS-1] =3D -1 }; -static int enable_wol[MAX_UNITS] =3D {[0 ... MAX_UNITS-1] =3D -1 }; -static int use_mmio[MAX_UNITS] =3D {[0 ... MAX_UNITS-1] =3D -1 }; -static int global_options =3D -1; -static int global_full_duplex =3D -1; -static int global_enable_wol =3D -1; -static int global_use_mmio =3D -1; - -/* Variables to work-around the Compaq PCI BIOS32 problem. */ -static int compaq_ioaddr, compaq_irq, compaq_device_id =3D 0x5900; -static struct net_device *compaq_net_device; - -static int vortex_cards_found; - -module_param(debug, int, 0); -module_param(global_options, int, 0); -module_param_array(options, int, NULL, 0); -module_param(global_full_duplex, int, 0); -module_param_array(full_duplex, int, NULL, 0); -module_param_array(hw_checksums, int, NULL, 0); -module_param_array(flow_ctrl, int, NULL, 0); -module_param(global_enable_wol, int, 0); -module_param_array(enable_wol, int, NULL, 0); -module_param(rx_copybreak, int, 0); -module_param(max_interrupt_work, int, 0); -module_param_hw(compaq_ioaddr, int, ioport, 0); -module_param_hw(compaq_irq, int, irq, 0); -module_param(compaq_device_id, int, 0); -module_param(watchdog, int, 0); -module_param(global_use_mmio, int, 0); -module_param_array(use_mmio, int, NULL, 0); -MODULE_PARM_DESC(debug, "3c59x debug level (0-6)"); -MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus masteri= ng, bit 9: full duplex"); -MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to a= ll NICs if options is unset"); -MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)"); -MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but appl= ies to all NICs if full_duplex is unset"); -MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapte= r(s) (0-1)"); -MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) = (0-1)"); -MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0= -1)"); -MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applie= s to all NICs if enable_wol is unset"); -MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-f= rames"); -MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per int= errupt"); -MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS p= roblem workaround)"); -MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem wo= rkaround)"); -MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS probl= em workaround)"); -MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds"); -MODULE_PARM_DESC(global_use_mmio, "3c59x: same as use_mmio, but applies to= all NICs if options is unset"); -MODULE_PARM_DESC(use_mmio, "3c59x: use memory-mapped PCI I/O resource (0-1= )"); - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void poll_vortex(struct net_device *dev) -{ - vortex_boomerang_interrupt(dev->irq, dev); -} -#endif - -#ifdef CONFIG_PM - -static int vortex_suspend(struct device *dev) -{ - struct net_device *ndev =3D dev_get_drvdata(dev); - - if (!ndev || !netif_running(ndev)) - return 0; - - netif_device_detach(ndev); - vortex_down(ndev, 1); - - return 0; -} - -static int vortex_resume(struct device *dev) -{ - struct net_device *ndev =3D dev_get_drvdata(dev); - int err; - - if (!ndev || !netif_running(ndev)) - return 0; - - err =3D vortex_up(ndev); - if (err) - return err; - - netif_device_attach(ndev); - - return 0; -} - -static const struct dev_pm_ops vortex_pm_ops =3D { - .suspend =3D vortex_suspend, - .resume =3D vortex_resume, - .freeze =3D vortex_suspend, - .thaw =3D vortex_resume, - .poweroff =3D vortex_suspend, - .restore =3D vortex_resume, -}; - -#define VORTEX_PM_OPS (&vortex_pm_ops) - -#else /* !CONFIG_PM */ - -#define VORTEX_PM_OPS NULL - -#endif /* !CONFIG_PM */ - -#ifdef CONFIG_EISA -static const struct eisa_device_id vortex_eisa_ids[] =3D { - { "TCM5920", CH_3C592 }, - { "TCM5970", CH_3C597 }, - { "" } -}; -MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); - -static int vortex_eisa_probe(struct device *device) -{ - void __iomem *ioaddr; - struct eisa_device *edev; - - edev =3D to_eisa_device(device); - - if (!request_region(edev->base_addr, VORTEX_TOTAL_SIZE, DRV_NAME)) - return -EBUSY; - - ioaddr =3D ioport_map(edev->base_addr, VORTEX_TOTAL_SIZE); - - if (vortex_probe1(device, ioaddr, ioread16(ioaddr + 0xC88) >> 12, - edev->id.driver_data, vortex_cards_found)) { - release_region(edev->base_addr, VORTEX_TOTAL_SIZE); - return -ENODEV; - } - - vortex_cards_found++; - - return 0; -} - -static int vortex_eisa_remove(struct device *device) -{ - struct eisa_device *edev; - struct net_device *dev; - struct vortex_private *vp; - void __iomem *ioaddr; - - edev =3D to_eisa_device(device); - dev =3D eisa_get_drvdata(edev); - - if (!dev) { - pr_err("vortex_eisa_remove called for Compaq device!\n"); - BUG(); - } - - vp =3D netdev_priv(dev); - ioaddr =3D vp->ioaddr; - - unregister_netdev(dev); - iowrite16(TotalReset|0x14, ioaddr + EL3_CMD); - release_region(edev->base_addr, VORTEX_TOTAL_SIZE); - - free_netdev(dev); - return 0; -} - -static struct eisa_driver vortex_eisa_driver =3D { - .id_table =3D vortex_eisa_ids, - .driver =3D { - .name =3D "3c59x", - .probe =3D vortex_eisa_probe, - .remove =3D vortex_eisa_remove - } -}; - -#endif /* CONFIG_EISA */ - -/* returns count found (>=3D 0), or negative on error */ -static int __init vortex_eisa_init(void) -{ - int eisa_found =3D 0; - int orig_cards_found =3D vortex_cards_found; - -#ifdef CONFIG_EISA - int err; - - err =3D eisa_driver_register (&vortex_eisa_driver); - if (!err) { - /* - * Because of the way EISA bus is probed, we cannot assume - * any device have been found when we exit from - * eisa_driver_register (the bus root driver may not be - * initialized yet). So we blindly assume something was - * found, and let the sysfs magic happened... - */ - eisa_found =3D 1; - } -#endif - - /* Special code to work-around the Compaq PCI BIOS32 problem. */ - if (compaq_ioaddr) { - vortex_probe1(NULL, ioport_map(compaq_ioaddr, VORTEX_TOTAL_SIZE), - compaq_irq, compaq_device_id, vortex_cards_found++); - } - - return vortex_cards_found - orig_cards_found + eisa_found; -} - -/* returns count (>=3D 0), or negative on error */ -static int vortex_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int rc, unit, pci_bar; - struct vortex_chip_info *vci; - void __iomem *ioaddr; - - /* wake up and enable device */ - rc =3D pci_enable_device(pdev); - if (rc < 0) - goto out; - - rc =3D pci_request_regions(pdev, DRV_NAME); - if (rc < 0) - goto out_disable; - - unit =3D vortex_cards_found; - - if (global_use_mmio < 0 && (unit >=3D MAX_UNITS || use_mmio[unit] < 0)) { - /* Determine the default if the user didn't override us */ - vci =3D &vortex_info_tbl[ent->driver_data]; - pci_bar =3D vci->drv_flags & (IS_CYCLONE | IS_TORNADO) ? 1 : 0; - } else if (unit < MAX_UNITS && use_mmio[unit] >=3D 0) - pci_bar =3D use_mmio[unit] ? 1 : 0; - else - pci_bar =3D global_use_mmio ? 1 : 0; - - ioaddr =3D pci_iomap(pdev, pci_bar, 0); - if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */ - ioaddr =3D pci_iomap(pdev, 0, 0); - if (!ioaddr) { - rc =3D -ENOMEM; - goto out_release; - } - - rc =3D vortex_probe1(&pdev->dev, ioaddr, pdev->irq, - ent->driver_data, unit); - if (rc < 0) - goto out_iounmap; - - vortex_cards_found++; - goto out; - -out_iounmap: - pci_iounmap(pdev, ioaddr); -out_release: - pci_release_regions(pdev); -out_disable: - pci_disable_device(pdev); -out: - return rc; -} - -static const struct net_device_ops boomrang_netdev_ops =3D { - .ndo_open =3D vortex_open, - .ndo_stop =3D vortex_close, - .ndo_start_xmit =3D boomerang_start_xmit, - .ndo_tx_timeout =3D vortex_tx_timeout, - .ndo_get_stats =3D vortex_get_stats, -#ifdef CONFIG_PCI - .ndo_eth_ioctl =3D vortex_ioctl, -#endif - .ndo_set_rx_mode =3D set_rx_mode, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D poll_vortex, -#endif -}; - -static const struct net_device_ops vortex_netdev_ops =3D { - .ndo_open =3D vortex_open, - .ndo_stop =3D vortex_close, - .ndo_start_xmit =3D vortex_start_xmit, - .ndo_tx_timeout =3D vortex_tx_timeout, - .ndo_get_stats =3D vortex_get_stats, -#ifdef CONFIG_PCI - .ndo_eth_ioctl =3D vortex_ioctl, -#endif - .ndo_set_rx_mode =3D set_rx_mode, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D poll_vortex, -#endif -}; - -/* - * Start up the PCI/EISA device which is described by *gendev. - * Return 0 on success. - * - * NOTE: pdev can be NULL, for the case of a Compaq device - */ -static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int = irq, - int chip_idx, int card_idx) -{ - struct vortex_private *vp; - int option; - unsigned int eeprom[0x40], checksum =3D 0; /* EEPROM contents */ - __be16 addr[ETH_ALEN / 2]; - int i, step; - struct net_device *dev; - static int printed_version; - int retval, print_info; - struct vortex_chip_info * const vci =3D &vortex_info_tbl[chip_idx]; - const char *print_name =3D "3c59x"; - struct pci_dev *pdev =3D NULL; - struct eisa_device *edev =3D NULL; - - if (!printed_version) { - pr_info("%s", version); - printed_version =3D 1; - } - - if (gendev) { - if ((pdev =3D DEVICE_PCI(gendev))) { - print_name =3D pci_name(pdev); - } - - if ((edev =3D DEVICE_EISA(gendev))) { - print_name =3D dev_name(&edev->dev); - } - } - - dev =3D alloc_etherdev(sizeof(*vp)); - retval =3D -ENOMEM; - if (!dev) - goto out; - - SET_NETDEV_DEV(dev, gendev); - vp =3D netdev_priv(dev); - - option =3D global_options; - - /* The lower four bits are the media type. */ - if (dev->mem_start) { - /* - * The 'options' param is passed in as the third arg to the - * LILO 'ether=3D' argument for non-modular use - */ - option =3D dev->mem_start; - } - else if (card_idx < MAX_UNITS) { - if (options[card_idx] >=3D 0) - option =3D options[card_idx]; - } - - if (option > 0) { - if (option & 0x8000) - vortex_debug =3D 7; - if (option & 0x4000) - vortex_debug =3D 2; - if (option & 0x0400) - vp->enable_wol =3D 1; - } - - print_info =3D (vortex_debug > 1); - if (print_info) - pr_info("See Documentation/networking/device_drivers/ethernet/3com/vorte= x.rst\n"); - - pr_info("%s: 3Com %s %s at %p.\n", - print_name, - pdev ? "PCI" : "EISA", - vci->name, - ioaddr); - - dev->base_addr =3D (unsigned long)ioaddr; - dev->irq =3D irq; - dev->mtu =3D mtu; - vp->ioaddr =3D ioaddr; - vp->large_frames =3D mtu > 1500; - vp->drv_flags =3D vci->drv_flags; - vp->has_nway =3D (vci->drv_flags & HAS_NWAY) ? 1 : 0; - vp->io_size =3D vci->io_size; - vp->card_idx =3D card_idx; - vp->window =3D -1; - - /* module list only for Compaq device */ - if (gendev =3D=3D NULL) { - compaq_net_device =3D dev; - } - - /* PCI-only startup logic */ - if (pdev) { - /* enable bus-mastering if necessary */ - if (vci->flags & PCI_USES_MASTER) - pci_set_master(pdev); - - if (vci->drv_flags & IS_VORTEX) { - u8 pci_latency; - u8 new_latency =3D 248; - - /* Check the PCI latency value. On the 3c590 series the latency timer - must be set to the maximum value to avoid data corruption that occurs - when the timer expires during a transfer. This bug exists the Vortex - chip only. */ - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < new_latency) { - pr_info("%s: Overriding PCI latency timer (CFLT) setting of %d, new va= lue is %d.\n", - print_name, pci_latency, new_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); - } - } - } - - spin_lock_init(&vp->lock); - spin_lock_init(&vp->mii_lock); - spin_lock_init(&vp->window_lock); - vp->gendev =3D gendev; - vp->mii.dev =3D dev; - vp->mii.mdio_read =3D mdio_read; - vp->mii.mdio_write =3D mdio_write; - vp->mii.phy_id_mask =3D 0x1f; - vp->mii.reg_num_mask =3D 0x1f; - - /* Makes sure rings are at least 16 byte aligned. */ - vp->rx_ring =3D dma_alloc_coherent(gendev, sizeof(struct boom_rx_desc) * = RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE, - &vp->rx_ring_dma, GFP_KERNEL); - retval =3D -ENOMEM; - if (!vp->rx_ring) - goto free_device; - - vp->tx_ring =3D (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); - vp->tx_ring_dma =3D vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RI= NG_SIZE; - - /* if we are a PCI driver, we store info in pdev->driver_data - * instead of a module list */ - if (pdev) - pci_set_drvdata(pdev, dev); - if (edev) - eisa_set_drvdata(edev, dev); - - vp->media_override =3D 7; - if (option >=3D 0) { - vp->media_override =3D ((option & 7) =3D=3D 2) ? 0 : option & 15; - if (vp->media_override !=3D 7) - vp->medialock =3D 1; - vp->full_duplex =3D (option & 0x200) ? 1 : 0; - vp->bus_master =3D (option & 16) ? 1 : 0; - } - - if (global_full_duplex > 0) - vp->full_duplex =3D 1; - if (global_enable_wol > 0) - vp->enable_wol =3D 1; - - if (card_idx < MAX_UNITS) { - if (full_duplex[card_idx] > 0) - vp->full_duplex =3D 1; - if (flow_ctrl[card_idx] > 0) - vp->flow_ctrl =3D 1; - if (enable_wol[card_idx] > 0) - vp->enable_wol =3D 1; - } - - vp->mii.force_media =3D vp->full_duplex; - vp->options =3D option; - /* Read the station address from the EEPROM. */ - { - int base; - - if (vci->drv_flags & EEPROM_8BIT) - base =3D 0x230; - else if (vci->drv_flags & EEPROM_OFFSET) - base =3D EEPROM_Read + 0x30; - else - base =3D EEPROM_Read; - - for (i =3D 0; i < 0x40; i++) { - int timer; - window_write16(vp, base + i, 0, Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer =3D 10; timer >=3D 0; timer--) { - udelay(162); - if ((window_read16(vp, 0, Wn0EepromCmd) & - 0x8000) =3D=3D 0) - break; - } - eeprom[i] =3D window_read16(vp, 0, Wn0EepromData); - } - } - for (i =3D 0; i < 0x18; i++) - checksum ^=3D eeprom[i]; - checksum =3D (checksum ^ (checksum >> 8)) & 0xff; - if (checksum !=3D 0x00) { /* Grrr, needless incompatible change 3Com. */ - while (i < 0x21) - checksum ^=3D eeprom[i++]; - checksum =3D (checksum ^ (checksum >> 8)) & 0xff; - } - if ((checksum !=3D 0x00) && !(vci->drv_flags & IS_TORNADO)) - pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); - for (i =3D 0; i < 3; i++) - addr[i] =3D htons(eeprom[i + 10]); - eth_hw_addr_set(dev, (u8 *)addr); - if (print_info) - pr_cont(" %pM", dev->dev_addr); - /* Unfortunately an all zero eeprom passes the checksum and this - gets found in the wild in failure cases. Crypto is hard 8) */ - if (!is_valid_ether_addr(dev->dev_addr)) { - retval =3D -EINVAL; - pr_err("*** EEPROM MAC address is invalid.\n"); - goto free_ring; /* With every pack */ - } - for (i =3D 0; i < 6; i++) - window_write8(vp, dev->dev_addr[i], 2, i); - - if (print_info) - pr_cont(", IRQ %d\n", dev->irq); - /* Tell them about an invalid IRQ. */ - if (dev->irq <=3D 0 || dev->irq >=3D irq_get_nr_irqs()) - pr_warn(" *** Warning: IRQ %d is unlikely to work! ***\n", - dev->irq); - - step =3D (window_read8(vp, 4, Wn4_NetDiag) & 0x1e) >> 1; - if (print_info) { - pr_info(" product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n", - eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], - step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); - } - - - if (pdev && vci->drv_flags & HAS_CB_FNS) { - unsigned short n; - - vp->cb_fn_base =3D pci_iomap(pdev, 2, 0); - if (!vp->cb_fn_base) { - retval =3D -ENOMEM; - goto free_ring; - } - - if (print_info) { - pr_info("%s: CardBus functions mapped %16.16llx->%p\n", - print_name, - (unsigned long long)pci_resource_start(pdev, 2), - vp->cb_fn_base); - } - - n =3D window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010; - if (vp->drv_flags & INVERT_LED_PWR) - n |=3D 0x10; - if (vp->drv_flags & INVERT_MII_PWR) - n |=3D 0x4000; - window_write16(vp, n, 2, Wn2_ResetOptions); - if (vp->drv_flags & WNO_XCVR_PWR) { - window_write16(vp, 0x0800, 0, 0); - } - } - - /* Extract our information from the EEPROM data. */ - vp->info1 =3D eeprom[13]; - vp->info2 =3D eeprom[15]; - vp->capabilities =3D eeprom[16]; - - if (vp->info1 & 0x8000) { - vp->full_duplex =3D 1; - if (print_info) - pr_info("Full duplex capable\n"); - } - - { - static const char * const ram_split[] =3D {"5:3", "3:1", "1:1", "3:5"}; - unsigned int config; - vp->available_media =3D window_read16(vp, 3, Wn3_Options); - if ((vp->available_media & 0xff) =3D=3D 0) /* Broken 3c916 */ - vp->available_media =3D 0x40; - config =3D window_read32(vp, 3, Wn3_Config); - if (print_info) { - pr_debug(" Internal config register is %4.4x, transceivers %#x.\n", - config, window_read16(vp, 3, Wn3_Options)); - pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << RAM_SIZE(config), - RAM_WIDTH(config) ? "word" : "byte", - ram_split[RAM_SPLIT(config)], - AUTOSELECT(config) ? "autoselect/" : "", - XCVR(config) > XCVR_ExtMII ? "" : - media_tbl[XCVR(config)].name); - } - vp->default_media =3D XCVR(config); - if (vp->default_media =3D=3D XCVR_NWAY) - vp->has_nway =3D 1; - vp->autoselect =3D AUTOSELECT(config); - } - - if (vp->media_override !=3D 7) { - pr_info("%s: Media override to transceiver type %d (%s).\n", - print_name, vp->media_override, - media_tbl[vp->media_override].name); - dev->if_port =3D vp->media_override; - } else - dev->if_port =3D vp->default_media; - - if ((vp->available_media & 0x40) || (vci->drv_flags & HAS_NWAY) || - dev->if_port =3D=3D XCVR_MII || dev->if_port =3D=3D XCVR_NWAY) { - int phy, phy_idx =3D 0; - mii_preamble_required++; - if (vp->drv_flags & EXTRA_PREAMBLE) - mii_preamble_required++; - mdio_sync(vp, 32); - mdio_read(dev, 24, MII_BMSR); - for (phy =3D 0; phy < 32 && phy_idx < 1; phy++) { - int mii_status, phyx; - - /* - * For the 3c905CX we look at index 24 first, because it bogusly - * reports an external PHY at all indices - */ - if (phy =3D=3D 0) - phyx =3D 24; - else if (phy <=3D 24) - phyx =3D phy - 1; - else - phyx =3D phy; - mii_status =3D mdio_read(dev, phyx, MII_BMSR); - if (mii_status && mii_status !=3D 0xffff) { - vp->phys[phy_idx++] =3D phyx; - if (print_info) { - pr_info(" MII transceiver found at address %d, status %4x.\n", - phyx, mii_status); - } - if ((mii_status & 0x0040) =3D=3D 0) - mii_preamble_required++; - } - } - mii_preamble_required--; - if (phy_idx =3D=3D 0) { - pr_warn(" ***WARNING*** No MII transceivers found!\n"); - vp->phys[0] =3D 24; - } else { - vp->advertising =3D mdio_read(dev, vp->phys[0], MII_ADVERTISE); - if (vp->full_duplex) { - /* Only advertise the FD media types. */ - vp->advertising &=3D ~0x02A0; - mdio_write(dev, vp->phys[0], 4, vp->advertising); - } - } - vp->mii.phy_id =3D vp->phys[0]; - } - - if (vp->capabilities & CapBusMaster) { - vp->full_bus_master_tx =3D 1; - if (print_info) { - pr_info(" Enabling bus-master transmits and %s receives.\n", - (vp->info2 & 1) ? "early" : "whole-frame" ); - } - vp->full_bus_master_rx =3D (vp->info2 & 1) ? 1 : 2; - vp->bus_master =3D 0; /* AKPM: vortex only */ - } - - /* The 3c59x-specific entries in the device structure. */ - if (vp->full_bus_master_tx) { - dev->netdev_ops =3D &boomrang_netdev_ops; - /* Actually, it still should work with iommu. */ - if (card_idx < MAX_UNITS && - ((hw_checksums[card_idx] =3D=3D -1 && (vp->drv_flags & HAS_HWCKSM)) = || - hw_checksums[card_idx] =3D=3D 1)) { - dev->features |=3D NETIF_F_IP_CSUM | NETIF_F_SG; - } - } else - dev->netdev_ops =3D &vortex_netdev_ops; - - if (print_info) { - pr_info("%s: scatter/gather %sabled. h/w checksums %sabled\n", - print_name, - (dev->features & NETIF_F_SG) ? "en":"dis", - (dev->features & NETIF_F_IP_CSUM) ? "en":"dis"); - } - - dev->ethtool_ops =3D &vortex_ethtool_ops; - dev->watchdog_timeo =3D (watchdog * HZ) / 1000; - - if (pdev) { - vp->pm_state_valid =3D 1; - pci_save_state(pdev); - acpi_set_WOL(dev); - } - retval =3D register_netdev(dev); - if (retval =3D=3D 0) - return 0; - -free_ring: - dma_free_coherent(gendev, - sizeof(struct boom_rx_desc) * RX_RING_SIZE + - sizeof(struct boom_tx_desc) * TX_RING_SIZE, - vp->rx_ring, vp->rx_ring_dma); -free_device: - free_netdev(dev); - pr_err(PFX "vortex_probe1 fails. Returns %d\n", retval); -out: - return retval; -} - -static void -issue_and_wait(struct net_device *dev, int cmd) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - int i; - - iowrite16(cmd, ioaddr + EL3_CMD); - for (i =3D 0; i < 2000; i++) { - if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) - return; - } - - /* OK, that didn't work. Do it the slow way. One second */ - for (i =3D 0; i < 100000; i++) { - if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) { - if (vortex_debug > 1) - pr_info("%s: command 0x%04x took %d usecs\n", - dev->name, cmd, i * 10); - return; - } - udelay(10); - } - pr_err("%s: command 0x%04x did not complete! Status=3D0x%x\n", - dev->name, cmd, ioread16(ioaddr + EL3_STATUS)); -} - -static void -vortex_set_duplex(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - pr_info("%s: setting %s-duplex.\n", - dev->name, (vp->full_duplex) ? "full" : "half"); - - /* Set the full-duplex bit. */ - window_write16(vp, - ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (vp->large_frames ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? - 0x100 : 0), - 3, Wn3_MAC_Ctrl); -} - -static void vortex_check_media(struct net_device *dev, unsigned int init) -{ - struct vortex_private *vp =3D netdev_priv(dev); - unsigned int ok_to_print =3D 0; - - if (vortex_debug > 3) - ok_to_print =3D 1; - - if (mii_check_media(&vp->mii, ok_to_print, init)) { - vp->full_duplex =3D vp->mii.full_duplex; - vortex_set_duplex(dev); - } else if (init) { - vortex_set_duplex(dev); - } -} - -static int -vortex_up(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - unsigned int config; - int i, mii_reg5, err =3D 0; - - if (VORTEX_PCI(vp)) { - pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */ - if (vp->pm_state_valid) - pci_restore_state(VORTEX_PCI(vp)); - err =3D pci_enable_device(VORTEX_PCI(vp)); - if (err) { - pr_warn("%s: Could not enable device\n", dev->name); - goto err_out; - } - } - - /* Before initializing select the active media port. */ - config =3D window_read32(vp, 3, Wn3_Config); - - if (vp->media_override !=3D 7) { - pr_info("%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); - dev->if_port =3D vp->media_override; - } else if (vp->autoselect) { - if (vp->has_nway) { - if (vortex_debug > 1) - pr_info("%s: using NWAY device table, not %d\n", - dev->name, dev->if_port); - dev->if_port =3D XCVR_NWAY; - } else { - /* Find first available media type, starting with 100baseTx. */ - dev->if_port =3D XCVR_100baseTx; - while (! (vp->available_media & media_tbl[dev->if_port].mask)) - dev->if_port =3D media_tbl[dev->if_port].next; - if (vortex_debug > 1) - pr_info("%s: first available media type: %s\n", - dev->name, media_tbl[dev->if_port].name); - } - } else { - dev->if_port =3D vp->default_media; - if (vortex_debug > 1) - pr_info("%s: using default media %s\n", - dev->name, media_tbl[dev->if_port].name); - } - - timer_setup(&vp->timer, vortex_timer, 0); - mod_timer(&vp->timer, RUN_AT(media_tbl[dev->if_port].wait)); - - if (vortex_debug > 1) - pr_debug("%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); - - vp->full_duplex =3D vp->mii.force_media; - config =3D BFINS(config, dev->if_port, 20, 4); - if (vortex_debug > 6) - pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config); - window_write32(vp, config, 3, Wn3_Config); - - if (dev->if_port =3D=3D XCVR_MII || dev->if_port =3D=3D XCVR_NWAY) { - mdio_read(dev, vp->phys[0], MII_BMSR); - mii_reg5 =3D mdio_read(dev, vp->phys[0], MII_LPA); - vp->partner_flow_ctrl =3D ((mii_reg5 & 0x0400) !=3D 0); - vp->mii.full_duplex =3D vp->full_duplex; - - vortex_check_media(dev, 1); - } - else - vortex_set_duplex(dev); - - issue_and_wait(dev, TxReset); - /* - * Don't reset the PHY - that upsets autonegotiation during DHCP operatio= ns. - */ - issue_and_wait(dev, RxReset|0x04); - - - iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - - if (vortex_debug > 1) { - pr_debug("%s: vortex_up() irq %d media status %4.4x.\n", - dev->name, dev->irq, window_read16(vp, 4, Wn4_Media)); - } - - /* Set the station address and mask in window 2 each time opened. */ - for (i =3D 0; i < 6; i++) - window_write8(vp, dev->dev_addr[i], 2, i); - for (; i < 12; i+=3D2) - window_write16(vp, 0, 2, i); - - if (vp->cb_fn_base) { - unsigned short n =3D window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010; - if (vp->drv_flags & INVERT_LED_PWR) - n |=3D 0x10; - if (vp->drv_flags & INVERT_MII_PWR) - n |=3D 0x4000; - window_write16(vp, n, 2, Wn2_ResetOptions); - } - - if (dev->if_port =3D=3D XCVR_10base2) - /* Start the thinnet transceiver. We should really wait 50ms...*/ - iowrite16(StartCoax, ioaddr + EL3_CMD); - if (dev->if_port !=3D XCVR_NWAY) { - window_write16(vp, - (window_read16(vp, 4, Wn4_Media) & - ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, - 4, Wn4_Media); - } - - /* Switch to the stats window, and clear all stats by reading. */ - iowrite16(StatsDisable, ioaddr + EL3_CMD); - for (i =3D 0; i < 10; i++) - window_read8(vp, 6, i); - window_read16(vp, 6, 10); - window_read16(vp, 6, 12); - /* New: On the Vortex we must also clear the BadSSD counter. */ - window_read8(vp, 4, 12); - /* ..and on the Boomerang we enable the extra statistics bits. */ - window_write16(vp, 0x0040, 4, Wn4_NetDiag); - - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ - vp->cur_rx =3D 0; - /* Initialize the RxEarly register as recommended. */ - iowrite16(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD); - iowrite32(0x0020, ioaddr + PktStatus); - iowrite32(vp->rx_ring_dma, ioaddr + UpListPtr); - } - if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ - vp->cur_tx =3D vp->dirty_tx =3D 0; - if (vp->drv_flags & IS_BOOMERANG) - iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet= . */ - /* Clear the Rx, Tx rings. */ - for (i =3D 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_ope= n, too */ - vp->rx_ring[i].status =3D 0; - for (i =3D 0; i < TX_RING_SIZE; i++) - vp->tx_skbuff[i] =3D NULL; - iowrite32(0, ioaddr + DownListPtr); - } - /* Set receiver mode: presumably accept b-case and phys addr only. */ - set_rx_mode(dev); - /* enable 802.1q tagged frames */ - set_8021q_mode(dev, 1); - iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - iowrite16(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - iowrite16(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - vp->status_enable =3D SetStatusEnb | HostError|IntReq|StatsFull|TxComplet= e| - (vp->full_bus_master_tx ? DownComplete : TxAvailable) | - (vp->full_bus_master_rx ? UpComplete : RxComplete) | - (vp->bus_master ? DMADone : 0); - vp->intr_enable =3D SetIntrEnb | IntLatch | TxAvailable | - (vp->full_bus_master_rx ? 0 : RxComplete) | - StatsFull | HostError | TxComplete | IntReq - | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete; - iowrite16(vp->status_enable, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - iowrite16(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - iowrite16(vp->intr_enable, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - iowrite32(0x8000, vp->cb_fn_base + 4); - netif_start_queue (dev); - netdev_reset_queue(dev); -err_out: - return err; -} - -static int -vortex_open(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - int i; - int retval; - dma_addr_t dma; - - /* Use the now-standard shared IRQ implementation. */ - if ((retval =3D request_irq(dev->irq, vortex_boomerang_interrupt, IRQF_SH= ARED, dev->name, dev))) { - pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq); - goto err; - } - - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ - if (vortex_debug > 2) - pr_debug("%s: Filling in the Rx ring.\n", dev->name); - for (i =3D 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - vp->rx_ring[i].next =3D cpu_to_le32(vp->rx_ring_dma + sizeof(struct boo= m_rx_desc) * (i+1)); - vp->rx_ring[i].status =3D 0; /* Clear complete bit. */ - vp->rx_ring[i].length =3D cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); - - skb =3D __netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN, - GFP_KERNEL); - vp->rx_skbuff[i] =3D skb; - if (skb =3D=3D NULL) - break; /* Bad news! */ - - skb_reserve(skb, NET_IP_ALIGN); /* Align IP on 16 byte boundaries */ - dma =3D dma_map_single(vp->gendev, skb->data, - PKT_BUF_SZ, DMA_FROM_DEVICE); - if (dma_mapping_error(vp->gendev, dma)) - break; - vp->rx_ring[i].addr =3D cpu_to_le32(dma); - } - if (i !=3D RX_RING_SIZE) { - pr_emerg("%s: no memory for rx ring\n", dev->name); - retval =3D -ENOMEM; - goto err_free_skb; - } - /* Wrap the ring. */ - vp->rx_ring[i-1].next =3D cpu_to_le32(vp->rx_ring_dma); - } - - retval =3D vortex_up(dev); - if (!retval) - goto out; - -err_free_skb: - for (i =3D 0; i < RX_RING_SIZE; i++) { - if (vp->rx_skbuff[i]) { - dev_kfree_skb(vp->rx_skbuff[i]); - vp->rx_skbuff[i] =3D NULL; - } - } - free_irq(dev->irq, dev); -err: - if (vortex_debug > 1) - pr_err("%s: vortex_open() fails: returning %d\n", dev->name, retval); -out: - return retval; -} - -static void -vortex_timer(struct timer_list *t) -{ - struct vortex_private *vp =3D timer_container_of(vp, t, timer); - struct net_device *dev =3D vp->mii.dev; - void __iomem *ioaddr =3D vp->ioaddr; - int next_tick =3D 60*HZ; - int ok =3D 0; - int media_status; - - if (vortex_debug > 2) { - pr_debug("%s: Media selection timer tick happened, %s.\n", - dev->name, media_tbl[dev->if_port].name); - pr_debug("dev->watchdog_timeo=3D%d\n", dev->watchdog_timeo); - } - - media_status =3D window_read16(vp, 4, Wn4_Media); - switch (dev->if_port) { - case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: - if (media_status & Media_LnkBeat) { - netif_carrier_on(dev); - ok =3D 1; - if (vortex_debug > 1) - pr_debug("%s: Media %s has link beat, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - } else { - netif_carrier_off(dev); - if (vortex_debug > 1) { - pr_debug("%s: Media %s has no link beat, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - } - } - break; - case XCVR_MII: case XCVR_NWAY: - { - ok =3D 1; - vortex_check_media(dev, 0); - } - break; - default: /* Other media types handled by Tx timeouts. */ - if (vortex_debug > 1) - pr_debug("%s: Media %s has no indication, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - ok =3D 1; - } - - if (dev->flags & IFF_SLAVE || !netif_carrier_ok(dev)) - next_tick =3D 5*HZ; - - if (vp->medialock) - goto leave_media_alone; - - if (!ok) { - unsigned int config; - - spin_lock_irq(&vp->lock); - - do { - dev->if_port =3D media_tbl[dev->if_port].next; - } while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); - if (dev->if_port =3D=3D XCVR_Default) { /* Go back to default. */ - dev->if_port =3D vp->default_media; - if (vortex_debug > 1) - pr_debug("%s: Media selection failing, using default %s port.\n", - dev->name, media_tbl[dev->if_port].name); - } else { - if (vortex_debug > 1) - pr_debug("%s: Media selection failed, now trying %s port.\n", - dev->name, media_tbl[dev->if_port].name); - next_tick =3D media_tbl[dev->if_port].wait; - } - window_write16(vp, - (media_status & ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, - 4, Wn4_Media); - - config =3D window_read32(vp, 3, Wn3_Config); - config =3D BFINS(config, dev->if_port, 20, 4); - window_write32(vp, config, 3, Wn3_Config); - - iowrite16(dev->if_port =3D=3D XCVR_10base2 ? StartCoax : StopCoax, - ioaddr + EL3_CMD); - if (vortex_debug > 1) - pr_debug("wrote 0x%08x to Wn3_Config\n", config); - /* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */ - - spin_unlock_irq(&vp->lock); - } - -leave_media_alone: - if (vortex_debug > 2) - pr_debug("%s: Media selection timer finished, %s.\n", - dev->name, media_tbl[dev->if_port].name); - - mod_timer(&vp->timer, RUN_AT(next_tick)); - if (vp->deferred) - iowrite16(FakeIntr, ioaddr + EL3_CMD); -} - -static void vortex_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - - pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", - dev->name, ioread8(ioaddr + TxStatus), - ioread16(ioaddr + EL3_STATUS)); - pr_err(" diagnostics: net %04x media %04x dma %08x fifo %04x\n", - window_read16(vp, 4, Wn4_NetDiag), - window_read16(vp, 4, Wn4_Media), - ioread32(ioaddr + PktStatus), - window_read16(vp, 4, Wn4_FIFODiag)); - /* Slight code bloat to be user friendly. */ - if ((ioread8(ioaddr + TxStatus) & 0x88) =3D=3D 0x88) - pr_err("%s: Transmitter encountered 16 collisions --" - " network cable problem?\n", dev->name); - if (ioread16(ioaddr + EL3_STATUS) & IntLatch) { - pr_err("%s: Interrupt posted but not delivered --" - " IRQ blocked by another device?\n", dev->name); - /* Bad idea here.. but we might as well handle a few events. */ - vortex_boomerang_interrupt(dev->irq, dev); - } - - if (vortex_debug > 0) - dump_tx_ring(dev); - - issue_and_wait(dev, TxReset); - - dev->stats.tx_errors++; - if (vp->full_bus_master_tx) { - pr_debug("%s: Resetting the Tx ring pointer.\n", dev->name); - if (vp->cur_tx - vp->dirty_tx > 0 && ioread32(ioaddr + DownListPtr) = =3D=3D 0) - iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(stru= ct boom_tx_desc), - ioaddr + DownListPtr); - if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) { - netif_wake_queue (dev); - netdev_reset_queue (dev); - } - if (vp->drv_flags & IS_BOOMERANG) - iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); - iowrite16(DownUnstall, ioaddr + EL3_CMD); - } else { - dev->stats.tx_dropped++; - netif_wake_queue(dev); - netdev_reset_queue(dev); - } - /* Issue Tx Enable */ - iowrite16(TxEnable, ioaddr + EL3_CMD); - netif_trans_update(dev); /* prevent tx timeout */ -} - -/* - * Handle uncommon interrupt sources. This is a separate routine to minim= ize - * the cache impact. - */ -static void -vortex_error(struct net_device *dev, int status) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - int do_tx_reset =3D 0, reset_mask =3D 0; - unsigned char tx_status =3D 0; - - if (vortex_debug > 2) { - pr_err("%s: vortex_error(), status=3D0x%x\n", dev->name, status); - } - - if (status & TxComplete) { /* Really "TxError" for us. */ - tx_status =3D ioread8(ioaddr + TxStatus); - /* Presumably a tx-timeout. We must merely re-enable. */ - if (vortex_debug > 2 || - (tx_status !=3D 0x88 && vortex_debug > 0)) { - pr_err("%s: Transmit error, Tx status register %2.2x.\n", - dev->name, tx_status); - if (tx_status =3D=3D 0x82) { - pr_err("Probably a duplex mismatch. See " - "Documentation/networking/device_drivers/ethernet/3com/vortex.rst\n"= ); - } - dump_tx_ring(dev); - } - if (tx_status & 0x14) dev->stats.tx_fifo_errors++; - if (tx_status & 0x38) dev->stats.tx_aborted_errors++; - if (tx_status & 0x08) vp->xstats.tx_max_collisions++; - iowrite8(0, ioaddr + TxStatus); - if (tx_status & 0x30) { /* txJabber or txUnderrun */ - do_tx_reset =3D 1; - } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) = { /* maxCollisions */ - do_tx_reset =3D 1; - reset_mask =3D 0x0108; /* Reset interface logic, but not download logi= c */ - } else { /* Merely re-enable the transmitter. */ - iowrite16(TxEnable, ioaddr + EL3_CMD); - } - } - - if (status & RxEarly) /* Rx early is unused. */ - iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD); - - if (status & StatsFull) { /* Empty statistics. */ - static int DoneDidThat; - if (vortex_debug > 4) - pr_debug("%s: Updating stats.\n", dev->name); - update_stats(ioaddr, dev); - /* HACK: Disable statistics as an interrupt source. */ - /* This occurs when we have the wrong media type! */ - if (DoneDidThat =3D=3D 0 && - ioread16(ioaddr + EL3_STATUS) & StatsFull) { - pr_warn("%s: Updating statistics failed, disabling stats as an interrup= t source\n", - dev->name); - iowrite16(SetIntrEnb | - (window_read16(vp, 5, 10) & ~StatsFull), - ioaddr + EL3_CMD); - vp->intr_enable &=3D ~StatsFull; - DoneDidThat++; - } - } - if (status & IntReq) { /* Restore all interrupt sources. */ - iowrite16(vp->status_enable, ioaddr + EL3_CMD); - iowrite16(vp->intr_enable, ioaddr + EL3_CMD); - } - if (status & HostError) { - u16 fifo_diag; - fifo_diag =3D window_read16(vp, 4, Wn4_FIFODiag); - pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n", - dev->name, fifo_diag); - /* Adapter failure requires Tx/Rx reset and reinit. */ - if (vp->full_bus_master_tx) { - int bus_status =3D ioread32(ioaddr + PktStatus); - /* 0x80000000 PCI master abort. */ - /* 0x40000000 PCI target abort. */ - if (vortex_debug) - pr_err("%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); - - /* In this case, blow the card away */ - /* Must not enter D3 or we can't legally issue the reset! */ - vortex_down(dev, 0); - issue_and_wait(dev, TotalReset | 0xff); - vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is= full. It may not be. */ - } else if (fifo_diag & 0x0400) - do_tx_reset =3D 1; - if (fifo_diag & 0x3000) { - /* Reset Rx fifo and upload logic */ - issue_and_wait(dev, RxReset|0x07); - /* Set the Rx filter to the current state. */ - set_rx_mode(dev); - /* enable 802.1q VLAN tagged frames */ - set_8021q_mode(dev, 1); - iowrite16(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - iowrite16(AckIntr | HostError, ioaddr + EL3_CMD); - } - } - - if (do_tx_reset) { - issue_and_wait(dev, TxReset|reset_mask); - iowrite16(TxEnable, ioaddr + EL3_CMD); - if (!vp->full_bus_master_tx) - netif_wake_queue(dev); - } -} - -static netdev_tx_t -vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - int skblen =3D skb->len; - - /* Put out the doubleword header... */ - iowrite32(skb->len, ioaddr + TX_FIFO); - if (vp->bus_master) { - /* Set the bus-master controller to transfer the packet. */ - int len =3D (skb->len + 3) & ~3; - vp->tx_skb_dma =3D dma_map_single(vp->gendev, skb->data, len, - DMA_TO_DEVICE); - if (dma_mapping_error(vp->gendev, vp->tx_skb_dma)) { - dev_kfree_skb_any(skb); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - spin_lock_irq(&vp->window_lock); - window_set(vp, 7); - iowrite32(vp->tx_skb_dma, ioaddr + Wn7_MasterAddr); - iowrite16(len, ioaddr + Wn7_MasterLen); - spin_unlock_irq(&vp->window_lock); - vp->tx_skb =3D skb; - skb_tx_timestamp(skb); - iowrite16(StartDMADown, ioaddr + EL3_CMD); - /* netif_wake_queue() will be called at the DMADone interrupt. */ - } else { - /* ... and the packet rounded to a doubleword. */ - skb_tx_timestamp(skb); - iowrite32_rep(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_consume_skb_any (skb); - if (ioread16(ioaddr + TxFree) > 1536) { - netif_start_queue (dev); /* AKPM: redundant? */ - } else { - /* Interrupt us when the FIFO has room for max-sized packet. */ - netif_stop_queue(dev); - iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - } - } - - netdev_sent_queue(dev, skblen); - - /* Clear the Tx status stack. */ - { - int tx_status; - int i =3D 32; - - while (--i > 0 && (tx_status =3D ioread8(ioaddr + TxStatus)) > 0) { - if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ - if (vortex_debug > 2) - pr_debug("%s: Tx error, status %2.2x.\n", - dev->name, tx_status); - if (tx_status & 0x04) dev->stats.tx_fifo_errors++; - if (tx_status & 0x38) dev->stats.tx_aborted_errors++; - if (tx_status & 0x30) { - issue_and_wait(dev, TxReset); - } - iowrite16(TxEnable, ioaddr + EL3_CMD); - } - iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */ - } - } - return NETDEV_TX_OK; -} - -static netdev_tx_t -boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - /* Calculate the next Tx descriptor entry. */ - int entry =3D vp->cur_tx % TX_RING_SIZE; - int skblen =3D skb->len; - struct boom_tx_desc *prev_entry =3D &vp->tx_ring[(vp->cur_tx-1) % TX_RING= _SIZE]; - unsigned long flags; - dma_addr_t dma_addr; - - if (vortex_debug > 6) { - pr_debug("boomerang_start_xmit()\n"); - pr_debug("%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); - } - - /* - * We can't allow a recursion from our interrupt handler back into the - * tx routine, as they take the same spin lock, and that causes - * deadlock. Just return NETDEV_TX_BUSY and let the stack try again in - * a bit - */ - if (vp->handling_irq) - return NETDEV_TX_BUSY; - - if (vp->cur_tx - vp->dirty_tx >=3D TX_RING_SIZE) { - if (vortex_debug > 0) - pr_warn("%s: BUG! Tx Ring full, refusing to send buffer\n", - dev->name); - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - - vp->tx_skbuff[entry] =3D skb; - - vp->tx_ring[entry].next =3D 0; -#if DO_ZEROCOPY - if (skb->ip_summed !=3D CHECKSUM_PARTIAL) - vp->tx_ring[entry].status =3D cpu_to_le32(skb->len | TxIntrUploaded); - else - vp->tx_ring[entry].status =3D cpu_to_le32(skb->len | TxIntrUploaded | A= ddTCPChksum | AddUDPChksum); - - if (!skb_shinfo(skb)->nr_frags) { - dma_addr =3D dma_map_single(vp->gendev, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(vp->gendev, dma_addr)) - goto out_dma_err; - - vp->tx_ring[entry].frag[0].addr =3D cpu_to_le32(dma_addr); - vp->tx_ring[entry].frag[0].length =3D cpu_to_le32(skb->len | LAST_FRAG); - } else { - int i; - - dma_addr =3D dma_map_single(vp->gendev, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); - if (dma_mapping_error(vp->gendev, dma_addr)) - goto out_dma_err; - - vp->tx_ring[entry].frag[0].addr =3D cpu_to_le32(dma_addr); - vp->tx_ring[entry].frag[0].length =3D cpu_to_le32(skb_headlen(skb)); - - for (i =3D 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag =3D &skb_shinfo(skb)->frags[i]; - - dma_addr =3D skb_frag_dma_map(vp->gendev, frag, - 0, - skb_frag_size(frag), - DMA_TO_DEVICE); - if (dma_mapping_error(vp->gendev, dma_addr)) { - for(i =3D i-1; i >=3D 0; i--) - dma_unmap_page(vp->gendev, - le32_to_cpu(vp->tx_ring[entry].frag[i+1].addr), - le32_to_cpu(vp->tx_ring[entry].frag[i+1].length), - DMA_TO_DEVICE); - - dma_unmap_single(vp->gendev, - le32_to_cpu(vp->tx_ring[entry].frag[0].addr), - le32_to_cpu(vp->tx_ring[entry].frag[0].length), - DMA_TO_DEVICE); - - goto out_dma_err; - } - - vp->tx_ring[entry].frag[i+1].addr =3D - cpu_to_le32(dma_addr); - - if (i =3D=3D skb_shinfo(skb)->nr_frags-1) - vp->tx_ring[entry].frag[i+1].length =3D cpu_to_le32(skb_frag_size(fra= g)|LAST_FRAG); - else - vp->tx_ring[entry].frag[i+1].length =3D cpu_to_le32(skb_frag_size(fra= g)); - } - } -#else - dma_addr =3D dma_map_single(vp->gendev, skb->data, skb->len, DMA_TO_DEVIC= E); - if (dma_mapping_error(vp->gendev, dma_addr)) - goto out_dma_err; - vp->tx_ring[entry].addr =3D cpu_to_le32(dma_addr); - vp->tx_ring[entry].length =3D cpu_to_le32(skb->len | LAST_FRAG); - vp->tx_ring[entry].status =3D cpu_to_le32(skb->len | TxIntrUploaded); -#endif - - spin_lock_irqsave(&vp->lock, flags); - /* Wait for the stall to complete. */ - issue_and_wait(dev, DownStall); - prev_entry->next =3D cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct = boom_tx_desc)); - if (ioread32(ioaddr + DownListPtr) =3D=3D 0) { - iowrite32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr = + DownListPtr); - vp->queued_packet++; - } - - vp->cur_tx++; - netdev_sent_queue(dev, skblen); - - if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { - netif_stop_queue (dev); - } else { /* Clear previous interrupt enable. */ -#if defined(tx_interrupt_mitigation) - /* Dubious. If in boomeang_interrupt "faster" cyclone ifdef - * were selected, this would corrupt DN_COMPLETE. No? - */ - prev_entry->status &=3D cpu_to_le32(~TxIntrUploaded); -#endif - } - skb_tx_timestamp(skb); - iowrite16(DownUnstall, ioaddr + EL3_CMD); - spin_unlock_irqrestore(&vp->lock, flags); -out: - return NETDEV_TX_OK; -out_dma_err: - dev_err(vp->gendev, "Error mapping dma buffer\n"); - goto out; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ - -/* - * This is the ISR for the vortex series chips. - * full_bus_master_tx =3D=3D 0 && full_bus_master_rx =3D=3D 0 - */ - -static irqreturn_t -_vortex_interrupt(int irq, struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr; - int status; - int work_done =3D max_interrupt_work; - int handled =3D 0; - unsigned int bytes_compl =3D 0, pkts_compl =3D 0; - - ioaddr =3D vp->ioaddr; - - status =3D ioread16(ioaddr + EL3_STATUS); - - if (vortex_debug > 6) - pr_debug("vortex_interrupt(). status=3D0x%4x\n", status); - - if ((status & IntLatch) =3D=3D 0) - goto handler_exit; /* No interrupt: shared IRQs cause this */ - handled =3D 1; - - if (status & IntReq) { - status |=3D vp->deferred; - vp->deferred =3D 0; - } - - if (status =3D=3D 0xffff) /* h/w no longer present (hotplug)? */ - goto handler_exit; - - if (vortex_debug > 4) - pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n", - dev->name, status, ioread8(ioaddr + Timer)); - - spin_lock(&vp->window_lock); - window_set(vp, 7); - - do { - if (vortex_debug > 5) - pr_debug("%s: In interrupt loop, status %4.4x.\n", - dev->name, status); - if (status & RxComplete) - vortex_rx(dev); - - if (status & TxAvailable) { - if (vortex_debug > 5) - pr_debug(" TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue (dev); - } - - if (status & DMADone) { - if (ioread16(ioaddr + Wn7_MasterStatus) & 0x1000) { - iowrite16(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - dma_unmap_single(vp->gendev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~= 3, DMA_TO_DEVICE); - pkts_compl++; - bytes_compl +=3D vp->tx_skb->len; - dev_consume_skb_irq(vp->tx_skb); /* Release the transferred buffer */ - if (ioread16(ioaddr + TxFree) > 1536) { - /* - * AKPM: FIXME: I don't think we need this. If the queue was stopped= due to - * insufficient FIFO room, the TxAvailable test will succeed and call - * netif_wake_queue() - */ - netif_wake_queue(dev); - } else { /* Interrupt when FIFO has room for max-sized packet. */ - iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - netif_stop_queue(dev); - } - } - } - /* Check for all uncommon interrupts at once. */ - if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { - if (status =3D=3D 0xffff) - break; - if (status & RxEarly) - vortex_rx(dev); - spin_unlock(&vp->window_lock); - vortex_error(dev, status); - spin_lock(&vp->window_lock); - window_set(vp, 7); - } - - if (--work_done < 0) { - pr_warn("%s: Too much work in interrupt, status %4.4x\n", - dev->name, status); - /* Disable all pending interrupts. */ - do { - vp->deferred |=3D status; - iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable), - ioaddr + EL3_CMD); - iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); - } while ((status =3D ioread16(ioaddr + EL3_CMD)) & IntLatch); - /* The timer will reenable interrupts. */ - mod_timer(&vp->timer, jiffies + 1*HZ); - break; - } - /* Acknowledge the IRQ. */ - iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } while ((status =3D ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxCompl= ete)); - - netdev_completed_queue(dev, pkts_compl, bytes_compl); - spin_unlock(&vp->window_lock); - - if (vortex_debug > 4) - pr_debug("%s: exiting interrupt, status %4.4x.\n", - dev->name, status); -handler_exit: - return IRQ_RETVAL(handled); -} - -/* - * This is the ISR for the boomerang series chips. - * full_bus_master_tx =3D=3D 1 && full_bus_master_rx =3D=3D 1 - */ - -static irqreturn_t -_boomerang_interrupt(int irq, struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr; - int status; - int work_done =3D max_interrupt_work; - int handled =3D 0; - unsigned int bytes_compl =3D 0, pkts_compl =3D 0; - - ioaddr =3D vp->ioaddr; - - vp->handling_irq =3D 1; - - status =3D ioread16(ioaddr + EL3_STATUS); - - if (vortex_debug > 6) - pr_debug("boomerang_interrupt. status=3D0x%4x\n", status); - - if ((status & IntLatch) =3D=3D 0) - goto handler_exit; /* No interrupt: shared IRQs can cause this */ - handled =3D 1; - - if (status =3D=3D 0xffff) { /* h/w no longer present (hotplug)? */ - if (vortex_debug > 1) - pr_debug("boomerang_interrupt(1): status =3D 0xffff\n"); - goto handler_exit; - } - - if (status & IntReq) { - status |=3D vp->deferred; - vp->deferred =3D 0; - } - - if (vortex_debug > 4) - pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n", - dev->name, status, ioread8(ioaddr + Timer)); - do { - if (vortex_debug > 5) - pr_debug("%s: In interrupt loop, status %4.4x.\n", - dev->name, status); - if (status & UpComplete) { - iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD); - if (vortex_debug > 5) - pr_debug("boomerang_interrupt->boomerang_rx\n"); - boomerang_rx(dev); - } - - if (status & DownComplete) { - unsigned int dirty_tx =3D vp->dirty_tx; - - iowrite16(AckIntr | DownComplete, ioaddr + EL3_CMD); - while (vp->cur_tx - dirty_tx > 0) { - int entry =3D dirty_tx % TX_RING_SIZE; -#if 1 /* AKPM: the latter is faster, but cyclone-only */ - if (ioread32(ioaddr + DownListPtr) =3D=3D - vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)) - break; /* It still hasn't been processed. */ -#else - if ((vp->tx_ring[entry].status & DN_COMPLETE) =3D=3D 0) - break; /* It still hasn't been processed. */ -#endif - - if (vp->tx_skbuff[entry]) { - struct sk_buff *skb =3D vp->tx_skbuff[entry]; -#if DO_ZEROCOPY - int i; - dma_unmap_single(vp->gendev, - le32_to_cpu(vp->tx_ring[entry].frag[0].addr), - le32_to_cpu(vp->tx_ring[entry].frag[0].length)&0xFFF, - DMA_TO_DEVICE); - - for (i=3D1; i<=3Dskb_shinfo(skb)->nr_frags; i++) - dma_unmap_page(vp->gendev, - le32_to_cpu(vp->tx_ring[entry].frag[i].addr), - le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF, - DMA_TO_DEVICE); -#else - dma_unmap_single(vp->gendev, - le32_to_cpu(vp->tx_ring[entry].addr), skb->len, DMA_TO_DEVICE); -#endif - pkts_compl++; - bytes_compl +=3D skb->len; - dev_consume_skb_irq(skb); - vp->tx_skbuff[entry] =3D NULL; - } else { - pr_debug("boomerang_interrupt: no skb!\n"); - } - /* dev->stats.tx_packets++; Counted below. */ - dirty_tx++; - } - vp->dirty_tx =3D dirty_tx; - if (vp->cur_tx - dirty_tx <=3D TX_RING_SIZE - 1) { - if (vortex_debug > 6) - pr_debug("boomerang_interrupt: wake queue\n"); - netif_wake_queue (dev); - } - } - - /* Check for all uncommon interrupts at once. */ - if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) - vortex_error(dev, status); - - if (--work_done < 0) { - pr_warn("%s: Too much work in interrupt, status %4.4x\n", - dev->name, status); - /* Disable all pending interrupts. */ - do { - vp->deferred |=3D status; - iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable), - ioaddr + EL3_CMD); - iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); - } while ((status =3D ioread16(ioaddr + EL3_CMD)) & IntLatch); - /* The timer will reenable interrupts. */ - mod_timer(&vp->timer, jiffies + 1*HZ); - break; - } - /* Acknowledge the IRQ. */ - iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - iowrite32(0x8000, vp->cb_fn_base + 4); - - } while ((status =3D ioread16(ioaddr + EL3_STATUS)) & IntLatch); - netdev_completed_queue(dev, pkts_compl, bytes_compl); - - if (vortex_debug > 4) - pr_debug("%s: exiting interrupt, status %4.4x.\n", - dev->name, status); -handler_exit: - vp->handling_irq =3D 0; - return IRQ_RETVAL(handled); -} - -static irqreturn_t -vortex_boomerang_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D dev_id; - struct vortex_private *vp =3D netdev_priv(dev); - unsigned long flags; - irqreturn_t ret; - - spin_lock_irqsave(&vp->lock, flags); - - if (vp->full_bus_master_rx) - ret =3D _boomerang_interrupt(dev->irq, dev); - else - ret =3D _vortex_interrupt(dev->irq, dev); - - spin_unlock_irqrestore(&vp->lock, flags); - - return ret; -} - -static int vortex_rx(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - int i; - short rx_status; - - if (vortex_debug > 5) - pr_debug("vortex_rx(): status %4.4x, rx_status %4.4x.\n", - ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus)); - while ((rx_status =3D ioread16(ioaddr + RxStatus)) > 0) { - if (rx_status & 0x4000) { /* Error, update stats. */ - unsigned char rx_error =3D ioread8(ioaddr + RxErrors); - if (vortex_debug > 2) - pr_debug(" Rx error: status %2.2x.\n", rx_error); - dev->stats.rx_errors++; - if (rx_error & 0x01) dev->stats.rx_over_errors++; - if (rx_error & 0x02) dev->stats.rx_length_errors++; - if (rx_error & 0x04) dev->stats.rx_frame_errors++; - if (rx_error & 0x08) dev->stats.rx_crc_errors++; - if (rx_error & 0x10) dev->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - int pkt_len =3D rx_status & 0x1fff; - struct sk_buff *skb; - - skb =3D netdev_alloc_skb(dev, pkt_len + 5); - if (vortex_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb !=3D NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - if (vp->bus_master && - ! (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)) { - dma_addr_t dma =3D dma_map_single(vp->gendev, skb_put(skb, pkt_len), - pkt_len, DMA_FROM_DEVICE); - iowrite32(dma, ioaddr + Wn7_MasterAddr); - iowrite16((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); - iowrite16(StartDMAUp, ioaddr + EL3_CMD); - while (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000) - ; - dma_unmap_single(vp->gendev, dma, pkt_len, DMA_FROM_DEVICE); - } else { - ioread32_rep(ioaddr + RX_FIFO, - skb_put(skb, pkt_len), - (pkt_len + 3) >> 2); - } - iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - /* Wait a limited time to go to next packet. */ - for (i =3D 200; i >=3D 0; i--) - if ( ! (ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - continue; - } else if (vortex_debug > 0) - pr_notice("%s: No memory to allocate a sk_buff of size %d.\n", - dev->name, pkt_len); - dev->stats.rx_dropped++; - } - issue_and_wait(dev, RxDiscard); - } - - return 0; -} - -static int -boomerang_rx(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - int entry =3D vp->cur_rx % RX_RING_SIZE; - void __iomem *ioaddr =3D vp->ioaddr; - int rx_status; - int rx_work_limit =3D RX_RING_SIZE; - - if (vortex_debug > 5) - pr_debug("boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS)); - - while ((rx_status =3D le32_to_cpu(vp->rx_ring[entry].status)) & RxDComple= te){ - if (--rx_work_limit < 0) - break; - if (rx_status & RxDError) { /* Error, update stats. */ - unsigned char rx_error =3D rx_status >> 16; - if (vortex_debug > 2) - pr_debug(" Rx error: status %2.2x.\n", rx_error); - dev->stats.rx_errors++; - if (rx_error & 0x01) dev->stats.rx_over_errors++; - if (rx_error & 0x02) dev->stats.rx_length_errors++; - if (rx_error & 0x04) dev->stats.rx_frame_errors++; - if (rx_error & 0x08) dev->stats.rx_crc_errors++; - if (rx_error & 0x10) dev->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - int pkt_len =3D rx_status & 0x1fff; - struct sk_buff *skb, *newskb; - dma_addr_t newdma; - dma_addr_t dma =3D le32_to_cpu(vp->rx_ring[entry].addr); - - if (vortex_debug > 4) - pr_debug("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - - /* Check if the packet is long enough to just accept without - copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb =3D netdev_alloc_skb(dev, pkt_len + 2)) !=3D NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - dma_sync_single_for_cpu(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE); - /* 'skb_put()' points to the start of sk_buff data area. */ - skb_put_data(skb, vp->rx_skbuff[entry]->data, - pkt_len); - dma_sync_single_for_device(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVIC= E); - vp->rx_copy++; - } else { - /* Pre-allocate the replacement skb. If it or its - * mapping fails then recycle the buffer thats already - * in place - */ - newskb =3D netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ); - if (!newskb) { - dev->stats.rx_dropped++; - goto clear_complete; - } - newdma =3D dma_map_single(vp->gendev, newskb->data, - PKT_BUF_SZ, DMA_FROM_DEVICE); - if (dma_mapping_error(vp->gendev, newdma)) { - dev->stats.rx_dropped++; - consume_skb(newskb); - goto clear_complete; - } - - /* Pass up the skbuff already on the Rx ring. */ - skb =3D vp->rx_skbuff[entry]; - vp->rx_skbuff[entry] =3D newskb; - vp->rx_ring[entry].addr =3D cpu_to_le32(newdma); - skb_put(skb, pkt_len); - dma_unmap_single(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE); - vp->rx_nocopy++; - } - skb->protocol =3D eth_type_trans(skb, dev); - { /* Use hardware checksum info. */ - int csum_bits =3D rx_status & 0xee000000; - if (csum_bits && - (csum_bits =3D=3D (IPChksumValid | TCPChksumValid) || - csum_bits =3D=3D (IPChksumValid | UDPChksumValid))) { - skb->ip_summed =3D CHECKSUM_UNNECESSARY; - vp->rx_csumhits++; - } - } - netif_rx(skb); - dev->stats.rx_packets++; - } - -clear_complete: - vp->rx_ring[entry].status =3D 0; /* Clear complete bit. */ - iowrite16(UpUnstall, ioaddr + EL3_CMD); - entry =3D (++vp->cur_rx) % RX_RING_SIZE; - } - return 0; -} - -static void -vortex_down(struct net_device *dev, int final_down) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - - netdev_reset_queue(dev); - netif_stop_queue(dev); - - timer_delete_sync(&vp->timer); - - /* Turn off statistics ASAP. We update dev->stats below. */ - iowrite16(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - iowrite16(RxDisable, ioaddr + EL3_CMD); - iowrite16(TxDisable, ioaddr + EL3_CMD); - - /* Disable receiving 802.1q tagged frames */ - set_8021q_mode(dev, 0); - - if (dev->if_port =3D=3D XCVR_10base2) - /* Turn off thinnet power. Green! */ - iowrite16(StopCoax, ioaddr + EL3_CMD); - - iowrite16(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - - update_stats(ioaddr, dev); - if (vp->full_bus_master_rx) - iowrite32(0, ioaddr + UpListPtr); - if (vp->full_bus_master_tx) - iowrite32(0, ioaddr + DownListPtr); - - if (final_down && VORTEX_PCI(vp)) { - vp->pm_state_valid =3D 1; - pci_save_state(VORTEX_PCI(vp)); - acpi_set_WOL(dev); - } -} - -static int -vortex_close(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - int i; - - if (netif_device_present(dev)) - vortex_down(dev, 1); - - if (vortex_debug > 1) { - pr_debug("%s: vortex_close() status %4.4x, Tx status %2.2x.\n", - dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus)= ); - pr_debug("%s: vortex close stats: rx_nocopy %d rx_copy %d" - " tx_queued %d Rx pre-checksummed %d.\n", - dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csu= mhits); - } - -#if DO_ZEROCOPY - if (vp->rx_csumhits && - (vp->drv_flags & HAS_HWCKSM) =3D=3D 0 && - (vp->card_idx >=3D MAX_UNITS || hw_checksums[vp->card_idx] =3D=3D -1)= ) { - pr_warn("%s supports hardware checksums, and we're not using them!\n", - dev->name); - } -#endif - - free_irq(dev->irq, dev); - - if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ - for (i =3D 0; i < RX_RING_SIZE; i++) - if (vp->rx_skbuff[i]) { - dma_unmap_single(vp->gendev, le32_to_cpu(vp->rx_ring[i].addr), - PKT_BUF_SZ, DMA_FROM_DEVICE); - dev_kfree_skb(vp->rx_skbuff[i]); - vp->rx_skbuff[i] =3D NULL; - } - } - if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - for (i =3D 0; i < TX_RING_SIZE; i++) { - if (vp->tx_skbuff[i]) { - struct sk_buff *skb =3D vp->tx_skbuff[i]; -#if DO_ZEROCOPY - int k; - - for (k=3D0; k<=3Dskb_shinfo(skb)->nr_frags; k++) - dma_unmap_single(vp->gendev, - le32_to_cpu(vp->tx_ring[i].frag[k].addr), - le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF, - DMA_TO_DEVICE); -#else - dma_unmap_single(vp->gendev, le32_to_cpu(vp->tx_ring[i].addr), skb->le= n, DMA_TO_DEVICE); -#endif - dev_kfree_skb(skb); - vp->tx_skbuff[i] =3D NULL; - } - } - } - - return 0; -} - -static void -dump_tx_ring(struct net_device *dev) -{ - if (vortex_debug > 0) { - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - - if (vp->full_bus_master_tx) { - int i; - int stalled =3D ioread32(ioaddr + PktStatus) & 0x04; /* Possible racy. = But it's only debug stuff */ - - pr_err(" Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", - vp->full_bus_master_tx, - vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, - vp->cur_tx, vp->cur_tx % TX_RING_SIZE); - pr_err(" Transmit list %8.8x vs. %p.\n", - ioread32(ioaddr + DownListPtr), - &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); - issue_and_wait(dev, DownStall); - for (i =3D 0; i < TX_RING_SIZE; i++) { - unsigned int length; - -#if DO_ZEROCOPY - length =3D le32_to_cpu(vp->tx_ring[i].frag[0].length); -#else - length =3D le32_to_cpu(vp->tx_ring[i].length); -#endif - pr_err(" %d: @%p length %8.8x status %8.8x\n", - i, &vp->tx_ring[i], length, - le32_to_cpu(vp->tx_ring[i].status)); - } - if (!stalled) - iowrite16(DownUnstall, ioaddr + EL3_CMD); - } - } -} - -static struct net_device_stats *vortex_get_stats(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - unsigned long flags; - - if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */ - spin_lock_irqsave (&vp->lock, flags); - update_stats(ioaddr, dev); - spin_unlock_irqrestore (&vp->lock, flags); - } - return &dev->stats; -} - -/* Update statistics. - Unlike with the EL3 we need not worry about interrupts changing - the window setting from underneath us, but we must still guard - against a race condition with a StatsUpdate interrupt updating the - table. This is done by checking that the ASM (!) code generated uses - atomic updates with '+=3D'. - */ -static void update_stats(void __iomem *ioaddr, struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - /* Unlike the 3c5x9 we need not turn off stats updates while reading. */ - /* Switch to the stats window, and read everything. */ - dev->stats.tx_carrier_errors +=3D window_read8(vp, 6, 0); - dev->stats.tx_heartbeat_errors +=3D window_read8(vp, 6, 1); - dev->stats.tx_window_errors +=3D window_read8(vp, 6, 4); - dev->stats.rx_fifo_errors +=3D window_read8(vp, 6, 5); - dev->stats.tx_packets +=3D window_read8(vp, 6, 6); - dev->stats.tx_packets +=3D (window_read8(vp, 6, 9) & - 0x30) << 4; - /* Rx packets */ window_read8(vp, 6, 7); /* Must read to clear */ - /* Don't bother with register 9, an extension of registers 6&7. - If we do use the 6&7 values the atomic update assumption above - is invalid. */ - dev->stats.rx_bytes +=3D window_read16(vp, 6, 10); - dev->stats.tx_bytes +=3D window_read16(vp, 6, 12); - /* Extra stats for get_ethtool_stats() */ - vp->xstats.tx_multiple_collisions +=3D window_read8(vp, 6, 2); - vp->xstats.tx_single_collisions +=3D window_read8(vp, 6, 3); - vp->xstats.tx_deferred +=3D window_read8(vp, 6, 8); - vp->xstats.rx_bad_ssd +=3D window_read8(vp, 4, 12); - - dev->stats.collisions =3D vp->xstats.tx_multiple_collisions - + vp->xstats.tx_single_collisions - + vp->xstats.tx_max_collisions; - - { - u8 up =3D window_read8(vp, 4, 13); - dev->stats.rx_bytes +=3D (up & 0x0f) << 16; - dev->stats.tx_bytes +=3D (up & 0xf0) << 12; - } -} - -static int vortex_nway_reset(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - return mii_nway_restart(&vp->mii); -} - -static int vortex_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - mii_ethtool_get_link_ksettings(&vp->mii, cmd); - - return 0; -} - -static int vortex_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - return mii_ethtool_set_link_ksettings(&vp->mii, cmd); -} - -static u32 vortex_get_msglevel(struct net_device *dev) -{ - return vortex_debug; -} - -static void vortex_set_msglevel(struct net_device *dev, u32 dbg) -{ - vortex_debug =3D dbg; -} - -static int vortex_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return VORTEX_NUM_STATS; - default: - return -EOPNOTSUPP; - } -} - -static void vortex_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - unsigned long flags; - - spin_lock_irqsave(&vp->lock, flags); - update_stats(ioaddr, dev); - spin_unlock_irqrestore(&vp->lock, flags); - - data[0] =3D vp->xstats.tx_deferred; - data[1] =3D vp->xstats.tx_max_collisions; - data[2] =3D vp->xstats.tx_multiple_collisions; - data[3] =3D vp->xstats.tx_single_collisions; - data[4] =3D vp->xstats.rx_bad_ssd; -} - - -static void vortex_get_strings(struct net_device *dev, u32 stringset, u8 *= data) -{ - switch (stringset) { - case ETH_SS_STATS: - memcpy(data, ðtool_stats_keys, sizeof(ethtool_stats_keys)); - break; - default: - WARN_ON(1); - break; - } -} - -static void vortex_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - if (VORTEX_PCI(vp)) { - strscpy(info->bus_info, pci_name(VORTEX_PCI(vp)), - sizeof(info->bus_info)); - } else { - if (VORTEX_EISA(vp)) - strscpy(info->bus_info, dev_name(vp->gendev), - sizeof(info->bus_info)); - else - snprintf(info->bus_info, sizeof(info->bus_info), - "EISA 0x%lx %d", dev->base_addr, dev->irq); - } -} - -static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo = *wol) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - if (!VORTEX_PCI(vp)) - return; - - wol->supported =3D WAKE_MAGIC; - - wol->wolopts =3D 0; - if (vp->enable_wol) - wol->wolopts |=3D WAKE_MAGIC; -} - -static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *= wol) -{ - struct vortex_private *vp =3D netdev_priv(dev); - - if (!VORTEX_PCI(vp)) - return -EOPNOTSUPP; - - if (wol->wolopts & ~WAKE_MAGIC) - return -EINVAL; - - if (wol->wolopts & WAKE_MAGIC) - vp->enable_wol =3D 1; - else - vp->enable_wol =3D 0; - acpi_set_WOL(dev); - - return 0; -} - -static const struct ethtool_ops vortex_ethtool_ops =3D { - .get_drvinfo =3D vortex_get_drvinfo, - .get_strings =3D vortex_get_strings, - .get_msglevel =3D vortex_get_msglevel, - .set_msglevel =3D vortex_set_msglevel, - .get_ethtool_stats =3D vortex_get_ethtool_stats, - .get_sset_count =3D vortex_get_sset_count, - .get_link =3D ethtool_op_get_link, - .nway_reset =3D vortex_nway_reset, - .get_wol =3D vortex_get_wol, - .set_wol =3D vortex_set_wol, - .get_ts_info =3D ethtool_op_get_ts_info, - .get_link_ksettings =3D vortex_get_link_ksettings, - .set_link_ksettings =3D vortex_set_link_ksettings, -}; - -#ifdef CONFIG_PCI -/* - * Must power the device up to do MDIO operations - */ -static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - int err; - struct vortex_private *vp =3D netdev_priv(dev); - pci_power_t state =3D 0; - - if(VORTEX_PCI(vp)) - state =3D VORTEX_PCI(vp)->current_state; - - /* The kernel core really should have pci_get_power_state() */ - - if(state !=3D 0) - pci_set_power_state(VORTEX_PCI(vp), PCI_D0); - err =3D generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL); - if(state !=3D 0) - pci_set_power_state(VORTEX_PCI(vp), state); - - return err; -} -#endif - - -/* Pre-Cyclone chips have no documented multicast filter, so the only - multicast setting is to receive all multicast frames. At least - the chip has a very clean way to set the mode, unlike many others. */ -static void set_rx_mode(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - int new_mode; - - if (dev->flags & IFF_PROMISC) { - if (vortex_debug > 3) - pr_notice("%s: Setting promiscuous mode.\n", dev->name); - new_mode =3D SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; - } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) { - new_mode =3D SetRxFilter|RxStation|RxMulticast|RxBroadcast; - } else - new_mode =3D SetRxFilter | RxStation | RxBroadcast; - - iowrite16(new_mode, ioaddr + EL3_CMD); -} - -#if IS_ENABLED(CONFIG_VLAN_8021Q) -/* Setup the card so that it can receive frames with an 802.1q VLAN tag. - Note that this must be done after each RxReset due to some backwards - compatibility logic in the Cyclone and Tornado ASICs */ - -/* The Ethernet Type used for 802.1q tagged frames */ -#define VLAN_ETHER_TYPE 0x8100 - -static void set_8021q_mode(struct net_device *dev, int enable) -{ - struct vortex_private *vp =3D netdev_priv(dev); - int mac_ctrl; - - if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) { - /* cyclone and tornado chipsets can recognize 802.1q - * tagged frames and treat them correctly */ - - int max_pkt_size =3D dev->mtu+14; /* MTU+Ethernet header */ - if (enable) - max_pkt_size +=3D 4; /* 802.1Q VLAN tag */ - - window_write16(vp, max_pkt_size, 3, Wn3_MaxPktSize); - - /* set VlanEtherType to let the hardware checksumming - treat tagged frames correctly */ - window_write16(vp, VLAN_ETHER_TYPE, 7, Wn7_VlanEtherType); - } else { - /* on older cards we have to enable large frames */ - - vp->large_frames =3D dev->mtu > 1500 || enable; - - mac_ctrl =3D window_read16(vp, 3, Wn3_MAC_Ctrl); - if (vp->large_frames) - mac_ctrl |=3D 0x40; - else - mac_ctrl &=3D ~0x40; - window_write16(vp, mac_ctrl, 3, Wn3_MAC_Ctrl); - } -} -#else - -static void set_8021q_mode(struct net_device *dev, int enable) -{ -} - - -#endif - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. */ - -/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues. */ -static void mdio_delay(struct vortex_private *vp) -{ - window_read32(vp, 4, Wn4_PhysicalMgmt); -} - -#define MDIO_SHIFT_CLK 0x01 -#define MDIO_DIR_WRITE 0x04 -#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE) -#define MDIO_DATA_READ 0x02 -#define MDIO_ENB_IN 0x00 - -/* Generate the preamble required for initial synchronization and - a few older transceivers. */ -static void mdio_sync(struct vortex_private *vp, int bits) -{ - /* Establish sync by sending at least 32 logic ones. */ - while (-- bits >=3D 0) { - window_write16(vp, MDIO_DATA_WRITE1, 4, Wn4_PhysicalMgmt); - mdio_delay(vp); - window_write16(vp, MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, - 4, Wn4_PhysicalMgmt); - mdio_delay(vp); - } -} - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - int i; - struct vortex_private *vp =3D netdev_priv(dev); - int read_cmd =3D (0xf6 << 10) | (phy_id << 5) | location; - unsigned int retval =3D 0; - - spin_lock_bh(&vp->mii_lock); - - if (mii_preamble_required) - mdio_sync(vp, 32); - - /* Shift the read command bits out. */ - for (i =3D 14; i >=3D 0; i--) { - int dataval =3D (read_cmd&(1< 0; i--) { - window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt); - mdio_delay(vp); - retval =3D (retval << 1) | - ((window_read16(vp, 4, Wn4_PhysicalMgmt) & - MDIO_DATA_READ) ? 1 : 0); - window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK, - 4, Wn4_PhysicalMgmt); - mdio_delay(vp); - } - - spin_unlock_bh(&vp->mii_lock); - - return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, i= nt value) -{ - struct vortex_private *vp =3D netdev_priv(dev); - int write_cmd =3D 0x50020000 | (phy_id << 23) | (location << 18) | value; - int i; - - spin_lock_bh(&vp->mii_lock); - - if (mii_preamble_required) - mdio_sync(vp, 32); - - /* Shift the command bits out. */ - for (i =3D 31; i >=3D 0; i--) { - int dataval =3D (write_cmd&(1<=3D 0; i--) { - window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt); - mdio_delay(vp); - window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK, - 4, Wn4_PhysicalMgmt); - mdio_delay(vp); - } - - spin_unlock_bh(&vp->mii_lock); -} - -/* ACPI: Advanced Configuration and Power Interface. */ -/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ -static void acpi_set_WOL(struct net_device *dev) -{ - struct vortex_private *vp =3D netdev_priv(dev); - void __iomem *ioaddr =3D vp->ioaddr; - - device_set_wakeup_enable(vp->gendev, vp->enable_wol); - - if (vp->enable_wol) { - /* Power up on: 1=3D=3DDownloaded Filter, 2=3D=3DMagic Packets, 4=3D=3DL= ink Status. */ - window_write16(vp, 2, 7, 0x0c); - /* The RxFilter must accept the WOL frames. */ - iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CM= D); - iowrite16(RxEnable, ioaddr + EL3_CMD); - - if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) { - pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp))); - - vp->enable_wol =3D 0; - return; - } - - if (VORTEX_PCI(vp)->current_state < PCI_D3hot) - return; - - /* Change the power state to D3; RxEnable doesn't take effect. */ - pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot); - } -} - - -static void vortex_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev =3D pci_get_drvdata(pdev); - struct vortex_private *vp; - - if (!dev) { - pr_err("vortex_remove_one called for Compaq device!\n"); - BUG(); - } - - vp =3D netdev_priv(dev); - - if (vp->cb_fn_base) - pci_iounmap(pdev, vp->cb_fn_base); - - unregister_netdev(dev); - - pci_set_power_state(pdev, PCI_D0); /* Go active */ - if (vp->pm_state_valid) - pci_restore_state(pdev); - pci_disable_device(pdev); - - /* Should really use issue_and_wait() here */ - iowrite16(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14), - vp->ioaddr + EL3_CMD); - - pci_iounmap(pdev, vp->ioaddr); - - dma_free_coherent(&pdev->dev, - sizeof(struct boom_rx_desc) * RX_RING_SIZE + - sizeof(struct boom_tx_desc) * TX_RING_SIZE, - vp->rx_ring, vp->rx_ring_dma); - - pci_release_regions(pdev); - - free_netdev(dev); -} - - -static struct pci_driver vortex_driver =3D { - .name =3D "3c59x", - .probe =3D vortex_init_one, - .remove =3D vortex_remove_one, - .id_table =3D vortex_pci_tbl, - .driver.pm =3D VORTEX_PM_OPS, -}; - - -static int vortex_have_pci; -static int vortex_have_eisa; - - -static int __init vortex_init(void) -{ - int pci_rc, eisa_rc; - - pci_rc =3D pci_register_driver(&vortex_driver); - eisa_rc =3D vortex_eisa_init(); - - if (pci_rc =3D=3D 0) - vortex_have_pci =3D 1; - if (eisa_rc > 0) - vortex_have_eisa =3D 1; - - return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV; -} - - -static void __exit vortex_eisa_cleanup(void) -{ - void __iomem *ioaddr; - -#ifdef CONFIG_EISA - /* Take care of the EISA devices */ - eisa_driver_unregister(&vortex_eisa_driver); -#endif - - if (compaq_net_device) { - ioaddr =3D ioport_map(compaq_net_device->base_addr, - VORTEX_TOTAL_SIZE); - - unregister_netdev(compaq_net_device); - iowrite16(TotalReset, ioaddr + EL3_CMD); - release_region(compaq_net_device->base_addr, - VORTEX_TOTAL_SIZE); - - free_netdev(compaq_net_device); - } -} - - -static void __exit vortex_cleanup(void) -{ - if (vortex_have_pci) - pci_unregister_driver(&vortex_driver); - if (vortex_have_eisa) - vortex_eisa_cleanup(); -} - - -module_init(vortex_init); -module_exit(vortex_cleanup); diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/= Kconfig index 399cb6c56198..5db57c4bc6fb 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -17,27 +17,6 @@ config NET_VENDOR_3COM =20 if NET_VENDOR_3COM =20 -config VORTEX - tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support" - depends on (PCI || EISA) && HAS_IOPORT_MAP - select MII - help - This option enables driver support for a large number of 10Mbps and - 10/100Mbps EISA, PCI and Cardbus 3Com network cards: - - "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI - "Boomerang" (EtherLink XL 3c900 or 3c905) PCI - "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus - "Tornado" (3c905) PCI - "Hurricane" (3c555/3cSOHO) PCI - - If you have such a card, say Y here. More specific information is in - - and in the comments at the beginning of - . - - To compile this support as a module, choose M here. - config TYPHOON tristate "3cr990 series \"Typhoon\" support" depends on PCI diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com= /Makefile index 5c4d07f1d456..6e250add60fe 100644 --- a/drivers/net/ethernet/3com/Makefile +++ b/drivers/net/ethernet/3com/Makefile @@ -3,5 +3,4 @@ # Makefile for the 3Com Ethernet device drivers # =20 -obj-$(CONFIG_VORTEX) +=3D 3c59x.o obj-$(CONFIG_TYPHOON) +=3D typhoon.o --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 01806382F07; Tue, 21 Apr 2026 19:31:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799902; cv=none; b=NTjAjPDFcZCs2KIkEZcwC3odxY1/gf5ClMUYh+RNHHUxPgvxJcVismeXGj+TECFwYNwq1h2/AUShWPVO2hFziGJWR4lEtPCYLVBybbDp2uwtjOu4YkSORGbJ4J7zAGa+8WAmZ3kNeId8T/lIu7oYUnrVUEVH55Z3hlvi3K5aU3s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799902; c=relaxed/simple; bh=QzVjYhlVs8O7FjQC4I9T81l+70WbEErYqShy73VvZx4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kXsnSRwB+vHtn1ChK8UQwBsbg6AbW4Azf8NWFthExJEQTMBRJmZLM7G8viprkHKKdTaHD5jA4KHLY+ghbyVzG3hQpSpO9teRaBK9X8k54kFzFM5tpbXwZVh/h5549Hy/AUrbl3fh82QFzggBOntdv8QuaDVbVYajxW9B7ZVJtUE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=BAhP6voP; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="BAhP6voP" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=0BqQhgcpaaIsToikKUuvpKUZ1Hg++TGl3gSSbJqq5LM=; b=BA hP6voP041GK1qxe6nKCGHri3IL+rN4DOKCDZo3YlHUBa3cF5HjaPRq3KsuAZ/Txbh3F5ehycZWuqR 86y6rWXXdiUBX13FaFO7HAXG6+pWokAzWhxBcF6LTHr2yaFONQVYopvP9Et5GZKGurOdW9Xu4Ay56 3/1CWOBhrpYH+5c=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGom-00GwVc-04; Tue, 21 Apr 2026 21:31:32 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:09 -0500 Subject: [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-6-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=47473; i=andrew@lunn.ch; h=from:subject:message-id; bh=QzVjYhlVs8O7FjQC4I9T81l+70WbEErYqShy73VvZx4=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CBmWCGp3YB3NfOaoRv40h1hti4pS1FzI0/g M4Pb3vNh4eJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hGyMD/9ZQSqFlPuLUTEfXB+JOVf93IZYC1fOv1ZstXCURLavtMO0CCMhnqcvYni6NThIdnHuoeY S1r2PoyjkSq2v7fRNpKd6AunAXophAE4ySvP3v+EqaHIKNwqyGggBSpVIodZ1hu8RVsJ6ViSh7C SJeUSLiQ+d+1ilAibyeS+kKcLcOqIBykwNpm+MrU/Cc8BKCvdpps6qL2iguW3eQwMhOTYJVfmE5 OtCf4wWcRbWxKGJq9ztmE4cSAIPIBtvYtRGbCpwqnQRvxIOqK/njbwnJqktDkBEdgR4AOEf0Di/ rWma2IFh5R73qXMwmt7LGrtGSHG+DcWMITF4dSEWU3UrLiQdddfuebxi3qbHIuKBEpWMLly4NHJ wZlrMDL9vrjD3voCp7+uPqtc5rumeLs8Z+5iKs9xS7E1PWV+IpzrsQVXHJ5Z1iPA6TujjaVlke9 rm8WN2u10BVxC4N9W8ogs4XQu32lAUjA4W28MCsGOgvCQH8FCMARDagrGtErgDxD/e74anznzaT v35JQWeRfp03CIuVf8Dev8H8AlZ0hO4I8V6GHF0OXIVgULDb2kDgIDpmfZWoCcMfcU5FHrSyQd0 6Q7Qkx2IBCiqLfJ81AXpN6uL/iSE5Aq3q2XZAhgvQQxZ4qTUQRvaj37SLhz8N+oR6llLhIIqrS3 XehBlrlPXEHIXew== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 These drivers use the 7990 core with wrappers for the HP300 and Motorola MVME147 SBC circa 1998. It is unlikely they are used with a modern kernel. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/amd/7990.c | 671 ---------------------------------= ---- drivers/net/ethernet/amd/7990.h | 251 -------------- drivers/net/ethernet/amd/Kconfig | 18 - drivers/net/ethernet/amd/Makefile | 2 - drivers/net/ethernet/amd/hplance.c | 238 ------------- drivers/net/ethernet/amd/hplance.h | 27 -- drivers/net/ethernet/amd/mvme147.c | 198 ----------- 7 files changed, 1405 deletions(-) diff --git a/drivers/net/ethernet/amd/7990.c b/drivers/net/ethernet/amd/799= 0.c deleted file mode 100644 index 27792a52b6cf..000000000000 --- a/drivers/net/ethernet/amd/7990.c +++ /dev/null @@ -1,671 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * 7990.c -- LANCE ethernet IC generic routines. - * This is an attempt to separate out the bits of various ethernet - * drivers that are common because they all use the AMD 7990 LANCE - * (Local Area Network Controller for Ethernet) chip. - * - * Copyright (C) 05/1998 Peter Maydell - * - * Most of this stuff was obtained by looking at other LANCE drivers, - * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful. - * NB: this was made easy by the fact that Jes Sorensen had cleaned up - * most of a2025 and sunlance with the aim of merging them, so the - * common code was pretty obvious. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* Used for the temporal inet entries and routing */ -#include -#include - -#include -#include -#ifdef CONFIG_HP300 -#include -#endif - -#include "7990.h" - -#define WRITERAP(lp, x) out_be16(lp->base + LANCE_RAP, (x)) -#define WRITERDP(lp, x) out_be16(lp->base + LANCE_RDP, (x)) -#define READRDP(lp) in_be16(lp->base + LANCE_RDP) - -#if IS_ENABLED(CONFIG_HPLANCE) -#include "hplance.h" - -#undef WRITERAP -#undef WRITERDP -#undef READRDP - -#if IS_ENABLED(CONFIG_MVME147_NET) - -/* Lossage Factor Nine, Mr Sulu. */ -#define WRITERAP(lp, x) (lp->writerap(lp, x)) -#define WRITERDP(lp, x) (lp->writerdp(lp, x)) -#define READRDP(lp) (lp->readrdp(lp)) - -#else - -/* These inlines can be used if only CONFIG_HPLANCE is defined */ -static inline void WRITERAP(struct lance_private *lp, __u16 value) -{ - do { - out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value); - } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) =3D=3D 0); -} - -static inline void WRITERDP(struct lance_private *lp, __u16 value) -{ - do { - out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value); - } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) =3D=3D 0); -} - -static inline __u16 READRDP(struct lance_private *lp) -{ - __u16 value; - do { - value =3D in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP); - } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) =3D=3D 0); - return value; -} - -#endif -#endif /* IS_ENABLED(CONFIG_HPLANCE) */ - -/* debugging output macros, various flavours */ -/* #define TEST_HITS */ -#ifdef UNDEF -#define PRINT_RINGS() \ -do { \ - int t; \ - for (t =3D 0; t < RX_RING_SIZE; t++) { \ - printk("R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X\n", \ - t, ib->brx_ring[t].rmd1_hadr, ib->brx_ring[t].rmd0, \ - ib->brx_ring[t].length, \ - ib->brx_ring[t].mblength, ib->brx_ring[t].rmd1_bits); \ - } \ - for (t =3D 0; t < TX_RING_SIZE; t++) { \ - printk("T%d: @(%02X %04X) len %04X, misc %04X, bits %02X\n", \ - t, ib->btx_ring[t].tmd1_hadr, ib->btx_ring[t].tmd0, \ - ib->btx_ring[t].length, \ - ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits); \ - } \ -} while (0) -#else -#define PRINT_RINGS() -#endif - -/* Load the CSR registers. The LANCE has to be STOPped when we do this! */ -static void load_csrs(struct lance_private *lp) -{ - volatile struct lance_init_block *aib =3D lp->lance_init_block; - int leptr; - - leptr =3D LANCE_ADDR(aib); - - WRITERAP(lp, LE_CSR1); /* load address of init block */ - WRITERDP(lp, leptr & 0xFFFF); - WRITERAP(lp, LE_CSR2); - WRITERDP(lp, leptr >> 16); - WRITERAP(lp, LE_CSR3); - WRITERDP(lp, lp->busmaster_regval); /* set byteswap/ALEctrl/byte ct= rl */ - - /* Point back to csr0 */ - WRITERAP(lp, LE_CSR0); -} - -/* #define to 0 or 1 appropriately */ -#define DEBUG_IRING 0 -/* Set up the Lance Rx and Tx rings and the init block */ -static void lance_init_ring(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - volatile struct lance_init_block *ib =3D lp->init_block; - volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */ - int leptr; - int i; - - aib =3D lp->lance_init_block; - - lp->rx_new =3D lp->tx_new =3D 0; - lp->rx_old =3D lp->tx_old =3D 0; - - ib->mode =3D LE_MO_PROM; /* normal, enable Tx= & Rx */ - - /* Copy the ethernet address to the lance init block - * Notice that we do a byteswap if we're big endian. - * [I think this is the right criterion; at least, sunlance, - * a2065 and atarilance do the byteswap and lance.c (PC) doesn't. - * However, the datasheet says that the BSWAP bit doesn't affect - * the init block, so surely it should be low byte first for - * everybody? Um.] - * We could define the ib->physaddr as three 16bit values and - * use (addr[1] << 8) | addr[0] & co, but this is more efficient. - */ -#ifdef __BIG_ENDIAN - ib->phys_addr[0] =3D dev->dev_addr[1]; - ib->phys_addr[1] =3D dev->dev_addr[0]; - ib->phys_addr[2] =3D dev->dev_addr[3]; - ib->phys_addr[3] =3D dev->dev_addr[2]; - ib->phys_addr[4] =3D dev->dev_addr[5]; - ib->phys_addr[5] =3D dev->dev_addr[4]; -#else - for (i =3D 0; i < 6; i++) - ib->phys_addr[i] =3D dev->dev_addr[i]; -#endif - - if (DEBUG_IRING) - printk("TX rings:\n"); - - lp->tx_full =3D 0; - /* Setup the Tx ring entries */ - for (i =3D 0; i < (1 << lp->lance_log_tx_bufs); i++) { - leptr =3D LANCE_ADDR(&aib->tx_buf[i][0]); - ib->btx_ring[i].tmd0 =3D leptr; - ib->btx_ring[i].tmd1_hadr =3D leptr >> 16; - ib->btx_ring[i].tmd1_bits =3D 0; - ib->btx_ring[i].length =3D 0xf000; /* The ones required by tmd2 */ - ib->btx_ring[i].misc =3D 0; - if (DEBUG_IRING) - printk("%d: 0x%8.8x\n", i, leptr); - } - - /* Setup the Rx ring entries */ - if (DEBUG_IRING) - printk("RX rings:\n"); - for (i =3D 0; i < (1 << lp->lance_log_rx_bufs); i++) { - leptr =3D LANCE_ADDR(&aib->rx_buf[i][0]); - - ib->brx_ring[i].rmd0 =3D leptr; - ib->brx_ring[i].rmd1_hadr =3D leptr >> 16; - ib->brx_ring[i].rmd1_bits =3D LE_R1_OWN; - /* 0xf000 =3D=3D bits that must be one (reserved, presumably) */ - ib->brx_ring[i].length =3D -RX_BUFF_SIZE | 0xf000; - ib->brx_ring[i].mblength =3D 0; - if (DEBUG_IRING) - printk("%d: 0x%8.8x\n", i, leptr); - } - - /* Setup the initialization block */ - - /* Setup rx descriptor pointer */ - leptr =3D LANCE_ADDR(&aib->brx_ring); - ib->rx_len =3D (lp->lance_log_rx_bufs << 13) | (leptr >> 16); - ib->rx_ptr =3D leptr; - if (DEBUG_IRING) - printk("RX ptr: %8.8x\n", leptr); - - /* Setup tx descriptor pointer */ - leptr =3D LANCE_ADDR(&aib->btx_ring); - ib->tx_len =3D (lp->lance_log_tx_bufs << 13) | (leptr >> 16); - ib->tx_ptr =3D leptr; - if (DEBUG_IRING) - printk("TX ptr: %8.8x\n", leptr); - - /* Clear the multicast filter */ - ib->filter[0] =3D 0; - ib->filter[1] =3D 0; - PRINT_RINGS(); -} - -/* LANCE must be STOPped before we do this, too... */ -static int init_restart_lance(struct lance_private *lp) -{ - int i; - - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_INIT); - - /* Need a hook here for sunlance ledma stuff */ - - /* Wait for the lance to complete initialization */ - for (i =3D 0; (i < 100) && !(READRDP(lp) & (LE_C0_ERR | LE_C0_IDON)); i++) - barrier(); - if ((i =3D=3D 100) || (READRDP(lp) & LE_C0_ERR)) { - printk("LANCE unopened after %d ticks, csr0=3D%4.4x.\n", i, READRDP(lp)); - return -1; - } - - /* Clear IDON by writing a "1", enable interrupts and start lance */ - WRITERDP(lp, LE_C0_IDON); - WRITERDP(lp, LE_C0_INEA | LE_C0_STRT); - - return 0; -} - -static int lance_reset(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - int status; - - /* Stop the lance */ - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_STOP); - - load_csrs(lp); - lance_init_ring(dev); - netif_trans_update(dev); /* prevent tx timeout */ - status =3D init_restart_lance(lp); -#ifdef DEBUG_DRIVER - printk("Lance restart=3D%d\n", status); -#endif - return status; -} - -static int lance_rx(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - volatile struct lance_init_block *ib =3D lp->init_block; - volatile struct lance_rx_desc *rd; - unsigned char bits; -#ifdef TEST_HITS - int i; -#endif - -#ifdef TEST_HITS - printk("["); - for (i =3D 0; i < RX_RING_SIZE; i++) { - if (i =3D=3D lp->rx_new) - printk("%s", - ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "_" : "X"); - else - printk("%s", - ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1"); - } - printk("]"); -#endif -#ifdef CONFIG_HP300 - blinken_leds(0x40, 0); -#endif - WRITERDP(lp, LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */ - for (rd =3D &ib->brx_ring[lp->rx_new]; /* For each Rx ring we own... = */ - !((bits =3D rd->rmd1_bits) & LE_R1_OWN); - rd =3D &ib->brx_ring[lp->rx_new]) { - - /* We got an incomplete frame? */ - if ((bits & LE_R1_POK) !=3D LE_R1_POK) { - dev->stats.rx_over_errors++; - dev->stats.rx_errors++; - continue; - } else if (bits & LE_R1_ERR) { - /* Count only the end frame as a rx error, - * not the beginning - */ - if (bits & LE_R1_BUF) - dev->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) - dev->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) - dev->stats.rx_over_errors++; - if (bits & LE_R1_FRA) - dev->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) - dev->stats.rx_errors++; - } else { - int len =3D (rd->mblength & 0xfff) - 4; - struct sk_buff *skb =3D netdev_alloc_skb(dev, len + 2); - - if (!skb) { - dev->stats.rx_dropped++; - rd->mblength =3D 0; - rd->rmd1_bits =3D LE_R1_OWN; - lp->rx_new =3D (lp->rx_new + 1) & lp->rx_ring_mod_mask; - return 0; - } - - skb_reserve(skb, 2); /* 16 byte align */ - skb_put(skb, len); /* make room */ - skb_copy_to_linear_data(skb, - (unsigned char *)&(ib->rx_buf[lp->rx_new][0]), - len); - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D len; - } - - /* Return the packet to the pool */ - rd->mblength =3D 0; - rd->rmd1_bits =3D LE_R1_OWN; - lp->rx_new =3D (lp->rx_new + 1) & lp->rx_ring_mod_mask; - } - return 0; -} - -static int lance_tx(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - volatile struct lance_init_block *ib =3D lp->init_block; - volatile struct lance_tx_desc *td; - int i, j; - int status; - -#ifdef CONFIG_HP300 - blinken_leds(0x80, 0); -#endif - /* csr0 is 2f3 */ - WRITERDP(lp, LE_C0_TINT | LE_C0_INEA); - /* csr0 is 73 */ - - j =3D lp->tx_old; - for (i =3D j; i !=3D lp->tx_new; i =3D j) { - td =3D &ib->btx_ring[i]; - - /* If we hit a packet not owned by us, stop */ - if (td->tmd1_bits & LE_T1_OWN) - break; - - if (td->tmd1_bits & LE_T1_ERR) { - status =3D td->misc; - - dev->stats.tx_errors++; - if (status & LE_T3_RTY) - dev->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) - dev->stats.tx_window_errors++; - - if (status & LE_T3_CLOS) { - dev->stats.tx_carrier_errors++; - if (lp->auto_select) { - lp->tpe =3D 1 - lp->tpe; - printk("%s: Carrier Lost, trying %s\n", - dev->name, - lp->tpe ? "TPE" : "AUI"); - /* Stop the lance */ - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_STOP); - lance_init_ring(dev); - load_csrs(lp); - init_restart_lance(lp); - return 0; - } - } - - /* buffer errors and underflows turn off the transmitter */ - /* Restart the adapter */ - if (status & (LE_T3_BUF|LE_T3_UFL)) { - dev->stats.tx_fifo_errors++; - - printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", - dev->name); - /* Stop the lance */ - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_STOP); - lance_init_ring(dev); - load_csrs(lp); - init_restart_lance(lp); - return 0; - } - } else if ((td->tmd1_bits & LE_T1_POK) =3D=3D LE_T1_POK) { - /* - * So we don't count the packet more than once. - */ - td->tmd1_bits &=3D ~(LE_T1_POK); - - /* One collision before packet was sent. */ - if (td->tmd1_bits & LE_T1_EONE) - dev->stats.collisions++; - - /* More than one collision, be optimistic. */ - if (td->tmd1_bits & LE_T1_EMORE) - dev->stats.collisions +=3D 2; - - dev->stats.tx_packets++; - } - - j =3D (j + 1) & lp->tx_ring_mod_mask; - } - lp->tx_old =3D j; - WRITERDP(lp, LE_C0_TINT | LE_C0_INEA); - return 0; -} - -static irqreturn_t -lance_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D (struct net_device *)dev_id; - struct lance_private *lp =3D netdev_priv(dev); - int csr0; - - spin_lock(&lp->devlock); - - WRITERAP(lp, LE_CSR0); /* LANCE Controller Status */ - csr0 =3D READRDP(lp); - - PRINT_RINGS(); - - if (!(csr0 & LE_C0_INTR)) { /* Check if any interrupt has */ - spin_unlock(&lp->devlock); - return IRQ_NONE; /* been generated by the Lance. */ - } - - /* Acknowledge all the interrupt sources ASAP */ - WRITERDP(lp, csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_I= NIT)); - - if ((csr0 & LE_C0_ERR)) { - /* Clear the error condition */ - WRITERDP(lp, LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA); - } - - if (csr0 & LE_C0_RINT) - lance_rx(dev); - - if (csr0 & LE_C0_TINT) - lance_tx(dev); - - /* Log misc errors. */ - if (csr0 & LE_C0_BABL) - dev->stats.tx_errors++; /* Tx babble. */ - if (csr0 & LE_C0_MISS) - dev->stats.rx_errors++; /* Missed a Rx frame. */ - if (csr0 & LE_C0_MERR) { - printk("%s: Bus master arbitration failure, status %4.4x.\n", - dev->name, csr0); - /* Restart the chip. */ - WRITERDP(lp, LE_C0_STRT); - } - - if (lp->tx_full && netif_queue_stopped(dev) && (TX_BUFFS_AVAIL >=3D 0)) { - lp->tx_full =3D 0; - netif_wake_queue(dev); - } - - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0= _INEA); - - spin_unlock(&lp->devlock); - return IRQ_HANDLED; -} - -int lance_open(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - int res; - - /* Install the Interrupt handler. Or we could shunt this out to specific = drivers? */ - if (request_irq(lp->irq, lance_interrupt, IRQF_SHARED, lp->name, dev)) - return -EAGAIN; - - res =3D lance_reset(dev); - spin_lock_init(&lp->devlock); - netif_start_queue(dev); - - return res; -} -EXPORT_SYMBOL_GPL(lance_open); - -int lance_close(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - - netif_stop_queue(dev); - - /* Stop the LANCE */ - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_STOP); - - free_irq(lp->irq, dev); - - return 0; -} -EXPORT_SYMBOL_GPL(lance_close); - -void lance_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - printk("lance_tx_timeout\n"); - lance_reset(dev); - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); -} -EXPORT_SYMBOL_GPL(lance_tx_timeout); - -netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - volatile struct lance_init_block *ib =3D lp->init_block; - int entry, skblen, len; - static int outs; - unsigned long flags; - - netif_stop_queue(dev); - - if (!TX_BUFFS_AVAIL) { - dev_consume_skb_any(skb); - return NETDEV_TX_OK; - } - - skblen =3D skb->len; - -#ifdef DEBUG_DRIVER - /* dump the packet */ - { - int i; - - for (i =3D 0; i < 64; i++) { - if ((i % 16) =3D=3D 0) - printk("\n"); - printk("%2.2x ", skb->data[i]); - } - } -#endif - len =3D (skblen <=3D ETH_ZLEN) ? ETH_ZLEN : skblen; - entry =3D lp->tx_new & lp->tx_ring_mod_mask; - ib->btx_ring[entry].length =3D (-len) | 0xf000; - ib->btx_ring[entry].misc =3D 0; - - if (skb->len < ETH_ZLEN) - memset((void *)&ib->tx_buf[entry][0], 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen); - - /* Now, give the packet to the lance */ - ib->btx_ring[entry].tmd1_bits =3D (LE_T1_POK|LE_T1_OWN); - lp->tx_new =3D (lp->tx_new + 1) & lp->tx_ring_mod_mask; - - outs++; - /* Kick the lance: transmit now */ - WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD); - dev_consume_skb_any(skb); - - spin_lock_irqsave(&lp->devlock, flags); - if (TX_BUFFS_AVAIL) - netif_start_queue(dev); - else - lp->tx_full =3D 1; - spin_unlock_irqrestore(&lp->devlock, flags); - - return NETDEV_TX_OK; -} -EXPORT_SYMBOL_GPL(lance_start_xmit); - -/* taken from the depca driver via a2065.c */ -static void lance_load_multicast(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - volatile struct lance_init_block *ib =3D lp->init_block; - volatile u16 *mcast_table =3D (u16 *)&ib->filter; - struct netdev_hw_addr *ha; - u32 crc; - - /* set all multicast bits */ - if (dev->flags & IFF_ALLMULTI) { - ib->filter[0] =3D 0xffffffff; - ib->filter[1] =3D 0xffffffff; - return; - } - /* clear the multicast filter */ - ib->filter[0] =3D 0; - ib->filter[1] =3D 0; - - /* Add addresses */ - netdev_for_each_mc_addr(ha, dev) { - crc =3D ether_crc_le(6, ha->addr); - crc =3D crc >> 26; - mcast_table[crc >> 4] |=3D 1 << (crc & 0xf); - } -} - - -void lance_set_multicast(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - volatile struct lance_init_block *ib =3D lp->init_block; - int stopped; - - stopped =3D netif_queue_stopped(dev); - if (!stopped) - netif_stop_queue(dev); - - while (lp->tx_old !=3D lp->tx_new) - schedule(); - - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_STOP); - lance_init_ring(dev); - - if (dev->flags & IFF_PROMISC) { - ib->mode |=3D LE_MO_PROM; - } else { - ib->mode &=3D ~LE_MO_PROM; - lance_load_multicast(dev); - } - load_csrs(lp); - init_restart_lance(lp); - - if (!stopped) - netif_start_queue(dev); -} -EXPORT_SYMBOL_GPL(lance_set_multicast); - -#ifdef CONFIG_NET_POLL_CONTROLLER -void lance_poll(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - - spin_lock(&lp->devlock); - WRITERAP(lp, LE_CSR0); - WRITERDP(lp, LE_C0_STRT); - spin_unlock(&lp->devlock); - lance_interrupt(dev->irq, dev); -} -EXPORT_SYMBOL_GPL(lance_poll); -#endif - -MODULE_DESCRIPTION("LANCE Ethernet IC generic routines"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/amd/7990.h b/drivers/net/ethernet/amd/799= 0.h deleted file mode 100644 index e53551daeea1..000000000000 --- a/drivers/net/ethernet/amd/7990.h +++ /dev/null @@ -1,251 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * 7990.h -- LANCE ethernet IC generic routines. - * This is an attempt to separate out the bits of various ethernet - * drivers that are common because they all use the AMD 7990 LANCE - * (Local Area Network Controller for Ethernet) chip. - * - * Copyright (C) 05/1998 Peter Maydell - * - * Most of this stuff was obtained by looking at other LANCE drivers, - * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful. - */ - -#ifndef _7990_H -#define _7990_H - -/* The lance only has two register locations. We communicate mostly via me= mory. */ -#define LANCE_RDP 0 /* Register Data Port */ -#define LANCE_RAP 2 /* Register Address Port */ - -/* Transmit/receive ring definitions. - * We allow the specific drivers to override these defaults if they want t= o. - * NB: according to lance.c, increasing the number of buffers is a waste - * of space and reduces the chance that an upper layer will be able to - * reorder queued Tx packets based on priority. [Clearly there is a minimum - * limit too: too small and we drop rx packets and can't tx at full speed.] - * 4+4 seems to be the usual setting; the atarilance driver uses 3 and 5. - */ - -/* Blast! This won't work. The problem is that we can't specify a default - * setting because that would cause the lance_init_block struct to be - * too long (and overflow the RAM on shared-memory cards like the HP LANCE. - */ -#ifndef LANCE_LOG_TX_BUFFERS -#define LANCE_LOG_TX_BUFFERS 1 -#define LANCE_LOG_RX_BUFFERS 3 -#endif - -#define TX_RING_SIZE (1 << LANCE_LOG_TX_BUFFERS) -#define RX_RING_SIZE (1 << LANCE_LOG_RX_BUFFERS) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) -#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) -#define PKT_BUFF_SIZE (1544) -#define RX_BUFF_SIZE PKT_BUFF_SIZE -#define TX_BUFF_SIZE PKT_BUFF_SIZE - -/* Each receive buffer is described by a receive message descriptor (RMD) = */ -struct lance_rx_desc { - volatile unsigned short rmd0; /* low address of packet */ - volatile unsigned char rmd1_bits; /* descriptor bits */ - volatile unsigned char rmd1_hadr; /* high address of packet */ - volatile short length; /* This length is 2s complement (negative)! - * Buffer length */ - volatile unsigned short mblength; /* Actual number of bytes received */ -}; - -/* Ditto for TMD: */ -struct lance_tx_desc { - volatile unsigned short tmd0; /* low address of packet */ - volatile unsigned char tmd1_bits; /* descriptor bits */ - volatile unsigned char tmd1_hadr; /* high address of packet */ - volatile short length; /* Length is 2s complement (negative)! */ - volatile unsigned short misc; -}; - -/* There are three memory structures accessed by the LANCE: - * the initialization block, the receive and transmit descriptor rings, - * and the data buffers themselves. In fact we might as well put the - * init block,the Tx and Rx rings and the buffers together in memory: - */ -struct lance_init_block { - volatile unsigned short mode; /* Pre-set mode (reg. 15) */ - volatile unsigned char phys_addr[6]; /* Physical ethernet address */ - volatile unsigned filter[2]; /* Multicast filter (64 bits) */ - - /* Receive and transmit ring base, along with extra bits. */ - volatile unsigned short rx_ptr; /* receive descriptor addr */ - volatile unsigned short rx_len; /* receive len and high addr */ - volatile unsigned short tx_ptr; /* transmit descriptor addr */ - volatile unsigned short tx_len; /* transmit len and high addr */ - - /* The Tx and Rx ring entries must be aligned on 8-byte boundaries. - * This will be true if this whole struct is 8-byte aligned. - */ - volatile struct lance_tx_desc btx_ring[TX_RING_SIZE]; - volatile struct lance_rx_desc brx_ring[RX_RING_SIZE]; - - volatile char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE]; - volatile char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE]; - /* we use this just to make the struct big enough that we can move its st= artaddr - * in order to force alignment to an eight byte boundary. - */ -}; - -/* This is where we keep all the stuff the driver needs to know about. - * I'm definitely unhappy about the mechanism for allowing specific - * drivers to add things... - */ -struct lance_private { - const char *name; - unsigned long base; - volatile struct lance_init_block *init_block; /* CPU address of RAM */ - volatile struct lance_init_block *lance_init_block; /* LANCE address of R= AM */ - - int rx_new, tx_new; - int rx_old, tx_old; - - int lance_log_rx_bufs, lance_log_tx_bufs; - int rx_ring_mod_mask, tx_ring_mod_mask; - - int tpe; /* TPE is selected */ - int auto_select; /* cable-selection is by carrier */ - unsigned short busmaster_regval; - - unsigned int irq; /* IRQ to register */ - - /* This is because the HP LANCE is disgusting and you have to check - * a DIO-specific register every time you read/write the LANCE regs :-< - * [could we get away with making these some sort of macro?] - */ - void (*writerap)(void *, unsigned short); - void (*writerdp)(void *, unsigned short); - unsigned short (*readrdp)(void *); - spinlock_t devlock; - char tx_full; -}; - -/* - * Am7990 Control and Status Registers - */ -#define LE_CSR0 0x0000 /* LANCE Controller Status */ -#define LE_CSR1 0x0001 /* IADR[15:0] (bit0=3D=3D0 ie word aligned) */ -#define LE_CSR2 0x0002 /* IADR[23:16] (high bits reserved) */ -#define LE_CSR3 0x0003 /* Misc */ - -/* - * Bit definitions for CSR0 (LANCE Controller Status) - */ -#define LE_C0_ERR 0x8000 /* Error =3D BABL | CERR | MISS | MERR */ -#define LE_C0_BABL 0x4000 /* Babble: Transmitted too many bits */ -#define LE_C0_CERR 0x2000 /* No Heartbeat (10BASE-T) */ -#define LE_C0_MISS 0x1000 /* Missed Frame (no rx buffer to put it in) */ -#define LE_C0_MERR 0x0800 /* Memory Error */ -#define LE_C0_RINT 0x0400 /* Receive Interrupt */ -#define LE_C0_TINT 0x0200 /* Transmit Interrupt */ -#define LE_C0_IDON 0x0100 /* Initialization Done */ -#define LE_C0_INTR 0x0080 /* Interrupt Flag - =3D BABL | MISS | MERR | RINT | TINT | IDON */ -#define LE_C0_INEA 0x0040 /* Interrupt Enable */ -#define LE_C0_RXON 0x0020 /* Receive On */ -#define LE_C0_TXON 0x0010 /* Transmit On */ -#define LE_C0_TDMD 0x0008 /* Transmit Demand */ -#define LE_C0_STOP 0x0004 /* Stop */ -#define LE_C0_STRT 0x0002 /* Start */ -#define LE_C0_INIT 0x0001 /* Initialize */ - - -/* - * Bit definitions for CSR3 - */ -#define LE_C3_BSWP 0x0004 /* Byte Swap (on for big endian byte order) */ -#define LE_C3_ACON 0x0002 /* ALE Control (on for active low ALE) */ -#define LE_C3_BCON 0x0001 /* Byte Control */ - - -/* - * Mode Flags - */ -#define LE_MO_PROM 0x8000 /* Promiscuous Mode */ -/* these next ones 0x4000 -- 0x0080 are not available on the LANCE 7990, - * but they are in NetBSD's am7990.h, presumably for backwards-compatible = chips - */ -#define LE_MO_DRCVBC 0x4000 /* disable receive broadcast */ -#define LE_MO_DRCVPA 0x2000 /* disable physical address detection */ -#define LE_MO_DLNKTST 0x1000 /* disable link status */ -#define LE_MO_DAPC 0x0800 /* disable automatic polarity correction */ -#define LE_MO_MENDECL 0x0400 /* MENDEC loopback mode */ -#define LE_MO_LRTTSEL 0x0200 /* lower RX threshold / TX mode selection */ -#define LE_MO_PSEL1 0x0100 /* port selection bit1 */ -#define LE_MO_PSEL0 0x0080 /* port selection bit0 */ -/* and this one is from the C-LANCE data sheet... */ -#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm - (C-LANCE, not original LANCE) */ -#define LE_MO_INTL 0x0040 /* Internal Loopback */ -#define LE_MO_DRTY 0x0020 /* Disable Retry */ -#define LE_MO_FCOLL 0x0010 /* Force Collision */ -#define LE_MO_DXMTFCS 0x0008 /* Disable Transmit CRC */ -#define LE_MO_LOOP 0x0004 /* Loopback Enable */ -#define LE_MO_DTX 0x0002 /* Disable Transmitter */ -#define LE_MO_DRX 0x0001 /* Disable Receiver */ - - -/* - * Receive Flags - */ -#define LE_R1_OWN 0x80 /* LANCE owns the descriptor */ -#define LE_R1_ERR 0x40 /* Error */ -#define LE_R1_FRA 0x20 /* Framing Error */ -#define LE_R1_OFL 0x10 /* Overflow Error */ -#define LE_R1_CRC 0x08 /* CRC Error */ -#define LE_R1_BUF 0x04 /* Buffer Error */ -#define LE_R1_SOP 0x02 /* Start of Packet */ -#define LE_R1_EOP 0x01 /* End of Packet */ -#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ - - -/* - * Transmit Flags - */ -#define LE_T1_OWN 0x80 /* LANCE owns the descriptor */ -#define LE_T1_ERR 0x40 /* Error */ -#define LE_T1_RES 0x20 /* Reserved, LANCE writes this with a zero */ -#define LE_T1_EMORE 0x10 /* More than one retry needed */ -#define LE_T1_EONE 0x08 /* One retry needed */ -#define LE_T1_EDEF 0x04 /* Deferred */ -#define LE_T1_SOP 0x02 /* Start of Packet */ -#define LE_T1_EOP 0x01 /* End of Packet */ -#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ - -/* - * Error Flags - */ -#define LE_T3_BUF 0x8000 /* Buffer Error */ -#define LE_T3_UFL 0x4000 /* Underflow Error */ -#define LE_T3_LCOL 0x1000 /* Late Collision */ -#define LE_T3_CLOS 0x0800 /* Loss of Carrier */ -#define LE_T3_RTY 0x0400 /* Retry Error */ -#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry */ - -/* Miscellaneous useful macros */ - -#define TX_BUFFS_AVAIL ((lp->tx_old <=3D lp->tx_new) ? \ - lp->tx_old + lp->tx_ring_mod_mask - lp->tx_new : \ - lp->tx_old - lp->tx_new - 1) - -/* The LANCE only uses 24 bit addresses. This does the obvious thing. */ -#define LANCE_ADDR(x) ((int)(x) & ~0xff000000) - -/* Now the prototypes we export */ -int lance_open(struct net_device *dev); -int lance_close(struct net_device *dev); -netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev); -void lance_set_multicast(struct net_device *dev); -void lance_tx_timeout(struct net_device *dev, unsigned int txqueue); -#ifdef CONFIG_NET_POLL_CONTROLLER -void lance_poll(struct net_device *dev); -#endif - -#endif /* ndef _7990_H */ diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kc= onfig index 45e8d698781c..9e83f3aa435a 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -93,14 +93,6 @@ config DECLANCE DEC (now Compaq) based on the AMD LANCE chipset, including the DEPCA series. (This chipset is better known via the NE2100 cards.) =20 -config HPLANCE - tristate "HP on-board LANCE support" - depends on DIO - select CRC32 - help - If you want to use the builtin "LANCE" Ethernet controller on an - HP300 machine, say Y here. - config MIPS_AU1X00_ENET tristate "MIPS AU1000 Ethernet support" depends on MIPS_ALCHEMY @@ -110,16 +102,6 @@ config MIPS_AU1X00_ENET If you have an Alchemy Semi AU1X00 based system say Y. Otherwise, say N. =20 -config MVME147_NET - tristate "MVME147 (LANCE) Ethernet support" - depends on MVME147 - select CRC32 - help - Support for the on-board Ethernet interface on the Motorola MVME147 - single-board computer. Say Y here to include the - driver for this chip in your kernel. - To compile this driver as a module, choose M here. - config PCMCIA_NMCLAN tristate "New Media PCMCIA support" depends on PCMCIA && HAS_IOPORT diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/M= akefile index 2dcfb84731e1..387ec74e8e95 100644 --- a/drivers/net/ethernet/amd/Makefile +++ b/drivers/net/ethernet/amd/Makefile @@ -8,10 +8,8 @@ obj-$(CONFIG_AMD8111_ETH) +=3D amd8111e.o obj-$(CONFIG_ARIADNE) +=3D ariadne.o obj-$(CONFIG_ATARILANCE) +=3D atarilance.o obj-$(CONFIG_DECLANCE) +=3D declance.o -obj-$(CONFIG_HPLANCE) +=3D hplance.o 7990.o obj-$(CONFIG_LANCE) +=3D lance.o obj-$(CONFIG_MIPS_AU1X00_ENET) +=3D au1000_eth.o -obj-$(CONFIG_MVME147_NET) +=3D mvme147.o 7990.o obj-$(CONFIG_PCMCIA_NMCLAN) +=3D nmclan_cs.o obj-$(CONFIG_PCNET32) +=3D pcnet32.o obj-$(CONFIG_SUN3LANCE) +=3D sun3lance.o diff --git a/drivers/net/ethernet/amd/hplance.c b/drivers/net/ethernet/amd/= hplance.c deleted file mode 100644 index df42294530cb..000000000000 --- a/drivers/net/ethernet/amd/hplance.c +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* hplance.c : the Linux/hp300/lance ethernet driver - * - * Copyright (C) 05/1998 Peter Maydell - * Based on the Sun Lance driver and the NetBSD HP Lance driver - * Uses the generic 7990.c LANCE code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* Used for the temporal inet entries and routing */ -#include -#include -#include -#include -#include -#include - -#include - -#include "hplance.h" - -/* We have 16392 bytes of RAM for the init block and buffers. This places - * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx - * buffers and 2 Tx buffers, it takes (8 + 2) * 1544 bytes. - */ -#define LANCE_LOG_TX_BUFFERS 1 -#define LANCE_LOG_RX_BUFFERS 3 - -#include "7990.h" /* use generic LANCE cod= e */ - -/* Our private data structure */ -struct hplance_private { - struct lance_private lance; -}; - -/* function prototypes... This is easy because all the grot is in the - * generic LANCE support. All we have to support is probing for boards, - * plus board-specific init, open and close actions. - * Oh, and we need to tell the generic code how to read and write LANCE re= gisters... - */ -static int hplance_init_one(struct dio_dev *d, const struct dio_device_id = *ent); -static void hplance_init(struct net_device *dev, struct dio_dev *d); -static void hplance_remove_one(struct dio_dev *d); -static void hplance_writerap(void *priv, unsigned short value); -static void hplance_writerdp(void *priv, unsigned short value); -static unsigned short hplance_readrdp(void *priv); -static int hplance_open(struct net_device *dev); -static int hplance_close(struct net_device *dev); - -static struct dio_device_id hplance_dio_tbl[] =3D { - { DIO_ID_LAN }, - { 0 } -}; - -static struct dio_driver hplance_driver =3D { - .name =3D "hplance", - .id_table =3D hplance_dio_tbl, - .probe =3D hplance_init_one, - .remove =3D hplance_remove_one, -}; - -static const struct net_device_ops hplance_netdev_ops =3D { - .ndo_open =3D hplance_open, - .ndo_stop =3D hplance_close, - .ndo_start_xmit =3D lance_start_xmit, - .ndo_set_rx_mode =3D lance_set_multicast, - .ndo_validate_addr =3D eth_validate_addr, - .ndo_set_mac_address =3D eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D lance_poll, -#endif -}; - -/* Find all the HP Lance boards and initialise them... */ -static int hplance_init_one(struct dio_dev *d, const struct dio_device_id = *ent) -{ - struct net_device *dev; - int err =3D -ENOMEM; - - dev =3D alloc_etherdev(sizeof(struct hplance_private)); - if (!dev) - goto out; - - err =3D -EBUSY; - if (!request_mem_region(dio_resource_start(d), - dio_resource_len(d), d->name)) - goto out_free_netdev; - - hplance_init(dev, d); - err =3D register_netdev(dev); - if (err) - goto out_release_mem_region; - - dio_set_drvdata(d, dev); - - printk(KERN_INFO "%s: %s; select code %d, addr %pM, irq %d\n", - dev->name, d->name, d->scode, dev->dev_addr, d->ipl); - - return 0; - - out_release_mem_region: - release_mem_region(dio_resource_start(d), dio_resource_len(d)); - out_free_netdev: - free_netdev(dev); - out: - return err; -} - -static void hplance_remove_one(struct dio_dev *d) -{ - struct net_device *dev =3D dio_get_drvdata(d); - - unregister_netdev(dev); - release_mem_region(dio_resource_start(d), dio_resource_len(d)); - free_netdev(dev); -} - -/* Initialise a single lance board at the given DIO device */ -static void hplance_init(struct net_device *dev, struct dio_dev *d) -{ - unsigned long va =3D (d->resource.start + DIO_VIRADDRBASE); - struct hplance_private *lp; - u8 addr[ETH_ALEN]; - int i; - - /* reset the board */ - out_8(va + DIO_IDOFF, 0xff); - udelay(100); /* ariba! ariba! udelay! udelay= ! */ - - /* Fill the dev fields */ - dev->base_addr =3D va; - dev->netdev_ops =3D &hplance_netdev_ops; - dev->dma =3D 0; - - for (i =3D 0; i < 6; i++) { - /* The NVRAM holds our ethernet address, one nibble per byte, - * at bytes NVRAMOFF+1,3,5,7,9... - */ - addr[i] =3D ((in_8(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4) - | (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF); - } - eth_hw_addr_set(dev, addr); - - lp =3D netdev_priv(dev); - lp->lance.name =3D d->name; - lp->lance.base =3D va; - lp->lance.init_block =3D (struct lance_init_block *)(va + HPLANCE_MEMOFF)= ; /* CPU addr */ - lp->lance.lance_init_block =3D NULL; /* LANCE addr of same R= AM */ - lp->lance.busmaster_regval =3D LE_C3_BSWP; /* we're bigendian */ - lp->lance.irq =3D d->ipl; - lp->lance.writerap =3D hplance_writerap; - lp->lance.writerdp =3D hplance_writerdp; - lp->lance.readrdp =3D hplance_readrdp; - lp->lance.lance_log_rx_bufs =3D LANCE_LOG_RX_BUFFERS; - lp->lance.lance_log_tx_bufs =3D LANCE_LOG_TX_BUFFERS; - lp->lance.rx_ring_mod_mask =3D RX_RING_MOD_MASK; - lp->lance.tx_ring_mod_mask =3D TX_RING_MOD_MASK; -} - -/* This is disgusting. We have to check the DIO status register for ack ev= ery - * time we read or write the LANCE registers. - */ -static void hplance_writerap(void *priv, unsigned short value) -{ - struct lance_private *lp =3D (struct lance_private *)priv; - - do { - out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value); - } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) =3D=3D 0); -} - -static void hplance_writerdp(void *priv, unsigned short value) -{ - struct lance_private *lp =3D (struct lance_private *)priv; - - do { - out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value); - } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) =3D=3D 0); -} - -static unsigned short hplance_readrdp(void *priv) -{ - struct lance_private *lp =3D (struct lance_private *)priv; - __u16 value; - - do { - value =3D in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP); - } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) =3D=3D 0); - return value; -} - -static int hplance_open(struct net_device *dev) -{ - int status; - struct lance_private *lp =3D netdev_priv(dev); - - status =3D lance_open(dev); /* call generic lance open co= de */ - if (status) - return status; - /* enable interrupts at board level. */ - out_8(lp->base + HPLANCE_STATUS, LE_IE); - - return 0; -} - -static int hplance_close(struct net_device *dev) -{ - struct lance_private *lp =3D netdev_priv(dev); - - out_8(lp->base + HPLANCE_STATUS, 0); /* disable interrupts at boardlevel = */ - lance_close(dev); - return 0; -} - -static int __init hplance_init_module(void) -{ - return dio_register_driver(&hplance_driver); -} - -static void __exit hplance_cleanup_module(void) -{ - dio_unregister_driver(&hplance_driver); -} - -module_init(hplance_init_module); -module_exit(hplance_cleanup_module); - -MODULE_DESCRIPTION("HP300 on-board LANCE Ethernet driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/amd/hplance.h b/drivers/net/ethernet/amd/= hplance.h deleted file mode 100644 index bc845a2c60c1..000000000000 --- a/drivers/net/ethernet/amd/hplance.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Random defines and structures for the HP Lance driver. - * Copyright (C) 05/1998 Peter Maydell - * Based on the Sun Lance driver and the NetBSD HP Lance driver - */ - -/* Registers */ -#define HPLANCE_ID 0x01 /* DIO register: ID byte */ -#define HPLANCE_STATUS 0x03 /* DIO register: interrupt enable/status */ - -/* Control and status bits for the status register */ -#define LE_IE 0x80 /* interrupt enable */ -#define LE_IR 0x40 /* interrupt requested */ -#define LE_LOCK 0x08 /* lock status register = */ -#define LE_ACK 0x04 /* ack of lock */ -#define LE_JAB 0x02 /* loss of tx clock (???= ) */ -/* We can also extract the IPL from the status register with the standard - * DIO_IPL(hplance) macro, or using dio_scodetoipl() - */ - -/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg, - * memory and NVRAM: - */ -#define HPLANCE_IDOFF 0 /* board baseaddr */ -#define HPLANCE_REGOFF 0x4000 /* lance registers */ -#define HPLANCE_MEMOFF 0x8000 /* struct lance_init_blo= ck */ -#define HPLANCE_NVRAMOFF 0xC008 /* etheraddress as one *= nibble* per byte */ diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/= mvme147.c deleted file mode 100644 index f19b04b92fa9..000000000000 --- a/drivers/net/ethernet/amd/mvme147.c +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* mvme147.c : the Linux/mvme147/lance ethernet driver - * - * Copyright (C) 05/1998 Peter Maydell - * Based on the Sun Lance driver and the NetBSD HP Lance driver - * Uses the generic 7990.c LANCE code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* Used for the temporal inet entries and routing */ -#include -#include -#include -#include -#include - -#include -#include - -/* We have 32K of RAM for the init block and buffers. This places - * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx - * buffers and 2 Tx buffers, it takes (8 + 2) * 1544 bytes. - */ -#define LANCE_LOG_TX_BUFFERS 1 -#define LANCE_LOG_RX_BUFFERS 3 - -#include "7990.h" /* use generic LANCE cod= e */ - -/* Our private data structure */ -struct m147lance_private { - struct lance_private lance; - unsigned long ram; -}; - -/* function prototypes... This is easy because all the grot is in the - * generic LANCE support. All we have to support is probing for boards, - * plus board-specific init, open and close actions. - * Oh, and we need to tell the generic code how to read and write LANCE re= gisters... - */ -static int m147lance_open(struct net_device *dev); -static int m147lance_close(struct net_device *dev); -static void m147lance_writerap(struct lance_private *lp, unsigned short va= lue); -static void m147lance_writerdp(struct lance_private *lp, unsigned short va= lue); -static unsigned short m147lance_readrdp(struct lance_private *lp); - -typedef void (*writerap_t)(void *, unsigned short); -typedef void (*writerdp_t)(void *, unsigned short); -typedef unsigned short (*readrdp_t)(void *); - -static const struct net_device_ops lance_netdev_ops =3D { - .ndo_open =3D m147lance_open, - .ndo_stop =3D m147lance_close, - .ndo_start_xmit =3D lance_start_xmit, - .ndo_set_rx_mode =3D lance_set_multicast, - .ndo_tx_timeout =3D lance_tx_timeout, - .ndo_validate_addr =3D eth_validate_addr, - .ndo_set_mac_address =3D eth_mac_addr, -}; - -/* Initialise the one and only on-board 7990 */ -static struct net_device * __init mvme147lance_probe(void) -{ - struct net_device *dev; - static int called; - static const char name[] =3D "MVME147 LANCE"; - struct m147lance_private *lp; - u8 macaddr[ETH_ALEN]; - u_long *addr; - u_long address; - int err; - - if (!MACH_IS_MVME147 || called) - return ERR_PTR(-ENODEV); - called++; - - dev =3D alloc_etherdev(sizeof(struct m147lance_private)); - if (!dev) - return ERR_PTR(-ENOMEM); - - /* Fill the dev fields */ - dev->base_addr =3D (unsigned long)MVME147_LANCE_BASE; - dev->netdev_ops =3D &lance_netdev_ops; - dev->dma =3D 0; - - addr =3D (u_long *)ETHERNET_ADDRESS; - address =3D *addr; - macaddr[0] =3D 0x08; - macaddr[1] =3D 0x00; - macaddr[2] =3D 0x3e; - address =3D address >> 8; - macaddr[5] =3D address&0xff; - address =3D address >> 8; - macaddr[4] =3D address&0xff; - address =3D address >> 8; - macaddr[3] =3D address&0xff; - eth_hw_addr_set(dev, macaddr); - - lp =3D netdev_priv(dev); - lp->ram =3D __get_dma_pages(GFP_ATOMIC, 3); /* 32K */ - if (!lp->ram) { - printk("%s: No memory for LANCE buffers\n", dev->name); - free_netdev(dev); - return ERR_PTR(-ENOMEM); - } - - lp->lance.name =3D name; - lp->lance.base =3D dev->base_addr; - lp->lance.init_block =3D (struct lance_init_block *)(lp->ram); /* CPU add= r */ - lp->lance.lance_init_block =3D (struct lance_init_block *)(lp->ram); = /* LANCE addr of same RAM */ - lp->lance.busmaster_regval =3D LE_C3_BSWP; /* we're bigendian */ - lp->lance.irq =3D MVME147_LANCE_IRQ; - lp->lance.writerap =3D (writerap_t)m147lance_writerap; - lp->lance.writerdp =3D (writerdp_t)m147lance_writerdp; - lp->lance.readrdp =3D (readrdp_t)m147lance_readrdp; - lp->lance.lance_log_rx_bufs =3D LANCE_LOG_RX_BUFFERS; - lp->lance.lance_log_tx_bufs =3D LANCE_LOG_TX_BUFFERS; - lp->lance.rx_ring_mod_mask =3D RX_RING_MOD_MASK; - lp->lance.tx_ring_mod_mask =3D TX_RING_MOD_MASK; - - err =3D register_netdev(dev); - if (err) { - free_pages(lp->ram, 3); - free_netdev(dev); - return ERR_PTR(err); - } - - netdev_info(dev, "MVME147 at 0x%08lx, irq %d, Hardware Address %pM\n", - dev->base_addr, MVME147_LANCE_IRQ, dev->dev_addr); - - return dev; -} - -static void m147lance_writerap(struct lance_private *lp, unsigned short va= lue) -{ - out_be16(lp->base + LANCE_RAP, value); -} - -static void m147lance_writerdp(struct lance_private *lp, unsigned short va= lue) -{ - out_be16(lp->base + LANCE_RDP, value); -} - -static unsigned short m147lance_readrdp(struct lance_private *lp) -{ - return in_be16(lp->base + LANCE_RDP); -} - -static int m147lance_open(struct net_device *dev) -{ - int status; - - status =3D lance_open(dev); /* call generic lance open co= de */ - if (status) - return status; - /* enable interrupts at board level. */ - m147_pcc->lan_cntrl =3D 0; /* clear the interrupts (if any) */ - m147_pcc->lan_cntrl =3D 0x08 | 0x04; /* Enable irq 4 */ - - return 0; -} - -static int m147lance_close(struct net_device *dev) -{ - /* disable interrupts at boardlevel */ - m147_pcc->lan_cntrl =3D 0x0; /* disable interrupts */ - lance_close(dev); - return 0; -} - -MODULE_DESCRIPTION("MVME147 LANCE Ethernet driver"); -MODULE_LICENSE("GPL"); - -static struct net_device *dev_mvme147_lance; -static int __init m147lance_init(void) -{ - dev_mvme147_lance =3D mvme147lance_probe(); - return PTR_ERR_OR_ZERO(dev_mvme147_lance); -} -module_init(m147lance_init); - -static void __exit m147lance_exit(void) -{ - struct m147lance_private *lp =3D netdev_priv(dev_mvme147_lance); - unregister_netdev(dev_mvme147_lance); - free_pages(lp->ram, 3); - free_netdev(dev_mvme147_lance); -} -module_exit(m147lance_exit); --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BA25D3DCD8C; Tue, 21 Apr 2026 19:31:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799906; cv=none; b=nSkOm5/rMlaDlajpFt7yJyU2OM6Q5k0xVH2ygfj4EdZD+NzST0PAHK0Es3Ru9arkzz3YSZ3FgMVvKpsaIKObqcqhMbs4GegtRRUNAlaMO3B05PYHs7joO4RP46YqbeIlLJ/wBB7Zs/BwvemfR5H0uOuukQMZR+paUgeuLNKbteA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799906; c=relaxed/simple; bh=KpWwQHe1lvgOqeKD6rprzKdlt+f2oAcqKhCFR+x/7Hs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qf7FoZ7BMD4D6YMpnoy/iz1BS3VheJ7aAApW3Sl50n5wBH2R/AAfT7qK1v97ase6CSAVVuOhIphtG8r3rwYDXfGIW9T15xbkPRe/RJCvak+VzgZXMz7RSXgEWQgSdMC3wloiIvkPTEmfANunsTeXbNIzxfS/81gB2z4Rrf8HVt4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=k9O+h24z; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="k9O+h24z" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=n6JhG9WC1H1Km0XBTEHnjfvhnOvwP1+MnmMCfeon+Fg=; b=k9 O+h24zkgbGLbLvA+RWcu7Y6QeePa4hxl8k9CgEPj8v5ji0FJ/mY0EvU9sP6HRvC2ZJleu64XNzmRl mv3kWKN71zgR1uOZVdSca27U+tKkZrniaWh19MU8KlAeDgdrqMCyajMtDWjDZw64sxEoEe1zV+TWZ YZ/3QkcVxHgFelU=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGoo-00GwVc-G6; Tue, 21 Apr 2026 21:31:34 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:10 -0500 Subject: [PATCH net 07/18] drivers: net: amd: lance: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-7-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=46250; i=andrew@lunn.ch; h=from:subject:message-id; bh=KpWwQHe1lvgOqeKD6rprzKdlt+f2oAcqKhCFR+x/7Hs=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CBlOh2fLOM2bh0HwcVapi3wZbIn78EAc0xh /0yZxxXs2WJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hDtbEACe7qe9ZHXCpiaMGW8bwi/JLsS5fXO2XmBxrDMB8NW0h/1IBZ0gEcsg1FR4mqX1GKTDcrW GG3zkilt2dJtJ71amQ374rGZTxObbvx+DziXqPccDBgc5TKwRAYIu5PoCrPOVpzGrNU2AdeaWxf o73lFzbmAbNoZSIfeHwWZmvCycCDAkeGIOkfXHJ48651MA9HVp1I2BN+eD89s2nIBHx1ZDSQ6EP o+a6kjSoGmzWFxNKgRy8g2Oee14zgJfnb4FCl9FVRWZKkm38t4BIgaDlkJ1G0gwR/V769/pRMfJ +hfxwPYXR/mHSIRFUf74/vIq2rG2bzub9oWCK18qGDSYpYY4Vo3mTWHGIzaVg2+i5gABPFjXYf4 +fiFHx0KcoBvSR2eFDAo5JC+22Ovp05/ep7yZfffLyqRF8F/KMl0kL0h4pp2qagNLJ/KiMSW5ka GM+7XwWOjwU8fVug90aC12RGKtsJDk73Ogq41QhMAw6uhW39GKN92hJmgWvm91c+YZ3ReaRLdvm WuiwV7EyOq9X9VtzOd5RA3F49Z9GQiZYNYG1IAtHGHYfINpGp+9jeHCIS25xtvsElWR8pPIWXKe R78sQxD+Jv0JIGs2r+K64Wdsxbo8I5n23tqXKI6qSzrW0V8o1YdrlVYU+DH5WTH/c+8rBAjZrHr 5S/QvVAXQ1wH4BQ== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The lance was written by Donald Becker between 1993-1998. It is an ISA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/amd/Kconfig | 11 - drivers/net/ethernet/amd/Makefile | 1 - drivers/net/ethernet/amd/lance.c | 1317 ---------------------------------= ---- 3 files changed, 1329 deletions(-) diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kc= onfig index 9e83f3aa435a..f08b2ce8b952 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -43,17 +43,6 @@ config AMD8111_ETH To compile this driver as a module, choose M here. The module will be called amd8111e. =20 -config LANCE - tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" - depends on ISA && ISA_DMA_API && !ARM && !PPC32 - select NETDEV_LEGACY_INIT - help - If you have a network (Ethernet) card of this type, say Y here. - Some LinkSys cards are of this type. - - To compile this driver as a module, choose M here: the module - will be called lance. This is recommended. - config PCNET32 tristate "AMD PCnet32 PCI support" depends on PCI && HAS_IOPORT diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/M= akefile index 387ec74e8e95..d0aebfeedec3 100644 --- a/drivers/net/ethernet/amd/Makefile +++ b/drivers/net/ethernet/amd/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_AMD8111_ETH) +=3D amd8111e.o obj-$(CONFIG_ARIADNE) +=3D ariadne.o obj-$(CONFIG_ATARILANCE) +=3D atarilance.o obj-$(CONFIG_DECLANCE) +=3D declance.o -obj-$(CONFIG_LANCE) +=3D lance.o obj-$(CONFIG_MIPS_AU1X00_ENET) +=3D au1000_eth.o obj-$(CONFIG_PCMCIA_NMCLAN) +=3D nmclan_cs.o obj-$(CONFIG_PCNET32) +=3D pcnet32.o diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/la= nce.c deleted file mode 100644 index 98afd8cb0efb..000000000000 --- a/drivers/net/ethernet/amd/lance.c +++ /dev/null @@ -1,1317 +0,0 @@ -/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */ -/* - Written/copyright 1993-1998 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - This driver is for the Allied Telesis AT1500 and HP J2405A, and should wo= rk - with most other LANCE-based bus-master (NE2100/NE2500) ethercards. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Andrey V. Savochkin: - - alignment problem with 1.3.* kernel and some minor changes. - Thomas Bogendoerfer (tsbogend@bigbug.franken.de): - - added support for Linux/Alpha, but removed most of it, because - it worked only for the PCI chip. - - added hook for the 32bit lance driver - - added PCnetPCI II (79C970A) to chip table - Paul Gortmaker (gpg109@rsphy1.anu.edu.au): - - hopefully fix above so Linux/Alpha can use ISA cards too. - 8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb - v1.12 10/27/97 Module support -djb - v1.14 2/3/98 Module support modified, made PCI support optional -djb - v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed - before unregister_netdev() which caused NULL pointer - reference later in the chain (in rtnetlink_fill_ifinfo()) - -- Mika Kuoppala - - Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from - the 2.1 version of the old driver - Alan Cox - - Get rid of check_region, check kmalloc return in lance_probe1 - Arnaldo Carvalho de Melo - 11/01/2001 - - Reworked detection, added support for Racal InterLan EtherBlaster cards - Vesselin Kostadinov - 22/4/2004 -*/ - -static const char version[] =3D "lance.c:v1.16 2006/11/09 dplatt@3do.com, = becker@cesdis.gsfc.nasa.gov\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static unsigned int lance_portlist[] __initdata =3D { 0x300, 0x320, 0x340,= 0x360, 0}; -static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int o= ptions); -static int __init do_lance_probe(struct net_device *dev); - - -static struct card { - char id_offset14; - char id_offset15; -} cards[] =3D { - { //"normal" - .id_offset14 =3D 0x57, - .id_offset15 =3D 0x57, - }, - { //NI6510EB - .id_offset14 =3D 0x52, - .id_offset15 =3D 0x44, - }, - { //Racal InterLan EtherBlaster - .id_offset14 =3D 0x52, - .id_offset15 =3D 0x49, - }, -}; -#define NUM_CARDS 3 - -#ifdef LANCE_DEBUG -static int lance_debug =3D LANCE_DEBUG; -#else -static int lance_debug =3D 1; -#endif - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the AMD 79C960, the "PCnet-ISA -single-chip ethernet controller for ISA". This chip is used in a wide -variety of boards from vendors such as Allied Telesis, HP, Kingston, -and Boca. This driver is also intended to work with older AMD 7990 -designs, such as the NE1500 and NE2100, and newer 79C961. For convenience, -I use the name LANCE to refer to all of the AMD chips, even though it prop= erly -refers only to the original 7990. - -II. Board-specific settings - -The driver is designed to work the boards that use the faster -bus-master mode, rather than in shared memory mode. (Only older designs -have on-board buffer memory needed to support the slower shared memory mod= e.) - -Most ISA boards have jumpered settings for the I/O base, IRQ line, and DMA -channel. This driver probes the likely base addresses: -{0x300, 0x320, 0x340, 0x360}. -After the board is found it generates a DMA-timeout interrupt and uses -autoIRQ to find the IRQ line. The DMA channel can be set with the low bits -of the otherwise-unused dev->mem_start value (aka PARAM1). If unset it is -probed for by enabling each free DMA channel in turn and checking if -initialization succeeds. - -The HP-J2405A board is an exception: with this board it is easy to read the -EEPROM-set values for the base, IRQ, and DMA. (Of course you must already -_know_ the base address -- that field is for writing the EEPROM.) - -III. Driver operation - -IIIa. Ring buffers -The LANCE uses ring buffers of Tx and Rx descriptors. Each entry describes -the base and length of the data buffer, along with status bits. The length -of these buffers is set by LANCE_LOG_{RX,TX}_BUFFERS, which is log_2() of -the buffer length (rather than being directly the buffer length) for -implementation ease. The current values are 2 (Tx) and 4 (Rx), which lead= s to -ring sizes of 4 (Tx) and 16 (Rx). Increasing the number of ring entries -needlessly uses extra space and reduces the chance that an upper layer will -be able to reorder queued Tx packets based on priority. Decreasing the nu= mber -of entries makes it more difficult to achieve back-to-back packet transmis= sion -and increases the chance that Rx ring will overflow. (Consider the worst = case -of receiving back-to-back minimum-sized packets.) - -The LANCE has the capability to "chain" both Rx and Tx buffers, but this d= river -statically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers= to -avoid the administrative overhead. For the Rx side this avoids dynamically -allocating full-sized buffers "just in case", at the expense of a -memory-to-memory data copy for each packet received. For most systems this -is a good tradeoff: the Rx buffer will always be in low memory, the copy -is inexpensive, and it primes the cache for later packet processing. For = Tx -the buffers are only used when needed as low-memory bounce buffers. - -IIIB. 16M memory limitations. -For the ISA bus master mode all structures used directly by the LANCE, -the initialization block, Rx and Tx rings, and data buffers, must be -accessible from the ISA bus, i.e. in the lower 16M of real memory. -This is a problem for current Linux kernels on >16M machines. The network -devices are initialized after memory initialization, and the kernel doles = out -memory from the top of memory downward. The current solution is to have a -special network initialization routine that's called before memory -initialization; this will eventually be generalized for all network device= s. -As mentioned before, low-memory "bounce-buffers" are used when needed. - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is sing= le -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbus= y' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the ne= xt -queue slot is empty, it clears the tbusy flag when finished otherwise it s= ets -the 'lp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records s= tats -from the Tx ring. (The Tx-done interrupt can't be selectively turned off, = so -we can't avoid the interrupt overhead by having the Tx routine reap the Tx -stats.) After reaping the stats, it marks the queue entry as empty by set= ting -the 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the -tx_full and tbusy flags. - -*/ - -/* Set the number of Tx and Rx buffers, using Log_2(# buffers). - Reasonable default values are 16 Tx buffers, and 16 Rx buffers. - That translates to 4 and 4 (16 =3D=3D 2^^4). - This is a compile-time option for efficiency. - */ -#ifndef LANCE_LOG_TX_BUFFERS -#define LANCE_LOG_TX_BUFFERS 4 -#define LANCE_LOG_RX_BUFFERS 4 -#endif - -#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) - -#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) - -#define PKT_BUF_SZ 1544 - -/* Offsets from base I/O address. */ -#define LANCE_DATA 0x10 -#define LANCE_ADDR 0x12 -#define LANCE_RESET 0x14 -#define LANCE_BUS_IF 0x16 -#define LANCE_TOTAL_SIZE 0x18 - -#define TX_TIMEOUT (HZ/5) - -/* The LANCE Rx and Tx ring descriptors. */ -struct lance_rx_head { - s32 base; - s16 buf_length; /* This length is 2s complement (negative)! */ - s16 msg_length; /* This length is "normal". */ -}; - -struct lance_tx_head { - s32 base; - s16 length; /* Length is 2s complement (negative)! */ - s16 misc; -}; - -/* The LANCE initialization block, described in databook. */ -struct lance_init_block { - u16 mode; /* Pre-set mode (reg. 15) */ - u8 phys_addr[6]; /* Physical ethernet address */ - u32 filter[2]; /* Multicast filter (unused). */ - /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; /* Tx and Rx ring base pointers */ - u32 tx_ring; -}; - -struct lance_private { - /* The Tx and Rx ring entries must be aligned on 8-byte boundaries. */ - struct lance_rx_head rx_ring[RX_RING_SIZE]; - struct lance_tx_head tx_ring[TX_RING_SIZE]; - struct lance_init_block init_block; - const char *name; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - unsigned long rx_buffs; /* Address of Rx and Tx buffers. */ - /* Tx low-memory "bounce buffer" address. */ - char (*tx_bounce_buffs)[PKT_BUF_SZ]; - int cur_rx, cur_tx; /* The next free ring entry */ - int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - int dma; - unsigned char chip_version; /* See lance_chip_type. */ - spinlock_t devlock; -}; - -#define LANCE_MUST_PAD 0x00000001 -#define LANCE_ENABLE_AUTOSELECT 0x00000002 -#define LANCE_MUST_REINIT_RING 0x00000004 -#define LANCE_MUST_UNRESET 0x00000008 -#define LANCE_HAS_MISSED_FRAME 0x00000010 - -/* A mapping from the chip ID number to the part number and features. - These are from the datasheets -- in real life the '970 version - reportedly has the same ID as the '965. */ -static struct lance_chip_type { - int id_number; - const char *name; - int flags; -} chip_table[] =3D { - {0x0000, "LANCE 7990", /* Ancient lance chip. */ - LANCE_MUST_PAD + LANCE_MUST_UNRESET}, - {0x0003, "PCnet/ISA 79C960", /* 79C960 PCnet/ISA. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x2260, "PCnet/ISA+ 79C961", /* 79C961 PCnet/ISA+, Plug-n-Play. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x2420, "PCnet/PCI 79C970", /* 79C970 or 79C974 PCnet-SCSI, PCI. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - /* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call - it the PCnet32. */ - {0x2430, "PCnet32", /* 79C965 PCnet for VL bus. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */ - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, - {0x0, "PCnet (unknown)", - LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + - LANCE_HAS_MISSED_FRAME}, -}; - -enum {OLD_LANCE =3D 0, PCNET_ISA=3D1, PCNET_ISAP=3D2, PCNET_PCI=3D3, PCNET= _VLB=3D4, PCNET_PCI_II=3D5, LANCE_UNKNOWN=3D6}; - - -/* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers. - Assume yes until we know the memory size. */ -static unsigned char lance_need_isa_bounce_buffers =3D 1; - -static int lance_open(struct net_device *dev); -static void lance_init_ring(struct net_device *dev, gfp_t mode); -static netdev_tx_t lance_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int lance_rx(struct net_device *dev); -static irqreturn_t lance_interrupt(int irq, void *dev_id); -static int lance_close(struct net_device *dev); -static struct net_device_stats *lance_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void lance_tx_timeout (struct net_device *dev, unsigned int txqueue= ); - - - -#ifdef MODULE -#define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ - -static struct net_device *dev_lance[MAX_CARDS]; -static int io[MAX_CARDS]; -static int dma[MAX_CARDS]; -static int irq[MAX_CARDS]; - -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(dma, int, dma, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param(lance_debug, int, 0); -MODULE_PARM_DESC(io, "LANCE/PCnet I/O base address(es),required"); -MODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devic= es)"); -MODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)"); -MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)"); - -static int __init lance_init_module(void) -{ - struct net_device *dev; - int this_dev, found =3D 0; - - for (this_dev =3D 0; this_dev < MAX_CARDS; this_dev++) { - if (io[this_dev] =3D=3D 0) { - if (this_dev !=3D 0) /* only complain once */ - break; - printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"i= o=3D0xNNN\" value(s).\n"); - return -EPERM; - } - dev =3D alloc_etherdev(0); - if (!dev) - break; - dev->irq =3D irq[this_dev]; - dev->base_addr =3D io[this_dev]; - dev->dma =3D dma[this_dev]; - if (do_lance_probe(dev) =3D=3D 0) { - dev_lance[found++] =3D dev; - continue; - } - free_netdev(dev); - break; - } - if (found !=3D 0) - return 0; - return -ENXIO; -} -module_init(lance_init_module); - -static void cleanup_card(struct net_device *dev) -{ - struct lance_private *lp =3D dev->ml_priv; - if (dev->dma !=3D 4) - free_dma(dev->dma); - release_region(dev->base_addr, LANCE_TOTAL_SIZE); - kfree(lp->tx_bounce_buffs); - kfree((void*)lp->rx_buffs); - kfree(lp); -} - -static void __exit lance_cleanup_module(void) -{ - int this_dev; - - for (this_dev =3D 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev =3D dev_lance[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -module_exit(lance_cleanup_module); -#endif /* MODULE */ -MODULE_DESCRIPTION("AMD LANCE/PCnet Ethernet driver"); -MODULE_LICENSE("GPL"); - - -/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other - board probes now that kmalloc() can allocate ISA DMA-able regions. - This also allows the LANCE driver to be used as a module. - */ -static int __init do_lance_probe(struct net_device *dev) -{ - unsigned int *port; - int result; - - if (high_memory <=3D phys_to_virt(16*1024*1024)) - lance_need_isa_bounce_buffers =3D 0; - - for (port =3D lance_portlist; *port; port++) { - int ioaddr =3D *port; - struct resource *r =3D request_region(ioaddr, LANCE_TOTAL_SIZE, - "lance-probe"); - - if (r) { - /* Detect the card with minimal I/O reads */ - char offset14 =3D inb(ioaddr + 14); - int card; - for (card =3D 0; card < NUM_CARDS; ++card) - if (cards[card].id_offset14 =3D=3D offset14) - break; - if (card < NUM_CARDS) {/*yes, the first byte matches*/ - char offset15 =3D inb(ioaddr + 15); - for (card =3D 0; card < NUM_CARDS; ++card) - if ((cards[card].id_offset14 =3D=3D offset14) && - (cards[card].id_offset15 =3D=3D offset15)) - break; - } - if (card < NUM_CARDS) { /*Signature OK*/ - result =3D lance_probe1(dev, ioaddr, 0, 0); - if (!result) { - struct lance_private *lp =3D dev->ml_priv; - int ver =3D lp->chip_version; - - r->name =3D chip_table[ver].name; - return 0; - } - } - release_region(ioaddr, LANCE_TOTAL_SIZE); - } - } - return -ENODEV; -} - -#ifndef MODULE -struct net_device * __init lance_probe(int unit) -{ - struct net_device *dev =3D alloc_etherdev(0); - int err; - - if (!dev) - return ERR_PTR(-ENODEV); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err =3D do_lance_probe(dev); - if (err) - goto out; - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif - -static const struct net_device_ops lance_netdev_ops =3D { - .ndo_open =3D lance_open, - .ndo_start_xmit =3D lance_start_xmit, - .ndo_stop =3D lance_close, - .ndo_get_stats =3D lance_get_stats, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_tx_timeout =3D lance_tx_timeout, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - -static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq= , int options) -{ - struct lance_private *lp; - unsigned long dma_channels; /* Mark spuriously-busy DMA channels */ - int i, reset_val, lance_version; - const char *chipname; - /* Flags for specific chips or boards. */ - unsigned char hpJ2405A =3D 0; /* HP ISA adaptor */ - int hp_builtin =3D 0; /* HP on-board ethernet. */ - static int did_version; /* Already printed version info. */ - unsigned long flags; - int err =3D -ENOMEM; - void __iomem *bios; - u8 addr[ETH_ALEN]; - - /* First we look for special cases. - Check for HP's on-board ethernet by looking for 'HP' in the BIOS. - There are two HP versions, check the BIOS for the configuration port. - This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com. - */ - bios =3D ioremap(0xf00f0, 0x14); - if (!bios) - return -ENOMEM; - if (readw(bios + 0x12) =3D=3D 0x5048) { - static const short ioaddr_table[] =3D { 0x300, 0x320, 0x340, 0x360}; - int hp_port =3D (readl(bios + 1) & 1) ? 0x499 : 0x99; - /* We can have boards other than the built-in! Verify this is on-board.= */ - if ((inb(hp_port) & 0xc0) =3D=3D 0x80 && - ioaddr_table[inb(hp_port) & 3] =3D=3D ioaddr) - hp_builtin =3D hp_port; - } - iounmap(bios); - /* We also recognize the HP Vectra on-board here, but check below. */ - hpJ2405A =3D (inb(ioaddr) =3D=3D 0x08 && inb(ioaddr+1) =3D=3D 0x00 && - inb(ioaddr+2) =3D=3D 0x09); - - /* Reset the LANCE. */ - reset_val =3D inw(ioaddr+LANCE_RESET); /* Reset the LANCE */ - - /* The Un-Reset needed is only needed for the real NE2100, and will - confuse the HP board. */ - if (!hpJ2405A) - outw(reset_val, ioaddr+LANCE_RESET); - - outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */ - if (inw(ioaddr+LANCE_DATA) !=3D 0x0004) - return -ENODEV; - - /* Get the version of the chip. */ - outw(88, ioaddr+LANCE_ADDR); - if (inw(ioaddr+LANCE_ADDR) !=3D 88) { - lance_version =3D 0; - } else { /* Good, it's a newer chip. */ - int chip_version =3D inw(ioaddr+LANCE_DATA); - outw(89, ioaddr+LANCE_ADDR); - chip_version |=3D inw(ioaddr+LANCE_DATA) << 16; - if (lance_debug > 2) - printk(" LANCE chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) !=3D 0x003) - return -ENODEV; - chip_version =3D (chip_version >> 12) & 0xffff; - for (lance_version =3D 1; chip_table[lance_version].id_number; lance_ver= sion++) { - if (chip_table[lance_version].id_number =3D=3D chip_version) - break; - } - } - - /* We can't allocate private data from alloc_etherdev() because it must - a ISA DMA-able region. */ - chipname =3D chip_table[lance_version].name; - printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr); - - /* There is a 16 byte station address PROM at the base address. - The first six bytes are the station address. */ - for (i =3D 0; i < 6; i++) - addr[i] =3D inb(ioaddr + i); - eth_hw_addr_set(dev, addr); - printk("%pM", dev->dev_addr); - - dev->base_addr =3D ioaddr; - /* Make certain the data structures used by the LANCE are aligned and DMA= ble. */ - - lp =3D kzalloc_obj(*lp, GFP_DMA | GFP_KERNEL); - if (!lp) - return -ENOMEM; - if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); - dev->ml_priv =3D lp; - lp->name =3D chipname; - lp->rx_buffs =3D (unsigned long)kmalloc_array(RX_RING_SIZE, PKT_BUF_SZ, - GFP_DMA | GFP_KERNEL); - if (!lp->rx_buffs) - goto out_lp; - if (lance_need_isa_bounce_buffers) { - lp->tx_bounce_buffs =3D kmalloc_array(TX_RING_SIZE, PKT_BUF_SZ, - GFP_DMA | GFP_KERNEL); - if (!lp->tx_bounce_buffs) - goto out_rx; - } else - lp->tx_bounce_buffs =3D NULL; - - lp->chip_version =3D lance_version; - spin_lock_init(&lp->devlock); - - lp->init_block.mode =3D 0x0003; /* Disable Rx and Tx. */ - for (i =3D 0; i < 6; i++) - lp->init_block.phys_addr[i] =3D dev->dev_addr[i]; - lp->init_block.filter[0] =3D 0x00000000; - lp->init_block.filter[1] =3D 0x00000000; - lp->init_block.rx_ring =3D ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff)= | RX_RING_LEN_BITS; - lp->init_block.tx_ring =3D ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff)= | TX_RING_LEN_BITS; - - outw(0x0001, ioaddr+LANCE_ADDR); - inw(ioaddr+LANCE_ADDR); - outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA); - outw(0x0002, ioaddr+LANCE_ADDR); - inw(ioaddr+LANCE_ADDR); - outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA); - outw(0x0000, ioaddr+LANCE_ADDR); - inw(ioaddr+LANCE_ADDR); - - if (irq) { /* Set iff PCI card. */ - dev->dma =3D 4; /* Native bus-master, no DMA channel needed. */ - dev->irq =3D irq; - } else if (hp_builtin) { - static const char dma_tbl[4] =3D {3, 5, 6, 0}; - static const char irq_tbl[4] =3D {3, 4, 5, 9}; - unsigned char port_val =3D inb(hp_builtin); - dev->dma =3D dma_tbl[(port_val >> 4) & 3]; - dev->irq =3D irq_tbl[(port_val >> 2) & 3]; - printk(" HP Vectra IRQ %d DMA %d.\n", dev->irq, dev->dma); - } else if (hpJ2405A) { - static const char dma_tbl[4] =3D {3, 5, 6, 7}; - static const char irq_tbl[8] =3D {3, 4, 5, 9, 10, 11, 12, 15}; - short reset_val =3D inw(ioaddr+LANCE_RESET); - dev->dma =3D dma_tbl[(reset_val >> 2) & 3]; - dev->irq =3D irq_tbl[(reset_val >> 4) & 7]; - printk(" HP J2405A IRQ %d DMA %d.\n", dev->irq, dev->dma); - } else if (lance_version =3D=3D PCNET_ISAP) { /* The plug-n-play version= . */ - short bus_info; - outw(8, ioaddr+LANCE_ADDR); - bus_info =3D inw(ioaddr+LANCE_BUS_IF); - dev->dma =3D bus_info & 0x07; - dev->irq =3D (bus_info >> 4) & 0x0F; - } else { - /* The DMA channel may be passed in PARAM1. */ - if (dev->mem_start & 0x07) - dev->dma =3D dev->mem_start & 0x07; - } - - if (dev->dma =3D=3D 0) { - /* Read the DMA channel status register, so that we can avoid - stuck DMA channels in the DMA detection below. */ - dma_channels =3D ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | - (inb(DMA2_STAT_REG) & 0xf0); - } - err =3D -ENODEV; - if (dev->irq >=3D 2) - printk(" assigned IRQ %d", dev->irq); - else if (lance_version !=3D 0) { /* 7990 boards need DMA detection first= . */ - unsigned long irq_mask; - - /* To auto-IRQ we enable the initialization-done and DMA error - interrupts. For ISA boards we get a DMA error, but VLB and PCI - boards will work. */ - irq_mask =3D probe_irq_on(); - - /* Trigger an initialization just for the interrupt. */ - outw(0x0041, ioaddr+LANCE_DATA); - - mdelay(20); - dev->irq =3D probe_irq_off(irq_mask); - if (dev->irq) - printk(", probed IRQ %d", dev->irq); - else { - printk(", failed to detect IRQ line.\n"); - goto out_tx; - } - - /* Check for the initialization done bit, 0x0100, which means - that we don't need a DMA channel. */ - if (inw(ioaddr+LANCE_DATA) & 0x0100) - dev->dma =3D 4; - } - - if (dev->dma =3D=3D 4) { - printk(", no DMA needed.\n"); - } else if (dev->dma) { - if (request_dma(dev->dma, chipname)) { - printk("DMA %d allocation failed.\n", dev->dma); - goto out_tx; - } else - printk(", assigned DMA %d.\n", dev->dma); - } else { /* OK, we have to auto-DMA. */ - for (i =3D 0; i < 4; i++) { - static const char dmas[] =3D { 5, 6, 7, 3 }; - int dma =3D dmas[i]; - int boguscnt; - - /* Don't enable a permanently busy DMA channel, or the machine - will hang. */ - if (test_bit(dma, &dma_channels)) - continue; - outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */ - if (request_dma(dma, chipname)) - continue; - - flags=3Dclaim_dma_lock(); - set_dma_mode(dma, DMA_MODE_CASCADE); - enable_dma(dma); - release_dma_lock(flags); - - /* Trigger an initialization. */ - outw(0x0001, ioaddr+LANCE_DATA); - for (boguscnt =3D 100; boguscnt > 0; --boguscnt) - if (inw(ioaddr+LANCE_DATA) & 0x0900) - break; - if (inw(ioaddr+LANCE_DATA) & 0x0100) { - dev->dma =3D dma; - printk(", DMA %d.\n", dev->dma); - break; - } else { - flags=3Dclaim_dma_lock(); - disable_dma(dma); - release_dma_lock(flags); - free_dma(dma); - } - } - if (i =3D=3D 4) { /* Failure: bail. */ - printk("DMA detection failed.\n"); - goto out_tx; - } - } - - if (lance_version =3D=3D 0 && dev->irq =3D=3D 0) { - /* We may auto-IRQ now that we have a DMA channel. */ - /* Trigger an initialization just for the interrupt. */ - unsigned long irq_mask; - - irq_mask =3D probe_irq_on(); - outw(0x0041, ioaddr+LANCE_DATA); - - mdelay(40); - dev->irq =3D probe_irq_off(irq_mask); - if (dev->irq =3D=3D 0) { - printk(" Failed to detect the 7990 IRQ line.\n"); - goto out_dma; - } - printk(" Auto-IRQ detected IRQ%d.\n", dev->irq); - } - - if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) { - /* Turn on auto-select of media (10baseT or BNC) so that the user - can watch the LEDs even if the board isn't opened. */ - outw(0x0002, ioaddr+LANCE_ADDR); - /* Don't touch 10base2 power bit. */ - outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF); - } - - if (lance_debug > 0 && did_version++ =3D=3D 0) - printk(version); - - /* The LANCE-specific entries in the device structure. */ - dev->netdev_ops =3D &lance_netdev_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - - err =3D register_netdev(dev); - if (err) - goto out_dma; - return 0; -out_dma: - if (dev->dma !=3D 4) - free_dma(dev->dma); -out_tx: - kfree(lp->tx_bounce_buffs); -out_rx: - kfree((void*)lp->rx_buffs); -out_lp: - kfree(lp); - return err; -} - - -static int -lance_open(struct net_device *dev) -{ - struct lance_private *lp =3D dev->ml_priv; - int ioaddr =3D dev->base_addr; - int i; - - if (dev->irq =3D=3D 0 || - request_irq(dev->irq, lance_interrupt, 0, dev->name, dev)) { - return -EAGAIN; - } - - /* We used to allocate DMA here, but that was silly. - DMA lines can't be shared! We now permanently allocate them. */ - - /* Reset the LANCE */ - inw(ioaddr+LANCE_RESET); - - /* The DMA controller is used as a no-operation slave, "cascade mode". */ - if (dev->dma !=3D 4) { - unsigned long flags=3Dclaim_dma_lock(); - enable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - release_dma_lock(flags); - } - - /* Un-Reset the LANCE, needed only for the NE2100. */ - if (chip_table[lp->chip_version].flags & LANCE_MUST_UNRESET) - outw(0, ioaddr+LANCE_RESET); - - if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) { - /* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */ - outw(0x0002, ioaddr+LANCE_ADDR); - /* Only touch autoselect bit. */ - outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF); - } - - if (lance_debug > 1) - printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n", - dev->name, dev->irq, dev->dma, - (u32) isa_virt_to_bus(lp->tx_ring), - (u32) isa_virt_to_bus(lp->rx_ring), - (u32) isa_virt_to_bus(&lp->init_block)); - - lance_init_ring(dev, GFP_KERNEL); - /* Re-initialize the LANCE, and start it when done. */ - outw(0x0001, ioaddr+LANCE_ADDR); - outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA); - outw(0x0002, ioaddr+LANCE_ADDR); - outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA); - - outw(0x0004, ioaddr+LANCE_ADDR); - outw(0x0915, ioaddr+LANCE_DATA); - - outw(0x0000, ioaddr+LANCE_ADDR); - outw(0x0001, ioaddr+LANCE_DATA); - - netif_start_queue (dev); - - i =3D 0; - while (i++ < 100) - if (inw(ioaddr+LANCE_DATA) & 0x0100) - break; - /* - * We used to clear the InitDone bit, 0x0100, here but Mark Stockton - * reports that doing so triggers a bug in the '974. - */ - outw(0x0042, ioaddr+LANCE_DATA); - - if (lance_debug > 2) - printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n", - dev->name, i, (u32) isa_virt_to_bus(&lp->init_block), inw(ioaddr+LAN= CE_DATA)); - - return 0; /* Always succeed */ -} - -/* The LANCE has been halted for one reason or another (busmaster memory - arbitration error, Tx FIFO underflow, driver stopped it to reconfigure, - etc.). Modern LANCE variants always reload their ring-buffer - configuration when restarted, so we must reinitialize our ring - context before restarting. As part of this reinitialization, - find all packets still on the Tx ring and pretend that they had been - sent (in effect, drop the packets on the floor) - the higher-level - protocols will time out and retransmit. It'd be better to shuffle - these skbs to a temp list and then actually re-Tx them after - restarting the chip, but I'm too lazy to do so right now. dplatt@3do.c= om -*/ - -static void -lance_purge_ring(struct net_device *dev) -{ - struct lance_private *lp =3D dev->ml_priv; - int i; - - /* Free all the skbuffs in the Rx and Tx queues. */ - for (i =3D 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb =3D lp->rx_skbuff[i]; - lp->rx_skbuff[i] =3D NULL; - lp->rx_ring[i].base =3D 0; /* Not owned by LANCE chip. */ - if (skb) - dev_kfree_skb_any(skb); - } - for (i =3D 0; i < TX_RING_SIZE; i++) { - if (lp->tx_skbuff[i]) { - dev_kfree_skb_any(lp->tx_skbuff[i]); - lp->tx_skbuff[i] =3D NULL; - } - } -} - - -/* Initialize the LANCE Rx and Tx rings. */ -static void -lance_init_ring(struct net_device *dev, gfp_t gfp) -{ - struct lance_private *lp =3D dev->ml_priv; - int i; - - lp->cur_rx =3D lp->cur_tx =3D 0; - lp->dirty_rx =3D lp->dirty_tx =3D 0; - - for (i =3D 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - void *rx_buff; - - skb =3D alloc_skb(PKT_BUF_SZ, GFP_DMA | gfp); - lp->rx_skbuff[i] =3D skb; - if (skb) - rx_buff =3D skb->data; - else - rx_buff =3D kmalloc(PKT_BUF_SZ, GFP_DMA | gfp); - if (!rx_buff) - lp->rx_ring[i].base =3D 0; - else - lp->rx_ring[i].base =3D (u32)isa_virt_to_bus(rx_buff) | 0x80000000; - lp->rx_ring[i].buf_length =3D -PKT_BUF_SZ; - } - /* The Tx buffer address is filled in as needed, but we do need to clear - the upper ownership bit. */ - for (i =3D 0; i < TX_RING_SIZE; i++) { - lp->tx_skbuff[i] =3D NULL; - lp->tx_ring[i].base =3D 0; - } - - lp->init_block.mode =3D 0x0000; - for (i =3D 0; i < 6; i++) - lp->init_block.phys_addr[i] =3D dev->dev_addr[i]; - lp->init_block.filter[0] =3D 0x00000000; - lp->init_block.filter[1] =3D 0x00000000; - lp->init_block.rx_ring =3D ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff)= | RX_RING_LEN_BITS; - lp->init_block.tx_ring =3D ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff)= | TX_RING_LEN_BITS; -} - -static void -lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_rei= nit) -{ - struct lance_private *lp =3D dev->ml_priv; - - if (must_reinit || - (chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) { - lance_purge_ring(dev); - lance_init_ring(dev, GFP_ATOMIC); - } - outw(0x0000, dev->base_addr + LANCE_ADDR); - outw(csr0_bits, dev->base_addr + LANCE_DATA); -} - - -static void lance_tx_timeout (struct net_device *dev, unsigned int txqueue) -{ - struct lance_private *lp =3D (struct lance_private *) dev->ml_priv; - int ioaddr =3D dev->base_addr; - - outw (0, ioaddr + LANCE_ADDR); - printk ("%s: transmit timed out, status %4.4x, resetting.\n", - dev->name, inw (ioaddr + LANCE_DATA)); - outw (0x0004, ioaddr + LANCE_DATA); - dev->stats.tx_errors++; -#ifndef final_version - if (lance_debug > 3) { - int i; - printk (" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", - lp->dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? " (full)" : "", - lp->cur_rx); - for (i =3D 0; i < RX_RING_SIZE; i++) - printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, - lp->rx_ring[i].msg_length); - for (i =3D 0; i < TX_RING_SIZE; i++) - printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - lp->tx_ring[i].base, -lp->tx_ring[i].length, - lp->tx_ring[i].misc); - printk ("\n"); - } -#endif - lance_restart (dev, 0x0043, 1); - - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue (dev); -} - - -static netdev_tx_t lance_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct lance_private *lp =3D dev->ml_priv; - int ioaddr =3D dev->base_addr; - int entry; - unsigned long flags; - - spin_lock_irqsave(&lp->devlock, flags); - - if (lance_debug > 3) { - outw(0x0000, ioaddr+LANCE_ADDR); - printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, - inw(ioaddr+LANCE_DATA)); - outw(0x0000, ioaddr+LANCE_DATA); - } - - /* Fill in a Tx ring entry */ - - /* Mask to ring buffer boundary. */ - entry =3D lp->cur_tx & TX_RING_MOD_MASK; - - /* Caution: the write order is important here, set the base address - with the "ownership" bits last. */ - - /* The old LANCE chips doesn't automatically pad buffers to min. size. */ - if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) { - if (skb->len < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) - goto out; - lp->tx_ring[entry].length =3D -ETH_ZLEN; - } - else - lp->tx_ring[entry].length =3D -skb->len; - } else - lp->tx_ring[entry].length =3D -skb->len; - - lp->tx_ring[entry].misc =3D 0x0000; - - dev->stats.tx_bytes +=3D skb->len; - - /* If any part of this buffer is >16M we must copy it to a low-memory - buffer. */ - if ((u32)isa_virt_to_bus(skb->data) + skb->len > 0x01000000) { - if (lance_debug > 5) - printk("%s: bouncing a high-memory packet (%#x).\n", - dev->name, (u32)isa_virt_to_bus(skb->data)); - skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len); - lp->tx_ring[entry].base =3D - ((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83= 000000; - dev_consume_skb_irq(skb); - } else { - lp->tx_skbuff[entry] =3D skb; - lp->tx_ring[entry].base =3D ((u32)isa_virt_to_bus(skb->data) & 0xffffff)= | 0x83000000; - } - lp->cur_tx++; - - /* Trigger an immediate send poll. */ - outw(0x0000, ioaddr+LANCE_ADDR); - outw(0x0048, ioaddr+LANCE_DATA); - - if ((lp->cur_tx - lp->dirty_tx) >=3D TX_RING_SIZE) - netif_stop_queue(dev); - -out: - spin_unlock_irqrestore(&lp->devlock, flags); - return NETDEV_TX_OK; -} - -/* The LANCE interrupt handler. */ -static irqreturn_t lance_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D dev_id; - struct lance_private *lp; - int csr0, ioaddr, boguscnt=3D10; - int must_restart; - - ioaddr =3D dev->base_addr; - lp =3D dev->ml_priv; - - spin_lock (&lp->devlock); - - outw(0x00, dev->base_addr + LANCE_ADDR); - while ((csr0 =3D inw(dev->base_addr + LANCE_DATA)) & 0x8600 && - --boguscnt >=3D 0) { - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA); - - must_restart =3D 0; - - if (lance_debug > 5) - printk("%s: interrupt csr0=3D%#2.2x new csr=3D%#2.2x.\n", - dev->name, csr0, inw(dev->base_addr + LANCE_DATA)); - - if (csr0 & 0x0400) /* Rx interrupt */ - lance_rx(dev); - - if (csr0 & 0x0200) { /* Tx-done interrupt */ - int dirty_tx =3D lp->dirty_tx; - - while (dirty_tx < lp->cur_tx) { - int entry =3D dirty_tx & TX_RING_MOD_MASK; - int status =3D lp->tx_ring[entry].base; - - if (status < 0) - break; /* It still hasn't been Txed */ - - lp->tx_ring[entry].base =3D 0; - - if (status & 0x40000000) { - /* There was an major error, log it. */ - int err_status =3D lp->tx_ring[entry].misc; - dev->stats.tx_errors++; - if (err_status & 0x0400) - dev->stats.tx_aborted_errors++; - if (err_status & 0x0800) - dev->stats.tx_carrier_errors++; - if (err_status & 0x1000) - dev->stats.tx_window_errors++; - if (err_status & 0x4000) { - /* Ackk! On FIFO errors the Tx unit is turned off! */ - dev->stats.tx_fifo_errors++; - /* Remove this verbosity later! */ - printk("%s: Tx FIFO error! Status %4.4x.\n", - dev->name, csr0); - /* Restart the chip. */ - must_restart =3D 1; - } - } else { - if (status & 0x18000000) - dev->stats.collisions++; - dev->stats.tx_packets++; - } - - /* We must free the original skb if it's not a data-only copy - in the bounce buffer. */ - if (lp->tx_skbuff[entry]) { - dev_consume_skb_irq(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] =3D NULL; - } - dirty_tx++; - } - -#ifndef final_version - if (lp->cur_tx - dirty_tx >=3D TX_RING_SIZE) { - printk("out-of-sync dirty pointer, %d vs. %d, full=3D%s.\n", - dirty_tx, lp->cur_tx, - netif_queue_stopped(dev) ? "yes" : "no"); - dirty_tx +=3D TX_RING_SIZE; - } -#endif - - /* if the ring is no longer full, accept more packets */ - if (netif_queue_stopped(dev) && - dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) - netif_wake_queue (dev); - - lp->dirty_tx =3D dirty_tx; - } - - /* Log misc errors. */ - if (csr0 & 0x4000) - dev->stats.tx_errors++; /* Tx babble. */ - if (csr0 & 0x1000) - dev->stats.rx_errors++; /* Missed a Rx frame. */ - if (csr0 & 0x0800) { - printk("%s: Bus master arbitration failure, status %4.4x.\n", - dev->name, csr0); - /* Restart the chip. */ - must_restart =3D 1; - } - - if (must_restart) { - /* stop the chip to clear the error condition, then restart */ - outw(0x0000, dev->base_addr + LANCE_ADDR); - outw(0x0004, dev->base_addr + LANCE_DATA); - lance_restart(dev, 0x0002, 0); - } - } - - /* Clear any other interrupt, and set interrupt enable. */ - outw(0x0000, dev->base_addr + LANCE_ADDR); - outw(0x7940, dev->base_addr + LANCE_DATA); - - if (lance_debug > 4) - printk("%s: exiting interrupt, csr%d=3D%#4.4x.\n", - dev->name, inw(ioaddr + LANCE_ADDR), - inw(dev->base_addr + LANCE_DATA)); - - spin_unlock (&lp->devlock); - return IRQ_HANDLED; -} - -static int -lance_rx(struct net_device *dev) -{ - struct lance_private *lp =3D dev->ml_priv; - int entry =3D lp->cur_rx & RX_RING_MOD_MASK; - int i; - - /* If we own the next entry, it's a new packet. Send it up. */ - while (lp->rx_ring[entry].base >=3D 0) { - int status =3D lp->rx_ring[entry].base >> 24; - - if (status !=3D 0x03) { /* There was an error. */ - /* There is a tricky error noted by John Murphy, - to Russ Nelson: Even with full-sized - buffers it's possible for a jabber packet to use two - buffers, with only the last correctly noting the error. */ - if (status & 0x01) /* Only count a general error at the */ - dev->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x20) - dev->stats.rx_frame_errors++; - if (status & 0x10) - dev->stats.rx_over_errors++; - if (status & 0x08) - dev->stats.rx_crc_errors++; - if (status & 0x04) - dev->stats.rx_fifo_errors++; - lp->rx_ring[entry].base &=3D 0x03ffffff; - } - else - { - /* Malloc up new buffer, compatible with net3. */ - short pkt_len =3D (lp->rx_ring[entry].msg_length & 0xfff)-4; - struct sk_buff *skb; - - if(pkt_len<60) - { - printk("%s: Runt packet!\n",dev->name); - dev->stats.rx_errors++; - } - else - { - skb =3D dev_alloc_skb(pkt_len+2); - if (!skb) - { - printk("%s: Memory squeeze, deferring packet.\n", dev->name); - for (i=3D0; i < RX_RING_SIZE; i++) - if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0) - break; - - if (i > RX_RING_SIZE -2) - { - dev->stats.rx_dropped++; - lp->rx_ring[entry].base |=3D 0x80000000; - lp->cur_rx++; - } - break; - } - skb_reserve(skb,2); /* 16 byte align */ - skb_put(skb,pkt_len); /* Make room */ - skb_copy_to_linear_data(skb, - (unsigned char *)isa_bus_to_virt((lp->rx_ring[entry].base & 0x00fffff= f)), - pkt_len); - skb->protocol=3Deth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pkt_len; - } - } - /* The docs say that the buffer length isn't touched, but Andrew Boyd - of QNX reports that some revs of the 79C965 clear it. */ - lp->rx_ring[entry].buf_length =3D -PKT_BUF_SZ; - lp->rx_ring[entry].base |=3D 0x80000000; - entry =3D (++lp->cur_rx) & RX_RING_MOD_MASK; - } - - /* We should check that at least two ring entries are free. If not, - we should free one and mark stats->rx_dropped++. */ - - return 0; -} - -static int -lance_close(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - struct lance_private *lp =3D dev->ml_priv; - - netif_stop_queue (dev); - - if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { - outw(112, ioaddr+LANCE_ADDR); - dev->stats.rx_missed_errors =3D inw(ioaddr+LANCE_DATA); - } - outw(0, ioaddr+LANCE_ADDR); - - if (lance_debug > 1) - printk("%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inw(ioaddr+LANCE_DATA)); - - /* We stop the LANCE here -- it occasionally polls - memory if we don't. */ - outw(0x0004, ioaddr+LANCE_DATA); - - if (dev->dma !=3D 4) - { - unsigned long flags=3Dclaim_dma_lock(); - disable_dma(dev->dma); - release_dma_lock(flags); - } - free_irq(dev->irq, dev); - - lance_purge_ring(dev); - - return 0; -} - -static struct net_device_stats *lance_get_stats(struct net_device *dev) -{ - struct lance_private *lp =3D dev->ml_priv; - - if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { - short ioaddr =3D dev->base_addr; - short saved_addr; - unsigned long flags; - - spin_lock_irqsave(&lp->devlock, flags); - saved_addr =3D inw(ioaddr+LANCE_ADDR); - outw(112, ioaddr+LANCE_ADDR); - dev->stats.rx_missed_errors =3D inw(ioaddr+LANCE_DATA); - outw(saved_addr, ioaddr+LANCE_ADDR); - spin_unlock_irqrestore(&lp->devlock, flags); - } - - return &dev->stats; -} - -/* Set or clear the multicast filter for this adaptor. - */ - -static void set_multicast_list(struct net_device *dev) -{ - short ioaddr =3D dev->base_addr; - - outw(0, ioaddr+LANCE_ADDR); - outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */ - - if (dev->flags&IFF_PROMISC) { - outw(15, ioaddr+LANCE_ADDR); - outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */ - } else { - short multicast_table[4]; - int i; - int num_addrs=3Dnetdev_mc_count(dev); - if(dev->flags&IFF_ALLMULTI) - num_addrs=3D1; - /* FIXIT: We don't use the multicast table, but rely on upper-layer filt= ering. */ - memset(multicast_table, (num_addrs =3D=3D 0) ? 0 : -1, sizeof(multicast_= table)); - for (i =3D 0; i < 4; i++) { - outw(8 + i, ioaddr+LANCE_ADDR); - outw(multicast_table[i], ioaddr+LANCE_DATA); - } - outw(15, ioaddr+LANCE_ADDR); - outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */ - } - - lance_restart(dev, 0x0142, 0); /* Resume normal operation */ - -} - --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 836A13DCDB6; Tue, 21 Apr 2026 19:31:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799908; cv=none; b=M3SqjciG718IxwGOro5wL3YdI309bQgDkXYm7p20ArI7HGdp12iZ8LrNyCnrZjKcY9RIco1Vlxixeqk1t2jNuQFlc+rn5dnSdd1751ytRh5UdcsVFLKTk3flCsmnT/agGUtUVBQiGTcmpTHI+ND1X8EIez8DI9nvhGAPb1rreYc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799908; c=relaxed/simple; bh=k+3cqPieWti2YakE0tt3TG59qx8qQGcUs/WStRaqH5U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=daihGO21Fqk+FTnD2SqplKaUXhmRkLys8mTJsNMT5RHJijrsIhC5/PGG2BfXtgtVC3CGw0/3zTM3zydy9y5VfDfAwAGWKrmbVxGuRoQzJZiHCRBYJ9l3N1A6LaDF2BtmNhNCM1dbqpS5LQ6PloDgIXATjU113j1nHoFDv4jILz8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=r3EXW8Hv; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="r3EXW8Hv" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=kBl8oqlwczA5dIohC5IfYVU1Uo95O0E+JCBu8lRCJOk=; b=r3 EXW8HvO0xJQqVIa+TwfSGN7DfQcU6JbmPSQExNX69v5aOrqYp1FIMXFFRH4SkZgphSlb1/1sNoHZg Z0bmj3mMz1W+qRksQ1t/+sz4nLBNoxTPA7wqb29myX2g54SDlftTT9ictlaECZ9kYr+A4zMzr5mBL BqVTElYBuXoG9fg=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGor-00GwVc-0X; Tue, 21 Apr 2026 21:31:37 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:11 -0500 Subject: [PATCH net 08/18] drivers: net: amd: nmclan: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-8-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=50371; i=andrew@lunn.ch; h=from:subject:message-id; bh=k+3cqPieWti2YakE0tt3TG59qx8qQGcUs/WStRaqH5U=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CBw/Wk2za8UbIlYt5wFGo0Cjj4qJ4d/zbeT LlG3FVgDcSJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hA8WEADJz3LWLSbPQX3UTDlhBhX+cSv/6AepY8Hk9Cb7u87RVJlSAgF73TT2ihzocn6LY1Y8ohV uTuYOW9Z5cjMgfiPEc8aN2OiCqLHBK8nJpy/c4a2TCkhWLquVJSZ+n0tnKUBsdht/U9n5KoBhTQ 6RvOiuYi7IAAWEE5PYZXZpBbbwcaMBWSUtfhw81ddBbi6SwvG/9MbHJXujiRmyx2ecjdXkfdf2Z fmvRP91fu4+oN/n1jXLfrq5+lED993Jv0GVCafqhO+HToiycd0S8Qldva4kNjRQmey/qJyVufAr FMcrdwCh/dtBpE6X0BLgtddc2gknqAYpj3WYD+L2G8jATNiDslfu1ABgqpl6xbk1GFElA6UH3Or DTA8H50Gc1oOBKqnphmmbspNCcFN2rbhhZ+aobEVp1LXBPluw9+zXKBxxaGfLnSeaI0UrRQYhAB Ejg+kkvNyPXwyeYuJ4W9sidTXcZAXtrCA1D7CNUYJwHdPPsYQJcRZbE7kUV1MQaFVkwbhbp9nks 2TOM/KOhlks2vteseXi/ucMvodxwG8QjCQMKNVNQngoz00kaUi1fhKzzTcw5THnsf1mIiKxae/C fwsDnb690/4Tj9CUdbrbv6j9tG/XilrsXMM4FyPNP1bQn+dE2hleN8XRpjnb4TALe0Nv22BxeOl I3zYkrIwU1WGaOg== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The nmclan was written by Roger C Pao in 1995. It is an PCMCIA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/amd/Kconfig | 10 - drivers/net/ethernet/amd/Makefile | 1 - drivers/net/ethernet/amd/nmclan_cs.c | 1508 ------------------------------= ---- 3 files changed, 1519 deletions(-) diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kc= onfig index f08b2ce8b952..69cd0b3d098c 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -91,16 +91,6 @@ config MIPS_AU1X00_ENET If you have an Alchemy Semi AU1X00 based system say Y. Otherwise, say N. =20 -config PCMCIA_NMCLAN - tristate "New Media PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach a New Media Ethernet or LiveWire - PCMCIA (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called nmclan_cs. If unsure, say N. - config SUN3LANCE tristate "Sun3/Sun3x on-board LANCE support" depends on (SUN3 || SUN3X) diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/M= akefile index d0aebfeedec3..a352f1be2b45 100644 --- a/drivers/net/ethernet/amd/Makefile +++ b/drivers/net/ethernet/amd/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_ARIADNE) +=3D ariadne.o obj-$(CONFIG_ATARILANCE) +=3D atarilance.o obj-$(CONFIG_DECLANCE) +=3D declance.o obj-$(CONFIG_MIPS_AU1X00_ENET) +=3D au1000_eth.o -obj-$(CONFIG_PCMCIA_NMCLAN) +=3D nmclan_cs.o obj-$(CONFIG_PCNET32) +=3D pcnet32.o obj-$(CONFIG_SUN3LANCE) +=3D sun3lance.o obj-$(CONFIG_SUNLANCE) +=3D sunlance.o diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/am= d/nmclan_cs.c deleted file mode 100644 index 37054a670407..000000000000 --- a/drivers/net/ethernet/amd/nmclan_cs.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* -----------------------------------------------------------------------= ----- -Linux PCMCIA ethernet adapter driver for the New Media Ethernet LAN. - nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao - - The Ethernet LAN uses the Advanced Micro Devices (AMD) Am79C940 Media - Access Controller for Ethernet (MACE). It is essentially the Am2150 - PCMCIA Ethernet card contained in the Am2150 Demo Kit. - -Written by Roger C. Pao - Copyright 1995 Roger C. Pao - Linux 2.5 cleanups Copyright Red Hat 2003 - - This software may be used and distributed according to the terms of - the GNU General Public License. - -Ported to Linux 1.3.* network driver environment by - Matti Aarnio - -References - - Am2150 Technical Reference Manual, Revision 1.0, August 17, 1993 - Am79C940 (MACE) Data Sheet, 1994 - Am79C90 (C-LANCE) Data Sheet, 1994 - Linux PCMCIA Programmer's Guide v1.17 - /usr/src/linux/net/inet/dev.c, Linux kernel 1.2.8 - - Eric Mears, New Media Corporation - Tom Pollard, New Media Corporation - Dean Siasoyco, New Media Corporation - Ken Lesniak, Silicon Graphics, Inc. - Donald Becker - David Hinds - - The Linux client driver is based on the 3c589_cs.c client driver by - David Hinds. - - The Linux network driver outline is based on the 3c589_cs.c driver, - the 8390.c driver, and the example skeleton.c kernel code, which are - by Donald Becker. - - The Am2150 network driver hardware interface code is based on the - OS/9000 driver for the New Media Ethernet LAN by Eric Mears. - - Special thanks for testing and help in debugging this driver goes - to Ken Lesniak. - ---------------------------------------------------------------------------= ----- -Driver Notes and Issues ---------------------------------------------------------------------------= ----- - -1. Developed on a Dell 320SLi - PCMCIA Card Services 2.6.2 - Linux dell 1.2.10 #1 Thu Jun 29 20:23:41 PDT 1995 i386 - -2. rc.pcmcia may require loading pcmcia_core with io_speed=3D300: - 'insmod pcmcia_core.o io_speed=3D300'. - This will avoid problems with fast systems which causes rx_framecnt - to return random values. - -3. If hot extraction does not work for you, use 'ifconfig eth0 down' - before extraction. - -4. There is a bad slow-down problem in this driver. - -5. Future: Multicast processing. In the meantime, do _not_ compile your - kernel with multicast ip enabled. - ---------------------------------------------------------------------------= ----- -History ---------------------------------------------------------------------------= ----- -Log: nmclan_cs.c,v - * 2.5.75-ac1 2003/07/11 Alan Cox - * Fixed hang on card eject as we probe it - * Cleaned up to use new style locking. - * - * Revision 0.16 1995/07/01 06:42:17 rpao - * Bug fix: nmclan_reset() called CardServices incorrectly. - * - * Revision 0.15 1995/05/24 08:09:47 rpao - * Re-implement MULTI_TX dev->tbusy handling. - * - * Revision 0.14 1995/05/23 03:19:30 rpao - * Added, in nmclan_config(), "tuple.Attributes =3D 0;". - * Modified MACE ID check to ignore chip revision level. - * Avoid tx_free_frames race condition between _start_xmit and _interrupt. - * - * Revision 0.13 1995/05/18 05:56:34 rpao - * Statistics changes. - * Bug fix: nmclan_reset did not enable TX and RX: call restore_multicast_= list. - * Bug fix: mace_interrupt checks ~MACE_IMR_DEFAULT. Fixes driver lockup. - * - * Revision 0.12 1995/05/14 00:12:23 rpao - * Statistics overhaul. - * - -95/05/13 rpao V0.10a - Bug fix: MACE statistics counters used wrong I/O ports. - Bug fix: mace_interrupt() needed to allow statistics to be - processed without RX or TX interrupts pending. -95/05/11 rpao V0.10 - Multiple transmit request processing. - Modified statistics to use MACE counters where possible. -95/05/10 rpao V0.09 Bug fix: Must use IO_DATA_PATH_WIDTH_AUTO. - *Released -95/05/10 rpao V0.08 - Bug fix: Make all non-exported functions private by using - static keyword. - Bug fix: Test IntrCnt _before_ reading MACE_IR. -95/05/10 rpao V0.07 Statistics. -95/05/09 rpao V0.06 Fix rx_framecnt problem by addition of PCIC wait state= s. - ---------------------------------------------------------------------------= -- */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DRV_NAME "nmclan_cs" - -/* -----------------------------------------------------------------------= ----- -Conditional Compilation Options ---------------------------------------------------------------------------= -- */ - -#define MULTI_TX 0 -#define RESET_ON_TIMEOUT 1 -#define TX_INTERRUPTABLE 1 -#define RESET_XILINX 0 - -/* -----------------------------------------------------------------------= ----- -Include Files ---------------------------------------------------------------------------= -- */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/* -----------------------------------------------------------------------= ----- -Defines ---------------------------------------------------------------------------= -- */ - -#define MACE_LADRF_LEN 8 - /* 8 bytes in Logical Address Filter */ - -/* Loop Control Defines */ -#define MACE_MAX_IR_ITERATIONS 10 -#define MACE_MAX_RX_ITERATIONS 12 - /* - TBD: Dean brought this up, and I assumed the hardware would - handle it: - - If MACE_MAX_RX_ITERATIONS is > 1, rx_framecnt may still be - non-zero when the isr exits. We may not get another interrupt - to process the remaining packets for some time. - */ - -/* -The Am2150 has a Xilinx XC3042 field programmable gate array (FPGA) -which manages the interface between the MACE and the PCMCIA bus. It -also includes buffer management for the 32K x 8 SRAM to control up to -four transmit and 12 receive frames at a time. -*/ -#define AM2150_MAX_TX_FRAMES 4 -#define AM2150_MAX_RX_FRAMES 12 - -/* Am2150 Ethernet Card I/O Mapping */ -#define AM2150_RCV 0x00 -#define AM2150_XMT 0x04 -#define AM2150_XMT_SKIP 0x09 -#define AM2150_RCV_NEXT 0x0A -#define AM2150_RCV_FRAME_COUNT 0x0B -#define AM2150_MACE_BANK 0x0C -#define AM2150_MACE_BASE 0x10 - -/* MACE Registers */ -#define MACE_RCVFIFO 0 -#define MACE_XMTFIFO 1 -#define MACE_XMTFC 2 -#define MACE_XMTFS 3 -#define MACE_XMTRC 4 -#define MACE_RCVFC 5 -#define MACE_RCVFS 6 -#define MACE_FIFOFC 7 -#define MACE_IR 8 -#define MACE_IMR 9 -#define MACE_PR 10 -#define MACE_BIUCC 11 -#define MACE_FIFOCC 12 -#define MACE_MACCC 13 -#define MACE_PLSCC 14 -#define MACE_PHYCC 15 -#define MACE_CHIPIDL 16 -#define MACE_CHIPIDH 17 -#define MACE_IAC 18 -/* Reserved */ -#define MACE_LADRF 20 -#define MACE_PADR 21 -/* Reserved */ -/* Reserved */ -#define MACE_MPC 24 -/* Reserved */ -#define MACE_RNTPC 26 -#define MACE_RCVCC 27 -/* Reserved */ -#define MACE_UTR 29 -#define MACE_RTR1 30 -#define MACE_RTR2 31 - -/* MACE Bit Masks */ -#define MACE_XMTRC_EXDEF 0x80 -#define MACE_XMTRC_XMTRC 0x0F - -#define MACE_XMTFS_XMTSV 0x80 -#define MACE_XMTFS_UFLO 0x40 -#define MACE_XMTFS_LCOL 0x20 -#define MACE_XMTFS_MORE 0x10 -#define MACE_XMTFS_ONE 0x08 -#define MACE_XMTFS_DEFER 0x04 -#define MACE_XMTFS_LCAR 0x02 -#define MACE_XMTFS_RTRY 0x01 - -#define MACE_RCVFS_RCVSTS 0xF000 -#define MACE_RCVFS_OFLO 0x8000 -#define MACE_RCVFS_CLSN 0x4000 -#define MACE_RCVFS_FRAM 0x2000 -#define MACE_RCVFS_FCS 0x1000 - -#define MACE_FIFOFC_RCVFC 0xF0 -#define MACE_FIFOFC_XMTFC 0x0F - -#define MACE_IR_JAB 0x80 -#define MACE_IR_BABL 0x40 -#define MACE_IR_CERR 0x20 -#define MACE_IR_RCVCCO 0x10 -#define MACE_IR_RNTPCO 0x08 -#define MACE_IR_MPCO 0x04 -#define MACE_IR_RCVINT 0x02 -#define MACE_IR_XMTINT 0x01 - -#define MACE_MACCC_PROM 0x80 -#define MACE_MACCC_DXMT2PD 0x40 -#define MACE_MACCC_EMBA 0x20 -#define MACE_MACCC_RESERVED 0x10 -#define MACE_MACCC_DRCVPA 0x08 -#define MACE_MACCC_DRCVBC 0x04 -#define MACE_MACCC_ENXMT 0x02 -#define MACE_MACCC_ENRCV 0x01 - -#define MACE_PHYCC_LNKFL 0x80 -#define MACE_PHYCC_DLNKTST 0x40 -#define MACE_PHYCC_REVPOL 0x20 -#define MACE_PHYCC_DAPC 0x10 -#define MACE_PHYCC_LRT 0x08 -#define MACE_PHYCC_ASEL 0x04 -#define MACE_PHYCC_RWAKE 0x02 -#define MACE_PHYCC_AWAKE 0x01 - -#define MACE_IAC_ADDRCHG 0x80 -#define MACE_IAC_PHYADDR 0x04 -#define MACE_IAC_LOGADDR 0x02 - -#define MACE_UTR_RTRE 0x80 -#define MACE_UTR_RTRD 0x40 -#define MACE_UTR_RPA 0x20 -#define MACE_UTR_FCOLL 0x10 -#define MACE_UTR_RCVFCSE 0x08 -#define MACE_UTR_LOOP_INCL_MENDEC 0x06 -#define MACE_UTR_LOOP_NO_MENDEC 0x04 -#define MACE_UTR_LOOP_EXTERNAL 0x02 -#define MACE_UTR_LOOP_NONE 0x00 -#define MACE_UTR_RESERVED 0x01 - -/* Switch MACE register bank (only 0 and 1 are valid) */ -#define MACEBANK(win_num) outb((win_num), ioaddr + AM2150_MACE_BANK) - -#define MACE_IMR_DEFAULT \ - (0xFF - \ - ( \ - MACE_IR_CERR | \ - MACE_IR_RCVCCO | \ - MACE_IR_RNTPCO | \ - MACE_IR_MPCO | \ - MACE_IR_RCVINT | \ - MACE_IR_XMTINT \ - ) \ - ) -#undef MACE_IMR_DEFAULT -#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything = */ - -#define TX_TIMEOUT ((400*HZ)/1000) - -/* -----------------------------------------------------------------------= ----- -Type Definitions ---------------------------------------------------------------------------= -- */ - -typedef struct _mace_statistics { - /* MACE_XMTFS */ - int xmtsv; - int uflo; - int lcol; - int more; - int one; - int defer; - int lcar; - int rtry; - - /* MACE_XMTRC */ - int exdef; - int xmtrc; - - /* RFS1--Receive Status (RCVSTS) */ - int oflo; - int clsn; - int fram; - int fcs; - - /* RFS2--Runt Packet Count (RNTPC) */ - int rfs_rntpc; - - /* RFS3--Receive Collision Count (RCVCC) */ - int rfs_rcvcc; - - /* MACE_IR */ - int jab; - int babl; - int cerr; - int rcvcco; - int rntpco; - int mpco; - - /* MACE_MPC */ - int mpc; - - /* MACE_RNTPC */ - int rntpc; - - /* MACE_RCVCC */ - int rcvcc; -} mace_statistics; - -typedef struct _mace_private { - struct pcmcia_device *p_dev; - mace_statistics mace_stats; /* MACE chip statistics counters */ - - /* restore_multicast_list() state variables */ - int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */ - int multicast_num_addrs; - - char tx_free_frames; /* Number of free transmit frame buffers */ - char tx_irq_disabled; /* MACE TX interrupt disabled */ - - spinlock_t bank_lock; /* Must be held if you step off bank 0 */ -} mace_private; - -/* -----------------------------------------------------------------------= ----- -Private Global Variables ---------------------------------------------------------------------------= -- */ - -static const char *if_names[]=3D{ - "Auto", "10baseT", "BNC", -}; - -/* -----------------------------------------------------------------------= ----- -Parameters - These are the parameters that can be set during loading with - 'insmod'. ---------------------------------------------------------------------------= -- */ - -MODULE_DESCRIPTION("New Media PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n =3D v; module_param(n, int, 0) - -/* 0=3Dauto, 1=3D10baseT, 2 =3D 10base2, default=3Dauto */ -INT_MODULE_PARM(if_port, 0); - - -/* -----------------------------------------------------------------------= ----- -Function Prototypes ---------------------------------------------------------------------------= -- */ - -static int nmclan_config(struct pcmcia_device *link); -static void nmclan_release(struct pcmcia_device *link); - -static void nmclan_reset(struct net_device *dev); -static int mace_config(struct net_device *dev, struct ifmap *map); -static int mace_open(struct net_device *dev); -static int mace_close(struct net_device *dev); -static netdev_tx_t mace_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static void mace_tx_timeout(struct net_device *dev, unsigned int txqueue); -static irqreturn_t mace_interrupt(int irq, void *dev_id); -static struct net_device_stats *mace_get_stats(struct net_device *dev); -static int mace_rx(struct net_device *dev, unsigned char RxCnt); -static void restore_multicast_list(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static const struct ethtool_ops netdev_ethtool_ops; - - -static void nmclan_detach(struct pcmcia_device *p_dev); - -static const struct net_device_ops mace_netdev_ops =3D { - .ndo_open =3D mace_open, - .ndo_stop =3D mace_close, - .ndo_start_xmit =3D mace_start_xmit, - .ndo_tx_timeout =3D mace_tx_timeout, - .ndo_set_config =3D mace_config, - .ndo_get_stats =3D mace_get_stats, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - -static int nmclan_probe(struct pcmcia_device *link) -{ - mace_private *lp; - struct net_device *dev; - - dev_dbg(&link->dev, "nmclan_attach()\n"); - - /* Create new ethernet device */ - dev =3D alloc_etherdev(sizeof(mace_private)); - if (!dev) - return -ENOMEM; - lp =3D netdev_priv(dev); - lp->p_dev =3D link; - link->priv =3D dev; - - spin_lock_init(&lp->bank_lock); - link->resource[0]->end =3D 32; - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_AUTO; - link->config_flags |=3D CONF_ENABLE_IRQ; - link->config_index =3D 1; - link->config_regs =3D PRESENT_OPTION; - - lp->tx_free_frames=3DAM2150_MAX_TX_FRAMES; - - dev->netdev_ops =3D &mace_netdev_ops; - dev->ethtool_ops =3D &netdev_ethtool_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - - return nmclan_config(link); -} /* nmclan_attach */ - -static void nmclan_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - dev_dbg(&link->dev, "nmclan_detach\n"); - - unregister_netdev(dev); - - nmclan_release(link); - - free_netdev(dev); -} /* nmclan_detach */ - -/* -----------------------------------------------------------------------= ----- -mace_read - Reads a MACE register. This is bank independent; however, the - caller must ensure that this call is not interruptable. We are - assuming that during normal operation, the MACE is always in - bank 0. ---------------------------------------------------------------------------= -- */ -static int mace_read(mace_private *lp, unsigned int ioaddr, int reg) -{ - int data =3D 0xFF; - unsigned long flags; - - switch (reg >> 4) { - case 0: /* register 0-15 */ - data =3D inb(ioaddr + AM2150_MACE_BASE + reg); - break; - case 1: /* register 16-31 */ - spin_lock_irqsave(&lp->bank_lock, flags); - MACEBANK(1); - data =3D inb(ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); - MACEBANK(0); - spin_unlock_irqrestore(&lp->bank_lock, flags); - break; - } - return data & 0xFF; -} /* mace_read */ - -/* -----------------------------------------------------------------------= ----- -mace_write - Writes to a MACE register. This is bank independent; however, - the caller must ensure that this call is not interruptable. We - are assuming that during normal operation, the MACE is always in - bank 0. ---------------------------------------------------------------------------= -- */ -static void mace_write(mace_private *lp, unsigned int ioaddr, int reg, - int data) -{ - unsigned long flags; - - switch (reg >> 4) { - case 0: /* register 0-15 */ - outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + reg); - break; - case 1: /* register 16-31 */ - spin_lock_irqsave(&lp->bank_lock, flags); - MACEBANK(1); - outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); - MACEBANK(0); - spin_unlock_irqrestore(&lp->bank_lock, flags); - break; - } -} /* mace_write */ - -/* -----------------------------------------------------------------------= ----- -mace_init - Resets the MACE chip. ---------------------------------------------------------------------------= -- */ -static int mace_init(mace_private *lp, unsigned int ioaddr, - const char *enet_addr) -{ - int i; - int ct =3D 0; - - /* MACE Software reset */ - mace_write(lp, ioaddr, MACE_BIUCC, 1); - while (mace_read(lp, ioaddr, MACE_BIUCC) & 0x01) { - /* Wait for reset bit to be cleared automatically after <=3D 200ns */; - if(++ct > 500) - { - pr_err("reset failed, card removed?\n"); - return -1; - } - udelay(1); - } - mace_write(lp, ioaddr, MACE_BIUCC, 0); - - /* The Am2150 requires that the MACE FIFOs operate in burst mode. */ - mace_write(lp, ioaddr, MACE_FIFOCC, 0x0F); - - mace_write(lp,ioaddr, MACE_RCVFC, 0); /* Disable Auto Strip Receive */ - mace_write(lp, ioaddr, MACE_IMR, 0xFF); /* Disable all interrupts until = _open */ - - /* - * Bit 2-1 PORTSEL[1-0] Port Select. - * 00 AUI/10Base-2 - * 01 10Base-T - * 10 DAI Port (reserved in Am2150) - * 11 GPSI - * For this card, only the first two are valid. - * So, PLSCC should be set to - * 0x00 for 10Base-2 - * 0x02 for 10Base-T - * Or just set ASEL in PHYCC below! - */ - switch (if_port) { - case 1: - mace_write(lp, ioaddr, MACE_PLSCC, 0x02); - break; - case 2: - mace_write(lp, ioaddr, MACE_PLSCC, 0x00); - break; - default: - mace_write(lp, ioaddr, MACE_PHYCC, /* ASEL */ 4); - /* ASEL Auto Select. When set, the PORTSEL[1-0] bits are overridden, - and the MACE device will automatically select the operating media - interface port. */ - break; - } - - mace_write(lp, ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_PHYADDR); - /* Poll ADDRCHG bit */ - ct =3D 0; - while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG) - { - if(++ ct > 500) - { - pr_err("ADDRCHG timeout, card removed?\n"); - return -1; - } - } - /* Set PADR register */ - for (i =3D 0; i < ETH_ALEN; i++) - mace_write(lp, ioaddr, MACE_PADR, enet_addr[i]); - - /* MAC Configuration Control Register should be written last */ - /* Let set_multicast_list set this. */ - /* mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRC= V); */ - mace_write(lp, ioaddr, MACE_MACCC, 0x00); - return 0; -} /* mace_init */ - -static int nmclan_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - mace_private *lp =3D netdev_priv(dev); - u8 *buf; - size_t len; - int i, ret; - unsigned int ioaddr; - - dev_dbg(&link->dev, "nmclan_config\n"); - - link->io_lines =3D 5; - ret =3D pcmcia_request_io(link); - if (ret) - goto failed; - ret =3D pcmcia_request_irq(link, mace_interrupt); - if (ret) - goto failed; - ret =3D pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq =3D link->irq; - dev->base_addr =3D link->resource[0]->start; - - ioaddr =3D dev->base_addr; - - /* Read the ethernet address from the CIS. */ - len =3D pcmcia_get_tuple(link, 0x80, &buf); - if (!buf || len < ETH_ALEN) { - kfree(buf); - goto failed; - } - eth_hw_addr_set(dev, buf); - kfree(buf); - - /* Verify configuration by reading the MACE ID. */ - { - char sig[2]; - - sig[0] =3D mace_read(lp, ioaddr, MACE_CHIPIDL); - sig[1] =3D mace_read(lp, ioaddr, MACE_CHIPIDH); - if ((sig[0] =3D=3D 0x40) && ((sig[1] & 0x0F) =3D=3D 0x09)) { - dev_dbg(&link->dev, "nmclan_cs configured: mace id=3D%x %x\n", - sig[0], sig[1]); - } else { - pr_notice("mace id not found: %x %x should be 0x40 0x?9\n", - sig[0], sig[1]); - goto failed; - } - } - - if(mace_init(lp, ioaddr, dev->dev_addr) =3D=3D -1) - goto failed; - - /* The if_port symbol can be set when the module is loaded */ - if (if_port <=3D 2) - dev->if_port =3D if_port; - else - pr_notice("invalid if_port requested\n"); - - SET_NETDEV_DEV(dev, &link->dev); - - i =3D register_netdev(dev); - if (i !=3D 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "nmclan: port %#3lx, irq %d, %s port, hw_addr %pM\n", - dev->base_addr, dev->irq, if_names[dev->if_port], dev->dev_addr); - return 0; - -failed: - nmclan_release(link); - return -ENODEV; -} /* nmclan_config */ - -static void nmclan_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "nmclan_release\n"); - pcmcia_disable_device(link); -} - -static int nmclan_suspend(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int nmclan_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) { - nmclan_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -/* -----------------------------------------------------------------------= ----- -nmclan_reset - Reset and restore all of the Xilinx and MACE registers. ---------------------------------------------------------------------------= -- */ -static void nmclan_reset(struct net_device *dev) -{ - mace_private *lp =3D netdev_priv(dev); - -#if RESET_XILINX - struct pcmcia_device *link =3D &lp->link; - u8 OrigCorValue; - - /* Save original COR value */ - pcmcia_read_config_byte(link, CISREG_COR, &OrigCorValue); - - /* Reset Xilinx */ - dev_dbg(&link->dev, "nmclan_reset: OrigCorValue=3D0x%x, resetting...\n", - OrigCorValue); - pcmcia_write_config_byte(link, CISREG_COR, COR_SOFT_RESET); - /* Need to wait for 20 ms for PCMCIA to finish reset. */ - - /* Restore original COR configuration index */ - pcmcia_write_config_byte(link, CISREG_COR, - (COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK))); - /* Xilinx is now completely reset along with the MACE chip. */ - lp->tx_free_frames=3DAM2150_MAX_TX_FRAMES; - -#endif /* #if RESET_XILINX */ - - /* Xilinx is now completely reset along with the MACE chip. */ - lp->tx_free_frames=3DAM2150_MAX_TX_FRAMES; - - /* Reinitialize the MACE chip for operation. */ - mace_init(lp, dev->base_addr, dev->dev_addr); - mace_write(lp, dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT); - - /* Restore the multicast list and enable TX and RX. */ - restore_multicast_list(dev); -} /* nmclan_reset */ - -/* -----------------------------------------------------------------------= ----- -mace_config - [Someone tell me what this is supposed to do? Is if_port a defined - standard? If so, there should be defines to indicate 1=3D10Base-T, - 2=3D10Base-2, etc. including limited automatic detection.] ---------------------------------------------------------------------------= -- */ -static int mace_config(struct net_device *dev, struct ifmap *map) -{ - if ((map->port !=3D (u_char)(-1)) && (map->port !=3D dev->if_port)) { - if (map->port <=3D 2) { - WRITE_ONCE(dev->if_port, map->port); - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - } else - return -EINVAL; - } - return 0; -} /* mace_config */ - -/* -----------------------------------------------------------------------= ----- -mace_open - Open device driver. ---------------------------------------------------------------------------= -- */ -static int mace_open(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - mace_private *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - link->open++; - - MACEBANK(0); - - netif_start_queue(dev); - nmclan_reset(dev); - - return 0; /* Always succeed */ -} /* mace_open */ - -/* -----------------------------------------------------------------------= ----- -mace_close - Closes device driver. ---------------------------------------------------------------------------= -- */ -static int mace_close(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - mace_private *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); - - /* Mask off all interrupts from the MACE chip. */ - outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR); - - link->open--; - netif_stop_queue(dev); - - return 0; -} /* mace_close */ - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - snprintf(info->bus_info, sizeof(info->bus_info), - "PCMCIA 0x%lx", dev->base_addr); -} - -static const struct ethtool_ops netdev_ethtool_ops =3D { - .get_drvinfo =3D netdev_get_drvinfo, -}; - -/* -----------------------------------------------------------------------= ----- -mace_start_xmit - This routine begins the packet transmit function. When completed, - it will generate a transmit interrupt. - - According to /usr/src/linux/net/inet/dev.c, if _start_xmit - returns 0, the "packet is now solely the responsibility of the - driver." If _start_xmit returns non-zero, the "transmission - failed, put skb back into a list." ---------------------------------------------------------------------------= -- */ - -static void mace_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - mace_private *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - netdev_notice(dev, "transmit timed out -- "); -#if RESET_ON_TIMEOUT - pr_cont("resetting card\n"); - pcmcia_reset_card(link->socket); -#else /* #if RESET_ON_TIMEOUT */ - pr_cont("NOT resetting card\n"); -#endif /* #if RESET_ON_TIMEOUT */ - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); -} - -static netdev_tx_t mace_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - mace_private *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - - netif_stop_queue(dev); - - pr_debug("%s: mace_start_xmit(length =3D %ld) called.\n", - dev->name, (long)skb->len); - -#if (!TX_INTERRUPTABLE) - /* Disable MACE TX interrupts. */ - outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT, - ioaddr + AM2150_MACE_BASE + MACE_IMR); - lp->tx_irq_disabled=3D1; -#endif /* #if (!TX_INTERRUPTABLE) */ - - { - /* This block must not be interrupted by another transmit request! - mace_tx_timeout will take care of timer-based retransmissions from - the upper layers. The interrupt handler is guaranteed never to - service a transmit interrupt while we are in here. - */ - - dev->stats.tx_bytes +=3D skb->len; - lp->tx_free_frames--; - - /* WARNING: Write the _exact_ number of bytes written in the header! */ - /* Put out the word header [must be an outw()] . . . */ - outw(skb->len, ioaddr + AM2150_XMT); - /* . . . and the packet [may be any combination of outw() and outb()] = */ - outsw(ioaddr + AM2150_XMT, skb->data, skb->len >> 1); - if (skb->len & 1) { - /* Odd byte transfer */ - outb(skb->data[skb->len-1], ioaddr + AM2150_XMT); - } - -#if MULTI_TX - if (lp->tx_free_frames > 0) - netif_start_queue(dev); -#endif /* #if MULTI_TX */ - } - -#if (!TX_INTERRUPTABLE) - /* Re-enable MACE TX interrupts. */ - lp->tx_irq_disabled=3D0; - outb(MACE_IMR_DEFAULT, ioaddr + AM2150_MACE_BASE + MACE_IMR); -#endif /* #if (!TX_INTERRUPTABLE) */ - - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} /* mace_start_xmit */ - -/* -----------------------------------------------------------------------= ----- -mace_interrupt - The interrupt handler. ---------------------------------------------------------------------------= -- */ -static irqreturn_t mace_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D (struct net_device *) dev_id; - mace_private *lp =3D netdev_priv(dev); - unsigned int ioaddr; - int status; - int IntrCnt =3D MACE_MAX_IR_ITERATIONS; - - if (!dev) { - pr_debug("mace_interrupt(): irq 0x%X for unknown device.\n", - irq); - return IRQ_NONE; - } - - ioaddr =3D dev->base_addr; - - if (lp->tx_irq_disabled) { - const char *msg; - if (lp->tx_irq_disabled) - msg =3D "Interrupt with tx_irq_disabled"; - else - msg =3D "Re-entering the interrupt handler"; - netdev_notice(dev, "%s [isr=3D%02X, imr=3D%02X]\n", - msg, - inb(ioaddr + AM2150_MACE_BASE + MACE_IR), - inb(ioaddr + AM2150_MACE_BASE + MACE_IMR)); - /* WARNING: MACE_IR has been read! */ - return IRQ_NONE; - } - - if (!netif_device_present(dev)) { - netdev_dbg(dev, "interrupt from dead card\n"); - return IRQ_NONE; - } - - do { - /* WARNING: MACE_IR is a READ/CLEAR port! */ - status =3D inb(ioaddr + AM2150_MACE_BASE + MACE_IR); - if (!(status & ~MACE_IMR_DEFAULT) && IntrCnt =3D=3D MACE_MAX_IR_ITERAT= IONS) - return IRQ_NONE; - - pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); - - if (status & MACE_IR_RCVINT) { - mace_rx(dev, MACE_MAX_RX_ITERATIONS); - } - - if (status & MACE_IR_XMTINT) { - unsigned char fifofc; - unsigned char xmtrc; - unsigned char xmtfs; - - fifofc =3D inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC); - if ((fifofc & MACE_FIFOFC_XMTFC)=3D=3D0) { - dev->stats.tx_errors++; - outb(0xFF, ioaddr + AM2150_XMT_SKIP); - } - - /* Transmit Retry Count (XMTRC, reg 4) */ - xmtrc =3D inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC); - if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++; - lp->mace_stats.xmtrc +=3D (xmtrc & MACE_XMTRC_XMTRC); - - if ( - (xmtfs =3D inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) & - MACE_XMTFS_XMTSV /* Transmit Status Valid */ - ) { - lp->mace_stats.xmtsv++; - - if (xmtfs & ~MACE_XMTFS_XMTSV) { - if (xmtfs & MACE_XMTFS_UFLO) { - /* Underflow. Indicates that the Transmit FIFO emptied before - the end of frame was reached. */ - lp->mace_stats.uflo++; - } - if (xmtfs & MACE_XMTFS_LCOL) { - /* Late Collision */ - lp->mace_stats.lcol++; - } - if (xmtfs & MACE_XMTFS_MORE) { - /* MORE than one retry was needed */ - lp->mace_stats.more++; - } - if (xmtfs & MACE_XMTFS_ONE) { - /* Exactly ONE retry occurred */ - lp->mace_stats.one++; - } - if (xmtfs & MACE_XMTFS_DEFER) { - /* Transmission was defered */ - lp->mace_stats.defer++; - } - if (xmtfs & MACE_XMTFS_LCAR) { - /* Loss of carrier */ - lp->mace_stats.lcar++; - } - if (xmtfs & MACE_XMTFS_RTRY) { - /* Retry error: transmit aborted after 16 attempts */ - lp->mace_stats.rtry++; - } - } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */ - - } /* if (xmtfs & MACE_XMTFS_XMTSV) */ - - dev->stats.tx_packets++; - lp->tx_free_frames++; - netif_wake_queue(dev); - } /* if (status & MACE_IR_XMTINT) */ - - if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) { - if (status & MACE_IR_JAB) { - /* Jabber Error. Excessive transmit duration (20-150ms). */ - lp->mace_stats.jab++; - } - if (status & MACE_IR_BABL) { - /* Babble Error. >1518 bytes transmitted. */ - lp->mace_stats.babl++; - } - if (status & MACE_IR_CERR) { - /* Collision Error. CERR indicates the absence of the - Signal Quality Error Test message after a packet - transmission. */ - lp->mace_stats.cerr++; - } - if (status & MACE_IR_RCVCCO) { - /* Receive Collision Count Overflow; */ - lp->mace_stats.rcvcco++; - } - if (status & MACE_IR_RNTPCO) { - /* Runt Packet Count Overflow */ - lp->mace_stats.rntpco++; - } - if (status & MACE_IR_MPCO) { - /* Missed Packet Count Overflow */ - lp->mace_stats.mpco++; - } - } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTIN= T) */ - - } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt)); - - return IRQ_HANDLED; -} /* mace_interrupt */ - -/* -----------------------------------------------------------------------= ----- -mace_rx - Receives packets. ---------------------------------------------------------------------------= -- */ -static int mace_rx(struct net_device *dev, unsigned char RxCnt) -{ - mace_private *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - unsigned char rx_framecnt; - unsigned short rx_status; - - while ( - ((rx_framecnt =3D inb(ioaddr + AM2150_RCV_FRAME_COUNT)) > 0) && - (rx_framecnt <=3D 12) && /* rx_framecnt=3D=3D0xFF if card is extracted= . */ - (RxCnt--) - ) { - rx_status =3D inw(ioaddr + AM2150_RCV); - - pr_debug("%s: in mace_rx(), framecnt 0x%X, rx_status" - " 0x%X.\n", dev->name, rx_framecnt, rx_status); - - if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */ - dev->stats.rx_errors++; - if (rx_status & MACE_RCVFS_OFLO) { - lp->mace_stats.oflo++; - } - if (rx_status & MACE_RCVFS_CLSN) { - lp->mace_stats.clsn++; - } - if (rx_status & MACE_RCVFS_FRAM) { - lp->mace_stats.fram++; - } - if (rx_status & MACE_RCVFS_FCS) { - lp->mace_stats.fcs++; - } - } else { - short pkt_len =3D (rx_status & ~MACE_RCVFS_RCVSTS) - 4; - /* Auto Strip is off, always subtract 4 */ - struct sk_buff *skb; - - lp->mace_stats.rfs_rntpc +=3D inb(ioaddr + AM2150_RCV); - /* runt packet count */ - lp->mace_stats.rfs_rcvcc +=3D inb(ioaddr + AM2150_RCV); - /* rcv collision count */ - - pr_debug(" receiving packet size 0x%X rx_status" - " 0x%X.\n", pkt_len, rx_status); - - skb =3D netdev_alloc_skb(dev, pkt_len + 2); - - if (skb) { - skb_reserve(skb, 2); - insw(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1); - if (pkt_len & 1) - *(skb_tail_pointer(skb) - 1) =3D inb(ioaddr + AM2150_RCV); - skb->protocol =3D eth_type_trans(skb, dev); - - netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ - - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pkt_len; - outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ - continue; - } else { - pr_debug("%s: couldn't allocate a sk_buff of size" - " %d.\n", dev->name, pkt_len); - dev->stats.rx_dropped++; - } - } - outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ - } /* while */ - - return 0; -} /* mace_rx */ - -/* -----------------------------------------------------------------------= ----- -pr_linux_stats ---------------------------------------------------------------------------= -- */ -static void pr_linux_stats(struct net_device_stats *pstats) -{ - pr_debug("pr_linux_stats\n"); - pr_debug(" rx_packets=3D%-7ld tx_packets=3D%ld\n", - (long)pstats->rx_packets, (long)pstats->tx_packets); - pr_debug(" rx_errors=3D%-7ld tx_errors=3D%ld\n", - (long)pstats->rx_errors, (long)pstats->tx_errors); - pr_debug(" rx_dropped=3D%-7ld tx_dropped=3D%ld\n", - (long)pstats->rx_dropped, (long)pstats->tx_dropped); - pr_debug(" multicast=3D%-7ld collisions=3D%ld\n", - (long)pstats->multicast, (long)pstats->collisions); - - pr_debug(" rx_length_errors=3D%-7ld rx_over_errors=3D%ld\n", - (long)pstats->rx_length_errors, (long)pstats->rx_over_errors); - pr_debug(" rx_crc_errors=3D%-7ld rx_frame_errors=3D%ld\n", - (long)pstats->rx_crc_errors, (long)pstats->rx_frame_errors); - pr_debug(" rx_fifo_errors=3D%-7ld rx_missed_errors=3D%ld\n", - (long)pstats->rx_fifo_errors, (long)pstats->rx_missed_errors); - - pr_debug(" tx_aborted_errors=3D%-7ld tx_carrier_errors=3D%ld\n", - (long)pstats->tx_aborted_errors, (long)pstats->tx_carrier_errors); - pr_debug(" tx_fifo_errors=3D%-7ld tx_heartbeat_errors=3D%ld\n", - (long)pstats->tx_fifo_errors, (long)pstats->tx_heartbeat_errors); - pr_debug(" tx_window_errors=3D%ld\n", - (long)pstats->tx_window_errors); -} /* pr_linux_stats */ - -/* -----------------------------------------------------------------------= ----- -pr_mace_stats ---------------------------------------------------------------------------= -- */ -static void pr_mace_stats(mace_statistics *pstats) -{ - pr_debug("pr_mace_stats\n"); - - pr_debug(" xmtsv=3D%-7d uflo=3D%d\n", - pstats->xmtsv, pstats->uflo); - pr_debug(" lcol=3D%-7d more=3D%d\n", - pstats->lcol, pstats->more); - pr_debug(" one=3D%-7d defer=3D%d\n", - pstats->one, pstats->defer); - pr_debug(" lcar=3D%-7d rtry=3D%d\n", - pstats->lcar, pstats->rtry); - - /* MACE_XMTRC */ - pr_debug(" exdef=3D%-7d xmtrc=3D%d\n", - pstats->exdef, pstats->xmtrc); - - /* RFS1--Receive Status (RCVSTS) */ - pr_debug(" oflo=3D%-7d clsn=3D%d\n", - pstats->oflo, pstats->clsn); - pr_debug(" fram=3D%-7d fcs=3D%d\n", - pstats->fram, pstats->fcs); - - /* RFS2--Runt Packet Count (RNTPC) */ - /* RFS3--Receive Collision Count (RCVCC) */ - pr_debug(" rfs_rntpc=3D%-7d rfs_rcvcc=3D%d\n", - pstats->rfs_rntpc, pstats->rfs_rcvcc); - - /* MACE_IR */ - pr_debug(" jab=3D%-7d babl=3D%d\n", - pstats->jab, pstats->babl); - pr_debug(" cerr=3D%-7d rcvcco=3D%d\n", - pstats->cerr, pstats->rcvcco); - pr_debug(" rntpco=3D%-7d mpco=3D%d\n", - pstats->rntpco, pstats->mpco); - - /* MACE_MPC */ - pr_debug(" mpc=3D%d\n", pstats->mpc); - - /* MACE_RNTPC */ - pr_debug(" rntpc=3D%d\n", pstats->rntpc); - - /* MACE_RCVCC */ - pr_debug(" rcvcc=3D%d\n", pstats->rcvcc); - -} /* pr_mace_stats */ - -/* -----------------------------------------------------------------------= ----- -update_stats - Update statistics. We change to register window 1, so this - should be run single-threaded if the device is active. This is - expected to be a rare operation, and it's simpler for the rest - of the driver to assume that window 0 is always valid rather - than use a special window-state variable. - - oflo & uflo should _never_ occur since it would mean the Xilinx - was not able to transfer data between the MACE FIFO and the - card's SRAM fast enough. If this happens, something is - seriously wrong with the hardware. ---------------------------------------------------------------------------= -- */ -static void update_stats(unsigned int ioaddr, struct net_device *dev) -{ - mace_private *lp =3D netdev_priv(dev); - - lp->mace_stats.rcvcc +=3D mace_read(lp, ioaddr, MACE_RCVCC); - lp->mace_stats.rntpc +=3D mace_read(lp, ioaddr, MACE_RNTPC); - lp->mace_stats.mpc +=3D mace_read(lp, ioaddr, MACE_MPC); - /* At this point, mace_stats is fully updated for this call. - We may now update the netdev stats. */ - - /* The MACE has no equivalent for netdev stats field which are commented - out. */ - - /* dev->stats.multicast; */ - dev->stats.collisions =3D - lp->mace_stats.rcvcco * 256 + lp->mace_stats.rcvcc; - /* Collision: The MACE may retry sending a packet 15 times - before giving up. The retry count is in XMTRC. - Does each retry constitute a collision? - If so, why doesn't the RCVCC record these collisions? */ - - /* detailed rx_errors: */ - dev->stats.rx_length_errors =3D - lp->mace_stats.rntpco * 256 + lp->mace_stats.rntpc; - /* dev->stats.rx_over_errors */ - dev->stats.rx_crc_errors =3D lp->mace_stats.fcs; - dev->stats.rx_frame_errors =3D lp->mace_stats.fram; - dev->stats.rx_fifo_errors =3D lp->mace_stats.oflo; - dev->stats.rx_missed_errors =3D - lp->mace_stats.mpco * 256 + lp->mace_stats.mpc; - - /* detailed tx_errors */ - dev->stats.tx_aborted_errors =3D lp->mace_stats.rtry; - dev->stats.tx_carrier_errors =3D lp->mace_stats.lcar; - /* LCAR usually results from bad cabling. */ - dev->stats.tx_fifo_errors =3D lp->mace_stats.uflo; - dev->stats.tx_heartbeat_errors =3D lp->mace_stats.cerr; - /* dev->stats.tx_window_errors; */ -} /* update_stats */ - -/* -----------------------------------------------------------------------= ----- -mace_get_stats - Gathers ethernet statistics from the MACE chip. ---------------------------------------------------------------------------= -- */ -static struct net_device_stats *mace_get_stats(struct net_device *dev) -{ - mace_private *lp =3D netdev_priv(dev); - - update_stats(dev->base_addr, dev); - - pr_debug("%s: updating the statistics.\n", dev->name); - pr_linux_stats(&dev->stats); - pr_mace_stats(&lp->mace_stats); - - return &dev->stats; -} /* net_device_stats */ - -/* -----------------------------------------------------------------------= ----- -updateCRC - Modified from Am79C90 data sheet. ---------------------------------------------------------------------------= -- */ - -#ifdef BROKEN_MULTICAST - -static void updateCRC(int *CRC, int bit) -{ - static const int poly[]=3D{ - 1,1,1,0, 1,1,0,1, - 1,0,1,1, 1,0,0,0, - 1,0,0,0, 0,0,1,1, - 0,0,1,0, 0,0,0,0 - }; /* CRC polynomial. poly[n] =3D coefficient of the x**n term of the - CRC generator polynomial. */ - - int j; - - /* shift CRC and control bit (CRC[32]) */ - for (j =3D 32; j > 0; j--) - CRC[j] =3D CRC[j-1]; - CRC[0] =3D 0; - - /* If bit XOR(control bit) =3D 1, set CRC =3D CRC XOR polynomial. */ - if (bit ^ CRC[32]) - for (j =3D 0; j < 32; j++) - CRC[j] ^=3D poly[j]; -} /* updateCRC */ - -/* -----------------------------------------------------------------------= ----- -BuildLAF - Build logical address filter. - Modified from Am79C90 data sheet. - -Input - ladrf: logical address filter (contents initialized to 0) - adr: ethernet address ---------------------------------------------------------------------------= -- */ -static void BuildLAF(int *ladrf, int *adr) -{ - int CRC[33]=3D{1}; /* CRC register, 1 word/bit + extra control bit */ - - int i, byte; /* temporary array indices */ - int hashcode; /* the output object */ - - CRC[32]=3D0; - - for (byte =3D 0; byte < 6; byte++) - for (i =3D 0; i < 8; i++) - updateCRC(CRC, (adr[byte] >> i) & 1); - - hashcode =3D 0; - for (i =3D 0; i < 6; i++) - hashcode =3D (hashcode << 1) + CRC[i]; - - byte =3D hashcode >> 3; - ladrf[byte] |=3D (1 << (hashcode & 7)); - -#ifdef PCMCIA_DEBUG - if (0) - printk(KERN_DEBUG " adr =3D%pM\n", adr); - printk(KERN_DEBUG " hashcode =3D %d(decimal), ladrf[0:63] =3D", hashc= ode); - for (i =3D 0; i < 8; i++) - pr_cont(" %02X", ladrf[i]); - pr_cont("\n"); -#endif -} /* BuildLAF */ - -/* -----------------------------------------------------------------------= ----- -restore_multicast_list - Restores the multicast filter for MACE chip to the last - set_multicast_list() call. - -Input - multicast_num_addrs - multicast_ladrf[] ---------------------------------------------------------------------------= -- */ -static void restore_multicast_list(struct net_device *dev) -{ - mace_private *lp =3D netdev_priv(dev); - int num_addrs =3D lp->multicast_num_addrs; - int *ladrf =3D lp->multicast_ladrf; - unsigned int ioaddr =3D dev->base_addr; - int i; - - pr_debug("%s: restoring Rx mode to %d addresses.\n", - dev->name, num_addrs); - - if (num_addrs > 0) { - - pr_debug("Attempt to restore multicast list detected.\n"); - - mace_write(lp, ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_LOGADDR); - /* Poll ADDRCHG bit */ - while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG) - ; - /* Set LADRF register */ - for (i =3D 0; i < MACE_LADRF_LEN; i++) - mace_write(lp, ioaddr, MACE_LADRF, ladrf[i]); - - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_RCVFCSE | MACE_UTR_LOOP_EXTE= RNAL); - mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV= ); - - } else if (num_addrs < 0) { - - /* Promiscuous mode: receive all packets */ - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, - MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV - ); - - } else { - - /* Normal mode */ - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV= ); - - } -} /* restore_multicast_list */ - -/* -----------------------------------------------------------------------= ----- -set_multicast_list - Set or clear the multicast filter for this adaptor. - -Input - num_addrs =3D=3D -1 Promiscuous mode, receive all packets - num_addrs =3D=3D 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. -Output - multicast_num_addrs - multicast_ladrf[] ---------------------------------------------------------------------------= -- */ - -static void set_multicast_list(struct net_device *dev) -{ - mace_private *lp =3D netdev_priv(dev); - int adr[ETH_ALEN] =3D {0}; /* Ethernet address */ - struct netdev_hw_addr *ha; - -#ifdef PCMCIA_DEBUG - { - static int old; - if (netdev_mc_count(dev) !=3D old) { - old =3D netdev_mc_count(dev); - pr_debug("%s: setting Rx mode to %d addresses.\n", - dev->name, old); - } - } -#endif - - /* Set multicast_num_addrs. */ - lp->multicast_num_addrs =3D netdev_mc_count(dev); - - /* Set multicast_ladrf. */ - if (num_addrs > 0) { - /* Calculate multicast logical address filter */ - memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN); - netdev_for_each_mc_addr(ha, dev) { - memcpy(adr, ha->addr, ETH_ALEN); - BuildLAF(lp->multicast_ladrf, adr); - } - } - - restore_multicast_list(dev); - -} /* set_multicast_list */ - -#endif /* BROKEN_MULTICAST */ - -static void restore_multicast_list(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - mace_private *lp =3D netdev_priv(dev); - - pr_debug("%s: restoring Rx mode to %d addresses.\n", dev->name, - lp->multicast_num_addrs); - - if (dev->flags & IFF_PROMISC) { - /* Promiscuous mode: receive all packets */ - mace_write(lp,ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, - MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV - ); - } else { - /* Normal mode */ - mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); - mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV= ); - } -} /* restore_multicast_list */ - -static void set_multicast_list(struct net_device *dev) -{ - mace_private *lp =3D netdev_priv(dev); - -#ifdef PCMCIA_DEBUG - { - static int old; - if (netdev_mc_count(dev) !=3D old) { - old =3D netdev_mc_count(dev); - pr_debug("%s: setting Rx mode to %d addresses.\n", - dev->name, old); - } - } -#endif - - lp->multicast_num_addrs =3D netdev_mc_count(dev); - restore_multicast_list(dev); - -} /* set_multicast_list */ - -static const struct pcmcia_device_id nmclan_ids[] =3D { - PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, = 0x00b2e941), - PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad6= 73aaf), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, nmclan_ids); - -static struct pcmcia_driver nmclan_cs_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "nmclan_cs", - .probe =3D nmclan_probe, - .remove =3D nmclan_detach, - .id_table =3D nmclan_ids, - .suspend =3D nmclan_suspend, - .resume =3D nmclan_resume, -}; -module_pcmcia_driver(nmclan_cs_driver); --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0632E3DD526; Tue, 21 Apr 2026 19:31:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799912; cv=none; b=k4Uk84u3s8hURSbDB5xTZguyE8ENjw+UcGSFNliXfMX4Yov0zHuMXtYX4k3qGZ3KO8mmf/vwvEGDHdVEFlqeTUyxWtf2NNh4JvCwvhICwSkpwU7Z/foYk1dUq2ILrnqTynVz+f7pYgAOInkZfTQnqHwKS8pO//RmWgxV1Vp2anc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776799912; c=relaxed/simple; bh=7yx3iH1bM4Piy0aVECMvW/mxEbE/Nh7juVzdKPK1XGU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ofOUYshINEHY5vPlAyDECNN5PIcjzKN4ufQXAuuAIJvx6Og1Iz8TkbZyxLSeiF8L8KK4aGEqAgG7YKgiSoKfBPSKYcBU3c5OvYcsDpCgTT7qSKtwoyJFgOrggH47JUqVgm0n77JsRzItyk1Dyh5FJ2BGfjpwQFIJf3XVmimW0Qo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=nQW/H57V; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="nQW/H57V" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=O+2LfDMbtYefuBsM9e9O/GSxAF/tGcBT45zPb2p8uO8=; b=nQ W/H57Vdw8n6ZqPpNEPgkNOGfX3BLIOT1bvt3GSxD/qnt+QOusAJP8q/96B/71cCR4nMSLxLqRvnog g4JPopybtIGkFOwbmuSzza8dKWUQy3JW6JKUygTP9aGqrSKr5qJ6xkp/lqJOyhWm8GDw1102xr4XR +jXY5ZsYStTItS8=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGot-00GwVc-HF; Tue, 21 Apr 2026 21:31:39 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:12 -0500 Subject: [PATCH net 09/18] drivers: net: smsc: smc9194: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-9-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=48306; i=andrew@lunn.ch; h=from:subject:message-id; bh=7yx3iH1bM4Piy0aVECMvW/mxEbE/Nh7juVzdKPK1XGU=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CB4EhfssfmEV1LIUx0RfzC0G6jhftxKZalX FgjemANQ1+JAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQgQAKCRDmvw3LpmlM hGinD/4/e/mqvN5oeFV+TGnK+vzgQAfJNsAXVF7R8IRzpdBjrRuMWLqecmOI1jLQr0iIQeR1Vn5 bWkKN0aUC2RtRQqN/rPJYaHYJtqkOKquZjJu0YudFFF2EjBcXmifnV9DQaXG8OiCAu+m9ZQdMnk z0HEw6EH80CUl2kcdslSDqoMixDzkRAL7oHBFXEV31RiL5sS24ol5OgE40ykUKsCAanfu/nRGmG IqfGTsg8n2QItj/YL5hTckDN1KXgQgZzVbRkn2yXIzwTjbGWAWpiE2x8zVuooQYj02Cwt9hWMbm iNfgyB7y1KQjsni52gEOS1tLke1+E2WnaJVfUSlgp0DURptJUzM5N9wBrAHP2zCXGCAOxX/r2aC yvSHMPBlIjpAXRw6US1MJE5Dzf6s58HQQInfNThvH323peaOWr1IVUKMMG4U7NmP9fSynWIm+8r HRXLfSECAUvbuC3+GXIB7S3pg81XDCrTP/rmshMiATFnescGZvtYXade1fJYds0hlyBn4xAgH5G 6MtdklM+q8wQrZoV55DAs78ZSFsQyaibR6lYMTCeiLK1A2Dsz4FA7RpgGAm2QVRMBVBAdC87iPP gikRFluHCi3dvyQzpPElgkKC80Pa1Go72Vv+EZcNT7rpN+DNdY4Bfy7S6tAcO89kBCEfmpM4RMR 8iUrvqXvcSwtHmw== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The smc9194 was written by Erik Stahlman in 1996. It is an ISA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/smsc/Kconfig | 15 - drivers/net/ethernet/smsc/Makefile | 1 - drivers/net/ethernet/smsc/smc9194.c | 1535 -------------------------------= ---- 3 files changed, 1551 deletions(-) diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/= Kconfig index 13ce9086a9ca..d25bbcc98854 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -19,21 +19,6 @@ config NET_VENDOR_SMSC =20 if NET_VENDOR_SMSC =20 -config SMC9194 - tristate "SMC 9194 support" - depends on ISA - select CRC32 - select NETDEV_LEGACY_INIT - help - This is support for the SMC9xxx based Ethernet cards. Choose this - option if you have a DELL laptop with the docking station, or - another SMC9192/9194 based chipset. Say Y if you want it compiled - into the kernel, and read the file - . - - To compile this driver as a module, choose M here. The module - will be called smc9194. - config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc= /Makefile index 1501fa364c13..afea0b94c2a4 100644 --- a/drivers/net/ethernet/smsc/Makefile +++ b/drivers/net/ethernet/smsc/Makefile @@ -3,7 +3,6 @@ # Makefile for the SMSC network device drivers. # =20 -obj-$(CONFIG_SMC9194) +=3D smc9194.o obj-$(CONFIG_SMC91X) +=3D smc91x.o obj-$(CONFIG_PCMCIA_SMC91C92) +=3D smc91c92_cs.o obj-$(CONFIG_EPIC100) +=3D epic100.o diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/sms= c/smc9194.c deleted file mode 100644 index e2e7b1c68563..000000000000 --- a/drivers/net/ethernet/smsc/smc9194.c +++ /dev/null @@ -1,1535 +0,0 @@ -/*------------------------------------------------------------------------ - . smc9194.c - . This is a driver for SMC's 9000 series of Ethernet cards. - . - . Copyright (C) 1996 by Erik Stahlman - . This software may be used and distributed according to the terms - . of the GNU General Public License, incorporated herein by reference. - . - . "Features" of the SMC chip: - . 4608 byte packet memory. ( for the 91C92. Others have more ) - . EEPROM for configuration - . AUI/TP selection ( mine has 10Base2/10BaseT select ) - . - . Arguments: - . io =3D for the base address - . irq =3D for the IRQ - . ifport =3D 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 ) - . - . author: - . Erik Stahlman ( erik@vt.edu ) - . contributors: - . Arnaldo Carvalho de Melo - . - . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) - . - . Sources: - . o SMC databook - . o skeleton.c by Donald Becker ( becker@scyld.com ) - . o ( a LOT of advice from Becker as well ) - . - . History: - . 12/07/95 Erik Stahlman written, got receive/xmit handled - . 01/03/96 Erik Stahlman worked out some bugs, actually usable!!! :-) - . 01/06/96 Erik Stahlman cleaned up some, better testing, etc - . 01/29/96 Erik Stahlman fixed autoirq, added multicast - . 02/01/96 Erik Stahlman 1. disabled all interrupts in smc_reset - . 2. got rid of post-decrementing bug -- UGH. - . 02/13/96 Erik Stahlman Tried to fix autoirq failure. Added more - . descriptive error messages. - . 02/15/96 Erik Stahlman Fixed typo that caused detection failure - . 02/23/96 Erik Stahlman Modified it to fit into kernel tree - . Added support to change hardware address - . Cleared stats on opens - . 02/26/96 Erik Stahlman Trial support for Kernel 1.2.13 - . Kludge for automatic IRQ detection - . 03/04/96 Erik Stahlman Fixed kernel 1.3.70 + - . Fixed bug reported by Gardner Buchanan in - . smc_enable, with outw instead of outb - . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert - . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory - . allocation - . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet - . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" - . 11/08/01 Matt Domsch Use common crc32 function - -------------------------------------------------------------------------= ---*/ - -static const char version[] =3D - "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "smc9194.h" - -#define DRV_NAME "smc9194" - -/*------------------------------------------------------------------------ - . - . Configuration options, for the experienced user to change. - . - -------------------------------------------------------------------------= */ - -/* - . Do you want to use 32 bit xfers? This should work on all chips, as - . the chipset is designed to accommodate them. -*/ -#ifdef __sh__ -#undef USE_32_BIT -#else -#define USE_32_BIT 1 -#endif - -/* - .the SMC9194 can be at any of the following port addresses. To change, - .for a slightly different card, you can add it to the array. Keep in - .mind that the array must end in zero. -*/ - -struct devlist { - unsigned int port; - unsigned int irq; -}; - -static struct devlist smc_devlist[] __initdata =3D { - {.port =3D 0x200, .irq =3D 0}, - {.port =3D 0x220, .irq =3D 0}, - {.port =3D 0x240, .irq =3D 0}, - {.port =3D 0x260, .irq =3D 0}, - {.port =3D 0x280, .irq =3D 0}, - {.port =3D 0x2A0, .irq =3D 0}, - {.port =3D 0x2C0, .irq =3D 0}, - {.port =3D 0x2E0, .irq =3D 0}, - {.port =3D 0x300, .irq =3D 0}, - {.port =3D 0x320, .irq =3D 0}, - {.port =3D 0x340, .irq =3D 0}, - {.port =3D 0x360, .irq =3D 0}, - {.port =3D 0x380, .irq =3D 0}, - {.port =3D 0x3A0, .irq =3D 0}, - {.port =3D 0x3C0, .irq =3D 0}, - {.port =3D 0x3E0, .irq =3D 0}, - {.port =3D 0, .irq =3D 0}, -}; -/* - . Wait time for memory to be free. This probably shouldn't be - . tuned that much, as waiting for this means nothing else happens - . in the system -*/ -#define MEMORY_WAIT_TIME 16 - -/* - . DEBUGGING LEVELS - . - . 0 for normal operation - . 1 for slightly more details - . >2 for various levels of increasingly useless information - . 2 for interrupt tracking, status flags - . 3 for packet dumps, etc. -*/ -#define SMC_DEBUG 0 - -#if (SMC_DEBUG > 2 ) -#define PRINTK3(x) printk x -#else -#define PRINTK3(x) -#endif - -#if SMC_DEBUG > 1 -#define PRINTK2(x) printk x -#else -#define PRINTK2(x) -#endif - -#ifdef SMC_DEBUG -#define PRINTK(x) printk x -#else -#define PRINTK(x) -#endif - - -/*------------------------------------------------------------------------ - . - . The internal workings of the driver. If you are changing anything - . here with the SMC stuff, you should have the datasheet and known - . what you are doing. - . - -------------------------------------------------------------------------= */ -#define CARDNAME "SMC9194" - - -/* store this information for the driver.. */ -struct smc_local { - /* - If I have to wait until memory is available to send - a packet, I will store the skbuff here, until I get the - desired memory. Then, I'll send it out and free it. - */ - struct sk_buff * saved_skb; - - /* - . This keeps track of how many packets that I have - . sent out. When an TX_EMPTY interrupt comes, I know - . that all of these have been sent. - */ - int packets_waiting; -}; - - -/*----------------------------------------------------------------- - . - . The driver can be entered at any of the following entry points. - . - .------------------------------------------------------------------ */ - -/* - . This is called by register_netdev(). It is responsible for - . checking the portlist for the SMC9000 series chipset. If it finds - . one, then it will initialize the device, find the hardware information, - . and sets up the appropriate device parameters. - . NOTE: Interrupts are *OFF* when this procedure is called. - . - . NB:This shouldn't be static since it is referred to externally. -*/ -struct net_device *smc_init(int unit); - -/* - . The kernel calls this function when someone wants to use the device, - . typically 'ifconfig ethX up'. -*/ -static int smc_open(struct net_device *dev); - -/* - . Our watchdog timed out. Called by the networking layer -*/ -static void smc_timeout(struct net_device *dev, unsigned int txqueue); - -/* - . This is called by the kernel in response to 'ifconfig ethX down'. It - . is responsible for cleaning up everything that the open routine - . does, and maybe putting the card into a powerdown state. -*/ -static int smc_close(struct net_device *dev); - -/* - . Finally, a call to set promiscuous mode ( for TCPDUMP and related - . programs ) and multicast modes. -*/ -static void smc_set_multicast_list(struct net_device *dev); - - -/*--------------------------------------------------------------- - . - . Interrupt level calls.. - . - ----------------------------------------------------------------*/ - -/* - . Handles the actual interrupt -*/ -static irqreturn_t smc_interrupt(int irq, void *); -/* - . This is a separate procedure to handle the receipt of a packet, to - . leave the interrupt code looking slightly cleaner -*/ -static inline void smc_rcv( struct net_device *dev ); -/* - . This handles a TX interrupt, which is only called when an error - . relating to a packet is sent. -*/ -static inline void smc_tx( struct net_device * dev ); - -/* - ------------------------------------------------------------ - . - . Internal routines - . - ------------------------------------------------------------ -*/ - -/* - . Test if a given location contains a chip, trying to cause as - . little damage as possible if it's not a SMC chip. -*/ -static int smc_probe(struct net_device *dev, int ioaddr); - -/* - . A rather simple routine to print out a packet for debugging purposes. -*/ -#if SMC_DEBUG > 2 -static void print_packet( byte *, int ); -#endif - -#define tx_done(dev) 1 - -/* this is called to actually send the packet to the chip */ -static void smc_hardware_send_packet( struct net_device * dev ); - -/* Since I am not sure if I will have enough room in the chip's ram - . to store the packet, I call this routine, which either sends it - . now, or generates an interrupt when the card is ready for the - . packet */ -static netdev_tx_t smc_wait_to_send_packet( struct sk_buff * skb, - struct net_device *dev ); - -/* this does a soft reset on the device */ -static void smc_reset( int ioaddr ); - -/* Enable Interrupts, Receive, and Transmit */ -static void smc_enable( int ioaddr ); - -/* this puts the device in an inactive state */ -static void smc_shutdown( int ioaddr ); - -/* This routine will find the IRQ of the driver if one is not - . specified in the input to the device. */ -static int smc_findirq( int ioaddr ); - -/* - . Function: smc_reset( int ioaddr ) - . Purpose: - . This sets the SMC91xx chip to its normal state, hopefully from whatev= er - . mess that any other DOS driver has put it in. - . - . Maybe I should reset more registers to defaults in here? SOFTRESET sh= ould - . do that for me. - . - . Method: - . 1. send a SOFT RESET - . 2. wait for it to finish - . 3. enable autorelease mode - . 4. reset the memory management unit - . 5. clear all interrupts - . -*/ -static void smc_reset( int ioaddr ) -{ - /* This resets the registers mostly to defaults, but doesn't - affect EEPROM. That seems unnecessary */ - SMC_SELECT_BANK( 0 ); - outw( RCR_SOFTRESET, ioaddr + RCR ); - - /* this should pause enough for the chip to be happy */ - SMC_DELAY( ); - - /* Set the transmit and receive configuration registers to - default values */ - outw( RCR_CLEAR, ioaddr + RCR ); - outw( TCR_CLEAR, ioaddr + TCR ); - - /* set the control register to automatically - release successfully transmitted packets, to make the best - use out of our limited memory */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); - - /* Reset the MMU */ - SMC_SELECT_BANK( 2 ); - outw( MC_RESET, ioaddr + MMU_CMD ); - - /* Note: It doesn't seem that waiting for the MMU busy is needed here, - but this is a place where future chipsets _COULD_ break. Be wary - of issuing another MMU command right after this */ - - outb( 0, ioaddr + INT_MASK ); -} - -/* - . Function: smc_enable - . Purpose: let the chip talk to the outside work - . Method: - . 1. Enable the transmitter - . 2. Enable the receiver - . 3. Enable interrupts -*/ -static void smc_enable( int ioaddr ) -{ - SMC_SELECT_BANK( 0 ); - /* see the header file for options in TCR/RCR NORMAL*/ - outw( TCR_NORMAL, ioaddr + TCR ); - outw( RCR_NORMAL, ioaddr + RCR ); - - /* now, enable interrupts */ - SMC_SELECT_BANK( 2 ); - outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK ); -} - -/* - . Function: smc_shutdown - . Purpose: closes down the SMC91xxx chip. - . Method: - . 1. zero the interrupt mask - . 2. clear the enable receive flag - . 3. clear the enable xmit flags - . - . TODO: - . (1) maybe utilize power down mode. - . Why not yet? Because while the chip will go into power down mode, - . the manual says that it will wake up in response to any I/O requests - . in the register space. Empirical results do not show this working. -*/ -static void smc_shutdown( int ioaddr ) -{ - /* no more interrupts for me */ - SMC_SELECT_BANK( 2 ); - outb( 0, ioaddr + INT_MASK ); - - /* and tell the card to stay away from that nasty outside world */ - SMC_SELECT_BANK( 0 ); - outb( RCR_CLEAR, ioaddr + RCR ); - outb( TCR_CLEAR, ioaddr + TCR ); -#if 0 - /* finally, shut the chip down */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL ); -#endif -} - - -/* - . Function: smc_setmulticast( int ioaddr, struct net_device *dev ) - . Purpose: - . This sets the internal hardware table to filter out unwanted multica= st - . packets before they take up memory. - . - . The SMC chip uses a hash table where the high 6 bits of the CRC of - . address are the offset into the table. If that bit is 1, then the - . multicast packet is accepted. Otherwise, it's dropped silently. - . - . To use the 6 bits as an offset into the table, the high 3 bits are t= he - . number of the 8 bit register, while the low 3 bits are the bit within - . that register. - . - . This routine is based very heavily on the one provided by Peter Cammaer= t. -*/ - - -static void smc_setmulticast(int ioaddr, struct net_device *dev) -{ - int i; - unsigned char multicast_table[ 8 ]; - struct netdev_hw_addr *ha; - /* table for flipping the order of 3 bits */ - unsigned char invert3[] =3D { 0, 4, 2, 6, 1, 5, 3, 7 }; - - /* start with a table of all zeros: reject all */ - memset( multicast_table, 0, sizeof( multicast_table ) ); - - netdev_for_each_mc_addr(ha, dev) { - int position; - - /* only use the low order bits */ - position =3D ether_crc_le(6, ha->addr) & 0x3f; - - /* do some messy swapping to put the bit in the right spot */ - multicast_table[invert3[position&7]] |=3D - (1<>3)&7]); - - } - /* now, the table can be loaded into the chipset */ - SMC_SELECT_BANK( 3 ); - - for ( i =3D 0; i < 8 ; i++ ) { - outb( multicast_table[i], ioaddr + MULTICAST1 + i ); - } -} - -/* - . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_dev= ice * ) - . Purpose: - . Attempt to allocate memory for a packet, if chip-memory is not - . available, then tell the card to generate an interrupt when it - . is available. - . - . Algorithm: - . - . o if the saved_skb is not currently null, then drop this packet - . on the floor. This should never happen, because of TBUSY. - . o if the saved_skb is null, then replace it with the current packet, - . o See if I can sending it now. - . o (NO): Enable interrupts and let the interrupt handler deal with it. - . o (YES):Send it now. -*/ -static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct smc_local *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - word length; - unsigned short numPages; - word time_out; - - netif_stop_queue(dev); - /* Well, I want to send the packet.. but I don't know - if I can send it right now... */ - - if ( lp->saved_skb) { - /* THIS SHOULD NEVER HAPPEN. */ - dev->stats.tx_aborted_errors++; - printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); - return NETDEV_TX_BUSY; - } - lp->saved_skb =3D skb; - - length =3D skb->len; - - if (length < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) { - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - length =3D ETH_ZLEN; - } - - /* - ** The MMU wants the number of pages to be the number of 256 bytes - ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) - ** - ** Pkt size for allocating is data length +6 (for additional status words, - ** length and ctl!) If odd size last byte is included in this header. - */ - numPages =3D ((length & 0xfffe) + 6) / 256; - - if (numPages > 7 ) { - printk(CARDNAME": Far too big packet error.\n"); - /* freeing the packet is a good thing here... but should - . any packets of this size get down here? */ - dev_kfree_skb (skb); - lp->saved_skb =3D NULL; - /* this IS an error, but, i don't want the skb saved */ - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - /* either way, a packet is waiting now */ - lp->packets_waiting++; - - /* now, try to allocate the memory */ - SMC_SELECT_BANK( 2 ); - outw( MC_ALLOC | numPages, ioaddr + MMU_CMD ); - /* - . Performance Hack - . - . wait a short amount of time.. if I can send a packet now, I send - . it now. Otherwise, I enable an interrupt and wait for one to be - . available. - . - . I could have handled this a slightly different way, by checking to - . see if any memory was available in the FREE MEMORY register. However, - . either way, I need to generate an allocation, and the allocation works - . no matter what, so I saw no point in checking free memory. - */ - time_out =3D MEMORY_WAIT_TIME; - do { - word status; - - status =3D inb( ioaddr + INTERRUPT ); - if ( status & IM_ALLOC_INT ) { - /* acknowledge the interrupt */ - outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); - break; - } - } while ( -- time_out ); - - if ( !time_out ) { - /* oh well, wait until the chip finds memory later */ - SMC_ENABLE_INT( IM_ALLOC_INT ); - PRINTK2((CARDNAME": memory allocation deferred.\n")); - /* it's deferred, but I'll handle it later */ - return NETDEV_TX_OK; - } - /* or YES! I can send the packet now.. */ - smc_hardware_send_packet(dev); - netif_wake_queue(dev); - return NETDEV_TX_OK; -} - -/* - . Function: smc_hardware_send_packet(struct net_device * ) - . Purpose: - . This sends the actual packet to the SMC9xxx chip. - . - . Algorithm: - . First, see if a saved_skb is available. - . ( this should NOT be called if there is no 'saved_skb' - . Now, find the packet number that the chip allocated - . Point the data pointers at it in memory - . Set the length word in the chip's memory - . Dump the packet to chip memory - . Check if a last byte is needed ( odd length packet ) - . if so, set the control flag right - . Tell the card to send it - . Enable the transmit interrupt, so I know if it failed - . Free the kernel data if I actually sent it. -*/ -static void smc_hardware_send_packet( struct net_device * dev ) -{ - struct smc_local *lp =3D netdev_priv(dev); - byte packet_no; - struct sk_buff * skb =3D lp->saved_skb; - word length; - unsigned int ioaddr; - byte * buf; - - ioaddr =3D dev->base_addr; - - if ( !skb ) { - PRINTK((CARDNAME": In XMIT with no packet to send\n")); - return; - } - length =3D ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buf =3D skb->data; - - /* If I get here, I _know_ there is a packet slot waiting for me */ - packet_no =3D inb( ioaddr + PNR_ARR + 1 ); - if ( packet_no & 0x80 ) { - /* or isn't there? BAD CHIP! */ - netdev_dbg(dev, CARDNAME": Memory allocation failed.\n"); - dev_kfree_skb_any(skb); - lp->saved_skb =3D NULL; - netif_wake_queue(dev); - return; - } - - /* we have a packet address, so tell the card to use it */ - outb( packet_no, ioaddr + PNR_ARR ); - - /* point to the beginning of the packet */ - outw( PTR_AUTOINC , ioaddr + POINTER ); - - PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length)); -#if SMC_DEBUG > 2 - print_packet( buf, length ); -#endif - - /* send the packet length ( +6 for status, length and ctl byte ) - and the status word ( set to zeros ) */ -#ifdef USE_32_BIT - outl( (length +6 ) << 16 , ioaddr + DATA_1 ); -#else - outw( 0, ioaddr + DATA_1 ); - /* send the packet length ( +6 for status words, length, and ctl*/ - outb( (length+6) & 0xFF,ioaddr + DATA_1 ); - outb( (length+6) >> 8 , ioaddr + DATA_1 ); -#endif - - /* send the actual data - . I _think_ it's faster to send the longs first, and then - . mop up by sending the last word. It depends heavily - . on alignment, at least on the 486. Maybe it would be - . a good idea to check which is optimal? But that could take - . almost as much time as is saved? - */ -#ifdef USE_32_BIT - if ( length & 0x2 ) { - outsl(ioaddr + DATA_1, buf, length >> 2 ); - outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); - } - else - outsl(ioaddr + DATA_1, buf, length >> 2 ); -#else - outsw(ioaddr + DATA_1 , buf, (length ) >> 1); -#endif - /* Send the last byte, if there is one. */ - - if ( (length & 1) =3D=3D 0 ) { - outw( 0, ioaddr + DATA_1 ); - } else { - outb( buf[length -1 ], ioaddr + DATA_1 ); - outb( 0x20, ioaddr + DATA_1); - } - - /* enable the interrupts */ - SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); - - /* and let the chipset deal with it */ - outw( MC_ENQUEUE , ioaddr + MMU_CMD ); - - PRINTK2((CARDNAME": Sent packet of length %d\n", length)); - - lp->saved_skb =3D NULL; - dev_kfree_skb_any (skb); - - netif_trans_update(dev); - - /* we can send another packet */ - netif_wake_queue(dev); -} - -/*------------------------------------------------------------------------- - | - | smc_init(int unit) - | Input parameters: - | dev->base_addr =3D=3D 0, try to find all possible locations - | dev->base_addr =3D=3D 1, return failure code - | dev->base_addr =3D=3D 2, always allocate space, and return success - | dev->base_addr =3D=3D this is the address to check - | - | Output: - | pointer to net_device or ERR_PTR(error) - | - -------------------------------------------------------------------------= -- -*/ -static int io; -static int irq; -static int ifport; - -struct net_device * __init smc_init(int unit) -{ - struct net_device *dev =3D alloc_etherdev(sizeof(struct smc_local)); - struct devlist *smcdev =3D smc_devlist; - int err =3D 0; - - if (!dev) - return ERR_PTR(-ENODEV); - - if (unit >=3D 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - io =3D dev->base_addr; - irq =3D dev->irq; - } - - if (io > 0x1ff) { /* Check a single specified location. */ - err =3D smc_probe(dev, io); - } else if (io !=3D 0) { /* Don't probe at all. */ - err =3D -ENXIO; - } else { - for (;smcdev->port; smcdev++) { - if (smc_probe(dev, smcdev->port) =3D=3D 0) - break; - } - if (!smcdev->port) - err =3D -ENODEV; - } - if (err) - goto out; - err =3D register_netdev(dev); - if (err) - goto out1; - return dev; -out1: - free_irq(dev->irq, dev); - release_region(dev->base_addr, SMC_IO_EXTENT); -out: - free_netdev(dev); - return ERR_PTR(err); -} - -/*---------------------------------------------------------------------- - . smc_findirq - . - . This routine has a simple purpose -- make the SMC chip generate an - . interrupt, so an auto-detect routine can detect it, and find the IRQ, - ------------------------------------------------------------------------ -*/ -static int __init smc_findirq(int ioaddr) -{ -#ifndef NO_AUTOPROBE - int timeout =3D 20; - unsigned long cookie; - - - cookie =3D probe_irq_on(); - - /* - * What I try to do here is trigger an ALLOC_INT. This is done - * by allocating a small chunk of memory, which will give an interrupt - * when done. - */ - - - SMC_SELECT_BANK(2); - /* enable ALLOCation interrupts ONLY */ - outb( IM_ALLOC_INT, ioaddr + INT_MASK ); - - /* - . Allocate 512 bytes of memory. Note that the chip was just - . reset so all the memory is available - */ - outw( MC_ALLOC | 1, ioaddr + MMU_CMD ); - - /* - . Wait until positive that the interrupt has been generated - */ - while ( timeout ) { - byte int_status; - - int_status =3D inb( ioaddr + INTERRUPT ); - - if ( int_status & IM_ALLOC_INT ) - break; /* got the interrupt */ - timeout--; - } - /* there is really nothing that I can do here if timeout fails, - as probe_irq_off will return a 0 anyway, which is what I - want in this case. Plus, the clean up is needed in both - cases. */ - - /* DELAY HERE! - On a fast machine, the status might change before the interrupt - is given to the processor. This means that the interrupt was - never detected, and probe_irq_off fails to report anything. - This should fix probe_irq_* problems. - */ - SMC_DELAY(); - SMC_DELAY(); - - /* and disable all interrupts again */ - outb( 0, ioaddr + INT_MASK ); - - /* and return what I found */ - return probe_irq_off(cookie); -#else /* NO_AUTOPROBE */ - struct devlist *smcdev; - for (smcdev =3D smc_devlist; smcdev->port; smcdev++) { - if (smcdev->port =3D=3D ioaddr) - return smcdev->irq; - } - return 0; -#endif -} - -static const struct net_device_ops smc_netdev_ops =3D { - .ndo_open =3D smc_open, - .ndo_stop =3D smc_close, - .ndo_start_xmit =3D smc_wait_to_send_packet, - .ndo_tx_timeout =3D smc_timeout, - .ndo_set_rx_mode =3D smc_set_multicast_list, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - -/*---------------------------------------------------------------------- - . Function: smc_probe( int ioaddr ) - . - . Purpose: - . Tests to see if a given ioaddr points to an SMC9xxx chip. - . Returns a 0 on success - . - . Algorithm: - . (1) see if the high byte of BANK_SELECT is 0x33 - . (2) compare the ioaddr with the base register's address - . (3) see if I recognize the chip ID in the appropriate register - . - .--------------------------------------------------------------------- - */ - -/*--------------------------------------------------------------- - . Here I do typical initialization tasks. - . - . o Initialize the structure if needed - . o print out my vanity message if not done so already - . o print out what type of hardware is detected - . o print out the ethernet address - . o find the IRQ - . o set up my private data - . o configure the dev structure with my subroutines - . o actually GRAB the irq. - . o GRAB the region - .----------------------------------------------------------------- -*/ -static int __init smc_probe(struct net_device *dev, int ioaddr) -{ - int i, memory, retval; - unsigned int bank; - - const char *version_string; - const char *if_string; - - /* registers */ - word revision_register; - word base_address_register; - word configuration_register; - word memory_info_register; - word memory_cfg_register; - u8 addr[ETH_ALEN]; - - /* Grab the region so that no one else tries to probe our ioports. */ - if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) - return -EBUSY; - - dev->irq =3D irq; - dev->if_port =3D ifport; - - /* First, see if the high byte is 0x33 */ - bank =3D inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00) !=3D 0x3300 ) { - retval =3D -ENODEV; - goto err_out; - } - /* The above MIGHT indicate a device, but I need to write to further - test this. */ - outw( 0x0, ioaddr + BANK_SELECT ); - bank =3D inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00 ) !=3D 0x3300 ) { - retval =3D -ENODEV; - goto err_out; - } - /* well, we've already written once, so hopefully another time won't - hurt. This time, I need to switch the bank register to bank 1, - so I can access the base address register */ - SMC_SELECT_BANK(1); - base_address_register =3D inw( ioaddr + BASE ); - if ( ioaddr !=3D ( base_address_register >> 3 & 0x3E0 ) ) { - printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). " - "Probably not a SMC chip\n", - ioaddr, base_address_register >> 3 & 0x3E0 ); - /* well, the base address register didn't match. Must not have - been a SMC chip after all. */ - retval =3D -ENODEV; - goto err_out; - } - - /* check if the revision register is something that I recognize. - These might need to be added to later, as future revisions - could be added. */ - SMC_SELECT_BANK(3); - revision_register =3D inw( ioaddr + REVISION ); - if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { - /* I don't recognize this chip, so... */ - printk(CARDNAME ": IO %x: Unrecognized revision register:" - " %x, Contact author.\n", ioaddr, revision_register); - - retval =3D -ENODEV; - goto err_out; - } - - /* at this point I'll assume that the chip is an SMC9xxx. - It might be prudent to check a listing of MAC addresses - against the hardware address, or do some other tests. */ - - pr_info_once("%s\n", version); - - /* fill in some of the fields */ - dev->base_addr =3D ioaddr; - - /* - . Get the MAC address ( bank 1, regs 4 - 9 ) - */ - SMC_SELECT_BANK( 1 ); - for ( i =3D 0; i < 6; i +=3D 2 ) { - word address; - - address =3D inw( ioaddr + ADDR0 + i ); - addr[i + 1] =3D address >> 8; - addr[i] =3D address & 0xFF; - } - eth_hw_addr_set(dev, addr); - - /* get the memory information */ - - SMC_SELECT_BANK( 0 ); - memory_info_register =3D inw( ioaddr + MIR ); - memory_cfg_register =3D inw( ioaddr + MCR ); - memory =3D ( memory_cfg_register >> 9 ) & 0x7; /* multiplier */ - memory *=3D 256 * ( memory_info_register & 0xFF ); - - /* - Now, I want to find out more about the chip. This is sort of - redundant, but it's cleaner to have it in both, rather than having - one VERY long probe procedure. - */ - SMC_SELECT_BANK(3); - revision_register =3D inw( ioaddr + REVISION ); - version_string =3D chip_ids[ ( revision_register >> 4 ) & 0xF ]; - if ( !version_string ) { - /* I shouldn't get here because this call was done before.... */ - retval =3D -ENODEV; - goto err_out; - } - - /* is it using AUI or 10BaseT ? */ - if ( dev->if_port =3D=3D 0 ) { - SMC_SELECT_BANK(1); - configuration_register =3D inw( ioaddr + CONFIG ); - if ( configuration_register & CFG_AUI_SELECT ) - dev->if_port =3D 2; - else - dev->if_port =3D 1; - } - if_string =3D interfaces[ dev->if_port - 1 ]; - - /* now, reset the chip, and put it into a known state */ - smc_reset( ioaddr ); - - /* - . If dev->irq is 0, then the device has to be banged on to see - . what the IRQ is. - . - . This banging doesn't always detect the IRQ, for unknown reasons. - . a workaround is to reset the chip and try again. - . - . Interestingly, the DOS packet driver *SETS* the IRQ on the card to - . be what is requested on the command line. I don't do that, mostly - . because the card that I have uses a non-standard method of accessing - . the IRQs, and because this _should_ work in most configurations. - . - . Specifying an IRQ is done with the assumption that the user knows - . what (s)he is doing. No checking is done!!!! - . - */ - if ( dev->irq < 2 ) { - int trials; - - trials =3D 3; - while ( trials-- ) { - dev->irq =3D smc_findirq( ioaddr ); - if ( dev->irq ) - break; - /* kick the card and try again */ - smc_reset( ioaddr ); - } - } - if (dev->irq =3D=3D 0 ) { - printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=3Dxx.\n"); - retval =3D -ENODEV; - goto err_out; - } - - /* now, print out the card info, in a short format.. */ - - netdev_info(dev, "%s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", - version_string, revision_register & 0xF, ioaddr, dev->irq, - if_string, memory); - /* - . Print the Ethernet address - */ - netdev_info(dev, "ADDR: %pM\n", dev->dev_addr); - - /* Grab the IRQ */ - retval =3D request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev); - if (retval) { - netdev_warn(dev, "%s: unable to get IRQ %d (irqval=3D%d).\n", - DRV_NAME, dev->irq, retval); - goto err_out; - } - - dev->netdev_ops =3D &smc_netdev_ops; - dev->watchdog_timeo =3D HZ/20; - - return 0; - -err_out: - release_region(ioaddr, SMC_IO_EXTENT); - return retval; -} - -#if SMC_DEBUG > 2 -static void print_packet( byte * buf, int length ) -{ -#if 0 - print_hex_dump_debug(DRV_NAME, DUMP_PREFIX_OFFSET, 16, 1, - buf, length, true); -#endif -} -#endif - - -/* - * Open and Initialize the board - * - * Set up everything, reset the card, etc .. - * - */ -static int smc_open(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - - int i; /* used to set hw ethernet address */ - - /* clear out all the junk that was put here before... */ - memset(netdev_priv(dev), 0, sizeof(struct smc_local)); - - /* reset the hardware */ - - smc_reset( ioaddr ); - smc_enable( ioaddr ); - - /* Select which interface to use */ - - SMC_SELECT_BANK( 1 ); - if ( dev->if_port =3D=3D 1 ) { - outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT, - ioaddr + CONFIG ); - } - else if ( dev->if_port =3D=3D 2 ) { - outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT, - ioaddr + CONFIG ); - } - - /* - According to Becker, I have to set the hardware address - at this point, because the (l)user can set it with an - ioctl. Easily done... - */ - SMC_SELECT_BANK( 1 ); - for ( i =3D 0; i < 6; i +=3D 2 ) { - word address; - - address =3D dev->dev_addr[ i + 1 ] << 8 ; - address |=3D dev->dev_addr[ i ]; - outw( address, ioaddr + ADDR0 + i ); - } - - netif_start_queue(dev); - return 0; -} - -/*-------------------------------------------------------- - . Called by the kernel to send a packet out into the void - . of the net. This routine is largely based on - . skeleton.c, from Becker. - .-------------------------------------------------------- -*/ - -static void smc_timeout(struct net_device *dev, unsigned int txqueue) -{ - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - netdev_warn(dev, CARDNAME": transmit timed out, %s?\n", - tx_done(dev) ? "IRQ conflict" : "network cable problem"); - /* "kick" the adaptor */ - smc_reset( dev->base_addr ); - smc_enable( dev->base_addr ); - netif_trans_update(dev); /* prevent tx timeout */ - /* clear anything saved */ - ((struct smc_local *)netdev_priv(dev))->saved_skb =3D NULL; - netif_wake_queue(dev); -} - -/*------------------------------------------------------------- - . - . smc_rcv - receive a packet from the card - . - . There is ( at least ) a packet waiting to be read from - . chip-memory. - . - . o Read the status - . o If an error, record it - . o otherwise, read in the packet - -------------------------------------------------------------- -*/ -static void smc_rcv(struct net_device *dev) -{ - int ioaddr =3D dev->base_addr; - int packet_number; - word status; - word packet_length; - - /* assume bank 2 */ - - packet_number =3D inw( ioaddr + FIFO_PORTS ); - - if ( packet_number & FP_RXEMPTY ) { - /* we got called , but nothing was on the FIFO */ - PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO.\n")); - /* don't need to restore anything */ - return; - } - - /* start reading from the start of the packet */ - outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER ); - - /* First two words are status and packet_length */ - status =3D inw( ioaddr + DATA_1 ); - packet_length =3D inw( ioaddr + DATA_1 ); - - packet_length &=3D 0x07ff; /* mask off top bits */ - - PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length )); - /* - . the packet length contains 3 extra words : - . status, length, and an extra word with an odd byte . - */ - packet_length -=3D 6; - - if ( !(status & RS_ERRORS ) ){ - /* do stuff to make a new packet */ - struct sk_buff * skb; - byte * data; - - /* read one extra byte */ - if ( status & RS_ODDFRAME ) - packet_length++; - - /* set multicast stats */ - if ( status & RS_MULTICAST ) - dev->stats.multicast++; - - skb =3D netdev_alloc_skb(dev, packet_length + 5); - if ( skb =3D=3D NULL ) { - dev->stats.rx_dropped++; - goto done; - } - - /* - ! This should work without alignment, but it could be - ! in the worse case - */ - - skb_reserve( skb, 2 ); /* 16 bit alignment */ - - data =3D skb_put( skb, packet_length); - -#ifdef USE_32_BIT - /* QUESTION: Like in the TX routine, do I want - to send the DWORDs or the bytes first, or some - mixture. A mixture might improve already slow PIO - performance */ - PRINTK3((" Reading %d dwords (and %d bytes)\n", - packet_length >> 2, packet_length & 3 )); - insl(ioaddr + DATA_1 , data, packet_length >> 2 ); - /* read the left over bytes */ - insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC), - packet_length & 0x3 ); -#else - PRINTK3((" Reading %d words and %d byte(s)\n", - (packet_length >> 1 ), packet_length & 1 )); - insw(ioaddr + DATA_1 , data, packet_length >> 1); - if ( packet_length & 1 ) { - data +=3D packet_length & ~1; - *(data++) =3D inb( ioaddr + DATA_1 ); - } -#endif -#if SMC_DEBUG > 2 - print_packet( data, packet_length ); -#endif - - skb->protocol =3D eth_type_trans(skb, dev ); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D packet_length; - } else { - /* error ... */ - dev->stats.rx_errors++; - - if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++; - if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) - dev->stats.rx_length_errors++; - if ( status & RS_BADCRC) dev->stats.rx_crc_errors++; - } - -done: - /* error or good, tell the card to get rid of this packet */ - outw( MC_RELEASE, ioaddr + MMU_CMD ); -} - - -/************************************************************************* - . smc_tx - . - . Purpose: Handle a transmit error message. This will only be called - . when an error, because of the AUTO_RELEASE mode. - . - . Algorithm: - . Save pointer and packet no - . Get the packet no from the top of the queue - . check if it's valid ( if not, is this an error??? ) - . read the status word - . record the error - . ( resend? Not really, since we don't want old packets around ) - . Restore saved values - ************************************************************************/ -static void smc_tx( struct net_device * dev ) -{ - int ioaddr =3D dev->base_addr; - struct smc_local *lp =3D netdev_priv(dev); - byte saved_packet; - byte packet_no; - word tx_status; - - - /* assume bank 2 */ - - saved_packet =3D inb( ioaddr + PNR_ARR ); - packet_no =3D inw( ioaddr + FIFO_PORTS ); - packet_no &=3D 0x7F; - - /* select this as the packet to read from */ - outb( packet_no, ioaddr + PNR_ARR ); - - /* read the first word from this packet */ - outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER ); - - tx_status =3D inw( ioaddr + DATA_1 ); - PRINTK3((CARDNAME": TX DONE STATUS: %4x\n", tx_status)); - - dev->stats.tx_errors++; - if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++; - if ( tx_status & TS_LATCOL ) { - netdev_dbg(dev, CARDNAME": Late collision occurred on last xmit.\n"); - dev->stats.tx_window_errors++; - } -#if 0 - if ( tx_status & TS_16COL ) { ... } -#endif - - if ( tx_status & TS_SUCCESS ) { - netdev_info(dev, CARDNAME": Successful packet caused interrupt\n"); - } - /* re-enable transmit */ - SMC_SELECT_BANK( 0 ); - outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR ); - - /* kill the packet */ - SMC_SELECT_BANK( 2 ); - outw( MC_FREEPKT, ioaddr + MMU_CMD ); - - /* one less packet waiting for me */ - lp->packets_waiting--; - - outb( saved_packet, ioaddr + PNR_ARR ); -} - -/*-------------------------------------------------------------------- - . - . This is the main routine of the driver, to handle the device when - . it needs some attention. - . - . So: - . first, save state of the chipset - . branch off into routines to handle each case, and acknowledge - . each to the interrupt register - . and finally restore state. - . - ---------------------------------------------------------------------*/ - -static irqreturn_t smc_interrupt(int irq, void * dev_id) -{ - struct net_device *dev =3D dev_id; - int ioaddr =3D dev->base_addr; - struct smc_local *lp =3D netdev_priv(dev); - - byte status; - word card_stats; - byte mask; - int timeout; - /* state registers */ - word saved_bank; - word saved_pointer; - int handled =3D 0; - - - PRINTK3((CARDNAME": SMC interrupt started\n")); - - saved_bank =3D inw( ioaddr + BANK_SELECT ); - - SMC_SELECT_BANK(2); - saved_pointer =3D inw( ioaddr + POINTER ); - - mask =3D inb( ioaddr + INT_MASK ); - /* clear all interrupts */ - outb( 0, ioaddr + INT_MASK ); - - - /* set a timeout value, so I don't stay here forever */ - timeout =3D 4; - - PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x\n", mask)); - do { - /* read the status flag, and mask it */ - status =3D inb( ioaddr + INTERRUPT ) & mask; - if (!status ) - break; - - handled =3D 1; - - PRINTK3((KERN_WARNING CARDNAME - ": Handling interrupt status %x\n", status)); - - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - PRINTK2((KERN_WARNING CARDNAME - ": Receive Interrupt\n")); - smc_rcv(dev); - } else if (status & IM_TX_INT ) { - PRINTK2((KERN_WARNING CARDNAME - ": TX ERROR handled\n")); - smc_tx(dev); - outb(IM_TX_INT, ioaddr + INTERRUPT ); - } else if (status & IM_TX_EMPTY_INT ) { - /* update stats */ - SMC_SELECT_BANK( 0 ); - card_stats =3D inw( ioaddr + COUNTER ); - /* single collisions */ - dev->stats.collisions +=3D card_stats & 0xF; - card_stats >>=3D 4; - /* multiple collisions */ - dev->stats.collisions +=3D card_stats & 0xF; - - /* these are for when linux supports these statistics */ - - SMC_SELECT_BANK( 2 ); - PRINTK2((KERN_WARNING CARDNAME - ": TX_BUFFER_EMPTY handled\n")); - outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); - mask &=3D ~IM_TX_EMPTY_INT; - dev->stats.tx_packets +=3D lp->packets_waiting; - lp->packets_waiting =3D 0; - - } else if (status & IM_ALLOC_INT ) { - PRINTK2((KERN_DEBUG CARDNAME - ": Allocation interrupt\n")); - /* clear this interrupt so it doesn't happen again */ - mask &=3D ~IM_ALLOC_INT; - - smc_hardware_send_packet( dev ); - - /* enable xmit interrupts based on this */ - mask |=3D ( IM_TX_EMPTY_INT | IM_TX_INT ); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - - PRINTK2((CARDNAME": Handoff done successfully.\n")); - } else if (status & IM_RX_OVRN_INT ) { - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); - } else if (status & IM_EPH_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT\n")); - } else if (status & IM_ERCV_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT\n")); - outb( IM_ERCV_INT, ioaddr + INTERRUPT ); - } - } while ( timeout -- ); - - - /* restore state register */ - SMC_SELECT_BANK( 2 ); - outb( mask, ioaddr + INT_MASK ); - - PRINTK3((KERN_WARNING CARDNAME ": MASK is now %x\n", mask)); - outw( saved_pointer, ioaddr + POINTER ); - - SMC_SELECT_BANK( saved_bank ); - - PRINTK3((CARDNAME ": Interrupt done\n")); - return IRQ_RETVAL(handled); -} - - -/*---------------------------------------------------- - . smc_close - . - . this makes the board clean up everything that it can - . and not talk to the outside world. Caused by - . an 'ifconfig ethX down' - . - -----------------------------------------------------*/ -static int smc_close(struct net_device *dev) -{ - netif_stop_queue(dev); - /* clear everything */ - smc_shutdown( dev->base_addr ); - - /* Update the statistics here. */ - return 0; -} - -/*----------------------------------------------------------- - . smc_set_multicast_list - . - . This routine will, depending on the values passed to it, - . either make it accept multicast packets, go into - . promiscuous mode ( for TCPDUMP and cousins ) or accept - . a select set of multicast packets -*/ -static void smc_set_multicast_list(struct net_device *dev) -{ - short ioaddr =3D dev->base_addr; - - SMC_SELECT_BANK(0); - if ( dev->flags & IFF_PROMISC ) - outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR ); - -/* BUG? I never disable promiscuous mode if multicasting was turned on. - Now, I turn off promiscuous mode, but I don't do anything to multicasti= ng - when promiscuous mode is turned on. -*/ - - /* Here, I am setting this to accept all multicast packets. - I don't need to zero the multicast table, because the flag is - checked before the table is - */ - else if (dev->flags & IFF_ALLMULTI) - outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR ); - - /* We just get all multicast packets even if we only want them - . from one source. This will be changed at some future - . point. */ - else if (!netdev_mc_empty(dev)) { - /* support hardware multicasting */ - - /* be sure I get rid of flags I might have set */ - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); - /* NOTE: this has to set the bank, so make sure it is the - last thing called. The bank is set to zero at the top */ - smc_setmulticast(ioaddr, dev); - } - else { - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); - - /* - since I'm disabling all multicast entirely, I need to - clear the multicast list - */ - SMC_SELECT_BANK( 3 ); - outw( 0, ioaddr + MULTICAST1 ); - outw( 0, ioaddr + MULTICAST2 ); - outw( 0, ioaddr + MULTICAST3 ); - outw( 0, ioaddr + MULTICAST4 ); - } -} - -#ifdef MODULE - -static struct net_device *devSMC9194; -MODULE_DESCRIPTION("SMC 9194 Ethernet driver"); -MODULE_LICENSE("GPL"); - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param(ifport, int, 0); -MODULE_PARM_DESC(io, "SMC 99194 I/O base address"); -MODULE_PARM_DESC(irq, "SMC 99194 IRQ number"); -MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI= )"); - -static int __init smc_init_module(void) -{ - if (io =3D=3D 0) - printk(KERN_WARNING - CARDNAME": You shouldn't use auto-probing with insmod!\n" ); - - /* copy the parameters from insmod into the device structure */ - devSMC9194 =3D smc_init(-1); - return PTR_ERR_OR_ZERO(devSMC9194); -} -module_init(smc_init_module); - -static void __exit smc_cleanup_module(void) -{ - unregister_netdev(devSMC9194); - free_irq(devSMC9194->irq, devSMC9194); - release_region(devSMC9194->base_addr, SMC_IO_EXTENT); - free_netdev(devSMC9194); -} -module_exit(smc_cleanup_module); - -#endif /* MODULE */ --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9E2F3DDDA7; Tue, 21 Apr 2026 19:58:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801544; cv=none; b=rUJ17rlk+jZI2FqQL8tdbVrmHn5wxXOD17wm93PSetgsb2kchfurE4rzM+GzdwH9ixsMqE3r+pwLRuTN0TJPBIJhxVe9AFMOoWxg0D+Xg2mcGSMcb906yFzhsj0R3QAdM9U0iIQjCRuS4qIyyUUZgQMFY1CqjfZ1X2eSIdk9rXQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801544; c=relaxed/simple; bh=EBTpd3rn3+mbk5DlC25ZkdnYfP3KbgEi41HZ3a4tJFw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=D6t+tv0vgYWs4QgUtmcn1mpbf5sm9AxX+yLUKnMF+XpS7h3zE5RpIJpLgh8nlp5tk982mePWbf7UVDTJyqUwRLs0PJ3Qmo4JpR5rtC2AJLDNLrwfoU4RkkFWEhj/0gM7/N4++AEAReXND3Ym4gpLjnE6+BLLnewGCAqGe/aZQw4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=I/VznQ3t; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="I/VznQ3t" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=pkdpIeEFVwm2ve7KzUIIeNTrhXQ0hEZdmx3y4xkHamY=; b=I/ VznQ3tSOfaza0E8QXKA+8fJcguLMjxiVhky9AYshR1BZcBxITQZTBb5DhUF7o+4M9PWOu0M0Bg/Ny SI4Dyde9tRALmW2LFBXv9T9BEXUZjcb298xvqR9LCuzxr73hvYDIDIXHPhUMtcTUCJVDA8STxwVn/ czRXLdUmooWGLrE=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGow-00GwVc-0Z; Tue, 21 Apr 2026 21:31:42 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:13 -0500 Subject: [PATCH net 10/18] drivers: net: smsc: smc91c92: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-10-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=66083; i=andrew@lunn.ch; h=from:subject:message-id; bh=EBTpd3rn3+mbk5DlC25ZkdnYfP3KbgEi41HZ3a4tJFw=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CCfAXSSKryNQ7JGkq5YQ/jgHZA5d2dhBusr ELL4ejgpgCJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hCwQEACW7+CEAC/F1szFIk94FOfaiVIigGgpiAhhR9zukM8s2KwuGXR/9Lc1DCYNdGxShwO4sjn C4dSK5FCxuYwR9ZDEX6n57VehftoKYeWV52Traay57Xth+ekupyCxGgsqdm3ckxhCuClfW5Cbdl jH3qIZ499yBBwfrN6J3AcrpJzZAZpgDPVXBwFOAtC9SETEr6ws6UtNuOBqdoD2Al4Fn9c8ucm2F WQhJcnoKYCSm0zt2vfinAJDeL/iGueKZDeFZk1qLEd0c/zaE66CBG7Cjoip4aBsYOUsa1qrbSS3 4ByPVKhUNSOdCeDfo3TA7wZ0jRwbU+k2pACx+eRiZlcD9kRehmTPBbpeQcBBgFFctdKw19aEUp/ nceZ+GvrcEgl8slWyZFp7hKWwaBT1ddhABEv61T3CgJq1UbGgqwRL23R251janfB9XXfCMwtWqR ai4BChz8SCCSTyW6BgFAyd7+wA4cH2VD6jeToW+4d6wJY94AEszA04Bp8GcZum34p/nl91aQ56F Ux06FngfEM+jgPrFWCZ4ibSkapMxCIY96wNm+p+xCRrH5PhT3dA2YRrrNrdVNw+nowGHUAYuNMz mgN7ydkO1LE8HFZs222NuGgnvwQu8bn9kGMruD47OWkuxYTanShjp5SUFZ2aYVUF1O5ydw2xDjh L/eMEugs5zh/h/A== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The smc91c92 was written by David A Hinds in 1999. It is an PCMCIA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/smsc/Kconfig | 12 - drivers/net/ethernet/smsc/Makefile | 1 - drivers/net/ethernet/smsc/smc91c92_cs.c | 2059 ---------------------------= ---- 3 files changed, 2072 deletions(-) diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/= Kconfig index d25bbcc98854..66bca803b19c 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -37,18 +37,6 @@ config SMC91X The module will be called smc91x. If you want to compile it as a module, say M here and read . =20 -config PCMCIA_SMC91C92 - tristate "SMC 91Cxx PCMCIA support" - depends on PCMCIA && HAS_IOPORT - select CRC32 - select MII - help - Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA - (PC-card) Ethernet or Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called smc91c92_cs. If unsure, say N. - config EPIC100 tristate "SMC EtherPower II" depends on PCI diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc= /Makefile index afea0b94c2a4..ab6f03f7ba17 100644 --- a/drivers/net/ethernet/smsc/Makefile +++ b/drivers/net/ethernet/smsc/Makefile @@ -4,7 +4,6 @@ # =20 obj-$(CONFIG_SMC91X) +=3D smc91x.o -obj-$(CONFIG_PCMCIA_SMC91C92) +=3D smc91c92_cs.o obj-$(CONFIG_EPIC100) +=3D epic100.o obj-$(CONFIG_SMSC9420) +=3D smsc9420.o obj-$(CONFIG_SMSC911X) +=3D smsc911x.o diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet= /smsc/smc91c92_cs.c deleted file mode 100644 index cc0c75694351..000000000000 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ /dev/null @@ -1,2059 +0,0 @@ -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - A PCMCIA ethernet driver for SMC91c92-based cards. - - This driver supports Megahertz PCMCIA ethernet cards; and - Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem - multifunction cards. - - Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - - smc91c92_cs.c 1.122 2002/10/25 06:26:39 - - This driver contains code written by Donald Becker - (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au), - David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman - (erik@vt.edu). Donald wrote the SMC 91c92 code using parts of - Erik's SMC 91c94 driver. Rowan wrote a similar driver, and I've - incorporated some parts of his driver here. I (Dave) wrote most - of the PCMCIA glue code, and the Ositech support code. Kelly - Stephens (kstephen@holli.com) added support for the Motorola - Mariner, with help from Allen Brost. - - This software may be used and distributed according to the terms of - the GNU General Public License, incorporated herein by reference. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static const char *if_names[] =3D { "auto", "10baseT", "10base2"}; - -/* Firmware name */ -#define FIRMWARE_NAME "ositech/Xilinx7OD.bin" - -/* Module parameters */ - -MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FIRMWARE_NAME); - -#define INT_MODULE_PARM(n, v) static int n =3D v; module_param(n, int, 0) - -/* - Transceiver/media type. - 0 =3D auto - 1 =3D 10baseT (and autoselect if #define AUTOSELECT), - 2 =3D AUI/10base2, -*/ -INT_MODULE_PARM(if_port, 0); - - -#define DRV_NAME "smc91c92_cs" -#define DRV_VERSION "1.123" - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Operational parameter that usually are not changed. */ - -/* Time in jiffies before concluding Tx hung */ -#define TX_TIMEOUT ((400*HZ)/1000) - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -#define INTR_WORK 4 - -/* Times to check the check the chip before concluding that it doesn't - currently have room for another Tx packet. */ -#define MEMORY_WAIT_TIME 8 - -struct smc_private { - struct pcmcia_device *p_dev; - spinlock_t lock; - u_short manfid; - u_short cardid; - - struct sk_buff *saved_skb; - int packets_waiting; - void __iomem *base; - u_short cfg; - struct timer_list media; - int watchdog, tx_err; - u_short media_status; - u_short fast_poll; - u_short link_status; - struct mii_if_info mii_if; - int duplex; - int rx_ovrn; - unsigned long last_rx; -}; - -/* Special definitions for Megahertz multifunction cards */ -#define MEGAHERTZ_ISR 0x0380 - -/* Special function registers for Motorola Mariner */ -#define MOT_LAN 0x0000 -#define MOT_UART 0x0020 -#define MOT_EEPROM 0x20 - -#define MOT_NORMAL \ -(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA) - -/* Special function registers for Ositech cards */ -#define OSITECH_AUI_CTL 0x0c -#define OSITECH_PWRDOWN 0x0d -#define OSITECH_RESET 0x0e -#define OSITECH_ISR 0x0f -#define OSITECH_AUI_PWR 0x0c -#define OSITECH_RESET_ISR 0x0e - -#define OSI_AUI_PWR 0x40 -#define OSI_LAN_PWRDOWN 0x02 -#define OSI_MODEM_PWRDOWN 0x01 -#define OSI_LAN_RESET 0x02 -#define OSI_MODEM_RESET 0x01 - -/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */ -#define BANK_SELECT 14 /* Window select register. */ -#define SMC_SELECT_BANK(x) { outw(x, ioaddr + BANK_SELECT); } - -/* Bank 0 registers. */ -#define TCR 0 /* transmit control register */ -#define TCR_CLEAR 0 /* do NOTHING */ -#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */ -#define TCR_PAD_EN 0x0080 /* pads short packets to 64 bytes */ -#define TCR_MONCSN 0x0400 /* Monitor Carrier. */ -#define TCR_FDUPLX 0x0800 /* Full duplex mode. */ -#define TCR_NORMAL TCR_ENABLE | TCR_PAD_EN - -#define EPH 2 /* Ethernet Protocol Handler report. */ -#define EPH_TX_SUC 0x0001 -#define EPH_SNGLCOL 0x0002 -#define EPH_MULCOL 0x0004 -#define EPH_LTX_MULT 0x0008 -#define EPH_16COL 0x0010 -#define EPH_SQET 0x0020 -#define EPH_LTX_BRD 0x0040 -#define EPH_TX_DEFR 0x0080 -#define EPH_LAT_COL 0x0200 -#define EPH_LOST_CAR 0x0400 -#define EPH_EXC_DEF 0x0800 -#define EPH_CTR_ROL 0x1000 -#define EPH_RX_OVRN 0x2000 -#define EPH_LINK_OK 0x4000 -#define EPH_TX_UNRN 0x8000 -#define MEMINFO 8 /* Memory Information Register */ -#define MEMCFG 10 /* Memory Configuration Register */ - -/* Bank 1 registers. */ -#define CONFIG 0 -#define CFG_MII_SELECT 0x8000 /* 91C100 only */ -#define CFG_NO_WAIT 0x1000 -#define CFG_FULL_STEP 0x0400 -#define CFG_SET_SQLCH 0x0200 -#define CFG_AUI_SELECT 0x0100 -#define CFG_16BIT 0x0080 -#define CFG_DIS_LINK 0x0040 -#define CFG_STATIC 0x0030 -#define CFG_IRQ_SEL_1 0x0004 -#define CFG_IRQ_SEL_0 0x0002 -#define BASE_ADDR 2 -#define ADDR0 4 -#define GENERAL 10 -#define CONTROL 12 -#define CTL_STORE 0x0001 -#define CTL_RELOAD 0x0002 -#define CTL_EE_SELECT 0x0004 -#define CTL_TE_ENABLE 0x0020 -#define CTL_CR_ENABLE 0x0040 -#define CTL_LE_ENABLE 0x0080 -#define CTL_AUTO_RELEASE 0x0800 -#define CTL_POWERDOWN 0x2000 - -/* Bank 2 registers. */ -#define MMU_CMD 0 -#define MC_ALLOC 0x20 /* or with number of 256 byte packets */ -#define MC_RESET 0x40 -#define MC_RELEASE 0x80 /* remove and release the current rx packet */ -#define MC_FREEPKT 0xA0 /* Release packet in PNR register */ -#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */ -#define PNR_ARR 2 -#define FIFO_PORTS 4 -#define FP_RXEMPTY 0x8000 -#define POINTER 6 -#define PTR_AUTO_INC 0x0040 -#define PTR_READ 0x2000 -#define PTR_AUTOINC 0x4000 -#define PTR_RCV 0x8000 -#define DATA_1 8 -#define INTERRUPT 12 -#define IM_RCV_INT 0x1 -#define IM_TX_INT 0x2 -#define IM_TX_EMPTY_INT 0x4 -#define IM_ALLOC_INT 0x8 -#define IM_RX_OVRN_INT 0x10 -#define IM_EPH_INT 0x20 - -#define RCR 4 -enum RxCfg { RxAllMulti =3D 0x0004, RxPromisc =3D 0x0002, - RxEnable =3D 0x0100, RxStripCRC =3D 0x0200}; -#define RCR_SOFTRESET 0x8000 /* resets the chip */ -#define RCR_STRIP_CRC 0x200 /* strips CRC */ -#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */ -#define RCR_ALMUL 0x4 /* receive all multicast packets */ -#define RCR_PROMISC 0x2 /* enable promiscuous mode */ - -/* the normal settings for the RCR register : */ -#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE) -#define RCR_CLEAR 0x0 /* set it to a base state */ -#define COUNTER 6 - -/* BANK 3 -- not the same values as in smc9194! */ -#define MULTICAST0 0 -#define MULTICAST2 2 -#define MULTICAST4 4 -#define MULTICAST6 6 -#define MGMT 8 -#define REVISION 0x0a - -/* Transmit status bits. */ -#define TS_SUCCESS 0x0001 -#define TS_16COL 0x0010 -#define TS_LATCOL 0x0200 -#define TS_LOSTCAR 0x0400 - -/* Receive status bits. */ -#define RS_ALGNERR 0x8000 -#define RS_BADCRC 0x2000 -#define RS_ODDFRAME 0x1000 -#define RS_TOOLONG 0x0800 -#define RS_TOOSHORT 0x0400 -#define RS_MULTICAST 0x0001 -#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) - -#define set_bits(v, p) outw(inw(p)|(v), (p)) -#define mask_bits(v, p) outw(inw(p)&(v), (p)) - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void smc91c92_detach(struct pcmcia_device *p_dev); -static int smc91c92_config(struct pcmcia_device *link); -static void smc91c92_release(struct pcmcia_device *link); - -static int smc_open(struct net_device *dev); -static int smc_close(struct net_device *dev); -static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue); -static netdev_tx_t smc_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t smc_interrupt(int irq, void *dev_id); -static void smc_rx(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static int s9k_config(struct net_device *dev, struct ifmap *map); -static void smc_set_xcvr(struct net_device *dev, int if_port); -static void smc_reset(struct net_device *dev); -static void media_check(struct timer_list *t); -static void mdio_sync(unsigned int addr); -static int mdio_read(struct net_device *dev, int phy_id, int loc); -static void mdio_write(struct net_device *dev, int phy_id, int loc, int va= lue); -static int smc_link_ok(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; - -static const struct net_device_ops smc_netdev_ops =3D { - .ndo_open =3D smc_open, - .ndo_stop =3D smc_close, - .ndo_start_xmit =3D smc_start_xmit, - .ndo_tx_timeout =3D smc_tx_timeout, - .ndo_set_config =3D s9k_config, - .ndo_set_rx_mode =3D set_rx_mode, - .ndo_eth_ioctl =3D smc_ioctl, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - -static int smc91c92_probe(struct pcmcia_device *link) -{ - struct smc_private *smc; - struct net_device *dev; - - dev_dbg(&link->dev, "smc91c92_attach()\n"); - - /* Create new ethernet device */ - dev =3D alloc_etherdev(sizeof(struct smc_private)); - if (!dev) - return -ENOMEM; - smc =3D netdev_priv(dev); - smc->p_dev =3D link; - link->priv =3D dev; - - spin_lock_init(&smc->lock); - - /* The SMC91c92-specific entries in the device structure. */ - dev->netdev_ops =3D &smc_netdev_ops; - dev->ethtool_ops =3D ðtool_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - - smc->mii_if.dev =3D dev; - smc->mii_if.mdio_read =3D mdio_read; - smc->mii_if.mdio_write =3D mdio_write; - smc->mii_if.phy_id_mask =3D 0x1f; - smc->mii_if.reg_num_mask =3D 0x1f; - - return smc91c92_config(link); -} /* smc91c92_attach */ - -static void smc91c92_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - dev_dbg(&link->dev, "smc91c92_detach\n"); - - unregister_netdev(dev); - - smc91c92_release(link); - - free_netdev(dev); -} /* smc91c92_detach */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int cvt_ascii_address(struct net_device *dev, char *s) -{ - u8 mac[ETH_ALEN]; - int i, j, da, c; - - if (strlen(s) !=3D 12) - return -1; - for (i =3D 0; i < 6; i++) { - da =3D 0; - for (j =3D 0; j < 2; j++) { - c =3D *s++; - da <<=3D 4; - da +=3D ((c >=3D '0') && (c <=3D '9')) ? - (c - '0') : ((c & 0x0f) + 9); - } - mac[i] =3D da; - } - eth_hw_addr_set(dev, mac); - return 0; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Configuration stuff for Megahertz cards - - mhz_3288_power() is used to power up a 3288's ethernet chip. - mhz_mfc_config() handles socket setup for multifunction (1144 - and 3288) cards. mhz_setup() gets a card's hardware ethernet - address. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int mhz_3288_power(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct smc_private *smc =3D netdev_priv(dev); - u_char tmp; - - /* Read the ISR twice... */ - readb(smc->base+MEGAHERTZ_ISR); - udelay(5); - readb(smc->base+MEGAHERTZ_ISR); - - /* Pause 200ms... */ - mdelay(200); - - /* Now read and write the COR... */ - tmp =3D readb(smc->base + link->config_base + CISREG_COR); - udelay(5); - writeb(tmp, smc->base + link->config_base + CISREG_COR); - - return 0; -} - -static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_da= ta) -{ - int k; - p_dev->io_lines =3D 16; - p_dev->resource[1]->start =3D p_dev->resource[0]->start; - p_dev->resource[1]->end =3D 8; - p_dev->resource[1]->flags &=3D ~IO_DATA_PATH_WIDTH; - p_dev->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end =3D 16; - p_dev->resource[0]->flags &=3D ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_AUTO; - for (k =3D 0; k < 0x400; k +=3D 0x10) { - if (k & 0x80) - continue; - p_dev->resource[0]->start =3D k ^ 0x300; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; -} - -static int mhz_mfc_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct smc_private *smc =3D netdev_priv(dev); - unsigned int offset; - int i; - - link->config_flags |=3D CONF_ENABLE_SPKR | CONF_ENABLE_IRQ | - CONF_AUTO_SET_IO; - - /* The Megahertz combo cards have modem-like CIS entries, so - we have to explicitly try a bunch of port combinations. */ - if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL)) - return -ENODEV; - - dev->base_addr =3D link->resource[0]->start; - - /* Allocate a memory window, for accessing the ISR */ - link->resource[2]->flags =3D WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_E= NABLE; - link->resource[2]->start =3D link->resource[2]->end =3D 0; - i =3D pcmcia_request_window(link, link->resource[2], 0); - if (i !=3D 0) - return -ENODEV; - - smc->base =3D ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - offset =3D (smc->manfid =3D=3D MANFID_MOTOROLA) ? link->config_base : = 0; - i =3D pcmcia_map_mem_page(link, link->resource[2], offset); - if ((i =3D=3D 0) && - (smc->manfid =3D=3D MANFID_MEGAHERTZ) && - (smc->cardid =3D=3D PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); - - return 0; -} - -static int pcmcia_get_versmac(struct pcmcia_device *p_dev, - tuple_t *tuple, - void *priv) -{ - struct net_device *dev =3D priv; - cisparse_t parse; - u8 *buf; - - if (pcmcia_parse_tuple(tuple, &parse)) - return -EINVAL; - - buf =3D parse.version_1.str + parse.version_1.ofs[3]; - - if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) =3D=3D 0)) - return 0; - - return -EINVAL; -}; - -static int mhz_setup(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - size_t len; - u8 *buf; - int rc; - - /* Read the station address from the CIS. It is stored as the last - (fourth) string in the Version 1 Version/ID tuple. */ - if ((link->prod_id[3]) && - (cvt_ascii_address(dev, link->prod_id[3]) =3D=3D 0)) - return 0; - - /* Workarounds for broken cards start here. */ - /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev)) - return 0; - - /* Another possibility: for the EM3288, in a special tuple */ - rc =3D -1; - len =3D pcmcia_get_tuple(link, 0x81, &buf); - if (buf && len >=3D 13) { - buf[12] =3D '\0'; - if (cvt_ascii_address(dev, buf) =3D=3D 0) - rc =3D 0; - } - kfree(buf); - - return rc; -}; - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Configuration stuff for the Motorola Mariner - - mot_config() writes directly to the Mariner configuration - registers because the CIS is just bogus. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void mot_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - unsigned int iouart =3D link->resource[1]->start; - - /* Set UART base address and force map with COR bit 1 */ - writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0); - writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1); - writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR); - - /* Set SMC base address and force map with COR bit 1 */ - writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0); - writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1); - writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR); - - /* Wait for things to settle down */ - mdelay(100); -} - -static int mot_setup(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - unsigned int ioaddr =3D dev->base_addr; - int i, wait, loop; - u8 mac[ETH_ALEN]; - u_int addr; - - /* Read Ethernet address from Serial EEPROM */ - - for (i =3D 0; i < 3; i++) { - SMC_SELECT_BANK(2); - outw(MOT_EEPROM + i, ioaddr + POINTER); - SMC_SELECT_BANK(1); - outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL); - - for (loop =3D wait =3D 0; loop < 200; loop++) { - udelay(10); - wait =3D ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL)); - if (wait =3D=3D 0) break; - } -=09 - if (wait) - return -1; -=09 - addr =3D inw(ioaddr + GENERAL); - mac[2*i] =3D addr & 0xff; - mac[2*i+1] =3D (addr >> 8) & 0xff; - } - eth_hw_addr_set(dev, mac); - - return 0; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->end =3D 16; - p_dev->resource[0]->flags &=3D ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_AUTO; - - return pcmcia_request_io(p_dev); -} - -static int smc_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - int i; - - link->config_flags |=3D CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - i =3D pcmcia_loop_config(link, smc_configcheck, NULL); - if (!i) - dev->base_addr =3D link->resource[0]->start; - - return i; -} - - -static int smc_setup(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - /* Check for a LAN function extension tuple */ - if (!pcmcia_get_mac_from_cis(link, dev)) - return 0; - - /* Try the third string in the Version 1 Version/ID tuple. */ - if (link->prod_id[2]) { - if (cvt_ascii_address(dev, link->prod_id[2]) =3D=3D 0) - return 0; - } - return -1; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int osi_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - static const unsigned int com[4] =3D { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; - int i, j; - - link->config_flags |=3D CONF_ENABLE_SPKR | CONF_ENABLE_IRQ; - link->resource[0]->end =3D 64; - link->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_8; - link->resource[1]->end =3D 8; - - /* Enable Hard Decode, LAN, Modem */ - link->io_lines =3D 16; - link->config_index =3D 0x23; - - for (i =3D j =3D 0; j < 4; j++) { - link->resource[1]->start =3D com[j]; - i =3D pcmcia_request_io(link); - if (i =3D=3D 0) - break; - } - if (i !=3D 0) { - /* Fallback: turn off hard decode */ - link->config_index =3D 0x03; - link->resource[1]->end =3D 0; - i =3D pcmcia_request_io(link); - } - dev->base_addr =3D link->resource[0]->start + 0x10; - return i; -} - -static int osi_load_firmware(struct pcmcia_device *link) -{ - const struct firmware *fw; - int i, err; - - err =3D request_firmware(&fw, FIRMWARE_NAME, &link->dev); - if (err) { - pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME); - return err; - } - - /* Download the Seven of Diamonds firmware */ - for (i =3D 0; i < fw->size; i++) { - outb(fw->data[i], link->resource[0]->start + 2); - udelay(50); - } - release_firmware(fw); - return err; -} - -static int pcmcia_osi_mac(struct pcmcia_device *p_dev, - tuple_t *tuple, - void *priv) -{ - struct net_device *dev =3D priv; - - if (tuple->TupleDataLen < 8) - return -EINVAL; - if (tuple->TupleData[0] !=3D 0x04) - return -EINVAL; - - eth_hw_addr_set(dev, &tuple->TupleData[2]); - return 0; -}; - - -static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short c= ardid) -{ - struct net_device *dev =3D link->priv; - int rc; - - /* Read the station address from tuple 0x90, subtuple 0x04 */ - if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev)) - return -1; - - if (((manfid =3D=3D MANFID_OSITECH) && - (cardid =3D=3D PRODID_OSITECH_SEVEN)) || - ((manfid =3D=3D MANFID_PSION) && - (cardid =3D=3D PRODID_PSION_NET100))) { - rc =3D osi_load_firmware(link); - if (rc) - return rc; - } else if (manfid =3D=3D MANFID_OSITECH) { - /* Make sure both functions are powered up */ - set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR); - /* Now, turn on the interrupt for both card functions */ - set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR); - dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n", - inw(link->resource[0]->start + OSITECH_AUI_PWR), - inw(link->resource[0]->start + OSITECH_RESET_ISR)); - } - return 0; -} - -static int smc91c92_suspend(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int smc91c92_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct smc_private *smc =3D netdev_priv(dev); - int i; - - if ((smc->manfid =3D=3D MANFID_MEGAHERTZ) && - (smc->cardid =3D=3D PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); - if (smc->manfid =3D=3D MANFID_MOTOROLA) - mot_config(link); - if ((smc->manfid =3D=3D MANFID_OSITECH) && - (smc->cardid !=3D PRODID_OSITECH_SEVEN)) { - /* Power up the card and enable interrupts */ - set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); - set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); - } - if (((smc->manfid =3D=3D MANFID_OSITECH) && - (smc->cardid =3D=3D PRODID_OSITECH_SEVEN)) || - ((smc->manfid =3D=3D MANFID_PSION) && - (smc->cardid =3D=3D PRODID_PSION_NET100))) { - i =3D osi_load_firmware(link); - if (i) { - netdev_err(dev, "Failed to load firmware\n"); - return i; - } - } - if (link->open) { - smc_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - This verifies that the chip is some SMC91cXX variant, and returns - the revision code if successful. Otherwise, it returns -ENODEV. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int check_sig(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - unsigned int ioaddr =3D dev->base_addr; - int width; - u_short s; - - SMC_SELECT_BANK(1); - if (inw(ioaddr + BANK_SELECT) >> 8 !=3D 0x33) { - /* Try powering up the chip */ - outw(0, ioaddr + CONTROL); - mdelay(55); - } - - /* Try setting bus width */ - width =3D (link->resource[0]->flags =3D=3D IO_DATA_PATH_WIDTH_AUTO); - s =3D inb(ioaddr + CONFIG); - if (width) - s |=3D CFG_16BIT; - else - s &=3D ~CFG_16BIT; - outb(s, ioaddr + CONFIG); - - /* Check Base Address Register to make sure bus width is OK */ - s =3D inw(ioaddr + BASE_ADDR); - if ((inw(ioaddr + BANK_SELECT) >> 8 =3D=3D 0x33) && - ((s >> 8) !=3D (s & 0xff))) { - SMC_SELECT_BANK(3); - s =3D inw(ioaddr + REVISION); - return s & 0xff; - } - - if (width) { - netdev_info(dev, "using 8-bit IO window\n"); - - smc91c92_suspend(link); - pcmcia_fixup_iowidth(link); - smc91c92_resume(link); - return check_sig(link); - } - return -ENODEV; -} - -static int smc91c92_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct smc_private *smc =3D netdev_priv(dev); - char *name; - int i, rev, j =3D 0; - unsigned int ioaddr; - u_long mir; - - dev_dbg(&link->dev, "smc91c92_config\n"); - - smc->manfid =3D link->manf_id; - smc->cardid =3D link->card_id; - - if ((smc->manfid =3D=3D MANFID_OSITECH) && - (smc->cardid !=3D PRODID_OSITECH_SEVEN)) { - i =3D osi_config(link); - } else if ((smc->manfid =3D=3D MANFID_MOTOROLA) || - ((smc->manfid =3D=3D MANFID_MEGAHERTZ) && - ((smc->cardid =3D=3D PRODID_MEGAHERTZ_VARIOUS) || - (smc->cardid =3D=3D PRODID_MEGAHERTZ_EM3288)))) { - i =3D mhz_mfc_config(link); - } else { - i =3D smc_config(link); - } - if (i) - goto config_failed; - - i =3D pcmcia_request_irq(link, smc_interrupt); - if (i) - goto config_failed; - i =3D pcmcia_enable_device(link); - if (i) - goto config_failed; - - if (smc->manfid =3D=3D MANFID_MOTOROLA) - mot_config(link); - - dev->irq =3D link->irq; - - if ((if_port >=3D 0) && (if_port <=3D 2)) - dev->if_port =3D if_port; - else - dev_notice(&link->dev, "invalid if_port requested\n"); - - switch (smc->manfid) { - case MANFID_OSITECH: - case MANFID_PSION: - i =3D osi_setup(link, smc->manfid, smc->cardid); break; - case MANFID_SMC: - case MANFID_NEW_MEDIA: - i =3D smc_setup(link); break; - case 0x128: /* For broken Megahertz cards */ - case MANFID_MEGAHERTZ: - i =3D mhz_setup(link); break; - case MANFID_MOTOROLA: - default: /* get the hw address from EEPROM */ - i =3D mot_setup(link); break; - } - - if (i !=3D 0) { - dev_notice(&link->dev, "Unable to find hardware address.\n"); - goto config_failed; - } - - smc->duplex =3D 0; - smc->rx_ovrn =3D 0; - - rev =3D check_sig(link); - name =3D "???"; - if (rev > 0) - switch (rev >> 4) { - case 3: name =3D "92"; break; - case 4: name =3D ((rev & 15) >=3D 6) ? "96" : "94"; break; - case 5: name =3D "95"; break; - case 7: name =3D "100"; break; - case 8: name =3D "100-FD"; break; - case 9: name =3D "110"; break; - } - - ioaddr =3D dev->base_addr; - if (rev > 0) { - u_long mcr; - SMC_SELECT_BANK(0); - mir =3D inw(ioaddr + MEMINFO) & 0xff; - if (mir =3D=3D 0xff) mir++; - /* Get scale factor for memory size */ - mcr =3D ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200; - mir *=3D 128 * (1<<((mcr >> 9) & 7)); - SMC_SELECT_BANK(1); - smc->cfg =3D inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; - smc->cfg |=3D CFG_NO_WAIT | CFG_16BIT | CFG_STATIC; - if (smc->manfid =3D=3D MANFID_OSITECH) - smc->cfg |=3D CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0; - if ((rev >> 4) >=3D 7) - smc->cfg |=3D CFG_MII_SELECT; - } else - mir =3D 0; - - if (smc->cfg & CFG_MII_SELECT) { - SMC_SELECT_BANK(3); - - for (i =3D 0; i < 32; i++) { - j =3D mdio_read(dev, i, 1); - if ((j !=3D 0) && (j !=3D 0xffff)) break; - } - smc->mii_if.phy_id =3D (i < 32) ? i : -1; - - SMC_SELECT_BANK(0); - } - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) !=3D 0) { - dev_err(&link->dev, "register_netdev() failed\n"); - goto config_undo; - } - - netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n", - name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr); - - if (rev > 0) { - if (mir & 0x3ff) - netdev_info(dev, " %lu byte", mir); - else - netdev_info(dev, " %lu kb", mir>>10); - pr_cont(" buffer, %s xcvr\n", - (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]); - } - - if (smc->cfg & CFG_MII_SELECT) { - if (smc->mii_if.phy_id !=3D -1) { - netdev_dbg(dev, " MII transceiver at index %d, status %x\n", - smc->mii_if.phy_id, j); - } else { - netdev_notice(dev, " No MII transceivers found!\n"); - } - } - return 0; - -config_undo: - unregister_netdev(dev); -config_failed: - smc91c92_release(link); - free_netdev(dev); - return -ENODEV; -} /* smc91c92_config */ - -static void smc91c92_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "smc91c92_release\n"); - if (link->resource[2]->end) { - struct net_device *dev =3D link->priv; - struct smc_private *smc =3D netdev_priv(dev); - iounmap(smc->base); - } - pcmcia_disable_device(link); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - MII interface support for SMC91cXX based cards -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#define MDIO_SHIFT_CLK 0x04 -#define MDIO_DATA_OUT 0x01 -#define MDIO_DIR_WRITE 0x08 -#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT) -#define MDIO_DATA_READ 0x02 - -static void mdio_sync(unsigned int addr) -{ - int bits; - for (bits =3D 0; bits < 32; bits++) { - outb(MDIO_DATA_WRITE1, addr); - outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); - } -} - -static int mdio_read(struct net_device *dev, int phy_id, int loc) -{ - unsigned int addr =3D dev->base_addr + MGMT; - u_int cmd =3D (0x06<<10)|(phy_id<<5)|loc; - int i, retval =3D 0; - - mdio_sync(addr); - for (i =3D 13; i >=3D 0; i--) { - int dat =3D (cmd&(1< 0; i--) { - outb(0, addr); - retval =3D (retval << 1) | ((inb(addr) & MDIO_DATA_READ) !=3D 0); - outb(MDIO_SHIFT_CLK, addr); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int loc, int va= lue) -{ - unsigned int addr =3D dev->base_addr + MGMT; - u_int cmd =3D (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; - int i; - - mdio_sync(addr); - for (i =3D 31; i >=3D 0; i--) { - int dat =3D (cmd&(1<=3D 0; i--) { - outb(0, addr); - outb(MDIO_SHIFT_CLK, addr); - } -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - The driver core code, most of which should be common with a - non-PCMCIA implementation. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#ifdef PCMCIA_DEBUG -static void smc_dump(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - u_short i, w, save; - save =3D inw(ioaddr + BANK_SELECT); - for (w =3D 0; w < 4; w++) { - SMC_SELECT_BANK(w); - netdev_dbg(dev, "bank %d: ", w); - for (i =3D 0; i < 14; i +=3D 2) - pr_cont(" %04x", inw(ioaddr + i)); - pr_cont("\n"); - } - outw(save, ioaddr + BANK_SELECT); -} -#endif - -static int smc_open(struct net_device *dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - struct pcmcia_device *link =3D smc->p_dev; - - dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n", - dev->name, dev, inw(dev->base_addr + BANK_SELECT)); -#ifdef PCMCIA_DEBUG - smc_dump(dev); -#endif - - /* Check that the PCMCIA card is still here. */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - /* Physical device present signature. */ - if (check_sig(link) < 0) { - netdev_info(dev, "Yikes! Bad chip signature!\n"); - return -ENODEV; - } - link->open++; - - netif_start_queue(dev); - smc->saved_skb =3D NULL; - smc->packets_waiting =3D 0; - - smc_reset(dev); - timer_setup(&smc->media, media_check, 0); - mod_timer(&smc->media, jiffies + HZ); - - return 0; -} /* smc_open */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int smc_close(struct net_device *dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - struct pcmcia_device *link =3D smc->p_dev; - unsigned int ioaddr =3D dev->base_addr; - - dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n", - dev->name, inw(ioaddr + BANK_SELECT)); - - netif_stop_queue(dev); - - /* Shut off all interrupts, and turn off the Tx and Rx sections. - Don't bother to check for chip present. */ - SMC_SELECT_BANK(2); /* Nominally paranoia, but do no assume... */ - outw(0, ioaddr + INTERRUPT); - SMC_SELECT_BANK(0); - mask_bits(0xff00, ioaddr + RCR); - mask_bits(0xff00, ioaddr + TCR); - - /* Put the chip into power-down mode. */ - SMC_SELECT_BANK(1); - outw(CTL_POWERDOWN, ioaddr + CONTROL ); - - link->open--; - timer_delete_sync(&smc->media); - - return 0; -} /* smc_close */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Transfer a packet to the hardware and trigger the packet send. - This may be called at either from either the Tx queue code - or the interrupt handler. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void smc_hardware_send_packet(struct net_device * dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - struct sk_buff *skb =3D smc->saved_skb; - unsigned int ioaddr =3D dev->base_addr; - u_char packet_no; - - if (!skb) { - netdev_err(dev, "In XMIT with no packet to send\n"); - return; - } - - /* There should be a packet slot waiting. */ - packet_no =3D inw(ioaddr + PNR_ARR) >> 8; - if (packet_no & 0x80) { - /* If not, there is a hardware problem! Likely an ejected card. */ - netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n", - packet_no); - dev_kfree_skb_irq(skb); - smc->saved_skb =3D NULL; - netif_start_queue(dev); - return; - } - - dev->stats.tx_bytes +=3D skb->len; - /* The card should use the just-allocated buffer. */ - outw(packet_no, ioaddr + PNR_ARR); - /* point to the beginning of the packet */ - outw(PTR_AUTOINC , ioaddr + POINTER); - - /* Send the packet length (+6 for status, length and ctl byte) - and the status word (set to zeros). */ - { - u_char *buf =3D skb->data; - u_int length =3D skb->len; /* The chip will pad to ethernet min. */ - - netdev_dbg(dev, "Trying to xmit packet of length %d\n", length); -=09 - /* send the packet length: +6 for status word, length, and ctl */ - outw(0, ioaddr + DATA_1); - outw(length + 6, ioaddr + DATA_1); - outsw(ioaddr + DATA_1, buf, length >> 1); -=09 - /* The odd last byte, if there is one, goes in the control word. */ - outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1); - } - - /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */ - outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) | - (inw(ioaddr + INTERRUPT) & 0xff00), - ioaddr + INTERRUPT); - - /* The chip does the rest of the work. */ - outw(MC_ENQUEUE , ioaddr + MMU_CMD); - - smc->saved_skb =3D NULL; - dev_kfree_skb_irq(skb); - netif_trans_update(dev); - netif_start_queue(dev); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - - netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\= n", - inw(ioaddr)&0xff, inw(ioaddr + 2)); - dev->stats.tx_errors++; - smc_reset(dev); - netif_trans_update(dev); /* prevent tx timeout */ - smc->saved_skb =3D NULL; - netif_wake_queue(dev); -} - -static netdev_tx_t smc_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - u_short num_pages; - short time_out, ir; - unsigned long flags; - - netif_stop_queue(dev); - - netdev_dbg(dev, "smc_start_xmit(length =3D %d) called, status %04x\n", - skb->len, inw(ioaddr + 2)); - - if (smc->saved_skb) { - /* THIS SHOULD NEVER HAPPEN. */ - dev->stats.tx_aborted_errors++; - netdev_dbg(dev, "Internal error -- sent packet while busy\n"); - return NETDEV_TX_BUSY; - } - smc->saved_skb =3D skb; - - num_pages =3D skb->len >> 8; - - if (num_pages > 7) { - netdev_err(dev, "Far too big packet error: %d pages\n", num_pages); - dev_kfree_skb (skb); - smc->saved_skb =3D NULL; - dev->stats.tx_dropped++; - return NETDEV_TX_OK; /* Do not re-queue this packet. */ - } - /* A packet is now waiting. */ - smc->packets_waiting++; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(2); /* Paranoia, we should always be in window 2 */ - - /* need MC_RESET to keep the memory consistent. errata? */ - if (smc->rx_ovrn) { - outw(MC_RESET, ioaddr + MMU_CMD); - smc->rx_ovrn =3D 0; - } - - /* Allocate the memory; send the packet now if we win. */ - outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD); - for (time_out =3D MEMORY_WAIT_TIME; time_out >=3D 0; time_out--) { - ir =3D inw(ioaddr+INTERRUPT); - if (ir & IM_ALLOC_INT) { - /* Acknowledge the interrupt, send the packet. */ - outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT); - smc_hardware_send_packet(dev); /* Send the packet now.. */ - spin_unlock_irqrestore(&smc->lock, flags); - return NETDEV_TX_OK; - } - } - - /* Otherwise defer until the Tx-space-allocated interrupt. */ - netdev_dbg(dev, "memory allocation deferred.\n"); - outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); - spin_unlock_irqrestore(&smc->lock, flags); - - return NETDEV_TX_OK; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Handle a Tx anomalous event. Entered while in Window 2. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void smc_tx_err(struct net_device * dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - int saved_packet =3D inw(ioaddr + PNR_ARR) & 0xff; - int packet_no =3D inw(ioaddr + FIFO_PORTS) & 0x7f; - int tx_status; - - /* select this as the packet to read from */ - outw(packet_no, ioaddr + PNR_ARR); - - /* read the first word from this packet */ - outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER); - - tx_status =3D inw(ioaddr + DATA_1); - - dev->stats.tx_errors++; - if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++; - if (tx_status & TS_LATCOL) dev->stats.tx_window_errors++; - if (tx_status & TS_16COL) { - dev->stats.tx_aborted_errors++; - smc->tx_err++; - } - - if (tx_status & TS_SUCCESS) { - netdev_notice(dev, "Successful packet caused error interrupt?\n"); - } - /* re-enable transmit */ - SMC_SELECT_BANK(0); - outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR); - SMC_SELECT_BANK(2); - - outw(MC_FREEPKT, ioaddr + MMU_CMD); /* Free the packet memory. */ - - /* one less packet waiting for me */ - smc->packets_waiting--; - - outw(saved_packet, ioaddr + PNR_ARR); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void smc_eph_irq(struct net_device *dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - u_short card_stats, ephs; - - SMC_SELECT_BANK(0); - ephs =3D inw(ioaddr + EPH); - netdev_dbg(dev, "Ethernet protocol handler interrupt, status %4.4x.\n", - ephs); - /* Could be a counter roll-over warning: update stats. */ - card_stats =3D inw(ioaddr + COUNTER); - /* single collisions */ - dev->stats.collisions +=3D card_stats & 0xF; - card_stats >>=3D 4; - /* multiple collisions */ - dev->stats.collisions +=3D card_stats & 0xF; -#if 0 /* These are for when linux supports these statistics */ - card_stats >>=3D 4; /* deferred */ - card_stats >>=3D 4; /* excess deferred */ -#endif - /* If we had a transmit error we must re-enable the transmitter. */ - outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR); - - /* Clear a link error interrupt. */ - SMC_SELECT_BANK(1); - outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL); - outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, - ioaddr + CONTROL); - SMC_SELECT_BANK(2); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static irqreturn_t smc_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D dev_id; - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr; - u_short saved_bank, saved_pointer, mask, status; - unsigned int handled =3D 1; - char bogus_cnt =3D INTR_WORK; /* Work we are willing to do. */ - - if (!netif_device_present(dev)) - return IRQ_NONE; - - ioaddr =3D dev->base_addr; - - netdev_dbg(dev, "SMC91c92 interrupt %d at %#x.\n", - irq, ioaddr); - - spin_lock(&smc->lock); - smc->watchdog =3D 0; - saved_bank =3D inw(ioaddr + BANK_SELECT); - if ((saved_bank & 0xff00) !=3D 0x3300) { - /* The device does not exist -- the card could be off-line, or - maybe it has been ejected. */ - netdev_dbg(dev, "SMC91c92 interrupt %d for non-existent/ejected device.\n= ", - irq); - handled =3D 0; - goto irq_done; - } - - SMC_SELECT_BANK(2); - saved_pointer =3D inw(ioaddr + POINTER); - mask =3D inw(ioaddr + INTERRUPT) >> 8; - /* clear all interrupts */ - outw(0, ioaddr + INTERRUPT); - - do { /* read the status flag, and mask it */ - status =3D inw(ioaddr + INTERRUPT) & 0xff; - netdev_dbg(dev, "Status is %#2.2x (mask %#2.2x).\n", - status, mask); - if ((status & mask) =3D=3D 0) { - if (bogus_cnt =3D=3D INTR_WORK) - handled =3D 0; - break; - } - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - smc_rx(dev); - } - if (status & IM_TX_INT) { - smc_tx_err(dev); - outw(IM_TX_INT, ioaddr + INTERRUPT); - } - status &=3D mask; - if (status & IM_TX_EMPTY_INT) { - outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT); - mask &=3D ~IM_TX_EMPTY_INT; - dev->stats.tx_packets +=3D smc->packets_waiting; - smc->packets_waiting =3D 0; - } - if (status & IM_ALLOC_INT) { - /* Clear this interrupt so it doesn't happen again */ - mask &=3D ~IM_ALLOC_INT; -=09 - smc_hardware_send_packet(dev); -=09 - /* enable xmit interrupts based on this */ - mask |=3D (IM_TX_EMPTY_INT | IM_TX_INT); -=09 - /* and let the card send more packets to me */ - netif_wake_queue(dev); - } - if (status & IM_RX_OVRN_INT) { - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - if (smc->duplex) - smc->rx_ovrn =3D 1; /* need MC_RESET outside smc_interrupt */ - outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT); - } - if (status & IM_EPH_INT) - smc_eph_irq(dev); - } while (--bogus_cnt); - - netdev_dbg(dev, " Restoring saved registers mask %2.2x bank %4.4x poi= nter %4.4x.\n", - mask, saved_bank, saved_pointer); - - /* restore state register */ - outw((mask<<8), ioaddr + INTERRUPT); - outw(saved_pointer, ioaddr + POINTER); - SMC_SELECT_BANK(saved_bank); - - netdev_dbg(dev, "Exiting interrupt IRQ%d.\n", irq); - -irq_done: - - if ((smc->manfid =3D=3D MANFID_OSITECH) && - (smc->cardid !=3D PRODID_OSITECH_SEVEN)) { - /* Retrigger interrupt if needed */ - mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR); - set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR); - } - if (smc->manfid =3D=3D MANFID_MOTOROLA) { - u_char cor; - cor =3D readb(smc->base + MOT_UART + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR); - writeb(cor, smc->base + MOT_UART + CISREG_COR); - cor =3D readb(smc->base + MOT_LAN + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR); - writeb(cor, smc->base + MOT_LAN + CISREG_COR); - } - - if ((smc->base !=3D NULL) && /* Megahertz MFC's */ - (smc->manfid =3D=3D MANFID_MEGAHERTZ) && - (smc->cardid =3D=3D PRODID_MEGAHERTZ_EM3288)) { - - u_char tmp; - tmp =3D readb(smc->base+MEGAHERTZ_ISR); - tmp =3D readb(smc->base+MEGAHERTZ_ISR); - - /* Retrigger interrupt if needed */ - writeb(tmp, smc->base + MEGAHERTZ_ISR); - writeb(tmp, smc->base + MEGAHERTZ_ISR); - } - - spin_unlock(&smc->lock); - return IRQ_RETVAL(handled); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void smc_rx(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - int rx_status; - int packet_length; /* Caution: not frame length, rather words - to transfer from the chip. */ - - /* Assertion: we are in Window 2. */ - - if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) { - netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n"); - return; - } - - /* Reset the read pointer, and read the status and packet length. */ - outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER); - rx_status =3D inw(ioaddr + DATA_1); - packet_length =3D inw(ioaddr + DATA_1) & 0x07ff; - - netdev_dbg(dev, "Receive status %4.4x length %d.\n", - rx_status, packet_length); - - if (!(rx_status & RS_ERRORS)) { - /* do stuff to make a new packet */ - struct sk_buff *skb; - struct smc_private *smc =3D netdev_priv(dev); -=09 - /* Note: packet_length adds 5 or 6 extra bytes here! */ - skb =3D netdev_alloc_skb(dev, packet_length+2); -=09 - if (skb =3D=3D NULL) { - netdev_dbg(dev, "Low memory, packet dropped.\n"); - dev->stats.rx_dropped++; - outw(MC_RELEASE, ioaddr + MMU_CMD); - return; - } -=09 - packet_length -=3D (rx_status & RS_ODDFRAME ? 5 : 6); - skb_reserve(skb, 2); - insw(ioaddr+DATA_1, skb_put(skb, packet_length), - (packet_length+1)>>1); - skb->protocol =3D eth_type_trans(skb, dev); -=09 - netif_rx(skb); - smc->last_rx =3D jiffies; - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D packet_length; - if (rx_status & RS_MULTICAST) - dev->stats.multicast++; - } else { - /* error ... */ - dev->stats.rx_errors++; -=09 - if (rx_status & RS_ALGNERR) dev->stats.rx_frame_errors++; - if (rx_status & (RS_TOOSHORT | RS_TOOLONG)) - dev->stats.rx_length_errors++; - if (rx_status & RS_BADCRC) dev->stats.rx_crc_errors++; - } - /* Let the MMU free the memory of this packet. */ - outw(MC_RELEASE, ioaddr + MMU_CMD); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Set the receive mode. - - This routine is used by both the protocol level to notify us of - promiscuous/multicast mode changes, and by the open/reset code to - initialize the Rx registers. We always set the multicast list and - leave the receiver running. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct smc_private *smc =3D netdev_priv(dev); - unsigned char multicast_table[8]; - unsigned long flags; - u_short rx_cfg_setting; - int i; - - memset(multicast_table, 0, sizeof(multicast_table)); - - if (dev->flags & IFF_PROMISC) { - rx_cfg_setting =3D RxStripCRC | RxEnable | RxPromisc | RxAllMulti; - } else if (dev->flags & IFF_ALLMULTI) - rx_cfg_setting =3D RxStripCRC | RxEnable | RxAllMulti; - else { - if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, dev) { - u_int position =3D ether_crc(6, ha->addr); - multicast_table[position >> 29] |=3D 1 << ((position >> 26) & 7); - } - } - rx_cfg_setting =3D RxStripCRC | RxEnable; - } - - /* Load MC table and Rx setting into the chip without interrupts. */ - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - for (i =3D 0; i < 8; i++) - outb(multicast_table[i], ioaddr + MULTICAST0 + i); - SMC_SELECT_BANK(0); - outw(rx_cfg_setting, ioaddr + RCR); - SMC_SELECT_BANK(2); - spin_unlock_irqrestore(&smc->lock, flags); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Senses when a card's config changes. Here, it's coax or TP. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int s9k_config(struct net_device *dev, struct ifmap *map) -{ - struct smc_private *smc =3D netdev_priv(dev); - if ((map->port !=3D (u_char)(-1)) && (map->port !=3D dev->if_port)) { - if (smc->cfg & CFG_MII_SELECT) - return -EOPNOTSUPP; - else if (map->port > 2) - return -EINVAL; - WRITE_ONCE(dev->if_port, map->port); - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - smc_reset(dev); - } - return 0; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Reset the chip, reloading every register that might be corrupted. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* - Set transceiver type, perhaps to something other than what the user - specified in dev->if_port. -*/ -static void smc_set_xcvr(struct net_device *dev, int if_port) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - u_short saved_bank; - - saved_bank =3D inw(ioaddr + BANK_SELECT); - SMC_SELECT_BANK(1); - if (if_port =3D=3D 2) { - outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG); - if ((smc->manfid =3D=3D MANFID_OSITECH) && - (smc->cardid !=3D PRODID_OSITECH_SEVEN)) - set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - smc->media_status =3D ((dev->if_port =3D=3D 0) ? 0x0001 : 0x0002); - } else { - outw(smc->cfg, ioaddr + CONFIG); - if ((smc->manfid =3D=3D MANFID_OSITECH) && - (smc->cardid !=3D PRODID_OSITECH_SEVEN)) - mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - smc->media_status =3D ((dev->if_port =3D=3D 0) ? 0x0012 : 0x4001); - } - SMC_SELECT_BANK(saved_bank); -} - -static void smc_reset(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct smc_private *smc =3D netdev_priv(dev); - int i; - - netdev_dbg(dev, "smc91c92 reset called.\n"); - - /* The first interaction must be a write to bring the chip out - of sleep mode. */ - SMC_SELECT_BANK(0); - /* Reset the chip. */ - outw(RCR_SOFTRESET, ioaddr + RCR); - udelay(10); - - /* Clear the transmit and receive configuration registers. */ - outw(RCR_CLEAR, ioaddr + RCR); - outw(TCR_CLEAR, ioaddr + TCR); - - /* Set the Window 1 control, configuration and station addr registers. - No point in writing the I/O base register ;-> */ - SMC_SELECT_BANK(1); - /* Automatically release successfully transmitted packets, - Accept link errors, counter and Tx error interrupts. */ - outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, - ioaddr + CONTROL); - smc_set_xcvr(dev, dev->if_port); - if ((smc->manfid =3D=3D MANFID_OSITECH) && - (smc->cardid !=3D PRODID_OSITECH_SEVEN)) - outw((dev->if_port =3D=3D 2 ? OSI_AUI_PWR : 0) | - (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00), - ioaddr - 0x10 + OSITECH_AUI_PWR); - - /* Fill in the physical address. The databook is wrong about the orde= r! */ - for (i =3D 0; i < 6; i +=3D 2) - outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i], - ioaddr + ADDR0 + i); - - /* Reset the MMU */ - SMC_SELECT_BANK(2); - outw(MC_RESET, ioaddr + MMU_CMD); - outw(0, ioaddr + INTERRUPT); - - /* Re-enable the chip. */ - SMC_SELECT_BANK(0); - outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) | - TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR); - set_rx_mode(dev); - - if (smc->cfg & CFG_MII_SELECT) { - SMC_SELECT_BANK(3); - - /* Reset MII */ - mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000); - - /* Advertise 100F, 100H, 10F, 10H */ - mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1); - - /* Restart MII autonegotiation */ - mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000); - mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200); - } - - /* Enable interrupts. */ - SMC_SELECT_BANK(2); - outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8, - ioaddr + INTERRUPT); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Media selection timer routine - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void media_check(struct timer_list *t) -{ - struct smc_private *smc =3D timer_container_of(smc, t, media); - struct net_device *dev =3D smc->mii_if.dev; - unsigned int ioaddr =3D dev->base_addr; - u_short i, media, saved_bank; - u_short link; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - - saved_bank =3D inw(ioaddr + BANK_SELECT); - - if (!netif_device_present(dev)) - goto reschedule; - - SMC_SELECT_BANK(2); - - /* need MC_RESET to keep the memory consistent. errata? */ - if (smc->rx_ovrn) { - outw(MC_RESET, ioaddr + MMU_CMD); - smc->rx_ovrn =3D 0; - } - i =3D inw(ioaddr + INTERRUPT); - SMC_SELECT_BANK(0); - media =3D inw(ioaddr + EPH) & EPH_LINK_OK; - SMC_SELECT_BANK(1); - media |=3D (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1; - - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - - /* Check for pending interrupt with watchdog flag set: with - this, we can limp along even if the interrupt is blocked */ - if (smc->watchdog++ && ((i>>8) & i)) { - if (!smc->fast_poll) - netdev_info(dev, "interrupt(s) dropped!\n"); - local_irq_save(flags); - smc_interrupt(dev->irq, dev); - local_irq_restore(flags); - smc->fast_poll =3D HZ; - } - if (smc->fast_poll) { - smc->fast_poll--; - smc->media.expires =3D jiffies + HZ/100; - add_timer(&smc->media); - return; - } - - spin_lock_irqsave(&smc->lock, flags); - - saved_bank =3D inw(ioaddr + BANK_SELECT); - - if (smc->cfg & CFG_MII_SELECT) { - if (smc->mii_if.phy_id < 0) - goto reschedule; - - SMC_SELECT_BANK(3); - link =3D mdio_read(dev, smc->mii_if.phy_id, 1); - if (!link || (link =3D=3D 0xffff)) { - netdev_info(dev, "MII is missing!\n"); - smc->mii_if.phy_id =3D -1; - goto reschedule; - } - - link &=3D 0x0004; - if (link !=3D smc->link_status) { - u_short p =3D mdio_read(dev, smc->mii_if.phy_id, 5); - netdev_info(dev, "%s link beat\n", link ? "found" : "lost"); - smc->duplex =3D (((p & 0x0100) || ((p & 0x1c0) =3D=3D 0x40)) - ? TCR_FDUPLX : 0); - if (link) { - netdev_info(dev, "autonegotiation complete: " - "%dbaseT-%cD selected\n", - (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H'); - } - SMC_SELECT_BANK(0); - outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR); - smc->link_status =3D link; - } - goto reschedule; - } - - /* Ignore collisions unless we've had no rx's recently */ - if (time_after(jiffies, smc->last_rx + HZ)) { - if (smc->tx_err || (smc->media_status & EPH_16COL)) - media |=3D EPH_16COL; - } - smc->tx_err =3D 0; - - if (media !=3D smc->media_status) { - if ((media & smc->media_status & 1) && - ((smc->media_status ^ media) & EPH_LINK_OK)) - netdev_info(dev, "%s link beat\n", - smc->media_status & EPH_LINK_OK ? "lost" : "found"); - else if ((media & smc->media_status & 2) && - ((smc->media_status ^ media) & EPH_16COL)) - netdev_info(dev, "coax cable %s\n", - media & EPH_16COL ? "problem" : "ok"); - if (dev->if_port =3D=3D 0) { - if (media & 1) { - if (media & EPH_LINK_OK) - netdev_info(dev, "flipped to 10baseT\n"); - else - smc_set_xcvr(dev, 2); - } else { - if (media & EPH_16COL) - smc_set_xcvr(dev, 1); - else - netdev_info(dev, "flipped to 10base2\n"); - } - } - smc->media_status =3D media; - } - -reschedule: - smc->media.expires =3D jiffies + HZ; - add_timer(&smc->media); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); -} - -static int smc_link_ok(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct smc_private *smc =3D netdev_priv(dev); - - if (smc->cfg & CFG_MII_SELECT) { - return mii_link_ok(&smc->mii_if); - } else { - SMC_SELECT_BANK(0); - return inw(ioaddr + EPH) & EPH_LINK_OK; - } -} - -static void smc_netdev_get_ecmd(struct net_device *dev, - struct ethtool_link_ksettings *ecmd) -{ - u16 tmp; - unsigned int ioaddr =3D dev->base_addr; - u32 supported; - - supported =3D (SUPPORTED_TP | SUPPORTED_AUI | - SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full); - - SMC_SELECT_BANK(1); - tmp =3D inw(ioaddr + CONFIG); - ecmd->base.port =3D (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP; - ecmd->base.speed =3D SPEED_10; - ecmd->base.phy_address =3D ioaddr + MGMT; - - SMC_SELECT_BANK(0); - tmp =3D inw(ioaddr + TCR); - ecmd->base.duplex =3D (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF; - - ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported, - supported); -} - -static int smc_netdev_set_ecmd(struct net_device *dev, - const struct ethtool_link_ksettings *ecmd) -{ - u16 tmp; - unsigned int ioaddr =3D dev->base_addr; - - if (ecmd->base.speed !=3D SPEED_10) - return -EINVAL; - if (ecmd->base.duplex !=3D DUPLEX_HALF && - ecmd->base.duplex !=3D DUPLEX_FULL) - return -EINVAL; - if (ecmd->base.port !=3D PORT_TP && ecmd->base.port !=3D PORT_AUI) - return -EINVAL; - - if (ecmd->base.port =3D=3D PORT_AUI) - smc_set_xcvr(dev, 1); - else - smc_set_xcvr(dev, 0); - - SMC_SELECT_BANK(0); - tmp =3D inw(ioaddr + TCR); - if (ecmd->base.duplex =3D=3D DUPLEX_FULL) - tmp |=3D TCR_FDUPLX; - else - tmp &=3D ~TCR_FDUPLX; - outw(tmp, ioaddr + TCR); - - return 0; -} - -static int check_if_running(struct net_device *dev) -{ - if (!netif_running(dev)) - return -EINVAL; - return 0; -} - -static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo= *info) -{ - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->version, DRV_VERSION, sizeof(info->version)); -} - -static int smc_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *ecmd) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - u16 saved_bank =3D inw(ioaddr + BANK_SELECT); - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - if (smc->cfg & CFG_MII_SELECT) - mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd); - else - smc_netdev_get_ecmd(dev, ecmd); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return 0; -} - -static int smc_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *ecmd) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - u16 saved_bank =3D inw(ioaddr + BANK_SELECT); - int ret; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - if (smc->cfg & CFG_MII_SELECT) - ret =3D mii_ethtool_set_link_ksettings(&smc->mii_if, ecmd); - else - ret =3D smc_netdev_set_ecmd(dev, ecmd); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return ret; -} - -static u32 smc_get_link(struct net_device *dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - u16 saved_bank =3D inw(ioaddr + BANK_SELECT); - u32 ret; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - ret =3D smc_link_ok(dev); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return ret; -} - -static int smc_nway_reset(struct net_device *dev) -{ - struct smc_private *smc =3D netdev_priv(dev); - if (smc->cfg & CFG_MII_SELECT) { - unsigned int ioaddr =3D dev->base_addr; - u16 saved_bank =3D inw(ioaddr + BANK_SELECT); - int res; - - SMC_SELECT_BANK(3); - res =3D mii_nway_restart(&smc->mii_if); - SMC_SELECT_BANK(saved_bank); - - return res; - } else - return -EOPNOTSUPP; -} - -static const struct ethtool_ops ethtool_ops =3D { - .begin =3D check_if_running, - .get_drvinfo =3D smc_get_drvinfo, - .get_link =3D smc_get_link, - .nway_reset =3D smc_nway_reset, - .get_link_ksettings =3D smc_get_link_ksettings, - .set_link_ksettings =3D smc_set_link_ksettings, -}; - -static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct smc_private *smc =3D netdev_priv(dev); - struct mii_ioctl_data *mii =3D if_mii(rq); - int rc =3D 0; - u16 saved_bank; - unsigned int ioaddr =3D dev->base_addr; - unsigned long flags; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irqsave(&smc->lock, flags); - saved_bank =3D inw(ioaddr + BANK_SELECT); - SMC_SELECT_BANK(3); - rc =3D generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return rc; -} - -static const struct pcmcia_device_id smc91c92_ids[] =3D { - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CEL= L ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CEL= L ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0= xf510db04, 0x856d66c8, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA= MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x= 662c394c), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db= 04, 0x52d21e1e), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Mod= em+Ethernet", 0xc2f80cd, 0x656947b9), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem= +Ethernet", 0xc2f80cd, 0xdc9ba5ed), - PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020), - PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023), - PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "= SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb), - PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xd= cea68bc), - PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8,= 0x6a2161d1), - PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5), - PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734= e9), - PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953), - PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a), - PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet",= 0xc2f80cd, 0xb3466314), - PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet"= , 0xc2f80cd, 0x194b650a), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xd= cea68bc), - PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9), - PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0= eeb2d), - /* These conflict with other cards! */ - /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */ - /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids); - -static struct pcmcia_driver smc91c92_cs_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "smc91c92_cs", - .probe =3D smc91c92_probe, - .remove =3D smc91c92_detach, - .id_table =3D smc91c92_ids, - .suspend =3D smc91c92_suspend, - .resume =3D smc91c92_resume, -}; -module_pcmcia_driver(smc91c92_cs_driver); --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8136F3DCDB2; Tue, 21 Apr 2026 19:58:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801530; cv=none; b=R1eH4aTjfOGTNhmDtCxhZNfMh0kNAKPviaMCqzsKpq+9HP/6Hp2GHGFqLvq7/QK7EEID3V5DjuMPMc3Uz07yWjAH9MXqabtDLqNWgQTXjtdusRmzPEsFRtLxOnIrYkIFr/LrmJan41e6upRB4AWYtb/hVVxkc3zZ9QNdvw03zvY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801530; c=relaxed/simple; bh=fg0rM0htz42brRDER0fA2WXvsxMsMFJpe4BtBcHweYs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AUV7H3tt429TH0V0PXT4SsJL2+iN7tPgkLA8G08kiiGPqQMIMgmwM2gzSlqKwIb8uVYANuL+4dyj4S4Xp6F1lyVcILhoGFKClZOKecMAv9vLKSONwc7vmxIAEdanTf9tKSF36mXfwx6DiPZvcm3QQT4/4faB01JCI0sRfcW5Yjk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=LBpsORqP; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="LBpsORqP" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=gM1XUVQnSQ5B3ZxWbqYmzQ1CouEMx5NLXT2jEhb0KXU=; b=LB psORqPe1sGHmqezEI40MWI6p+ilowEA9s1rSkXm71HwGHjvgOg1wBS7K6ai4PuoOw1bzlDcKCJKjm IAcKkeIsZauG2gEp9Vw8IWX8U4GJWon9HaHaSKI/MAP74tNz+G4x3RVbtkjfki+g12Xm3oQ4nufLu rVTPQ0PJoB0Ddak=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGoy-00GwVc-Gg; Tue, 21 Apr 2026 21:31:44 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:14 -0500 Subject: [PATCH net 11/18] drivers: net: cirrus: cs89x0: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-11-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=58123; i=andrew@lunn.ch; h=from:subject:message-id; bh=fg0rM0htz42brRDER0fA2WXvsxMsMFJpe4BtBcHweYs=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CC3ek8iHe3E8nAVD1RyZOaka4NlGHNqg/P0 g05kwxd2bGJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hArZEADLOIPjRjoKoHDMfkc36yFu1S16bqGsc5L8K5Ncg04Rs+PjTPwpbdYtnj6HUZ7Pe8jGNai L7m1/Q+fRel083j9pT4MSWiNrcrsB7Na3sKNEdkKS3HoGQhwHj/S5fboG8yIZ9Hci1y10UKIKvr wLiepjWns+P03O4uUVj0+mUd9JF80/rSatIeo+CMZUHP1e3Xx1FTLXZly1sXfF9l4QC8D+SXuH2 JhVtTeavm1fOqKF1CYX9GVlxFbbk5Kxlkp8kXH8BaOJJ4NNKTZH14P6ElUlOkQHtY7WAah5lBnC TtIOPEdM9pwKOt23SSMMQfxVw4RNxuA9fnSAN3JcnVO+uS2gj873Q/nNRZsLqUHxpGpAiRfIS/E qk9G2VB6xh2Lg1fTn7mcCn2AgFZuWYWvNwDdoITTfkQeRQVsjiXBvWQ5MxjfDMT/54yjPLIicxe 2RJi+3ax6hXGVHEzlRh49Hgg3ZogxfbqXFU9sn6mv4pINJUAqJMTBA+zRTdyjkyEo6LloQsUNtZ pKr5uHMsRsBzhU9rHwiDQ67LpZChSY3QRtarrnArI/dbQeezMC/p+DUwkCNZF8bGuemdncB68Lw amr07UKoI2MS9xgo8KhOyMskaRw97nNvFhPkhVADKZRBg8q11mhImhHkWUwXlB3SlH9oxFwX4+W Pp8nicrmpO8EEOQ== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The cs89x0 was written by Bonald Becker 1993 to 1994. It is an ISA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/cirrus/Kconfig | 30 - drivers/net/ethernet/cirrus/Makefile | 1 - drivers/net/ethernet/cirrus/cs89x0.c | 1915 ------------------------------= ---- 3 files changed, 1946 deletions(-) diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cir= rus/Kconfig index 5bdf731d9503..1a0c7b3bfcd6 100644 --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@ -17,36 +17,6 @@ config NET_VENDOR_CIRRUS =20 if NET_VENDOR_CIRRUS =20 -config CS89x0 - tristate - -config CS89x0_ISA - tristate "CS89x0 ISA driver support" - depends on HAS_IOPORT_MAP - depends on ISA - depends on !PPC32 - depends on CS89x0_PLATFORM=3Dn - select NETDEV_LEGACY_INIT - select CS89x0 - help - Support for CS89x0 chipset based Ethernet cards. If you have a - network (Ethernet) card of this type, say Y and read the file - . - - To compile this driver as a module, choose M here. The module - will be called cs89x0. - -config CS89x0_PLATFORM - tristate "CS89x0 platform driver support" - depends on ARM || (COMPILE_TEST && !PPC) - select CS89x0 - help - Say Y to compile the cs89x0 platform driver. This makes this driver - suitable for use on certain evaluation boards such as the iMX21ADS. - - To compile this driver as a module, choose M here. The module - will be called cs89x0. - config EP93XX_ETH tristate "EP93xx Ethernet support" depends on (ARM && ARCH_EP93XX) || COMPILE_TEST diff --git a/drivers/net/ethernet/cirrus/Makefile b/drivers/net/ethernet/ci= rrus/Makefile index 84865e593788..cb740939d976 100644 --- a/drivers/net/ethernet/cirrus/Makefile +++ b/drivers/net/ethernet/cirrus/Makefile @@ -3,6 +3,5 @@ # Makefile for the Cirrus network device drivers. # =20 -obj-$(CONFIG_CS89x0) +=3D cs89x0.o obj-$(CONFIG_EP93XX_ETH) +=3D ep93xx_eth.o obj-$(CONFIG_MAC89x0) +=3D mac89x0.o diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/ci= rrus/cs89x0.c deleted file mode 100644 index fa5857923db4..000000000000 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ /dev/null @@ -1,1915 +0,0 @@ -/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 - * driver for linux. - * Written 1996 by Russell Nelson, with reference to skeleton.c - * written 1993-1994 by Donald Becker. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * The author may be reached at nelson@crynwr.com, Crynwr - * Software, 521 Pleasant Valley Rd., Potsdam, NY 13676 - * - * Other contributors: - * Mike Cruse : mcruse@cti-ltd.com - * Russ Nelson - * Melody Lee : ethernet@crystal.cirrus.com - * Alan Cox - * Andrew Morton - * Oskar Schirmer : oskar@scara.com - * Deepak Saxena : dsaxena@plexity.net - * Dmitry Pervushin : dpervushin@ru.mvista.com - * Deepak Saxena : dsaxena@plexity.net - * Domenico Andreoli : cavokz@gmail.com - */ - - -/* - * Set this to zero to disable DMA code - * - * Note that even if DMA is turned off we still support the 'dma' and 'us= e_dma' - * module options so we don't break any startup scripts. - */ -#ifndef CONFIG_ISA_DMA_API -#define ALLOW_DMA 0 -#else -#define ALLOW_DMA 1 -#endif - -/* - * Set this to zero to remove all the debug statements via - * dead code elimination - */ -#define DEBUGGING 1 - -/* Sources: - * Crynwr packet driver epktisa. - * Crystal Semiconductor data sheets. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#if ALLOW_DMA -#include -#endif - -#include "cs89x0.h" - -#define cs89_dbg(val, level, fmt, ...) \ -do { \ - if (val <=3D net_debug) \ - pr_##level(fmt, ##__VA_ARGS__); \ -} while (0) - -static char version[] __initdata =3D - "v2.4.3-pre1 Russell Nelson , Andrew Morton"; - -#define DRV_NAME "cs89x0" - -/* First, a few definitions that the brave might change. - * A zero-terminated list of I/O addresses to be probed. Some special flag= s.. - * Addr & 1 =3D Read back the address port, look for signature and reset - * the page window before probing - * Addr & 3 =3D Reset the page window and probe - * The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space, - * but it is possible that a Cirrus board could be plugged into the ISA - * slots. - */ -/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps - * them to system IRQ numbers. This mapping is card specific and is set to - * the configuration of the Cirrus Eval board for this chip. - */ -#if IS_ENABLED(CONFIG_CS89x0_ISA) -static unsigned int netcard_portlist[] __used __initdata =3D { - 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, - 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0 -}; -static unsigned int cs8900_irq_map[] =3D { - 10, 11, 12, 5 -}; -#endif - -#if DEBUGGING -static unsigned int net_debug =3D DEBUGGING; -#else -#define net_debug 0 /* gcc will remove all the debug code for us */ -#endif - -/* The number of low I/O ports used by the ethercard. */ -#define NETCARD_IO_EXTENT 16 - -/* we allow the user to override various values normally set in the EEPROM= */ -#define FORCE_RJ45 0x0001 /* pick one of these three */ -#define FORCE_AUI 0x0002 -#define FORCE_BNC 0x0004 - -#define FORCE_AUTO 0x0010 /* pick one of these three */ -#define FORCE_HALF 0x0020 -#define FORCE_FULL 0x0030 - -/* Information that need to be kept for each board. */ -struct net_local { - int chip_type; /* one of: CS8900, CS8920, CS8920M */ - char chip_revision; /* revision letter of the chip ('A'...) */ - int send_cmd; /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AF= TER_ALL */ - int auto_neg_cnf; /* auto-negotiation word from EEPROM */ - int adapter_cnf; /* adapter configuration from EEPROM */ - int isa_config; /* ISA configuration from EEPROM */ - int irq_map; /* IRQ map from EEPROM */ - int rx_mode; /* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_AC= CEPT */ - int curr_rx_cfg; /* a copy of PP_RxCFG */ - int linectl; /* either 0 or LOW_RX_SQUELCH, depending on configuration. = */ - int send_underrun; /* keep track of how many underruns in a row we get */ - int force; /* force various values; see FORCE* above. */ - spinlock_t lock; - void __iomem *virt_addr;/* CS89x0 virtual address. */ -#if ALLOW_DMA - int use_dma; /* Flag: we're using dma */ - int dma; /* DMA channel */ - int dmasize; /* 16 or 64 */ - unsigned char *dma_buff; /* points to the beginning of the buffer */ - unsigned char *end_dma_buff; /* points to the end of the buffer */ - unsigned char *rx_dma_ptr; /* points to the next packet */ -#endif -}; - -/* Example routines you must write ;->. */ -#define tx_done(dev) 1 - -/* - * Permit 'cs89x0_dma=3DN' in the kernel boot environment - */ -#if !defined(MODULE) -#if ALLOW_DMA -static int g_cs89x0_dma; - -static int __init dma_fn(char *str) -{ - g_cs89x0_dma =3D simple_strtol(str, NULL, 0); - return 1; -} - -__setup("cs89x0_dma=3D", dma_fn); -#endif /* ALLOW_DMA */ - -static int g_cs89x0_media__force; - -static int __init media_fn(char *str) -{ - if (!strcmp(str, "rj45")) - g_cs89x0_media__force =3D FORCE_RJ45; - else if (!strcmp(str, "aui")) - g_cs89x0_media__force =3D FORCE_AUI; - else if (!strcmp(str, "bnc")) - g_cs89x0_media__force =3D FORCE_BNC; - - return 1; -} - -__setup("cs89x0_media=3D", media_fn); -#endif - -static void readwords(struct net_local *lp, int portno, void *buf, int len= gth) -{ - u8 *buf8 =3D (u8 *)buf; - - do { - u16 tmp16; - - tmp16 =3D ioread16(lp->virt_addr + portno); - *buf8++ =3D (u8)tmp16; - *buf8++ =3D (u8)(tmp16 >> 8); - } while (--length); -} - -static void writewords(struct net_local *lp, int portno, void *buf, int le= ngth) -{ - u8 *buf8 =3D (u8 *)buf; - - do { - u16 tmp16; - - tmp16 =3D *buf8++; - tmp16 |=3D (*buf8++) << 8; - iowrite16(tmp16, lp->virt_addr + portno); - } while (--length); -} - -static u16 -readreg(struct net_device *dev, u16 regno) -{ - struct net_local *lp =3D netdev_priv(dev); - - iowrite16(regno, lp->virt_addr + ADD_PORT); - return ioread16(lp->virt_addr + DATA_PORT); -} - -static void -writereg(struct net_device *dev, u16 regno, u16 value) -{ - struct net_local *lp =3D netdev_priv(dev); - - iowrite16(regno, lp->virt_addr + ADD_PORT); - iowrite16(value, lp->virt_addr + DATA_PORT); -} - -static int __init -wait_eeprom_ready(struct net_device *dev) -{ - unsigned long timeout =3D jiffies; - /* check to see if the EEPROM is ready, - * a timeout is used just in case EEPROM is ready when - * SI_BUSY in the PP_SelfST is clear - */ - while (readreg(dev, PP_SelfST) & SI_BUSY) - if (time_after_eq(jiffies, timeout + 40)) - return -1; - return 0; -} - -static int __init -get_eeprom_data(struct net_device *dev, int off, int len, int *buffer) -{ - int i; - - cs89_dbg(3, info, "EEPROM data from %x for %x:", off, len); - for (i =3D 0; i < len; i++) { - if (wait_eeprom_ready(dev) < 0) - return -1; - /* Now send the EEPROM read command and EEPROM location to read */ - writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD); - if (wait_eeprom_ready(dev) < 0) - return -1; - buffer[i] =3D readreg(dev, PP_EEData); - cs89_dbg(3, cont, " %04x", buffer[i]); - } - cs89_dbg(3, cont, "\n"); - return 0; -} - -static int __init -get_eeprom_cksum(int off, int len, int *buffer) -{ - int i, cksum; - - cksum =3D 0; - for (i =3D 0; i < len; i++) - cksum +=3D buffer[i]; - cksum &=3D 0xffff; - if (cksum =3D=3D 0) - return 0; - return -1; -} - -static void -write_irq(struct net_device *dev, int chip_type, int irq) -{ - int i; - - if (chip_type =3D=3D CS8900) { -#if IS_ENABLED(CONFIG_CS89x0_ISA) - /* Search the mapping table for the corresponding IRQ pin. */ - for (i =3D 0; i !=3D ARRAY_SIZE(cs8900_irq_map); i++) - if (cs8900_irq_map[i] =3D=3D irq) - break; - /* Not found */ - if (i =3D=3D ARRAY_SIZE(cs8900_irq_map)) - i =3D 3; -#else - /* INTRQ0 pin is used for interrupt generation. */ - i =3D 0; -#endif - writereg(dev, PP_CS8900_ISAINT, i); - } else { - writereg(dev, PP_CS8920_ISAINT, irq); - } -} - -static void -count_rx_errors(int status, struct net_device *dev) -{ - dev->stats.rx_errors++; - if (status & RX_RUNT) - dev->stats.rx_length_errors++; - if (status & RX_EXTRA_DATA) - dev->stats.rx_length_errors++; - if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA | RX_RUNT))) - /* per str 172 */ - dev->stats.rx_crc_errors++; - if (status & RX_DRIBBLE) - dev->stats.rx_frame_errors++; -} - -/********************************* - * This page contains DMA routines - *********************************/ - -#if ALLOW_DMA - -#define dma_page_eq(ptr1, ptr2) ((long)(ptr1) >> 17 =3D=3D (long)(ptr2) >>= 17) - -static void -get_dma_channel(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - - if (lp->dma) { - dev->dma =3D lp->dma; - lp->isa_config |=3D ISA_RxDMA; - } else { - if ((lp->isa_config & ANY_ISA_DMA) =3D=3D 0) - return; - dev->dma =3D lp->isa_config & DMA_NO_MASK; - if (lp->chip_type =3D=3D CS8900) - dev->dma +=3D 5; - if (dev->dma < 5 || dev->dma > 7) { - lp->isa_config &=3D ~ANY_ISA_DMA; - return; - } - } -} - -static void -write_dma(struct net_device *dev, int chip_type, int dma) -{ - struct net_local *lp =3D netdev_priv(dev); - if ((lp->isa_config & ANY_ISA_DMA) =3D=3D 0) - return; - if (chip_type =3D=3D CS8900) - writereg(dev, PP_CS8900_ISADMA, dma - 5); - else - writereg(dev, PP_CS8920_ISADMA, dma); -} - -static void -set_dma_cfg(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - - if (lp->use_dma) { - if ((lp->isa_config & ANY_ISA_DMA) =3D=3D 0) { - cs89_dbg(3, err, "set_dma_cfg(): no DMA\n"); - return; - } - if (lp->isa_config & ISA_RxDMA) { - lp->curr_rx_cfg |=3D RX_DMA_ONLY; - cs89_dbg(3, info, "set_dma_cfg(): RX_DMA_ONLY\n"); - } else { - lp->curr_rx_cfg |=3D AUTO_RX_DMA; /* not that we support it... */ - cs89_dbg(3, info, "set_dma_cfg(): AUTO_RX_DMA\n"); - } - } -} - -static int -dma_bufcfg(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - if (lp->use_dma) - return (lp->isa_config & ANY_ISA_DMA) ? RX_DMA_ENBL : 0; - else - return 0; -} - -static int -dma_busctl(struct net_device *dev) -{ - int retval =3D 0; - struct net_local *lp =3D netdev_priv(dev); - if (lp->use_dma) { - if (lp->isa_config & ANY_ISA_DMA) - retval |=3D RESET_RX_DMA; /* Reset the DMA pointer */ - if (lp->isa_config & DMA_BURST) - retval |=3D DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */ - if (lp->dmasize =3D=3D 64) - retval |=3D RX_DMA_SIZE_64K; /* did they ask for 64K? */ - retval |=3D MEMORY_ON; /* we need memory enabled to use DMA. */ - } - return retval; -} - -static void -dma_rx(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - struct sk_buff *skb; - int status, length; - unsigned char *bp =3D lp->rx_dma_ptr; - - status =3D bp[0] + (bp[1] << 8); - length =3D bp[2] + (bp[3] << 8); - bp +=3D 4; - - cs89_dbg(5, debug, "%s: receiving DMA packet at %lx, status %x, length %x= \n", - dev->name, (unsigned long)bp, status, length); - - if ((status & RX_OK) =3D=3D 0) { - count_rx_errors(status, dev); - goto skip_this_frame; - } - - /* Malloc up new buffer. */ - skb =3D netdev_alloc_skb(dev, length + 2); - if (skb =3D=3D NULL) { - dev->stats.rx_dropped++; - - /* AKPM: advance bp to the next frame */ -skip_this_frame: - bp +=3D (length + 3) & ~3; - if (bp >=3D lp->end_dma_buff) - bp -=3D lp->dmasize * 1024; - lp->rx_dma_ptr =3D bp; - return; - } - skb_reserve(skb, 2); /* longword align L3 header */ - - if (bp + length > lp->end_dma_buff) { - int semi_cnt =3D lp->end_dma_buff - bp; - skb_put_data(skb, bp, semi_cnt); - skb_put_data(skb, lp->dma_buff, length - semi_cnt); - } else { - skb_put_data(skb, bp, length); - } - bp +=3D (length + 3) & ~3; - if (bp >=3D lp->end_dma_buff) - bp -=3D lp->dmasize*1024; - lp->rx_dma_ptr =3D bp; - - cs89_dbg(3, info, "%s: received %d byte DMA packet of type %x\n", - dev->name, length, - ((skb->data[ETH_ALEN + ETH_ALEN] << 8) | - skb->data[ETH_ALEN + ETH_ALEN + 1])); - - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D length; -} - -static void release_dma_buff(struct net_local *lp) -{ - if (lp->dma_buff) { - free_pages((unsigned long)(lp->dma_buff), - get_order(lp->dmasize * 1024)); - lp->dma_buff =3D NULL; - } -} - -#endif /* ALLOW_DMA */ - -static void -control_dc_dc(struct net_device *dev, int on_not_off) -{ - struct net_local *lp =3D netdev_priv(dev); - unsigned int selfcontrol; - unsigned long timenow =3D jiffies; - /* control the DC to DC convertor in the SelfControl register. - * Note: This is hooked up to a general purpose pin, might not - * always be a DC to DC convertor. - */ - - selfcontrol =3D HCB1_ENBL; /* Enable the HCB1 bit as an output */ - if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) !=3D 0) ^ on_not_off) - selfcontrol |=3D HCB1; - else - selfcontrol &=3D ~HCB1; - writereg(dev, PP_SelfCTL, selfcontrol); - - /* Wait for the DC/DC converter to power up - 500ms */ - while (time_before(jiffies, timenow + HZ)) - ; -} - -/* send a test packet - return true if carrier bits are ok */ -static int -send_test_pkt(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - char test_packet[] =3D { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 46, /* A 46 in network order */ - 0, 0, /* DSAP=3D0 & SSAP=3D0 fields */ - 0xf3, 0 /* Control (Test Req + P bit set) */ - }; - unsigned long timenow =3D jiffies; - - writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON); - - memcpy(test_packet, dev->dev_addr, ETH_ALEN); - memcpy(test_packet + ETH_ALEN, dev->dev_addr, ETH_ALEN); - - iowrite16(TX_AFTER_ALL, lp->virt_addr + TX_CMD_PORT); - iowrite16(ETH_ZLEN, lp->virt_addr + TX_LEN_PORT); - - /* Test to see if the chip has allocated memory for the packet */ - while (time_before(jiffies, timenow + 5)) - if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW) - break; - if (time_after_eq(jiffies, timenow + 5)) - return 0; /* this shouldn't happen */ - - /* Write the contents of the packet */ - writewords(lp, TX_FRAME_PORT, test_packet, (ETH_ZLEN + 1) >> 1); - - cs89_dbg(1, debug, "Sending test packet "); - /* wait a couple of jiffies for packet to be received */ - for (timenow =3D jiffies; time_before(jiffies, timenow + 3);) - ; - if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) =3D=3D TX_OK) { - cs89_dbg(1, cont, "succeeded\n"); - return 1; - } - cs89_dbg(1, cont, "failed\n"); - return 0; -} - -#define DETECTED_NONE 0 -#define DETECTED_RJ45H 1 -#define DETECTED_RJ45F 2 -#define DETECTED_AUI 3 -#define DETECTED_BNC 4 - -static int -detect_tp(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - unsigned long timenow =3D jiffies; - int fdx; - - cs89_dbg(1, debug, "%s: Attempting TP\n", dev->name); - - /* If connected to another full duplex capable 10-Base-T card - * the link pulses seem to be lost when the auto detect bit in - * the LineCTL is set. To overcome this the auto detect bit will - * be cleared whilst testing the 10-Base-T interface. This would - * not be necessary for the sparrow chip but is simpler to do it - * anyway. - */ - writereg(dev, PP_LineCTL, lp->linectl & ~AUI_ONLY); - control_dc_dc(dev, 0); - - /* Delay for the hardware to work out if the TP cable is present - * - 150ms - */ - for (timenow =3D jiffies; time_before(jiffies, timenow + 15);) - ; - if ((readreg(dev, PP_LineST) & LINK_OK) =3D=3D 0) - return DETECTED_NONE; - - if (lp->chip_type =3D=3D CS8900) { - switch (lp->force & 0xf0) { -#if 0 - case FORCE_AUTO: - pr_info("%s: cs8900 doesn't autonegotiate\n", - dev->name); - return DETECTED_NONE; -#endif - /* CS8900 doesn't support AUTO, change to HALF*/ - case FORCE_AUTO: - lp->force &=3D ~FORCE_AUTO; - lp->force |=3D FORCE_HALF; - break; - case FORCE_HALF: - break; - case FORCE_FULL: - writereg(dev, PP_TestCTL, - readreg(dev, PP_TestCTL) | FDX_8900); - break; - } - fdx =3D readreg(dev, PP_TestCTL) & FDX_8900; - } else { - switch (lp->force & 0xf0) { - case FORCE_AUTO: - lp->auto_neg_cnf =3D AUTO_NEG_ENABLE; - break; - case FORCE_HALF: - lp->auto_neg_cnf =3D 0; - break; - case FORCE_FULL: - lp->auto_neg_cnf =3D RE_NEG_NOW | ALLOW_FDX; - break; - } - - writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK); - - if ((lp->auto_neg_cnf & AUTO_NEG_BITS) =3D=3D AUTO_NEG_ENABLE) { - pr_info("%s: negotiating duplex...\n", dev->name); - while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) { - if (time_after(jiffies, timenow + 4000)) { - pr_err("**** Full / half duplex auto-negotiation timed out ****\n"); - break; - } - } - } - fdx =3D readreg(dev, PP_AutoNegST) & FDX_ACTIVE; - } - if (fdx) - return DETECTED_RJ45F; - else - return DETECTED_RJ45H; -} - -static int -detect_bnc(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - - cs89_dbg(1, debug, "%s: Attempting BNC\n", dev->name); - control_dc_dc(dev, 1); - - writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); - - if (send_test_pkt(dev)) - return DETECTED_BNC; - else - return DETECTED_NONE; -} - -static int -detect_aui(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - - cs89_dbg(1, debug, "%s: Attempting AUI\n", dev->name); - control_dc_dc(dev, 0); - - writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); - - if (send_test_pkt(dev)) - return DETECTED_AUI; - else - return DETECTED_NONE; -} - -/* We have a good packet(s), get it/them out of the buffers. */ -static void -net_rx(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - struct sk_buff *skb; - int status, length; - - status =3D ioread16(lp->virt_addr + RX_FRAME_PORT); - length =3D ioread16(lp->virt_addr + RX_FRAME_PORT); - - if ((status & RX_OK) =3D=3D 0) { - count_rx_errors(status, dev); - return; - } - - /* Malloc up new buffer. */ - skb =3D netdev_alloc_skb(dev, length + 2); - if (skb =3D=3D NULL) { - dev->stats.rx_dropped++; - return; - } - skb_reserve(skb, 2); /* longword align L3 header */ - - readwords(lp, RX_FRAME_PORT, skb_put(skb, length), length >> 1); - if (length & 1) - skb->data[length-1] =3D ioread16(lp->virt_addr + RX_FRAME_PORT); - - cs89_dbg(3, debug, "%s: received %d byte packet of type %x\n", - dev->name, length, - (skb->data[ETH_ALEN + ETH_ALEN] << 8) | - skb->data[ETH_ALEN + ETH_ALEN + 1]); - - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D length; -} - -/* The typical workload of the driver: - * Handle the network interface interrupts. - */ - -static irqreturn_t net_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D dev_id; - struct net_local *lp; - int status; - int handled =3D 0; - - lp =3D 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 =3D ioread16(lp->virt_addr + ISQ_PORT))) { - cs89_dbg(4, debug, "%s: event=3D%04x\n", dev->name, status); - handled =3D 1; - switch (status & ISQ_EVENT_MASK) { - case ISQ_RECEIVER_EVENT: - /* Got a packet(s). */ - net_rx(dev); - break; - case ISQ_TRANSMITTER_EVENT: - dev->stats.tx_packets++; - netif_wake_queue(dev); /* Inform upper layers. */ - if ((status & (TX_OK | - TX_LOST_CRS | - TX_SQE_ERROR | - TX_LATE_COL | - TX_16_COL)) !=3D TX_OK) { - if ((status & TX_OK) =3D=3D 0) - dev->stats.tx_errors++; - if (status & TX_LOST_CRS) - dev->stats.tx_carrier_errors++; - if (status & TX_SQE_ERROR) - dev->stats.tx_heartbeat_errors++; - if (status & TX_LATE_COL) - dev->stats.tx_window_errors++; - if (status & TX_16_COL) - dev->stats.tx_aborted_errors++; - } - break; - case ISQ_BUFFER_EVENT: - if (status & READY_FOR_TX) { - /* we tried to transmit a packet earlier, - * but inexplicably ran out of buffers. - * That shouldn't happen since we only ever - * load one packet. Shrug. Do the right - * thing anyway. - */ - netif_wake_queue(dev); /* Inform upper layers. */ - } - if (status & TX_UNDERRUN) { - cs89_dbg(0, err, "%s: transmit underrun\n", - dev->name); - lp->send_underrun++; - if (lp->send_underrun =3D=3D 3) - lp->send_cmd =3D TX_AFTER_381; - else if (lp->send_underrun =3D=3D 6) - lp->send_cmd =3D TX_AFTER_ALL; - /* transmit cycle is done, although - * frame wasn't transmitted - this - * avoids having to wait for the upper - * layers to timeout on us, in the - * event of a tx underrun - */ - netif_wake_queue(dev); /* Inform upper layers. */ - } -#if ALLOW_DMA - if (lp->use_dma && (status & RX_DMA)) { - int count =3D readreg(dev, PP_DmaFrameCnt); - while (count) { - cs89_dbg(5, debug, - "%s: receiving %d DMA frames\n", - dev->name, count); - if (count > 1) - cs89_dbg(2, debug, - "%s: receiving %d DMA frames\n", - dev->name, count); - dma_rx(dev); - if (--count =3D=3D 0) - count =3D readreg(dev, PP_DmaFrameCnt); - if (count > 0) - cs89_dbg(2, debug, - "%s: continuing with %d DMA frames\n", - dev->name, count); - } - } -#endif - break; - case ISQ_RX_MISS_EVENT: - dev->stats.rx_missed_errors +=3D (status >> 6); - break; - case ISQ_TX_COL_EVENT: - dev->stats.collisions +=3D (status >> 6); - break; - } - } - return IRQ_RETVAL(handled); -} - -/* Open/initialize the board. This is called (in the current kernel) - sometime after booting when the 'ifconfig' program is run. - - This routine should set everything up anew at each open, even - registers that "should" only need to be set once at boot, so that - there is non-reboot way to recover if something goes wrong. -*/ - -/* AKPM: do we need to do any locking here? */ - -static int -net_open(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - int result =3D 0; - int i; - int ret; - - if (dev->irq < 2) { - /* Allow interrupts to be generated by the chip */ -/* Cirrus' release had this: */ -#if 0 - writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); -#endif -/* And 2.3.47 had this: */ - writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); - - for (i =3D 2; i < CS8920_NO_INTS; i++) { - if ((1 << i) & lp->irq_map) { - if (request_irq(i, net_interrupt, 0, dev->name, - dev) =3D=3D 0) { - dev->irq =3D i; - write_irq(dev, lp->chip_type, i); - /* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */ - break; - } - } - } - - if (i >=3D CS8920_NO_INTS) { - writereg(dev, PP_BusCTL, 0); /* disable interrupts. */ - pr_err("can't get an interrupt\n"); - ret =3D -EAGAIN; - goto bad_out; - } - } else { -#if IS_ENABLED(CONFIG_CS89x0_ISA) - if (((1 << dev->irq) & lp->irq_map) =3D=3D 0) { - pr_err("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", - dev->name, dev->irq, lp->irq_map); - ret =3D -EAGAIN; - goto bad_out; - } -#endif -/* FIXME: Cirrus' release had this: */ - writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ); -/* And 2.3.47 had this: */ -#if 0 - writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); -#endif - write_irq(dev, lp->chip_type, dev->irq); - ret =3D request_irq(dev->irq, net_interrupt, 0, dev->name, dev); - if (ret) { - pr_err("request_irq(%d) failed\n", dev->irq); - goto bad_out; - } - } - -#if ALLOW_DMA - if (lp->use_dma && (lp->isa_config & ANY_ISA_DMA)) { - unsigned long flags; - lp->dma_buff =3D (unsigned char *)__get_dma_pages(GFP_KERNEL, - get_order(lp->dmasize * 1024)); - if (!lp->dma_buff) { - pr_err("%s: cannot get %dK memory for DMA\n", - dev->name, lp->dmasize); - goto release_irq; - } - cs89_dbg(1, debug, "%s: dma %lx %lx\n", - dev->name, - (unsigned long)lp->dma_buff, - (unsigned long)isa_virt_to_bus(lp->dma_buff)); - if ((unsigned long)lp->dma_buff >=3D MAX_DMA_ADDRESS || - !dma_page_eq(lp->dma_buff, - lp->dma_buff + lp->dmasize * 1024 - 1)) { - pr_err("%s: not usable as DMA buffer\n", dev->name); - goto release_irq; - } - memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */ - if (request_dma(dev->dma, dev->name)) { - pr_err("%s: cannot get dma channel %d\n", - dev->name, dev->dma); - goto release_irq; - } - write_dma(dev, lp->chip_type, dev->dma); - lp->rx_dma_ptr =3D lp->dma_buff; - lp->end_dma_buff =3D lp->dma_buff + lp->dmasize * 1024; - spin_lock_irqsave(&lp->lock, flags); - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */ - set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff)); - set_dma_count(dev->dma, lp->dmasize * 1024); - enable_dma(dev->dma); - spin_unlock_irqrestore(&lp->lock, flags); - } -#endif /* ALLOW_DMA */ - - /* set the Ethernet address */ - for (i =3D 0; i < ETH_ALEN / 2; i++) - writereg(dev, PP_IA + i * 2, - (dev->dev_addr[i * 2] | - (dev->dev_addr[i * 2 + 1] << 8))); - - /* while we're testing the interface, leave interrupts disabled */ - writereg(dev, PP_BusCTL, MEMORY_ON); - - /* Set the LineCTL quintuplet based on adapter configuration read from EE= PROM */ - if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && - (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) - lp->linectl =3D LOW_RX_SQUELCH; - else - lp->linectl =3D 0; - - /* check to make sure that they have the "right" hardware available */ - switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) { - case A_CNF_MEDIA_10B_T: - result =3D lp->adapter_cnf & A_CNF_10B_T; - break; - case A_CNF_MEDIA_AUI: - result =3D lp->adapter_cnf & A_CNF_AUI; - break; - case A_CNF_MEDIA_10B_2: - result =3D lp->adapter_cnf & A_CNF_10B_2; - break; - default: - result =3D lp->adapter_cnf & (A_CNF_10B_T | - A_CNF_AUI | - A_CNF_10B_2); - } - if (!result) { - pr_err("%s: EEPROM is configured for unavailable media\n", - dev->name); -release_dma: -#if ALLOW_DMA - free_dma(dev->dma); -release_irq: - release_dma_buff(lp); -#endif - writereg(dev, PP_LineCTL, - readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); - free_irq(dev->irq, dev); - ret =3D -EAGAIN; - goto bad_out; - } - - /* set the hardware to the configured choice */ - switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) { - case A_CNF_MEDIA_10B_T: - result =3D detect_tp(dev); - if (result =3D=3D DETECTED_NONE) { - pr_warn("%s: 10Base-T (RJ-45) has no cable\n", - dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result =3D DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse = */ - } - break; - case A_CNF_MEDIA_AUI: - result =3D detect_aui(dev); - if (result =3D=3D DETECTED_NONE) { - pr_warn("%s: 10Base-5 (AUI) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result =3D DETECTED_AUI; /* Yes! I don't care if I see a carrier */ - } - break; - case A_CNF_MEDIA_10B_2: - result =3D detect_bnc(dev); - if (result =3D=3D DETECTED_NONE) { - pr_warn("%s: 10Base-2 (BNC) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result =3D DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */ - } - break; - case A_CNF_MEDIA_AUTO: - writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET); - if (lp->adapter_cnf & A_CNF_10B_T) { - result =3D detect_tp(dev); - if (result !=3D DETECTED_NONE) - break; - } - if (lp->adapter_cnf & A_CNF_AUI) { - result =3D detect_aui(dev); - if (result !=3D DETECTED_NONE) - break; - } - if (lp->adapter_cnf & A_CNF_10B_2) { - result =3D detect_bnc(dev); - if (result !=3D DETECTED_NONE) - break; - } - pr_err("%s: no media detected\n", dev->name); - goto release_dma; - } - switch (result) { - case DETECTED_NONE: - pr_err("%s: no network cable attached to configured media\n", - dev->name); - goto release_dma; - case DETECTED_RJ45H: - pr_info("%s: using half-duplex 10Base-T (RJ-45)\n", dev->name); - break; - case DETECTED_RJ45F: - pr_info("%s: using full-duplex 10Base-T (RJ-45)\n", dev->name); - break; - case DETECTED_AUI: - pr_info("%s: using 10Base-5 (AUI)\n", dev->name); - break; - case DETECTED_BNC: - pr_info("%s: using 10Base-2 (BNC)\n", dev->name); - break; - } - - /* Turn on both receive and transmit operations */ - writereg(dev, PP_LineCTL, - readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); - - /* Receive only error free packets addressed to this card */ - lp->rx_mode =3D 0; - writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); - - lp->curr_rx_cfg =3D RX_OK_ENBL | RX_CRC_ERROR_ENBL; - - if (lp->isa_config & STREAM_TRANSFER) - lp->curr_rx_cfg |=3D RX_STREAM_ENBL; -#if ALLOW_DMA - set_dma_cfg(dev); -#endif - writereg(dev, PP_RxCFG, lp->curr_rx_cfg); - - writereg(dev, PP_TxCFG, (TX_LOST_CRS_ENBL | - TX_SQE_ERROR_ENBL | - TX_OK_ENBL | - TX_LATE_COL_ENBL | - TX_JBR_ENBL | - TX_ANY_COL_ENBL | - TX_16_COL_ENBL)); - - writereg(dev, PP_BufCFG, (READY_FOR_TX_ENBL | - RX_MISS_COUNT_OVRFLOW_ENBL | -#if ALLOW_DMA - dma_bufcfg(dev) | -#endif - TX_COL_COUNT_OVRFLOW_ENBL | - TX_UNDERRUN_ENBL)); - - /* now that we've got our act together, enable everything */ - writereg(dev, PP_BusCTL, (ENABLE_IRQ - | (dev->mem_start ? MEMORY_ON : 0) /* turn memory on */ -#if ALLOW_DMA - | dma_busctl(dev) -#endif - )); - netif_start_queue(dev); - cs89_dbg(1, debug, "net_open() succeeded\n"); - return 0; -bad_out: - return ret; -} - -/* The inverse routine to net_open(). */ -static int -net_close(struct net_device *dev) -{ -#if ALLOW_DMA - struct net_local *lp =3D netdev_priv(dev); -#endif - - netif_stop_queue(dev); - - writereg(dev, PP_RxCFG, 0); - writereg(dev, PP_TxCFG, 0); - writereg(dev, PP_BufCFG, 0); - writereg(dev, PP_BusCTL, 0); - - free_irq(dev->irq, dev); - -#if ALLOW_DMA - if (lp->use_dma && lp->dma) { - free_dma(dev->dma); - release_dma_buff(lp); - } -#endif - - /* Update the statistics here. */ - return 0; -} - -/* Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats * -net_get_stats(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&lp->lock, flags); - /* Update the statistics from the device registers. */ - dev->stats.rx_missed_errors +=3D (readreg(dev, PP_RxMiss) >> 6); - dev->stats.collisions +=3D (readreg(dev, PP_TxCol) >> 6); - spin_unlock_irqrestore(&lp->lock, flags); - - return &dev->stats; -} - -static void net_timeout(struct net_device *dev, unsigned int txqueue) -{ - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - cs89_dbg(0, err, "%s: transmit timed out, %s?\n", - dev->name, - tx_done(dev) ? "IRQ conflict" : "network cable problem"); - /* Try to restart the adaptor. */ - netif_wake_queue(dev); -} - -static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device = *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - unsigned long flags; - - cs89_dbg(3, debug, "%s: sent %d byte packet of type %x\n", - dev->name, skb->len, - ((skb->data[ETH_ALEN + ETH_ALEN] << 8) | - skb->data[ETH_ALEN + ETH_ALEN + 1])); - - /* keep the upload from being interrupted, since we - * ask the chip to start transmitting before the - * whole packet has been completely uploaded. - */ - - spin_lock_irqsave(&lp->lock, flags); - netif_stop_queue(dev); - - /* initiate a transmit sequence */ - iowrite16(lp->send_cmd, lp->virt_addr + TX_CMD_PORT); - iowrite16(skb->len, lp->virt_addr + TX_LEN_PORT); - - /* Test to see if the chip has allocated memory for the packet */ - if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) =3D=3D 0) { - /* Gasp! It hasn't. But that shouldn't happen since - * we're waiting for TxOk, so return 1 and requeue this packet. - */ - - spin_unlock_irqrestore(&lp->lock, flags); - cs89_dbg(0, err, "Tx buffer not free!\n"); - return NETDEV_TX_BUSY; - } - /* Write the contents of the packet */ - writewords(lp, TX_FRAME_PORT, skb->data, (skb->len + 1) >> 1); - spin_unlock_irqrestore(&lp->lock, flags); - dev->stats.tx_bytes +=3D skb->len; - dev_consume_skb_any(skb); - - /* We DO NOT call netif_wake_queue() here. - * We also DO NOT call netif_start_queue(). - * - * Either of these would cause another bottom half run through - * net_send_packet() before this packet has fully gone out. - * That causes us to hit the "Gasp!" above and the send is rescheduled. - * it runs like a dog. We just return and wait for the Tx completion - * interrupt handler to restart the netdevice layer - */ - - return NETDEV_TX_OK; -} - -static void set_multicast_list(struct net_device *dev) -{ - struct net_local *lp =3D netdev_priv(dev); - unsigned long flags; - u16 cfg; - - spin_lock_irqsave(&lp->lock, flags); - if (dev->flags & IFF_PROMISC) - lp->rx_mode =3D 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 =3D RX_MULTCAST_ACCEPT; - else - lp->rx_mode =3D 0; - - writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); - - /* in promiscuous mode, we accept errored packets, - * so we have to enable interrupts on them also - */ - cfg =3D lp->curr_rx_cfg; - if (lp->rx_mode =3D=3D RX_ALL_ACCEPT) - cfg |=3D RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL; - writereg(dev, PP_RxCFG, cfg); - spin_unlock_irqrestore(&lp->lock, flags); -} - -static int set_mac_address(struct net_device *dev, void *p) -{ - int i; - struct sockaddr *addr =3D p; - - if (netif_running(dev)) - return -EBUSY; - - eth_hw_addr_set(dev, addr->sa_data); - - cs89_dbg(0, debug, "%s: Setting MAC address to %pM\n", - dev->name, dev->dev_addr); - - /* set the Ethernet address */ - for (i =3D 0; i < ETH_ALEN / 2; i++) - writereg(dev, PP_IA + i * 2, - (dev->dev_addr[i * 2] | - (dev->dev_addr[i * 2 + 1] << 8))); - - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling receive - used by netconsole and other diagnostic tools - * to allow network i/o with interrupts disabled. - */ -static void net_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - net_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -static const struct net_device_ops net_ops =3D { - .ndo_open =3D net_open, - .ndo_stop =3D net_close, - .ndo_tx_timeout =3D net_timeout, - .ndo_start_xmit =3D net_send_packet, - .ndo_get_stats =3D net_get_stats, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_set_mac_address =3D set_mac_address, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D net_poll_controller, -#endif - .ndo_validate_addr =3D eth_validate_addr, -}; - -static void __init reset_chip(struct net_device *dev) -{ -#if !defined(CONFIG_MACH_MX31ADS) - struct net_local *lp =3D netdev_priv(dev); - unsigned long reset_start_time; - - writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); - - /* wait 30 ms */ - msleep(30); - - if (lp->chip_type !=3D CS8900) { - /* Hardware problem requires PNP registers to be reconfigured after a re= set */ - iowrite16(PP_CS8920_ISAINT, lp->virt_addr + ADD_PORT); - iowrite8(dev->irq, lp->virt_addr + DATA_PORT); - iowrite8(0, lp->virt_addr + DATA_PORT + 1); - - iowrite16(PP_CS8920_ISAMemB, lp->virt_addr + ADD_PORT); - iowrite8((dev->mem_start >> 16) & 0xff, - lp->virt_addr + DATA_PORT); - iowrite8((dev->mem_start >> 8) & 0xff, - lp->virt_addr + DATA_PORT + 1); - } - - /* Wait until the chip is reset */ - reset_start_time =3D jiffies; - while ((readreg(dev, PP_SelfST) & INIT_DONE) =3D=3D 0 && - time_before(jiffies, reset_start_time + 2)) - ; -#endif /* !CONFIG_MACH_MX31ADS */ -} - -/* This is the real probe routine. - * Linux has a history of friendly device probes on the ISA bus. - * A good device probes avoids doing writes, and - * verifies that the correct device exists and functions. - * Return 0 on success. - */ -static int __init -cs89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular) -{ - struct net_local *lp =3D netdev_priv(dev); - int i; - int tmp; - unsigned rev_type =3D 0; - int eeprom_buff[CHKSUM_LEN]; - u8 addr[ETH_ALEN]; - int retval; - - /* Initialize the device structure. */ - if (!modular) { - memset(lp, 0, sizeof(*lp)); - spin_lock_init(&lp->lock); -#ifndef MODULE -#if ALLOW_DMA - if (g_cs89x0_dma) { - lp->use_dma =3D 1; - lp->dma =3D g_cs89x0_dma; - lp->dmasize =3D 16; /* Could make this an option... */ - } -#endif - lp->force =3D g_cs89x0_media__force; -#endif - } - - pr_debug("PP_addr at %p[%x]: 0x%x\n", - ioaddr, ADD_PORT, ioread16(ioaddr + ADD_PORT)); - iowrite16(PP_ChipID, ioaddr + ADD_PORT); - - tmp =3D ioread16(ioaddr + DATA_PORT); - if (tmp !=3D CHIP_EISA_ID_SIG) { - pr_debug("%s: incorrect signature at %p[%x]: 0x%x!=3D" - CHIP_EISA_ID_SIG_STR "\n", - dev->name, ioaddr, DATA_PORT, tmp); - retval =3D -ENODEV; - goto out1; - } - - lp->virt_addr =3D ioaddr; - - /* get the chip type */ - rev_type =3D readreg(dev, PRODUCT_ID_ADD); - lp->chip_type =3D rev_type & ~REVISON_BITS; - lp->chip_revision =3D ((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 =3D TX_AFTER_381; - if (lp->chip_type =3D=3D CS8900 && lp->chip_revision >=3D 'F') - lp->send_cmd =3D TX_NOW; - if (lp->chip_type !=3D CS8900 && lp->chip_revision >=3D 'C') - lp->send_cmd =3D TX_NOW; - - pr_info_once("%s\n", version); - - pr_info("%s: cs89%c0%s rev %c found at %p ", - dev->name, - lp->chip_type =3D=3D CS8900 ? '0' : '2', - lp->chip_type =3D=3D CS8920M ? "M" : "", - lp->chip_revision, - lp->virt_addr); - - reset_chip(dev); - - /* Here we read the current configuration of the chip. - * If there is no Extended EEPROM then the idea is to not disturb - * the chip configuration, it should have been correctly setup by - * automatic EEPROM read on reset. So, if the chip says it read - * the EEPROM the driver will always do *something* instead of - * complain that adapter_cnf is 0. - */ - - if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) =3D=3D - (EEPROM_OK | EEPROM_PRESENT)) { - /* Load the MAC. */ - for (i =3D 0; i < ETH_ALEN / 2; i++) { - unsigned int Addr; - Addr =3D readreg(dev, PP_IA + i * 2); - addr[i * 2] =3D Addr & 0xFF; - addr[i * 2 + 1] =3D Addr >> 8; - } - eth_hw_addr_set(dev, addr); - - /* Load the Adapter Configuration. - * Note: Barring any more specific information from some - * other source (ie EEPROM+Schematics), we would not know - * how to operate a 10Base2 interface on the AUI port. - * However, since we do read the status of HCB1 and use - * settings that always result in calls to control_dc_dc(dev,0) - * a BNC interface should work if the enable pin - * (dc/dc converter) is on HCB1. - * It will be called AUI however. - */ - - lp->adapter_cnf =3D 0; - i =3D readreg(dev, PP_LineCTL); - /* Preserve the setting of the HCB1 pin. */ - if ((i & (HCB1 | HCB1_ENBL)) =3D=3D (HCB1 | HCB1_ENBL)) - lp->adapter_cnf |=3D A_CNF_DC_DC_POLARITY; - /* Save the sqelch bit */ - if ((i & LOW_RX_SQUELCH) =3D=3D LOW_RX_SQUELCH) - lp->adapter_cnf |=3D A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH; - /* Check if the card is in 10Base-t only mode */ - if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) =3D=3D 0) - lp->adapter_cnf |=3D A_CNF_10B_T | A_CNF_MEDIA_10B_T; - /* Check if the card is in AUI only mode */ - if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) =3D=3D AUI_ONLY) - lp->adapter_cnf |=3D A_CNF_AUI | A_CNF_MEDIA_AUI; - /* Check if the card is in Auto mode. */ - if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) =3D=3D AUTO_AUI_10BASET) - lp->adapter_cnf |=3D A_CNF_AUI | A_CNF_10B_T | - A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO; - - cs89_dbg(1, info, "%s: PP_LineCTL=3D0x%x, adapter_cnf=3D0x%x\n", - dev->name, i, lp->adapter_cnf); - - /* IRQ. Other chips already probe, see below. */ - if (lp->chip_type =3D=3D CS8900) - lp->isa_config =3D readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK; - - pr_cont("[Cirrus EEPROM] "); - } - - pr_cont("\n"); - - /* First check to see if an EEPROM is attached. */ - - if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) =3D=3D 0) - pr_warn("No EEPROM, relying on command line....\n"); - else if (get_eeprom_data(dev, START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff)= < 0) { - pr_warn("EEPROM read failed, relying on command line\n"); - } else if (get_eeprom_cksum(START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) <= 0) { - /* Check if the chip was able to read its own configuration starting - at 0 in the EEPROM*/ - if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=3D - (EEPROM_OK | EEPROM_PRESENT)) - pr_warn("Extended EEPROM checksum bad and no Cirrus EEPROM, relying on = command line\n"); - - } else { - /* This reads an extended EEPROM that is not documented - * in the CS8900 datasheet. - */ - - /* get transmission control word but keep the autonegotiation bits */ - if (!lp->auto_neg_cnf) - lp->auto_neg_cnf =3D eeprom_buff[AUTO_NEG_CNF_OFFSET / 2]; - /* Store adapter configuration */ - if (!lp->adapter_cnf) - lp->adapter_cnf =3D eeprom_buff[ADAPTER_CNF_OFFSET / 2]; - /* Store ISA configuration */ - lp->isa_config =3D eeprom_buff[ISA_CNF_OFFSET / 2]; - dev->mem_start =3D eeprom_buff[PACKET_PAGE_OFFSET / 2] << 8; - - /* eeprom_buff has 32-bit ints, so we can't just memcpy it */ - /* store the initial memory base address */ - for (i =3D 0; i < ETH_ALEN / 2; i++) { - addr[i * 2] =3D eeprom_buff[i]; - addr[i * 2 + 1] =3D eeprom_buff[i] >> 8; - } - eth_hw_addr_set(dev, addr); - cs89_dbg(1, debug, "%s: new adapter_cnf: 0x%x\n", - dev->name, lp->adapter_cnf); - } - - /* allow them to force multiple transceivers. If they force multiple, au= tosense */ - { - int count =3D 0; - if (lp->force & FORCE_RJ45) { - lp->adapter_cnf |=3D A_CNF_10B_T; - count++; - } - if (lp->force & FORCE_AUI) { - lp->adapter_cnf |=3D A_CNF_AUI; - count++; - } - if (lp->force & FORCE_BNC) { - lp->adapter_cnf |=3D A_CNF_10B_2; - count++; - } - if (count > 1) - lp->adapter_cnf |=3D A_CNF_MEDIA_AUTO; - else if (lp->force & FORCE_RJ45) - lp->adapter_cnf |=3D A_CNF_MEDIA_10B_T; - else if (lp->force & FORCE_AUI) - lp->adapter_cnf |=3D A_CNF_MEDIA_AUI; - else if (lp->force & FORCE_BNC) - lp->adapter_cnf |=3D A_CNF_MEDIA_10B_2; - } - - cs89_dbg(1, debug, "%s: after force 0x%x, adapter_cnf=3D0x%x\n", - dev->name, lp->force, lp->adapter_cnf); - - /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the = command line: add it here */ - - /* FIXME: We don't let you set the IMM bit from the command line: add it = to lp->auto_neg_cnf here */ - - /* FIXME: we don't set the Ethernet address on the command line. Use - * ifconfig IFACE hw ether AABBCCDDEEFF - */ - - pr_info("media %s%s%s", - (lp->adapter_cnf & A_CNF_10B_T) ? "RJ-45," : "", - (lp->adapter_cnf & A_CNF_AUI) ? "AUI," : "", - (lp->adapter_cnf & A_CNF_10B_2) ? "BNC," : ""); - - lp->irq_map =3D 0xffff; - - /* If this is a CS8900 then no pnp soft */ - if (lp->chip_type !=3D CS8900 && - /* Check if the ISA IRQ has been set */ - (i =3D readreg(dev, PP_CS8920_ISAINT) & 0xff, - (i !=3D 0 && i < CS8920_NO_INTS))) { - if (!dev->irq) - dev->irq =3D i; - } else { - i =3D lp->isa_config & INT_NO_MASK; -#if IS_ENABLED(CONFIG_CS89x0_ISA) - if (lp->chip_type =3D=3D CS8900) { - /* Translate the IRQ using the IRQ mapping table. */ - if (i >=3D ARRAY_SIZE(cs8900_irq_map)) - pr_err("invalid ISA interrupt number %d\n", i); - else - i =3D cs8900_irq_map[i]; - - lp->irq_map =3D CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */ - } else { - int irq_map_buff[IRQ_MAP_LEN/2]; - - if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA, - IRQ_MAP_LEN / 2, - irq_map_buff) >=3D 0) { - if ((irq_map_buff[0] & 0xff) =3D=3D PNP_IRQ_FRMT) - lp->irq_map =3D ((irq_map_buff[0] >> 8) | - (irq_map_buff[1] << 8)); - } - } -#endif - if (!dev->irq) - dev->irq =3D i; - } - - pr_cont(" IRQ %d", dev->irq); - -#if ALLOW_DMA - if (lp->use_dma) { - get_dma_channel(dev); - pr_cont(", DMA %d", dev->dma); - } else -#endif - pr_cont(", programmed I/O"); - - /* print the ethernet address. */ - pr_cont(", MAC %pM\n", dev->dev_addr); - - dev->netdev_ops =3D &net_ops; - dev->watchdog_timeo =3D HZ; - - cs89_dbg(0, info, "cs89x0_probe1() successful\n"); - - retval =3D register_netdev(dev); - if (retval) - goto out2; - return 0; -out2: - iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT); -out1: - return retval; -} - -#if IS_ENABLED(CONFIG_CS89x0_ISA) -/* - * This function converts the I/O port address used by the cs89x0_probe() = and - * init_module() functions to the I/O memory address used by the - * cs89x0_probe1() function. - */ -static int __init -cs89x0_ioport_probe(struct net_device *dev, unsigned long ioport, int modu= lar) -{ - struct net_local *lp =3D netdev_priv(dev); - int ret; - void __iomem *io_mem; - - if (!lp) - return -ENOMEM; - - dev->base_addr =3D ioport; - - if (!request_region(ioport, NETCARD_IO_EXTENT, DRV_NAME)) { - ret =3D -EBUSY; - goto out; - } - - io_mem =3D ioport_map(ioport & ~3, NETCARD_IO_EXTENT); - if (!io_mem) { - ret =3D -ENOMEM; - goto release; - } - - /* if they give us an odd I/O address, then do ONE write to - * the address port, to get it back to address zero, where we - * expect to find the EISA signature word. An IO with a base of 0x3 - * will skip the test for the ADD_PORT. - */ - if (ioport & 1) { - cs89_dbg(1, info, "%s: odd ioaddr 0x%lx\n", dev->name, ioport); - if ((ioport & 2) !=3D 2) { - if ((ioread16(io_mem + ADD_PORT) & ADD_MASK) !=3D - ADD_SIG) { - pr_err("%s: bad signature 0x%x\n", - dev->name, ioread16(io_mem + ADD_PORT)); - ret =3D -ENODEV; - goto unmap; - } - } - } - - ret =3D cs89x0_probe1(dev, io_mem, modular); - if (!ret) - goto out; -unmap: - ioport_unmap(io_mem); -release: - release_region(ioport, NETCARD_IO_EXTENT); -out: - return ret; -} - -#ifndef MODULE -/* Check for a network adaptor of this type, and return '0' iff one exists. - * If dev->base_addr =3D=3D 0, probe all likely locations. - * If dev->base_addr =3D=3D 1, always return failure. - * If dev->base_addr =3D=3D 2, allocate space for the device and return su= ccess - * (detachable devices only). - * Return 0 on success. - */ - -struct net_device * __init cs89x0_probe(int unit) -{ - struct net_device *dev =3D alloc_etherdev(sizeof(struct net_local)); - unsigned *port; - int err =3D 0; - int irq; - int io; - - if (!dev) - return ERR_PTR(-ENODEV); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - io =3D dev->base_addr; - irq =3D dev->irq; - - cs89_dbg(0, info, "cs89x0_probe(0x%x)\n", io); - - if (io > 0x1ff) { /* Check a single specified location. */ - err =3D cs89x0_ioport_probe(dev, io, 0); - } else if (io !=3D 0) { /* Don't probe at all. */ - err =3D -ENXIO; - } else { - for (port =3D netcard_portlist; *port; port++) { - if (cs89x0_ioport_probe(dev, *port, 0) =3D=3D 0) - break; - dev->irq =3D irq; - } - if (!*port) - err =3D -ENODEV; - } - if (err) - goto out; - return dev; -out: - free_netdev(dev); - pr_warn("no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP= \n"); - return ERR_PTR(err); -} -#else -static struct net_device *dev_cs89x0; - -/* Support the 'debug' module parm even if we're compiled for non-debug to - * avoid breaking someone's startup scripts - */ - -static int io; -static int irq; -static int debug; -static char media[8]; -static int duplex =3D -1; - -static int use_dma; /* These generate unused var warnings if ALLOW_DMA = =3D 0 */ -static int dma; -static int dmasize =3D 16; /* or 64 */ - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param(debug, int, 0); -module_param_string(media, media, sizeof(media), 0); -module_param(duplex, int, 0); -module_param_hw(dma , int, dma, 0); -module_param(dmasize , int, 0); -module_param(use_dma , int, 0); -MODULE_PARM_DESC(io, "cs89x0 I/O base address"); -MODULE_PARM_DESC(irq, "cs89x0 IRQ number"); -#if DEBUGGING -MODULE_PARM_DESC(debug, "cs89x0 debug level (0-6)"); -#else -MODULE_PARM_DESC(debug, "(ignored)"); -#endif -MODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui= )"); -/* No other value than -1 for duplex seems to be currently interpreted */ -MODULE_PARM_DESC(duplex, "(ignored)"); -#if ALLOW_DMA -MODULE_PARM_DESC(dma , "cs89x0 ISA DMA channel; ignored if use_dma=3D0"); -MODULE_PARM_DESC(dmasize , "cs89x0 DMA size in kB (16,64); ignored if use_= dma=3D0"); -MODULE_PARM_DESC(use_dma , "cs89x0 using DMA (0-1)"); -#else -MODULE_PARM_DESC(dma , "(ignored)"); -MODULE_PARM_DESC(dmasize , "(ignored)"); -MODULE_PARM_DESC(use_dma , "(ignored)"); -#endif - -MODULE_AUTHOR("Mike Cruse, Russwll Nelson , Andrew Mort= on"); -MODULE_LICENSE("GPL"); - -/* - * media=3Dt - specify media type - * or media=3D2 - * or media=3Daui - * or medai=3Dauto - * duplex=3D0 - specify forced half/full/autonegotiate duplex - * debug=3D# - debug level - * - * Default Chip Configuration: - * DMA Burst =3D enabled - * IOCHRDY Enabled =3D enabled - * UseSA =3D enabled - * CS8900 defaults to half-duplex if not specified on command-line - * CS8920 defaults to autoneg if not specified on command-line - * Use reset defaults for other config parameters - * - * Assumptions: - * media type specified is supported (circuitry is present) - * if memory address is > 1MB, then required mem decode hw is present - * if 10B-2, then agent other than driver will enable DC/DC converter - * (hw or software util) - */ - -static int __init cs89x0_isa_init_module(void) -{ - struct net_device *dev; - struct net_local *lp; - int ret =3D 0; - -#if DEBUGGING - net_debug =3D debug; -#else - debug =3D 0; -#endif - dev =3D alloc_etherdev(sizeof(struct net_local)); - if (!dev) - return -ENOMEM; - - dev->irq =3D irq; - dev->base_addr =3D io; - lp =3D netdev_priv(dev); - -#if ALLOW_DMA - if (use_dma) { - lp->use_dma =3D use_dma; - lp->dma =3D dma; - lp->dmasize =3D dmasize; - } -#endif - - spin_lock_init(&lp->lock); - - /* boy, they'd better get these right */ - if (!strcmp(media, "rj45")) - lp->adapter_cnf =3D A_CNF_MEDIA_10B_T | A_CNF_10B_T; - else if (!strcmp(media, "aui")) - lp->adapter_cnf =3D A_CNF_MEDIA_AUI | A_CNF_AUI; - else if (!strcmp(media, "bnc")) - lp->adapter_cnf =3D A_CNF_MEDIA_10B_2 | A_CNF_10B_2; - else - lp->adapter_cnf =3D A_CNF_MEDIA_10B_T | A_CNF_10B_T; - - if (duplex =3D=3D -1) - lp->auto_neg_cnf =3D AUTO_NEG_ENABLE; - - if (io =3D=3D 0) { - pr_err("Module autoprobing not allowed\n"); - pr_err("Append io=3D0xNNN\n"); - ret =3D -EPERM; - goto out; - } else if (io <=3D 0x1ff) { - ret =3D -ENXIO; - goto out; - } - -#if ALLOW_DMA - if (use_dma && dmasize !=3D 16 && dmasize !=3D 64) { - pr_err("dma size must be either 16K or 64K, not %dK\n", - dmasize); - ret =3D -EPERM; - goto out; - } -#endif - ret =3D cs89x0_ioport_probe(dev, io, 1); - if (ret) - goto out; - - dev_cs89x0 =3D dev; - return 0; -out: - free_netdev(dev); - return ret; -} -module_init(cs89x0_isa_init_module); - -static void __exit cs89x0_isa_cleanup_module(void) -{ - struct net_local *lp =3D netdev_priv(dev_cs89x0); - - unregister_netdev(dev_cs89x0); - iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT); - ioport_unmap(lp->virt_addr); - release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); - free_netdev(dev_cs89x0); -} -module_exit(cs89x0_isa_cleanup_module); -#endif /* MODULE */ -#endif /* CONFIG_CS89x0_ISA */ - -#if IS_ENABLED(CONFIG_CS89x0_PLATFORM) -static int __init cs89x0_platform_probe(struct platform_device *pdev) -{ - struct net_device *dev =3D alloc_etherdev(sizeof(struct net_local)); - void __iomem *virt_addr; - int err; - - if (!dev) - return -ENOMEM; - - dev->irq =3D platform_get_irq(pdev, 0); - if (dev->irq < 0) { - err =3D dev->irq; - goto free; - } - - virt_addr =3D devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(virt_addr)) { - err =3D PTR_ERR(virt_addr); - goto free; - } - - err =3D cs89x0_probe1(dev, virt_addr, 0); - if (err) { - dev_warn(&dev->dev, "no cs8900 or cs8920 detected\n"); - goto free; - } - - platform_set_drvdata(pdev, dev); - return 0; - -free: - free_netdev(dev); - return err; -} - -static void cs89x0_platform_remove(struct platform_device *pdev) -{ - struct net_device *dev =3D platform_get_drvdata(pdev); - - /* This platform_get_resource() call will not return NULL, because - * the same call in cs89x0_platform_probe() has returned a non NULL - * value. - */ - unregister_netdev(dev); - free_netdev(dev); -} - -static const struct of_device_id __maybe_unused cs89x0_match[] =3D { - { .compatible =3D "cirrus,cs8900", }, - { .compatible =3D "cirrus,cs8920", }, - { }, -}; -MODULE_DEVICE_TABLE(of, cs89x0_match); - -static struct platform_driver cs89x0_driver =3D { - .driver =3D { - .name =3D DRV_NAME, - .of_match_table =3D of_match_ptr(cs89x0_match), - }, - .remove =3D cs89x0_platform_remove, -}; - -module_platform_driver_probe(cs89x0_driver, cs89x0_platform_probe); - -#endif /* CONFIG_CS89x0_PLATFORM */ - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 net= work driver"); -MODULE_AUTHOR("Russell Nelson "); --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2E7023DCDB5; Tue, 21 Apr 2026 19:57:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801473; cv=none; b=kSbePN3bCl8bd+lRFvBBkXq45EuBeQWiw9Qu3v8rb+eHep475vCK03s3QtNtP8xgXNcxC1N9XIt4Z+BGyxqIMSRWipFngQmWWmplbze0uC0ofP8K/HNJPrmonC4zmPvf4fDO3oNTePPi+LDgtQ46k+A28D/BRHXGnDUn9b9b+/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801473; c=relaxed/simple; bh=W1gByLU7axMFlzQs7RTKWTuBeaHMDgQ5lwxUGkNl6HY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=e28Vo5N8TjFTLZrohrFVXkKSdeqX8QT/TF159WEBDenNARimlOZbv9W5w5tWY6KT+c91GyKlattWu1Q6sMjHhQG7XBX2r99ubBI/q798G55C8URBC/jdtZJrsTBUNKl8Gr+v6ZEItF/+TPPuGJvaxfJSjJMNOwgyUnvPdj/WZZ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=5McdgCw1; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="5McdgCw1" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=Gd0a+9Q2VoHOHPG1E+QCXElTHRR9W0KDTLt9O+vVhTI=; b=5M cdgCw1EmrZ8dYVKZIxscB8mLLVjowyTJizh7KitQrBeYzSvnbK3AjUIrdqAyk6F/n/8967qE1ZPrF 0O8T705/GQ3IJOH3wzMxrygkWdIVt+0jGctbw5VIxcx6MBBTGK5DY6sqqW3m48SOAUr6ZG3frOdCs x/++y0LRUNZsUQQ=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGp1-00GwVc-0X; Tue, 21 Apr 2026 21:31:47 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:15 -0500 Subject: [PATCH net 12/18] drivers: net: cirrus: mac89x0: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-12-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=37353; i=andrew@lunn.ch; h=from:subject:message-id; bh=W1gByLU7axMFlzQs7RTKWTuBeaHMDgQ5lwxUGkNl6HY=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CCrWRWDeCPtow9iT9kHuJ9PwyUfcJZt73+H EW+0LVj2suJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hI6nEADcNEHlBlyAzxJo5LnqQ7rRYxwI7CJwTdJ1EgecHN7Z2+Ohbix0Aeg8VmBDMAARtrKbXhP Efy8dumX6uWVM2i+tYhqKcBmfHyp+XmXsZc++/6KuTw3+H3rdj8qfD3Y815HZ3Ngi472kCWj0OT LvWwliOD35lwNxYx7Bdsm8Qdyow9hLNNAjHhhMGWRPJJm/0gB/sKUp3vvrI7Bd7QnxOJ8ThFQzJ umMgxGsTmilWEgCmaio7N0/Nuy0ffieyDFEOx1EtAo/Zw84icc0B8ngAWIo8K/d4nEmVY9OlDei VeXcoF6sFp0DhWpKhYVO0UTOoSV/b+72586OzhRa7PaG0HcBP/Lr2nbUuaMuRLjQ71QsLMjGdPz PS4EagEyAS9WU/JrsTRdkL4XXW6RcyKV1Nl6qOIpH1HBXc/egGDySsUsMwqyNRLQTg9Gi0C/Ktg fXif6ywEyAlUz+bqWcbiYVsNgKfMS59gzG/f+MCxcEMx6O8fZwyzTniHCYQTPKFv/Re0wzY8G75 bDxzkeWJ4kzQOkKUsPIcf6LLvaLFTGyRsSCKcS3B9XaX23NeCBO//YnCCrOKzvxsPnAi4nljhtb yBN7xr0x4mXXpp5j5WlREQYQ2VmMR4/IhbiMq+OYgJLRGzVpGRVSH2Wn7/bQ6bcn3r4Jshzr3e+ 3NWp5FiP1LXbU+g== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 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 --- 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/cir= rus/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. =20 -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/ci= rrus/Makefile index cb740939d976..03800af0f0e1 100644 --- a/drivers/net/ethernet/cirrus/Makefile +++ b/drivers/net/ethernet/cirrus/Makefile @@ -4,4 +4,3 @@ # =20 obj-$(CONFIG_EP93XX_ETH) +=3D ep93xx_eth.o -obj-$(CONFIG_MAC89x0) +=3D mac89x0.o diff --git a/drivers/net/ethernet/cirrus/cs89x0.h b/drivers/net/ethernet/ci= rrus/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 (CS= 8900 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 co= de) */ -#define MONGOOSE_BIT 0x2000 /* PART_NO_SIG + MONGOOSE_BUT =3D> ID of mong= oose */ -#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 fr= ee */ -#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/w= rite */ -#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_N= EG_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 fr= ame */ -#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_ENABL= E|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/c= irrus/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 - - 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 - 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[] =3D -"cs89x0.c:v1.02 11/26/96 Russell Nelson \n"; - -#include - -/* - Sources: - - Crynwr packet driver epktisa. - - Crystal Semiconductor data sheets. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "cs89x0.h" - -static int debug =3D -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 r= ow 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 =3D { - .ndo_open =3D net_open, - .ndo_stop =3D net_close, - .ndo_start_xmit =3D net_send_packet, - .ndo_get_stats =3D net_get_stats, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_set_mac_address =3D set_mac_address, - .ndo_validate_addr =3D 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 =3D 0; - unsigned long ioaddr; - unsigned short sig; - int err =3D -ENODEV; - struct nubus_rsrc *fres; - - dev =3D alloc_etherdev(sizeof(struct net_local)); - if (!dev) - return -ENOMEM; - - /* We might have to parameterize this later */ - slot =3D 0xE; - /* Get out now if there's a real NuBus card in slot E */ - for_each_func_rsrc(fres) - if (fres->board->slot =3D=3D slot) - goto out; - - /* The pseudo-ISA bits always live at offset 0x300 (gee, - wonder why...) */ - ioaddr =3D (unsigned long) - nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE); - { - int card_present; - - card_present =3D (hwreg_present((void *)ioaddr + 4) && - hwreg_present((void *)ioaddr + DATA_PORT)); - if (!card_present) - goto out; - } - - nubus_writew(0, ioaddr + ADD_PORT); - sig =3D nubus_readw(ioaddr + DATA_PORT); - if (sig !=3D swab16(CHIP_EISA_ID_SIG)) - goto out; - - SET_NETDEV_DEV(dev, &pdev->dev); - - /* Initialize the net_device structure. */ - lp =3D netdev_priv(dev); - - lp->msg_enable =3D netif_msg_init(debug, 0); - - /* Fill in the 'dev' fields. */ - dev->base_addr =3D ioaddr; - dev->mem_start =3D (unsigned long) - nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE); - dev->mem_end =3D dev->mem_start + 0x1000; - - /* Turn on shared memory */ - writereg_io(dev, PP_BusCTL, MEMORY_ON); - - /* get the chip type */ - rev_type =3D readreg(dev, PRODUCT_ID_ADD); - lp->chip_type =3D rev_type &~ REVISON_BITS; - lp->chip_revision =3D ((rev_type & REVISON_BITS) >> 8) + 'A'; - - /* Check the chip type and revision in order to set the correct send comm= and - CS8920 revision C and CS8900 revision F can use the faster send. */ - lp->send_cmd =3D TX_AFTER_381; - if (lp->chip_type =3D=3D CS8900 && lp->chip_revision >=3D 'F') - lp->send_cmd =3D TX_NOW; - if (lp->chip_type !=3D CS8900 && lp->chip_revision >=3D 'C') - lp->send_cmd =3D TX_NOW; - - netif_dbg(lp, drv, dev, "%s", version); - - pr_info("cs89%c0%s rev %c found at %#8lx\n", - lp->chip_type =3D=3D CS8900 ? '0' : '2', - lp->chip_type =3D=3D CS8920M ? "M" : "", - lp->chip_revision, dev->base_addr); - - /* Try to read the MAC address */ - if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) =3D=3D 0) { - pr_info("No EEPROM, giving up now.\n"); - goto out1; - } else { - u8 addr[ETH_ALEN]; - - for (i =3D 0; i < ETH_ALEN; i +=3D 2) { - /* Big-endian (why??!) */ - unsigned short s =3D readreg(dev, PP_IA + i); - addr[i] =3D s >> 8; - addr[i+1] =3D s & 0xff; - } - eth_hw_addr_set(dev, addr); - } - - dev->irq =3D SLOT2IRQ(slot); - - /* print the IRQ and ethernet address. */ - - pr_info("MAC %pM, IRQ %d\n", dev->dev_addr, dev->irq); - - dev->netdev_ops =3D &mac89x0_netdev_ops; - - err =3D 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 =3D 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 =3D=3D CS8900) - writereg(dev, PP_CS8900_ISAINT, 0); - else - writereg(dev, PP_CS8920_ISAINT, 0); - - /* set the Ethernet address */ - for (i=3D0; 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 | SERIA= L_TX_ON); - - /* Receive only error free packets addressed to this card */ - lp->rx_mode =3D 0; - writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); - - lp->curr_rx_cfg =3D 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 =3D 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) =3D=3D 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 =3D dev_id; - struct net_local *lp; - int ioaddr, status; - - ioaddr =3D dev->base_addr; - lp =3D 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 lim= it - 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 =3D swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) { - netif_dbg(lp, intr, dev, "status=3D%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) =3D=3D 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 =3D=3D 3) lp->send_c= md =3D TX_AFTER_381; - else if (lp->send_underrun =3D=3D 6) lp->s= end_cmd =3D TX_AFTER_ALL; - } - break; - case ISQ_RX_MISS_EVENT: - dev->stats.rx_missed_errors +=3D (status >> 6); - break; - case ISQ_TX_COL_EVENT: - dev->stats.collisions +=3D (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 =3D netdev_priv(dev); - struct sk_buff *skb; - int status, length; - - status =3D readreg(dev, PP_RxStatus); - if ((status & RX_OK) =3D=3D 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 =3D readreg(dev, PP_RxLength); - /* Malloc up new buffer. */ - skb =3D alloc_skb(length, GFP_ATOMIC); - if (skb =3D=3D 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=3Deth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D 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 +=3D (readreg(dev, PP_RxMiss) >> 6); - dev->stats.collisions +=3D (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 =3D netdev_priv(dev); - - if(dev->flags&IFF_PROMISC) - { - lp->rx_mode =3D 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 =3D RX_MULTCAST_ACCEPT; - } - else - lp->rx_mode =3D 0; - - writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); - - /* in promiscuous mode, we accept errored packets, so we have to enable i= nterrupts on them also */ - writereg(dev, PP_RxCFG, lp->curr_rx_cfg | - (lp->rx_mode =3D=3D RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|R= X_EXTRA_DATA_ENBL) : 0)); -} - - -static int set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *saddr =3D 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=3D0; 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 =3D 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 =3D { - .probe =3D mac89x0_device_probe, - .remove =3D mac89x0_device_remove, - .driver =3D { - .name =3D "mac89x0", - }, -}; - -module_platform_driver(mac89x0_platform_driver); --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A6C33D88F0; Tue, 21 Apr 2026 19:57:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801461; cv=none; b=DKItHj8kTwhDOeO49H2x4cJk6u2mqFuxU+0GlHowan/8qbFu5d+POc0vaSEVI3R8FL2cm7vzPA/3N87/URjFh5sPVbLRnpfx30AhhsWd+xB9L2y5itF0eKt9cwtlZMVwDskJvd8H7LhGZ2zqW+EeGJiVvO0BOJqVsvV1nfwr8fw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801461; c=relaxed/simple; bh=j210VXmsgnfsiosK3HjwZL9RWuyMORt8TMmSCCX8R4E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tDChYZDss0vrEGp7Z3iDXZAV+84clFEfNa7TQx5STPHii+lC+Wn14IJIZoE4LsnG4qUPnNKLVX5jHRYE2hBMxpPZl9FdrO2fV6MdllISu/BguydN0/UulpCOqMNC32DmKxrdHoZ3G+r7+X4ugbibXYR0oSGs/nerfSDRXXPrLI8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=XWt20gKJ; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="XWt20gKJ" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=cHVrIBNbMEO2oaXaakSg+VH8OQ+PF2rR6fx1P1Tt6B0=; b=XW t20gKJosgVrEwHv64Kivg/qMDwLb8+Zjzi+Z/oLaecV2Gno0gjjJx9FsqIzI3KQrPnHOSJpRGeBwp yUp2OfF5nJm1w9DYHgKzwtao8IdVRA2vZ8gkFcfWRaIEV+hJIG7ve0tyy2su/9dthsy8hE8nU9obc ckVvciPP0TBFp04=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGp3-00GwVc-Gg; Tue, 21 Apr 2026 21:31:49 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:16 -0500 Subject: [PATCH net 13/18] drivers: net: fujitsu: fmvj18x: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-13-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=39103; i=andrew@lunn.ch; h=from:subject:message-id; bh=j210VXmsgnfsiosK3HjwZL9RWuyMORt8TMmSCCX8R4E=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CCdyYydtSutPM46YfMsyZ++4g3YlUizh8GB 78BLXQVSPqJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hFS2D/9cpys1VcUh0AwIcQ8fdJCfgKzSNIM7gnFI1O2UZtuNJnYm/idltmoEYMXUeZXGU6n+43n 7BpWXaLTJzgRfYxAnpI7PC9VzS6q3hCYtl0m6wqkI/eslisjsosM03QSJhBHCeezxyxu8iNm/5B v9IBnkMNeF5W/cjVmaW7YaA14afdhGSi/8HdOmOFKxzn30aIJT272yTczRJVEXtJpx8kwtIvV32 UtBzS3Y3qilS+DcxkW6CP+6uCkfcWu+aBvyxfwLCPwd1J0Hx35GAlLxNS/3cclvB575zibo/D1g T6Ut7BMSPpXStqZ/sgSivWQZBUSNWq1kCnqGA9QJuxL7/pJOXoVP/p1KtaH1y8gy3xKGFdPdCKX 0lnQsnpYzjqMKpRZvGMaR80e4kRieNRvxA8i9yywfmJ4U3/XBJaKU4oxHY6OhTFWpJtOblWWODQ bFq1DeTsV30pa7egZU/eaXNWW3zB5ynaHRHW1u7Xa09aTfFTRoq5A2oJ44p4KS+mJK4G6x0XBn7 1Gw2odW7C/AAOWUOs0a4RtJfNCKvkL10E4+0KV8Li5RNFmQm6usAejXWy75Q9prWe0dlYTYSy3o xI8QSOIzK1MEuejXCblba6RoP3KeXI8KvZNyVhORnjEew/T9KgOCxD/Ovz1FaSlHDSCdeY5DGWV nd9DFEBoAeFDIOg== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 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 --- 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/fu= jitsu/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/f= ujitsu/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) +=3D fmvj18x_cs.o diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethern= et/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 @@ -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - 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=20 - 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. - =20 - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - =20 - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - =20 -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DRV_NAME "fmvj18x_cs" -#define DRV_VERSION "2.9" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Module parameters */ - -MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n =3D v; module_param(n, int, 0) - -/* SRAM configuration */ -/* 0:4KB*2 TX buffer else:8KB*2 TX buffer */ -INT_MODULE_PARM(sram_config, 0); - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ -/* - 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 - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ -/*=20 - ioport offset from the base address=20 - */ -#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 */ - -/*=20 - control bits=20 - */ -#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 =3D { - .ndo_open =3D fjn_open, - .ndo_stop =3D fjn_close, - .ndo_start_xmit =3D fjn_start_xmit, - .ndo_tx_timeout =3D fjn_tx_timeout, - .ndo_set_config =3D fjn_config, - .ndo_set_rx_mode =3D set_rx_mode, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D 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 =3D alloc_etherdev(sizeof(struct local_info)); - if (!dev) - return -ENOMEM; - lp =3D netdev_priv(dev); - link->priv =3D dev; - lp->p_dev =3D link; - lp->base =3D NULL; - - /* The io structure describes IO port mapping */ - link->resource[0]->end =3D 32; - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_AUTO; - - /* General socket configuration */ - link->config_flags |=3D CONF_ENABLE_IRQ; - - dev->netdev_ops =3D &fjn_netdev_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - - dev->ethtool_ops =3D &netdev_ethtool_ops; - - return fmvj18x_config(link); -} /* fmvj18x_attach */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void fmvj18x_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - dev_dbg(&link->dev, "fmvj18x_detach\n"); - - unregister_netdev(dev); - - fmvj18x_release(link); - - free_netdev(dev); -} /* fmvj18x_detach */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int mfc_try_io_port(struct pcmcia_device *link) -{ - int i, ret; - static const unsigned int serial_base[5] =3D - { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - - for (i =3D 0; i < 5; i++) { - link->resource[1]->start =3D serial_base[i]; - link->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_8; - if (link->resource[1]->start =3D=3D 0) { - link->resource[1]->end =3D 0; - pr_notice("out of resource for serial\n"); - } - ret =3D pcmcia_request_io(link); - if (ret =3D=3D 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 =3D 0x300; ioaddr < 0x3e0; ioaddr +=3D 0x20) { - link->resource[0]->start =3D ioaddr; - ret =3D pcmcia_request_io(link); - if (ret =3D=3D 0) { - /* calculate ConfigIndex value */ - link->config_index =3D - ((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 =3D link->priv; - struct local_info *lp =3D netdev_priv(dev); - int i, ret; - unsigned int ioaddr; - enum cardtype cardtype; - char *card_name =3D "unknown"; - u8 *buf; - size_t len; - u_char buggybuf[32]; - u8 addr[ETH_ALEN]; - - dev_dbg(&link->dev, "fmvj18x_config\n"); - - link->io_lines =3D 5; - - len =3D pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); - kfree(buf); - - if (len) { - /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ - ret =3D pcmcia_loop_config(link, fmvj18x_ioprobe, NULL); - if (ret !=3D 0) - goto failed; - - switch (link->manf_id) { - case MANFID_TDK: - cardtype =3D TDK; - if (link->card_id =3D=3D PRODID_TDK_GN3410 || - link->card_id =3D=3D PRODID_TDK_NP9610 || - link->card_id =3D=3D PRODID_TDK_MN3200) { - /* MultiFunction Card */ - link->config_base =3D 0x800; - link->config_index =3D 0x47; - link->resource[1]->end =3D 8; - } - break; - case MANFID_NEC: - cardtype =3D NEC; /* MultiFunction Card */ - link->config_base =3D 0x800; - link->config_index =3D 0x47; - link->resource[1]->end =3D 8; - break; - case MANFID_KME: - cardtype =3D KME; /* MultiFunction Card */ - link->config_base =3D 0x800; - link->config_index =3D 0x47; - link->resource[1]->end =3D 8; - break; - case MANFID_CONTEC: - cardtype =3D CONTEC; - break; - case MANFID_FUJITSU: - if (link->config_base =3D=3D 0x0fe0) - cardtype =3D MBH10302; - else if (link->card_id =3D=3D PRODID_FUJITSU_MBH10302)=20 - /* RATOC REX-5588/9822/4886's PRODID are 0004(=3DMBH10302), - but these are MBH10304 based card. */=20 - cardtype =3D MBH10304; - else if (link->card_id =3D=3D PRODID_FUJITSU_MBH10304) - cardtype =3D MBH10304; - else - cardtype =3D LA501; - break; - default: - cardtype =3D MBH10304; - } - } else { - /* old type card */ - switch (link->manf_id) { - case MANFID_FUJITSU: - if (link->card_id =3D=3D PRODID_FUJITSU_MBH10304) { - cardtype =3D XXX10304; /* MBH10304 with buggy CIS */ - link->config_index =3D 0x20; - } else { - cardtype =3D MBH10302; /* NextCom NC5310, etc. */ - link->config_index =3D 1; - } - break; - case MANFID_UNGERMANN: - cardtype =3D UNGERMANN; - break; - default: - cardtype =3D MBH10302; - link->config_index =3D 1; - } - } - - if (link->resource[1]->end !=3D 0) { - ret =3D mfc_try_io_port(link); - if (ret !=3D 0) goto failed; - } else if (cardtype =3D=3D UNGERMANN) { - ret =3D ungermann_try_io_port(link); - if (ret !=3D 0) goto failed; - } else {=20 - ret =3D pcmcia_request_io(link); - if (ret) - goto failed; - } - ret =3D pcmcia_request_irq(link, fjn_interrupt); - if (ret) - goto failed; - ret =3D pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq =3D link->irq; - dev->base_addr =3D link->resource[0]->start; - - if (resource_size(link->resource[1]) !=3D 0) { - ret =3D fmvj18x_setup_mfc(link); - if (ret !=3D 0) goto failed; - } - - ioaddr =3D dev->base_addr; - - /* Reset controller */ - if (sram_config =3D=3D 0)=20 - outb(CONFIG0_RST, ioaddr + CONFIG_0); - else - outb(CONFIG0_RST_1, ioaddr + CONFIG_0); - - /* Power On chip and select bank 0 */ - if (cardtype =3D=3D MBH10302) - outb(BANK_0, ioaddr + CONFIG_1); - else - outb(BANK_0U, ioaddr + CONFIG_1); - =20 - /* Set hardware address */ - switch (cardtype) { - case MBH10304: - case TDK: - case LA501: - case CONTEC: - case NEC: - case KME: - if (cardtype =3D=3D MBH10304) { - card_name =3D "FMV-J182"; - - len =3D 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 =3D=3D TDK ) { - card_name =3D "TDK LAK-CD021"; - } else if( cardtype =3D=3D LA501 ) { - card_name =3D "LA501"; - } else if( cardtype =3D=3D NEC ) { - card_name =3D "PK-UG-J001"; - } else if( cardtype =3D=3D KME ) { - card_name =3D "Panasonic"; - } else { - card_name =3D "C-NET(PC)C"; - } - } - break; - case UNGERMANN: - /* Read MACID from register */ - for (i =3D 0; i < 6; i++)=20 - addr[i] =3D inb(ioaddr + UNGERMANN_MAC_ID + i); - eth_hw_addr_set(dev, addr); - card_name =3D "Access/CARD"; - break; - case XXX10304: - /* Read MACID from Buggy CIS */ - if (fmvj18x_get_hwinfo(link, buggybuf) =3D=3D -1) { - pr_notice("unable to read hardware net address\n"); - goto failed; - } - eth_hw_addr_set(dev, buggybuf); - card_name =3D "FMV-J182"; - break; - case MBH10302: - default: - /* Read MACID from register */ - for (i =3D 0; i < 6; i++)=20 - addr[i] =3D inb(ioaddr + MAC_ID + i); - eth_hw_addr_set(dev, addr); - card_name =3D "FMV-J181"; - break; - } - - lp->cardtype =3D cardtype; - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) !=3D 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 =3D=3D 0 ? "4K TX*2" : "8K TX*2", - dev->base_addr, dev->irq, dev->dev_addr); - - return 0; - =20 -failed: - fmvj18x_release(link); - return -ENODEV; -} /* fmvj18x_config */ -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -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 |=3D WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_= ENABLE; - link->resource[2]->start =3D 0; link->resource[2]->end =3D 0; - i =3D pcmcia_request_window(link, link->resource[2], 0); - if (i !=3D 0) - return -1; - - base =3D ioremap(link->resource[2]->start, resource_size(link->resourc= e[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. - */=20 - for (i =3D 0; i < 0x200; i++) { - if (readb(base+i*2) =3D=3D 0x22) {=09 - if (readb(base+(i-1)*2) =3D=3D 0xff && - readb(base+(i+5)*2) =3D=3D 0x04 && - readb(base+(i+6)*2) =3D=3D 0x06 && - readb(base+(i+13)*2) =3D=3D 0xff) - break; - } - } - - if (i !=3D 0x200) { - for (j =3D 0 ; j < 6; j++,i++) { - node_id[j] =3D readb(base+(i+7)*2); - } - } - - iounmap(base); - j =3D pcmcia_release_window(link, link->resource[2]); - return (i !=3D 0x200) ? 0 : -1; - -} /* fmvj18x_get_hwinfo */ -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int fmvj18x_setup_mfc(struct pcmcia_device *link) -{ - int i; - struct net_device *dev =3D link->priv; - unsigned int ioaddr; - struct local_info *lp =3D netdev_priv(dev); - - /* Allocate a small memory window */ - link->resource[3]->flags =3D WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_E= NABLE; - link->resource[3]->start =3D link->resource[3]->end =3D 0; - i =3D pcmcia_request_window(link, link->resource[3], 0); - if (i !=3D 0) - return -1; - - lp->base =3D ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - if (lp->base =3D=3D NULL) { - netdev_notice(dev, "ioremap failed\n"); - return -1; - } - - i =3D pcmcia_map_mem_page(link, link->resource[3], 0); - if (i !=3D 0) { - iounmap(lp->base); - lp->base =3D NULL; - return -1; - } - =20 - ioaddr =3D 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= */ - =20 - writeb(0x45, lp->base+0x820); /* Config Option Register of Modem */ - writeb(0x8, lp->base+0x822); /* Config and Status Register */ - - return 0; - -} -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void fmvj18x_release(struct pcmcia_device *link) -{ - - struct net_device *dev =3D link->priv; - struct local_info *lp =3D netdev_priv(dev); - u_char __iomem *tmp; - - dev_dbg(&link->dev, "fmvj18x_release\n"); - - if (lp->base !=3D NULL) { - tmp =3D lp->base; - lp->base =3D NULL; /* set NULL before iounmap */ - iounmap(tmp); - } - - pcmcia_disable_device(link); - -} - -static int fmvj18x_suspend(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int fmvj18x_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) { - fjn_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static const struct pcmcia_device_id fmvj18x_ids[] =3D { - 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 10B= T", 0xf47e6c66, 0x877f9922), - PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5b= af31db), - 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 ", 0x8cef4d3= a, 0x075fc7b6), - PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0 ", 0x8cef4d3= a, 0xbccf43e6), - PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c1= 0e17, 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", 0x1eae= 9475, 0xd9a93bed), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b106= 4), - 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 =3D { - .owner =3D THIS_MODULE, - .name =3D "fmvj18x_cs", - .probe =3D fmvj18x_probe, - .remove =3D fmvj18x_detach, - .id_table =3D fmvj18x_ids, - .suspend =3D fmvj18x_suspend, - .resume =3D fmvj18x_resume, -}; -module_pcmcia_driver(fmvj18x_cs_driver); - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static irqreturn_t fjn_interrupt(int dummy, void *dev_id) -{ - struct net_device *dev =3D dev_id; - struct local_info *lp =3D netdev_priv(dev); - unsigned int ioaddr; - unsigned short tx_stat, rx_stat; - - ioaddr =3D dev->base_addr; - - /* avoid multiple interrupts */ - outw(0x0000, ioaddr + TX_INTR); - - /* wait for a while */ - udelay(1); - - /* get status */ - tx_stat =3D inb(ioaddr + TX_STATUS); - rx_stat =3D inb(ioaddr + RX_STATUS); - - /* clear status */ - outb(tx_stat, ioaddr + TX_STATUS); - outb(rx_stat, ioaddr + RX_STATUS); - =20 - pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat); - pr_debug(" tx_status %02x.\n", tx_stat); - =20 - if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) =3D=3D 0) { - /* there is packet(s) in rx buffer */ - fjn_rx(dev); - } - if (tx_stat & F_TMT_RDY) { - dev->stats.tx_packets +=3D lp->sent ; - lp->sent =3D 0 ; - if (lp->tx_queue) { - outb(DO_TX | lp->tx_queue, ioaddr + TX_START); - lp->sent =3D lp->tx_queue ; - lp->tx_queue =3D 0; - lp->tx_queue_len =3D 0; - netif_trans_update(dev); - } else { - lp->tx_started =3D 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 !=3D NULL) { - /* Ack interrupt for multifunction card */ - writeb(0x01, lp->base+0x802); - writeb(0x09, lp->base+0x822); - } - - return IRQ_HANDLED; - -} /* fjn_interrupt */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct local_info *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D 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 =3D 0; - lp->tx_queue =3D 0; - lp->tx_queue_len =3D 0; - lp->sent =3D 0; - lp->open_time =3D 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 =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - short length =3D skb->len; - =20 - if (length < ETH_ZLEN) - { - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - length =3D ETH_ZLEN; - } - - netif_stop_queue(dev); - - { - unsigned char *buf =3D 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 +=3D 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 +=3D ((length+3) & ~1); - - if (lp->tx_started =3D=3D 0) { - /* If the Tx is idle, always trigger a transmit. */ - outb(DO_TX | lp->tx_queue, ioaddr + TX_START); - lp->sent =3D lp->tx_queue ; - lp->tx_queue =3D 0; - lp->tx_queue_len =3D 0; - lp->tx_started =3D 1; - netif_start_queue(dev); - } else { - if( sram_config =3D=3D 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)) &&=20 - 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 */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void fjn_reset(struct net_device *dev) -{ - struct local_info *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - int i; - - netdev_dbg(dev, "fjn_reset() called\n"); - - /* Reset controller */ - if( sram_config =3D=3D 0 )=20 - outb(CONFIG0_RST, ioaddr + CONFIG_0); - else - outb(CONFIG0_RST_1, ioaddr + CONFIG_0); - - /* Power On chip and select bank 0 */ - if (lp->cardtype =3D=3D 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 =3D 0; i < 6; i++)=20 - 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 =3D=3D MBH10302) - outb(BANK_2, ioaddr + CONFIG_1); - else - outb(BANK_2U, ioaddr + CONFIG_1); - - /* set 16col ctrl bits */ - if( lp->cardtype =3D=3D TDK || lp->cardtype =3D=3D CONTEC)=20 - 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 =3D=3D 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 =3D=3D 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 =3D=3D MBH10302) - outb(INTR_ON, ioaddr + LAN_CTRL); -} /* fjn_reset */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void fjn_rx(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - int boguscount =3D 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) =3D=3D 0) { - u_short status =3D inw(ioaddr + DATAPORT); - - netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n", - inb(ioaddr + RX_MODE), status); -#ifndef final_version - if (status =3D=3D 0) { - outb(F_SKP_PKT, ioaddr + RX_SKIP); - break; - } -#endif - if ((status & 0xF0) !=3D 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 =3D 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 =3D netdev_alloc_skb(dev, pkt_len + 2); - if (skb =3D=3D 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 =3D eth_type_trans(skb, dev); - - { - int i; - pr_debug("%s: Rxed packet of length %d: ", - dev->name, pkt_len); - for (i =3D 0; i < 14; i++) - pr_debug(" %02x", skb->data[i]); - pr_debug(".\n"); - } - - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pkt_len; - } - if (--boguscount <=3D 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 !=3D TDK) { - int i; - for (i =3D 0; i < 20; i++) { - if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) =3D=3D 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 */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -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 =3D { - .get_drvinfo =3D 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 =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - pr_debug("fjn_open('%s').\n", dev->name); - - if (!pcmcia_dev_present(link)) - return -ENODEV; - =20 - link->open++; - =20 - fjn_reset(dev); - =20 - lp->tx_started =3D 0; - lp->tx_queue =3D 0; - lp->tx_queue_len =3D 0; - lp->open_time =3D jiffies; - netif_start_queue(dev); - =20 - return 0; -} /* fjn_open */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int fjn_close(struct net_device *dev) -{ - struct local_info *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - unsigned int ioaddr =3D dev->base_addr; - - pr_debug("fjn_close('%s').\n", dev->name); - - lp->open_time =3D 0; - netif_stop_queue(dev); - - /* Set configuration register 0 to disable Tx and Rx. */ - if( sram_config =3D=3D 0 )=20 - 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 =3D=3D MBH10302) - outb(INTR_OFF, ioaddr + LAN_CTRL); - - link->open--; - - return 0; -} /* fjn_close */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* - Set the multicast/promiscuous mode for this adaptor. -*/ - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - u_char mc_filter[8]; /* Multicast hash filter */ - u_long flags; - int i; - =20 - int saved_bank; - int saved_config_0 =3D inb(ioaddr + CONFIG_0); - =20 - local_irq_save(flags);=20 - - /* Disable Tx and Rx */ - if (sram_config =3D=3D 0)=20 - 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 =3D ether_crc_le(ETH_ALEN, ha->addr) >> 26; - mc_filter[bit >> 3] |=3D (1 << (bit & 7)); - } - outb(2, ioaddr + RX_MODE); /* Use normal mode. */ - } - - /* Switch to bank 1 and set the multicast table. */ - saved_bank =3D inb(ioaddr + CONFIG_1); - outb(0xe4, ioaddr + CONFIG_1); - - for (i =3D 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); -} --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E4ECA3242BE; Tue, 21 Apr 2026 19:58:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801487; cv=none; b=ld6uUnZyUNW8bjX54MCR0fjyW0uXIqOYf8CyA54sl1hZdHvEC1Qf5Ml7B+sIi0e7RIJYcuBksnwjUVj05o/H7FkYZIKqRCREKs+xGCWEpiPDTv+AVX6dDzJUDCrwMOTEMIDShxlCIWV1IM3M0kwcjhDvuIZ8O0u11NSkWp6xvY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801487; c=relaxed/simple; bh=NShMqnlTirV3JQCEwIZE0aVXyAsMTWs0eK6xeXMHSFY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gD6Ay70K64rCHLPbpTtQ3n7BY7QQhyxawiEd/Je2K74mzb7dYFi0vaUZA424j5KPEzEC2VpHFNosFoqMSFI5LSsbCYNwkeZx2s2Sxyupy8BW9p9Sofn29ZDld565c9jHZSsfFtoEmXx91tojwTGwKwxkhyokOb6KhJ4VnVevlR0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=fE4QYUL+; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="fE4QYUL+" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=QJsxcOFAbO2ve9ibjgeHEwUwz4c5m98+MwLmC+bbb/g=; b=fE 4QYUL+ujPCTHSF57coPonWmsvZi1TWPBxvjSEl7EIYNhNEXHx1t/9uBYqQKxriAuur2O7n+GweCd5 6hRjLw0xjW5rZYK31ZBe5Y1h130qyNvw8yMWf1ZwtJ3KJ3VCn5nHGh2bcdFM5hxHx589jDGdnJ8qK eCijyete18ru8WU=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGp6-00GwVc-09; Tue, 21 Apr 2026 21:31:52 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:17 -0500 Subject: [PATCH net 14/18] drivers: net: xircom: xirc2ps: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-14-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=59599; i=andrew@lunn.ch; h=from:subject:message-id; bh=NShMqnlTirV3JQCEwIZE0aVXyAsMTWs0eK6xeXMHSFY=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CCkKdfuh42rdklNqY7cthqDDw3ajXaN6Jff GV0hRpLouOJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hNqkEADU8/Y2rXvq5Zzl/FdXHBeFz7e1geP7SCawTYbkhtZhcPqFDzZUIoEeBUsMg2qEOE3xw2U 7cGS8XUZf4YUE250dBBCxjtlmfHahUDExTTrhp0UrU23NUa2nk+d0ndUHi+OGqpOvQOB4mxB2/Q LKulmhZ6176of72DZ3hPddKcAc4IlJsS0T9wu1U86jT4Dqs7EY2fYTuiIXafspipnKoGQ+P5uth Sa5qYGtpYFDNvF5niQE+EFU+FSzz3up2NmR65KligrR5iSabfTPrNWlw0qh3YNUZ0zWyWK63e9v VPjTvNFxz43E3M5FtQm5a8dXLf6gwUDfm1B6hbgbxbiysw8Ac2SToYMNIeXLOJ+OCQyp8KhaukC 394G05auo05EdZ0Hj9qtOdkWffHjAU/WVnl6ohGdGQOd7+ftDIBoTe7gHIRfkEbblRDH487bDIo gRaL58pm+IMoGG1hSkAHQu2BtzRAvxtZbshR+JQe3rqHrreauDuiIvYFOH4R4WBinySYM5RGWWk kW4f3DEuQDKJlm2L8M1moSSKNxYBFPQHDrSaYopNcIxXTwPKy8ADMNqkHVBHU7xB+IGuErV+InX d1QDqUz9i/hq7agy3SLVN+Tdo9V3WH/1L+Rn/cfKCK/IGLijvtykO0V88eTqbfWxZYtOpH6toGM hDW72wof6CTh+Vw== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 The xirc2ps was written by Werner Koch in 1997. It is an PCMCIA device, so unlikely to be used with modern kernels. Signed-off-by: Andrew Lunn --- drivers/net/ethernet/Kconfig | 1 - drivers/net/ethernet/xircom/Kconfig | 30 - drivers/net/ethernet/xircom/Makefile | 6 - drivers/net/ethernet/xircom/xirc2ps_cs.c | 1794 --------------------------= ---- 4 files changed, 1831 deletions(-) diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index c94e8f27af94..5171d9046ea4 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -188,6 +188,5 @@ source "drivers/net/ethernet/via/Kconfig" source "drivers/net/ethernet/wangxun/Kconfig" source "drivers/net/ethernet/wiznet/Kconfig" source "drivers/net/ethernet/xilinx/Kconfig" -source "drivers/net/ethernet/xircom/Kconfig" =20 endif # ETHERNET diff --git a/drivers/net/ethernet/xircom/Kconfig b/drivers/net/ethernet/xir= com/Kconfig deleted file mode 100644 index bfbdcf758afb..000000000000 --- a/drivers/net/ethernet/xircom/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Xircom network device configuration -# - -config NET_VENDOR_XIRCOM - bool "Xircom devices" - default y - depends on PCMCIA - help - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Xircom cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_XIRCOM - -config PCMCIA_XIRC2PS - tristate "Xircom 16-bit PCMCIA support" - depends on PCMCIA && HAS_IOPORT - help - Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card) - Ethernet or Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called xirc2ps_cs. If unsure, say N. - -endif # NET_VENDOR_XIRCOM diff --git a/drivers/net/ethernet/xircom/Makefile b/drivers/net/ethernet/xi= rcom/Makefile deleted file mode 100644 index 07667fefafc2..000000000000 --- a/drivers/net/ethernet/xircom/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the Xircom network device drivers. -# - -obj-$(CONFIG_PCMCIA_XIRC2PS) +=3D xirc2ps_cs.o diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/etherne= t/xircom/xirc2ps_cs.c deleted file mode 100644 index 97e88886253f..000000000000 --- a/drivers/net/ethernet/xircom/xirc2ps_cs.c +++ /dev/null @@ -1,1794 +0,0 @@ -/* [xirc2ps_cs.c wk 03.11.99] (1.40 1999/11/18 00:06:03) - * Xircom CreditCard Ethernet Adapter IIps driver - * Xircom Realport 10/100 (RE-100) driver=20 - * - * This driver supports various Xircom CreditCard Ethernet adapters - * including the CE2, CE IIps, RE-10, CEM28, CEM33, CE33, CEM56, - * CE3-100, CE3B, RE-100, REM10BT, and REM56G-100. - * - * 2000-09-24 The Xircom CE3B-100 may not - * autodetect the media properly. In this case use the - * if_port=3D1 (for 10BaseT) or if_port=3D4 (for 100BaseT) options - * to force the media type. - *=20 - * Written originally by Werner Koch based on David Hinds' skeleton of the - * PCMCIA driver. - * - * Copyright (c) 1997,1998 Werner Koch (dd9jn) - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * It is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * - * - * ALTERNATIVELY, this driver may be distributed under the terms of - * the following license, in which case the provisions of this license - * are required INSTEAD OF the GNU General Public License. (This clause - * is necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifndef MANFID_COMPAQ - #define MANFID_COMPAQ 0x0138 - #define MANFID_COMPAQ2 0x0183 /* is this correct? */ -#endif - -#include - -/* Time in jiffies before concluding Tx hung */ -#define TX_TIMEOUT ((400*HZ)/1000) - -/**************** - * Some constants used to access the hardware - */ - -/* Register offsets and value constans */ -#define XIRCREG_CR 0 /* Command register (wr) */ -enum xirc_cr { - TransmitPacket =3D 0x01, - SoftReset =3D 0x02, - EnableIntr =3D 0x04, - ForceIntr =3D 0x08, - ClearTxFIFO =3D 0x10, - ClearRxOvrun =3D 0x20, - RestartTx =3D 0x40 -}; -#define XIRCREG_ESR 0 /* Ethernet status register (rd) */ -enum xirc_esr { - FullPktRcvd =3D 0x01, /* full packet in receive buffer */ - PktRejected =3D 0x04, /* a packet has been rejected */ - TxPktPend =3D 0x08, /* TX Packet Pending */ - IncorPolarity =3D 0x10, - MediaSelect =3D 0x20 /* set if TP, clear if AUI */ -}; -#define XIRCREG_PR 1 /* Page Register select */ -#define XIRCREG_EDP 4 /* Ethernet Data Port Register */ -#define XIRCREG_ISR 6 /* Ethernet Interrupt Status Register */ -enum xirc_isr { - TxBufOvr =3D 0x01, /* TX Buffer Overflow */ - PktTxed =3D 0x02, /* Packet Transmitted */ - MACIntr =3D 0x04, /* MAC Interrupt occurred */ - TxResGrant =3D 0x08, /* Tx Reservation Granted */ - RxFullPkt =3D 0x20, /* Rx Full Packet */ - RxPktRej =3D 0x40, /* Rx Packet Rejected */ - ForcedIntr=3D 0x80 /* Forced Interrupt */ -}; -#define XIRCREG1_IMR0 12 /* Ethernet Interrupt Mask Register (on page 1)*/ -#define XIRCREG1_IMR1 13 -#define XIRCREG0_TSO 8 /* Transmit Space Open Register (on page 0)*/ -#define XIRCREG0_TRS 10 /* Transmit reservation Size Register (page 0)*/ -#define XIRCREG0_DO 12 /* Data Offset Register (page 0) (wr) */ -#define XIRCREG0_RSR 12 /* Receive Status Register (page 0) (rd) */ -enum xirc_rsr { - PhyPkt =3D 0x01, /* set:physical packet, clear: multicast packet */ - BrdcstPkt =3D 0x02, /* set if it is a broadcast packet */ - PktTooLong =3D 0x04, /* set if packet length > 1518 */ - AlignErr =3D 0x10, /* incorrect CRC and last octet not complete */ - CRCErr =3D 0x20, /* incorrect CRC and last octet is complete */ - PktRxOk =3D 0x80 /* received ok */ -}; -#define XIRCREG0_PTR 13 /* packets transmitted register (rd) */ -#define XIRCREG0_RBC 14 /* receive byte count regsister (rd) */ -#define XIRCREG1_ECR 14 /* ethernet configurationn register */ -enum xirc_ecr { - FullDuplex =3D 0x04, /* enable full duplex mode */ - LongTPMode =3D 0x08, /* adjust for longer lengths of TP cable */ - DisablePolCor =3D 0x10,/* disable auto polarity correction */ - DisableLinkPulse =3D 0x20, /* disable link pulse generation */ - DisableAutoTx =3D 0x40, /* disable auto-transmit */ -}; -#define XIRCREG2_RBS 8 /* receive buffer start register */ -#define XIRCREG2_LED 10 /* LED Configuration register */ -/* values for the leds: Bits 2-0 for led 1 - * 0 disabled Bits 5-3 for led 2 - * 1 collision - * 2 noncollision - * 3 link_detected - * 4 incor_polarity - * 5 jabber - * 6 auto_assertion - * 7 rx_tx_activity - */ -#define XIRCREG2_MSR 12 /* Mohawk specific register */ - -#define XIRCREG4_GPR0 8 /* General Purpose Register 0 */ -#define XIRCREG4_GPR1 9 /* General Purpose Register 1 */ -#define XIRCREG2_GPR2 13 /* General Purpose Register 2 (page2!)*/ -#define XIRCREG4_BOV 10 /* Bonding Version Register */ -#define XIRCREG4_LMA 12 /* Local Memory Address Register */ -#define XIRCREG4_LMD 14 /* Local Memory Data Port */ -/* MAC register can only by accessed with 8 bit operations */ -#define XIRCREG40_CMD0 8 /* Command Register (wr) */ -enum xirc_cmd { /* Commands */ - Transmit =3D 0x01, - EnableRecv =3D 0x04, - DisableRecv =3D 0x08, - Abort =3D 0x10, - Online =3D 0x20, - IntrAck =3D 0x40, - Offline =3D 0x80 -}; -#define XIRCREG5_RHSA0 10 /* Rx Host Start Address */ -#define XIRCREG40_RXST0 9 /* Receive Status Register */ -#define XIRCREG40_TXST0 11 /* Transmit Status Register 0 */ -#define XIRCREG40_TXST1 12 /* Transmit Status Register 10 */ -#define XIRCREG40_RMASK0 13 /* Receive Mask Register */ -#define XIRCREG40_TMASK0 14 /* Transmit Mask Register 0 */ -#define XIRCREG40_TMASK1 15 /* Transmit Mask Register 0 */ -#define XIRCREG42_SWC0 8 /* Software Configuration 0 */ -#define XIRCREG42_SWC1 9 /* Software Configuration 1 */ -#define XIRCREG42_BOC 10 /* Back-Off Configuration */ -#define XIRCREG44_TDR0 8 /* Time Domain Reflectometry 0 */ -#define XIRCREG44_TDR1 9 /* Time Domain Reflectometry 1 */ -#define XIRCREG44_RXBC_LO 10 /* Rx Byte Count 0 (rd) */ -#define XIRCREG44_RXBC_HI 11 /* Rx Byte Count 1 (rd) */ -#define XIRCREG45_REV 15 /* Revision Register (rd) */ -#define XIRCREG50_IA 8 /* Individual Address (8-13) */ - -static const char *if_names[] =3D { "Auto", "10BaseT", "10Base2", "AUI", "= 100BaseT" }; - -/* card types */ -#define XIR_UNKNOWN 0 /* unknown: not supported */ -#define XIR_CE 1 /* (prodid 1) different hardware: not supported */ -#define XIR_CE2 2 /* (prodid 2) */ -#define XIR_CE3 3 /* (prodid 3) */ -#define XIR_CEM 4 /* (prodid 1) different hardware: not supported */ -#define XIR_CEM2 5 /* (prodid 2) */ -#define XIR_CEM3 6 /* (prodid 3) */ -#define XIR_CEM33 7 /* (prodid 4) */ -#define XIR_CEM56M 8 /* (prodid 5) */ -#define XIR_CEM56 9 /* (prodid 6) */ -#define XIR_CM28 10 /* (prodid 3) modem only: not supported here */ -#define XIR_CM33 11 /* (prodid 4) modem only: not supported here */ -#define XIR_CM56 12 /* (prodid 5) modem only: not supported here */ -#define XIR_CG 13 /* (prodid 1) GSM modem only: not supported */ -#define XIR_CBE 14 /* (prodid 1) cardbus ethernet: not supported */ -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Module parameters */ - -MODULE_DESCRIPTION("Xircom PCMCIA ethernet driver"); -MODULE_LICENSE("Dual MPL/GPL"); - -#define INT_MODULE_PARM(n, v) static int n =3D v; module_param(n, int, 0) - -INT_MODULE_PARM(if_port, 0); -INT_MODULE_PARM(full_duplex, 0); -INT_MODULE_PARM(do_sound, 1); -INT_MODULE_PARM(lockup_hack, 0); /* anti lockup hack */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* We do not process more than these number of bytes during one - * interrupt. (Of course we receive complete packets, so this is not - * an exact value). - * Something between 2000..22000; first value gives best interrupt latency, - * the second enables the usage of the complete on-chip buffer. We use the - * high value as the initial value. - */ -static unsigned maxrx_bytes =3D 22000; - -/* MII management prototypes */ -static void mii_idle(unsigned int ioaddr); -static void mii_putbit(unsigned int ioaddr, unsigned data); -static int mii_getbit(unsigned int ioaddr); -static void mii_wbits(unsigned int ioaddr, unsigned data, int len); -static unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg); -static void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, - unsigned data, int len); - -static int has_ce2_string(struct pcmcia_device * link); -static int xirc2ps_config(struct pcmcia_device * link); -static void xirc2ps_release(struct pcmcia_device * link); -static void xirc2ps_detach(struct pcmcia_device *p_dev); - -static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id); - -struct local_info { - struct net_device *dev; - struct pcmcia_device *p_dev; - - int card_type; - int probe_port; - int silicon; /* silicon revision. 0=3Dold CE2, 1=3DScipper, 4=3DMohawk= */ - int mohawk; /* a CE3 type card */ - int dingo; /* a CEM56 type card */ - int new_mii; /* has full 10baseT/100baseT MII */ - int modem; /* is a multi function card (i.e with a modem) */ - void __iomem *dingo_ccr; /* only used for CEM56 cards */ - unsigned last_ptr_value; /* last packets transmitted value */ - const char *manf_str; - struct work_struct tx_timeout_task; -}; - -/**************** - * Some more prototypes - */ -static netdev_tx_t do_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static void xirc_tx_timeout(struct net_device *dev, unsigned int txqueue); -static void xirc2ps_tx_timeout_task(struct work_struct *work); -static void set_addresses(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static int set_card_type(struct pcmcia_device *link); -static int do_config(struct net_device *dev, struct ifmap *map); -static int do_open(struct net_device *dev); -static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static const struct ethtool_ops netdev_ethtool_ops; -static void hardreset(struct net_device *dev); -static void do_reset(struct net_device *dev, int full); -static int init_mii(struct net_device *dev); -static void do_powerdown(struct net_device *dev); -static int do_stop(struct net_device *dev); - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Helper functions =3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ -#define SelectPage(pgnr) outb((pgnr), ioaddr + XIRCREG_PR) -#define GetByte(reg) ((unsigned)inb(ioaddr + (reg))) -#define GetWord(reg) ((unsigned)inw(ioaddr + (reg))) -#define PutByte(reg,value) outb((value), ioaddr+(reg)) -#define PutWord(reg,value) outw((value), ioaddr+(reg)) - -/*=3D=3D=3D=3D=3D=3D Functions used for debugging =3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= */ -#if 0 /* reading regs may change system status */ -static void -PrintRegisters(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - - if (pc_debug > 1) { - int i, page; - - printk(KERN_DEBUG pr_fmt("Register common: ")); - for (i =3D 0; i < 8; i++) - pr_cont(" %2.2x", GetByte(i)); - pr_cont("\n"); - for (page =3D 0; page <=3D 8; page++) { - printk(KERN_DEBUG pr_fmt("Register page %2x: "), page); - SelectPage(page); - for (i =3D 8; i < 16; i++) - pr_cont(" %2.2x", GetByte(i)); - pr_cont("\n"); - } - for (page=3D0x40 ; page <=3D 0x5f; page++) { - if (page =3D=3D 0x43 || (page >=3D 0x46 && page <=3D 0x4f) || - (page >=3D 0x51 && page <=3D0x5e)) - continue; - printk(KERN_DEBUG pr_fmt("Register page %2x: "), page); - SelectPage(page); - for (i =3D 8; i < 16; i++) - pr_cont(" %2.2x", GetByte(i)); - pr_cont("\n"); - } - } -} -#endif /* 0 */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D MII Management functions =3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/**************** - * Turn around for read - */ -static void -mii_idle(unsigned int ioaddr) -{ - PutByte(XIRCREG2_GPR2, 0x04|0); /* drive MDCK low */ - udelay(1); - PutByte(XIRCREG2_GPR2, 0x04|1); /* and drive MDCK high */ - udelay(1); -} - -/**************** - * Write a bit to MDI/O - */ -static void -mii_putbit(unsigned int ioaddr, unsigned data) -{ - #if 1 - if (data) { - PutByte(XIRCREG2_GPR2, 0x0c|2|0); /* set MDIO */ - udelay(1); - PutByte(XIRCREG2_GPR2, 0x0c|2|1); /* and drive MDCK high */ - udelay(1); - } else { - PutByte(XIRCREG2_GPR2, 0x0c|0|0); /* clear MDIO */ - udelay(1); - PutByte(XIRCREG2_GPR2, 0x0c|0|1); /* and drive MDCK high */ - udelay(1); - } - #else - if (data) { - PutWord(XIRCREG2_GPR2-1, 0x0e0e); - udelay(1); - PutWord(XIRCREG2_GPR2-1, 0x0f0f); - udelay(1); - } else { - PutWord(XIRCREG2_GPR2-1, 0x0c0c); - udelay(1); - PutWord(XIRCREG2_GPR2-1, 0x0d0d); - udelay(1); - } - #endif -} - -/**************** - * Get a bit from MDI/O - */ -static int -mii_getbit(unsigned int ioaddr) -{ - unsigned d; - - PutByte(XIRCREG2_GPR2, 4|0); /* drive MDCK low */ - udelay(1); - d =3D GetByte(XIRCREG2_GPR2); /* read MDIO */ - PutByte(XIRCREG2_GPR2, 4|1); /* drive MDCK high again */ - udelay(1); - return d & 0x20; /* read MDIO */ -} - -static void -mii_wbits(unsigned int ioaddr, unsigned data, int len) -{ - unsigned m =3D 1 << (len-1); - for (; m; m >>=3D 1) - mii_putbit(ioaddr, data & m); -} - -static unsigned -mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg) -{ - int i; - unsigned data=3D0, m; - - SelectPage(2); - for (i=3D0; i < 32; i++) /* 32 bit preamble */ - mii_putbit(ioaddr, 1); - mii_wbits(ioaddr, 0x06, 4); /* Start and opcode for read */ - mii_wbits(ioaddr, phyaddr, 5); /* PHY address to be accessed */ - mii_wbits(ioaddr, phyreg, 5); /* PHY register to read */ - mii_idle(ioaddr); /* turn around */ - mii_getbit(ioaddr); - - for (m =3D 1<<15; m; m >>=3D 1) - if (mii_getbit(ioaddr)) - data |=3D m; - mii_idle(ioaddr); - return data; -} - -static void -mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data, - int len) -{ - int i; - - SelectPage(2); - for (i=3D0; i < 32; i++) /* 32 bit preamble */ - mii_putbit(ioaddr, 1); - mii_wbits(ioaddr, 0x05, 4); /* Start and opcode for write */ - mii_wbits(ioaddr, phyaddr, 5); /* PHY address to be accessed */ - mii_wbits(ioaddr, phyreg, 5); /* PHY Register to write */ - mii_putbit(ioaddr, 1); /* turn around */ - mii_putbit(ioaddr, 0); - mii_wbits(ioaddr, data, len); /* And write the data */ - mii_idle(ioaddr); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Main bulk of functions =3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static const struct net_device_ops netdev_ops =3D { - .ndo_open =3D do_open, - .ndo_stop =3D do_stop, - .ndo_start_xmit =3D do_start_xmit, - .ndo_tx_timeout =3D xirc_tx_timeout, - .ndo_set_config =3D do_config, - .ndo_eth_ioctl =3D do_ioctl, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -}; - -static int -xirc2ps_probe(struct pcmcia_device *link) -{ - struct net_device *dev; - struct local_info *local; - - dev_dbg(&link->dev, "attach()\n"); - - /* Allocate the device structure */ - dev =3D alloc_etherdev(sizeof(struct local_info)); - if (!dev) - return -ENOMEM; - local =3D netdev_priv(dev); - local->dev =3D dev; - local->p_dev =3D link; - link->priv =3D dev; - - /* General socket configuration */ - link->config_index =3D 1; - - /* Fill in card specific entries */ - dev->netdev_ops =3D &netdev_ops; - dev->ethtool_ops =3D &netdev_ethtool_ops; - dev->watchdog_timeo =3D TX_TIMEOUT; - INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task); - - return xirc2ps_config(link); -} /* xirc2ps_attach */ - -static void -xirc2ps_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct local_info *local =3D netdev_priv(dev); - - netif_carrier_off(dev); - netif_tx_disable(dev); - cancel_work_sync(&local->tx_timeout_task); - - dev_dbg(&link->dev, "detach\n"); - - unregister_netdev(dev); - - xirc2ps_release(link); - - free_netdev(dev); -} /* xirc2ps_detach */ - -/**************** - * Detect the type of the card. s is the buffer with the data of tuple 0x20 - * Returns: 0 :=3D not supported - * mediaid=3D11 and prodid=3D47 - * Media-Id bits: - * Ethernet 0x01 - * Tokenring 0x02 - * Arcnet 0x04 - * Wireless 0x08 - * Modem 0x10 - * GSM only 0x20 - * Prod-Id bits: - * Pocket 0x10 - * External 0x20 - * Creditcard 0x40 - * Cardbus 0x80 - * - */ -static int -set_card_type(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct local_info *local =3D netdev_priv(dev); - u8 *buf; - unsigned int cisrev, mediaid, prodid; - size_t len; - - len =3D pcmcia_get_tuple(link, CISTPL_MANFID, &buf); - if (len < 5) { - dev_err(&link->dev, "invalid CIS -- sorry\n"); - return 0; - } - - cisrev =3D buf[2]; - mediaid =3D buf[3]; - prodid =3D buf[4]; - - dev_dbg(&link->dev, "cisrev=3D%02x mediaid=3D%02x prodid=3D%02x\n", - cisrev, mediaid, prodid); - - local->mohawk =3D 0; - local->dingo =3D 0; - local->modem =3D 0; - local->card_type =3D XIR_UNKNOWN; - if (!(prodid & 0x40)) { - pr_notice("Oops: Not a creditcard\n"); - return 0; - } - if (!(mediaid & 0x01)) { - pr_notice("Not an Ethernet card\n"); - return 0; - } - if (mediaid & 0x10) { - local->modem =3D 1; - switch(prodid & 15) { - case 1: local->card_type =3D XIR_CEM ; break; - case 2: local->card_type =3D XIR_CEM2 ; break; - case 3: local->card_type =3D XIR_CEM3 ; break; - case 4: local->card_type =3D XIR_CEM33 ; break; - case 5: local->card_type =3D XIR_CEM56M; - local->mohawk =3D 1; - break; - case 6: - case 7: /* 7 is the RealPort 10/56 */ - local->card_type =3D XIR_CEM56 ; - local->mohawk =3D 1; - local->dingo =3D 1; - break; - } - } else { - switch(prodid & 15) { - case 1: local->card_type =3D has_ce2_string(link)? XIR_CE2 : XIR_CE ; - break; - case 2: local->card_type =3D XIR_CE2; break; - case 3: local->card_type =3D XIR_CE3; - local->mohawk =3D 1; - break; - } - } - if (local->card_type =3D=3D XIR_CE || local->card_type =3D=3D XIR_CEM)= { - pr_notice("Sorry, this is an old CE card\n"); - return 0; - } - if (local->card_type =3D=3D XIR_UNKNOWN) - pr_notice("unknown card (mediaid=3D%02x prodid=3D%02x)\n", mediaid, prodi= d); - - return 1; -} - -/**************** - * There are some CE2 cards out which claim to be a CE card. - * This function looks for a "CE2" in the 3rd version field. - * Returns: true if this is a CE2 - */ -static int -has_ce2_string(struct pcmcia_device * p_dev) -{ - if (p_dev->prod_id[2] && strstr(p_dev->prod_id[2], "CE2")) - return 1; - return 0; -} - -static int -xirc2ps_config_modem(struct pcmcia_device *p_dev, void *priv_data) -{ - unsigned int ioaddr; - - if ((p_dev->resource[0]->start & 0xf) =3D=3D 8) - return -ENODEV; - - p_dev->resource[0]->end =3D 16; - p_dev->resource[1]->end =3D 8; - p_dev->resource[0]->flags &=3D ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_16; - p_dev->resource[1]->flags &=3D ~IO_DATA_PATH_WIDTH; - p_dev->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_8; - p_dev->io_lines =3D 10; - - p_dev->resource[1]->start =3D p_dev->resource[0]->start; - for (ioaddr =3D 0x300; ioaddr < 0x400; ioaddr +=3D 0x10) { - p_dev->resource[0]->start =3D ioaddr; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; -} - -static int -xirc2ps_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - int *pass =3D priv_data; - resource_size_t tmp =3D p_dev->resource[1]->start; - - tmp +=3D (*pass ? (p_dev->config_index & 0x20 ? -24 : 8) - : (p_dev->config_index & 0x20 ? 8 : -24)); - - if ((p_dev->resource[0]->start & 0xf) =3D=3D 8) - return -ENODEV; - - p_dev->resource[0]->end =3D 18; - p_dev->resource[1]->end =3D 8; - p_dev->resource[0]->flags &=3D ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_16; - p_dev->resource[1]->flags &=3D ~IO_DATA_PATH_WIDTH; - p_dev->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_8; - p_dev->io_lines =3D 10; - - p_dev->resource[1]->start =3D p_dev->resource[0]->start; - p_dev->resource[0]->start =3D tmp; - return pcmcia_request_io(p_dev); -} - - -static int pcmcia_get_mac_ce(struct pcmcia_device *p_dev, - tuple_t *tuple, - void *priv) -{ - struct net_device *dev =3D priv; - - if (tuple->TupleDataLen !=3D 13) - return -EINVAL; - if ((tuple->TupleData[0] !=3D 2) || (tuple->TupleData[1] !=3D 1) || - (tuple->TupleData[2] !=3D 6)) - return -EINVAL; - /* another try (James Lehmer's CE2 version 4.1)*/ - dev_addr_mod(dev, 2, &tuple->TupleData[2], 4); - return 0; -}; - - -static int -xirc2ps_config(struct pcmcia_device * link) -{ - struct net_device *dev =3D link->priv; - struct local_info *local =3D netdev_priv(dev); - unsigned int ioaddr; - int err; - u8 *buf; - size_t len; - - local->dingo_ccr =3D NULL; - - dev_dbg(&link->dev, "config\n"); - - /* Is this a valid card */ - if (link->has_manf_id =3D=3D 0) { - pr_notice("manfid not found in CIS\n"); - goto failure; - } - - switch (link->manf_id) { - case MANFID_XIRCOM: - local->manf_str =3D "Xircom"; - break; - case MANFID_ACCTON: - local->manf_str =3D "Accton"; - break; - case MANFID_COMPAQ: - case MANFID_COMPAQ2: - local->manf_str =3D "Compaq"; - break; - case MANFID_INTEL: - local->manf_str =3D "Intel"; - break; - case MANFID_TOSHIBA: - local->manf_str =3D "Toshiba"; - break; - default: - pr_notice("Unknown Card Manufacturer ID: 0x%04x\n", - (unsigned)link->manf_id); - goto failure; - } - dev_dbg(&link->dev, "found %s card\n", local->manf_str); - - if (!set_card_type(link)) { - pr_notice("this card is not supported\n"); - goto failure; - } - - /* get the ethernet address from the CIS */ - err =3D pcmcia_get_mac_from_cis(link, dev); - - /* not found: try to get the node-id from tuple 0x89 */ - if (err) { - len =3D pcmcia_get_tuple(link, 0x89, &buf); - /* data layout looks like tuple 0x22 */ - if (buf && len =3D=3D 8) { - if (*buf =3D=3D CISTPL_FUNCE_LAN_NODE_ID) - dev_addr_mod(dev, 2, &buf[2], 4); - else - err =3D -1; - } - kfree(buf); - } - - if (err) - err =3D pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev); - - if (err) { - pr_notice("node-id not found in CIS\n"); - goto failure; - } - - if (local->modem) { - int pass; - link->config_flags |=3D CONF_AUTO_SET_IO; - - if (local->dingo) { - /* Take the Modem IO port from the CIS and scan for a free - * Ethernet port */ - if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL)) - goto port_found; - } else { - /* We do 2 passes here: The first one uses the regular mapping and - * the second tries again, thereby considering that the 32 ports are - * mirrored every 32 bytes. Actually we use a mirrored port for - * the Mako if (on the first pass) the COR bit 5 is set. - */ - for (pass=3D0; pass < 2; pass++) - if (!pcmcia_loop_config(link, xirc2ps_config_check, - &pass)) - goto port_found; - /* if special option: - * try to configure as Ethernet only. - * .... */ - } - pr_notice("no ports available\n"); - } else { - link->io_lines =3D 10; - link->resource[0]->end =3D 16; - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_16; - for (ioaddr =3D 0x300; ioaddr < 0x400; ioaddr +=3D 0x10) { - link->resource[0]->start =3D ioaddr; - if (!(err =3D pcmcia_request_io(link))) - goto port_found; - } - link->resource[0]->start =3D 0; /* let CS decide */ - if ((err =3D pcmcia_request_io(link))) - goto config_error; - } - port_found: - - /**************** - * Now allocate an interrupt line. Note that this does not - * actually assign a handler to the interrupt. - */ - if ((err=3Dpcmcia_request_irq(link, xirc2ps_interrupt))) - goto config_error; - - link->config_flags |=3D CONF_ENABLE_IRQ; - if (do_sound) - link->config_flags |=3D CONF_ENABLE_SPKR; - - if ((err =3D pcmcia_enable_device(link))) - goto config_error; - - if (local->dingo) { - /* Reset the modem's BAR to the correct value - * This is necessary because in the RequestConfiguration call, - * the base address of the ethernet port (BasePort1) is written - * to the BAR registers of the modem. - */ - err =3D pcmcia_write_config_byte(link, CISREG_IOBASE_0, (u8) - link->resource[1]->start & 0xff); - if (err) - goto config_error; - - err =3D pcmcia_write_config_byte(link, CISREG_IOBASE_1, - (link->resource[1]->start >> 8) & 0xff); - if (err) - goto config_error; - - /* There is no config entry for the Ethernet part which - * is at 0x0800. So we allocate a window into the attribute - * memory and write direct to the CIS registers - */ - link->resource[2]->flags =3D WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | - WIN_ENABLE; - link->resource[2]->start =3D link->resource[2]->end =3D 0; - if ((err =3D pcmcia_request_window(link, link->resource[2], 0))) - goto config_error; - - local->dingo_ccr =3D ioremap(link->resource[2]->start, 0x1000) + 0x0800; - if ((err =3D pcmcia_map_mem_page(link, link->resource[2], 0))) - goto config_error; - - /* Setup the CCRs; there are no infos in the CIS about the Ethernet - * part. - */ - writeb(0x47, local->dingo_ccr + CISREG_COR); - ioaddr =3D link->resource[0]->start; - writeb(ioaddr & 0xff , local->dingo_ccr + CISREG_IOBASE_0); - writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1); - - #if 0 - { - u_char tmp; - pr_info("ECOR:"); - for (i=3D0; i < 7; i++) { - tmp =3D readb(local->dingo_ccr + i*2); - pr_cont(" %02x", tmp); - } - pr_cont("\n"); - pr_info("DCOR:"); - for (i=3D0; i < 4; i++) { - tmp =3D readb(local->dingo_ccr + 0x20 + i*2); - pr_cont(" %02x", tmp); - } - pr_cont("\n"); - pr_info("SCOR:"); - for (i=3D0; i < 10; i++) { - tmp =3D readb(local->dingo_ccr + 0x40 + i*2); - pr_cont(" %02x", tmp); - } - pr_cont("\n"); - } - #endif - - writeb(0x01, local->dingo_ccr + 0x20); - writeb(0x0c, local->dingo_ccr + 0x22); - writeb(0x00, local->dingo_ccr + 0x24); - writeb(0x00, local->dingo_ccr + 0x26); - writeb(0x00, local->dingo_ccr + 0x28); - } - - /* The if_port symbol can be set when the module is loaded */ - local->probe_port=3D0; - if (!if_port) { - local->probe_port =3D dev->if_port =3D 1; - } else if ((if_port >=3D 1 && if_port <=3D 2) || - (local->mohawk && if_port=3D=3D4)) - dev->if_port =3D if_port; - else - pr_notice("invalid if_port requested\n"); - - /* we can now register the device with the net subsystem */ - dev->irq =3D link->irq; - dev->base_addr =3D link->resource[0]->start; - - if (local->dingo) - do_reset(dev, 1); /* a kludge to make the cem56 work */ - - SET_NETDEV_DEV(dev, &link->dev); - - if ((err=3Dregister_netdev(dev))) { - pr_notice("register_netdev() failed\n"); - goto config_error; - } - - /* give some infos about the hardware */ - netdev_info(dev, "%s: port %#3lx, irq %d, hwaddr %pM\n", - local->manf_str, (u_long)dev->base_addr, (int)dev->irq, - dev->dev_addr); - - return 0; - - config_error: - xirc2ps_release(link); - return -ENODEV; - - failure: - return -ENODEV; -} /* xirc2ps_config */ - -static void -xirc2ps_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "release\n"); - - if (link->resource[2]->end) { - struct net_device *dev =3D link->priv; - struct local_info *local =3D netdev_priv(dev); - if (local->dingo) - iounmap(local->dingo_ccr - 0x0800); - } - pcmcia_disable_device(link); -} /* xirc2ps_release */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - - -static int xirc2ps_suspend(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) { - netif_device_detach(dev); - do_powerdown(dev); - } - - return 0; -} - -static int xirc2ps_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) { - do_reset(dev,1); - netif_device_attach(dev); - } - - return 0; -} - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/**************** - * This is the Interrupt service route. - */ -static irqreturn_t -xirc2ps_interrupt(int irq, void *dev_id) -{ - struct net_device *dev =3D (struct net_device *)dev_id; - struct local_info *lp =3D netdev_priv(dev); - unsigned int ioaddr; - u_char saved_page; - unsigned bytes_rcvd; - unsigned int_status, eth_status, rx_status, tx_status; - unsigned rsr, pktlen; - ulong start_ticks =3D jiffies; /* fixme: jiffies rollover every 497 da= ys - * is this something to worry about? - * -- on a laptop? - */ - - if (!netif_device_present(dev)) - return IRQ_HANDLED; - - ioaddr =3D dev->base_addr; - if (lp->mohawk) { /* must disable the interrupt */ - PutByte(XIRCREG_CR, 0); - } - - pr_debug("%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr); - - saved_page =3D GetByte(XIRCREG_PR); - /* Read the ISR to see whats the cause for the interrupt. - * This also clears the interrupt flags on CE2 cards - */ - int_status =3D GetByte(XIRCREG_ISR); - bytes_rcvd =3D 0; - loop_entry: - if (int_status =3D=3D 0xff) { /* card may be ejected */ - pr_debug("%s: interrupt %d for dead card\n", dev->name, irq); - goto leave; - } - eth_status =3D GetByte(XIRCREG_ESR); - - SelectPage(0x40); - rx_status =3D GetByte(XIRCREG40_RXST0); - PutByte(XIRCREG40_RXST0, (~rx_status & 0xff)); - tx_status =3D GetByte(XIRCREG40_TXST0); - tx_status |=3D GetByte(XIRCREG40_TXST1) << 8; - PutByte(XIRCREG40_TXST0, 0); - PutByte(XIRCREG40_TXST1, 0); - - pr_debug("%s: ISR=3D%#2.2x ESR=3D%#2.2x RSR=3D%#2.2x TSR=3D%#4.4x\n", - dev->name, int_status, eth_status, rx_status, tx_status); - - /***** receive section ******/ - SelectPage(0); - while (eth_status & FullPktRcvd) { - rsr =3D GetByte(XIRCREG0_RSR); - if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) { - /* too many bytes received during this int, drop the rest of the - * packets */ - dev->stats.rx_dropped++; - pr_debug("%s: RX drop, too much done\n", dev->name); - } else if (rsr & PktRxOk) { - struct sk_buff *skb; - - pktlen =3D GetWord(XIRCREG0_RBC); - bytes_rcvd +=3D pktlen; - - pr_debug("rsr=3D%#02x packet_length=3D%u\n", rsr, pktlen); - - /* 1 extra so we can use insw */ - skb =3D netdev_alloc_skb(dev, pktlen + 3); - if (!skb) { - dev->stats.rx_dropped++; - } else { /* okay get the packet */ - skb_reserve(skb, 2); - if (lp->silicon =3D=3D 0 ) { /* work around a hardware bug */ - unsigned rhsa; /* receive start address */ - - SelectPage(5); - rhsa =3D GetWord(XIRCREG5_RHSA0); - SelectPage(0); - rhsa +=3D 3; /* skip control infos */ - if (rhsa >=3D 0x8000) - rhsa =3D 0; - if (rhsa + pktlen > 0x8000) { - unsigned i; - u_char *buf =3D skb_put(skb, pktlen); - for (i=3D0; i < pktlen ; i++, rhsa++) { - buf[i] =3D GetByte(XIRCREG_EDP); - if (rhsa =3D=3D 0x8000) { - rhsa =3D 0; - i--; - } - } - } else { - insw(ioaddr+XIRCREG_EDP, - skb_put(skb, pktlen), (pktlen+1)>>1); - } - } - #if 0 - else if (lp->mohawk) { - /* To use this 32 bit access we should use - * a manual optimized loop - * Also the words are swapped, we can get more - * performance by using 32 bit access and swapping - * the words in a register. Will need this for cardbus - * - * Note: don't forget to change the ALLOC_SKB to .. +3 - */ - unsigned i; - u_long *p =3D skb_put(skb, pktlen); - register u_long a; - unsigned int edpreg =3D ioaddr+XIRCREG_EDP-2; - for (i=3D0; i < len ; i +=3D 4, p++) { - a =3D inl(edpreg); - __asm__("rorl $16,%0\n\t" - :"=3Dq" (a) - : "0" (a)); - *p =3D a; - } - } - #endif - else { - insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen), - (pktlen+1)>>1); - } - skb->protocol =3D eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pktlen; - if (!(rsr & PhyPkt)) - dev->stats.multicast++; - } - } else { /* bad packet */ - pr_debug("rsr=3D%#02x\n", rsr); - } - if (rsr & PktTooLong) { - dev->stats.rx_frame_errors++; - pr_debug("%s: Packet too long\n", dev->name); - } - if (rsr & CRCErr) { - dev->stats.rx_crc_errors++; - pr_debug("%s: CRC error\n", dev->name); - } - if (rsr & AlignErr) { - dev->stats.rx_fifo_errors++; /* okay ? */ - pr_debug("%s: Alignment error\n", dev->name); - } - - /* clear the received/dropped/error packet */ - PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ - - /* get the new ethernet status */ - eth_status =3D GetByte(XIRCREG_ESR); - } - if (rx_status & 0x10) { /* Receive overrun */ - dev->stats.rx_over_errors++; - PutByte(XIRCREG_CR, ClearRxOvrun); - pr_debug("receive overrun cleared\n"); - } - - /***** transmit section ******/ - if (int_status & PktTxed) { - unsigned n, nn; - - n =3D lp->last_ptr_value; - nn =3D GetByte(XIRCREG0_PTR); - lp->last_ptr_value =3D nn; - if (nn < n) /* rollover */ - dev->stats.tx_packets +=3D 256 - n; - else if (n =3D=3D nn) { /* happens sometimes - don't know why */ - pr_debug("PTR not changed?\n"); - } else - dev->stats.tx_packets +=3D lp->last_ptr_value - n; - netif_wake_queue(dev); - } - if (tx_status & 0x0002) { /* Excessive collisions */ - pr_debug("tx restarted due to excessive collisions\n"); - PutByte(XIRCREG_CR, RestartTx); /* restart transmitter process */ - } - if (tx_status & 0x0040) - dev->stats.tx_aborted_errors++; - - /* recalculate our work chunk so that we limit the duration of this - * ISR to about 1/10 of a second. - * Calculate only if we received a reasonable amount of bytes. - */ - if (bytes_rcvd > 1000) { - u_long duration =3D jiffies - start_ticks; - - if (duration >=3D HZ/10) { /* if more than about 1/10 second */ - maxrx_bytes =3D (bytes_rcvd * (HZ/10)) / duration; - if (maxrx_bytes < 2000) - maxrx_bytes =3D 2000; - else if (maxrx_bytes > 22000) - maxrx_bytes =3D 22000; - pr_debug("set maxrx=3D%u (rcvd=3D%u ticks=3D%lu)\n", - maxrx_bytes, bytes_rcvd, duration); - } else if (!duration && maxrx_bytes < 22000) { - /* now much faster */ - maxrx_bytes +=3D 2000; - if (maxrx_bytes > 22000) - maxrx_bytes =3D 22000; - pr_debug("set maxrx=3D%u\n", maxrx_bytes); - } - } - - leave: - if (lockup_hack) { - if (int_status !=3D 0xff && (int_status =3D GetByte(XIRCREG_ISR)) !=3D 0) - goto loop_entry; - } - SelectPage(saved_page); - PutByte(XIRCREG_CR, EnableIntr); /* re-enable interrupts */ - /* Instead of dropping packets during a receive, we could - * force an interrupt with this command: - * PutByte(XIRCREG_CR, EnableIntr|ForceIntr); - */ - return IRQ_HANDLED; -} /* xirc2ps_interrupt */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void -xirc2ps_tx_timeout_task(struct work_struct *work) -{ - struct local_info *local =3D - container_of(work, struct local_info, tx_timeout_task); - struct net_device *dev =3D local->dev; - /* reset the card */ - do_reset(dev,1); - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); -} - -static void -xirc_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct local_info *lp =3D netdev_priv(dev); - dev->stats.tx_errors++; - netdev_notice(dev, "transmit timed out\n"); - schedule_work(&lp->tx_timeout_task); -} - -static netdev_tx_t -do_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct local_info *lp =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - int okay; - unsigned freespace; - unsigned pktlen =3D skb->len; - - pr_debug("do_start_xmit(skb=3D%p, dev=3D%p) len=3D%u\n", - skb, dev, pktlen); - - - /* adjust the packet length to min. required - * and hope that the buffer is large enough - * to provide some random data. - * fixme: For Mohawk we can change this by sending - * a larger packetlen than we actually have; the chip will - * pad this in his buffer with random bytes - */ - if (pktlen < ETH_ZLEN) - { - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - pktlen =3D ETH_ZLEN; - } - - netif_stop_queue(dev); - SelectPage(0); - PutWord(XIRCREG0_TRS, (u_short)pktlen+2); - freespace =3D GetWord(XIRCREG0_TSO) & 0x7fff; - /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */ - okay =3D pktlen +2 < freespace; - pr_debug("%s: avail. tx space=3D%u%s\n", - dev->name, freespace, okay ? " (okay)":" (not enough)"); - if (!okay) { /* not enough space */ - return NETDEV_TX_BUSY; /* upper layer may decide to requeue this packet = */ - } - /* send the packet */ - PutWord(XIRCREG_EDP, (u_short)pktlen); - outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1); - if (pktlen & 1) - PutByte(XIRCREG_EDP, skb->data[pktlen-1]); - - if (lp->mohawk) - PutByte(XIRCREG_CR, TransmitPacket|EnableIntr); - - dev_kfree_skb (skb); - dev->stats.tx_bytes +=3D pktlen; - netif_start_queue(dev); - return NETDEV_TX_OK; -} - -struct set_address_info { - int reg_nr; - int page_nr; - int mohawk; - unsigned int ioaddr; -}; - -static void set_address(struct set_address_info *sa_info, const char *addr) -{ - unsigned int ioaddr =3D sa_info->ioaddr; - int i; - - for (i =3D 0; i < 6; i++) { - if (sa_info->reg_nr > 15) { - sa_info->reg_nr =3D 8; - sa_info->page_nr++; - SelectPage(sa_info->page_nr); - } - if (sa_info->mohawk) - PutByte(sa_info->reg_nr++, addr[5 - i]); - else - PutByte(sa_info->reg_nr++, addr[i]); - } -} - -/**************** - * Set all addresses: This first one is the individual address, - * the next 9 addresses are taken from the multicast list and - * the rest is filled with the individual address. - */ -static void set_addresses(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct local_info *lp =3D netdev_priv(dev); - struct netdev_hw_addr *ha; - struct set_address_info sa_info; - int i; - - /* - * Setup the info structure so that by first set_address call it will do - * SelectPage with the right page number. Hence these ones here. - */ - sa_info.reg_nr =3D 15 + 1; - sa_info.page_nr =3D 0x50 - 1; - sa_info.mohawk =3D lp->mohawk; - sa_info.ioaddr =3D ioaddr; - - set_address(&sa_info, dev->dev_addr); - i =3D 0; - netdev_for_each_mc_addr(ha, dev) { - if (i++ =3D=3D 9) - break; - set_address(&sa_info, ha->addr); - } - while (i++ < 9) - set_address(&sa_info, dev->dev_addr); - SelectPage(0); -} - -/**************** - * Set or clear the multicast filter for this adaptor. - * We can filter up to 9 addresses, if more are requested we set - * multicast promiscuous mode. - */ - -static void -set_multicast_list(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - unsigned value; - - SelectPage(0x42); - value =3D GetByte(XIRCREG42_SWC1) & 0xC0; - - if (dev->flags & IFF_PROMISC) { /* snoop */ - PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */ - } else if (netdev_mc_count(dev) > 9 || (dev->flags & IFF_ALLMULTI)) { - PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */ - } else if (!netdev_mc_empty(dev)) { - /* the chip can filter 9 addresses perfectly */ - PutByte(XIRCREG42_SWC1, value | 0x01); - SelectPage(0x40); - PutByte(XIRCREG40_CMD0, Offline); - set_addresses(dev); - SelectPage(0x40); - PutByte(XIRCREG40_CMD0, EnableRecv | Online); - } else { /* standard usage */ - PutByte(XIRCREG42_SWC1, value | 0x00); - } - SelectPage(0); -} - -static int -do_config(struct net_device *dev, struct ifmap *map) -{ - struct local_info *local =3D netdev_priv(dev); - - pr_debug("do_config(%p)\n", dev); - if (map->port !=3D 255 && map->port !=3D dev->if_port) { - if (map->port > 4) - return -EINVAL; - if (!map->port) { - local->probe_port =3D 1; - WRITE_ONCE(dev->if_port, 1); - } else { - local->probe_port =3D 0; - WRITE_ONCE(dev->if_port, map->port); - } - netdev_info(dev, "switching to %s port\n", if_names[dev->if_port]); - do_reset(dev,1); /* not the fine way :-) */ - } - return 0; -} - -/**************** - * Open the driver - */ -static int -do_open(struct net_device *dev) -{ - struct local_info *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - dev_dbg(&link->dev, "do_open(%p)\n", dev); - - /* Check that the PCMCIA card is still here. */ - /* Physical device present signature. */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - - /* okay */ - link->open++; - - netif_start_queue(dev); - do_reset(dev,1); - - return 0; -} - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strscpy(info->driver, "xirc2ps_cs", sizeof(info->driver)); - snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx", - dev->base_addr); -} - -static const struct ethtool_ops netdev_ethtool_ops =3D { - .get_drvinfo =3D netdev_get_drvinfo, -}; - -static int -do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct local_info *local =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - struct mii_ioctl_data *data =3D if_mii(rq); - - pr_debug("%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", - dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data->phy_id, data->reg_num, data->val_in, data->val_out); - - if (!local->mohawk) - return -EOPNOTSUPP; - - switch(cmd) { - case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data->phy_id =3D 0; /* we have only this address */ - fallthrough; - case SIOCGMIIREG: /* Read the specified MII register. */ - data->val_out =3D mii_rd(ioaddr, data->phy_id & 0x1f, - data->reg_num & 0x1f); - break; - case SIOCSMIIREG: /* Write the specified MII register */ - mii_wr(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in, - 16); - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -static void -hardreset(struct net_device *dev) -{ - struct local_info *local =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - - SelectPage(4); - udelay(1); - PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ - msleep(40); /* wait 40 msec */ - if (local->mohawk) - PutByte(XIRCREG4_GPR1, 1); /* set bit 0: power up */ - else - PutByte(XIRCREG4_GPR1, 1 | 4); /* set bit 0: power up, bit 2: AIC */ - msleep(20); /* wait 20 msec */ -} - -static void -do_reset(struct net_device *dev, int full) -{ - struct local_info *local =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - unsigned value; - - pr_debug("%s: do_reset(%p,%d)\n", dev->name, dev, full); - - hardreset(dev); - PutByte(XIRCREG_CR, SoftReset); /* set */ - msleep(20); /* wait 20 msec */ - PutByte(XIRCREG_CR, 0); /* clear */ - msleep(40); /* wait 40 msec */ - if (local->mohawk) { - SelectPage(4); - /* set pin GP1 and GP2 to output (0x0c) - * set GP1 to low to power up the ML6692 (0x00) - * set GP2 to high to power up the 10Mhz chip (0x02) - */ - PutByte(XIRCREG4_GPR0, 0x0e); - } - - /* give the circuits some time to power up */ - msleep(500); /* about 500ms */ - - local->last_ptr_value =3D 0; - local->silicon =3D local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4 - : (GetByte(XIRCREG4_BOV) & 0x30) >> 4; - - if (local->probe_port) { - if (!local->mohawk) { - SelectPage(4); - PutByte(XIRCREG4_GPR0, 4); - local->probe_port =3D 0; - } - } else if (dev->if_port =3D=3D 2) { /* enable 10Base2 */ - SelectPage(0x42); - PutByte(XIRCREG42_SWC1, 0xC0); - } else { /* enable 10BaseT */ - SelectPage(0x42); - PutByte(XIRCREG42_SWC1, 0x80); - } - msleep(40); /* wait 40 msec to let it complete */ - - #if 0 - { - SelectPage(0); - value =3D GetByte(XIRCREG_ESR); /* read the ESR */ - pr_debug("%s: ESR is: %#02x\n", dev->name, value); - } - #endif - - /* setup the ECR */ - SelectPage(1); - PutByte(XIRCREG1_IMR0, 0xff); /* allow all ints */ - PutByte(XIRCREG1_IMR1, 1 ); /* and Set TxUnderrunDetect */ - value =3D GetByte(XIRCREG1_ECR); - #if 0 - if (local->mohawk) - value |=3D DisableLinkPulse; - PutByte(XIRCREG1_ECR, value); - #endif - pr_debug("%s: ECR is: %#02x\n", dev->name, value); - - SelectPage(0x42); - PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */ - - if (local->silicon !=3D 1) { - /* set the local memory dividing line. - * The comments in the sample code say that this is only - * settable with the scipper version 2 which is revision 0. - * Always for CE3 cards - */ - SelectPage(2); - PutWord(XIRCREG2_RBS, 0x2000); - } - - if (full) - set_addresses(dev); - - /* Hardware workaround: - * The receive byte pointer after reset is off by 1 so we need - * to move the offset pointer back to 0. - */ - SelectPage(0); - PutWord(XIRCREG0_DO, 0x2000); /* change offset command, off=3D0 */ - - /* setup MAC IMRs and clear status registers */ - SelectPage(0x40); /* Bit 7 ... bit 0 */ - PutByte(XIRCREG40_RMASK0, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, M= P */ - PutByte(XIRCREG40_TMASK0, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, C= RS */ - PutByte(XIRCREG40_TMASK1, 0xb0); /* rsv, rsv, PTD, EXT, rsv,rsv,rsv, r= sv*/ - PutByte(XIRCREG40_RXST0, 0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, M= P */ - PutByte(XIRCREG40_TXST0, 0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, C= RS */ - PutByte(XIRCREG40_TXST1, 0x00); /* TEN, rsv, PTD, EXT, retry_counter:= 4 */ - - if (full && local->mohawk && init_mii(dev)) { - if (dev->if_port =3D=3D 4 || local->dingo || local->new_mii) { - netdev_info(dev, "MII selected\n"); - SelectPage(2); - PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08); - msleep(20); - } else { - netdev_info(dev, "MII detected; using 10mbs\n"); - SelectPage(0x42); - if (dev->if_port =3D=3D 2) /* enable 10Base2 */ - PutByte(XIRCREG42_SWC1, 0xC0); - else /* enable 10BaseT */ - PutByte(XIRCREG42_SWC1, 0x80); - msleep(40); /* wait 40 msec to let it complete */ - } - if (full_duplex) - PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR) | FullDuplex); - } else { /* No MII */ - SelectPage(0); - value =3D GetByte(XIRCREG_ESR); /* read the ESR */ - dev->if_port =3D (value & MediaSelect) ? 1 : 2; - } - - /* configure the LEDs */ - SelectPage(2); - if (dev->if_port =3D=3D 1 || dev->if_port =3D=3D 4) /* TP: Link and Ac= tivity */ - PutByte(XIRCREG2_LED, 0x3b); - else /* Coax: Not-Collision and Activity */ - PutByte(XIRCREG2_LED, 0x3a); - - if (local->dingo) - PutByte(0x0b, 0x04); /* 100 Mbit LED */ - - /* enable receiver and put the mac online */ - if (full) { - set_multicast_list(dev); - SelectPage(0x40); - PutByte(XIRCREG40_CMD0, EnableRecv | Online); - } - - /* setup Ethernet IMR and enable interrupts */ - SelectPage(1); - PutByte(XIRCREG1_IMR0, 0xff); - udelay(1); - SelectPage(0); - PutByte(XIRCREG_CR, EnableIntr); - if (local->modem && !local->dingo) { /* do some magic */ - if (!(GetByte(0x10) & 0x01)) - PutByte(0x10, 0x11); /* unmask master-int bit */ - } - - if (full) - netdev_info(dev, "media %s, silicon revision %d\n", - if_names[dev->if_port], local->silicon); - /* We should switch back to page 0 to avoid a bug in revision 0 - * where regs with offset below 8 can't be read after an access - * to the MAC registers */ - SelectPage(0); -} - -/**************** - * Initialize the Media-Independent-Interface - * Returns: True if we have a good MII - */ -static int -init_mii(struct net_device *dev) -{ - struct local_info *local =3D netdev_priv(dev); - unsigned int ioaddr =3D dev->base_addr; - unsigned control, status, linkpartner; - int i; - - if (if_port =3D=3D 4 || if_port =3D=3D 1) { /* force 100BaseT or 10Bas= eT */ - dev->if_port =3D if_port; - local->probe_port =3D 0; - return 1; - } - - status =3D mii_rd(ioaddr, 0, 1); - if ((status & 0xff00) !=3D 0x7800) - return 0; /* No MII */ - - local->new_mii =3D (mii_rd(ioaddr, 0, 2) !=3D 0xffff); - =20 - if (local->probe_port) - control =3D 0x1000; /* auto neg */ - else if (dev->if_port =3D=3D 4) - control =3D 0x2000; /* no auto neg, 100mbs mode */ - else - control =3D 0x0000; /* no auto neg, 10mbs mode */ - mii_wr(ioaddr, 0, 0, control, 16); - udelay(100); - control =3D mii_rd(ioaddr, 0, 0); - - if (control & 0x0400) { - netdev_notice(dev, "can't take PHY out of isolation mode\n"); - local->probe_port =3D 0; - return 0; - } - - if (local->probe_port) { - /* according to the DP83840A specs the auto negotiation process - * may take up to 3.5 sec, so we use this also for our ML6692 - * Fixme: Better to use a timer here! - */ - for (i=3D0; i < 35; i++) { - msleep(100); /* wait 100 msec */ - status =3D mii_rd(ioaddr, 0, 1); - if ((status & 0x0020) && (status & 0x0004)) - break; - } - - if (!(status & 0x0020)) { - netdev_info(dev, "autonegotiation failed; using 10mbs\n"); - if (!local->new_mii) { - control =3D 0x0000; - mii_wr(ioaddr, 0, 0, control, 16); - udelay(100); - SelectPage(0); - dev->if_port =3D (GetByte(XIRCREG_ESR) & MediaSelect) ? 1 : 2; - } - } else { - linkpartner =3D mii_rd(ioaddr, 0, 5); - netdev_info(dev, "MII link partner: %04x\n", linkpartner); - if (linkpartner & 0x0080) { - dev->if_port =3D 4; - } else - dev->if_port =3D 1; - } - } - - return 1; -} - -static void -do_powerdown(struct net_device *dev) -{ - - unsigned int ioaddr =3D dev->base_addr; - - pr_debug("do_powerdown(%p)\n", dev); - - SelectPage(4); - PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ - SelectPage(0); -} - -static int -do_stop(struct net_device *dev) -{ - unsigned int ioaddr =3D dev->base_addr; - struct local_info *lp =3D netdev_priv(dev); - struct pcmcia_device *link =3D lp->p_dev; - - dev_dbg(&link->dev, "do_stop(%p)\n", dev); - - if (!link) - return -ENODEV; - - netif_stop_queue(dev); - - SelectPage(0); - PutByte(XIRCREG_CR, 0); /* disable interrupts */ - SelectPage(0x01); - PutByte(XIRCREG1_IMR0, 0x00); /* forbid all ints */ - SelectPage(4); - PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ - SelectPage(0); - - link->open--; - return 0; -} - -static const struct pcmcia_device_id xirc2ps_ids[] =3D { - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a), - PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea), - PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM33", 0x2e3ee845, 0x80609023), - PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a), - PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29), - PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf140371= 9), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet+Modem II", = 0x2e3ee845, 0xeca401bf), - PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a), - PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b9= 4fe, 0xf381c1a2), - PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37), - PCMCIA_DEVICE_PROD_ID13("Xircom", "PS-CE2-10", 0x2e3ee845, 0x947d9073), - PCMCIA_DEVICE_PROD_ID13("Xircom", "R2E-100BTX", 0x2e3ee845, 0x2464a6e3), - PCMCIA_DEVICE_PROD_ID13("Xircom", "RE-10", 0x2e3ee845, 0x3e08d609), - PCMCIA_DEVICE_PROD_ID13("Xircom", "XE2000", 0x2e3ee845, 0xf7188e46), - PCMCIA_DEVICE_PROD_ID12("Compaq", "Ethernet LAN Card", 0x54f7c49c, 0x9fd2= f0a2), - PCMCIA_DEVICE_PROD_ID12("Compaq", "Netelligent 10/100 PC Card", 0x54f7c49= c, 0xefe96769), - PCMCIA_DEVICE_PROD_ID12("Intel", "EtherExpress(TM) PRO/100 PC Card Mobile= Adapter16", 0x816cc815, 0x174397db), - PCMCIA_DEVICE_PROD_ID12("Toshiba", "10/100 Ethernet PC Card", 0x44a09d9c,= 0xb44deecf), - /* also matches CFE-10 cards! */ - /* PCMCIA_DEVICE_MANF_CARD(0x0105, 0x010a), */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids); - - -static struct pcmcia_driver xirc2ps_cs_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "xirc2ps_cs", - .probe =3D xirc2ps_probe, - .remove =3D xirc2ps_detach, - .id_table =3D xirc2ps_ids, - .suspend =3D xirc2ps_suspend, - .resume =3D xirc2ps_resume, -}; -module_pcmcia_driver(xirc2ps_cs_driver); - -#ifndef MODULE -static int __init setup_xirc2ps_cs(char *str) -{ - /* if_port, full_duplex, do_sound, lockup_hack - */ - int ints[10] =3D { -1 }; - - str =3D get_options(str, ARRAY_SIZE(ints), ints); - -#define MAYBE_SET(X,Y) if (ints[0] >=3D Y && ints[Y] !=3D -1) { X =3D ints= [Y]; } - MAYBE_SET(if_port, 3); - MAYBE_SET(full_duplex, 4); - MAYBE_SET(do_sound, 5); - MAYBE_SET(lockup_hack, 6); -#undef MAYBE_SET - - return 1; -} - -__setup("xirc2ps_cs=3D", setup_xirc2ps_cs); -#endif --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4058337BE80; Tue, 21 Apr 2026 19:58:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801501; cv=none; b=oc9NlPQ3V01Uj4N6Pbr8u09PtPSlYBQLF4nyGnmJl+9UFvdGEQJuTHSQLqhUedO8bKnCa6BwXRW9z1BFyy98sJ6MuyuC0Bz95TwF9F5uqnmYlzYWuFo6QEVYZkIppTTI/QcjUBM5vZOhM/t2z9bZjy2FiBBSKCju88UkBr3JwPM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801501; c=relaxed/simple; bh=GHQFcfdbqb4mZ11DRdAknE42emJCYE7ffe2k8yQyu0M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gNT5kSffJkp6MEmjQgWY421N5Ptc1yUFWZF3tGm1q9RNXav5NdfO+zKSTrQTqWdUvii/JlmKPjilObcNSOEZLUF56FCSYa4soavaFsP7gyDVcegs0qlKi+gGHrdfgPyc/9p90nlos+Knq9kvu7wQFMrIvCPlvDh91YT/8wKGB4A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=25fDWLbh; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="25fDWLbh" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=pCWZ70U/PxE0BAx4eSTpboTeYuUSVwDNPDi9kI+LZro=; b=25 fDWLbhrnaUKabTvHhMJfI7mqSRZ3nFgxZV2d43E+EbVg8GMYWXmFfHCe8CqGNDl8yaBHDQjP7xuON q7CCbDvuOdY8VW6e23JBcskUuoWamMer1m8TbbjL6e5845kGUDEnP04dmq4Hi14EiaxYbXg38+7g0 oORvL/ir9Kz9GW4=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGp8-00GwVc-Fx; Tue, 21 Apr 2026 21:31:54 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:18 -0500 Subject: [PATCH net 15/18] drivers: net: 8390: AX88190: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-15-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=57091; i=andrew@lunn.ch; h=from:subject:message-id; bh=GHQFcfdbqb4mZ11DRdAknE42emJCYE7ffe2k8yQyu0M=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CC1pxkcMo9clMhGV4Q2flLnEUafzA8icyeg hWcN1lm6RWJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hJT3EAC6gW2gsQ64ZhLgmmtr+jDM6GrsmigHLtvk+Yk7TugMkvSMhmWakJAw0LRTuE/fyz5QeVa a2WNym/cJjdnAo3539INb1DtWbOk8w5uG1eIpDJfBfeG6t5VXLmWdwUVkSJaXvMc1+vrJHxjXRy ZF0+zMGfrmGIisBYRe8DIHhdhxLghZPQoMJ/0BDONX0dZ+g20a3Lr1pSEVySiA3gdqA+v0Tp2MD eOpFWj7cXiUBQuKYeQiLYJl32CA5h3hsnULFgdm9Q+qFJZvN8jXMUxr4rwWpZWhgTt1xPViIi+n vL39+ZQaur4PdGKVOoDaTAen2SHDvOqU7jnofrZu4xa2uKv9TDEcuNkiroQN9F+kaGAGPvR3ftp NetgeFWKhapBZxSVdG26/7yPaqMsBVtAb+WXau9Rti/DsmvYt+j4RHU+d3sEMPBM243t5QnCaOO 5dC3RG+RY5WWo7iRM+oh++R0RdnrPakFCnIiKN3dMyCr3M03TTRwc7PMYMV4Hevv5bprv88UR2u XjTfMa//Ic779iWHT9fuOwk1v25lkdq6BZB2KXU87PzJKmoVhJDUgZJ74clfKHS7KrfjydnHc7t s5Hmxo0kLv8vuQYgenK0FIb6II6nhWNb29LyCt3GEBwCp0gzj0H3I1U+ixj86GfHvQrFSR8gqqi 7HJ/tma5rNoKtbQ== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 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 --- 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 =20 if NET_VENDOR_8390 =20 -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) +=3D hydra.o obj-$(CONFIG_MCF8390) +=3D mcf8390.o obj-$(CONFIG_NE2000) +=3D ne.o 8390p.o obj-$(CONFIG_NE2K_PCI) +=3D ne2k-pci.o 8390.o -obj-$(CONFIG_PCMCIA_AXNET) +=3D axnet_cs.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) +=3D pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) +=3D stnic.o 8390.o obj-$(CONFIG_ULTRA) +=3D smc-ultra.o 8390.o diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/83= 90/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+ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - 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 - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "8390.h" - -#include -#include -#include -#include - -#include -#include -#include - -#define AXNET_CMD 0x00 -#define AXNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ -#define AXNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ -#define AXNET_MII_EEP 0x14 /* Offset of MII access port */ -#define AXNET_TEST 0x15 /* Offset of TEST Register port */ -#define AXNET_GPIO 0x17 /* Offset of General Purpose Register Port */ - -#define AXNET_START_PG 0x40 /* First page of TX buffer */ -#define AXNET_STOP_PG 0x80 /* Last page +1 of RX ring */ - -#define AXNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ - -#define IS_AX88190 0x0001 -#define IS_AX88790 0x0002 - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -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); - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -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 =3D (char *)netdev_priv(dev) + sizeof(struct ei_device); - return p; -} - -static const struct net_device_ops axnet_netdev_ops =3D { - .ndo_open =3D axnet_open, - .ndo_stop =3D axnet_close, - .ndo_eth_ioctl =3D axnet_ioctl, - .ndo_start_xmit =3D axnet_start_xmit, - .ndo_tx_timeout =3D axnet_tx_timeout, - .ndo_get_stats =3D get_stats, - .ndo_set_rx_mode =3D set_multicast_list, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D 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 =3D alloc_etherdev(sizeof(struct ei_device) + sizeof(struct axnet_= dev)); - if (!dev) - return -ENOMEM; - - ei_local =3D netdev_priv(dev); - spin_lock_init(&ei_local->page_lock); - - info =3D PRIV(dev); - info->p_dev =3D link; - link->priv =3D dev; - link->config_flags |=3D CONF_ENABLE_IRQ; - - dev->netdev_ops =3D &axnet_netdev_ops; - - dev->watchdog_timeo =3D TX_TIMEOUT; - - return axnet_config(link); -} /* axnet_attach */ - -static void axnet_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - dev_dbg(&link->dev, "axnet_detach(0x%p)\n", link); - - unregister_netdev(dev); - - axnet_release(link); - - free_netdev(dev); -} /* axnet_detach */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - This probes for a card's hardware address by reading the PROM. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int get_prom(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - unsigned int ioaddr =3D 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[] =3D { - {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 !=3D 0x03c0) - return 0; - - axnet_reset_8390(dev); - mdelay(10); - - for (i =3D 0; i < ARRAY_SIZE(program_seq); i++) - outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); - - for (i =3D 0; i < 6; i +=3D 2) { - j =3D inw(ioaddr + AXNET_DATAPORT); - addr[i] =3D j & 0xff; - addr[i+1] =3D 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 &=3D ~IO_DATA_PATH_WIDTH; - link->resource[1]->flags &=3D ~IO_DATA_PATH_WIDTH; - if (link->resource[0]->end =3D=3D 32) { - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_AUTO; - /* for master/slave multifunction cards */ - if (link->resource[1]->end > 0) - link->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_8; - } else { - /* This should be two 16-port windows */ - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_8; - link->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_16; - } - if (link->resource[0]->start =3D=3D 0) { - for (j =3D 0; j < 0x400; j +=3D 0x20) { - link->resource[0]->start =3D j ^ 0x300; - link->resource[1]->start =3D (j ^ 0x300) + 0x10; - link->io_lines =3D 16; - ret =3D pcmcia_request_io(link); - if (ret =3D=3D 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 =3D=3D 0) - return -EINVAL; - - p_dev->config_index =3D 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 =3D link->priv; - struct axnet_dev *info =3D 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 =3D 0x63; - link->config_flags |=3D CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - ret =3D pcmcia_loop_config(link, axnet_configcheck, NULL); - if (ret !=3D 0) - goto failed; - - if (!link->irq) - goto failed; - - if (resource_size(link->resource[1]) =3D=3D 8) - link->config_flags |=3D CONF_ENABLE_SPKR; - =20 - ret =3D pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq =3D link->irq; - dev->base_addr =3D 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 =3D "AX88190"; - ei_status.word16 =3D 1; - ei_status.tx_start_page =3D AXNET_START_PG; - ei_status.rx_start_page =3D AXNET_START_PG + TX_PAGES; - ei_status.stop_page =3D AXNET_STOP_PG; - ei_status.reset_8390 =3D axnet_reset_8390; - ei_status.get_8390_hdr =3D get_8390_hdr; - ei_status.block_input =3D block_input; - ei_status.block_output =3D block_output; - - if (inb(dev->base_addr + AXNET_TEST) !=3D 0) - info->flags |=3D IS_AX88790; - else - info->flags |=3D IS_AX88190; - - if (info->flags & IS_AX88790) - outb(0x10, dev->base_addr + AXNET_GPIO); /* select Internal PHY */ - - info->active_low =3D 0; - - for (i =3D 0; i < 32; i++) { - j =3D mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); - j2 =3D mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2); - if (j =3D=3D j2) continue; - if ((j !=3D 0) && (j !=3D 0xffff)) break; - } - - if (i =3D=3D 32) { - /* Maybe PHY is in power down mode. (PPD_SET =3D 1) - Bit 2 of CCSR is active low. */ - pcmcia_write_config_byte(link, CISREG_CCSR, 0x04); - for (i =3D 0; i < 32; i++) { - j =3D mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); - j2 =3D mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2); - if (j =3D=3D j2) continue; - if ((j !=3D 0) && (j !=3D 0xffff)) { - info->active_low =3D 1; - break; - } - } - } - - info->phy_id =3D (i < 32) ? i : -1; - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) !=3D 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 !=3D -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 =3D link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int axnet_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct axnet_dev *info =3D PRIV(dev); - - if (link->open) { - if (info->active_low =3D=3D 1) - pcmcia_write_config_byte(link, CISREG_CCSR, 0x04); - - axnet_reset_8390(dev); - AX88190_init(dev, 1); - netif_device_attach(dev); - } - - return 0; -} - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - MII interface support - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#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 =3D 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 =3D (0xf6<<10)|(phy_id<<5)|loc; - int i, retval =3D 0; - - mdio_sync(addr); - for (i =3D 14; i >=3D 0; i--) { - int dat =3D (cmd&(1< 0; i--) { - outb_p(MDIO_ENB_IN, addr); - retval =3D (retval << 1) | ((inb_p(addr) & MDIO_DATA_READ) !=3D 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 =3D (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; - int i; - - mdio_sync(addr); - for (i =3D 31; i >=3D 0; i--) { - int dat =3D (cmd&(1<=3D 0; i--) { - outb_p(MDIO_ENB_IN, addr); - outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr); - } -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int axnet_open(struct net_device *dev) -{ - int ret; - struct axnet_dev *info =3D PRIV(dev); - struct pcmcia_device *link =3D info->p_dev; - unsigned int nic_base =3D dev->base_addr; - =20 - 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 =3D request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs",= dev); - if (ret) - return ret; - - link->open++; - - info->link_status =3D 0x00; - timer_setup(&info->watchdog, ei_watchdog, 0); - mod_timer(&info->watchdog, jiffies + HZ); - - return ax_open(dev); -} /* axnet_open */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int axnet_close(struct net_device *dev) -{ - struct axnet_dev *info =3D PRIV(dev); - struct pcmcia_device *link =3D info->p_dev; - - dev_dbg(&link->dev, "axnet_close('%s')\n", dev->name); - - ax_close(dev); - free_irq(dev->irq, dev); - =20 - link->open--; - netif_stop_queue(dev); - timer_delete_sync(&info->watchdog); - - return 0; -} /* axnet_close */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Hard reset the card. This used to pause for the same period that - a 8390 reset command required, but that shouldn't be necessary. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void axnet_reset_8390(struct net_device *dev) -{ - unsigned int nic_base =3D dev->base_addr; - int i; - - ei_status.txing =3D ei_status.dmaing =3D 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 =3D 0; i < 100; i++) { - if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) !=3D 0) - break; - udelay(100); - } - outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */ - =20 - if (i =3D=3D 100) - netdev_err(dev, "axnet_reset_8390() did not complete\n"); - =20 -} /* axnet_reset_8390 */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id) -{ - struct net_device *dev =3D dev_id; - PRIV(dev)->stale =3D 0; - return ax_interrupt(irq, dev_id); -} - -static void ei_watchdog(struct timer_list *t) -{ - struct axnet_dev *info =3D timer_container_of(info, t, watchdog); - struct net_device *dev =3D info->p_dev->priv; - unsigned int nic_base =3D dev->base_addr; - unsigned int mii_addr =3D 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 =3D HZ; - } - if (info->fast_poll) { - info->fast_poll--; - info->watchdog.expires =3D jiffies + 1; - add_timer(&info->watchdog); - return; - } - - if (info->phy_id < 0) - goto reschedule; - link =3D mdio_read(mii_addr, info->phy_id, 1); - if (!link || (link =3D=3D 0xffff)) { - netdev_info(dev, "MII is missing!\n"); - info->phy_id =3D -1; - goto reschedule; - } - - link &=3D 0x0004; - if (link !=3D info->link_status) { - u_short p =3D mdio_read(mii_addr, info->phy_id, 5); - netdev_info(dev, "%s link beat\n", link ? "found" : "lost"); - if (link) { - info->duplex_flag =3D (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 =3D link; - } - -reschedule: - info->watchdog.expires =3D jiffies + HZ; - add_timer(&info->watchdog); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct axnet_dev *info =3D PRIV(dev); - struct mii_ioctl_data *data =3D if_mii(rq); - unsigned int mii_addr =3D dev->base_addr + AXNET_MII_EEP; - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id =3D info->phy_id; - fallthrough; - case SIOCGMIIREG: /* Read MII PHY register. */ - data->val_out =3D 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; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, - int ring_page) -{ - unsigned int nic_base =3D 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 =3D le16_to_cpu(hdr->count); - -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset) -{ - unsigned int nic_base =3D dev->base_addr; - struct ei_device *ei_local =3D netdev_priv(dev); - char *buf =3D skb->data; - - if ((netif_msg_rx_status(ei_local)) && (count !=3D 4)) - netdev_dbg(dev, "[bi=3D%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] =3D inb(nic_base + AXNET_DATAPORT); - } -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void block_output(struct net_device *dev, int count, - const u_char *buf, const int start_page) -{ - unsigned int nic_base =3D dev->base_addr; - - pr_debug("%s: [bo=3D%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[] =3D { - 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),=20 - 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", 0x= b4be14e3, 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, 0x00e9= 90cc), - PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440= f, 0x436768c5), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x52614= 40f, 0x730df72e), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXM", 0x5261440= f, 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, 0xa= b9be5ef), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, axnet_ids); - -static struct pcmcia_driver axnet_cs_driver =3D { - .owner =3D THIS_MODULE, - .name =3D "axnet_cs", - .probe =3D axnet_probe, - .remove =3D axnet_detach, - .id_table =3D axnet_ids, - .suspend =3D axnet_suspend, - .resume =3D axnet_resume, -}; -module_pcmcia_driver(axnet_cs_driver); - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* 8390.c: A general NS8390 ethernet driver core for linux. */ -/* - Written 1992-94 by Donald Becker. - =20 - 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=20 - ei_block_input() for eth_io_copy_and_sum(). - Paul Gortmaker : exchange static int ei_pingpong for a #define, - also add better Tx error handling. - Paul Gortmaker : rewrite Rx overrun handling as per NS specs. - Alexey Kuznetsov : use the 8390's six bit hash multicast filter. - Paul Gortmaker : tweak ANK's above multicast changes a bit. - Paul Gortmaker : update packet statistics for v2.1.x - Alan Cox : support arbitrary stupid port mappings on the - 68K Macintosh. Support >16bit I/O spaces - Paul Gortmaker : add kmod support for auto-loading of the 8390 - module by all drivers that require it. - Alan Cox : Spinlocking work, added 'BUG_83C690' - Paul Gortmaker : Separate out Tx timeout code from Tx path. - - Sources: - The National Semiconductor LAN Databook, and the 3Com 3c503 databook. - - */ - -#include -#include -#include -#include -#include - -#define BUG_83C690 - -/* These are the operational function interfaces to board-specific - routines. - void reset_8390(struct net_device *dev) - Resets the board associated with DEV, including a hardware reset of - the 8390. This is only called when there is a transmit timeout, and - it is always followed by 8390_init(). - void block_output(struct net_device *dev, int count, const unsigned char = *buf, - int start_page) - Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The - "page" value uses the 8390's 256-byte pages. - void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring= _page) - Read the 4 byte, page aligned 8390 header. *If* there is a - subsequent read, it will be of the rest of the packet. - void block_input(struct net_device *dev, int count, struct sk_buff *skb, = int ring_offset) - Read COUNT bytes from the packet buffer into the skb data area. Start=20 - reading from RING_OFFSET, the address as the 8390 sees it. This will al= ways - follow the read of the 8390 header.=20 -*/ -#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 lengt= h, - 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 oth= er - * 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=20 - * 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=20 - * annoying the transmit function is called bh atomic. That places - * restrictions on the user context callers as disable_irq won't save - * them. - */ -=20 -/** - * 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 =3D netdev_priv(dev); - - /* - * Grab the page lock so we own the register set, then call - * the init function. - */ - =20 - 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 =3D 0; - return 0; -} - -#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock) - -/** - * ax_close - shut down network device - * @dev: network device to close - * - * Opposite of ax_open(). Only used when "ifconfig down" is done. - */ -static int ax_close(struct net_device *dev) -{ - unsigned long flags; - - /* - * Hold the page lock during close - */ - - spin_lock_irqsave(&dev_lock(dev), flags); - AX88190_init(dev, 0); - spin_unlock_irqrestore(&dev_lock(dev), flags); - netif_stop_queue(dev); - return 0; -} - -/** - * axnet_tx_timeout - handle transmit time out condition - * @dev: network device which has apparently fallen asleep - * @txqueue: unused - * - * Called by kernel when device never acknowledges a transmit has - * completed (or failed) - i.e. never posted a Tx related interrupt. - */ - -static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - long e8390_base =3D dev->base_addr; - struct ei_device *ei_local =3D netdev_priv(dev); - int txsr, isr, tickssofar =3D jiffies - dev_trans_start(dev); - unsigned long flags; - - dev->stats.tx_errors++; - - spin_lock_irqsave(&ei_local->page_lock, flags); - txsr =3D inb(e8390_base+EN0_TSR); - isr =3D inb(e8390_base+EN0_ISR); - spin_unlock_irqrestore(&ei_local->page_lock, flags); - - netdev_dbg(dev, "Tx timed out, %s TSR=3D%#2x, ISR=3D%#2x, t=3D%d.\n", - (txsr & ENTSR_ABT) ? "excess collisions." : - (isr) ? "lost interrupt?" : "cable problem?", - txsr, isr, tickssofar); - - if (!isr && !dev->stats.tx_packets)=20 - { - /* The 8390 probably hasn't gotten on the cable yet. */ - ei_local->interface_num ^=3D 1; /* Try a different xcvr. */ - } - - /* Ugly but a reset can be slow, yet must be protected */ - =09 - spin_lock_irqsave(&ei_local->page_lock, flags); - =09 - /* Try to restart the card. Perhaps the user has fixed something. */ - ei_reset_8390(dev); - AX88190_init(dev, 1); - =09 - spin_unlock_irqrestore(&ei_local->page_lock, flags); - netif_wake_queue(dev); -} - =20 -/** - * 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. - */ -=20 -static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - long e8390_base =3D dev->base_addr; - struct ei_device *ei_local =3D netdev_priv(dev); - int length, send_length, output_page; - unsigned long flags; - u8 packet[ETH_ZLEN]; -=09 - netif_stop_queue(dev); - - length =3D skb->len; - - /* Mask interrupts from the ethercard.=20 - 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 */ - =20 - spin_lock_irqsave(&ei_local->page_lock, flags); - outb_p(0x00, e8390_base + EN0_IMR); -=09 - /* - * Slow phase with lock held. - */ - =20 - ei_local->irqlock =3D 1; - - send_length =3D 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 =3D=3D 0)=20 - { - output_page =3D ei_local->tx_start_page; - ei_local->tx1 =3D send_length; - if ((netif_msg_tx_queued(ei_local)) && - ei_local->tx2 > 0) - netdev_dbg(dev, - "idle transmitter tx2=3D%d, lasttx=3D%d, txing=3D%d\n", - ei_local->tx2, ei_local->lasttx, - ei_local->txing); - } - else if (ei_local->tx2 =3D=3D 0)=20 - { - output_page =3D ei_local->tx_start_page + TX_PAGES/2; - ei_local->tx2 =3D send_length; - if ((netif_msg_tx_queued(ei_local)) && - ei_local->tx1 > 0) - netdev_dbg(dev, - "idle transmitter, tx1=3D%d, lasttx=3D%d, txing=3D%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=3D%d tx2=3D%d last=3D%d\n", - ei_local->tx1, ei_local->tx2, - ei_local->lasttx); - ei_local->irqlock =3D 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 =3D=3D 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); - } -=09 - if (! ei_local->txing)=20 - { - ei_local->txing =3D 1; - NS8390_trigger_send(dev, send_length, output_page); - netif_trans_update(dev); - if (output_page =3D=3D ei_local->tx_start_page)=20 - { - ei_local->tx1 =3D -1; - ei_local->lasttx =3D -1; - } - else=20 - { - ei_local->tx2 =3D -1; - ei_local->lasttx =3D -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 =3D 0; - outb_p(ENISR_ALL, e8390_base + EN0_IMR); -=09 - spin_unlock_irqrestore(&ei_local->page_lock, flags); - - dev_kfree_skb (skb); - dev->stats.tx_bytes +=3D send_length; - =20 - 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 =3D dev_id; - long e8390_base; - int interrupts, nr_serviced =3D 0, i; - struct ei_device *ei_local; - int handled =3D 0; - unsigned long flags; - - e8390_base =3D dev->base_addr; - ei_local =3D netdev_priv(dev); - - /* - * Protect the irq test too. - */ - =20 - 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 lin= e */ - const char *msg; - /* The "irqlock" check is only for testing. */ - if (ei_local->irqlock) - msg =3D "Interrupted while interrupts are masked!"; - else - msg =3D "Reentering the interrupt handler!"; - netdev_info(dev, "%s, isr=3D%#2x imr=3D%#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=3D%#2.2x)\n", - inb_p(e8390_base + EN0_ISR)); - - outb_p(0x00, e8390_base + EN0_ISR); - ei_local->irqlock =3D 1; - =20 - /* !!Assumption!! -- we stay in page 0. Don't break this. */ - while ((interrupts =3D inb_p(e8390_base + EN0_ISR)) !=3D 0 && - ++nr_serviced < MAX_SERVICE) - { - if (!netif_running(dev) || (interrupts =3D=3D 0xff)) { - netif_warn(ei_local, intr, dev, - "interrupt from stopped card\n"); - outb_p(interrupts, e8390_base + EN0_ISR); - interrupts =3D 0; - break; - } - handled =3D 1; - - /* AX88190 bug fix. */ - outb_p(interrupts, e8390_base + EN0_ISR); - for (i =3D 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)=20 - ei_rx_overrun(dev); - else if (interrupts & (ENISR_RX+ENISR_RX_ERR))=20 - { - /* 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)=20 - { - dev->stats.rx_frame_errors +=3D inb_p(e8390_base + EN0_COUNTER0); - dev->stats.rx_crc_errors +=3D inb_p(e8390_base + EN0_COUNTER1); - dev->stats.rx_missed_errors+=3D inb_p(e8390_base + EN0_COUNTER2); - } - } - =20 - if (interrupts && (netif_msg_intr(ei_local))) - { - handled =3D 1; - if (nr_serviced >=3D MAX_SERVICE)=20 - { - /* 0xFF is valid for a card removal */ - if (interrupts !=3D 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 =3D 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 =3D dev->base_addr; - unsigned char txsr =3D inb_p(e8390_base+EN0_TSR); - unsigned char tx_was_aborted =3D 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=20 - { - 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 =3D dev->base_addr; - struct ei_device *ei_local =3D netdev_priv(dev); - int status =3D inb(e8390_base + EN0_TSR); - =20 - /* - * 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)=20 - { - if (ei_local->lasttx !=3D 1 && ei_local->lasttx !=3D -1) - netdev_err(dev, "%s: bogus last_tx_buffer %d, tx1=3D%d\n", - ei_local->name, ei_local->lasttx, - ei_local->tx1); - ei_local->tx1 =3D 0; - if (ei_local->tx2 > 0)=20 - { - ei_local->txing =3D 1; - NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6); - netif_trans_update(dev); - ei_local->tx2 =3D -1; - ei_local->lasttx =3D 2; - } else { - ei_local->lasttx =3D 20; - ei_local->txing =3D 0; - } - } - else if (ei_local->tx2 < 0)=20 - { - if (ei_local->lasttx !=3D 2 && ei_local->lasttx !=3D -2) - netdev_err(dev, "%s: bogus last_tx_buffer %d, tx2=3D%d\n", - ei_local->name, ei_local->lasttx, - ei_local->tx2); - ei_local->tx2 =3D 0; - if (ei_local->tx1 > 0)=20 - { - ei_local->txing =3D 1; - NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page); - netif_trans_update(dev); - ei_local->tx1 =3D -1; - ei_local->lasttx =3D 1; - } else { - ei_local->lasttx =3D 10; - ei_local->txing =3D 0; - } - } -// else -// netdev_warn(dev, "unexpected TX-done interrupt, lasttx=3D%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=20 - { - dev->stats.tx_errors++; - if (status & ENTSR_ABT)=20 - { - dev->stats.tx_aborted_errors++; - dev->stats.collisions +=3D 16; - } - if (status & ENTSR_CRS)=20 - dev->stats.tx_carrier_errors++; - if (status & ENTSR_FU)=20 - 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.=20 - * Called with lock held. - */ - -static void ei_receive(struct net_device *dev) -{ - long e8390_base =3D dev->base_addr; - struct ei_device *ei_local =3D netdev_priv(dev); - unsigned char rxing_page, this_frame, next_frame; - unsigned short current_offset; - int rx_pkt_count =3D 0; - struct e8390_pkt_hdr rx_frame; - =20 - while (++rx_pkt_count < 10)=20 - { - int pkt_len, pkt_stat; - =09 - /* Get the rx page (incoming packet pointer). */ - rxing_page =3D inb_p(e8390_base + EN1_CURPAG -1); - =09 - /* Remove one frame from the ring. Boundary is always a page behind. */ - this_frame =3D inb_p(e8390_base + EN0_BOUNDARY) + 1; - if (this_frame >=3D ei_local->stop_page) - this_frame =3D ei_local->rx_start_page; - =09 - /* Someday we'll omit the previous, iff we never get this message. - (There is at least one clone claimed to have a problem.) =20 - =20 - 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 !=3D ei_local->current_page && - (this_frame !=3D 0x0 || rxing_page !=3D 0xFF)) - netdev_err(dev, "mismatched read page pointers %2x vs %2x\n", - this_frame, ei_local->current_page); - =09 - if (this_frame =3D=3D rxing_page) /* Read all the frames? */ - break; /* Done for now */ - =09 - current_offset =3D this_frame << 8; - ei_get_8390_hdr(dev, &rx_frame, this_frame); - =09 - pkt_len =3D rx_frame.count - sizeof(struct e8390_pkt_hdr); - pkt_stat =3D rx_frame.status; - =09 - next_frame =3D this_frame + 1 + ((pkt_len+4)>>8); - =09 - if (pkt_len < 60 || pkt_len > 1518)=20 - { - netif_err(ei_local, rx_err, dev, - "bogus packet size: %d, status=3D%#2x nxpg=3D%#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) =3D=3D ENRSR_RXOK)=20 - { - struct sk_buff *skb; - =09 - skb =3D netdev_alloc_skb(dev, pkt_len + 2); - if (skb =3D=3D NULL)=20 - { - 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=3Deth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes +=3D pkt_len; - if (pkt_stat & ENRSR_PHY) - dev->stats.multicast++; - } - }=20 - else=20 - { - netif_err(ei_local, rx_err, dev, - "bogus packet: status=3D%#2x nxpg=3D%#2x size=3D%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 =3D rx_frame.next; - =09 - /* This _should_ never happen: it's here for avoiding bad clones. */ - if (next_frame >=3D ei_local->stop_page) { - netdev_info(dev, "next frame inconsistency, %#2x\n", - next_frame); - next_frame =3D ei_local->rx_start_page; - } - ei_local->current_page =3D 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.=20 - */ - -static void ei_rx_overrun(struct net_device *dev) -{ - struct axnet_dev *info =3D PRIV(dev); - long e8390_base =3D dev->base_addr; - unsigned char was_txing, must_resend =3D 0; - struct ei_device *ei_local =3D netdev_priv(dev); - =20 - /* - * Record whether a Tx was in progress and then issue the - * stop command. - */ - was_txing =3D 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++; - =20 - /*=20 - * 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) - {=20 - unsigned char tx_completed =3D inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENI= SR_TX_ERR); - if (!tx_completed) - must_resend =3D 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);=20 - 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. - */ -=20 -static struct net_device_stats *get_stats(struct net_device *dev) -{ - long ioaddr =3D dev->base_addr; - struct ei_device *ei_local =3D netdev_priv(dev); - unsigned long flags; - =20 - /* 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 +=3D inb_p(ioaddr + EN0_COUNTER0); - dev->stats.rx_crc_errors +=3D inb_p(ioaddr + EN0_COUNTER1); - dev->stats.rx_missed_errors+=3D inb_p(ioaddr + EN0_COUNTER2); - spin_unlock_irqrestore(&ei_local->page_lock, flags); - =20 - return &dev->stats; -} - -/* - * Form the 64 bit 8390 multicast table from the linked list of addresses - * associated with this dev structure. - */ -=20 -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 =3D ether_crc(ETH_ALEN, ha->addr); - /*=20 - * The 8390 uses the 6 most significant bits of the - * CRC to index the multicast table. - */ - bits[crc>>29] |=3D (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.=20 - */ -=20 -static void do_set_multicast_list(struct net_device *dev) -{ - long e8390_base =3D dev->base_addr; - int i; - struct ei_device *ei_local =3D 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 =3D 0; i < 8; i++)=20 - { - 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); -}=09 - -/* 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 =3D PRIV(dev); - long e8390_base =3D dev->base_addr; - struct ei_device *ei_local =3D netdev_priv(dev); - int i; - int endcfg =3D ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; - =20 - if(sizeof(struct e8390_pkt_hdr)!=3D4) - panic("8390.c: header struct mispacked\n"); =20 - /* 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 =3D ei_local->tx2 =3D 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 0= x3f,NS0x26*/ - ei_local->current_page =3D 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); - =20 - /* Copy the station address into the DS8390 registers. */ - - outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* = 0x61 */ - for(i =3D 0; i < 6; i++)=20 - { - outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i)); - if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=3Ddev->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 =3D ei_local->tx2 =3D 0; - ei_local->txing =3D 0; - - if (info->flags & IS_AX88790) /* select Internal PHY */ - outb(0x10, e8390_base + AXNET_GPIO); - - if (startp)=20 - { - 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.=20 - Always called with the page lock held */ - =20 -static void NS8390_trigger_send(struct net_device *dev, unsigned int lengt= h, - int start_page) -{ - long e8390_base =3D dev->base_addr; - struct ei_device *ei_local __attribute((unused)) =3D netdev_priv(dev); - =20 - if (inb_p(e8390_base) & E8390_TRANS)=20 - { - 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); -} --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCA3B3DD524; Tue, 21 Apr 2026 19:59:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801559; cv=none; b=Ul+u+S+eSDG2mkS12tcgaxOjiPUi8EM1j6iQGI6veJTnfhz1xDOKIaQikupqtfyCgnxZzXERJmxGdrh7hRO1AsyLcEGWAY8mbJMA2bnHduCBVCJMABjDQGlAxNlRrsHdIbKw38dEb+JDrTrAjXJ+ZXtra3emG78Dr91sCDzT/+k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801559; c=relaxed/simple; bh=tkbf36HfUUXENCA1HWmb57p4TMRgnEq3lOr6qs22br0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RMMU1O8JkTRG2UhaNYIuJlc36Jm3W8eCGsyJDT1VKs9NjO6xBLnNP//7ygAH/NUAplXNoqvTkhkq1xTWwwXI7F8BKGjW6SydPLy2xhSwhHUDxtZR6oypSejcHA7VKWBMPrkC+ZcZ2V1ZsL6GOnEh1pQj5hgzjJbCJsqEKavYo1I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=iZeCA+eo; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="iZeCA+eo" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=BXfQOzFq4jpfTWhZWZmzGdBJ2jTyW6fweXsGf2U7Toc=; b=iZ eCA+eonoORFufylEBUze7kSUOcM0plh8Ah7KyZi61fn2dlHmZ+nZDYNzaHY/r5NlvczONtCaimvG1 78q2FfqAUjkvn4rfScWNdcsMTpLDruTK0i5TTtReEwuCeHM9PafIAAP15RiV/81XLYKUOgfmS6jtl SASp40/+d3JT43o=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGpB-00GwVc-03; Tue, 21 Apr 2026 21:31:57 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:19 -0500 Subject: [PATCH net 16/18] drivers: net: 8390: pcnet: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-16-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=67444; i=andrew@lunn.ch; h=from:subject:message-id; bh=tkbf36HfUUXENCA1HWmb57p4TMRgnEq3lOr6qs22br0=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CCPasRi/44Er3j+Yy93+WJUkdn/m+ZRBkai sAc9tVBlYCJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hJL+EACrX6hmDPe3EtOpgfXV5GC+F64il5/5NrSMR1NkKNHoWeLP+bPR3WVdm36bw+2vinlog1W B2nPmQDHuGigqCQCTtCo42iA3vW95x12LjczZCR26QR669fLPflAQxQtmbpSTMzhQH3jcO6iBju t2mhuQS8ew4fU/lfdcbgtikB2MAGd8fUKtnqsTwee0ErmHvJUe4/fOCtZsRwEgLdDDf4XxUsED1 PyOXprP9B0vg+IT16PPV6olcGAmwWX0sQaxSezPedtYsQDBRMBQjpvvJgbOHPA+5R6qaNi9WsEC 1KjtiSBnW3cUDcfXpVRmT5SOpzdUnQuKtJYr//HqwLnpNfhy0OpGm81/2B4Vygj3TNDoQYRZHDq IKaybvgbcTQrLLqeda+f9/N1FyR+yoAXCtXIsy5KzHmkZr0/io4n8H8VFIjLYGusIAyuPFMTUQn yPWIIt5oGKwFLi0kshfYMUb7iC8Mc3UmBU0SeodkoGga43R4B9nDYvYxTI1PAipPL3h8yRWd7OP L1Jlbmazdsgtuq305AkKOYhprk2pacRvLDW192nirtUVz7PJqN3vyWFmpTgG2qqRo4OCEGZDMVJ 8NS/MrpQsgVRajqUhFPo9zhlc/16UacdRXevgEz/EGeD+VotRQw44+kiBDjVSTByPdqSl0bTqIV K10g0F3d1Zu1J6g== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 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 --- 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. =20 -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) +=3D hydra.o obj-$(CONFIG_MCF8390) +=3D mcf8390.o obj-$(CONFIG_NE2000) +=3D ne.o 8390p.o obj-$(CONFIG_NE2K_PCI) +=3D ne2k-pci.o 8390.o -obj-$(CONFIG_PCMCIA_PCNET) +=3D pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) +=3D stnic.o 8390.o obj-$(CONFIG_ULTRA) +=3D smc-ultra.o 8390.o obj-$(CONFIG_WD80x3) +=3D wd.o 8390.o diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/83= 90/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+ -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - 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. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "8390.h" - -#include -#include -#include -#include - -#include -#include -#include - -#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[] =3D { "auto", "10baseT", "10base2"}; - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("NE2000 compatible PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); - -#define INT_MODULE_PARM(n, v) static int n =3D 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] =3D { 0, /* ... */ }; -module_param_array(hw_addr, int, NULL, 0); - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -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); - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -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[] =3D { - { /* 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 =3D { 0, 0, 0, 0, 0 }; -static struct hw_info dl10019_info =3D { 0, 0, 0, 0, IS_DL10019|HAS_MII }; -static struct hw_info dl10022_info =3D { 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 =3D netdev_priv(dev); - return (struct pcnet_dev *)(p + sizeof(struct ei_device)); -} - -static const struct net_device_ops pcnet_netdev_ops =3D { - .ndo_open =3D pcnet_open, - .ndo_stop =3D pcnet_close, - .ndo_set_config =3D set_config, - .ndo_start_xmit =3D ei_start_xmit, - .ndo_get_stats =3D ei_get_stats, - .ndo_eth_ioctl =3D ei_ioctl, - .ndo_set_rx_mode =3D ei_set_multicast_list, - .ndo_tx_timeout =3D ei_tx_timeout, - .ndo_set_mac_address =3D eth_mac_addr, - .ndo_validate_addr =3D eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D 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 =3D __alloc_ei_netdev(sizeof(struct pcnet_dev)); - if (!dev) return -ENOMEM; - info =3D PRIV(dev); - info->p_dev =3D link; - link->priv =3D dev; - - link->config_flags |=3D CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - dev->netdev_ops =3D &pcnet_netdev_ops; - - return pcnet_config(link); -} /* pcnet_attach */ - -static void pcnet_detach(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - dev_dbg(&link->dev, "pcnet_detach\n"); - - unregister_netdev(dev); - - pcnet_release(link); - - free_netdev(dev); -} /* pcnet_detach */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - This probes for a card's hardware address, for card types that - encode this information in their CIS. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static struct hw_info *get_hwinfo(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - u_char __iomem *base, *virt; - u8 addr[ETH_ALEN]; - int i, j; - - /* Allocate a small memory window */ - link->resource[2]->flags |=3D WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_= ENABLE; - link->resource[2]->start =3D 0; link->resource[2]->end =3D 0; - i =3D pcmcia_request_window(link, link->resource[2], 0); - if (i !=3D 0) - return NULL; - - virt =3D ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - if (unlikely(!virt)) { - pcmcia_release_window(link, link->resource[2]); - return NULL; - } - - for (i =3D 0; i < NR_INFO; i++) { - pcmcia_map_mem_page(link, link->resource[2], - hw_info[i].offset & ~(resource_size(link->resource[2])-1)); - base =3D &virt[hw_info[i].offset & (resource_size(link->resource[2])-1)]; - if ((readb(base+0) =3D=3D hw_info[i].a0) && - (readb(base+2) =3D=3D hw_info[i].a1) && - (readb(base+4) =3D=3D hw_info[i].a2)) { - for (j =3D 0; j < 6; j++) - addr[j] =3D readb(base + (j<<1)); - eth_hw_addr_set(dev, addr); - break; - } - } - - iounmap(virt); - j =3D pcmcia_release_window(link, link->resource[2]); - return (i < NR_INFO) ? hw_info+i : NULL; -} /* get_hwinfo */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - 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. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static struct hw_info *get_prom(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - unsigned int ioaddr =3D 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[] =3D { - {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 =3D 0; i < ARRAY_SIZE(program_seq); i++) - outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); - - for (i =3D 0; i < 32; i++) - prom[i] =3D inb(ioaddr + PCNET_DATAPORT); - for (i =3D 0; i < NR_INFO; i++) { - if ((prom[0] =3D=3D hw_info[i].a0) && - (prom[2] =3D=3D hw_info[i].a1) && - (prom[4] =3D=3D hw_info[i].a2)) - break; - } - if ((i < NR_INFO) || ((prom[28] =3D=3D 0x57) && (prom[30] =3D=3D 0x57)= )) { - for (j =3D 0; j < 6; j++) - addr[j] =3D prom[j<<1]; - eth_hw_addr_set(dev, addr); - return (i < NR_INFO) ? hw_info+i : &default_info; - } - return NULL; -} /* get_prom */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - For DL10019 based cards, like the Linksys EtherFast - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static struct hw_info *get_dl10019(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - u8 addr[ETH_ALEN]; - int i; - u_char sum; - - for (sum =3D 0, i =3D 0x14; i < 0x1c; i++) - sum +=3D inb_p(dev->base_addr + i); - if (sum !=3D 0xff) - return NULL; - for (i =3D 0; i < 6; i++) - addr[i] =3D inb_p(dev->base_addr + 0x14 + i); - eth_hw_addr_set(dev, addr); - i =3D inb(dev->base_addr + 0x1f); - return ((i =3D=3D 0x91)||(i =3D=3D 0x99)) ? &dl10022_info : &dl10019_i= nfo; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - For Asix AX88190 based cards - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static struct hw_info *get_ax88190(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - unsigned int ioaddr =3D dev->base_addr; - u8 addr[ETH_ALEN]; - int i, j; - - /* Not much of a test, but the alternatives are messy */ - if (link->config_base !=3D 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 =3D 0; i < 6; i +=3D 2) { - j =3D inw(ioaddr + PCNET_DATAPORT); - addr[i] =3D j & 0xff; - addr[i+1] =3D j >> 8; - } - eth_hw_addr_set(dev, addr); - return NULL; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - 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. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static struct hw_info *get_hwired(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - u8 addr[ETH_ALEN]; - int i; - - for (i =3D 0; i < 6; i++) - if (hw_addr[i] !=3D 0) break; - if (i =3D=3D 6) - return NULL; - - for (i =3D 0; i < 6; i++) - addr[i] =3D 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 &=3D ~IO_DATA_PATH_WIDTH; - link->resource[1]->flags &=3D ~IO_DATA_PATH_WIDTH; - if (link->resource[0]->end =3D=3D 32) { - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_AUTO; - if (link->resource[1]->end > 0) { - /* for master/slave multifunction cards */ - link->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_8; - } - } else { - /* This should be two 16-port windows */ - link->resource[0]->flags |=3D IO_DATA_PATH_WIDTH_8; - link->resource[1]->flags |=3D IO_DATA_PATH_WIDTH_16; - } - if (link->resource[0]->start =3D=3D 0) { - for (j =3D 0; j < 0x400; j +=3D 0x20) { - link->resource[0]->start =3D j ^ 0x300; - link->resource[1]->start =3D (j ^ 0x300) + 0x10; - link->io_lines =3D 16; - ret =3D pcmcia_request_io(link); - if (ret =3D=3D 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 =3D priv_data; - int try =3D (*priv & 0x1); - - *priv &=3D (p_dev->resource[2]->end >=3D 0x4000) ? 0x10 : ~0x10; - - if (p_dev->config_index =3D=3D 0) - return -EINVAL; - - if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32) - return -EINVAL; - - if (try) - p_dev->io_lines =3D 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 =3D link->priv; - struct hw_info *local_hw_info; - struct pcnet_dev *info =3D PRIV(dev); - int priv =3D try; - int ret; - - ret =3D pcmcia_loop_config(link, pcnet_confcheck, &priv); - if (ret) { - dev_warn(&link->dev, "no useable port range found\n"); - return NULL; - } - *has_shmem =3D (priv & 0x10); - - if (!link->irq) - return NULL; - - if (resource_size(link->resource[1]) =3D=3D 8) - link->config_flags |=3D CONF_ENABLE_SPKR; - - if ((link->manf_id =3D=3D MANFID_IBM) && - (link->card_id =3D=3D PRODID_IBM_HOME_AND_AWAY)) - link->config_index |=3D 0x10; - - ret =3D pcmcia_enable_device(link); - if (ret) - return NULL; - - dev->irq =3D link->irq; - dev->base_addr =3D link->resource[0]->start; - - if (info->flags & HAS_MISC_REG) { - if ((if_port =3D=3D 1) || (if_port =3D=3D 2)) - dev->if_port =3D if_port; - else - dev_notice(&link->dev, "invalid if_port requested\n"); - } else - dev->if_port =3D 0; - - if ((link->config_base =3D=3D 0x03c0) && - (link->manf_id =3D=3D 0x149) && (link->card_id =3D=3D 0xc1ab)) { - dev_info(&link->dev, - "this is an AX88190 card - use axnet_cs instead.\n"); - return NULL; - } - - local_hw_info =3D get_hwinfo(link); - if (!local_hw_info) - local_hw_info =3D get_prom(link); - if (!local_hw_info) - local_hw_info =3D get_dl10019(link); - if (!local_hw_info) - local_hw_info =3D get_ax88190(link); - if (!local_hw_info) - local_hw_info =3D get_hwired(link); - - return local_hw_info; -} - -static int pcnet_config(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - struct pcnet_dev *info =3D PRIV(dev); - int start_pg, stop_pg, cm_offset; - int has_shmem =3D 0; - struct hw_info *local_hw_info; - - dev_dbg(&link->dev, "pcnet_config\n"); - - local_hw_info =3D 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 =3D pcnet_try_config(link, &has_shmem, 1); - if (local_hw_info =3D=3D NULL) { - dev_notice(&link->dev, "unable to read hardware net" - " address for io base %#3lx\n", dev->base_addr); - goto failed; - } - } - - info->flags =3D local_hw_info->flags; - /* Check for user overrides */ - info->flags |=3D (delay_output) ? DELAY_OUTPUT : 0; - if ((link->manf_id =3D=3D MANFID_SOCKET) && - ((link->card_id =3D=3D PRODID_SOCKET_LPE) || - (link->card_id =3D=3D PRODID_SOCKET_LPE_CF) || - (link->card_id =3D=3D PRODID_SOCKET_EIO))) - info->flags &=3D ~USE_BIG_BUF; - if (!use_big_buf) - info->flags &=3D ~USE_BIG_BUF; - - if (info->flags & USE_BIG_BUF) { - start_pg =3D SOCKET_START_PG; - stop_pg =3D SOCKET_STOP_PG; - cm_offset =3D 0x10000; - } else { - start_pg =3D PCNET_START_PG; - stop_pg =3D PCNET_STOP_PG; - cm_offset =3D 0; - } - - /* has_shmem is ignored if use_shmem !=3D -1 */ - if ((use_shmem =3D=3D 0) || (!has_shmem && (use_shmem =3D=3D -1)) || - (setup_shmem_window(link, start_pg, stop_pg, cm_offset) !=3D 0)) - setup_dma_config(link, start_pg, stop_pg); - - ei_status.name =3D "NE2000"; - ei_status.word16 =3D 1; - ei_status.reset_8390 =3D pcnet_reset_8390; - - if (info->flags & (IS_DL10019|IS_DL10022)) - mii_phy_probe(dev); - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) !=3D 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - if (info->flags & (IS_DL10019|IS_DL10022)) { - u_char id =3D 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 =3D 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 =3D link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int pcnet_resume(struct pcmcia_device *link) -{ - struct net_device *dev =3D link->priv; - - if (link->open) { - pcnet_reset_8390(dev); - NS8390_init(dev, 1); - netif_device_attach(dev); - } - - return 0; -} - - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - 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. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#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 =3D inb(addr) & MDIO_MASK; - for (bits =3D 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 =3D (0x06<<10)|(phy_id<<5)|loc; - int i, retval =3D 0, mask =3D inb(addr) & MDIO_MASK; - - mdio_sync(addr); - for (i =3D 13; i >=3D 0; i--) { - int dat =3D (cmd&(1< 0; i--) { - outb(mask, addr); - retval =3D (retval << 1) | ((inb(addr) & MDIO_DATA_READ) !=3D 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 =3D (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; - int i, mask =3D inb(addr) & MDIO_MASK; - - mdio_sync(addr); - for (i =3D 31; i >=3D 0; i--) { - int dat =3D (cmd&(1<=3D 0; i--) { - outb(mask, addr); - outb(mask | MDIO_SHIFT_CLK, addr); - } -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - EEPROM access routines for DL10019 and DL10022 based cards - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -#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 =3D 0; - unsigned int ee_addr =3D ioaddr + DLINK_EEPROM; - int read_cmd =3D location | (EE_READ_CMD << 8); - - outb(0, ee_addr); - outb(EE_EEP|EE_CS, ee_addr); - - /* Shift the read command bits out. */ - for (i =3D 10; i >=3D 0; i--) { - short dataval =3D (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 =3D 16; i > 0; i--) { - outb_p(EE_EEP|EE_CS | EE_CK, ee_addr); - retval =3D (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 =3D ioaddr + DLINK_EEPROM; - short dataval; - int read_cmd =3D location | (EE_READ_CMD << 8); - - asic_data |=3D read_eeprom(ioaddr, location); - - outb(0, ee_addr); - outb(EE_ASIC|EE_CS|EE_DI, ee_addr); - - read_cmd =3D read_cmd >> 1; - - /* Shift the read command bits out. */ - for (i =3D 9; i >=3D 0; i--) { - dataval =3D (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 =3D 15; i >=3D 0; i--) { - dataval =3D (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); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void set_misc_reg(struct net_device *dev) -{ - unsigned int nic_base =3D dev->base_addr; - struct pcnet_dev *info =3D PRIV(dev); - u_char tmp; - - if (info->flags & HAS_MISC_REG) { - tmp =3D inb_p(nic_base + PCNET_MISC) & ~3; - if (dev->if_port =3D=3D 2) - tmp |=3D 1; - if (info->flags & USE_BIG_BUF) - tmp |=3D 2; - if (info->flags & HAS_IBM_MISC) - tmp |=3D 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 =3D 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); - } -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void mii_phy_probe(struct net_device *dev) -{ - struct pcnet_dev *info =3D PRIV(dev); - unsigned int mii_addr =3D dev->base_addr + DLINK_GPIO; - int i; - u_int tmp, phyid; - - for (i =3D 31; i >=3D 0; i--) { - tmp =3D mdio_read(mii_addr, i, 1); - if ((tmp =3D=3D 0) || (tmp =3D=3D 0xffff)) - continue; - tmp =3D mdio_read(mii_addr, i, MII_PHYID_REG1); - phyid =3D tmp << 16; - phyid |=3D mdio_read(mii_addr, i, MII_PHYID_REG2); - phyid &=3D MII_PHYID_REV_MASK; - netdev_dbg(dev, "MII at %d is 0x%08x\n", i, phyid); - if (phyid =3D=3D AM79C9XX_HOME_PHY) { - info->pna_phy =3D i; - } else if (phyid !=3D AM79C9XX_ETH_PHY) { - info->eth_phy =3D i; - } - } -} - -static int pcnet_open(struct net_device *dev) -{ - int ret; - struct pcnet_dev *info =3D PRIV(dev); - struct pcmcia_device *link =3D info->p_dev; - unsigned int nic_base =3D 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 =3D request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev->name, = dev); - if (ret) - return ret; - - link->open++; - - info->phy_id =3D info->eth_phy; - info->link_status =3D 0x00; - timer_setup(&info->watchdog, ei_watchdog, 0); - mod_timer(&info->watchdog, jiffies + HZ); - - return ei_open(dev); -} /* pcnet_open */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int pcnet_close(struct net_device *dev) -{ - struct pcnet_dev *info =3D PRIV(dev); - struct pcmcia_device *link =3D 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 */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - - Hard reset the card. This used to pause for the same period that - a 8390 reset command required, but that shouldn't be necessary. - -=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void pcnet_reset_8390(struct net_device *dev) -{ - unsigned int nic_base =3D dev->base_addr; - int i; - - ei_status.txing =3D ei_status.dmaing =3D 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 =3D 0; i < 100; i++) { - if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) !=3D 0) - break; - udelay(100); - } - outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */ - - if (i =3D=3D 100) - netdev_err(dev, "pcnet_reset_8390() did not complete.\n"); - - set_misc_reg(dev); - -} /* pcnet_reset_8390 */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int set_config(struct net_device *dev, struct ifmap *map) -{ - struct pcnet_dev *info =3D PRIV(dev); - if ((map->port !=3D (u_char)(-1)) && (map->port !=3D 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; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static irqreturn_t ei_irq_wrapper(int irq, void *dev_id) -{ - struct net_device *dev =3D dev_id; - struct pcnet_dev *info; - irqreturn_t ret =3D ei_interrupt(irq, dev_id); - - if (ret =3D=3D IRQ_HANDLED) { - info =3D PRIV(dev); - info->stale =3D 0; - } - return ret; -} - -static void ei_watchdog(struct timer_list *t) -{ - struct pcnet_dev *info =3D timer_container_of(info, t, watchdog); - struct net_device *dev =3D info->p_dev->priv; - unsigned int nic_base =3D dev->base_addr; - unsigned int mii_addr =3D 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 =3D HZ; - } - if (info->fast_poll) { - info->fast_poll--; - info->watchdog.expires =3D jiffies + 1; - add_timer(&info->watchdog); - return; - } - - if (!(info->flags & HAS_MII)) - goto reschedule; - - mdio_read(mii_addr, info->phy_id, 1); - link =3D mdio_read(mii_addr, info->phy_id, 1); - if (!link || (link =3D=3D 0xffff)) { - if (info->eth_phy) { - info->phy_id =3D info->eth_phy =3D 0; - } else { - netdev_info(dev, "MII is missing!\n"); - info->flags &=3D ~HAS_MII; - } - goto reschedule; - } - - link &=3D 0x0004; - if (link !=3D info->link_status) { - u_short p =3D 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 =3D=3D 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 =3D link; - } - if (info->pna_phy && time_after(jiffies, info->mii_reset + 6*HZ)) { - link =3D mdio_read(mii_addr, info->eth_phy, 1) & 0x0004; - if (((info->phy_id =3D=3D info->pna_phy) && link) || - ((info->phy_id !=3D 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 ^=3D info->pna_phy ^ info->eth_phy; - netdev_info(dev, "switched to %s transceiver\n", - (info->phy_id =3D=3D info->eth_phy) ? "ethernet" : "PNA"); - mdio_write(mii_addr, info->phy_id, 0, - (info->phy_id =3D=3D info->eth_phy) ? 0x1000 : 0); - info->link_status =3D 0; - info->mii_reset =3D jiffies; - } - } - -reschedule: - info->watchdog.expires =3D jiffies + HZ; - add_timer(&info->watchdog); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - - -static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct pcnet_dev *info =3D PRIV(dev); - struct mii_ioctl_data *data =3D if_mii(rq); - unsigned int mii_addr =3D dev->base_addr + DLINK_GPIO; - - if (!(info->flags & (IS_DL10019|IS_DL10022))) - return -EINVAL; - - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id =3D info->phy_id; - fallthrough; - case SIOCGMIIREG: /* Read MII PHY register. */ - data->val_out =3D 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; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void dma_get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, - int ring_page) -{ - unsigned int nic_base =3D 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 |=3D 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 =3D le16_to_cpu(hdr->count); - - outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &=3D ~0x01; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void dma_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset) -{ - unsigned int nic_base =3D dev->base_addr; - int xfer_count =3D count; - char *buf =3D skb->data; - struct ei_device *ei_local =3D netdev_priv(dev); - - if ((netif_msg_rx_status(ei_local)) && (count !=3D 4)) - netdev_dbg(dev, "[bi=3D%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 |=3D 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] =3D 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 =3D 20; - do { - /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here - -- it's broken for Rx on some cards! */ - int high =3D inb_p(nic_base + EN0_RSARHI); - int low =3D inb_p(nic_base + EN0_RSARLO); - addr =3D (high << 8) + low; - if (((ring_offset + xfer_count) & 0xff) =3D=3D (addr & 0xff)) - break; - } while (--tries > 0); - if (tries <=3D 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 &=3D ~0x01; -} /* dma_block_input */ - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void dma_block_output(struct net_device *dev, int count, - const u_char *buf, const int start_page) -{ - unsigned int nic_base =3D dev->base_addr; - struct pcnet_dev *info =3D PRIV(dev); -#ifdef PCMCIA_DEBUG - int retries =3D 0; - struct ei_device *ei_local =3D netdev_priv(dev); -#endif - u_long dma_start; - -#ifdef PCMCIA_DEBUG - netif_dbg(ei_local, tx_queued, dev, "[bo=3D%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 |=3D 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 =3D 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 =3D 20; - do { - int high =3D inb_p(nic_base + EN0_RSARHI); - int low =3D inb_p(nic_base + EN0_RSARLO); - addr =3D (high << 8) + low; - if ((start_page << 8) + count =3D=3D addr) - break; - } while (--tries > 0); - if (tries <=3D 0) { - netdev_notice(dev, "Tx packet transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - (start_page << 8) + count, addr); - if (retries++ =3D=3D 0) - goto retry; - } - } -#endif - - while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) =3D=3D 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 &=3D ~0x01; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int setup_dma_config(struct pcmcia_device *link, int start_pg, - int stop_pg) -{ - struct net_device *dev =3D link->priv; - - ei_status.tx_start_page =3D start_pg; - ei_status.rx_start_page =3D start_pg + TX_PAGES; - ei_status.stop_page =3D stop_pg; - - /* set up block i/o functions */ - ei_status.get_8390_hdr =3D dma_get_8390_hdr; - ei_status.block_input =3D dma_block_input; - ei_status.block_output =3D dma_block_output; - - return 0; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void copyin(void *dest, void __iomem *src, int c) -{ - u_short *d =3D dest; - u_short __iomem *s =3D src; - int odd; - - if (c <=3D 0) - return; - odd =3D (c & 1); c >>=3D 1; - - if (c) { - do { *d++ =3D __raw_readw(s++); } while (--c); - } - /* get last byte by fetching a word and masking */ - if (odd) - *((u_char *)d) =3D readw(s) & 0xff; -} - -static void copyout(void __iomem *dest, const void *src, int c) -{ - u_short __iomem *d =3D dest; - const u_short *s =3D src; - int odd; - - if (c <=3D 0) - return; - odd =3D (c & 1); c >>=3D 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); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void shmem_get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, - int ring_page) -{ - void __iomem *xfer_start =3D 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 =3D le16_to_cpu(hdr->count); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void shmem_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset) -{ - void __iomem *base =3D ei_status.mem; - unsigned long offset =3D (TX_PAGES<<8) + ring_offset - - (ei_status.rx_start_page << 8); - char *buf =3D skb->data; - - if (offset + count > ei_status.priv) { - /* We must wrap the input move. */ - int semi_count =3D ei_status.priv - offset; - copyin(buf, base + offset, semi_count); - buf +=3D semi_count; - offset =3D TX_PAGES<<8; - count -=3D semi_count; - } - copyin(buf, base + offset, count); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static void shmem_block_output(struct net_device *dev, int count, - const u_char *buf, const int start_page) -{ - void __iomem *shmem =3D ei_status.mem + (start_page << 8); - shmem -=3D ei_status.tx_start_page << 8; - copyout(shmem, buf, count); -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static int setup_shmem_window(struct pcmcia_device *link, int start_pg, - int stop_pg, int cm_offset) -{ - struct net_device *dev =3D link->priv; - struct pcnet_dev *info =3D PRIV(dev); - int i, window_size, offset, ret; - - window_size =3D (stop_pg - start_pg) << 8; - if (window_size > 32 * 1024) - window_size =3D 32 * 1024; - - /* Make sure it's a power of two. */ - window_size =3D roundup_pow_of_two(window_size); - - /* Allocate a memory window */ - link->resource[3]->flags |=3D WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN= _ENABLE; - link->resource[3]->flags |=3D WIN_USE_WAIT; - link->resource[3]->start =3D 0; link->resource[3]->end =3D window_size; - ret =3D pcmcia_request_window(link, link->resource[3], mem_speed); - if (ret) - goto failed; - - offset =3D (start_pg << 8) + cm_offset; - offset -=3D offset % window_size; - ret =3D pcmcia_map_mem_page(link, link->resource[3], offset); - if (ret) - goto failed; - - /* Try scribbling on the buffer */ - info->base =3D ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - if (unlikely(!info->base)) { - ret =3D -ENOMEM; - goto failed; - } - - for (i =3D 0; i < (TX_PAGES<<8); i +=3D 2) - __raw_writew((i>>1), info->base+offset+i); - udelay(100); - for (i =3D 0; i < (TX_PAGES<<8); i +=3D 2) - if (__raw_readw(info->base+offset+i) !=3D (i>>1)) break; - pcnet_reset_8390(dev); - if (i !=3D (TX_PAGES<<8)) { - iounmap(info->base); - pcmcia_release_window(link, link->resource[3]); - info->base =3D NULL; - goto failed; - } - - ei_status.mem =3D info->base + offset; - ei_status.priv =3D resource_size(link->resource[3]); - dev->mem_start =3D (u_long)ei_status.mem; - dev->mem_end =3D dev->mem_start + resource_size(link->resource[3]); - - ei_status.tx_start_page =3D start_pg; - ei_status.rx_start_page =3D start_pg + TX_PAGES; - ei_status.stop_page =3D start_pg + ( - (resource_size(link->resource[3]) - offset) >> 8); - - /* set up block i/o functions */ - ei_status.get_8390_hdr =3D shmem_get_8390_hdr; - ei_status.block_input =3D shmem_block_input; - ei_status.block_output =3D shmem_block_output; - - info->flags |=3D USE_SHMEM; - return 0; - -failed: - return 1; -} - -/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ - -static const struct pcmcia_device_id pcnet_ids[] =3D { - 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", 0x5= 78ba6e7, 0xb0ac62c4), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c17= 4e), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897f= f), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b9= 32ae), - 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, 0x7a821= b58), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced= 065, 0x3ced0555), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd89= 06cc), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c6= 48f), - 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 ", 0= xb569a6e5, 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 ", 0x1ed5930= 2), - 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, 0x= 281f1c5d, 0x3ff7175b), - PCMCIA_DEVICE_PROD_ID123("CNet ", "CN30BC", "ETHERNET", 0x9fe55d3d, 0x85= 601198, 0x3ff7175b), - PCMCIA_DEVICE_PROD_ID123("Digital", "Ethernet", "Adapter", 0x9999ab35, 0x= 00b2e941, 0x4b0d829e), - PCMCIA_DEVICE_PROD_ID123("Edimax Technology Inc.", "PCMCIA", "Ethernet Ca= rd", 0x738a0019, 0x281f1c5d, 0x5e9d92c0), - PCMCIA_DEVICE_PROD_ID123("EFA ", "EFA207", "ETHERNET", 0x3d294be4, 0xeb= 9aab6c, 0x3ff7175b), - PCMCIA_DEVICE_PROD_ID123("I-O DATA", "PCLA", "ETHERNET", 0x1d55d7ec, 0xe4= c64d34, 0x3ff7175b), - PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCLATE", "ETHERNET", 0x547e66dc, 0x6= b260753, 0x3ff7175b), - PCMCIA_DEVICE_PROD_ID123("KingMax Technology Inc.", "EN10-T2", "PCMCIA Et= hernet Card", 0x932b7189, 0x699e4436, 0x6f6652e0), - PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216", 0x28= 1f1c5d, 0xd4cd2f20, 0xb87add82), - PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2620", 0x28= 1f1c5d, 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, 0= x5542bfff), - 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", 0x= bb7fBdd7, 0x28e299f8), - PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0= x62241d96), - 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, 0x93= 9fedbd), - PCMCIA_DEVICE_PROD_ID12("AROWANA", "PCMCIA Ethernet LAN Card", 0x313adbc8= , 0x08d9f190), - PCMCIA_DEVICE_PROD_ID12("ASANTE", "FriendlyNet PC Card", 0x3a7ade0f, 0x41= c64504), - 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 Etherneta= dapter", 0xfa2e424d, 0xe9190d8a), - PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ether= net", 0xfa2e424d, 0x3953d9b9), - PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f9072= 2), - PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a= 2), - PCMCIA_DEVICE_PROD_ID12("corega", "Ether CF-TD", 0x0a21501a, 0x6589340a), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether CF-TD LAN Card", 0x5= 261440f, 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", 0x5261440= f, 0xc49bd73d), - PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd= 8, 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", 0x52614= 40f, 0x485e85d9), - PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0= x9fd2f0a2), - PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0= x9fd2f0a2), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "(CG-LAPCCTXD)", 0x5261440f, 0x73e= c0d88), - PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2= add04), - 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", 0x= 0c629325, 0xb4e7dbaf), - PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100", 0x697403d8, 0xe= 160b995), - PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100 Dongless", 0x6974= 03d8, 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, 0xf1e= fee84), - PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x7= 25b842d, 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", 0x53c= 864c6, 0xedd059f6), - PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet Combo card", 0x53c86= 4c6, 0x929c486c), - PCMCIA_DEVICE_PROD_ID12("Ethernet", "Adapter", 0x00b2e941, 0x4b0d829e), - PCMCIA_DEVICE_PROD_ID12("Ethernet Adapter", "E2000 PCMCIA Ethernet", 0x96= 767301, 0x71fbbc61), - PCMCIA_DEVICE_PROD_ID12("Ethernet PCMCIA adapter", "EP-210", 0x8dd86181, = 0xf2b52517), - PCMCIA_DEVICE_PROD_ID12("Fast Ethernet", "Adapter", 0xb4be14e3, 0x4b0d829= e), - 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, 0x11= b0ffc0), - PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b= 4, 0xcc51a956), - PCMCIA_DEVICE_PROD_ID12("KENTRONICS", "KEP-230", 0xaf8144c9, 0x868f6616), - PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d= 3, 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 Ethe= rnet 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)", 0x= 0733cc81, 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 P= C 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-VE= L211", 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", 0x4b91= cec7, 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", 0x36e= 1191f, 0x60c229b9), - PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x3= 6e1191f, 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 Ca= rd", 0x820a67b6, 0x31ed1a5f), - PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050e= f1), - 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, 0x= 4de2f6c8), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Card", 0x281f1c5d, 0x5e9d92c0= ), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Combo card", 0x281f1c5d, 0x92= 9c486c), - 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, 0xec5= dbca7), - 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", 0x281= f1c5d, 0x42d5d7e1), - PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10baseT 3.3V", 0xe= bf91155, 0x30074c80), - PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xe= bf91155, 0x7f5a4f50), - PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, = 0x3a30e110), - PCMCIA_DEVICE_PROD_ID12("=3DRELIA=3D=3D", "Ethernet", 0xcdd0644a, 0x00b2e= 941), - PCMCIA_DEVICE_PROD_ID12("RIOS Systems Co.", "PC CARD3 ETHERNET", 0x7dd334= 81, 0x10b41826), - PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66= e22, 0xb96150df), - PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6= f88fd, 0x4a7e2ae0), - PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6= f88fd, 0x4bcbd7fd), - PCMCIA_DEVICE_PROD_ID12("RPTI LTD.", "EP400", 0xc53ac515, 0x81e39388), - PCMCIA_DEVICE_PROD_ID12("SCM", "Ethernet Combo card", 0xbdc3b102, 0x929c4= 86c), - PCMCIA_DEVICE_PROD_ID12("Seiko Epson Corp.", "Ethernet", 0x09928730, 0x00= b2e941), - PCMCIA_DEVICE_PROD_ID12("SMC", "EZCard-10-PCMCIA", 0xc4f8b18b, 0xfb21d265= ), - PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LA= N Adapter Revision D", 0xc70a4760, 0x2ade483e), - PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LA= N Adapter Revision E", 0xc70a4760, 0x5dd978a8), - PCMCIA_DEVICE_PROD_ID12("TDK", "LAK-CD031 for PCMCIA", 0x1eae9475, 0x0ed3= 86fa), - PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE450T", 0x46= 6b05f0, 0x8b74bc4f), - PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE550T", 0x46= 6b05f0, 0x33c8db2a), - PCMCIA_DEVICE_PROD_ID13("Hypertec", "EP401", 0x8787bec7, 0xf6e4a31e), - PCMCIA_DEVICE_PROD_ID13("KingMax Technology Inc.", "Ethernet Card", 0x932= b7189, 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", 0x281f1c= 5d, 0x570f348e, "cis/PCMLM28.cis"), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c= 5d, 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, 0x66= 881874, "cis/PCMLM28.cis"), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "TOSHIBA", "Modem/LAN Card", 0xb4585a1= a, 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/DP= 83903.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", 0x= 2ad62f3c, 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, "c= is/NE2K.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "= cis/PE-200.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e94= 1, "cis/tamarack.cis"), - PCMCIA_DEVICE_PROD_ID12("Ethernet", "CF Size PC Card", 0x00b2e941, 0x43ac= 239b), - 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 =3D { - .name =3D "pcnet_cs", - .probe =3D pcnet_probe, - .remove =3D pcnet_detach, - .owner =3D THIS_MODULE, - .id_table =3D pcnet_ids, - .suspend =3D pcnet_suspend, - .resume =3D pcnet_resume, -}; -module_pcmcia_driver(pcnet_driver); --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A92D43DCDA4; Tue, 21 Apr 2026 19:58:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801515; cv=none; b=CZMwzfgLax/1eR9YrjU0JHz9VEGbCkXPaSEScTzYZvuccdZ/EjO7LIFGEp/rxr7xOsGhZJu+jjaIZMvg1jzyTIi3yyWSHviN/0+gkYJo2fpzwkpZzhA/MbkWn9chS+xNVuxh0/InYfCaAZa4THJrL1yFxtZb2V1+sG5K1UxzoUw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801515; c=relaxed/simple; bh=xOHHL8yexAVpOqGpkiyLva5sUcO4KH2knUcbz1Ejj2M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=re2HVXGQSLi/JnCXd7iz7gFB7InZm+KRgmDQRuJKvaiodAa7tJ6pUu0abfdVHK4ukC0EEo2KlclnSkeg6o3/SI3jTXUw30nSRl8DkPnBFDICWCM5nhI37vol+L1tLhpTQY3JQpp+FNCYH0XBma4zrMbAOrxOFDKIFvyXaOubOOY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=KxnDUU2g; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="KxnDUU2g" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=vekPGwSC4UwwBOzYvmaaexuQKq7eOTOZyIMgvQHYhyY=; b=Kx nDUU2gCDe7dIhTYX8ijASXoxrliDSLPJSlf7hM4H+cE9cQcSEEqH7qHA/gIdXEPNgNkRlefE1lmTy Csl7+JkwWkINaq1jInTcY8D6UNSkGTpbFNm014E7Zc9FP2PeK02NenVCUqeirg5NlGvtlZBeZRHqu yOlmieGVFnrCbYo=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGpD-00GwVc-Fl; Tue, 21 Apr 2026 21:31:59 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:20 -0500 Subject: [PATCH net 17/18] drivers: net: 8390: ultra: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-17-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=22885; i=andrew@lunn.ch; h=from:subject:message-id; bh=xOHHL8yexAVpOqGpkiyLva5sUcO4KH2knUcbz1Ejj2M=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CCCiGqEaZSt1jLDxpmPkMobIuED11EL3QeX QUxyrujtEKJAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hModD/0dr0w1/9UgeUby6Bu26N8Ke6qkVYcoW2WeYscWcnNj9nlZZd538Hr2p6Cdhn6I5GrQld5 HzUJkMuaxZzXap4rDYOopBECAp7SSDjPmsrt1qGPQqxMMMQKEo9vVzDC/dZNNd85op7KPVUu1Oi cHzRXS5i1Joq5TBptV+qhtlhz5CCy4zLBNJCY0TM8Uy6oagjZjFVK+ynkdpdDDSvtx6jkYDsv5W hpVFuYSEj47Q9dy7brEJohLZ2DiPNOxPfB+qfRd0uIvzWyGKCAoKOVq6sL2pW1SsXbAAZlOv5ZF xYSr6gq5ZEttH5mrXud1hAH7JO5Ge4+YOHDzamo4lE0TA9TWpsa8G2ajBXqfBZdkZEy1kxD/efK yKdFiSev1vB0a6g1GDO0dy3XmkU8R3r/6lEE/tLPZOE+Jm/9mv5uhiVw54mZYEIwnpctk5YD1t9 cjgyaG35DKgawYYnCtFqgdiUVlE/AbUqkg29vJ6MdJ0Sz8igT/c6JcOytTAlf588S9W4QgbF0SQ /fvqeY+ww47g+RdxwJaknNyLxMEfE3zdhhjuo7ujnRcngUaXfwZs0enUmMEHTHdQZkVEoE5LPMh qDIPUOW7mGW4g03VG8MlWlNmpHeL7/FpKwYVoa/UcnGRaXSzwGNtKCJWWG2YBbsuK/YdhuD/x2O qM5axDVeOTL1QNw== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 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 --- 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 =20 If unsure, say N. =20 -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) +=3D mcf8390.o obj-$(CONFIG_NE2000) +=3D ne.o 8390p.o obj-$(CONFIG_NE2K_PCI) +=3D ne2k-pci.o 8390.o obj-$(CONFIG_STNIC) +=3D stnic.o 8390.o -obj-$(CONFIG_ULTRA) +=3D smc-ultra.o 8390.o obj-$(CONFIG_WD80x3) +=3D wd.o 8390.o obj-$(CONFIG_XSURF100) +=3D xsurf100.o obj-$(CONFIG_ZORRO8390) +=3D zorro8390.o diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8= 390/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=3D0x___ option. -*/ - -static const char version[] =3D - "smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "8390.h" - -#define DRV_NAME "smc-ultra" - -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int ultra_portlist[] __initdata =3D -{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_hd= r *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 =3D { - { ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), - ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), - (long) "SMC EtherEZ (8416)" }, - { } /* terminate list */ -}; - -MODULE_DEVICE_TABLE(isapnp, ultra_device_ids); -#endif - -static u32 ultra_msg_enable; - -#define START_PG 0x00 /* First page of TX buffer */ - -#define ULTRA_CMDREG 0 /* Offset to ASIC command register. */ -#define ULTRA_RESET 0x80 /* Board reset, in ULTRA_CMDREG. */ -#define ULTRA_MEMENB 0x40 /* Enable the shared memory. */ -#define IOPD 0x02 /* I/O Pipe Data (16 bits), PIO operation. */ -#define IOPA 0x07 /* I/O Pipe Address for PIO operation. */ -#define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */ -#define ULTRA_IO_EXTENT 32 -#define EN0_ERWCNT 0x08 /* Early receive warning count. */ - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void ultra_poll(struct net_device *dev) -{ - disable_irq(dev->irq); - ei_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif -/* Probe for the Ultra. This looks like a 8013 with the station - address PROM at I/O ports +8 to +13, with a checksum - following. -*/ - -static int __init do_ultra_probe(struct net_device *dev) -{ - int i; - int base_addr =3D dev->base_addr; - int irq =3D dev->irq; - - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ultra_probe1(dev, base_addr); - else if (base_addr !=3D 0) /* Don't probe at all. */ - return -ENXIO; - -#ifdef __ISAPNP__ - /* Look for any installed ISAPnP cards */ - if (isapnp_present() && (ultra_probe_isapnp(dev) =3D=3D 0)) - return 0; -#endif - - for (i =3D 0; ultra_portlist[i]; i++) { - dev->irq =3D irq; - if (ultra_probe1(dev, ultra_portlist[i]) =3D=3D 0) - return 0; - } - - return -ENODEV; -} - -#ifndef MODULE -struct net_device * __init ultra_probe(int unit) -{ - struct net_device *dev =3D alloc_ei_netdev(); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err =3D 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 =3D { - .ndo_open =3D ultra_open, - .ndo_stop =3D ultra_close_card, - - .ndo_start_xmit =3D ei_start_xmit, - .ndo_tx_timeout =3D ei_tx_timeout, - .ndo_get_stats =3D ei_get_stats, - .ndo_set_rx_mode =3D ei_set_multicast_list, - .ndo_validate_addr =3D eth_validate_addr, - .ndo_set_mac_address =3D eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D ultra_poll, -#endif -}; - -static int __init ultra_probe1(struct net_device *dev, int ioaddr) -{ - int i, retval; - int checksum =3D 0; - u8 macaddr[ETH_ALEN]; - const char *model_name; - unsigned char eeprom_irq =3D 0; - static unsigned version_printed; - /* Values from various config regs. */ - unsigned char num_pages, irqreg, addr, piomode; - unsigned char idreg =3D inb(ioaddr + 7); - unsigned char reg4 =3D inb(ioaddr + 4) & 0x7f; - struct ei_device *ei_local =3D netdev_priv(dev); - - if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) - return -EBUSY; - - /* Check the ID nibble. */ - if ((idreg & 0xF0) !=3D 0x20 /* SMC Ultra */ - && (idreg & 0xF0) !=3D 0x40) { /* SMC EtherEZ */ - retval =3D -ENODEV; - goto out; - } - - /* Select the station address register set. */ - outb(reg4, ioaddr + 4); - - for (i =3D 0; i < 8; i++) - checksum +=3D inb(ioaddr + 8 + i); - if ((checksum & 0xff) !=3D 0xFF) { - retval =3D -ENODEV; - goto out; - } - - if ((ultra_msg_enable & NETIF_MSG_DRV) && (version_printed++ =3D=3D 0)) - netdev_info(dev, version); - - model_name =3D (idreg & 0xF0) =3D=3D 0x20 ? "SMC Ultra" : "SMC EtherEZ"; - - for (i =3D 0; i < 6; i++) - macaddr[i] =3D 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 =3D inb(ioaddr + 0x8); - addr =3D inb(ioaddr + 0xb); - irqreg =3D inb(ioaddr + 0xd); - - /* Switch back to the station address register set so that the MS-DOS dri= ver - can find the card after a warm boot. */ - outb(reg4, ioaddr + 4); - - if (dev->irq < 2) { - unsigned char irqmap[] =3D {0, 9, 3, 5, 7, 10, 11, 15}; - int irq; - - /* The IRQ bits are split. */ - irq =3D irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)]; - - if (irq =3D=3D 0) { - pr_cont(", failed to detect IRQ line.\n"); - retval =3D -EAGAIN; - goto out; - } - dev->irq =3D irq; - eeprom_irq =3D 1; - } - - /* The 8390 isn't at the base address, so fake the offset */ - dev->base_addr =3D ioaddr+ULTRA_NIC_OFFSET; - - { - static const int addr_tbl[4] =3D { - 0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000 - }; - static const short num_pages_tbl[4] =3D { - 0x20, 0x40, 0x80, 0xff - }; - - dev->mem_start =3D ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ; - num_pages =3D num_pages_tbl[(addr >> 4) & 3]; - } - - ei_status.name =3D model_name; - ei_status.word16 =3D 1; - ei_status.tx_start_page =3D START_PG; - ei_status.rx_start_page =3D START_PG + TX_PAGES; - ei_status.stop_page =3D num_pages; - - ei_status.mem =3D ioremap(dev->mem_start, (ei_status.stop_page - START_PG= )*256); - if (!ei_status.mem) { - pr_cont(", failed to ioremap.\n"); - retval =3D -ENOMEM; - goto out; - } - - dev->mem_end =3D 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 =3D &ultra_pio_input; - ei_status.block_output =3D &ultra_pio_output; - ei_status.get_8390_hdr =3D &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 =3D &ultra_block_input; - ei_status.block_output =3D &ultra_block_output; - ei_status.get_8390_hdr =3D &ultra_get_8390_hdr; - } - ei_status.reset_8390 =3D &ultra_reset_8390; - - dev->netdev_ops =3D &ultra_netdev_ops; - NS8390_init(dev, 0); - ei_local->msg_enable =3D ultra_msg_enable; - - retval =3D 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 =3D 0; ultra_device_ids[i].vendor !=3D 0; i++) { - struct pnp_dev *idev =3D NULL; - - while ((idev =3D 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 =3D pnp_port_start(idev, 0); - dev->irq =3D 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) !=3D 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 =3D (unsigned long)idev; - break; - } - if (!idev) - continue; - return 0; - } - - return -ENODEV; -} -#endif - -static int -ultra_open(struct net_device *dev) -{ - int retval; - int ioaddr =3D dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ - unsigned char irq2reg[] =3D {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40, - 0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, }; - - retval =3D 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 =3D=3D &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 =3D dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */ - struct ei_device *ei_local =3D netdev_priv(dev); - - outb(ULTRA_RESET, cmd_port); - netif_dbg(ei_local, hw, dev, "resetting Ultra, t=3D%ld...\n", jiffies); - ei_status.txing =3D 0; - - outb(0x00, cmd_port); /* Disable shared memory for safety. */ - outb(0x80, cmd_port + 5); - if (ei_status.block_input =3D=3D &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 =3D 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 =3D le16_to_cpu(hdr->count); -#else - ((unsigned int*)hdr)[0] =3D 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 =3D 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 =3D ei_status.stop_page*256 - ring_offset; - memcpy_fromio(skb->data, xfer_start, semi_count); - count -=3D semi_count; - memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, co= unt); - } 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 =3D 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 chang= e. - 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 =3D 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 =3D dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ - char *buf =3D 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 =3D 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 =3D dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */ - struct ei_device *ei_local =3D 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 f= or 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 =3D 0; - - for (this_dev =3D 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - if (io[this_dev] =3D=3D 0) { - if (this_dev !=3D 0) break; /* only autoprobe 1st one */ - printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended= ) for a single card.\n"); - } - dev =3D alloc_ei_netdev(); - if (!dev) - break; - dev->irq =3D irq[this_dev]; - dev->base_addr =3D io[this_dev]; - if (do_ultra_probe(dev) =3D=3D 0) { - dev_ultra[found++] =3D dev; - continue; - } - free_netdev(dev); - printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o =3D 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 =3D (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 =3D 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev =3D dev_ultra[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -module_exit(ultra_cleanup_module); -#endif /* MODULE */ --=20 2.53.0 From nobody Wed Jun 17 03:11:25 2026 Received: from vps0.lunn.ch (vps0.lunn.ch [156.67.10.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1D1AA37BE80; Tue, 21 Apr 2026 19:57:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.67.10.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801447; cv=none; b=Kz2iclFpzerN0kkAZKVZXtLSapfLMfIfWyhzq0mB7Z110zfq+ajvmAwFA4JS4rtltBEwAliBwHC9q8sUl+H4hrbObWQAzN0VRXn6nhSu+nvAJZzKIT2J73OQOGZJta63j8qvhGpv4P2JgFr8hyxLzV87lTvB7uqbPB5SufWRasM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776801447; c=relaxed/simple; bh=3niLEYN1mi916fgg49/UmCFdkyAMBFcJ4sI1ojm0dAw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QO+5o260nDz/JT2mGfZTWszW1ORlX8BmpQUOFW4Fhohx0cE1sJykUVpTTq/nK0SNgOMXj5Jb7pNX0pvMrf/pMOcktYSdkI2cLbEmVaKdgRpl8I6h4sNBhFilm3dbd5JPpx1ZZqMT2qZ6I7NLB385zFfU/S05JpEdYwg8TWwHeV4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch; spf=pass smtp.mailfrom=lunn.ch; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b=W9CBVKKu; arc=none smtp.client-ip=156.67.10.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lunn.ch Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lunn.ch Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=lunn.ch header.i=@lunn.ch header.b="W9CBVKKu" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:From: Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Content-Disposition: In-Reply-To:References; bh=8FjaLY1FvoBrxRPonnN8yhzUiBRvtk/PyZtxQZu1zKA=; b=W9 CBVKKuLckQNeH5Qo7V6m5anytbJmUxORhhKPD82KU0ThHey8HeCbSuVMPF35J4u2qwPKccvun0r6Y nbQcZydReb2by02ALUGy3yC3gq6jdtQdi6vQ43MQNv/UqAnIgxdcn8B3x1zx9G3kdpalJnCUzNXeO Ul5iDZqWfcah25g=; Received: from c-66-41-74-139.hsd1.mn.comcast.net ([66.41.74.139] helo=thinkpad.home.lunn.ch) by vps0.lunn.ch with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1wFGpF-00GwVc-Vo; Tue, 21 Apr 2026 21:32:02 +0200 From: Andrew Lunn Date: Tue, 21 Apr 2026 14:31:21 -0500 Subject: [PATCH net 18/18] drivers: net: 8390: wd80x3: Remove this driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-v7-0-0-net-next-driver-removal-v1-v1-18-69517c689d1f@lunn.ch> References: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, Andrew Lunn X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=20898; i=andrew@lunn.ch; h=from:subject:message-id; bh=3niLEYN1mi916fgg49/UmCFdkyAMBFcJ4sI1ojm0dAw=; b=owEBbQKS/ZANAwAIAea/DcumaUyEAcsmYgBp59CChFLulMW0pe8E36jl7B+H2Jb8xS8Nq+Jfb mRoaqy30c2JAjMEAAEIAB0WIQRh+xAly1MmORb54bfmvw3LpmlMhAUCaefQggAKCRDmvw3LpmlM hLX1EAC0d9ZCFKaRQu4B7MCk7BSxH3opAsBJSrpPGgB5ZZHqLILqyJUoK2uOjklW+yiGlfHkC+1 Q0so6DW66TOFu2t8j6WqAz0dH+KLYK/nu+L1dkTZrBwDatwdcDwanbzUZY/jZkMTcufpBdyjrPJ I6q27fQx/jsUrdJPM1ESjaGRQDQ+W0IGZ7EgZfI4XwSd/IHdCHIez6on58u4ENFEn7O2BlSsSB7 Acgc5ZnxeB19tX6Pef3Yc1vhu5xG9x6nRbWENTjX1Onu+1LFPJRJC2yy2TllF/he7c1trlBaLhW gkk6XXRIgb+77+n1q/An4eztA3287jDpXGTgw5da1DNzyq8a9lWkjbMKDY2S82cfrf5sc8fNB3D BYkadoPRXSuO7yK908C+I/ET21UkAHTbyhcqIzPzEWSbD46TYrYCmzj9F9VJC9xaEbfSyncvKE5 DIPh5vKrTSXwKwCpc8QbLWFUQE52GlimXGnYcIo1bnyycNHOQgUCzSOSOCiX/RGtrSNmKKGkVkR 4+GSvyyM7eqzK1H+YIv22SItVFgq7Hrua1guqHbrG2mHnHNDaBASGoBYnTZTwI8VloMuJhxENVJ 6CqbAU45TTL34Km8NyBBJLi83B/WVcn3ojOEPHEk/p2uYlyG0ZLiJLvXQmF/W+8kkLwzemLzm28 3U8fjBeklS/FFaA== X-Developer-Key: i=andrew@lunn.ch; a=openpgp; fpr=61FB1025CB53263916F9E1B7E6BF0DCBA6694C84 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 --- 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 =20 If unsure, say N. =20 -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) +=3D mcf8390.o obj-$(CONFIG_NE2000) +=3D ne.o 8390p.o obj-$(CONFIG_NE2K_PCI) +=3D ne2k-pci.o 8390.o obj-$(CONFIG_STNIC) +=3D stnic.o 8390.o -obj-$(CONFIG_WD80x3) +=3D wd.o 8390.o obj-$(CONFIG_XSURF100) +=3D xsurf100.o obj-$(CONFIG_ZORRO8390) +=3D 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[] =3D - "wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "8390.h" - -#define DRV_NAME "wd" - -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int wd_portlist[] __initdata =3D -{0x300, 0x280, 0x380, 0x240, 0}; - -static int wd_probe1(struct net_device *dev, int ioaddr); - -static int wd_open(struct net_device *dev); -static void wd_reset_8390(struct net_device *dev); -static void wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *= hdr, - int ring_page); -static void wd_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void wd_block_output(struct net_device *dev, int count, - const unsigned char *buf, int start_page); -static int wd_close(struct net_device *dev); - -static u32 wd_msg_enable; - -#define WD_START_PG 0x00 /* First page of TX buffer */ -#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ -#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ - -#define WD_CMDREG 0 /* Offset to ASIC command register. */ -#define WD_RESET 0x80 /* Board reset, in WD_CMDREG. */ -#define WD_MEMENB 0x40 /* Enable the shared memory. */ -#define WD_CMDREG5 5 /* Offset to 16-bit-only ASIC register 5. */ -#define ISA16 0x80 /* Enable 16 bit access from the ISA bus. */ -#define NIC16 0x40 /* Enable 16 bit access from the 8390. */ -#define WD_NIC_OFFSET 16 /* Offset to the 8390 from the base_addr. */ -#define WD_IO_EXTENT 32 - - -/* Probe for the WD8003 and WD8013. These cards have the station - address PROM at I/O ports +8 to +13, with a checksum - following. A Soundblaster can have the same checksum as an WDethercard, - so we have an extra exclusionary check for it. - - The wd_probe1() routine initializes the card and fills the - station address field. */ - -static int __init do_wd_probe(struct net_device *dev) -{ - int i; - struct resource *r; - int base_addr =3D dev->base_addr; - int irq =3D dev->irq; - int mem_start =3D dev->mem_start; - int mem_end =3D dev->mem_end; - - if (base_addr > 0x1ff) { /* Check a user specified location. */ - r =3D request_region(base_addr, WD_IO_EXTENT, "wd-probe"); - if ( r =3D=3D NULL) - return -EBUSY; - i =3D wd_probe1(dev, base_addr); - if (i !=3D 0) - release_region(base_addr, WD_IO_EXTENT); - else - r->name =3D dev->name; - return i; - } - else if (base_addr !=3D 0) /* Don't probe at all. */ - return -ENXIO; - - for (i =3D 0; wd_portlist[i]; i++) { - int ioaddr =3D wd_portlist[i]; - r =3D request_region(ioaddr, WD_IO_EXTENT, "wd-probe"); - if (r =3D=3D NULL) - continue; - if (wd_probe1(dev, ioaddr) =3D=3D 0) { - r->name =3D dev->name; - return 0; - } - release_region(ioaddr, WD_IO_EXTENT); - dev->irq =3D irq; - dev->mem_start =3D mem_start; - dev->mem_end =3D mem_end; - } - - return -ENODEV; -} - -#ifndef MODULE -struct net_device * __init wd_probe(int unit) -{ - struct net_device *dev =3D alloc_ei_netdev(); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err =3D 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 =3D { - .ndo_open =3D wd_open, - .ndo_stop =3D wd_close, - .ndo_start_xmit =3D ei_start_xmit, - .ndo_tx_timeout =3D ei_tx_timeout, - .ndo_get_stats =3D ei_get_stats, - .ndo_set_rx_mode =3D ei_set_multicast_list, - .ndo_validate_addr =3D eth_validate_addr, - .ndo_set_mac_address =3D eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller =3D ei_poll, -#endif -}; - -static int __init wd_probe1(struct net_device *dev, int ioaddr) -{ - int i; - int err; - int checksum =3D 0; - int ancient =3D 0; /* An old card without config registers. */ - int word16 =3D 0; /* 0 =3D 8 bit, 1 =3D 16 bit */ - u8 addr[ETH_ALEN]; - const char *model_name; - static unsigned version_printed; - struct ei_device *ei_local =3D netdev_priv(dev); - - for (i =3D 0; i < 8; i++) - checksum +=3D inb(ioaddr + 8 + i); - if (inb(ioaddr + 8) =3D=3D 0xff /* Extra check to avoid soundcard. */ - || inb(ioaddr + 9) =3D=3D 0xff - || (checksum & 0xff) !=3D 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 - ign= ored.\n"); - dev->mem_start =3D 0; - dev->mem_end =3D 0; - } - - if ((wd_msg_enable & NETIF_MSG_DRV) && (version_printed++ =3D=3D 0)) - netdev_info(dev, version); - - for (i =3D 0; i < 6; i++) - addr[i] =3D inb(ioaddr + 8 + i); - eth_hw_addr_set(dev, addr); - - netdev_info(dev, "WD80x3 at %#3x, %pM", ioaddr, dev->dev_addr); - - /* The following PureData probe code was contributed by - Mike Jagdis . Puredata does software - configuration differently from others so we have to check for them. - This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card. - */ - if (inb(ioaddr+0) =3D=3D 'P' && inb(ioaddr+1) =3D=3D 'D') { - unsigned char reg5 =3D inb(ioaddr+5); - - switch (inb(ioaddr+2)) { - case 0x03: word16 =3D 0; model_name =3D "PDI8023-8"; break; - case 0x05: word16 =3D 0; model_name =3D "PDUC8023"; break; - case 0x0a: word16 =3D 1; model_name =3D "PDI8023-16"; break; - /* Either 0x01 (dumb) or they've released a new version. */ - default: word16 =3D 0; model_name =3D "PDI8023"; break; - } - dev->mem_start =3D ((reg5 & 0x1c) + 0xc0) << 12; - dev->irq =3D (reg5 & 0xe0) =3D=3D 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>=3D6 here -- it hangs the old 8003 boards! */ - for (i =3D 0; i < 6; i++) - if (inb(ioaddr+i) !=3D inb(ioaddr+8+i)) - break; - if (i >=3D 6) { - ancient =3D 1; - model_name =3D "WD8003-old"; - word16 =3D 0; - } else { - int tmp =3D inb(ioaddr+1); /* fiddle with 16bit bit */ - outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */ - if (((inb( ioaddr+1) & 0x01) =3D=3D 0x01) /* A 16 bit card */ - && (tmp & 0x01) =3D=3D 0x01 ) { /* In a 16 slot. */ - int asic_reg5 =3D 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 =3D "WD8013"; - word16 =3D 1; /* We have a 16bit board here! */ - } else { - model_name =3D "WD8003"; - word16 =3D 0; - } - outb(tmp, ioaddr+1); /* Restore original reg1 value. */ - } -#ifndef final_version - if ( !ancient && (inb(ioaddr+1) & 0x01) !=3D (word16 & 0x01)) - pr_cont("\nWD80?3: Bus width conflict, %d (probe) !=3D %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 =3D WD_SHMEM; -#else - if (dev->mem_start =3D=3D 0) { - /* Sanity and old 8003 check */ - int reg0 =3D inb(ioaddr); - if (reg0 =3D=3D 0xff || reg0 =3D=3D 0) { - /* Future plan: this could check a few likely locations first. */ - dev->mem_start =3D 0xd0000; - pr_cont(" assigning address %#lx", dev->mem_start); - } else { - int high_addr_bits =3D inb(ioaddr+WD_CMDREG5) & 0x1f; - /* Some boards don't have the register 5 -- it returns 0xff. */ - if (high_addr_bits =3D=3D 0x1f || word16 =3D=3D 0) - high_addr_bits =3D 0x01; - dev->mem_start =3D ((reg0&0x3f) << 13) + (high_addr_bits << 19); - } - } -#endif - - /* The 8390 isn't at the base address -- the ASIC regs are there! */ - dev->base_addr =3D ioaddr+WD_NIC_OFFSET; - - if (dev->irq < 2) { - static const int irqmap[] =3D {9, 3, 5, 7, 10, 11, 15, 4}; - int reg1 =3D inb(ioaddr+1); - int reg4 =3D inb(ioaddr+4); - if (ancient || reg1 =3D=3D 0xff) { /* Ack!! No way to read the IRQ! */ - short nic_addr =3D 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 =3D 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 =3D 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 =3D word16 ? 10 : 5; - } else - dev->irq =3D irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)]; - } else if (dev->irq =3D=3D 2) /* Fixup bogosity: IRQ2 is really IRQ9 */ - dev->irq =3D 9; - - /* Snarf the interrupt now. There's no point in waiting since we cannot - share and the board will usually be enabled. */ - i =3D 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 =3D model_name; - ei_status.word16 =3D word16; - ei_status.tx_start_page =3D WD_START_PG; - ei_status.rx_start_page =3D 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 !=3D 0) { - ei_status.stop_page =3D (dev->mem_end - dev->mem_start)/256; - ei_status.priv =3D dev->mem_end - dev->mem_start; - } else { - ei_status.stop_page =3D word16 ? WD13_STOP_PG : WD03_STOP_PG; - dev->mem_end =3D dev->mem_start + (ei_status.stop_page - WD_START_PG)*25= 6; - ei_status.priv =3D (ei_status.stop_page - WD_START_PG)*256; - } - - ei_status.mem =3D 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 =3D wd_reset_8390; - ei_status.block_input =3D wd_block_input; - ei_status.block_output =3D wd_block_output; - ei_status.get_8390_hdr =3D wd_get_8390_hdr; - - dev->netdev_ops =3D &wd_netdev_ops; - NS8390_init(dev, 0); - ei_local->msg_enable =3D 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 =3D 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 =3D 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 =3D ((dev->mem_start>>13) & 0x3f) | WD_MEMENB; - ei_status.reg5 =3D ((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 =3D dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - struct ei_device *ei_local =3D netdev_priv(dev); - - outb(WD_RESET, wd_cmd_port); - netif_dbg(ei_local, hw, dev, "resetting the WD80x3 t=3D%lu...\n", - jiffies); - ei_status.txing =3D 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 rin= g_page) -{ - - int wd_cmdreg =3D dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - void __iomem *hdr_start =3D 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 =3D le16_to_cpu(hdr->count); -#else - ((unsigned int*)hdr)[0] =3D 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 =3D dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - unsigned long offset =3D ring_offset - (WD_START_PG<<8); - void __iomem *xfer_start =3D ei_status.mem + offset; - - if (offset + count > ei_status.priv) { - /* We must wrap the input move. */ - int semi_count =3D ei_status.priv - offset; - memcpy_fromio(skb->data, xfer_start, semi_count); - count -=3D semi_count; - memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, co= unt); - } 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 *bu= f, - int start_page) -{ - int wd_cmdreg =3D dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - void __iomem *shmem =3D 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 =3D dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ - struct ei_device *ei_local =3D 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 f= or 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 =3D 0; - - for (this_dev =3D 0; this_dev < MAX_WD_CARDS; this_dev++) { - if (io[this_dev] =3D=3D 0) { - if (this_dev !=3D 0) break; /* only autoprobe 1st one */ - printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a= single card.\n"); - } - dev =3D alloc_ei_netdev(); - if (!dev) - break; - dev->irq =3D irq[this_dev]; - dev->base_addr =3D io[this_dev]; - dev->mem_start =3D mem[this_dev]; - dev->mem_end =3D mem_end[this_dev]; - if (do_wd_probe(dev) =3D=3D 0) { - dev_wd[found++] =3D dev; - continue; - } - free_netdev(dev); - printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o =3D 0x%x).\n", io[t= his_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 =3D 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev =3D dev_wd[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -module_exit(wd_cleanup_module); -#endif /* MODULE */ --=20 2.53.0