10a3360e1SGeert Uytterhoeven /* mac89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
20a3360e1SGeert Uytterhoeven /*
30a3360e1SGeert Uytterhoeven Written 1996 by Russell Nelson, with reference to skeleton.c
40a3360e1SGeert Uytterhoeven written 1993-1994 by Donald Becker.
50a3360e1SGeert Uytterhoeven
60a3360e1SGeert Uytterhoeven This software may be used and distributed according to the terms
70a3360e1SGeert Uytterhoeven of the GNU General Public License, incorporated herein by reference.
80a3360e1SGeert Uytterhoeven
90a3360e1SGeert Uytterhoeven The author may be reached at nelson@crynwr.com, Crynwr
100a3360e1SGeert Uytterhoeven Software, 11 Grant St., Potsdam, NY 13676
110a3360e1SGeert Uytterhoeven
120a3360e1SGeert Uytterhoeven Changelog:
130a3360e1SGeert Uytterhoeven
140a3360e1SGeert Uytterhoeven Mike Cruse : mcruse@cti-ltd.com
150a3360e1SGeert Uytterhoeven : Changes for Linux 2.0 compatibility.
160a3360e1SGeert Uytterhoeven : Added dev_id parameter in net_interrupt(),
170a3360e1SGeert Uytterhoeven : request_irq() and free_irq(). Just NULL for now.
180a3360e1SGeert Uytterhoeven
190a3360e1SGeert Uytterhoeven Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
200a3360e1SGeert Uytterhoeven : in net_open() and net_close() so kerneld would know
210a3360e1SGeert Uytterhoeven : that the module is in use and wouldn't eject the
220a3360e1SGeert Uytterhoeven : driver prematurely.
230a3360e1SGeert Uytterhoeven
240a3360e1SGeert Uytterhoeven Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c
250a3360e1SGeert Uytterhoeven : as an example. Disabled autoprobing in init_module(),
260a3360e1SGeert Uytterhoeven : not a good thing to do to other devices while Linux
270a3360e1SGeert Uytterhoeven : is running from all accounts.
280a3360e1SGeert Uytterhoeven
290a3360e1SGeert Uytterhoeven Alan Cox : Removed 1.2 support, added 2.1 extra counters.
300a3360e1SGeert Uytterhoeven
310a3360e1SGeert Uytterhoeven David Huggins-Daines <dhd@debian.org>
320a3360e1SGeert Uytterhoeven
330a3360e1SGeert Uytterhoeven Split this off into mac89x0.c, and gutted it of all parts which are
340a3360e1SGeert Uytterhoeven not relevant to the existing CS8900 cards on the Macintosh
350a3360e1SGeert Uytterhoeven (i.e. basically the Daynaport CS and LC cards). To be precise:
360a3360e1SGeert Uytterhoeven
370a3360e1SGeert Uytterhoeven * Removed all the media-detection stuff, because these cards are
380a3360e1SGeert Uytterhoeven TP-only.
390a3360e1SGeert Uytterhoeven
400a3360e1SGeert Uytterhoeven * Lobotomized the ISA interrupt bogosity, because these cards use
410a3360e1SGeert Uytterhoeven a hardwired NuBus interrupt and a magic ISAIRQ value in the card.
420a3360e1SGeert Uytterhoeven
430a3360e1SGeert Uytterhoeven * Basically eliminated everything not relevant to getting the
440a3360e1SGeert Uytterhoeven cards minimally functioning on the Macintosh.
450a3360e1SGeert Uytterhoeven
460a3360e1SGeert Uytterhoeven I might add that these cards are badly designed even from the Mac
470a3360e1SGeert Uytterhoeven standpoint, in that Dayna, in their infinite wisdom, used NuBus slot
480a3360e1SGeert Uytterhoeven I/O space and NuBus interrupts for these cards, but neglected to
490a3360e1SGeert Uytterhoeven provide anything even remotely resembling a NuBus ROM. Therefore we
500a3360e1SGeert Uytterhoeven have to probe for them in a brain-damaged ISA-like fashion.
510a3360e1SGeert Uytterhoeven
520a3360e1SGeert Uytterhoeven Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
530a3360e1SGeert Uytterhoeven check kmalloc and release the allocated memory on failure in
540a3360e1SGeert Uytterhoeven mac89x0_probe and in init_module
550a3360e1SGeert Uytterhoeven use local_irq_{save,restore}(flags) in net_get_stat, not just
560a3360e1SGeert Uytterhoeven local_irq_{dis,en}able()
570a3360e1SGeert Uytterhoeven */
580a3360e1SGeert Uytterhoeven
5986c2666eSFinn Thain #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6086c2666eSFinn Thain
6106324664SKees Cook static const char version[] =
620a3360e1SGeert Uytterhoeven "cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
630a3360e1SGeert Uytterhoeven
640a3360e1SGeert Uytterhoeven #include <linux/module.h>
650a3360e1SGeert Uytterhoeven
660a3360e1SGeert Uytterhoeven /*
670a3360e1SGeert Uytterhoeven Sources:
680a3360e1SGeert Uytterhoeven
690a3360e1SGeert Uytterhoeven Crynwr packet driver epktisa.
700a3360e1SGeert Uytterhoeven
710a3360e1SGeert Uytterhoeven Crystal Semiconductor data sheets.
720a3360e1SGeert Uytterhoeven
730a3360e1SGeert Uytterhoeven */
740a3360e1SGeert Uytterhoeven
750a3360e1SGeert Uytterhoeven #include <linux/kernel.h>
760a3360e1SGeert Uytterhoeven #include <linux/types.h>
770a3360e1SGeert Uytterhoeven #include <linux/fcntl.h>
780a3360e1SGeert Uytterhoeven #include <linux/interrupt.h>
790a3360e1SGeert Uytterhoeven #include <linux/ioport.h>
800a3360e1SGeert Uytterhoeven #include <linux/in.h>
810a3360e1SGeert Uytterhoeven #include <linux/string.h>
820a3360e1SGeert Uytterhoeven #include <linux/nubus.h>
830a3360e1SGeert Uytterhoeven #include <linux/errno.h>
840a3360e1SGeert Uytterhoeven #include <linux/init.h>
850a3360e1SGeert Uytterhoeven #include <linux/netdevice.h>
8643bf2e6dSFinn Thain #include <linux/platform_device.h>
870a3360e1SGeert Uytterhoeven #include <linux/etherdevice.h>
880a3360e1SGeert Uytterhoeven #include <linux/skbuff.h>
890a3360e1SGeert Uytterhoeven #include <linux/delay.h>
900a3360e1SGeert Uytterhoeven #include <linux/bitops.h>
910a3360e1SGeert Uytterhoeven #include <linux/gfp.h>
920a3360e1SGeert Uytterhoeven
930a3360e1SGeert Uytterhoeven #include <asm/io.h>
940a3360e1SGeert Uytterhoeven #include <asm/hwtest.h>
950a3360e1SGeert Uytterhoeven #include <asm/macints.h>
960a3360e1SGeert Uytterhoeven
970a3360e1SGeert Uytterhoeven #include "cs89x0.h"
980a3360e1SGeert Uytterhoeven
995a3b7504SFinn Thain static int debug = -1;
10043bf2e6dSFinn Thain module_param(debug, int, 0);
1015a3b7504SFinn Thain MODULE_PARM_DESC(debug, "debug message level");
1020a3360e1SGeert Uytterhoeven
1030a3360e1SGeert Uytterhoeven /* Information that need to be kept for each board. */
1040a3360e1SGeert Uytterhoeven struct net_local {
1055a3b7504SFinn Thain int msg_enable;
1060a3360e1SGeert Uytterhoeven int chip_type; /* one of: CS8900, CS8920, CS8920M */
1070a3360e1SGeert Uytterhoeven char chip_revision; /* revision letter of the chip ('A'...) */
1080a3360e1SGeert Uytterhoeven int send_cmd; /* the propercommand used to send a packet. */
1090a3360e1SGeert Uytterhoeven int rx_mode;
1100a3360e1SGeert Uytterhoeven int curr_rx_cfg;
1110a3360e1SGeert Uytterhoeven int send_underrun; /* keep track of how many underruns in a row we get */
1120a3360e1SGeert Uytterhoeven };
1130a3360e1SGeert Uytterhoeven
1140a3360e1SGeert Uytterhoeven /* Index to functions, as function prototypes. */
1150a3360e1SGeert Uytterhoeven static int net_open(struct net_device *dev);
116f3bf939fSYueHaibing static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev);
1170a3360e1SGeert Uytterhoeven static irqreturn_t net_interrupt(int irq, void *dev_id);
1180a3360e1SGeert Uytterhoeven static void set_multicast_list(struct net_device *dev);
1190a3360e1SGeert Uytterhoeven static void net_rx(struct net_device *dev);
1200a3360e1SGeert Uytterhoeven static int net_close(struct net_device *dev);
1210a3360e1SGeert Uytterhoeven static struct net_device_stats *net_get_stats(struct net_device *dev);
1220a3360e1SGeert Uytterhoeven static int set_mac_address(struct net_device *dev, void *addr);
1230a3360e1SGeert Uytterhoeven
1240a3360e1SGeert Uytterhoeven /* For reading/writing registers ISA-style */
1250a3360e1SGeert Uytterhoeven static inline int
readreg_io(struct net_device * dev,int portno)1260a3360e1SGeert Uytterhoeven readreg_io(struct net_device *dev, int portno)
1270a3360e1SGeert Uytterhoeven {
1280a3360e1SGeert Uytterhoeven nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
1290a3360e1SGeert Uytterhoeven return swab16(nubus_readw(dev->base_addr + DATA_PORT));
1300a3360e1SGeert Uytterhoeven }
1310a3360e1SGeert Uytterhoeven
1320a3360e1SGeert Uytterhoeven static inline void
writereg_io(struct net_device * dev,int portno,int value)1330a3360e1SGeert Uytterhoeven writereg_io(struct net_device *dev, int portno, int value)
1340a3360e1SGeert Uytterhoeven {
1350a3360e1SGeert Uytterhoeven nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
1360a3360e1SGeert Uytterhoeven nubus_writew(swab16(value), dev->base_addr + DATA_PORT);
1370a3360e1SGeert Uytterhoeven }
1380a3360e1SGeert Uytterhoeven
1390a3360e1SGeert Uytterhoeven /* These are for reading/writing registers in shared memory */
1400a3360e1SGeert Uytterhoeven static inline int
readreg(struct net_device * dev,int portno)1410a3360e1SGeert Uytterhoeven readreg(struct net_device *dev, int portno)
1420a3360e1SGeert Uytterhoeven {
1430a3360e1SGeert Uytterhoeven return swab16(nubus_readw(dev->mem_start + portno));
1440a3360e1SGeert Uytterhoeven }
1450a3360e1SGeert Uytterhoeven
1460a3360e1SGeert Uytterhoeven static inline void
writereg(struct net_device * dev,int portno,int value)1470a3360e1SGeert Uytterhoeven writereg(struct net_device *dev, int portno, int value)
1480a3360e1SGeert Uytterhoeven {
1490a3360e1SGeert Uytterhoeven nubus_writew(swab16(value), dev->mem_start + portno);
1500a3360e1SGeert Uytterhoeven }
1510a3360e1SGeert Uytterhoeven
1520a3360e1SGeert Uytterhoeven static const struct net_device_ops mac89x0_netdev_ops = {
1530a3360e1SGeert Uytterhoeven .ndo_open = net_open,
1540a3360e1SGeert Uytterhoeven .ndo_stop = net_close,
1550a3360e1SGeert Uytterhoeven .ndo_start_xmit = net_send_packet,
1560a3360e1SGeert Uytterhoeven .ndo_get_stats = net_get_stats,
1570a3360e1SGeert Uytterhoeven .ndo_set_rx_mode = set_multicast_list,
1580a3360e1SGeert Uytterhoeven .ndo_set_mac_address = set_mac_address,
1590a3360e1SGeert Uytterhoeven .ndo_validate_addr = eth_validate_addr,
1600a3360e1SGeert Uytterhoeven };
1610a3360e1SGeert Uytterhoeven
1620a3360e1SGeert Uytterhoeven /* Probe for the CS8900 card in slot E. We won't bother looking
1630a3360e1SGeert Uytterhoeven anywhere else until we have a really good reason to do so. */
mac89x0_device_probe(struct platform_device * pdev)16443bf2e6dSFinn Thain static int mac89x0_device_probe(struct platform_device *pdev)
1650a3360e1SGeert Uytterhoeven {
1660a3360e1SGeert Uytterhoeven struct net_device *dev;
1670a3360e1SGeert Uytterhoeven struct net_local *lp;
1680a3360e1SGeert Uytterhoeven int i, slot;
1690a3360e1SGeert Uytterhoeven unsigned rev_type = 0;
1700a3360e1SGeert Uytterhoeven unsigned long ioaddr;
1710a3360e1SGeert Uytterhoeven unsigned short sig;
1720a3360e1SGeert Uytterhoeven int err = -ENODEV;
17341b84816SFinn Thain struct nubus_rsrc *fres;
1740a3360e1SGeert Uytterhoeven
1750a3360e1SGeert Uytterhoeven dev = alloc_etherdev(sizeof(struct net_local));
1760a3360e1SGeert Uytterhoeven if (!dev)
17743bf2e6dSFinn Thain return -ENOMEM;
1780a3360e1SGeert Uytterhoeven
1790a3360e1SGeert Uytterhoeven /* We might have to parameterize this later */
1800a3360e1SGeert Uytterhoeven slot = 0xE;
1810a3360e1SGeert Uytterhoeven /* Get out now if there's a real NuBus card in slot E */
18241b84816SFinn Thain for_each_func_rsrc(fres)
18341b84816SFinn Thain if (fres->board->slot == slot)
1840a3360e1SGeert Uytterhoeven goto out;
1850a3360e1SGeert Uytterhoeven
1860a3360e1SGeert Uytterhoeven /* The pseudo-ISA bits always live at offset 0x300 (gee,
1870a3360e1SGeert Uytterhoeven wonder why...) */
1880a3360e1SGeert Uytterhoeven ioaddr = (unsigned long)
1890a3360e1SGeert Uytterhoeven nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
1900a3360e1SGeert Uytterhoeven {
1910a3360e1SGeert Uytterhoeven int card_present;
1920a3360e1SGeert Uytterhoeven
1930a3360e1SGeert Uytterhoeven card_present = (hwreg_present((void *)ioaddr + 4) &&
1940a3360e1SGeert Uytterhoeven hwreg_present((void *)ioaddr + DATA_PORT));
1950a3360e1SGeert Uytterhoeven if (!card_present)
1960a3360e1SGeert Uytterhoeven goto out;
1970a3360e1SGeert Uytterhoeven }
1980a3360e1SGeert Uytterhoeven
1990a3360e1SGeert Uytterhoeven nubus_writew(0, ioaddr + ADD_PORT);
2000a3360e1SGeert Uytterhoeven sig = nubus_readw(ioaddr + DATA_PORT);
2010a3360e1SGeert Uytterhoeven if (sig != swab16(CHIP_EISA_ID_SIG))
2020a3360e1SGeert Uytterhoeven goto out;
2030a3360e1SGeert Uytterhoeven
20443bf2e6dSFinn Thain SET_NETDEV_DEV(dev, &pdev->dev);
20543bf2e6dSFinn Thain
2060a3360e1SGeert Uytterhoeven /* Initialize the net_device structure. */
2070a3360e1SGeert Uytterhoeven lp = netdev_priv(dev);
2080a3360e1SGeert Uytterhoeven
2095a3b7504SFinn Thain lp->msg_enable = netif_msg_init(debug, 0);
2105a3b7504SFinn Thain
2110a3360e1SGeert Uytterhoeven /* Fill in the 'dev' fields. */
2120a3360e1SGeert Uytterhoeven dev->base_addr = ioaddr;
2130a3360e1SGeert Uytterhoeven dev->mem_start = (unsigned long)
2140a3360e1SGeert Uytterhoeven nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
2150a3360e1SGeert Uytterhoeven dev->mem_end = dev->mem_start + 0x1000;
2160a3360e1SGeert Uytterhoeven
2170a3360e1SGeert Uytterhoeven /* Turn on shared memory */
2180a3360e1SGeert Uytterhoeven writereg_io(dev, PP_BusCTL, MEMORY_ON);
2190a3360e1SGeert Uytterhoeven
2200a3360e1SGeert Uytterhoeven /* get the chip type */
2210a3360e1SGeert Uytterhoeven rev_type = readreg(dev, PRODUCT_ID_ADD);
2220a3360e1SGeert Uytterhoeven lp->chip_type = rev_type &~ REVISON_BITS;
2230a3360e1SGeert Uytterhoeven lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
2240a3360e1SGeert Uytterhoeven
2250a3360e1SGeert Uytterhoeven /* Check the chip type and revision in order to set the correct send command
2260a3360e1SGeert Uytterhoeven CS8920 revision C and CS8900 revision F can use the faster send. */
2270a3360e1SGeert Uytterhoeven lp->send_cmd = TX_AFTER_381;
2280a3360e1SGeert Uytterhoeven if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
2290a3360e1SGeert Uytterhoeven lp->send_cmd = TX_NOW;
2300a3360e1SGeert Uytterhoeven if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
2310a3360e1SGeert Uytterhoeven lp->send_cmd = TX_NOW;
2320a3360e1SGeert Uytterhoeven
2335a3b7504SFinn Thain netif_dbg(lp, drv, dev, "%s", version);
2340a3360e1SGeert Uytterhoeven
23586c2666eSFinn Thain pr_info("cs89%c0%s rev %c found at %#8lx\n",
2360a3360e1SGeert Uytterhoeven lp->chip_type == CS8900 ? '0' : '2',
2370a3360e1SGeert Uytterhoeven lp->chip_type == CS8920M ? "M" : "",
23886c2666eSFinn Thain lp->chip_revision, dev->base_addr);
2390a3360e1SGeert Uytterhoeven
2400a3360e1SGeert Uytterhoeven /* Try to read the MAC address */
2410a3360e1SGeert Uytterhoeven if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
24286c2666eSFinn Thain pr_info("No EEPROM, giving up now.\n");
2430a3360e1SGeert Uytterhoeven goto out1;
2440a3360e1SGeert Uytterhoeven } else {
2459a962aedSJakub Kicinski u8 addr[ETH_ALEN];
2469a962aedSJakub Kicinski
2470a3360e1SGeert Uytterhoeven for (i = 0; i < ETH_ALEN; i += 2) {
2480a3360e1SGeert Uytterhoeven /* Big-endian (why??!) */
2490a3360e1SGeert Uytterhoeven unsigned short s = readreg(dev, PP_IA + i);
2509a962aedSJakub Kicinski addr[i] = s >> 8;
2519a962aedSJakub Kicinski addr[i+1] = s & 0xff;
2520a3360e1SGeert Uytterhoeven }
2539a962aedSJakub Kicinski eth_hw_addr_set(dev, addr);
2540a3360e1SGeert Uytterhoeven }
2550a3360e1SGeert Uytterhoeven
2560a3360e1SGeert Uytterhoeven dev->irq = SLOT2IRQ(slot);
2570a3360e1SGeert Uytterhoeven
2580a3360e1SGeert Uytterhoeven /* print the IRQ and ethernet address. */
2590a3360e1SGeert Uytterhoeven
26086c2666eSFinn Thain pr_info("MAC %pM, IRQ %d\n", dev->dev_addr, dev->irq);
2610a3360e1SGeert Uytterhoeven
2620a3360e1SGeert Uytterhoeven dev->netdev_ops = &mac89x0_netdev_ops;
2630a3360e1SGeert Uytterhoeven
2640a3360e1SGeert Uytterhoeven err = register_netdev(dev);
2650a3360e1SGeert Uytterhoeven if (err)
2660a3360e1SGeert Uytterhoeven goto out1;
26743bf2e6dSFinn Thain
26843bf2e6dSFinn Thain platform_set_drvdata(pdev, dev);
26943bf2e6dSFinn Thain return 0;
2700a3360e1SGeert Uytterhoeven out1:
2710a3360e1SGeert Uytterhoeven nubus_writew(0, dev->base_addr + ADD_PORT);
2720a3360e1SGeert Uytterhoeven out:
2730a3360e1SGeert Uytterhoeven free_netdev(dev);
27443bf2e6dSFinn Thain return err;
2750a3360e1SGeert Uytterhoeven }
2760a3360e1SGeert Uytterhoeven
2770a3360e1SGeert Uytterhoeven /* Open/initialize the board. This is called (in the current kernel)
2780a3360e1SGeert Uytterhoeven sometime after booting when the 'ifconfig' program is run.
2790a3360e1SGeert Uytterhoeven
2800a3360e1SGeert Uytterhoeven This routine should set everything up anew at each open, even
2810a3360e1SGeert Uytterhoeven registers that "should" only need to be set once at boot, so that
2820a3360e1SGeert Uytterhoeven there is non-reboot way to recover if something goes wrong.
2830a3360e1SGeert Uytterhoeven */
2840a3360e1SGeert Uytterhoeven static int
net_open(struct net_device * dev)2850a3360e1SGeert Uytterhoeven net_open(struct net_device *dev)
2860a3360e1SGeert Uytterhoeven {
2870a3360e1SGeert Uytterhoeven struct net_local *lp = netdev_priv(dev);
2880a3360e1SGeert Uytterhoeven int i;
2890a3360e1SGeert Uytterhoeven
2900a3360e1SGeert Uytterhoeven /* Disable the interrupt for now */
2910a3360e1SGeert Uytterhoeven writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);
2920a3360e1SGeert Uytterhoeven
2930a3360e1SGeert Uytterhoeven /* Grab the interrupt */
2940a3360e1SGeert Uytterhoeven if (request_irq(dev->irq, net_interrupt, 0, "cs89x0", dev))
2950a3360e1SGeert Uytterhoeven return -EAGAIN;
2960a3360e1SGeert Uytterhoeven
2970a3360e1SGeert Uytterhoeven /* Set up the IRQ - Apparently magic */
2980a3360e1SGeert Uytterhoeven if (lp->chip_type == CS8900)
2990a3360e1SGeert Uytterhoeven writereg(dev, PP_CS8900_ISAINT, 0);
3000a3360e1SGeert Uytterhoeven else
3010a3360e1SGeert Uytterhoeven writereg(dev, PP_CS8920_ISAINT, 0);
3020a3360e1SGeert Uytterhoeven
3030a3360e1SGeert Uytterhoeven /* set the Ethernet address */
3040a3360e1SGeert Uytterhoeven for (i=0; i < ETH_ALEN/2; i++)
3050a3360e1SGeert Uytterhoeven writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
3060a3360e1SGeert Uytterhoeven
3070a3360e1SGeert Uytterhoeven /* Turn on both receive and transmit operations */
3080a3360e1SGeert Uytterhoeven writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
3090a3360e1SGeert Uytterhoeven
3100a3360e1SGeert Uytterhoeven /* Receive only error free packets addressed to this card */
3110a3360e1SGeert Uytterhoeven lp->rx_mode = 0;
3120a3360e1SGeert Uytterhoeven writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
3130a3360e1SGeert Uytterhoeven
3140a3360e1SGeert Uytterhoeven lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
3150a3360e1SGeert Uytterhoeven
3160a3360e1SGeert Uytterhoeven writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
3170a3360e1SGeert Uytterhoeven
3180a3360e1SGeert Uytterhoeven writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
3190a3360e1SGeert Uytterhoeven TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
3200a3360e1SGeert Uytterhoeven
3210a3360e1SGeert Uytterhoeven writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
3220a3360e1SGeert Uytterhoeven TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
3230a3360e1SGeert Uytterhoeven
3240a3360e1SGeert Uytterhoeven /* now that we've got our act together, enable everything */
3250a3360e1SGeert Uytterhoeven writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
3260a3360e1SGeert Uytterhoeven netif_start_queue(dev);
3270a3360e1SGeert Uytterhoeven return 0;
3280a3360e1SGeert Uytterhoeven }
3290a3360e1SGeert Uytterhoeven
330f3bf939fSYueHaibing static netdev_tx_t
net_send_packet(struct sk_buff * skb,struct net_device * dev)3310a3360e1SGeert Uytterhoeven net_send_packet(struct sk_buff *skb, struct net_device *dev)
3320a3360e1SGeert Uytterhoeven {
3330a3360e1SGeert Uytterhoeven struct net_local *lp = netdev_priv(dev);
3340a3360e1SGeert Uytterhoeven unsigned long flags;
3350a3360e1SGeert Uytterhoeven
3365a3b7504SFinn Thain netif_dbg(lp, tx_queued, dev, "sent %d byte packet of type %x\n",
3375a3b7504SFinn Thain skb->len, skb->data[ETH_ALEN + ETH_ALEN] << 8 |
3385a3b7504SFinn Thain skb->data[ETH_ALEN + ETH_ALEN + 1]);
3390a3360e1SGeert Uytterhoeven
3400a3360e1SGeert Uytterhoeven /* keep the upload from being interrupted, since we
3410a3360e1SGeert Uytterhoeven ask the chip to start transmitting before the
3420a3360e1SGeert Uytterhoeven whole packet has been completely uploaded. */
3430a3360e1SGeert Uytterhoeven local_irq_save(flags);
3440a3360e1SGeert Uytterhoeven netif_stop_queue(dev);
3450a3360e1SGeert Uytterhoeven
3460a3360e1SGeert Uytterhoeven /* initiate a transmit sequence */
3470a3360e1SGeert Uytterhoeven writereg(dev, PP_TxCMD, lp->send_cmd);
3480a3360e1SGeert Uytterhoeven writereg(dev, PP_TxLength, skb->len);
3490a3360e1SGeert Uytterhoeven
3500a3360e1SGeert Uytterhoeven /* Test to see if the chip has allocated memory for the packet */
3510a3360e1SGeert Uytterhoeven if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
3520a3360e1SGeert Uytterhoeven /* Gasp! It hasn't. But that shouldn't happen since
3530a3360e1SGeert Uytterhoeven we're waiting for TxOk, so return 1 and requeue this packet. */
3540a3360e1SGeert Uytterhoeven local_irq_restore(flags);
3550a3360e1SGeert Uytterhoeven return NETDEV_TX_BUSY;
3560a3360e1SGeert Uytterhoeven }
3570a3360e1SGeert Uytterhoeven
3580a3360e1SGeert Uytterhoeven /* Write the contents of the packet */
3590a3360e1SGeert Uytterhoeven skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame),
3600a3360e1SGeert Uytterhoeven skb->len+1);
3610a3360e1SGeert Uytterhoeven
3620a3360e1SGeert Uytterhoeven local_irq_restore(flags);
3630a3360e1SGeert Uytterhoeven dev_kfree_skb (skb);
3640a3360e1SGeert Uytterhoeven
3650a3360e1SGeert Uytterhoeven return NETDEV_TX_OK;
3660a3360e1SGeert Uytterhoeven }
3670a3360e1SGeert Uytterhoeven
3680a3360e1SGeert Uytterhoeven /* The typical workload of the driver:
3690a3360e1SGeert Uytterhoeven Handle the network interface interrupts. */
net_interrupt(int irq,void * dev_id)3700a3360e1SGeert Uytterhoeven static irqreturn_t net_interrupt(int irq, void *dev_id)
3710a3360e1SGeert Uytterhoeven {
3720a3360e1SGeert Uytterhoeven struct net_device *dev = dev_id;
3730a3360e1SGeert Uytterhoeven struct net_local *lp;
3740a3360e1SGeert Uytterhoeven int ioaddr, status;
3750a3360e1SGeert Uytterhoeven
3760a3360e1SGeert Uytterhoeven ioaddr = dev->base_addr;
3770a3360e1SGeert Uytterhoeven lp = netdev_priv(dev);
3780a3360e1SGeert Uytterhoeven
3790a3360e1SGeert Uytterhoeven /* we MUST read all the events out of the ISQ, otherwise we'll never
3800a3360e1SGeert Uytterhoeven get interrupted again. As a consequence, we can't have any limit
3810a3360e1SGeert Uytterhoeven on the number of times we loop in the interrupt handler. The
3820a3360e1SGeert Uytterhoeven hardware guarantees that eventually we'll run out of events. Of
3830a3360e1SGeert Uytterhoeven course, if you're on a slow machine, and packets are arriving
3840a3360e1SGeert Uytterhoeven faster than you can read them off, you're screwed. Hasta la
3850a3360e1SGeert Uytterhoeven vista, baby! */
3860a3360e1SGeert Uytterhoeven while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) {
3875a3b7504SFinn Thain netif_dbg(lp, intr, dev, "status=%04x\n", status);
3880a3360e1SGeert Uytterhoeven switch(status & ISQ_EVENT_MASK) {
3890a3360e1SGeert Uytterhoeven case ISQ_RECEIVER_EVENT:
3900a3360e1SGeert Uytterhoeven /* Got a packet(s). */
3910a3360e1SGeert Uytterhoeven net_rx(dev);
3920a3360e1SGeert Uytterhoeven break;
3930a3360e1SGeert Uytterhoeven case ISQ_TRANSMITTER_EVENT:
3940a3360e1SGeert Uytterhoeven dev->stats.tx_packets++;
3950a3360e1SGeert Uytterhoeven netif_wake_queue(dev);
3960a3360e1SGeert Uytterhoeven if ((status & TX_OK) == 0)
3970a3360e1SGeert Uytterhoeven dev->stats.tx_errors++;
3980a3360e1SGeert Uytterhoeven if (status & TX_LOST_CRS)
3990a3360e1SGeert Uytterhoeven dev->stats.tx_carrier_errors++;
4000a3360e1SGeert Uytterhoeven if (status & TX_SQE_ERROR)
4010a3360e1SGeert Uytterhoeven dev->stats.tx_heartbeat_errors++;
4020a3360e1SGeert Uytterhoeven if (status & TX_LATE_COL)
4030a3360e1SGeert Uytterhoeven dev->stats.tx_window_errors++;
4040a3360e1SGeert Uytterhoeven if (status & TX_16_COL)
4050a3360e1SGeert Uytterhoeven dev->stats.tx_aborted_errors++;
4060a3360e1SGeert Uytterhoeven break;
4070a3360e1SGeert Uytterhoeven case ISQ_BUFFER_EVENT:
4080a3360e1SGeert Uytterhoeven if (status & READY_FOR_TX) {
4090a3360e1SGeert Uytterhoeven /* we tried to transmit a packet earlier,
4100a3360e1SGeert Uytterhoeven but inexplicably ran out of buffers.
4110a3360e1SGeert Uytterhoeven That shouldn't happen since we only ever
4120a3360e1SGeert Uytterhoeven load one packet. Shrug. Do the right
4130a3360e1SGeert Uytterhoeven thing anyway. */
4140a3360e1SGeert Uytterhoeven netif_wake_queue(dev);
4150a3360e1SGeert Uytterhoeven }
4160a3360e1SGeert Uytterhoeven if (status & TX_UNDERRUN) {
4175a3b7504SFinn Thain netif_dbg(lp, tx_err, dev, "transmit underrun\n");
4180a3360e1SGeert Uytterhoeven lp->send_underrun++;
4190a3360e1SGeert Uytterhoeven if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
4200a3360e1SGeert Uytterhoeven else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
4210a3360e1SGeert Uytterhoeven }
4220a3360e1SGeert Uytterhoeven break;
4230a3360e1SGeert Uytterhoeven case ISQ_RX_MISS_EVENT:
4240a3360e1SGeert Uytterhoeven dev->stats.rx_missed_errors += (status >> 6);
4250a3360e1SGeert Uytterhoeven break;
4260a3360e1SGeert Uytterhoeven case ISQ_TX_COL_EVENT:
4270a3360e1SGeert Uytterhoeven dev->stats.collisions += (status >> 6);
4280a3360e1SGeert Uytterhoeven break;
4290a3360e1SGeert Uytterhoeven }
4300a3360e1SGeert Uytterhoeven }
4310a3360e1SGeert Uytterhoeven return IRQ_HANDLED;
4320a3360e1SGeert Uytterhoeven }
4330a3360e1SGeert Uytterhoeven
4340a3360e1SGeert Uytterhoeven /* We have a good packet(s), get it/them out of the buffers. */
4350a3360e1SGeert Uytterhoeven static void
net_rx(struct net_device * dev)4360a3360e1SGeert Uytterhoeven net_rx(struct net_device *dev)
4370a3360e1SGeert Uytterhoeven {
4385a3b7504SFinn Thain struct net_local *lp = netdev_priv(dev);
4390a3360e1SGeert Uytterhoeven struct sk_buff *skb;
4400a3360e1SGeert Uytterhoeven int status, length;
4410a3360e1SGeert Uytterhoeven
4420a3360e1SGeert Uytterhoeven status = readreg(dev, PP_RxStatus);
4430a3360e1SGeert Uytterhoeven if ((status & RX_OK) == 0) {
4440a3360e1SGeert Uytterhoeven dev->stats.rx_errors++;
4450a3360e1SGeert Uytterhoeven if (status & RX_RUNT)
4460a3360e1SGeert Uytterhoeven dev->stats.rx_length_errors++;
4470a3360e1SGeert Uytterhoeven if (status & RX_EXTRA_DATA)
4480a3360e1SGeert Uytterhoeven dev->stats.rx_length_errors++;
4490a3360e1SGeert Uytterhoeven if ((status & RX_CRC_ERROR) &&
4500a3360e1SGeert Uytterhoeven !(status & (RX_EXTRA_DATA|RX_RUNT)))
4510a3360e1SGeert Uytterhoeven /* per str 172 */
4520a3360e1SGeert Uytterhoeven dev->stats.rx_crc_errors++;
4530a3360e1SGeert Uytterhoeven if (status & RX_DRIBBLE)
4540a3360e1SGeert Uytterhoeven dev->stats.rx_frame_errors++;
4550a3360e1SGeert Uytterhoeven return;
4560a3360e1SGeert Uytterhoeven }
4570a3360e1SGeert Uytterhoeven
4580a3360e1SGeert Uytterhoeven length = readreg(dev, PP_RxLength);
4590a3360e1SGeert Uytterhoeven /* Malloc up new buffer. */
4600a3360e1SGeert Uytterhoeven skb = alloc_skb(length, GFP_ATOMIC);
4610a3360e1SGeert Uytterhoeven if (skb == NULL) {
4620a3360e1SGeert Uytterhoeven dev->stats.rx_dropped++;
4630a3360e1SGeert Uytterhoeven return;
4640a3360e1SGeert Uytterhoeven }
4650a3360e1SGeert Uytterhoeven skb_put(skb, length);
4660a3360e1SGeert Uytterhoeven
4670a3360e1SGeert Uytterhoeven skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame),
4680a3360e1SGeert Uytterhoeven length);
4690a3360e1SGeert Uytterhoeven
4705a3b7504SFinn Thain netif_dbg(lp, rx_status, dev, "received %d byte packet of type %x\n",
4715a3b7504SFinn Thain length, skb->data[ETH_ALEN + ETH_ALEN] << 8 |
4725a3b7504SFinn Thain skb->data[ETH_ALEN + ETH_ALEN + 1]);
4730a3360e1SGeert Uytterhoeven
4740a3360e1SGeert Uytterhoeven skb->protocol=eth_type_trans(skb,dev);
4750a3360e1SGeert Uytterhoeven netif_rx(skb);
4760a3360e1SGeert Uytterhoeven dev->stats.rx_packets++;
4770a3360e1SGeert Uytterhoeven dev->stats.rx_bytes += length;
4780a3360e1SGeert Uytterhoeven }
4790a3360e1SGeert Uytterhoeven
4800a3360e1SGeert Uytterhoeven /* The inverse routine to net_open(). */
4810a3360e1SGeert Uytterhoeven static int
net_close(struct net_device * dev)4820a3360e1SGeert Uytterhoeven net_close(struct net_device *dev)
4830a3360e1SGeert Uytterhoeven {
4840a3360e1SGeert Uytterhoeven
4850a3360e1SGeert Uytterhoeven writereg(dev, PP_RxCFG, 0);
4860a3360e1SGeert Uytterhoeven writereg(dev, PP_TxCFG, 0);
4870a3360e1SGeert Uytterhoeven writereg(dev, PP_BufCFG, 0);
4880a3360e1SGeert Uytterhoeven writereg(dev, PP_BusCTL, 0);
4890a3360e1SGeert Uytterhoeven
4900a3360e1SGeert Uytterhoeven netif_stop_queue(dev);
4910a3360e1SGeert Uytterhoeven
4920a3360e1SGeert Uytterhoeven free_irq(dev->irq, dev);
4930a3360e1SGeert Uytterhoeven
4940a3360e1SGeert Uytterhoeven /* Update the statistics here. */
4950a3360e1SGeert Uytterhoeven
4960a3360e1SGeert Uytterhoeven return 0;
4970a3360e1SGeert Uytterhoeven
4980a3360e1SGeert Uytterhoeven }
4990a3360e1SGeert Uytterhoeven
5000a3360e1SGeert Uytterhoeven /* Get the current statistics. This may be called with the card open or
5010a3360e1SGeert Uytterhoeven closed. */
5020a3360e1SGeert Uytterhoeven static struct net_device_stats *
net_get_stats(struct net_device * dev)5030a3360e1SGeert Uytterhoeven net_get_stats(struct net_device *dev)
5040a3360e1SGeert Uytterhoeven {
5050a3360e1SGeert Uytterhoeven unsigned long flags;
5060a3360e1SGeert Uytterhoeven
5070a3360e1SGeert Uytterhoeven local_irq_save(flags);
5080a3360e1SGeert Uytterhoeven /* Update the statistics from the device registers. */
5090a3360e1SGeert Uytterhoeven dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
5100a3360e1SGeert Uytterhoeven dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
5110a3360e1SGeert Uytterhoeven local_irq_restore(flags);
5120a3360e1SGeert Uytterhoeven
5130a3360e1SGeert Uytterhoeven return &dev->stats;
5140a3360e1SGeert Uytterhoeven }
5150a3360e1SGeert Uytterhoeven
set_multicast_list(struct net_device * dev)5160a3360e1SGeert Uytterhoeven static void set_multicast_list(struct net_device *dev)
5170a3360e1SGeert Uytterhoeven {
5180a3360e1SGeert Uytterhoeven struct net_local *lp = netdev_priv(dev);
5190a3360e1SGeert Uytterhoeven
5200a3360e1SGeert Uytterhoeven if(dev->flags&IFF_PROMISC)
5210a3360e1SGeert Uytterhoeven {
5220a3360e1SGeert Uytterhoeven lp->rx_mode = RX_ALL_ACCEPT;
5230a3360e1SGeert Uytterhoeven } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
5240a3360e1SGeert Uytterhoeven /* The multicast-accept list is initialized to accept-all, and we
5250a3360e1SGeert Uytterhoeven rely on higher-level filtering for now. */
5260a3360e1SGeert Uytterhoeven lp->rx_mode = RX_MULTCAST_ACCEPT;
5270a3360e1SGeert Uytterhoeven }
5280a3360e1SGeert Uytterhoeven else
5290a3360e1SGeert Uytterhoeven lp->rx_mode = 0;
5300a3360e1SGeert Uytterhoeven
5310a3360e1SGeert Uytterhoeven writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
5320a3360e1SGeert Uytterhoeven
5330a3360e1SGeert Uytterhoeven /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
5340a3360e1SGeert Uytterhoeven writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
5350a3360e1SGeert Uytterhoeven (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
5360a3360e1SGeert Uytterhoeven }
5370a3360e1SGeert Uytterhoeven
5380a3360e1SGeert Uytterhoeven
set_mac_address(struct net_device * dev,void * addr)5390a3360e1SGeert Uytterhoeven static int set_mac_address(struct net_device *dev, void *addr)
5400a3360e1SGeert Uytterhoeven {
54166dc92edSDanny Kukawka struct sockaddr *saddr = addr;
5429100eb01SDavid S. Miller int i;
54366dc92edSDanny Kukawka
5449100eb01SDavid S. Miller if (!is_valid_ether_addr(saddr->sa_data))
54566dc92edSDanny Kukawka return -EADDRNOTAVAIL;
54666dc92edSDanny Kukawka
547a96d317fSJakub Kicinski eth_hw_addr_set(dev, saddr->sa_data);
54886c2666eSFinn Thain netdev_info(dev, "Setting MAC address to %pM\n", dev->dev_addr);
54966dc92edSDanny Kukawka
5500a3360e1SGeert Uytterhoeven /* set the Ethernet address */
5510a3360e1SGeert Uytterhoeven for (i=0; i < ETH_ALEN/2; i++)
5520a3360e1SGeert Uytterhoeven writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
5530a3360e1SGeert Uytterhoeven
5540a3360e1SGeert Uytterhoeven return 0;
5550a3360e1SGeert Uytterhoeven }
5560a3360e1SGeert Uytterhoeven
557*5e736135SJeff Johnson MODULE_DESCRIPTION("Macintosh CS89x0-based Ethernet driver");
5580a3360e1SGeert Uytterhoeven MODULE_LICENSE("GPL");
5590a3360e1SGeert Uytterhoeven
mac89x0_device_remove(struct platform_device * pdev)5608ca0ae6aSUwe Kleine-König static void mac89x0_device_remove(struct platform_device *pdev)
5610a3360e1SGeert Uytterhoeven {
56243bf2e6dSFinn Thain struct net_device *dev = platform_get_drvdata(pdev);
56343bf2e6dSFinn Thain
56443bf2e6dSFinn Thain unregister_netdev(dev);
56543bf2e6dSFinn Thain nubus_writew(0, dev->base_addr + ADD_PORT);
56643bf2e6dSFinn Thain free_netdev(dev);
5670a3360e1SGeert Uytterhoeven }
5680a3360e1SGeert Uytterhoeven
56943bf2e6dSFinn Thain static struct platform_driver mac89x0_platform_driver = {
57043bf2e6dSFinn Thain .probe = mac89x0_device_probe,
5718ca0ae6aSUwe Kleine-König .remove_new = mac89x0_device_remove,
57243bf2e6dSFinn Thain .driver = {
57343bf2e6dSFinn Thain .name = "mac89x0",
57443bf2e6dSFinn Thain },
57543bf2e6dSFinn Thain };
57643bf2e6dSFinn Thain
57743bf2e6dSFinn Thain module_platform_driver(mac89x0_platform_driver);
578