brintos

brintos / linux-shallow public Read only

0
0
Text · 16.7 KiB · 828edca Raw
615 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 12004 *5 * (C) Copyright 1997 Alain Malek6 *                    (Alain.Malek@cryogen.com)7 *8 * ----------------------------------------------------------------------------9 *10 * This program is based on11 *12 * ne.c:       A general non-shared-memory NS8390 ethernet driver for linux13 *             Written 1992-94 by Donald Becker.14 *15 * 8390.c:     A general NS8390 ethernet driver core for linux.16 *             Written 1992-94 by Donald Becker.17 *18 * cnetdevice: A Sana-II ethernet driver for AmigaOS19 *             Written by Bruce Abbott (bhabbott@inhb.co.nz)20 *21 * ----------------------------------------------------------------------------22 *23 */24 25 26#include <linux/module.h>27#include <linux/kernel.h>28#include <linux/errno.h>29#include <linux/pci.h>30#include <linux/init.h>31#include <linux/delay.h>32#include <linux/netdevice.h>33#include <linux/etherdevice.h>34#include <linux/interrupt.h>35#include <linux/jiffies.h>36 37#include <asm/io.h>38#include <asm/setup.h>39#include <asm/amigaints.h>40#include <asm/amigahw.h>41#include <asm/amigayle.h>42#include <asm/amipcmcia.h>43 44#include "8390.h"45 46/* ---- No user-serviceable parts below ---- */47 48#define DRV_NAME "apne"49 50#define NE_BASE	 (dev->base_addr)51#define NE_CMD	 		0x0052#define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */53#define NE_RESET		0x1f            /* Issue a read to reset, a write to clear. */54#define NE_IO_EXTENT	        0x2055 56#define NE_EN0_ISR		0x0757#define NE_EN0_DCFG		0x0e58 59#define NE_EN0_RSARLO	        0x0860#define NE_EN0_RSARHI	        0x0961#define NE_EN0_RCNTLO	        0x0a62#define NE_EN0_RXCR		0x0c63#define NE_EN0_TXCR		0x0d64#define NE_EN0_RCNTHI	        0x0b65#define NE_EN0_IMR		0x0f66 67#define NE1SM_START_PG	0x20	/* First page of TX buffer */68#define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */69#define NESM_START_PG	0x40	/* First page of TX buffer */70#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */71 72 73static int apne_probe1(struct net_device *dev, int ioaddr);74 75static void apne_reset_8390(struct net_device *dev);76static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,77			  int ring_page);78static void apne_block_input(struct net_device *dev, int count,79								struct sk_buff *skb, int ring_offset);80static void apne_block_output(struct net_device *dev, const int count,81							const unsigned char *buf, const int start_page);82static irqreturn_t apne_interrupt(int irq, void *dev_id);83 84static int init_pcmcia(void);85 86/* IO base address used for nic */87 88#define IOBASE 0x30089 90/*91   use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand92   you can find the values to use by looking at the cnet.device93   config file example (the default values are for the CNET40BC card)94*/95 96/*97#define MANUAL_CONFIG 0x2098#define MANUAL_OFFSET 0x3f899 100#define MANUAL_HWADDR0 0x00101#define MANUAL_HWADDR1 0x12102#define MANUAL_HWADDR2 0x34103#define MANUAL_HWADDR3 0x56104#define MANUAL_HWADDR4 0x78105#define MANUAL_HWADDR5 0x9a106*/107 108static const char version[] =109    "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";110 111static int apne_owned;	/* signal if card already owned */112 113static u32 apne_msg_enable;114module_param_named(msg_enable, apne_msg_enable, uint, 0444);115MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");116 117static struct net_device * __init apne_probe(void)118{119	struct net_device *dev;120	struct ei_device *ei_local;121 122#ifndef MANUAL_CONFIG123	char tuple[8];124#endif125	int err;126 127	if (!MACH_IS_AMIGA)128		return ERR_PTR(-ENODEV);129 130	if (apne_owned)131		return ERR_PTR(-ENODEV);132 133	if ( !(AMIGAHW_PRESENT(PCMCIA)) )134		return ERR_PTR(-ENODEV);135 136	pr_info("Looking for PCMCIA ethernet card : ");137 138	/* check if a card is inserted */139	if (!(PCMCIA_INSERTED)) {140		pr_cont("NO PCMCIA card inserted\n");141		return ERR_PTR(-ENODEV);142	}143 144	dev = alloc_ei_netdev();145	if (!dev)146		return ERR_PTR(-ENOMEM);147	ei_local = netdev_priv(dev);148	ei_local->msg_enable = apne_msg_enable;149 150	/* disable pcmcia irq for readtuple */151	pcmcia_disable_irq();152 153#ifndef MANUAL_CONFIG154	if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) ||155		(tuple[2] != CISTPL_FUNCID_NETWORK)) {156		pr_cont("not an ethernet card\n");157		/* XXX: shouldn't we re-enable irq here? */158		free_netdev(dev);159		return ERR_PTR(-ENODEV);160	}161#endif162 163	pr_cont("ethernet PCMCIA card inserted\n");164 165	if (!init_pcmcia()) {166		/* XXX: shouldn't we re-enable irq here? */167		free_netdev(dev);168		return ERR_PTR(-ENODEV);169	}170 171	if (!request_region(IOBASE, 0x20, DRV_NAME)) {172		free_netdev(dev);173		return ERR_PTR(-EBUSY);174	}175 176	err = apne_probe1(dev, IOBASE);177	if (err) {178		release_region(IOBASE, 0x20);179		free_netdev(dev);180		return ERR_PTR(err);181	}182	err = register_netdev(dev);183	if (!err)184		return dev;185 186	pcmcia_disable_irq();187	free_irq(IRQ_AMIGA_PORTS, dev);188	pcmcia_reset();189	release_region(IOBASE, 0x20);190	free_netdev(dev);191	return ERR_PTR(err);192}193 194static int __init apne_probe1(struct net_device *dev, int ioaddr)195{196    int i;197    unsigned char SA_prom[32];198    int wordlength = 2;199    const char *name = NULL;200    int start_page, stop_page;201#ifndef MANUAL_HWADDR0202    int neX000, ctron;203#endif204    static unsigned version_printed;205 206    if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))207		netdev_info(dev, version);208 209    netdev_info(dev, "PCMCIA NE*000 ethercard probe");210 211    /* Reset card. Who knows what dain-bramaged state it was left in. */212    {	unsigned long reset_start_time = jiffies;213 214	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);215 216	while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)217		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {218			pr_cont(" not found (no reset ack).\n");219			return -ENODEV;220		}221 222	outb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */223    }224 225#ifndef MANUAL_HWADDR0226 227    /* Read the 16 bytes of station address PROM.228       We must first initialize registers, similar to NS8390_init(eifdev, 0).229       We can't reliably read the SAPROM address without this.230       (I learned the hard way!). */231    {232	struct {unsigned long value, offset; } program_seq[] = {233	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/234	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */235	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */236	    {0x00,	NE_EN0_RCNTHI},237	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */238	    {0xFF,	NE_EN0_ISR},239	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */240	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */241	    {32,	NE_EN0_RCNTLO},242	    {0x00,	NE_EN0_RCNTHI},243	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */244	    {0x00,	NE_EN0_RSARHI},245	    {E8390_RREAD+E8390_START, NE_CMD},246	};247	for (i = 0; i < ARRAY_SIZE(program_seq); i++) {248	    outb(program_seq[i].value, ioaddr + program_seq[i].offset);249	}250 251    }252    for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {253	SA_prom[i] = inb(ioaddr + NE_DATAPORT);254	SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);255	if (SA_prom[i] != SA_prom[i+1])256	    wordlength = 1;257    }258 259    /*	At this point, wordlength *only* tells us if the SA_prom is doubled260	up or not because some broken PCI cards don't respect the byte-wide261	request in program_seq above, and hence don't have doubled up values.262	These broken cards would otherwise be detected as an ne1000.  */263 264    if (wordlength == 2)265	for (i = 0; i < 16; i++)266		SA_prom[i] = SA_prom[i+i];267 268    if (wordlength == 2) {269	/* We must set the 8390 for word mode. */270	outb(0x49, ioaddr + NE_EN0_DCFG);271	start_page = NESM_START_PG;272	stop_page = NESM_STOP_PG;273    } else {274	start_page = NE1SM_START_PG;275	stop_page = NE1SM_STOP_PG;276    }277 278    neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);279    ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);280 281    /* Set up the rest of the parameters. */282    if (neX000) {283	name = (wordlength == 2) ? "NE2000" : "NE1000";284    } else if (ctron) {285	name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";286	start_page = 0x01;287	stop_page = (wordlength == 2) ? 0x40 : 0x20;288    } else {289	pr_cont(" not found.\n");290	return -ENXIO;291 292    }293 294#else295    wordlength = 2;296    /* We must set the 8390 for word mode. */297    outb(0x49, ioaddr + NE_EN0_DCFG);298    start_page = NESM_START_PG;299    stop_page = NESM_STOP_PG;300 301    SA_prom[0] = MANUAL_HWADDR0;302    SA_prom[1] = MANUAL_HWADDR1;303    SA_prom[2] = MANUAL_HWADDR2;304    SA_prom[3] = MANUAL_HWADDR3;305    SA_prom[4] = MANUAL_HWADDR4;306    SA_prom[5] = MANUAL_HWADDR5;307    name = "NE2000";308#endif309 310    dev->base_addr = ioaddr;311    dev->irq = IRQ_AMIGA_PORTS;312    dev->netdev_ops = &ei_netdev_ops;313 314    /* Install the Interrupt handler */315    i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);316    if (i) return i;317 318    eth_hw_addr_set(dev, SA_prom);319 320    pr_cont(" %pM\n", dev->dev_addr);321 322    netdev_info(dev, "%s found.\n", name);323 324    ei_status.name = name;325    ei_status.tx_start_page = start_page;326    ei_status.stop_page = stop_page;327    ei_status.word16 = (wordlength == 2);328 329    ei_status.rx_start_page = start_page + TX_PAGES;330 331    ei_status.reset_8390 = &apne_reset_8390;332    ei_status.block_input = &apne_block_input;333    ei_status.block_output = &apne_block_output;334    ei_status.get_8390_hdr = &apne_get_8390_hdr;335 336    NS8390_init(dev, 0);337 338    pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */339    pcmcia_enable_irq();340 341    apne_owned = 1;342 343    return 0;344}345 346/* Hard reset the card.  This used to pause for the same period that a347   8390 reset command required, but that shouldn't be necessary. */348static void349apne_reset_8390(struct net_device *dev)350{351    unsigned long reset_start_time = jiffies;352    struct ei_device *ei_local = netdev_priv(dev);353 354    init_pcmcia();355 356    netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies);357 358    outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);359 360    ei_status.txing = 0;361    ei_status.dmaing = 0;362 363    /* This check _should_not_ be necessary, omit eventually. */364    while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)365	if (time_after(jiffies, reset_start_time + 2*HZ/100)) {366		netdev_err(dev, "ne_reset_8390() did not complete.\n");367		break;368	}369    outb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */370}371 372/* Grab the 8390 specific header. Similar to the block_input routine, but373   we don't need to be concerned with ring wrap as the header will be at374   the start of a page, so we optimize accordingly. */375 376static void377apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)378{379 380    int nic_base = dev->base_addr;381    int cnt;382    char *ptrc;383    short *ptrs;384 385    /* This *shouldn't* happen. If it does, it's the last thing you'll see */386    if (ei_status.dmaing) {387	netdev_err(dev, "DMAing conflict in ne_get_8390_hdr "388		   "[DMAstat:%d][irqlock:%d][intr:%d].\n",389		   ei_status.dmaing, ei_status.irqlock, dev->irq);390	return;391    }392 393    ei_status.dmaing |= 0x01;394    outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);395    outb(ENISR_RDC, nic_base + NE_EN0_ISR);396    outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);397    outb(0, nic_base + NE_EN0_RCNTHI);398    outb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */399    outb(ring_page, nic_base + NE_EN0_RSARHI);400    outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);401 402    if (ei_status.word16) {403        ptrs = (short*)hdr;404        for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)405            *ptrs++ = inw(NE_BASE + NE_DATAPORT);406    } else {407        ptrc = (char*)hdr;408        for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)409            *ptrc++ = inb(NE_BASE + NE_DATAPORT);410    }411 412    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */413    ei_status.dmaing &= ~0x01;414 415    le16_to_cpus(&hdr->count);416}417 418/* Block input and output, similar to the Crynwr packet driver.  If you419   are porting to a new ethercard, look at the packet driver source for hints.420   The NEx000 doesn't share the on-board packet memory -- you have to put421   the packet out through the "remote DMA" dataport using outb. */422 423static void424apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)425{426    int nic_base = dev->base_addr;427    char *buf = skb->data;428    char *ptrc;429    short *ptrs;430    int cnt;431 432    /* This *shouldn't* happen. If it does, it's the last thing you'll see */433    if (ei_status.dmaing) {434		netdev_err(dev, "DMAing conflict in ne_block_input "435			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",436			   ei_status.dmaing, ei_status.irqlock, dev->irq);437	return;438    }439    ei_status.dmaing |= 0x01;440    outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);441    outb(ENISR_RDC, nic_base + NE_EN0_ISR);442    outb(count & 0xff, nic_base + NE_EN0_RCNTLO);443    outb(count >> 8, nic_base + NE_EN0_RCNTHI);444    outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);445    outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);446    outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);447    if (ei_status.word16) {448      ptrs = (short*)buf;449      for (cnt = 0; cnt < (count>>1); cnt++)450        *ptrs++ = inw(NE_BASE + NE_DATAPORT);451      if (count & 0x01) {452	buf[count-1] = inb(NE_BASE + NE_DATAPORT);453      }454    } else {455      ptrc = buf;456      for (cnt = 0; cnt < count; cnt++)457        *ptrc++ = inb(NE_BASE + NE_DATAPORT);458    }459 460    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */461    ei_status.dmaing &= ~0x01;462}463 464static void465apne_block_output(struct net_device *dev, int count,466		const unsigned char *buf, const int start_page)467{468    int nic_base = NE_BASE;469    unsigned long dma_start;470    char *ptrc;471    short *ptrs;472    int cnt;473 474    /* Round the count up for word writes.  Do we need to do this?475       What effect will an odd byte count have on the 8390?476       I should check someday. */477    if (ei_status.word16 && (count & 0x01))478      count++;479 480    /* This *shouldn't* happen. If it does, it's the last thing you'll see */481    if (ei_status.dmaing) {482		netdev_err(dev, "DMAing conflict in ne_block_output."483			   "[DMAstat:%d][irqlock:%d][intr:%d]\n",484			   ei_status.dmaing, ei_status.irqlock, dev->irq);485	return;486    }487    ei_status.dmaing |= 0x01;488    /* We should already be in page 0, but to be safe... */489    outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);490 491    outb(ENISR_RDC, nic_base + NE_EN0_ISR);492 493   /* Now the normal output. */494    outb(count & 0xff, nic_base + NE_EN0_RCNTLO);495    outb(count >> 8,   nic_base + NE_EN0_RCNTHI);496    outb(0x00, nic_base + NE_EN0_RSARLO);497    outb(start_page, nic_base + NE_EN0_RSARHI);498 499    outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);500    if (ei_status.word16) {501        ptrs = (short*)buf;502        for (cnt = 0; cnt < count>>1; cnt++)503            outw(*ptrs++, NE_BASE+NE_DATAPORT);504    } else {505        ptrc = (char*)buf;506        for (cnt = 0; cnt < count; cnt++)507	    outb(*ptrc++, NE_BASE + NE_DATAPORT);508    }509 510    dma_start = jiffies;511 512    while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)513	if (time_after(jiffies, dma_start + 2*HZ/100)) {	/* 20ms */514		netdev_warn(dev, "timeout waiting for Tx RDC.\n");515		apne_reset_8390(dev);516		NS8390_init(dev,1);517		break;518	}519 520    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */521    ei_status.dmaing &= ~0x01;522}523 524static irqreturn_t apne_interrupt(int irq, void *dev_id)525{526    unsigned char pcmcia_intreq;527 528    if (!(gayle.inten & GAYLE_IRQ_IRQ))529        return IRQ_NONE;530 531    pcmcia_intreq = pcmcia_get_intreq();532 533    if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) {534        pcmcia_ack_int(pcmcia_intreq);535        return IRQ_NONE;536    }537    if (apne_msg_enable & NETIF_MSG_INTR)538	pr_debug("pcmcia intreq = %x\n", pcmcia_intreq);539    pcmcia_disable_irq();			/* to get rid of the sti() within ei_interrupt */540    ei_interrupt(irq, dev_id);541    pcmcia_ack_int(pcmcia_get_intreq());542    pcmcia_enable_irq();543    return IRQ_HANDLED;544}545 546static struct net_device *apne_dev;547 548static int __init apne_module_init(void)549{550	apne_dev = apne_probe();551	return PTR_ERR_OR_ZERO(apne_dev);552}553 554static void __exit apne_module_exit(void)555{556	unregister_netdev(apne_dev);557 558	pcmcia_disable_irq();559 560	free_irq(IRQ_AMIGA_PORTS, apne_dev);561 562	pcmcia_reset();563 564	release_region(IOBASE, 0x20);565 566	free_netdev(apne_dev);567}568module_init(apne_module_init);569module_exit(apne_module_exit);570 571static int init_pcmcia(void)572{573	u_char config;574#ifndef MANUAL_CONFIG575	u_char tuple[32];576	int offset_len;577#endif578	u_long offset;579 580	pcmcia_reset();581	pcmcia_program_voltage(PCMCIA_0V);582	pcmcia_access_speed(PCMCIA_SPEED_250NS);583	pcmcia_write_enable();584 585#ifdef MANUAL_CONFIG586	config = MANUAL_CONFIG;587#else588	/* get and write config byte to enable IO port */589 590	if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3)591		return 0;592 593	config = tuple[2] & 0x3f;594#endif595#ifdef MANUAL_OFFSET596	offset = MANUAL_OFFSET;597#else598	if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)599		return 0;600 601	offset_len = (tuple[2] & 0x3) + 1;602	offset = 0;603	while(offset_len--) {604		offset = (offset << 8) | tuple[4+offset_len];605	}606#endif607 608	out_8(GAYLE_ATTRIBUTE+offset, config);609 610	return 1;611}612 613MODULE_DESCRIPTION("National Semiconductor 8390 Amiga PCMCIA ethernet driver");614MODULE_LICENSE("GPL");615