11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc91x.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1996 by Erik Stahlman 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 Standard Microsystems Corporation 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Developed by Simple Network Magic Corporation 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Monta Vista Software, Inc. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unified SMC91x driver by Nicolas Pitre 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments: 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * io = for the base address 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * irq = for the IRQ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nowait = 0 for normal wait states, 1 eliminates additional wait states 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * original author: 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Erik Stahlman <erik@vt.edu> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware multicast code: 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Peter Cammaert <pc@denkart.be> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * contributors: 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Daris A Nevil <dnevil@snmc.com> 382f82af08fcc7dc01a7e98a49a5995a77e32a2925Nicolas Pitre * Nicolas Pitre <nico@fluxnic.net> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Russell King <rmk@arm.linux.org.uk> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * History: 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 08/22/01 Scott Anderson merge changes from smc9194 to smc91111 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races, 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * more bus abstraction, big cleanup, etc. 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29/09/03 Russell King - add driver model support 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - ethtool support 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - convert to use generic MII interface 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - add link up/down notification 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - don't try to handle full negotiation in 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_phy_configure 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - clean up (and fix stack overrun) in PHY 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MII read/write functions 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22/09/04 Nicolas Pitre big update (see commit log for details) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char version[] = 612f82af08fcc7dc01a7e98a49a5995a77e32a2925Nicolas Pitre "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@fluxnic.net>\n"; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Debugging level */ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SMC_DEBUG 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMC_DEBUG 0 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 75476c32c47a84fcf8033b93c588761405fefb3980David Howells#include <linux/irq.h> 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/crc32.h> 79d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ethtool.h> 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mii.h> 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h> 84682a1694115ec1c8fcd794c35b80354166978207Thomas Chou#include <linux/of.h> 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "smc91x.h" 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SMC_NOWAIT 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define SMC_NOWAIT 0 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nowait = SMC_NOWAIT; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(nowait, int, 0400); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(nowait, "set to 1 for no wait state"); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transmit timeout, default 5 seconds. 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 104ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitrestatic int watchdog = 1000; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(watchdog, int, 0400); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 10972abb46101fb5c47a9592914adb221b430ff26bdKay SieversMODULE_ALIAS("platform:smc91x"); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The internal workings of the driver. If you are changing anything 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here with the SMC stuff, you should have the datasheet and know 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * what you are doing. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CARDNAME "smc91x" 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use power-down feature of the chip 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define POWER_DOWN 1 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait time for memory to be free. This probably shouldn't be 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tuned that much, as waiting for this means nothing else happens 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the system 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MEMORY_WAIT_TIME 16 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1315d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre * The maximum number of processing loops allowed for each call to the 1326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * IRQ handler. 1335d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre */ 1345d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre#define MAX_IRQ_LOOPS 8 1355d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre 1365d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre/* 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This selects whether TX packets are sent one by one to the SMC91x internal 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * memory and throttled until transmission completes. This may prevent 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RX overruns a litle by keeping much of the memory free for RX packets 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but to the expense of reduced TX throughput and increased IRQ overhead. 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note this is not a cure for a too slow data bus or too high IRQ latency. 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define THROTTLE_TX_PKTS 0 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The MII clock high/low times. 2x this number gives the MII clock period 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MII_DELAY 1 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SMC_DEBUG > 0 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(n, args...) \ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { \ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SMC_DEBUG >= (n)) \ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(args); \ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRINTK(args...) printk(args) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(n, args...) do { } while(0) 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRINTK(args...) printk(KERN_DEBUG args) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SMC_DEBUG > 3 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void PRINT_PKT(u_char *buf, int length) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int remainder; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lines; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lines = length / 16; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remainder = length % 16; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < lines ; i ++) { 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cur; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cur = 0; cur < 8; cur++) { 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char a, b; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a = *buf++; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b = *buf++; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%02x%02x ", a, b); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < remainder/2 ; i++) { 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char a, b; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a = *buf++; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b = *buf++; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%02x%02x ", a, b); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRINT_PKT(x...) do { } while(0) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* this enables an interrupt in the interrupt mask register */ 198cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm#define SMC_ENABLE_INT(lp, x) do { \ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mask; \ 2008ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng unsigned long smc_enable_flags; \ 2018ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng spin_lock_irqsave(&lp->lock, smc_enable_flags); \ 202cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm mask = SMC_GET_INT_MASK(lp); \ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= (x); \ 204cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, mask); \ 2058ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng spin_unlock_irqrestore(&lp->lock, smc_enable_flags); \ 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* this disables an interrupt from the interrupt mask register */ 209cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm#define SMC_DISABLE_INT(lp, x) do { \ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mask; \ 2118ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng unsigned long smc_disable_flags; \ 2128ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng spin_lock_irqsave(&lp->lock, smc_disable_flags); \ 213cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm mask = SMC_GET_INT_MASK(lp); \ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask &= ~(x); \ 215cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, mask); \ 2168ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng spin_unlock_irqrestore(&lp->lock, smc_disable_flags); \ 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait while MMU is busy. This is usually in the order of a few nanosecs 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if at all, but let's avoid deadlocking the system if the hardware 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * decides to go south. 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 224cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm#define SMC_WAIT_MMU_BUSY(lp) do { \ 225cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm if (unlikely(SMC_GET_MMU_CMD(lp) & MC_BUSY)) { \ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long timeout = jiffies + 2; \ 227cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm while (SMC_GET_MMU_CMD(lp) & MC_BUSY) { \ 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, timeout)) { \ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: timeout %s line %d\n", \ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, __FILE__, __LINE__); \ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; \ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } \ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_relax(); \ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } \ 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } \ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this does a soft reset on the device 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_reset(struct net_device *dev) 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ctl, cfg; 247be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre struct sk_buff *pending_skb; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 249b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre /* Disable all interrupts, block TX tasklet */ 25276cb4fe7c0926c2c59f4a36ab169aa2d547c93d1Russell King spin_lock_irq(&lp->lock); 253cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 254cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, 0); 255be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre pending_skb = lp->pending_tx_skb; 256be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre lp->pending_tx_skb = NULL; 25776cb4fe7c0926c2c59f4a36ab169aa2d547c93d1Russell King spin_unlock_irq(&lp->lock); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 259be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre /* free any pending tx skb */ 260be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre if (pending_skb) { 261be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre dev_kfree_skb(pending_skb); 26209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_errors++; 26309f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_aborted_errors++; 264be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre } 265be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This resets the registers mostly to defaults, but doesn't 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * affect EEPROM. That seems unnecessary 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 270cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 271cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_RCR(lp, RCR_SOFTRST); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup the Configuration Register 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is necessary because the CONFIG_REG is not affected 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by a soft reset 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 278cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 1); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfg = CONFIG_DEFAULT; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup for fast accesses if requested. If the card/system 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't handle it then there will be no recovery except for 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a hard reset or power cycle 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 287c4f0e76747e80578a8f7fddd82fd0ce8127bd2f8Eric Miao if (lp->cfg.flags & SMC91X_NOWAIT) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfg |= CONFIG_NO_WAIT; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release from possible power-down state 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configuration register is not affected by Soft Reset 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfg |= CONFIG_EPH_POWER_EN; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 296cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_CONFIG(lp, cfg); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this should pause enough for the chip to be happy */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * elaborate? What does the chip _need_? --jgarzik 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This seems to be undocumented, but something the original 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver(s) have always done. Suspect undocumented timing 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * info/determined empirically. --rmk 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable transmit and receive functionality */ 309cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 310cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_RCR(lp, RCR_CLEAR); 311cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_TCR(lp, TCR_CLEAR); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 313cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 1); 314cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm ctl = SMC_GET_CTL(lp) | CTL_LE_ENABLE; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the control register to automatically release successfully 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transmitted packets, to make the best use out of our limited 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * memory 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!THROTTLE_TX_PKTS) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctl |= CTL_AUTO_RELEASE; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctl &= ~CTL_AUTO_RELEASE; 325cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_CTL(lp, ctl); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset the MMU */ 328cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 329cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_RESET); 330cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_WAIT_MMU_BUSY(lp); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable Interrupts, Receive, and Transmit 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_enable(struct net_device *dev) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 342b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see the header file for options in TCR/RCR DEFAULT */ 345cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 346cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_TCR(lp, lp->tcr_cur_mode); 347cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_RCR(lp, lp->rcr_cur_mode); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 349cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 1); 350cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MAC_ADDR(lp, dev->dev_addr); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now, enable interrupts */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->version >= (CHIP_91100 << 4)) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= IM_MDINT; 356cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 357cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, mask); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * From this point the register bank must _NOT_ be switched away 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to something else than bank 2 without proper locking against 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * races with any tasklet or interrupt handlers until smc_shutdown() 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or smc_reset() is called. 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this puts the device in an inactive state 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_shutdown(struct net_device *dev) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 374be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre struct sk_buff *pending_skb; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 376b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", CARDNAME, __func__); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no more interrupts for me */ 37976cb4fe7c0926c2c59f4a36ab169aa2d547c93d1Russell King spin_lock_irq(&lp->lock); 380cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 381cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, 0); 382be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre pending_skb = lp->pending_tx_skb; 383be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre lp->pending_tx_skb = NULL; 38476cb4fe7c0926c2c59f4a36ab169aa2d547c93d1Russell King spin_unlock_irq(&lp->lock); 385be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre if (pending_skb) 386be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre dev_kfree_skb(pending_skb); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* and tell the card to stay away from that nasty outside world */ 389cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 390cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_RCR(lp, RCR_CLEAR); 391cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_TCR(lp, TCR_CLEAR); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef POWER_DOWN 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* finally, shut the chip down */ 395cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 1); 396cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_CONFIG(lp, SMC_GET_CONFIG(lp) & ~CONFIG_EPH_POWER_EN); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the procedure to handle the receipt of a packet. 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void smc_rcv(struct net_device *dev) 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int packet_number, status, packet_len; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 409b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(3, "%s: %s\n", dev->name, __func__); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm packet_number = SMC_GET_RXFIFO(lp); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(packet_number & RXFIFO_REMPTY)) { 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read from start of packet */ 418cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_PTR(lp, PTR_READ | PTR_RCV | PTR_AUTOINC); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First two words are status and packet length */ 421cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_GET_PKT_HDR(lp, status, packet_len); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet_len &= 0x07ff; /* mask off top bits */ 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, packet_number, status, 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet_len, packet_len); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds back: 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(packet_len < 6 || status & RS_ERRORS)) { 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) { 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* accept VLAN packets */ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= ~RS_TOOLONG; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto back; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (packet_len < 6) { 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bloody hardware */ 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: fubar (rxlen %u status %x\n", 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, packet_len, status); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status |= RS_TOOSHORT; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 440cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_WAIT_MMU_BUSY(lp); 441cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_RELEASE); 44209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & RS_ALGNERR) 44409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_frame_errors++; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (RS_TOOSHORT | RS_TOOLONG)) 44609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_length_errors++; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & RS_BADCRC) 44809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_crc_errors++; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int data_len; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set multicast stats */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & RS_MULTICAST) 45609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.multicast++; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Actual payload is packet_len - 6 (or 5 if odd byte). 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We want skb_reserve(2) and the final ctrl word 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (2 bytes, possibly containing the payload odd byte). 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Furthermore, we add 2 bytes to allow rounding up to 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multiple of 4 bytes on 32 bit buses. 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hence packet_len - 6 + 2 + 2 + 2. 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = dev_alloc_skb(packet_len); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(skb == NULL)) { 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name); 470cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_WAIT_MMU_BUSY(lp); 471cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_RELEASE); 47209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_dropped++; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Align IP header to 32 bits */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 2); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->version == 0x90) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status |= RS_ODDFRAME; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If odd length: packet_len - 5, 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * otherwise packet_len - 6. 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * With the trailing ctrl byte it's packet_len - 4. 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = skb_put(skb, data_len); 490cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_PULL_DATA(lp, data, packet_len - 4); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 492cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_WAIT_MMU_BUSY(lp); 493cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_RELEASE); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINT_PKT(data, packet_len - 4); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, dev); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 49909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_packets++; 50009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_bytes += data_len; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SMP 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On SMP we have the following problem: 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A = smc_hardware_send_pkt() 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * B = smc_hard_start_xmit() 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * C = smc_interrupt() 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A and B can never be executed simultaneously. However, at least on UP, 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is possible (and even desirable) for C to interrupt execution of 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A or B in order to have better RX reliability and avoid overruns. 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * C, just like A and B, must have exclusive access to the chip and 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * each of them must lock against any other concurrent access. 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unfortunately this is not possible to have C suspend execution of A or 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * B taking place on another CPU. On UP this is no an issue since A and B 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are run from softirq context and C from hard IRQ context, and there is 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no other CPU where concurrent access can happen. 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If ever there is a way to force at least B and C to always be executed 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on the same CPU then we could use read/write locks to protect against 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any other concurrent access and C would always interrupt B. But life 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isn't that easy in a SMP world... 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5268ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng#define smc_special_trylock(lock, flags) \ 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds({ \ 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int __ret; \ 5298ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng local_irq_save(flags); \ 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ret = spin_trylock(lock); \ 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!__ret) \ 5328ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng local_irq_restore(flags); \ 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ret; \ 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}) 5350b4f2928f14c4a9770b0866923fc81beb7f4aa57Alexey Dobriyan#define smc_special_lock(lock, flags) spin_lock_irqsave(lock, flags) 5368ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng#define smc_special_unlock(lock, flags) spin_unlock_irqrestore(lock, flags) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 538fd0775bfc9feb036e6efb669133d644ae29e12b8Mike Frysinger#define smc_special_trylock(lock, flags) (flags == flags) 539fd0775bfc9feb036e6efb669133d644ae29e12b8Mike Frysinger#define smc_special_lock(lock, flags) do { flags = 0; } while (0) 540fd0775bfc9feb036e6efb669133d644ae29e12b8Mike Frysinger#define smc_special_unlock(lock, flags) do { flags = 0; } while (0) 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is called to actually send a packet to the chip. 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_hardware_send_pkt(unsigned long data) 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = (struct net_device *)data; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int packet_no, len; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buf; 5548ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng unsigned long flags; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 556b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(3, "%s: %s\n", dev->name, __func__); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5588ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng if (!smc_special_trylock(&lp->lock, flags)) { 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_schedule(&lp->tx_task); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = lp->pending_tx_skb; 565be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre if (unlikely(!skb)) { 5668ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng smc_special_unlock(&lp->lock, flags); 567be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre return; 568be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre } 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->pending_tx_skb = NULL; 570be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre 571cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm packet_no = SMC_GET_AR(lp); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(packet_no & AR_FAILED)) { 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Memory allocation failed.\n", dev->name); 57409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_errors++; 57509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_fifo_errors++; 5768ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng smc_special_unlock(&lp->lock, flags); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* point to the beginning of the packet */ 581cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_PN(lp, packet_no); 582cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_PTR(lp, PTR_AUTOINC); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = skb->data; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = skb->len; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n", 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, packet_no, len, len, buf); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINT_PKT(buf, len); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send the packet length (+6 for status words, length, and ctl. 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The card will pad to 64 bytes with zeroes if packet is too small. 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 594cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_PUT_PKT_HDR(lp, 0, len + 6); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send the actual data */ 597cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_PUSH_DATA(lp, buf, len & ~1); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Send final ctl word with the last byte if there is one */ 600cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG(lp)); 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 603ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre * If THROTTLE_TX_PKTS is set, we stop the queue here. This will 604ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre * have the effect of having at most one packet queued for TX 605ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre * in the chip's memory at all time. 606ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre * 607ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre * If THROTTLE_TX_PKTS is not set then the queue is stopped only 608ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre * when memory allocation (MC_ALLOC) does not succeed right away. 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 610ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre if (THROTTLE_TX_PKTS) 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* queue the packet for TX */ 614cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_ENQUEUE); 6158ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng smc_special_unlock(&lp->lock, flags); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->trans_start = jiffies; 61809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_packets++; 61909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_bytes += len; 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_ENABLE_INT(lp, IM_TX_INT | IM_TX_EMPTY_INT); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: if (!THROTTLE_TX_PKTS) 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since I am not sure if I will have enough room in the chip's ram 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to store the packet, I call this routine which either sends it 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * now, or set the card to generates an interrupt when ready 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for the packet. 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int numPages, poll_count, status; 6408ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng unsigned long flags; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 642b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(3, "%s: %s\n", dev->name, __func__); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(lp->pending_tx_skb != NULL); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The MMU wants the number of pages to be the number of 256 bytes 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'pages', minus 1 (since a packet can't ever have 0 pages :)) 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The 91C111 ignores the size bits, but earlier models don't. 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Pkt size for allocating is data length +6 (for additional status 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * words, length and ctl) 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If odd size then last byte is included in ctl word. 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds numPages = ((skb->len & ~1) + (6 - 1)) >> 8; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(numPages > 7)) { 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Far too big packet error.\n", dev->name); 66009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_errors++; 66109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_dropped++; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 6636ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6668ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng smc_special_lock(&lp->lock, flags); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now, try to allocate the memory */ 669cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_ALLOC | numPages); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Poll the chip for a short amount of time in case the 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocation succeeds quickly. 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds poll_count = MEMORY_WAIT_TIME; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 677cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm status = SMC_GET_INT(lp); 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & IM_ALLOC_INT) { 679cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_ACK_INT(lp, IM_ALLOC_INT); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--poll_count); 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6848ff499e43c537648399fca8ba39d24c0768b3fabDongdong Deng smc_special_unlock(&lp->lock, flags); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 686be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre lp->pending_tx_skb = skb; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!poll_count) { 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* oh well, wait until the chip finds memory later */ 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: TX memory allocation deferred.\n", dev->name); 691cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_ENABLE_INT(lp, IM_ALLOC_INT); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocation succeeded: push packet to the chip's own memory 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * immediately. 6966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik */ 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_hardware_send_pkt((unsigned long)dev); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7006ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This handles a TX interrupt, which is only called when: 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - a TX error occurred, or 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - CTL_AUTO_RELEASE is not set and TX of a packet completed. 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_tx(struct net_device *dev) 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int saved_packet, packet_no, tx_status, pkt_len; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 714b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(3, "%s: %s\n", dev->name, __func__); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the TX FIFO is empty then nothing to do */ 717cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm packet_no = SMC_GET_TXFIFO(lp); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(packet_no & TXFIFO_TEMPTY)) { 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* select packet to read from */ 724cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm saved_packet = SMC_GET_PN(lp); 725cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_PN(lp, packet_no); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read the first word (status word) from this packet */ 728cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_PTR(lp, PTR_AUTOINC | PTR_READ); 729cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_GET_PKT_HDR(lp, tx_status, pkt_len); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n", 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, tx_status, packet_no); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7338de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre if (!(tx_status & ES_TX_SUC)) 73409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_errors++; 7358de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre 7368de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre if (tx_status & ES_LOSTCARR) 73709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_carrier_errors++; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7398de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre if (tx_status & (ES_LATCOL | ES_16COL)) { 7408de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre PRINTK("%s: %s occurred on last xmit\n", dev->name, 7418de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre (tx_status & ES_LATCOL) ? 7428de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre "late collision" : "too many collisions"); 74309f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_window_errors++; 74409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) { 7458de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre printk(KERN_INFO "%s: unexpectedly large number of " 7468de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre "bad collisions. Please check duplex " 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "setting.\n", dev->name); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* kill the packet */ 752cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_WAIT_MMU_BUSY(lp); 753cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_FREEPKT); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't restore Packet Number Reg until busy bit is cleared */ 756cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_WAIT_MMU_BUSY(lp); 757cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_PN(lp, saved_packet); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* re-enable transmit */ 760cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 761cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_TCR(lp, lp->tcr_cur_mode); 762cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_mii_out(struct net_device *dev, unsigned int val, int bits) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mii_reg, mask; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 774cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO); 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mii_reg |= MII_MDOE; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (mask = 1 << (bits - 1); mask; mask >>= 1) { 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val & mask) 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mii_reg |= MII_MDO; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mii_reg &= ~MII_MDO; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 783cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MII(lp, mii_reg); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(MII_DELAY); 785cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MII(lp, mii_reg | MII_MCLK); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(MII_DELAY); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int smc_mii_in(struct net_device *dev, int bits) 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mii_reg, mask, val; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 796cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO); 797cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MII(lp, mii_reg); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (mask = 1 << (bits - 1), val = 0; mask; mask >>= 1) { 800cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm if (SMC_GET_MII(lp) & MII_MDI) 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= mask; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 803cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MII(lp, mii_reg); 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(MII_DELAY); 805cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MII(lp, mii_reg | MII_MCLK); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(MII_DELAY); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reads a register from the MII Management serial interface 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int phydata; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 3); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Idle - 32 ones */ 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_mii_out(dev, 0xffffffff, 32); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start code (01) + read (10) + phyaddr + phyreg */ 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_mii_out(dev, 6 << 10 | phyaddr << 5 | phyreg, 14); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turnaround (2bits) + phydata */ 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phydata = smc_mii_in(dev, 18); 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return to idle state */ 833cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO)); 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", 836b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison __func__, phyaddr, phyreg, phydata); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 838cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return phydata; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Writes a register to the MII Management serial interface 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg, 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phydata) 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 3); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Idle - 32 ones */ 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_mii_out(dev, 0xffffffff, 32); 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start code (01) + write (01) + phyaddr + phyreg + turnaround + phydata */ 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_mii_out(dev, 5 << 28 | phyaddr << 23 | phyreg << 18 | 2 << 16 | phydata, 32); 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return to idle state */ 860cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO)); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", 863b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison __func__, phyaddr, phyreg, phydata); 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 865cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finds and reports the PHY address 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_phy_detect(struct net_device *dev) 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phyaddr; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 876b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->phy_type = 0; 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Scan all 32 PHY addresses if necessary, starting at 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PHY#1 to PHY#31, and then PHY#0 last. 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (phyaddr = 1; phyaddr < 33; ++phyaddr) { 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int id1, id2; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read the PHY identifiers */ 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id1 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID1); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id2 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID2); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(3, "%s: phy_id1=0x%x, phy_id2=0x%x\n", 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, id1, id2); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure it is a valid identifier */ 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (id1 != 0x0000 && id1 != 0xffff && id1 != 0x8000 && 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id2 != 0x0000 && id2 != 0xffff && id2 != 0x8000) { 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Save the PHY's address */ 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.phy_id = phyaddr & 31; 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->phy_type = id1 << 16 | id2; 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sets the PHY to a configuration as determined by the user 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int smc_phy_fixed(struct net_device *dev) 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phyaddr = lp->mii.phy_id; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bmcr, cfg1; 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 915b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(3, "%s: %s\n", dev->name, __func__); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enter Link Disable state */ 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG); 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfg1 |= PHY_CFG1_LNKDIS; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_write(dev, phyaddr, PHY_CFG1_REG, cfg1); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set our fixed capabilities 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable auto-negotiation 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr = 0; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->ctl_rfduplx) 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr |= BMCR_FULLDPLX; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->ctl_rspeed == 100) 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr |= BMCR_SPEED100; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write our capabilities to the phy control register */ 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_write(dev, phyaddr, MII_BMCR, bmcr); 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Re-Configure the Receive/Phy Control register */ 938cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 939cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_RPC(lp, lp->rpc_cur_mode); 940cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_phy_reset - reset the phy 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: net device 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @phy: phy address 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Issue a software reset for the specified PHY and 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * wait up to 100ms for the reset to complete. We should 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not access the PHY for 50ms after issuing the reset. 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The time to wait appears to be dependent on the PHY. 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must be called with lp->lock locked. 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int smc_phy_reset(struct net_device *dev, int phy) 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bmcr; 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int timeout; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_write(dev, phy, MII_BMCR, BMCR_RESET); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (timeout = 2; timeout; timeout--) { 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(50); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr = smc_phy_read(dev, phy, MII_BMCR); 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(bmcr & BMCR_RESET)) 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bmcr & BMCR_RESET; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_phy_powerdown - powerdown phy 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: net device 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power down the specified PHY 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_phy_powerdown(struct net_device *dev) 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bmcr; 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phy = lp->mii.phy_id; 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type == 0) 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We need to ensure that no calls to smc_phy_configure are 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending. 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9974bb073c0e32a0862bdb5215d11af19f6c0180c98David S. Miller cancel_work_sync(&lp->phy_configure); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmcr = smc_phy_read(dev, phy, MII_BMCR); 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_phy_check_media - check the media status and adjust TCR 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: net device 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @init: set true for initialisation 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select duplex mode depending on negotiation state. This 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * also updates our carrier state. 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_phy_check_media(struct net_device *dev, int init) 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* duplex state has changed */ 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->mii.full_duplex) { 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tcr_cur_mode |= TCR_SWFDUP; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tcr_cur_mode &= ~TCR_SWFDUP; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1024cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 1025cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_TCR(lp, lp->tcr_cur_mode); 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configures the specified PHY through the MII management interface 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * using Autonegotiation. 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calls smc_phy_fixed() if the user has requested a certain config. 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If RPC ANEG bit is set, the media selection is dependent purely on 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the selection by the MII (either in the MII BMCR reg or the result 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of autonegotiation.) If the RPC ANEG bit is cleared, the selection 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is controlled by the RPC SPEED and RPC DPLX bits. 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10386d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howellsstatic void smc_phy_configure(struct work_struct *work) 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10406d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells struct smc_local *lp = 10416d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells container_of(work, struct smc_local, phy_configure); 10426d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells struct net_device *dev = lp->dev; 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phyaddr = lp->mii.phy_id; 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int my_phy_caps; /* My PHY capabilities */ 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int my_ad_caps; /* My Advertised capabilities */ 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(3, "%s:smc_program_phy()\n", dev->name); 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We should not be called if phy_type is zero. 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type == 0) 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto smc_phy_configure_exit; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (smc_phy_reset(dev, phyaddr)) { 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: PHY reset timed out\n", dev->name); 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto smc_phy_configure_exit; 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable PHY Interrupts (for register 18) 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interrupts listed here are disabled 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_write(dev, phyaddr, PHY_MASK_REG, 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PHY_INT_SPDDET | PHY_INT_DPLXDET); 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Configure the Receive/Phy Control register */ 1074cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 1075cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_RPC(lp, lp->rpc_cur_mode); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the user requested no auto neg, then go set his request */ 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->mii.force_media) { 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_fixed(dev); 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto smc_phy_configure_exit; 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */ 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_phy_caps = smc_phy_read(dev, phyaddr, MII_BMSR); 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(my_phy_caps & BMSR_ANEGCAPABLE)) { 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "Auto negotiation NOT supported\n"); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_fixed(dev); 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto smc_phy_configure_exit; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps = ADVERTISE_CSMA; /* I am CSMA capable */ 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (my_phy_caps & BMSR_100BASE4) 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps |= ADVERTISE_100BASE4; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (my_phy_caps & BMSR_100FULL) 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps |= ADVERTISE_100FULL; 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (my_phy_caps & BMSR_100HALF) 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps |= ADVERTISE_100HALF; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (my_phy_caps & BMSR_10FULL) 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps |= ADVERTISE_10FULL; 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (my_phy_caps & BMSR_10HALF) 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps |= ADVERTISE_10HALF; 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable capabilities not selected by our user */ 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->ctl_rspeed != 100) 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lp->ctl_rfduplx) 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Update our Auto-Neg Advertisement Register */ 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_write(dev, phyaddr, MII_ADVERTISE, my_ad_caps); 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.advertising = my_ad_caps; 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the register back. Without this, it appears that when 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * auto-negotiation is restarted, sometimes it isn't ready and 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the link does not come up. 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = smc_phy_read(dev, phyaddr, MII_ADVERTISE); 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: phy caps=%x\n", dev->name, my_phy_caps); 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: phy advertised caps=%x\n", dev->name, my_ad_caps); 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restart auto-negotiation process in order to advertise my caps */ 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_write(dev, phyaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_check_media(dev, 1); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmc_phy_configure_exit: 1132cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_phy_interrupt 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Purpose: Handle interrupts relating to PHY register 18. This is 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called from the "hard" interrupt handler under our private spinlock. 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_phy_interrupt(struct net_device *dev) 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phyaddr = lp->mii.phy_id; 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phy18; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1148b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type == 0) 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(;;) { 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_check_media(dev, 0); 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read PHY Register 18, Status Output */ 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phy18 = smc_phy_read(dev, phyaddr, PHY_INT_REG); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((phy18 & PHY_INT_INT) == 0) 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/ 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_10bt_check_media(struct net_device *dev, int init) 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int old_carrier, new_carrier; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_carrier = netif_carrier_ok(dev) ? 1 : 0; 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1173cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 1174cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm new_carrier = (SMC_GET_EPH_STATUS(lp) & ES_LINK_OK) ? 1 : 0; 1175cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init || (old_carrier != new_carrier)) { 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!new_carrier) { 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(dev); 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_on(dev); 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_msg_link(lp)) 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: link %s\n", dev->name, 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_carrier ? "up" : "down"); 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_eph_interrupt(struct net_device *dev) 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ctl; 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_10bt_check_media(dev, 0); 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1197cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 1); 1198cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm ctl = SMC_GET_CTL(lp); 1199cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_CTL(lp, ctl & ~CTL_LE_ENABLE); 1200cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_CTL(lp, ctl); 1201cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the main routine of the driver, to handle the device when 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it needs some attention. 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12087d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t smc_interrupt(int irq, void *dev_id) 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_id; 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status, mask, timeout, card_stats; 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int saved_pointer; 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1216b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(3, "%s: %s\n", dev->name, __func__); 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&lp->lock); 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* A preamble may be used when there is a potential race 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * between the interruptible transmit functions and this 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISR. */ 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMC_INTERRUPT_PREAMBLE; 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1225cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm saved_pointer = SMC_GET_PTR(lp); 1226cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm mask = SMC_GET_INT_MASK(lp); 1227cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, 0); 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set a timeout value, so I don't stay here forever */ 12305d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre timeout = MAX_IRQ_LOOPS; 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 1233cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm status = SMC_GET_INT(lp); 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, status, mask, 1237cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm ({ int meminfo; SMC_SELECT_BANK(lp, 0); 1238cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm meminfo = SMC_GET_MIR(lp); 1239cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); meminfo; }), 1240cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_GET_FIFO(lp)); 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= mask; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!status) 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1246ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre if (status & IM_TX_INT) { 1247ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre /* do this before RX as it will free memory quickly */ 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(3, "%s: TX int\n", dev->name); 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_tx(dev); 1250cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_ACK_INT(lp, IM_TX_INT); 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (THROTTLE_TX_PKTS) 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 1253ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre } else if (status & IM_RCV_INT) { 1254ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre DBG(3, "%s: RX irq\n", dev->name); 1255ea9375607f8b312cf4389d68909330ed32a622efNicolas Pitre smc_rcv(dev); 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & IM_ALLOC_INT) { 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(3, "%s: Allocation irq\n", dev->name); 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_hi_schedule(&lp->tx_task); 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask &= ~IM_ALLOC_INT; 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & IM_TX_EMPTY_INT) { 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(3, "%s: TX empty\n", dev->name); 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask &= ~IM_TX_EMPTY_INT; 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* update stats */ 1265cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 1266cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm card_stats = SMC_GET_COUNTER(lp); 1267cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* single collisions */ 127009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.collisions += card_stats & 0xF; 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card_stats >>= 4; 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* multiple collisions */ 127409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.collisions += card_stats & 0xF; 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & IM_RX_OVRN_INT) { 12768de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name, 1277cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm ({ int eph_st; SMC_SELECT_BANK(lp, 0); 1278cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm eph_st = SMC_GET_EPH_STATUS(lp); 1279cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); eph_st; })); 1280cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_ACK_INT(lp, IM_RX_OVRN_INT); 128109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; 128209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_fifo_errors++; 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & IM_EPH_INT) { 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_eph_interrupt(dev); 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & IM_MDINT) { 1286cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_ACK_INT(lp, IM_MDINT); 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_interrupt(dev); 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & IM_ERCV_INT) { 1289cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_ACK_INT(lp, IM_ERCV_INT); 129084d57bd61866c06aee5658fabe43292a231a5992Frans Pop PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT\n", dev->name); 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--timeout); 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* restore register states */ 1295cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_PTR(lp, saved_pointer); 1296cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, mask); 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lp->lock); 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1299c500cb265e35c76d741714a61bc635e0f02d64d2Sonic Zhang#ifndef CONFIG_NET_POLL_CONTROLLER 13005d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre if (timeout == MAX_IRQ_LOOPS) 13015d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre PRINTK("%s: spurious interrupt (mask = 0x%02x)\n", 13025d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre dev->name, mask); 1303c500cb265e35c76d741714a61bc635e0f02d64d2Sonic Zhang#endif 13045d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre DBG(3, "%s: Interrupt done (%d loops)\n", 13055d0571d915f3e281f151df9a18a6a0be5a57c4b0Nicolas Pitre dev->name, MAX_IRQ_LOOPS - timeout); 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We return IRQ_HANDLED unconditionally here even if there was 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nothing to do. There is a possibility that a packet might 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get enqueued into the chip right after TX_EMPTY_INT is raised 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but just before the CPU acknowledges the IRQ. 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Better take an unneeded IRQ in some occasions than complexifying 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the code for all cases. 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_POLL_CONTROLLER 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Polling receive - used by netconsole and other diagnostic tools 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to allow network i/o with interrupts disabled. 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_poll_controller(struct net_device *dev) 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_irq(dev->irq); 13269c8e7f5cc965d30006c917ab19221e06fcc5a4f9Al Viro smc_interrupt(dev->irq, dev); 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq(dev->irq); 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Our watchdog timed out. Called by the networking layer */ 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_timeout(struct net_device *dev) 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 13368de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre int status, mask, eph_st, meminfo, fifo; 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1338b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 1341cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm status = SMC_GET_INT(lp); 1342cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm mask = SMC_GET_INT_MASK(lp); 1343cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm fifo = SMC_GET_FIFO(lp); 1344cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 1345cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm eph_st = SMC_GET_EPH_STATUS(lp); 1346cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm meminfo = SMC_GET_MIR(lp); 1347cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 13498de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre PRINTK( "%s: TX timeout (INT 0x%02x INTMASK 0x%02x " 13508de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre "MEM 0x%04x FIFO 0x%04x EPH_ST 0x%04x)\n", 13518de901150f3c58b019b2a3ce497d23ab662dbb8bNicolas Pitre dev->name, status, mask, meminfo, fifo, eph_st ); 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_reset(dev); 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_enable(dev); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reconfiguring the PHY doesn't seem like a bad idea here, but 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_phy_configure() calls msleep() which calls schedule_timeout() 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which calls schedule(). Hence we use a work queue. 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13614bb073c0e32a0862bdb5215d11af19f6c0180c98David S. Miller if (lp->phy_type != 0) 13624bb073c0e32a0862bdb5215d11af19f6c0180c98David S. Miller schedule_work(&lp->phy_configure); 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can accept TX packets again */ 13651ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet dev->trans_start = jiffies; /* prevent tx timeout */ 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will, depending on the values passed to it, 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * either make it accept multicast packets, go into 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * promiscuous mode (for TCPDUMP and cousins) or accept 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a select set of multicast packets 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_set_multicast_list(struct net_device *dev) 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = lp->base; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char multicast_table[8]; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int update_multicast = 0; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1382b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->flags & IFF_PROMISC) { 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: RCR_PRMS\n", dev->name); 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->rcr_cur_mode |= RCR_PRMS; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* BUG? I never disable promiscuous mode if multicasting was turned on. 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Now, I turn off promiscuous mode, but I don't do anything to multicasting 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds when promiscuous mode is turned on. 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Here, I am setting this to accept all multicast packets. 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I don't need to zero the multicast table, because the flag is 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * checked before the table is 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13994cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: RCR_ALMUL\n", dev->name); 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->rcr_cur_mode |= RCR_ALMUL; 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This sets the internal hardware table to filter out unwanted 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multicast packets before they take up memory. 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SMC chip uses a hash table where the high 6 bits of the CRC of 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address are the offset into the table. If that bit is 1, then the 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multicast packet is accepted. Otherwise, it's dropped silently. 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To use the 6 bits as an offset into the table, the high 3 bits are 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the number of the 8 bit register, while the low 3 bits are the bit 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * within that register. 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14164cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko else if (!netdev_mc_empty(dev)) { 141722bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* table for flipping the order of 3 bits */ 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7}; 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* start with a table of all zeros: reject all */ 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(multicast_table, 0, sizeof(multicast_table)); 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 142522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) { 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int position; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* only use the low order bits */ 142922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko position = crc32_le(~0, ha->addr, 6) & 0x3f; 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* do some messy swapping to put the bit in the right spot */ 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds multicast_table[invert3[position&7]] |= 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<invert3[(position>>3)&7]); 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* be sure I get rid of flags I might have set */ 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now, the table can be loaded into the chipset */ 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_multicast = 1; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since I'm disabling all multicast entirely, I need to 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clear the multicast list 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(multicast_table, 0, sizeof(multicast_table)); 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_multicast = 1; 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 1454cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 1455cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_RCR(lp, lp->rcr_cur_mode); 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (update_multicast) { 1457cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 3); 1458cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MCAST(lp, multicast_table); 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1460cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open and Initialize the board 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up everything, reset the card, etc.. 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmc_open(struct net_device *dev) 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1475b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check that the address is valid. If its not, refuse 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to bring the device up. The user must specify an 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_valid_ether_addr(dev->dev_addr)) { 1483b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison PRINTK("%s: no valid ethernet hw addr\n", __func__); 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup the default Register Modes */ 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tcr_cur_mode = TCR_DEFAULT; 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->rcr_cur_mode = RCR_DEFAULT; 1490b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King lp->rpc_cur_mode = RPC_DEFAULT | 1491b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King lp->cfg.leda << RPC_LSXA_SHFT | 1492b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King lp->cfg.ledb << RPC_LSXB_SHFT; 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are not using a MII interface, we need to 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * monitor our own carrier signal to detect faults. 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type == 0) 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tcr_cur_mode |= TCR_MON_CSN; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* reset the hardware */ 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_reset(dev); 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_enable(dev); 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Configure the PHY, initialize the link state */ 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type != 0) 15076d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells smc_phy_configure(&lp->phy_configure); 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_10bt_check_media(dev, 1); 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_close 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this makes the board clean up everything that it can 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and not talk to the outside world. Caused by 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an 'ifconfig ethX down' 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int smc_close(struct net_device *dev) 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1529b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", dev->name, __func__); 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(dev); 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear everything */ 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_shutdown(dev); 1536be83668a253149d99085ca4afe6cd8dc8a43fcd0Nicolas Pitre tasklet_kill(&lp->tx_task); 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_powerdown(dev); 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ethtool support 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->maxtxpkt = 1; 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->maxrxpkt = 1; 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type != 0) { 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mii_ethtool_gset(&lp->mii, cmd); 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->supported = SUPPORTED_10baseT_Half | 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SUPPORTED_10baseT_Full | 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SUPPORTED_TP | SUPPORTED_AUI; 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->ctl_rspeed == 10) 1563707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny ethtool_cmd_speed_set(cmd, SPEED_10); 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (lp->ctl_rspeed == 100) 1565707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny ethtool_cmd_speed_set(cmd, SPEED_100); 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->autoneg = AUTONEG_DISABLE; 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->transceiver = XCVR_INTERNAL; 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->port = 0; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->duplex = lp->tcr_cur_mode & TCR_SWFDUP ? DUPLEX_FULL : DUPLEX_HALF; 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type != 0) { 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mii_ethtool_sset(&lp->mii, cmd); 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->autoneg != AUTONEG_DISABLE || 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->speed != SPEED_10 || 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) || 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd->port != PORT_TP && cmd->port != PORT_AUI)) 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// lp->port = cmd->port; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL; 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// if (netif_running(dev)) 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// smc_set_port(dev); 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncpy(info->driver, CARDNAME, sizeof(info->driver)); 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncpy(info->version, version, sizeof(info->version)); 1612db1d7bf70f42124f73675fca62fe32f3ab1111b4Kay Sievers strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info)); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int smc_ethtool_nwayreset(struct net_device *dev) 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EINVAL; 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type != 0) { 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mii_nway_restart(&lp->mii); 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 smc_ethtool_getmsglevel(struct net_device *dev) 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lp->msg_enable; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_ethtool_setmsglevel(struct net_device *dev, u32 level) 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->msg_enable = level; 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauderstatic int smc_write_eeprom_word(struct net_device *dev, u16 addr, u16 word) 1642357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder{ 1643357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder u16 ctl; 1644357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder struct smc_local *lp = netdev_priv(dev); 1645357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder void __iomem *ioaddr = lp->base; 1646357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1647357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder spin_lock_irq(&lp->lock); 1648357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* load word into GP register */ 1649357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SELECT_BANK(lp, 1); 1650357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_GP(lp, word); 1651357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* set the address to put the data in EEPROM */ 1652357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SELECT_BANK(lp, 2); 1653357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_PTR(lp, addr); 1654357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* tell it to write */ 1655357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SELECT_BANK(lp, 1); 1656357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder ctl = SMC_GET_CTL(lp); 1657357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_STORE)); 1658357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* wait for it to finish */ 1659357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder do { 1660357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder udelay(1); 1661357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder } while (SMC_GET_CTL(lp) & CTL_STORE); 1662357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* clean up */ 1663357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_CTL(lp, ctl); 1664357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SELECT_BANK(lp, 2); 1665357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder spin_unlock_irq(&lp->lock); 1666357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder return 0; 1667357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder} 1668357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1669357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauderstatic int smc_read_eeprom_word(struct net_device *dev, u16 addr, u16 *word) 1670357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder{ 1671357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder u16 ctl; 1672357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder struct smc_local *lp = netdev_priv(dev); 1673357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder void __iomem *ioaddr = lp->base; 1674357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1675357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder spin_lock_irq(&lp->lock); 1676357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* set the EEPROM address to get the data from */ 1677357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SELECT_BANK(lp, 2); 1678357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_PTR(lp, addr | PTR_READ); 1679357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* tell it to load */ 1680357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SELECT_BANK(lp, 1); 1681357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_GP(lp, 0xffff); /* init to known */ 1682357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder ctl = SMC_GET_CTL(lp); 1683357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_RELOAD)); 1684357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* wait for it to finish */ 1685357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder do { 1686357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder udelay(1); 1687357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder } while (SMC_GET_CTL(lp) & CTL_RELOAD); 1688357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* read word from GP register */ 1689357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder *word = SMC_GET_GP(lp); 1690357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder /* clean up */ 1691357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SET_CTL(lp, ctl); 1692357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder SMC_SELECT_BANK(lp, 2); 1693357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder spin_unlock_irq(&lp->lock); 1694357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder return 0; 1695357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder} 1696357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1697357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauderstatic int smc_ethtool_geteeprom_len(struct net_device *dev) 1698357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder{ 1699357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder return 0x23 * 2; 1700357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder} 1701357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1702357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauderstatic int smc_ethtool_geteeprom(struct net_device *dev, 1703357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder struct ethtool_eeprom *eeprom, u8 *data) 1704357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder{ 1705357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int i; 1706357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int imax; 1707357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1708357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder DBG(1, "Reading %d bytes at %d(0x%x)\n", 1709357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder eeprom->len, eeprom->offset, eeprom->offset); 1710357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder imax = smc_ethtool_geteeprom_len(dev); 1711357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder for (i = 0; i < eeprom->len; i += 2) { 1712357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int ret; 1713357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder u16 wbuf; 1714357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int offset = i + eeprom->offset; 1715357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder if (offset > imax) 1716357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder break; 1717357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder ret = smc_read_eeprom_word(dev, offset >> 1, &wbuf); 1718357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder if (ret != 0) 1719357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder return ret; 1720357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder DBG(2, "Read 0x%x from 0x%x\n", wbuf, offset >> 1); 1721357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder data[i] = (wbuf >> 8) & 0xff; 1722357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder data[i+1] = wbuf & 0xff; 1723357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder } 1724357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder return 0; 1725357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder} 1726357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1727357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauderstatic int smc_ethtool_seteeprom(struct net_device *dev, 1728357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder struct ethtool_eeprom *eeprom, u8 *data) 1729357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder{ 1730357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int i; 1731357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int imax; 1732357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1733357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder DBG(1, "Writing %d bytes to %d(0x%x)\n", 1734357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder eeprom->len, eeprom->offset, eeprom->offset); 1735357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder imax = smc_ethtool_geteeprom_len(dev); 1736357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder for (i = 0; i < eeprom->len; i += 2) { 1737357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int ret; 1738357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder u16 wbuf; 1739357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder int offset = i + eeprom->offset; 1740357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder if (offset > imax) 1741357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder break; 1742357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder wbuf = (data[i] << 8) | data[i + 1]; 1743357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder DBG(2, "Writing 0x%x to 0x%x\n", wbuf, offset >> 1); 1744357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder ret = smc_write_eeprom_word(dev, offset >> 1, wbuf); 1745357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder if (ret != 0) 1746357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder return ret; 1747357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder } 1748357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder return 0; 1749357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder} 1750357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 1751357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder 17527282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops smc_ethtool_ops = { 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_settings = smc_ethtool_getsettings, 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_settings = smc_ethtool_setsettings, 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_drvinfo = smc_ethtool_getdrvinfo, 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_msglevel = smc_ethtool_getmsglevel, 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_msglevel = smc_ethtool_setmsglevel, 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .nway_reset = smc_ethtool_nwayreset, 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_link = ethtool_op_get_link, 1761357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder .get_eeprom_len = smc_ethtool_geteeprom_len, 1762357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder .get_eeprom = smc_ethtool_geteeprom, 1763357fe2c6d2b12482abd1c3f24a086a2f507f03fcVernon Sauder .set_eeprom = smc_ethtool_seteeprom, 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1766a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Dammstatic const struct net_device_ops smc_netdev_ops = { 1767a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm .ndo_open = smc_open, 1768a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm .ndo_stop = smc_close, 1769a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm .ndo_start_xmit = smc_hard_start_xmit, 1770a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm .ndo_tx_timeout = smc_timeout, 1771afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = smc_set_multicast_list, 1772635ecaa70e862f85f652581305fe0074810893beBen Hutchings .ndo_change_mtu = eth_change_mtu, 1773a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm .ndo_validate_addr = eth_validate_addr, 1774a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm .ndo_set_mac_address = eth_mac_addr, 1775a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm#ifdef CONFIG_NET_POLL_CONTROLLER 1776a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm .ndo_poll_controller = smc_poll_controller, 1777a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm#endif 1778a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm}; 1779a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_findirq 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine has a simple purpose -- make the SMC chip generate an 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt, so an auto-detect routine can detect it, and find the IRQ, 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does this still work? 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I just deleted auto_irq.c, since it was never built... 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * --jgarzik 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1792f57628d76bd201a444ca822f3622522a44acbf60Al Virostatic int __devinit smc_findirq(struct smc_local *lp) 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1794cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm void __iomem *ioaddr = lp->base; 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int timeout = 20; 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cookie; 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1798b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", CARDNAME, __func__); 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cookie = probe_irq_on(); 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * What I try to do here is trigger an ALLOC_INT. This is done 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by allocating a small chunk of memory, which will give an interrupt 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when done. 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable ALLOCation interrupts ONLY */ 1808cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 2); 1809cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, IM_ALLOC_INT); 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate 512 bytes of memory. Note that the chip was just 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reset so all the memory is available 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1815cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_MMU_CMD(lp, MC_ALLOC | 1); 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait until positive that the interrupt has been generated 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int int_status; 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(10); 1823cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm int_status = SMC_GET_INT(lp); 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (int_status & IM_ALLOC_INT) 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* got the interrupt */ 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--timeout); 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there is really nothing that I can do here if timeout fails, 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as autoirq_report will return a 0 anyway, which is what I 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * want in this case. Plus, the clean up is needed in both 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cases. 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* and disable all interrupts again */ 1836cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SET_INT_MASK(lp, 0); 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* and return what I found */ 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return probe_irq_off(cookie); 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function: smc_probe(unsigned long ioaddr) 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Purpose: 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tests to see if a given ioaddr points to an SMC91x chip. 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns a 0 on success 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Algorithm: 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (1) see if the high byte of BANK_SELECT is 0x33 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (2) compare the ioaddr with the base register's address 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (3) see if I recognize the chip ID in the appropriate register 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Here I do typical initialization tasks. 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o Initialize the structure if needed 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o print out my vanity message if not done so already 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o print out what type of hardware is detected 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o print out the ethernet address 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o find the IRQ 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o set up my private data 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o configure the dev structure with my subroutines 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o actually GRAB the irq. 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o GRAB the region 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1866f57628d76bd201a444ca822f3622522a44acbf60Al Virostatic int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr, 1867e7b3dc7ef1e27fd5713a0df71f82c0a27de1c2ebRussell King unsigned long irq_flags) 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(dev); 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int version_printed = 0; 18710795af5729b18218767fab27c44b1384f72dc9adJoe Perches int retval; 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int val, revision_register; 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *version_string; 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1875b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison DBG(2, "%s: %s\n", CARDNAME, __func__); 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First, see if the high byte is 0x33 */ 1878cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm val = SMC_CURRENT_BANK(lp); 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val); 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((val & 0xFF00) != 0x3300) { 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((val & 0xFF) == 0x33) { 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s: Detected possible byte-swapped interface" 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " at IOADDR %p\n", CARDNAME, ioaddr); 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The above MIGHT indicate a device, but I need to write to 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * further test this. 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1894cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 0); 1895cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm val = SMC_CURRENT_BANK(lp); 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((val & 0xFF00) != 0x3300) { 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * well, we've already written once, so hopefully another 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * time won't hurt. This time, I need to switch the bank 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register to bank 1, so I can access the base address 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1907cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 1); 1908cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm val = SMC_GET_BASE(lp); 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; 191053155109b6ac611d9bb4a4ef9d3109b219b8d0e1Nicolas Pitre if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) { 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: IOADDR %p doesn't match configuration (%x).\n", 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CARDNAME, ioaddr, val); 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check if the revision register is something that I 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * recognize. These might need to be added to later, 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as future revisions could be added. 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1920cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 3); 1921cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm revision_register = SMC_GET_REV(lp); 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(2, "%s: revision = 0x%04x\n", CARDNAME, revision_register); 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds version_string = chip_ids[ (revision_register >> 4) & 0xF]; 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!version_string || (revision_register & 0xff00) != 0x3300) { 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* I don't recognize this chip, so... */ 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: IO %p: Unrecognized revision register 0x%04x" 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ", Contact author.\n", CARDNAME, 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr, revision_register); 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* At this point I'll assume that the chip is an SMC91x. */ 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (version_printed++ == 0) 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s", version); 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fill in some of the fields */ 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = (unsigned long)ioaddr; 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->base = ioaddr; 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->version = revision_register & 0xff; 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&lp->lock); 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the MAC address */ 1945cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_SELECT_BANK(lp, 1); 1946cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm SMC_GET_MAC_ADDR(lp, dev->dev_addr); 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now, reset the chip, and put it into a known state */ 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_reset(dev); 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If dev->irq is 0, then the device has to be banged on to see 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * what the IRQ is. 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This banging doesn't always detect the IRQ, for unknown reasons. 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a workaround is to reset the chip and try again. 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interestingly, the DOS packet driver *SETS* the IRQ on the card to 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be what is requested on the command line. I don't do that, mostly 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * because the card that I have uses a non-standard method of accessing 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the IRQs, and because this _should_ work in most configurations. 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Specifying an IRQ is done with the assumption that the user knows 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * what (s)he is doing. No checking is done!!!! 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq < 1) { 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int trials; 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds trials = 3; 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (trials--) { 1971cfdfa86536d2fbc8102780ec15faea185e957d3dMagnus Damm dev->irq = smc_findirq(lp); 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq) 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* kick the card and try again */ 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_reset(dev); 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq == 0) { 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name); 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq_canonicalize(dev->irq); 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fill in the fields of the device structure with ethernet values. */ 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ether_setup(dev); 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->watchdog_timeo = msecs_to_jiffies(watchdog); 1990a528079e01aa9cf6cddc852d5ab5cf4908974745Magnus Damm dev->netdev_ops = &smc_netdev_ops; 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->ethtool_ops = &smc_ethtool_ops; 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev); 19946d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells INIT_WORK(&lp->phy_configure, smc_phy_configure); 19956d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells lp->dev = dev; 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.phy_id_mask = 0x1f; 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.reg_num_mask = 0x1f; 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.force_media = 0; 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.full_duplex = 0; 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.dev = dev; 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.mdio_read = smc_phy_read; 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->mii.mdio_write = smc_phy_write; 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Locate the phy, if any. 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->version >= (CHIP_91100 << 4)) 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_detect(dev); 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201099e1baf869cf20791e66e38facd51d14b28551f8Nicolas Pitre /* then shut everything down to save power */ 201199e1baf869cf20791e66e38facd51d14b28551f8Nicolas Pitre smc_shutdown(dev); 201299e1baf869cf20791e66e38facd51d14b28551f8Nicolas Pitre smc_phy_powerdown(dev); 201399e1baf869cf20791e66e38facd51d14b28551f8Nicolas Pitre 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set default parameters */ 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->msg_enable = NETIF_MSG_LINK; 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->ctl_rfduplx = 0; 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->ctl_rspeed = 10; 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->version >= (CHIP_91100 << 4)) { 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->ctl_rfduplx = 1; 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->ctl_rspeed = 100; 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Grab the IRQ */ 2025a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches retval = request_irq(dev->irq, smc_interrupt, irq_flags, dev->name, dev); 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out; 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 202952256c0e06e4a4df67134b951a21b50c713a9588Eric Miao#ifdef CONFIG_ARCH_PXA 203052256c0e06e4a4df67134b951a21b50c713a9588Eric Miao# ifdef SMC_USE_PXA_DMA 203152256c0e06e4a4df67134b951a21b50c713a9588Eric Miao lp->cfg.flags |= SMC91X_USE_DMA; 203252256c0e06e4a4df67134b951a21b50c713a9588Eric Miao# endif 203352256c0e06e4a4df67134b951a21b50c713a9588Eric Miao if (lp->cfg.flags & SMC91X_USE_DMA) { 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_pxa_dma_irq, NULL); 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dma >= 0) 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dma = dma; 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = register_netdev(dev); 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval == 0) { 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now, print out the card info, in a short format.. */ 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: %s (rev %d) at %p IRQ %d", 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, version_string, revision_register & 0x0f, 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->base, dev->irq); 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->dma != (unsigned char)-1) 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" DMA %d", dev->dma); 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051d6bc372ea1196066b618908dc522b08cd28993dfMagnus Damm printk("%s%s\n", 2052d6bc372ea1196066b618908dc522b08cd28993dfMagnus Damm lp->cfg.flags & SMC91X_NOWAIT ? " [nowait]" : "", 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds THROTTLE_TX_PKTS ? " [throttle_tx]" : ""); 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_valid_ether_addr(dev->dev_addr)) { 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Invalid ethernet MAC address. Please " 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "set using ifconfig\n", dev->name); 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Print the Ethernet address */ 2060e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("%s: Ethernet addr: %pM\n", 2061e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, dev->dev_addr); 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type == 0) { 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK("%s: No PHY found\n", dev->name); 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lp->phy_type & 0xfffffff0) == 0x0016f840) { 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK("%s: PHY LAN83C183 (LAN91C111 Internal)\n", dev->name); 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((lp->phy_type & 0xfffffff0) == 0x02821c50) { 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK("%s: PHY LAN83C180\n", dev->name); 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out: 207452256c0e06e4a4df67134b951a21b50c713a9588Eric Miao#ifdef CONFIG_ARCH_PXA 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval && dev->dma != (unsigned char)-1) 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_free_dma(dev->dma); 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int smc_enable_device(struct platform_device *pdev) 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20833e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm struct net_device *ndev = platform_get_drvdata(pdev); 20843e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm struct smc_local *lp = netdev_priv(ndev); 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ecor, ecsr; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *addr; 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource * res; 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Map the attribute space. This is overkill, but clean. 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr = ioremap(res->start, ATTRIB_SIZE); 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!addr) 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the device. We must disable IRQs around this 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since a reset causes the IRQ line become active. 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET; 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT)); 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds readb(addr + (ECOR << SMC_IO_SHIFT)); 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait 100us for the chip to reset. 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(100); 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device will ignore all writes to the enable bit while 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reset is asserted, even if the reset bit is cleared in the 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * same write. Must clear reset first, then enable the device. 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(ecor, addr + (ECOR << SMC_IO_SHIFT)); 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(ecor | ECOR_ENABLE, addr + (ECOR << SMC_IO_SHIFT)); 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the appropriate byte/word mode. 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8; 21273e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm if (!SMC_16BIT(lp)) 212809779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre ecsr |= ECSR_IOIS8; 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT)); 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(addr); 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the chip to wake up. We could poll the control 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register in the main register space, but that isn't mapped 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * yet. We know this is going to take 750us. 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(1); 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2144159198862adad7109bb347bb30a620f67beac45fEric Miaostatic int smc_request_attrib(struct platform_device *pdev, 2145159198862adad7109bb347bb30a620f67beac45fEric Miao struct net_device *ndev) 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); 214855c8eb6c8eaa5009eed1557b296da5d4ea9c369aDavid S. Miller struct smc_local *lp __maybe_unused = netdev_priv(ndev); 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME)) 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2159159198862adad7109bb347bb30a620f67beac45fEric Miaostatic void smc_release_attrib(struct platform_device *pdev, 2160159198862adad7109bb347bb30a620f67beac45fEric Miao struct net_device *ndev) 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); 216355c8eb6c8eaa5009eed1557b296da5d4ea9c369aDavid S. Miller struct smc_local *lp __maybe_unused = netdev_priv(ndev); 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(res->start, ATTRIB_SIZE); 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 216909779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitrestatic inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 217109779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre if (SMC_CAN_USE_DATACS) { 217209779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); 217309779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre struct smc_local *lp = netdev_priv(ndev); 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217509779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre if (!res) 217609779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre return; 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217809779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) { 217909779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME); 218009779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre return; 218109779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre } 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 218309779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre lp->datacs = ioremap(res->start, SMC_DATA_EXTENT); 218409779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre } 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 218909779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre if (SMC_CAN_USE_DATACS) { 219009779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre struct smc_local *lp = netdev_priv(ndev); 219109779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 219309779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre if (lp->datacs) 219409779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre iounmap(lp->datacs); 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 219609779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre lp->datacs = NULL; 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 219809779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre if (res) 219909779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre release_mem_region(res->start, SMC_DATA_EXTENT); 220009779c6df2dbe95483269d194b327d41fe2cc57eNicolas Pitre } 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * smc_init(void) 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Input parameters: 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev->base_addr == 0, try to find all possible locations 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev->base_addr > 0x1ff, this is the address to check 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dev->base_addr == <anything else>, return failure code 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Output: 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 --> there is a device 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * anything else, error 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2214f57628d76bd201a444ca822f3622522a44acbf60Al Virostatic int __devinit smc_drv_probe(struct platform_device *pdev) 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22163e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm struct smc91x_platdata *pd = pdev->dev.platform_data; 22173e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm struct smc_local *lp; 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *ndev; 2219e7b3dc7ef1e27fd5713a0df71f82c0a27de1c2ebRussell King struct resource *res, *ires; 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int __iomem *addr; 2221d280eadc4fba0bf99fb1c3b60e8c5e007f7da02cEric Miao unsigned long irq_flags = SMC_IRQ_FLAGS; 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ndev = alloc_etherdev(sizeof(struct smc_local)); 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ndev) { 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: could not allocate device.\n", CARDNAME); 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 2228159198862adad7109bb347bb30a620f67beac45fEric Miao goto out; 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22303ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King SET_NETDEV_DEV(ndev, &pdev->dev); 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22323e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm /* get configuration from platform data, only allow use of 22333e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm * bus width if both SMC_CAN_USE_xxx and SMC91X_USE_xxx are set. 22343e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm */ 22353e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm 22363e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm lp = netdev_priv(ndev); 22373e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm 2238159198862adad7109bb347bb30a620f67beac45fEric Miao if (pd) { 22393e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm memcpy(&lp->cfg, pd, sizeof(lp->cfg)); 2240159198862adad7109bb347bb30a620f67beac45fEric Miao lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags); 2241159198862adad7109bb347bb30a620f67beac45fEric Miao } else { 2242fa6d3be08538bb80274d20c7e59f9beca48fa44aEric Miao lp->cfg.flags |= (SMC_CAN_USE_8BIT) ? SMC91X_USE_8BIT : 0; 2243fa6d3be08538bb80274d20c7e59f9beca48fa44aEric Miao lp->cfg.flags |= (SMC_CAN_USE_16BIT) ? SMC91X_USE_16BIT : 0; 2244fa6d3be08538bb80274d20c7e59f9beca48fa44aEric Miao lp->cfg.flags |= (SMC_CAN_USE_32BIT) ? SMC91X_USE_32BIT : 0; 2245c4f0e76747e80578a8f7fddd82fd0ce8127bd2f8Eric Miao lp->cfg.flags |= (nowait) ? SMC91X_NOWAIT : 0; 22463e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm } 22473e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm 2248b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King if (!lp->cfg.leda && !lp->cfg.ledb) { 2249b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King lp->cfg.leda = RPC_LSA_DEFAULT; 2250b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King lp->cfg.ledb = RPC_LSB_DEFAULT; 2251b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King } 2252b0dbcf511c4bd10350902e79a1bdd4f5dcca66b6Russell King 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ndev->dma = (unsigned char)-1; 2254e7b3dc7ef1e27fd5713a0df71f82c0a27de1c2ebRussell King 2255159198862adad7109bb347bb30a620f67beac45fEric Miao res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); 2256159198862adad7109bb347bb30a620f67beac45fEric Miao if (!res) 2257159198862adad7109bb347bb30a620f67beac45fEric Miao res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2258159198862adad7109bb347bb30a620f67beac45fEric Miao if (!res) { 2259159198862adad7109bb347bb30a620f67beac45fEric Miao ret = -ENODEV; 2260159198862adad7109bb347bb30a620f67beac45fEric Miao goto out_free_netdev; 2261159198862adad7109bb347bb30a620f67beac45fEric Miao } 2262159198862adad7109bb347bb30a620f67beac45fEric Miao 2263159198862adad7109bb347bb30a620f67beac45fEric Miao 2264159198862adad7109bb347bb30a620f67beac45fEric Miao if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) { 2265159198862adad7109bb347bb30a620f67beac45fEric Miao ret = -EBUSY; 2266159198862adad7109bb347bb30a620f67beac45fEric Miao goto out_free_netdev; 2267159198862adad7109bb347bb30a620f67beac45fEric Miao } 2268159198862adad7109bb347bb30a620f67beac45fEric Miao 2269e7b3dc7ef1e27fd5713a0df71f82c0a27de1c2ebRussell King ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 2270e7b3dc7ef1e27fd5713a0df71f82c0a27de1c2ebRussell King if (!ires) { 2271489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel ret = -ENODEV; 2272159198862adad7109bb347bb30a620f67beac45fEric Miao goto out_release_io; 2273489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel } 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2275e7b3dc7ef1e27fd5713a0df71f82c0a27de1c2ebRussell King ndev->irq = ires->start; 2276d280eadc4fba0bf99fb1c3b60e8c5e007f7da02cEric Miao 2277d5ccd67bb77ced5249067d05171992a7d5020393Russell King - ARM Linux if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK) 2278d280eadc4fba0bf99fb1c3b60e8c5e007f7da02cEric Miao irq_flags = ires->flags & IRQF_TRIGGER_MASK; 2279e7b3dc7ef1e27fd5713a0df71f82c0a27de1c2ebRussell King 2280159198862adad7109bb347bb30a620f67beac45fEric Miao ret = smc_request_attrib(pdev, ndev); 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 2282159198862adad7109bb347bb30a620f67beac45fEric Miao goto out_release_io; 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_SA1100_ASSABET) 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NCR_0 |= NCR_ENET_OSC_EN; 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22863e94794355724f77dc6cbb5ad956f7c72d8313a4Magnus Damm platform_set_drvdata(pdev, ndev); 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = smc_enable_device(pdev); 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_release_attrib; 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr = ioremap(res->start, SMC_IO_EXTENT); 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!addr) { 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_release_attrib; 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 229752256c0e06e4a4df67134b951a21b50c713a9588Eric Miao#ifdef CONFIG_ARCH_PXA 2298073ac8fd4a3e9a9265e8a59e0a79bc4b0b3822c3Russell King { 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(ndev); 2300073ac8fd4a3e9a9265e8a59e0a79bc4b0b3822c3Russell King lp->device = &pdev->dev; 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->physaddr = res->start; 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2305d280eadc4fba0bf99fb1c3b60e8c5e007f7da02cEric Miao ret = smc_probe(ndev, addr, irq_flags); 2306073ac8fd4a3e9a9265e8a59e0a79bc4b0b3822c3Russell King if (ret != 0) 2307073ac8fd4a3e9a9265e8a59e0a79bc4b0b3822c3Russell King goto out_iounmap; 2308073ac8fd4a3e9a9265e8a59e0a79bc4b0b3822c3Russell King 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_request_datacs(pdev, ndev); 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_iounmap: 23143ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_set_drvdata(pdev, NULL); 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(addr); 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_release_attrib: 2317159198862adad7109bb347bb30a620f67beac45fEric Miao smc_release_attrib(pdev, ndev); 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_release_io: 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(res->start, SMC_IO_EXTENT); 2320159198862adad7109bb347bb30a620f67beac45fEric Miao out_free_netdev: 2321159198862adad7109bb347bb30a620f67beac45fEric Miao free_netdev(ndev); 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: not found (%d).\n", CARDNAME, ret); 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2328f57628d76bd201a444ca822f3622522a44acbf60Al Virostatic int __devexit smc_drv_remove(struct platform_device *pdev) 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23303ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King struct net_device *ndev = platform_get_drvdata(pdev); 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(ndev); 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource *res; 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23343ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_set_drvdata(pdev, NULL); 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(ndev); 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(ndev->irq, ndev); 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 234052256c0e06e4a4df67134b951a21b50c713a9588Eric Miao#ifdef CONFIG_ARCH_PXA 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ndev->dma != (unsigned char)-1) 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_free_dma(ndev->dma); 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(lp->base); 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_release_datacs(pdev,ndev); 2347159198862adad7109bb347bb30a620f67beac45fEric Miao smc_release_attrib(pdev,ndev); 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) 23516fc30db563c57e383ca2ec836d8c9208c52d265aJeff Garzik res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(res->start, SMC_IO_EXTENT); 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(ndev); 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23599f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilmanstatic int smc_drv_suspend(struct device *dev) 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23619f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman struct platform_device *pdev = to_platform_device(dev); 23629f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman struct net_device *ndev = platform_get_drvdata(pdev); 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23649480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King if (ndev) { 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_running(ndev)) { 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_device_detach(ndev); 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_shutdown(ndev); 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_phy_powerdown(ndev); 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23749f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilmanstatic int smc_drv_resume(struct device *dev) 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23769f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman struct platform_device *pdev = to_platform_device(dev); 23779f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman struct net_device *ndev = platform_get_drvdata(pdev); 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23799480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King if (ndev) { 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct smc_local *lp = netdev_priv(ndev); 23815fc3441349936ea6f1f95a1ef17492223c76a695Paul Mundt smc_enable_device(pdev); 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_running(ndev)) { 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_reset(ndev); 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smc_enable(ndev); 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->phy_type != 0) 23866d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells smc_phy_configure(&lp->phy_configure); 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_device_attach(ndev); 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2393682a1694115ec1c8fcd794c35b80354166978207Thomas Chou#ifdef CONFIG_OF 2394682a1694115ec1c8fcd794c35b80354166978207Thomas Choustatic const struct of_device_id smc91x_match[] = { 2395682a1694115ec1c8fcd794c35b80354166978207Thomas Chou { .compatible = "smsc,lan91c94", }, 2396682a1694115ec1c8fcd794c35b80354166978207Thomas Chou { .compatible = "smsc,lan91c111", }, 2397682a1694115ec1c8fcd794c35b80354166978207Thomas Chou {}, 23985fb9fb132c5a83010cd8d4bf6d0ee34fb3b9d488Grant Likely}; 2399682a1694115ec1c8fcd794c35b80354166978207Thomas ChouMODULE_DEVICE_TABLE(of, smc91x_match); 24005fb9fb132c5a83010cd8d4bf6d0ee34fb3b9d488Grant Likely#else 24015fb9fb132c5a83010cd8d4bf6d0ee34fb3b9d488Grant Likely#define smc91x_match NULL 2402682a1694115ec1c8fcd794c35b80354166978207Thomas Chou#endif 2403682a1694115ec1c8fcd794c35b80354166978207Thomas Chou 24049f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilmanstatic struct dev_pm_ops smc_drv_pm_ops = { 24059f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman .suspend = smc_drv_suspend, 24069f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman .resume = smc_drv_resume, 24079f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman}; 24089f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman 24093ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver smc_driver = { 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = smc_drv_probe, 2411f57628d76bd201a444ca822f3622522a44acbf60Al Viro .remove = __devexit_p(smc_drv_remove), 24123ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 24133ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = CARDNAME, 241472abb46101fb5c47a9592914adb221b430ff26bdKay Sievers .owner = THIS_MODULE, 24159f950f72e57fe4bf9b16ace67e4cc5ffcee79d00Kevin Hilman .pm = &smc_drv_pm_ops, 2416682a1694115ec1c8fcd794c35b80354166978207Thomas Chou .of_match_table = smc91x_match, 24173ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2420db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(smc_driver); 2421