11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for the Macintosh 68K onboard MACE controller with PSC 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driven DMA. The MACE driver code is derived from mace.c. The 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mac68k theory of operation is courtesy of the MacBSD wizards. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1996 Paul Mackerras. 12113aa838ec3a235d883f8357d31d90e16c47fc89Alan Cox * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver 158b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * 168b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * Copyright (C) 2007 Finn Thain 178b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * 188b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * Converted to DMA API, converted to unified driver model, 198b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * sync'd some routines with mace.c and fixed various bugs. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/crc32.h> 30bc63eb9c7ec0eb7b091db2d82d46d1e68ff9e231Akinobu Mita#include <linux/bitrev.h> 318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#include <linux/dma-mapping.h> 328b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#include <linux/platform_device.h> 335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 34ce43aa6c142d69820a267431ea342d1bd9f6d3ceFinn Thain#include <linux/interrupt.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/macints.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mac_psc.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/page.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mace.h" 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 418b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic char mac_mace_string[] = "macmace"; 428b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 438b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_TX_BUFF_ORDER 0 448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_TX_RING (1 << N_TX_BUFF_ORDER) 458b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_RX_BUFF_ORDER 3 468b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_RX_RING (1 << N_RX_BUFF_ORDER) 478b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_TIMEOUT HZ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 508b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define MACE_BUFF_SIZE 0x800 518b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain/* Chip rev needs workaround on HW & multicast addr change */ 538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define BROKEN_ADDRCHG_REV 0x0941 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The MACE is simply wired down on a Mac68K box */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MACE_BASE (void *)(0x50F1C000) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MACE_PROM (void *)(0x50F08001) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mace_data { 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mace; 628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned char *tx_ring; 638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain dma_addr_t tx_ring_phys; 648b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned char *rx_ring; 658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain dma_addr_t rx_ring_phys; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dma_intr; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_slot, rx_tail; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_slot, tx_sloti, tx_count; 698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain int chipid; 708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct device *device; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mace_frame { 748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 rcvcnt; 758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 pad1; 768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 rcvsts; 778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 pad2; 788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 rntpc; 798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 pad3; 808b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 rcvcc; 818b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u8 pad4; 828b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u32 pad5; 838b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain u32 pad6; 846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik u8 data[1]; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* And frame continues.. */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRIV_BYTES sizeof(struct mace_data) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_open(struct net_device *dev); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_close(struct net_device *dev); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_set_multicast(struct net_device *dev); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_set_address(struct net_device *dev, void *addr); 958b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void mace_reset(struct net_device *dev); 967d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mace_interrupt(int irq, void *dev_id); 977d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mace_dma_intr(int irq, void *dev_id); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_tx_timeout(struct net_device *dev); 998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void __mace_set_address(struct net_device *dev, void *addr); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Load a receive DMA channel with a base address and ring length 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_load_rxdma_base(struct net_device *dev, int set) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1078b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + set, 0x0100); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + set, 0x9800); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->rx_tail = 0; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the receive DMA subsystem 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_rxdma_reset(struct net_device *dev) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mace = mp->mace; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 maccc = mace->maccc; 1256aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace->maccc = maccc & ~ENRCV; 1276aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x8800); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_load_rxdma_base(dev, 0x00); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x0400); 1316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x8800); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_load_rxdma_base(dev, 0x10); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x0400); 1356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace->maccc = maccc; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->rx_slot = 0; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x9800); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x9800); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the transmit DMA subsystem 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_txdma_reset(struct net_device *dev) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1498b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mace = mp->mace; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 maccc; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CTL, 0x8800); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maccc = mace->maccc; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace->maccc = maccc & ~ENXMT; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->tx_slot = mp->tx_sloti = 0; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->tx_count = N_TX_RING; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CTL, 0x0400); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace->maccc = maccc; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable DMA 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_dma_off(struct net_device *dev) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x8800); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x1000); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x1100); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x1100); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CTL, 0x8800); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CTL, 0x1000); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CMD + PSC_SET0, 0x1100); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1820d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalovstatic const struct net_device_ops mace_netdev_ops = { 1830d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov .ndo_open = mace_open, 1840d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov .ndo_stop = mace_close, 1850d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov .ndo_start_xmit = mace_xmit_start, 1860d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov .ndo_tx_timeout = mace_tx_timeout, 187afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = mace_set_multicast, 1880d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov .ndo_set_mac_address = mace_set_address, 1890d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov .ndo_change_mtu = eth_change_mtu, 1900d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov .ndo_validate_addr = eth_validate_addr, 1910d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov}; 1920d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Not really much of a probe. The hardware table tells us if this 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * model of Macintrash has a MACE (AV macintoshes) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1976aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int __devinit mace_probe(struct platform_device *pdev) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mace_data *mp; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *addr; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char checksum = 0; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 2066aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_etherdev(PRIV_BYTES); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 2098b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return -ENOMEM; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2118b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp = netdev_priv(dev); 2128b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2138b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->device = &pdev->dev; 2148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain SET_NETDEV_DEV(dev, &pdev->dev); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = (u32)MACE_BASE; 21743d620c82985b19008d87a437b4cf83f356264f7Joe Perches mp->mace = MACE_BASE; 2186aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = IRQ_MAC_MACE; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->dma_intr = IRQ_MAC_MACE_DMA; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo; 2238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The PROM contains 8 bytes which total 0xFF when XOR'd 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * together. Due to the usual peculiar apple brain damage 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the bytes are spaced out in a strange boundary and the 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits are reversed. 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr = (void *)MACE_PROM; 2326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < 6; ++j) { 234bc63eb9c7ec0eb7b091db2d82d46d1e68ff9e231Akinobu Mita u8 v = bitrev8(addr[j<<4]); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum ^= v; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dev_addr[j] = v; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; j < 8; ++j) { 239bc63eb9c7ec0eb7b091db2d82d46d1e68ff9e231Akinobu Mita checksum ^= bitrev8(addr[j<<4]); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (checksum != 0xFF) { 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 2448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return -ENODEV; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2470d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov dev->netdev_ops = &mace_netdev_ops; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->watchdog_timeo = TX_TIMEOUT; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 250e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk(KERN_INFO "%s: 68K MACE, hardware address %pM\n", 251e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, dev->dev_addr); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) 2558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return 0; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 2588b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return err; 2598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain} 2608b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain/* 2628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * Reset the chip. 2638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain */ 2648b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void mace_reset(struct net_device *dev) 2668b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{ 2678b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 2688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain volatile struct mace *mb = mp->mace; 2698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain int i; 2708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* soft-reset the chip */ 2728b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain i = 200; 2738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain while (--i) { 2748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->biucc = SWRST; 2758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mb->biucc & SWRST) { 2768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain udelay(10); 2778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain continue; 2788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 2798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain break; 2808b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 2818b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (!i) { 2828b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_ERR "macmace: cannot reset chip!\n"); 2838b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return; 2848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 2858b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->maccc = 0; /* turn off tx, rx */ 2878b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->imr = 0xFF; /* disable all intrs for now */ 2888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain i = mb->ir; 2898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2908b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->biucc = XMTSP_64; 2918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->utr = RTRD; 2928b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU; 2938b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2948b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ 2958b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->rcvfc = 0; 2968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 2978b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* load up the hardware address */ 2988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain __mace_set_address(dev, dev->dev_addr); 2998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 3008b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* clear the multicast filter */ 3018b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->chipid == BROKEN_ADDRCHG_REV) 3028b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = LOGADDR; 3038b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain else { 3048b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = ADDRCHG | LOGADDR; 3058b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain while ((mb->iac & ADDRCHG) != 0) 3068b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain ; 3078b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 3088b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain for (i = 0; i < 8; ++i) 3098b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->ladrf = 0; 3108b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 3118b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* done changing address */ 3128b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->chipid != BROKEN_ADDRCHG_REV) 3138b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = 0; 3148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 3158b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->plscc = PORTSEL_AUI; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Load the address on a mace controller. 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void __mace_set_address(struct net_device *dev, void *addr) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mb = mp->mace; 3268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned char *p = addr; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 3298b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* load up the hardware address */ 3308b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->chipid == BROKEN_ADDRCHG_REV) 3318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = PHYADDR; 3328b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain else { 3338b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = ADDRCHG | PHYADDR; 3348b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain while ((mb->iac & ADDRCHG) != 0) 3358b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain ; 3368b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 3378b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain for (i = 0; i < 6; ++i) 3388b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->padr = dev->dev_addr[i] = p[i]; 3398b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->chipid != BROKEN_ADDRCHG_REV) 3408b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = 0; 3418b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain} 3428b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 3438b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int mace_set_address(struct net_device *dev, void *addr) 3448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{ 3458b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 3468b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain volatile struct mace *mb = mp->mace; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 maccc; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maccc = mb->maccc; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain __mace_set_address(dev, addr); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb->maccc = maccc; 3578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open the Macintosh MACE. Most of this is playing with the DMA 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * engine. The ethernet chip is quite friendly. 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_open(struct net_device *dev) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mb = mp->mace; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* reset the chip */ 3748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mace_reset(dev); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) { 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_irq(mp->dma_intr, mace_dma_intr, 0, dev->name, dev)) { 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: can't get irq %d\n", dev->name, mp->dma_intr); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the DMA ring buffers */ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->tx_ring = dma_alloc_coherent(mp->device, 3898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain N_TX_RING * MACE_BUFF_SIZE, 3908b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain &mp->tx_ring_phys, GFP_KERNEL); 3918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->tx_ring == NULL) { 3928b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name); 3938b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain goto out1; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->rx_ring = dma_alloc_coherent(mp->device, 3978b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain N_RX_RING * MACE_BUFF_SIZE, 3988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain &mp->rx_ring_phys, GFP_KERNEL); 3998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->rx_ring == NULL) { 4008b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name); 4018b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain goto out2; 4028b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_dma_off(dev); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not sure what these do */ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CTL, 0x9000); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x9000); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CTL, 0x0400); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CTL, 0x0400); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_rxdma_reset(dev); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_txdma_reset(dev); 4156aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4168b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* turn it on! */ 4178b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->maccc = ENXMT | ENRCV; 4188b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* enable all interrupts except receive interrupts */ 4198b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->imr = RCVINT; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4218b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 4228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainout2: 4238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, 4248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->tx_ring, mp->tx_ring_phys); 4258b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainout1: 4268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain free_irq(dev->irq, dev); 4278b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain free_irq(mp->dma_intr, dev); 4288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return -ENOMEM; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Shut down the mace and its interrupt channel 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4346aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_close(struct net_device *dev) 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4378b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mb = mp->mace; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb->maccc = 0; /* disable rx and tx */ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb->imr = 0xFF; /* disable all irqs */ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_dma_off(dev); /* disable rx and tx dma */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transmit a frame 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 4548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned long flags; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4568b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* Stop the queue since there's only the one buffer */ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4588b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_save(flags); 4598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain netif_stop_queue(dev); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mp->tx_count) { 4618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_ERR "macmace: tx queue running but no free buffers.\n"); 4628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_restore(flags); 4638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return NETDEV_TX_BUSY; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->tx_count--; 4668b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_restore(flags); 4676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 46809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_packets++; 46909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_bytes += skb->len; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We need to copy into our xmit buffer to take care of alignment and caching issues */ 472d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, mp->tx_ring, skb->len); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* load the Tx DMA and fire it off */ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, (u32) mp->tx_ring_phys); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->tx_slot ^= 0x10; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return NETDEV_TX_OK; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_set_multicast(struct net_device *dev) 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mb = mp->mace; 491f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko int i; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 crc; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 maccc; 4948b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned long flags; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_save(flags); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maccc = mb->maccc; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb->maccc &= ~PROM; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->flags & IFF_PROMISC) { 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb->maccc |= PROM; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char multicast_filter[8]; 50422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->flags & IFF_ALLMULTI) { 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) { 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds multicast_filter[i] = 0xFF; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds multicast_filter[i] = 0; 51322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) { 51422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko crc = ether_crc_le(6, ha->addr); 515f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko /* bit number in multicast_filter */ 516f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko i = crc >> 26; 517f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko multicast_filter[i >> 3] |= 1 << (i & 7); 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5218b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->chipid == BROKEN_ADDRCHG_REV) 5228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = LOGADDR; 5238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain else { 5248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = ADDRCHG | LOGADDR; 5258b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain while ((mb->iac & ADDRCHG) != 0) 5268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain ; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain for (i = 0; i < 8; ++i) 5298b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->ladrf = multicast_filter[i]; 5308b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->chipid != BROKEN_ADDRCHG_REV) 5318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->iac = 0; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb->maccc = maccc; 5358b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_restore(flags); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5383649ba001b5d037e2cead173b6cff54d32ef154aGeert Uytterhoevenstatic void mace_handle_misc_intrs(struct net_device *dev, int intr) 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5403649ba001b5d037e2cead173b6cff54d32ef154aGeert Uytterhoeven struct mace_data *mp = netdev_priv(dev); 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mb = mp->mace; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int mace_babbles, mace_jabbers; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (intr & MPCO) 54509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_missed_errors += 256; 54609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_missed_errors += mb->mpc; /* reading clears it */ 5478b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (intr & RNTPCO) 54809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_length_errors += 256; 54909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */ 5508b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (intr & CERR) 55109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik ++dev->stats.tx_heartbeat_errors; 5528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (intr & BABBLE) 5538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mace_babbles++ < 4) 5548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_DEBUG "macmace: babbling transmitter\n"); 5558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (intr & JABBER) 5568b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mace_jabbers++ < 4) 5578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_DEBUG "macmace: jabbering transceiver\n"); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5608b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic irqreturn_t mace_interrupt(int irq, void *dev_id) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct net_device *dev = (struct net_device *) dev_id; 5638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mb = mp->mace; 5658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain int intr, fs; 566099575b6cb7eaf18211ba72de56264f67651b90bAlexey Dobriyan unsigned long flags; 5676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* don't want the dma interrupt handler to fire */ 5698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_save(flags); 5706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain intr = mb->ir; /* read interrupt register */ 5723649ba001b5d037e2cead173b6cff54d32ef154aGeert Uytterhoeven mace_handle_misc_intrs(dev, intr); 5738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 5748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (intr & XMTINT) { 5758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain fs = mb->xmtfs; 5768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if ((fs & XMTSV) == 0) { 5778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs); 5788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mace_reset(dev); 5798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* 5808b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * XXX mace likes to hang the machine after a xmtfs error. 5818b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * This is hard to reproduce, reseting *may* help 5828b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain */ 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* dma should have finished */ 5858b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (!mp->tx_count) { 5868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs); 5878b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 5888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* Update stats */ 5898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (fs & (UFLO|LCOL|LCAR|RTRY)) { 59009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik ++dev->stats.tx_errors; 5918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (fs & LCAR) 59209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik ++dev->stats.tx_carrier_errors; 5938b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain else if (fs & (UFLO|LCOL|RTRY)) { 59409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik ++dev->stats.tx_aborted_errors; 5958b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mb->xmtfs & UFLO) { 5968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_ERR "%s: DMA underrun.\n", dev->name); 59709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_fifo_errors++; 5988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mace_txdma_reset(dev); 5998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 6008b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6026aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik } 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6048b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (mp->tx_count) 6058b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain netif_wake_queue(dev); 6066aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6078b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_restore(flags); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6098b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return IRQ_HANDLED; 6108b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain} 6116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6128b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void mace_tx_timeout(struct net_device *dev) 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile struct mace *mb = mp->mace; 6168b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned long flags; 6176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6188b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_save(flags); 6196aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6208b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* turn off both tx and rx and reset the chip */ 6218b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->maccc = 0; 6228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_ERR "macmace: transmit timeout - resetting\n"); 6238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mace_txdma_reset(dev); 6248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mace_reset(dev); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* restart rx dma */ 6278b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mace_rxdma_reset(dev); 6288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 6298b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->tx_count = N_TX_RING; 6308b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain netif_wake_queue(dev); 6318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 6328b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* turn it on! */ 6338b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->maccc = ENXMT | ENRCV; 6348b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain /* enable all interrupts except receive interrupts */ 6358b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mb->imr = RCVINT; 6368b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 6378b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain local_irq_restore(flags); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle a newly arrived frame 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 6478b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned int frame_status = mf->rcvsts; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6498b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) { 65009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; 6518b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (frame_status & RS_OFLO) { 6528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name); 65309f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_fifo_errors++; 6548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 6558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (frame_status & RS_CLSN) 65609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.collisions++; 6578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (frame_status & RS_FRAMERR) 65809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_frame_errors++; 6598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (frame_status & RS_FCSERR) 66009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_crc_errors++; 6618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } else { 6628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 ); 6636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6641d266430546acf01438ae42d0a7370db4817e2adPradeep A Dalvi skb = netdev_alloc_skb(dev, frame_length + 2); 6658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain if (!skb) { 66609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_dropped++; 6678b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return; 6688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain } 6698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain skb_reserve(skb, 2); 6708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain memcpy(skb_put(skb, frame_length), mf->data, frame_length); 6718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 6728b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain skb->protocol = eth_type_trans(skb, dev); 6738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain netif_rx(skb); 67409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_packets++; 67509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_bytes += frame_length; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The PSC has passed us a DMA interrupt event. 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6837d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mace_dma_intr(int irq, void *dev_id) 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = (struct net_device *) dev_id; 6868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int left, head; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 status; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 baka; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not sure what this does */ 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((baka = psc_read_long(PSC_MYSTERY)) != psc_read_long(PSC_MYSTERY)); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(baka & 0x60000000)) return IRQ_NONE; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process the read queue 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6996aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = psc_read_word(PSC_ENETRD_CTL); 7016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & 0x2000) { 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_rxdma_reset(dev); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & 0x0100) { 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100); 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = psc_read_long(PSC_ENETRD_LEN + mp->rx_slot); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = N_RX_RING - left; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Loop through the ring buffer and process new packages */ 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (mp->rx_tail < head) { 7138b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring 7148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain + (mp->rx_tail * MACE_BUFF_SIZE))); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->rx_tail++; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we're out of buffers in this ring then switch to */ 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the other set, otherwise just reactivate this one. */ 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!left) { 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_load_rxdma_base(dev, mp->rx_slot); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->rx_slot ^= 0x10; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process the write queue 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = psc_read_word(PSC_ENETWR_CTL); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & 0x2000) { 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mace_txdma_reset(dev); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & 0x0100) { 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->tx_sloti ^= 0x10; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp->tx_count++; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 7468b6aaab8c8bdbe011aac79af218dd1e657984babFinn ThainMODULE_DESCRIPTION("Macintosh MACE ethernet driver"); 747eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn ThainMODULE_ALIAS("platform:macmace"); 7488b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7498b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int __devexit mac_mace_device_remove (struct platform_device *pdev) 7508b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{ 7518b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct net_device *dev = platform_get_drvdata(pdev); 7528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain struct mace_data *mp = netdev_priv(dev); 7538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain unregister_netdev(dev); 7558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7568b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain free_irq(dev->irq, dev); 7578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain free_irq(IRQ_MAC_MACE_DMA, dev); 7588b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE, 7608b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->rx_ring, mp->rx_ring_phys); 7618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, 7628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain mp->tx_ring, mp->tx_ring_phys); 7638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7648b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain free_netdev(dev); 7658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7668b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain return 0; 7678b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain} 7688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic struct platform_driver mac_mace_driver = { 7708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain .probe = mace_probe, 7718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain .remove = __devexit_p(mac_mace_device_remove), 7728b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain .driver = { 773eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn Thain .name = mac_mace_string, 774eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn Thain .owner = THIS_MODULE, 7758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain }, 7768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain}; 7778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int __init mac_mace_init_module(void) 7798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{ 7800f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven if (!MACH_IS_MAC) 7810f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven return -ENODEV; 7820f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven 783eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn Thain return platform_driver_register(&mac_mace_driver); 7848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain} 7858b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void __exit mac_mace_cleanup_module(void) 7878b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{ 7888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain platform_driver_unregister(&mac_mace_driver); 7898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain} 7908b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain 7918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainmodule_init(mac_mace_init_module); 7928b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainmodule_exit(mac_mace_cleanup_module); 793