162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+ 262306a36Sopenharmony_ci/* A Linux device driver for PCI NE2000 clones. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors and other copyright holders: 562306a36Sopenharmony_ci * 1992-2000 by Donald Becker, NE2000 core and various modifications. 662306a36Sopenharmony_ci * 1995-1998 by Paul Gortmaker, core modifications and PCI support. 762306a36Sopenharmony_ci * Copyright 1993 assigned to the United States Government as represented 862306a36Sopenharmony_ci * by the Director, National Security Agency. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This software may be used and distributed according to the terms of 1162306a36Sopenharmony_ci * the GNU General Public License (GPL), incorporated herein by reference. 1262306a36Sopenharmony_ci * Drivers based on or derived from this code fall under the GPL and must 1362306a36Sopenharmony_ci * retain the authorship, copyright and license notice. This file is not 1462306a36Sopenharmony_ci * a complete program and may only be used when the entire operating 1562306a36Sopenharmony_ci * system is licensed under the GPL. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * The author may be reached as becker@scyld.com, or C/O 1862306a36Sopenharmony_ci * Scyld Computing Corporation 1962306a36Sopenharmony_ci * 410 Severn Ave., Suite 210 2062306a36Sopenharmony_ci * Annapolis MD 21403 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Issues remaining: 2362306a36Sopenharmony_ci * People are making PCI NE2000 clones! Oh the horror, the horror... 2462306a36Sopenharmony_ci * Limited full-duplex support. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DRV_NAME "ne2k-pci" 2862306a36Sopenharmony_ci#define DRV_DESCRIPTION "PCI NE2000 clone driver" 2962306a36Sopenharmony_ci#define DRV_AUTHOR "Donald Becker / Paul Gortmaker" 3062306a36Sopenharmony_ci#define DRV_VERSION "1.03" 3162306a36Sopenharmony_ci#define DRV_RELDATE "9/22/2003" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* The user-configurable values. 3662306a36Sopenharmony_ci * These may be modified when a driver module is loaded. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* More are supported, limit only on options */ 4062306a36Sopenharmony_ci#define MAX_UNITS 8 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Used to pass the full-duplex flag, etc. */ 4362306a36Sopenharmony_cistatic int full_duplex[MAX_UNITS]; 4462306a36Sopenharmony_cistatic int options[MAX_UNITS]; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* Force a non std. amount of memory. Units are 256 byte pages. */ 4762306a36Sopenharmony_ci/* #define PACKETBUF_MEMSIZE 0x40 */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include <linux/module.h> 5162306a36Sopenharmony_ci#include <linux/kernel.h> 5262306a36Sopenharmony_ci#include <linux/errno.h> 5362306a36Sopenharmony_ci#include <linux/pci.h> 5462306a36Sopenharmony_ci#include <linux/init.h> 5562306a36Sopenharmony_ci#include <linux/interrupt.h> 5662306a36Sopenharmony_ci#include <linux/ethtool.h> 5762306a36Sopenharmony_ci#include <linux/netdevice.h> 5862306a36Sopenharmony_ci#include <linux/etherdevice.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#include <linux/io.h> 6162306a36Sopenharmony_ci#include <asm/irq.h> 6262306a36Sopenharmony_ci#include <linux/uaccess.h> 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#include "8390.h" 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int ne2k_msg_enable; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic const int default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | 6962306a36Sopenharmony_ci NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#if defined(__powerpc__) 7262306a36Sopenharmony_ci#define inl_le(addr) le32_to_cpu(inl(addr)) 7362306a36Sopenharmony_ci#define inw_le(addr) le16_to_cpu(inw(addr)) 7462306a36Sopenharmony_ci#endif 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciMODULE_AUTHOR(DRV_AUTHOR); 7762306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESCRIPTION); 7862306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 7962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cimodule_param_named(msg_enable, ne2k_msg_enable, int, 0444); 8262306a36Sopenharmony_cimodule_param_array(options, int, NULL, 0); 8362306a36Sopenharmony_cimodule_param_array(full_duplex, int, NULL, 0); 8462306a36Sopenharmony_ciMODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); 8562306a36Sopenharmony_ciMODULE_PARM_DESC(options, "Bit 5: full duplex"); 8662306a36Sopenharmony_ciMODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)"); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* Some defines that people can play with if so inclined. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Use 32 bit data-movement operations instead of 16 bit. */ 9262306a36Sopenharmony_ci#define USE_LONGIO 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* Do we implement the read before write bugfix ? */ 9562306a36Sopenharmony_ci/* #define NE_RW_BUGFIX */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* Flags. We rename an existing ei_status field to store flags! 9862306a36Sopenharmony_ci * Thus only the low 8 bits are usable for non-init-time flags. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci#define ne2k_flags reg0 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cienum { 10362306a36Sopenharmony_ci /* Chip can do only 16/32-bit xfers. */ 10462306a36Sopenharmony_ci ONLY_16BIT_IO = 8, ONLY_32BIT_IO = 4, 10562306a36Sopenharmony_ci /* User override. */ 10662306a36Sopenharmony_ci FORCE_FDX = 0x20, 10762306a36Sopenharmony_ci REALTEK_FDX = 0x40, HOLTEK_FDX = 0x80, 10862306a36Sopenharmony_ci STOP_PG_0x60 = 0x100, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cienum ne2k_pci_chipsets { 11262306a36Sopenharmony_ci CH_RealTek_RTL_8029 = 0, 11362306a36Sopenharmony_ci CH_Winbond_89C940, 11462306a36Sopenharmony_ci CH_Compex_RL2000, 11562306a36Sopenharmony_ci CH_KTI_ET32P2, 11662306a36Sopenharmony_ci CH_NetVin_NV5000SC, 11762306a36Sopenharmony_ci CH_Via_86C926, 11862306a36Sopenharmony_ci CH_SureCom_NE34, 11962306a36Sopenharmony_ci CH_Winbond_W89C940F, 12062306a36Sopenharmony_ci CH_Holtek_HT80232, 12162306a36Sopenharmony_ci CH_Holtek_HT80229, 12262306a36Sopenharmony_ci CH_Winbond_89C940_8c4a, 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic struct { 12762306a36Sopenharmony_ci char *name; 12862306a36Sopenharmony_ci int flags; 12962306a36Sopenharmony_ci} pci_clone_list[] = { 13062306a36Sopenharmony_ci {"RealTek RTL-8029(AS)", REALTEK_FDX}, 13162306a36Sopenharmony_ci {"Winbond 89C940", 0}, 13262306a36Sopenharmony_ci {"Compex RL2000", 0}, 13362306a36Sopenharmony_ci {"KTI ET32P2", 0}, 13462306a36Sopenharmony_ci {"NetVin NV5000SC", 0}, 13562306a36Sopenharmony_ci {"Via 86C926", ONLY_16BIT_IO}, 13662306a36Sopenharmony_ci {"SureCom NE34", 0}, 13762306a36Sopenharmony_ci {"Winbond W89C940F", 0}, 13862306a36Sopenharmony_ci {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, 13962306a36Sopenharmony_ci {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, 14062306a36Sopenharmony_ci {"Winbond W89C940(misprogrammed)", 0}, 14162306a36Sopenharmony_ci {NULL,} 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic const struct pci_device_id ne2k_pci_tbl[] = { 14662306a36Sopenharmony_ci { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 }, 14762306a36Sopenharmony_ci { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 }, 14862306a36Sopenharmony_ci { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 }, 14962306a36Sopenharmony_ci { 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 }, 15062306a36Sopenharmony_ci { 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC }, 15162306a36Sopenharmony_ci { 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 }, 15262306a36Sopenharmony_ci { 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 }, 15362306a36Sopenharmony_ci { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F }, 15462306a36Sopenharmony_ci { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 }, 15562306a36Sopenharmony_ci { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 }, 15662306a36Sopenharmony_ci { 0x8c4a, 0x1980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940_8c4a }, 15762306a36Sopenharmony_ci { 0, } 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ne2k_pci_tbl); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* ---- No user-serviceable parts below ---- */ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#define NE_BASE (dev->base_addr) 16662306a36Sopenharmony_ci#define NE_CMD 0x00 16762306a36Sopenharmony_ci#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */ 16862306a36Sopenharmony_ci#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */ 16962306a36Sopenharmony_ci#define NE_IO_EXTENT 0x20 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#define NESM_START_PG 0x40 /* First page of TX buffer */ 17262306a36Sopenharmony_ci#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int ne2k_pci_open(struct net_device *dev); 17662306a36Sopenharmony_cistatic int ne2k_pci_close(struct net_device *dev); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic void ne2k_pci_reset_8390(struct net_device *dev); 17962306a36Sopenharmony_cistatic void ne2k_pci_get_8390_hdr(struct net_device *dev, 18062306a36Sopenharmony_ci struct e8390_pkt_hdr *hdr, int ring_page); 18162306a36Sopenharmony_cistatic void ne2k_pci_block_input(struct net_device *dev, int count, 18262306a36Sopenharmony_ci struct sk_buff *skb, int ring_offset); 18362306a36Sopenharmony_cistatic void ne2k_pci_block_output(struct net_device *dev, const int count, 18462306a36Sopenharmony_ci const unsigned char *buf, 18562306a36Sopenharmony_ci const int start_page); 18662306a36Sopenharmony_cistatic const struct ethtool_ops ne2k_pci_ethtool_ops; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* There is no room in the standard 8390 structure for extra info we need, 19162306a36Sopenharmony_ci * so we build a meta/outer-wrapper structure.. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_cistruct ne2k_pci_card { 19462306a36Sopenharmony_ci struct net_device *dev; 19562306a36Sopenharmony_ci struct pci_dev *pci_dev; 19662306a36Sopenharmony_ci}; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet 20162306a36Sopenharmony_ci * buffer memory space. By-the-spec NE2000 clones have 0x57,0x57 in bytes 20262306a36Sopenharmony_ci * 0x0e,0x0f of the SAPROM, while other supposed NE2000 clones must be 20362306a36Sopenharmony_ci * detected by their SA prefix. 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * Reading the SAPROM from a word-wide card with the 8390 set in byte-wide 20662306a36Sopenharmony_ci * mode results in doubled values, which can be detected and compensated for. 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * The probe is also responsible for initializing the card and filling 20962306a36Sopenharmony_ci * in the 'dev' and 'ei_status' structures. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic const struct net_device_ops ne2k_netdev_ops = { 21362306a36Sopenharmony_ci .ndo_open = ne2k_pci_open, 21462306a36Sopenharmony_ci .ndo_stop = ne2k_pci_close, 21562306a36Sopenharmony_ci .ndo_start_xmit = ei_start_xmit, 21662306a36Sopenharmony_ci .ndo_tx_timeout = ei_tx_timeout, 21762306a36Sopenharmony_ci .ndo_get_stats = ei_get_stats, 21862306a36Sopenharmony_ci .ndo_set_rx_mode = ei_set_multicast_list, 21962306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 22062306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 22162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 22262306a36Sopenharmony_ci .ndo_poll_controller = ei_poll, 22362306a36Sopenharmony_ci#endif 22462306a36Sopenharmony_ci}; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int ne2k_pci_init_one(struct pci_dev *pdev, 22762306a36Sopenharmony_ci const struct pci_device_id *ent) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct net_device *dev; 23062306a36Sopenharmony_ci int i; 23162306a36Sopenharmony_ci unsigned char SA_prom[32]; 23262306a36Sopenharmony_ci int start_page, stop_page; 23362306a36Sopenharmony_ci int irq, reg0, chip_idx = ent->driver_data; 23462306a36Sopenharmony_ci static unsigned int fnd_cnt; 23562306a36Sopenharmony_ci long ioaddr; 23662306a36Sopenharmony_ci int flags = pci_clone_list[chip_idx].flags; 23762306a36Sopenharmony_ci struct ei_device *ei_local; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci fnd_cnt++; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci i = pci_enable_device(pdev); 24262306a36Sopenharmony_ci if (i) 24362306a36Sopenharmony_ci return i; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ioaddr = pci_resource_start(pdev, 0); 24662306a36Sopenharmony_ci irq = pdev->irq; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (!ioaddr || ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) == 0)) { 24962306a36Sopenharmony_ci dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n"); 25062306a36Sopenharmony_ci goto err_out; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) { 25462306a36Sopenharmony_ci dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n", 25562306a36Sopenharmony_ci NE_IO_EXTENT, ioaddr); 25662306a36Sopenharmony_ci goto err_out; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci reg0 = inb(ioaddr); 26062306a36Sopenharmony_ci if (reg0 == 0xFF) 26162306a36Sopenharmony_ci goto err_out_free_res; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Do a preliminary verification that we have a 8390. */ 26462306a36Sopenharmony_ci { 26562306a36Sopenharmony_ci int regd; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci outb(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD); 26862306a36Sopenharmony_ci regd = inb(ioaddr + 0x0d); 26962306a36Sopenharmony_ci outb(0xff, ioaddr + 0x0d); 27062306a36Sopenharmony_ci outb(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD); 27162306a36Sopenharmony_ci /* Clear the counter by reading. */ 27262306a36Sopenharmony_ci inb(ioaddr + EN0_COUNTER0); 27362306a36Sopenharmony_ci if (inb(ioaddr + EN0_COUNTER0) != 0) { 27462306a36Sopenharmony_ci outb(reg0, ioaddr); 27562306a36Sopenharmony_ci /* Restore the old values. */ 27662306a36Sopenharmony_ci outb(regd, ioaddr + 0x0d); 27762306a36Sopenharmony_ci goto err_out_free_res; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */ 28262306a36Sopenharmony_ci dev = alloc_ei_netdev(); 28362306a36Sopenharmony_ci if (!dev) { 28462306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot allocate ethernet device\n"); 28562306a36Sopenharmony_ci goto err_out_free_res; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci dev->netdev_ops = &ne2k_netdev_ops; 28862306a36Sopenharmony_ci ei_local = netdev_priv(dev); 28962306a36Sopenharmony_ci ei_local->msg_enable = netif_msg_init(ne2k_msg_enable, default_msg_level); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Reset card. Who knows what dain-bramaged state it was left in. */ 29462306a36Sopenharmony_ci { 29562306a36Sopenharmony_ci unsigned long reset_start_time = jiffies; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* This looks like a horrible timing loop, but it should never 30062306a36Sopenharmony_ci * take more than a few cycles. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0) 30362306a36Sopenharmony_ci /* Limit wait: '2' avoids jiffy roll-over. */ 30462306a36Sopenharmony_ci if (jiffies - reset_start_time > 2) { 30562306a36Sopenharmony_ci dev_err(&pdev->dev, 30662306a36Sopenharmony_ci "Card failure (no reset ack).\n"); 30762306a36Sopenharmony_ci goto err_out_free_netdev; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci /* Ack all intr. */ 31062306a36Sopenharmony_ci outb(0xff, ioaddr + EN0_ISR); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Read the 16 bytes of station address PROM. 31462306a36Sopenharmony_ci * We must first initialize registers, similar 31562306a36Sopenharmony_ci * to NS8390_init(eifdev, 0). 31662306a36Sopenharmony_ci * We can't reliably read the SAPROM address without this. 31762306a36Sopenharmony_ci * (I learned the hard way!). 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci { 32062306a36Sopenharmony_ci struct {unsigned char value, offset; } program_seq[] = { 32162306a36Sopenharmony_ci /* Select page 0 */ 32262306a36Sopenharmony_ci {E8390_NODMA + E8390_PAGE0 + E8390_STOP, E8390_CMD}, 32362306a36Sopenharmony_ci /* Set word-wide access */ 32462306a36Sopenharmony_ci {0x49, EN0_DCFG}, 32562306a36Sopenharmony_ci /* Clear the count regs. */ 32662306a36Sopenharmony_ci {0x00, EN0_RCNTLO}, 32762306a36Sopenharmony_ci /* Mask completion IRQ */ 32862306a36Sopenharmony_ci {0x00, EN0_RCNTHI}, 32962306a36Sopenharmony_ci {0x00, EN0_IMR}, 33062306a36Sopenharmony_ci {0xFF, EN0_ISR}, 33162306a36Sopenharmony_ci /* 0x20 Set to monitor */ 33262306a36Sopenharmony_ci {E8390_RXOFF, EN0_RXCR}, 33362306a36Sopenharmony_ci /* 0x02 and loopback mode */ 33462306a36Sopenharmony_ci {E8390_TXOFF, EN0_TXCR}, 33562306a36Sopenharmony_ci {32, EN0_RCNTLO}, 33662306a36Sopenharmony_ci {0x00, EN0_RCNTHI}, 33762306a36Sopenharmony_ci /* DMA starting at 0x0000 */ 33862306a36Sopenharmony_ci {0x00, EN0_RSARLO}, 33962306a36Sopenharmony_ci {0x00, EN0_RSARHI}, 34062306a36Sopenharmony_ci {E8390_RREAD+E8390_START, E8390_CMD}, 34162306a36Sopenharmony_ci }; 34262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(program_seq); i++) 34362306a36Sopenharmony_ci outb(program_seq[i].value, 34462306a36Sopenharmony_ci ioaddr + program_seq[i].offset); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Note: all PCI cards have at least 16 bit access, so we don't have 34962306a36Sopenharmony_ci * to check for 8 bit cards. Most cards permit 32 bit access. 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_ci if (flags & ONLY_32BIT_IO) { 35262306a36Sopenharmony_ci for (i = 0; i < 4 ; i++) 35362306a36Sopenharmony_ci ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT)); 35462306a36Sopenharmony_ci } else 35562306a36Sopenharmony_ci for (i = 0; i < 32 /* sizeof(SA_prom )*/; i++) 35662306a36Sopenharmony_ci SA_prom[i] = inb(ioaddr + NE_DATAPORT); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* We always set the 8390 registers for word mode. */ 35962306a36Sopenharmony_ci outb(0x49, ioaddr + EN0_DCFG); 36062306a36Sopenharmony_ci start_page = NESM_START_PG; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci stop_page = flags & STOP_PG_0x60 ? 0x60 : NESM_STOP_PG; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* Set up the rest of the parameters. */ 36562306a36Sopenharmony_ci dev->irq = irq; 36662306a36Sopenharmony_ci dev->base_addr = ioaddr; 36762306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ei_status.name = pci_clone_list[chip_idx].name; 37062306a36Sopenharmony_ci ei_status.tx_start_page = start_page; 37162306a36Sopenharmony_ci ei_status.stop_page = stop_page; 37262306a36Sopenharmony_ci ei_status.word16 = 1; 37362306a36Sopenharmony_ci ei_status.ne2k_flags = flags; 37462306a36Sopenharmony_ci if (fnd_cnt < MAX_UNITS) { 37562306a36Sopenharmony_ci if (full_duplex[fnd_cnt] > 0 || (options[fnd_cnt] & FORCE_FDX)) 37662306a36Sopenharmony_ci ei_status.ne2k_flags |= FORCE_FDX; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ei_status.rx_start_page = start_page + TX_PAGES; 38062306a36Sopenharmony_ci#ifdef PACKETBUF_MEMSIZE 38162306a36Sopenharmony_ci /* Allow the packet buffer size to be overridden by know-it-alls. */ 38262306a36Sopenharmony_ci ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; 38362306a36Sopenharmony_ci#endif 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ei_status.reset_8390 = &ne2k_pci_reset_8390; 38662306a36Sopenharmony_ci ei_status.block_input = &ne2k_pci_block_input; 38762306a36Sopenharmony_ci ei_status.block_output = &ne2k_pci_block_output; 38862306a36Sopenharmony_ci ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr; 38962306a36Sopenharmony_ci ei_status.priv = (unsigned long) pdev; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci dev->ethtool_ops = &ne2k_pci_ethtool_ops; 39262306a36Sopenharmony_ci NS8390_init(dev, 0); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci eth_hw_addr_set(dev, SA_prom); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci i = register_netdev(dev); 39762306a36Sopenharmony_ci if (i) 39862306a36Sopenharmony_ci goto err_out_free_netdev; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci netdev_info(dev, "%s found at %#lx, IRQ %d, %pM.\n", 40162306a36Sopenharmony_ci pci_clone_list[chip_idx].name, ioaddr, dev->irq, 40262306a36Sopenharmony_ci dev->dev_addr); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cierr_out_free_netdev: 40762306a36Sopenharmony_ci free_netdev(dev); 40862306a36Sopenharmony_cierr_out_free_res: 40962306a36Sopenharmony_ci release_region(ioaddr, NE_IO_EXTENT); 41062306a36Sopenharmony_cierr_out: 41162306a36Sopenharmony_ci pci_disable_device(pdev); 41262306a36Sopenharmony_ci return -ENODEV; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/* Magic incantation sequence for full duplex on the supported cards. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_cistatic inline int set_realtek_fdx(struct net_device *dev) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci long ioaddr = dev->base_addr; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */ 42262306a36Sopenharmony_ci outb(0xC0, ioaddr + 0x01); /* Enable writes to CONFIG3 */ 42362306a36Sopenharmony_ci outb(0x40, ioaddr + 0x06); /* Enable full duplex */ 42462306a36Sopenharmony_ci outb(0x00, ioaddr + 0x01); /* Disable writes to CONFIG3 */ 42562306a36Sopenharmony_ci outb(E8390_PAGE0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 0 */ 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic inline int set_holtek_fdx(struct net_device *dev) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci long ioaddr = dev->base_addr; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20); 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int ne2k_pci_set_fdx(struct net_device *dev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci if (ei_status.ne2k_flags & REALTEK_FDX) 44062306a36Sopenharmony_ci return set_realtek_fdx(dev); 44162306a36Sopenharmony_ci else if (ei_status.ne2k_flags & HOLTEK_FDX) 44262306a36Sopenharmony_ci return set_holtek_fdx(dev); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return -EOPNOTSUPP; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int ne2k_pci_open(struct net_device *dev) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci int ret = request_irq(dev->irq, ei_interrupt, IRQF_SHARED, 45062306a36Sopenharmony_ci dev->name, dev); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (ret) 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (ei_status.ne2k_flags & FORCE_FDX) 45662306a36Sopenharmony_ci ne2k_pci_set_fdx(dev); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci ei_open(dev); 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int ne2k_pci_close(struct net_device *dev) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci ei_close(dev); 46562306a36Sopenharmony_ci free_irq(dev->irq, dev); 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* Hard reset the card. This used to pause for the same period that a 47062306a36Sopenharmony_ci * 8390 reset command required, but that shouldn't be necessary. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic void ne2k_pci_reset_8390(struct net_device *dev) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci unsigned long reset_start_time = jiffies; 47562306a36Sopenharmony_ci struct ei_device *ei_local = netdev_priv(dev); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", 47862306a36Sopenharmony_ci jiffies); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci ei_status.txing = 0; 48362306a36Sopenharmony_ci ei_status.dmaing = 0; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* This check _should_not_ be necessary, omit eventually. */ 48662306a36Sopenharmony_ci while ((inb(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) 48762306a36Sopenharmony_ci if (jiffies - reset_start_time > 2) { 48862306a36Sopenharmony_ci netdev_err(dev, "%s did not complete.\n", __func__); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci /* Ack intr. */ 49262306a36Sopenharmony_ci outb(ENISR_RESET, NE_BASE + EN0_ISR); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci/* Grab the 8390 specific header. Similar to the block_input routine, but 49662306a36Sopenharmony_ci * we don't need to be concerned with ring wrap as the header will be at 49762306a36Sopenharmony_ci * the start of a page, so we optimize accordingly. 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void ne2k_pci_get_8390_hdr(struct net_device *dev, 50162306a36Sopenharmony_ci struct e8390_pkt_hdr *hdr, int ring_page) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci long nic_base = dev->base_addr; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* This *shouldn't* happen. If it does, it's the last thing you'll see 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci if (ei_status.dmaing) { 50962306a36Sopenharmony_ci netdev_err(dev, "DMAing conflict in %s [DMAstat:%d][irqlock:%d].\n", 51062306a36Sopenharmony_ci __func__, ei_status.dmaing, ei_status.irqlock); 51162306a36Sopenharmony_ci return; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci ei_status.dmaing |= 0x01; 51562306a36Sopenharmony_ci outb(E8390_NODMA + E8390_PAGE0 + E8390_START, nic_base + NE_CMD); 51662306a36Sopenharmony_ci outb(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); 51762306a36Sopenharmony_ci outb(0, nic_base + EN0_RCNTHI); 51862306a36Sopenharmony_ci outb(0, nic_base + EN0_RSARLO); /* On page boundary */ 51962306a36Sopenharmony_ci outb(ring_page, nic_base + EN0_RSARHI); 52062306a36Sopenharmony_ci outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (ei_status.ne2k_flags & ONLY_16BIT_IO) { 52362306a36Sopenharmony_ci insw(NE_BASE + NE_DATAPORT, hdr, 52462306a36Sopenharmony_ci sizeof(struct e8390_pkt_hdr) >> 1); 52562306a36Sopenharmony_ci } else { 52662306a36Sopenharmony_ci *(u32 *)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT)); 52762306a36Sopenharmony_ci le16_to_cpus(&hdr->count); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci /* Ack intr. */ 53062306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + EN0_ISR); 53162306a36Sopenharmony_ci ei_status.dmaing &= ~0x01; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/* Block input and output, similar to the Crynwr packet driver. If you 53562306a36Sopenharmony_ci *are porting to a new ethercard, look at the packet driver source for hints. 53662306a36Sopenharmony_ci *The NEx000 doesn't share the on-board packet memory -- you have to put 53762306a36Sopenharmony_ci *the packet out through the "remote DMA" dataport using outb. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void ne2k_pci_block_input(struct net_device *dev, int count, 54162306a36Sopenharmony_ci struct sk_buff *skb, int ring_offset) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci long nic_base = dev->base_addr; 54462306a36Sopenharmony_ci char *buf = skb->data; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* This *shouldn't* happen. 54762306a36Sopenharmony_ci * If it does, it's the last thing you'll see. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ci if (ei_status.dmaing) { 55062306a36Sopenharmony_ci netdev_err(dev, "DMAing conflict in %s [DMAstat:%d][irqlock:%d]\n", 55162306a36Sopenharmony_ci __func__, ei_status.dmaing, ei_status.irqlock); 55262306a36Sopenharmony_ci return; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci ei_status.dmaing |= 0x01; 55562306a36Sopenharmony_ci if (ei_status.ne2k_flags & ONLY_32BIT_IO) 55662306a36Sopenharmony_ci count = (count + 3) & 0xFFFC; 55762306a36Sopenharmony_ci outb(E8390_NODMA + E8390_PAGE0 + E8390_START, nic_base + NE_CMD); 55862306a36Sopenharmony_ci outb(count & 0xff, nic_base + EN0_RCNTLO); 55962306a36Sopenharmony_ci outb(count >> 8, nic_base + EN0_RCNTHI); 56062306a36Sopenharmony_ci outb(ring_offset & 0xff, nic_base + EN0_RSARLO); 56162306a36Sopenharmony_ci outb(ring_offset >> 8, nic_base + EN0_RSARHI); 56262306a36Sopenharmony_ci outb(E8390_RREAD + E8390_START, nic_base + NE_CMD); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (ei_status.ne2k_flags & ONLY_16BIT_IO) { 56562306a36Sopenharmony_ci insw(NE_BASE + NE_DATAPORT, buf, count >> 1); 56662306a36Sopenharmony_ci if (count & 0x01) 56762306a36Sopenharmony_ci buf[count-1] = inb(NE_BASE + NE_DATAPORT); 56862306a36Sopenharmony_ci } else { 56962306a36Sopenharmony_ci insl(NE_BASE + NE_DATAPORT, buf, count >> 2); 57062306a36Sopenharmony_ci if (count & 3) { 57162306a36Sopenharmony_ci buf += count & ~3; 57262306a36Sopenharmony_ci if (count & 2) { 57362306a36Sopenharmony_ci __le16 *b = (__le16 *)buf; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci *b++ = cpu_to_le16(inw(NE_BASE + NE_DATAPORT)); 57662306a36Sopenharmony_ci buf = (char *)b; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci if (count & 1) 57962306a36Sopenharmony_ci *buf = inb(NE_BASE + NE_DATAPORT); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci /* Ack intr. */ 58362306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + EN0_ISR); 58462306a36Sopenharmony_ci ei_status.dmaing &= ~0x01; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void ne2k_pci_block_output(struct net_device *dev, int count, 58862306a36Sopenharmony_ci const unsigned char *buf, const int start_page) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci long nic_base = NE_BASE; 59162306a36Sopenharmony_ci unsigned long dma_start; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* On little-endian it's always safe to round the count up for 59462306a36Sopenharmony_ci * word writes. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci if (ei_status.ne2k_flags & ONLY_32BIT_IO) 59762306a36Sopenharmony_ci count = (count + 3) & 0xFFFC; 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci if (count & 0x01) 60062306a36Sopenharmony_ci count++; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* This *shouldn't* happen. 60362306a36Sopenharmony_ci * If it does, it's the last thing you'll see. 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci if (ei_status.dmaing) { 60662306a36Sopenharmony_ci netdev_err(dev, "DMAing conflict in %s [DMAstat:%d][irqlock:%d]\n", 60762306a36Sopenharmony_ci __func__, ei_status.dmaing, ei_status.irqlock); 60862306a36Sopenharmony_ci return; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci ei_status.dmaing |= 0x01; 61162306a36Sopenharmony_ci /* We should already be in page 0, but to be safe... */ 61262306a36Sopenharmony_ci outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci#ifdef NE_RW_BUGFIX 61562306a36Sopenharmony_ci /* Handle the read-before-write bug the same way as the 61662306a36Sopenharmony_ci * Crynwr packet driver -- the NatSemi method doesn't work. 61762306a36Sopenharmony_ci * Actually this doesn't always work either, but if you have 61862306a36Sopenharmony_ci * problems with your NEx000 this is better than nothing! 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci outb(0x42, nic_base + EN0_RCNTLO); 62162306a36Sopenharmony_ci outb(0x00, nic_base + EN0_RCNTHI); 62262306a36Sopenharmony_ci outb(0x42, nic_base + EN0_RSARLO); 62362306a36Sopenharmony_ci outb(0x00, nic_base + EN0_RSARHI); 62462306a36Sopenharmony_ci outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); 62562306a36Sopenharmony_ci#endif 62662306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + EN0_ISR); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* Now the normal output. */ 62962306a36Sopenharmony_ci outb(count & 0xff, nic_base + EN0_RCNTLO); 63062306a36Sopenharmony_ci outb(count >> 8, nic_base + EN0_RCNTHI); 63162306a36Sopenharmony_ci outb(0x00, nic_base + EN0_RSARLO); 63262306a36Sopenharmony_ci outb(start_page, nic_base + EN0_RSARHI); 63362306a36Sopenharmony_ci outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); 63462306a36Sopenharmony_ci if (ei_status.ne2k_flags & ONLY_16BIT_IO) { 63562306a36Sopenharmony_ci outsw(NE_BASE + NE_DATAPORT, buf, count >> 1); 63662306a36Sopenharmony_ci } else { 63762306a36Sopenharmony_ci outsl(NE_BASE + NE_DATAPORT, buf, count >> 2); 63862306a36Sopenharmony_ci if (count & 3) { 63962306a36Sopenharmony_ci buf += count & ~3; 64062306a36Sopenharmony_ci if (count & 2) { 64162306a36Sopenharmony_ci __le16 *b = (__le16 *)buf; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci outw(le16_to_cpu(*b++), NE_BASE + NE_DATAPORT); 64462306a36Sopenharmony_ci buf = (char *)b; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci dma_start = jiffies; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) 65262306a36Sopenharmony_ci /* Avoid clock roll-over. */ 65362306a36Sopenharmony_ci if (jiffies - dma_start > 2) { 65462306a36Sopenharmony_ci netdev_warn(dev, "timeout waiting for Tx RDC.\n"); 65562306a36Sopenharmony_ci ne2k_pci_reset_8390(dev); 65662306a36Sopenharmony_ci NS8390_init(dev, 1); 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci /* Ack intr. */ 66062306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + EN0_ISR); 66162306a36Sopenharmony_ci ei_status.dmaing &= ~0x01; 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic void ne2k_pci_get_drvinfo(struct net_device *dev, 66562306a36Sopenharmony_ci struct ethtool_drvinfo *info) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct ei_device *ei = netdev_priv(dev); 66862306a36Sopenharmony_ci struct pci_dev *pci_dev = (struct pci_dev *) ei->priv; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 67162306a36Sopenharmony_ci strscpy(info->version, DRV_VERSION, sizeof(info->version)); 67262306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info)); 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic u32 ne2k_pci_get_msglevel(struct net_device *dev) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct ei_device *ei_local = netdev_priv(dev); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return ei_local->msg_enable; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void ne2k_pci_set_msglevel(struct net_device *dev, u32 v) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct ei_device *ei_local = netdev_priv(dev); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci ei_local->msg_enable = v; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic const struct ethtool_ops ne2k_pci_ethtool_ops = { 69062306a36Sopenharmony_ci .get_drvinfo = ne2k_pci_get_drvinfo, 69162306a36Sopenharmony_ci .get_msglevel = ne2k_pci_get_msglevel, 69262306a36Sopenharmony_ci .set_msglevel = ne2k_pci_set_msglevel, 69362306a36Sopenharmony_ci}; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic void ne2k_pci_remove_one(struct pci_dev *pdev) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci BUG_ON(!dev); 70062306a36Sopenharmony_ci unregister_netdev(dev); 70162306a36Sopenharmony_ci release_region(dev->base_addr, NE_IO_EXTENT); 70262306a36Sopenharmony_ci free_netdev(dev); 70362306a36Sopenharmony_ci pci_disable_device(pdev); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int __maybe_unused ne2k_pci_suspend(struct device *dev_d) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct net_device *dev = dev_get_drvdata(dev_d); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci netif_device_detach(dev); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int __maybe_unused ne2k_pci_resume(struct device *dev_d) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct net_device *dev = dev_get_drvdata(dev_d); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci NS8390_init(dev, 1); 72062306a36Sopenharmony_ci netif_device_attach(dev); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ne2k_pci_pm_ops, ne2k_pci_suspend, ne2k_pci_resume); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic struct pci_driver ne2k_driver = { 72862306a36Sopenharmony_ci .name = DRV_NAME, 72962306a36Sopenharmony_ci .probe = ne2k_pci_init_one, 73062306a36Sopenharmony_ci .remove = ne2k_pci_remove_one, 73162306a36Sopenharmony_ci .id_table = ne2k_pci_tbl, 73262306a36Sopenharmony_ci .driver.pm = &ne2k_pci_pm_ops, 73362306a36Sopenharmony_ci}; 73462306a36Sopenharmony_cimodule_pci_driver(ne2k_driver); 735