11f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* cassini.c: Sun Microsystems Cassini(+) ethernet driver.
21f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
31f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Copyright (C) 2004 Sun Microsystems Inc.
41f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Copyright (C) 2003 Adrian Sun (asun@darksunrising.com)
51f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
61f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * This program is free software; you can redistribute it and/or
71f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * modify it under the terms of the GNU General Public License as
81f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * published by the Free Software Foundation; either version 2 of the
91f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * License, or (at your option) any later version.
101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * This program is distributed in the hope that it will be useful,
121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * but WITHOUT ANY WARRANTY; without even the implied warranty of
131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * GNU General Public License for more details.
151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * You should have received a copy of the GNU General Public License
171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * along with this program; if not, write to the Free Software
181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * 02111-1307, USA.
201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * This driver uses the sungem driver (c) David Miller
221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * (davem@redhat.com) as its basis.
231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * The cassini chip has a number of features that distinguish it from
251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * the gem chip:
261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  4 transmit descriptor rings that are used for either QoS (VLAN) or
271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *      load balancing (non-VLAN mode)
281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  batching of multiple packets
291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  multiple CPU dispatching
301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  page-based RX descriptor engine with separate completion rings
311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  Gigabit support (GMII and PCS interface)
321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  MIF link up/down detection works
331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * RX is handled by page sized buffers that are attached as fragments to
351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * the skb. here's what's done:
361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  -- driver allocates pages at a time and keeps reference counts
371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     on them.
381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  -- the upper protocol layers assume that the header is in the skb
391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     itself. as a result, cassini will copy a small amount (64 bytes)
401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     to make them happy.
411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  -- driver appends the rest of the data pages as frags to skbuffs
421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     and increments the reference count
431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  -- on page reclamation, the driver swaps the page with a spare page.
441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     if that page is still in use, it frees its reference to that page,
451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     and allocates a new page for use. otherwise, it just recycles the
466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *     the page.
471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * NOTE: cassini can parse the header. however, it's not worth it
491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       as long as the network stack requires a header copy.
501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * TX has 4 queues. currently these queues are used in a round-robin
521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * fashion for load balancing. They can also be used for QoS. for that
531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * to work, however, QoS information needs to be exposed down to the driver
5425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * level so that subqueues get targeted to particular transmit rings.
551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * alternatively, the queues can be configured via use of the all-purpose
561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * ioctl.
571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * RX DATA: the rx completion ring has all the info, but the rx desc
591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * ring has all of the data. RX can conceivably come in under multiple
601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * interrupts, but the INT# assignment needs to be set up properly by
611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * the BIOS and conveyed to the driver. PCI BIOSes don't know how to do
621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * that. also, the two descriptor rings are designed to distinguish between
636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * encrypted and non-encrypted packets, but we use them for buffering
641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * instead.
651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * by default, the selective clear mask is set up to process rx packets.
671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
69436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/module.h>
721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/kernel.h>
731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/types.h>
741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/compiler.h>
751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/slab.h>
761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/delay.h>
771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/init.h>
78a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
79fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh#include <linux/vmalloc.h>
801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/ioport.h>
811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/pci.h>
821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/mm.h>
831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/highmem.h>
841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/list.h>
851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/dma-mapping.h>
861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/netdevice.h>
881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/etherdevice.h>
891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/skbuff.h>
901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/ethtool.h>
911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/crc32.h>
921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/random.h>
931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/mii.h>
941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/ip.h>
951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <linux/tcp.h>
96758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar#include <linux/mutex.h>
97fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh#include <linux/firmware.h>
981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <net/checksum.h>
1001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10160063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
1021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <asm/io.h>
1031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <asm/byteorder.h>
1041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include <asm/uaccess.h>
1051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1064679026d783eb5ac90247bc466d66b817b213abfCong Wang#define cas_page_map(x)      kmap_atomic((x))
1074679026d783eb5ac90247bc466d66b817b213abfCong Wang#define cas_page_unmap(x)    kunmap_atomic((x))
1081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_NCPUS            num_online_cpus()
1091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define cas_skb_release(x)  netif_rx(x)
1111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* select which firmware to use */
1136aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#define USE_HP_WORKAROUND
1141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define HP_WORKAROUND_DEFAULT /* select which firmware to use as default */
1151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_HP_ALT_FIRMWARE   cas_prog_null /* alternate firmware */
1161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#include "cassini.h"
1181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define USE_TX_COMPWB      /* use completion writeback registers */
1201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define USE_CSMA_CD_PROTO  /* standard CSMA/CD */
1211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define USE_RX_BLANK       /* hw interrupt mitigation */
1221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#undef USE_ENTROPY_DEV     /* don't test for entropy device */
1231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* NOTE: these aren't useable unless PCI interrupts can be assigned.
1251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * also, we need to make cp->lock finer-grained.
1261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
1271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#undef  USE_PCI_INTB
1281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#undef  USE_PCI_INTC
1291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#undef  USE_PCI_INTD
1301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#undef  USE_QOS
1311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#undef  USE_VPD_DEBUG       /* debug vpd information if defined */
1331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* rx processing options */
1351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define USE_PAGE_ORDER      /* specify to allocate large rx pages */
1361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define RX_DONT_BATCH  0    /* if 1, don't batch flows */
1371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define RX_COPY_ALWAYS 0    /* if 0, use frags */
1381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define RX_COPY_MIN    64   /* copy a little to make upper layers happy */
1391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#undef  RX_COUNT_BUFFERS    /* define to calculate RX buffer stats */
1401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define DRV_MODULE_NAME		"cassini"
142b1443e2f6501f06930a162ff1ff08382a98bf23eDavid S. Miller#define DRV_MODULE_VERSION	"1.6"
143b1443e2f6501f06930a162ff1ff08382a98bf23eDavid S. Miller#define DRV_MODULE_RELDATE	"21 May 2008"
1441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_DEF_MSG_ENABLE	  \
1461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	(NETIF_MSG_DRV		| \
1471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 NETIF_MSG_PROBE	| \
1481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 NETIF_MSG_LINK		| \
1491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 NETIF_MSG_TIMER	| \
1501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 NETIF_MSG_IFDOWN	| \
1511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 NETIF_MSG_IFUP		| \
1521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 NETIF_MSG_RX_ERR	| \
1531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 NETIF_MSG_TX_ERR)
1541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* length of time before we decide the hardware is borked,
1561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * and dev->tx_timeout() should be called to fix the problem
1571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
1581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_TX_TIMEOUT			(HZ)
1591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_LINK_TIMEOUT                (22*HZ/10)
1601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_LINK_FAST_TIMEOUT           (1)
1611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* timeout values for state changing. these specify the number
1631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * of 10us delays to be used before giving up.
1641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
1651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define STOP_TRIES_PHY 1000
1661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define STOP_TRIES     5000
1671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/* specify a minimum frame size to deal with some fifo issues
1691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * max mtu == 2 * page size - ethernet header - 64 - swivel =
1701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *            2 * page_size - 0x50
1711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
1721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_MIN_FRAME			97
1731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_1000MB_MIN_FRAME            255
1741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_MIN_MTU                     60
1751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_MAX_MTU                     min(((cp->page_size << 1) - 0x50), 9000)
1761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
1781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/*
1791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Eliminate these and use separate atomic counters for each, to
1801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * avoid a race condition.
1811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
1821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
1831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_RESET_MTU                   1
1841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_RESET_ALL                   2
1851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_RESET_SPARE                 3
1861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
1871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic char version[] __devinitdata =
1891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
1901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1918d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellstatic int cassini_debug = -1;	/* -1 == use CAS_DEF_MSG_ENABLE as value */
1928d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellstatic int link_mode;
1938d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russell
1941f26dac32057baaf67d10b45c6b5277db862911dDavid S. MillerMODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)");
1951f26dac32057baaf67d10b45c6b5277db862911dDavid S. MillerMODULE_DESCRIPTION("Sun Cassini(+) ethernet driver");
1961f26dac32057baaf67d10b45c6b5277db862911dDavid S. MillerMODULE_LICENSE("GPL");
197fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder SinghMODULE_FIRMWARE("sun/cassini.bin");
1988d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(cassini_debug, int, 0);
1991f26dac32057baaf67d10b45c6b5277db862911dDavid S. MillerMODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value");
2008d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(link_mode, int, 0);
2011f26dac32057baaf67d10b45c6b5277db862911dDavid S. MillerMODULE_PARM_DESC(link_mode, "default link mode");
2021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/*
2041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Work around for a PCS bug in which the link goes down due to the chip
2051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * being confused and never showing a link status of "up."
2061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
2071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define DEFAULT_LINKDOWN_TIMEOUT 5
2086aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/*
2091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Value in seconds, for user input.
2101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
2111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int linkdown_timeout = DEFAULT_LINKDOWN_TIMEOUT;
2128d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(linkdown_timeout, int, 0);
2131f26dac32057baaf67d10b45c6b5277db862911dDavid S. MillerMODULE_PARM_DESC(linkdown_timeout,
2141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller"min reset interval in sec. for PCS linkdown issue; disabled if not positive");
2151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/*
2171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * value in 'ticks' (units used by jiffies). Set when we init the
2181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * module because 'HZ' in actually a function call on some flavors of
2191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Linux.  This will default to DEFAULT_LINKDOWN_TIMEOUT * HZ.
2201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
2211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int link_transition_timeout;
2221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic u16 link_modes[] __devinitdata = {
2261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	BMCR_ANENABLE,			 /* 0 : autoneg */
2271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	0,				 /* 1 : 10bt half duplex */
2281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	BMCR_SPEED100,			 /* 2 : 100bt half duplex */
2291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	BMCR_FULLDPLX,			 /* 3 : 10bt full duplex */
2301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	BMCR_SPEED100|BMCR_FULLDPLX,	 /* 4 : 100bt full duplex */
2311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	CAS_BMCR_SPEED1000|BMCR_FULLDPLX /* 5 : 1000bt full duplex */
2321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller};
2331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
234a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(cas_pci_tbl) = {
2351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_CASSINI,
2361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
2371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SATURN,
2381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
2391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{ 0, }
2401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller};
2411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2421f26dac32057baaf67d10b45c6b5277db862911dDavid S. MillerMODULE_DEVICE_TABLE(pci, cas_pci_tbl);
2431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_set_link_modes(struct cas *cp);
2451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_lock_tx(struct cas *cp)
2471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
2481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
2491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	for (i = 0; i < N_TX_RINGS; i++)
2511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->tx_lock[i]);
2521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
2531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_lock_all(struct cas *cp)
2551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
2561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irq(&cp->lock);
2571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_lock_tx(cp);
2581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
2591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* WTZ: QA was finding deadlock problems with the previous
2611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * versions after long test runs with multiple cards per machine.
2621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * See if replacing cas_lock_all with safer versions helps. The
2631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * symptoms QA is reporting match those we'd expect if interrupts
2641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * aren't being properly restored, and we fixed a previous deadlock
2651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * with similar symptoms by using save/restore versions in other
2661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * places.
2671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
2681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define cas_lock_all_save(cp, flags) \
2691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdo { \
2701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *xxxcp = (cp); \
2711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&xxxcp->lock, flags); \
2721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_lock_tx(xxxcp); \
2731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller} while (0)
2741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_unlock_tx(struct cas *cp)
2761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
2771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
2781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2796aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	for (i = N_TX_RINGS; i > 0; i--)
2806aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		spin_unlock(&cp->tx_lock[i - 1]);
2811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
2821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_unlock_all(struct cas *cp)
2841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
2851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_unlock_tx(cp);
2861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irq(&cp->lock);
2871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
2881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define cas_unlock_all_restore(cp, flags) \
2901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdo { \
2911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *xxxcp = (cp); \
2921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_unlock_tx(xxxcp); \
2931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&xxxcp->lock, flags); \
2941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller} while (0)
2951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_disable_irq(struct cas *cp, const int ring)
2971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
2981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Make sure we won't get any more interrupts */
2991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (ring == 0) {
3001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0xFFFFFFFF, cp->regs + REG_INTR_MASK);
3011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
3021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
3031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* disable completion interrupts and selectively mask */
3051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
3061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		switch (ring) {
3071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if defined (USE_PCI_INTB) || defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
3081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTB
3091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		case 1:
3101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTC
3121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		case 2:
3131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTD
3151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		case 3:
3161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			writel(INTRN_MASK_CLEAR_ALL | INTRN_MASK_RX_EN,
3181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       cp->regs + REG_PLUS_INTRN_MASK(ring));
3191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
3201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		default:
3221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			writel(INTRN_MASK_CLEAR_ALL, cp->regs +
3231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       REG_PLUS_INTRN_MASK(ring));
3241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
3251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
3261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
3271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
3281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_mask_intr(struct cas *cp)
3301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
3311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
3321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_COMP_RINGS; i++)
3341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_disable_irq(cp, i);
3351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
3361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_enable_irq(struct cas *cp, const int ring)
3381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
3391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (ring == 0) { /* all but TX_DONE */
3401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(INTR_TX_DONE, cp->regs + REG_INTR_MASK);
3411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
3421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
3431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
3451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		switch (ring) {
3461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if defined (USE_PCI_INTB) || defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
3471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTB
3481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		case 1:
3491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTC
3511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		case 2:
3521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTD
3541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		case 3:
3551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			writel(INTRN_MASK_RX_EN, cp->regs +
3571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       REG_PLUS_INTRN_MASK(ring));
3581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
3591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		default:
3611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
3621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
3631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
3641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
3651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_unmask_intr(struct cas *cp)
3671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
3681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
3691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_COMP_RINGS; i++)
3711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_enable_irq(cp, i);
3721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
3731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_entropy_gather(struct cas *cp)
3751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
3761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_ENTROPY_DEV
3771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((cp->cas_flags & CAS_FLAG_ENTROPY_DEV) == 0)
3781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
3791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	batch_entropy_store(readl(cp->regs + REG_ENTROPY_IV),
3811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    readl(cp->regs + REG_ENTROPY_IV),
3821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    sizeof(uint64_t)*8);
3831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
3841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
3851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_entropy_reset(struct cas *cp)
3871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
3881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_ENTROPY_DEV
3891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((cp->cas_flags & CAS_FLAG_ENTROPY_DEV) == 0)
3901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
3911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3926aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	writel(BIM_LOCAL_DEV_PAD | BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_EXT,
3931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       cp->regs + REG_BIM_LOCAL_DEV_EN);
3941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writeb(ENTROPY_RESET_STC_MODE, cp->regs + REG_ENTROPY_RESET);
3951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writeb(0x55, cp->regs + REG_ENTROPY_RAND_REG);
3961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* if we read back 0x0, we don't have an entropy device */
3981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (readb(cp->regs + REG_ENTROPY_RAND_REG) == 0)
3991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->cas_flags &= ~CAS_FLAG_ENTROPY_DEV;
4001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
4011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
4021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4036aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/* access to the phy. the following assumes that we've initialized the MIF to
4041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * be in frame rather than bit-bang mode
4051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
4061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic u16 cas_phy_read(struct cas *cp, int reg)
4071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
4081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 cmd;
4091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int limit = STOP_TRIES_PHY;
4101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd = MIF_FRAME_ST | MIF_FRAME_OP_READ;
4121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd |= CAS_BASE(MIF_FRAME_PHY_ADDR, cp->phy_addr);
4131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd |= CAS_BASE(MIF_FRAME_REG_ADDR, reg);
4141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd |= MIF_FRAME_TURN_AROUND_MSB;
4151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(cmd, cp->regs + REG_MIF_FRAME);
4166aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* poll for completion */
4181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (limit-- > 0) {
4191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
4201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cmd = readl(cp->regs + REG_MIF_FRAME);
4211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cmd & MIF_FRAME_TURN_AROUND_LSB)
422807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet			return cmd & MIF_FRAME_DATA_MASK;
4231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
4241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0xFFFF; /* -1 */
4251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
4261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_phy_write(struct cas *cp, int reg, u16 val)
4281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
4291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int limit = STOP_TRIES_PHY;
4301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 cmd;
4311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd = MIF_FRAME_ST | MIF_FRAME_OP_WRITE;
4331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd |= CAS_BASE(MIF_FRAME_PHY_ADDR, cp->phy_addr);
4341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd |= CAS_BASE(MIF_FRAME_REG_ADDR, reg);
4351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd |= MIF_FRAME_TURN_AROUND_MSB;
4361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cmd |= val & MIF_FRAME_DATA_MASK;
4371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(cmd, cp->regs + REG_MIF_FRAME);
4386aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* poll for completion */
4401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (limit-- > 0) {
4411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
4421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cmd = readl(cp->regs + REG_MIF_FRAME);
4431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cmd & MIF_FRAME_TURN_AROUND_LSB)
4441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return 0;
4451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
4461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return -1;
4471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
4481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_phy_powerup(struct cas *cp)
4501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
4516aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	u16 ctl = cas_phy_read(cp, MII_BMCR);
4521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((ctl & BMCR_PDOWN) == 0)
4541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
4551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	ctl &= ~BMCR_PDOWN;
4561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, MII_BMCR, ctl);
4571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
4581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_phy_powerdown(struct cas *cp)
4601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
4616aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	u16 ctl = cas_phy_read(cp, MII_BMCR);
4621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (ctl & BMCR_PDOWN)
4641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
4651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	ctl |= BMCR_PDOWN;
4661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, MII_BMCR, ctl);
4671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
4681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* cp->lock held. note: the last put_page will free the buffer */
4701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_page_free(struct cas *cp, cas_page_t *page)
4711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
4726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
4731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       PCI_DMA_FROMDEVICE);
4741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	__free_pages(page->buffer, cp->page_order);
4751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	kfree(page);
4761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
4771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
4781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef RX_COUNT_BUFFERS
4801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define RX_USED_ADD(x, y)       ((x)->used += (y))
4811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define RX_USED_SET(x, y)       ((x)->used  = (y))
4821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
4836aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#define RX_USED_ADD(x, y)
4841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define RX_USED_SET(x, y)
4851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
4861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* local page allocation routines for the receive buffers. jumbo pages
4881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * require at least 8K contiguous and 8K aligned buffers.
4891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
4909e24974db6b01ec067c24de09588282b6a1407f0Al Virostatic cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags)
4911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
4921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t *page;
4931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	page = kmalloc(sizeof(cas_page_t), flags);
4951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!page)
4961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return NULL;
4971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	INIT_LIST_HEAD(&page->list);
4991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	RX_USED_SET(page, 0);
5001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	page->buffer = alloc_pages(flags, cp->page_order);
5011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!page->buffer)
5021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto page_err;
5031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	page->dma_addr = pci_map_page(cp->pdev, page->buffer, 0,
5041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				      cp->page_size, PCI_DMA_FROMDEVICE);
5051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return page;
5061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerpage_err:
5081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	kfree(page);
5091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return NULL;
5101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
5111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* initialize spare pool of rx buffers, but allocate during the open */
5131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_spare_init(struct cas *cp)
5141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
5151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller  	spin_lock(&cp->rx_inuse_lock);
5161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	INIT_LIST_HEAD(&cp->rx_inuse_list);
5171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_inuse_lock);
5181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_spare_lock);
5201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	INIT_LIST_HEAD(&cp->rx_spare_list);
5211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_spares_needed = RX_SPARE_COUNT;
5221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_spare_lock);
5231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
5241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* used on close. free all the spare buffers. */
5261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_spare_free(struct cas *cp)
5271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
5281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct list_head list, *elem, *tmp;
5291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* free spare buffers */
5311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	INIT_LIST_HEAD(&list);
5321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_spare_lock);
5339bd512f619cc116b7830134d7c9f6e404a38c7bfRobert P. J. Day	list_splice_init(&cp->rx_spare_list, &list);
5341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_spare_lock);
5351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	list_for_each_safe(elem, tmp, &list) {
5361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_free(cp, list_entry(elem, cas_page_t, list));
5371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
5381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	INIT_LIST_HEAD(&list);
5401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
5411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/*
5421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * Looks like Adrian had protected this with a different
5431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * lock than used everywhere else to manipulate this list.
5441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
5451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_inuse_lock);
5469bd512f619cc116b7830134d7c9f6e404a38c7bfRobert P. J. Day	list_splice_init(&cp->rx_inuse_list, &list);
5471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_inuse_lock);
5481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
5491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_spare_lock);
5509bd512f619cc116b7830134d7c9f6e404a38c7bfRobert P. J. Day	list_splice_init(&cp->rx_inuse_list, &list);
5511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_spare_lock);
5521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
5531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	list_for_each_safe(elem, tmp, &list) {
5541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_free(cp, list_entry(elem, cas_page_t, list));
5551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
5561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
5571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* replenish spares if needed */
5599e24974db6b01ec067c24de09588282b6a1407f0Al Virostatic void cas_spare_recover(struct cas *cp, const gfp_t flags)
5601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
5611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct list_head list, *elem, *tmp;
5621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int needed, i;
5631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* check inuse list. if we don't need any more free buffers,
5651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * just free it
5661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
5671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* make a local copy of the list */
5691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	INIT_LIST_HEAD(&list);
5701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_inuse_lock);
5719bd512f619cc116b7830134d7c9f6e404a38c7bfRobert P. J. Day	list_splice_init(&cp->rx_inuse_list, &list);
5721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_inuse_lock);
5736aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	list_for_each_safe(elem, tmp, &list) {
5751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_t *page = list_entry(elem, cas_page_t, list);
5761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
577e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		/*
578e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * With the lockless pagecache, cassini buffering scheme gets
579e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * slightly less accurate: we might find that a page has an
580e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * elevated reference count here, due to a speculative ref,
581e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * and skip it as in-use. Ideally we would be able to reclaim
582e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * it. However this would be such a rare case, it doesn't
583e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * matter too much as we should pick it up the next time round.
584e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 *
585e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * Importantly, if we find that the page has a refcount of 1
586e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * here (our refcount), then we know it is definitely not inuse
587e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 * so we can reuse it.
588e286781d5f2e9c846e012a39653a166e9d31777dNick Piggin		 */
5899de4dfb4c7176e5bb232a21cdd8df78da2b15cacDavid S. Miller		if (page_count(page->buffer) > 1)
5901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			continue;
5911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		list_del(elem);
5931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->rx_spare_lock);
5941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->rx_spares_needed > 0) {
5951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			list_add(elem, &cp->rx_spare_list);
5961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->rx_spares_needed--;
5971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_unlock(&cp->rx_spare_lock);
5981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
5991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_unlock(&cp->rx_spare_lock);
6001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_page_free(cp, page);
6011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
6021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
6031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* put any inuse buffers back on the list */
6051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!list_empty(&list)) {
6061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->rx_inuse_lock);
6071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		list_splice(&list, &cp->rx_inuse_list);
6081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->rx_inuse_lock);
6091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
6106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_spare_lock);
6121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	needed = cp->rx_spares_needed;
6131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_spare_lock);
6141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!needed)
6151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
6161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* we still need spares, so try to allocate some */
6181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	INIT_LIST_HEAD(&list);
6191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = 0;
6201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (i < needed) {
6211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_t *spare = cas_page_alloc(cp, flags);
6226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		if (!spare)
6231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
6241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		list_add(&spare->list, &list);
6251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i++;
6261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
6271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_spare_lock);
6291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	list_splice(&list, &cp->rx_spare_list);
6301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_spares_needed -= i;
6311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_spare_lock);
6321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
6331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* pull a page from the list. */
6351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic cas_page_t *cas_page_dequeue(struct cas *cp)
6361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
6371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct list_head *entry;
6381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int recover;
6391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->rx_spare_lock);
6411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (list_empty(&cp->rx_spare_list)) {
6421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* try to do a quick recovery */
6431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->rx_spare_lock);
6441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_spare_recover(cp, GFP_ATOMIC);
6451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->rx_spare_lock);
6461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (list_empty(&cp->rx_spare_list)) {
647436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netif_err(cp, rx_err, cp->dev,
648436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				  "no spare buffers available\n");
6491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_unlock(&cp->rx_spare_lock);
6501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return NULL;
6511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
6521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
6531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = cp->rx_spare_list.next;
6551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	list_del(entry);
6561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	recover = ++cp->rx_spares_needed;
6571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->rx_spare_lock);
6581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* trigger the timer to do the recovery */
6601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((recover & (RX_SPARE_RECOVER_VAL - 1)) == 0) {
6611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
6621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending);
6631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending_spare);
6641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		schedule_work(&cp->reset_task);
6651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
6661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_set(&cp->reset_task_pending, CAS_RESET_SPARE);
6671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		schedule_work(&cp->reset_task);
6681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
6691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
6701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return list_entry(entry, cas_page_t, list);
6711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
6721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_mif_poll(struct cas *cp, const int enable)
6751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
6761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 cfg;
6776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	cfg  = readl(cp->regs + REG_MIF_CFG);
6791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cfg &= (MIF_CFG_MDIO_0 | MIF_CFG_MDIO_1);
6801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->phy_type & CAS_PHY_MII_MDIO1)
6826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		cfg |= MIF_CFG_PHY_SELECT;
6831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* poll and interrupt on link status change. */
6851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (enable) {
6861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cfg |= MIF_CFG_POLL_EN;
6871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cfg |= CAS_BASE(MIF_CFG_POLL_REG, MII_BMSR);
6881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cfg |= CAS_BASE(MIF_CFG_POLL_PHY, cp->phy_addr);
6891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
6906aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	writel((enable) ? ~(BMSR_LSTATUS | BMSR_ANEGCOMPLETE) : 0xFFFF,
6916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	       cp->regs + REG_MIF_MASK);
6921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(cfg, cp->regs + REG_MIF_CFG);
6931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
6941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
6951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock */
6961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_begin_auto_negotiation(struct cas *cp, struct ethtool_cmd *ep)
6971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
6981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u16 ctl;
6991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
7001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int lcntl;
7011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int changed = 0;
7021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int oldstate = cp->lstate;
7031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int link_was_not_down = !(oldstate == link_down);
7041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
7051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Setup link parameters */
7061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!ep)
7071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto start_aneg;
7081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	lcntl = cp->link_cntl;
7091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (ep->autoneg == AUTONEG_ENABLE)
7101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_cntl = BMCR_ANENABLE;
7111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else {
71225db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny		u32 speed = ethtool_cmd_speed(ep);
7131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_cntl = 0;
71425db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny		if (speed == SPEED_100)
7151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_cntl |= BMCR_SPEED100;
71625db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny		else if (speed == SPEED_1000)
7171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_cntl |= CAS_BMCR_SPEED1000;
7181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (ep->duplex == DUPLEX_FULL)
7191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_cntl |= BMCR_FULLDPLX;
7201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
7211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
7221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	changed = (lcntl != cp->link_cntl);
7231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
7241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstart_aneg:
7251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->lstate == link_up) {
726436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_info(cp->dev, "PCS link down\n");
7271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
7281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (changed) {
729436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_info(cp->dev, "link configuration changed\n");
7301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
7311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
7321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->lstate = link_down;
7331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->link_transition = LINK_TRANSITION_LINK_DOWN;
7341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!cp->hw_running)
7351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
7361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
7371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/*
7381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * WTZ: If the old state was link_up, we turn off the carrier
7391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * to replicate everything we do elsewhere on a link-down
7406aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	 * event when we were already in a link-up state..
7411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
7421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (oldstate == link_up)
7431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_carrier_off(cp->dev);
7441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (changed  && link_was_not_down) {
7451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/*
7461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * WTZ: This branch will simply schedule a full reset after
7471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * we explicitly changed link modes in an ioctl. See if this
7486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		 * fixes the link-problems we were having for forced mode.
7491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
7501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending);
7511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending_all);
7521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		schedule_work(&cp->reset_task);
7531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->timer_ticks = 0;
7541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		mod_timer(&cp->link_timer, jiffies + CAS_LINK_TIMEOUT);
7551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
7561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
7571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
7581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->phy_type & CAS_PHY_SERDES) {
7591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 val = readl(cp->regs + REG_PCS_MII_CTRL);
7601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
7611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->link_cntl & BMCR_ANENABLE) {
7621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val |= (PCS_MII_RESTART_AUTONEG | PCS_MII_AUTONEG_EN);
7631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->lstate = link_aneg;
7641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
7651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (cp->link_cntl & BMCR_FULLDPLX)
7661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				val |= PCS_MII_CTRL_DUPLEX;
7671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val &= ~PCS_MII_AUTONEG_EN;
7681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->lstate = link_force_ok;
7691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
7701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
7711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_PCS_MII_CTRL);
7721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
7731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
7741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 0);
7751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		ctl = cas_phy_read(cp, MII_BMCR);
7766aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
7771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 CAS_BMCR_SPEED1000 | BMCR_ANENABLE);
7781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		ctl |= cp->link_cntl;
7791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (ctl & BMCR_ANENABLE) {
7801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			ctl |= BMCR_ANRESTART;
7811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->lstate = link_aneg;
7821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
7831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->lstate = link_force_ok;
7841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
7851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
7861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_phy_write(cp, MII_BMCR, ctl);
7871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 1);
7881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
7891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
7901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->timer_ticks = 0;
7911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	mod_timer(&cp->link_timer, jiffies + CAS_LINK_TIMEOUT);
7921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
7931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
7941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
7951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_reset_mii_phy(struct cas *cp)
7961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
7971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int limit = STOP_TRIES_PHY;
7981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u16 val;
7996aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
8001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, MII_BMCR, BMCR_RESET);
8011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	udelay(100);
802ff01b9163655ace76b29b7ff2f56b25c32f795daRoel Kluin	while (--limit) {
8031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = cas_phy_read(cp, MII_BMCR);
8041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((val & BMCR_RESET) == 0)
8051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
8061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
8071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
808807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return limit <= 0;
8091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
8101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
811fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singhstatic int cas_saturn_firmware_init(struct cas *cp)
812fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh{
813fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	const struct firmware *fw;
814fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	const char fw_name[] = "sun/cassini.bin";
815fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	int err;
816fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh
817fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	if (PHY_NS_DP83065 != cp->phy_id)
818fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		return 0;
819fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh
820fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	err = request_firmware(&fw, fw_name, &cp->pdev->dev);
821fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	if (err) {
822436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_err("Failed to load firmware \"%s\"\n",
823fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		       fw_name);
824fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		return err;
825fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	}
826fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	if (fw->size < 2) {
827436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_err("bogus length %zu in \"%s\"\n",
828fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		       fw->size, fw_name);
829fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		err = -EINVAL;
830fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		goto out;
831fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	}
832fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	cp->fw_load_addr= fw->data[1] << 8 | fw->data[0];
833fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	cp->fw_size = fw->size - 2;
834fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	cp->fw_data = vmalloc(cp->fw_size);
835fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	if (!cp->fw_data) {
836fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		err = -ENOMEM;
837fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		goto out;
838fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	}
839fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	memcpy(cp->fw_data, &fw->data[2], cp->fw_size);
840fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singhout:
841fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	release_firmware(fw);
842fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	return err;
843fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh}
844fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh
8451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_saturn_firmware_load(struct cas *cp)
8461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
847fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	int i;
8481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_powerdown(cp);
8501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* expanded memory access mode */
8521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_MEM, 0x0);
8531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* pointer configuration for new firmware */
8551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGE, 0x8ff9);
8561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGD, 0xbd);
8571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGE, 0x8ffa);
8581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGD, 0x82);
8591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGE, 0x8ffb);
8601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGD, 0x0);
8611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGE, 0x8ffc);
8621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGD, 0x39);
8631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* download new firmware */
8651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_MEM, 0x1);
866fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	cas_phy_write(cp, DP83065_MII_REGE, cp->fw_load_addr);
867fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	for (i = 0; i < cp->fw_size; i++)
868fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		cas_phy_write(cp, DP83065_MII_REGD, cp->fw_data[i]);
8691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* enable firmware */
8711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGE, 0x8ff8);
8721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_write(cp, DP83065_MII_REGD, 0x1);
8731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
8741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* phy initialization */
8771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_phy_init(struct cas *cp)
8781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
8791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u16 val;
8801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* if we're in MII/GMII mode, set up phy */
8821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (CAS_PHY_MII(cp->phy_type)) {
8831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(PCS_DATAPATH_MODE_MII,
8841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       cp->regs + REG_PCS_DATAPATH_MODE);
8851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 0);
8871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_reset_mii_phy(cp); /* take out of isolate mode */
8881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (PHY_LUCENT_B0 == cp->phy_id) {
8901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* workaround link up/down issue with lucent */
8911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, LUCENT_MII_REG, 0x8000);
8921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, MII_BMCR, 0x00f1);
8931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, LUCENT_MII_REG, 0x0);
8941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
8951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else if (PHY_BROADCOM_B0 == (cp->phy_id & 0xFFFFFFFC)) {
8961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* workarounds for broadcom phy */
8971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG8, 0x0C20);
8981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG7, 0x0012);
8991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG5, 0x1804);
9001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG7, 0x0013);
9011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG5, 0x1204);
9021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG7, 0x8006);
9031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG5, 0x0132);
9041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG7, 0x8006);
9051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG5, 0x0232);
9061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG7, 0x201F);
9071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, BROADCOM_MII_REG5, 0x0A20);
9081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else if (PHY_BROADCOM_5411 == cp->phy_id) {
9101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val = cas_phy_read(cp, BROADCOM_MII_REG4);
9111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val = cas_phy_read(cp, BROADCOM_MII_REG4);
9121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (val & 0x0080) {
9131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				/* link workaround */
9146aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik				cas_phy_write(cp, BROADCOM_MII_REG4,
9151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					      val & ~0x0080);
9161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
9176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
9181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else if (cp->cas_flags & CAS_FLAG_SATURN) {
9196aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			writel((cp->phy_type & CAS_PHY_MII_MDIO0) ?
9206aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			       SATURN_PCFG_FSI : 0x0,
9211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       cp->regs + REG_SATURN_PCFG);
9221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* load firmware to address 10Mbps auto-negotiation
9246aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * issue. NOTE: this will need to be changed if the
9251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * default firmware gets fixed.
9261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 */
9271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (PHY_NS_DP83065 == cp->phy_id) {
9281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cas_saturn_firmware_load(cp);
9291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
9301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_powerup(cp);
9311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
9321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* advertise capabilities */
9341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = cas_phy_read(cp, MII_BMCR);
9351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val &= ~BMCR_ANENABLE;
9361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_phy_write(cp, MII_BMCR, val);
9371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
9381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_phy_write(cp, MII_ADVERTISE,
9401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			      cas_phy_read(cp, MII_ADVERTISE) |
9411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			      (ADVERTISE_10HALF | ADVERTISE_10FULL |
9421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       ADVERTISE_100HALF | ADVERTISE_100FULL |
9436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			       CAS_ADVERTISE_PAUSE |
9441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       CAS_ADVERTISE_ASYM_PAUSE));
9456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
9461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
9471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* make sure that we don't advertise half
9481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * duplex to avoid a chip issue
9491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 */
9501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val  = cas_phy_read(cp, CAS_MII_1000_CTRL);
9511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val &= ~CAS_ADVERTISE_1000HALF;
9521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val |= CAS_ADVERTISE_1000FULL;
9531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, CAS_MII_1000_CTRL, val);
9541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
9551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
9571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* reset pcs for serdes */
9581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 val;
9591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int limit;
9601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(PCS_DATAPATH_MODE_SERDES,
9621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       cp->regs + REG_PCS_DATAPATH_MODE);
9631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* enable serdes pins on saturn */
9651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->cas_flags & CAS_FLAG_SATURN)
9661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			writel(0, cp->regs + REG_SATURN_PCFG);
9671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Reset PCS unit. */
9691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = readl(cp->regs + REG_PCS_MII_CTRL);
9701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= PCS_MII_RESET;
9711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_PCS_MII_CTRL);
9721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		limit = STOP_TRIES;
974ff01b9163655ace76b29b7ff2f56b25c32f795daRoel Kluin		while (--limit > 0) {
9751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			udelay(10);
9766aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			if ((readl(cp->regs + REG_PCS_MII_CTRL) &
9771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			     PCS_MII_RESET) == 0)
9781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				break;
9791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
9801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (limit <= 0)
981436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_warn(cp->dev, "PCS reset bit would not clear [%08x]\n",
982436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				    readl(cp->regs + REG_PCS_STATE_MACHINE));
9831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Make sure PCS is disabled while changing advertisement
9851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * configuration.
9861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
9871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x0, cp->regs + REG_PCS_CFG);
9881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Advertise all capabilities except half-duplex. */
9901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val  = readl(cp->regs + REG_PCS_MII_ADVERT);
9911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val &= ~PCS_MII_ADVERT_HD;
9926aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		val |= (PCS_MII_ADVERT_FD | PCS_MII_ADVERT_SYM_PAUSE |
9931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			PCS_MII_ADVERT_ASYM_PAUSE);
9941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_PCS_MII_ADVERT);
9951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* enable PCS */
9971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(PCS_CFG_EN, cp->regs + REG_PCS_CFG);
9981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
9991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* pcs workaround: enable sync detect */
10001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(PCS_SERDES_CTRL_SYNCD_EN,
10011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       cp->regs + REG_PCS_SERDES_CTRL);
10021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
10031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
10041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_pcs_link_check(struct cas *cp)
10071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
10081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 stat, state_machine;
10091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int retval = 0;
10101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* The link status bit latches on zero, so you must
10121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * read it twice in such a case to see a transition
10131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * to the link being up.
10141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
10151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stat = readl(cp->regs + REG_PCS_MII_STATUS);
10161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((stat & PCS_MII_STATUS_LINK_STATUS) == 0)
10171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stat = readl(cp->regs + REG_PCS_MII_STATUS);
10181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* The remote-fault indication is only valid
10201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * when autoneg has completed.
10211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
10221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((stat & (PCS_MII_STATUS_AUTONEG_COMP |
10231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		     PCS_MII_STATUS_REMOTE_FAULT)) ==
1024436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	    (PCS_MII_STATUS_AUTONEG_COMP | PCS_MII_STATUS_REMOTE_FAULT))
1025436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netif_info(cp, link, cp->dev, "PCS RemoteFault\n");
10261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* work around link detection issue by querying the PCS state
10281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * machine directly.
10291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
10301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	state_machine = readl(cp->regs + REG_PCS_STATE_MACHINE);
10311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((state_machine & PCS_SM_LINK_STATE_MASK) != SM_LINK_STATE_UP) {
10321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stat &= ~PCS_MII_STATUS_LINK_STATUS;
10331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (state_machine & PCS_SM_WORD_SYNC_STATE_MASK) {
10341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stat |= PCS_MII_STATUS_LINK_STATUS;
10351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
10361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & PCS_MII_STATUS_LINK_STATUS) {
10381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->lstate != link_up) {
10391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (cp->opened) {
10401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->lstate = link_up;
10411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->link_transition = LINK_TRANSITION_LINK_UP;
10426aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
10431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cas_set_link_modes(cp);
10441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				netif_carrier_on(cp->dev);
10451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
10461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
10471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (cp->lstate == link_up) {
10481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->lstate = link_down;
10491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (link_transition_timeout != 0 &&
10501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    cp->link_transition != LINK_TRANSITION_REQUESTED_RESET &&
10511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    !cp->link_transition_jiffies_valid) {
10521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/*
10536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * force a reset, as a workaround for the
10546aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * link-failure problem. May want to move this to a
10551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * point a bit earlier in the sequence. If we had
10561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * generated a reset a short time ago, we'll wait for
10571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * the link timer to check the status until a
10581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * timer expires (link_transistion_jiffies_valid is
10591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * true when the timer is running.)  Instead of using
10601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * a system timer, we just do a check whenever the
10611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * link timer is running - this clears the flag after
10621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * a suitable delay.
10631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 */
10641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			retval = 1;
10651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition = LINK_TRANSITION_REQUESTED_RESET;
10661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition_jiffies = jiffies;
10671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition_jiffies_valid = 1;
10681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
10691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition = LINK_TRANSITION_ON_FAILURE;
10701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
10711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_carrier_off(cp->dev);
1072436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		if (cp->opened)
1073436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netif_info(cp, link, cp->dev, "PCS link down\n");
10741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
10751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Cassini only: if you force a mode, there can be
10761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * sync problems on link down. to fix that, the following
10771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * things need to be checked:
10781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * 1) read serialink state register
10791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * 2) read pcs status register to verify link down.
10801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * 3) if link down and serial link == 0x03, then you need
10811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 *    to global reset the chip.
10821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
10831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((cp->cas_flags & CAS_FLAG_REG_PLUS) == 0) {
10841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* should check to see if we're in a forced mode */
10851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			stat = readl(cp->regs + REG_PCS_SERDES_STATE);
10861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (stat == 0x03)
10871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				return 1;
10881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
10891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (cp->lstate == link_down) {
10901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (link_transition_timeout != 0 &&
10911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    cp->link_transition != LINK_TRANSITION_REQUESTED_RESET &&
10921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    !cp->link_transition_jiffies_valid) {
10931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* force a reset, as a workaround for the
10941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * link-failure problem.  May want to move
10951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * this to a point a bit earlier in the
10961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * sequence.
10971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 */
10981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			retval = 1;
10991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition = LINK_TRANSITION_REQUESTED_RESET;
11001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition_jiffies = jiffies;
11011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition_jiffies_valid = 1;
11021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
11031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition = LINK_TRANSITION_STILL_FAILED;
11041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
11051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
11061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return retval;
11081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
11091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic int cas_pcs_interrupt(struct net_device *dev,
11111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			     struct cas *cp, u32 status)
11121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
11131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 stat = readl(cp->regs + REG_PCS_INTR_STATUS);
11141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11156aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if ((stat & PCS_INTR_STATUS_LINK_CHANGE) == 0)
11161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
11171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return cas_pcs_link_check(cp);
11181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
11191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11206aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic int cas_txmac_interrupt(struct net_device *dev,
11211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       struct cas *cp, u32 status)
11221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
11231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 txmac_stat = readl(cp->regs + REG_MAC_TX_STATUS);
11241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!txmac_stat)
11261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
11271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1128436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_printk(cp, intr, KERN_DEBUG, cp->dev,
1129436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     "txmac interrupt, txmac_stat: 0x%x\n", txmac_stat);
11301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Defer timer expiration is quite normal,
11321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * don't even log the event.
11331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
11341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((txmac_stat & MAC_TX_DEFER_TIMER) &&
11351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    !(txmac_stat & ~MAC_TX_DEFER_TIMER))
11361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
11371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->stat_lock[0]);
11391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (txmac_stat & MAC_TX_UNDERRUN) {
1140436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "TX MAC xmit underrun\n");
11411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].tx_fifo_errors++;
11421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
11431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (txmac_stat & MAC_TX_MAX_PACKET_ERR) {
1145436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "TX MAC max packet size error\n");
11461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].tx_errors++;
11471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
11481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* The rest are all cases of one of the 16-bit TX
11501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * counters expiring.
11511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
11521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (txmac_stat & MAC_TX_COLL_NORMAL)
11531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].collisions += 0x10000;
11541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (txmac_stat & MAC_TX_COLL_EXCESS) {
11561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].tx_aborted_errors += 0x10000;
11571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].collisions += 0x10000;
11581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
11591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (txmac_stat & MAC_TX_COLL_LATE) {
11611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].tx_aborted_errors += 0x10000;
11621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].collisions += 0x10000;
11631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
11641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->stat_lock[0]);
11651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* We do not keep track of MAC_TX_COLL_FIRST and
11671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * MAC_TX_PEAK_ATTEMPTS events.
11681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
11691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
11701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
11711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic void cas_load_firmware(struct cas *cp, cas_hp_inst_t *firmware)
11731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
11741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_hp_inst_t *inst;
11751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
11761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
11771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = 0;
11791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while ((inst = firmware) && inst->note) {
11801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(i, cp->regs + REG_HP_INSTR_RAM_ADDR);
11811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = CAS_BASE(HP_INSTR_RAM_HI_VAL, inst->val);
11831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_HI_MASK, inst->mask);
11841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_HP_INSTR_RAM_DATA_HI);
11851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = CAS_BASE(HP_INSTR_RAM_MID_OUTARG, inst->outarg >> 10);
11871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_MID_OUTOP, inst->outop);
11881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_MID_FNEXT, inst->fnext);
11891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_MID_FOFF, inst->foff);
11901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_MID_SNEXT, inst->snext);
11911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_MID_SOFF, inst->soff);
11921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_MID_OP, inst->op);
11931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_HP_INSTR_RAM_DATA_MID);
11941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
11951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = CAS_BASE(HP_INSTR_RAM_LOW_OUTMASK, inst->outmask);
11961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_LOW_OUTSHIFT, inst->outshift);
11971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_LOW_OUTEN, inst->outenab);
11981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(HP_INSTR_RAM_LOW_OUTARG, inst->outarg);
11991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_HP_INSTR_RAM_DATA_LOW);
12001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		++firmware;
12011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		++i;
12021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
12031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
12041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_init_rx_dma(struct cas *cp)
12061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
12076aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	u64 desc_dma = cp->block_dvma;
12081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
12091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i, size;
12101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* rx free descriptors */
12126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	val = CAS_BASE(RX_CFG_SWIVEL, RX_SWIVEL_OFF_VAL);
12131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val |= CAS_BASE(RX_CFG_DESC_RING, RX_DESC_RINGN_INDEX(0));
12141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val |= CAS_BASE(RX_CFG_COMP_RING, RX_COMP_RINGN_INDEX(0));
12151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((N_RX_DESC_RINGS > 1) &&
12161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    (cp->cas_flags & CAS_FLAG_REG_PLUS))  /* do desc 2 */
12171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_BASE(RX_CFG_DESC_RING1, RX_DESC_RINGN_INDEX(1));
12181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_RX_CFG);
12191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12206aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	val = (unsigned long) cp->init_rxds[0] -
12211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		(unsigned long) cp->init_block;
12221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((desc_dma + val) >> 32, cp->regs + REG_RX_DB_HI);
12231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_DB_LOW);
12241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(RX_DESC_RINGN_SIZE(0) - 4, cp->regs + REG_RX_KICK);
12251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
12276aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		/* rx desc 2 is for IPSEC packets. however,
12281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * we don't it that for that purpose.
12291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
12306aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		val = (unsigned long) cp->init_rxds[1] -
12311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			(unsigned long) cp->init_block;
12321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel((desc_dma + val) >> 32, cp->regs + REG_PLUS_RX_DB1_HI);
12336aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		writel((desc_dma + val) & 0xffffffff, cp->regs +
12341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       REG_PLUS_RX_DB1_LOW);
12356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		writel(RX_DESC_RINGN_SIZE(1) - 4, cp->regs +
12361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       REG_PLUS_RX_KICK1);
12371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
12386aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
12391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* rx completion registers */
12406aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	val = (unsigned long) cp->init_rxcs[0] -
12411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		(unsigned long) cp->init_block;
12421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((desc_dma + val) >> 32, cp->regs + REG_RX_CB_HI);
12431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_CB_LOW);
12441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
12461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* rx comp 2-4 */
12471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (i = 1; i < MAX_RX_COMP_RINGS; i++) {
12486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			val = (unsigned long) cp->init_rxcs[i] -
12491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				(unsigned long) cp->init_block;
12506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			writel((desc_dma + val) >> 32, cp->regs +
12511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       REG_PLUS_RX_CBN_HI(i));
12526aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			writel((desc_dma + val) & 0xffffffff, cp->regs +
12531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       REG_PLUS_RX_CBN_LOW(i));
12541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
12551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
12561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* read selective clear regs to prevent spurious interrupts
12581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * on reset because complete == kick.
12591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * selective clear set up to prevent interrupts on resets
12601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
12611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	readl(cp->regs + REG_INTR_STATUS_ALIAS);
12621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(INTR_RX_DONE | INTR_RX_BUF_UNAVAIL, cp->regs + REG_ALIAS_CLEAR);
12631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
12641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (i = 1; i < N_RX_COMP_RINGS; i++)
12651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			readl(cp->regs + REG_PLUS_INTRN_STATUS_ALIAS(i));
12661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* 2 is different from 3 and 4 */
12681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (N_RX_COMP_RINGS > 1)
12696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			writel(INTR_RX_DONE_ALT | INTR_RX_BUF_UNAVAIL_1,
12701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       cp->regs + REG_PLUS_ALIASN_CLEAR(1));
12711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		for (i = 2; i < N_RX_COMP_RINGS; i++)
12736aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			writel(INTR_RX_DONE_ALT,
12741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       cp->regs + REG_PLUS_ALIASN_CLEAR(i));
12751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
12761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* set up pause thresholds */
12781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val  = CAS_BASE(RX_PAUSE_THRESH_OFF,
12791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->rx_pause_off / RX_PAUSE_THRESH_QUANTUM);
12806aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	val |= CAS_BASE(RX_PAUSE_THRESH_ON,
12811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->rx_pause_on / RX_PAUSE_THRESH_QUANTUM);
12821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_RX_PAUSE_THRESH);
12836aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
12841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* zero out dma reassembly buffers */
12851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < 64; i++) {
12861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(i, cp->regs + REG_RX_TABLE_ADDR);
12871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x0, cp->regs + REG_RX_TABLE_DATA_LOW);
12881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x0, cp->regs + REG_RX_TABLE_DATA_MID);
12891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x0, cp->regs + REG_RX_TABLE_DATA_HI);
12901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
12911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* make sure address register is 0 for normal operation */
12931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x0, cp->regs + REG_RX_CTRL_FIFO_ADDR);
12941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x0, cp->regs + REG_RX_IPP_FIFO_ADDR);
12951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
12961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* interrupt mitigation */
12971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_RX_BLANK
12981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = CAS_BASE(RX_BLANK_INTR_TIME, RX_BLANK_INTR_TIME_VAL);
12991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val |= CAS_BASE(RX_BLANK_INTR_PKT, RX_BLANK_INTR_PKT_VAL);
13001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_RX_BLANK);
13011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
13021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x0, cp->regs + REG_RX_BLANK);
13031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
13041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* interrupt generation as a function of low water marks for
13061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * free desc and completion entries. these are used to trigger
13071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * housekeeping for rx descs. we don't use the free interrupt
13081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * as it's not very useful
13091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
13101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* val = CAS_BASE(RX_AE_THRESH_FREE, RX_AE_FREEN_VAL(0)); */
13111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = CAS_BASE(RX_AE_THRESH_COMP, RX_AE_COMP_VAL);
13121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_RX_AE_THRESH);
13131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
13141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = CAS_BASE(RX_AE1_THRESH_FREE, RX_AE_FREEN_VAL(1));
13151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_PLUS_RX_AE1_THRESH);
13161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
13171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Random early detect registers. useful for congestion avoidance.
13191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * this should be tunable.
13201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
13211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x0, cp->regs + REG_RX_RED);
13226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
13231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* receive page sizes. default == 2K (0x800) */
13241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = 0;
13251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->page_size == 0x1000)
13261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = 0x1;
13271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else if (cp->page_size == 0x2000)
13281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = 0x2;
13291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else if (cp->page_size == 0x4000)
13301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = 0x3;
13316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
13321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* round mtu + offset. constrain to page size. */
13331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	size = cp->dev->mtu + 64;
13341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (size > cp->page_size)
13351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		size = cp->page_size;
13361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (size <= 0x400)
13381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = 0x0;
13391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else if (size <= 0x800)
13401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = 0x1;
13411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else if (size <= 0x1000)
13421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = 0x2;
13431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else
13441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = 0x3;
13451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->mtu_stride = 1 << (i + 10);
13471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val  = CAS_BASE(RX_PAGE_SIZE, val);
13486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	val |= CAS_BASE(RX_PAGE_SIZE_MTU_STRIDE, i);
13491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val |= CAS_BASE(RX_PAGE_SIZE_MTU_COUNT, cp->page_size >> (i + 10));
13501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val |= CAS_BASE(RX_PAGE_SIZE_MTU_OFF, 0x1);
13511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_RX_PAGE_SIZE);
13526aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
13531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* enable the header parser if desired */
13541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (CAS_HP_FIRMWARE == cas_prog_null)
13551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
13561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = CAS_BASE(HP_CFG_NUM_CPU, CAS_NCPUS > 63 ? 0 : CAS_NCPUS);
13581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val |= HP_CFG_PARSE_EN | HP_CFG_SYN_INC_MASK;
13591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val |= CAS_BASE(HP_CFG_TCP_THRESH, HP_TCP_THRESH_VAL);
13601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_HP_CFG);
13611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
13621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_rxc_init(struct cas_rx_comp *rxc)
13641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
13651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	memset(rxc, 0, sizeof(*rxc));
13666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	rxc->word4 = cpu_to_le64(RX_COMP4_ZERO);
13671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
13681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* NOTE: we use the ENC RX DESC ring for spares. the rx_page[0,1]
13701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * flipping is protected by the fact that the chip will not
13711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * hand back the same page index while it's being processed.
13721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
13731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline cas_page_t *cas_page_spare(struct cas *cp, const int index)
13741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
13751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t *page = cp->rx_pages[1][index];
13761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t *new;
13771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13789de4dfb4c7176e5bb232a21cdd8df78da2b15cacDavid S. Miller	if (page_count(page->buffer) == 1)
13791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return page;
13801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	new = cas_page_dequeue(cp);
13821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (new) {
13831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->rx_inuse_lock);
13841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		list_add(&page->list, &cp->rx_inuse_list);
13851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->rx_inuse_lock);
13861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
13871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return new;
13881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
13896aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
13901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* this needs to be changed if we actually use the ENC RX DESC ring */
13916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic cas_page_t *cas_page_swap(struct cas *cp, const int ring,
13921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				 const int index)
13931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
13941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t **page0 = cp->rx_pages[0];
13951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t **page1 = cp->rx_pages[1];
13961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
13971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* swap if buffer is in use */
13989de4dfb4c7176e5bb232a21cdd8df78da2b15cacDavid S. Miller	if (page_count(page0[index]->buffer) > 1) {
13991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_t *new = cas_page_spare(cp, index);
14001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (new) {
14011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			page1[index] = page0[index];
14021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			page0[index] = new;
14031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
14046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	}
14051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	RX_USED_SET(page0[index], 0);
14061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return page0[index];
14071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
14081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_clean_rxds(struct cas *cp)
14101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
14111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* only clean ring 0 as ring 1 is used for spare buffers */
14121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller        struct cas_rx_desc *rxd = cp->init_rxds[0];
14131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i, size;
14141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* release all rx flows */
14161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_FLOWS; i++) {
14171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		struct sk_buff *skb;
14181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		while ((skb = __skb_dequeue(&cp->rx_flows[i]))) {
14191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_skb_release(skb);
14201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
14211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* initialize descriptors */
14241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	size = RX_DESC_RINGN_SIZE(0);
14251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < size; i++) {
14261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_t *page = cas_page_swap(cp, 0, i);
14271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		rxd[i].buffer = cpu_to_le64(page->dma_addr);
14286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		rxd[i].index  = cpu_to_le64(CAS_BASE(RX_INDEX_NUM, i) |
14291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					    CAS_BASE(RX_INDEX_RING, 0));
14301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	cp->rx_old[0]  = RX_DESC_RINGN_SIZE(0) - 4;
14331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_last[0] = 0;
14341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->cas_flags &= ~CAS_FLAG_RXD_POST(0);
14351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
14361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_clean_rxcs(struct cas *cp)
14381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
14391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i, j;
14401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* take ownership of rx comp descriptors */
14421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	memset(cp->rx_cur, 0, sizeof(*cp->rx_cur)*N_RX_COMP_RINGS);
14431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	memset(cp->rx_new, 0, sizeof(*cp->rx_new)*N_RX_COMP_RINGS);
14441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_COMP_RINGS; i++) {
14451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		struct cas_rx_comp *rxc = cp->init_rxcs[i];
14461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (j = 0; j < RX_COMP_RINGN_SIZE(i); j++) {
14471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_rxc_init(rxc + j);
14481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
14491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
14511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 0
14531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* When we get a RX fifo overflow, the RX unit is probably hung
14541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * so we do the following.
14551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
14561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * If any part of the reset goes wrong, we return 1 and that causes the
14571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * whole chip to be reset.
14581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
14591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_rxmac_reset(struct cas *cp)
14601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
14611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = cp->dev;
14621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int limit;
14631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
14641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* First, reset MAC RX. */
14661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(cp->mac_rx_cfg & ~MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
14671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (limit = 0; limit < STOP_TRIES; limit++) {
14681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!(readl(cp->regs + REG_MAC_RX_CFG) & MAC_RX_CFG_EN))
14691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
14701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
14711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (limit == STOP_TRIES) {
1473436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "RX MAC will not disable, resetting whole chip\n");
14741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 1;
14751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Second, disable RX DMA. */
14781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_RX_CFG);
14791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (limit = 0; limit < STOP_TRIES; limit++) {
14801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!(readl(cp->regs + REG_RX_CFG) & RX_CFG_DMA_EN))
14811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
14821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
14831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (limit == STOP_TRIES) {
1485436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "RX DMA will not disable, resetting whole chip\n");
14861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 1;
14871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	mdelay(5);
14901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
14911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Execute RX reset command. */
14921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(SW_RESET_RX, cp->regs + REG_SW_RESET);
14931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (limit = 0; limit < STOP_TRIES; limit++) {
14941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!(readl(cp->regs + REG_SW_RESET) & SW_RESET_RX))
14951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
14961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
14971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
14981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (limit == STOP_TRIES) {
1499436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "RX reset command will not execute, resetting whole chip\n");
15001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 1;
15011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
15021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* reset driver rx state */
15041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clean_rxds(cp);
15051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clean_rxcs(cp);
15061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Now, reprogram the rest of RX unit. */
15081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_init_rx_dma(cp);
15091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* re-enable */
15111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_RX_CFG);
15121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val | RX_CFG_DMA_EN, cp->regs + REG_RX_CFG);
15131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(MAC_RX_FRAME_RECV, cp->regs + REG_MAC_RX_MASK);
15141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_MAC_RX_CFG);
15151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val | MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
15161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
15171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
15181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
15191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_rxmac_interrupt(struct net_device *dev, struct cas *cp,
15211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       u32 status)
15221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
15231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 stat = readl(cp->regs + REG_MAC_RX_STATUS);
15241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!stat)
15261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
15271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1528436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_dbg(cp, intr, cp->dev, "rxmac interrupt, stat: 0x%x\n", stat);
15291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* these are all rollovers */
15311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->stat_lock[0]);
15326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (stat & MAC_RX_ALIGN_ERR)
15331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_frame_errors += 0x10000;
15341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & MAC_RX_CRC_ERR)
15361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_crc_errors += 0x10000;
15371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & MAC_RX_LEN_ERR)
15391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_length_errors += 0x10000;
15401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & MAC_RX_OVERFLOW) {
15421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_over_errors++;
15431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_fifo_errors++;
15441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
15451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* We do not track MAC_RX_FRAME_COUNT and MAC_RX_VIOL_ERR
15471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * events.
15481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
15491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->stat_lock[0]);
15501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
15511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
15521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_mac_interrupt(struct net_device *dev, struct cas *cp,
15541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			     u32 status)
15551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
15561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 stat = readl(cp->regs + REG_MAC_CTRL_STATUS);
15571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!stat)
15591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
15601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1561436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_printk(cp, intr, KERN_DEBUG, cp->dev,
1562436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     "mac interrupt, stat: 0x%x\n", stat);
15631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* This interrupt is just for pause frame and pause
15651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * tracking.  It is useful for diagnostics and debug
15661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * but probably by default we will mask these events.
15671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
15681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & MAC_CTRL_PAUSE_STATE)
15691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->pause_entered++;
15701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & MAC_CTRL_PAUSE_RECEIVED)
15721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->pause_last_time_recvd = (stat >> 16);
15731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
15751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
15761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
15781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
15791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline int cas_mdio_link_not_up(struct cas *cp)
15801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
15811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u16 val;
15826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
15831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	switch (cp->lstate) {
15841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	case link_force_ret:
1585436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netif_info(cp, link, cp->dev, "Autoneg failed again, keeping forced mode\n");
15861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_phy_write(cp, MII_BMCR, cp->link_fcntl);
15871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->timer_ticks = 5;
15881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->lstate = link_force_ok;
15891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
15901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		break;
15916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
15921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	case link_aneg:
15931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = cas_phy_read(cp, MII_BMCR);
15941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
15951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Try forced modes. we try things in the following order:
15961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * 1000 full -> 100 full/half -> 10 half
15971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
15981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
15991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= BMCR_FULLDPLX;
16006aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		val |= (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
16011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			CAS_BMCR_SPEED1000 : BMCR_SPEED100;
16021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_phy_write(cp, MII_BMCR, val);
16031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->timer_ticks = 5;
16041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->lstate = link_force_try;
16051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
16061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		break;
16071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	case link_force_try:
16091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Downgrade from 1000 to 100 to 10 Mbps if necessary. */
16101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = cas_phy_read(cp, MII_BMCR);
16111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->timer_ticks = 5;
16121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (val & CAS_BMCR_SPEED1000) { /* gigabit */
16131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val &= ~CAS_BMCR_SPEED1000;
16141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val |= (BMCR_SPEED100 | BMCR_FULLDPLX);
16151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, MII_BMCR, val);
16161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
16171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
16181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (val & BMCR_SPEED100) {
16201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (val & BMCR_FULLDPLX) /* fd failed */
16211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				val &= ~BMCR_FULLDPLX;
16221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			else { /* 100Mbps failed */
16231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				val &= ~BMCR_SPEED100;
16241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
16251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, MII_BMCR, val);
16261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
16271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
16281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	default:
16291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		break;
16301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
16311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
16321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
16331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* must be invoked with cp->lock held */
16361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_mii_link_check(struct cas *cp, const u16 bmsr)
16371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
16381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int restart;
16391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (bmsr & BMSR_LSTATUS) {
16411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Ok, here we got a link. If we had it due to a forced
16426aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		 * fallback, and we were configured for autoneg, we
16431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * retry a short autoneg pass. If you know your hub is
16441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * broken, use ethtool ;)
16451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
16466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		if ((cp->lstate == link_force_try) &&
16471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    (cp->link_cntl & BMCR_ANENABLE)) {
16481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->lstate = link_force_ret;
16491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
16501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_mif_poll(cp, 0);
16511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_fcntl = cas_phy_read(cp, MII_BMCR);
16521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->timer_ticks = 5;
1653436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			if (cp->opened)
1654436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				netif_info(cp, link, cp->dev,
1655436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches					   "Got link after fallback, retrying autoneg once...\n");
16561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_phy_write(cp, MII_BMCR,
16571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				      cp->link_fcntl | BMCR_ANENABLE |
16581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				      BMCR_ANRESTART);
16591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_mif_poll(cp, 1);
16601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else if (cp->lstate != link_up) {
16621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->lstate = link_up;
16631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->link_transition = LINK_TRANSITION_LINK_UP;
16641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (cp->opened) {
16661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cas_set_link_modes(cp);
16671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				netif_carrier_on(cp->dev);
16681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
16691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
16701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
16711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
16721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* link not up. if the link was previously up, we restart the
16741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * whole process
16751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
16761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	restart = 0;
16771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->lstate == link_up) {
16781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->lstate = link_down;
16791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_transition = LINK_TRANSITION_LINK_DOWN;
16801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_carrier_off(cp->dev);
1682436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		if (cp->opened)
1683436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netif_info(cp, link, cp->dev, "Link down\n");
16841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		restart = 1;
16856aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
16861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (++cp->timer_ticks > 10)
16871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mdio_link_not_up(cp);
16886aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
16891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return restart;
16901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
16911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_mif_interrupt(struct net_device *dev, struct cas *cp,
16931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			     u32 status)
16941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
16951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 stat = readl(cp->regs + REG_MIF_STATUS);
16961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u16 bmsr;
16971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
16981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* check for a link change */
16991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (CAS_VAL(MIF_STATUS_POLL_STATUS, stat) == 0)
17001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
17011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	bmsr = CAS_VAL(MIF_STATUS_POLL_DATA, stat);
17031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return cas_mii_link_check(cp, bmsr);
17041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
17051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_pci_interrupt(struct net_device *dev, struct cas *cp,
17071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			     u32 status)
17081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
17091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 stat = readl(cp->regs + REG_PCI_ERR_STATUS);
17101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!stat)
17121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
17131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1714436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "PCI error [%04x:%04x]",
1715436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   stat, readl(cp->regs + REG_BIM_DIAG));
17161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* cassini+ has this reserved */
17181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((stat & PCI_ERR_BADACK) &&
17191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    ((cp->cas_flags & CAS_FLAG_REG_PLUS) == 0))
1720436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_cont(" <No ACK64# during ABS64 cycle>");
17211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & PCI_ERR_DTRTO)
1723436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_cont(" <Delayed transaction timeout>");
17241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & PCI_ERR_OTHER)
1725436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_cont(" <other>");
17261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & PCI_ERR_BIM_DMA_WRITE)
1727436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_cont(" <BIM DMA 0 write req>");
17281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & PCI_ERR_BIM_DMA_READ)
1729436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_cont(" <BIM DMA 0 read req>");
1730436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	pr_cont("\n");
17311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (stat & PCI_ERR_OTHER) {
17331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u16 cfg;
17341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Interrogate PCI config space for the
17361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * true cause.
17371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
17381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_read_config_word(cp->pdev, PCI_STATUS, &cfg);
1739436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "Read PCI cfg space status [%04x]\n", cfg);
17401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cfg & PCI_STATUS_PARITY)
1741436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_err(dev, "PCI parity error detected\n");
17421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cfg & PCI_STATUS_SIG_TARGET_ABORT)
1743436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_err(dev, "PCI target abort\n");
17441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cfg & PCI_STATUS_REC_TARGET_ABORT)
1745436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_err(dev, "PCI master acks target abort\n");
17461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cfg & PCI_STATUS_REC_MASTER_ABORT)
1747436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_err(dev, "PCI master abort\n");
17481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cfg & PCI_STATUS_SIG_SYSTEM_ERROR)
1749436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_err(dev, "PCI system error SERR#\n");
17501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cfg & PCI_STATUS_DETECTED_PARITY)
1751436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_err(dev, "PCI parity error\n");
17521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Write the error bits back to clear them. */
17541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cfg &= (PCI_STATUS_PARITY |
17551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			PCI_STATUS_SIG_TARGET_ABORT |
17561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			PCI_STATUS_REC_TARGET_ABORT |
17571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			PCI_STATUS_REC_MASTER_ABORT |
17581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			PCI_STATUS_SIG_SYSTEM_ERROR |
17591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			PCI_STATUS_DETECTED_PARITY);
17601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_write_config_word(cp->pdev, PCI_STATUS, cfg);
17611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
17621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* For all PCI errors, we should reset the chip. */
17641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 1;
17651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
17661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* All non-normal interrupt conditions get serviced here.
17681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Returns non-zero if we should just exit the interrupt
17691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * handler right now (ie. if we reset the card which invalidates
17701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * all of the other original irq status bits).
17711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
17721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_abnormal_irq(struct net_device *dev, struct cas *cp,
17731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    u32 status)
17741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
17751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_TAG_ERROR) {
17761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* corrupt RX tag framing */
1777436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
1778436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			     "corrupt rx tag framing\n");
17791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->stat_lock[0]);
17801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_errors++;
17811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->stat_lock[0]);
17821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto do_reset;
17831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
17841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_LEN_MISMATCH) {
17861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* length mismatch. */
1787436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
1788436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			     "length mismatch for rx frame\n");
17891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->stat_lock[0]);
17901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_errors++;
17911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->stat_lock[0]);
17921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto do_reset;
17931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
17941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
17951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_PCS_STATUS) {
17961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cas_pcs_interrupt(dev, cp, status))
17971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto do_reset;
17981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
17991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_TX_MAC_STATUS) {
18011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cas_txmac_interrupt(dev, cp, status))
18021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto do_reset;
18031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
18041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_MAC_STATUS) {
18061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cas_rxmac_interrupt(dev, cp, status))
18071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto do_reset;
18081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
18091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_MAC_CTRL_STATUS) {
18111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cas_mac_interrupt(dev, cp, status))
18121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto do_reset;
18131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
18141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_MIF_STATUS) {
18161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cas_mif_interrupt(dev, cp, status))
18171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto do_reset;
18181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
18191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_PCI_ERROR_STATUS) {
18211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cas_pci_interrupt(dev, cp, status))
18221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto do_reset;
18231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
18241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
18251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdo_reset:
18271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
18281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_inc(&cp->reset_task_pending);
18291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_inc(&cp->reset_task_pending_all);
1830436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "reset called in cas_abnormal_irq [0x%x]\n", status);
18311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	schedule_work(&cp->reset_task);
18321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
18331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
1834436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "reset called in cas_abnormal_irq\n");
18351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	schedule_work(&cp->reset_task);
18361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
18371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 1;
18381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
18391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* NOTE: CAS_TABORT returns 1 or 2 so that it can be used when
18411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       determining whether to do a netif_stop/wakeup
18421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
18431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_TABORT(x)      (((x)->cas_flags & CAS_FLAG_TARGET_ABORT) ? 2 : 1)
18441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_ROUND_PAGE(x)  (((x) + PAGE_SIZE - 1) & PAGE_MASK)
18451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline int cas_calc_tabort(struct cas *cp, const unsigned long addr,
18461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				  const int len)
18471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
18481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long off = addr + len;
18491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (CAS_TABORT(cp) == 1)
18511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
18521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((CAS_ROUND_PAGE(off) - off) > TX_TARGET_ABORT_LEN)
18531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
18541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return TX_TARGET_ABORT_LEN;
18551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
18561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_tx_ringN(struct cas *cp, int ring, int limit)
18581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
18591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas_tx_desc *txds;
18601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct sk_buff **skbs;
18611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = cp->dev;
18621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int entry, count;
18631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->tx_lock[ring]);
18651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	txds = cp->init_txds[ring];
18661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	skbs = cp->tx_skbs[ring];
18671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = cp->tx_old[ring];
18681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	count = TX_BUFF_COUNT(ring, entry, limit);
18701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (entry != limit) {
18711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		struct sk_buff *skb = skbs[entry];
18721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		dma_addr_t daddr;
18731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 dlen;
18741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int frag;
18751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!skb) {
18771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* this should never occur */
18781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			entry = TX_DESC_NEXT(ring, entry);
18791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			continue;
18801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
18811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* however, we might get only a partial skb release. */
18831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		count -= skb_shinfo(skb)->nr_frags +
18841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			+ cp->tx_tiny_use[ring][entry].nbufs + 1;
18851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (count < 0)
18861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
18871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1888436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netif_printk(cp, tx_done, KERN_DEBUG, cp->dev,
1889436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			     "tx[%d] done, slot %d\n", ring, entry);
18901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skbs[entry] = NULL;
18921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->tx_tiny_use[ring][entry].nbufs = 0;
18936aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
18941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
18951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			struct cas_tx_desc *txd = txds + entry;
18961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
18971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			daddr = le64_to_cpu(txd->buffer);
18981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			dlen = CAS_VAL(TX_DESC_BUFLEN,
18991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				       le64_to_cpu(txd->control));
19001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			pci_unmap_page(cp->pdev, daddr, dlen,
19011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				       PCI_DMA_TODEVICE);
19021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			entry = TX_DESC_NEXT(ring, entry);
19031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* tiny buffer may follow */
19051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (cp->tx_tiny_use[ring][entry].used) {
19061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->tx_tiny_use[ring][entry].used = 0;
19071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				entry = TX_DESC_NEXT(ring, entry);
19086aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			}
19091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
19101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->stat_lock[ring]);
19121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[ring].tx_packets++;
19131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[ring].tx_bytes += skb->len;
19141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->stat_lock[ring]);
19151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		dev_kfree_skb_irq(skb);
19161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
19171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->tx_old[ring] = entry;
19181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* this is wrong for multiple tx rings. the net device needs
19201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * multiple queues for this to do the right thing.  we wait
19211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * for 2*packets to be available when using tiny buffers
19221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
19231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (netif_queue_stopped(dev) &&
19241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    (TX_BUFFS_AVAIL(cp, ring) > CAS_TABORT(cp)*(MAX_SKB_FRAGS + 1)))
19251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_wake_queue(dev);
19261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->tx_lock[ring]);
19271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
19281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_tx(struct net_device *dev, struct cas *cp,
19301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		   u32 status)
19311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
19321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller        int limit, ring;
19331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_TX_COMPWB
19341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u64 compwb = le64_to_cpu(cp->init_block->tx_compwb);
19351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
1936436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_printk(cp, intr, KERN_DEBUG, cp->dev,
1937436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     "tx interrupt, status: 0x%x, %llx\n",
1938436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     status, (unsigned long long)compwb);
19391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* process all the rings */
19401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (ring = 0; ring < N_TX_RINGS; ring++) {
19411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_TX_COMPWB
19421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* use the completion writeback registers */
19431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		limit = (CAS_VAL(TX_COMPWB_MSB, compwb) << 8) |
19441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			CAS_VAL(TX_COMPWB_LSB, compwb);
19451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		compwb = TX_COMPWB_NEXT(compwb);
19461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
19471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		limit = readl(cp->regs + REG_TX_COMPN(ring));
19481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
19496aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		if (cp->tx_old[ring] != limit)
19501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_tx_ringN(cp, ring, limit);
19511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
19521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
19531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19556aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
19566aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			      int entry, const u64 *words,
19571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			      struct sk_buff **skbref)
19581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
19591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int dlen, hlen, len, i, alloclen;
19601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int off, swivel = RX_SWIVEL_OFF_VAL;
19611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas_page *page;
19621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct sk_buff *skb;
19631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	void *addr, *crcaddr;
1964e5e025401f6e926c1d9dc3f3f2813cf98a2d8708Al Viro	__sum16 csum;
19656aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	char *p;
19661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
19681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dlen = CAS_VAL(RX_COMP1_DATA_SIZE, words[0]);
19691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	len  = hlen + dlen;
19701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (RX_COPY_ALWAYS || (words[2] & RX_COMP3_SMALL_PKT))
19721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		alloclen = len;
19736aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	else
19741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		alloclen = max(hlen, RX_COPY_MIN);
19751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
1976dae2e9f430c46c29e3f771110094bd3da3625aa4Pradeep A. Dalvi	skb = netdev_alloc_skb(cp->dev, alloclen + swivel + cp->crc_size);
19776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (skb == NULL)
19781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return -1;
19791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	*skbref = skb;
19811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	skb_reserve(skb, swivel);
19821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	p = skb->data;
19841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	addr = crcaddr = NULL;
19851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (hlen) { /* always copy header pages */
19861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = CAS_VAL(RX_COMP2_HDR_INDEX, words[1]);
19871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
19886aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		off = CAS_VAL(RX_COMP2_HDR_OFF, words[1]) * 0x100 +
19891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			swivel;
19901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
19911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = hlen;
19921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!dlen) /* attach FCS */
19931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i += cp->crc_size;
19941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr + off, i,
19951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    PCI_DMA_FROMDEVICE);
19961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		addr = cas_page_map(page->buffer);
19971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		memcpy(p, addr + off, i);
19981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_dma_sync_single_for_device(cp->pdev, page->dma_addr + off, i,
19991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    PCI_DMA_FROMDEVICE);
20001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_unmap(addr);
20011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		RX_USED_ADD(page, 0x100);
20021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		p += hlen;
20031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		swivel = 0;
20046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	}
20051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (alloclen < (hlen + dlen)) {
20081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb_frag_t *frag = skb_shinfo(skb)->frags;
20091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* normal or jumbo packets. we use frags */
20111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
20121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
20131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		off = CAS_VAL(RX_COMP1_DATA_OFF, words[0]) + swivel;
20141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		hlen = min(cp->page_size - off, dlen);
20161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (hlen < 0) {
2017436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
2018436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				     "rx page overflow: %d\n", hlen);
20191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			dev_kfree_skb_irq(skb);
20201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return -1;
20211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
20221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = hlen;
20231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (i == dlen)  /* attach FCS */
20241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i += cp->crc_size;
20251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr + off, i,
20261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    PCI_DMA_FROMDEVICE);
20271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* make sure we always copy a header */
20291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		swivel = 0;
20301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (p == (char *) skb->data) { /* not split */
20311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			addr = cas_page_map(page->buffer);
20321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			memcpy(p, addr + off, RX_COPY_MIN);
20331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			pci_dma_sync_single_for_device(cp->pdev, page->dma_addr + off, i,
20341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					PCI_DMA_FROMDEVICE);
20351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_page_unmap(addr);
20361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			off += RX_COPY_MIN;
20371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			swivel = RX_COPY_MIN;
20381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			RX_USED_ADD(page, cp->mtu_stride);
20391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
20401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			RX_USED_ADD(page, hlen);
20411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
20421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb_put(skb, alloclen);
20431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb_shinfo(skb)->nr_frags++;
20451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb->data_len += hlen - swivel;
2046d011a231675b240157a3c335dd53e9b849d7d30dDavid S. Miller		skb->truesize += hlen - swivel;
20471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb->len      += hlen - swivel;
20481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
204918324d690d6a5028e3c174fc1921447aedead2b8Ian Campbell		__skb_frag_set_page(frag, page->buffer);
205018324d690d6a5028e3c174fc1921447aedead2b8Ian Campbell		__skb_frag_ref(frag);
20511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		frag->page_offset = off;
20529e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		skb_frag_size_set(frag, hlen - swivel);
20536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
20541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* any more data? */
20551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
20561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			hlen = dlen;
20571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			off = 0;
20581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
20601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
20616aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
20626aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					    hlen + cp->crc_size,
20631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					    PCI_DMA_FROMDEVICE);
20641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			pci_dma_sync_single_for_device(cp->pdev, page->dma_addr,
20651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					    hlen + cp->crc_size,
20661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					    PCI_DMA_FROMDEVICE);
20671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			skb_shinfo(skb)->nr_frags++;
20691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			skb->data_len += hlen;
20706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			skb->len      += hlen;
20711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			frag++;
20721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
207318324d690d6a5028e3c174fc1921447aedead2b8Ian Campbell			__skb_frag_set_page(frag, page->buffer);
207418324d690d6a5028e3c174fc1921447aedead2b8Ian Campbell			__skb_frag_ref(frag);
20751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			frag->page_offset = 0;
20769e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet			skb_frag_size_set(frag, hlen);
20771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			RX_USED_ADD(page, hlen + cp->crc_size);
20781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
20791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->crc_size) {
20811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			addr = cas_page_map(page->buffer);
20821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			crcaddr  = addr + off + hlen;
20831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
20841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
20861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* copying packet */
20871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!dlen)
20881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto end_copy_pkt;
20891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
20901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
20911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
20921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		off = CAS_VAL(RX_COMP1_DATA_OFF, words[0]) + swivel;
20931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		hlen = min(cp->page_size - off, dlen);
20941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (hlen < 0) {
2095436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
2096436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				     "rx page overflow: %d\n", hlen);
20971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			dev_kfree_skb_irq(skb);
20981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return -1;
20991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
21001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i = hlen;
21011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (i == dlen) /* attach FCS */
21021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i += cp->crc_size;
21031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr + off, i,
21041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    PCI_DMA_FROMDEVICE);
21051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		addr = cas_page_map(page->buffer);
21061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		memcpy(p, addr + off, i);
21071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_dma_sync_single_for_device(cp->pdev, page->dma_addr + off, i,
21081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    PCI_DMA_FROMDEVICE);
21091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_page_unmap(addr);
21101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (p == (char *) skb->data) /* not split */
21111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			RX_USED_ADD(page, cp->mtu_stride);
21121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		else
21131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			RX_USED_ADD(page, i);
21146aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
21151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* any more data? */
21161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
21171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			p += hlen;
21181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
21191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
21206aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
21216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					    dlen + cp->crc_size,
21221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					    PCI_DMA_FROMDEVICE);
21231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			addr = cas_page_map(page->buffer);
21241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			memcpy(p, addr, dlen + cp->crc_size);
21251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			pci_dma_sync_single_for_device(cp->pdev, page->dma_addr,
21261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					    dlen + cp->crc_size,
21271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					    PCI_DMA_FROMDEVICE);
21281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_page_unmap(addr);
21296aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			RX_USED_ADD(page, dlen + cp->crc_size);
21301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
21311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerend_copy_pkt:
21321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->crc_size) {
21331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			addr    = NULL;
21341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			crcaddr = skb->data + alloclen;
21351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
21361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb_put(skb, alloclen);
21371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
21381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2139e5e025401f6e926c1d9dc3f3f2813cf98a2d8708Al Viro	csum = (__force __sum16)htons(CAS_VAL(RX_COMP4_TCP_CSUM, words[3]));
21401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->crc_size) {
21411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* checksum includes FCS. strip it out. */
2142e5e025401f6e926c1d9dc3f3f2813cf98a2d8708Al Viro		csum = csum_fold(csum_partial(crcaddr, cp->crc_size,
2143e5e025401f6e926c1d9dc3f3f2813cf98a2d8708Al Viro					      csum_unfold(csum)));
21441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (addr)
21451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_page_unmap(addr);
21461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
21471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	skb->protocol = eth_type_trans(skb, cp->dev);
2148b1443e2f6501f06930a162ff1ff08382a98bf23eDavid S. Miller	if (skb->protocol == htons(ETH_P_IP)) {
2149b1443e2f6501f06930a162ff1ff08382a98bf23eDavid S. Miller		skb->csum = csum_unfold(~csum);
2150b1443e2f6501f06930a162ff1ff08382a98bf23eDavid S. Miller		skb->ip_summed = CHECKSUM_COMPLETE;
2151b1443e2f6501f06930a162ff1ff08382a98bf23eDavid S. Miller	} else
2152bc8acf2c8c3e43fcc192762a9f964b3e9a17748bEric Dumazet		skb_checksum_none_assert(skb);
21531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return len;
21541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
21551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
21561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
21571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* we can handle up to 64 rx flows at a time. we do the same thing
21586aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * as nonreassm except that we batch up the buffers.
21591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * NOTE: we currently just treat each flow as a bunch of packets that
21601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       we pass up. a better way would be to coalesce the packets
21611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       into a jumbo packet. to do that, we need to do the following:
21621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       1) the first packet will have a clean split between header and
21631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *          data. save both.
21641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       2) each time the next flow packet comes in, extend the
21651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *          data length and merge the checksums.
21661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       3) on flow release, fix up the header.
21671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       4) make sure the higher layer doesn't care.
21686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * because packets get coalesced, we shouldn't run into fragment count
21691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * issues.
21701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
21711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words,
21721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				   struct sk_buff *skb)
21731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
21741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int flowid = CAS_VAL(RX_COMP3_FLOWID, words[2]) & (N_RX_FLOWS - 1);
21751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct sk_buff_head *flow = &cp->rx_flows[flowid];
21766aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
21776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	/* this is protected at a higher layer, so no need to
21781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * do any additional locking here. stick the buffer
21791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * at the end.
21801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
218143f59c89399fd76883a06c551f24794e98409432David S. Miller	__skb_queue_tail(flow, skb);
21821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (words[0] & RX_COMP1_RELEASE_FLOW) {
21831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		while ((skb = __skb_dequeue(flow))) {
21841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_skb_release(skb);
21851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
21861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
21871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
21881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
21891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* put rx descriptor back on ring. if a buffer is in use by a higher
21901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * layer, this will need to put in a replacement.
21911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
21921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_post_page(struct cas *cp, const int ring, const int index)
21931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
21941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t *new;
21951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int entry;
21961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
21971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = cp->rx_old[ring];
21981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
21991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	new = cas_page_swap(cp, ring, index);
22001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->init_rxds[ring][entry].buffer = cpu_to_le64(new->dma_addr);
22011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->init_rxds[ring][entry].index  =
22026aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		cpu_to_le64(CAS_BASE(RX_INDEX_NUM, index) |
22031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    CAS_BASE(RX_INDEX_RING, ring));
22041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = RX_DESC_ENTRY(ring, entry + 1);
22061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_old[ring] = entry;
22076aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
22081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (entry % 4)
22091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
22101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (ring == 0)
22121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(entry, cp->regs + REG_RX_KICK);
22131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else if ((N_RX_DESC_RINGS > 1) &&
22146aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		 (cp->cas_flags & CAS_FLAG_REG_PLUS))
22151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(entry, cp->regs + REG_PLUS_RX_KICK1);
22161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
22171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* only when things are bad */
22201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
22211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
22221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned int entry, last, count, released;
22231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int cluster;
22241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t **page = cp->rx_pages[ring];
22251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = cp->rx_old[ring];
22271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2228436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_printk(cp, intr, KERN_DEBUG, cp->dev,
2229436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     "rxd[%d] interrupt, done: %d\n", ring, entry);
22301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cluster = -1;
22326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	count = entry & 0x3;
22331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	last = RX_DESC_ENTRY(ring, num ? entry + num - 4: entry - 4);
22341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	released = 0;
22351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (entry != last) {
22361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* make a new buffer if it's still in use */
22379de4dfb4c7176e5bb232a21cdd8df78da2b15cacDavid S. Miller		if (page_count(page[entry]->buffer) > 1) {
22381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_page_t *new = cas_page_dequeue(cp);
22391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (!new) {
22406aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik				/* let the timer know that we need to
22411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				 * do this again
22421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				 */
22431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->cas_flags |= CAS_FLAG_RXD_POST(ring);
22441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				if (!timer_pending(&cp->link_timer))
22456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					mod_timer(&cp->link_timer, jiffies +
22461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller						  CAS_LINK_FAST_TIMEOUT);
22471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->rx_old[ring]  = entry;
22481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->rx_last[ring] = num ? num - released : 0;
22491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				return -ENOMEM;
22501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
22511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_lock(&cp->rx_inuse_lock);
22521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			list_add(&page[entry]->list, &cp->rx_inuse_list);
22531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_unlock(&cp->rx_inuse_lock);
22546aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			cp->init_rxds[ring][entry].buffer =
22551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cpu_to_le64(new->dma_addr);
22561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			page[entry] = new;
22576aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
22581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
22591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (++count == 4) {
22611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cluster = entry;
22621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			count = 0;
22631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
22641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		released++;
22651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		entry = RX_DESC_ENTRY(ring, entry + 1);
22661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
22671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_old[ring] = entry;
22681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (cluster < 0)
22701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
22711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (ring == 0)
22731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(cluster, cp->regs + REG_RX_KICK);
22741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else if ((N_RX_DESC_RINGS > 1) &&
22756aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		 (cp->cas_flags & CAS_FLAG_REG_PLUS))
22761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(cluster, cp->regs + REG_PLUS_RX_KICK1);
22771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
22781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
22791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
22811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* process a completion ring. packets are set up in three basic ways:
22821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * small packets: should be copied header + data in single buffer.
22831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * large packets: header and data in a single buffer.
22846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * split packets: header in a separate buffer from data.
22851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *                data may be in multiple pages. data may be > 256
22866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *                bytes but in a single page.
22871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
22881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * NOTE: RX page posting is done in this routine as well. while there's
22891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       the capability of using multiple RX completion rings, it isn't
22901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *       really worthwhile due to the fact that the page posting will
22916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *       force serialization on the single descriptor ring.
22921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
22931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_rx_ringN(struct cas *cp, int ring, int budget)
22941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
22951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas_rx_comp *rxcs = cp->init_rxcs[ring];
22961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int entry, drops;
22971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int npackets = 0;
22981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2299436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_printk(cp, intr, KERN_DEBUG, cp->dev,
2300436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     "rx[%d] interrupt, done: %d/%d\n",
2301436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     ring,
2302436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     readl(cp->regs + REG_RX_COMP_HEAD), cp->rx_new[ring]);
23031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = cp->rx_new[ring];
23051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	drops = 0;
23061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (1) {
23071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		struct cas_rx_comp *rxc = rxcs + entry;
2308b71e839f9a33abf8634b1eea4875bc8057fe39e2Ingo Molnar		struct sk_buff *uninitialized_var(skb);
23091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int type, len;
23101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u64 words[4];
23111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int i, dring;
23121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		words[0] = le64_to_cpu(rxc->word1);
23141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		words[1] = le64_to_cpu(rxc->word2);
23151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		words[2] = le64_to_cpu(rxc->word3);
23161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		words[3] = le64_to_cpu(rxc->word4);
23171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* don't touch if still owned by hw */
23191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		type = CAS_VAL(RX_COMP1_TYPE, words[0]);
23201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (type == 0)
23211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
23221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* hw hasn't cleared the zero bit yet */
23241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (words[3] & RX_COMP4_ZERO) {
23251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
23261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
23271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* get info on the packet */
23291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (words[3] & (RX_COMP4_LEN_MISMATCH | RX_COMP4_BAD)) {
23301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_lock(&cp->stat_lock[ring]);
23311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->net_stats[ring].rx_errors++;
23321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (words[3] & RX_COMP4_LEN_MISMATCH)
23331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->net_stats[ring].rx_length_errors++;
23341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (words[3] & RX_COMP4_BAD)
23351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->net_stats[ring].rx_crc_errors++;
23361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_unlock(&cp->stat_lock[ring]);
23371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* We'll just return it to Cassini. */
23391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		drop_it:
23401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_lock(&cp->stat_lock[ring]);
23411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			++cp->net_stats[ring].rx_dropped;
23421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			spin_unlock(&cp->stat_lock[ring]);
23431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto next;
23441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
23451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		len = cas_rx_process_pkt(cp, rxc, entry, words, &skb);
23471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (len < 0) {
23481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			++drops;
23491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto drop_it;
23501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
23511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* see if it's a flow re-assembly or not. the driver
23531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * itself handles release back up.
23541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
23551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (RX_DONT_BATCH || (type == 0x2)) {
23561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* non-reassm: these always get released */
23576aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			cas_skb_release(skb);
23581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
23591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_rx_flow_pkt(cp, words, skb);
23601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
23611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->stat_lock[ring]);
23631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[ring].rx_packets++;
23641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[ring].rx_bytes += len;
23651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->stat_lock[ring]);
23661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	next:
23681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		npackets++;
23691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* should it be released? */
23711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (words[0] & RX_COMP1_RELEASE_HDR) {
23721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_COMP2_HDR_INDEX, words[1]);
23731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			dring = CAS_VAL(RX_INDEX_RING, i);
23741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_INDEX_NUM, i);
23751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_post_page(cp, dring, i);
23761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
23776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
23781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (words[0] & RX_COMP1_RELEASE_DATA) {
23791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
23801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			dring = CAS_VAL(RX_INDEX_RING, i);
23811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_INDEX_NUM, i);
23821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_post_page(cp, dring, i);
23831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
23841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (words[0] & RX_COMP1_RELEASE_NEXT) {
23861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
23871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			dring = CAS_VAL(RX_INDEX_RING, i);
23881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			i = CAS_VAL(RX_INDEX_NUM, i);
23891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_post_page(cp, dring, i);
23901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
23911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
23921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* skip to the next entry */
23936aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		entry = RX_COMP_ENTRY(ring, entry + 1 +
23941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				      CAS_VAL(RX_COMP1_SKIP, words[0]));
23951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_NAPI
23961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (budget && (npackets >= budget))
23971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
23981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
23991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
24001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_new[ring] = entry;
24011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (drops)
2403436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_info(cp->dev, "Memory squeeze, deferring packet\n");
24041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return npackets;
24051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
24061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* put completion entries back on the ring */
24091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_post_rxcs_ringN(struct net_device *dev,
24101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				struct cas *cp, int ring)
24111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
24121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas_rx_comp *rxc = cp->init_rxcs[ring];
24131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int last, entry;
24141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	last = cp->rx_cur[ring];
24166aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	entry = cp->rx_new[ring];
2417436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_printk(cp, intr, KERN_DEBUG, dev,
2418436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     "rxc[%d] interrupt, done: %d/%d\n",
2419436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     ring, readl(cp->regs + REG_RX_COMP_HEAD), entry);
24206aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
24211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* zero and re-mark descriptors */
24221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (last != entry) {
24231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_rxc_init(rxc + last);
24241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		last = RX_COMP_ENTRY(ring, last + 1);
24251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
24261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_cur[ring] = last;
24271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (ring == 0)
24291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(last, cp->regs + REG_RX_COMP_TAIL);
24306aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	else if (cp->cas_flags & CAS_FLAG_REG_PLUS)
24311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(last, cp->regs + REG_PLUS_RX_COMPN_TAIL(ring));
24321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
24331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24366aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/* cassini can use all four PCI interrupts for the completion ring.
24371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * rings 3 and 4 are identical
24381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
24391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
24406aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic inline void cas_handle_irqN(struct net_device *dev,
24411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				   struct cas *cp, const u32 status,
24421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				   const int ring)
24431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
24446aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (status & (INTR_RX_COMP_FULL_ALT | INTR_RX_COMP_AF_ALT))
24451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_post_rxcs_ringN(dev, cp, ring);
24461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
24471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24487d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t cas_interruptN(int irq, void *dev_id)
24491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
24501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = dev_id;
24511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
24521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
24533d015565f316584139946a1c450d44209beefeb6françois romieu	int ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
24541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(ring));
24551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* check for shared irq */
24571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status == 0)
24581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return IRQ_NONE;
24591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
24611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
24621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_NAPI
24631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mask_intr(cp);
2464288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_schedule(&cp->napi);
24651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
24661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_rx_ringN(cp, ring, 0);
24671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
24681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		status &= ~INTR_RX_DONE_ALT;
24691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
24701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status)
24721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_handle_irqN(dev, cp, status, ring);
24731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
24741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return IRQ_HANDLED;
24751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
24761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
24771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTB
24791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* everything but rx packets */
24801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_handle_irq1(struct cas *cp, const u32 status)
24811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
24821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_BUF_UNAVAIL_1) {
24836aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		/* Frame arrived, no free RX buffers available.
24841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * NOTE: we can get this on a link transition. */
24851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_post_rxds_ringN(cp, 1, 0);
24861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->stat_lock[1]);
24871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[1].rx_dropped++;
24881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->stat_lock[1]);
24891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
24901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (status & INTR_RX_BUF_AE_1)
24926aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		cas_post_rxds_ringN(cp, 1, RX_DESC_RINGN_SIZE(1) -
24931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    RX_AE_FREEN_VAL(1));
24941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & (INTR_RX_COMP_AF | INTR_RX_COMP_FULL))
24961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_post_rxcs_ringN(cp, 1);
24971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
24981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
24991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* ring 2 handles a few more events than 3 and 4 */
25007d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t cas_interrupt1(int irq, void *dev_id)
25011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
25021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = dev_id;
25031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
25041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
25051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(1));
25061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* check for shared interrupt */
25081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status == 0)
25091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return IRQ_NONE;
25101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
25121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
25131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_NAPI
25141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mask_intr(cp);
2515288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_schedule(&cp->napi);
25161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
25171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_rx_ringN(cp, 1, 0);
25181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
25191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		status &= ~INTR_RX_DONE_ALT;
25201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
25211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status)
25221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_handle_irq1(cp, status);
25231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
25241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return IRQ_HANDLED;
25251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
25261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
25271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_handle_irq(struct net_device *dev,
25291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				  struct cas *cp, const u32 status)
25301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
25311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* housekeeping interrupts */
25321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_ERROR_MASK)
25331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_abnormal_irq(dev, cp, status);
25341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_BUF_UNAVAIL) {
25366aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		/* Frame arrived, no free RX buffers available.
25371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * NOTE: we can get this on a link transition.
25381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
25391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_post_rxds_ringN(cp, 0, 0);
25401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->stat_lock[0]);
25411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->net_stats[0].rx_dropped++;
25421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->stat_lock[0]);
25431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (status & INTR_RX_BUF_AE) {
25441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_post_rxds_ringN(cp, 0, RX_DESC_RINGN_SIZE(0) -
25451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    RX_AE_FREEN_VAL(0));
25461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
25471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & (INTR_RX_COMP_AF | INTR_RX_COMP_FULL))
25491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_post_rxcs_ringN(dev, cp, 0);
25501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
25511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25527d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t cas_interrupt(int irq, void *dev_id)
25531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
25541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = dev_id;
25551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
25561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
25571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 status = readl(cp->regs + REG_INTR_STATUS);
25581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status == 0)
25601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return IRQ_NONE;
25611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
25631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & (INTR_TX_ALL | INTR_TX_INTME)) {
25641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_tx(dev, cp, status);
25651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		status &= ~(INTR_TX_ALL | INTR_TX_INTME);
25661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
25671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status & INTR_RX_DONE) {
25691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_NAPI
25701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mask_intr(cp);
2571288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_schedule(&cp->napi);
25721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
25731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_rx_ringN(cp, 0, 0);
25741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
25751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		status &= ~INTR_RX_DONE;
25761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
25771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status)
25791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_handle_irq(dev, cp, status);
25801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
25811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return IRQ_HANDLED;
25821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
25831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_NAPI
2586bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemmingerstatic int cas_poll(struct napi_struct *napi, int budget)
25871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
2588bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	struct cas *cp = container_of(napi, struct cas, napi);
2589bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	struct net_device *dev = cp->dev;
259086216268b9cdad57f9aa540ebf49cbae2f38b583David S. Miller	int i, enable_intr, credits;
25911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 status = readl(cp->regs + REG_INTR_STATUS);
25921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
25931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
25951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_tx(dev, cp, status);
25961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
25971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
25981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* NAPI rx packets. we spread the credits across all of the
25991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * rxc rings
2600bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	 *
2601bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	 * to make sure we're fair with the work we loop through each
26026aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	 * ring N_RX_COMP_RING times with a request of
2603bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	 * budget / N_RX_COMP_RINGS
26041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
26051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	enable_intr = 1;
26061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	credits = 0;
26071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_COMP_RINGS; i++) {
26081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int j;
26091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (j = 0; j < N_RX_COMP_RINGS; j++) {
2610bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger			credits += cas_rx_ringN(cp, j, budget / N_RX_COMP_RINGS);
2611bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger			if (credits >= budget) {
26121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				enable_intr = 0;
26131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				goto rx_comp;
26141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
26151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
26161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerrx_comp:
26191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* final rx completion */
26201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
26211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (status)
26221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_handle_irq(dev, cp, status);
26231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTB
26251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (N_RX_COMP_RINGS > 1) {
26261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		status = readl(cp->regs + REG_PLUS_INTRN_STATUS(1));
26271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (status)
26281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_handle_irq1(dev, cp, status);
26291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTC
26331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (N_RX_COMP_RINGS > 2) {
26341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		status = readl(cp->regs + REG_PLUS_INTRN_STATUS(2));
26351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (status)
26361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_handle_irqN(dev, cp, status, 2);
26371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTD
26411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (N_RX_COMP_RINGS > 3) {
26421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		status = readl(cp->regs + REG_PLUS_INTRN_STATUS(3));
26431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (status)
26441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_handle_irqN(dev, cp, status, 3);
26451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
26481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (enable_intr) {
2649288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_complete(napi);
26501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_unmask_intr(cp);
26511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
2652bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	return credits;
26531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
26541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef CONFIG_NET_POLL_CONTROLLER
26571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_netpoll(struct net_device *dev)
26581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
26591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
26601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_disable_irq(cp, 0);
26627d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells	cas_interrupt(cp->pdev->irq, dev);
26631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_enable_irq(cp, 0);
26641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTB
26661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (N_RX_COMP_RINGS > 1) {
26671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* cas_interrupt1(); */
26681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTC
26711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (N_RX_COMP_RINGS > 2) {
26721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* cas_interruptN(); */
26731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PCI_INTD
26761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (N_RX_COMP_RINGS > 3) {
26771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* cas_interruptN(); */
26781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
26811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
26821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
26831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_tx_timeout(struct net_device *dev)
26841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
26851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
26861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2687436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "transmit timed out, resetting\n");
26881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!cp->hw_running) {
2689436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "hrm.. hw not running!\n");
26901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
26911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
26921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2693436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "MIF_STATE[%08x]\n",
2694436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MIF_STATE_MACHINE));
2695436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches
2696436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "MAC_STATE[%08x]\n",
2697436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MAC_STATE_MACHINE));
2698436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches
2699436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "TX_STATE[%08x:%08x:%08x] FIFO[%08x:%08x:%08x] SM1[%08x] SM2[%08x]\n",
2700436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_TX_CFG),
2701436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MAC_TX_STATUS),
2702436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MAC_TX_CFG),
2703436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_TX_FIFO_PKT_CNT),
2704436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_TX_FIFO_WRITE_PTR),
2705436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_TX_FIFO_READ_PTR),
2706436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_TX_SM_1),
2707436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_TX_SM_2));
2708436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches
2709436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "RX_STATE[%08x:%08x:%08x]\n",
2710436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_RX_CFG),
2711436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MAC_RX_STATUS),
2712436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MAC_RX_CFG));
2713436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches
2714436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(dev, "HP_STATE[%08x:%08x:%08x:%08x]\n",
2715436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_HP_STATE_MACHINE),
2716436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_HP_STATUS0),
2717436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_HP_STATUS1),
2718436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_HP_STATUS2));
27191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
27211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_inc(&cp->reset_task_pending);
27221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_inc(&cp->reset_task_pending_all);
27231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	schedule_work(&cp->reset_task);
27241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
27251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
27261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	schedule_work(&cp->reset_task);
27271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
27281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
27291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline int cas_intme(int ring, int entry)
27311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
27321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Algorithm: IRQ every 1/2 of descriptors. */
27331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!(entry & ((TX_DESC_RINGN_SIZE(ring) >> 1) - 1)))
27341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 1;
27351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
27361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
27371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_write_txd(struct cas *cp, int ring, int entry,
27401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			  dma_addr_t mapping, int len, u64 ctrl, int last)
27411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
27421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas_tx_desc *txd = cp->init_txds[ring] + entry;
27431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	ctrl |= CAS_BASE(TX_DESC_BUFLEN, len);
27451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cas_intme(ring, entry))
27461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		ctrl |= TX_DESC_INTME;
27471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (last)
27481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		ctrl |= TX_DESC_EOF;
27491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	txd->control = cpu_to_le64(ctrl);
27501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	txd->buffer = cpu_to_le64(mapping);
27511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
27521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic inline void *tx_tiny_buf(struct cas *cp, const int ring,
27541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				const int entry)
27551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
27561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return cp->tx_tiny_bufs[ring] + TX_TINY_BUF_LEN*entry;
27571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
27581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27596aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic inline dma_addr_t tx_tiny_map(struct cas *cp, const int ring,
27601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				     const int entry, const int tentry)
27611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
27621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->tx_tiny_use[ring][tentry].nbufs++;
27631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->tx_tiny_use[ring][entry].used = 1;
27641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return cp->tx_tiny_dvma[ring] + TX_TINY_BUF_LEN*entry;
27651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
27661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
27681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    struct sk_buff *skb)
27691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
27701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = cp->dev;
27711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int entry, nr_frags, frag, tabort, tentry;
27721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dma_addr_t mapping;
27731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
27741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u64 ctrl;
27751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 len;
27761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->tx_lock[ring], flags);
27781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* This is a hard error, log it. */
27806aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (TX_BUFFS_AVAIL(cp, ring) <=
27811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    CAS_TABORT(cp)*(skb_shinfo(skb)->nr_frags + 1)) {
27821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_stop_queue(dev);
27831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
2784436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
27851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 1;
27861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
27871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	ctrl = 0;
278984fa7933a33f806bbbaae6775e87459b1ec584c0Patrick McHardy	if (skb->ip_summed == CHECKSUM_PARTIAL) {
27900d0b16727f24f8258eeb33818347ca0f4557f982Michał Mirosław		const u64 csum_start_off = skb_checksum_start_offset(skb);
2791ea2ae17d6443abddc79480dc9f7af8feacabddc4Arnaldo Carvalho de Melo		const u64 csum_stuff_off = csum_start_off + skb->csum_offset;
27921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27936aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		ctrl =  TX_DESC_CSUM_EN |
27941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			CAS_BASE(TX_DESC_CSUM_START, csum_start_off) |
27951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			CAS_BASE(TX_DESC_CSUM_STUFF, csum_stuff_off);
27961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
27971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
27981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = cp->tx_new[ring];
27991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->tx_skbs[ring][entry] = skb;
28001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	nr_frags = skb_shinfo(skb)->nr_frags;
28021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	len = skb_headlen(skb);
28031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	mapping = pci_map_page(cp->pdev, virt_to_page(skb->data),
28041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       offset_in_page(skb->data), len,
28051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       PCI_DMA_TODEVICE);
28061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	tentry = entry;
28081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	tabort = cas_calc_tabort(cp, (unsigned long) skb->data, len);
28091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (unlikely(tabort)) {
28101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* NOTE: len is always >  tabort */
28116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		cas_write_txd(cp, ring, entry, mapping, len - tabort,
28121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			      ctrl | TX_DESC_SOF, 0);
28131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		entry = TX_DESC_NEXT(ring, entry);
28141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2815d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo		skb_copy_from_linear_data_offset(skb, len - tabort,
2816d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo			      tx_tiny_buf(cp, ring, entry), tabort);
28171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		mapping = tx_tiny_map(cp, ring, entry, tentry);
28181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_write_txd(cp, ring, entry, mapping, tabort, ctrl,
28191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			      (nr_frags == 0));
28201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
28216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		cas_write_txd(cp, ring, entry, mapping, len, ctrl |
28221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			      TX_DESC_SOF, (nr_frags == 0));
28231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
28241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	entry = TX_DESC_NEXT(ring, entry);
28251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (frag = 0; frag < nr_frags; frag++) {
28279e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		const skb_frag_t *fragp = &skb_shinfo(skb)->frags[frag];
28281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28299e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		len = skb_frag_size(fragp);
283018324d690d6a5028e3c174fc1921447aedead2b8Ian Campbell		mapping = skb_frag_dma_map(&cp->pdev->dev, fragp, 0, len,
28315d6bcdfe38ce883946aebf751a64695471ce1ab5Ian Campbell					   DMA_TO_DEVICE);
28321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		tabort = cas_calc_tabort(cp, fragp->page_offset, len);
28341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (unlikely(tabort)) {
28351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			void *addr;
28361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* NOTE: len is always > tabort */
28381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_write_txd(cp, ring, entry, mapping, len - tabort,
28391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				      ctrl, 0);
28401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			entry = TX_DESC_NEXT(ring, entry);
28416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
284218324d690d6a5028e3c174fc1921447aedead2b8Ian Campbell			addr = cas_page_map(skb_frag_page(fragp));
28431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			memcpy(tx_tiny_buf(cp, ring, entry),
28446aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			       addr + fragp->page_offset + len - tabort,
28451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       tabort);
28461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_page_unmap(addr);
28471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			mapping = tx_tiny_map(cp, ring, entry, tentry);
28481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			len     = tabort;
28491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
28501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_write_txd(cp, ring, entry, mapping, len, ctrl,
28521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			      (frag + 1 == nr_frags));
28531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		entry = TX_DESC_NEXT(ring, entry);
28541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
28551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->tx_new[ring] = entry;
28571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (TX_BUFFS_AVAIL(cp, ring) <= CAS_TABORT(cp)*(MAX_SKB_FRAGS + 1))
28581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_stop_queue(dev);
28591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2860436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_printk(cp, tx_queued, KERN_DEBUG, dev,
2861436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     "tx[%d] queued, slot %d, skblen %d, avail %d\n",
2862436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		     ring, entry, skb->len, TX_BUFFS_AVAIL(cp, ring));
28631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(entry, cp->regs + REG_TX_KICKN(ring));
28641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
28651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
28666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik}
28671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
286861357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
28691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
28701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
28711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* this is only used as a load-balancing hint, so it doesn't
28731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * need to be SMP safe
28741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
28756aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	static int ring;
28761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28775b057c6b1a25d57edf2b4d1e956e50936480a9ffHerbert Xu	if (skb_padto(skb, cp->min_frame_size))
28786ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy		return NETDEV_TX_OK;
28791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* XXX: we need some higher-level QoS hooks to steer packets to
28811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 *      individual queues.
28821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
28831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb))
28845b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy		return NETDEV_TX_BUSY;
28856ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
28861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
28871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_init_tx_dma(struct cas *cp)
28891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
28901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u64 desc_dma = cp->block_dvma;
28911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long off;
28921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
28931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
28941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
28951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* set up tx completion writeback registers. must be 8-byte aligned */
28961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_TX_COMPWB
28971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	off = offsetof(struct cas_init_block, tx_compwb);
28981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((desc_dma + off) >> 32, cp->regs + REG_TX_COMPWB_DB_HI);
28991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((desc_dma + off) & 0xffffffff, cp->regs + REG_TX_COMPWB_DB_LOW);
29001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
29011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
29021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* enable completion writebacks, enable paced mode,
29031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * disable read pipe, and disable pre-interrupt compwbs
29041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
29056aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	val =   TX_CFG_COMPWB_Q1 | TX_CFG_COMPWB_Q2 |
29061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		TX_CFG_COMPWB_Q3 | TX_CFG_COMPWB_Q4 |
29076aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		TX_CFG_DMA_RDPIPE_DIS | TX_CFG_PACED_MODE |
29081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		TX_CFG_INTR_COMPWB_DIS;
29091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
29101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* write out tx ring info and tx desc bases */
29111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < MAX_TX_RINGS; i++) {
29126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		off = (unsigned long) cp->init_txds[i] -
29131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			(unsigned long) cp->init_block;
29141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
29151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= CAS_TX_RINGN_BASE(i);
29161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel((desc_dma + off) >> 32, cp->regs + REG_TX_DBN_HI(i));
29171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel((desc_dma + off) & 0xffffffff, cp->regs +
29181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       REG_TX_DBN_LOW(i));
29191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* don't zero out the kick register here as the system
29201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * will wedge
29211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
29221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
29231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_TX_CFG);
29241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
29251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* program max burst sizes. these numbers should be different
29261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * if doing QoS.
29271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
29281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_QOS
29291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x800, cp->regs + REG_TX_MAXBURST_0);
29301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x1600, cp->regs + REG_TX_MAXBURST_1);
29311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x2400, cp->regs + REG_TX_MAXBURST_2);
29321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x4800, cp->regs + REG_TX_MAXBURST_3);
29331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
29341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x800, cp->regs + REG_TX_MAXBURST_0);
29351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x800, cp->regs + REG_TX_MAXBURST_1);
29361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x800, cp->regs + REG_TX_MAXBURST_2);
29371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x800, cp->regs + REG_TX_MAXBURST_3);
29381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
29391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
29401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
29411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
29421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_init_dma(struct cas *cp)
29431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
29441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_init_tx_dma(cp);
29451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_init_rx_dma(cp);
29461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
29471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
2948d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirkostatic void cas_process_mc_list(struct cas *cp)
2949d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko{
2950d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko	u16 hash_table[16];
2951d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko	u32 crc;
295222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
2953d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko	int i = 1;
2954d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko
2955d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko	memset(hash_table, 0, sizeof(hash_table));
295622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	netdev_for_each_mc_addr(ha, cp->dev) {
2957d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko		if (i <= CAS_MC_EXACT_MATCH_SIZE) {
2958d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			/* use the alternate mac address registers for the
2959d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			 * first 15 multicast addresses
2960d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			 */
296122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko			writel((ha->addr[4] << 8) | ha->addr[5],
2962d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			       cp->regs + REG_MAC_ADDRN(i*3 + 0));
296322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko			writel((ha->addr[2] << 8) | ha->addr[3],
2964d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			       cp->regs + REG_MAC_ADDRN(i*3 + 1));
296522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko			writel((ha->addr[0] << 8) | ha->addr[1],
2966d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			       cp->regs + REG_MAC_ADDRN(i*3 + 2));
2967d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			i++;
2968d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko		}
2969d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko		else {
2970d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			/* use hw hash table for the next series of
2971d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			 * multicast addresses
2972d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			 */
297322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko			crc = ether_crc_le(ETH_ALEN, ha->addr);
2974d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			crc >>= 24;
2975d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko			hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
2976d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko		}
2977d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko	}
2978d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko	for (i = 0; i < 16; i++)
2979d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko		writel(hash_table[i], cp->regs + REG_MAC_HASH_TABLEN(i));
2980d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko}
2981d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko
29821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
29831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic u32 cas_setup_multicast(struct cas *cp)
29841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
29851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 rxcfg = 0;
29861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
29876aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
29881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->dev->flags & IFF_PROMISC) {
29891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		rxcfg |= MAC_RX_CFG_PROMISC_EN;
29901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
29911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (cp->dev->flags & IFF_ALLMULTI) {
29921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    	for (i=0; i < 16; i++)
29931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			writel(0xFFFF, cp->regs + REG_MAC_HASH_TABLEN(i));
29941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
29951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
29961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
2997d7b855c2dcc89587f36338bd383203322efb9903Jiri Pirko		cas_process_mc_list(cp);
29981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
29991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
30001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return rxcfg;
30021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
30031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* must be invoked under cp->stat_lock[N_TX_RINGS] */
30051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_clear_mac_err(struct cas *cp)
30061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
30071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_COLL_NORMAL);
30081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_COLL_FIRST);
30091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_COLL_EXCESS);
30101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_COLL_LATE);
30111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_TIMER_DEFER);
30121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_ATTEMPTS_PEAK);
30131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_RECV_FRAME);
30141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_LEN_ERR);
30151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_ALIGN_ERR);
30161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_FCS_ERR);
30171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_RX_CODE_ERR);
30181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
30191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_mac_reset(struct cas *cp)
30221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
30231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
30241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* do both TX and RX reset */
30261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x1, cp->regs + REG_MAC_TX_RESET);
30271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x1, cp->regs + REG_MAC_RX_RESET);
30281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* wait for TX */
30301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = STOP_TRIES;
30311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (i-- > 0) {
30321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (readl(cp->regs + REG_MAC_TX_RESET) == 0)
30331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
30341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
30351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
30361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* wait for RX */
30381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = STOP_TRIES;
30391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (i-- > 0) {
30401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (readl(cp->regs + REG_MAC_RX_RESET) == 0)
30411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
30421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
30431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
30441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (readl(cp->regs + REG_MAC_TX_RESET) |
30461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    readl(cp->regs + REG_MAC_RX_RESET))
3047436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(cp->dev, "mac tx[%d]/rx[%d] reset failed [%08x]\n",
3048436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			   readl(cp->regs + REG_MAC_TX_RESET),
3049436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			   readl(cp->regs + REG_MAC_RX_RESET),
3050436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			   readl(cp->regs + REG_MAC_STATE_MACHINE));
30511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
30521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
30551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_init_mac(struct cas *cp)
30561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
30571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned char *e = &cp->dev->dev_addr[0];
30581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
30591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_mac_reset(cp);
30601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* setup core arbitration weight register */
30621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(CAWR_RR_DIS, cp->regs + REG_CAWR);
30631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* XXX Use pci_dma_burst_advice() */
30651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
30661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* set the infinite burst register for chips that don't have
30671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * pci issues.
30681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
30691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((cp->cas_flags & CAS_FLAG_TARGET_ABORT) == 0)
30701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(INF_BURST_EN, cp->regs + REG_INF_BURST);
30711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
30721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x1BF0, cp->regs + REG_MAC_SEND_PAUSE);
30741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x00, cp->regs + REG_MAC_IPG0);
30761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x08, cp->regs + REG_MAC_IPG1);
30771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x04, cp->regs + REG_MAC_IPG2);
30786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
30791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* change later for 802.3z */
30806aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
30811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* min frame + FCS */
30831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(ETH_ZLEN + 4, cp->regs + REG_MAC_FRAMESIZE_MIN);
30841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Ethernet payload + header + FCS + optional VLAN tag. NOTE: we
30866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	 * specify the maximum frame size to prevent RX tag errors on
30871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * oversized frames.
30881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
30891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(CAS_BASE(MAC_FRAMESIZE_MAX_BURST, 0x2000) |
30906aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	       CAS_BASE(MAC_FRAMESIZE_MAX_FRAME,
30916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			(CAS_MAX_MTU + ETH_HLEN + 4 + 4)),
30921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       cp->regs + REG_MAC_FRAMESIZE_MAX);
30931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
30946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	/* NOTE: crc_size is used as a surrogate for half-duplex.
30951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * workaround saturn half-duplex issue by increasing preamble
30961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * size to 65 bytes.
30971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
30981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((cp->cas_flags & CAS_FLAG_SATURN) && cp->crc_size)
30991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x41, cp->regs + REG_MAC_PA_SIZE);
31001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else
31011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x07, cp->regs + REG_MAC_PA_SIZE);
31021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x04, cp->regs + REG_MAC_JAM_SIZE);
31031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x10, cp->regs + REG_MAC_ATTEMPT_LIMIT);
31041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x8808, cp->regs + REG_MAC_CTRL_TYPE);
31051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((e[5] | (e[4] << 8)) & 0x3ff, cp->regs + REG_MAC_RANDOM_SEED);
31071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_ADDR_FILTER0);
31091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_ADDR_FILTER1);
31101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_ADDR_FILTER2);
31111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_ADDR_FILTER2_1_MASK);
31121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_MAC_ADDR_FILTER0_MASK);
31131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* setup mac address in perfect filter array */
31151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < 45; i++)
31161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x0, cp->regs + REG_MAC_ADDRN(i));
31171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((e[4] << 8) | e[5], cp->regs + REG_MAC_ADDRN(0));
31191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((e[2] << 8) | e[3], cp->regs + REG_MAC_ADDRN(1));
31201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel((e[0] << 8) | e[1], cp->regs + REG_MAC_ADDRN(2));
31211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x0001, cp->regs + REG_MAC_ADDRN(42));
31231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0xc200, cp->regs + REG_MAC_ADDRN(43));
31241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0x0180, cp->regs + REG_MAC_ADDRN(44));
31251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->mac_rx_cfg = cas_setup_multicast(cp);
3127ff08546b12a6ab3a8a9992627926a03d2176656eChristoph Egger
31281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->stat_lock[N_TX_RINGS]);
31291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clear_mac_err(cp);
31301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->stat_lock[N_TX_RINGS]);
31311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Setup MAC interrupts.  We want to get all of the interesting
31331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * counter expiration events, but we do not want to hear about
31341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * normal rx/tx as the DMA engine tells us that.
31351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
31361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(MAC_TX_FRAME_XMIT, cp->regs + REG_MAC_TX_MASK);
31371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(MAC_RX_FRAME_RECV, cp->regs + REG_MAC_RX_MASK);
31381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Don't enable even the PAUSE interrupts for now, we
31401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * make no use of those events other than to record them.
31411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
31421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0xffffffff, cp->regs + REG_MAC_CTRL_MASK);
31431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
31441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
31461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_init_pause_thresholds(struct cas *cp)
31471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
31481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Calculate pause thresholds.  Setting the OFF threshold to the
31491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * full RX fifo size effectively disables PAUSE generation
31501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
31511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->rx_fifo_size <= (2 * 1024)) {
31521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->rx_pause_off = cp->rx_pause_on = cp->rx_fifo_size;
31531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
31541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int max_frame = (cp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63;
31551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (max_frame * 3 > cp->rx_fifo_size) {
31561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->rx_pause_off = 7104;
31571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->rx_pause_on  = 960;
31581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
31591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			int off = (cp->rx_fifo_size - (max_frame * 2));
31601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			int on = off - max_frame;
31611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->rx_pause_off = off;
31621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->rx_pause_on = on;
31631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
31641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
31651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
31661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_vpd_match(const void __iomem *p, const char *str)
31681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
31691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int len = strlen(str) + 1;
31701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
31716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
31721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < len; i++) {
31731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (readb(p + i) != str[i])
31741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return 0;
31751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
31761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 1;
31771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
31781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
31801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* get the mac address by reading the vpd information in the rom.
31811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * also get the phy type and determine if there's an entropy generator.
31821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * NOTE: this is a bit convoluted for the following reasons:
31831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  1) vpd info has order-dependent mac addresses for multinic cards
31841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  2) the only way to determine the nic order is to use the slot
31851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     number.
31861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *  3) fiber cards don't have bridges, so their slot numbers don't
31871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     mean anything.
31886aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *  4) we don't actually know we have a fiber card until after
31891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *     the mac addresses are parsed.
31901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
31911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
31921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    const int offset)
31931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
31941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	void __iomem *p = cp->regs + REG_EXPANSION_ROM_RUN_START;
31951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	void __iomem *base, *kstart;
31961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i, len;
31971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int found = 0;
31981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define VPD_FOUND_MAC        0x01
31991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define VPD_FOUND_PHY        0x02
32001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int phy_type = CAS_PHY_MII_MDIO0; /* default phy type */
32021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int mac_off  = 0;
32031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
320492d76e81b9df5f33b0c9e2091e892560a437a15fDavid S. Miller#if defined(CONFIG_SPARC)
32054e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer	const unsigned char *addr;
32064e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer#endif
32074e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer
32081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* give us access to the PROM */
32091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_PAD,
32101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       cp->regs + REG_BIM_LOCAL_DEV_EN);
32111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* check for an expansion rom */
32131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (readb(p) != 0x55 || readb(p + 1) != 0xaa)
32141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto use_random_mac_addr;
32151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* search for beginning of vpd */
321746d7031ecb8a8360b0022abd8014f38cc1197166Al Viro	base = NULL;
32181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 2; i < EXPANSION_ROM_SIZE; i++) {
32191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* check for PCIR */
32201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((readb(p + i + 0) == 0x50) &&
32211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    (readb(p + i + 1) == 0x43) &&
32221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    (readb(p + i + 2) == 0x49) &&
32231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    (readb(p + i + 3) == 0x52)) {
32246aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			base = p + (readb(p + i + 8) |
32251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    (readb(p + i + 9) << 8));
32261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
32276aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		}
32281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
32291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!base || (readb(base) != 0x82))
32311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto use_random_mac_addr;
32326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
32331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = (readb(base + 1) | (readb(base + 2) << 8)) + 3;
32341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (i < EXPANSION_ROM_SIZE) {
32351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (readb(base + i) != 0x90) /* no vpd found */
32361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto use_random_mac_addr;
32371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* found a vpd field */
32391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		len = readb(base + i + 1) | (readb(base + i + 2) << 8);
32401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* extract keywords */
32421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		kstart = base + i + 3;
32431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		p = kstart;
32441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		while ((p - kstart) < len) {
32451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			int klen = readb(p + 2);
32461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			int j;
32471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			char type;
32481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			p += 3;
32506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
32511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* look for the following things:
32521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- correct length == 29
32536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 3 (type) + 2 (size) +
32546aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 18 (strlen("local-mac-address") + 1) +
32556aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 6 (mac addr)
32561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Instance 'I'
32571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Type Bytes 'B'
32581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD data length == 6
32591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- property string == local-mac-address
32606aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 *
32611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- correct length == 24
32626aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 3 (type) + 2 (size) +
32636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 12 (strlen("entropy-dev") + 1) +
32641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * 7 (strlen("vms110") + 1)
32651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Instance 'I'
32661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Type String 'B'
32671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD data length == 7
32681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- property string == entropy-dev
32691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 *
32701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- correct length == 18
32716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 3 (type) + 2 (size) +
32726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 9 (strlen("phy-type") + 1) +
32731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * 4 (strlen("pcs") + 1)
32741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Instance 'I'
32751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Type String 'S'
32761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD data length == 4
32771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- property string == phy-type
32786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 *
32791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- correct length == 23
32806aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 3 (type) + 2 (size) +
32816aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 * 14 (strlen("phy-interface") + 1) +
32821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * 4 (strlen("pcs") + 1)
32831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Instance 'I'
32841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD Type String 'S'
32851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- VPD data length == 4
32861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * -- property string == phy-interface
32871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 */
32881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (readb(p) != 'I')
32891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				goto next;
32901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
32911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* finally, check string and length */
32921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			type = readb(p + 3);
32931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (type == 'B') {
32941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				if ((klen == 29) && readb(p + 4) == 6 &&
32956aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik				    cas_vpd_match(p + 5,
32961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller						  "local-mac-address")) {
32976aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					if (mac_off++ > offset)
32981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller						goto next;
32991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					/* set mac address */
33016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					for (j = 0; j < 6; j++)
33026aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik						dev_addr[j] =
33031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller							readb(p + 23 + j);
33041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					goto found_mac;
33051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				}
33061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
33071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (type != 'S')
33091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				goto next;
33101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_ENTROPY_DEV
33126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			if ((klen == 24) &&
33131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    cas_vpd_match(p + 5, "entropy-dev") &&
33141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    cas_vpd_match(p + 17, "vms110")) {
33151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->cas_flags |= CAS_FLAG_ENTROPY_DEV;
33161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				goto next;
33171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
33181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
33191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (found & VPD_FOUND_PHY)
33211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				goto next;
33221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if ((klen == 18) && readb(p + 4) == 4 &&
33241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    cas_vpd_match(p + 5, "phy-type")) {
33251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				if (cas_vpd_match(p + 14, "pcs")) {
33261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					phy_type = CAS_PHY_SERDES;
33271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					goto found_phy;
33281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				}
33291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
33306aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
33311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if ((klen == 23) && readb(p + 4) == 4 &&
33321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    cas_vpd_match(p + 5, "phy-interface")) {
33331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				if (cas_vpd_match(p + 19, "pcs")) {
33341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					phy_type = CAS_PHY_SERDES;
33351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					goto found_phy;
33361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				}
33371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
33381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerfound_mac:
33391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			found |= VPD_FOUND_MAC;
33401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto next;
33411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerfound_phy:
33431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			found |= VPD_FOUND_PHY;
33441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millernext:
33461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			p += klen;
33471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
33481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		i += len + 3;
33491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
33501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Milleruse_random_mac_addr:
33521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (found & VPD_FOUND_MAC)
33531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto done;
33541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
335592d76e81b9df5f33b0c9e2091e892560a437a15fDavid S. Miller#if defined(CONFIG_SPARC)
33564e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer	addr = of_get_property(cp->of_node, "local-mac-address", NULL);
33574e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer	if (addr != NULL) {
33584e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer		memcpy(dev_addr, addr, 6);
33594e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer		goto done;
33604e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer	}
33614e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer#endif
33624e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer
33631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Sun MAC prefix then 3 random bytes. */
3364436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	pr_info("MAC address not found in ROM VPD\n");
33651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev_addr[0] = 0x08;
33661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev_addr[1] = 0x00;
33671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev_addr[2] = 0x20;
33681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	get_random_bytes(dev_addr + 3, 3);
33691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdone:
33711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_BIM_LOCAL_DEV_EN);
33721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return phy_type;
33731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
33741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* check pci invariants */
33761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_check_pci_invariants(struct cas *cp)
33771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
33781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct pci_dev *pdev = cp->pdev;
33791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->cas_flags = 0;
33811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
33821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    (pdev->device == PCI_DEVICE_ID_SUN_CASSINI)) {
338344c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		if (pdev->revision >= CAS_ID_REVPLUS)
33841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->cas_flags |= CAS_FLAG_REG_PLUS;
338544c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		if (pdev->revision < CAS_ID_REVPLUS02u)
33861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->cas_flags |= CAS_FLAG_TARGET_ABORT;
33871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Original Cassini supports HW CSUM, but it's not
33891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * enabled by default as it can trigger TX hangs.
33901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
339144c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		if (pdev->revision < CAS_ID_REV2)
33921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->cas_flags |= CAS_FLAG_NO_HW_CSUM;
33931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
33941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Only sun has original cassini chips.  */
33951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->cas_flags |= CAS_FLAG_REG_PLUS;
33961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
33971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* We use a flag because the same phy might be externally
33981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * connected.
33991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
34001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((pdev->vendor == PCI_VENDOR_ID_NS) &&
34011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    (pdev->device == PCI_DEVICE_ID_NS_SATURN))
34021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->cas_flags |= CAS_FLAG_SATURN;
34031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
34041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
34051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_check_invariants(struct cas *cp)
34081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
34091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct pci_dev *pdev = cp->pdev;
34101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 cfg;
34111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
34121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* get page size for rx buffers. */
34146aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	cp->page_order = 0;
34151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_PAGE_ORDER
34161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (PAGE_SHIFT < CAS_JUMBO_PAGE_SHIFT) {
34171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* see if we can allocate larger pages */
34186aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		struct page *page = alloc_pages(GFP_ATOMIC,
34196aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik						CAS_JUMBO_PAGE_SHIFT -
34201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller						PAGE_SHIFT);
34211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (page) {
34221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			__free_pages(page, CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT);
34231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->page_order = CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT;
34241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
3425436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			printk("MTU limited to %d bytes\n", CAS_MAX_MTU);
34261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
34271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
34281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
34291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->page_size = (PAGE_SIZE << cp->page_order);
34301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Fetch the FIFO configurations. */
34321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->tx_fifo_size = readl(cp->regs + REG_TX_FIFO_SIZE) * 64;
34331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->rx_fifo_size = RX_FIFO_SIZE;
34341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	/* finish phy determination. MDIO1 takes precedence over MDIO0 if
34361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * they're both connected.
34371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
34386aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	cp->phy_type = cas_get_vpd_info(cp, cp->dev->dev_addr,
34391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					PCI_SLOT(pdev->devfn));
34401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->phy_type & CAS_PHY_SERDES) {
34411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->cas_flags |= CAS_FLAG_1000MB_CAP;
34421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0; /* no more checking needed */
34436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	}
34441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* MII */
34461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cfg = readl(cp->regs + REG_MIF_CFG);
34471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cfg & MIF_CFG_MDIO_1) {
34481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->phy_type = CAS_PHY_MII_MDIO1;
34491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (cfg & MIF_CFG_MDIO_0) {
34501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->phy_type = CAS_PHY_MII_MDIO0;
34511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
34521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_mif_poll(cp, 0);
34541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(PCS_DATAPATH_MODE_MII, cp->regs + REG_PCS_DATAPATH_MODE);
34551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < 32; i++) {
34571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 phy_id;
34581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int j;
34591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (j = 0; j < 3; j++) {
34611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->phy_addr = i;
34621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			phy_id = cas_phy_read(cp, MII_PHYSID1) << 16;
34631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			phy_id |= cas_phy_read(cp, MII_PHYSID2);
34641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (phy_id && (phy_id != 0xFFFFFFFF)) {
34651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				cp->phy_id = phy_id;
34661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				goto done;
34671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
34681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
34691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
3470436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	pr_err("MII phy did not respond [%08x]\n",
34711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       readl(cp->regs + REG_MIF_STATE_MACHINE));
34721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return -1;
34731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdone:
34751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* see if we can do gigabit */
34761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cfg = cas_phy_read(cp, MII_BMSR);
34776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if ((cfg & CAS_BMSR_1000_EXTEND) &&
34781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    cas_phy_read(cp, CAS_MII_1000_EXTEND))
34791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->cas_flags |= CAS_FLAG_1000MB_CAP;
34801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
34811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
34821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
34841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_start_dma(struct cas *cp)
34851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
34861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
34871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
34881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int txfailed = 0;
34896aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
34901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* enable dma */
34911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_TX_CFG) | TX_CFG_DMA_EN;
34921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_TX_CFG);
34931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_RX_CFG) | RX_CFG_DMA_EN;
34941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_RX_CFG);
34951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
34961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* enable the mac */
34971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_MAC_TX_CFG) | MAC_TX_CFG_EN;
34981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_MAC_TX_CFG);
34991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_MAC_RX_CFG) | MAC_RX_CFG_EN;
35001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_MAC_RX_CFG);
35011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = STOP_TRIES;
35031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (i-- > 0) {
35041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = readl(cp->regs + REG_MAC_TX_CFG);
35051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((val & MAC_TX_CFG_EN))
35061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
35071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
35081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
35091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (i < 0) txfailed = 1;
35101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = STOP_TRIES;
35111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (i-- > 0) {
35121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = readl(cp->regs + REG_MAC_RX_CFG);
35131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((val & MAC_RX_CFG_EN)) {
35141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (txfailed) {
3515436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				netdev_err(cp->dev,
3516436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches					   "enabling mac failed [tx:%08x:%08x]\n",
3517436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches					   readl(cp->regs + REG_MIF_STATE_MACHINE),
3518436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches					   readl(cp->regs + REG_MAC_STATE_MACHINE));
35191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
35201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto enable_rx_done;
35211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
35221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
35231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
3524436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(cp->dev, "enabling mac failed [%s:%08x:%08x]\n",
3525436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   (txfailed ? "tx,rx" : "rx"),
3526436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MIF_STATE_MACHINE),
3527436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   readl(cp->regs + REG_MAC_STATE_MACHINE));
35281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerenable_rx_done:
35301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_unmask_intr(cp); /* enable interrupts */
35311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(RX_DESC_RINGN_SIZE(0) - 4, cp->regs + REG_RX_KICK);
35321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(0, cp->regs + REG_RX_COMP_TAIL);
35331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
35356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		if (N_RX_DESC_RINGS > 1)
35366aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			writel(RX_DESC_RINGN_SIZE(1) - 4,
35371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       cp->regs + REG_PLUS_RX_KICK1);
35381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35396aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		for (i = 1; i < N_RX_COMP_RINGS; i++)
35401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			writel(0, cp->regs + REG_PLUS_RX_COMPN_TAIL(i));
35411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
35421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
35431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
35451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_read_pcs_link_mode(struct cas *cp, int *fd, int *spd,
35461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				   int *pause)
35471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
35481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val = readl(cp->regs + REG_PCS_MII_LPA);
35491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	*fd     = (val & PCS_MII_LPA_FD) ? 1 : 0;
35501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	*pause  = (val & PCS_MII_LPA_SYM_PAUSE) ? 0x01 : 0x00;
35511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (val & PCS_MII_LPA_ASYM_PAUSE)
35521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		*pause |= 0x10;
35531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	*spd = 1000;
35541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
35551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
35571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_read_mii_link_mode(struct cas *cp, int *fd, int *spd,
35581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				   int *pause)
35591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
35601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
35611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	*fd = 0;
35631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	*spd = 10;
35641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	*pause = 0;
35656aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
35661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* use GMII registers */
35671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = cas_phy_read(cp, MII_LPA);
35681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (val & CAS_LPA_PAUSE)
35691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		*pause = 0x01;
35701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (val & CAS_LPA_ASYM_PAUSE)
35721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		*pause |= 0x10;
35731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (val & LPA_DUPLEX)
35751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		*fd = 1;
35761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (val & LPA_100)
35771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		*spd = 100;
35781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
35801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = cas_phy_read(cp, CAS_MII_1000_STATUS);
35811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (val & (CAS_LPA_1000FULL | CAS_LPA_1000HALF))
35821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			*spd = 1000;
35831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (val & CAS_LPA_1000FULL)
35841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			*fd = 1;
35851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
35861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
35871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* A link-up condition has occurred, initialize and enable the
35891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * rest of the chip.
35901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller *
35911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * Must be invoked under cp->lock.
35921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
35931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_set_link_modes(struct cas *cp)
35941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
35951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
35961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int full_duplex, speed, pause;
35971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
35981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	full_duplex = 0;
35991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	speed = 10;
36001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pause = 0;
36011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (CAS_PHY_MII(cp->phy_type)) {
36031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 0);
36041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = cas_phy_read(cp, MII_BMCR);
36051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (val & BMCR_ANENABLE) {
36066aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			cas_read_mii_link_mode(cp, &full_duplex, &speed,
36071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					       &pause);
36081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
36091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (val & BMCR_FULLDPLX)
36101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				full_duplex = 1;
36111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (val & BMCR_SPEED100)
36131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				speed = 100;
36141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			else if (val & CAS_BMCR_SPEED1000)
36151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				speed = (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
36161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					1000 : 100;
36171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
36181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 1);
36191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
36211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = readl(cp->regs + REG_PCS_MII_CTRL);
36221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_read_pcs_link_mode(cp, &full_duplex, &speed, &pause);
36231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((val & PCS_MII_AUTONEG_EN) == 0) {
36241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (val & PCS_MII_CTRL_DUPLEX)
36251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				full_duplex = 1;
36261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
36271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
36281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3629436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netif_info(cp, link, cp->dev, "Link up at %d Mbps, %s-duplex\n",
3630436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		   speed, full_duplex ? "full" : "half");
36311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = MAC_XIF_TX_MII_OUTPUT_EN | MAC_XIF_LINK_LED;
36331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (CAS_PHY_MII(cp->phy_type)) {
36341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_XIF_MII_BUFFER_OUTPUT_EN;
36351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!full_duplex)
36361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val |= MAC_XIF_DISABLE_ECHO;
36371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
36386aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (full_duplex)
36391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_XIF_FDPLX_LED;
36401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (speed == 1000)
36411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_XIF_GMII_MODE;
36421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_MAC_XIF_CFG);
36431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* deal with carrier and collision detect. */
36451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = MAC_TX_CFG_IPG_EN;
36461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (full_duplex) {
36471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_TX_CFG_IGNORE_CARRIER;
36481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_TX_CFG_IGNORE_COLL;
36491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
36501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifndef USE_CSMA_CD_PROTO
36511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_TX_CFG_NEVER_GIVE_UP_EN;
36521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_TX_CFG_NEVER_GIVE_UP_LIM;
36531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
36541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
36551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* val now set up for REG_MAC_TX_CFG */
36561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* If gigabit and half-duplex, enable carrier extension
36586aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	 * mode.  increase slot time to 512 bytes as well.
36591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * else, disable it and make sure slot time is 64 bytes.
36601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * also activate checksum bug workaround
36611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
36621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((speed == 1000) && !full_duplex) {
36636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		writel(val | MAC_TX_CFG_CARRIER_EXTEND,
36641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       cp->regs + REG_MAC_TX_CFG);
36651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = readl(cp->regs + REG_MAC_RX_CFG);
36671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val &= ~MAC_RX_CFG_STRIP_FCS; /* checksum workaround */
36686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		writel(val | MAC_RX_CFG_CARRIER_EXTEND,
36691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       cp->regs + REG_MAC_RX_CFG);
36701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x200, cp->regs + REG_MAC_SLOT_TIME);
36721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->crc_size = 4;
36741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* minimum size gigabit frame at half duplex */
36751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->min_frame_size = CAS_1000MB_MIN_FRAME;
36761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
36781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(val, cp->regs + REG_MAC_TX_CFG);
36791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36806aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		/* checksum bug workaround. don't strip FCS when in
36811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * half-duplex mode
36821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
36831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val = readl(cp->regs + REG_MAC_RX_CFG);
36841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (full_duplex) {
36851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val |= MAC_RX_CFG_STRIP_FCS;
36861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->crc_size = 0;
36871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->min_frame_size = CAS_MIN_MTU;
36881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
36891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val &= ~MAC_RX_CFG_STRIP_FCS;
36901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->crc_size = 4;
36911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->min_frame_size = CAS_MIN_FRAME;
36921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
36936aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		writel(val & ~MAC_RX_CFG_CARRIER_EXTEND,
36941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       cp->regs + REG_MAC_RX_CFG);
36951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
36961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
36971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
36981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (netif_msg_link(cp)) {
36991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (pause & 0x01) {
3700436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_info(cp->dev, "Pause is enabled (rxfifo: %d off: %d on: %d)\n",
3701436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				    cp->rx_fifo_size,
3702436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				    cp->rx_pause_off,
3703436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				    cp->rx_pause_on);
37041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else if (pause & 0x10) {
3705436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_info(cp->dev, "TX pause enabled\n");
37061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
3707436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netdev_info(cp->dev, "Pause is disabled\n");
37081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
37091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
37101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_MAC_CTRL_CFG);
37121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val &= ~(MAC_CTRL_CFG_SEND_PAUSE_EN | MAC_CTRL_CFG_RECV_PAUSE_EN);
37131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (pause) { /* symmetric or asymmetric pause */
37141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val |= MAC_CTRL_CFG_SEND_PAUSE_EN;
37151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (pause & 0x01) { /* symmetric pause */
37161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val |= MAC_CTRL_CFG_RECV_PAUSE_EN;
37176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		}
37181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
37191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_MAC_CTRL_CFG);
37201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_start_dma(cp);
37211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
37221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
37241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_init_hw(struct cas *cp, int restart_link)
37251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
37261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (restart_link)
37271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_phy_init(cp);
37281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_init_pause_thresholds(cp);
37301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_init_mac(cp);
37311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_init_dma(cp);
37321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (restart_link) {
37341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Default aneg parameters */
37351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->timer_ticks = 0;
37361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_begin_auto_negotiation(cp, NULL);
37371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else if (cp->lstate == link_up) {
37381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_set_link_modes(cp);
37391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_carrier_on(cp->dev);
37401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
37411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
37421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. on earlier cassini boards,
37441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * SOFT_0 is tied to PCI reset. we use this to force a pci reset,
37451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * let it settle out, and then restore pci state.
37461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
37471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_hard_reset(struct cas *cp)
37481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
37496aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	writel(BIM_LOCAL_DEV_SOFT_0, cp->regs + REG_BIM_LOCAL_DEV_EN);
37501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	udelay(20);
37511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_restore_state(cp->pdev);
37521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
37531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_global_reset(struct cas *cp, int blkflag)
37561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
37571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int limit;
37581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* issue a global reset. don't use RSTOUT. */
37601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (blkflag && !CAS_PHY_MII(cp->phy_type)) {
37611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* For PCS, when the blkflag is set, we should set the
37621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * SW_REST_BLOCK_PCS_SLINK bit to prevent the results of
37631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * the last autonegotiation from being cleared.  We'll
37641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * need some special handling if the chip is set into a
37651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * loopback mode.
37661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
37676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		writel((SW_RESET_TX | SW_RESET_RX | SW_RESET_BLOCK_PCS_SLINK),
37681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		       cp->regs + REG_SW_RESET);
37691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
37701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		writel(SW_RESET_TX | SW_RESET_RX, cp->regs + REG_SW_RESET);
37711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
37721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* need to wait at least 3ms before polling register */
37741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	mdelay(3);
37751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	limit = STOP_TRIES;
37771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (limit-- > 0) {
37781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 val = readl(cp->regs + REG_SW_RESET);
37791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((val & (SW_RESET_TX | SW_RESET_RX)) == 0)
37801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto done;
37811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
37821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
3783436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_err(cp->dev, "sw reset failed\n");
37841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdone:
37861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* enable various BIM interrupts */
37876aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	writel(BIM_CFG_DPAR_INTR_ENABLE | BIM_CFG_RMA_INTR_ENABLE |
37881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       BIM_CFG_RTA_INTR_ENABLE, cp->regs + REG_BIM_CFG);
37891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* clear out pci error status mask for handled errors.
37911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * we don't deal with DMA counter overflows as they happen
37921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * all the time.
37931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
37946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	writel(0xFFFFFFFFU & ~(PCI_ERR_BADACK | PCI_ERR_DTRTO |
37956aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			       PCI_ERR_OTHER | PCI_ERR_BIM_DMA_WRITE |
37966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			       PCI_ERR_BIM_DMA_READ), cp->regs +
37971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       REG_PCI_ERR_STATUS_MASK);
37981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
37991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* set up for MII by default to address mac rx reset timeout
38001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * issue
38011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
38021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(PCS_DATAPATH_MODE_MII, cp->regs + REG_PCS_DATAPATH_MODE);
38031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
38041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_reset(struct cas *cp, int blkflag)
38061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
38071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 val;
38081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_mask_intr(cp);
38101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_global_reset(cp, blkflag);
38111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_mac_reset(cp);
38121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_entropy_reset(cp);
38131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* disable dma engines. */
38151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_TX_CFG);
38161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val &= ~TX_CFG_DMA_EN;
38171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_TX_CFG);
38181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val = readl(cp->regs + REG_RX_CFG);
38201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	val &= ~RX_CFG_DMA_EN;
38211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(val, cp->regs + REG_RX_CFG);
38221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* program header parser */
38241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((cp->cas_flags & CAS_FLAG_TARGET_ABORT) ||
38251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    (CAS_HP_ALT_FIRMWARE == cas_prog_null)) {
38261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_load_firmware(cp, CAS_HP_FIRMWARE);
38271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
38281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_load_firmware(cp, CAS_HP_ALT_FIRMWARE);
38291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
38301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* clear out error registers */
38321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->stat_lock[N_TX_RINGS]);
38331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clear_mac_err(cp);
38341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->stat_lock[N_TX_RINGS]);
38351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
38361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
3837758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar/* Shut down the chip, must be called with pm_mutex held.  */
38381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_shutdown(struct cas *cp)
38391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
38401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
38411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Make us not-running to avoid timers respawning */
38431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->hw_running = 0;
38441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	del_timer_sync(&cp->link_timer);
38461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Stop the reset task */
38481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 0
38491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (atomic_read(&cp->reset_task_pending_mtu) ||
38501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       atomic_read(&cp->reset_task_pending_spare) ||
38511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	       atomic_read(&cp->reset_task_pending_all))
38521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		schedule();
38531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
38551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (atomic_read(&cp->reset_task_pending))
38561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		schedule();
38576aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif
38581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Actually stop the chip */
38591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_lock_all_save(cp, flags);
38601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_reset(cp, 0);
38611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->cas_flags & CAS_FLAG_SATURN)
38621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_phy_powerdown(cp);
38631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_unlock_all_restore(cp, flags);
38641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
38651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_change_mtu(struct net_device *dev, int new_mtu)
38671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
38681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
38691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (new_mtu < CAS_MIN_MTU || new_mtu > CAS_MAX_MTU)
38711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return -EINVAL;
38721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev->mtu = new_mtu;
38741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!netif_running(dev) || !netif_device_present(dev))
38751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return 0;
38761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* let the reset task handle it */
38781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
38791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_inc(&cp->reset_task_pending);
38801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((cp->phy_type & CAS_PHY_SERDES)) {
38811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending_all);
38821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
38831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending_mtu);
38841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
38851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	schedule_work(&cp->reset_task);
38861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
38876aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	atomic_set(&cp->reset_task_pending, (cp->phy_type & CAS_PHY_SERDES) ?
38881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		   CAS_RESET_ALL : CAS_RESET_MTU);
3889436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	pr_err("reset called in cas_change_mtu\n");
38901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	schedule_work(&cp->reset_task);
38911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
38921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
389323f333a2bfafba80339315b724808982a9de57d9Tejun Heo	flush_work_sync(&cp->reset_task);
38941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
38951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
38961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
38971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_clean_txd(struct cas *cp, int ring)
38981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
38991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas_tx_desc *txd = cp->init_txds[ring];
39001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct sk_buff *skb, **skbs = cp->tx_skbs[ring];
39011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u64 daddr, dlen;
39021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i, size;
39031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	size = TX_DESC_RINGN_SIZE(ring);
39051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < size; i++) {
39061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int frag;
39071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (skbs[i] == NULL)
39091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			continue;
39101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb = skbs[i];
39121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skbs[i] = NULL;
39131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (frag = 0; frag <= skb_shinfo(skb)->nr_frags;  frag++) {
39151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			int ent = i & (size - 1);
39161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* first buffer is never a tiny buffer and so
39181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * needs to be unmapped.
39191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 */
39201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			daddr = le64_to_cpu(txd[ent].buffer);
39216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			dlen  =  CAS_VAL(TX_DESC_BUFLEN,
39221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					 le64_to_cpu(txd[ent].control));
39231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			pci_unmap_page(cp->pdev, daddr, dlen,
39241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				       PCI_DMA_TODEVICE);
39251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (frag != skb_shinfo(skb)->nr_frags) {
39271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				i++;
39281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				/* next buffer might by a tiny buffer.
39301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				 * skip past it.
39311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				 */
39321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				ent = i & (size - 1);
39331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				if (cp->tx_tiny_use[ring][ent].used)
39341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					i++;
39351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
39361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
39371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		dev_kfree_skb_any(skb);
39381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
39391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* zero out tiny buf usage */
39411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	memset(cp->tx_tiny_use[ring], 0, size*sizeof(*cp->tx_tiny_use[ring]));
39421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
39431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* freed on close */
39451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline void cas_free_rx_desc(struct cas *cp, int ring)
39461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
39471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t **page = cp->rx_pages[ring];
39481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i, size;
39491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	size = RX_DESC_RINGN_SIZE(ring);
39511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < size; i++) {
39521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (page[i]) {
39531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_page_free(cp, page[i]);
39541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			page[i] = NULL;
39551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
39561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
39571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
39581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_free_rxds(struct cas *cp)
39601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
39611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
39621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_DESC_RINGS; i++)
39641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_free_rx_desc(cp, i);
39651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
39661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* Must be invoked under cp->lock. */
39681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_clean_rings(struct cas *cp)
39691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
39701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
39711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* need to clean all tx rings */
39731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	memset(cp->tx_old, 0, sizeof(*cp->tx_old)*N_TX_RINGS);
39741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	memset(cp->tx_new, 0, sizeof(*cp->tx_new)*N_TX_RINGS);
39751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_TX_RINGS; i++)
39761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_clean_txd(cp, i);
39771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* zero out init block */
39791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	memset(cp->init_block, 0, sizeof(struct cas_init_block));
39801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clean_rxds(cp);
39811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clean_rxcs(cp);
39821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
39831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller/* allocated on open */
39851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic inline int cas_alloc_rx_desc(struct cas *cp, int ring)
39861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
39871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_page_t **page = cp->rx_pages[ring];
39881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int size, i = 0;
39891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	size = RX_DESC_RINGN_SIZE(ring);
39911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < size; i++) {
39926aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		if ((page[i] = cas_page_alloc(cp, GFP_KERNEL)) == NULL)
39931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return -1;
39941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
39951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
39961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
39971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
39981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_alloc_rxds(struct cas *cp)
39991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
40001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
40011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
40021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_DESC_RINGS; i++) {
40031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cas_alloc_rx_desc(cp, i) < 0) {
40041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_free_rxds(cp);
40051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return -1;
40061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
40071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
40081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
40091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
40101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4011c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void cas_reset_task(struct work_struct *work)
40121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
4013c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct cas *cp = container_of(work, struct cas, reset_task);
40141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 0
40151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int pending = atomic_read(&cp->reset_task_pending);
40161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
40171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int pending_all = atomic_read(&cp->reset_task_pending_all);
40181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int pending_spare = atomic_read(&cp->reset_task_pending_spare);
40191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int pending_mtu = atomic_read(&cp->reset_task_pending_mtu);
40201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
40211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (pending_all == 0 && pending_spare == 0 && pending_mtu == 0) {
40221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* We can have more tasks scheduled than actually
40231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * needed.
40241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
40251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_dec(&cp->reset_task_pending);
40261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
40271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
40281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
40291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* The link went down, we reset the ring, but keep
40301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * DMA stopped. Use this function for reset
40311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * on error as well.
40321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
40331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->hw_running) {
40341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		unsigned long flags;
40351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
40361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Make sure we don't get interrupts or tx packets */
40371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_device_detach(cp->dev);
40381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_lock_all_save(cp, flags);
40391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
40401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->opened) {
40411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* We call cas_spare_recover when we call cas_open.
40421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * but we do not initialize the lists cas_spare_recover
40431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 * uses until cas_open is called.
40441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			 */
40451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_spare_recover(cp, GFP_ATOMIC);
40461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
40471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
40481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* test => only pending_spare set */
40491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!pending_all && !pending_mtu)
40501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto done;
40511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
40521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (pending == CAS_RESET_SPARE)
40531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto done;
40541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
40551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* when pending == CAS_RESET_ALL, the following
40561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * call to cas_init_hw will restart auto negotiation.
40571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * Setting the second argument of cas_reset to
40581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * !(pending == CAS_RESET_ALL) will set this argument
40596aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		 * to 1 (avoiding reinitializing the PHY for the normal
40601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * PCS case) when auto negotiation is not restarted.
40611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
40621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
40631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_reset(cp, !(pending_all > 0));
40641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->opened)
40651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_clean_rings(cp);
40661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_init_hw(cp, (pending_all > 0));
40671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
40681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_reset(cp, !(pending == CAS_RESET_ALL));
40691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (cp->opened)
40701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_clean_rings(cp);
40711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_init_hw(cp, pending == CAS_RESET_ALL);
40721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
40731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
40741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdone:
40751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_unlock_all_restore(cp, flags);
40761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_device_attach(cp->dev);
40771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
40781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
40791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_sub(pending_all, &cp->reset_task_pending_all);
40801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_sub(pending_spare, &cp->reset_task_pending_spare);
40811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_sub(pending_mtu, &cp->reset_task_pending_mtu);
40821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_dec(&cp->reset_task_pending);
40831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
40841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_set(&cp->reset_task_pending, 0);
40851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
40861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
40871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
40881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_link_timer(unsigned long data)
40891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
40901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = (struct cas *) data;
40911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int mask, pending = 0, reset = 0;
40921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
40931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
40941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (link_transition_timeout != 0 &&
40951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    cp->link_transition_jiffies_valid &&
40966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	    ((jiffies - cp->link_transition_jiffies) >
40971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	      (link_transition_timeout))) {
40986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		/* One-second counter so link-down workaround doesn't
40991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * cause resets to occur so fast as to fool the switch
41001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * into thinking the link is down.
41011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
41021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_transition_jiffies_valid = 0;
41031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
41041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!cp->hw_running)
41061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
41071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
41091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_lock_tx(cp);
41101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_entropy_gather(cp);
41111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* If the link task is still pending, we just
41131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * reschedule the link timer
41141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
41151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
41161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (atomic_read(&cp->reset_task_pending_all) ||
41171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	    atomic_read(&cp->reset_task_pending_spare) ||
41186aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	    atomic_read(&cp->reset_task_pending_mtu))
41191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto done;
41201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
41216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	if (atomic_read(&cp->reset_task_pending))
41221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto done;
41231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
41241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* check for rx cleaning */
41261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((mask = (cp->cas_flags & CAS_FLAG_RXD_POST_MASK))) {
41271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int i, rmask;
41281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		for (i = 0; i < MAX_RX_DESC_RINGS; i++) {
41301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			rmask = CAS_FLAG_RXD_POST(i);
41311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if ((mask & rmask) == 0)
41321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				continue;
41331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			/* post_rxds will do a mod_timer */
41351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			if (cas_post_rxds_ringN(cp, i, cp->rx_last[i]) < 0) {
41361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				pending = 1;
41371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				continue;
41381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
41391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cp->cas_flags &= ~rmask;
41401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
41411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
41421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (CAS_PHY_MII(cp->phy_type)) {
41441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u16 bmsr;
41451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 0);
41461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		bmsr = cas_phy_read(cp, MII_BMSR);
41471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* WTZ: Solaris driver reads this twice, but that
41481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * may be due to the PCS case and the use of a
41491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * common implementation. Read it twice here to be
41501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * safe.
41511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
41521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		bmsr = cas_phy_read(cp, MII_BMSR);
41531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 1);
41541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		readl(cp->regs + REG_MIF_STATUS); /* avoid dups */
41551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		reset = cas_mii_link_check(cp, bmsr);
41561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
41571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		reset = cas_pcs_link_check(cp);
41581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
41591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (reset)
41611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto done;
41621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* check for tx state machine confusion */
41641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((readl(cp->regs + REG_MAC_TX_STATUS) & MAC_TX_FRAME_XMIT) == 0) {
41651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 val = readl(cp->regs + REG_MAC_STATE_MACHINE);
41661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 wptr, rptr;
41671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		int tlm  = CAS_VAL(MAC_SM_TLM, val);
41681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (((tlm == 0x5) || (tlm == 0x3)) &&
41701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		    (CAS_VAL(MAC_SM_ENCAP_SM, val) == 0)) {
4171436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netif_printk(cp, tx_err, KERN_DEBUG, cp->dev,
4172436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				     "tx err: MAC_STATE[%08x]\n", val);
41731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			reset = 1;
41741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto done;
41751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
41761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		val  = readl(cp->regs + REG_TX_FIFO_PKT_CNT);
41781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		wptr = readl(cp->regs + REG_TX_FIFO_WRITE_PTR);
41791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		rptr = readl(cp->regs + REG_TX_FIFO_READ_PTR);
41801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if ((val == 0) && (wptr != rptr)) {
4181436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			netif_printk(cp, tx_err, KERN_DEBUG, cp->dev,
4182436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				     "tx err: TX_FIFO[%08x:%08x:%08x]\n",
4183436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches				     val, wptr, rptr);
41841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			reset = 1;
41851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
41861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (reset)
41881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_hard_reset(cp);
41891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
41901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
41911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerdone:
41921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (reset) {
41931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
41941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending);
41951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_inc(&cp->reset_task_pending_all);
41961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		schedule_work(&cp->reset_task);
41971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
41981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
4199436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_err("reset called in cas_link_timer\n");
42001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		schedule_work(&cp->reset_task);
42011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
42021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
42031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!pending)
42051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		mod_timer(&cp->link_timer, jiffies + CAS_LINK_TIMEOUT);
42061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_unlock_tx(cp);
42071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
42081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
42091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/* tiny buffers are used to avoid target abort issues with
42111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller * older cassini's
42121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller */
42131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_tx_tiny_free(struct cas *cp)
42141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
42151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct pci_dev *pdev = cp->pdev;
42161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
42171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_TX_RINGS; i++) {
42191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!cp->tx_tiny_bufs[i])
42201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			continue;
42211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		pci_free_consistent(pdev, TX_TINY_BUF_BLOCK,
42231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    cp->tx_tiny_bufs[i],
42241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    cp->tx_tiny_dvma[i]);
42251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->tx_tiny_bufs[i] = NULL;
42261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
42271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
42281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_tx_tiny_alloc(struct cas *cp)
42301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
42311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct pci_dev *pdev = cp->pdev;
42321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
42331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_TX_RINGS; i++) {
42356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		cp->tx_tiny_bufs[i] =
42361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			pci_alloc_consistent(pdev, TX_TINY_BUF_BLOCK,
42371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					     &cp->tx_tiny_dvma[i]);
42381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!cp->tx_tiny_bufs[i]) {
42391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			cas_tx_tiny_free(cp);
42401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			return -1;
42411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
42421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
42431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
42441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
42451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_open(struct net_device *dev)
42481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
42491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
42501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int hw_was_up, err;
42511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
42521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4253758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_lock(&cp->pm_mutex);
42541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	hw_was_up = cp->hw_running;
42561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4257758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	/* The power-management mutex protects the hw_running
42581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * etc. state so it is safe to do this bit without cp->lock
42591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
42601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!cp->hw_running) {
42611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Reset the chip */
42621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_lock_all_save(cp, flags);
42631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* We set the second arg to cas_reset to zero
42646aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		 * because cas_init_hw below will have its second
42651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * argument set to non-zero, which will force
42661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * autonegotiation to start.
42671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
42681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_reset(cp, 0);
42691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->hw_running = 1;
42701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_unlock_all_restore(cp, flags);
42711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
42721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
427387d75b52414a22c54cf8382bcdd329376b1bce78Jiri Slaby	err = -ENOMEM;
42741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cas_tx_tiny_alloc(cp) < 0)
427587d75b52414a22c54cf8382bcdd329376b1bce78Jiri Slaby		goto err_unlock;
42761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* alloc rx descriptors */
42781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cas_alloc_rxds(cp) < 0)
42791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_tx_tiny;
42806aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
42811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* allocate spares */
42821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_spare_init(cp);
42831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_spare_recover(cp, GFP_KERNEL);
42841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
42851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* We can now request the interrupt as we know it's masked
42861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * on the controller. cassini+ has up to 4 interrupts
42876aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	 * that can be used, but you need to do explicit pci interrupt
42881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * mapping to expose them
42891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
42901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (request_irq(cp->pdev->irq, cas_interrupt,
42911fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner			IRQF_SHARED, dev->name, (void *) dev)) {
4292436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		netdev_err(cp->dev, "failed to request irq !\n");
42931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		err = -EAGAIN;
42941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_spare;
42951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
42961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4297bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#ifdef USE_NAPI
4298bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	napi_enable(&cp->napi);
4299bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#endif
43001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* init hw */
43011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_lock_all_save(cp, flags);
43021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clean_rings(cp);
43031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_init_hw(cp, !hw_was_up);
43041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->opened = 1;
43051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_unlock_all_restore(cp, flags);
43061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	netif_start_queue(dev);
4308758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
43091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
43101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_spare:
43121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_spare_free(cp);
43131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_free_rxds(cp);
43141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_tx_tiny:
43151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_tx_tiny_free(cp);
431687d75b52414a22c54cf8382bcdd329376b1bce78Jiri Slabyerr_unlock:
4317758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
43181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return err;
43191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
43201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_close(struct net_device *dev)
43221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
43231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
43241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
43251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4326bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#ifdef USE_NAPI
432786216268b9cdad57f9aa540ebf49cbae2f38b583David S. Miller	napi_disable(&cp->napi);
4328bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#endif
43291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Make sure we don't get distracted by suspend/resume */
4330758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_lock(&cp->pm_mutex);
43311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	netif_stop_queue(dev);
43331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Stop traffic, mark us closed */
43351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_lock_all_save(cp, flags);
43366aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	cp->opened = 0;
43371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_reset(cp, 0);
43386aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	cas_phy_init(cp);
43391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_begin_auto_negotiation(cp, NULL);
43401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clean_rings(cp);
43411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_unlock_all_restore(cp, flags);
43421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	free_irq(cp->pdev->irq, (void *) dev);
43441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_spare_free(cp);
43451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_free_rxds(cp);
43461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_tx_tiny_free(cp);
4347758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
43481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
43491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
43501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic struct {
43521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	const char name[ETH_GSTRING_LEN];
43531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller} ethtool_cassini_statnames[] = {
43541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"collisions"},
43551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_bytes"},
43561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_crc_errors"},
43571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_dropped"},
43581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_errors"},
43591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_fifo_errors"},
43601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_frame_errors"},
43611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_length_errors"},
43621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_over_errors"},
43631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"rx_packets"},
43641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"tx_aborted_errors"},
43651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"tx_bytes"},
43661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"tx_dropped"},
43671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"tx_errors"},
43681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"tx_fifo_errors"},
43691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{"tx_packets"}
43701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller};
43714c3616cdda0632a3d0e39069765f9ea0e6bd093eAlejandro Martinez Ruiz#define CAS_NUM_STAT_KEYS ARRAY_SIZE(ethtool_cassini_statnames)
43721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
43731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic struct {
43741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	const int offsets;	/* neg. values for 2nd arg to cas_read_phy */
43751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller} ethtool_register_table[] = {
43761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{-MII_BMSR},
43771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{-MII_BMCR},
43781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_CAWR},
43791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_INF_BURST},
43801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_BIM_CFG},
43811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_RX_CFG},
43821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_HP_CFG},
43831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_MAC_TX_CFG},
43841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_MAC_RX_CFG},
43851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_MAC_CTRL_CFG},
43861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_MAC_XIF_CFG},
43871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_MIF_CFG},
43881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_PCS_CFG},
43891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_SATURN_PCFG},
43901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_PCS_MII_STATUS},
43911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_PCS_STATE_MACHINE},
43921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_MAC_COLL_EXCESS},
43931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	{REG_MAC_COLL_LATE}
43941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller};
4395e9edda697ed7697f1288d0656570e49c47e204aeAlejandro Martinez Ruiz#define CAS_REG_LEN 	ARRAY_SIZE(ethtool_register_table)
43961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#define CAS_MAX_REGS 	(sizeof (u32)*CAS_REG_LEN)
43971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4398a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic void cas_read_regs(struct cas *cp, u8 *ptr, int len)
43991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
44001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u8 *p;
44011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
44021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
44031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
44041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
4405a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	for (i = 0, p = ptr; i < len ; i ++, p += sizeof(u32)) {
44061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u16 hval;
44071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		u32 val;
44081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (ethtool_register_table[i].offsets < 0) {
44091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			hval = cas_phy_read(cp,
44101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				    -ethtool_register_table[i].offsets);
44111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val = hval;
44121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
44131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			val= readl(cp->regs+ethtool_register_table[i].offsets);
44141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
44151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		memcpy(p, (u8 *)&val, sizeof(u32));
44161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
44171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
44181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
44191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
44201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic struct net_device_stats *cas_get_stats(struct net_device *dev)
44211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
44221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
44231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device_stats *stats = cp->net_stats;
44241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
44251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i;
44261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long tmp;
44271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
44281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* we collate all of the stats into net_stats[N_TX_RING] */
44291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!cp->hw_running)
44301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return stats + N_TX_RINGS;
44316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
44321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* collect outstanding stats */
44331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* WTZ: the Cassini spec gives these as 16 bit counters but
44341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * stored in 32-bit words.  Added a mask of 0xffff to be safe,
44351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * in case the chip somehow puts any garbage in the other bits.
44361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * Also, counter usage didn't seem to mach what Adrian did
44371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * in the parts of the code that set these quantities. Made
44381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * that consistent.
44391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
44401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->stat_lock[N_TX_RINGS], flags);
44416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	stats[N_TX_RINGS].rx_crc_errors +=
44421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	  readl(cp->regs + REG_MAC_FCS_ERR) & 0xffff;
44436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	stats[N_TX_RINGS].rx_frame_errors +=
44441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		readl(cp->regs + REG_MAC_ALIGN_ERR) &0xffff;
44456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	stats[N_TX_RINGS].rx_length_errors +=
44461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		readl(cp->regs + REG_MAC_LEN_ERR) & 0xffff;
44471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
44481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	tmp = (readl(cp->regs + REG_MAC_COLL_EXCESS) & 0xffff) +
44491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		(readl(cp->regs + REG_MAC_COLL_LATE) & 0xffff);
44501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].tx_aborted_errors += tmp;
44511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].collisions +=
44521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	  tmp + (readl(cp->regs + REG_MAC_COLL_NORMAL) & 0xffff);
44531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#else
44546aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	stats[N_TX_RINGS].tx_aborted_errors +=
44551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		readl(cp->regs + REG_MAC_COLL_EXCESS);
44561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].collisions += readl(cp->regs + REG_MAC_COLL_EXCESS) +
44571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		readl(cp->regs + REG_MAC_COLL_LATE);
44581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
44591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_clear_mac_err(cp);
44601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
44611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* saved bits that are unique to ring 0 */
44621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock(&cp->stat_lock[0]);
44631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].collisions        += stats[0].collisions;
44641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].rx_over_errors    += stats[0].rx_over_errors;
44651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].rx_frame_errors   += stats[0].rx_frame_errors;
44661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].rx_fifo_errors    += stats[0].rx_fifo_errors;
44671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].tx_aborted_errors += stats[0].tx_aborted_errors;
44681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	stats[N_TX_RINGS].tx_fifo_errors    += stats[0].tx_fifo_errors;
44691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock(&cp->stat_lock[0]);
44701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
44711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_TX_RINGS; i++) {
44721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock(&cp->stat_lock[i]);
44736aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		stats[N_TX_RINGS].rx_length_errors +=
44741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			stats[i].rx_length_errors;
44751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].rx_crc_errors += stats[i].rx_crc_errors;
44761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].rx_packets    += stats[i].rx_packets;
44771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].tx_packets    += stats[i].tx_packets;
44781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].rx_bytes      += stats[i].rx_bytes;
44791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].tx_bytes      += stats[i].tx_bytes;
44801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].rx_errors     += stats[i].rx_errors;
44811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].tx_errors     += stats[i].tx_errors;
44821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].rx_dropped    += stats[i].rx_dropped;
44831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		stats[N_TX_RINGS].tx_dropped    += stats[i].tx_dropped;
44841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		memset(stats + i, 0, sizeof(struct net_device_stats));
44851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock(&cp->stat_lock[i]);
44861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
44871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->stat_lock[N_TX_RINGS], flags);
44881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return stats + N_TX_RINGS;
44891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
44901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
44911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
44921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void cas_set_multicast(struct net_device *dev)
44931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
44941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
44951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u32 rxcfg, rxcfg_new;
44961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
44971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int limit = STOP_TRIES;
44986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
44991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!cp->hw_running)
45001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
45016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
45021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_irqsave(&cp->lock, flags);
45031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	rxcfg = readl(cp->regs + REG_MAC_RX_CFG);
45041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
45051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* disable RX MAC and wait for completion */
45061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(rxcfg & ~MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
45071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (readl(cp->regs + REG_MAC_RX_CFG) & MAC_RX_CFG_EN) {
45081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!limit--)
45091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
45101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
45111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
45121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
45131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* disable hash filter and wait for completion */
45141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	limit = STOP_TRIES;
45151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	rxcfg &= ~(MAC_RX_CFG_PROMISC_EN | MAC_RX_CFG_HASH_FILTER_EN);
45161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(rxcfg & ~MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
45171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	while (readl(cp->regs + REG_MAC_RX_CFG) & MAC_RX_CFG_HASH_FILTER_EN) {
45181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (!limit--)
45191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			break;
45201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		udelay(10);
45211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
45221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
45231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* program hash filters */
45241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->mac_rx_cfg = rxcfg_new = cas_setup_multicast(cp);
45251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	rxcfg |= rxcfg_new;
45261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	writel(rxcfg, cp->regs + REG_MAC_RX_CFG);
45271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_unlock_irqrestore(&cp->lock, flags);
45281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
45291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4530a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic void cas_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
4531a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4532a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4533612a94d6f24eb2427eabf554392080302da664ddRick Jones	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
4534612a94d6f24eb2427eabf554392080302da664ddRick Jones	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
4535612a94d6f24eb2427eabf554392080302da664ddRick Jones	strlcpy(info->bus_info, pci_name(cp->pdev), sizeof(info->bus_info));
4536a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	info->regdump_len = cp->casreg_len < CAS_MAX_REGS ?
4537a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cp->casreg_len : CAS_MAX_REGS;
4538a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	info->n_stats = CAS_NUM_STAT_KEYS;
4539a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
4540a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro
4541a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
45421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
45431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
45441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u16 bmcr;
45451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int full_duplex, speed, pause;
45461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
45471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	enum link_state linkstate = link_up;
45481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4549a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	cmd->advertising = 0;
4550a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	cmd->supported = SUPPORTED_Autoneg;
4551a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
4552a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->supported |= SUPPORTED_1000baseT_Full;
4553a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->advertising |= ADVERTISED_1000baseT_Full;
45541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
45551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4556a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	/* Record PHY settings if HW is on. */
4557a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	spin_lock_irqsave(&cp->lock, flags);
4558a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	bmcr = 0;
4559a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	linkstate = cp->lstate;
4560a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	if (CAS_PHY_MII(cp->phy_type)) {
4561a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->port = PORT_MII;
4562a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ?
4563a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			XCVR_INTERNAL : XCVR_EXTERNAL;
4564a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->phy_address = cp->phy_addr;
4565a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->advertising |= ADVERTISED_TP | ADVERTISED_MII |
45666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			ADVERTISED_10baseT_Half |
45676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			ADVERTISED_10baseT_Full |
45686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			ADVERTISED_100baseT_Half |
4569a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			ADVERTISED_100baseT_Full;
4570a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro
4571a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->supported |=
45726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			(SUPPORTED_10baseT_Half |
4573a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			 SUPPORTED_10baseT_Full |
45746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			 SUPPORTED_100baseT_Half |
4575a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			 SUPPORTED_100baseT_Full |
4576a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			 SUPPORTED_TP | SUPPORTED_MII);
4577a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro
4578a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		if (cp->hw_running) {
4579a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			cas_mif_poll(cp, 0);
4580a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			bmcr = cas_phy_read(cp, MII_BMCR);
45816aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			cas_read_mii_link_mode(cp, &full_duplex,
4582a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro					       &speed, &pause);
4583a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			cas_mif_poll(cp, 1);
45841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
45851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4586a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	} else {
4587a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->port = PORT_FIBRE;
4588a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->transceiver = XCVR_INTERNAL;
4589a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->phy_address = 0;
4590a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->supported   |= SUPPORTED_FIBRE;
4591a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->advertising |= ADVERTISED_FIBRE;
4592a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro
4593a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		if (cp->hw_running) {
45946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			/* pcs uses the same bits as mii */
4595a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			bmcr = readl(cp->regs + REG_PCS_MII_CTRL);
45966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			cas_read_pcs_link_mode(cp, &full_duplex,
4597a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro					       &speed, &pause);
45981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
4599a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	}
4600a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	spin_unlock_irqrestore(&cp->lock, flags);
46011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4602a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	if (bmcr & BMCR_ANENABLE) {
4603a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->advertising |= ADVERTISED_Autoneg;
4604a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->autoneg = AUTONEG_ENABLE;
4605707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny		ethtool_cmd_speed_set(cmd, ((speed == 10) ?
4606707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny					    SPEED_10 :
4607707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny					    ((speed == 1000) ?
4608707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny					     SPEED_1000 : SPEED_100)));
4609a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
4610a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	} else {
4611a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->autoneg = AUTONEG_DISABLE;
4612707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny		ethtool_cmd_speed_set(cmd, ((bmcr & CAS_BMCR_SPEED1000) ?
4613707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny					    SPEED_1000 :
4614707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny					    ((bmcr & BMCR_SPEED100) ?
4615707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny					     SPEED_100 : SPEED_10)));
4616a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		cmd->duplex =
4617a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			(bmcr & BMCR_FULLDPLX) ?
4618a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			DUPLEX_FULL : DUPLEX_HALF;
4619a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	}
4620a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	if (linkstate != link_up) {
4621a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		/* Force these to "unknown" if the link is not up and
46226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		 * autonogotiation in enabled. We can set the link
4623a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 * speed to 0, but not cmd->duplex,
4624a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 * because its legal values are 0 and 1.  Ethtool will
4625a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 * print the value reported in parentheses after the
4626a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 * word "Unknown" for unrecognized values.
4627a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 *
4628a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 * If in forced mode, we report the speed and duplex
4629a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 * settings that we configured.
4630a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		 */
4631a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		if (cp->link_cntl & BMCR_ANENABLE) {
4632707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny			ethtool_cmd_speed_set(cmd, 0);
4633a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			cmd->duplex = 0xff;
46341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		} else {
4635707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny			ethtool_cmd_speed_set(cmd, SPEED_10);
4636a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			if (cp->link_cntl & BMCR_SPEED100) {
4637707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny				ethtool_cmd_speed_set(cmd, SPEED_100);
4638a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			} else if (cp->link_cntl & CAS_BMCR_SPEED1000) {
4639707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny				ethtool_cmd_speed_set(cmd, SPEED_1000);
46401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			}
4641a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)?
4642a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro				DUPLEX_FULL : DUPLEX_HALF;
46431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
4644a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	}
4645a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	return 0;
4646a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
46471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4648a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
4649a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4650a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4651a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	unsigned long flags;
465225db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny	u32 speed = ethtool_cmd_speed(cmd);
46531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4654a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	/* Verify the settings we care about. */
4655a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	if (cmd->autoneg != AUTONEG_ENABLE &&
4656a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	    cmd->autoneg != AUTONEG_DISABLE)
4657a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		return -EINVAL;
46581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4659a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	if (cmd->autoneg == AUTONEG_DISABLE &&
466025db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny	    ((speed != SPEED_1000 &&
466125db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny	      speed != SPEED_100 &&
466225db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny	      speed != SPEED_10) ||
4663a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	     (cmd->duplex != DUPLEX_HALF &&
4664a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	      cmd->duplex != DUPLEX_FULL)))
4665a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		return -EINVAL;
46661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4667a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	/* Apply settings and restart link process. */
4668a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	spin_lock_irqsave(&cp->lock, flags);
4669a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	cas_begin_auto_negotiation(cp, cmd);
4670a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	spin_unlock_irqrestore(&cp->lock, flags);
4671a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	return 0;
4672a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
46731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4674a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic int cas_nway_reset(struct net_device *dev)
4675a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4676a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4677a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	unsigned long flags;
46781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4679a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	if ((cp->link_cntl & BMCR_ANENABLE) == 0)
4680a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro		return -EINVAL;
46811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4682a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	/* Restart link process. */
4683a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	spin_lock_irqsave(&cp->lock, flags);
4684a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	cas_begin_auto_negotiation(cp, NULL);
4685a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	spin_unlock_irqrestore(&cp->lock, flags);
46861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4687a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	return 0;
4688a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
46891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4690a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic u32 cas_get_link(struct net_device *dev)
4691a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4692a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4693a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	return cp->lstate == link_up;
4694a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
46951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4696a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic u32 cas_get_msglevel(struct net_device *dev)
4697a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4698a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4699a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	return cp->msg_enable;
4700a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
47011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4702a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic void cas_set_msglevel(struct net_device *dev, u32 value)
4703a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4704a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4705a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	cp->msg_enable = value;
4706a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
47071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4708a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic int cas_get_regs_len(struct net_device *dev)
4709a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4710a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4711a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	return cp->casreg_len < CAS_MAX_REGS ? cp->casreg_len: CAS_MAX_REGS;
4712a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
47131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4714a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs,
4715a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro			     void *p)
4716a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4717a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4718a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	regs->version = 0;
4719a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	/* cas_read_regs handles locks (cp->lock).  */
4720a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	cas_read_regs(cp, p, regs->len / sizeof(u32));
4721a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
47221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4723b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzikstatic int cas_get_sset_count(struct net_device *dev, int sset)
4724a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4725b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	switch (sset) {
4726b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	case ETH_SS_STATS:
4727b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik		return CAS_NUM_STAT_KEYS;
4728b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	default:
4729b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik		return -EOPNOTSUPP;
4730b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	}
4731a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
47321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4733a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
4734a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
47356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	 memcpy(data, &ethtool_cassini_statnames,
4736a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro					 CAS_NUM_STAT_KEYS * ETH_GSTRING_LEN);
4737a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro}
47381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4739a232f76732e11c91c2215d3a43cf9ebc7f939939Al Virostatic void cas_get_ethtool_stats(struct net_device *dev,
4740a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro				      struct ethtool_stats *estats, u64 *data)
4741a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro{
4742a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct cas *cp = netdev_priv(dev);
4743a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	struct net_device_stats *stats = cas_get_stats(cp->dev);
4744a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	int i = 0;
4745a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->collisions;
4746a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_bytes;
4747a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_crc_errors;
4748a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_dropped;
4749a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_errors;
4750a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_fifo_errors;
4751a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_frame_errors;
4752a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_length_errors;
4753a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_over_errors;
4754a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->rx_packets;
4755a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->tx_aborted_errors;
4756a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->tx_bytes;
4757a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->tx_dropped;
4758a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->tx_errors;
4759a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->tx_fifo_errors;
4760a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	data[i++] = stats->tx_packets;
4761a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	BUG_ON(i != CAS_NUM_STAT_KEYS);
47621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
47631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
47647282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops cas_ethtool_ops = {
4765a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_drvinfo		= cas_get_drvinfo,
4766a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_settings		= cas_get_settings,
4767a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.set_settings		= cas_set_settings,
4768a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.nway_reset		= cas_nway_reset,
4769a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_link		= cas_get_link,
4770a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_msglevel		= cas_get_msglevel,
4771a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.set_msglevel		= cas_set_msglevel,
4772a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_regs_len		= cas_get_regs_len,
4773a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_regs		= cas_get_regs,
4774b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	.get_sset_count		= cas_get_sset_count,
4775a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_strings		= cas_get_strings,
4776a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	.get_ethtool_stats	= cas_get_ethtool_stats,
4777a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro};
4778a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro
47791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
47801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
47811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
478246d7031ecb8a8360b0022abd8014f38cc1197166Al Viro	struct mii_ioctl_data *data = if_mii(ifr);
47831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
47841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int rc = -EOPNOTSUPP;
47856aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4786758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	/* Hold the PM mutex while doing ioctl's or we may collide
47871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * with open/close and power management and oops.
47881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
4789758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_lock(&cp->pm_mutex);
47901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	switch (cmd) {
47911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
47921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		data->phy_id = cp->phy_addr;
47931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Fallthrough... */
47941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
47951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	case SIOCGMIIREG:		/* Read MII PHY register. */
47961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock_irqsave(&cp->lock, flags);
47971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 0);
47981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		data->val_out = cas_phy_read(cp, data->reg_num & 0x1f);
47991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 1);
48001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock_irqrestore(&cp->lock, flags);
48011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		rc = 0;
48021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		break;
48031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
48041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	case SIOCSMIIREG:		/* Write MII PHY register. */
48051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock_irqsave(&cp->lock, flags);
48061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 0);
48071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		rc = cas_phy_write(cp, data->reg_num & 0x1f, data->val_in);
48081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_mif_poll(cp, 1);
48091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_unlock_irqrestore(&cp->lock, flags);
48101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		break;
48111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	default:
48121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		break;
4813ee289b6440c3b0ccb9459495783e8c299bec6604Joe Perches	}
48141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
4815758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
48161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return rc;
48171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
48181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
48199e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller/* When this chip sits underneath an Intel 31154 bridge, it is the
48209e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller * only subordinate device and we can tweak the bridge settings to
48219e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller * reflect that fact.
48229e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller */
48239e1848b60d09a715ff1e19aa6fda47e061d04965David S. Millerstatic void __devinit cas_program_bridge(struct pci_dev *cas_pdev)
48249e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller{
48259e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	struct pci_dev *pdev = cas_pdev->bus->self;
48269e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	u32 val;
48279e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
48289e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	if (!pdev)
48299e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller		return;
48309e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
48319e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	if (pdev->vendor != 0x8086 || pdev->device != 0x537c)
48329e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller		return;
48339e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
48349e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	/* Clear bit 10 (Bus Parking Control) in the Secondary
48359e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * Arbiter Control/Status Register which lives at offset
48369e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * 0x41.  Using a 32-bit word read/modify/write at 0x40
48379e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * is much simpler so that's how we do this.
48389e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 */
48399e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	pci_read_config_dword(pdev, 0x40, &val);
48409e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	val &= ~0x00040000;
48419e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	pci_write_config_dword(pdev, 0x40, val);
48429e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
48439e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	/* Max out the Multi-Transaction Timer settings since
48449e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * Cassini is the only device present.
48459e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48469e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * The register is 16-bit and lives at 0x50.  When the
48479e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * settings are enabled, it extends the GRANT# signal
48489e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * for a requestor after a transaction is complete.  This
48499e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * allows the next request to run without first needing
48509e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * to negotiate the GRANT# signal back.
48519e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48529e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * Bits 12:10 define the grant duration:
48539e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48549e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	1	--	16 clocks
48559e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	2	--	32 clocks
48569e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	3	--	64 clocks
48579e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	4	--	128 clocks
48589e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	5	--	256 clocks
48599e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48609e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * All other values are illegal.
48619e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48629e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * Bits 09:00 define which REQ/GNT signal pairs get the
48639e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * GRANT# signal treatment.  We set them all.
48649e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 */
48659e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	pci_write_config_word(pdev, 0x50, (5 << 10) | 0x3ff);
48669e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
48679e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	/* The Read Prefecth Policy register is 16-bit and sits at
48689e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * offset 0x52.  It enables a "smart" pre-fetch policy.  We
48699e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * enable it and max out all of the settings since only one
48709e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * device is sitting underneath and thus bandwidth sharing is
48719e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * not an issue.
48729e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48739e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * The register has several 3 bit fields, which indicates a
48749e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * multiplier applied to the base amount of prefetching the
48759e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * chip would do.  These fields are at:
48769e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48779e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	15:13	---	ReRead Primary Bus
48789e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	12:10	---	FirstRead Primary Bus
48799e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	09:07	---	ReRead Secondary Bus
48809e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *	06:04	---	FirstRead Secondary Bus
48819e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 *
48829e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * Bits 03:00 control which REQ/GNT pairs the prefetch settings
48839e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * get enabled on.  Bit 3 is a grouped enabler which controls
48849e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * all of the REQ/GNT pairs from [8:3].  Bits 2 to 0 control
48859e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * the individual REQ/GNT pairs [2:0].
48869e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 */
48879e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	pci_write_config_word(pdev, 0x52,
48889e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller			      (0x7 << 13) |
48899e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller			      (0x7 << 10) |
48909e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller			      (0x7 <<  7) |
48919e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller			      (0x7 <<  4) |
48929e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller			      (0xf <<  0));
48939e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
48949e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	/* Force cacheline size to 0x8 */
48959e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
48969e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
48979e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	/* Force latency timer to maximum setting so Cassini can
48989e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 * sit on the bus as long as it likes.
48999e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	 */
49009e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xff);
49019e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller}
49029e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
490383d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemmingerstatic const struct net_device_ops cas_netdev_ops = {
490483d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_open		= cas_open,
490583d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_stop		= cas_close,
490683d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_start_xmit		= cas_start_xmit,
490783d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_get_stats 		= cas_get_stats,
4908afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= cas_set_multicast,
490983d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_do_ioctl		= cas_ioctl,
491083d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_tx_timeout		= cas_tx_timeout,
491183d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_change_mtu		= cas_change_mtu,
491283d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_set_mac_address	= eth_mac_addr,
491383d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_validate_addr	= eth_validate_addr,
491483d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER
491583d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	.ndo_poll_controller	= cas_netpoll,
491683d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger#endif
491783d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger};
491883d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger
49191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int __devinit cas_init_one(struct pci_dev *pdev,
49201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				  const struct pci_device_id *ent)
49211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
49221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	static int cas_version_printed = 0;
492318e37f2a979dd696e6b4495b6f2470c01ffeab6cMarc Zyngier	unsigned long casreg_len;
49241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev;
49251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp;
49261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	int i, err, pci_using_dac;
49271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u16 pci_cmd;
49281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	u8 orig_cacheline_size = 0, cas_cacheline_size = 0;
49291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cas_version_printed++ == 0)
4931436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_info("%s", version);
49321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	err = pci_enable_device(pdev);
49341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (err) {
4935436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
49361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return err;
49371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
49381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
49409b91cf9daac41eeaaea57ecfe68dc13bb0305fa9Jeff Garzik		dev_err(&pdev->dev, "Cannot find proper PCI device "
4941436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		       "base address, aborting\n");
49421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		err = -ENODEV;
49431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_out_disable_pdev;
49441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
49451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev = alloc_etherdev(sizeof(*cp));
49471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!dev) {
49481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		err = -ENOMEM;
49491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_out_disable_pdev;
49501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
49511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	SET_NETDEV_DEV(dev, &pdev->dev);
49521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	err = pci_request_regions(pdev, dev->name);
49541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (err) {
4955436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
49561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_out_free_netdev;
49571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
49581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_set_master(pdev);
49591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* we must always turn on parity response or else parity
49611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * doesn't get generated properly. disable SERR/PERR as well.
49621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * in addition, we want to turn MWI on.
49631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
49641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
49651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_cmd &= ~PCI_COMMAND_SERR;
49661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_cmd |= PCI_COMMAND_PARITY;
49671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
4968694625c0b322905d6892fad873029f764cd4823fRandy Dunlap	if (pci_try_set_mwi(pdev))
4969436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		pr_warning("Could not enable MWI for %s\n", pci_name(pdev));
497004efb8787e4d8a7b21a61aeb723de33154311256David S. Miller
49719e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller	cas_program_bridge(pdev);
49729e1848b60d09a715ff1e19aa6fda47e061d04965David S. Miller
49731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/*
49741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * On some architectures, the default cache line size set
4975694625c0b322905d6892fad873029f764cd4823fRandy Dunlap	 * by pci_try_set_mwi reduces perforamnce.  We have to increase
49761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * it for this case.  To start, we'll print some configuration
49771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * data.
49781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
49791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
49801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
49811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			     &orig_cacheline_size);
49821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (orig_cacheline_size < CAS_PREF_CACHELINE_SIZE) {
49836aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		cas_cacheline_size =
49846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			(CAS_PREF_CACHELINE_SIZE < SMP_CACHE_BYTES) ?
49851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			CAS_PREF_CACHELINE_SIZE : SMP_CACHE_BYTES;
49866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		if (pci_write_config_byte(pdev,
49876aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					  PCI_CACHE_LINE_SIZE,
49881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller					  cas_cacheline_size)) {
49899b91cf9daac41eeaaea57ecfe68dc13bb0305fa9Jeff Garzik			dev_err(&pdev->dev, "Could not set PCI cache "
49901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       "line size\n");
49911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto err_write_cacheline;
49921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
49931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
49941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
49951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
49971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Configure DMA attributes. */
49986a35528a8346f6e6fd32ed7e51f04d1fa4ca2c01Yang Hongyang	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
49991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_using_dac = 1;
50001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		err = pci_set_consistent_dma_mask(pdev,
50016a35528a8346f6e6fd32ed7e51f04d1fa4ca2c01Yang Hongyang						  DMA_BIT_MASK(64));
50021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (err < 0) {
50039b91cf9daac41eeaaea57ecfe68dc13bb0305fa9Jeff Garzik			dev_err(&pdev->dev, "Unable to obtain 64-bit DMA "
50041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			       "for consistent allocations\n");
50051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto err_out_free_res;
50061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
50071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	} else {
5009284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
50101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		if (err) {
50119b91cf9daac41eeaaea57ecfe68dc13bb0305fa9Jeff Garzik			dev_err(&pdev->dev, "No usable DMA configuration, "
5012436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches			       "aborting\n");
50131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			goto err_out_free_res;
50141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		}
50151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_using_dac = 0;
50161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
50171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	casreg_len = pci_resource_len(pdev, 0);
50191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp = netdev_priv(dev);
50211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->pdev = pdev;
50221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
50231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* A value of 0 indicates we never explicitly set it */
50241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->orig_cacheline_size = cas_cacheline_size ? orig_cacheline_size: 0;
50251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
50261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->dev = dev;
50276aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
50281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	  cassini_debug;
50291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
503092d76e81b9df5f33b0c9e2091e892560a437a15fDavid S. Miller#if defined(CONFIG_SPARC)
50314e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer	cp->of_node = pci_device_to_OF_node(pdev);
50324e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer#endif
50334e3dbdb1392a83bd21a6ff8f6bc785495058d37cRichard Mortimer
50341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->link_transition = LINK_TRANSITION_UNKNOWN;
50351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->link_transition_jiffies_valid = 0;
50361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_init(&cp->lock);
50381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_init(&cp->rx_inuse_lock);
50391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_init(&cp->rx_spare_lock);
50401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_TX_RINGS; i++) {
50411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock_init(&cp->stat_lock[i]);
50421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		spin_lock_init(&cp->tx_lock[i]);
50431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
50441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	spin_lock_init(&cp->stat_lock[N_TX_RINGS]);
5045758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_init(&cp->pm_mutex);
50461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	init_timer(&cp->link_timer);
50481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->link_timer.function = cas_link_timer;
50491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->link_timer.data = (unsigned long) cp;
50501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
50521f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Just in case the implementation of atomic operations
50531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 * change so that an explicit initialization is necessary.
50541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
50551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_set(&cp->reset_task_pending, 0);
50561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_set(&cp->reset_task_pending_all, 0);
50571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_set(&cp->reset_task_pending_spare, 0);
50581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	atomic_set(&cp->reset_task_pending_mtu, 0);
50591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
5060c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	INIT_WORK(&cp->reset_task, cas_reset_task);
50611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Default link parameters */
5063bf829370a8d664d87a61697c8a0d6d780c336aa4Dan Carpenter	if (link_mode >= 0 && link_mode < 6)
50641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_cntl = link_modes[link_mode];
50651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else
50661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->link_cntl = BMCR_ANENABLE;
50671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->lstate = link_down;
50681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->link_transition = LINK_TRANSITION_LINK_DOWN;
50691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	netif_carrier_off(cp->dev);
50701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->timer_ticks = 0;
50711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* give us access to cassini registers */
507318e37f2a979dd696e6b4495b6f2470c01ffeab6cMarc Zyngier	cp->regs = pci_iomap(pdev, 0, casreg_len);
507479ea13ce07c951bb4d95471e7300baa0f1be9e78Al Viro	if (!cp->regs) {
5075436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		dev_err(&pdev->dev, "Cannot map device registers, aborting\n");
50761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_out_free_res;
50771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
50781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->casreg_len = casreg_len;
50791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_save_state(pdev);
50811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_check_pci_invariants(cp);
50821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_hard_reset(cp);
50831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_reset(cp, 0);
50841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cas_check_invariants(cp))
50851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_out_iounmap;
5086fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	if (cp->cas_flags & CAS_FLAG_SATURN)
5087fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		if (cas_saturn_firmware_init(cp))
5088fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh			goto err_out_iounmap;
50891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50901f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->init_block = (struct cas_init_block *)
50911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
50921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				     &cp->block_dvma);
50931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!cp->init_block) {
5094436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		dev_err(&pdev->dev, "Cannot allocate init block, aborting\n");
50951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_out_iounmap;
50961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
50971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
50986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	for (i = 0; i < N_TX_RINGS; i++)
50991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->init_txds[i] = cp->init_block->txds[i];
51001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	for (i = 0; i < N_RX_DESC_RINGS; i++)
51021f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->init_rxds[i] = cp->init_block->rxds[i];
51031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	for (i = 0; i < N_RX_COMP_RINGS; i++)
51051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->init_rxcs[i] = cp->init_block->rxcs[i];
51061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	for (i = 0; i < N_RX_FLOWS; i++)
51081f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		skb_queue_head_init(&cp->rx_flows[i]);
51091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
511083d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger	dev->netdev_ops = &cas_netdev_ops;
5111a232f76732e11c91c2215d3a43cf9ebc7f939939Al Viro	dev->ethtool_ops = &cas_ethtool_ops;
51121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev->watchdog_timeo = CAS_TX_TIMEOUT;
511383d6f0352cc47b41d42cc1d6fb31bc8d9753b772Stephen Hemminger
51141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef USE_NAPI
5115bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	netif_napi_add(dev, &cp->napi, cas_poll, 64);
51161f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
51171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev->irq = pdev->irq;
51181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	dev->dma = 0;
51191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* Cassini features. */
51211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if ((cp->cas_flags & CAS_FLAG_NO_HW_CSUM) == 0)
51221f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
51231f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (pci_using_dac)
51251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		dev->features |= NETIF_F_HIGHDMA;
51261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (register_netdev(dev)) {
5128436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		dev_err(&pdev->dev, "Cannot register net device, aborting\n");
51291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		goto err_out_free_consistent;
51301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
51311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	i = readl(cp->regs + REG_BIM_CFG);
5133436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_info(dev, "Sun Cassini%s (%sbit/%sMHz PCI/%s) Ethernet[%d] %pM\n",
5134436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		    (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
5135436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		    (i & BIM_CFG_32BIT) ? "32" : "64",
5136436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		    (i & BIM_CFG_66MHZ) ? "66" : "33",
5137436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		    (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq,
5138436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches		    dev->dev_addr);
51391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_set_drvdata(pdev, dev);
51411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp->hw_running = 1;
51421f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_entropy_reset(cp);
51431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_phy_init(cp);
51441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_begin_auto_negotiation(cp, NULL);
51451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
51461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_out_free_consistent:
51481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_free_consistent(pdev, sizeof(struct cas_init_block),
51491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    cp->init_block, cp->block_dvma);
51501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_out_iounmap:
5152758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_lock(&cp->pm_mutex);
51531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->hw_running)
51541f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_shutdown(cp);
5155758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
51561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
515718e37f2a979dd696e6b4495b6f2470c01ffeab6cMarc Zyngier	pci_iounmap(pdev, cp->regs);
51581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_out_free_res:
51611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_release_regions(pdev);
51621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_write_cacheline:
516425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* Try to restore it in case the error occurred after we
51656aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	 * set it.
51661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	 */
51671f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, orig_cacheline_size);
51681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_out_free_netdev:
51701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	free_netdev(dev);
51711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millererr_out_disable_pdev:
51731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_disable_device(pdev);
51741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_set_drvdata(pdev, NULL);
51751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return -ENODEV;
51761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
51771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void __devexit cas_remove_one(struct pci_dev *pdev)
51791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
51801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = pci_get_drvdata(pdev);
51811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp;
51821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (!dev)
51831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		return;
51841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cp = netdev_priv(dev);
51861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unregister_netdev(dev);
51871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5188fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh	if (cp->fw_data)
5189fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh		vfree(cp->fw_data);
5190fcaa40669cd798ca2ac0d15441e8a1d1145f2b16Jaswinder Singh
5191758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_lock(&cp->pm_mutex);
519223f333a2bfafba80339315b724808982a9de57d9Tejun Heo	cancel_work_sync(&cp->reset_task);
51931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->hw_running)
51941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_shutdown(cp);
5195758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
51961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
51971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#if 1
51981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->orig_cacheline_size) {
51991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* Restore the cache line size if we had modified
52001f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * it.
52011f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
52026aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
52031f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller				      cp->orig_cacheline_size);
52041f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
52051f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
52061f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_free_consistent(pdev, sizeof(struct cas_init_block),
52071f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller			    cp->init_block, cp->block_dvma);
520818e37f2a979dd696e6b4495b6f2470c01ffeab6cMarc Zyngier	pci_iounmap(pdev, cp->regs);
52091f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	free_netdev(dev);
52101f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_release_regions(pdev);
52111f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_disable_device(pdev);
52121f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_set_drvdata(pdev, NULL);
52131f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
52141f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52151f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef CONFIG_PM
521646d7031ecb8a8360b0022abd8014f38cc1197166Al Virostatic int cas_suspend(struct pci_dev *pdev, pm_message_t state)
52171f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
52181f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = pci_get_drvdata(pdev);
52191f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
52201f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	unsigned long flags;
52211f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5222758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_lock(&cp->pm_mutex);
52236aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
52241f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	/* If the driver is opened, we stop the DMA */
52251f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->opened) {
52261f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_device_detach(dev);
52271f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52281f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_lock_all_save(cp, flags);
52291f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52301f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		/* We can set the second arg of cas_reset to 0
52311f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * because on resume, we'll call cas_init_hw with
52321f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * its second arg set so that autonegotiation is
52331f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 * restarted.
52341f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		 */
52351f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_reset(cp, 0);
52361f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_clean_rings(cp);
52371f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_unlock_all_restore(cp, flags);
52381f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
52391f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52401f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->hw_running)
52411f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_shutdown(cp);
5242758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
52431f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52441f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
52451f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
52461f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52471f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int cas_resume(struct pci_dev *pdev)
52481f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
52491f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct net_device *dev = pci_get_drvdata(pdev);
52501f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	struct cas *cp = netdev_priv(dev);
52511f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5252436d27d1db147713e4cd17b2fa491d22374bda98Joe Perches	netdev_info(dev, "resuming\n");
52531f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5254758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_lock(&cp->pm_mutex);
52551f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	cas_hard_reset(cp);
52561f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (cp->opened) {
52571f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		unsigned long flags;
52581f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_lock_all_save(cp, flags);
52591f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_reset(cp, 0);
52601f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cp->hw_running = 1;
52611f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_clean_rings(cp);
52621f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_init_hw(cp, 1);
52631f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		cas_unlock_all_restore(cp, flags);
52641f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52651f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		netif_device_attach(dev);
52661f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	}
5267758df69ee01f7be99c2df5562ef278bab05623ddIngo Molnar	mutex_unlock(&cp->pm_mutex);
52681f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	return 0;
52691f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
52701f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif /* CONFIG_PM */
52711f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52721f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic struct pci_driver cas_driver = {
52731f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	.name		= DRV_MODULE_NAME,
52741f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	.id_table	= cas_pci_tbl,
52751f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	.probe		= cas_init_one,
52761f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	.remove		= __devexit_p(cas_remove_one),
52771f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#ifdef CONFIG_PM
52781f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	.suspend	= cas_suspend,
52791f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	.resume		= cas_resume
52801f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller#endif
52811f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller};
52821f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52831f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic int __init cas_init(void)
52841f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
52851f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	if (linkdown_timeout > 0)
52861f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		link_transition_timeout = linkdown_timeout * HZ;
52871f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	else
52881f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller		link_transition_timeout = 0;
52891f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
5290299176206b266f204be859adf9e66efd06628ab2Jeff Garzik	return pci_register_driver(&cas_driver);
52911f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
52921f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52931f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millerstatic void __exit cas_cleanup(void)
52941f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller{
52951f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller	pci_unregister_driver(&cas_driver);
52961f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller}
52971f26dac32057baaf67d10b45c6b5277db862911dDavid S. Miller
52981f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millermodule_init(cas_init);
52991f26dac32057baaf67d10b45c6b5277db862911dDavid S. Millermodule_exit(cas_cleanup);
5300