162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+ 262306a36Sopenharmony_ci/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as 362306a36Sopenharmony_ci munged into HPPA boxen . 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci This driver is based upon 82596.c, original credits are below... 662306a36Sopenharmony_ci but there were too many hoops which HP wants jumped through to 762306a36Sopenharmony_ci keep this code in there in a sane manner. 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci 3 primary sources of the mess -- 1062306a36Sopenharmony_ci 1) hppa needs *lots* of cacheline flushing to keep this kind of 1162306a36Sopenharmony_ci MMIO running. 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci 2) The 82596 needs to see all of its pointers as their physical 1462306a36Sopenharmony_ci address. Thus virt_to_bus/bus_to_virt are *everywhere*. 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci 3) The implementation HP is using seems to be significantly pickier 1762306a36Sopenharmony_ci about when and how the command and RX units are started. some 1862306a36Sopenharmony_ci command ordering was changed. 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci Examination of the mach driver leads one to believe that there 2162306a36Sopenharmony_ci might be a saner way to pull this off... anyone who feels like a 2262306a36Sopenharmony_ci full rewrite can be my guest. 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci Split 02/13/2000 Sam Creasey (sammy@oh.verio.com) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci 02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de) 2762306a36Sopenharmony_ci 03/02/2000 changes for better/correct(?) cache-flushing (deller) 2862306a36Sopenharmony_ci*/ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 82596.c: A generic 82596 ethernet driver for linux. */ 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci Based on Apricot.c 3362306a36Sopenharmony_ci Written 1994 by Mark Evans. 3462306a36Sopenharmony_ci This driver is for the Apricot 82596 bus-master interface 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci Modularised 12/94 Mark Evans 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci Modified to support the 82596 ethernet chips on 680x0 VME boards. 4062306a36Sopenharmony_ci by Richard Hirst <richard@sleepie.demon.co.uk> 4162306a36Sopenharmony_ci Renamed to be 82596.c 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci 980825: Changed to receive directly in to sk_buffs which are 4462306a36Sopenharmony_ci allocated at open() time. Eliminates copy on incoming frames 4562306a36Sopenharmony_ci (small ones are still copied). Shared data now held in a 4662306a36Sopenharmony_ci non-cached page, so we can run on 68060 in copyback mode. 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci TBD: 4962306a36Sopenharmony_ci * look at deferring rx frames rather than discarding (as per tulip) 5062306a36Sopenharmony_ci * handle tx ring full as per tulip 5162306a36Sopenharmony_ci * performance test to tune rx_copybreak 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci Most of my modifications relate to the braindead big-endian 5462306a36Sopenharmony_ci implementation by Intel. When the i596 is operating in 5562306a36Sopenharmony_ci 'big-endian' mode, it thinks a 32 bit value of 0x12345678 5662306a36Sopenharmony_ci should be stored as 0x56781234. This is a real pain, when 5762306a36Sopenharmony_ci you have linked lists which are shared by the 680x0 and the 5862306a36Sopenharmony_ci i596. 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci Driver skeleton 6162306a36Sopenharmony_ci Written 1993 by Donald Becker. 6262306a36Sopenharmony_ci Copyright 1993 United States Government as represented by the Director, 6362306a36Sopenharmony_ci National Security Agency. 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci The author may be reached as becker@scyld.com, or C/O 6662306a36Sopenharmony_ci Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#include <linux/module.h> 7162306a36Sopenharmony_ci#include <linux/kernel.h> 7262306a36Sopenharmony_ci#include <linux/string.h> 7362306a36Sopenharmony_ci#include <linux/errno.h> 7462306a36Sopenharmony_ci#include <linux/ioport.h> 7562306a36Sopenharmony_ci#include <linux/interrupt.h> 7662306a36Sopenharmony_ci#include <linux/delay.h> 7762306a36Sopenharmony_ci#include <linux/netdevice.h> 7862306a36Sopenharmony_ci#include <linux/etherdevice.h> 7962306a36Sopenharmony_ci#include <linux/skbuff.h> 8062306a36Sopenharmony_ci#include <linux/types.h> 8162306a36Sopenharmony_ci#include <linux/bitops.h> 8262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 8362306a36Sopenharmony_ci#include <linux/io.h> 8462306a36Sopenharmony_ci#include <linux/irq.h> 8562306a36Sopenharmony_ci#include <linux/gfp.h> 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* DEBUG flags 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define DEB_INIT 0x0001 9162306a36Sopenharmony_ci#define DEB_PROBE 0x0002 9262306a36Sopenharmony_ci#define DEB_SERIOUS 0x0004 9362306a36Sopenharmony_ci#define DEB_ERRORS 0x0008 9462306a36Sopenharmony_ci#define DEB_MULTI 0x0010 9562306a36Sopenharmony_ci#define DEB_TDR 0x0020 9662306a36Sopenharmony_ci#define DEB_OPEN 0x0040 9762306a36Sopenharmony_ci#define DEB_RESET 0x0080 9862306a36Sopenharmony_ci#define DEB_ADDCMD 0x0100 9962306a36Sopenharmony_ci#define DEB_STATUS 0x0200 10062306a36Sopenharmony_ci#define DEB_STARTTX 0x0400 10162306a36Sopenharmony_ci#define DEB_RXADDR 0x0800 10262306a36Sopenharmony_ci#define DEB_TXADDR 0x1000 10362306a36Sopenharmony_ci#define DEB_RXFRAME 0x2000 10462306a36Sopenharmony_ci#define DEB_INTS 0x4000 10562306a36Sopenharmony_ci#define DEB_STRUCT 0x8000 10662306a36Sopenharmony_ci#define DEB_ANY 0xffff 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define DEB(x, y) if (i596_debug & (x)) { y; } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * The MPU_PORT command allows direct access to the 82596. With PORT access 11462306a36Sopenharmony_ci * the following commands are available (p5-18). The 32-bit port command 11562306a36Sopenharmony_ci * must be word-swapped with the most significant word written first. 11662306a36Sopenharmony_ci * This only applies to VME boards. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci#define PORT_RESET 0x00 /* reset 82596 */ 11962306a36Sopenharmony_ci#define PORT_SELFTEST 0x01 /* selftest */ 12062306a36Sopenharmony_ci#define PORT_ALTSCP 0x02 /* alternate SCB address */ 12162306a36Sopenharmony_ci#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int i596_debug = (DEB_SERIOUS|DEB_PROBE); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* Copy frames shorter than rx_copybreak, otherwise pass on up in 12662306a36Sopenharmony_ci * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha). 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistatic int rx_copybreak = 100; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define PKT_BUF_SZ 1536 13162306a36Sopenharmony_ci#define MAX_MC_CNT 64 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define ISCP_BUSY 0x0001 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define I596_NULL ((u32)0xffffffff) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci#define CMD_EOL 0x8000 /* The last command of the list, stop. */ 13862306a36Sopenharmony_ci#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ 13962306a36Sopenharmony_ci#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */ 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#define CMD_FLEX 0x0008 /* Enable flexible memory model */ 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cienum commands { 14462306a36Sopenharmony_ci CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3, 14562306a36Sopenharmony_ci CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define STAT_C 0x8000 /* Set to 0 after execution */ 14962306a36Sopenharmony_ci#define STAT_B 0x4000 /* Command being executed */ 15062306a36Sopenharmony_ci#define STAT_OK 0x2000 /* Command executed ok */ 15162306a36Sopenharmony_ci#define STAT_A 0x1000 /* Command aborted */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define CUC_START 0x0100 15462306a36Sopenharmony_ci#define CUC_RESUME 0x0200 15562306a36Sopenharmony_ci#define CUC_SUSPEND 0x0300 15662306a36Sopenharmony_ci#define CUC_ABORT 0x0400 15762306a36Sopenharmony_ci#define RX_START 0x0010 15862306a36Sopenharmony_ci#define RX_RESUME 0x0020 15962306a36Sopenharmony_ci#define RX_SUSPEND 0x0030 16062306a36Sopenharmony_ci#define RX_ABORT 0x0040 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define TX_TIMEOUT (HZ/20) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistruct i596_reg { 16662306a36Sopenharmony_ci unsigned short porthi; 16762306a36Sopenharmony_ci unsigned short portlo; 16862306a36Sopenharmony_ci u32 ca; 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#define EOF 0x8000 17262306a36Sopenharmony_ci#define SIZE_MASK 0x3fff 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistruct i596_tbd { 17562306a36Sopenharmony_ci unsigned short size; 17662306a36Sopenharmony_ci unsigned short pad; 17762306a36Sopenharmony_ci u32 next; 17862306a36Sopenharmony_ci u32 data; 17962306a36Sopenharmony_ci u32 cache_pad[5]; /* Total 32 bytes... */ 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* The command structure has two 'next' pointers; v_next is the address of 18362306a36Sopenharmony_ci * the next command as seen by the CPU, b_next is the address of the next 18462306a36Sopenharmony_ci * command as seen by the 82596. The b_next pointer, as used by the 82596 18562306a36Sopenharmony_ci * always references the status field of the next command, rather than the 18662306a36Sopenharmony_ci * v_next field, because the 82596 is unaware of v_next. It may seem more 18762306a36Sopenharmony_ci * logical to put v_next at the end of the structure, but we cannot do that 18862306a36Sopenharmony_ci * because the 82596 expects other fields to be there, depending on command 18962306a36Sopenharmony_ci * type. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistruct i596_cmd { 19362306a36Sopenharmony_ci struct i596_cmd *v_next; /* Address from CPUs viewpoint */ 19462306a36Sopenharmony_ci unsigned short status; 19562306a36Sopenharmony_ci unsigned short command; 19662306a36Sopenharmony_ci u32 b_next; /* Address from i596 viewpoint */ 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistruct tx_cmd { 20062306a36Sopenharmony_ci struct i596_cmd cmd; 20162306a36Sopenharmony_ci u32 tbd; 20262306a36Sopenharmony_ci unsigned short size; 20362306a36Sopenharmony_ci unsigned short pad; 20462306a36Sopenharmony_ci struct sk_buff *skb; /* So we can free it after tx */ 20562306a36Sopenharmony_ci dma_addr_t dma_addr; 20662306a36Sopenharmony_ci#ifdef __LP64__ 20762306a36Sopenharmony_ci u32 cache_pad[6]; /* Total 64 bytes... */ 20862306a36Sopenharmony_ci#else 20962306a36Sopenharmony_ci u32 cache_pad[1]; /* Total 32 bytes... */ 21062306a36Sopenharmony_ci#endif 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistruct tdr_cmd { 21462306a36Sopenharmony_ci struct i596_cmd cmd; 21562306a36Sopenharmony_ci unsigned short status; 21662306a36Sopenharmony_ci unsigned short pad; 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistruct mc_cmd { 22062306a36Sopenharmony_ci struct i596_cmd cmd; 22162306a36Sopenharmony_ci short mc_cnt; 22262306a36Sopenharmony_ci char mc_addrs[MAX_MC_CNT*6]; 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistruct sa_cmd { 22662306a36Sopenharmony_ci struct i596_cmd cmd; 22762306a36Sopenharmony_ci char eth_addr[8]; 22862306a36Sopenharmony_ci}; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistruct cf_cmd { 23162306a36Sopenharmony_ci struct i596_cmd cmd; 23262306a36Sopenharmony_ci char i596_config[16]; 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistruct i596_rfd { 23662306a36Sopenharmony_ci unsigned short stat; 23762306a36Sopenharmony_ci unsigned short cmd; 23862306a36Sopenharmony_ci u32 b_next; /* Address from i596 viewpoint */ 23962306a36Sopenharmony_ci u32 rbd; 24062306a36Sopenharmony_ci unsigned short count; 24162306a36Sopenharmony_ci unsigned short size; 24262306a36Sopenharmony_ci struct i596_rfd *v_next; /* Address from CPUs viewpoint */ 24362306a36Sopenharmony_ci struct i596_rfd *v_prev; 24462306a36Sopenharmony_ci#ifndef __LP64__ 24562306a36Sopenharmony_ci u32 cache_pad[2]; /* Total 32 bytes... */ 24662306a36Sopenharmony_ci#endif 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistruct i596_rbd { 25062306a36Sopenharmony_ci /* hardware data */ 25162306a36Sopenharmony_ci unsigned short count; 25262306a36Sopenharmony_ci unsigned short zero1; 25362306a36Sopenharmony_ci u32 b_next; 25462306a36Sopenharmony_ci u32 b_data; /* Address from i596 viewpoint */ 25562306a36Sopenharmony_ci unsigned short size; 25662306a36Sopenharmony_ci unsigned short zero2; 25762306a36Sopenharmony_ci /* driver data */ 25862306a36Sopenharmony_ci struct sk_buff *skb; 25962306a36Sopenharmony_ci struct i596_rbd *v_next; 26062306a36Sopenharmony_ci u32 b_addr; /* This rbd addr from i596 view */ 26162306a36Sopenharmony_ci unsigned char *v_data; /* Address from CPUs viewpoint */ 26262306a36Sopenharmony_ci /* Total 32 bytes... */ 26362306a36Sopenharmony_ci#ifdef __LP64__ 26462306a36Sopenharmony_ci u32 cache_pad[4]; 26562306a36Sopenharmony_ci#endif 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* These values as chosen so struct i596_dma fits in one page... */ 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci#define TX_RING_SIZE 32 27162306a36Sopenharmony_ci#define RX_RING_SIZE 16 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistruct i596_scb { 27462306a36Sopenharmony_ci unsigned short status; 27562306a36Sopenharmony_ci unsigned short command; 27662306a36Sopenharmony_ci u32 cmd; 27762306a36Sopenharmony_ci u32 rfd; 27862306a36Sopenharmony_ci u32 crc_err; 27962306a36Sopenharmony_ci u32 align_err; 28062306a36Sopenharmony_ci u32 resource_err; 28162306a36Sopenharmony_ci u32 over_err; 28262306a36Sopenharmony_ci u32 rcvdt_err; 28362306a36Sopenharmony_ci u32 short_err; 28462306a36Sopenharmony_ci unsigned short t_on; 28562306a36Sopenharmony_ci unsigned short t_off; 28662306a36Sopenharmony_ci}; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistruct i596_iscp { 28962306a36Sopenharmony_ci u32 stat; 29062306a36Sopenharmony_ci u32 scb; 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistruct i596_scp { 29462306a36Sopenharmony_ci u32 sysbus; 29562306a36Sopenharmony_ci u32 pad; 29662306a36Sopenharmony_ci u32 iscp; 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistruct i596_dma { 30062306a36Sopenharmony_ci struct i596_scp scp __attribute__((aligned(32))); 30162306a36Sopenharmony_ci volatile struct i596_iscp iscp __attribute__((aligned(32))); 30262306a36Sopenharmony_ci volatile struct i596_scb scb __attribute__((aligned(32))); 30362306a36Sopenharmony_ci struct sa_cmd sa_cmd __attribute__((aligned(32))); 30462306a36Sopenharmony_ci struct cf_cmd cf_cmd __attribute__((aligned(32))); 30562306a36Sopenharmony_ci struct tdr_cmd tdr_cmd __attribute__((aligned(32))); 30662306a36Sopenharmony_ci struct mc_cmd mc_cmd __attribute__((aligned(32))); 30762306a36Sopenharmony_ci struct i596_rfd rfds[RX_RING_SIZE] __attribute__((aligned(32))); 30862306a36Sopenharmony_ci struct i596_rbd rbds[RX_RING_SIZE] __attribute__((aligned(32))); 30962306a36Sopenharmony_ci struct tx_cmd tx_cmds[TX_RING_SIZE] __attribute__((aligned(32))); 31062306a36Sopenharmony_ci struct i596_tbd tbds[TX_RING_SIZE] __attribute__((aligned(32))); 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistruct i596_private { 31462306a36Sopenharmony_ci struct i596_dma *dma; 31562306a36Sopenharmony_ci u32 stat; 31662306a36Sopenharmony_ci int last_restart; 31762306a36Sopenharmony_ci struct i596_rfd *rfd_head; 31862306a36Sopenharmony_ci struct i596_rbd *rbd_head; 31962306a36Sopenharmony_ci struct i596_cmd *cmd_tail; 32062306a36Sopenharmony_ci struct i596_cmd *cmd_head; 32162306a36Sopenharmony_ci int cmd_backlog; 32262306a36Sopenharmony_ci u32 last_cmd; 32362306a36Sopenharmony_ci int next_tx_cmd; 32462306a36Sopenharmony_ci int options; 32562306a36Sopenharmony_ci spinlock_t lock; /* serialize access to chip */ 32662306a36Sopenharmony_ci dma_addr_t dma_addr; 32762306a36Sopenharmony_ci void __iomem *mpu_port; 32862306a36Sopenharmony_ci void __iomem *ca; 32962306a36Sopenharmony_ci}; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic const char init_setup[] = 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci 0x8E, /* length, prefetch on */ 33462306a36Sopenharmony_ci 0xC8, /* fifo to 8, monitor off */ 33562306a36Sopenharmony_ci 0x80, /* don't save bad frames */ 33662306a36Sopenharmony_ci 0x2E, /* No source address insertion, 8 byte preamble */ 33762306a36Sopenharmony_ci 0x00, /* priority and backoff defaults */ 33862306a36Sopenharmony_ci 0x60, /* interframe spacing */ 33962306a36Sopenharmony_ci 0x00, /* slot time LSB */ 34062306a36Sopenharmony_ci 0xf2, /* slot time and retries */ 34162306a36Sopenharmony_ci 0x00, /* promiscuous mode */ 34262306a36Sopenharmony_ci 0x00, /* collision detect */ 34362306a36Sopenharmony_ci 0x40, /* minimum frame length */ 34462306a36Sopenharmony_ci 0xff, 34562306a36Sopenharmony_ci 0x00, 34662306a36Sopenharmony_ci 0x7f /* *multi IA */ }; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int i596_open(struct net_device *dev); 34962306a36Sopenharmony_cistatic netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev); 35062306a36Sopenharmony_cistatic irqreturn_t i596_interrupt(int irq, void *dev_id); 35162306a36Sopenharmony_cistatic int i596_close(struct net_device *dev); 35262306a36Sopenharmony_cistatic void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); 35362306a36Sopenharmony_cistatic void i596_tx_timeout (struct net_device *dev, unsigned int txqueue); 35462306a36Sopenharmony_cistatic void print_eth(unsigned char *buf, char *str); 35562306a36Sopenharmony_cistatic void set_multicast_list(struct net_device *dev); 35662306a36Sopenharmony_cistatic inline void ca(struct net_device *dev); 35762306a36Sopenharmony_cistatic void mpu_port(struct net_device *dev, int c, dma_addr_t x); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int rx_ring_size = RX_RING_SIZE; 36062306a36Sopenharmony_cistatic int ticks_limit = 100; 36162306a36Sopenharmony_cistatic int max_cmd_backlog = TX_RING_SIZE-1; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 36462306a36Sopenharmony_cistatic void i596_poll_controller(struct net_device *dev); 36562306a36Sopenharmony_ci#endif 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic inline dma_addr_t virt_to_dma(struct i596_private *lp, volatile void *v) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci return lp->dma_addr + ((unsigned long)v - (unsigned long)lp->dma); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci#ifdef NONCOHERENT_DMA 37362306a36Sopenharmony_cistatic inline void dma_sync_dev(struct net_device *ndev, volatile void *addr, 37462306a36Sopenharmony_ci size_t len) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci dma_sync_single_for_device(ndev->dev.parent, 37762306a36Sopenharmony_ci virt_to_dma(netdev_priv(ndev), addr), len, 37862306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic inline void dma_sync_cpu(struct net_device *ndev, volatile void *addr, 38262306a36Sopenharmony_ci size_t len) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci dma_sync_single_for_cpu(ndev->dev.parent, 38562306a36Sopenharmony_ci virt_to_dma(netdev_priv(ndev), addr), len, 38662306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci#else 38962306a36Sopenharmony_cistatic inline void dma_sync_dev(struct net_device *ndev, volatile void *addr, 39062306a36Sopenharmony_ci size_t len) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_cistatic inline void dma_sync_cpu(struct net_device *ndev, volatile void *addr, 39462306a36Sopenharmony_ci size_t len) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci#endif /* NONCOHERENT_DMA */ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci dma_sync_cpu(dev, &(dma->iscp), sizeof(struct i596_iscp)); 40262306a36Sopenharmony_ci while (--delcnt && dma->iscp.stat) { 40362306a36Sopenharmony_ci udelay(10); 40462306a36Sopenharmony_ci dma_sync_cpu(dev, &(dma->iscp), sizeof(struct i596_iscp)); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci if (!delcnt) { 40762306a36Sopenharmony_ci printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n", 40862306a36Sopenharmony_ci dev->name, str, SWAP16(dma->iscp.stat)); 40962306a36Sopenharmony_ci return -1; 41062306a36Sopenharmony_ci } else 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci dma_sync_cpu(dev, &(dma->scb), sizeof(struct i596_scb)); 41862306a36Sopenharmony_ci while (--delcnt && dma->scb.command) { 41962306a36Sopenharmony_ci udelay(10); 42062306a36Sopenharmony_ci dma_sync_cpu(dev, &(dma->scb), sizeof(struct i596_scb)); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci if (!delcnt) { 42362306a36Sopenharmony_ci printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n", 42462306a36Sopenharmony_ci dev->name, str, 42562306a36Sopenharmony_ci SWAP16(dma->scb.status), 42662306a36Sopenharmony_ci SWAP16(dma->scb.command)); 42762306a36Sopenharmony_ci return -1; 42862306a36Sopenharmony_ci } else 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void i596_display_data(struct net_device *dev) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 43662306a36Sopenharmony_ci struct i596_dma *dma = lp->dma; 43762306a36Sopenharmony_ci struct i596_cmd *cmd; 43862306a36Sopenharmony_ci struct i596_rfd *rfd; 43962306a36Sopenharmony_ci struct i596_rbd *rbd; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n", 44262306a36Sopenharmony_ci &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp)); 44362306a36Sopenharmony_ci printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n", 44462306a36Sopenharmony_ci &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb)); 44562306a36Sopenharmony_ci printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x," 44662306a36Sopenharmony_ci " .cmd = %08x, .rfd = %08x\n", 44762306a36Sopenharmony_ci &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command), 44862306a36Sopenharmony_ci SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd)); 44962306a36Sopenharmony_ci printk(KERN_DEBUG " errors: crc %x, align %x, resource %x," 45062306a36Sopenharmony_ci " over %x, rcvdt %x, short %x\n", 45162306a36Sopenharmony_ci SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err), 45262306a36Sopenharmony_ci SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err), 45362306a36Sopenharmony_ci SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err)); 45462306a36Sopenharmony_ci cmd = lp->cmd_head; 45562306a36Sopenharmony_ci while (cmd != NULL) { 45662306a36Sopenharmony_ci printk(KERN_DEBUG 45762306a36Sopenharmony_ci "cmd at %p, .status = %04x, .command = %04x," 45862306a36Sopenharmony_ci " .b_next = %08x\n", 45962306a36Sopenharmony_ci cmd, SWAP16(cmd->status), SWAP16(cmd->command), 46062306a36Sopenharmony_ci SWAP32(cmd->b_next)); 46162306a36Sopenharmony_ci cmd = cmd->v_next; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci rfd = lp->rfd_head; 46462306a36Sopenharmony_ci printk(KERN_DEBUG "rfd_head = %p\n", rfd); 46562306a36Sopenharmony_ci do { 46662306a36Sopenharmony_ci printk(KERN_DEBUG 46762306a36Sopenharmony_ci " %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x," 46862306a36Sopenharmony_ci " count %04x\n", 46962306a36Sopenharmony_ci rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd), 47062306a36Sopenharmony_ci SWAP32(rfd->b_next), SWAP32(rfd->rbd), 47162306a36Sopenharmony_ci SWAP16(rfd->count)); 47262306a36Sopenharmony_ci rfd = rfd->v_next; 47362306a36Sopenharmony_ci } while (rfd != lp->rfd_head); 47462306a36Sopenharmony_ci rbd = lp->rbd_head; 47562306a36Sopenharmony_ci printk(KERN_DEBUG "rbd_head = %p\n", rbd); 47662306a36Sopenharmony_ci do { 47762306a36Sopenharmony_ci printk(KERN_DEBUG 47862306a36Sopenharmony_ci " %p .count %04x, b_next %08x, b_data %08x," 47962306a36Sopenharmony_ci " size %04x\n", 48062306a36Sopenharmony_ci rbd, SWAP16(rbd->count), SWAP32(rbd->b_next), 48162306a36Sopenharmony_ci SWAP32(rbd->b_data), SWAP16(rbd->size)); 48262306a36Sopenharmony_ci rbd = rbd->v_next; 48362306a36Sopenharmony_ci } while (rbd != lp->rbd_head); 48462306a36Sopenharmony_ci dma_sync_cpu(dev, dma, sizeof(struct i596_dma)); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic inline int init_rx_bufs(struct net_device *dev) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 49062306a36Sopenharmony_ci struct i596_dma *dma = lp->dma; 49162306a36Sopenharmony_ci int i; 49262306a36Sopenharmony_ci struct i596_rfd *rfd; 49362306a36Sopenharmony_ci struct i596_rbd *rbd; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* First build the Receive Buffer Descriptor List */ 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) { 49862306a36Sopenharmony_ci dma_addr_t dma_addr; 49962306a36Sopenharmony_ci struct sk_buff *skb; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ); 50262306a36Sopenharmony_ci if (skb == NULL) 50362306a36Sopenharmony_ci return -1; 50462306a36Sopenharmony_ci dma_addr = dma_map_single(dev->dev.parent, skb->data, 50562306a36Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 50662306a36Sopenharmony_ci rbd->v_next = rbd+1; 50762306a36Sopenharmony_ci rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1)); 50862306a36Sopenharmony_ci rbd->b_addr = SWAP32(virt_to_dma(lp, rbd)); 50962306a36Sopenharmony_ci rbd->skb = skb; 51062306a36Sopenharmony_ci rbd->v_data = skb->data; 51162306a36Sopenharmony_ci rbd->b_data = SWAP32(dma_addr); 51262306a36Sopenharmony_ci rbd->size = SWAP16(PKT_BUF_SZ); 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci lp->rbd_head = dma->rbds; 51562306a36Sopenharmony_ci rbd = dma->rbds + rx_ring_size - 1; 51662306a36Sopenharmony_ci rbd->v_next = dma->rbds; 51762306a36Sopenharmony_ci rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds)); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* Now build the Receive Frame Descriptor List */ 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) { 52262306a36Sopenharmony_ci rfd->rbd = I596_NULL; 52362306a36Sopenharmony_ci rfd->v_next = rfd+1; 52462306a36Sopenharmony_ci rfd->v_prev = rfd-1; 52562306a36Sopenharmony_ci rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1)); 52662306a36Sopenharmony_ci rfd->cmd = SWAP16(CMD_FLEX); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci lp->rfd_head = dma->rfds; 52962306a36Sopenharmony_ci dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds)); 53062306a36Sopenharmony_ci rfd = dma->rfds; 53162306a36Sopenharmony_ci rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head)); 53262306a36Sopenharmony_ci rfd->v_prev = dma->rfds + rx_ring_size - 1; 53362306a36Sopenharmony_ci rfd = dma->rfds + rx_ring_size - 1; 53462306a36Sopenharmony_ci rfd->v_next = dma->rfds; 53562306a36Sopenharmony_ci rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds)); 53662306a36Sopenharmony_ci rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci dma_sync_dev(dev, dma, sizeof(struct i596_dma)); 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic inline void remove_rx_bufs(struct net_device *dev) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 54562306a36Sopenharmony_ci struct i596_rbd *rbd; 54662306a36Sopenharmony_ci int i; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) { 54962306a36Sopenharmony_ci if (rbd->skb == NULL) 55062306a36Sopenharmony_ci break; 55162306a36Sopenharmony_ci dma_unmap_single(dev->dev.parent, 55262306a36Sopenharmony_ci (dma_addr_t)SWAP32(rbd->b_data), 55362306a36Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 55462306a36Sopenharmony_ci dev_kfree_skb(rbd->skb); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic void rebuild_rx_bufs(struct net_device *dev) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 56262306a36Sopenharmony_ci struct i596_dma *dma = lp->dma; 56362306a36Sopenharmony_ci int i; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Ensure rx frame/buffer descriptors are tidy */ 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci for (i = 0; i < rx_ring_size; i++) { 56862306a36Sopenharmony_ci dma->rfds[i].rbd = I596_NULL; 56962306a36Sopenharmony_ci dma->rfds[i].cmd = SWAP16(CMD_FLEX); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX); 57262306a36Sopenharmony_ci lp->rfd_head = dma->rfds; 57362306a36Sopenharmony_ci dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds)); 57462306a36Sopenharmony_ci lp->rbd_head = dma->rbds; 57562306a36Sopenharmony_ci dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds)); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci dma_sync_dev(dev, dma, sizeof(struct i596_dma)); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic int init_i596_mem(struct net_device *dev) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 58462306a36Sopenharmony_ci struct i596_dma *dma = lp->dma; 58562306a36Sopenharmony_ci unsigned long flags; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci mpu_port(dev, PORT_RESET, 0); 58862306a36Sopenharmony_ci udelay(100); /* Wait 100us - seems to help */ 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* change the scp address */ 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci lp->last_cmd = jiffies; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci dma->scp.sysbus = SYSBUS; 59562306a36Sopenharmony_ci dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp))); 59662306a36Sopenharmony_ci dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb))); 59762306a36Sopenharmony_ci dma->iscp.stat = SWAP32(ISCP_BUSY); 59862306a36Sopenharmony_ci lp->cmd_backlog = 0; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci lp->cmd_head = NULL; 60162306a36Sopenharmony_ci dma->scb.cmd = I596_NULL; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name)); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->scp), sizeof(struct i596_scp)); 60662306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->iscp), sizeof(struct i596_iscp)); 60762306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb)); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp)); 61062306a36Sopenharmony_ci ca(dev); 61162306a36Sopenharmony_ci if (wait_istat(dev, dma, 1000, "initialization timed out")) 61262306a36Sopenharmony_ci goto failed; 61362306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_DEBUG 61462306a36Sopenharmony_ci "%s: i82596 initialization successful\n", 61562306a36Sopenharmony_ci dev->name)); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) { 61862306a36Sopenharmony_ci printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq); 61962306a36Sopenharmony_ci goto failed; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Ensure rx frame/buffer descriptors are tidy */ 62362306a36Sopenharmony_ci rebuild_rx_bufs(dev); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci dma->scb.command = 0; 62662306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb)); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_DEBUG 62962306a36Sopenharmony_ci "%s: queuing CmdConfigure\n", dev->name)); 63062306a36Sopenharmony_ci memcpy(dma->cf_cmd.i596_config, init_setup, 14); 63162306a36Sopenharmony_ci dma->cf_cmd.cmd.command = SWAP16(CmdConfigure); 63262306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->cf_cmd), sizeof(struct cf_cmd)); 63362306a36Sopenharmony_ci i596_add_cmd(dev, &dma->cf_cmd.cmd); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name)); 63662306a36Sopenharmony_ci memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, ETH_ALEN); 63762306a36Sopenharmony_ci dma->sa_cmd.cmd.command = SWAP16(CmdSASetup); 63862306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->sa_cmd), sizeof(struct sa_cmd)); 63962306a36Sopenharmony_ci i596_add_cmd(dev, &dma->sa_cmd.cmd); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name)); 64262306a36Sopenharmony_ci dma->tdr_cmd.cmd.command = SWAP16(CmdTDR); 64362306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd)); 64462306a36Sopenharmony_ci i596_add_cmd(dev, &dma->tdr_cmd.cmd); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci spin_lock_irqsave (&lp->lock, flags); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) { 64962306a36Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 65062306a36Sopenharmony_ci goto failed_free_irq; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name)); 65362306a36Sopenharmony_ci dma->scb.command = SWAP16(RX_START); 65462306a36Sopenharmony_ci dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds)); 65562306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb)); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci ca(dev); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 66062306a36Sopenharmony_ci if (wait_cmd(dev, dma, 1000, "RX_START not processed")) 66162306a36Sopenharmony_ci goto failed_free_irq; 66262306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_DEBUG 66362306a36Sopenharmony_ci "%s: Receive unit started OK\n", dev->name)); 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cifailed_free_irq: 66762306a36Sopenharmony_ci free_irq(dev->irq, dev); 66862306a36Sopenharmony_cifailed: 66962306a36Sopenharmony_ci printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name); 67062306a36Sopenharmony_ci mpu_port(dev, PORT_RESET, 0); 67162306a36Sopenharmony_ci return -1; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic inline int i596_rx(struct net_device *dev) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 67862306a36Sopenharmony_ci struct i596_rfd *rfd; 67962306a36Sopenharmony_ci struct i596_rbd *rbd; 68062306a36Sopenharmony_ci int frames = 0; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci DEB(DEB_RXFRAME, printk(KERN_DEBUG 68362306a36Sopenharmony_ci "i596_rx(), rfd_head %p, rbd_head %p\n", 68462306a36Sopenharmony_ci lp->rfd_head, lp->rbd_head)); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci rfd = lp->rfd_head; /* Ref next frame to check */ 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci dma_sync_cpu(dev, rfd, sizeof(struct i596_rfd)); 69062306a36Sopenharmony_ci while (rfd->stat & SWAP16(STAT_C)) { /* Loop while complete frames */ 69162306a36Sopenharmony_ci if (rfd->rbd == I596_NULL) 69262306a36Sopenharmony_ci rbd = NULL; 69362306a36Sopenharmony_ci else if (rfd->rbd == lp->rbd_head->b_addr) { 69462306a36Sopenharmony_ci rbd = lp->rbd_head; 69562306a36Sopenharmony_ci dma_sync_cpu(dev, rbd, sizeof(struct i596_rbd)); 69662306a36Sopenharmony_ci } else { 69762306a36Sopenharmony_ci printk(KERN_ERR "%s: rbd chain broken!\n", dev->name); 69862306a36Sopenharmony_ci /* XXX Now what? */ 69962306a36Sopenharmony_ci rbd = NULL; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci DEB(DEB_RXFRAME, printk(KERN_DEBUG 70262306a36Sopenharmony_ci " rfd %p, rfd.rbd %08x, rfd.stat %04x\n", 70362306a36Sopenharmony_ci rfd, rfd->rbd, rfd->stat)); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) { 70662306a36Sopenharmony_ci /* a good frame */ 70762306a36Sopenharmony_ci int pkt_len = SWAP16(rbd->count) & 0x3fff; 70862306a36Sopenharmony_ci struct sk_buff *skb = rbd->skb; 70962306a36Sopenharmony_ci int rx_in_place = 0; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci DEB(DEB_RXADDR, print_eth(rbd->v_data, "received")); 71262306a36Sopenharmony_ci frames++; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* Check if the packet is long enough to just accept 71562306a36Sopenharmony_ci * without copying to a properly sized skbuff. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (pkt_len > rx_copybreak) { 71962306a36Sopenharmony_ci struct sk_buff *newskb; 72062306a36Sopenharmony_ci dma_addr_t dma_addr; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci dma_unmap_single(dev->dev.parent, 72362306a36Sopenharmony_ci (dma_addr_t)SWAP32(rbd->b_data), 72462306a36Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 72562306a36Sopenharmony_ci /* Get fresh skbuff to replace filled one. */ 72662306a36Sopenharmony_ci newskb = netdev_alloc_skb_ip_align(dev, 72762306a36Sopenharmony_ci PKT_BUF_SZ); 72862306a36Sopenharmony_ci if (newskb == NULL) { 72962306a36Sopenharmony_ci skb = NULL; /* drop pkt */ 73062306a36Sopenharmony_ci goto memory_squeeze; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* Pass up the skb already on the Rx ring. */ 73462306a36Sopenharmony_ci skb_put(skb, pkt_len); 73562306a36Sopenharmony_ci rx_in_place = 1; 73662306a36Sopenharmony_ci rbd->skb = newskb; 73762306a36Sopenharmony_ci dma_addr = dma_map_single(dev->dev.parent, 73862306a36Sopenharmony_ci newskb->data, 73962306a36Sopenharmony_ci PKT_BUF_SZ, 74062306a36Sopenharmony_ci DMA_FROM_DEVICE); 74162306a36Sopenharmony_ci rbd->v_data = newskb->data; 74262306a36Sopenharmony_ci rbd->b_data = SWAP32(dma_addr); 74362306a36Sopenharmony_ci dma_sync_dev(dev, rbd, sizeof(struct i596_rbd)); 74462306a36Sopenharmony_ci } else { 74562306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(dev, pkt_len); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_cimemory_squeeze: 74862306a36Sopenharmony_ci if (skb == NULL) { 74962306a36Sopenharmony_ci /* XXX tulip.c can defer packets here!! */ 75062306a36Sopenharmony_ci dev->stats.rx_dropped++; 75162306a36Sopenharmony_ci } else { 75262306a36Sopenharmony_ci if (!rx_in_place) { 75362306a36Sopenharmony_ci /* 16 byte align the data fields */ 75462306a36Sopenharmony_ci dma_sync_single_for_cpu(dev->dev.parent, 75562306a36Sopenharmony_ci (dma_addr_t)SWAP32(rbd->b_data), 75662306a36Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 75762306a36Sopenharmony_ci skb_put_data(skb, rbd->v_data, 75862306a36Sopenharmony_ci pkt_len); 75962306a36Sopenharmony_ci dma_sync_single_for_device(dev->dev.parent, 76062306a36Sopenharmony_ci (dma_addr_t)SWAP32(rbd->b_data), 76162306a36Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci skb->len = pkt_len; 76462306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 76562306a36Sopenharmony_ci netif_rx(skb); 76662306a36Sopenharmony_ci dev->stats.rx_packets++; 76762306a36Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci } else { 77062306a36Sopenharmony_ci DEB(DEB_ERRORS, printk(KERN_DEBUG 77162306a36Sopenharmony_ci "%s: Error, rfd.stat = 0x%04x\n", 77262306a36Sopenharmony_ci dev->name, rfd->stat)); 77362306a36Sopenharmony_ci dev->stats.rx_errors++; 77462306a36Sopenharmony_ci if (rfd->stat & SWAP16(0x0100)) 77562306a36Sopenharmony_ci dev->stats.collisions++; 77662306a36Sopenharmony_ci if (rfd->stat & SWAP16(0x8000)) 77762306a36Sopenharmony_ci dev->stats.rx_length_errors++; 77862306a36Sopenharmony_ci if (rfd->stat & SWAP16(0x0001)) 77962306a36Sopenharmony_ci dev->stats.rx_over_errors++; 78062306a36Sopenharmony_ci if (rfd->stat & SWAP16(0x0002)) 78162306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 78262306a36Sopenharmony_ci if (rfd->stat & SWAP16(0x0004)) 78362306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 78462306a36Sopenharmony_ci if (rfd->stat & SWAP16(0x0008)) 78562306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 78662306a36Sopenharmony_ci if (rfd->stat & SWAP16(0x0010)) 78762306a36Sopenharmony_ci dev->stats.rx_length_errors++; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* Clear the buffer descriptor count and EOF + F flags */ 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (rbd != NULL && (rbd->count & SWAP16(0x4000))) { 79362306a36Sopenharmony_ci rbd->count = 0; 79462306a36Sopenharmony_ci lp->rbd_head = rbd->v_next; 79562306a36Sopenharmony_ci dma_sync_dev(dev, rbd, sizeof(struct i596_rbd)); 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* Tidy the frame descriptor, marking it as end of list */ 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci rfd->rbd = I596_NULL; 80162306a36Sopenharmony_ci rfd->stat = 0; 80262306a36Sopenharmony_ci rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX); 80362306a36Sopenharmony_ci rfd->count = 0; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* Update record of next frame descriptor to process */ 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci lp->dma->scb.rfd = rfd->b_next; 80862306a36Sopenharmony_ci lp->rfd_head = rfd->v_next; 80962306a36Sopenharmony_ci dma_sync_dev(dev, rfd, sizeof(struct i596_rfd)); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* Remove end-of-list from old end descriptor */ 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci rfd->v_prev->cmd = SWAP16(CMD_FLEX); 81462306a36Sopenharmony_ci dma_sync_dev(dev, rfd->v_prev, sizeof(struct i596_rfd)); 81562306a36Sopenharmony_ci rfd = lp->rfd_head; 81662306a36Sopenharmony_ci dma_sync_cpu(dev, rfd, sizeof(struct i596_rfd)); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames)); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return 0; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct i596_cmd *ptr; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci while (lp->cmd_head != NULL) { 83062306a36Sopenharmony_ci ptr = lp->cmd_head; 83162306a36Sopenharmony_ci lp->cmd_head = ptr->v_next; 83262306a36Sopenharmony_ci lp->cmd_backlog--; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci switch (SWAP16(ptr->command) & 0x7) { 83562306a36Sopenharmony_ci case CmdTx: 83662306a36Sopenharmony_ci { 83762306a36Sopenharmony_ci struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; 83862306a36Sopenharmony_ci struct sk_buff *skb = tx_cmd->skb; 83962306a36Sopenharmony_ci dma_unmap_single(dev->dev.parent, 84062306a36Sopenharmony_ci tx_cmd->dma_addr, 84162306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci dev_kfree_skb(skb); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci dev->stats.tx_errors++; 84662306a36Sopenharmony_ci dev->stats.tx_aborted_errors++; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci ptr->v_next = NULL; 84962306a36Sopenharmony_ci ptr->b_next = I596_NULL; 85062306a36Sopenharmony_ci tx_cmd->cmd.command = 0; /* Mark as free */ 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci default: 85462306a36Sopenharmony_ci ptr->v_next = NULL; 85562306a36Sopenharmony_ci ptr->b_next = I596_NULL; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci dma_sync_dev(dev, ptr, sizeof(struct i596_cmd)); 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out"); 86162306a36Sopenharmony_ci lp->dma->scb.cmd = I596_NULL; 86262306a36Sopenharmony_ci dma_sync_dev(dev, &(lp->dma->scb), sizeof(struct i596_scb)); 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic inline void i596_reset(struct net_device *dev, struct i596_private *lp) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci unsigned long flags; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n")); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci spin_lock_irqsave (&lp->lock, flags); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci wait_cmd(dev, lp->dma, 100, "i596_reset timed out"); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci netif_stop_queue(dev); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* FIXME: this command might cause an lpmc */ 87962306a36Sopenharmony_ci lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT); 88062306a36Sopenharmony_ci dma_sync_dev(dev, &(lp->dma->scb), sizeof(struct i596_scb)); 88162306a36Sopenharmony_ci ca(dev); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* wait for shutdown */ 88462306a36Sopenharmony_ci wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out"); 88562306a36Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci i596_cleanup_cmd(dev, lp); 88862306a36Sopenharmony_ci i596_rx(dev); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci netif_start_queue(dev); 89162306a36Sopenharmony_ci init_i596_mem(dev); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 89862306a36Sopenharmony_ci struct i596_dma *dma = lp->dma; 89962306a36Sopenharmony_ci unsigned long flags; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n", 90262306a36Sopenharmony_ci lp->cmd_head)); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci cmd->status = 0; 90562306a36Sopenharmony_ci cmd->command |= SWAP16(CMD_EOL | CMD_INTR); 90662306a36Sopenharmony_ci cmd->v_next = NULL; 90762306a36Sopenharmony_ci cmd->b_next = I596_NULL; 90862306a36Sopenharmony_ci dma_sync_dev(dev, cmd, sizeof(struct i596_cmd)); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci spin_lock_irqsave (&lp->lock, flags); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (lp->cmd_head != NULL) { 91362306a36Sopenharmony_ci lp->cmd_tail->v_next = cmd; 91462306a36Sopenharmony_ci lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status)); 91562306a36Sopenharmony_ci dma_sync_dev(dev, lp->cmd_tail, sizeof(struct i596_cmd)); 91662306a36Sopenharmony_ci } else { 91762306a36Sopenharmony_ci lp->cmd_head = cmd; 91862306a36Sopenharmony_ci wait_cmd(dev, dma, 100, "i596_add_cmd timed out"); 91962306a36Sopenharmony_ci dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status)); 92062306a36Sopenharmony_ci dma->scb.command = SWAP16(CUC_START); 92162306a36Sopenharmony_ci dma_sync_dev(dev, &(dma->scb), sizeof(struct i596_scb)); 92262306a36Sopenharmony_ci ca(dev); 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci lp->cmd_tail = cmd; 92562306a36Sopenharmony_ci lp->cmd_backlog++; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci spin_unlock_irqrestore (&lp->lock, flags); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (lp->cmd_backlog > max_cmd_backlog) { 93062306a36Sopenharmony_ci unsigned long tickssofar = jiffies - lp->last_cmd; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (tickssofar < ticks_limit) 93362306a36Sopenharmony_ci return; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci printk(KERN_ERR 93662306a36Sopenharmony_ci "%s: command unit timed out, status resetting.\n", 93762306a36Sopenharmony_ci dev->name); 93862306a36Sopenharmony_ci#if 1 93962306a36Sopenharmony_ci i596_reset(dev, lp); 94062306a36Sopenharmony_ci#endif 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic int i596_open(struct net_device *dev) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci DEB(DEB_OPEN, printk(KERN_DEBUG 94762306a36Sopenharmony_ci "%s: i596_open() irq %d.\n", dev->name, dev->irq)); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (init_rx_bufs(dev)) { 95062306a36Sopenharmony_ci printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name); 95162306a36Sopenharmony_ci return -EAGAIN; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci if (init_i596_mem(dev)) { 95462306a36Sopenharmony_ci printk(KERN_ERR "%s: Failed to init memory\n", dev->name); 95562306a36Sopenharmony_ci goto out_remove_rx_bufs; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci netif_start_queue(dev); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci return 0; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ciout_remove_rx_bufs: 96262306a36Sopenharmony_ci remove_rx_bufs(dev); 96362306a36Sopenharmony_ci return -EAGAIN; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic void i596_tx_timeout (struct net_device *dev, unsigned int txqueue) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Transmitter timeout, serious problems. */ 97162306a36Sopenharmony_ci DEB(DEB_ERRORS, printk(KERN_DEBUG 97262306a36Sopenharmony_ci "%s: transmit timed out, status resetting.\n", 97362306a36Sopenharmony_ci dev->name)); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci dev->stats.tx_errors++; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* Try to restart the adaptor */ 97862306a36Sopenharmony_ci if (lp->last_restart == dev->stats.tx_packets) { 97962306a36Sopenharmony_ci DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n")); 98062306a36Sopenharmony_ci /* Shutdown and restart */ 98162306a36Sopenharmony_ci i596_reset (dev, lp); 98262306a36Sopenharmony_ci } else { 98362306a36Sopenharmony_ci /* Issue a channel attention signal */ 98462306a36Sopenharmony_ci DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n")); 98562306a36Sopenharmony_ci lp->dma->scb.command = SWAP16(CUC_START | RX_START); 98662306a36Sopenharmony_ci dma_sync_dev(dev, &(lp->dma->scb), sizeof(struct i596_scb)); 98762306a36Sopenharmony_ci ca (dev); 98862306a36Sopenharmony_ci lp->last_restart = dev->stats.tx_packets; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 99262306a36Sopenharmony_ci netif_wake_queue (dev); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 99962306a36Sopenharmony_ci struct tx_cmd *tx_cmd; 100062306a36Sopenharmony_ci struct i596_tbd *tbd; 100162306a36Sopenharmony_ci short length = skb->len; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci DEB(DEB_STARTTX, printk(KERN_DEBUG 100462306a36Sopenharmony_ci "%s: i596_start_xmit(%x,%p) called\n", 100562306a36Sopenharmony_ci dev->name, skb->len, skb->data)); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (length < ETH_ZLEN) { 100862306a36Sopenharmony_ci if (skb_padto(skb, ETH_ZLEN)) 100962306a36Sopenharmony_ci return NETDEV_TX_OK; 101062306a36Sopenharmony_ci length = ETH_ZLEN; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci netif_stop_queue(dev); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd; 101662306a36Sopenharmony_ci tbd = lp->dma->tbds + lp->next_tx_cmd; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (tx_cmd->cmd.command) { 101962306a36Sopenharmony_ci DEB(DEB_ERRORS, printk(KERN_DEBUG 102062306a36Sopenharmony_ci "%s: xmit ring full, dropping packet.\n", 102162306a36Sopenharmony_ci dev->name)); 102262306a36Sopenharmony_ci dev->stats.tx_dropped++; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 102562306a36Sopenharmony_ci } else { 102662306a36Sopenharmony_ci if (++lp->next_tx_cmd == TX_RING_SIZE) 102762306a36Sopenharmony_ci lp->next_tx_cmd = 0; 102862306a36Sopenharmony_ci tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd)); 102962306a36Sopenharmony_ci tbd->next = I596_NULL; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx); 103262306a36Sopenharmony_ci tx_cmd->skb = skb; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci tx_cmd->pad = 0; 103562306a36Sopenharmony_ci tx_cmd->size = 0; 103662306a36Sopenharmony_ci tbd->pad = 0; 103762306a36Sopenharmony_ci tbd->size = SWAP16(EOF | length); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data, 104062306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 104162306a36Sopenharmony_ci tbd->data = SWAP32(tx_cmd->dma_addr); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued")); 104462306a36Sopenharmony_ci dma_sync_dev(dev, tx_cmd, sizeof(struct tx_cmd)); 104562306a36Sopenharmony_ci dma_sync_dev(dev, tbd, sizeof(struct i596_tbd)); 104662306a36Sopenharmony_ci i596_add_cmd(dev, &tx_cmd->cmd); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci dev->stats.tx_packets++; 104962306a36Sopenharmony_ci dev->stats.tx_bytes += length; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci netif_start_queue(dev); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return NETDEV_TX_OK; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic void print_eth(unsigned char *add, char *str) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", 106062306a36Sopenharmony_ci add, add + 6, add, add[12], add[13], str); 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_cistatic const struct net_device_ops i596_netdev_ops = { 106362306a36Sopenharmony_ci .ndo_open = i596_open, 106462306a36Sopenharmony_ci .ndo_stop = i596_close, 106562306a36Sopenharmony_ci .ndo_start_xmit = i596_start_xmit, 106662306a36Sopenharmony_ci .ndo_set_rx_mode = set_multicast_list, 106762306a36Sopenharmony_ci .ndo_tx_timeout = i596_tx_timeout, 106862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 106962306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 107062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 107162306a36Sopenharmony_ci .ndo_poll_controller = i596_poll_controller, 107262306a36Sopenharmony_ci#endif 107362306a36Sopenharmony_ci}; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic int i82596_probe(struct net_device *dev) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 107862306a36Sopenharmony_ci int ret; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* This lot is ensure things have been cache line aligned. */ 108162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct i596_rfd) != 32); 108262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct i596_rbd) & 31); 108362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct tx_cmd) & 31); 108462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct i596_tbd) != 32); 108562306a36Sopenharmony_ci#ifndef __LP64__ 108662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct i596_dma) > 4096); 108762306a36Sopenharmony_ci#endif 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (!dev->base_addr || !dev->irq) 109062306a36Sopenharmony_ci return -ENODEV; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci dev->netdev_ops = &i596_netdev_ops; 109362306a36Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci memset(lp->dma, 0, sizeof(struct i596_dma)); 109662306a36Sopenharmony_ci lp->dma->scb.command = 0; 109762306a36Sopenharmony_ci lp->dma->scb.cmd = I596_NULL; 109862306a36Sopenharmony_ci lp->dma->scb.rfd = I596_NULL; 109962306a36Sopenharmony_ci spin_lock_init(&lp->lock); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci dma_sync_dev(dev, lp->dma, sizeof(struct i596_dma)); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci ret = register_netdev(dev); 110462306a36Sopenharmony_ci if (ret) 110562306a36Sopenharmony_ci return ret; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n", 110862306a36Sopenharmony_ci dev->name, dev->base_addr, dev->dev_addr, 110962306a36Sopenharmony_ci dev->irq)); 111062306a36Sopenharmony_ci DEB(DEB_INIT, printk(KERN_INFO 111162306a36Sopenharmony_ci "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n", 111262306a36Sopenharmony_ci dev->name, lp->dma, (int)sizeof(struct i596_dma), 111362306a36Sopenharmony_ci &lp->dma->scb)); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 111962306a36Sopenharmony_cistatic void i596_poll_controller(struct net_device *dev) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci disable_irq(dev->irq); 112262306a36Sopenharmony_ci i596_interrupt(dev->irq, dev); 112362306a36Sopenharmony_ci enable_irq(dev->irq); 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci#endif 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic irqreturn_t i596_interrupt(int irq, void *dev_id) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci struct net_device *dev = dev_id; 113062306a36Sopenharmony_ci struct i596_private *lp; 113162306a36Sopenharmony_ci struct i596_dma *dma; 113262306a36Sopenharmony_ci unsigned short status, ack_cmd = 0; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci lp = netdev_priv(dev); 113562306a36Sopenharmony_ci dma = lp->dma; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci spin_lock (&lp->lock); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci wait_cmd(dev, dma, 100, "i596 interrupt, timeout"); 114062306a36Sopenharmony_ci status = SWAP16(dma->scb.status); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci DEB(DEB_INTS, printk(KERN_DEBUG 114362306a36Sopenharmony_ci "%s: i596 interrupt, IRQ %d, status %4.4x.\n", 114462306a36Sopenharmony_ci dev->name, dev->irq, status)); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci ack_cmd = status & 0xf000; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (!ack_cmd) { 114962306a36Sopenharmony_ci DEB(DEB_ERRORS, printk(KERN_DEBUG 115062306a36Sopenharmony_ci "%s: interrupt with no events\n", 115162306a36Sopenharmony_ci dev->name)); 115262306a36Sopenharmony_ci spin_unlock (&lp->lock); 115362306a36Sopenharmony_ci return IRQ_NONE; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if ((status & 0x8000) || (status & 0x2000)) { 115762306a36Sopenharmony_ci struct i596_cmd *ptr; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if ((status & 0x8000)) 116062306a36Sopenharmony_ci DEB(DEB_INTS, 116162306a36Sopenharmony_ci printk(KERN_DEBUG 116262306a36Sopenharmony_ci "%s: i596 interrupt completed command.\n", 116362306a36Sopenharmony_ci dev->name)); 116462306a36Sopenharmony_ci if ((status & 0x2000)) 116562306a36Sopenharmony_ci DEB(DEB_INTS, 116662306a36Sopenharmony_ci printk(KERN_DEBUG 116762306a36Sopenharmony_ci "%s: i596 interrupt command unit inactive %x.\n", 116862306a36Sopenharmony_ci dev->name, status & 0x0700)); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci while (lp->cmd_head != NULL) { 117162306a36Sopenharmony_ci dma_sync_cpu(dev, lp->cmd_head, sizeof(struct i596_cmd)); 117262306a36Sopenharmony_ci if (!(lp->cmd_head->status & SWAP16(STAT_C))) 117362306a36Sopenharmony_ci break; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci ptr = lp->cmd_head; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci DEB(DEB_STATUS, 117862306a36Sopenharmony_ci printk(KERN_DEBUG 117962306a36Sopenharmony_ci "cmd_head->status = %04x, ->command = %04x\n", 118062306a36Sopenharmony_ci SWAP16(lp->cmd_head->status), 118162306a36Sopenharmony_ci SWAP16(lp->cmd_head->command))); 118262306a36Sopenharmony_ci lp->cmd_head = ptr->v_next; 118362306a36Sopenharmony_ci lp->cmd_backlog--; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci switch (SWAP16(ptr->command) & 0x7) { 118662306a36Sopenharmony_ci case CmdTx: 118762306a36Sopenharmony_ci { 118862306a36Sopenharmony_ci struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; 118962306a36Sopenharmony_ci struct sk_buff *skb = tx_cmd->skb; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (ptr->status & SWAP16(STAT_OK)) { 119262306a36Sopenharmony_ci DEB(DEB_TXADDR, 119362306a36Sopenharmony_ci print_eth(skb->data, "tx-done")); 119462306a36Sopenharmony_ci } else { 119562306a36Sopenharmony_ci dev->stats.tx_errors++; 119662306a36Sopenharmony_ci if (ptr->status & SWAP16(0x0020)) 119762306a36Sopenharmony_ci dev->stats.collisions++; 119862306a36Sopenharmony_ci if (!(ptr->status & SWAP16(0x0040))) 119962306a36Sopenharmony_ci dev->stats.tx_heartbeat_errors++; 120062306a36Sopenharmony_ci if (ptr->status & SWAP16(0x0400)) 120162306a36Sopenharmony_ci dev->stats.tx_carrier_errors++; 120262306a36Sopenharmony_ci if (ptr->status & SWAP16(0x0800)) 120362306a36Sopenharmony_ci dev->stats.collisions++; 120462306a36Sopenharmony_ci if (ptr->status & SWAP16(0x1000)) 120562306a36Sopenharmony_ci dev->stats.tx_aborted_errors++; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci dma_unmap_single(dev->dev.parent, 120862306a36Sopenharmony_ci tx_cmd->dma_addr, 120962306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 121062306a36Sopenharmony_ci dev_consume_skb_irq(skb); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci tx_cmd->cmd.command = 0; /* Mark free */ 121362306a36Sopenharmony_ci break; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci case CmdTDR: 121662306a36Sopenharmony_ci { 121762306a36Sopenharmony_ci unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci if (status & 0x8000) { 122062306a36Sopenharmony_ci DEB(DEB_ANY, 122162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: link ok.\n", 122262306a36Sopenharmony_ci dev->name)); 122362306a36Sopenharmony_ci } else { 122462306a36Sopenharmony_ci if (status & 0x4000) 122562306a36Sopenharmony_ci printk(KERN_ERR 122662306a36Sopenharmony_ci "%s: Transceiver problem.\n", 122762306a36Sopenharmony_ci dev->name); 122862306a36Sopenharmony_ci if (status & 0x2000) 122962306a36Sopenharmony_ci printk(KERN_ERR 123062306a36Sopenharmony_ci "%s: Termination problem.\n", 123162306a36Sopenharmony_ci dev->name); 123262306a36Sopenharmony_ci if (status & 0x1000) 123362306a36Sopenharmony_ci printk(KERN_ERR 123462306a36Sopenharmony_ci "%s: Short circuit.\n", 123562306a36Sopenharmony_ci dev->name); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci DEB(DEB_TDR, 123862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Time %d.\n", 123962306a36Sopenharmony_ci dev->name, status & 0x07ff)); 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci break; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci case CmdConfigure: 124462306a36Sopenharmony_ci /* 124562306a36Sopenharmony_ci * Zap command so set_multicast_list() know 124662306a36Sopenharmony_ci * it is free 124762306a36Sopenharmony_ci */ 124862306a36Sopenharmony_ci ptr->command = 0; 124962306a36Sopenharmony_ci break; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci ptr->v_next = NULL; 125262306a36Sopenharmony_ci ptr->b_next = I596_NULL; 125362306a36Sopenharmony_ci dma_sync_dev(dev, ptr, sizeof(struct i596_cmd)); 125462306a36Sopenharmony_ci lp->last_cmd = jiffies; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* This mess is arranging that only the last of any outstanding 125862306a36Sopenharmony_ci * commands has the interrupt bit set. Should probably really 125962306a36Sopenharmony_ci * only add to the cmd queue when the CU is stopped. 126062306a36Sopenharmony_ci */ 126162306a36Sopenharmony_ci ptr = lp->cmd_head; 126262306a36Sopenharmony_ci while ((ptr != NULL) && (ptr != lp->cmd_tail)) { 126362306a36Sopenharmony_ci struct i596_cmd *prev = ptr; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci ptr->command &= SWAP16(0x1fff); 126662306a36Sopenharmony_ci ptr = ptr->v_next; 126762306a36Sopenharmony_ci dma_sync_dev(dev, prev, sizeof(struct i596_cmd)); 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (lp->cmd_head != NULL) 127162306a36Sopenharmony_ci ack_cmd |= CUC_START; 127262306a36Sopenharmony_ci dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status)); 127362306a36Sopenharmony_ci dma_sync_dev(dev, &dma->scb, sizeof(struct i596_scb)); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci if ((status & 0x1000) || (status & 0x4000)) { 127662306a36Sopenharmony_ci if ((status & 0x4000)) 127762306a36Sopenharmony_ci DEB(DEB_INTS, 127862306a36Sopenharmony_ci printk(KERN_DEBUG 127962306a36Sopenharmony_ci "%s: i596 interrupt received a frame.\n", 128062306a36Sopenharmony_ci dev->name)); 128162306a36Sopenharmony_ci i596_rx(dev); 128262306a36Sopenharmony_ci /* Only RX_START if stopped - RGH 07-07-96 */ 128362306a36Sopenharmony_ci if (status & 0x1000) { 128462306a36Sopenharmony_ci if (netif_running(dev)) { 128562306a36Sopenharmony_ci DEB(DEB_ERRORS, 128662306a36Sopenharmony_ci printk(KERN_DEBUG 128762306a36Sopenharmony_ci "%s: i596 interrupt receive unit inactive, status 0x%x\n", 128862306a36Sopenharmony_ci dev->name, status)); 128962306a36Sopenharmony_ci ack_cmd |= RX_START; 129062306a36Sopenharmony_ci dev->stats.rx_errors++; 129162306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 129262306a36Sopenharmony_ci rebuild_rx_bufs(dev); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci wait_cmd(dev, dma, 100, "i596 interrupt, timeout"); 129762306a36Sopenharmony_ci dma->scb.command = SWAP16(ack_cmd); 129862306a36Sopenharmony_ci dma_sync_dev(dev, &dma->scb, sizeof(struct i596_scb)); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* DANGER: I suspect that some kind of interrupt 130162306a36Sopenharmony_ci acknowledgement aside from acking the 82596 might be needed 130262306a36Sopenharmony_ci here... but it's running acceptably without */ 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci ca(dev); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout"); 130762306a36Sopenharmony_ci DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name)); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci spin_unlock (&lp->lock); 131062306a36Sopenharmony_ci return IRQ_HANDLED; 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic int i596_close(struct net_device *dev) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 131662306a36Sopenharmony_ci unsigned long flags; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci netif_stop_queue(dev); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci DEB(DEB_INIT, 132162306a36Sopenharmony_ci printk(KERN_DEBUG 132262306a36Sopenharmony_ci "%s: Shutting down ethercard, status was %4.4x.\n", 132362306a36Sopenharmony_ci dev->name, SWAP16(lp->dma->scb.status))); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci wait_cmd(dev, lp->dma, 100, "close1 timed out"); 132862306a36Sopenharmony_ci lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT); 132962306a36Sopenharmony_ci dma_sync_dev(dev, &lp->dma->scb, sizeof(struct i596_scb)); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci ca(dev); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci wait_cmd(dev, lp->dma, 100, "close2 timed out"); 133462306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 133562306a36Sopenharmony_ci DEB(DEB_STRUCT, i596_display_data(dev)); 133662306a36Sopenharmony_ci i596_cleanup_cmd(dev, lp); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci free_irq(dev->irq, dev); 133962306a36Sopenharmony_ci remove_rx_bufs(dev); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci return 0; 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci/* 134562306a36Sopenharmony_ci * Set or clear the multicast filter for this adaptor. 134662306a36Sopenharmony_ci */ 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic void set_multicast_list(struct net_device *dev) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci struct i596_private *lp = netdev_priv(dev); 135162306a36Sopenharmony_ci struct i596_dma *dma = lp->dma; 135262306a36Sopenharmony_ci int config = 0, cnt; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci DEB(DEB_MULTI, 135562306a36Sopenharmony_ci printk(KERN_DEBUG 135662306a36Sopenharmony_ci "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", 135762306a36Sopenharmony_ci dev->name, netdev_mc_count(dev), 135862306a36Sopenharmony_ci dev->flags & IFF_PROMISC ? "ON" : "OFF", 135962306a36Sopenharmony_ci dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if ((dev->flags & IFF_PROMISC) && 136262306a36Sopenharmony_ci !(dma->cf_cmd.i596_config[8] & 0x01)) { 136362306a36Sopenharmony_ci dma->cf_cmd.i596_config[8] |= 0x01; 136462306a36Sopenharmony_ci config = 1; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci if (!(dev->flags & IFF_PROMISC) && 136762306a36Sopenharmony_ci (dma->cf_cmd.i596_config[8] & 0x01)) { 136862306a36Sopenharmony_ci dma->cf_cmd.i596_config[8] &= ~0x01; 136962306a36Sopenharmony_ci config = 1; 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci if ((dev->flags & IFF_ALLMULTI) && 137262306a36Sopenharmony_ci (dma->cf_cmd.i596_config[11] & 0x20)) { 137362306a36Sopenharmony_ci dma->cf_cmd.i596_config[11] &= ~0x20; 137462306a36Sopenharmony_ci config = 1; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci if (!(dev->flags & IFF_ALLMULTI) && 137762306a36Sopenharmony_ci !(dma->cf_cmd.i596_config[11] & 0x20)) { 137862306a36Sopenharmony_ci dma->cf_cmd.i596_config[11] |= 0x20; 137962306a36Sopenharmony_ci config = 1; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci if (config) { 138262306a36Sopenharmony_ci if (dma->cf_cmd.cmd.command) 138362306a36Sopenharmony_ci printk(KERN_INFO 138462306a36Sopenharmony_ci "%s: config change request already queued\n", 138562306a36Sopenharmony_ci dev->name); 138662306a36Sopenharmony_ci else { 138762306a36Sopenharmony_ci dma->cf_cmd.cmd.command = SWAP16(CmdConfigure); 138862306a36Sopenharmony_ci dma_sync_dev(dev, &dma->cf_cmd, sizeof(struct cf_cmd)); 138962306a36Sopenharmony_ci i596_add_cmd(dev, &dma->cf_cmd.cmd); 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci cnt = netdev_mc_count(dev); 139462306a36Sopenharmony_ci if (cnt > MAX_MC_CNT) { 139562306a36Sopenharmony_ci cnt = MAX_MC_CNT; 139662306a36Sopenharmony_ci printk(KERN_NOTICE "%s: Only %d multicast addresses supported", 139762306a36Sopenharmony_ci dev->name, cnt); 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (!netdev_mc_empty(dev)) { 140162306a36Sopenharmony_ci struct netdev_hw_addr *ha; 140262306a36Sopenharmony_ci unsigned char *cp; 140362306a36Sopenharmony_ci struct mc_cmd *cmd; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci cmd = &dma->mc_cmd; 140662306a36Sopenharmony_ci cmd->cmd.command = SWAP16(CmdMulticastList); 140762306a36Sopenharmony_ci cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6); 140862306a36Sopenharmony_ci cp = cmd->mc_addrs; 140962306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 141062306a36Sopenharmony_ci if (!cnt--) 141162306a36Sopenharmony_ci break; 141262306a36Sopenharmony_ci memcpy(cp, ha->addr, ETH_ALEN); 141362306a36Sopenharmony_ci if (i596_debug > 1) 141462306a36Sopenharmony_ci DEB(DEB_MULTI, 141562306a36Sopenharmony_ci printk(KERN_DEBUG 141662306a36Sopenharmony_ci "%s: Adding address %pM\n", 141762306a36Sopenharmony_ci dev->name, cp)); 141862306a36Sopenharmony_ci cp += ETH_ALEN; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci dma_sync_dev(dev, &dma->mc_cmd, sizeof(struct mc_cmd)); 142162306a36Sopenharmony_ci i596_add_cmd(dev, &cmd->cmd); 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci} 1424