📄 macmace.c
字号:
/* * 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> */#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/timer.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 "mace.h"#define N_RX_RING 8#define N_TX_RING 2#define MAX_TX_ACTIVE 1#define NCMDS_TX 1 /* dma commands per element in tx ring */#define RX_BUFLEN (ETH_FRAME_LEN + 8)#define TX_TIMEOUT HZ /* 1 second *//* 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 mace68k_data{ volatile struct mace *mace; volatile unsigned char *tx_ring; volatile unsigned char *rx_ring; int dma_intr; unsigned char maccc; struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; int rx_slot, rx_done; int tx_slot, 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 mace68k_data)extern void psc_debug_dump(void);static int mace68k_open(struct net_device *dev);static int mace68k_close(struct net_device *dev);static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev);static struct net_device_stats *mace68k_stats(struct net_device *dev);static void mace68k_set_multicast(struct net_device *dev);static void mace68k_reset(struct net_device *dev);static int mace68k_set_address(struct net_device *dev, void *addr);static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs);static void mace68k_set_timeout(struct net_device *dev);static void mace68k_tx_timeout(unsigned long data);/* * PSC DMA engine control. As you'd expect on a macintosh its * more like a lawnmower engine supplied without instructions * * The basic theory of operation appears to be as follows. * * There are two sets of receive DMA registers and two sets * of transmit DMA registers. Instead of the more traditional * "ring buffer" approach the Mac68K DMA engine expects you * to be loading one chain while the other runs, and then * to flip register set. Each entry in the chain is a fixed * length. *//* * Load a receive DMA channel with a base address and ring length */ static void psc_load_rxdma_base(int set, void *base){ psc_write_word(PSC_ENETRD_CMD + set, 0x0100); psc_write_long(PSC_ENETRD_ADDR + set, (u32)base); psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); psc_write_word(PSC_ENETRD_CMD + set, 0x9800);}/* * Reset the receive DMA subsystem */ static void mace68k_rxdma_reset(struct net_device *dev){ struct mace68k_data *mp = (struct mace68k_data *) dev->priv; volatile struct mace *mace = mp->mace; u8 mcc = mace->maccc; /* * Turn off receive */ mcc&=~ENRCV; mace->maccc=mcc; /* * Program the DMA */ psc_write_word(PSC_ENETRD_CTL, 0x8800); psc_load_rxdma_base(0x0, (void *)virt_to_bus(mp->rx_ring)); psc_write_word(PSC_ENETRD_CTL, 0x0400); psc_write_word(PSC_ENETRD_CTL, 0x8800); psc_load_rxdma_base(0x10, (void *)virt_to_bus(mp->rx_ring)); psc_write_word(PSC_ENETRD_CTL, 0x0400); mace->maccc=mcc|ENRCV; #if 0 psc_write_word(PSC_ENETRD_CTL, 0x9800); psc_write_word(PSC_ENETRD_CTL+0x10, 0x9800);#endif}/* * Reset the transmit DMA subsystem */ static void mace68k_txdma_reset(struct net_device *dev){ struct mace68k_data *mp = (struct mace68k_data *) dev->priv; volatile struct mace *mace = mp->mace; u8 mcc = mace->maccc; psc_write_word(PSC_ENETWR_CTL,0x8800); mace->maccc = mcc&~ENXMT; psc_write_word(PSC_ENETWR_CTL,0x0400); mace->maccc = mcc;}/* * Disable DMA */ static void mace68k_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, 0x1100); psc_write_word(PSC_ENETRD_CMD+0x10, 0x1100); psc_write_word(PSC_ENETWR_CTL, 0x8800); psc_write_word(PSC_ENETWR_CTL, 0x1000); psc_write_word(PSC_ENETWR_CMD, 0x1100); psc_write_word(PSC_ENETWR_CMD+0x10, 0x1100);}/* 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;}/* * Not really much of a probe. The hardware table tells us if this * model of Macintrash has a MACE (AV macintoshes) */ int mace68k_probe(struct net_device *unused){ int j; static int once=0; struct mace68k_data *mp; unsigned char *addr; struct net_device *dev; unsigned char checksum = 0; /* * There can be only one... */ if (once) return -ENODEV; once = 1; if (macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; printk("MACE ethernet should be present "); dev = init_etherdev(0, PRIV_BYTES); if(dev==NULL) { printk("no free memory.\n"); return -ENOMEM; } mp = (struct mace68k_data *) dev->priv; dev->base_addr = (u32)MACE_BASE; mp->mace = (volatile struct mace *) MACE_BASE; printk("at 0x%p", mp->mace); /* * 16K RX ring and 4K TX ring should do nicely */ mp->rx_ring=(void *)__get_free_pages(GFP_KERNEL, 2); mp->tx_ring=(void *)__get_free_page(GFP_KERNEL); printk("."); if(mp->tx_ring==NULL || mp->rx_ring==NULL) { if(mp->tx_ring) free_page((u32)mp->tx_ring);// if(mp->rx_ring)// __free_pages(mp->rx_ring,2); printk("\nNo memory for ring buffers.\n"); return -ENOMEM; } /* We want the receive data to be uncached. We dont care about the byte reading order */ printk("."); kernel_set_cachemode((void *)mp->rx_ring, 16384, IOMAP_NOCACHE_NONSER); printk("."); /* The transmit buffer needs to be write through */ kernel_set_cachemode((void *)mp->tx_ring, 4096, IOMAP_WRITETHROUGH); printk(" Ok\n"); dev->irq = IRQ_MAC_MACE; printk(KERN_INFO "%s: MACE at", dev->name); /* * 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; printk("%c%.2x", (j ? ':' : ' '), dev->dev_addr[j]); } for (; j < 8; ++j) { checksum^=bitrev(addr[j<<4]); } if(checksum!=0xFF) { printk(" (invalid checksum)\n"); return -ENODEV; } printk("\n"); memset(&mp->stats, 0, sizeof(mp->stats)); init_timer(&mp->tx_timeout); mp->timeout_active = 0; dev->open = mace68k_open; dev->stop = mace68k_close; dev->hard_start_xmit = mace68k_xmit_start; dev->get_stats = mace68k_stats; dev->set_multicast_list = mace68k_set_multicast; dev->set_mac_address = mace68k_set_address; ether_setup(dev); mp = (struct mace68k_data *) dev->priv; mp->maccc = ENXMT | ENRCV; mp->dma_intr = IRQ_MAC_MACE_DMA; 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); /* apple's driver doesn't seem to do this */ /* except at driver shutdown time... */#if 0 mace68k_dma_off(dev);#endif return 0;}/* * Reset a MACE controller */ static void mace68k_reset(struct net_device *dev){ struct mace68k_data *mp = (struct mace68k_data *) dev->priv; volatile struct mace *mb = mp->mace; int i; /* soft-reset the chip */ i = 200; while (--i) { mb->biucc = SWRST; if (mb->biucc & SWRST) { udelay(10); continue; } break; } if (!i) { printk(KERN_ERR "mace: cannot reset chip!\n"); return; } mb->biucc = XMTSP_64; mb->imr = 0xff; /* disable all intrs for now */ i = mb->ir; mb->maccc = 0; /* turn off tx, rx */ mb->utr = RTRD; mb->fifocc = RCVFW_64; mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ /* 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;}/* * Load the address on a mace controller. */ static int mace68k_set_address(struct net_device *dev, void *addr){ unsigned char *p = addr; struct mace68k_data *mp = (struct mace68k_data *) dev->priv; volatile struct mace *mb = mp->mace; int i; unsigned long flags; save_flags(flags); cli(); /* 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]; /* note: setting ADDRCHG clears ENRCV */ mb->maccc = mp->maccc; restore_flags(flags); return 0;}/* * Open the Macintosh MACE. Most of this is playing with the DMA * engine. The ethernet chip is quite friendly. */ static int mace68k_open(struct net_device *dev){ struct mace68k_data *mp = (struct mace68k_data *) dev->priv; volatile struct mace *mb = mp->mace;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -