📄 hp100.c
字号:
/*** hp100.c ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters**** $Id: hp100.c,v 1.58 2001/09/24 18:03:01 perex Exp perex $**** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>** Extended for new busmaster capable chipsets by ** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>**** Maintained by: Jaroslav Kysela <perex@suse.cz>** ** This driver has only been tested with** -- HP J2585B 10/100 Mbit/s PCI Busmaster** -- HP J2585A 10/100 Mbit/s PCI ** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC** -- HP J2973 10 Mbit/s PCI 10base-T** -- HP J2573 10/100 ISA** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI** ** but it should also work with the other CASCADE based adapters.**** TODO:** - J2573 seems to hang sometimes when in shared memory mode.** - Mode for Priority TX** - Check PCI registers, performance might be improved?** - To reduce interrupt load in busmaster, one could switch off** the interrupts that are used to refill the queues whenever the** queues are filled up to more than a certain threshold.** - some updates for EISA version of card****** This code 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.**** This code 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.**** 1.57c -> 1.58** - used indent to change coding-style** - added KTI DP-200 EISA ID** - ioremap is also used for low (<1MB) memory (multi-architecture support)**** 1.57b -> 1.57c - Arnaldo Carvalho de Melo <acme@conectiva.com.br>** - release resources on failure in init_module**** 1.57 -> 1.57b - Jean II** - fix spinlocks, SMP is now working !**** 1.56 -> 1.57** - updates for new PCI interface for 2.1 kernels**** 1.55 -> 1.56** - removed printk in misc. interrupt and update statistics to allow** monitoring of card status** - timing changes in xmit routines, relogin to 100VG hub added when** driver does reset** - included fix for Compex FreedomLine PCI adapter** ** 1.54 -> 1.55** - fixed bad initialization in init_module** - added Compex FreedomLine adapter** - some fixes in card initialization**** 1.53 -> 1.54** - added hardware multicast filter support (doesn't work)** - little changes in hp100_sense_lan routine ** - added support for Coax and AUI (J2970)** - fix for multiple cards and hp100_mode parameter (insmod)** - fix for shared IRQ **** 1.52 -> 1.53** - fixed bug in multicast support***/#define HP100_DEFAULT_PRIORITY_TX 0#undef HP100_DEBUG#undef HP100_DEBUG_B /* Trace */#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */#undef HP100_DEBUG_TX#undef HP100_DEBUG_IRQ#undef HP100_DEBUG_RX#undef HP100_MULTICAST_FILTER /* Need to be debugged... */#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <asm/bitops.h>#include <asm/io.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/types.h>#include <linux/config.h> /* for CONFIG_PCI */#include <linux/delay.h>#include <linux/init.h>#define LINUX_2_1typedef struct net_device_stats hp100_stats_t;EXPORT_NO_SYMBOLS;#include "hp100.h"/* * defines */#define HP100_BUS_ISA 0#define HP100_BUS_EISA 1#define HP100_BUS_PCI 2#ifndef PCI_DEVICE_ID_HP_J2585B#define PCI_DEVICE_ID_HP_J2585B 0x1031#endif#ifndef PCI_VENDOR_ID_COMPEX#define PCI_VENDOR_ID_COMPEX 0x11f6#endif#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112#endif#ifndef PCI_VENDOR_ID_COMPEX2#define PCI_VENDOR_ID_COMPEX2 0x101a#endif#ifndef PCI_DEVICE_ID_COMPEX2_100VG#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005#endif#define HP100_REGION_SIZE 0x20 /* for ioports */#define HP100_MAX_PACKET_SIZE (1536+4)#define HP100_MIN_PACKET_SIZE 60#ifndef HP100_DEFAULT_RX_RATIO/* default - 75% onboard memory on the card are used for RX packets */#define HP100_DEFAULT_RX_RATIO 75#endif#ifndef HP100_DEFAULT_PRIORITY_TX/* default - don't enable transmit outgoing packets as priority */#define HP100_DEFAULT_PRIORITY_TX 0#endif/* * structures */struct hp100_eisa_id { u_int id; const char *name; u_char bus;};struct hp100_pci_id { u_short vendor; u_short device;};struct hp100_private { struct hp100_eisa_id *id; spinlock_t lock; u_short chip; u_short soft_model; u_int memory_size; u_int virt_memory_size; u_short rx_ratio; /* 1 - 99 */ u_short priority_tx; /* != 0 - priority tx */ u_short mode; /* PIO, Shared Mem or Busmaster */ u_char bus; struct pci_dev *pci_dev; short mem_mapped; /* memory mapped access */ void *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ unsigned long mem_ptr_phys; /* physical memory mapped area */ short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ int hub_status; /* was login to hub successful? */ u_char mac1_mode; u_char mac2_mode; u_char hash_bytes[8]; hp100_stats_t stats; /* Rings for busmaster mode: */ hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ hp100_ring_t *txrhead; /* Head (oldest) index into txring */ hp100_ring_t *txrtail; /* Tail (newest) index into txring */ hp100_ring_t rxring[MAX_RX_PDL]; hp100_ring_t txring[MAX_TX_PDL]; u_int *page_vaddr; /* Virtual address of allocated page */ u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ int rxrcommit; /* # Rx PDLs commited to adapter */ int txrcommit; /* # Tx PDLs commited to adapter */};/* * variables */static struct hp100_eisa_id hp100_eisa_ids[] = { /* 10/100 EISA card with revision A Cascade chip */ {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA}, /* 10/100 ISA card with revision A Cascade chip */ {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA}, /* 10 only EISA card with Cascade chip */ {0x2019F022, "HP 27248B", HP100_BUS_EISA}, /* 10/100 EISA card with Cascade chip */ {0x4019F022, "HP J2577", HP100_BUS_EISA}, /* 10/100 ISA card with Cascade chip */ {0x5019F022, "HP J2573", HP100_BUS_ISA}, /* 10/100 PCI card - old J2585A */ {0x1030103c, "HP J2585A", HP100_BUS_PCI}, /* 10/100 PCI card - new J2585B - master capable */ {0x1041103c, "HP J2585B", HP100_BUS_PCI}, /* 10 Mbit Combo Adapter */ {0x1042103c, "HP J2970", HP100_BUS_PCI}, /* 10 Mbit 10baseT Adapter */ {0x1040103c, "HP J2973", HP100_BUS_PCI}, /* 10/100 EISA card from Compex */ {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA}, /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */ /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */ /* version of adapter, too... */ {0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA}, /* 10/100 PCI card from Compex - FreedomLine * * I think this card doesn't like aic7178 scsi controller, but * I haven't tested this much. It works fine on diskless machines. * Jacek Lipkowski <sq5bpf@acid.ch.pw.edu.pl> */ {0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI}, /* 10/100 PCI card from Compex (J2585A compatible) */ {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI}, /* 10/100 PCI card from KTI */ {0x40008e2e, "KTI DP-200", HP100_BUS_PCI }};#define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id))#ifdef CONFIG_PCIstatic struct hp100_pci_id hp100_pci_ids[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B}, {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4}, {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG}};#endif#define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id))#if LINUX_VERSION_CODE >= 0x20400static struct pci_device_id hp100_pci_tbl[] __initdata = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID,}, {} /* Terminating entry */};MODULE_DEVICE_TABLE(pci, hp100_pci_tbl);#endif /* LINUX_VERSION_CODE >= 0x20400 */static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;static int hp100_mode = 1;MODULE_PARM(hp100_rx_ratio, "1i");MODULE_PARM(hp100_priority_tx, "1i");MODULE_PARM(hp100_mode, "1i");/* * prototypes */static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev);static int hp100_open(struct net_device *dev);static int hp100_close(struct net_device *dev);static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev);static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev);static void hp100_rx(struct net_device *dev);static hp100_stats_t *hp100_get_stats(struct net_device *dev);static void hp100_misc_interrupt(struct net_device *dev);static void hp100_update_stats(struct net_device *dev);static void hp100_clear_stats(struct hp100_private *lp, int ioaddr);static void hp100_set_multicast_list(struct net_device *dev);static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void hp100_start_interface(struct net_device *dev);static void hp100_stop_interface(struct net_device *dev);static void hp100_load_eeprom(struct net_device *dev, u_short ioaddr);static int hp100_sense_lan(struct net_device *dev);static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin);static int hp100_down_vg_link(struct net_device *dev);static void hp100_cascade_reset(struct net_device *dev, u_short enable);static void hp100_BM_shutdown(struct net_device *dev);static void hp100_mmuinit(struct net_device *dev);static void hp100_init_pdls(struct net_device *dev);static int hp100_init_rxpdl(struct net_device *dev, register hp100_ring_t * ringptr, register u_int * pdlptr);static int hp100_init_txpdl(struct net_device *dev, register hp100_ring_t * ringptr, register u_int * pdlptr);static void hp100_rxfill(struct net_device *dev);static void hp100_hwinit(struct net_device *dev);static void hp100_clean_txring(struct net_device *dev);#ifdef HP100_DEBUGstatic void hp100_RegisterDump(struct net_device *dev);#endif/* TODO: This function should not really be needed in a good design... */static void wait(void){ mdelay(1);}/* * probe functions * These functions should - if possible - avoid doing write operations * since this could cause problems when the card is not installed. */int __init hp100_probe(struct net_device *dev){ int base_addr = dev ? dev->base_addr : 0; int ioaddr = 0;#ifdef CONFIG_PCI int pci_start_index = 0;#endif#ifdef HP100_DEBUG_B hp100_outw(0x4200, TRACE); printk("hp100: %s: probe\n", dev->name);#endif if (base_addr > 0xff) { /* Check a single specified location. */ if (check_region(base_addr, HP100_REGION_SIZE)) return -EINVAL; if (base_addr < 0x400) return hp100_probe1(dev, base_addr, HP100_BUS_ISA, NULL); if (EISA_bus && base_addr >= 0x1c38 && ((base_addr - 0x1c38) & 0x3ff) == 0) return hp100_probe1(dev, base_addr, HP100_BUS_EISA, NULL);#ifdef CONFIG_PCI printk("hp100: %s: You must specify card # in i/o address parameter for PCI bus...", dev->name);#else return -ENODEV;#endif } else#ifdef CONFIG_PCI if (base_addr > 0 && base_addr < 8 + 1) pci_start_index = 0x100 | (base_addr - 1); else#endif if (base_addr != 0) return -ENXIO; /* First: scan PCI bus(es) */#ifdef CONFIG_PCI if (pcibios_present()) { int pci_index; struct pci_dev *pci_dev = NULL; int pci_id_index; u_short pci_command;#ifdef HP100_DEBUG_PCI printk("hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name);#endif pci_index = 0; for (pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++) { while ((pci_dev = pci_find_device(hp100_pci_ids[pci_id_index].vendor, hp100_pci_ids[pci_id_index].device, pci_dev)) != NULL) { if (pci_index < (pci_start_index & 7)) { pci_index++; continue; } if (pci_enable_device(pci_dev)) continue; /* found... */ ioaddr = pci_resource_start(pci_dev, 0); if (check_region(ioaddr, HP100_REGION_SIZE)) continue; pci_read_config_word(pci_dev, PCI_COMMAND, &pci_command); if (!(pci_command & PCI_COMMAND_IO)) {#ifdef HP100_DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -