162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright 1997 Alain Malek 662306a36Sopenharmony_ci * (Alain.Malek@cryogen.com) 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * ---------------------------------------------------------------------------- 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is based on 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * ne.c: A general non-shared-memory NS8390 ethernet driver for linux 1362306a36Sopenharmony_ci * Written 1992-94 by Donald Becker. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * 8390.c: A general NS8390 ethernet driver core for linux. 1662306a36Sopenharmony_ci * Written 1992-94 by Donald Becker. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * cnetdevice: A Sana-II ethernet driver for AmigaOS 1962306a36Sopenharmony_ci * Written by Bruce Abbott (bhabbott@inhb.co.nz) 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * ---------------------------------------------------------------------------- 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/module.h> 2762306a36Sopenharmony_ci#include <linux/kernel.h> 2862306a36Sopenharmony_ci#include <linux/errno.h> 2962306a36Sopenharmony_ci#include <linux/pci.h> 3062306a36Sopenharmony_ci#include <linux/init.h> 3162306a36Sopenharmony_ci#include <linux/delay.h> 3262306a36Sopenharmony_ci#include <linux/netdevice.h> 3362306a36Sopenharmony_ci#include <linux/etherdevice.h> 3462306a36Sopenharmony_ci#include <linux/interrupt.h> 3562306a36Sopenharmony_ci#include <linux/jiffies.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <asm/io.h> 3862306a36Sopenharmony_ci#include <asm/setup.h> 3962306a36Sopenharmony_ci#include <asm/amigaints.h> 4062306a36Sopenharmony_ci#include <asm/amigahw.h> 4162306a36Sopenharmony_ci#include <asm/amigayle.h> 4262306a36Sopenharmony_ci#include <asm/amipcmcia.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include "8390.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* ---- No user-serviceable parts below ---- */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define DRV_NAME "apne" 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define NE_BASE (dev->base_addr) 5162306a36Sopenharmony_ci#define NE_CMD 0x00 5262306a36Sopenharmony_ci#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */ 5362306a36Sopenharmony_ci#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */ 5462306a36Sopenharmony_ci#define NE_IO_EXTENT 0x20 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define NE_EN0_ISR 0x07 5762306a36Sopenharmony_ci#define NE_EN0_DCFG 0x0e 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define NE_EN0_RSARLO 0x08 6062306a36Sopenharmony_ci#define NE_EN0_RSARHI 0x09 6162306a36Sopenharmony_ci#define NE_EN0_RCNTLO 0x0a 6262306a36Sopenharmony_ci#define NE_EN0_RXCR 0x0c 6362306a36Sopenharmony_ci#define NE_EN0_TXCR 0x0d 6462306a36Sopenharmony_ci#define NE_EN0_RCNTHI 0x0b 6562306a36Sopenharmony_ci#define NE_EN0_IMR 0x0f 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define NE1SM_START_PG 0x20 /* First page of TX buffer */ 6862306a36Sopenharmony_ci#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ 6962306a36Sopenharmony_ci#define NESM_START_PG 0x40 /* First page of TX buffer */ 7062306a36Sopenharmony_ci#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int apne_probe1(struct net_device *dev, int ioaddr); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void apne_reset_8390(struct net_device *dev); 7662306a36Sopenharmony_cistatic void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, 7762306a36Sopenharmony_ci int ring_page); 7862306a36Sopenharmony_cistatic void apne_block_input(struct net_device *dev, int count, 7962306a36Sopenharmony_ci struct sk_buff *skb, int ring_offset); 8062306a36Sopenharmony_cistatic void apne_block_output(struct net_device *dev, const int count, 8162306a36Sopenharmony_ci const unsigned char *buf, const int start_page); 8262306a36Sopenharmony_cistatic irqreturn_t apne_interrupt(int irq, void *dev_id); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int init_pcmcia(void); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* IO base address used for nic */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define IOBASE 0x300 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand 9262306a36Sopenharmony_ci you can find the values to use by looking at the cnet.device 9362306a36Sopenharmony_ci config file example (the default values are for the CNET40BC card) 9462306a36Sopenharmony_ci*/ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci#define MANUAL_CONFIG 0x20 9862306a36Sopenharmony_ci#define MANUAL_OFFSET 0x3f8 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define MANUAL_HWADDR0 0x00 10162306a36Sopenharmony_ci#define MANUAL_HWADDR1 0x12 10262306a36Sopenharmony_ci#define MANUAL_HWADDR2 0x34 10362306a36Sopenharmony_ci#define MANUAL_HWADDR3 0x56 10462306a36Sopenharmony_ci#define MANUAL_HWADDR4 0x78 10562306a36Sopenharmony_ci#define MANUAL_HWADDR5 0x9a 10662306a36Sopenharmony_ci*/ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic const char version[] = 10962306a36Sopenharmony_ci "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n"; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int apne_owned; /* signal if card already owned */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic u32 apne_msg_enable; 11462306a36Sopenharmony_cimodule_param_named(msg_enable, apne_msg_enable, uint, 0444); 11562306a36Sopenharmony_ciMODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)"); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic struct net_device * __init apne_probe(void) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct net_device *dev; 12062306a36Sopenharmony_ci struct ei_device *ei_local; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#ifndef MANUAL_CONFIG 12362306a36Sopenharmony_ci char tuple[8]; 12462306a36Sopenharmony_ci#endif 12562306a36Sopenharmony_ci int err; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (!MACH_IS_AMIGA) 12862306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (apne_owned) 13162306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if ( !(AMIGAHW_PRESENT(PCMCIA)) ) 13462306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci pr_info("Looking for PCMCIA ethernet card : "); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* check if a card is inserted */ 13962306a36Sopenharmony_ci if (!(PCMCIA_INSERTED)) { 14062306a36Sopenharmony_ci pr_cont("NO PCMCIA card inserted\n"); 14162306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci dev = alloc_ei_netdev(); 14562306a36Sopenharmony_ci if (!dev) 14662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 14762306a36Sopenharmony_ci ei_local = netdev_priv(dev); 14862306a36Sopenharmony_ci ei_local->msg_enable = apne_msg_enable; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* disable pcmcia irq for readtuple */ 15162306a36Sopenharmony_ci pcmcia_disable_irq(); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#ifndef MANUAL_CONFIG 15462306a36Sopenharmony_ci if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) || 15562306a36Sopenharmony_ci (tuple[2] != CISTPL_FUNCID_NETWORK)) { 15662306a36Sopenharmony_ci pr_cont("not an ethernet card\n"); 15762306a36Sopenharmony_ci /* XXX: shouldn't we re-enable irq here? */ 15862306a36Sopenharmony_ci free_netdev(dev); 15962306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci#endif 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci pr_cont("ethernet PCMCIA card inserted\n"); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!init_pcmcia()) { 16662306a36Sopenharmony_ci /* XXX: shouldn't we re-enable irq here? */ 16762306a36Sopenharmony_ci free_netdev(dev); 16862306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!request_region(IOBASE, 0x20, DRV_NAME)) { 17262306a36Sopenharmony_ci free_netdev(dev); 17362306a36Sopenharmony_ci return ERR_PTR(-EBUSY); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci err = apne_probe1(dev, IOBASE); 17762306a36Sopenharmony_ci if (err) { 17862306a36Sopenharmony_ci release_region(IOBASE, 0x20); 17962306a36Sopenharmony_ci free_netdev(dev); 18062306a36Sopenharmony_ci return ERR_PTR(err); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci err = register_netdev(dev); 18362306a36Sopenharmony_ci if (!err) 18462306a36Sopenharmony_ci return dev; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci pcmcia_disable_irq(); 18762306a36Sopenharmony_ci free_irq(IRQ_AMIGA_PORTS, dev); 18862306a36Sopenharmony_ci pcmcia_reset(); 18962306a36Sopenharmony_ci release_region(IOBASE, 0x20); 19062306a36Sopenharmony_ci free_netdev(dev); 19162306a36Sopenharmony_ci return ERR_PTR(err); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int __init apne_probe1(struct net_device *dev, int ioaddr) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int i; 19762306a36Sopenharmony_ci unsigned char SA_prom[32]; 19862306a36Sopenharmony_ci int wordlength = 2; 19962306a36Sopenharmony_ci const char *name = NULL; 20062306a36Sopenharmony_ci int start_page, stop_page; 20162306a36Sopenharmony_ci#ifndef MANUAL_HWADDR0 20262306a36Sopenharmony_ci int neX000, ctron; 20362306a36Sopenharmony_ci#endif 20462306a36Sopenharmony_ci static unsigned version_printed; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) 20762306a36Sopenharmony_ci netdev_info(dev, version); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci netdev_info(dev, "PCMCIA NE*000 ethercard probe"); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Reset card. Who knows what dain-bramaged state it was left in. */ 21262306a36Sopenharmony_ci { unsigned long reset_start_time = jiffies; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) 21762306a36Sopenharmony_ci if (time_after(jiffies, reset_start_time + 2*HZ/100)) { 21862306a36Sopenharmony_ci pr_cont(" not found (no reset ack).\n"); 21962306a36Sopenharmony_ci return -ENODEV; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci outb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */ 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci#ifndef MANUAL_HWADDR0 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Read the 16 bytes of station address PROM. 22862306a36Sopenharmony_ci We must first initialize registers, similar to NS8390_init(eifdev, 0). 22962306a36Sopenharmony_ci We can't reliably read the SAPROM address without this. 23062306a36Sopenharmony_ci (I learned the hard way!). */ 23162306a36Sopenharmony_ci { 23262306a36Sopenharmony_ci struct {unsigned long value, offset; } program_seq[] = { 23362306a36Sopenharmony_ci {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/ 23462306a36Sopenharmony_ci {0x48, NE_EN0_DCFG}, /* Set byte-wide (0x48) access. */ 23562306a36Sopenharmony_ci {0x00, NE_EN0_RCNTLO}, /* Clear the count regs. */ 23662306a36Sopenharmony_ci {0x00, NE_EN0_RCNTHI}, 23762306a36Sopenharmony_ci {0x00, NE_EN0_IMR}, /* Mask completion irq. */ 23862306a36Sopenharmony_ci {0xFF, NE_EN0_ISR}, 23962306a36Sopenharmony_ci {E8390_RXOFF, NE_EN0_RXCR}, /* 0x20 Set to monitor */ 24062306a36Sopenharmony_ci {E8390_TXOFF, NE_EN0_TXCR}, /* 0x02 and loopback mode. */ 24162306a36Sopenharmony_ci {32, NE_EN0_RCNTLO}, 24262306a36Sopenharmony_ci {0x00, NE_EN0_RCNTHI}, 24362306a36Sopenharmony_ci {0x00, NE_EN0_RSARLO}, /* DMA starting at 0x0000. */ 24462306a36Sopenharmony_ci {0x00, NE_EN0_RSARHI}, 24562306a36Sopenharmony_ci {E8390_RREAD+E8390_START, NE_CMD}, 24662306a36Sopenharmony_ci }; 24762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(program_seq); i++) { 24862306a36Sopenharmony_ci outb(program_seq[i].value, ioaddr + program_seq[i].offset); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { 25362306a36Sopenharmony_ci SA_prom[i] = inb(ioaddr + NE_DATAPORT); 25462306a36Sopenharmony_ci SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); 25562306a36Sopenharmony_ci if (SA_prom[i] != SA_prom[i+1]) 25662306a36Sopenharmony_ci wordlength = 1; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* At this point, wordlength *only* tells us if the SA_prom is doubled 26062306a36Sopenharmony_ci up or not because some broken PCI cards don't respect the byte-wide 26162306a36Sopenharmony_ci request in program_seq above, and hence don't have doubled up values. 26262306a36Sopenharmony_ci These broken cards would otherwise be detected as an ne1000. */ 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (wordlength == 2) 26562306a36Sopenharmony_ci for (i = 0; i < 16; i++) 26662306a36Sopenharmony_ci SA_prom[i] = SA_prom[i+i]; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (wordlength == 2) { 26962306a36Sopenharmony_ci /* We must set the 8390 for word mode. */ 27062306a36Sopenharmony_ci outb(0x49, ioaddr + NE_EN0_DCFG); 27162306a36Sopenharmony_ci start_page = NESM_START_PG; 27262306a36Sopenharmony_ci stop_page = NESM_STOP_PG; 27362306a36Sopenharmony_ci } else { 27462306a36Sopenharmony_ci start_page = NE1SM_START_PG; 27562306a36Sopenharmony_ci stop_page = NE1SM_STOP_PG; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); 27962306a36Sopenharmony_ci ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Set up the rest of the parameters. */ 28262306a36Sopenharmony_ci if (neX000) { 28362306a36Sopenharmony_ci name = (wordlength == 2) ? "NE2000" : "NE1000"; 28462306a36Sopenharmony_ci } else if (ctron) { 28562306a36Sopenharmony_ci name = (wordlength == 2) ? "Ctron-8" : "Ctron-16"; 28662306a36Sopenharmony_ci start_page = 0x01; 28762306a36Sopenharmony_ci stop_page = (wordlength == 2) ? 0x40 : 0x20; 28862306a36Sopenharmony_ci } else { 28962306a36Sopenharmony_ci pr_cont(" not found.\n"); 29062306a36Sopenharmony_ci return -ENXIO; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci#else 29562306a36Sopenharmony_ci wordlength = 2; 29662306a36Sopenharmony_ci /* We must set the 8390 for word mode. */ 29762306a36Sopenharmony_ci outb(0x49, ioaddr + NE_EN0_DCFG); 29862306a36Sopenharmony_ci start_page = NESM_START_PG; 29962306a36Sopenharmony_ci stop_page = NESM_STOP_PG; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci SA_prom[0] = MANUAL_HWADDR0; 30262306a36Sopenharmony_ci SA_prom[1] = MANUAL_HWADDR1; 30362306a36Sopenharmony_ci SA_prom[2] = MANUAL_HWADDR2; 30462306a36Sopenharmony_ci SA_prom[3] = MANUAL_HWADDR3; 30562306a36Sopenharmony_ci SA_prom[4] = MANUAL_HWADDR4; 30662306a36Sopenharmony_ci SA_prom[5] = MANUAL_HWADDR5; 30762306a36Sopenharmony_ci name = "NE2000"; 30862306a36Sopenharmony_ci#endif 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci dev->base_addr = ioaddr; 31162306a36Sopenharmony_ci dev->irq = IRQ_AMIGA_PORTS; 31262306a36Sopenharmony_ci dev->netdev_ops = &ei_netdev_ops; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Install the Interrupt handler */ 31562306a36Sopenharmony_ci i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev); 31662306a36Sopenharmony_ci if (i) return i; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci eth_hw_addr_set(dev, SA_prom); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci pr_cont(" %pM\n", dev->dev_addr); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci netdev_info(dev, "%s found.\n", name); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ei_status.name = name; 32562306a36Sopenharmony_ci ei_status.tx_start_page = start_page; 32662306a36Sopenharmony_ci ei_status.stop_page = stop_page; 32762306a36Sopenharmony_ci ei_status.word16 = (wordlength == 2); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ei_status.rx_start_page = start_page + TX_PAGES; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ei_status.reset_8390 = &apne_reset_8390; 33262306a36Sopenharmony_ci ei_status.block_input = &apne_block_input; 33362306a36Sopenharmony_ci ei_status.block_output = &apne_block_output; 33462306a36Sopenharmony_ci ei_status.get_8390_hdr = &apne_get_8390_hdr; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci NS8390_init(dev, 0); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ 33962306a36Sopenharmony_ci pcmcia_enable_irq(); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci apne_owned = 1; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* Hard reset the card. This used to pause for the same period that a 34762306a36Sopenharmony_ci 8390 reset command required, but that shouldn't be necessary. */ 34862306a36Sopenharmony_cistatic void 34962306a36Sopenharmony_ciapne_reset_8390(struct net_device *dev) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci unsigned long reset_start_time = jiffies; 35262306a36Sopenharmony_ci struct ei_device *ei_local = netdev_priv(dev); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci init_pcmcia(); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ei_status.txing = 0; 36162306a36Sopenharmony_ci ei_status.dmaing = 0; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* This check _should_not_ be necessary, omit eventually. */ 36462306a36Sopenharmony_ci while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) 36562306a36Sopenharmony_ci if (time_after(jiffies, reset_start_time + 2*HZ/100)) { 36662306a36Sopenharmony_ci netdev_err(dev, "ne_reset_8390() did not complete.\n"); 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci outb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/* Grab the 8390 specific header. Similar to the block_input routine, but 37362306a36Sopenharmony_ci we don't need to be concerned with ring wrap as the header will be at 37462306a36Sopenharmony_ci the start of a page, so we optimize accordingly. */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void 37762306a36Sopenharmony_ciapne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci int nic_base = dev->base_addr; 38162306a36Sopenharmony_ci int cnt; 38262306a36Sopenharmony_ci char *ptrc; 38362306a36Sopenharmony_ci short *ptrs; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* This *shouldn't* happen. If it does, it's the last thing you'll see */ 38662306a36Sopenharmony_ci if (ei_status.dmaing) { 38762306a36Sopenharmony_ci netdev_err(dev, "DMAing conflict in ne_get_8390_hdr " 38862306a36Sopenharmony_ci "[DMAstat:%d][irqlock:%d][intr:%d].\n", 38962306a36Sopenharmony_ci ei_status.dmaing, ei_status.irqlock, dev->irq); 39062306a36Sopenharmony_ci return; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci ei_status.dmaing |= 0x01; 39462306a36Sopenharmony_ci outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); 39562306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + NE_EN0_ISR); 39662306a36Sopenharmony_ci outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO); 39762306a36Sopenharmony_ci outb(0, nic_base + NE_EN0_RCNTHI); 39862306a36Sopenharmony_ci outb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */ 39962306a36Sopenharmony_ci outb(ring_page, nic_base + NE_EN0_RSARHI); 40062306a36Sopenharmony_ci outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (ei_status.word16) { 40362306a36Sopenharmony_ci ptrs = (short*)hdr; 40462306a36Sopenharmony_ci for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++) 40562306a36Sopenharmony_ci *ptrs++ = inw(NE_BASE + NE_DATAPORT); 40662306a36Sopenharmony_ci } else { 40762306a36Sopenharmony_ci ptrc = (char*)hdr; 40862306a36Sopenharmony_ci for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++) 40962306a36Sopenharmony_ci *ptrc++ = inb(NE_BASE + NE_DATAPORT); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ 41362306a36Sopenharmony_ci ei_status.dmaing &= ~0x01; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci le16_to_cpus(&hdr->count); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/* Block input and output, similar to the Crynwr packet driver. If you 41962306a36Sopenharmony_ci are porting to a new ethercard, look at the packet driver source for hints. 42062306a36Sopenharmony_ci The NEx000 doesn't share the on-board packet memory -- you have to put 42162306a36Sopenharmony_ci the packet out through the "remote DMA" dataport using outb. */ 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void 42462306a36Sopenharmony_ciapne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci int nic_base = dev->base_addr; 42762306a36Sopenharmony_ci char *buf = skb->data; 42862306a36Sopenharmony_ci char *ptrc; 42962306a36Sopenharmony_ci short *ptrs; 43062306a36Sopenharmony_ci int cnt; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* This *shouldn't* happen. If it does, it's the last thing you'll see */ 43362306a36Sopenharmony_ci if (ei_status.dmaing) { 43462306a36Sopenharmony_ci netdev_err(dev, "DMAing conflict in ne_block_input " 43562306a36Sopenharmony_ci "[DMAstat:%d][irqlock:%d][intr:%d].\n", 43662306a36Sopenharmony_ci ei_status.dmaing, ei_status.irqlock, dev->irq); 43762306a36Sopenharmony_ci return; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci ei_status.dmaing |= 0x01; 44062306a36Sopenharmony_ci outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); 44162306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + NE_EN0_ISR); 44262306a36Sopenharmony_ci outb(count & 0xff, nic_base + NE_EN0_RCNTLO); 44362306a36Sopenharmony_ci outb(count >> 8, nic_base + NE_EN0_RCNTHI); 44462306a36Sopenharmony_ci outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO); 44562306a36Sopenharmony_ci outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI); 44662306a36Sopenharmony_ci outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); 44762306a36Sopenharmony_ci if (ei_status.word16) { 44862306a36Sopenharmony_ci ptrs = (short*)buf; 44962306a36Sopenharmony_ci for (cnt = 0; cnt < (count>>1); cnt++) 45062306a36Sopenharmony_ci *ptrs++ = inw(NE_BASE + NE_DATAPORT); 45162306a36Sopenharmony_ci if (count & 0x01) { 45262306a36Sopenharmony_ci buf[count-1] = inb(NE_BASE + NE_DATAPORT); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci } else { 45562306a36Sopenharmony_ci ptrc = buf; 45662306a36Sopenharmony_ci for (cnt = 0; cnt < count; cnt++) 45762306a36Sopenharmony_ci *ptrc++ = inb(NE_BASE + NE_DATAPORT); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ 46162306a36Sopenharmony_ci ei_status.dmaing &= ~0x01; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic void 46562306a36Sopenharmony_ciapne_block_output(struct net_device *dev, int count, 46662306a36Sopenharmony_ci const unsigned char *buf, const int start_page) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci int nic_base = NE_BASE; 46962306a36Sopenharmony_ci unsigned long dma_start; 47062306a36Sopenharmony_ci char *ptrc; 47162306a36Sopenharmony_ci short *ptrs; 47262306a36Sopenharmony_ci int cnt; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* Round the count up for word writes. Do we need to do this? 47562306a36Sopenharmony_ci What effect will an odd byte count have on the 8390? 47662306a36Sopenharmony_ci I should check someday. */ 47762306a36Sopenharmony_ci if (ei_status.word16 && (count & 0x01)) 47862306a36Sopenharmony_ci count++; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* This *shouldn't* happen. If it does, it's the last thing you'll see */ 48162306a36Sopenharmony_ci if (ei_status.dmaing) { 48262306a36Sopenharmony_ci netdev_err(dev, "DMAing conflict in ne_block_output." 48362306a36Sopenharmony_ci "[DMAstat:%d][irqlock:%d][intr:%d]\n", 48462306a36Sopenharmony_ci ei_status.dmaing, ei_status.irqlock, dev->irq); 48562306a36Sopenharmony_ci return; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci ei_status.dmaing |= 0x01; 48862306a36Sopenharmony_ci /* We should already be in page 0, but to be safe... */ 48962306a36Sopenharmony_ci outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + NE_EN0_ISR); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Now the normal output. */ 49462306a36Sopenharmony_ci outb(count & 0xff, nic_base + NE_EN0_RCNTLO); 49562306a36Sopenharmony_ci outb(count >> 8, nic_base + NE_EN0_RCNTHI); 49662306a36Sopenharmony_ci outb(0x00, nic_base + NE_EN0_RSARLO); 49762306a36Sopenharmony_ci outb(start_page, nic_base + NE_EN0_RSARHI); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); 50062306a36Sopenharmony_ci if (ei_status.word16) { 50162306a36Sopenharmony_ci ptrs = (short*)buf; 50262306a36Sopenharmony_ci for (cnt = 0; cnt < count>>1; cnt++) 50362306a36Sopenharmony_ci outw(*ptrs++, NE_BASE+NE_DATAPORT); 50462306a36Sopenharmony_ci } else { 50562306a36Sopenharmony_ci ptrc = (char*)buf; 50662306a36Sopenharmony_ci for (cnt = 0; cnt < count; cnt++) 50762306a36Sopenharmony_ci outb(*ptrc++, NE_BASE + NE_DATAPORT); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci dma_start = jiffies; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) 51362306a36Sopenharmony_ci if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ 51462306a36Sopenharmony_ci netdev_warn(dev, "timeout waiting for Tx RDC.\n"); 51562306a36Sopenharmony_ci apne_reset_8390(dev); 51662306a36Sopenharmony_ci NS8390_init(dev,1); 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ 52162306a36Sopenharmony_ci ei_status.dmaing &= ~0x01; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic irqreturn_t apne_interrupt(int irq, void *dev_id) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci unsigned char pcmcia_intreq; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (!(gayle.inten & GAYLE_IRQ_IRQ)) 52962306a36Sopenharmony_ci return IRQ_NONE; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci pcmcia_intreq = pcmcia_get_intreq(); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) { 53462306a36Sopenharmony_ci pcmcia_ack_int(pcmcia_intreq); 53562306a36Sopenharmony_ci return IRQ_NONE; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci if (apne_msg_enable & NETIF_MSG_INTR) 53862306a36Sopenharmony_ci pr_debug("pcmcia intreq = %x\n", pcmcia_intreq); 53962306a36Sopenharmony_ci pcmcia_disable_irq(); /* to get rid of the sti() within ei_interrupt */ 54062306a36Sopenharmony_ci ei_interrupt(irq, dev_id); 54162306a36Sopenharmony_ci pcmcia_ack_int(pcmcia_get_intreq()); 54262306a36Sopenharmony_ci pcmcia_enable_irq(); 54362306a36Sopenharmony_ci return IRQ_HANDLED; 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic struct net_device *apne_dev; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int __init apne_module_init(void) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci apne_dev = apne_probe(); 55162306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(apne_dev); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void __exit apne_module_exit(void) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci unregister_netdev(apne_dev); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci pcmcia_disable_irq(); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci free_irq(IRQ_AMIGA_PORTS, apne_dev); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci pcmcia_reset(); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci release_region(IOBASE, 0x20); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci free_netdev(apne_dev); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_cimodule_init(apne_module_init); 56962306a36Sopenharmony_cimodule_exit(apne_module_exit); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int init_pcmcia(void) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci u_char config; 57462306a36Sopenharmony_ci#ifndef MANUAL_CONFIG 57562306a36Sopenharmony_ci u_char tuple[32]; 57662306a36Sopenharmony_ci int offset_len; 57762306a36Sopenharmony_ci#endif 57862306a36Sopenharmony_ci u_long offset; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci pcmcia_reset(); 58162306a36Sopenharmony_ci pcmcia_program_voltage(PCMCIA_0V); 58262306a36Sopenharmony_ci pcmcia_access_speed(PCMCIA_SPEED_250NS); 58362306a36Sopenharmony_ci pcmcia_write_enable(); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci#ifdef MANUAL_CONFIG 58662306a36Sopenharmony_ci config = MANUAL_CONFIG; 58762306a36Sopenharmony_ci#else 58862306a36Sopenharmony_ci /* get and write config byte to enable IO port */ 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3) 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci config = tuple[2] & 0x3f; 59462306a36Sopenharmony_ci#endif 59562306a36Sopenharmony_ci#ifdef MANUAL_OFFSET 59662306a36Sopenharmony_ci offset = MANUAL_OFFSET; 59762306a36Sopenharmony_ci#else 59862306a36Sopenharmony_ci if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6) 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci offset_len = (tuple[2] & 0x3) + 1; 60262306a36Sopenharmony_ci offset = 0; 60362306a36Sopenharmony_ci while(offset_len--) { 60462306a36Sopenharmony_ci offset = (offset << 8) | tuple[4+offset_len]; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci#endif 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci out_8(GAYLE_ATTRIBUTE+offset, config); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return 1; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 614