diff options
Diffstat (limited to 'drivers/net/macmace.c')
| -rw-r--r-- | drivers/net/macmace.c | 710 |
1 files changed, 0 insertions, 710 deletions
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c deleted file mode 100644 index 79a6fc13975..00000000000 --- a/drivers/net/macmace.c +++ /dev/null @@ -1,710 +0,0 @@ -/* - * Driver for the Macintosh 68K onboard MACE controller with PSC - * driven DMA. The MACE driver code is derived from mace.c. The - * Mac68k theory of operation is courtesy of the MacBSD wizards. - * - * This program 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. - * - * Copyright (C) 1996 Paul Mackerras. - * Copyright (C) 1998 Alan Cox <alan@redhat.com> - * - * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver - */ - - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/crc32.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/macintosh.h> -#include <asm/macints.h> -#include <asm/mac_psc.h> -#include <asm/page.h> -#include "mace.h" - -#define N_TX_RING 1 -#define N_RX_RING 8 -#define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE) -#define TX_TIMEOUT HZ - -/* Bits in transmit DMA status */ -#define TX_DMA_ERR 0x80 - -/* The MACE is simply wired down on a Mac68K box */ - -#define MACE_BASE (void *)(0x50F1C000) -#define MACE_PROM (void *)(0x50F08001) - -struct mace_data { - volatile struct mace *mace; - volatile unsigned char *tx_ring; - volatile unsigned char *tx_ring_phys; - volatile unsigned char *rx_ring; - volatile unsigned char *rx_ring_phys; - int dma_intr; - struct net_device_stats stats; - int rx_slot, rx_tail; - int tx_slot, tx_sloti, tx_count; -}; - -struct mace_frame { - u16 len; - u16 status; - u16 rntpc; - u16 rcvcc; - u32 pad1; - u32 pad2; - u8 data[1]; - /* And frame continues.. */ -}; - -#define PRIV_BYTES sizeof(struct mace_data) - -extern void psc_debug_dump(void); - -static int mace_open(struct net_device *dev); -static int mace_close(struct net_device *dev); -static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *mace_stats(struct net_device *dev); -static void mace_set_multicast(struct net_device *dev); -static int mace_set_address(struct net_device *dev, void *addr); -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs); -static void mace_tx_timeout(struct net_device *dev); - -/* Bit-reverse one byte of an ethernet hardware address. */ - -static int bitrev(int b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) { - d = (d << 1) | (b & 1); - } - - return d; -} - -/* - * Load a receive DMA channel with a base address and ring length - */ - -static void mace_load_rxdma_base(struct net_device *dev, int set) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - - psc_write_word(PSC_ENETRD_CMD + set, 0x0100); - psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys); - psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); - psc_write_word(PSC_ENETRD_CMD + set, 0x9800); - mp->rx_tail = 0; -} - -/* - * Reset the receive DMA subsystem - */ - -static void mace_rxdma_reset(struct net_device *dev) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mace = mp->mace; - u8 maccc = mace->maccc; - - mace->maccc = maccc & ~ENRCV; - - psc_write_word(PSC_ENETRD_CTL, 0x8800); - mace_load_rxdma_base(dev, 0x00); - psc_write_word(PSC_ENETRD_CTL, 0x0400); - - psc_write_word(PSC_ENETRD_CTL, 0x8800); - mace_load_rxdma_base(dev, 0x10); - psc_write_word(PSC_ENETRD_CTL, 0x0400); - - mace->maccc = maccc; - mp->rx_slot = 0; - - psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x9800); - psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x9800); -} - -/* - * Reset the transmit DMA subsystem - */ - -static void mace_txdma_reset(struct net_device *dev) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mace = mp->mace; - u8 maccc; - - psc_write_word(PSC_ENETWR_CTL, 0x8800); - - maccc = mace->maccc; - mace->maccc = maccc & ~ENXMT; - - mp->tx_slot = mp->tx_sloti = 0; - mp->tx_count = N_TX_RING; - - psc_write_word(PSC_ENETWR_CTL, 0x0400); - mace->maccc = maccc; -} - -/* - * Disable DMA - */ - -static void mace_dma_off(struct net_device *dev) -{ - psc_write_word(PSC_ENETRD_CTL, 0x8800); - psc_write_word(PSC_ENETRD_CTL, 0x1000); - psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x1100); - psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x1100); - - psc_write_word(PSC_ENETWR_CTL, 0x8800); - psc_write_word(PSC_ENETWR_CTL, 0x1000); - psc_write_word(PSC_ENETWR_CMD + PSC_SET0, 0x1100); - psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100); -} - -/* - * Not really much of a probe. The hardware table tells us if this - * model of Macintrash has a MACE (AV macintoshes) - */ - -struct net_device *mace_probe(int unit) -{ - int j; - struct mace_data *mp; - unsigned char *addr; - struct net_device *dev; - unsigned char checksum = 0; - static int found = 0; - int err; - - if (found || macintosh_config->ether_type != MAC_ETHER_MACE) - return ERR_PTR(-ENODEV); - - found = 1; /* prevent 'finding' one on every device probe */ - - dev = alloc_etherdev(PRIV_BYTES); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) - sprintf(dev->name, "eth%d", unit); - - mp = (struct mace_data *) dev->priv; - dev->base_addr = (u32)MACE_BASE; - mp->mace = (volatile struct mace *) MACE_BASE; - - dev->irq = IRQ_MAC_MACE; - mp->dma_intr = IRQ_MAC_MACE_DMA; - - /* - * The PROM contains 8 bytes which total 0xFF when XOR'd - * together. Due to the usual peculiar apple brain damage - * the bytes are spaced out in a strange boundary and the - * bits are reversed. - */ - - addr = (void *)MACE_PROM; - - for (j = 0; j < 6; ++j) { - u8 v=bitrev(addr[j<<4]); - checksum ^= v; - dev->dev_addr[j] = v; - } - for (; j < 8; ++j) { - checksum ^= bitrev(addr[j<<4]); - } - - if (checksum != 0xFF) { - free_netdev(dev); - return ERR_PTR(-ENODEV); - } - - memset(&mp->stats, 0, sizeof(mp->stats)); - - dev->open = mace_open; - dev->stop = mace_close; - dev->hard_start_xmit = mace_xmit_start; - dev->tx_timeout = mace_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->get_stats = mace_stats; - dev->set_multicast_list = mace_set_multicast; - dev->set_mac_address = mace_set_address; - - printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]); - for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]); - printk("\n"); - - err = register_netdev(dev); - if (!err) - return dev; - - free_netdev(dev); - return ERR_PTR(err); -} - -/* - * Load the address on a mace controller. - */ - -static int mace_set_address(struct net_device *dev, void *addr) -{ - unsigned char *p = addr; - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; - int i; - unsigned long flags; - u8 maccc; - - local_irq_save(flags); - - maccc = mb->maccc; - - /* load up the hardware address */ - mb->iac = ADDRCHG | PHYADDR; - while ((mb->iac & ADDRCHG) != 0); - - for (i = 0; i < 6; ++i) { - mb->padr = dev->dev_addr[i] = p[i]; - } - - mb->maccc = maccc; - local_irq_restore(flags); - - return 0; -} - -/* - * Open the Macintosh MACE. Most of this is playing with the DMA - * engine. The ethernet chip is quite friendly. - */ - -static int mace_open(struct net_device *dev) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; -#if 0 - int i; - - i = 200; - while (--i) { - mb->biucc = SWRST; - if (mb->biucc & SWRST) { - udelay(10); - continue; - } - break; - } - if (!i) { - printk(KERN_ERR "%s: software reset failed!!\n", dev->name); - return -EAGAIN; - } -#endif - - mb->biucc = XMTSP_64; - mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST; - mb->xmtfc = AUTO_PAD_XMIT; - mb->plscc = PORTSEL_AUI; - /* mb->utr = RTRD; */ - - if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) { - printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq); - return -EAGAIN; - } - if (request_irq(mp->dma_intr, mace_dma_intr, 0, dev->name, dev)) { - printk(KERN_ERR "%s: can't get irq %d\n", dev->name, mp->dma_intr); - free_irq(dev->irq, dev); - return -EAGAIN; - } - - /* Allocate the DMA ring buffers */ - - mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES); - mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0); - - if (mp->tx_ring==NULL || mp->rx_ring==NULL) { - if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES); - if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0); - free_irq(dev->irq, dev); - free_irq(mp->dma_intr, dev); - printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name); - return -ENOMEM; - } - - mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring); - mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring); - - /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */ - - kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER); - kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH); - - mace_dma_off(dev); - - /* Not sure what these do */ - - psc_write_word(PSC_ENETWR_CTL, 0x9000); - psc_write_word(PSC_ENETRD_CTL, 0x9000); - psc_write_word(PSC_ENETWR_CTL, 0x0400); - psc_write_word(PSC_ENETRD_CTL, 0x0400); - -#if 0 - /* load up the hardware address */ - - mb->iac = ADDRCHG | PHYADDR; - - while ((mb->iac & ADDRCHG) != 0); - - for (i = 0; i < 6; ++i) - mb->padr = dev->dev_addr[i]; - - /* clear the multicast filter */ - mb->iac = ADDRCHG | LOGADDR; - - while ((mb->iac & ADDRCHG) != 0); - - for (i = 0; i < 8; ++i) - mb->ladrf = 0; - - mb->plscc = PORTSEL_GPSI + ENPLSIO; - - mb->maccc = ENXMT | ENRCV; - mb->imr = RCVINT; -#endif - - mace_rxdma_reset(dev); - mace_txdma_reset(dev); - - return 0; -} - -/* - * Shut down the mace and its interrupt channel - */ - -static int mace_close(struct net_device *dev) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; - - mb->maccc = 0; /* disable rx and tx */ - mb->imr = 0xFF; /* disable all irqs */ - mace_dma_off(dev); /* disable rx and tx dma */ - - free_irq(dev->irq, dev); - free_irq(IRQ_MAC_MACE_DMA, dev); - - free_pages((u32) mp->rx_ring, N_RX_PAGES); - free_pages((u32) mp->tx_ring, 0); - - return 0; -} - -/* - * Transmit a frame - */ - -static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - - /* Stop the queue if the buffer is full */ - - if (!mp->tx_count) { - netif_stop_queue(dev); - return 1; - } - mp->tx_count--; - - mp->stats.tx_packets++; - mp->stats.tx_bytes += skb->len; - - /* We need to copy into our xmit buffer to take care of alignment and caching issues */ - - memcpy((void *) mp->tx_ring, skb->data, skb->len); - - /* load the Tx DMA and fire it off */ - - psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, (u32) mp->tx_ring_phys); - psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); - psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); - - mp->tx_slot ^= 0x10; - - dev_kfree_skb(skb); - - return 0; -} - -static struct net_device_stats *mace_stats(struct net_device *dev) -{ - struct mace_data *p = (struct mace_data *) dev->priv; - return &p->stats; -} - -static void mace_set_multicast(struct net_device *dev) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; - int i, j; - u32 crc; - u8 maccc; - - maccc = mb->maccc; - mb->maccc &= ~PROM; - - if (dev->flags & IFF_PROMISC) { - mb->maccc |= PROM; - } else { - unsigned char multicast_filter[8]; - struct dev_mc_list *dmi = dev->mc_list; - - if (dev->flags & IFF_ALLMULTI) { - for (i = 0; i < 8; i++) { - multicast_filter[i] = 0xFF; - } - } else { - for (i = 0; i < 8; i++) - multicast_filter[i] = 0; - for (i = 0; i < dev->mc_count; i++) { - crc = ether_crc_le(6, dmi->dmi_addr); - j = crc >> 26; /* bit number in multicast_filter */ - multicast_filter[j >> 3] |= 1 << (j & 7); - dmi = dmi->next; - } - } - - mb->iac = ADDRCHG | LOGADDR; - while (mb->iac & ADDRCHG); - - for (i = 0; i < 8; ++i) { - mb->ladrf = multicast_filter[i]; - } - } - - mb->maccc = maccc; -} - -/* - * Miscellaneous interrupts are handled here. We may end up - * having to bash the chip on the head for bad errors - */ - -static void mace_handle_misc_intrs(struct mace_data *mp, int intr) -{ - volatile struct mace *mb = mp->mace; - static int mace_babbles, mace_jabbers; - - if (intr & MPCO) { - mp->stats.rx_missed_errors += 256; - } - mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ - - if (intr & RNTPCO) { - mp->stats.rx_length_errors += 256; - } - mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ - - if (intr & CERR) { - ++mp->stats.tx_heartbeat_errors; - } - if (intr & BABBLE) { - if (mace_babbles++ < 4) { - printk(KERN_DEBUG "mace: babbling transmitter\n"); - } - } - if (intr & JABBER) { - if (mace_jabbers++ < 4) { - printk(KERN_DEBUG "mace: jabbering transceiver\n"); - } - } -} - -/* - * A transmit error has occurred. (We kick the transmit side from - * the DMA completion) - */ - -static void mace_xmit_error(struct net_device *dev) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; - u8 xmtfs, xmtrc; - - xmtfs = mb->xmtfs; - xmtrc = mb->xmtrc; - - if (xmtfs & XMTSV) { - if (xmtfs & UFLO) { - printk("%s: DMA underrun.\n", dev->name); - mp->stats.tx_errors++; - mp->stats.tx_fifo_errors++; - mace_txdma_reset(dev); - } - if (xmtfs & RTRY) { - mp->stats.collisions++; - } - } -} - -/* - * A receive interrupt occurred. - */ - -static void mace_recv_interrupt(struct net_device *dev) -{ -/* struct mace_data *mp = (struct mace_data *) dev->priv; */ -// volatile struct mace *mb = mp->mace; -} - -/* - * Process the chip interrupt - */ - -static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; - u8 ir; - - ir = mb->ir; - mace_handle_misc_intrs(mp, ir); - - if (ir & XMTINT) { - mace_xmit_error(dev); - } - if (ir & RCVINT) { - mace_recv_interrupt(dev); - } - return IRQ_HANDLED; -} - -static void mace_tx_timeout(struct net_device *dev) -{ -/* struct mace_data *mp = (struct mace_data *) dev->priv; */ -// volatile struct mace *mb = mp->mace; -} - -/* - * Handle a newly arrived frame - */ - -static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) -{ - struct mace_data *mp = (struct mace_data *) dev->priv; - struct sk_buff *skb; - - if (mf->status & RS_OFLO) { - printk("%s: fifo overflow.\n", dev->name); - mp->stats.rx_errors++; - mp->stats.rx_fifo_errors++; - } - if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) - mp->stats.rx_errors++; - - if (mf->status&RS_CLSN) { - mp->stats.collisions++; - } - if (mf->status&RS_FRAMERR) { - mp->stats.rx_frame_errors++; - } - if (mf->status&RS_FCSERR) { - mp->stats.rx_crc_errors++; - } - - skb = dev_alloc_skb(mf->len+2); - if (!skb) { - mp->stats.rx_dropped++; - return; - } - skb_reserve(skb,2); - memcpy(skb_put(skb, mf->len), mf->data, mf->len); - - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - mp->stats.rx_packets++; - mp->stats.rx_bytes += mf->len; -} - -/* - * The PSC has passed us a DMA interrupt event. - */ - -static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; - int left, head; - u16 status; - u32 baka; - - /* Not sure what this does */ - - while ((baka = psc_read_long(PSC_MYSTERY)) != psc_read_long(PSC_MYSTERY)); - if (!(baka & 0x60000000)) return IRQ_NONE; - - /* - * Process the read queue - */ - - status = psc_read_word(PSC_ENETRD_CTL); - - if (status & 0x2000) { - mace_rxdma_reset(dev); - } else if (status & 0x0100) { - psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100); - - left = psc_read_long(PSC_ENETRD_LEN + mp->rx_slot); - head = N_RX_RING - left; - - /* Loop through the ring buffer and process new packages */ - - while (mp->rx_tail < head) { - mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800))); - mp->rx_tail++; - } - - /* If we're out of buffers in this ring then switch to */ - /* the other set, otherwise just reactivate this one. */ - - if (!left) { - mace_load_rxdma_base(dev, mp->rx_slot); - mp->rx_slot ^= 0x10; - } else { - psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800); - } - } - - /* - * Process the write queue - */ - - status = psc_read_word(PSC_ENETWR_CTL); - - if (status & 0x2000) { - mace_txdma_reset(dev); - } else if (status & 0x0100) { - psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100); - mp->tx_sloti ^= 0x10; - mp->tx_count++; - netif_wake_queue(dev); - } - return IRQ_HANDLED; -} - -MODULE_LICENSE("GPL"); |
