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