18c2ecf20Sopenharmony_ci/* 82596.c: A generic 82596 ethernet driver for linux. */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Based on Apricot.c 48c2ecf20Sopenharmony_ci Written 1994 by Mark Evans. 58c2ecf20Sopenharmony_ci This driver is for the Apricot 82596 bus-master interface 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Modularised 12/94 Mark Evans 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci Modified to support the 82596 ethernet chips on 680x0 VME boards. 118c2ecf20Sopenharmony_ci by Richard Hirst <richard@sleepie.demon.co.uk> 128c2ecf20Sopenharmony_ci Renamed to be 82596.c 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci 980825: Changed to receive directly in to sk_buffs which are 158c2ecf20Sopenharmony_ci allocated at open() time. Eliminates copy on incoming frames 168c2ecf20Sopenharmony_ci (small ones are still copied). Shared data now held in a 178c2ecf20Sopenharmony_ci non-cached page, so we can run on 68060 in copyback mode. 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci TBD: 208c2ecf20Sopenharmony_ci * look at deferring rx frames rather than discarding (as per tulip) 218c2ecf20Sopenharmony_ci * handle tx ring full as per tulip 228c2ecf20Sopenharmony_ci * performance test to tune rx_copybreak 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci Most of my modifications relate to the braindead big-endian 258c2ecf20Sopenharmony_ci implementation by Intel. When the i596 is operating in 268c2ecf20Sopenharmony_ci 'big-endian' mode, it thinks a 32 bit value of 0x12345678 278c2ecf20Sopenharmony_ci should be stored as 0x56781234. This is a real pain, when 288c2ecf20Sopenharmony_ci you have linked lists which are shared by the 680x0 and the 298c2ecf20Sopenharmony_ci i596. 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci Driver skeleton 328c2ecf20Sopenharmony_ci Written 1993 by Donald Becker. 338c2ecf20Sopenharmony_ci Copyright 1993 United States Government as represented by the Director, 348c2ecf20Sopenharmony_ci National Security Agency. This software may only be used and distributed 358c2ecf20Sopenharmony_ci according to the terms of the GNU General Public License as modified by SRC, 368c2ecf20Sopenharmony_ci incorporated herein by reference. 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci The author may be reached as becker@scyld.com, or C/O 398c2ecf20Sopenharmony_ci Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <linux/module.h> 448c2ecf20Sopenharmony_ci#include <linux/kernel.h> 458c2ecf20Sopenharmony_ci#include <linux/string.h> 468c2ecf20Sopenharmony_ci#include <linux/errno.h> 478c2ecf20Sopenharmony_ci#include <linux/ioport.h> 488c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 498c2ecf20Sopenharmony_ci#include <linux/delay.h> 508c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 518c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 528c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 538c2ecf20Sopenharmony_ci#include <linux/init.h> 548c2ecf20Sopenharmony_ci#include <linux/bitops.h> 558c2ecf20Sopenharmony_ci#include <linux/gfp.h> 568c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#include <asm/io.h> 598c2ecf20Sopenharmony_ci#include <asm/dma.h> 608c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic char version[] __initdata = 638c2ecf20Sopenharmony_ci "82596.c $Revision: 1.5 $\n"; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define DRV_NAME "82596" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* DEBUG flags 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define DEB_INIT 0x0001 718c2ecf20Sopenharmony_ci#define DEB_PROBE 0x0002 728c2ecf20Sopenharmony_ci#define DEB_SERIOUS 0x0004 738c2ecf20Sopenharmony_ci#define DEB_ERRORS 0x0008 748c2ecf20Sopenharmony_ci#define DEB_MULTI 0x0010 758c2ecf20Sopenharmony_ci#define DEB_TDR 0x0020 768c2ecf20Sopenharmony_ci#define DEB_OPEN 0x0040 778c2ecf20Sopenharmony_ci#define DEB_RESET 0x0080 788c2ecf20Sopenharmony_ci#define DEB_ADDCMD 0x0100 798c2ecf20Sopenharmony_ci#define DEB_STATUS 0x0200 808c2ecf20Sopenharmony_ci#define DEB_STARTTX 0x0400 818c2ecf20Sopenharmony_ci#define DEB_RXADDR 0x0800 828c2ecf20Sopenharmony_ci#define DEB_TXADDR 0x1000 838c2ecf20Sopenharmony_ci#define DEB_RXFRAME 0x2000 848c2ecf20Sopenharmony_ci#define DEB_INTS 0x4000 858c2ecf20Sopenharmony_ci#define DEB_STRUCT 0x8000 868c2ecf20Sopenharmony_ci#define DEB_ANY 0xffff 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define DEB(x,y) if (i596_debug & (x)) y 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MVME16x_NET) 938c2ecf20Sopenharmony_ci#define ENABLE_MVME16x_NET 948c2ecf20Sopenharmony_ci#endif 958c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_BVME6000_NET) 968c2ecf20Sopenharmony_ci#define ENABLE_BVME6000_NET 978c2ecf20Sopenharmony_ci#endif 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 1008c2ecf20Sopenharmony_ci#include <asm/mvme16xhw.h> 1018c2ecf20Sopenharmony_ci#endif 1028c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 1038c2ecf20Sopenharmony_ci#include <asm/bvme6000hw.h> 1048c2ecf20Sopenharmony_ci#endif 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * Define various macros for Channel Attention, word swapping etc., dependent 1088c2ecf20Sopenharmony_ci * on architecture. MVME and BVME are 680x0 based, otherwise it is Intel. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#ifdef __mc68000__ 1128c2ecf20Sopenharmony_ci#define WSWAPrfd(x) ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) 1138c2ecf20Sopenharmony_ci#define WSWAPrbd(x) ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) 1148c2ecf20Sopenharmony_ci#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16))) 1158c2ecf20Sopenharmony_ci#define WSWAPscb(x) ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) 1168c2ecf20Sopenharmony_ci#define WSWAPcmd(x) ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) 1178c2ecf20Sopenharmony_ci#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) 1188c2ecf20Sopenharmony_ci#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16))) 1198c2ecf20Sopenharmony_ci#define ISCP_BUSY 0x00010000 1208c2ecf20Sopenharmony_ci#else 1218c2ecf20Sopenharmony_ci#error 82596.c: unknown architecture 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* 1258c2ecf20Sopenharmony_ci * These were the intel versions, left here for reference. There 1268c2ecf20Sopenharmony_ci * are currently no x86 users of this legacy i82596 chip. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci#if 0 1298c2ecf20Sopenharmony_ci#define WSWAPrfd(x) ((struct i596_rfd *)((long)x)) 1308c2ecf20Sopenharmony_ci#define WSWAPrbd(x) ((struct i596_rbd *)((long)x)) 1318c2ecf20Sopenharmony_ci#define WSWAPiscp(x) ((struct i596_iscp *)((long)x)) 1328c2ecf20Sopenharmony_ci#define WSWAPscb(x) ((struct i596_scb *)((long)x)) 1338c2ecf20Sopenharmony_ci#define WSWAPcmd(x) ((struct i596_cmd *)((long)x)) 1348c2ecf20Sopenharmony_ci#define WSWAPtbd(x) ((struct i596_tbd *)((long)x)) 1358c2ecf20Sopenharmony_ci#define WSWAPchar(x) ((char *)((long)x)) 1368c2ecf20Sopenharmony_ci#define ISCP_BUSY 0x0001 1378c2ecf20Sopenharmony_ci#endif 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * The MPU_PORT command allows direct access to the 82596. With PORT access 1418c2ecf20Sopenharmony_ci * the following commands are available (p5-18). The 32-bit port command 1428c2ecf20Sopenharmony_ci * must be word-swapped with the most significant word written first. 1438c2ecf20Sopenharmony_ci * This only applies to VME boards. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci#define PORT_RESET 0x00 /* reset 82596 */ 1468c2ecf20Sopenharmony_ci#define PORT_SELFTEST 0x01 /* selftest */ 1478c2ecf20Sopenharmony_ci#define PORT_ALTSCP 0x02 /* alternate SCB address */ 1488c2ecf20Sopenharmony_ci#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int i596_debug = (DEB_SERIOUS|DEB_PROBE); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Richard Hirst"); 1538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("i82596 driver"); 1548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cimodule_param(i596_debug, int, 0); 1578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(i596_debug, "i82596 debug mask"); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* Copy frames shorter than rx_copybreak, otherwise pass on up in 1618c2ecf20Sopenharmony_ci * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha). 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic int rx_copybreak = 100; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define PKT_BUF_SZ 1536 1668c2ecf20Sopenharmony_ci#define MAX_MC_CNT 64 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define I596_TOTAL_SIZE 17 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#define I596_NULL ((void *)0xffffffff) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#define CMD_EOL 0x8000 /* The last command of the list, stop. */ 1738c2ecf20Sopenharmony_ci#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ 1748c2ecf20Sopenharmony_ci#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define CMD_FLEX 0x0008 /* Enable flexible memory model */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cienum commands { 1798c2ecf20Sopenharmony_ci CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3, 1808c2ecf20Sopenharmony_ci CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define STAT_C 0x8000 /* Set to 0 after execution */ 1848c2ecf20Sopenharmony_ci#define STAT_B 0x4000 /* Command being executed */ 1858c2ecf20Sopenharmony_ci#define STAT_OK 0x2000 /* Command executed ok */ 1868c2ecf20Sopenharmony_ci#define STAT_A 0x1000 /* Command aborted */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define CUC_START 0x0100 1898c2ecf20Sopenharmony_ci#define CUC_RESUME 0x0200 1908c2ecf20Sopenharmony_ci#define CUC_SUSPEND 0x0300 1918c2ecf20Sopenharmony_ci#define CUC_ABORT 0x0400 1928c2ecf20Sopenharmony_ci#define RX_START 0x0010 1938c2ecf20Sopenharmony_ci#define RX_RESUME 0x0020 1948c2ecf20Sopenharmony_ci#define RX_SUSPEND 0x0030 1958c2ecf20Sopenharmony_ci#define RX_ABORT 0x0040 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define TX_TIMEOUT (HZ/20) 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistruct i596_reg { 2018c2ecf20Sopenharmony_ci unsigned short porthi; 2028c2ecf20Sopenharmony_ci unsigned short portlo; 2038c2ecf20Sopenharmony_ci unsigned long ca; 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#define EOF 0x8000 2078c2ecf20Sopenharmony_ci#define SIZE_MASK 0x3fff 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistruct i596_tbd { 2108c2ecf20Sopenharmony_ci unsigned short size; 2118c2ecf20Sopenharmony_ci unsigned short pad; 2128c2ecf20Sopenharmony_ci struct i596_tbd *next; 2138c2ecf20Sopenharmony_ci char *data; 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* The command structure has two 'next' pointers; v_next is the address of 2178c2ecf20Sopenharmony_ci * the next command as seen by the CPU, b_next is the address of the next 2188c2ecf20Sopenharmony_ci * command as seen by the 82596. The b_next pointer, as used by the 82596 2198c2ecf20Sopenharmony_ci * always references the status field of the next command, rather than the 2208c2ecf20Sopenharmony_ci * v_next field, because the 82596 is unaware of v_next. It may seem more 2218c2ecf20Sopenharmony_ci * logical to put v_next at the end of the structure, but we cannot do that 2228c2ecf20Sopenharmony_ci * because the 82596 expects other fields to be there, depending on command 2238c2ecf20Sopenharmony_ci * type. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistruct i596_cmd { 2278c2ecf20Sopenharmony_ci struct i596_cmd *v_next; /* Address from CPUs viewpoint */ 2288c2ecf20Sopenharmony_ci unsigned short status; 2298c2ecf20Sopenharmony_ci unsigned short command; 2308c2ecf20Sopenharmony_ci struct i596_cmd *b_next; /* Address from i596 viewpoint */ 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistruct tx_cmd { 2348c2ecf20Sopenharmony_ci struct i596_cmd cmd; 2358c2ecf20Sopenharmony_ci struct i596_tbd *tbd; 2368c2ecf20Sopenharmony_ci unsigned short size; 2378c2ecf20Sopenharmony_ci unsigned short pad; 2388c2ecf20Sopenharmony_ci struct sk_buff *skb; /* So we can free it after tx */ 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistruct tdr_cmd { 2428c2ecf20Sopenharmony_ci struct i596_cmd cmd; 2438c2ecf20Sopenharmony_ci unsigned short status; 2448c2ecf20Sopenharmony_ci unsigned short pad; 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistruct mc_cmd { 2488c2ecf20Sopenharmony_ci struct i596_cmd cmd; 2498c2ecf20Sopenharmony_ci short mc_cnt; 2508c2ecf20Sopenharmony_ci char mc_addrs[MAX_MC_CNT*6]; 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistruct sa_cmd { 2548c2ecf20Sopenharmony_ci struct i596_cmd cmd; 2558c2ecf20Sopenharmony_ci char eth_addr[8]; 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistruct cf_cmd { 2598c2ecf20Sopenharmony_ci struct i596_cmd cmd; 2608c2ecf20Sopenharmony_ci char i596_config[16]; 2618c2ecf20Sopenharmony_ci}; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistruct i596_rfd { 2648c2ecf20Sopenharmony_ci unsigned short stat; 2658c2ecf20Sopenharmony_ci unsigned short cmd; 2668c2ecf20Sopenharmony_ci struct i596_rfd *b_next; /* Address from i596 viewpoint */ 2678c2ecf20Sopenharmony_ci struct i596_rbd *rbd; 2688c2ecf20Sopenharmony_ci unsigned short count; 2698c2ecf20Sopenharmony_ci unsigned short size; 2708c2ecf20Sopenharmony_ci struct i596_rfd *v_next; /* Address from CPUs viewpoint */ 2718c2ecf20Sopenharmony_ci struct i596_rfd *v_prev; 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistruct i596_rbd { 2758c2ecf20Sopenharmony_ci unsigned short count; 2768c2ecf20Sopenharmony_ci unsigned short zero1; 2778c2ecf20Sopenharmony_ci struct i596_rbd *b_next; 2788c2ecf20Sopenharmony_ci unsigned char *b_data; /* Address from i596 viewpoint */ 2798c2ecf20Sopenharmony_ci unsigned short size; 2808c2ecf20Sopenharmony_ci unsigned short zero2; 2818c2ecf20Sopenharmony_ci struct sk_buff *skb; 2828c2ecf20Sopenharmony_ci struct i596_rbd *v_next; 2838c2ecf20Sopenharmony_ci struct i596_rbd *b_addr; /* This rbd addr from i596 view */ 2848c2ecf20Sopenharmony_ci unsigned char *v_data; /* Address from CPUs viewpoint */ 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci#define TX_RING_SIZE 64 2888c2ecf20Sopenharmony_ci#define RX_RING_SIZE 16 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistruct i596_scb { 2918c2ecf20Sopenharmony_ci unsigned short status; 2928c2ecf20Sopenharmony_ci unsigned short command; 2938c2ecf20Sopenharmony_ci struct i596_cmd *cmd; 2948c2ecf20Sopenharmony_ci struct i596_rfd *rfd; 2958c2ecf20Sopenharmony_ci unsigned long crc_err; 2968c2ecf20Sopenharmony_ci unsigned long align_err; 2978c2ecf20Sopenharmony_ci unsigned long resource_err; 2988c2ecf20Sopenharmony_ci unsigned long over_err; 2998c2ecf20Sopenharmony_ci unsigned long rcvdt_err; 3008c2ecf20Sopenharmony_ci unsigned long short_err; 3018c2ecf20Sopenharmony_ci unsigned short t_on; 3028c2ecf20Sopenharmony_ci unsigned short t_off; 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistruct i596_iscp { 3068c2ecf20Sopenharmony_ci unsigned long stat; 3078c2ecf20Sopenharmony_ci struct i596_scb *scb; 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistruct i596_scp { 3118c2ecf20Sopenharmony_ci unsigned long sysbus; 3128c2ecf20Sopenharmony_ci unsigned long pad; 3138c2ecf20Sopenharmony_ci struct i596_iscp *iscp; 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistruct i596_private { 3178c2ecf20Sopenharmony_ci volatile struct i596_scp scp; 3188c2ecf20Sopenharmony_ci volatile struct i596_iscp iscp; 3198c2ecf20Sopenharmony_ci volatile struct i596_scb scb; 3208c2ecf20Sopenharmony_ci struct sa_cmd sa_cmd; 3218c2ecf20Sopenharmony_ci struct cf_cmd cf_cmd; 3228c2ecf20Sopenharmony_ci struct tdr_cmd tdr_cmd; 3238c2ecf20Sopenharmony_ci struct mc_cmd mc_cmd; 3248c2ecf20Sopenharmony_ci unsigned long stat; 3258c2ecf20Sopenharmony_ci int last_restart __attribute__((aligned(4))); 3268c2ecf20Sopenharmony_ci struct i596_rfd *rfd_head; 3278c2ecf20Sopenharmony_ci struct i596_rbd *rbd_head; 3288c2ecf20Sopenharmony_ci struct i596_cmd *cmd_tail; 3298c2ecf20Sopenharmony_ci struct i596_cmd *cmd_head; 3308c2ecf20Sopenharmony_ci int cmd_backlog; 3318c2ecf20Sopenharmony_ci unsigned long last_cmd; 3328c2ecf20Sopenharmony_ci struct i596_rfd rfds[RX_RING_SIZE]; 3338c2ecf20Sopenharmony_ci struct i596_rbd rbds[RX_RING_SIZE]; 3348c2ecf20Sopenharmony_ci struct tx_cmd tx_cmds[TX_RING_SIZE]; 3358c2ecf20Sopenharmony_ci struct i596_tbd tbds[TX_RING_SIZE]; 3368c2ecf20Sopenharmony_ci int next_tx_cmd; 3378c2ecf20Sopenharmony_ci spinlock_t lock; 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic char init_setup[] = 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci 0x8E, /* length, prefetch on */ 3438c2ecf20Sopenharmony_ci 0xC8, /* fifo to 8, monitor off */ 3448c2ecf20Sopenharmony_ci#ifdef CONFIG_VME 3458c2ecf20Sopenharmony_ci 0xc0, /* don't save bad frames */ 3468c2ecf20Sopenharmony_ci#else 3478c2ecf20Sopenharmony_ci 0x80, /* don't save bad frames */ 3488c2ecf20Sopenharmony_ci#endif 3498c2ecf20Sopenharmony_ci 0x2E, /* No source address insertion, 8 byte preamble */ 3508c2ecf20Sopenharmony_ci 0x00, /* priority and backoff defaults */ 3518c2ecf20Sopenharmony_ci 0x60, /* interframe spacing */ 3528c2ecf20Sopenharmony_ci 0x00, /* slot time LSB */ 3538c2ecf20Sopenharmony_ci 0xf2, /* slot time and retries */ 3548c2ecf20Sopenharmony_ci 0x00, /* promiscuous mode */ 3558c2ecf20Sopenharmony_ci 0x00, /* collision detect */ 3568c2ecf20Sopenharmony_ci 0x40, /* minimum frame length */ 3578c2ecf20Sopenharmony_ci 0xff, 3588c2ecf20Sopenharmony_ci 0x00, 3598c2ecf20Sopenharmony_ci 0x7f /* *multi IA */ }; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int i596_open(struct net_device *dev); 3628c2ecf20Sopenharmony_cistatic netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev); 3638c2ecf20Sopenharmony_cistatic irqreturn_t i596_interrupt(int irq, void *dev_id); 3648c2ecf20Sopenharmony_cistatic int i596_close(struct net_device *dev); 3658c2ecf20Sopenharmony_cistatic void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); 3668c2ecf20Sopenharmony_cistatic void i596_tx_timeout (struct net_device *dev, unsigned int txqueue); 3678c2ecf20Sopenharmony_cistatic void print_eth(unsigned char *buf, char *str); 3688c2ecf20Sopenharmony_cistatic void set_multicast_list(struct net_device *dev); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int rx_ring_size = RX_RING_SIZE; 3718c2ecf20Sopenharmony_cistatic int ticks_limit = 25; 3728c2ecf20Sopenharmony_cistatic int max_cmd_backlog = TX_RING_SIZE-1; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic inline void CA(struct net_device *dev) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 3788c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 3798c2ecf20Sopenharmony_ci ((struct i596_reg *) dev->base_addr)->ca = 1; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci#endif 3828c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 3838c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 3848c2ecf20Sopenharmony_ci volatile u32 i; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci i = *(volatile u32 *) (dev->base_addr); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci#endif 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic inline void MPU_PORT(struct net_device *dev, int c, volatile void *x) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 3958c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 3968c2ecf20Sopenharmony_ci struct i596_reg *p = (struct i596_reg *) (dev->base_addr); 3978c2ecf20Sopenharmony_ci p->porthi = ((c) | (u32) (x)) & 0xffff; 3988c2ecf20Sopenharmony_ci p->portlo = ((c) | (u32) (x)) >> 16; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci#endif 4018c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 4028c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 4038c2ecf20Sopenharmony_ci u32 v = (u32) (c) | (u32) (x); 4048c2ecf20Sopenharmony_ci v = ((u32) (v) << 16) | ((u32) (v) >> 16); 4058c2ecf20Sopenharmony_ci *(volatile u32 *) dev->base_addr = v; 4068c2ecf20Sopenharmony_ci udelay(1); 4078c2ecf20Sopenharmony_ci *(volatile u32 *) dev->base_addr = v; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci#endif 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci while (--delcnt && lp->iscp.stat) 4168c2ecf20Sopenharmony_ci udelay(10); 4178c2ecf20Sopenharmony_ci if (!delcnt) { 4188c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n", 4198c2ecf20Sopenharmony_ci dev->name, str, lp->scb.status, lp->scb.command); 4208c2ecf20Sopenharmony_ci return -1; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci else 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci while (--delcnt && lp->scb.command) 4308c2ecf20Sopenharmony_ci udelay(10); 4318c2ecf20Sopenharmony_ci if (!delcnt) { 4328c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n", 4338c2ecf20Sopenharmony_ci dev->name, str, lp->scb.status, lp->scb.command); 4348c2ecf20Sopenharmony_ci return -1; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci else 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci volatile struct i596_cmd *c = cmd; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci while (--delcnt && c->command) 4468c2ecf20Sopenharmony_ci udelay(10); 4478c2ecf20Sopenharmony_ci if (!delcnt) { 4488c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s.\n", dev->name, str); 4498c2ecf20Sopenharmony_ci return -1; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci else 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void i596_display_data(struct net_device *dev) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 4598c2ecf20Sopenharmony_ci struct i596_cmd *cmd; 4608c2ecf20Sopenharmony_ci struct i596_rfd *rfd; 4618c2ecf20Sopenharmony_ci struct i596_rbd *rbd; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci printk(KERN_ERR "lp and scp at %p, .sysbus = %08lx, .iscp = %p\n", 4648c2ecf20Sopenharmony_ci &lp->scp, lp->scp.sysbus, lp->scp.iscp); 4658c2ecf20Sopenharmony_ci printk(KERN_ERR "iscp at %p, iscp.stat = %08lx, .scb = %p\n", 4668c2ecf20Sopenharmony_ci &lp->iscp, lp->iscp.stat, lp->iscp.scb); 4678c2ecf20Sopenharmony_ci printk(KERN_ERR "scb at %p, scb.status = %04x, .command = %04x," 4688c2ecf20Sopenharmony_ci " .cmd = %p, .rfd = %p\n", 4698c2ecf20Sopenharmony_ci &lp->scb, lp->scb.status, lp->scb.command, 4708c2ecf20Sopenharmony_ci lp->scb.cmd, lp->scb.rfd); 4718c2ecf20Sopenharmony_ci printk(KERN_ERR " errors: crc %lx, align %lx, resource %lx," 4728c2ecf20Sopenharmony_ci " over %lx, rcvdt %lx, short %lx\n", 4738c2ecf20Sopenharmony_ci lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err, 4748c2ecf20Sopenharmony_ci lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err); 4758c2ecf20Sopenharmony_ci cmd = lp->cmd_head; 4768c2ecf20Sopenharmony_ci while (cmd != I596_NULL) { 4778c2ecf20Sopenharmony_ci printk(KERN_ERR "cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n", 4788c2ecf20Sopenharmony_ci cmd, cmd->status, cmd->command, cmd->b_next); 4798c2ecf20Sopenharmony_ci cmd = cmd->v_next; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci rfd = lp->rfd_head; 4828c2ecf20Sopenharmony_ci printk(KERN_ERR "rfd_head = %p\n", rfd); 4838c2ecf20Sopenharmony_ci do { 4848c2ecf20Sopenharmony_ci printk(KERN_ERR " %p .stat %04x, .cmd %04x, b_next %p, rbd %p," 4858c2ecf20Sopenharmony_ci " count %04x\n", 4868c2ecf20Sopenharmony_ci rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd, 4878c2ecf20Sopenharmony_ci rfd->count); 4888c2ecf20Sopenharmony_ci rfd = rfd->v_next; 4898c2ecf20Sopenharmony_ci } while (rfd != lp->rfd_head); 4908c2ecf20Sopenharmony_ci rbd = lp->rbd_head; 4918c2ecf20Sopenharmony_ci printk(KERN_ERR "rbd_head = %p\n", rbd); 4928c2ecf20Sopenharmony_ci do { 4938c2ecf20Sopenharmony_ci printk(KERN_ERR " %p .count %04x, b_next %p, b_data %p, size %04x\n", 4948c2ecf20Sopenharmony_ci rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size); 4958c2ecf20Sopenharmony_ci rbd = rbd->v_next; 4968c2ecf20Sopenharmony_ci } while (rbd != lp->rbd_head); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET) 5018c2ecf20Sopenharmony_cistatic irqreturn_t i596_error(int irq, void *dev_id) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 5048c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 5058c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 5068c2ecf20Sopenharmony_ci volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci pcc2[0x28] = 1; 5098c2ecf20Sopenharmony_ci pcc2[0x2b] = 0x1d; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci#endif 5128c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 5138c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 5148c2ecf20Sopenharmony_ci volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci *ethirq = 1; 5178c2ecf20Sopenharmony_ci *ethirq = 3; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci#endif 5208c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Error interrupt\n", dev->name); 5218c2ecf20Sopenharmony_ci i596_display_data(dev); 5228c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci#endif 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic inline void remove_rx_bufs(struct net_device *dev) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 5298c2ecf20Sopenharmony_ci struct i596_rbd *rbd; 5308c2ecf20Sopenharmony_ci int i; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { 5338c2ecf20Sopenharmony_ci if (rbd->skb == NULL) 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci dev_kfree_skb(rbd->skb); 5368c2ecf20Sopenharmony_ci rbd->skb = NULL; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic inline int init_rx_bufs(struct net_device *dev) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 5438c2ecf20Sopenharmony_ci int i; 5448c2ecf20Sopenharmony_ci struct i596_rfd *rfd; 5458c2ecf20Sopenharmony_ci struct i596_rbd *rbd; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* First build the Receive Buffer Descriptor List */ 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { 5508c2ecf20Sopenharmony_ci struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (skb == NULL) { 5538c2ecf20Sopenharmony_ci remove_rx_bufs(dev); 5548c2ecf20Sopenharmony_ci return -ENOMEM; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci rbd->v_next = rbd+1; 5588c2ecf20Sopenharmony_ci rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1)); 5598c2ecf20Sopenharmony_ci rbd->b_addr = WSWAPrbd(virt_to_bus(rbd)); 5608c2ecf20Sopenharmony_ci rbd->skb = skb; 5618c2ecf20Sopenharmony_ci rbd->v_data = skb->data; 5628c2ecf20Sopenharmony_ci rbd->b_data = WSWAPchar(virt_to_bus(skb->data)); 5638c2ecf20Sopenharmony_ci rbd->size = PKT_BUF_SZ; 5648c2ecf20Sopenharmony_ci#ifdef __mc68000__ 5658c2ecf20Sopenharmony_ci cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ); 5668c2ecf20Sopenharmony_ci#endif 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci lp->rbd_head = lp->rbds; 5698c2ecf20Sopenharmony_ci rbd = lp->rbds + rx_ring_size - 1; 5708c2ecf20Sopenharmony_ci rbd->v_next = lp->rbds; 5718c2ecf20Sopenharmony_ci rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds)); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Now build the Receive Frame Descriptor List */ 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) { 5768c2ecf20Sopenharmony_ci rfd->rbd = I596_NULL; 5778c2ecf20Sopenharmony_ci rfd->v_next = rfd+1; 5788c2ecf20Sopenharmony_ci rfd->v_prev = rfd-1; 5798c2ecf20Sopenharmony_ci rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1)); 5808c2ecf20Sopenharmony_ci rfd->cmd = CMD_FLEX; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci lp->rfd_head = lp->rfds; 5838c2ecf20Sopenharmony_ci lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds)); 5848c2ecf20Sopenharmony_ci rfd = lp->rfds; 5858c2ecf20Sopenharmony_ci rfd->rbd = lp->rbd_head; 5868c2ecf20Sopenharmony_ci rfd->v_prev = lp->rfds + rx_ring_size - 1; 5878c2ecf20Sopenharmony_ci rfd = lp->rfds + rx_ring_size - 1; 5888c2ecf20Sopenharmony_ci rfd->v_next = lp->rfds; 5898c2ecf20Sopenharmony_ci rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds)); 5908c2ecf20Sopenharmony_ci rfd->cmd = CMD_EOL|CMD_FLEX; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void rebuild_rx_bufs(struct net_device *dev) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 5998c2ecf20Sopenharmony_ci int i; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Ensure rx frame/buffer descriptors are tidy */ 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci for (i = 0; i < rx_ring_size; i++) { 6048c2ecf20Sopenharmony_ci lp->rfds[i].rbd = I596_NULL; 6058c2ecf20Sopenharmony_ci lp->rfds[i].cmd = CMD_FLEX; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX; 6088c2ecf20Sopenharmony_ci lp->rfd_head = lp->rfds; 6098c2ecf20Sopenharmony_ci lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds)); 6108c2ecf20Sopenharmony_ci lp->rbd_head = lp->rbds; 6118c2ecf20Sopenharmony_ci lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds)); 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int init_i596_mem(struct net_device *dev) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 6188c2ecf20Sopenharmony_ci unsigned long flags; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci MPU_PORT(dev, PORT_RESET, NULL); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci udelay(100); /* Wait 100us - seems to help */ 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET) 6258c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 6268c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 6278c2ecf20Sopenharmony_ci volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* Disable all ints for now */ 6308c2ecf20Sopenharmony_ci pcc2[0x28] = 1; 6318c2ecf20Sopenharmony_ci pcc2[0x2a] = 0x48; 6328c2ecf20Sopenharmony_ci /* Following disables snooping. Snooping is not required 6338c2ecf20Sopenharmony_ci * as we make appropriate use of non-cached pages for 6348c2ecf20Sopenharmony_ci * shared data, and cache_push/cache_clear. 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci pcc2[0x2b] = 0x08; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci#endif 6398c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 6408c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 6418c2ecf20Sopenharmony_ci volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci *ethirq = 1; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci#endif 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* change the scp address */ 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp)); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci#endif 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci lp->last_cmd = jiffies; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 6568c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) 6578c2ecf20Sopenharmony_ci lp->scp.sysbus = 0x00000054; 6588c2ecf20Sopenharmony_ci#endif 6598c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 6608c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) 6618c2ecf20Sopenharmony_ci lp->scp.sysbus = 0x0000004c; 6628c2ecf20Sopenharmony_ci#endif 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp)); 6658c2ecf20Sopenharmony_ci lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb)); 6668c2ecf20Sopenharmony_ci lp->iscp.stat = ISCP_BUSY; 6678c2ecf20Sopenharmony_ci lp->cmd_backlog = 0; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci lp->cmd_head = lp->scb.cmd = I596_NULL; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 6728c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 6738c2ecf20Sopenharmony_ci lp->scb.t_on = 7 * 25; 6748c2ecf20Sopenharmony_ci lp->scb.t_off = 1 * 25; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci#endif 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name)); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci CA(dev); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (wait_istat(dev,lp,1000,"initialization timed out")) 6838c2ecf20Sopenharmony_ci goto failed; 6848c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: i82596 initialization successful\n", dev->name)); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Ensure rx frame/buffer descriptors are tidy */ 6878c2ecf20Sopenharmony_ci rebuild_rx_bufs(dev); 6888c2ecf20Sopenharmony_ci lp->scb.command = 0; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 6918c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 6928c2ecf20Sopenharmony_ci volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* Enable ints, etc. now */ 6958c2ecf20Sopenharmony_ci pcc2[0x2a] = 0x55; /* Edge sensitive */ 6968c2ecf20Sopenharmony_ci pcc2[0x2b] = 0x15; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci#endif 6998c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 7008c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 7018c2ecf20Sopenharmony_ci volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci *ethirq = 3; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci#endif 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdConfigure\n", dev->name)); 7098c2ecf20Sopenharmony_ci memcpy(lp->cf_cmd.i596_config, init_setup, 14); 7108c2ecf20Sopenharmony_ci lp->cf_cmd.cmd.command = CmdConfigure; 7118c2ecf20Sopenharmony_ci i596_add_cmd(dev, &lp->cf_cmd.cmd); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name)); 7148c2ecf20Sopenharmony_ci memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, ETH_ALEN); 7158c2ecf20Sopenharmony_ci lp->sa_cmd.cmd.command = CmdSASetup; 7168c2ecf20Sopenharmony_ci i596_add_cmd(dev, &lp->sa_cmd.cmd); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name)); 7198c2ecf20Sopenharmony_ci lp->tdr_cmd.cmd.command = CmdTDR; 7208c2ecf20Sopenharmony_ci i596_add_cmd(dev, &lp->tdr_cmd.cmd); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci spin_lock_irqsave (&lp->lock, flags); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) { 7258c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 7268c2ecf20Sopenharmony_ci goto failed; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name)); 7298c2ecf20Sopenharmony_ci lp->scb.command = RX_START; 7308c2ecf20Sopenharmony_ci CA(dev); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (wait_cmd(dev,lp,1000,"RX_START not processed")) 7358c2ecf20Sopenharmony_ci goto failed; 7368c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: Receive unit started OK\n", dev->name)); 7378c2ecf20Sopenharmony_ci return 0; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cifailed: 7408c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s: Failed to initialise 82596\n", dev->name); 7418c2ecf20Sopenharmony_ci MPU_PORT(dev, PORT_RESET, NULL); 7428c2ecf20Sopenharmony_ci return -1; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic inline int i596_rx(struct net_device *dev) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 7488c2ecf20Sopenharmony_ci struct i596_rfd *rfd; 7498c2ecf20Sopenharmony_ci struct i596_rbd *rbd; 7508c2ecf20Sopenharmony_ci int frames = 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci DEB(DEB_RXFRAME,printk(KERN_DEBUG "i596_rx(), rfd_head %p, rbd_head %p\n", 7538c2ecf20Sopenharmony_ci lp->rfd_head, lp->rbd_head)); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci rfd = lp->rfd_head; /* Ref next frame to check */ 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci while ((rfd->stat) & STAT_C) { /* Loop while complete frames */ 7588c2ecf20Sopenharmony_ci if (rfd->rbd == I596_NULL) 7598c2ecf20Sopenharmony_ci rbd = I596_NULL; 7608c2ecf20Sopenharmony_ci else if (rfd->rbd == lp->rbd_head->b_addr) 7618c2ecf20Sopenharmony_ci rbd = lp->rbd_head; 7628c2ecf20Sopenharmony_ci else { 7638c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s: rbd chain broken!\n", dev->name); 7648c2ecf20Sopenharmony_ci /* XXX Now what? */ 7658c2ecf20Sopenharmony_ci rbd = I596_NULL; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci DEB(DEB_RXFRAME, printk(KERN_DEBUG " rfd %p, rfd.rbd %p, rfd.stat %04x\n", 7688c2ecf20Sopenharmony_ci rfd, rfd->rbd, rfd->stat)); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) { 7718c2ecf20Sopenharmony_ci /* a good frame */ 7728c2ecf20Sopenharmony_ci int pkt_len = rbd->count & 0x3fff; 7738c2ecf20Sopenharmony_ci struct sk_buff *skb = rbd->skb; 7748c2ecf20Sopenharmony_ci int rx_in_place = 0; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci DEB(DEB_RXADDR,print_eth(rbd->v_data, "received")); 7778c2ecf20Sopenharmony_ci frames++; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* Check if the packet is long enough to just accept 7808c2ecf20Sopenharmony_ci * without copying to a properly sized skbuff. 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (pkt_len > rx_copybreak) { 7848c2ecf20Sopenharmony_ci struct sk_buff *newskb; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* Get fresh skbuff to replace filled one. */ 7878c2ecf20Sopenharmony_ci newskb = netdev_alloc_skb(dev, PKT_BUF_SZ); 7888c2ecf20Sopenharmony_ci if (newskb == NULL) { 7898c2ecf20Sopenharmony_ci skb = NULL; /* drop pkt */ 7908c2ecf20Sopenharmony_ci goto memory_squeeze; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci /* Pass up the skb already on the Rx ring. */ 7938c2ecf20Sopenharmony_ci skb_put(skb, pkt_len); 7948c2ecf20Sopenharmony_ci rx_in_place = 1; 7958c2ecf20Sopenharmony_ci rbd->skb = newskb; 7968c2ecf20Sopenharmony_ci rbd->v_data = newskb->data; 7978c2ecf20Sopenharmony_ci rbd->b_data = WSWAPchar(virt_to_bus(newskb->data)); 7988c2ecf20Sopenharmony_ci#ifdef __mc68000__ 7998c2ecf20Sopenharmony_ci cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ); 8008c2ecf20Sopenharmony_ci#endif 8018c2ecf20Sopenharmony_ci } else { 8028c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, pkt_len + 2); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_cimemory_squeeze: 8058c2ecf20Sopenharmony_ci if (skb == NULL) { 8068c2ecf20Sopenharmony_ci /* XXX tulip.c can defer packets here!! */ 8078c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 8088c2ecf20Sopenharmony_ci } else { 8098c2ecf20Sopenharmony_ci if (!rx_in_place) { 8108c2ecf20Sopenharmony_ci /* 16 byte align the data fields */ 8118c2ecf20Sopenharmony_ci skb_reserve(skb, 2); 8128c2ecf20Sopenharmony_ci skb_put_data(skb, rbd->v_data, 8138c2ecf20Sopenharmony_ci pkt_len); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci skb->protocol=eth_type_trans(skb,dev); 8168c2ecf20Sopenharmony_ci skb->len = pkt_len; 8178c2ecf20Sopenharmony_ci#ifdef __mc68000__ 8188c2ecf20Sopenharmony_ci cache_clear(virt_to_phys(rbd->skb->data), 8198c2ecf20Sopenharmony_ci pkt_len); 8208c2ecf20Sopenharmony_ci#endif 8218c2ecf20Sopenharmony_ci netif_rx(skb); 8228c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 8238c2ecf20Sopenharmony_ci dev->stats.rx_bytes+=pkt_len; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci else { 8278c2ecf20Sopenharmony_ci DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n", 8288c2ecf20Sopenharmony_ci dev->name, rfd->stat)); 8298c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 8308c2ecf20Sopenharmony_ci if ((rfd->stat) & 0x0001) 8318c2ecf20Sopenharmony_ci dev->stats.collisions++; 8328c2ecf20Sopenharmony_ci if ((rfd->stat) & 0x0080) 8338c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 8348c2ecf20Sopenharmony_ci if ((rfd->stat) & 0x0100) 8358c2ecf20Sopenharmony_ci dev->stats.rx_over_errors++; 8368c2ecf20Sopenharmony_ci if ((rfd->stat) & 0x0200) 8378c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 8388c2ecf20Sopenharmony_ci if ((rfd->stat) & 0x0400) 8398c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors++; 8408c2ecf20Sopenharmony_ci if ((rfd->stat) & 0x0800) 8418c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 8428c2ecf20Sopenharmony_ci if ((rfd->stat) & 0x1000) 8438c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* Clear the buffer descriptor count and EOF + F flags */ 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (rbd != I596_NULL && (rbd->count & 0x4000)) { 8498c2ecf20Sopenharmony_ci rbd->count = 0; 8508c2ecf20Sopenharmony_ci lp->rbd_head = rbd->v_next; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* Tidy the frame descriptor, marking it as end of list */ 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci rfd->rbd = I596_NULL; 8568c2ecf20Sopenharmony_ci rfd->stat = 0; 8578c2ecf20Sopenharmony_ci rfd->cmd = CMD_EOL|CMD_FLEX; 8588c2ecf20Sopenharmony_ci rfd->count = 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Remove end-of-list from old end descriptor */ 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci rfd->v_prev->cmd = CMD_FLEX; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* Update record of next frame descriptor to process */ 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci lp->scb.rfd = rfd->b_next; 8678c2ecf20Sopenharmony_ci lp->rfd_head = rfd->v_next; 8688c2ecf20Sopenharmony_ci rfd = lp->rfd_head; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci DEB(DEB_RXFRAME,printk(KERN_DEBUG "frames %d\n", frames)); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci return 0; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci struct i596_cmd *ptr; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci while (lp->cmd_head != I596_NULL) { 8828c2ecf20Sopenharmony_ci ptr = lp->cmd_head; 8838c2ecf20Sopenharmony_ci lp->cmd_head = ptr->v_next; 8848c2ecf20Sopenharmony_ci lp->cmd_backlog--; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci switch ((ptr->command) & 0x7) { 8878c2ecf20Sopenharmony_ci case CmdTx: 8888c2ecf20Sopenharmony_ci { 8898c2ecf20Sopenharmony_ci struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; 8908c2ecf20Sopenharmony_ci struct sk_buff *skb = tx_cmd->skb; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 8958c2ecf20Sopenharmony_ci dev->stats.tx_aborted_errors++; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci ptr->v_next = ptr->b_next = I596_NULL; 8988c2ecf20Sopenharmony_ci tx_cmd->cmd.command = 0; /* Mark as free */ 8998c2ecf20Sopenharmony_ci break; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci default: 9028c2ecf20Sopenharmony_ci ptr->v_next = ptr->b_next = I596_NULL; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out"); 9078c2ecf20Sopenharmony_ci lp->scb.cmd = I596_NULL; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic void i596_reset(struct net_device *dev, struct i596_private *lp, 9118c2ecf20Sopenharmony_ci int ioaddr) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci unsigned long flags; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci DEB(DEB_RESET,printk(KERN_DEBUG "i596_reset\n")); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci spin_lock_irqsave (&lp->lock, flags); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci wait_cmd(dev,lp,100,"i596_reset timed out"); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci netif_stop_queue(dev); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci lp->scb.command = CUC_ABORT | RX_ABORT; 9248c2ecf20Sopenharmony_ci CA(dev); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* wait for shutdown */ 9278c2ecf20Sopenharmony_ci wait_cmd(dev,lp,1000,"i596_reset 2 timed out"); 9288c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci i596_cleanup_cmd(dev,lp); 9318c2ecf20Sopenharmony_ci i596_rx(dev); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci netif_start_queue(dev); 9348c2ecf20Sopenharmony_ci init_i596_mem(dev); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 9408c2ecf20Sopenharmony_ci int ioaddr = dev->base_addr; 9418c2ecf20Sopenharmony_ci unsigned long flags; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci DEB(DEB_ADDCMD,printk(KERN_DEBUG "i596_add_cmd\n")); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci cmd->status = 0; 9468c2ecf20Sopenharmony_ci cmd->command |= (CMD_EOL | CMD_INTR); 9478c2ecf20Sopenharmony_ci cmd->v_next = cmd->b_next = I596_NULL; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci spin_lock_irqsave (&lp->lock, flags); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (lp->cmd_head != I596_NULL) { 9528c2ecf20Sopenharmony_ci lp->cmd_tail->v_next = cmd; 9538c2ecf20Sopenharmony_ci lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status)); 9548c2ecf20Sopenharmony_ci } else { 9558c2ecf20Sopenharmony_ci lp->cmd_head = cmd; 9568c2ecf20Sopenharmony_ci wait_cmd(dev,lp,100,"i596_add_cmd timed out"); 9578c2ecf20Sopenharmony_ci lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status)); 9588c2ecf20Sopenharmony_ci lp->scb.command = CUC_START; 9598c2ecf20Sopenharmony_ci CA(dev); 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci lp->cmd_tail = cmd; 9628c2ecf20Sopenharmony_ci lp->cmd_backlog++; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (lp->cmd_backlog > max_cmd_backlog) { 9678c2ecf20Sopenharmony_ci unsigned long tickssofar = jiffies - lp->last_cmd; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (tickssofar < ticks_limit) 9708c2ecf20Sopenharmony_ci return; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: command unit timed out, status resetting.\n", dev->name); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci i596_reset(dev, lp, ioaddr); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic int i596_open(struct net_device *dev) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci int res = 0; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci DEB(DEB_OPEN,printk(KERN_DEBUG "%s: i596_open() irq %d.\n", dev->name, dev->irq)); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) { 9858c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq); 9868c2ecf20Sopenharmony_ci return -EAGAIN; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 9898c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 9908c2ecf20Sopenharmony_ci if (request_irq(0x56, i596_error, 0, "i82596_error", dev)) { 9918c2ecf20Sopenharmony_ci res = -EAGAIN; 9928c2ecf20Sopenharmony_ci goto err_irq_dev; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci#endif 9968c2ecf20Sopenharmony_ci res = init_rx_bufs(dev); 9978c2ecf20Sopenharmony_ci if (res) 9988c2ecf20Sopenharmony_ci goto err_irq_56; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci netif_start_queue(dev); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (init_i596_mem(dev)) { 10038c2ecf20Sopenharmony_ci res = -EAGAIN; 10048c2ecf20Sopenharmony_ci goto err_queue; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci return 0; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cierr_queue: 10108c2ecf20Sopenharmony_ci netif_stop_queue(dev); 10118c2ecf20Sopenharmony_ci remove_rx_bufs(dev); 10128c2ecf20Sopenharmony_cierr_irq_56: 10138c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 10148c2ecf20Sopenharmony_ci free_irq(0x56, dev); 10158c2ecf20Sopenharmony_cierr_irq_dev: 10168c2ecf20Sopenharmony_ci#endif 10178c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return res; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic void i596_tx_timeout (struct net_device *dev, unsigned int txqueue) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 10258c2ecf20Sopenharmony_ci int ioaddr = dev->base_addr; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Transmitter timeout, serious problems. */ 10288c2ecf20Sopenharmony_ci DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n", 10298c2ecf20Sopenharmony_ci dev->name)); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* Try to restart the adaptor */ 10348c2ecf20Sopenharmony_ci if (lp->last_restart == dev->stats.tx_packets) { 10358c2ecf20Sopenharmony_ci DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n")); 10368c2ecf20Sopenharmony_ci /* Shutdown and restart */ 10378c2ecf20Sopenharmony_ci i596_reset (dev, lp, ioaddr); 10388c2ecf20Sopenharmony_ci } else { 10398c2ecf20Sopenharmony_ci /* Issue a channel attention signal */ 10408c2ecf20Sopenharmony_ci DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n")); 10418c2ecf20Sopenharmony_ci lp->scb.command = CUC_START | RX_START; 10428c2ecf20Sopenharmony_ci CA (dev); 10438c2ecf20Sopenharmony_ci lp->last_restart = dev->stats.tx_packets; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 10478c2ecf20Sopenharmony_ci netif_wake_queue (dev); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 10538c2ecf20Sopenharmony_ci struct tx_cmd *tx_cmd; 10548c2ecf20Sopenharmony_ci struct i596_tbd *tbd; 10558c2ecf20Sopenharmony_ci short length = skb->len; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n", 10588c2ecf20Sopenharmony_ci dev->name, skb->len, skb->data)); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (skb->len < ETH_ZLEN) { 10618c2ecf20Sopenharmony_ci if (skb_padto(skb, ETH_ZLEN)) 10628c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10638c2ecf20Sopenharmony_ci length = ETH_ZLEN; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci netif_stop_queue(dev); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci tx_cmd = lp->tx_cmds + lp->next_tx_cmd; 10688c2ecf20Sopenharmony_ci tbd = lp->tbds + lp->next_tx_cmd; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (tx_cmd->cmd.command) { 10718c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n", 10728c2ecf20Sopenharmony_ci dev->name); 10738c2ecf20Sopenharmony_ci dev->stats.tx_dropped++; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 10768c2ecf20Sopenharmony_ci } else { 10778c2ecf20Sopenharmony_ci if (++lp->next_tx_cmd == TX_RING_SIZE) 10788c2ecf20Sopenharmony_ci lp->next_tx_cmd = 0; 10798c2ecf20Sopenharmony_ci tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd)); 10808c2ecf20Sopenharmony_ci tbd->next = I596_NULL; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci tx_cmd->cmd.command = CMD_FLEX | CmdTx; 10838c2ecf20Sopenharmony_ci tx_cmd->skb = skb; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci tx_cmd->pad = 0; 10868c2ecf20Sopenharmony_ci tx_cmd->size = 0; 10878c2ecf20Sopenharmony_ci tbd->pad = 0; 10888c2ecf20Sopenharmony_ci tbd->size = EOF | length; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci tbd->data = WSWAPchar(virt_to_bus(skb->data)); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci#ifdef __mc68000__ 10938c2ecf20Sopenharmony_ci cache_push(virt_to_phys(skb->data), length); 10948c2ecf20Sopenharmony_ci#endif 10958c2ecf20Sopenharmony_ci DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued")); 10968c2ecf20Sopenharmony_ci i596_add_cmd(dev, &tx_cmd->cmd); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 10998c2ecf20Sopenharmony_ci dev->stats.tx_bytes += length; 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci netif_start_queue(dev); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic void print_eth(unsigned char *add, char *str) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", 11108c2ecf20Sopenharmony_ci add, add + 6, add, add[12], add[13], str); 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic int io = 0x300; 11148c2ecf20Sopenharmony_cistatic int irq = 10; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic const struct net_device_ops i596_netdev_ops = { 11178c2ecf20Sopenharmony_ci .ndo_open = i596_open, 11188c2ecf20Sopenharmony_ci .ndo_stop = i596_close, 11198c2ecf20Sopenharmony_ci .ndo_start_xmit = i596_start_xmit, 11208c2ecf20Sopenharmony_ci .ndo_set_rx_mode = set_multicast_list, 11218c2ecf20Sopenharmony_ci .ndo_tx_timeout = i596_tx_timeout, 11228c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 11238c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 11248c2ecf20Sopenharmony_ci}; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistruct net_device * __init i82596_probe(int unit) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci struct net_device *dev; 11298c2ecf20Sopenharmony_ci int i; 11308c2ecf20Sopenharmony_ci struct i596_private *lp; 11318c2ecf20Sopenharmony_ci char eth_addr[8]; 11328c2ecf20Sopenharmony_ci static int probed; 11338c2ecf20Sopenharmony_ci int err; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (probed) 11368c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 11378c2ecf20Sopenharmony_ci probed++; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci dev = alloc_etherdev(0); 11408c2ecf20Sopenharmony_ci if (!dev) 11418c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (unit >= 0) { 11448c2ecf20Sopenharmony_ci sprintf(dev->name, "eth%d", unit); 11458c2ecf20Sopenharmony_ci netdev_boot_setup_check(dev); 11468c2ecf20Sopenharmony_ci } else { 11478c2ecf20Sopenharmony_ci dev->base_addr = io; 11488c2ecf20Sopenharmony_ci dev->irq = irq; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 11528c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 11538c2ecf20Sopenharmony_ci if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) { 11548c2ecf20Sopenharmony_ci printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n"); 11558c2ecf20Sopenharmony_ci err = -ENODEV; 11568c2ecf20Sopenharmony_ci goto out; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci memcpy(eth_addr, absolute_pointer(0xfffc1f2c), ETH_ALEN); /* YUCK! Get addr from NOVRAM */ 11598c2ecf20Sopenharmony_ci dev->base_addr = MVME_I596_BASE; 11608c2ecf20Sopenharmony_ci dev->irq = (unsigned) MVME16x_IRQ_I596; 11618c2ecf20Sopenharmony_ci goto found; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci#endif 11648c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 11658c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 11668c2ecf20Sopenharmony_ci volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE; 11678c2ecf20Sopenharmony_ci unsigned char msr = rtc[3]; 11688c2ecf20Sopenharmony_ci int i; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci rtc[3] |= 0x80; 11718c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 11728c2ecf20Sopenharmony_ci eth_addr[i] = rtc[i * 4 + 7]; /* Stored in RTC RAM at offset 1 */ 11738c2ecf20Sopenharmony_ci rtc[3] = msr; 11748c2ecf20Sopenharmony_ci dev->base_addr = BVME_I596_BASE; 11758c2ecf20Sopenharmony_ci dev->irq = (unsigned) BVME_IRQ_I596; 11768c2ecf20Sopenharmony_ci goto found; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci#endif 11798c2ecf20Sopenharmony_ci err = -ENODEV; 11808c2ecf20Sopenharmony_ci goto out; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cifound: 11838c2ecf20Sopenharmony_ci dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0); 11848c2ecf20Sopenharmony_ci if (!dev->mem_start) { 11858c2ecf20Sopenharmony_ci err = -ENOMEM; 11868c2ecf20Sopenharmony_ci goto out1; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr)); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 11928c2ecf20Sopenharmony_ci DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i])); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq)); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci DEB(DEB_PROBE,printk(KERN_INFO "%s", version)); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* The 82596-specific entries in the device structure. */ 11998c2ecf20Sopenharmony_ci dev->netdev_ops = &i596_netdev_ops; 12008c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci dev->ml_priv = (void *)(dev->mem_start); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci lp = dev->ml_priv; 12058c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), " 12068c2ecf20Sopenharmony_ci "lp->scb at 0x%08lx\n", 12078c2ecf20Sopenharmony_ci dev->name, (unsigned long)lp, 12088c2ecf20Sopenharmony_ci sizeof(struct i596_private), (unsigned long)&lp->scb)); 12098c2ecf20Sopenharmony_ci memset((void *) lp, 0, sizeof(struct i596_private)); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci#ifdef __mc68000__ 12128c2ecf20Sopenharmony_ci cache_push(virt_to_phys((void *)(dev->mem_start)), 4096); 12138c2ecf20Sopenharmony_ci cache_clear(virt_to_phys((void *)(dev->mem_start)), 4096); 12148c2ecf20Sopenharmony_ci kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER); 12158c2ecf20Sopenharmony_ci#endif 12168c2ecf20Sopenharmony_ci lp->scb.command = 0; 12178c2ecf20Sopenharmony_ci lp->scb.cmd = I596_NULL; 12188c2ecf20Sopenharmony_ci lp->scb.rfd = I596_NULL; 12198c2ecf20Sopenharmony_ci spin_lock_init(&lp->lock); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci err = register_netdev(dev); 12228c2ecf20Sopenharmony_ci if (err) 12238c2ecf20Sopenharmony_ci goto out2; 12248c2ecf20Sopenharmony_ci return dev; 12258c2ecf20Sopenharmony_ciout2: 12268c2ecf20Sopenharmony_ci#ifdef __mc68000__ 12278c2ecf20Sopenharmony_ci /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, 12288c2ecf20Sopenharmony_ci * XXX which may be invalid (CONFIG_060_WRITETHROUGH) 12298c2ecf20Sopenharmony_ci */ 12308c2ecf20Sopenharmony_ci kernel_set_cachemode((void *)(dev->mem_start), 4096, 12318c2ecf20Sopenharmony_ci IOMAP_FULL_CACHING); 12328c2ecf20Sopenharmony_ci#endif 12338c2ecf20Sopenharmony_ci free_page ((u32)(dev->mem_start)); 12348c2ecf20Sopenharmony_ciout1: 12358c2ecf20Sopenharmony_ciout: 12368c2ecf20Sopenharmony_ci free_netdev(dev); 12378c2ecf20Sopenharmony_ci return ERR_PTR(err); 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic irqreturn_t i596_interrupt(int irq, void *dev_id) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 12438c2ecf20Sopenharmony_ci struct i596_private *lp; 12448c2ecf20Sopenharmony_ci short ioaddr; 12458c2ecf20Sopenharmony_ci unsigned short status, ack_cmd = 0; 12468c2ecf20Sopenharmony_ci int handled = 0; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 12498c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 12508c2ecf20Sopenharmony_ci if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) { 12518c2ecf20Sopenharmony_ci i596_error(irq, dev_id); 12528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci#endif 12568c2ecf20Sopenharmony_ci if (dev == NULL) { 12578c2ecf20Sopenharmony_ci printk(KERN_ERR "i596_interrupt(): irq %d for unknown device.\n", irq); 12588c2ecf20Sopenharmony_ci return IRQ_NONE; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci ioaddr = dev->base_addr; 12628c2ecf20Sopenharmony_ci lp = dev->ml_priv; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci spin_lock (&lp->lock); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci wait_cmd(dev,lp,100,"i596 interrupt, timeout"); 12678c2ecf20Sopenharmony_ci status = lp->scb.status; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt, IRQ %d, status %4.4x.\n", 12708c2ecf20Sopenharmony_ci dev->name, irq, status)); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci ack_cmd = status & 0xf000; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if ((status & 0x8000) || (status & 0x2000)) { 12758c2ecf20Sopenharmony_ci struct i596_cmd *ptr; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci handled = 1; 12788c2ecf20Sopenharmony_ci if ((status & 0x8000)) 12798c2ecf20Sopenharmony_ci DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt completed command.\n", dev->name)); 12808c2ecf20Sopenharmony_ci if ((status & 0x2000)) 12818c2ecf20Sopenharmony_ci DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700)); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) { 12848c2ecf20Sopenharmony_ci ptr = lp->cmd_head; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci DEB(DEB_STATUS,printk(KERN_DEBUG "cmd_head->status = %04x, ->command = %04x\n", 12878c2ecf20Sopenharmony_ci lp->cmd_head->status, lp->cmd_head->command)); 12888c2ecf20Sopenharmony_ci lp->cmd_head = ptr->v_next; 12898c2ecf20Sopenharmony_ci lp->cmd_backlog--; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci switch ((ptr->command) & 0x7) { 12928c2ecf20Sopenharmony_ci case CmdTx: 12938c2ecf20Sopenharmony_ci { 12948c2ecf20Sopenharmony_ci struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; 12958c2ecf20Sopenharmony_ci struct sk_buff *skb = tx_cmd->skb; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if ((ptr->status) & STAT_OK) { 12988c2ecf20Sopenharmony_ci DEB(DEB_TXADDR,print_eth(skb->data, "tx-done")); 12998c2ecf20Sopenharmony_ci } else { 13008c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 13018c2ecf20Sopenharmony_ci if ((ptr->status) & 0x0020) 13028c2ecf20Sopenharmony_ci dev->stats.collisions++; 13038c2ecf20Sopenharmony_ci if (!((ptr->status) & 0x0040)) 13048c2ecf20Sopenharmony_ci dev->stats.tx_heartbeat_errors++; 13058c2ecf20Sopenharmony_ci if ((ptr->status) & 0x0400) 13068c2ecf20Sopenharmony_ci dev->stats.tx_carrier_errors++; 13078c2ecf20Sopenharmony_ci if ((ptr->status) & 0x0800) 13088c2ecf20Sopenharmony_ci dev->stats.collisions++; 13098c2ecf20Sopenharmony_ci if ((ptr->status) & 0x1000) 13108c2ecf20Sopenharmony_ci dev->stats.tx_aborted_errors++; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci dev_consume_skb_irq(skb); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci tx_cmd->cmd.command = 0; /* Mark free */ 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci case CmdTDR: 13198c2ecf20Sopenharmony_ci { 13208c2ecf20Sopenharmony_ci unsigned short status = ((struct tdr_cmd *)ptr)->status; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (status & 0x8000) { 13238c2ecf20Sopenharmony_ci DEB(DEB_TDR,printk(KERN_INFO "%s: link ok.\n", dev->name)); 13248c2ecf20Sopenharmony_ci } else { 13258c2ecf20Sopenharmony_ci if (status & 0x4000) 13268c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Transceiver problem.\n", dev->name); 13278c2ecf20Sopenharmony_ci if (status & 0x2000) 13288c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Termination problem.\n", dev->name); 13298c2ecf20Sopenharmony_ci if (status & 0x1000) 13308c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Short circuit.\n", dev->name); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci DEB(DEB_TDR,printk(KERN_INFO "%s: Time %d.\n", dev->name, status & 0x07ff)); 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci break; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci case CmdConfigure: 13378c2ecf20Sopenharmony_ci case CmdMulticastList: 13388c2ecf20Sopenharmony_ci /* Zap command so set_multicast_list() knows it is free */ 13398c2ecf20Sopenharmony_ci ptr->command = 0; 13408c2ecf20Sopenharmony_ci break; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci ptr->v_next = ptr->b_next = I596_NULL; 13438c2ecf20Sopenharmony_ci lp->last_cmd = jiffies; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci ptr = lp->cmd_head; 13478c2ecf20Sopenharmony_ci while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) { 13488c2ecf20Sopenharmony_ci ptr->command &= 0x1fff; 13498c2ecf20Sopenharmony_ci ptr = ptr->v_next; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if ((lp->cmd_head != I596_NULL)) 13538c2ecf20Sopenharmony_ci ack_cmd |= CUC_START; 13548c2ecf20Sopenharmony_ci lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status)); 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci if ((status & 0x1000) || (status & 0x4000)) { 13578c2ecf20Sopenharmony_ci if ((status & 0x4000)) 13588c2ecf20Sopenharmony_ci DEB(DEB_INTS,printk(KERN_DEBUG "%s: i596 interrupt received a frame.\n", dev->name)); 13598c2ecf20Sopenharmony_ci i596_rx(dev); 13608c2ecf20Sopenharmony_ci /* Only RX_START if stopped - RGH 07-07-96 */ 13618c2ecf20Sopenharmony_ci if (status & 0x1000) { 13628c2ecf20Sopenharmony_ci if (netif_running(dev)) { 13638c2ecf20Sopenharmony_ci DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); 13648c2ecf20Sopenharmony_ci ack_cmd |= RX_START; 13658c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 13668c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 13678c2ecf20Sopenharmony_ci rebuild_rx_bufs(dev); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci wait_cmd(dev,lp,100,"i596 interrupt, timeout"); 13728c2ecf20Sopenharmony_ci lp->scb.command = ack_cmd; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 13758c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 13768c2ecf20Sopenharmony_ci /* Ack the interrupt */ 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci pcc2[0x2a] |= 0x08; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci#endif 13838c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 13848c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 13858c2ecf20Sopenharmony_ci volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci *ethirq = 1; 13888c2ecf20Sopenharmony_ci *ethirq = 3; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci#endif 13918c2ecf20Sopenharmony_ci CA(dev); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name)); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci spin_unlock (&lp->lock); 13968c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_cistatic int i596_close(struct net_device *dev) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 14028c2ecf20Sopenharmony_ci unsigned long flags; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci netif_stop_queue(dev); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci DEB(DEB_INIT,printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", 14078c2ecf20Sopenharmony_ci dev->name, lp->scb.status)); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci wait_cmd(dev,lp,100,"close1 timed out"); 14128c2ecf20Sopenharmony_ci lp->scb.command = CUC_ABORT | RX_ABORT; 14138c2ecf20Sopenharmony_ci CA(dev); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci wait_cmd(dev,lp,100,"close2 timed out"); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 14188c2ecf20Sopenharmony_ci DEB(DEB_STRUCT,i596_display_data(dev)); 14198c2ecf20Sopenharmony_ci i596_cleanup_cmd(dev,lp); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 14228c2ecf20Sopenharmony_ci if (MACH_IS_MVME16x) { 14238c2ecf20Sopenharmony_ci volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci /* Disable all ints */ 14268c2ecf20Sopenharmony_ci pcc2[0x28] = 1; 14278c2ecf20Sopenharmony_ci pcc2[0x2a] = 0x40; 14288c2ecf20Sopenharmony_ci pcc2[0x2b] = 0x40; /* Set snooping bits now! */ 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci#endif 14318c2ecf20Sopenharmony_ci#ifdef ENABLE_BVME6000_NET 14328c2ecf20Sopenharmony_ci if (MACH_IS_BVME6000) { 14338c2ecf20Sopenharmony_ci volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci *ethirq = 1; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci#endif 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci#ifdef ENABLE_MVME16x_NET 14408c2ecf20Sopenharmony_ci free_irq(0x56, dev); 14418c2ecf20Sopenharmony_ci#endif 14428c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 14438c2ecf20Sopenharmony_ci remove_rx_bufs(dev); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci return 0; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci/* 14498c2ecf20Sopenharmony_ci * Set or clear the multicast filter for this adaptor. 14508c2ecf20Sopenharmony_ci */ 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_cistatic void set_multicast_list(struct net_device *dev) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci struct i596_private *lp = dev->ml_priv; 14558c2ecf20Sopenharmony_ci int config = 0, cnt; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", 14588c2ecf20Sopenharmony_ci dev->name, netdev_mc_count(dev), 14598c2ecf20Sopenharmony_ci dev->flags & IFF_PROMISC ? "ON" : "OFF", 14608c2ecf20Sopenharmony_ci dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (wait_cfg(dev, &lp->cf_cmd.cmd, 1000, "config change request timed out")) 14638c2ecf20Sopenharmony_ci return; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) { 14668c2ecf20Sopenharmony_ci lp->cf_cmd.i596_config[8] |= 0x01; 14678c2ecf20Sopenharmony_ci config = 1; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) { 14708c2ecf20Sopenharmony_ci lp->cf_cmd.i596_config[8] &= ~0x01; 14718c2ecf20Sopenharmony_ci config = 1; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) { 14748c2ecf20Sopenharmony_ci lp->cf_cmd.i596_config[11] &= ~0x20; 14758c2ecf20Sopenharmony_ci config = 1; 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) { 14788c2ecf20Sopenharmony_ci lp->cf_cmd.i596_config[11] |= 0x20; 14798c2ecf20Sopenharmony_ci config = 1; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci if (config) { 14828c2ecf20Sopenharmony_ci lp->cf_cmd.cmd.command = CmdConfigure; 14838c2ecf20Sopenharmony_ci i596_add_cmd(dev, &lp->cf_cmd.cmd); 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci cnt = netdev_mc_count(dev); 14878c2ecf20Sopenharmony_ci if (cnt > MAX_MC_CNT) 14888c2ecf20Sopenharmony_ci { 14898c2ecf20Sopenharmony_ci cnt = MAX_MC_CNT; 14908c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Only %d multicast addresses supported", 14918c2ecf20Sopenharmony_ci dev->name, cnt); 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (!netdev_mc_empty(dev)) { 14958c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 14968c2ecf20Sopenharmony_ci unsigned char *cp; 14978c2ecf20Sopenharmony_ci struct mc_cmd *cmd; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out")) 15008c2ecf20Sopenharmony_ci return; 15018c2ecf20Sopenharmony_ci cmd = &lp->mc_cmd; 15028c2ecf20Sopenharmony_ci cmd->cmd.command = CmdMulticastList; 15038c2ecf20Sopenharmony_ci cmd->mc_cnt = cnt * ETH_ALEN; 15048c2ecf20Sopenharmony_ci cp = cmd->mc_addrs; 15058c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 15068c2ecf20Sopenharmony_ci if (!cnt--) 15078c2ecf20Sopenharmony_ci break; 15088c2ecf20Sopenharmony_ci memcpy(cp, ha->addr, ETH_ALEN); 15098c2ecf20Sopenharmony_ci if (i596_debug > 1) 15108c2ecf20Sopenharmony_ci DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n", 15118c2ecf20Sopenharmony_ci dev->name, cp)); 15128c2ecf20Sopenharmony_ci cp += ETH_ALEN; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci i596_add_cmd(dev, &cmd->cmd); 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci#ifdef MODULE 15198c2ecf20Sopenharmony_cistatic struct net_device *dev_82596; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_cistatic int debug = -1; 15228c2ecf20Sopenharmony_cimodule_param(debug, int, 0); 15238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "i82596 debug mask"); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ciint __init init_module(void) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci if (debug >= 0) 15288c2ecf20Sopenharmony_ci i596_debug = debug; 15298c2ecf20Sopenharmony_ci dev_82596 = i82596_probe(-1); 15308c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(dev_82596); 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_civoid __exit cleanup_module(void) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci unregister_netdev(dev_82596); 15368c2ecf20Sopenharmony_ci#ifdef __mc68000__ 15378c2ecf20Sopenharmony_ci /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, 15388c2ecf20Sopenharmony_ci * XXX which may be invalid (CONFIG_060_WRITETHROUGH) 15398c2ecf20Sopenharmony_ci */ 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci kernel_set_cachemode((void *)(dev_82596->mem_start), 4096, 15428c2ecf20Sopenharmony_ci IOMAP_FULL_CACHING); 15438c2ecf20Sopenharmony_ci#endif 15448c2ecf20Sopenharmony_ci free_page ((u32)(dev_82596->mem_start)); 15458c2ecf20Sopenharmony_ci free_netdev(dev_82596); 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci#endif /* MODULE */ 1549