18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card
48c2ecf20Sopenharmony_ci *           and other Tigon based cards.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 1998-2002 by Jes Sorensen, <jes@trained-monkey.org>.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Thanks to Alteon and 3Com for providing hardware and documentation
98c2ecf20Sopenharmony_ci * enabling me to write this driver.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * A mailing list for discussing the use of this driver has been
128c2ecf20Sopenharmony_ci * setup, please subscribe to the lists if you have any questions
138c2ecf20Sopenharmony_ci * about the driver. Send mail to linux-acenic-help@sunsite.auc.dk to
148c2ecf20Sopenharmony_ci * see how to subscribe.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Additional credits:
178c2ecf20Sopenharmony_ci *   Pete Wyckoff <wyckoff@ca.sandia.gov>: Initial Linux/Alpha and trace
188c2ecf20Sopenharmony_ci *       dump support. The trace dump support has not been
198c2ecf20Sopenharmony_ci *       integrated yet however.
208c2ecf20Sopenharmony_ci *   Troy Benjegerdes: Big Endian (PPC) patches.
218c2ecf20Sopenharmony_ci *   Nate Stahl: Better out of memory handling and stats support.
228c2ecf20Sopenharmony_ci *   Aman Singla: Nasty race between interrupt handler and tx code dealing
238c2ecf20Sopenharmony_ci *                with 'testing the tx_ret_csm and setting tx_full'
248c2ecf20Sopenharmony_ci *   David S. Miller <davem@redhat.com>: conversion to new PCI dma mapping
258c2ecf20Sopenharmony_ci *                                       infrastructure and Sparc support
268c2ecf20Sopenharmony_ci *   Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the
278c2ecf20Sopenharmony_ci *                              driver under Linux/Sparc64
288c2ecf20Sopenharmony_ci *   Matt Domsch <Matt_Domsch@dell.com>: Detect Alteon 1000baseT cards
298c2ecf20Sopenharmony_ci *                                       ETHTOOL_GDRVINFO support
308c2ecf20Sopenharmony_ci *   Chip Salzenberg <chip@valinux.com>: Fix race condition between tx
318c2ecf20Sopenharmony_ci *                                       handler and close() cleanup.
328c2ecf20Sopenharmony_ci *   Ken Aaker <kdaaker@rchland.vnet.ibm.com>: Correct check for whether
338c2ecf20Sopenharmony_ci *                                       memory mapped IO is enabled to
348c2ecf20Sopenharmony_ci *                                       make the driver work on RS/6000.
358c2ecf20Sopenharmony_ci *   Takayoshi Kouchi <kouchi@hpc.bs1.fc.nec.co.jp>: Identifying problem
368c2ecf20Sopenharmony_ci *                                       where the driver would disable
378c2ecf20Sopenharmony_ci *                                       bus master mode if it had to disable
388c2ecf20Sopenharmony_ci *                                       write and invalidate.
398c2ecf20Sopenharmony_ci *   Stephen Hack <stephen_hack@hp.com>: Fixed ace_set_mac_addr for little
408c2ecf20Sopenharmony_ci *                                       endian systems.
418c2ecf20Sopenharmony_ci *   Val Henson <vhenson@esscom.com>:    Reset Jumbo skb producer and
428c2ecf20Sopenharmony_ci *                                       rx producer index when
438c2ecf20Sopenharmony_ci *                                       flushing the Jumbo ring.
448c2ecf20Sopenharmony_ci *   Hans Grobler <grobh@sun.ac.za>:     Memory leak fixes in the
458c2ecf20Sopenharmony_ci *                                       driver init path.
468c2ecf20Sopenharmony_ci *   Grant Grundler <grundler@cup.hp.com>: PCI write posting fixes.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#include <linux/module.h>
508c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
518c2ecf20Sopenharmony_ci#include <linux/types.h>
528c2ecf20Sopenharmony_ci#include <linux/errno.h>
538c2ecf20Sopenharmony_ci#include <linux/ioport.h>
548c2ecf20Sopenharmony_ci#include <linux/pci.h>
558c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
568c2ecf20Sopenharmony_ci#include <linux/kernel.h>
578c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
588c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
598c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
608c2ecf20Sopenharmony_ci#include <linux/delay.h>
618c2ecf20Sopenharmony_ci#include <linux/mm.h>
628c2ecf20Sopenharmony_ci#include <linux/highmem.h>
638c2ecf20Sopenharmony_ci#include <linux/sockios.h>
648c2ecf20Sopenharmony_ci#include <linux/firmware.h>
658c2ecf20Sopenharmony_ci#include <linux/slab.h>
668c2ecf20Sopenharmony_ci#include <linux/prefetch.h>
678c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#ifdef SIOCETHTOOL
708c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
718c2ecf20Sopenharmony_ci#endif
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#include <net/sock.h>
748c2ecf20Sopenharmony_ci#include <net/ip.h>
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#include <asm/io.h>
778c2ecf20Sopenharmony_ci#include <asm/irq.h>
788c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
798c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define DRV_NAME "acenic"
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#undef INDEX_DEBUG
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#ifdef CONFIG_ACENIC_OMIT_TIGON_I
878c2ecf20Sopenharmony_ci#define ACE_IS_TIGON_I(ap)	0
888c2ecf20Sopenharmony_ci#define ACE_TX_RING_ENTRIES(ap)	MAX_TX_RING_ENTRIES
898c2ecf20Sopenharmony_ci#else
908c2ecf20Sopenharmony_ci#define ACE_IS_TIGON_I(ap)	(ap->version == 1)
918c2ecf20Sopenharmony_ci#define ACE_TX_RING_ENTRIES(ap)	ap->tx_ring_entries
928c2ecf20Sopenharmony_ci#endif
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_ALTEON
958c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_ALTEON		0x12ae
968c2ecf20Sopenharmony_ci#endif
978c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE
988c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE  0x0001
998c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_ALTEON_ACENIC_COPPER 0x0002
1008c2ecf20Sopenharmony_ci#endif
1018c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_3COM_3C985
1028c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_3COM_3C985	0x0001
1038c2ecf20Sopenharmony_ci#endif
1048c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_NETGEAR
1058c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_NETGEAR		0x1385
1068c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
1078c2ecf20Sopenharmony_ci#endif
1088c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_NETGEAR_GA620T
1098c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_NETGEAR_GA620T	0x630a
1108c2ecf20Sopenharmony_ci#endif
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/*
1148c2ecf20Sopenharmony_ci * Farallon used the DEC vendor ID by mistake and they seem not
1158c2ecf20Sopenharmony_ci * to care - stinky!
1168c2ecf20Sopenharmony_ci */
1178c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
1188c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_FARALLON_PN9000SX	0x1a
1198c2ecf20Sopenharmony_ci#endif
1208c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_FARALLON_PN9100T
1218c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_FARALLON_PN9100T  0xfa
1228c2ecf20Sopenharmony_ci#endif
1238c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_SGI
1248c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_SGI		0x10a9
1258c2ecf20Sopenharmony_ci#endif
1268c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_SGI_ACENIC
1278c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_SGI_ACENIC	0x0009
1288c2ecf20Sopenharmony_ci#endif
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic const struct pci_device_id acenic_pci_tbl[] = {
1318c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE,
1328c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1338c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER,
1348c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1358c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C985,
1368c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1378c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620,
1388c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1398c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T,
1408c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1418c2ecf20Sopenharmony_ci	/*
1428c2ecf20Sopenharmony_ci	 * Farallon used the DEC vendor ID on their cards incorrectly,
1438c2ecf20Sopenharmony_ci	 * then later Alteon's ID.
1448c2ecf20Sopenharmony_ci	 */
1458c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX,
1468c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1478c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_FARALLON_PN9100T,
1488c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1498c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC,
1508c2ecf20Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
1518c2ecf20Sopenharmony_ci	{ }
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#define ace_sync_irq(irq)	synchronize_irq(irq)
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci#ifndef offset_in_page
1588c2ecf20Sopenharmony_ci#define offset_in_page(ptr)	((unsigned long)(ptr) & ~PAGE_MASK)
1598c2ecf20Sopenharmony_ci#endif
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci#define ACE_MAX_MOD_PARMS	8
1628c2ecf20Sopenharmony_ci#define BOARD_IDX_STATIC	0
1638c2ecf20Sopenharmony_ci#define BOARD_IDX_OVERFLOW	-1
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci#include "acenic.h"
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/*
1688c2ecf20Sopenharmony_ci * These must be defined before the firmware is included.
1698c2ecf20Sopenharmony_ci */
1708c2ecf20Sopenharmony_ci#define MAX_TEXT_LEN	96*1024
1718c2ecf20Sopenharmony_ci#define MAX_RODATA_LEN	8*1024
1728c2ecf20Sopenharmony_ci#define MAX_DATA_LEN	2*1024
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#ifndef tigon2FwReleaseLocal
1758c2ecf20Sopenharmony_ci#define tigon2FwReleaseLocal 0
1768c2ecf20Sopenharmony_ci#endif
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/*
1798c2ecf20Sopenharmony_ci * This driver currently supports Tigon I and Tigon II based cards
1808c2ecf20Sopenharmony_ci * including the Alteon AceNIC, the 3Com 3C985[B] and NetGear
1818c2ecf20Sopenharmony_ci * GA620. The driver should also work on the SGI, DEC and Farallon
1828c2ecf20Sopenharmony_ci * versions of the card, however I have not been able to test that
1838c2ecf20Sopenharmony_ci * myself.
1848c2ecf20Sopenharmony_ci *
1858c2ecf20Sopenharmony_ci * This card is really neat, it supports receive hardware checksumming
1868c2ecf20Sopenharmony_ci * and jumbo frames (up to 9000 bytes) and does a lot of work in the
1878c2ecf20Sopenharmony_ci * firmware. Also the programming interface is quite neat, except for
1888c2ecf20Sopenharmony_ci * the parts dealing with the i2c eeprom on the card ;-)
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * Using jumbo frames:
1918c2ecf20Sopenharmony_ci *
1928c2ecf20Sopenharmony_ci * To enable jumbo frames, simply specify an mtu between 1500 and 9000
1938c2ecf20Sopenharmony_ci * bytes to ifconfig. Jumbo frames can be enabled or disabled at any time
1948c2ecf20Sopenharmony_ci * by running `ifconfig eth<X> mtu <MTU>' with <X> being the Ethernet
1958c2ecf20Sopenharmony_ci * interface number and <MTU> being the MTU value.
1968c2ecf20Sopenharmony_ci *
1978c2ecf20Sopenharmony_ci * Module parameters:
1988c2ecf20Sopenharmony_ci *
1998c2ecf20Sopenharmony_ci * When compiled as a loadable module, the driver allows for a number
2008c2ecf20Sopenharmony_ci * of module parameters to be specified. The driver supports the
2018c2ecf20Sopenharmony_ci * following module parameters:
2028c2ecf20Sopenharmony_ci *
2038c2ecf20Sopenharmony_ci *  trace=<val> - Firmware trace level. This requires special traced
2048c2ecf20Sopenharmony_ci *                firmware to replace the firmware supplied with
2058c2ecf20Sopenharmony_ci *                the driver - for debugging purposes only.
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci *  link=<val>  - Link state. Normally you want to use the default link
2088c2ecf20Sopenharmony_ci *                parameters set by the driver. This can be used to
2098c2ecf20Sopenharmony_ci *                override these in case your switch doesn't negotiate
2108c2ecf20Sopenharmony_ci *                the link properly. Valid values are:
2118c2ecf20Sopenharmony_ci *         0x0001 - Force half duplex link.
2128c2ecf20Sopenharmony_ci *         0x0002 - Do not negotiate line speed with the other end.
2138c2ecf20Sopenharmony_ci *         0x0010 - 10Mbit/sec link.
2148c2ecf20Sopenharmony_ci *         0x0020 - 100Mbit/sec link.
2158c2ecf20Sopenharmony_ci *         0x0040 - 1000Mbit/sec link.
2168c2ecf20Sopenharmony_ci *         0x0100 - Do not negotiate flow control.
2178c2ecf20Sopenharmony_ci *         0x0200 - Enable RX flow control Y
2188c2ecf20Sopenharmony_ci *         0x0400 - Enable TX flow control Y (Tigon II NICs only).
2198c2ecf20Sopenharmony_ci *                Default value is 0x0270, ie. enable link+flow
2208c2ecf20Sopenharmony_ci *                control negotiation. Negotiating the highest
2218c2ecf20Sopenharmony_ci *                possible link speed with RX flow control enabled.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci *                When disabling link speed negotiation, only one link
2248c2ecf20Sopenharmony_ci *                speed is allowed to be specified!
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci *  tx_coal_tick=<val> - number of coalescing clock ticks (us) allowed
2278c2ecf20Sopenharmony_ci *                to wait for more packets to arive before
2288c2ecf20Sopenharmony_ci *                interrupting the host, from the time the first
2298c2ecf20Sopenharmony_ci *                packet arrives.
2308c2ecf20Sopenharmony_ci *
2318c2ecf20Sopenharmony_ci *  rx_coal_tick=<val> - number of coalescing clock ticks (us) allowed
2328c2ecf20Sopenharmony_ci *                to wait for more packets to arive in the transmit ring,
2338c2ecf20Sopenharmony_ci *                before interrupting the host, after transmitting the
2348c2ecf20Sopenharmony_ci *                first packet in the ring.
2358c2ecf20Sopenharmony_ci *
2368c2ecf20Sopenharmony_ci *  max_tx_desc=<val> - maximum number of transmit descriptors
2378c2ecf20Sopenharmony_ci *                (packets) transmitted before interrupting the host.
2388c2ecf20Sopenharmony_ci *
2398c2ecf20Sopenharmony_ci *  max_rx_desc=<val> - maximum number of receive descriptors
2408c2ecf20Sopenharmony_ci *                (packets) received before interrupting the host.
2418c2ecf20Sopenharmony_ci *
2428c2ecf20Sopenharmony_ci *  tx_ratio=<val> - 7 bit value (0 - 63) specifying the split in 64th
2438c2ecf20Sopenharmony_ci *                increments of the NIC's on board memory to be used for
2448c2ecf20Sopenharmony_ci *                transmit and receive buffers. For the 1MB NIC app. 800KB
2458c2ecf20Sopenharmony_ci *                is available, on the 1/2MB NIC app. 300KB is available.
2468c2ecf20Sopenharmony_ci *                68KB will always be available as a minimum for both
2478c2ecf20Sopenharmony_ci *                directions. The default value is a 50/50 split.
2488c2ecf20Sopenharmony_ci *  dis_pci_mem_inval=<val> - disable PCI memory write and invalidate
2498c2ecf20Sopenharmony_ci *                operations, default (1) is to always disable this as
2508c2ecf20Sopenharmony_ci *                that is what Alteon does on NT. I have not been able
2518c2ecf20Sopenharmony_ci *                to measure any real performance differences with
2528c2ecf20Sopenharmony_ci *                this on my systems. Set <val>=0 if you want to
2538c2ecf20Sopenharmony_ci *                enable these operations.
2548c2ecf20Sopenharmony_ci *
2558c2ecf20Sopenharmony_ci * If you use more than one NIC, specify the parameters for the
2568c2ecf20Sopenharmony_ci * individual NICs with a comma, ie. trace=0,0x00001fff,0 you want to
2578c2ecf20Sopenharmony_ci * run tracing on NIC #2 but not on NIC #1 and #3.
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * TODO:
2608c2ecf20Sopenharmony_ci *
2618c2ecf20Sopenharmony_ci * - Proper multicast support.
2628c2ecf20Sopenharmony_ci * - NIC dump support.
2638c2ecf20Sopenharmony_ci * - More tuning parameters.
2648c2ecf20Sopenharmony_ci *
2658c2ecf20Sopenharmony_ci * The mini ring is not used under Linux and I am not sure it makes sense
2668c2ecf20Sopenharmony_ci * to actually use it.
2678c2ecf20Sopenharmony_ci *
2688c2ecf20Sopenharmony_ci * New interrupt handler strategy:
2698c2ecf20Sopenharmony_ci *
2708c2ecf20Sopenharmony_ci * The old interrupt handler worked using the traditional method of
2718c2ecf20Sopenharmony_ci * replacing an skbuff with a new one when a packet arrives. However
2728c2ecf20Sopenharmony_ci * the rx rings do not need to contain a static number of buffer
2738c2ecf20Sopenharmony_ci * descriptors, thus it makes sense to move the memory allocation out
2748c2ecf20Sopenharmony_ci * of the main interrupt handler and do it in a bottom half handler
2758c2ecf20Sopenharmony_ci * and only allocate new buffers when the number of buffers in the
2768c2ecf20Sopenharmony_ci * ring is below a certain threshold. In order to avoid starving the
2778c2ecf20Sopenharmony_ci * NIC under heavy load it is however necessary to force allocation
2788c2ecf20Sopenharmony_ci * when hitting a minimum threshold. The strategy for alloction is as
2798c2ecf20Sopenharmony_ci * follows:
2808c2ecf20Sopenharmony_ci *
2818c2ecf20Sopenharmony_ci *     RX_LOW_BUF_THRES    - allocate buffers in the bottom half
2828c2ecf20Sopenharmony_ci *     RX_PANIC_LOW_THRES  - we are very low on buffers, allocate
2838c2ecf20Sopenharmony_ci *                           the buffers in the interrupt handler
2848c2ecf20Sopenharmony_ci *     RX_RING_THRES       - maximum number of buffers in the rx ring
2858c2ecf20Sopenharmony_ci *     RX_MINI_THRES       - maximum number of buffers in the mini ring
2868c2ecf20Sopenharmony_ci *     RX_JUMBO_THRES      - maximum number of buffers in the jumbo ring
2878c2ecf20Sopenharmony_ci *
2888c2ecf20Sopenharmony_ci * One advantagous side effect of this allocation approach is that the
2898c2ecf20Sopenharmony_ci * entire rx processing can be done without holding any spin lock
2908c2ecf20Sopenharmony_ci * since the rx rings and registers are totally independent of the tx
2918c2ecf20Sopenharmony_ci * ring and its registers.  This of course includes the kmalloc's of
2928c2ecf20Sopenharmony_ci * new skb's. Thus start_xmit can run in parallel with rx processing
2938c2ecf20Sopenharmony_ci * and the memory allocation on SMP systems.
2948c2ecf20Sopenharmony_ci *
2958c2ecf20Sopenharmony_ci * Note that running the skb reallocation in a bottom half opens up
2968c2ecf20Sopenharmony_ci * another can of races which needs to be handled properly. In
2978c2ecf20Sopenharmony_ci * particular it can happen that the interrupt handler tries to run
2988c2ecf20Sopenharmony_ci * the reallocation while the bottom half is either running on another
2998c2ecf20Sopenharmony_ci * CPU or was interrupted on the same CPU. To get around this the
3008c2ecf20Sopenharmony_ci * driver uses bitops to prevent the reallocation routines from being
3018c2ecf20Sopenharmony_ci * reentered.
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci * TX handling can also be done without holding any spin lock, wheee
3048c2ecf20Sopenharmony_ci * this is fun! since tx_ret_csm is only written to by the interrupt
3058c2ecf20Sopenharmony_ci * handler. The case to be aware of is when shutting down the device
3068c2ecf20Sopenharmony_ci * and cleaning up where it is necessary to make sure that
3078c2ecf20Sopenharmony_ci * start_xmit() is not running while this is happening. Well DaveM
3088c2ecf20Sopenharmony_ci * informs me that this case is already protected against ... bye bye
3098c2ecf20Sopenharmony_ci * Mr. Spin Lock, it was nice to know you.
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci * TX interrupts are now partly disabled so the NIC will only generate
3128c2ecf20Sopenharmony_ci * TX interrupts for the number of coal ticks, not for the number of
3138c2ecf20Sopenharmony_ci * TX packets in the queue. This should reduce the number of TX only,
3148c2ecf20Sopenharmony_ci * ie. when no RX processing is done, interrupts seen.
3158c2ecf20Sopenharmony_ci */
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/*
3188c2ecf20Sopenharmony_ci * Threshold values for RX buffer allocation - the low water marks for
3198c2ecf20Sopenharmony_ci * when to start refilling the rings are set to 75% of the ring
3208c2ecf20Sopenharmony_ci * sizes. It seems to make sense to refill the rings entirely from the
3218c2ecf20Sopenharmony_ci * intrrupt handler once it gets below the panic threshold, that way
3228c2ecf20Sopenharmony_ci * we don't risk that the refilling is moved to another CPU when the
3238c2ecf20Sopenharmony_ci * one running the interrupt handler just got the slab code hot in its
3248c2ecf20Sopenharmony_ci * cache.
3258c2ecf20Sopenharmony_ci */
3268c2ecf20Sopenharmony_ci#define RX_RING_SIZE		72
3278c2ecf20Sopenharmony_ci#define RX_MINI_SIZE		64
3288c2ecf20Sopenharmony_ci#define RX_JUMBO_SIZE		48
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci#define RX_PANIC_STD_THRES	16
3318c2ecf20Sopenharmony_ci#define RX_PANIC_STD_REFILL	(3*RX_PANIC_STD_THRES)/2
3328c2ecf20Sopenharmony_ci#define RX_LOW_STD_THRES	(3*RX_RING_SIZE)/4
3338c2ecf20Sopenharmony_ci#define RX_PANIC_MINI_THRES	12
3348c2ecf20Sopenharmony_ci#define RX_PANIC_MINI_REFILL	(3*RX_PANIC_MINI_THRES)/2
3358c2ecf20Sopenharmony_ci#define RX_LOW_MINI_THRES	(3*RX_MINI_SIZE)/4
3368c2ecf20Sopenharmony_ci#define RX_PANIC_JUMBO_THRES	6
3378c2ecf20Sopenharmony_ci#define RX_PANIC_JUMBO_REFILL	(3*RX_PANIC_JUMBO_THRES)/2
3388c2ecf20Sopenharmony_ci#define RX_LOW_JUMBO_THRES	(3*RX_JUMBO_SIZE)/4
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci/*
3428c2ecf20Sopenharmony_ci * Size of the mini ring entries, basically these just should be big
3438c2ecf20Sopenharmony_ci * enough to take TCP ACKs
3448c2ecf20Sopenharmony_ci */
3458c2ecf20Sopenharmony_ci#define ACE_MINI_SIZE		100
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci#define ACE_MINI_BUFSIZE	ACE_MINI_SIZE
3488c2ecf20Sopenharmony_ci#define ACE_STD_BUFSIZE		(ACE_STD_MTU + ETH_HLEN + 4)
3498c2ecf20Sopenharmony_ci#define ACE_JUMBO_BUFSIZE	(ACE_JUMBO_MTU + ETH_HLEN + 4)
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/*
3528c2ecf20Sopenharmony_ci * There seems to be a magic difference in the effect between 995 and 996
3538c2ecf20Sopenharmony_ci * but little difference between 900 and 995 ... no idea why.
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci * There is now a default set of tuning parameters which is set, depending
3568c2ecf20Sopenharmony_ci * on whether or not the user enables Jumbo frames. It's assumed that if
3578c2ecf20Sopenharmony_ci * Jumbo frames are enabled, the user wants optimal tuning for that case.
3588c2ecf20Sopenharmony_ci */
3598c2ecf20Sopenharmony_ci#define DEF_TX_COAL		400 /* 996 */
3608c2ecf20Sopenharmony_ci#define DEF_TX_MAX_DESC		60  /* was 40 */
3618c2ecf20Sopenharmony_ci#define DEF_RX_COAL		120 /* 1000 */
3628c2ecf20Sopenharmony_ci#define DEF_RX_MAX_DESC		25
3638c2ecf20Sopenharmony_ci#define DEF_TX_RATIO		21 /* 24 */
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci#define DEF_JUMBO_TX_COAL	20
3668c2ecf20Sopenharmony_ci#define DEF_JUMBO_TX_MAX_DESC	60
3678c2ecf20Sopenharmony_ci#define DEF_JUMBO_RX_COAL	30
3688c2ecf20Sopenharmony_ci#define DEF_JUMBO_RX_MAX_DESC	6
3698c2ecf20Sopenharmony_ci#define DEF_JUMBO_TX_RATIO	21
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci#if tigon2FwReleaseLocal < 20001118
3728c2ecf20Sopenharmony_ci/*
3738c2ecf20Sopenharmony_ci * Standard firmware and early modifications duplicate
3748c2ecf20Sopenharmony_ci * IRQ load without this flag (coal timer is never reset).
3758c2ecf20Sopenharmony_ci * Note that with this flag tx_coal should be less than
3768c2ecf20Sopenharmony_ci * time to xmit full tx ring.
3778c2ecf20Sopenharmony_ci * 400usec is not so bad for tx ring size of 128.
3788c2ecf20Sopenharmony_ci */
3798c2ecf20Sopenharmony_ci#define TX_COAL_INTS_ONLY	1	/* worth it */
3808c2ecf20Sopenharmony_ci#else
3818c2ecf20Sopenharmony_ci/*
3828c2ecf20Sopenharmony_ci * With modified firmware, this is not necessary, but still useful.
3838c2ecf20Sopenharmony_ci */
3848c2ecf20Sopenharmony_ci#define TX_COAL_INTS_ONLY	1
3858c2ecf20Sopenharmony_ci#endif
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci#define DEF_TRACE		0
3888c2ecf20Sopenharmony_ci#define DEF_STAT		(2 * TICKS_PER_SEC)
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic int link_state[ACE_MAX_MOD_PARMS];
3928c2ecf20Sopenharmony_cistatic int trace[ACE_MAX_MOD_PARMS];
3938c2ecf20Sopenharmony_cistatic int tx_coal_tick[ACE_MAX_MOD_PARMS];
3948c2ecf20Sopenharmony_cistatic int rx_coal_tick[ACE_MAX_MOD_PARMS];
3958c2ecf20Sopenharmony_cistatic int max_tx_desc[ACE_MAX_MOD_PARMS];
3968c2ecf20Sopenharmony_cistatic int max_rx_desc[ACE_MAX_MOD_PARMS];
3978c2ecf20Sopenharmony_cistatic int tx_ratio[ACE_MAX_MOD_PARMS];
3988c2ecf20Sopenharmony_cistatic int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
4018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
4038c2ecf20Sopenharmony_ci#ifndef CONFIG_ACENIC_OMIT_TIGON_I
4048c2ecf20Sopenharmony_ciMODULE_FIRMWARE("acenic/tg1.bin");
4058c2ecf20Sopenharmony_ci#endif
4068c2ecf20Sopenharmony_ciMODULE_FIRMWARE("acenic/tg2.bin");
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cimodule_param_array_named(link, link_state, int, NULL, 0);
4098c2ecf20Sopenharmony_cimodule_param_array(trace, int, NULL, 0);
4108c2ecf20Sopenharmony_cimodule_param_array(tx_coal_tick, int, NULL, 0);
4118c2ecf20Sopenharmony_cimodule_param_array(max_tx_desc, int, NULL, 0);
4128c2ecf20Sopenharmony_cimodule_param_array(rx_coal_tick, int, NULL, 0);
4138c2ecf20Sopenharmony_cimodule_param_array(max_rx_desc, int, NULL, 0);
4148c2ecf20Sopenharmony_cimodule_param_array(tx_ratio, int, NULL, 0);
4158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state");
4168c2ecf20Sopenharmony_ciMODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level");
4178c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives");
4188c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait");
4198c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives");
4208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait");
4218c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic const char version[] =
4258c2ecf20Sopenharmony_ci  "acenic.c: v0.92 08/05/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
4268c2ecf20Sopenharmony_ci  "                            http://home.cern.ch/~jes/gige/acenic.html\n";
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic int ace_get_link_ksettings(struct net_device *,
4298c2ecf20Sopenharmony_ci				  struct ethtool_link_ksettings *);
4308c2ecf20Sopenharmony_cistatic int ace_set_link_ksettings(struct net_device *,
4318c2ecf20Sopenharmony_ci				  const struct ethtool_link_ksettings *);
4328c2ecf20Sopenharmony_cistatic void ace_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic const struct ethtool_ops ace_ethtool_ops = {
4358c2ecf20Sopenharmony_ci	.get_drvinfo = ace_get_drvinfo,
4368c2ecf20Sopenharmony_ci	.get_link_ksettings = ace_get_link_ksettings,
4378c2ecf20Sopenharmony_ci	.set_link_ksettings = ace_set_link_ksettings,
4388c2ecf20Sopenharmony_ci};
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic void ace_watchdog(struct net_device *dev, unsigned int txqueue);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic const struct net_device_ops ace_netdev_ops = {
4438c2ecf20Sopenharmony_ci	.ndo_open		= ace_open,
4448c2ecf20Sopenharmony_ci	.ndo_stop		= ace_close,
4458c2ecf20Sopenharmony_ci	.ndo_tx_timeout		= ace_watchdog,
4468c2ecf20Sopenharmony_ci	.ndo_get_stats		= ace_get_stats,
4478c2ecf20Sopenharmony_ci	.ndo_start_xmit		= ace_start_xmit,
4488c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= ace_set_multicast_list,
4498c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
4508c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= ace_set_mac_addr,
4518c2ecf20Sopenharmony_ci	.ndo_change_mtu		= ace_change_mtu,
4528c2ecf20Sopenharmony_ci};
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int acenic_probe_one(struct pci_dev *pdev,
4558c2ecf20Sopenharmony_ci			    const struct pci_device_id *id)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	struct net_device *dev;
4588c2ecf20Sopenharmony_ci	struct ace_private *ap;
4598c2ecf20Sopenharmony_ci	static int boards_found;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct ace_private));
4628c2ecf20Sopenharmony_ci	if (dev == NULL)
4638c2ecf20Sopenharmony_ci		return -ENOMEM;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	ap = netdev_priv(dev);
4688c2ecf20Sopenharmony_ci	ap->ndev = dev;
4698c2ecf20Sopenharmony_ci	ap->pdev = pdev;
4708c2ecf20Sopenharmony_ci	ap->name = pci_name(pdev);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
4738c2ecf20Sopenharmony_ci	dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	dev->watchdog_timeo = 5*HZ;
4768c2ecf20Sopenharmony_ci	dev->min_mtu = 0;
4778c2ecf20Sopenharmony_ci	dev->max_mtu = ACE_JUMBO_MTU;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	dev->netdev_ops = &ace_netdev_ops;
4808c2ecf20Sopenharmony_ci	dev->ethtool_ops = &ace_ethtool_ops;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	/* we only display this string ONCE */
4838c2ecf20Sopenharmony_ci	if (!boards_found)
4848c2ecf20Sopenharmony_ci		printk(version);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (pci_enable_device(pdev))
4878c2ecf20Sopenharmony_ci		goto fail_free_netdev;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/*
4908c2ecf20Sopenharmony_ci	 * Enable master mode before we start playing with the
4918c2ecf20Sopenharmony_ci	 * pci_command word since pci_set_master() will modify
4928c2ecf20Sopenharmony_ci	 * it.
4938c2ecf20Sopenharmony_ci	 */
4948c2ecf20Sopenharmony_ci	pci_set_master(pdev);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	/* OpenFirmware on Mac's does not set this - DOH.. */
4998c2ecf20Sopenharmony_ci	if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
5008c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
5018c2ecf20Sopenharmony_ci		       "access - was not enabled by BIOS/Firmware\n",
5028c2ecf20Sopenharmony_ci		       ap->name);
5038c2ecf20Sopenharmony_ci		ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
5048c2ecf20Sopenharmony_ci		pci_write_config_word(ap->pdev, PCI_COMMAND,
5058c2ecf20Sopenharmony_ci				      ap->pci_command);
5068c2ecf20Sopenharmony_ci		wmb();
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ap->pci_latency);
5108c2ecf20Sopenharmony_ci	if (ap->pci_latency <= 0x40) {
5118c2ecf20Sopenharmony_ci		ap->pci_latency = 0x40;
5128c2ecf20Sopenharmony_ci		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ap->pci_latency);
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/*
5168c2ecf20Sopenharmony_ci	 * Remap the regs into kernel space - this is abuse of
5178c2ecf20Sopenharmony_ci	 * dev->base_addr since it was means for I/O port
5188c2ecf20Sopenharmony_ci	 * addresses but who gives a damn.
5198c2ecf20Sopenharmony_ci	 */
5208c2ecf20Sopenharmony_ci	dev->base_addr = pci_resource_start(pdev, 0);
5218c2ecf20Sopenharmony_ci	ap->regs = ioremap(dev->base_addr, 0x4000);
5228c2ecf20Sopenharmony_ci	if (!ap->regs) {
5238c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s:  Unable to map I/O register, "
5248c2ecf20Sopenharmony_ci		       "AceNIC %i will be disabled.\n",
5258c2ecf20Sopenharmony_ci		       ap->name, boards_found);
5268c2ecf20Sopenharmony_ci		goto fail_free_netdev;
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	switch(pdev->vendor) {
5308c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_ALTEON:
5318c2ecf20Sopenharmony_ci		if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
5328c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Farallon PN9100-T ",
5338c2ecf20Sopenharmony_ci			       ap->name);
5348c2ecf20Sopenharmony_ci		} else {
5358c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Alteon AceNIC ",
5368c2ecf20Sopenharmony_ci			       ap->name);
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci		break;
5398c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_3COM:
5408c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: 3Com 3C985 ", ap->name);
5418c2ecf20Sopenharmony_ci		break;
5428c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_NETGEAR:
5438c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: NetGear GA620 ", ap->name);
5448c2ecf20Sopenharmony_ci		break;
5458c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_DEC:
5468c2ecf20Sopenharmony_ci		if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
5478c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Farallon PN9000-SX ",
5488c2ecf20Sopenharmony_ci			       ap->name);
5498c2ecf20Sopenharmony_ci			break;
5508c2ecf20Sopenharmony_ci		}
5518c2ecf20Sopenharmony_ci		fallthrough;
5528c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_SGI:
5538c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: SGI AceNIC ", ap->name);
5548c2ecf20Sopenharmony_ci		break;
5558c2ecf20Sopenharmony_ci	default:
5568c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Unknown AceNIC ", ap->name);
5578c2ecf20Sopenharmony_ci		break;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
5618c2ecf20Sopenharmony_ci	printk("irq %d\n", pdev->irq);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci#ifdef CONFIG_ACENIC_OMIT_TIGON_I
5648c2ecf20Sopenharmony_ci	if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
5658c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Driver compiled without Tigon I"
5668c2ecf20Sopenharmony_ci		       " support - NIC disabled\n", dev->name);
5678c2ecf20Sopenharmony_ci		goto fail_uninit;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci#endif
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (ace_allocate_descriptors(dev))
5728c2ecf20Sopenharmony_ci		goto fail_free_netdev;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci#ifdef MODULE
5758c2ecf20Sopenharmony_ci	if (boards_found >= ACE_MAX_MOD_PARMS)
5768c2ecf20Sopenharmony_ci		ap->board_idx = BOARD_IDX_OVERFLOW;
5778c2ecf20Sopenharmony_ci	else
5788c2ecf20Sopenharmony_ci		ap->board_idx = boards_found;
5798c2ecf20Sopenharmony_ci#else
5808c2ecf20Sopenharmony_ci	ap->board_idx = BOARD_IDX_STATIC;
5818c2ecf20Sopenharmony_ci#endif
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (ace_init(dev))
5848c2ecf20Sopenharmony_ci		goto fail_free_netdev;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (register_netdev(dev)) {
5878c2ecf20Sopenharmony_ci		printk(KERN_ERR "acenic: device registration failed\n");
5888c2ecf20Sopenharmony_ci		goto fail_uninit;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci	ap->name = dev->name;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (ap->pci_using_dac)
5938c2ecf20Sopenharmony_ci		dev->features |= NETIF_F_HIGHDMA;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, dev);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	boards_found++;
5988c2ecf20Sopenharmony_ci	return 0;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci fail_uninit:
6018c2ecf20Sopenharmony_ci	ace_init_cleanup(dev);
6028c2ecf20Sopenharmony_ci fail_free_netdev:
6038c2ecf20Sopenharmony_ci	free_netdev(dev);
6048c2ecf20Sopenharmony_ci	return -ENODEV;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic void acenic_remove_one(struct pci_dev *pdev)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
6108c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
6118c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
6128c2ecf20Sopenharmony_ci	short i;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	unregister_netdev(dev);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
6178c2ecf20Sopenharmony_ci	if (ap->version >= 2)
6188c2ecf20Sopenharmony_ci		writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	/*
6218c2ecf20Sopenharmony_ci	 * This clears any pending interrupts
6228c2ecf20Sopenharmony_ci	 */
6238c2ecf20Sopenharmony_ci	writel(1, &regs->Mb0Lo);
6248c2ecf20Sopenharmony_ci	readl(&regs->CpuCtrl);	/* flush */
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	/*
6278c2ecf20Sopenharmony_ci	 * Make sure no other CPUs are processing interrupts
6288c2ecf20Sopenharmony_ci	 * on the card before the buffers are being released.
6298c2ecf20Sopenharmony_ci	 * Otherwise one might experience some `interesting'
6308c2ecf20Sopenharmony_ci	 * effects.
6318c2ecf20Sopenharmony_ci	 *
6328c2ecf20Sopenharmony_ci	 * Then release the RX buffers - jumbo buffers were
6338c2ecf20Sopenharmony_ci	 * already released in ace_close().
6348c2ecf20Sopenharmony_ci	 */
6358c2ecf20Sopenharmony_ci	ace_sync_irq(dev->irq);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
6388c2ecf20Sopenharmony_ci		struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		if (skb) {
6418c2ecf20Sopenharmony_ci			struct ring_info *ringp;
6428c2ecf20Sopenharmony_ci			dma_addr_t mapping;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci			ringp = &ap->skb->rx_std_skbuff[i];
6458c2ecf20Sopenharmony_ci			mapping = dma_unmap_addr(ringp, mapping);
6468c2ecf20Sopenharmony_ci			dma_unmap_page(&ap->pdev->dev, mapping,
6478c2ecf20Sopenharmony_ci				       ACE_STD_BUFSIZE, DMA_FROM_DEVICE);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci			ap->rx_std_ring[i].size = 0;
6508c2ecf20Sopenharmony_ci			ap->skb->rx_std_skbuff[i].skb = NULL;
6518c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
6528c2ecf20Sopenharmony_ci		}
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	if (ap->version >= 2) {
6568c2ecf20Sopenharmony_ci		for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
6578c2ecf20Sopenharmony_ci			struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci			if (skb) {
6608c2ecf20Sopenharmony_ci				struct ring_info *ringp;
6618c2ecf20Sopenharmony_ci				dma_addr_t mapping;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci				ringp = &ap->skb->rx_mini_skbuff[i];
6648c2ecf20Sopenharmony_ci				mapping = dma_unmap_addr(ringp,mapping);
6658c2ecf20Sopenharmony_ci				dma_unmap_page(&ap->pdev->dev, mapping,
6668c2ecf20Sopenharmony_ci					       ACE_MINI_BUFSIZE,
6678c2ecf20Sopenharmony_ci					       DMA_FROM_DEVICE);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci				ap->rx_mini_ring[i].size = 0;
6708c2ecf20Sopenharmony_ci				ap->skb->rx_mini_skbuff[i].skb = NULL;
6718c2ecf20Sopenharmony_ci				dev_kfree_skb(skb);
6728c2ecf20Sopenharmony_ci			}
6738c2ecf20Sopenharmony_ci		}
6748c2ecf20Sopenharmony_ci	}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
6778c2ecf20Sopenharmony_ci		struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
6788c2ecf20Sopenharmony_ci		if (skb) {
6798c2ecf20Sopenharmony_ci			struct ring_info *ringp;
6808c2ecf20Sopenharmony_ci			dma_addr_t mapping;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci			ringp = &ap->skb->rx_jumbo_skbuff[i];
6838c2ecf20Sopenharmony_ci			mapping = dma_unmap_addr(ringp, mapping);
6848c2ecf20Sopenharmony_ci			dma_unmap_page(&ap->pdev->dev, mapping,
6858c2ecf20Sopenharmony_ci				       ACE_JUMBO_BUFSIZE, DMA_FROM_DEVICE);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci			ap->rx_jumbo_ring[i].size = 0;
6888c2ecf20Sopenharmony_ci			ap->skb->rx_jumbo_skbuff[i].skb = NULL;
6898c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
6908c2ecf20Sopenharmony_ci		}
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	ace_init_cleanup(dev);
6948c2ecf20Sopenharmony_ci	free_netdev(dev);
6958c2ecf20Sopenharmony_ci}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_cistatic struct pci_driver acenic_pci_driver = {
6988c2ecf20Sopenharmony_ci	.name		= "acenic",
6998c2ecf20Sopenharmony_ci	.id_table	= acenic_pci_tbl,
7008c2ecf20Sopenharmony_ci	.probe		= acenic_probe_one,
7018c2ecf20Sopenharmony_ci	.remove		= acenic_remove_one,
7028c2ecf20Sopenharmony_ci};
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic void ace_free_descriptors(struct net_device *dev)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
7078c2ecf20Sopenharmony_ci	int size;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (ap->rx_std_ring != NULL) {
7108c2ecf20Sopenharmony_ci		size = (sizeof(struct rx_desc) *
7118c2ecf20Sopenharmony_ci			(RX_STD_RING_ENTRIES +
7128c2ecf20Sopenharmony_ci			 RX_JUMBO_RING_ENTRIES +
7138c2ecf20Sopenharmony_ci			 RX_MINI_RING_ENTRIES +
7148c2ecf20Sopenharmony_ci			 RX_RETURN_RING_ENTRIES));
7158c2ecf20Sopenharmony_ci		dma_free_coherent(&ap->pdev->dev, size, ap->rx_std_ring,
7168c2ecf20Sopenharmony_ci				  ap->rx_ring_base_dma);
7178c2ecf20Sopenharmony_ci		ap->rx_std_ring = NULL;
7188c2ecf20Sopenharmony_ci		ap->rx_jumbo_ring = NULL;
7198c2ecf20Sopenharmony_ci		ap->rx_mini_ring = NULL;
7208c2ecf20Sopenharmony_ci		ap->rx_return_ring = NULL;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci	if (ap->evt_ring != NULL) {
7238c2ecf20Sopenharmony_ci		size = (sizeof(struct event) * EVT_RING_ENTRIES);
7248c2ecf20Sopenharmony_ci		dma_free_coherent(&ap->pdev->dev, size, ap->evt_ring,
7258c2ecf20Sopenharmony_ci				  ap->evt_ring_dma);
7268c2ecf20Sopenharmony_ci		ap->evt_ring = NULL;
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci	if (ap->tx_ring != NULL && !ACE_IS_TIGON_I(ap)) {
7298c2ecf20Sopenharmony_ci		size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
7308c2ecf20Sopenharmony_ci		dma_free_coherent(&ap->pdev->dev, size, ap->tx_ring,
7318c2ecf20Sopenharmony_ci				  ap->tx_ring_dma);
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci	ap->tx_ring = NULL;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (ap->evt_prd != NULL) {
7368c2ecf20Sopenharmony_ci		dma_free_coherent(&ap->pdev->dev, sizeof(u32),
7378c2ecf20Sopenharmony_ci				  (void *)ap->evt_prd, ap->evt_prd_dma);
7388c2ecf20Sopenharmony_ci		ap->evt_prd = NULL;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci	if (ap->rx_ret_prd != NULL) {
7418c2ecf20Sopenharmony_ci		dma_free_coherent(&ap->pdev->dev, sizeof(u32),
7428c2ecf20Sopenharmony_ci				  (void *)ap->rx_ret_prd, ap->rx_ret_prd_dma);
7438c2ecf20Sopenharmony_ci		ap->rx_ret_prd = NULL;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci	if (ap->tx_csm != NULL) {
7468c2ecf20Sopenharmony_ci		dma_free_coherent(&ap->pdev->dev, sizeof(u32),
7478c2ecf20Sopenharmony_ci				  (void *)ap->tx_csm, ap->tx_csm_dma);
7488c2ecf20Sopenharmony_ci		ap->tx_csm = NULL;
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_cistatic int ace_allocate_descriptors(struct net_device *dev)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
7568c2ecf20Sopenharmony_ci	int size;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	size = (sizeof(struct rx_desc) *
7598c2ecf20Sopenharmony_ci		(RX_STD_RING_ENTRIES +
7608c2ecf20Sopenharmony_ci		 RX_JUMBO_RING_ENTRIES +
7618c2ecf20Sopenharmony_ci		 RX_MINI_RING_ENTRIES +
7628c2ecf20Sopenharmony_ci		 RX_RETURN_RING_ENTRIES));
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	ap->rx_std_ring = dma_alloc_coherent(&ap->pdev->dev, size,
7658c2ecf20Sopenharmony_ci					     &ap->rx_ring_base_dma, GFP_KERNEL);
7668c2ecf20Sopenharmony_ci	if (ap->rx_std_ring == NULL)
7678c2ecf20Sopenharmony_ci		goto fail;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	ap->rx_jumbo_ring = ap->rx_std_ring + RX_STD_RING_ENTRIES;
7708c2ecf20Sopenharmony_ci	ap->rx_mini_ring = ap->rx_jumbo_ring + RX_JUMBO_RING_ENTRIES;
7718c2ecf20Sopenharmony_ci	ap->rx_return_ring = ap->rx_mini_ring + RX_MINI_RING_ENTRIES;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	size = (sizeof(struct event) * EVT_RING_ENTRIES);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	ap->evt_ring = dma_alloc_coherent(&ap->pdev->dev, size,
7768c2ecf20Sopenharmony_ci					  &ap->evt_ring_dma, GFP_KERNEL);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (ap->evt_ring == NULL)
7798c2ecf20Sopenharmony_ci		goto fail;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/*
7828c2ecf20Sopenharmony_ci	 * Only allocate a host TX ring for the Tigon II, the Tigon I
7838c2ecf20Sopenharmony_ci	 * has to use PCI registers for this ;-(
7848c2ecf20Sopenharmony_ci	 */
7858c2ecf20Sopenharmony_ci	if (!ACE_IS_TIGON_I(ap)) {
7868c2ecf20Sopenharmony_ci		size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		ap->tx_ring = dma_alloc_coherent(&ap->pdev->dev, size,
7898c2ecf20Sopenharmony_ci						 &ap->tx_ring_dma, GFP_KERNEL);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		if (ap->tx_ring == NULL)
7928c2ecf20Sopenharmony_ci			goto fail;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	ap->evt_prd = dma_alloc_coherent(&ap->pdev->dev, sizeof(u32),
7968c2ecf20Sopenharmony_ci					 &ap->evt_prd_dma, GFP_KERNEL);
7978c2ecf20Sopenharmony_ci	if (ap->evt_prd == NULL)
7988c2ecf20Sopenharmony_ci		goto fail;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	ap->rx_ret_prd = dma_alloc_coherent(&ap->pdev->dev, sizeof(u32),
8018c2ecf20Sopenharmony_ci					    &ap->rx_ret_prd_dma, GFP_KERNEL);
8028c2ecf20Sopenharmony_ci	if (ap->rx_ret_prd == NULL)
8038c2ecf20Sopenharmony_ci		goto fail;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	ap->tx_csm = dma_alloc_coherent(&ap->pdev->dev, sizeof(u32),
8068c2ecf20Sopenharmony_ci					&ap->tx_csm_dma, GFP_KERNEL);
8078c2ecf20Sopenharmony_ci	if (ap->tx_csm == NULL)
8088c2ecf20Sopenharmony_ci		goto fail;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cifail:
8138c2ecf20Sopenharmony_ci	/* Clean up. */
8148c2ecf20Sopenharmony_ci	ace_init_cleanup(dev);
8158c2ecf20Sopenharmony_ci	return 1;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci/*
8208c2ecf20Sopenharmony_ci * Generic cleanup handling data allocated during init. Used when the
8218c2ecf20Sopenharmony_ci * module is unloaded or if an error occurs during initialization
8228c2ecf20Sopenharmony_ci */
8238c2ecf20Sopenharmony_cistatic void ace_init_cleanup(struct net_device *dev)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct ace_private *ap;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	ap = netdev_priv(dev);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	ace_free_descriptors(dev);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if (ap->info)
8328c2ecf20Sopenharmony_ci		dma_free_coherent(&ap->pdev->dev, sizeof(struct ace_info),
8338c2ecf20Sopenharmony_ci				  ap->info, ap->info_dma);
8348c2ecf20Sopenharmony_ci	kfree(ap->skb);
8358c2ecf20Sopenharmony_ci	kfree(ap->trace_buf);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (dev->irq)
8388c2ecf20Sopenharmony_ci		free_irq(dev->irq, dev);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	iounmap(ap->regs);
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci/*
8458c2ecf20Sopenharmony_ci * Commands are considered to be slow.
8468c2ecf20Sopenharmony_ci */
8478c2ecf20Sopenharmony_cistatic inline void ace_issue_cmd(struct ace_regs __iomem *regs, struct cmd *cmd)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	u32 idx;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	idx = readl(&regs->CmdPrd);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	writel(*(u32 *)(cmd), &regs->CmdRng[idx]);
8548c2ecf20Sopenharmony_ci	idx = (idx + 1) % CMD_RING_ENTRIES;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	writel(idx, &regs->CmdPrd);
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_cistatic int ace_init(struct net_device *dev)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct ace_private *ap;
8638c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs;
8648c2ecf20Sopenharmony_ci	struct ace_info *info = NULL;
8658c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
8668c2ecf20Sopenharmony_ci	unsigned long myjif;
8678c2ecf20Sopenharmony_ci	u64 tmp_ptr;
8688c2ecf20Sopenharmony_ci	u32 tig_ver, mac1, mac2, tmp, pci_state;
8698c2ecf20Sopenharmony_ci	int board_idx, ecode = 0;
8708c2ecf20Sopenharmony_ci	short i;
8718c2ecf20Sopenharmony_ci	unsigned char cache_size;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	ap = netdev_priv(dev);
8748c2ecf20Sopenharmony_ci	regs = ap->regs;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	board_idx = ap->board_idx;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/*
8798c2ecf20Sopenharmony_ci	 * aman@sgi.com - its useful to do a NIC reset here to
8808c2ecf20Sopenharmony_ci	 * address the `Firmware not running' problem subsequent
8818c2ecf20Sopenharmony_ci	 * to any crashes involving the NIC
8828c2ecf20Sopenharmony_ci	 */
8838c2ecf20Sopenharmony_ci	writel(HW_RESET | (HW_RESET << 24), &regs->HostCtrl);
8848c2ecf20Sopenharmony_ci	readl(&regs->HostCtrl);		/* PCI write posting */
8858c2ecf20Sopenharmony_ci	udelay(5);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	/*
8888c2ecf20Sopenharmony_ci	 * Don't access any other registers before this point!
8898c2ecf20Sopenharmony_ci	 */
8908c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
8918c2ecf20Sopenharmony_ci	/*
8928c2ecf20Sopenharmony_ci	 * This will most likely need BYTE_SWAP once we switch
8938c2ecf20Sopenharmony_ci	 * to using __raw_writel()
8948c2ecf20Sopenharmony_ci	 */
8958c2ecf20Sopenharmony_ci	writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)),
8968c2ecf20Sopenharmony_ci	       &regs->HostCtrl);
8978c2ecf20Sopenharmony_ci#else
8988c2ecf20Sopenharmony_ci	writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
8998c2ecf20Sopenharmony_ci	       &regs->HostCtrl);
9008c2ecf20Sopenharmony_ci#endif
9018c2ecf20Sopenharmony_ci	readl(&regs->HostCtrl);		/* PCI write posting */
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	/*
9048c2ecf20Sopenharmony_ci	 * Stop the NIC CPU and clear pending interrupts
9058c2ecf20Sopenharmony_ci	 */
9068c2ecf20Sopenharmony_ci	writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
9078c2ecf20Sopenharmony_ci	readl(&regs->CpuCtrl);		/* PCI write posting */
9088c2ecf20Sopenharmony_ci	writel(0, &regs->Mb0Lo);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	tig_ver = readl(&regs->HostCtrl) >> 28;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	switch(tig_ver){
9138c2ecf20Sopenharmony_ci#ifndef CONFIG_ACENIC_OMIT_TIGON_I
9148c2ecf20Sopenharmony_ci	case 4:
9158c2ecf20Sopenharmony_ci	case 5:
9168c2ecf20Sopenharmony_ci		printk(KERN_INFO "  Tigon I  (Rev. %i), Firmware: %i.%i.%i, ",
9178c2ecf20Sopenharmony_ci		       tig_ver, ap->firmware_major, ap->firmware_minor,
9188c2ecf20Sopenharmony_ci		       ap->firmware_fix);
9198c2ecf20Sopenharmony_ci		writel(0, &regs->LocalCtrl);
9208c2ecf20Sopenharmony_ci		ap->version = 1;
9218c2ecf20Sopenharmony_ci		ap->tx_ring_entries = TIGON_I_TX_RING_ENTRIES;
9228c2ecf20Sopenharmony_ci		break;
9238c2ecf20Sopenharmony_ci#endif
9248c2ecf20Sopenharmony_ci	case 6:
9258c2ecf20Sopenharmony_ci		printk(KERN_INFO "  Tigon II (Rev. %i), Firmware: %i.%i.%i, ",
9268c2ecf20Sopenharmony_ci		       tig_ver, ap->firmware_major, ap->firmware_minor,
9278c2ecf20Sopenharmony_ci		       ap->firmware_fix);
9288c2ecf20Sopenharmony_ci		writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
9298c2ecf20Sopenharmony_ci		readl(&regs->CpuBCtrl);		/* PCI write posting */
9308c2ecf20Sopenharmony_ci		/*
9318c2ecf20Sopenharmony_ci		 * The SRAM bank size does _not_ indicate the amount
9328c2ecf20Sopenharmony_ci		 * of memory on the card, it controls the _bank_ size!
9338c2ecf20Sopenharmony_ci		 * Ie. a 1MB AceNIC will have two banks of 512KB.
9348c2ecf20Sopenharmony_ci		 */
9358c2ecf20Sopenharmony_ci		writel(SRAM_BANK_512K, &regs->LocalCtrl);
9368c2ecf20Sopenharmony_ci		writel(SYNC_SRAM_TIMING, &regs->MiscCfg);
9378c2ecf20Sopenharmony_ci		ap->version = 2;
9388c2ecf20Sopenharmony_ci		ap->tx_ring_entries = MAX_TX_RING_ENTRIES;
9398c2ecf20Sopenharmony_ci		break;
9408c2ecf20Sopenharmony_ci	default:
9418c2ecf20Sopenharmony_ci		printk(KERN_WARNING "  Unsupported Tigon version detected "
9428c2ecf20Sopenharmony_ci		       "(%i)\n", tig_ver);
9438c2ecf20Sopenharmony_ci		ecode = -ENODEV;
9448c2ecf20Sopenharmony_ci		goto init_error;
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/*
9488c2ecf20Sopenharmony_ci	 * ModeStat _must_ be set after the SRAM settings as this change
9498c2ecf20Sopenharmony_ci	 * seems to corrupt the ModeStat and possible other registers.
9508c2ecf20Sopenharmony_ci	 * The SRAM settings survive resets and setting it to the same
9518c2ecf20Sopenharmony_ci	 * value a second time works as well. This is what caused the
9528c2ecf20Sopenharmony_ci	 * `Firmware not running' problem on the Tigon II.
9538c2ecf20Sopenharmony_ci	 */
9548c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
9558c2ecf20Sopenharmony_ci	writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL | ACE_BYTE_SWAP_BD |
9568c2ecf20Sopenharmony_ci	       ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
9578c2ecf20Sopenharmony_ci#else
9588c2ecf20Sopenharmony_ci	writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL |
9598c2ecf20Sopenharmony_ci	       ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
9608c2ecf20Sopenharmony_ci#endif
9618c2ecf20Sopenharmony_ci	readl(&regs->ModeStat);		/* PCI write posting */
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	mac1 = 0;
9648c2ecf20Sopenharmony_ci	for(i = 0; i < 4; i++) {
9658c2ecf20Sopenharmony_ci		int t;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		mac1 = mac1 << 8;
9688c2ecf20Sopenharmony_ci		t = read_eeprom_byte(dev, 0x8c+i);
9698c2ecf20Sopenharmony_ci		if (t < 0) {
9708c2ecf20Sopenharmony_ci			ecode = -EIO;
9718c2ecf20Sopenharmony_ci			goto init_error;
9728c2ecf20Sopenharmony_ci		} else
9738c2ecf20Sopenharmony_ci			mac1 |= (t & 0xff);
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci	mac2 = 0;
9768c2ecf20Sopenharmony_ci	for(i = 4; i < 8; i++) {
9778c2ecf20Sopenharmony_ci		int t;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci		mac2 = mac2 << 8;
9808c2ecf20Sopenharmony_ci		t = read_eeprom_byte(dev, 0x8c+i);
9818c2ecf20Sopenharmony_ci		if (t < 0) {
9828c2ecf20Sopenharmony_ci			ecode = -EIO;
9838c2ecf20Sopenharmony_ci			goto init_error;
9848c2ecf20Sopenharmony_ci		} else
9858c2ecf20Sopenharmony_ci			mac2 |= (t & 0xff);
9868c2ecf20Sopenharmony_ci	}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	writel(mac1, &regs->MacAddrHi);
9898c2ecf20Sopenharmony_ci	writel(mac2, &regs->MacAddrLo);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	dev->dev_addr[0] = (mac1 >> 8) & 0xff;
9928c2ecf20Sopenharmony_ci	dev->dev_addr[1] = mac1 & 0xff;
9938c2ecf20Sopenharmony_ci	dev->dev_addr[2] = (mac2 >> 24) & 0xff;
9948c2ecf20Sopenharmony_ci	dev->dev_addr[3] = (mac2 >> 16) & 0xff;
9958c2ecf20Sopenharmony_ci	dev->dev_addr[4] = (mac2 >> 8) & 0xff;
9968c2ecf20Sopenharmony_ci	dev->dev_addr[5] = mac2 & 0xff;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	printk("MAC: %pM\n", dev->dev_addr);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	/*
10018c2ecf20Sopenharmony_ci	 * Looks like this is necessary to deal with on all architectures,
10028c2ecf20Sopenharmony_ci	 * even this %$#%$# N440BX Intel based thing doesn't get it right.
10038c2ecf20Sopenharmony_ci	 * Ie. having two NICs in the machine, one will have the cache
10048c2ecf20Sopenharmony_ci	 * line set at boot time, the other will not.
10058c2ecf20Sopenharmony_ci	 */
10068c2ecf20Sopenharmony_ci	pdev = ap->pdev;
10078c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_size);
10088c2ecf20Sopenharmony_ci	cache_size <<= 2;
10098c2ecf20Sopenharmony_ci	if (cache_size != SMP_CACHE_BYTES) {
10108c2ecf20Sopenharmony_ci		printk(KERN_INFO "  PCI cache line size set incorrectly "
10118c2ecf20Sopenharmony_ci		       "(%i bytes) by BIOS/FW, ", cache_size);
10128c2ecf20Sopenharmony_ci		if (cache_size > SMP_CACHE_BYTES)
10138c2ecf20Sopenharmony_ci			printk("expecting %i\n", SMP_CACHE_BYTES);
10148c2ecf20Sopenharmony_ci		else {
10158c2ecf20Sopenharmony_ci			printk("correcting to %i\n", SMP_CACHE_BYTES);
10168c2ecf20Sopenharmony_ci			pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
10178c2ecf20Sopenharmony_ci					      SMP_CACHE_BYTES >> 2);
10188c2ecf20Sopenharmony_ci		}
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	pci_state = readl(&regs->PciState);
10228c2ecf20Sopenharmony_ci	printk(KERN_INFO "  PCI bus width: %i bits, speed: %iMHz, "
10238c2ecf20Sopenharmony_ci	       "latency: %i clks\n",
10248c2ecf20Sopenharmony_ci	       	(pci_state & PCI_32BIT) ? 32 : 64,
10258c2ecf20Sopenharmony_ci		(pci_state & PCI_66MHZ) ? 66 : 33,
10268c2ecf20Sopenharmony_ci		ap->pci_latency);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	/*
10298c2ecf20Sopenharmony_ci	 * Set the max DMA transfer size. Seems that for most systems
10308c2ecf20Sopenharmony_ci	 * the performance is better when no MAX parameter is
10318c2ecf20Sopenharmony_ci	 * set. However for systems enabling PCI write and invalidate,
10328c2ecf20Sopenharmony_ci	 * DMA writes must be set to the L1 cache line size to get
10338c2ecf20Sopenharmony_ci	 * optimal performance.
10348c2ecf20Sopenharmony_ci	 *
10358c2ecf20Sopenharmony_ci	 * The default is now to turn the PCI write and invalidate off
10368c2ecf20Sopenharmony_ci	 * - that is what Alteon does for NT.
10378c2ecf20Sopenharmony_ci	 */
10388c2ecf20Sopenharmony_ci	tmp = READ_CMD_MEM | WRITE_CMD_MEM;
10398c2ecf20Sopenharmony_ci	if (ap->version >= 2) {
10408c2ecf20Sopenharmony_ci		tmp |= (MEM_READ_MULTIPLE | (pci_state & PCI_66MHZ));
10418c2ecf20Sopenharmony_ci		/*
10428c2ecf20Sopenharmony_ci		 * Tuning parameters only supported for 8 cards
10438c2ecf20Sopenharmony_ci		 */
10448c2ecf20Sopenharmony_ci		if (board_idx == BOARD_IDX_OVERFLOW ||
10458c2ecf20Sopenharmony_ci		    dis_pci_mem_inval[board_idx]) {
10468c2ecf20Sopenharmony_ci			if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
10478c2ecf20Sopenharmony_ci				ap->pci_command &= ~PCI_COMMAND_INVALIDATE;
10488c2ecf20Sopenharmony_ci				pci_write_config_word(pdev, PCI_COMMAND,
10498c2ecf20Sopenharmony_ci						      ap->pci_command);
10508c2ecf20Sopenharmony_ci				printk(KERN_INFO "  Disabling PCI memory "
10518c2ecf20Sopenharmony_ci				       "write and invalidate\n");
10528c2ecf20Sopenharmony_ci			}
10538c2ecf20Sopenharmony_ci		} else if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
10548c2ecf20Sopenharmony_ci			printk(KERN_INFO "  PCI memory write & invalidate "
10558c2ecf20Sopenharmony_ci			       "enabled by BIOS, enabling counter measures\n");
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci			switch(SMP_CACHE_BYTES) {
10588c2ecf20Sopenharmony_ci			case 16:
10598c2ecf20Sopenharmony_ci				tmp |= DMA_WRITE_MAX_16;
10608c2ecf20Sopenharmony_ci				break;
10618c2ecf20Sopenharmony_ci			case 32:
10628c2ecf20Sopenharmony_ci				tmp |= DMA_WRITE_MAX_32;
10638c2ecf20Sopenharmony_ci				break;
10648c2ecf20Sopenharmony_ci			case 64:
10658c2ecf20Sopenharmony_ci				tmp |= DMA_WRITE_MAX_64;
10668c2ecf20Sopenharmony_ci				break;
10678c2ecf20Sopenharmony_ci			case 128:
10688c2ecf20Sopenharmony_ci				tmp |= DMA_WRITE_MAX_128;
10698c2ecf20Sopenharmony_ci				break;
10708c2ecf20Sopenharmony_ci			default:
10718c2ecf20Sopenharmony_ci				printk(KERN_INFO "  Cache line size %i not "
10728c2ecf20Sopenharmony_ci				       "supported, PCI write and invalidate "
10738c2ecf20Sopenharmony_ci				       "disabled\n", SMP_CACHE_BYTES);
10748c2ecf20Sopenharmony_ci				ap->pci_command &= ~PCI_COMMAND_INVALIDATE;
10758c2ecf20Sopenharmony_ci				pci_write_config_word(pdev, PCI_COMMAND,
10768c2ecf20Sopenharmony_ci						      ap->pci_command);
10778c2ecf20Sopenharmony_ci			}
10788c2ecf20Sopenharmony_ci		}
10798c2ecf20Sopenharmony_ci	}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci#ifdef __sparc__
10828c2ecf20Sopenharmony_ci	/*
10838c2ecf20Sopenharmony_ci	 * On this platform, we know what the best dma settings
10848c2ecf20Sopenharmony_ci	 * are.  We use 64-byte maximum bursts, because if we
10858c2ecf20Sopenharmony_ci	 * burst larger than the cache line size (or even cross
10868c2ecf20Sopenharmony_ci	 * a 64byte boundary in a single burst) the UltraSparc
10878c2ecf20Sopenharmony_ci	 * PCI controller will disconnect at 64-byte multiples.
10888c2ecf20Sopenharmony_ci	 *
10898c2ecf20Sopenharmony_ci	 * Read-multiple will be properly enabled above, and when
10908c2ecf20Sopenharmony_ci	 * set will give the PCI controller proper hints about
10918c2ecf20Sopenharmony_ci	 * prefetching.
10928c2ecf20Sopenharmony_ci	 */
10938c2ecf20Sopenharmony_ci	tmp &= ~DMA_READ_WRITE_MASK;
10948c2ecf20Sopenharmony_ci	tmp |= DMA_READ_MAX_64;
10958c2ecf20Sopenharmony_ci	tmp |= DMA_WRITE_MAX_64;
10968c2ecf20Sopenharmony_ci#endif
10978c2ecf20Sopenharmony_ci#ifdef __alpha__
10988c2ecf20Sopenharmony_ci	tmp &= ~DMA_READ_WRITE_MASK;
10998c2ecf20Sopenharmony_ci	tmp |= DMA_READ_MAX_128;
11008c2ecf20Sopenharmony_ci	/*
11018c2ecf20Sopenharmony_ci	 * All the docs say MUST NOT. Well, I did.
11028c2ecf20Sopenharmony_ci	 * Nothing terrible happens, if we load wrong size.
11038c2ecf20Sopenharmony_ci	 * Bit w&i still works better!
11048c2ecf20Sopenharmony_ci	 */
11058c2ecf20Sopenharmony_ci	tmp |= DMA_WRITE_MAX_128;
11068c2ecf20Sopenharmony_ci#endif
11078c2ecf20Sopenharmony_ci	writel(tmp, &regs->PciState);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci#if 0
11108c2ecf20Sopenharmony_ci	/*
11118c2ecf20Sopenharmony_ci	 * The Host PCI bus controller driver has to set FBB.
11128c2ecf20Sopenharmony_ci	 * If all devices on that PCI bus support FBB, then the controller
11138c2ecf20Sopenharmony_ci	 * can enable FBB support in the Host PCI Bus controller (or on
11148c2ecf20Sopenharmony_ci	 * the PCI-PCI bridge if that applies).
11158c2ecf20Sopenharmony_ci	 * -ggg
11168c2ecf20Sopenharmony_ci	 */
11178c2ecf20Sopenharmony_ci	/*
11188c2ecf20Sopenharmony_ci	 * I have received reports from people having problems when this
11198c2ecf20Sopenharmony_ci	 * bit is enabled.
11208c2ecf20Sopenharmony_ci	 */
11218c2ecf20Sopenharmony_ci	if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) {
11228c2ecf20Sopenharmony_ci		printk(KERN_INFO "  Enabling PCI Fast Back to Back\n");
11238c2ecf20Sopenharmony_ci		ap->pci_command |= PCI_COMMAND_FAST_BACK;
11248c2ecf20Sopenharmony_ci		pci_write_config_word(pdev, PCI_COMMAND, ap->pci_command);
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci#endif
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	/*
11298c2ecf20Sopenharmony_ci	 * Configure DMA attributes.
11308c2ecf20Sopenharmony_ci	 */
11318c2ecf20Sopenharmony_ci	if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
11328c2ecf20Sopenharmony_ci		ap->pci_using_dac = 1;
11338c2ecf20Sopenharmony_ci	} else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
11348c2ecf20Sopenharmony_ci		ap->pci_using_dac = 0;
11358c2ecf20Sopenharmony_ci	} else {
11368c2ecf20Sopenharmony_ci		ecode = -ENODEV;
11378c2ecf20Sopenharmony_ci		goto init_error;
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	/*
11418c2ecf20Sopenharmony_ci	 * Initialize the generic info block and the command+event rings
11428c2ecf20Sopenharmony_ci	 * and the control blocks for the transmit and receive rings
11438c2ecf20Sopenharmony_ci	 * as they need to be setup once and for all.
11448c2ecf20Sopenharmony_ci	 */
11458c2ecf20Sopenharmony_ci	if (!(info = dma_alloc_coherent(&ap->pdev->dev, sizeof(struct ace_info),
11468c2ecf20Sopenharmony_ci					&ap->info_dma, GFP_KERNEL))) {
11478c2ecf20Sopenharmony_ci		ecode = -EAGAIN;
11488c2ecf20Sopenharmony_ci		goto init_error;
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci	ap->info = info;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	/*
11538c2ecf20Sopenharmony_ci	 * Get the memory for the skb rings.
11548c2ecf20Sopenharmony_ci	 */
11558c2ecf20Sopenharmony_ci	if (!(ap->skb = kzalloc(sizeof(struct ace_skb), GFP_KERNEL))) {
11568c2ecf20Sopenharmony_ci		ecode = -EAGAIN;
11578c2ecf20Sopenharmony_ci		goto init_error;
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	ecode = request_irq(pdev->irq, ace_interrupt, IRQF_SHARED,
11618c2ecf20Sopenharmony_ci			    DRV_NAME, dev);
11628c2ecf20Sopenharmony_ci	if (ecode) {
11638c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
11648c2ecf20Sopenharmony_ci		       DRV_NAME, pdev->irq);
11658c2ecf20Sopenharmony_ci		goto init_error;
11668c2ecf20Sopenharmony_ci	} else
11678c2ecf20Sopenharmony_ci		dev->irq = pdev->irq;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci#ifdef INDEX_DEBUG
11708c2ecf20Sopenharmony_ci	spin_lock_init(&ap->debug_lock);
11718c2ecf20Sopenharmony_ci	ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1;
11728c2ecf20Sopenharmony_ci	ap->last_std_rx = 0;
11738c2ecf20Sopenharmony_ci	ap->last_mini_rx = 0;
11748c2ecf20Sopenharmony_ci#endif
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	ecode = ace_load_firmware(dev);
11778c2ecf20Sopenharmony_ci	if (ecode)
11788c2ecf20Sopenharmony_ci		goto init_error;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	ap->fw_running = 0;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	tmp_ptr = ap->info_dma;
11838c2ecf20Sopenharmony_ci	writel(tmp_ptr >> 32, &regs->InfoPtrHi);
11848c2ecf20Sopenharmony_ci	writel(tmp_ptr & 0xffffffff, &regs->InfoPtrLo);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event));
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma);
11898c2ecf20Sopenharmony_ci	info->evt_ctrl.flags = 0;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	*(ap->evt_prd) = 0;
11928c2ecf20Sopenharmony_ci	wmb();
11938c2ecf20Sopenharmony_ci	set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma);
11948c2ecf20Sopenharmony_ci	writel(0, &regs->EvtCsm);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	set_aceaddr(&info->cmd_ctrl.rngptr, 0x100);
11978c2ecf20Sopenharmony_ci	info->cmd_ctrl.flags = 0;
11988c2ecf20Sopenharmony_ci	info->cmd_ctrl.max_len = 0;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	for (i = 0; i < CMD_RING_ENTRIES; i++)
12018c2ecf20Sopenharmony_ci		writel(0, &regs->CmdRng[i]);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	writel(0, &regs->CmdPrd);
12048c2ecf20Sopenharmony_ci	writel(0, &regs->CmdCsm);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	tmp_ptr = ap->info_dma;
12078c2ecf20Sopenharmony_ci	tmp_ptr += (unsigned long) &(((struct ace_info *)0)->s.stats);
12088c2ecf20Sopenharmony_ci	set_aceaddr(&info->stats2_ptr, (dma_addr_t) tmp_ptr);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma);
12118c2ecf20Sopenharmony_ci	info->rx_std_ctrl.max_len = ACE_STD_BUFSIZE;
12128c2ecf20Sopenharmony_ci	info->rx_std_ctrl.flags =
12138c2ecf20Sopenharmony_ci	  RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | RCB_FLG_VLAN_ASSIST;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	memset(ap->rx_std_ring, 0,
12168c2ecf20Sopenharmony_ci	       RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	for (i = 0; i < RX_STD_RING_ENTRIES; i++)
12198c2ecf20Sopenharmony_ci		ap->rx_std_ring[i].flags = BD_FLG_TCP_UDP_SUM;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	ap->rx_std_skbprd = 0;
12228c2ecf20Sopenharmony_ci	atomic_set(&ap->cur_rx_bufs, 0);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	set_aceaddr(&info->rx_jumbo_ctrl.rngptr,
12258c2ecf20Sopenharmony_ci		    (ap->rx_ring_base_dma +
12268c2ecf20Sopenharmony_ci		     (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES)));
12278c2ecf20Sopenharmony_ci	info->rx_jumbo_ctrl.max_len = 0;
12288c2ecf20Sopenharmony_ci	info->rx_jumbo_ctrl.flags =
12298c2ecf20Sopenharmony_ci	  RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | RCB_FLG_VLAN_ASSIST;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	memset(ap->rx_jumbo_ring, 0,
12328c2ecf20Sopenharmony_ci	       RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++)
12358c2ecf20Sopenharmony_ci		ap->rx_jumbo_ring[i].flags = BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	ap->rx_jumbo_skbprd = 0;
12388c2ecf20Sopenharmony_ci	atomic_set(&ap->cur_jumbo_bufs, 0);
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	memset(ap->rx_mini_ring, 0,
12418c2ecf20Sopenharmony_ci	       RX_MINI_RING_ENTRIES * sizeof(struct rx_desc));
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	if (ap->version >= 2) {
12448c2ecf20Sopenharmony_ci		set_aceaddr(&info->rx_mini_ctrl.rngptr,
12458c2ecf20Sopenharmony_ci			    (ap->rx_ring_base_dma +
12468c2ecf20Sopenharmony_ci			     (sizeof(struct rx_desc) *
12478c2ecf20Sopenharmony_ci			      (RX_STD_RING_ENTRIES +
12488c2ecf20Sopenharmony_ci			       RX_JUMBO_RING_ENTRIES))));
12498c2ecf20Sopenharmony_ci		info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
12508c2ecf20Sopenharmony_ci		info->rx_mini_ctrl.flags =
12518c2ecf20Sopenharmony_ci		  RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_VLAN_ASSIST;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci		for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
12548c2ecf20Sopenharmony_ci			ap->rx_mini_ring[i].flags =
12558c2ecf20Sopenharmony_ci				BD_FLG_TCP_UDP_SUM | BD_FLG_MINI;
12568c2ecf20Sopenharmony_ci	} else {
12578c2ecf20Sopenharmony_ci		set_aceaddr(&info->rx_mini_ctrl.rngptr, 0);
12588c2ecf20Sopenharmony_ci		info->rx_mini_ctrl.flags = RCB_FLG_RNG_DISABLE;
12598c2ecf20Sopenharmony_ci		info->rx_mini_ctrl.max_len = 0;
12608c2ecf20Sopenharmony_ci	}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	ap->rx_mini_skbprd = 0;
12638c2ecf20Sopenharmony_ci	atomic_set(&ap->cur_mini_bufs, 0);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	set_aceaddr(&info->rx_return_ctrl.rngptr,
12668c2ecf20Sopenharmony_ci		    (ap->rx_ring_base_dma +
12678c2ecf20Sopenharmony_ci		     (sizeof(struct rx_desc) *
12688c2ecf20Sopenharmony_ci		      (RX_STD_RING_ENTRIES +
12698c2ecf20Sopenharmony_ci		       RX_JUMBO_RING_ENTRIES +
12708c2ecf20Sopenharmony_ci		       RX_MINI_RING_ENTRIES))));
12718c2ecf20Sopenharmony_ci	info->rx_return_ctrl.flags = 0;
12728c2ecf20Sopenharmony_ci	info->rx_return_ctrl.max_len = RX_RETURN_RING_ENTRIES;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	memset(ap->rx_return_ring, 0,
12758c2ecf20Sopenharmony_ci	       RX_RETURN_RING_ENTRIES * sizeof(struct rx_desc));
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	set_aceaddr(&info->rx_ret_prd_ptr, ap->rx_ret_prd_dma);
12788c2ecf20Sopenharmony_ci	*(ap->rx_ret_prd) = 0;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	writel(TX_RING_BASE, &regs->WinBase);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	if (ACE_IS_TIGON_I(ap)) {
12838c2ecf20Sopenharmony_ci		ap->tx_ring = (__force struct tx_desc *) regs->Window;
12848c2ecf20Sopenharmony_ci		for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
12858c2ecf20Sopenharmony_ci				 * sizeof(struct tx_desc)) / sizeof(u32); i++)
12868c2ecf20Sopenharmony_ci			writel(0, (__force void __iomem *)ap->tx_ring  + i * 4);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci		set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
12898c2ecf20Sopenharmony_ci	} else {
12908c2ecf20Sopenharmony_ci		memset(ap->tx_ring, 0,
12918c2ecf20Sopenharmony_ci		       MAX_TX_RING_ENTRIES * sizeof(struct tx_desc));
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci		set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma);
12948c2ecf20Sopenharmony_ci	}
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap);
12978c2ecf20Sopenharmony_ci	tmp = RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | RCB_FLG_VLAN_ASSIST;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	/*
13008c2ecf20Sopenharmony_ci	 * The Tigon I does not like having the TX ring in host memory ;-(
13018c2ecf20Sopenharmony_ci	 */
13028c2ecf20Sopenharmony_ci	if (!ACE_IS_TIGON_I(ap))
13038c2ecf20Sopenharmony_ci		tmp |= RCB_FLG_TX_HOST_RING;
13048c2ecf20Sopenharmony_ci#if TX_COAL_INTS_ONLY
13058c2ecf20Sopenharmony_ci	tmp |= RCB_FLG_COAL_INT_ONLY;
13068c2ecf20Sopenharmony_ci#endif
13078c2ecf20Sopenharmony_ci	info->tx_ctrl.flags = tmp;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma);
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	/*
13128c2ecf20Sopenharmony_ci	 * Potential item for tuning parameter
13138c2ecf20Sopenharmony_ci	 */
13148c2ecf20Sopenharmony_ci#if 0 /* NO */
13158c2ecf20Sopenharmony_ci	writel(DMA_THRESH_16W, &regs->DmaReadCfg);
13168c2ecf20Sopenharmony_ci	writel(DMA_THRESH_16W, &regs->DmaWriteCfg);
13178c2ecf20Sopenharmony_ci#else
13188c2ecf20Sopenharmony_ci	writel(DMA_THRESH_8W, &regs->DmaReadCfg);
13198c2ecf20Sopenharmony_ci	writel(DMA_THRESH_8W, &regs->DmaWriteCfg);
13208c2ecf20Sopenharmony_ci#endif
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	writel(0, &regs->MaskInt);
13238c2ecf20Sopenharmony_ci	writel(1, &regs->IfIdx);
13248c2ecf20Sopenharmony_ci#if 0
13258c2ecf20Sopenharmony_ci	/*
13268c2ecf20Sopenharmony_ci	 * McKinley boxes do not like us fiddling with AssistState
13278c2ecf20Sopenharmony_ci	 * this early
13288c2ecf20Sopenharmony_ci	 */
13298c2ecf20Sopenharmony_ci	writel(1, &regs->AssistState);
13308c2ecf20Sopenharmony_ci#endif
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	writel(DEF_STAT, &regs->TuneStatTicks);
13338c2ecf20Sopenharmony_ci	writel(DEF_TRACE, &regs->TuneTrace);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	ace_set_rxtx_parms(dev, 0);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	if (board_idx == BOARD_IDX_OVERFLOW) {
13388c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: more than %i NICs detected, "
13398c2ecf20Sopenharmony_ci		       "ignoring module parameters!\n",
13408c2ecf20Sopenharmony_ci		       ap->name, ACE_MAX_MOD_PARMS);
13418c2ecf20Sopenharmony_ci	} else if (board_idx >= 0) {
13428c2ecf20Sopenharmony_ci		if (tx_coal_tick[board_idx])
13438c2ecf20Sopenharmony_ci			writel(tx_coal_tick[board_idx],
13448c2ecf20Sopenharmony_ci			       &regs->TuneTxCoalTicks);
13458c2ecf20Sopenharmony_ci		if (max_tx_desc[board_idx])
13468c2ecf20Sopenharmony_ci			writel(max_tx_desc[board_idx], &regs->TuneMaxTxDesc);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		if (rx_coal_tick[board_idx])
13498c2ecf20Sopenharmony_ci			writel(rx_coal_tick[board_idx],
13508c2ecf20Sopenharmony_ci			       &regs->TuneRxCoalTicks);
13518c2ecf20Sopenharmony_ci		if (max_rx_desc[board_idx])
13528c2ecf20Sopenharmony_ci			writel(max_rx_desc[board_idx], &regs->TuneMaxRxDesc);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci		if (trace[board_idx])
13558c2ecf20Sopenharmony_ci			writel(trace[board_idx], &regs->TuneTrace);
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci		if ((tx_ratio[board_idx] > 0) && (tx_ratio[board_idx] < 64))
13588c2ecf20Sopenharmony_ci			writel(tx_ratio[board_idx], &regs->TxBufRat);
13598c2ecf20Sopenharmony_ci	}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	/*
13628c2ecf20Sopenharmony_ci	 * Default link parameters
13638c2ecf20Sopenharmony_ci	 */
13648c2ecf20Sopenharmony_ci	tmp = LNK_ENABLE | LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB |
13658c2ecf20Sopenharmony_ci		LNK_10MB | LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE;
13668c2ecf20Sopenharmony_ci	if(ap->version >= 2)
13678c2ecf20Sopenharmony_ci		tmp |= LNK_TX_FLOW_CTL_Y;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	/*
13708c2ecf20Sopenharmony_ci	 * Override link default parameters
13718c2ecf20Sopenharmony_ci	 */
13728c2ecf20Sopenharmony_ci	if ((board_idx >= 0) && link_state[board_idx]) {
13738c2ecf20Sopenharmony_ci		int option = link_state[board_idx];
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		tmp = LNK_ENABLE;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci		if (option & 0x01) {
13788c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Setting half duplex link\n",
13798c2ecf20Sopenharmony_ci			       ap->name);
13808c2ecf20Sopenharmony_ci			tmp &= ~LNK_FULL_DUPLEX;
13818c2ecf20Sopenharmony_ci		}
13828c2ecf20Sopenharmony_ci		if (option & 0x02)
13838c2ecf20Sopenharmony_ci			tmp &= ~LNK_NEGOTIATE;
13848c2ecf20Sopenharmony_ci		if (option & 0x10)
13858c2ecf20Sopenharmony_ci			tmp |= LNK_10MB;
13868c2ecf20Sopenharmony_ci		if (option & 0x20)
13878c2ecf20Sopenharmony_ci			tmp |= LNK_100MB;
13888c2ecf20Sopenharmony_ci		if (option & 0x40)
13898c2ecf20Sopenharmony_ci			tmp |= LNK_1000MB;
13908c2ecf20Sopenharmony_ci		if ((option & 0x70) == 0) {
13918c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: No media speed specified, "
13928c2ecf20Sopenharmony_ci			       "forcing auto negotiation\n", ap->name);
13938c2ecf20Sopenharmony_ci			tmp |= LNK_NEGOTIATE | LNK_1000MB |
13948c2ecf20Sopenharmony_ci				LNK_100MB | LNK_10MB;
13958c2ecf20Sopenharmony_ci		}
13968c2ecf20Sopenharmony_ci		if ((option & 0x100) == 0)
13978c2ecf20Sopenharmony_ci			tmp |= LNK_NEG_FCTL;
13988c2ecf20Sopenharmony_ci		else
13998c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Disabling flow control "
14008c2ecf20Sopenharmony_ci			       "negotiation\n", ap->name);
14018c2ecf20Sopenharmony_ci		if (option & 0x200)
14028c2ecf20Sopenharmony_ci			tmp |= LNK_RX_FLOW_CTL_Y;
14038c2ecf20Sopenharmony_ci		if ((option & 0x400) && (ap->version >= 2)) {
14048c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Enabling TX flow control\n",
14058c2ecf20Sopenharmony_ci			       ap->name);
14068c2ecf20Sopenharmony_ci			tmp |= LNK_TX_FLOW_CTL_Y;
14078c2ecf20Sopenharmony_ci		}
14088c2ecf20Sopenharmony_ci	}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	ap->link = tmp;
14118c2ecf20Sopenharmony_ci	writel(tmp, &regs->TuneLink);
14128c2ecf20Sopenharmony_ci	if (ap->version >= 2)
14138c2ecf20Sopenharmony_ci		writel(tmp, &regs->TuneFastLink);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	writel(ap->firmware_start, &regs->Pc);
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	writel(0, &regs->Mb0Lo);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	/*
14208c2ecf20Sopenharmony_ci	 * Set tx_csm before we start receiving interrupts, otherwise
14218c2ecf20Sopenharmony_ci	 * the interrupt handler might think it is supposed to process
14228c2ecf20Sopenharmony_ci	 * tx ints before we are up and running, which may cause a null
14238c2ecf20Sopenharmony_ci	 * pointer access in the int handler.
14248c2ecf20Sopenharmony_ci	 */
14258c2ecf20Sopenharmony_ci	ap->cur_rx = 0;
14268c2ecf20Sopenharmony_ci	ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	wmb();
14298c2ecf20Sopenharmony_ci	ace_set_txprd(regs, ap, 0);
14308c2ecf20Sopenharmony_ci	writel(0, &regs->RxRetCsm);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	/*
14338c2ecf20Sopenharmony_ci	 * Enable DMA engine now.
14348c2ecf20Sopenharmony_ci	 * If we do this sooner, Mckinley box pukes.
14358c2ecf20Sopenharmony_ci	 * I assume it's because Tigon II DMA engine wants to check
14368c2ecf20Sopenharmony_ci	 * *something* even before the CPU is started.
14378c2ecf20Sopenharmony_ci	 */
14388c2ecf20Sopenharmony_ci	writel(1, &regs->AssistState);  /* enable DMA */
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	/*
14418c2ecf20Sopenharmony_ci	 * Start the NIC CPU
14428c2ecf20Sopenharmony_ci	 */
14438c2ecf20Sopenharmony_ci	writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);
14448c2ecf20Sopenharmony_ci	readl(&regs->CpuCtrl);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	/*
14478c2ecf20Sopenharmony_ci	 * Wait for the firmware to spin up - max 3 seconds.
14488c2ecf20Sopenharmony_ci	 */
14498c2ecf20Sopenharmony_ci	myjif = jiffies + 3 * HZ;
14508c2ecf20Sopenharmony_ci	while (time_before(jiffies, myjif) && !ap->fw_running)
14518c2ecf20Sopenharmony_ci		cpu_relax();
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	if (!ap->fw_running) {
14548c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Firmware NOT running!\n", ap->name);
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		ace_dump_trace(ap);
14578c2ecf20Sopenharmony_ci		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
14588c2ecf20Sopenharmony_ci		readl(&regs->CpuCtrl);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci		/* aman@sgi.com - account for badly behaving firmware/NIC:
14618c2ecf20Sopenharmony_ci		 * - have observed that the NIC may continue to generate
14628c2ecf20Sopenharmony_ci		 *   interrupts for some reason; attempt to stop it - halt
14638c2ecf20Sopenharmony_ci		 *   second CPU for Tigon II cards, and also clear Mb0
14648c2ecf20Sopenharmony_ci		 * - if we're a module, we'll fail to load if this was
14658c2ecf20Sopenharmony_ci		 *   the only GbE card in the system => if the kernel does
14668c2ecf20Sopenharmony_ci		 *   see an interrupt from the NIC, code to handle it is
14678c2ecf20Sopenharmony_ci		 *   gone and OOps! - so free_irq also
14688c2ecf20Sopenharmony_ci		 */
14698c2ecf20Sopenharmony_ci		if (ap->version >= 2)
14708c2ecf20Sopenharmony_ci			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
14718c2ecf20Sopenharmony_ci			       &regs->CpuBCtrl);
14728c2ecf20Sopenharmony_ci		writel(0, &regs->Mb0Lo);
14738c2ecf20Sopenharmony_ci		readl(&regs->Mb0Lo);
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci		ecode = -EBUSY;
14768c2ecf20Sopenharmony_ci		goto init_error;
14778c2ecf20Sopenharmony_ci	}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	/*
14808c2ecf20Sopenharmony_ci	 * We load the ring here as there seem to be no way to tell the
14818c2ecf20Sopenharmony_ci	 * firmware to wipe the ring without re-initializing it.
14828c2ecf20Sopenharmony_ci	 */
14838c2ecf20Sopenharmony_ci	if (!test_and_set_bit(0, &ap->std_refill_busy))
14848c2ecf20Sopenharmony_ci		ace_load_std_rx_ring(dev, RX_RING_SIZE);
14858c2ecf20Sopenharmony_ci	else
14868c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Someone is busy refilling the RX ring\n",
14878c2ecf20Sopenharmony_ci		       ap->name);
14888c2ecf20Sopenharmony_ci	if (ap->version >= 2) {
14898c2ecf20Sopenharmony_ci		if (!test_and_set_bit(0, &ap->mini_refill_busy))
14908c2ecf20Sopenharmony_ci			ace_load_mini_rx_ring(dev, RX_MINI_SIZE);
14918c2ecf20Sopenharmony_ci		else
14928c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Someone is busy refilling "
14938c2ecf20Sopenharmony_ci			       "the RX mini ring\n", ap->name);
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci	return 0;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci init_error:
14988c2ecf20Sopenharmony_ci	ace_init_cleanup(dev);
14998c2ecf20Sopenharmony_ci	return ecode;
15008c2ecf20Sopenharmony_ci}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_cistatic void ace_set_rxtx_parms(struct net_device *dev, int jumbo)
15048c2ecf20Sopenharmony_ci{
15058c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
15068c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
15078c2ecf20Sopenharmony_ci	int board_idx = ap->board_idx;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	if (board_idx >= 0) {
15108c2ecf20Sopenharmony_ci		if (!jumbo) {
15118c2ecf20Sopenharmony_ci			if (!tx_coal_tick[board_idx])
15128c2ecf20Sopenharmony_ci				writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
15138c2ecf20Sopenharmony_ci			if (!max_tx_desc[board_idx])
15148c2ecf20Sopenharmony_ci				writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
15158c2ecf20Sopenharmony_ci			if (!rx_coal_tick[board_idx])
15168c2ecf20Sopenharmony_ci				writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
15178c2ecf20Sopenharmony_ci			if (!max_rx_desc[board_idx])
15188c2ecf20Sopenharmony_ci				writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
15198c2ecf20Sopenharmony_ci			if (!tx_ratio[board_idx])
15208c2ecf20Sopenharmony_ci				writel(DEF_TX_RATIO, &regs->TxBufRat);
15218c2ecf20Sopenharmony_ci		} else {
15228c2ecf20Sopenharmony_ci			if (!tx_coal_tick[board_idx])
15238c2ecf20Sopenharmony_ci				writel(DEF_JUMBO_TX_COAL,
15248c2ecf20Sopenharmony_ci				       &regs->TuneTxCoalTicks);
15258c2ecf20Sopenharmony_ci			if (!max_tx_desc[board_idx])
15268c2ecf20Sopenharmony_ci				writel(DEF_JUMBO_TX_MAX_DESC,
15278c2ecf20Sopenharmony_ci				       &regs->TuneMaxTxDesc);
15288c2ecf20Sopenharmony_ci			if (!rx_coal_tick[board_idx])
15298c2ecf20Sopenharmony_ci				writel(DEF_JUMBO_RX_COAL,
15308c2ecf20Sopenharmony_ci				       &regs->TuneRxCoalTicks);
15318c2ecf20Sopenharmony_ci			if (!max_rx_desc[board_idx])
15328c2ecf20Sopenharmony_ci				writel(DEF_JUMBO_RX_MAX_DESC,
15338c2ecf20Sopenharmony_ci				       &regs->TuneMaxRxDesc);
15348c2ecf20Sopenharmony_ci			if (!tx_ratio[board_idx])
15358c2ecf20Sopenharmony_ci				writel(DEF_JUMBO_TX_RATIO, &regs->TxBufRat);
15368c2ecf20Sopenharmony_ci		}
15378c2ecf20Sopenharmony_ci	}
15388c2ecf20Sopenharmony_ci}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_cistatic void ace_watchdog(struct net_device *data, unsigned int txqueue)
15428c2ecf20Sopenharmony_ci{
15438c2ecf20Sopenharmony_ci	struct net_device *dev = data;
15448c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
15458c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	/*
15488c2ecf20Sopenharmony_ci	 * We haven't received a stats update event for more than 2.5
15498c2ecf20Sopenharmony_ci	 * seconds and there is data in the transmit queue, thus we
15508c2ecf20Sopenharmony_ci	 * assume the card is stuck.
15518c2ecf20Sopenharmony_ci	 */
15528c2ecf20Sopenharmony_ci	if (*ap->tx_csm != ap->tx_ret_csm) {
15538c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n",
15548c2ecf20Sopenharmony_ci		       dev->name, (unsigned int)readl(&regs->HostCtrl));
15558c2ecf20Sopenharmony_ci		/* This can happen due to ieee flow control. */
15568c2ecf20Sopenharmony_ci	} else {
15578c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n",
15588c2ecf20Sopenharmony_ci		       dev->name);
15598c2ecf20Sopenharmony_ci#if 0
15608c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
15618c2ecf20Sopenharmony_ci#endif
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci}
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_cistatic void ace_tasklet(struct tasklet_struct *t)
15678c2ecf20Sopenharmony_ci{
15688c2ecf20Sopenharmony_ci	struct ace_private *ap = from_tasklet(ap, t, ace_tasklet);
15698c2ecf20Sopenharmony_ci	struct net_device *dev = ap->ndev;
15708c2ecf20Sopenharmony_ci	int cur_size;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	cur_size = atomic_read(&ap->cur_rx_bufs);
15738c2ecf20Sopenharmony_ci	if ((cur_size < RX_LOW_STD_THRES) &&
15748c2ecf20Sopenharmony_ci	    !test_and_set_bit(0, &ap->std_refill_busy)) {
15758c2ecf20Sopenharmony_ci#ifdef DEBUG
15768c2ecf20Sopenharmony_ci		printk("refilling buffers (current %i)\n", cur_size);
15778c2ecf20Sopenharmony_ci#endif
15788c2ecf20Sopenharmony_ci		ace_load_std_rx_ring(dev, RX_RING_SIZE - cur_size);
15798c2ecf20Sopenharmony_ci	}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	if (ap->version >= 2) {
15828c2ecf20Sopenharmony_ci		cur_size = atomic_read(&ap->cur_mini_bufs);
15838c2ecf20Sopenharmony_ci		if ((cur_size < RX_LOW_MINI_THRES) &&
15848c2ecf20Sopenharmony_ci		    !test_and_set_bit(0, &ap->mini_refill_busy)) {
15858c2ecf20Sopenharmony_ci#ifdef DEBUG
15868c2ecf20Sopenharmony_ci			printk("refilling mini buffers (current %i)\n",
15878c2ecf20Sopenharmony_ci			       cur_size);
15888c2ecf20Sopenharmony_ci#endif
15898c2ecf20Sopenharmony_ci			ace_load_mini_rx_ring(dev, RX_MINI_SIZE - cur_size);
15908c2ecf20Sopenharmony_ci		}
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	cur_size = atomic_read(&ap->cur_jumbo_bufs);
15948c2ecf20Sopenharmony_ci	if (ap->jumbo && (cur_size < RX_LOW_JUMBO_THRES) &&
15958c2ecf20Sopenharmony_ci	    !test_and_set_bit(0, &ap->jumbo_refill_busy)) {
15968c2ecf20Sopenharmony_ci#ifdef DEBUG
15978c2ecf20Sopenharmony_ci		printk("refilling jumbo buffers (current %i)\n", cur_size);
15988c2ecf20Sopenharmony_ci#endif
15998c2ecf20Sopenharmony_ci		ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE - cur_size);
16008c2ecf20Sopenharmony_ci	}
16018c2ecf20Sopenharmony_ci	ap->tasklet_pending = 0;
16028c2ecf20Sopenharmony_ci}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci/*
16068c2ecf20Sopenharmony_ci * Copy the contents of the NIC's trace buffer to kernel memory.
16078c2ecf20Sopenharmony_ci */
16088c2ecf20Sopenharmony_cistatic void ace_dump_trace(struct ace_private *ap)
16098c2ecf20Sopenharmony_ci{
16108c2ecf20Sopenharmony_ci#if 0
16118c2ecf20Sopenharmony_ci	if (!ap->trace_buf)
16128c2ecf20Sopenharmony_ci		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)))
16138c2ecf20Sopenharmony_ci		    return;
16148c2ecf20Sopenharmony_ci#endif
16158c2ecf20Sopenharmony_ci}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci/*
16198c2ecf20Sopenharmony_ci * Load the standard rx ring.
16208c2ecf20Sopenharmony_ci *
16218c2ecf20Sopenharmony_ci * Loading rings is safe without holding the spin lock since this is
16228c2ecf20Sopenharmony_ci * done only before the device is enabled, thus no interrupts are
16238c2ecf20Sopenharmony_ci * generated and by the interrupt handler/tasklet handler.
16248c2ecf20Sopenharmony_ci */
16258c2ecf20Sopenharmony_cistatic void ace_load_std_rx_ring(struct net_device *dev, int nr_bufs)
16268c2ecf20Sopenharmony_ci{
16278c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
16288c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
16298c2ecf20Sopenharmony_ci	short i, idx;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	prefetchw(&ap->cur_rx_bufs);
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	idx = ap->rx_std_skbprd;
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	for (i = 0; i < nr_bufs; i++) {
16378c2ecf20Sopenharmony_ci		struct sk_buff *skb;
16388c2ecf20Sopenharmony_ci		struct rx_desc *rd;
16398c2ecf20Sopenharmony_ci		dma_addr_t mapping;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(dev, ACE_STD_BUFSIZE);
16428c2ecf20Sopenharmony_ci		if (!skb)
16438c2ecf20Sopenharmony_ci			break;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci		mapping = dma_map_page(&ap->pdev->dev,
16468c2ecf20Sopenharmony_ci				       virt_to_page(skb->data),
16478c2ecf20Sopenharmony_ci				       offset_in_page(skb->data),
16488c2ecf20Sopenharmony_ci				       ACE_STD_BUFSIZE, DMA_FROM_DEVICE);
16498c2ecf20Sopenharmony_ci		ap->skb->rx_std_skbuff[idx].skb = skb;
16508c2ecf20Sopenharmony_ci		dma_unmap_addr_set(&ap->skb->rx_std_skbuff[idx],
16518c2ecf20Sopenharmony_ci				   mapping, mapping);
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci		rd = &ap->rx_std_ring[idx];
16548c2ecf20Sopenharmony_ci		set_aceaddr(&rd->addr, mapping);
16558c2ecf20Sopenharmony_ci		rd->size = ACE_STD_BUFSIZE;
16568c2ecf20Sopenharmony_ci		rd->idx = idx;
16578c2ecf20Sopenharmony_ci		idx = (idx + 1) % RX_STD_RING_ENTRIES;
16588c2ecf20Sopenharmony_ci	}
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	if (!i)
16618c2ecf20Sopenharmony_ci		goto error_out;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	atomic_add(i, &ap->cur_rx_bufs);
16648c2ecf20Sopenharmony_ci	ap->rx_std_skbprd = idx;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	if (ACE_IS_TIGON_I(ap)) {
16678c2ecf20Sopenharmony_ci		struct cmd cmd;
16688c2ecf20Sopenharmony_ci		cmd.evt = C_SET_RX_PRD_IDX;
16698c2ecf20Sopenharmony_ci		cmd.code = 0;
16708c2ecf20Sopenharmony_ci		cmd.idx = ap->rx_std_skbprd;
16718c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
16728c2ecf20Sopenharmony_ci	} else {
16738c2ecf20Sopenharmony_ci		writel(idx, &regs->RxStdPrd);
16748c2ecf20Sopenharmony_ci		wmb();
16758c2ecf20Sopenharmony_ci	}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci out:
16788c2ecf20Sopenharmony_ci	clear_bit(0, &ap->std_refill_busy);
16798c2ecf20Sopenharmony_ci	return;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci error_out:
16828c2ecf20Sopenharmony_ci	printk(KERN_INFO "Out of memory when allocating "
16838c2ecf20Sopenharmony_ci	       "standard receive buffers\n");
16848c2ecf20Sopenharmony_ci	goto out;
16858c2ecf20Sopenharmony_ci}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_cistatic void ace_load_mini_rx_ring(struct net_device *dev, int nr_bufs)
16898c2ecf20Sopenharmony_ci{
16908c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
16918c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
16928c2ecf20Sopenharmony_ci	short i, idx;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	prefetchw(&ap->cur_mini_bufs);
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	idx = ap->rx_mini_skbprd;
16978c2ecf20Sopenharmony_ci	for (i = 0; i < nr_bufs; i++) {
16988c2ecf20Sopenharmony_ci		struct sk_buff *skb;
16998c2ecf20Sopenharmony_ci		struct rx_desc *rd;
17008c2ecf20Sopenharmony_ci		dma_addr_t mapping;
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(dev, ACE_MINI_BUFSIZE);
17038c2ecf20Sopenharmony_ci		if (!skb)
17048c2ecf20Sopenharmony_ci			break;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci		mapping = dma_map_page(&ap->pdev->dev,
17078c2ecf20Sopenharmony_ci				       virt_to_page(skb->data),
17088c2ecf20Sopenharmony_ci				       offset_in_page(skb->data),
17098c2ecf20Sopenharmony_ci				       ACE_MINI_BUFSIZE, DMA_FROM_DEVICE);
17108c2ecf20Sopenharmony_ci		ap->skb->rx_mini_skbuff[idx].skb = skb;
17118c2ecf20Sopenharmony_ci		dma_unmap_addr_set(&ap->skb->rx_mini_skbuff[idx],
17128c2ecf20Sopenharmony_ci				   mapping, mapping);
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci		rd = &ap->rx_mini_ring[idx];
17158c2ecf20Sopenharmony_ci		set_aceaddr(&rd->addr, mapping);
17168c2ecf20Sopenharmony_ci		rd->size = ACE_MINI_BUFSIZE;
17178c2ecf20Sopenharmony_ci		rd->idx = idx;
17188c2ecf20Sopenharmony_ci		idx = (idx + 1) % RX_MINI_RING_ENTRIES;
17198c2ecf20Sopenharmony_ci	}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	if (!i)
17228c2ecf20Sopenharmony_ci		goto error_out;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	atomic_add(i, &ap->cur_mini_bufs);
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	ap->rx_mini_skbprd = idx;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	writel(idx, &regs->RxMiniPrd);
17298c2ecf20Sopenharmony_ci	wmb();
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci out:
17328c2ecf20Sopenharmony_ci	clear_bit(0, &ap->mini_refill_busy);
17338c2ecf20Sopenharmony_ci	return;
17348c2ecf20Sopenharmony_ci error_out:
17358c2ecf20Sopenharmony_ci	printk(KERN_INFO "Out of memory when allocating "
17368c2ecf20Sopenharmony_ci	       "mini receive buffers\n");
17378c2ecf20Sopenharmony_ci	goto out;
17388c2ecf20Sopenharmony_ci}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci/*
17428c2ecf20Sopenharmony_ci * Load the jumbo rx ring, this may happen at any time if the MTU
17438c2ecf20Sopenharmony_ci * is changed to a value > 1500.
17448c2ecf20Sopenharmony_ci */
17458c2ecf20Sopenharmony_cistatic void ace_load_jumbo_rx_ring(struct net_device *dev, int nr_bufs)
17468c2ecf20Sopenharmony_ci{
17478c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
17488c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
17498c2ecf20Sopenharmony_ci	short i, idx;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	idx = ap->rx_jumbo_skbprd;
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	for (i = 0; i < nr_bufs; i++) {
17548c2ecf20Sopenharmony_ci		struct sk_buff *skb;
17558c2ecf20Sopenharmony_ci		struct rx_desc *rd;
17568c2ecf20Sopenharmony_ci		dma_addr_t mapping;
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(dev, ACE_JUMBO_BUFSIZE);
17598c2ecf20Sopenharmony_ci		if (!skb)
17608c2ecf20Sopenharmony_ci			break;
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci		mapping = dma_map_page(&ap->pdev->dev,
17638c2ecf20Sopenharmony_ci				       virt_to_page(skb->data),
17648c2ecf20Sopenharmony_ci				       offset_in_page(skb->data),
17658c2ecf20Sopenharmony_ci				       ACE_JUMBO_BUFSIZE, DMA_FROM_DEVICE);
17668c2ecf20Sopenharmony_ci		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
17678c2ecf20Sopenharmony_ci		dma_unmap_addr_set(&ap->skb->rx_jumbo_skbuff[idx],
17688c2ecf20Sopenharmony_ci				   mapping, mapping);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci		rd = &ap->rx_jumbo_ring[idx];
17718c2ecf20Sopenharmony_ci		set_aceaddr(&rd->addr, mapping);
17728c2ecf20Sopenharmony_ci		rd->size = ACE_JUMBO_BUFSIZE;
17738c2ecf20Sopenharmony_ci		rd->idx = idx;
17748c2ecf20Sopenharmony_ci		idx = (idx + 1) % RX_JUMBO_RING_ENTRIES;
17758c2ecf20Sopenharmony_ci	}
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	if (!i)
17788c2ecf20Sopenharmony_ci		goto error_out;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	atomic_add(i, &ap->cur_jumbo_bufs);
17818c2ecf20Sopenharmony_ci	ap->rx_jumbo_skbprd = idx;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	if (ACE_IS_TIGON_I(ap)) {
17848c2ecf20Sopenharmony_ci		struct cmd cmd;
17858c2ecf20Sopenharmony_ci		cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
17868c2ecf20Sopenharmony_ci		cmd.code = 0;
17878c2ecf20Sopenharmony_ci		cmd.idx = ap->rx_jumbo_skbprd;
17888c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
17898c2ecf20Sopenharmony_ci	} else {
17908c2ecf20Sopenharmony_ci		writel(idx, &regs->RxJumboPrd);
17918c2ecf20Sopenharmony_ci		wmb();
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci out:
17958c2ecf20Sopenharmony_ci	clear_bit(0, &ap->jumbo_refill_busy);
17968c2ecf20Sopenharmony_ci	return;
17978c2ecf20Sopenharmony_ci error_out:
17988c2ecf20Sopenharmony_ci	if (net_ratelimit())
17998c2ecf20Sopenharmony_ci		printk(KERN_INFO "Out of memory when allocating "
18008c2ecf20Sopenharmony_ci		       "jumbo receive buffers\n");
18018c2ecf20Sopenharmony_ci	goto out;
18028c2ecf20Sopenharmony_ci}
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci/*
18068c2ecf20Sopenharmony_ci * All events are considered to be slow (RX/TX ints do not generate
18078c2ecf20Sopenharmony_ci * events) and are handled here, outside the main interrupt handler,
18088c2ecf20Sopenharmony_ci * to reduce the size of the handler.
18098c2ecf20Sopenharmony_ci */
18108c2ecf20Sopenharmony_cistatic u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
18118c2ecf20Sopenharmony_ci{
18128c2ecf20Sopenharmony_ci	struct ace_private *ap;
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	ap = netdev_priv(dev);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	while (evtcsm != evtprd) {
18178c2ecf20Sopenharmony_ci		switch (ap->evt_ring[evtcsm].evt) {
18188c2ecf20Sopenharmony_ci		case E_FW_RUNNING:
18198c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Firmware up and running\n",
18208c2ecf20Sopenharmony_ci			       ap->name);
18218c2ecf20Sopenharmony_ci			ap->fw_running = 1;
18228c2ecf20Sopenharmony_ci			wmb();
18238c2ecf20Sopenharmony_ci			break;
18248c2ecf20Sopenharmony_ci		case E_STATS_UPDATED:
18258c2ecf20Sopenharmony_ci			break;
18268c2ecf20Sopenharmony_ci		case E_LNK_STATE:
18278c2ecf20Sopenharmony_ci		{
18288c2ecf20Sopenharmony_ci			u16 code = ap->evt_ring[evtcsm].code;
18298c2ecf20Sopenharmony_ci			switch (code) {
18308c2ecf20Sopenharmony_ci			case E_C_LINK_UP:
18318c2ecf20Sopenharmony_ci			{
18328c2ecf20Sopenharmony_ci				u32 state = readl(&ap->regs->GigLnkState);
18338c2ecf20Sopenharmony_ci				printk(KERN_WARNING "%s: Optical link UP "
18348c2ecf20Sopenharmony_ci				       "(%s Duplex, Flow Control: %s%s)\n",
18358c2ecf20Sopenharmony_ci				       ap->name,
18368c2ecf20Sopenharmony_ci				       state & LNK_FULL_DUPLEX ? "Full":"Half",
18378c2ecf20Sopenharmony_ci				       state & LNK_TX_FLOW_CTL_Y ? "TX " : "",
18388c2ecf20Sopenharmony_ci				       state & LNK_RX_FLOW_CTL_Y ? "RX" : "");
18398c2ecf20Sopenharmony_ci				break;
18408c2ecf20Sopenharmony_ci			}
18418c2ecf20Sopenharmony_ci			case E_C_LINK_DOWN:
18428c2ecf20Sopenharmony_ci				printk(KERN_WARNING "%s: Optical link DOWN\n",
18438c2ecf20Sopenharmony_ci				       ap->name);
18448c2ecf20Sopenharmony_ci				break;
18458c2ecf20Sopenharmony_ci			case E_C_LINK_10_100:
18468c2ecf20Sopenharmony_ci				printk(KERN_WARNING "%s: 10/100BaseT link "
18478c2ecf20Sopenharmony_ci				       "UP\n", ap->name);
18488c2ecf20Sopenharmony_ci				break;
18498c2ecf20Sopenharmony_ci			default:
18508c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: Unknown optical link "
18518c2ecf20Sopenharmony_ci				       "state %02x\n", ap->name, code);
18528c2ecf20Sopenharmony_ci			}
18538c2ecf20Sopenharmony_ci			break;
18548c2ecf20Sopenharmony_ci		}
18558c2ecf20Sopenharmony_ci		case E_ERROR:
18568c2ecf20Sopenharmony_ci			switch(ap->evt_ring[evtcsm].code) {
18578c2ecf20Sopenharmony_ci			case E_C_ERR_INVAL_CMD:
18588c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: invalid command error\n",
18598c2ecf20Sopenharmony_ci				       ap->name);
18608c2ecf20Sopenharmony_ci				break;
18618c2ecf20Sopenharmony_ci			case E_C_ERR_UNIMP_CMD:
18628c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: unimplemented command "
18638c2ecf20Sopenharmony_ci				       "error\n", ap->name);
18648c2ecf20Sopenharmony_ci				break;
18658c2ecf20Sopenharmony_ci			case E_C_ERR_BAD_CFG:
18668c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: bad config error\n",
18678c2ecf20Sopenharmony_ci				       ap->name);
18688c2ecf20Sopenharmony_ci				break;
18698c2ecf20Sopenharmony_ci			default:
18708c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: unknown error %02x\n",
18718c2ecf20Sopenharmony_ci				       ap->name, ap->evt_ring[evtcsm].code);
18728c2ecf20Sopenharmony_ci			}
18738c2ecf20Sopenharmony_ci			break;
18748c2ecf20Sopenharmony_ci		case E_RESET_JUMBO_RNG:
18758c2ecf20Sopenharmony_ci		{
18768c2ecf20Sopenharmony_ci			int i;
18778c2ecf20Sopenharmony_ci			for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
18788c2ecf20Sopenharmony_ci				if (ap->skb->rx_jumbo_skbuff[i].skb) {
18798c2ecf20Sopenharmony_ci					ap->rx_jumbo_ring[i].size = 0;
18808c2ecf20Sopenharmony_ci					set_aceaddr(&ap->rx_jumbo_ring[i].addr, 0);
18818c2ecf20Sopenharmony_ci					dev_kfree_skb(ap->skb->rx_jumbo_skbuff[i].skb);
18828c2ecf20Sopenharmony_ci					ap->skb->rx_jumbo_skbuff[i].skb = NULL;
18838c2ecf20Sopenharmony_ci				}
18848c2ecf20Sopenharmony_ci			}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci 			if (ACE_IS_TIGON_I(ap)) {
18878c2ecf20Sopenharmony_ci 				struct cmd cmd;
18888c2ecf20Sopenharmony_ci 				cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
18898c2ecf20Sopenharmony_ci 				cmd.code = 0;
18908c2ecf20Sopenharmony_ci 				cmd.idx = 0;
18918c2ecf20Sopenharmony_ci 				ace_issue_cmd(ap->regs, &cmd);
18928c2ecf20Sopenharmony_ci 			} else {
18938c2ecf20Sopenharmony_ci 				writel(0, &((ap->regs)->RxJumboPrd));
18948c2ecf20Sopenharmony_ci 				wmb();
18958c2ecf20Sopenharmony_ci 			}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci			ap->jumbo = 0;
18988c2ecf20Sopenharmony_ci			ap->rx_jumbo_skbprd = 0;
18998c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Jumbo ring flushed\n",
19008c2ecf20Sopenharmony_ci			       ap->name);
19018c2ecf20Sopenharmony_ci			clear_bit(0, &ap->jumbo_refill_busy);
19028c2ecf20Sopenharmony_ci			break;
19038c2ecf20Sopenharmony_ci		}
19048c2ecf20Sopenharmony_ci		default:
19058c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Unhandled event 0x%02x\n",
19068c2ecf20Sopenharmony_ci			       ap->name, ap->evt_ring[evtcsm].evt);
19078c2ecf20Sopenharmony_ci		}
19088c2ecf20Sopenharmony_ci		evtcsm = (evtcsm + 1) % EVT_RING_ENTRIES;
19098c2ecf20Sopenharmony_ci	}
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	return evtcsm;
19128c2ecf20Sopenharmony_ci}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_cistatic void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
19188c2ecf20Sopenharmony_ci	u32 idx;
19198c2ecf20Sopenharmony_ci	int mini_count = 0, std_count = 0;
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	idx = rxretcsm;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	prefetchw(&ap->cur_rx_bufs);
19248c2ecf20Sopenharmony_ci	prefetchw(&ap->cur_mini_bufs);
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	while (idx != rxretprd) {
19278c2ecf20Sopenharmony_ci		struct ring_info *rip;
19288c2ecf20Sopenharmony_ci		struct sk_buff *skb;
19298c2ecf20Sopenharmony_ci		struct rx_desc *retdesc;
19308c2ecf20Sopenharmony_ci		u32 skbidx;
19318c2ecf20Sopenharmony_ci		int bd_flags, desc_type, mapsize;
19328c2ecf20Sopenharmony_ci		u16 csum;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci		/* make sure the rx descriptor isn't read before rxretprd */
19368c2ecf20Sopenharmony_ci		if (idx == rxretcsm)
19378c2ecf20Sopenharmony_ci			rmb();
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci		retdesc = &ap->rx_return_ring[idx];
19408c2ecf20Sopenharmony_ci		skbidx = retdesc->idx;
19418c2ecf20Sopenharmony_ci		bd_flags = retdesc->flags;
19428c2ecf20Sopenharmony_ci		desc_type = bd_flags & (BD_FLG_JUMBO | BD_FLG_MINI);
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci		switch(desc_type) {
19458c2ecf20Sopenharmony_ci			/*
19468c2ecf20Sopenharmony_ci			 * Normal frames do not have any flags set
19478c2ecf20Sopenharmony_ci			 *
19488c2ecf20Sopenharmony_ci			 * Mini and normal frames arrive frequently,
19498c2ecf20Sopenharmony_ci			 * so use a local counter to avoid doing
19508c2ecf20Sopenharmony_ci			 * atomic operations for each packet arriving.
19518c2ecf20Sopenharmony_ci			 */
19528c2ecf20Sopenharmony_ci		case 0:
19538c2ecf20Sopenharmony_ci			rip = &ap->skb->rx_std_skbuff[skbidx];
19548c2ecf20Sopenharmony_ci			mapsize = ACE_STD_BUFSIZE;
19558c2ecf20Sopenharmony_ci			std_count++;
19568c2ecf20Sopenharmony_ci			break;
19578c2ecf20Sopenharmony_ci		case BD_FLG_JUMBO:
19588c2ecf20Sopenharmony_ci			rip = &ap->skb->rx_jumbo_skbuff[skbidx];
19598c2ecf20Sopenharmony_ci			mapsize = ACE_JUMBO_BUFSIZE;
19608c2ecf20Sopenharmony_ci			atomic_dec(&ap->cur_jumbo_bufs);
19618c2ecf20Sopenharmony_ci			break;
19628c2ecf20Sopenharmony_ci		case BD_FLG_MINI:
19638c2ecf20Sopenharmony_ci			rip = &ap->skb->rx_mini_skbuff[skbidx];
19648c2ecf20Sopenharmony_ci			mapsize = ACE_MINI_BUFSIZE;
19658c2ecf20Sopenharmony_ci			mini_count++;
19668c2ecf20Sopenharmony_ci			break;
19678c2ecf20Sopenharmony_ci		default:
19688c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: unknown frame type (0x%02x) "
19698c2ecf20Sopenharmony_ci			       "returned by NIC\n", dev->name,
19708c2ecf20Sopenharmony_ci			       retdesc->flags);
19718c2ecf20Sopenharmony_ci			goto error;
19728c2ecf20Sopenharmony_ci		}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci		skb = rip->skb;
19758c2ecf20Sopenharmony_ci		rip->skb = NULL;
19768c2ecf20Sopenharmony_ci		dma_unmap_page(&ap->pdev->dev, dma_unmap_addr(rip, mapping),
19778c2ecf20Sopenharmony_ci			       mapsize, DMA_FROM_DEVICE);
19788c2ecf20Sopenharmony_ci		skb_put(skb, retdesc->size);
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci		/*
19818c2ecf20Sopenharmony_ci		 * Fly baby, fly!
19828c2ecf20Sopenharmony_ci		 */
19838c2ecf20Sopenharmony_ci		csum = retdesc->tcp_udp_csum;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, dev);
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci		/*
19888c2ecf20Sopenharmony_ci		 * Instead of forcing the poor tigon mips cpu to calculate
19898c2ecf20Sopenharmony_ci		 * pseudo hdr checksum, we do this ourselves.
19908c2ecf20Sopenharmony_ci		 */
19918c2ecf20Sopenharmony_ci		if (bd_flags & BD_FLG_TCP_UDP_SUM) {
19928c2ecf20Sopenharmony_ci			skb->csum = htons(csum);
19938c2ecf20Sopenharmony_ci			skb->ip_summed = CHECKSUM_COMPLETE;
19948c2ecf20Sopenharmony_ci		} else {
19958c2ecf20Sopenharmony_ci			skb_checksum_none_assert(skb);
19968c2ecf20Sopenharmony_ci		}
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci		/* send it up */
19998c2ecf20Sopenharmony_ci		if ((bd_flags & BD_FLG_VLAN_TAG))
20008c2ecf20Sopenharmony_ci			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), retdesc->vlan);
20018c2ecf20Sopenharmony_ci		netif_rx(skb);
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci		dev->stats.rx_packets++;
20048c2ecf20Sopenharmony_ci		dev->stats.rx_bytes += retdesc->size;
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci		idx = (idx + 1) % RX_RETURN_RING_ENTRIES;
20078c2ecf20Sopenharmony_ci	}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	atomic_sub(std_count, &ap->cur_rx_bufs);
20108c2ecf20Sopenharmony_ci	if (!ACE_IS_TIGON_I(ap))
20118c2ecf20Sopenharmony_ci		atomic_sub(mini_count, &ap->cur_mini_bufs);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci out:
20148c2ecf20Sopenharmony_ci	/*
20158c2ecf20Sopenharmony_ci	 * According to the documentation RxRetCsm is obsolete with
20168c2ecf20Sopenharmony_ci	 * the 12.3.x Firmware - my Tigon I NICs seem to disagree!
20178c2ecf20Sopenharmony_ci	 */
20188c2ecf20Sopenharmony_ci	if (ACE_IS_TIGON_I(ap)) {
20198c2ecf20Sopenharmony_ci		writel(idx, &ap->regs->RxRetCsm);
20208c2ecf20Sopenharmony_ci	}
20218c2ecf20Sopenharmony_ci	ap->cur_rx = idx;
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	return;
20248c2ecf20Sopenharmony_ci error:
20258c2ecf20Sopenharmony_ci	idx = rxretprd;
20268c2ecf20Sopenharmony_ci	goto out;
20278c2ecf20Sopenharmony_ci}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_cistatic inline void ace_tx_int(struct net_device *dev,
20318c2ecf20Sopenharmony_ci			      u32 txcsm, u32 idx)
20328c2ecf20Sopenharmony_ci{
20338c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	do {
20368c2ecf20Sopenharmony_ci		struct sk_buff *skb;
20378c2ecf20Sopenharmony_ci		struct tx_ring_info *info;
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci		info = ap->skb->tx_skbuff + idx;
20408c2ecf20Sopenharmony_ci		skb = info->skb;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci		if (dma_unmap_len(info, maplen)) {
20438c2ecf20Sopenharmony_ci			dma_unmap_page(&ap->pdev->dev,
20448c2ecf20Sopenharmony_ci				       dma_unmap_addr(info, mapping),
20458c2ecf20Sopenharmony_ci				       dma_unmap_len(info, maplen),
20468c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
20478c2ecf20Sopenharmony_ci			dma_unmap_len_set(info, maplen, 0);
20488c2ecf20Sopenharmony_ci		}
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci		if (skb) {
20518c2ecf20Sopenharmony_ci			dev->stats.tx_packets++;
20528c2ecf20Sopenharmony_ci			dev->stats.tx_bytes += skb->len;
20538c2ecf20Sopenharmony_ci			dev_consume_skb_irq(skb);
20548c2ecf20Sopenharmony_ci			info->skb = NULL;
20558c2ecf20Sopenharmony_ci		}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci		idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
20588c2ecf20Sopenharmony_ci	} while (idx != txcsm);
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	if (netif_queue_stopped(dev))
20618c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	wmb();
20648c2ecf20Sopenharmony_ci	ap->tx_ret_csm = txcsm;
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	/* So... tx_ret_csm is advanced _after_ check for device wakeup.
20678c2ecf20Sopenharmony_ci	 *
20688c2ecf20Sopenharmony_ci	 * We could try to make it before. In this case we would get
20698c2ecf20Sopenharmony_ci	 * the following race condition: hard_start_xmit on other cpu
20708c2ecf20Sopenharmony_ci	 * enters after we advanced tx_ret_csm and fills space,
20718c2ecf20Sopenharmony_ci	 * which we have just freed, so that we make illegal device wakeup.
20728c2ecf20Sopenharmony_ci	 * There is no good way to workaround this (at entry
20738c2ecf20Sopenharmony_ci	 * to ace_start_xmit detects this condition and prevents
20748c2ecf20Sopenharmony_ci	 * ring corruption, but it is not a good workaround.)
20758c2ecf20Sopenharmony_ci	 *
20768c2ecf20Sopenharmony_ci	 * When tx_ret_csm is advanced after, we wake up device _only_
20778c2ecf20Sopenharmony_ci	 * if we really have some space in ring (though the core doing
20788c2ecf20Sopenharmony_ci	 * hard_start_xmit can see full ring for some period and has to
20798c2ecf20Sopenharmony_ci	 * synchronize.) Superb.
20808c2ecf20Sopenharmony_ci	 * BUT! We get another subtle race condition. hard_start_xmit
20818c2ecf20Sopenharmony_ci	 * may think that ring is full between wakeup and advancing
20828c2ecf20Sopenharmony_ci	 * tx_ret_csm and will stop device instantly! It is not so bad.
20838c2ecf20Sopenharmony_ci	 * We are guaranteed that there is something in ring, so that
20848c2ecf20Sopenharmony_ci	 * the next irq will resume transmission. To speedup this we could
20858c2ecf20Sopenharmony_ci	 * mark descriptor, which closes ring with BD_FLG_COAL_NOW
20868c2ecf20Sopenharmony_ci	 * (see ace_start_xmit).
20878c2ecf20Sopenharmony_ci	 *
20888c2ecf20Sopenharmony_ci	 * Well, this dilemma exists in all lock-free devices.
20898c2ecf20Sopenharmony_ci	 * We, following scheme used in drivers by Donald Becker,
20908c2ecf20Sopenharmony_ci	 * select the least dangerous.
20918c2ecf20Sopenharmony_ci	 *							--ANK
20928c2ecf20Sopenharmony_ci	 */
20938c2ecf20Sopenharmony_ci}
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_cistatic irqreturn_t ace_interrupt(int irq, void *dev_id)
20978c2ecf20Sopenharmony_ci{
20988c2ecf20Sopenharmony_ci	struct net_device *dev = (struct net_device *)dev_id;
20998c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
21008c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
21018c2ecf20Sopenharmony_ci	u32 idx;
21028c2ecf20Sopenharmony_ci	u32 txcsm, rxretcsm, rxretprd;
21038c2ecf20Sopenharmony_ci	u32 evtcsm, evtprd;
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	/*
21068c2ecf20Sopenharmony_ci	 * In case of PCI shared interrupts or spurious interrupts,
21078c2ecf20Sopenharmony_ci	 * we want to make sure it is actually our interrupt before
21088c2ecf20Sopenharmony_ci	 * spending any time in here.
21098c2ecf20Sopenharmony_ci	 */
21108c2ecf20Sopenharmony_ci	if (!(readl(&regs->HostCtrl) & IN_INT))
21118c2ecf20Sopenharmony_ci		return IRQ_NONE;
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	/*
21148c2ecf20Sopenharmony_ci	 * ACK intr now. Otherwise we will lose updates to rx_ret_prd,
21158c2ecf20Sopenharmony_ci	 * which happened _after_ rxretprd = *ap->rx_ret_prd; but before
21168c2ecf20Sopenharmony_ci	 * writel(0, &regs->Mb0Lo).
21178c2ecf20Sopenharmony_ci	 *
21188c2ecf20Sopenharmony_ci	 * "IRQ avoidance" recommended in docs applies to IRQs served
21198c2ecf20Sopenharmony_ci	 * threads and it is wrong even for that case.
21208c2ecf20Sopenharmony_ci	 */
21218c2ecf20Sopenharmony_ci	writel(0, &regs->Mb0Lo);
21228c2ecf20Sopenharmony_ci	readl(&regs->Mb0Lo);
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	/*
21258c2ecf20Sopenharmony_ci	 * There is no conflict between transmit handling in
21268c2ecf20Sopenharmony_ci	 * start_xmit and receive processing, thus there is no reason
21278c2ecf20Sopenharmony_ci	 * to take a spin lock for RX handling. Wait until we start
21288c2ecf20Sopenharmony_ci	 * working on the other stuff - hey we don't need a spin lock
21298c2ecf20Sopenharmony_ci	 * anymore.
21308c2ecf20Sopenharmony_ci	 */
21318c2ecf20Sopenharmony_ci	rxretprd = *ap->rx_ret_prd;
21328c2ecf20Sopenharmony_ci	rxretcsm = ap->cur_rx;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	if (rxretprd != rxretcsm)
21358c2ecf20Sopenharmony_ci		ace_rx_int(dev, rxretprd, rxretcsm);
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	txcsm = *ap->tx_csm;
21388c2ecf20Sopenharmony_ci	idx = ap->tx_ret_csm;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	if (txcsm != idx) {
21418c2ecf20Sopenharmony_ci		/*
21428c2ecf20Sopenharmony_ci		 * If each skb takes only one descriptor this check degenerates
21438c2ecf20Sopenharmony_ci		 * to identity, because new space has just been opened.
21448c2ecf20Sopenharmony_ci		 * But if skbs are fragmented we must check that this index
21458c2ecf20Sopenharmony_ci		 * update releases enough of space, otherwise we just
21468c2ecf20Sopenharmony_ci		 * wait for device to make more work.
21478c2ecf20Sopenharmony_ci		 */
21488c2ecf20Sopenharmony_ci		if (!tx_ring_full(ap, txcsm, ap->tx_prd))
21498c2ecf20Sopenharmony_ci			ace_tx_int(dev, txcsm, idx);
21508c2ecf20Sopenharmony_ci	}
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	evtcsm = readl(&regs->EvtCsm);
21538c2ecf20Sopenharmony_ci	evtprd = *ap->evt_prd;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	if (evtcsm != evtprd) {
21568c2ecf20Sopenharmony_ci		evtcsm = ace_handle_event(dev, evtcsm, evtprd);
21578c2ecf20Sopenharmony_ci		writel(evtcsm, &regs->EvtCsm);
21588c2ecf20Sopenharmony_ci	}
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	/*
21618c2ecf20Sopenharmony_ci	 * This has to go last in the interrupt handler and run with
21628c2ecf20Sopenharmony_ci	 * the spin lock released ... what lock?
21638c2ecf20Sopenharmony_ci	 */
21648c2ecf20Sopenharmony_ci	if (netif_running(dev)) {
21658c2ecf20Sopenharmony_ci		int cur_size;
21668c2ecf20Sopenharmony_ci		int run_tasklet = 0;
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci		cur_size = atomic_read(&ap->cur_rx_bufs);
21698c2ecf20Sopenharmony_ci		if (cur_size < RX_LOW_STD_THRES) {
21708c2ecf20Sopenharmony_ci			if ((cur_size < RX_PANIC_STD_THRES) &&
21718c2ecf20Sopenharmony_ci			    !test_and_set_bit(0, &ap->std_refill_busy)) {
21728c2ecf20Sopenharmony_ci#ifdef DEBUG
21738c2ecf20Sopenharmony_ci				printk("low on std buffers %i\n", cur_size);
21748c2ecf20Sopenharmony_ci#endif
21758c2ecf20Sopenharmony_ci				ace_load_std_rx_ring(dev,
21768c2ecf20Sopenharmony_ci						     RX_RING_SIZE - cur_size);
21778c2ecf20Sopenharmony_ci			} else
21788c2ecf20Sopenharmony_ci				run_tasklet = 1;
21798c2ecf20Sopenharmony_ci		}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci		if (!ACE_IS_TIGON_I(ap)) {
21828c2ecf20Sopenharmony_ci			cur_size = atomic_read(&ap->cur_mini_bufs);
21838c2ecf20Sopenharmony_ci			if (cur_size < RX_LOW_MINI_THRES) {
21848c2ecf20Sopenharmony_ci				if ((cur_size < RX_PANIC_MINI_THRES) &&
21858c2ecf20Sopenharmony_ci				    !test_and_set_bit(0,
21868c2ecf20Sopenharmony_ci						      &ap->mini_refill_busy)) {
21878c2ecf20Sopenharmony_ci#ifdef DEBUG
21888c2ecf20Sopenharmony_ci					printk("low on mini buffers %i\n",
21898c2ecf20Sopenharmony_ci					       cur_size);
21908c2ecf20Sopenharmony_ci#endif
21918c2ecf20Sopenharmony_ci					ace_load_mini_rx_ring(dev,
21928c2ecf20Sopenharmony_ci							      RX_MINI_SIZE - cur_size);
21938c2ecf20Sopenharmony_ci				} else
21948c2ecf20Sopenharmony_ci					run_tasklet = 1;
21958c2ecf20Sopenharmony_ci			}
21968c2ecf20Sopenharmony_ci		}
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci		if (ap->jumbo) {
21998c2ecf20Sopenharmony_ci			cur_size = atomic_read(&ap->cur_jumbo_bufs);
22008c2ecf20Sopenharmony_ci			if (cur_size < RX_LOW_JUMBO_THRES) {
22018c2ecf20Sopenharmony_ci				if ((cur_size < RX_PANIC_JUMBO_THRES) &&
22028c2ecf20Sopenharmony_ci				    !test_and_set_bit(0,
22038c2ecf20Sopenharmony_ci						      &ap->jumbo_refill_busy)){
22048c2ecf20Sopenharmony_ci#ifdef DEBUG
22058c2ecf20Sopenharmony_ci					printk("low on jumbo buffers %i\n",
22068c2ecf20Sopenharmony_ci					       cur_size);
22078c2ecf20Sopenharmony_ci#endif
22088c2ecf20Sopenharmony_ci					ace_load_jumbo_rx_ring(dev,
22098c2ecf20Sopenharmony_ci							       RX_JUMBO_SIZE - cur_size);
22108c2ecf20Sopenharmony_ci				} else
22118c2ecf20Sopenharmony_ci					run_tasklet = 1;
22128c2ecf20Sopenharmony_ci			}
22138c2ecf20Sopenharmony_ci		}
22148c2ecf20Sopenharmony_ci		if (run_tasklet && !ap->tasklet_pending) {
22158c2ecf20Sopenharmony_ci			ap->tasklet_pending = 1;
22168c2ecf20Sopenharmony_ci			tasklet_schedule(&ap->ace_tasklet);
22178c2ecf20Sopenharmony_ci		}
22188c2ecf20Sopenharmony_ci	}
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
22218c2ecf20Sopenharmony_ci}
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_cistatic int ace_open(struct net_device *dev)
22248c2ecf20Sopenharmony_ci{
22258c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
22268c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
22278c2ecf20Sopenharmony_ci	struct cmd cmd;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	if (!(ap->fw_running)) {
22308c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Firmware not running!\n", dev->name);
22318c2ecf20Sopenharmony_ci		return -EBUSY;
22328c2ecf20Sopenharmony_ci	}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	writel(dev->mtu + ETH_HLEN + 4, &regs->IfMtu);
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	cmd.evt = C_CLEAR_STATS;
22378c2ecf20Sopenharmony_ci	cmd.code = 0;
22388c2ecf20Sopenharmony_ci	cmd.idx = 0;
22398c2ecf20Sopenharmony_ci	ace_issue_cmd(regs, &cmd);
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	cmd.evt = C_HOST_STATE;
22428c2ecf20Sopenharmony_ci	cmd.code = C_C_STACK_UP;
22438c2ecf20Sopenharmony_ci	cmd.idx = 0;
22448c2ecf20Sopenharmony_ci	ace_issue_cmd(regs, &cmd);
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	if (ap->jumbo &&
22478c2ecf20Sopenharmony_ci	    !test_and_set_bit(0, &ap->jumbo_refill_busy))
22488c2ecf20Sopenharmony_ci		ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE);
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
22518c2ecf20Sopenharmony_ci		cmd.evt = C_SET_PROMISC_MODE;
22528c2ecf20Sopenharmony_ci		cmd.code = C_C_PROMISC_ENABLE;
22538c2ecf20Sopenharmony_ci		cmd.idx = 0;
22548c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci		ap->promisc = 1;
22578c2ecf20Sopenharmony_ci	}else
22588c2ecf20Sopenharmony_ci		ap->promisc = 0;
22598c2ecf20Sopenharmony_ci	ap->mcast_all = 0;
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci#if 0
22628c2ecf20Sopenharmony_ci	cmd.evt = C_LNK_NEGOTIATION;
22638c2ecf20Sopenharmony_ci	cmd.code = 0;
22648c2ecf20Sopenharmony_ci	cmd.idx = 0;
22658c2ecf20Sopenharmony_ci	ace_issue_cmd(regs, &cmd);
22668c2ecf20Sopenharmony_ci#endif
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	netif_start_queue(dev);
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	/*
22718c2ecf20Sopenharmony_ci	 * Setup the bottom half rx ring refill handler
22728c2ecf20Sopenharmony_ci	 */
22738c2ecf20Sopenharmony_ci	tasklet_setup(&ap->ace_tasklet, ace_tasklet);
22748c2ecf20Sopenharmony_ci	return 0;
22758c2ecf20Sopenharmony_ci}
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_cistatic int ace_close(struct net_device *dev)
22798c2ecf20Sopenharmony_ci{
22808c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
22818c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
22828c2ecf20Sopenharmony_ci	struct cmd cmd;
22838c2ecf20Sopenharmony_ci	unsigned long flags;
22848c2ecf20Sopenharmony_ci	short i;
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	/*
22878c2ecf20Sopenharmony_ci	 * Without (or before) releasing irq and stopping hardware, this
22888c2ecf20Sopenharmony_ci	 * is an absolute non-sense, by the way. It will be reset instantly
22898c2ecf20Sopenharmony_ci	 * by the first irq.
22908c2ecf20Sopenharmony_ci	 */
22918c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	if (ap->promisc) {
22958c2ecf20Sopenharmony_ci		cmd.evt = C_SET_PROMISC_MODE;
22968c2ecf20Sopenharmony_ci		cmd.code = C_C_PROMISC_DISABLE;
22978c2ecf20Sopenharmony_ci		cmd.idx = 0;
22988c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
22998c2ecf20Sopenharmony_ci		ap->promisc = 0;
23008c2ecf20Sopenharmony_ci	}
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	cmd.evt = C_HOST_STATE;
23038c2ecf20Sopenharmony_ci	cmd.code = C_C_STACK_DOWN;
23048c2ecf20Sopenharmony_ci	cmd.idx = 0;
23058c2ecf20Sopenharmony_ci	ace_issue_cmd(regs, &cmd);
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	tasklet_kill(&ap->ace_tasklet);
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	/*
23108c2ecf20Sopenharmony_ci	 * Make sure one CPU is not processing packets while
23118c2ecf20Sopenharmony_ci	 * buffers are being released by another.
23128c2ecf20Sopenharmony_ci	 */
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	local_irq_save(flags);
23158c2ecf20Sopenharmony_ci	ace_mask_irq(dev);
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
23188c2ecf20Sopenharmony_ci		struct sk_buff *skb;
23198c2ecf20Sopenharmony_ci		struct tx_ring_info *info;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci		info = ap->skb->tx_skbuff + i;
23228c2ecf20Sopenharmony_ci		skb = info->skb;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci		if (dma_unmap_len(info, maplen)) {
23258c2ecf20Sopenharmony_ci			if (ACE_IS_TIGON_I(ap)) {
23268c2ecf20Sopenharmony_ci				/* NB: TIGON_1 is special, tx_ring is in io space */
23278c2ecf20Sopenharmony_ci				struct tx_desc __iomem *tx;
23288c2ecf20Sopenharmony_ci				tx = (__force struct tx_desc __iomem *) &ap->tx_ring[i];
23298c2ecf20Sopenharmony_ci				writel(0, &tx->addr.addrhi);
23308c2ecf20Sopenharmony_ci				writel(0, &tx->addr.addrlo);
23318c2ecf20Sopenharmony_ci				writel(0, &tx->flagsize);
23328c2ecf20Sopenharmony_ci			} else
23338c2ecf20Sopenharmony_ci				memset(ap->tx_ring + i, 0,
23348c2ecf20Sopenharmony_ci				       sizeof(struct tx_desc));
23358c2ecf20Sopenharmony_ci			dma_unmap_page(&ap->pdev->dev,
23368c2ecf20Sopenharmony_ci				       dma_unmap_addr(info, mapping),
23378c2ecf20Sopenharmony_ci				       dma_unmap_len(info, maplen),
23388c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
23398c2ecf20Sopenharmony_ci			dma_unmap_len_set(info, maplen, 0);
23408c2ecf20Sopenharmony_ci		}
23418c2ecf20Sopenharmony_ci		if (skb) {
23428c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
23438c2ecf20Sopenharmony_ci			info->skb = NULL;
23448c2ecf20Sopenharmony_ci		}
23458c2ecf20Sopenharmony_ci	}
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci	if (ap->jumbo) {
23488c2ecf20Sopenharmony_ci		cmd.evt = C_RESET_JUMBO_RNG;
23498c2ecf20Sopenharmony_ci		cmd.code = 0;
23508c2ecf20Sopenharmony_ci		cmd.idx = 0;
23518c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
23528c2ecf20Sopenharmony_ci	}
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	ace_unmask_irq(dev);
23558c2ecf20Sopenharmony_ci	local_irq_restore(flags);
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	return 0;
23588c2ecf20Sopenharmony_ci}
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_cistatic inline dma_addr_t
23628c2ecf20Sopenharmony_ciace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
23638c2ecf20Sopenharmony_ci	       struct sk_buff *tail, u32 idx)
23648c2ecf20Sopenharmony_ci{
23658c2ecf20Sopenharmony_ci	dma_addr_t mapping;
23668c2ecf20Sopenharmony_ci	struct tx_ring_info *info;
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	mapping = dma_map_page(&ap->pdev->dev, virt_to_page(skb->data),
23698c2ecf20Sopenharmony_ci			       offset_in_page(skb->data), skb->len,
23708c2ecf20Sopenharmony_ci			       DMA_TO_DEVICE);
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	info = ap->skb->tx_skbuff + idx;
23738c2ecf20Sopenharmony_ci	info->skb = tail;
23748c2ecf20Sopenharmony_ci	dma_unmap_addr_set(info, mapping, mapping);
23758c2ecf20Sopenharmony_ci	dma_unmap_len_set(info, maplen, skb->len);
23768c2ecf20Sopenharmony_ci	return mapping;
23778c2ecf20Sopenharmony_ci}
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistatic inline void
23818c2ecf20Sopenharmony_ciace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr,
23828c2ecf20Sopenharmony_ci	       u32 flagsize, u32 vlan_tag)
23838c2ecf20Sopenharmony_ci{
23848c2ecf20Sopenharmony_ci#if !USE_TX_COAL_NOW
23858c2ecf20Sopenharmony_ci	flagsize &= ~BD_FLG_COAL_NOW;
23868c2ecf20Sopenharmony_ci#endif
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	if (ACE_IS_TIGON_I(ap)) {
23898c2ecf20Sopenharmony_ci		struct tx_desc __iomem *io = (__force struct tx_desc __iomem *) desc;
23908c2ecf20Sopenharmony_ci		writel(addr >> 32, &io->addr.addrhi);
23918c2ecf20Sopenharmony_ci		writel(addr & 0xffffffff, &io->addr.addrlo);
23928c2ecf20Sopenharmony_ci		writel(flagsize, &io->flagsize);
23938c2ecf20Sopenharmony_ci		writel(vlan_tag, &io->vlanres);
23948c2ecf20Sopenharmony_ci	} else {
23958c2ecf20Sopenharmony_ci		desc->addr.addrhi = addr >> 32;
23968c2ecf20Sopenharmony_ci		desc->addr.addrlo = addr;
23978c2ecf20Sopenharmony_ci		desc->flagsize = flagsize;
23988c2ecf20Sopenharmony_ci		desc->vlanres = vlan_tag;
23998c2ecf20Sopenharmony_ci	}
24008c2ecf20Sopenharmony_ci}
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_cistatic netdev_tx_t ace_start_xmit(struct sk_buff *skb,
24048c2ecf20Sopenharmony_ci				  struct net_device *dev)
24058c2ecf20Sopenharmony_ci{
24068c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
24078c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
24088c2ecf20Sopenharmony_ci	struct tx_desc *desc;
24098c2ecf20Sopenharmony_ci	u32 idx, flagsize;
24108c2ecf20Sopenharmony_ci	unsigned long maxjiff = jiffies + 3*HZ;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_cirestart:
24138c2ecf20Sopenharmony_ci	idx = ap->tx_prd;
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	if (tx_ring_full(ap, ap->tx_ret_csm, idx))
24168c2ecf20Sopenharmony_ci		goto overflow;
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	if (!skb_shinfo(skb)->nr_frags)	{
24198c2ecf20Sopenharmony_ci		dma_addr_t mapping;
24208c2ecf20Sopenharmony_ci		u32 vlan_tag = 0;
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci		mapping = ace_map_tx_skb(ap, skb, skb, idx);
24238c2ecf20Sopenharmony_ci		flagsize = (skb->len << 16) | (BD_FLG_END);
24248c2ecf20Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_PARTIAL)
24258c2ecf20Sopenharmony_ci			flagsize |= BD_FLG_TCP_UDP_SUM;
24268c2ecf20Sopenharmony_ci		if (skb_vlan_tag_present(skb)) {
24278c2ecf20Sopenharmony_ci			flagsize |= BD_FLG_VLAN_TAG;
24288c2ecf20Sopenharmony_ci			vlan_tag = skb_vlan_tag_get(skb);
24298c2ecf20Sopenharmony_ci		}
24308c2ecf20Sopenharmony_ci		desc = ap->tx_ring + idx;
24318c2ecf20Sopenharmony_ci		idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci		/* Look at ace_tx_int for explanations. */
24348c2ecf20Sopenharmony_ci		if (tx_ring_full(ap, ap->tx_ret_csm, idx))
24358c2ecf20Sopenharmony_ci			flagsize |= BD_FLG_COAL_NOW;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci		ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag);
24388c2ecf20Sopenharmony_ci	} else {
24398c2ecf20Sopenharmony_ci		dma_addr_t mapping;
24408c2ecf20Sopenharmony_ci		u32 vlan_tag = 0;
24418c2ecf20Sopenharmony_ci		int i, len = 0;
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci		mapping = ace_map_tx_skb(ap, skb, NULL, idx);
24448c2ecf20Sopenharmony_ci		flagsize = (skb_headlen(skb) << 16);
24458c2ecf20Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_PARTIAL)
24468c2ecf20Sopenharmony_ci			flagsize |= BD_FLG_TCP_UDP_SUM;
24478c2ecf20Sopenharmony_ci		if (skb_vlan_tag_present(skb)) {
24488c2ecf20Sopenharmony_ci			flagsize |= BD_FLG_VLAN_TAG;
24498c2ecf20Sopenharmony_ci			vlan_tag = skb_vlan_tag_get(skb);
24508c2ecf20Sopenharmony_ci		}
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci		ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize, vlan_tag);
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci		idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
24578c2ecf20Sopenharmony_ci			const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
24588c2ecf20Sopenharmony_ci			struct tx_ring_info *info;
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci			len += skb_frag_size(frag);
24618c2ecf20Sopenharmony_ci			info = ap->skb->tx_skbuff + idx;
24628c2ecf20Sopenharmony_ci			desc = ap->tx_ring + idx;
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci			mapping = skb_frag_dma_map(&ap->pdev->dev, frag, 0,
24658c2ecf20Sopenharmony_ci						   skb_frag_size(frag),
24668c2ecf20Sopenharmony_ci						   DMA_TO_DEVICE);
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci			flagsize = skb_frag_size(frag) << 16;
24698c2ecf20Sopenharmony_ci			if (skb->ip_summed == CHECKSUM_PARTIAL)
24708c2ecf20Sopenharmony_ci				flagsize |= BD_FLG_TCP_UDP_SUM;
24718c2ecf20Sopenharmony_ci			idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci			if (i == skb_shinfo(skb)->nr_frags - 1) {
24748c2ecf20Sopenharmony_ci				flagsize |= BD_FLG_END;
24758c2ecf20Sopenharmony_ci				if (tx_ring_full(ap, ap->tx_ret_csm, idx))
24768c2ecf20Sopenharmony_ci					flagsize |= BD_FLG_COAL_NOW;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci				/*
24798c2ecf20Sopenharmony_ci				 * Only the last fragment frees
24808c2ecf20Sopenharmony_ci				 * the skb!
24818c2ecf20Sopenharmony_ci				 */
24828c2ecf20Sopenharmony_ci				info->skb = skb;
24838c2ecf20Sopenharmony_ci			} else {
24848c2ecf20Sopenharmony_ci				info->skb = NULL;
24858c2ecf20Sopenharmony_ci			}
24868c2ecf20Sopenharmony_ci			dma_unmap_addr_set(info, mapping, mapping);
24878c2ecf20Sopenharmony_ci			dma_unmap_len_set(info, maplen, skb_frag_size(frag));
24888c2ecf20Sopenharmony_ci			ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag);
24898c2ecf20Sopenharmony_ci		}
24908c2ecf20Sopenharmony_ci	}
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci 	wmb();
24938c2ecf20Sopenharmony_ci 	ap->tx_prd = idx;
24948c2ecf20Sopenharmony_ci 	ace_set_txprd(regs, ap, idx);
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	if (flagsize & BD_FLG_COAL_NOW) {
24978c2ecf20Sopenharmony_ci		netif_stop_queue(dev);
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci		/*
25008c2ecf20Sopenharmony_ci		 * A TX-descriptor producer (an IRQ) might have gotten
25018c2ecf20Sopenharmony_ci		 * between, making the ring free again. Since xmit is
25028c2ecf20Sopenharmony_ci		 * serialized, this is the only situation we have to
25038c2ecf20Sopenharmony_ci		 * re-test.
25048c2ecf20Sopenharmony_ci		 */
25058c2ecf20Sopenharmony_ci		if (!tx_ring_full(ap, ap->tx_ret_csm, idx))
25068c2ecf20Sopenharmony_ci			netif_wake_queue(dev);
25078c2ecf20Sopenharmony_ci	}
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_cioverflow:
25128c2ecf20Sopenharmony_ci	/*
25138c2ecf20Sopenharmony_ci	 * This race condition is unavoidable with lock-free drivers.
25148c2ecf20Sopenharmony_ci	 * We wake up the queue _before_ tx_prd is advanced, so that we can
25158c2ecf20Sopenharmony_ci	 * enter hard_start_xmit too early, while tx ring still looks closed.
25168c2ecf20Sopenharmony_ci	 * This happens ~1-4 times per 100000 packets, so that we can allow
25178c2ecf20Sopenharmony_ci	 * to loop syncing to other CPU. Probably, we need an additional
25188c2ecf20Sopenharmony_ci	 * wmb() in ace_tx_intr as well.
25198c2ecf20Sopenharmony_ci	 *
25208c2ecf20Sopenharmony_ci	 * Note that this race is relieved by reserving one more entry
25218c2ecf20Sopenharmony_ci	 * in tx ring than it is necessary (see original non-SG driver).
25228c2ecf20Sopenharmony_ci	 * However, with SG we need to reserve 2*MAX_SKB_FRAGS+1, which
25238c2ecf20Sopenharmony_ci	 * is already overkill.
25248c2ecf20Sopenharmony_ci	 *
25258c2ecf20Sopenharmony_ci	 * Alternative is to return with 1 not throttling queue. In this
25268c2ecf20Sopenharmony_ci	 * case loop becomes longer, no more useful effects.
25278c2ecf20Sopenharmony_ci	 */
25288c2ecf20Sopenharmony_ci	if (time_before(jiffies, maxjiff)) {
25298c2ecf20Sopenharmony_ci		barrier();
25308c2ecf20Sopenharmony_ci		cpu_relax();
25318c2ecf20Sopenharmony_ci		goto restart;
25328c2ecf20Sopenharmony_ci	}
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	/* The ring is stuck full. */
25358c2ecf20Sopenharmony_ci	printk(KERN_WARNING "%s: Transmit ring stuck full\n", dev->name);
25368c2ecf20Sopenharmony_ci	return NETDEV_TX_BUSY;
25378c2ecf20Sopenharmony_ci}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_cistatic int ace_change_mtu(struct net_device *dev, int new_mtu)
25418c2ecf20Sopenharmony_ci{
25428c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
25438c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	writel(new_mtu + ETH_HLEN + 4, &regs->IfMtu);
25468c2ecf20Sopenharmony_ci	dev->mtu = new_mtu;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	if (new_mtu > ACE_STD_MTU) {
25498c2ecf20Sopenharmony_ci		if (!(ap->jumbo)) {
25508c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Enabling Jumbo frame "
25518c2ecf20Sopenharmony_ci			       "support\n", dev->name);
25528c2ecf20Sopenharmony_ci			ap->jumbo = 1;
25538c2ecf20Sopenharmony_ci			if (!test_and_set_bit(0, &ap->jumbo_refill_busy))
25548c2ecf20Sopenharmony_ci				ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE);
25558c2ecf20Sopenharmony_ci			ace_set_rxtx_parms(dev, 1);
25568c2ecf20Sopenharmony_ci		}
25578c2ecf20Sopenharmony_ci	} else {
25588c2ecf20Sopenharmony_ci		while (test_and_set_bit(0, &ap->jumbo_refill_busy));
25598c2ecf20Sopenharmony_ci		ace_sync_irq(dev->irq);
25608c2ecf20Sopenharmony_ci		ace_set_rxtx_parms(dev, 0);
25618c2ecf20Sopenharmony_ci		if (ap->jumbo) {
25628c2ecf20Sopenharmony_ci			struct cmd cmd;
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci			cmd.evt = C_RESET_JUMBO_RNG;
25658c2ecf20Sopenharmony_ci			cmd.code = 0;
25668c2ecf20Sopenharmony_ci			cmd.idx = 0;
25678c2ecf20Sopenharmony_ci			ace_issue_cmd(regs, &cmd);
25688c2ecf20Sopenharmony_ci		}
25698c2ecf20Sopenharmony_ci	}
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	return 0;
25728c2ecf20Sopenharmony_ci}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_cistatic int ace_get_link_ksettings(struct net_device *dev,
25758c2ecf20Sopenharmony_ci				  struct ethtool_link_ksettings *cmd)
25768c2ecf20Sopenharmony_ci{
25778c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
25788c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
25798c2ecf20Sopenharmony_ci	u32 link;
25808c2ecf20Sopenharmony_ci	u32 supported;
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof(struct ethtool_link_ksettings));
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
25858c2ecf20Sopenharmony_ci		     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
25868c2ecf20Sopenharmony_ci		     SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full |
25878c2ecf20Sopenharmony_ci		     SUPPORTED_Autoneg | SUPPORTED_FIBRE);
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	cmd->base.port = PORT_FIBRE;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	link = readl(&regs->GigLnkState);
25928c2ecf20Sopenharmony_ci	if (link & LNK_1000MB) {
25938c2ecf20Sopenharmony_ci		cmd->base.speed = SPEED_1000;
25948c2ecf20Sopenharmony_ci	} else {
25958c2ecf20Sopenharmony_ci		link = readl(&regs->FastLnkState);
25968c2ecf20Sopenharmony_ci		if (link & LNK_100MB)
25978c2ecf20Sopenharmony_ci			cmd->base.speed = SPEED_100;
25988c2ecf20Sopenharmony_ci		else if (link & LNK_10MB)
25998c2ecf20Sopenharmony_ci			cmd->base.speed = SPEED_10;
26008c2ecf20Sopenharmony_ci		else
26018c2ecf20Sopenharmony_ci			cmd->base.speed = 0;
26028c2ecf20Sopenharmony_ci	}
26038c2ecf20Sopenharmony_ci	if (link & LNK_FULL_DUPLEX)
26048c2ecf20Sopenharmony_ci		cmd->base.duplex = DUPLEX_FULL;
26058c2ecf20Sopenharmony_ci	else
26068c2ecf20Sopenharmony_ci		cmd->base.duplex = DUPLEX_HALF;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	if (link & LNK_NEGOTIATE)
26098c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_ENABLE;
26108c2ecf20Sopenharmony_ci	else
26118c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_DISABLE;
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci#if 0
26148c2ecf20Sopenharmony_ci	/*
26158c2ecf20Sopenharmony_ci	 * Current struct ethtool_cmd is insufficient
26168c2ecf20Sopenharmony_ci	 */
26178c2ecf20Sopenharmony_ci	ecmd->trace = readl(&regs->TuneTrace);
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	ecmd->txcoal = readl(&regs->TuneTxCoalTicks);
26208c2ecf20Sopenharmony_ci	ecmd->rxcoal = readl(&regs->TuneRxCoalTicks);
26218c2ecf20Sopenharmony_ci#endif
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
26248c2ecf20Sopenharmony_ci						supported);
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	return 0;
26278c2ecf20Sopenharmony_ci}
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_cistatic int ace_set_link_ksettings(struct net_device *dev,
26308c2ecf20Sopenharmony_ci				  const struct ethtool_link_ksettings *cmd)
26318c2ecf20Sopenharmony_ci{
26328c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
26338c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
26348c2ecf20Sopenharmony_ci	u32 link, speed;
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	link = readl(&regs->GigLnkState);
26378c2ecf20Sopenharmony_ci	if (link & LNK_1000MB)
26388c2ecf20Sopenharmony_ci		speed = SPEED_1000;
26398c2ecf20Sopenharmony_ci	else {
26408c2ecf20Sopenharmony_ci		link = readl(&regs->FastLnkState);
26418c2ecf20Sopenharmony_ci		if (link & LNK_100MB)
26428c2ecf20Sopenharmony_ci			speed = SPEED_100;
26438c2ecf20Sopenharmony_ci		else if (link & LNK_10MB)
26448c2ecf20Sopenharmony_ci			speed = SPEED_10;
26458c2ecf20Sopenharmony_ci		else
26468c2ecf20Sopenharmony_ci			speed = SPEED_100;
26478c2ecf20Sopenharmony_ci	}
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci	link = LNK_ENABLE | LNK_1000MB | LNK_100MB | LNK_10MB |
26508c2ecf20Sopenharmony_ci		LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL;
26518c2ecf20Sopenharmony_ci	if (!ACE_IS_TIGON_I(ap))
26528c2ecf20Sopenharmony_ci		link |= LNK_TX_FLOW_CTL_Y;
26538c2ecf20Sopenharmony_ci	if (cmd->base.autoneg == AUTONEG_ENABLE)
26548c2ecf20Sopenharmony_ci		link |= LNK_NEGOTIATE;
26558c2ecf20Sopenharmony_ci	if (cmd->base.speed != speed) {
26568c2ecf20Sopenharmony_ci		link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB);
26578c2ecf20Sopenharmony_ci		switch (cmd->base.speed) {
26588c2ecf20Sopenharmony_ci		case SPEED_1000:
26598c2ecf20Sopenharmony_ci			link |= LNK_1000MB;
26608c2ecf20Sopenharmony_ci			break;
26618c2ecf20Sopenharmony_ci		case SPEED_100:
26628c2ecf20Sopenharmony_ci			link |= LNK_100MB;
26638c2ecf20Sopenharmony_ci			break;
26648c2ecf20Sopenharmony_ci		case SPEED_10:
26658c2ecf20Sopenharmony_ci			link |= LNK_10MB;
26668c2ecf20Sopenharmony_ci			break;
26678c2ecf20Sopenharmony_ci		}
26688c2ecf20Sopenharmony_ci	}
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	if (cmd->base.duplex == DUPLEX_FULL)
26718c2ecf20Sopenharmony_ci		link |= LNK_FULL_DUPLEX;
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	if (link != ap->link) {
26748c2ecf20Sopenharmony_ci		struct cmd cmd;
26758c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Renegotiating link state\n",
26768c2ecf20Sopenharmony_ci		       dev->name);
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci		ap->link = link;
26798c2ecf20Sopenharmony_ci		writel(link, &regs->TuneLink);
26808c2ecf20Sopenharmony_ci		if (!ACE_IS_TIGON_I(ap))
26818c2ecf20Sopenharmony_ci			writel(link, &regs->TuneFastLink);
26828c2ecf20Sopenharmony_ci		wmb();
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci		cmd.evt = C_LNK_NEGOTIATION;
26858c2ecf20Sopenharmony_ci		cmd.code = 0;
26868c2ecf20Sopenharmony_ci		cmd.idx = 0;
26878c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
26888c2ecf20Sopenharmony_ci	}
26898c2ecf20Sopenharmony_ci	return 0;
26908c2ecf20Sopenharmony_ci}
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_cistatic void ace_get_drvinfo(struct net_device *dev,
26938c2ecf20Sopenharmony_ci			    struct ethtool_drvinfo *info)
26948c2ecf20Sopenharmony_ci{
26958c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	strlcpy(info->driver, "acenic", sizeof(info->driver));
26988c2ecf20Sopenharmony_ci	snprintf(info->fw_version, sizeof(info->version), "%i.%i.%i",
26998c2ecf20Sopenharmony_ci		 ap->firmware_major, ap->firmware_minor, ap->firmware_fix);
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	if (ap->pdev)
27028c2ecf20Sopenharmony_ci		strlcpy(info->bus_info, pci_name(ap->pdev),
27038c2ecf20Sopenharmony_ci			sizeof(info->bus_info));
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci}
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci/*
27088c2ecf20Sopenharmony_ci * Set the hardware MAC address.
27098c2ecf20Sopenharmony_ci */
27108c2ecf20Sopenharmony_cistatic int ace_set_mac_addr(struct net_device *dev, void *p)
27118c2ecf20Sopenharmony_ci{
27128c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
27138c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
27148c2ecf20Sopenharmony_ci	struct sockaddr *addr=p;
27158c2ecf20Sopenharmony_ci	u8 *da;
27168c2ecf20Sopenharmony_ci	struct cmd cmd;
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci	if(netif_running(dev))
27198c2ecf20Sopenharmony_ci		return -EBUSY;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	da = (u8 *)dev->dev_addr;
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	writel(da[0] << 8 | da[1], &regs->MacAddrHi);
27268c2ecf20Sopenharmony_ci	writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5],
27278c2ecf20Sopenharmony_ci	       &regs->MacAddrLo);
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	cmd.evt = C_SET_MAC_ADDR;
27308c2ecf20Sopenharmony_ci	cmd.code = 0;
27318c2ecf20Sopenharmony_ci	cmd.idx = 0;
27328c2ecf20Sopenharmony_ci	ace_issue_cmd(regs, &cmd);
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci	return 0;
27358c2ecf20Sopenharmony_ci}
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_cistatic void ace_set_multicast_list(struct net_device *dev)
27398c2ecf20Sopenharmony_ci{
27408c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
27418c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
27428c2ecf20Sopenharmony_ci	struct cmd cmd;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	if ((dev->flags & IFF_ALLMULTI) && !(ap->mcast_all)) {
27458c2ecf20Sopenharmony_ci		cmd.evt = C_SET_MULTICAST_MODE;
27468c2ecf20Sopenharmony_ci		cmd.code = C_C_MCAST_ENABLE;
27478c2ecf20Sopenharmony_ci		cmd.idx = 0;
27488c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
27498c2ecf20Sopenharmony_ci		ap->mcast_all = 1;
27508c2ecf20Sopenharmony_ci	} else if (ap->mcast_all) {
27518c2ecf20Sopenharmony_ci		cmd.evt = C_SET_MULTICAST_MODE;
27528c2ecf20Sopenharmony_ci		cmd.code = C_C_MCAST_DISABLE;
27538c2ecf20Sopenharmony_ci		cmd.idx = 0;
27548c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
27558c2ecf20Sopenharmony_ci		ap->mcast_all = 0;
27568c2ecf20Sopenharmony_ci	}
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	if ((dev->flags & IFF_PROMISC) && !(ap->promisc)) {
27598c2ecf20Sopenharmony_ci		cmd.evt = C_SET_PROMISC_MODE;
27608c2ecf20Sopenharmony_ci		cmd.code = C_C_PROMISC_ENABLE;
27618c2ecf20Sopenharmony_ci		cmd.idx = 0;
27628c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
27638c2ecf20Sopenharmony_ci		ap->promisc = 1;
27648c2ecf20Sopenharmony_ci	}else if (!(dev->flags & IFF_PROMISC) && (ap->promisc)) {
27658c2ecf20Sopenharmony_ci		cmd.evt = C_SET_PROMISC_MODE;
27668c2ecf20Sopenharmony_ci		cmd.code = C_C_PROMISC_DISABLE;
27678c2ecf20Sopenharmony_ci		cmd.idx = 0;
27688c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
27698c2ecf20Sopenharmony_ci		ap->promisc = 0;
27708c2ecf20Sopenharmony_ci	}
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci	/*
27738c2ecf20Sopenharmony_ci	 * For the time being multicast relies on the upper layers
27748c2ecf20Sopenharmony_ci	 * filtering it properly. The Firmware does not allow one to
27758c2ecf20Sopenharmony_ci	 * set the entire multicast list at a time and keeping track of
27768c2ecf20Sopenharmony_ci	 * it here is going to be messy.
27778c2ecf20Sopenharmony_ci	 */
27788c2ecf20Sopenharmony_ci	if (!netdev_mc_empty(dev) && !ap->mcast_all) {
27798c2ecf20Sopenharmony_ci		cmd.evt = C_SET_MULTICAST_MODE;
27808c2ecf20Sopenharmony_ci		cmd.code = C_C_MCAST_ENABLE;
27818c2ecf20Sopenharmony_ci		cmd.idx = 0;
27828c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
27838c2ecf20Sopenharmony_ci	}else if (!ap->mcast_all) {
27848c2ecf20Sopenharmony_ci		cmd.evt = C_SET_MULTICAST_MODE;
27858c2ecf20Sopenharmony_ci		cmd.code = C_C_MCAST_DISABLE;
27868c2ecf20Sopenharmony_ci		cmd.idx = 0;
27878c2ecf20Sopenharmony_ci		ace_issue_cmd(regs, &cmd);
27888c2ecf20Sopenharmony_ci	}
27898c2ecf20Sopenharmony_ci}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci
27928c2ecf20Sopenharmony_cistatic struct net_device_stats *ace_get_stats(struct net_device *dev)
27938c2ecf20Sopenharmony_ci{
27948c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
27958c2ecf20Sopenharmony_ci	struct ace_mac_stats __iomem *mac_stats =
27968c2ecf20Sopenharmony_ci		(struct ace_mac_stats __iomem *)ap->regs->Stats;
27978c2ecf20Sopenharmony_ci
27988c2ecf20Sopenharmony_ci	dev->stats.rx_missed_errors = readl(&mac_stats->drop_space);
27998c2ecf20Sopenharmony_ci	dev->stats.multicast = readl(&mac_stats->kept_mc);
28008c2ecf20Sopenharmony_ci	dev->stats.collisions = readl(&mac_stats->coll);
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	return &dev->stats;
28038c2ecf20Sopenharmony_ci}
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_cistatic void ace_copy(struct ace_regs __iomem *regs, const __be32 *src,
28078c2ecf20Sopenharmony_ci		     u32 dest, int size)
28088c2ecf20Sopenharmony_ci{
28098c2ecf20Sopenharmony_ci	void __iomem *tdest;
28108c2ecf20Sopenharmony_ci	short tsize, i;
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	if (size <= 0)
28138c2ecf20Sopenharmony_ci		return;
28148c2ecf20Sopenharmony_ci
28158c2ecf20Sopenharmony_ci	while (size > 0) {
28168c2ecf20Sopenharmony_ci		tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
28178c2ecf20Sopenharmony_ci			    min_t(u32, size, ACE_WINDOW_SIZE));
28188c2ecf20Sopenharmony_ci		tdest = (void __iomem *) &regs->Window +
28198c2ecf20Sopenharmony_ci			(dest & (ACE_WINDOW_SIZE - 1));
28208c2ecf20Sopenharmony_ci		writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
28218c2ecf20Sopenharmony_ci		for (i = 0; i < (tsize / 4); i++) {
28228c2ecf20Sopenharmony_ci			/* Firmware is big-endian */
28238c2ecf20Sopenharmony_ci			writel(be32_to_cpup(src), tdest);
28248c2ecf20Sopenharmony_ci			src++;
28258c2ecf20Sopenharmony_ci			tdest += 4;
28268c2ecf20Sopenharmony_ci			dest += 4;
28278c2ecf20Sopenharmony_ci			size -= 4;
28288c2ecf20Sopenharmony_ci		}
28298c2ecf20Sopenharmony_ci	}
28308c2ecf20Sopenharmony_ci}
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_cistatic void ace_clear(struct ace_regs __iomem *regs, u32 dest, int size)
28348c2ecf20Sopenharmony_ci{
28358c2ecf20Sopenharmony_ci	void __iomem *tdest;
28368c2ecf20Sopenharmony_ci	short tsize = 0, i;
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci	if (size <= 0)
28398c2ecf20Sopenharmony_ci		return;
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	while (size > 0) {
28428c2ecf20Sopenharmony_ci		tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
28438c2ecf20Sopenharmony_ci				min_t(u32, size, ACE_WINDOW_SIZE));
28448c2ecf20Sopenharmony_ci		tdest = (void __iomem *) &regs->Window +
28458c2ecf20Sopenharmony_ci			(dest & (ACE_WINDOW_SIZE - 1));
28468c2ecf20Sopenharmony_ci		writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci		for (i = 0; i < (tsize / 4); i++) {
28498c2ecf20Sopenharmony_ci			writel(0, tdest + i*4);
28508c2ecf20Sopenharmony_ci		}
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci		dest += tsize;
28538c2ecf20Sopenharmony_ci		size -= tsize;
28548c2ecf20Sopenharmony_ci	}
28558c2ecf20Sopenharmony_ci}
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci/*
28598c2ecf20Sopenharmony_ci * Download the firmware into the SRAM on the NIC
28608c2ecf20Sopenharmony_ci *
28618c2ecf20Sopenharmony_ci * This operation requires the NIC to be halted and is performed with
28628c2ecf20Sopenharmony_ci * interrupts disabled and with the spinlock hold.
28638c2ecf20Sopenharmony_ci */
28648c2ecf20Sopenharmony_cistatic int ace_load_firmware(struct net_device *dev)
28658c2ecf20Sopenharmony_ci{
28668c2ecf20Sopenharmony_ci	const struct firmware *fw;
28678c2ecf20Sopenharmony_ci	const char *fw_name = "acenic/tg2.bin";
28688c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
28698c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
28708c2ecf20Sopenharmony_ci	const __be32 *fw_data;
28718c2ecf20Sopenharmony_ci	u32 load_addr;
28728c2ecf20Sopenharmony_ci	int ret;
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci	if (!(readl(&regs->CpuCtrl) & CPU_HALTED)) {
28758c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: trying to download firmware while the "
28768c2ecf20Sopenharmony_ci		       "CPU is running!\n", ap->name);
28778c2ecf20Sopenharmony_ci		return -EFAULT;
28788c2ecf20Sopenharmony_ci	}
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	if (ACE_IS_TIGON_I(ap))
28818c2ecf20Sopenharmony_ci		fw_name = "acenic/tg1.bin";
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci	ret = request_firmware(&fw, fw_name, &ap->pdev->dev);
28848c2ecf20Sopenharmony_ci	if (ret) {
28858c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
28868c2ecf20Sopenharmony_ci		       ap->name, fw_name);
28878c2ecf20Sopenharmony_ci		return ret;
28888c2ecf20Sopenharmony_ci	}
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci	fw_data = (void *)fw->data;
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	/* Firmware blob starts with version numbers, followed by
28938c2ecf20Sopenharmony_ci	   load and start address. Remainder is the blob to be loaded
28948c2ecf20Sopenharmony_ci	   contiguously from load address. We don't bother to represent
28958c2ecf20Sopenharmony_ci	   the BSS/SBSS sections any more, since we were clearing the
28968c2ecf20Sopenharmony_ci	   whole thing anyway. */
28978c2ecf20Sopenharmony_ci	ap->firmware_major = fw->data[0];
28988c2ecf20Sopenharmony_ci	ap->firmware_minor = fw->data[1];
28998c2ecf20Sopenharmony_ci	ap->firmware_fix = fw->data[2];
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci	ap->firmware_start = be32_to_cpu(fw_data[1]);
29028c2ecf20Sopenharmony_ci	if (ap->firmware_start < 0x4000 || ap->firmware_start >= 0x80000) {
29038c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: bogus load address %08x in \"%s\"\n",
29048c2ecf20Sopenharmony_ci		       ap->name, ap->firmware_start, fw_name);
29058c2ecf20Sopenharmony_ci		ret = -EINVAL;
29068c2ecf20Sopenharmony_ci		goto out;
29078c2ecf20Sopenharmony_ci	}
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci	load_addr = be32_to_cpu(fw_data[2]);
29108c2ecf20Sopenharmony_ci	if (load_addr < 0x4000 || load_addr >= 0x80000) {
29118c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: bogus load address %08x in \"%s\"\n",
29128c2ecf20Sopenharmony_ci		       ap->name, load_addr, fw_name);
29138c2ecf20Sopenharmony_ci		ret = -EINVAL;
29148c2ecf20Sopenharmony_ci		goto out;
29158c2ecf20Sopenharmony_ci	}
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	/*
29188c2ecf20Sopenharmony_ci	 * Do not try to clear more than 512KiB or we end up seeing
29198c2ecf20Sopenharmony_ci	 * funny things on NICs with only 512KiB SRAM
29208c2ecf20Sopenharmony_ci	 */
29218c2ecf20Sopenharmony_ci	ace_clear(regs, 0x2000, 0x80000-0x2000);
29228c2ecf20Sopenharmony_ci	ace_copy(regs, &fw_data[3], load_addr, fw->size-12);
29238c2ecf20Sopenharmony_ci out:
29248c2ecf20Sopenharmony_ci	release_firmware(fw);
29258c2ecf20Sopenharmony_ci	return ret;
29268c2ecf20Sopenharmony_ci}
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci/*
29308c2ecf20Sopenharmony_ci * The eeprom on the AceNIC is an Atmel i2c EEPROM.
29318c2ecf20Sopenharmony_ci *
29328c2ecf20Sopenharmony_ci * Accessing the EEPROM is `interesting' to say the least - don't read
29338c2ecf20Sopenharmony_ci * this code right after dinner.
29348c2ecf20Sopenharmony_ci *
29358c2ecf20Sopenharmony_ci * This is all about black magic and bit-banging the device .... I
29368c2ecf20Sopenharmony_ci * wonder in what hospital they have put the guy who designed the i2c
29378c2ecf20Sopenharmony_ci * specs.
29388c2ecf20Sopenharmony_ci *
29398c2ecf20Sopenharmony_ci * Oh yes, this is only the beginning!
29408c2ecf20Sopenharmony_ci *
29418c2ecf20Sopenharmony_ci * Thanks to Stevarino Webinski for helping tracking down the bugs in the
29428c2ecf20Sopenharmony_ci * code i2c readout code by beta testing all my hacks.
29438c2ecf20Sopenharmony_ci */
29448c2ecf20Sopenharmony_cistatic void eeprom_start(struct ace_regs __iomem *regs)
29458c2ecf20Sopenharmony_ci{
29468c2ecf20Sopenharmony_ci	u32 local;
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
29498c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
29508c2ecf20Sopenharmony_ci	local = readl(&regs->LocalCtrl);
29518c2ecf20Sopenharmony_ci	local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;
29528c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
29538c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
29548c2ecf20Sopenharmony_ci	mb();
29558c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
29568c2ecf20Sopenharmony_ci	local |= EEPROM_CLK_OUT;
29578c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
29588c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
29598c2ecf20Sopenharmony_ci	mb();
29608c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
29618c2ecf20Sopenharmony_ci	local &= ~EEPROM_DATA_OUT;
29628c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
29638c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
29648c2ecf20Sopenharmony_ci	mb();
29658c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
29668c2ecf20Sopenharmony_ci	local &= ~EEPROM_CLK_OUT;
29678c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
29688c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
29698c2ecf20Sopenharmony_ci	mb();
29708c2ecf20Sopenharmony_ci}
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_cistatic void eeprom_prep(struct ace_regs __iomem *regs, u8 magic)
29748c2ecf20Sopenharmony_ci{
29758c2ecf20Sopenharmony_ci	short i;
29768c2ecf20Sopenharmony_ci	u32 local;
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
29798c2ecf20Sopenharmony_ci	local = readl(&regs->LocalCtrl);
29808c2ecf20Sopenharmony_ci	local &= ~EEPROM_DATA_OUT;
29818c2ecf20Sopenharmony_ci	local |= EEPROM_WRITE_ENABLE;
29828c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
29838c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
29848c2ecf20Sopenharmony_ci	mb();
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++, magic <<= 1) {
29878c2ecf20Sopenharmony_ci		udelay(ACE_SHORT_DELAY);
29888c2ecf20Sopenharmony_ci		if (magic & 0x80)
29898c2ecf20Sopenharmony_ci			local |= EEPROM_DATA_OUT;
29908c2ecf20Sopenharmony_ci		else
29918c2ecf20Sopenharmony_ci			local &= ~EEPROM_DATA_OUT;
29928c2ecf20Sopenharmony_ci		writel(local, &regs->LocalCtrl);
29938c2ecf20Sopenharmony_ci		readl(&regs->LocalCtrl);
29948c2ecf20Sopenharmony_ci		mb();
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci		udelay(ACE_SHORT_DELAY);
29978c2ecf20Sopenharmony_ci		local |= EEPROM_CLK_OUT;
29988c2ecf20Sopenharmony_ci		writel(local, &regs->LocalCtrl);
29998c2ecf20Sopenharmony_ci		readl(&regs->LocalCtrl);
30008c2ecf20Sopenharmony_ci		mb();
30018c2ecf20Sopenharmony_ci		udelay(ACE_SHORT_DELAY);
30028c2ecf20Sopenharmony_ci		local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
30038c2ecf20Sopenharmony_ci		writel(local, &regs->LocalCtrl);
30048c2ecf20Sopenharmony_ci		readl(&regs->LocalCtrl);
30058c2ecf20Sopenharmony_ci		mb();
30068c2ecf20Sopenharmony_ci	}
30078c2ecf20Sopenharmony_ci}
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_cistatic int eeprom_check_ack(struct ace_regs __iomem *regs)
30118c2ecf20Sopenharmony_ci{
30128c2ecf20Sopenharmony_ci	int state;
30138c2ecf20Sopenharmony_ci	u32 local;
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci	local = readl(&regs->LocalCtrl);
30168c2ecf20Sopenharmony_ci	local &= ~EEPROM_WRITE_ENABLE;
30178c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
30188c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
30198c2ecf20Sopenharmony_ci	mb();
30208c2ecf20Sopenharmony_ci	udelay(ACE_LONG_DELAY);
30218c2ecf20Sopenharmony_ci	local |= EEPROM_CLK_OUT;
30228c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
30238c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
30248c2ecf20Sopenharmony_ci	mb();
30258c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
30268c2ecf20Sopenharmony_ci	/* sample data in middle of high clk */
30278c2ecf20Sopenharmony_ci	state = (readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0;
30288c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
30298c2ecf20Sopenharmony_ci	mb();
30308c2ecf20Sopenharmony_ci	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
30318c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
30328c2ecf20Sopenharmony_ci	mb();
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci	return state;
30358c2ecf20Sopenharmony_ci}
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_cistatic void eeprom_stop(struct ace_regs __iomem *regs)
30398c2ecf20Sopenharmony_ci{
30408c2ecf20Sopenharmony_ci	u32 local;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
30438c2ecf20Sopenharmony_ci	local = readl(&regs->LocalCtrl);
30448c2ecf20Sopenharmony_ci	local |= EEPROM_WRITE_ENABLE;
30458c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
30468c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
30478c2ecf20Sopenharmony_ci	mb();
30488c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
30498c2ecf20Sopenharmony_ci	local &= ~EEPROM_DATA_OUT;
30508c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
30518c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
30528c2ecf20Sopenharmony_ci	mb();
30538c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
30548c2ecf20Sopenharmony_ci	local |= EEPROM_CLK_OUT;
30558c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
30568c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
30578c2ecf20Sopenharmony_ci	mb();
30588c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
30598c2ecf20Sopenharmony_ci	local |= EEPROM_DATA_OUT;
30608c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
30618c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
30628c2ecf20Sopenharmony_ci	mb();
30638c2ecf20Sopenharmony_ci	udelay(ACE_LONG_DELAY);
30648c2ecf20Sopenharmony_ci	local &= ~EEPROM_CLK_OUT;
30658c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
30668c2ecf20Sopenharmony_ci	mb();
30678c2ecf20Sopenharmony_ci}
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci/*
30718c2ecf20Sopenharmony_ci * Read a whole byte from the EEPROM.
30728c2ecf20Sopenharmony_ci */
30738c2ecf20Sopenharmony_cistatic int read_eeprom_byte(struct net_device *dev, unsigned long offset)
30748c2ecf20Sopenharmony_ci{
30758c2ecf20Sopenharmony_ci	struct ace_private *ap = netdev_priv(dev);
30768c2ecf20Sopenharmony_ci	struct ace_regs __iomem *regs = ap->regs;
30778c2ecf20Sopenharmony_ci	unsigned long flags;
30788c2ecf20Sopenharmony_ci	u32 local;
30798c2ecf20Sopenharmony_ci	int result = 0;
30808c2ecf20Sopenharmony_ci	short i;
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci	/*
30838c2ecf20Sopenharmony_ci	 * Don't take interrupts on this CPU will bit banging
30848c2ecf20Sopenharmony_ci	 * the %#%#@$ I2C device
30858c2ecf20Sopenharmony_ci	 */
30868c2ecf20Sopenharmony_ci	local_irq_save(flags);
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci	eeprom_start(regs);
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_ci	eeprom_prep(regs, EEPROM_WRITE_SELECT);
30918c2ecf20Sopenharmony_ci	if (eeprom_check_ack(regs)) {
30928c2ecf20Sopenharmony_ci		local_irq_restore(flags);
30938c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Unable to sync eeprom\n", ap->name);
30948c2ecf20Sopenharmony_ci		result = -EIO;
30958c2ecf20Sopenharmony_ci		goto eeprom_read_error;
30968c2ecf20Sopenharmony_ci	}
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_ci	eeprom_prep(regs, (offset >> 8) & 0xff);
30998c2ecf20Sopenharmony_ci	if (eeprom_check_ack(regs)) {
31008c2ecf20Sopenharmony_ci		local_irq_restore(flags);
31018c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Unable to set address byte 0\n",
31028c2ecf20Sopenharmony_ci		       ap->name);
31038c2ecf20Sopenharmony_ci		result = -EIO;
31048c2ecf20Sopenharmony_ci		goto eeprom_read_error;
31058c2ecf20Sopenharmony_ci	}
31068c2ecf20Sopenharmony_ci
31078c2ecf20Sopenharmony_ci	eeprom_prep(regs, offset & 0xff);
31088c2ecf20Sopenharmony_ci	if (eeprom_check_ack(regs)) {
31098c2ecf20Sopenharmony_ci		local_irq_restore(flags);
31108c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Unable to set address byte 1\n",
31118c2ecf20Sopenharmony_ci		       ap->name);
31128c2ecf20Sopenharmony_ci		result = -EIO;
31138c2ecf20Sopenharmony_ci		goto eeprom_read_error;
31148c2ecf20Sopenharmony_ci	}
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	eeprom_start(regs);
31178c2ecf20Sopenharmony_ci	eeprom_prep(regs, EEPROM_READ_SELECT);
31188c2ecf20Sopenharmony_ci	if (eeprom_check_ack(regs)) {
31198c2ecf20Sopenharmony_ci		local_irq_restore(flags);
31208c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Unable to set READ_SELECT\n",
31218c2ecf20Sopenharmony_ci		       ap->name);
31228c2ecf20Sopenharmony_ci		result = -EIO;
31238c2ecf20Sopenharmony_ci		goto eeprom_read_error;
31248c2ecf20Sopenharmony_ci	}
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
31278c2ecf20Sopenharmony_ci		local = readl(&regs->LocalCtrl);
31288c2ecf20Sopenharmony_ci		local &= ~EEPROM_WRITE_ENABLE;
31298c2ecf20Sopenharmony_ci		writel(local, &regs->LocalCtrl);
31308c2ecf20Sopenharmony_ci		readl(&regs->LocalCtrl);
31318c2ecf20Sopenharmony_ci		udelay(ACE_LONG_DELAY);
31328c2ecf20Sopenharmony_ci		mb();
31338c2ecf20Sopenharmony_ci		local |= EEPROM_CLK_OUT;
31348c2ecf20Sopenharmony_ci		writel(local, &regs->LocalCtrl);
31358c2ecf20Sopenharmony_ci		readl(&regs->LocalCtrl);
31368c2ecf20Sopenharmony_ci		mb();
31378c2ecf20Sopenharmony_ci		udelay(ACE_SHORT_DELAY);
31388c2ecf20Sopenharmony_ci		/* sample data mid high clk */
31398c2ecf20Sopenharmony_ci		result = (result << 1) |
31408c2ecf20Sopenharmony_ci			((readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0);
31418c2ecf20Sopenharmony_ci		udelay(ACE_SHORT_DELAY);
31428c2ecf20Sopenharmony_ci		mb();
31438c2ecf20Sopenharmony_ci		local = readl(&regs->LocalCtrl);
31448c2ecf20Sopenharmony_ci		local &= ~EEPROM_CLK_OUT;
31458c2ecf20Sopenharmony_ci		writel(local, &regs->LocalCtrl);
31468c2ecf20Sopenharmony_ci		readl(&regs->LocalCtrl);
31478c2ecf20Sopenharmony_ci		udelay(ACE_SHORT_DELAY);
31488c2ecf20Sopenharmony_ci		mb();
31498c2ecf20Sopenharmony_ci		if (i == 7) {
31508c2ecf20Sopenharmony_ci			local |= EEPROM_WRITE_ENABLE;
31518c2ecf20Sopenharmony_ci			writel(local, &regs->LocalCtrl);
31528c2ecf20Sopenharmony_ci			readl(&regs->LocalCtrl);
31538c2ecf20Sopenharmony_ci			mb();
31548c2ecf20Sopenharmony_ci			udelay(ACE_SHORT_DELAY);
31558c2ecf20Sopenharmony_ci		}
31568c2ecf20Sopenharmony_ci	}
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci	local |= EEPROM_DATA_OUT;
31598c2ecf20Sopenharmony_ci	writel(local, &regs->LocalCtrl);
31608c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
31618c2ecf20Sopenharmony_ci	mb();
31628c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
31638c2ecf20Sopenharmony_ci	writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);
31648c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
31658c2ecf20Sopenharmony_ci	udelay(ACE_LONG_DELAY);
31668c2ecf20Sopenharmony_ci	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
31678c2ecf20Sopenharmony_ci	readl(&regs->LocalCtrl);
31688c2ecf20Sopenharmony_ci	mb();
31698c2ecf20Sopenharmony_ci	udelay(ACE_SHORT_DELAY);
31708c2ecf20Sopenharmony_ci	eeprom_stop(regs);
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	local_irq_restore(flags);
31738c2ecf20Sopenharmony_ci out:
31748c2ecf20Sopenharmony_ci	return result;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci eeprom_read_error:
31778c2ecf20Sopenharmony_ci	printk(KERN_ERR "%s: Unable to read eeprom byte 0x%02lx\n",
31788c2ecf20Sopenharmony_ci	       ap->name, offset);
31798c2ecf20Sopenharmony_ci	goto out;
31808c2ecf20Sopenharmony_ci}
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_cimodule_pci_driver(acenic_pci_driver);
3183