18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the Macintosh 68K onboard MACE controller with PSC 48c2ecf20Sopenharmony_ci * driven DMA. The MACE driver code is derived from mace.c. The 58c2ecf20Sopenharmony_ci * Mac68k theory of operation is courtesy of the MacBSD wizards. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras. 88c2ecf20Sopenharmony_ci * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2007 Finn Thain 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Converted to DMA API, converted to unified driver model, 158c2ecf20Sopenharmony_ci * sync'd some routines with mace.c and fixed various bugs. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 228c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/string.h> 258c2ecf20Sopenharmony_ci#include <linux/crc32.h> 268c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 278c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 288c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 298c2ecf20Sopenharmony_ci#include <linux/gfp.h> 308c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 318c2ecf20Sopenharmony_ci#include <asm/io.h> 328c2ecf20Sopenharmony_ci#include <asm/macints.h> 338c2ecf20Sopenharmony_ci#include <asm/mac_psc.h> 348c2ecf20Sopenharmony_ci#include <asm/page.h> 358c2ecf20Sopenharmony_ci#include "mace.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic char mac_mace_string[] = "macmace"; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define N_TX_BUFF_ORDER 0 408c2ecf20Sopenharmony_ci#define N_TX_RING (1 << N_TX_BUFF_ORDER) 418c2ecf20Sopenharmony_ci#define N_RX_BUFF_ORDER 3 428c2ecf20Sopenharmony_ci#define N_RX_RING (1 << N_RX_BUFF_ORDER) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define TX_TIMEOUT HZ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define MACE_BUFF_SIZE 0x800 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Chip rev needs workaround on HW & multicast addr change */ 498c2ecf20Sopenharmony_ci#define BROKEN_ADDRCHG_REV 0x0941 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* The MACE is simply wired down on a Mac68K box */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define MACE_BASE (void *)(0x50F1C000) 548c2ecf20Sopenharmony_ci#define MACE_PROM (void *)(0x50F08001) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct mace_data { 578c2ecf20Sopenharmony_ci volatile struct mace *mace; 588c2ecf20Sopenharmony_ci unsigned char *tx_ring; 598c2ecf20Sopenharmony_ci dma_addr_t tx_ring_phys; 608c2ecf20Sopenharmony_ci unsigned char *rx_ring; 618c2ecf20Sopenharmony_ci dma_addr_t rx_ring_phys; 628c2ecf20Sopenharmony_ci int dma_intr; 638c2ecf20Sopenharmony_ci int rx_slot, rx_tail; 648c2ecf20Sopenharmony_ci int tx_slot, tx_sloti, tx_count; 658c2ecf20Sopenharmony_ci int chipid; 668c2ecf20Sopenharmony_ci struct device *device; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct mace_frame { 708c2ecf20Sopenharmony_ci u8 rcvcnt; 718c2ecf20Sopenharmony_ci u8 pad1; 728c2ecf20Sopenharmony_ci u8 rcvsts; 738c2ecf20Sopenharmony_ci u8 pad2; 748c2ecf20Sopenharmony_ci u8 rntpc; 758c2ecf20Sopenharmony_ci u8 pad3; 768c2ecf20Sopenharmony_ci u8 rcvcc; 778c2ecf20Sopenharmony_ci u8 pad4; 788c2ecf20Sopenharmony_ci u32 pad5; 798c2ecf20Sopenharmony_ci u32 pad6; 808c2ecf20Sopenharmony_ci u8 data[1]; 818c2ecf20Sopenharmony_ci /* And frame continues.. */ 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define PRIV_BYTES sizeof(struct mace_data) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int mace_open(struct net_device *dev); 878c2ecf20Sopenharmony_cistatic int mace_close(struct net_device *dev); 888c2ecf20Sopenharmony_cistatic netdev_tx_t mace_xmit_start(struct sk_buff *skb, struct net_device *dev); 898c2ecf20Sopenharmony_cistatic void mace_set_multicast(struct net_device *dev); 908c2ecf20Sopenharmony_cistatic int mace_set_address(struct net_device *dev, void *addr); 918c2ecf20Sopenharmony_cistatic void mace_reset(struct net_device *dev); 928c2ecf20Sopenharmony_cistatic irqreturn_t mace_interrupt(int irq, void *dev_id); 938c2ecf20Sopenharmony_cistatic irqreturn_t mace_dma_intr(int irq, void *dev_id); 948c2ecf20Sopenharmony_cistatic void mace_tx_timeout(struct net_device *dev, unsigned int txqueue); 958c2ecf20Sopenharmony_cistatic void __mace_set_address(struct net_device *dev, void *addr); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Load a receive DMA channel with a base address and ring length 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void mace_load_rxdma_base(struct net_device *dev, int set) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + set, 0x0100); 1068c2ecf20Sopenharmony_ci psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys); 1078c2ecf20Sopenharmony_ci psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); 1088c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + set, 0x9800); 1098c2ecf20Sopenharmony_ci mp->rx_tail = 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* 1138c2ecf20Sopenharmony_ci * Reset the receive DMA subsystem 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void mace_rxdma_reset(struct net_device *dev) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 1198c2ecf20Sopenharmony_ci volatile struct mace *mace = mp->mace; 1208c2ecf20Sopenharmony_ci u8 maccc = mace->maccc; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci mace->maccc = maccc & ~ENRCV; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x8800); 1258c2ecf20Sopenharmony_ci mace_load_rxdma_base(dev, 0x00); 1268c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x0400); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x8800); 1298c2ecf20Sopenharmony_ci mace_load_rxdma_base(dev, 0x10); 1308c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x0400); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci mace->maccc = maccc; 1338c2ecf20Sopenharmony_ci mp->rx_slot = 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x9800); 1368c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x9800); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * Reset the transmit DMA subsystem 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void mace_txdma_reset(struct net_device *dev) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 1468c2ecf20Sopenharmony_ci volatile struct mace *mace = mp->mace; 1478c2ecf20Sopenharmony_ci u8 maccc; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CTL, 0x8800); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci maccc = mace->maccc; 1528c2ecf20Sopenharmony_ci mace->maccc = maccc & ~ENXMT; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci mp->tx_slot = mp->tx_sloti = 0; 1558c2ecf20Sopenharmony_ci mp->tx_count = N_TX_RING; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CTL, 0x0400); 1588c2ecf20Sopenharmony_ci mace->maccc = maccc; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * Disable DMA 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void mace_dma_off(struct net_device *dev) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x8800); 1688c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x1000); 1698c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x1100); 1708c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x1100); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CTL, 0x8800); 1738c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CTL, 0x1000); 1748c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CMD + PSC_SET0, 0x1100); 1758c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic const struct net_device_ops mace_netdev_ops = { 1798c2ecf20Sopenharmony_ci .ndo_open = mace_open, 1808c2ecf20Sopenharmony_ci .ndo_stop = mace_close, 1818c2ecf20Sopenharmony_ci .ndo_start_xmit = mace_xmit_start, 1828c2ecf20Sopenharmony_ci .ndo_tx_timeout = mace_tx_timeout, 1838c2ecf20Sopenharmony_ci .ndo_set_rx_mode = mace_set_multicast, 1848c2ecf20Sopenharmony_ci .ndo_set_mac_address = mace_set_address, 1858c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * Not really much of a probe. The hardware table tells us if this 1908c2ecf20Sopenharmony_ci * model of Macintrash has a MACE (AV macintoshes) 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int mace_probe(struct platform_device *pdev) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci int j; 1968c2ecf20Sopenharmony_ci struct mace_data *mp; 1978c2ecf20Sopenharmony_ci unsigned char *addr; 1988c2ecf20Sopenharmony_ci struct net_device *dev; 1998c2ecf20Sopenharmony_ci unsigned char checksum = 0; 2008c2ecf20Sopenharmony_ci int err; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci dev = alloc_etherdev(PRIV_BYTES); 2038c2ecf20Sopenharmony_ci if (!dev) 2048c2ecf20Sopenharmony_ci return -ENOMEM; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci mp = netdev_priv(dev); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci mp->device = &pdev->dev; 2098c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 2108c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci dev->base_addr = (u32)MACE_BASE; 2138c2ecf20Sopenharmony_ci mp->mace = MACE_BASE; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci dev->irq = IRQ_MAC_MACE; 2168c2ecf20Sopenharmony_ci mp->dma_intr = IRQ_MAC_MACE_DMA; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * The PROM contains 8 bytes which total 0xFF when XOR'd 2228c2ecf20Sopenharmony_ci * together. Due to the usual peculiar apple brain damage 2238c2ecf20Sopenharmony_ci * the bytes are spaced out in a strange boundary and the 2248c2ecf20Sopenharmony_ci * bits are reversed. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci addr = MACE_PROM; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci for (j = 0; j < 6; ++j) { 2308c2ecf20Sopenharmony_ci u8 v = bitrev8(addr[j<<4]); 2318c2ecf20Sopenharmony_ci checksum ^= v; 2328c2ecf20Sopenharmony_ci dev->dev_addr[j] = v; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci for (; j < 8; ++j) { 2358c2ecf20Sopenharmony_ci checksum ^= bitrev8(addr[j<<4]); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (checksum != 0xFF) { 2398c2ecf20Sopenharmony_ci free_netdev(dev); 2408c2ecf20Sopenharmony_ci return -ENODEV; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci dev->netdev_ops = &mace_netdev_ops; 2448c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci pr_info("Onboard MACE, hardware address %pM, chip revision 0x%04X\n", 2478c2ecf20Sopenharmony_ci dev->dev_addr, mp->chipid); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci err = register_netdev(dev); 2508c2ecf20Sopenharmony_ci if (!err) 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci free_netdev(dev); 2548c2ecf20Sopenharmony_ci return err; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* 2588c2ecf20Sopenharmony_ci * Reset the chip. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void mace_reset(struct net_device *dev) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 2648c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 2658c2ecf20Sopenharmony_ci int i; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* soft-reset the chip */ 2688c2ecf20Sopenharmony_ci i = 200; 2698c2ecf20Sopenharmony_ci while (--i) { 2708c2ecf20Sopenharmony_ci mb->biucc = SWRST; 2718c2ecf20Sopenharmony_ci if (mb->biucc & SWRST) { 2728c2ecf20Sopenharmony_ci udelay(10); 2738c2ecf20Sopenharmony_ci continue; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci if (!i) { 2788c2ecf20Sopenharmony_ci printk(KERN_ERR "macmace: cannot reset chip!\n"); 2798c2ecf20Sopenharmony_ci return; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci mb->maccc = 0; /* turn off tx, rx */ 2838c2ecf20Sopenharmony_ci mb->imr = 0xFF; /* disable all intrs for now */ 2848c2ecf20Sopenharmony_ci i = mb->ir; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci mb->biucc = XMTSP_64; 2878c2ecf20Sopenharmony_ci mb->utr = RTRD; 2888c2ecf20Sopenharmony_ci mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ 2918c2ecf20Sopenharmony_ci mb->rcvfc = 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* load up the hardware address */ 2948c2ecf20Sopenharmony_ci __mace_set_address(dev, dev->dev_addr); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* clear the multicast filter */ 2978c2ecf20Sopenharmony_ci if (mp->chipid == BROKEN_ADDRCHG_REV) 2988c2ecf20Sopenharmony_ci mb->iac = LOGADDR; 2998c2ecf20Sopenharmony_ci else { 3008c2ecf20Sopenharmony_ci mb->iac = ADDRCHG | LOGADDR; 3018c2ecf20Sopenharmony_ci while ((mb->iac & ADDRCHG) != 0) 3028c2ecf20Sopenharmony_ci ; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) 3058c2ecf20Sopenharmony_ci mb->ladrf = 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* done changing address */ 3088c2ecf20Sopenharmony_ci if (mp->chipid != BROKEN_ADDRCHG_REV) 3098c2ecf20Sopenharmony_ci mb->iac = 0; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci mb->plscc = PORTSEL_AUI; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* 3158c2ecf20Sopenharmony_ci * Load the address on a mace controller. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic void __mace_set_address(struct net_device *dev, void *addr) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 3218c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 3228c2ecf20Sopenharmony_ci unsigned char *p = addr; 3238c2ecf20Sopenharmony_ci int i; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* load up the hardware address */ 3268c2ecf20Sopenharmony_ci if (mp->chipid == BROKEN_ADDRCHG_REV) 3278c2ecf20Sopenharmony_ci mb->iac = PHYADDR; 3288c2ecf20Sopenharmony_ci else { 3298c2ecf20Sopenharmony_ci mb->iac = ADDRCHG | PHYADDR; 3308c2ecf20Sopenharmony_ci while ((mb->iac & ADDRCHG) != 0) 3318c2ecf20Sopenharmony_ci ; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci for (i = 0; i < 6; ++i) 3348c2ecf20Sopenharmony_ci mb->padr = dev->dev_addr[i] = p[i]; 3358c2ecf20Sopenharmony_ci if (mp->chipid != BROKEN_ADDRCHG_REV) 3368c2ecf20Sopenharmony_ci mb->iac = 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int mace_set_address(struct net_device *dev, void *addr) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 3428c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 3438c2ecf20Sopenharmony_ci unsigned long flags; 3448c2ecf20Sopenharmony_ci u8 maccc; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci local_irq_save(flags); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci maccc = mb->maccc; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci __mace_set_address(dev, addr); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci mb->maccc = maccc; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci local_irq_restore(flags); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* 3608c2ecf20Sopenharmony_ci * Open the Macintosh MACE. Most of this is playing with the DMA 3618c2ecf20Sopenharmony_ci * engine. The ethernet chip is quite friendly. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int mace_open(struct net_device *dev) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 3678c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* reset the chip */ 3708c2ecf20Sopenharmony_ci mace_reset(dev); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) { 3738c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq); 3748c2ecf20Sopenharmony_ci return -EAGAIN; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci if (request_irq(mp->dma_intr, mace_dma_intr, 0, dev->name, dev)) { 3778c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: can't get irq %d\n", dev->name, mp->dma_intr); 3788c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 3798c2ecf20Sopenharmony_ci return -EAGAIN; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Allocate the DMA ring buffers */ 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci mp->tx_ring = dma_alloc_coherent(mp->device, 3858c2ecf20Sopenharmony_ci N_TX_RING * MACE_BUFF_SIZE, 3868c2ecf20Sopenharmony_ci &mp->tx_ring_phys, GFP_KERNEL); 3878c2ecf20Sopenharmony_ci if (mp->tx_ring == NULL) 3888c2ecf20Sopenharmony_ci goto out1; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci mp->rx_ring = dma_alloc_coherent(mp->device, 3918c2ecf20Sopenharmony_ci N_RX_RING * MACE_BUFF_SIZE, 3928c2ecf20Sopenharmony_ci &mp->rx_ring_phys, GFP_KERNEL); 3938c2ecf20Sopenharmony_ci if (mp->rx_ring == NULL) 3948c2ecf20Sopenharmony_ci goto out2; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci mace_dma_off(dev); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* Not sure what these do */ 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CTL, 0x9000); 4018c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x9000); 4028c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CTL, 0x0400); 4038c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CTL, 0x0400); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci mace_rxdma_reset(dev); 4068c2ecf20Sopenharmony_ci mace_txdma_reset(dev); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* turn it on! */ 4098c2ecf20Sopenharmony_ci mb->maccc = ENXMT | ENRCV; 4108c2ecf20Sopenharmony_ci /* enable all interrupts except receive interrupts */ 4118c2ecf20Sopenharmony_ci mb->imr = RCVINT; 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ciout2: 4158c2ecf20Sopenharmony_ci dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, 4168c2ecf20Sopenharmony_ci mp->tx_ring, mp->tx_ring_phys); 4178c2ecf20Sopenharmony_ciout1: 4188c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 4198c2ecf20Sopenharmony_ci free_irq(mp->dma_intr, dev); 4208c2ecf20Sopenharmony_ci return -ENOMEM; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* 4248c2ecf20Sopenharmony_ci * Shut down the mace and its interrupt channel 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int mace_close(struct net_device *dev) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 4308c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci mb->maccc = 0; /* disable rx and tx */ 4338c2ecf20Sopenharmony_ci mb->imr = 0xFF; /* disable all irqs */ 4348c2ecf20Sopenharmony_ci mace_dma_off(dev); /* disable rx and tx dma */ 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* 4408c2ecf20Sopenharmony_ci * Transmit a frame 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic netdev_tx_t mace_xmit_start(struct sk_buff *skb, struct net_device *dev) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 4468c2ecf20Sopenharmony_ci unsigned long flags; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Stop the queue since there's only the one buffer */ 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci local_irq_save(flags); 4518c2ecf20Sopenharmony_ci netif_stop_queue(dev); 4528c2ecf20Sopenharmony_ci if (!mp->tx_count) { 4538c2ecf20Sopenharmony_ci printk(KERN_ERR "macmace: tx queue running but no free buffers.\n"); 4548c2ecf20Sopenharmony_ci local_irq_restore(flags); 4558c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci mp->tx_count--; 4588c2ecf20Sopenharmony_ci local_irq_restore(flags); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 4618c2ecf20Sopenharmony_ci dev->stats.tx_bytes += skb->len; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* We need to copy into our xmit buffer to take care of alignment and caching issues */ 4648c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, mp->tx_ring, skb->len); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* load the Tx DMA and fire it off */ 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, (u32) mp->tx_ring_phys); 4698c2ecf20Sopenharmony_ci psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); 4708c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci mp->tx_slot ^= 0x10; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void mace_set_multicast(struct net_device *dev) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 4828c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 4838c2ecf20Sopenharmony_ci int i; 4848c2ecf20Sopenharmony_ci u32 crc; 4858c2ecf20Sopenharmony_ci u8 maccc; 4868c2ecf20Sopenharmony_ci unsigned long flags; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci local_irq_save(flags); 4898c2ecf20Sopenharmony_ci maccc = mb->maccc; 4908c2ecf20Sopenharmony_ci mb->maccc &= ~PROM; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 4938c2ecf20Sopenharmony_ci mb->maccc |= PROM; 4948c2ecf20Sopenharmony_ci } else { 4958c2ecf20Sopenharmony_ci unsigned char multicast_filter[8]; 4968c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) { 4998c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 5008c2ecf20Sopenharmony_ci multicast_filter[i] = 0xFF; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci } else { 5038c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 5048c2ecf20Sopenharmony_ci multicast_filter[i] = 0; 5058c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 5068c2ecf20Sopenharmony_ci crc = ether_crc_le(6, ha->addr); 5078c2ecf20Sopenharmony_ci /* bit number in multicast_filter */ 5088c2ecf20Sopenharmony_ci i = crc >> 26; 5098c2ecf20Sopenharmony_ci multicast_filter[i >> 3] |= 1 << (i & 7); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (mp->chipid == BROKEN_ADDRCHG_REV) 5148c2ecf20Sopenharmony_ci mb->iac = LOGADDR; 5158c2ecf20Sopenharmony_ci else { 5168c2ecf20Sopenharmony_ci mb->iac = ADDRCHG | LOGADDR; 5178c2ecf20Sopenharmony_ci while ((mb->iac & ADDRCHG) != 0) 5188c2ecf20Sopenharmony_ci ; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) 5218c2ecf20Sopenharmony_ci mb->ladrf = multicast_filter[i]; 5228c2ecf20Sopenharmony_ci if (mp->chipid != BROKEN_ADDRCHG_REV) 5238c2ecf20Sopenharmony_ci mb->iac = 0; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci mb->maccc = maccc; 5278c2ecf20Sopenharmony_ci local_irq_restore(flags); 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void mace_handle_misc_intrs(struct net_device *dev, int intr) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 5338c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 5348c2ecf20Sopenharmony_ci static int mace_babbles, mace_jabbers; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (intr & MPCO) 5378c2ecf20Sopenharmony_ci dev->stats.rx_missed_errors += 256; 5388c2ecf20Sopenharmony_ci dev->stats.rx_missed_errors += mb->mpc; /* reading clears it */ 5398c2ecf20Sopenharmony_ci if (intr & RNTPCO) 5408c2ecf20Sopenharmony_ci dev->stats.rx_length_errors += 256; 5418c2ecf20Sopenharmony_ci dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */ 5428c2ecf20Sopenharmony_ci if (intr & CERR) 5438c2ecf20Sopenharmony_ci ++dev->stats.tx_heartbeat_errors; 5448c2ecf20Sopenharmony_ci if (intr & BABBLE) 5458c2ecf20Sopenharmony_ci if (mace_babbles++ < 4) 5468c2ecf20Sopenharmony_ci printk(KERN_DEBUG "macmace: babbling transmitter\n"); 5478c2ecf20Sopenharmony_ci if (intr & JABBER) 5488c2ecf20Sopenharmony_ci if (mace_jabbers++ < 4) 5498c2ecf20Sopenharmony_ci printk(KERN_DEBUG "macmace: jabbering transceiver\n"); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic irqreturn_t mace_interrupt(int irq, void *dev_id) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *) dev_id; 5558c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 5568c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 5578c2ecf20Sopenharmony_ci int intr, fs; 5588c2ecf20Sopenharmony_ci unsigned long flags; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* don't want the dma interrupt handler to fire */ 5618c2ecf20Sopenharmony_ci local_irq_save(flags); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci intr = mb->ir; /* read interrupt register */ 5648c2ecf20Sopenharmony_ci mace_handle_misc_intrs(dev, intr); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (intr & XMTINT) { 5678c2ecf20Sopenharmony_ci fs = mb->xmtfs; 5688c2ecf20Sopenharmony_ci if ((fs & XMTSV) == 0) { 5698c2ecf20Sopenharmony_ci printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs); 5708c2ecf20Sopenharmony_ci mace_reset(dev); 5718c2ecf20Sopenharmony_ci /* 5728c2ecf20Sopenharmony_ci * XXX mace likes to hang the machine after a xmtfs error. 5738c2ecf20Sopenharmony_ci * This is hard to reproduce, resetting *may* help 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci /* dma should have finished */ 5778c2ecf20Sopenharmony_ci if (!mp->tx_count) { 5788c2ecf20Sopenharmony_ci printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci /* Update stats */ 5818c2ecf20Sopenharmony_ci if (fs & (UFLO|LCOL|LCAR|RTRY)) { 5828c2ecf20Sopenharmony_ci ++dev->stats.tx_errors; 5838c2ecf20Sopenharmony_ci if (fs & LCAR) 5848c2ecf20Sopenharmony_ci ++dev->stats.tx_carrier_errors; 5858c2ecf20Sopenharmony_ci else if (fs & (UFLO|LCOL|RTRY)) { 5868c2ecf20Sopenharmony_ci ++dev->stats.tx_aborted_errors; 5878c2ecf20Sopenharmony_ci if (mb->xmtfs & UFLO) { 5888c2ecf20Sopenharmony_ci dev->stats.tx_fifo_errors++; 5898c2ecf20Sopenharmony_ci mace_txdma_reset(dev); 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (mp->tx_count) 5968c2ecf20Sopenharmony_ci netif_wake_queue(dev); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci local_irq_restore(flags); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic void mace_tx_timeout(struct net_device *dev, unsigned int txqueue) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 6068c2ecf20Sopenharmony_ci volatile struct mace *mb = mp->mace; 6078c2ecf20Sopenharmony_ci unsigned long flags; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci local_irq_save(flags); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* turn off both tx and rx and reset the chip */ 6128c2ecf20Sopenharmony_ci mb->maccc = 0; 6138c2ecf20Sopenharmony_ci printk(KERN_ERR "macmace: transmit timeout - resetting\n"); 6148c2ecf20Sopenharmony_ci mace_txdma_reset(dev); 6158c2ecf20Sopenharmony_ci mace_reset(dev); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* restart rx dma */ 6188c2ecf20Sopenharmony_ci mace_rxdma_reset(dev); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci mp->tx_count = N_TX_RING; 6218c2ecf20Sopenharmony_ci netif_wake_queue(dev); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* turn it on! */ 6248c2ecf20Sopenharmony_ci mb->maccc = ENXMT | ENRCV; 6258c2ecf20Sopenharmony_ci /* enable all interrupts except receive interrupts */ 6268c2ecf20Sopenharmony_ci mb->imr = RCVINT; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci local_irq_restore(flags); 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci/* 6328c2ecf20Sopenharmony_ci * Handle a newly arrived frame 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct sk_buff *skb; 6388c2ecf20Sopenharmony_ci unsigned int frame_status = mf->rcvsts; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) { 6418c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 6428c2ecf20Sopenharmony_ci if (frame_status & RS_OFLO) 6438c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 6448c2ecf20Sopenharmony_ci if (frame_status & RS_CLSN) 6458c2ecf20Sopenharmony_ci dev->stats.collisions++; 6468c2ecf20Sopenharmony_ci if (frame_status & RS_FRAMERR) 6478c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors++; 6488c2ecf20Sopenharmony_ci if (frame_status & RS_FCSERR) 6498c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 ); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, frame_length + 2); 6548c2ecf20Sopenharmony_ci if (!skb) { 6558c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 6568c2ecf20Sopenharmony_ci return; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci skb_reserve(skb, 2); 6598c2ecf20Sopenharmony_ci skb_put_data(skb, mf->data, frame_length); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 6628c2ecf20Sopenharmony_ci netif_rx(skb); 6638c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 6648c2ecf20Sopenharmony_ci dev->stats.rx_bytes += frame_length; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci/* 6698c2ecf20Sopenharmony_ci * The PSC has passed us a DMA interrupt event. 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic irqreturn_t mace_dma_intr(int irq, void *dev_id) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *) dev_id; 6758c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 6768c2ecf20Sopenharmony_ci int left, head; 6778c2ecf20Sopenharmony_ci u16 status; 6788c2ecf20Sopenharmony_ci u32 baka; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* Not sure what this does */ 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci while ((baka = psc_read_long(PSC_MYSTERY)) != psc_read_long(PSC_MYSTERY)); 6838c2ecf20Sopenharmony_ci if (!(baka & 0x60000000)) return IRQ_NONE; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* 6868c2ecf20Sopenharmony_ci * Process the read queue 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci status = psc_read_word(PSC_ENETRD_CTL); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (status & 0x2000) { 6928c2ecf20Sopenharmony_ci mace_rxdma_reset(dev); 6938c2ecf20Sopenharmony_ci } else if (status & 0x0100) { 6948c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci left = psc_read_long(PSC_ENETRD_LEN + mp->rx_slot); 6978c2ecf20Sopenharmony_ci head = N_RX_RING - left; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* Loop through the ring buffer and process new packages */ 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci while (mp->rx_tail < head) { 7028c2ecf20Sopenharmony_ci mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring 7038c2ecf20Sopenharmony_ci + (mp->rx_tail * MACE_BUFF_SIZE))); 7048c2ecf20Sopenharmony_ci mp->rx_tail++; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* If we're out of buffers in this ring then switch to */ 7088c2ecf20Sopenharmony_ci /* the other set, otherwise just reactivate this one. */ 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (!left) { 7118c2ecf20Sopenharmony_ci mace_load_rxdma_base(dev, mp->rx_slot); 7128c2ecf20Sopenharmony_ci mp->rx_slot ^= 0x10; 7138c2ecf20Sopenharmony_ci } else { 7148c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* 7198c2ecf20Sopenharmony_ci * Process the write queue 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci status = psc_read_word(PSC_ENETWR_CTL); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (status & 0x2000) { 7258c2ecf20Sopenharmony_ci mace_txdma_reset(dev); 7268c2ecf20Sopenharmony_ci } else if (status & 0x0100) { 7278c2ecf20Sopenharmony_ci psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100); 7288c2ecf20Sopenharmony_ci mp->tx_sloti ^= 0x10; 7298c2ecf20Sopenharmony_ci mp->tx_count++; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Macintosh MACE ethernet driver"); 7368c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:macmace"); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic int mac_mace_device_remove(struct platform_device *pdev) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 7418c2ecf20Sopenharmony_ci struct mace_data *mp = netdev_priv(dev); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci unregister_netdev(dev); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 7468c2ecf20Sopenharmony_ci free_irq(IRQ_MAC_MACE_DMA, dev); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE, 7498c2ecf20Sopenharmony_ci mp->rx_ring, mp->rx_ring_phys); 7508c2ecf20Sopenharmony_ci dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, 7518c2ecf20Sopenharmony_ci mp->tx_ring, mp->tx_ring_phys); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci free_netdev(dev); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic struct platform_driver mac_mace_driver = { 7598c2ecf20Sopenharmony_ci .probe = mace_probe, 7608c2ecf20Sopenharmony_ci .remove = mac_mace_device_remove, 7618c2ecf20Sopenharmony_ci .driver = { 7628c2ecf20Sopenharmony_ci .name = mac_mace_string, 7638c2ecf20Sopenharmony_ci }, 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cimodule_platform_driver(mac_mace_driver); 767