1753f492093da7a40141bfe083073400f518f4c68Michael Buesch/* b44.c: Broadcom 44xx/47xx Fast Ethernet device driver.
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 David S. Miller (davem@redhat.com)
4753f492093da7a40141bfe083073400f518f4c68Michael Buesch * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
5753f492093da7a40141bfe083073400f518f4c68Michael Buesch * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
6753f492093da7a40141bfe083073400f518f4c68Michael Buesch * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
78056bfafb8a845f3035e7aae5ffe405df118bc12Gary Zambrano * Copyright (C) 2006 Broadcom Corporation.
8eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch * Copyright (C) 2007 Michael Buesch <m@bues.ch>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Distribute under GPL.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
132fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
142fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ethtool.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mii.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ether.h>
2372f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger#include <linux/if_vlan.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
28a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
2989358f90ab6f6657d386e77e19c805d7ab88694fAndrew Morton#include <linux/dma-mapping.h>
30753f492093da7a40141bfe083073400f518f4c68Michael Buesch#include <linux/ssb/ssb.h>
315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37753f492093da7a40141bfe083073400f518f4c68Michael Buesch
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "b44.h"
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_MODULE_NAME		"b44"
41753f492093da7a40141bfe083073400f518f4c68Michael Buesch#define DRV_MODULE_VERSION	"2.0"
427329f0d58de01878d9ce4f0be7a76e136f223eefJoe Perches#define DRV_DESCRIPTION		"Broadcom 44xx/47xx 10/100 PCI ethernet driver"
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_DEF_MSG_ENABLE	  \
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(NETIF_MSG_DRV		| \
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 NETIF_MSG_PROBE	| \
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 NETIF_MSG_LINK		| \
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 NETIF_MSG_TIMER	| \
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 NETIF_MSG_IFDOWN	| \
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 NETIF_MSG_IFUP		| \
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 NETIF_MSG_RX_ERR	| \
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 NETIF_MSG_TX_ERR)
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* length of time before we decide the hardware is borked,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and dev->tx_timeout() should be called to fix the problem
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_TIMEOUT			(5 * HZ)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* hardware minimum and maximum for a single frame's data payload */
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_MIN_MTU			60
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_MAX_MTU			1500
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_RX_RING_SIZE		512
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_DEF_RX_RING_PENDING		200
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_RX_RING_BYTES	(sizeof(struct dma_desc) * \
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 B44_RX_RING_SIZE)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_RING_SIZE		512
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_DEF_TX_RING_PENDING		(B44_TX_RING_SIZE - 1)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_RING_BYTES	(sizeof(struct dma_desc) * \
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 B44_TX_RING_SIZE)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_GAP(BP)	\
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(B44_TX_RING_SIZE - (BP)->tx_pending)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_BUFFS_AVAIL(BP)						\
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(((BP)->tx_cons <= (BP)->tx_prod) ?				\
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  (BP)->tx_cons + (BP)->tx_pending - (BP)->tx_prod :		\
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  (BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NEXT_TX(N)		(((N) + 1) & (B44_TX_RING_SIZE - 1))
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
804ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau#define RX_PKT_OFFSET		(RX_HEADER_LEN + 2)
814ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau#define RX_PKT_BUF_SZ		(1536 + RX_PKT_OFFSET)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* minimum number of free TX descriptors required to wake up TX process */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define B44_TX_WAKEUP_THRESH		(B44_TX_RING_SIZE / 4)
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
86725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano/* b44 internal pattern match filter info */
87725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PATTERN_BASE	0x400
88725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PATTERN_SIZE	0x80
89725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PMASK_BASE		0x600
90725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_PMASK_SIZE		0x10
91725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_MAX_PATTERNS	16
92725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_ETHIPV6UDP_HLEN	62
93725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano#define B44_ETHIPV4UDP_HLEN	42
94725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
95753f492093da7a40141bfe083073400f518f4c68Michael BueschMODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
967329f0d58de01878d9ce4f0be7a76e136f223eefJoe PerchesMODULE_DESCRIPTION(DRV_DESCRIPTION);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(DRV_MODULE_VERSION);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_debug = -1;	/* -1 == use B44_DEF_MSG_ENABLE as value */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(b44_debug, int, 0);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
105753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI
106a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(b44_pci_tbl) = {
107753f492093da7a40141bfe083073400f518f4c68Michael Buesch	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
108753f492093da7a40141bfe083073400f518f4c68Michael Buesch	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
109753f492093da7a40141bfe083073400f518f4c68Michael Buesch	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
110753f492093da7a40141bfe083073400f518f4c68Michael Buesch	{ 0 } /* terminate list with empty entry */
111753f492093da7a40141bfe083073400f518f4c68Michael Buesch};
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, b44_pci_tbl);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
114753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic struct pci_driver b44_pci_driver = {
115753f492093da7a40141bfe083073400f518f4c68Michael Buesch	.name		= DRV_MODULE_NAME,
116753f492093da7a40141bfe083073400f518f4c68Michael Buesch	.id_table	= b44_pci_tbl,
117753f492093da7a40141bfe083073400f518f4c68Michael Buesch};
118753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif /* CONFIG_B44_PCI */
119753f492093da7a40141bfe083073400f518f4c68Michael Buesch
120753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic const struct ssb_device_id b44_ssb_tbl[] = {
121753f492093da7a40141bfe083073400f518f4c68Michael Buesch	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
122753f492093da7a40141bfe083073400f518f4c68Michael Buesch	SSB_DEVTABLE_END
123753f492093da7a40141bfe083073400f518f4c68Michael Buesch};
124753f492093da7a40141bfe083073400f518f4c68Michael BueschMODULE_DEVICE_TABLE(ssb, b44_ssb_tbl);
125753f492093da7a40141bfe083073400f518f4c68Michael Buesch
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_halt(struct b44 *);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_init_rings(struct b44 *);
1285fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan
1295fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan#define B44_FULL_RESET		1
1305fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan#define B44_FULL_RESET_SKIP_PHY	2
1315fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan#define B44_PARTIAL_RESET	3
132fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón#define B44_CHIP_RESET_FULL	4
133fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón#define B44_CHIP_RESET_PARTIAL	5
1345fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan
13500e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambranostatic void b44_init_hw(struct b44 *, int);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1379f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linvillestatic int dma_desc_sync_size;
138753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int instance;
1399f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
1403353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieustatic const char b44_gstrings[][ETH_GSTRING_LEN] = {
1413353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu#define _B44(x...)	# x,
1423353930d9d026ca94747d0766f864b2a0a8c714bFrancois RomieuB44_STAT_REG_DECLARE
1433353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu#undef _B44
1443353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu};
1453353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
146753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
147753f492093da7a40141bfe083073400f518f4c68Michael Buesch						dma_addr_t dma_base,
148753f492093da7a40141bfe083073400f518f4c68Michael Buesch						unsigned long offset,
149753f492093da7a40141bfe083073400f518f4c68Michael Buesch						enum dma_data_direction dir)
1509f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville{
15139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	dma_sync_single_for_device(sdev->dma_dev, dma_base + offset,
15239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				   dma_desc_sync_size, dir);
1539f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville}
1549f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
155753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
156753f492093da7a40141bfe083073400f518f4c68Michael Buesch					     dma_addr_t dma_base,
157753f492093da7a40141bfe083073400f518f4c68Michael Buesch					     unsigned long offset,
158753f492093da7a40141bfe083073400f518f4c68Michael Buesch					     enum dma_data_direction dir)
1599f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville{
16039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset,
16139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				dma_desc_sync_size, dir);
1629f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville}
1639f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned long br32(const struct b44 *bp, unsigned long reg)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
166753f492093da7a40141bfe083073400f518f4c68Michael Buesch	return ssb_read32(bp->sdev, reg);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16910badc215493a435e2dbdc691386f2650a1778deJeff Garzikstatic inline void bw32(const struct b44 *bp,
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long reg, unsigned long val)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
172753f492093da7a40141bfe083073400f518f4c68Michael Buesch	ssb_write32(bp->sdev, reg, val);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_wait_bit(struct b44 *bp, unsigned long reg,
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 bit, unsigned long timeout, const int clear)
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long i;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < timeout; i++) {
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 val = br32(bp, reg);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clear && !(val & bit))
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!clear && (val & bit))
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == timeout) {
190f6ca057f1bfe251d944505fc5ba4df3762802539Jochen Friedrich		if (net_ratelimit())
1912fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			netdev_err(bp->dev, "BUG!  Timeout waiting for bit %08x of register %lx to %s\n",
1922fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches				   bit, reg, clear ? "clear" : "set");
1932fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
199753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
203753f492093da7a40141bfe083073400f518f4c68Michael Buesch	bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ |
204753f492093da7a40141bfe083073400f518f4c68Michael Buesch			    (index << CAM_CTRL_INDEX_SHIFT)));
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
206753f492093da7a40141bfe083073400f518f4c68Michael Buesch	b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
208753f492093da7a40141bfe083073400f518f4c68Michael Buesch	val = br32(bp, B44_CAM_DATA_LO);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210753f492093da7a40141bfe083073400f518f4c68Michael Buesch	data[2] = (val >> 24) & 0xFF;
211753f492093da7a40141bfe083073400f518f4c68Michael Buesch	data[3] = (val >> 16) & 0xFF;
212753f492093da7a40141bfe083073400f518f4c68Michael Buesch	data[4] = (val >> 8) & 0xFF;
213753f492093da7a40141bfe083073400f518f4c68Michael Buesch	data[5] = (val >> 0) & 0xFF;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
215753f492093da7a40141bfe083073400f518f4c68Michael Buesch	val = br32(bp, B44_CAM_DATA_HI);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
217753f492093da7a40141bfe083073400f518f4c68Michael Buesch	data[0] = (val >> 8) & 0xFF;
218753f492093da7a40141bfe083073400f518f4c68Michael Buesch	data[1] = (val >> 0) & 0xFF;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val  = ((u32) data[2]) << 24;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= ((u32) data[3]) << 16;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= ((u32) data[4]) <<  8;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= ((u32) data[5]) <<  0;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_CAM_DATA_LO, val);
23010badc215493a435e2dbdc691386f2650a1778deJeff Garzik	val = (CAM_DATA_HI_VALID |
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       (((u32) data[0]) << 8) |
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       (((u32) data[1]) << 0));
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_CAM_DATA_HI, val);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE |
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (index << CAM_CTRL_INDEX_SHIFT)));
23610badc215493a435e2dbdc691386f2650a1778deJeff Garzik	b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __b44_disable_ints(struct b44 *bp)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_IMASK, 0);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_disable_ints(struct b44 *bp)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__b44_disable_ints(bp);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Flush posted writes. */
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	br32(bp, B44_IMASK);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_enable_ints(struct b44 *bp)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_IMASK, bp->imask);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
257753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
264753f492093da7a40141bfe083073400f518f4c68Michael Buesch			     (phy_addr << MDIO_DATA_PMD_SHIFT) |
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (reg << MDIO_DATA_RA_SHIFT) |
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
273753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
278753f492093da7a40141bfe083073400f518f4c68Michael Buesch			     (phy_addr << MDIO_DATA_PMD_SHIFT) |
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (reg << MDIO_DATA_RA_SHIFT) |
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (val & MDIO_DATA_DATA)));
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
285753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
286753f492093da7a40141bfe083073400f518f4c68Michael Buesch{
287753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
288753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return 0;
289753f492093da7a40141bfe083073400f518f4c68Michael Buesch
290753f492093da7a40141bfe083073400f518f4c68Michael Buesch	return __b44_readphy(bp, bp->phy_addr, reg, val);
291753f492093da7a40141bfe083073400f518f4c68Michael Buesch}
292753f492093da7a40141bfe083073400f518f4c68Michael Buesch
293753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline int b44_writephy(struct b44 *bp, int reg, u32 val)
294753f492093da7a40141bfe083073400f518f4c68Michael Buesch{
295753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
296753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return 0;
297753f492093da7a40141bfe083073400f518f4c68Michael Buesch
298753f492093da7a40141bfe083073400f518f4c68Michael Buesch	return __b44_writephy(bp, bp->phy_addr, reg, val);
299753f492093da7a40141bfe083073400f518f4c68Michael Buesch}
300753f492093da7a40141bfe083073400f518f4c68Michael Buesch
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* miilib interface */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_mii_read(struct net_device *dev, int phy_id, int location)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
306753f492093da7a40141bfe083073400f518f4c68Michael Buesch	int rc = __b44_readphy(bp, phy_id, location, &val);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0xffffffff;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_mii_write(struct net_device *dev, int phy_id, int location,
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 int val)
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
316753f492093da7a40141bfe083073400f518f4c68Michael Buesch	__b44_writephy(bp, phy_id, location, val);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_phy_reset(struct b44 *bp)
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
325753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return 0;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(100);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = b44_readphy(bp, MII_BMCR, &val);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!err) {
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val & BMCR_RESET) {
3332fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			netdev_err(bp->dev, "PHY Reset would not complete\n");
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENODEV;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3388850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens	return err;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags)
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->flags &= ~(B44_FLAG_TX_PAUSE | B44_FLAG_RX_PAUSE);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->flags |= pause_flags;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = br32(bp, B44_RXCONFIG);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pause_flags & B44_FLAG_RX_PAUSE)
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= RXCONFIG_FLOW;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val &= ~RXCONFIG_FLOW;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_RXCONFIG, val);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = br32(bp, B44_MAC_FLOW);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pause_flags & B44_FLAG_TX_PAUSE)
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= (MAC_FLOW_PAUSE_ENAB |
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(0xc0 & MAC_FLOW_RX_HI_WATER));
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val &= ~MAC_FLOW_PAUSE_ENAB;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_MAC_FLOW, val);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
36610badc215493a435e2dbdc691386f2650a1778deJeff Garzik	u32 pause_enab = 0;
3672b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano
3682b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano	/* The driver supports only rx pause by default because
36910badc215493a435e2dbdc691386f2650a1778deJeff Garzik	   the b44 mac tx pause mechanism generates excessive
37010badc215493a435e2dbdc691386f2650a1778deJeff Garzik	   pause frames.
3712b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano	   Use ethtool to turn on b44 tx pause if necessary.
3722b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano	 */
3732b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano	if ((local & ADVERTISE_PAUSE_CAP) &&
37410badc215493a435e2dbdc691386f2650a1778deJeff Garzik	    (local & ADVERTISE_PAUSE_ASYM)){
3752b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano		if ((remote & LPA_PAUSE_ASYM) &&
3762b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano		    !(remote & LPA_PAUSE_CAP))
3772b474cf53870abf1bbad631c3368b9efc9b5ba9dGary Zambrano			pause_enab |= B44_FLAG_RX_PAUSE;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__b44_set_flow_ctrl(bp, pause_enab);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3836c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens#ifdef CONFIG_BCM47XX
3846c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens#include <asm/mach-bcm47xx/nvram.h>
385753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic void b44_wap54g10_workaround(struct b44 *bp)
386753f492093da7a40141bfe083073400f518f4c68Michael Buesch{
3876c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens	char buf[20];
388753f492093da7a40141bfe083073400f518f4c68Michael Buesch	u32 val;
389753f492093da7a40141bfe083073400f518f4c68Michael Buesch	int err;
390753f492093da7a40141bfe083073400f518f4c68Michael Buesch
391753f492093da7a40141bfe083073400f518f4c68Michael Buesch	/*
392753f492093da7a40141bfe083073400f518f4c68Michael Buesch	 * workaround for bad hardware design in Linksys WAP54G v1.0
393753f492093da7a40141bfe083073400f518f4c68Michael Buesch	 * see https://dev.openwrt.org/ticket/146
394753f492093da7a40141bfe083073400f518f4c68Michael Buesch	 * check and reset bit "isolate"
395753f492093da7a40141bfe083073400f518f4c68Michael Buesch	 */
3966c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens	if (nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
397753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return;
3986c08af030212d1a34593397bb01f262ff31c3629Hauke Mehrtens	if (simple_strtoul(buf, NULL, 0) == 2) {
399753f492093da7a40141bfe083073400f518f4c68Michael Buesch		err = __b44_readphy(bp, 0, MII_BMCR, &val);
400753f492093da7a40141bfe083073400f518f4c68Michael Buesch		if (err)
401753f492093da7a40141bfe083073400f518f4c68Michael Buesch			goto error;
402753f492093da7a40141bfe083073400f518f4c68Michael Buesch		if (!(val & BMCR_ISOLATE))
403753f492093da7a40141bfe083073400f518f4c68Michael Buesch			return;
404753f492093da7a40141bfe083073400f518f4c68Michael Buesch		val &= ~BMCR_ISOLATE;
405753f492093da7a40141bfe083073400f518f4c68Michael Buesch		err = __b44_writephy(bp, 0, MII_BMCR, val);
406753f492093da7a40141bfe083073400f518f4c68Michael Buesch		if (err)
407753f492093da7a40141bfe083073400f518f4c68Michael Buesch			goto error;
408753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
409753f492093da7a40141bfe083073400f518f4c68Michael Buesch	return;
410753f492093da7a40141bfe083073400f518f4c68Michael Buescherror:
4112fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches	pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
412753f492093da7a40141bfe083073400f518f4c68Michael Buesch}
413753f492093da7a40141bfe083073400f518f4c68Michael Buesch#else
414753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_wap54g10_workaround(struct b44 *bp)
415753f492093da7a40141bfe083073400f518f4c68Michael Buesch{
416753f492093da7a40141bfe083073400f518f4c68Michael Buesch}
417753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif
418753f492093da7a40141bfe083073400f518f4c68Michael Buesch
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_setup_phy(struct b44 *bp)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
424753f492093da7a40141bfe083073400f518f4c68Michael Buesch	b44_wap54g10_workaround(bp);
425753f492093da7a40141bfe083073400f518f4c68Michael Buesch
426753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
427753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return 0;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				val & MII_ALEDCTRL_ALLMSK)) != 0)
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((err = b44_readphy(bp, B44_MII_TLEDCTRL, &val)) != 0)
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((err = b44_writephy(bp, B44_MII_TLEDCTRL,
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				val | MII_TLEDCTRL_ENABLE)) != 0)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(bp->flags & B44_FLAG_FORCE_LINK)) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 adv = ADVERTISE_CSMA;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bp->flags & B44_FLAG_ADV_10HALF)
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adv |= ADVERTISE_10HALF;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bp->flags & B44_FLAG_ADV_10FULL)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adv |= ADVERTISE_10FULL;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bp->flags & B44_FLAG_ADV_100HALF)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adv |= ADVERTISE_100HALF;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bp->flags & B44_FLAG_ADV_100FULL)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adv |= ADVERTISE_100FULL;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bp->flags & B44_FLAG_PAUSE_AUTO)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((err = b44_writephy(bp, MII_ADVERTISE, adv)) != 0)
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((err = b44_writephy(bp, MII_BMCR, (BMCR_ANENABLE |
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       BMCR_ANRESTART))) != 0)
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 bmcr;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((err = b44_readphy(bp, MII_BMCR, &bmcr)) != 0)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bmcr &= ~(BMCR_FULLDPLX | BMCR_ANENABLE | BMCR_SPEED100);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bp->flags & B44_FLAG_100_BASE_T)
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bmcr |= BMCR_SPEED100;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bp->flags & B44_FLAG_FULL_DUPLEX)
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bmcr |= BMCR_FULLDPLX;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((err = b44_writephy(bp, MII_BMCR, bmcr)) != 0)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Since we will not be negotiating there is no safe way
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to determine if the link partner supports flow control
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * or not.  So just disable it completely in this case.
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_set_flow_ctrl(bp, 0, 0);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_stats_update(struct b44 *bp)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long reg;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 *val;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = &bp->hw_stats.tx_good_octets;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) {
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*val++ += br32(bp, reg);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4923353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
4933353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	/* Pad */
4943353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	reg += 8*4UL;
4953353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) {
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*val++ += br32(bp, reg);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_link_report(struct b44 *bp)
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!netif_carrier_ok(bp->dev)) {
5042fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		netdev_info(bp->dev, "Link is down\n");
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5062fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		netdev_info(bp->dev, "Link is up at %d Mbps, %s duplex\n",
5072fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			    (bp->flags & B44_FLAG_100_BASE_T) ? 100 : 10,
5082fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			    (bp->flags & B44_FLAG_FULL_DUPLEX) ? "full" : "half");
5092fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches
5102fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		netdev_info(bp->dev, "Flow control is %s for TX and %s for RX\n",
5112fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			    (bp->flags & B44_FLAG_TX_PAUSE) ? "on" : "off",
5122fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			    (bp->flags & B44_FLAG_RX_PAUSE) ? "on" : "off");
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_check_phy(struct b44 *bp)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 bmsr, aux;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
520753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
521753f492093da7a40141bfe083073400f518f4c68Michael Buesch		bp->flags |= B44_FLAG_100_BASE_T;
522753f492093da7a40141bfe083073400f518f4c68Michael Buesch		bp->flags |= B44_FLAG_FULL_DUPLEX;
523753f492093da7a40141bfe083073400f518f4c68Michael Buesch		if (!netif_carrier_ok(bp->dev)) {
524753f492093da7a40141bfe083073400f518f4c68Michael Buesch			u32 val = br32(bp, B44_TX_CTRL);
525753f492093da7a40141bfe083073400f518f4c68Michael Buesch			val |= TX_CTRL_DUPLEX;
526753f492093da7a40141bfe083073400f518f4c68Michael Buesch			bw32(bp, B44_TX_CTRL, val);
527753f492093da7a40141bfe083073400f518f4c68Michael Buesch			netif_carrier_on(bp->dev);
528753f492093da7a40141bfe083073400f518f4c68Michael Buesch			b44_link_report(bp);
529753f492093da7a40141bfe083073400f518f4c68Michael Buesch		}
530753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return;
531753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
532753f492093da7a40141bfe083073400f518f4c68Michael Buesch
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (bmsr != 0xffff)) {
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (aux & MII_AUXCTRL_SPEED)
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bp->flags |= B44_FLAG_100_BASE_T;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bp->flags &= ~B44_FLAG_100_BASE_T;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (aux & MII_AUXCTRL_DUPLEX)
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bp->flags |= B44_FLAG_FULL_DUPLEX;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bp->flags &= ~B44_FLAG_FULL_DUPLEX;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!netif_carrier_ok(bp->dev) &&
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (bmsr & BMSR_LSTATUS)) {
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 val = br32(bp, B44_TX_CTRL);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 local_adv, remote_adv;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bp->flags & B44_FLAG_FULL_DUPLEX)
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				val |= TX_CTRL_DUPLEX;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				val &= ~TX_CTRL_DUPLEX;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bw32(bp, B44_TX_CTRL, val);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(bp->flags & B44_FLAG_FORCE_LINK) &&
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    !b44_readphy(bp, MII_ADVERTISE, &local_adv) &&
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    !b44_readphy(bp, MII_LPA, &remote_adv))
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				b44_set_flow_ctrl(bp, local_adv, remote_adv);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Link now up */
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_carrier_on(bp->dev);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			b44_link_report(bp);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (netif_carrier_ok(bp->dev) && !(bmsr & BMSR_LSTATUS)) {
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Link now down */
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_carrier_off(bp->dev);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			b44_link_report(bp);
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bmsr & BMSR_RFAULT)
5712fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			netdev_warn(bp->dev, "Remote fault detected in PHY\n");
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bmsr & BMSR_JCD)
5732fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			netdev_warn(bp->dev, "Jabber detected in PHY\n");
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_timer(unsigned long __opaque)
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = (struct b44 *) __opaque;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_check_phy(bp);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_stats_update(bp);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
589a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger	mod_timer(&bp->timer, round_jiffies(jiffies + HZ));
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_tx(struct b44 *bp)
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 cur, cons;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cur  = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cur /= sizeof(struct dma_desc);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX needs updating when NETIF_F_SG is supported */
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (cons = bp->tx_cons; cons != cur; cons = NEXT_TX(cons)) {
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ring_info *rp = &bp->tx_buffers[cons];
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb = rp->skb;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6045d9428de1a9785f10a4339f80b717be665ba51c7Eric Sesterhenn		BUG_ON(skb == NULL);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		dma_unmap_single(bp->sdev->dma_dev,
60739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				 rp->mapping,
60839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				 skb->len,
60939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				 DMA_TO_DEVICE);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rp->skb = NULL;
61115ac2b08a2fd0f4aacbe8ae39788252fea6fbe63Xander Hover		dev_kfree_skb_irq(skb);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->tx_cons = cons;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_queue_stopped(bp->dev) &&
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH)
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(bp->dev);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_GPTIMER, 0);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Works like this.  This chip writes a 'struct rx_header" 30 bytes
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * before the DMA address you give it.  So we allocate 30 more bytes
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for the RX buffer, DMA map all of it, skb_reserve the 30 bytes, then
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * point the chip at 30 bytes past where the rx_header will go.
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dma_desc *dp;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ring_info *src_map, *map;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rx_header *rh;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t mapping;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dest_idx;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ctrl;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	src_map = NULL;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (src_idx >= 0)
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src_map = &bp->rx_buffers[src_idx];
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map = &bp->rx_buffers[dest_idx];
642bf0dcbd929faf036f1a4f2918090344d0e249cf5Stephen Hemminger	skb = netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb == NULL)
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
64739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				 RX_PKT_BUF_SZ,
64839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				 DMA_FROM_DEVICE);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Hardware bug work-around, the chip is unable to do PCI DMA
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to/from anything above 1GB :-( */
65239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
65328b767967763835d8526f6baedc25a8a86052640Yang Hongyang		mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Sigh... */
65539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
65639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			dma_unmap_single(bp->sdev->dma_dev, mapping,
657f225763a7d6c92c4932dbd528437997078496fccMichael Buesch					     RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb_any(skb);
659bf0dcbd929faf036f1a4f2918090344d0e249cf5Stephen Hemminger		skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb == NULL)
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
66239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
66339a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 RX_PKT_BUF_SZ,
66439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 DMA_FROM_DEVICE);
66539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
66639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		    mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
66739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
66839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb_any(skb);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
672a58c891a53aca81c78f9cbe0572a301042470e96Eric Dumazet		bp->force_copybreak = 1;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67572f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger	rh = (struct rx_header *) skb->data;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rh->len = 0;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rh->flags = 0;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map->skb = skb;
681753f492093da7a40141bfe083073400f518f4c68Michael Buesch	map->mapping = mapping;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (src_map != NULL)
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src_map->skb = NULL;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6864ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau	ctrl = (DESC_CTRL_LEN & RX_PKT_BUF_SZ);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dest_idx == (B44_RX_RING_SIZE - 1))
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl |= DESC_CTRL_EOT;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dp = &bp->rx_ring[dest_idx];
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dp->ctrl = cpu_to_le32(ctrl);
6924ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau	dp->addr = cpu_to_le32((u32) mapping + bp->dma_offset);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6949f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (bp->flags & B44_FLAG_RX_RING_HACK)
695753f492093da7a40141bfe083073400f518f4c68Michael Buesch		b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
6965d4d9e8ad6c646c4811bf0049df761dee6affc3dMichael Buesch			                    dest_idx * sizeof(*dp),
697753f492093da7a40141bfe083073400f518f4c68Michael Buesch			                    DMA_BIDIRECTIONAL);
6989f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return RX_PKT_BUF_SZ;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dma_desc *src_desc, *dest_desc;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ring_info *src_map, *dest_map;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rx_header *rh;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dest_idx;
708a7bed27dc69e3bc9238549a4964ea94ec318362cAl Viro	__le32 ctrl;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dest_desc = &bp->rx_ring[dest_idx];
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dest_map = &bp->rx_buffers[dest_idx];
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	src_desc = &bp->rx_ring[src_idx];
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	src_map = &bp->rx_buffers[src_idx];
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dest_map->skb = src_map->skb;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rh = (struct rx_header *) src_map->skb->data;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rh->len = 0;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rh->flags = 0;
720753f492093da7a40141bfe083073400f518f4c68Michael Buesch	dest_map->mapping = src_map->mapping;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7229f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (bp->flags & B44_FLAG_RX_RING_HACK)
723753f492093da7a40141bfe083073400f518f4c68Michael Buesch		b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma,
7245d4d9e8ad6c646c4811bf0049df761dee6affc3dMichael Buesch			                 src_idx * sizeof(*src_desc),
725753f492093da7a40141bfe083073400f518f4c68Michael Buesch			                 DMA_BIDIRECTIONAL);
7269f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl = src_desc->ctrl;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dest_idx == (B44_RX_RING_SIZE - 1))
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl |= cpu_to_le32(DESC_CTRL_EOT);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl &= cpu_to_le32(~DESC_CTRL_EOT);
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dest_desc->ctrl = ctrl;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dest_desc->addr = src_desc->addr;
7359f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	src_map->skb = NULL;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7389f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (bp->flags & B44_FLAG_RX_RING_HACK)
739753f492093da7a40141bfe083073400f518f4c68Michael Buesch		b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
7405d4d9e8ad6c646c4811bf0049df761dee6affc3dMichael Buesch					     dest_idx * sizeof(*dest_desc),
741753f492093da7a40141bfe083073400f518f4c68Michael Buesch					     DMA_BIDIRECTIONAL);
7429f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
74339a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping,
74439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				   RX_PKT_BUF_SZ,
74539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				   DMA_FROM_DEVICE);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_rx(struct b44 *bp, int budget)
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int received;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 cons, prod;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	received = 0;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prod  = br32(bp, B44_DMARX_STAT) & DMARX_STAT_CDMASK;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prod /= sizeof(struct dma_desc);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cons = bp->rx_cons;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (cons != prod && budget > 0) {
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct ring_info *rp = &bp->rx_buffers[cons];
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb = rp->skb;
761753f492093da7a40141bfe083073400f518f4c68Michael Buesch		dma_addr_t map = rp->mapping;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct rx_header *rh;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 len;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
76639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					RX_PKT_BUF_SZ,
76739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					DMA_FROM_DEVICE);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rh = (struct rx_header *) skb->data;
769a7bed27dc69e3bc9238549a4964ea94ec318362cAl Viro		len = le16_to_cpu(rh->len);
77072f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger		if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drop_it:
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			b44_recycle_rx(bp, cons, bp->rx_prod);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drop_it_no_recycle:
775553e2335625e6c96cb6d76c0d63cfc1034747614Eric Dumazet			bp->dev->stats.rx_dropped++;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto next_pkt;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len == 0) {
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int i = 0;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do {
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				udelay(2);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				barrier();
785a7bed27dc69e3bc9238549a4964ea94ec318362cAl Viro				len = le16_to_cpu(rh->len);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} while (len == 0 && i++ < 5);
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto drop_it;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Omit CRC. */
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len -= 4;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
794a58c891a53aca81c78f9cbe0572a301042470e96Eric Dumazet		if (!bp->force_copybreak && len > RX_COPY_THRESHOLD) {
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int skb_size;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (skb_size < 0)
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto drop_it;
79939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			dma_unmap_single(bp->sdev->dma_dev, map,
80039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 skb_size, DMA_FROM_DEVICE);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Leave out rx_header */
8024ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau			skb_put(skb, len + RX_PKT_OFFSET);
8034ca857958c129781b46870ec1d2d13c50aafb8c5Felix Fietkau			skb_pull(skb, RX_PKT_OFFSET);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct sk_buff *copy_skb;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			b44_recycle_rx(bp, cons, bp->rx_prod);
80853639207c032ec63dac3661af94447f9774cd40bHauke Mehrtens			copy_skb = netdev_alloc_skb(bp->dev, len + 2);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy_skb == NULL)
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto drop_it_no_recycle;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_reserve(copy_skb, 2);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_put(copy_skb, len);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* DMA sync done above, copy just the actual packet */
81572f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger			skb_copy_from_linear_data_offset(skb, RX_PKT_OFFSET,
816d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo							 copy_skb->data, len);
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb = copy_skb;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
819bc8acf2c8c3e43fcc192762a9f964b3e9a17748bEric Dumazet		skb_checksum_none_assert(skb);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->protocol = eth_type_trans(skb, bp->dev);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_receive_skb(skb);
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		received++;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		budget--;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	next_pkt:
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->rx_prod = (bp->rx_prod + 1) &
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(B44_RX_RING_SIZE - 1);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cons = (cons + 1) & (B44_RX_RING_SIZE - 1);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->rx_cons = cons;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_DMARX_PTR, cons * sizeof(struct dma_desc));
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return received;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
836bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemmingerstatic int b44_poll(struct napi_struct *napi, int budget)
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
838bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	struct b44 *bp = container_of(napi, struct b44, napi);
839bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	int work_done;
840e99b1f04d922f132ffab8310b470bcc93d3ddf80Dongdong Deng	unsigned long flags;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
842e99b1f04d922f132ffab8310b470bcc93d3ddf80Dongdong Deng	spin_lock_irqsave(&bp->lock, flags);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->istat & (ISTAT_TX | ISTAT_TO)) {
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* spin_lock(&bp->tx_lock); */
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_tx(bp);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* spin_unlock(&bp->tx_lock); */
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
84932737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord	if (bp->istat & ISTAT_RFO) {	/* fast recovery, in ~20msec */
85032737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord		bp->istat &= ~ISTAT_RFO;
85132737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord		b44_disable_ints(bp);
85232737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord		ssb_device_enable(bp->sdev, 0); /* resets ISTAT_RFO */
85332737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord		b44_init_rings(bp);
85432737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord		b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
85532737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord		netif_wake_queue(bp->dev);
85632737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord	}
85732737e934a952c1b0c744f2a78d80089d15c7ee3Mark Lord
858e99b1f04d922f132ffab8310b470bcc93d3ddf80Dongdong Deng	spin_unlock_irqrestore(&bp->lock, flags);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
860bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	work_done = 0;
861bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	if (bp->istat & ISTAT_RX)
862bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger		work_done += b44_rx(bp, budget);
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->istat & ISTAT_ERRORS) {
865d15e9c4d9a75702b30e00cdf95c71c88e3f3f51eFrancois Romieu		spin_lock_irqsave(&bp->lock, flags);
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_halt(bp);
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_init_rings(bp);
8685fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan		b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(bp->dev);
870d15e9c4d9a75702b30e00cdf95c71c88e3f3f51eFrancois Romieu		spin_unlock_irqrestore(&bp->lock, flags);
871bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger		work_done = 0;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
874bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	if (work_done < budget) {
875288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_complete(napi);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_enable_ints(bp);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
879bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	return work_done;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8827d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t b44_interrupt(int irq, void *dev_id)
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 istat, imask;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int handled = 0;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
88965b984f26f16e97168ee29e53145055412f38a23Francois Romieu	spin_lock(&bp->lock);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	istat = br32(bp, B44_ISTAT);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	imask = br32(bp, B44_IMASK);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
894e78181feb0b94fb6afeaef3b28d4f5df1b847c98Johannes Berg	/* The interrupt mask register controls which interrupt bits
895e78181feb0b94fb6afeaef3b28d4f5df1b847c98Johannes Berg	 * will actually raise an interrupt to the CPU when set by hw/firmware,
896e78181feb0b94fb6afeaef3b28d4f5df1b847c98Johannes Berg	 * but doesn't mask off the bits.
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	istat &= imask;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (istat) {
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		handled = 1;
901ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu
902ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu		if (unlikely(!netif_running(dev))) {
9032fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			netdev_info(dev, "late interrupt\n");
904ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu			goto irq_ack;
905ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu		}
906ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu
907288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		if (napi_schedule_prep(&bp->napi)) {
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: These writes are posted by the readback of
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 *       the ISTAT register below.
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bp->istat = istat;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			__b44_disable_ints(bp);
913288379f050284087578b77e04f040b57db3db3f8Ben Hutchings			__napi_schedule(&bp->napi);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
916ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieuirq_ack:
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_ISTAT, istat);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		br32(bp, B44_ISTAT);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
92065b984f26f16e97168ee29e53145055412f38a23Francois Romieu	spin_unlock(&bp->lock);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(handled);
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_tx_timeout(struct net_device *dev)
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9282fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches	netdev_err(dev, "transmit timed out, resetting\n");
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_halt(bp);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_init_rings(bp);
9345fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan	b44_init_hw(bp, B44_FULL_RESET);
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_enable_ints(bp);
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(dev);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
94361357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
946c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu	int rc = NETDEV_TX_OK;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t mapping;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 len, entry, ctrl;
94922580f894ac190c46beebb5c3172e450a2318f79Dongdong Deng	unsigned long flags;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = skb->len;
95222580f894ac190c46beebb5c3172e450a2318f79Dongdong Deng	spin_lock_irqsave(&bp->lock, flags);
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This is a hard error, log it. */
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) {
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
9572fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
958c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu		goto err_out;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
96139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
96239a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
963f65a71775cc3eb5d5d8ac4c349c8f48a7d5c7759Stephen Hemminger		struct sk_buff *bounce_skb;
964f65a71775cc3eb5d5d8ac4c349c8f48a7d5c7759Stephen Hemminger
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Chip can't handle DMA to/from >1GB, use bounce buffer */
96639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
96739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			dma_unmap_single(bp->sdev->dma_dev, mapping, len,
968f225763a7d6c92c4932dbd528437997078496fccMichael Buesch					     DMA_TO_DEVICE);
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9709034f77bad1e86c4b43e5f5739eb3b8f4878e947David S. Miller		bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA);
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!bounce_skb)
972c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu			goto err_out;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
97439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
97539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 len, DMA_TO_DEVICE);
97639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
97739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
97839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				dma_unmap_single(bp->sdev->dma_dev, mapping,
979f225763a7d6c92c4932dbd528437997078496fccMichael Buesch						     len, DMA_TO_DEVICE);
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb_any(bounce_skb);
981c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu			goto err_out;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
984f65a71775cc3eb5d5d8ac4c349c8f48a7d5c7759Stephen Hemminger		skb_copy_from_linear_data(skb, skb_put(bounce_skb, len), len);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb_any(skb);
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = bounce_skb;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = bp->tx_prod;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->tx_buffers[entry].skb = skb;
991753f492093da7a40141bfe083073400f518f4c68Michael Buesch	bp->tx_buffers[entry].mapping = mapping;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl  = (len & DESC_CTRL_LEN);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (entry == (B44_TX_RING_SIZE - 1))
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl |= DESC_CTRL_EOT;
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10019f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (bp->flags & B44_FLAG_TX_RING_HACK)
1002753f492093da7a40141bfe083073400f518f4c68Michael Buesch		b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma,
1003753f492093da7a40141bfe083073400f518f4c68Michael Buesch			                    entry * sizeof(bp->tx_ring[0]),
1004753f492093da7a40141bfe083073400f518f4c68Michael Buesch			                    DMA_TO_DEVICE);
10059f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = NEXT_TX(entry);
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->tx_prod = entry;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc));
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->flags & B44_FLAG_BUGGY_TXPTR)
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc));
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->flags & B44_FLAG_REORDER_BUG)
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		br32(bp, B44_DMATX_PTR);
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (TX_BUFFS_AVAIL(bp) < 1)
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieuout_unlock:
102222580f894ac190c46beebb5c3172e450a2318f79Dongdong Deng	spin_unlock_irqrestore(&bp->lock, flags);
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1024c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu	return rc;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1026c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieuerr_out:
1027c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu	rc = NETDEV_TX_BUSY;
1028c719369350bc566d2643067421fbf05f4b90e70bFrancois Romieu	goto out_unlock;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_change_mtu(struct net_device *dev, int new_mtu)
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_mtu < B44_MIN_MTU || new_mtu > B44_MAX_MTU)
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!netif_running(dev)) {
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We'll just catch it later when the
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * device is up'd.
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->mtu = new_mtu;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_halt(bp);
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->mtu = new_mtu;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_init_rings(bp);
10505fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan	b44_init_hw(bp, B44_FULL_RESET);
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_enable_ints(bp);
105410badc215493a435e2dbdc691386f2650a1778deJeff Garzik
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Free up pending packets in all rx/tx rings.
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip has been shut down and the driver detached from
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the networking, so no interrupts or new tx packets will
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * end up in the driver.  bp->lock is not held and we are not
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in an interrupt context and thus may sleep.
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_free_rings(struct b44 *bp)
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ring_info *rp;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < B44_RX_RING_SIZE; i++) {
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rp = &bp->rx_buffers[i];
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rp->skb == NULL)
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
107539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
107639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				 DMA_FROM_DEVICE);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb_any(rp->skb);
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rp->skb = NULL;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX needs changes once NETIF_F_SG is set... */
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < B44_TX_RING_SIZE; i++) {
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rp = &bp->tx_buffers[i];
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rp->skb == NULL)
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
108739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
108839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori				 DMA_TO_DEVICE);
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb_any(rp->skb);
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rp->skb = NULL;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize tx/rx rings for packet processing.
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip has been shut down and the driver detached from
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the networking, so no interrupts or new tx packets will
1098874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu * end up in the driver.
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_init_rings(struct b44 *bp)
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_free_rings(bp);
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(bp->rx_ring, 0, B44_RX_RING_BYTES);
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11099f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (bp->flags & B44_FLAG_RX_RING_HACK)
111039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
111139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					   DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
11129f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
11139f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (bp->flags & B44_FLAG_TX_RING_HACK)
111439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
111539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					   DMA_TABLE_BYTES, DMA_TO_DEVICE);
11169f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < bp->rx_pending; i++) {
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (b44_alloc_rx_skb(bp, -1, i) < 0)
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must not be invoked with interrupt sources disabled and
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the hardware shutdown down.
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_free_consistent(struct b44 *bp)
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1129b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl	kfree(bp->rx_buffers);
1130b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl	bp->rx_buffers = NULL;
1131b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl	kfree(bp->tx_buffers);
1132b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl	bp->tx_buffers = NULL;
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->rx_ring) {
11349f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		if (bp->flags & B44_FLAG_RX_RING_HACK) {
113539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
113639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
11379f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			kfree(bp->rx_ring);
11389f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		} else
113939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
114039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					  bp->rx_ring, bp->rx_ring_dma);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->rx_ring = NULL;
11429f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->flags &= ~B44_FLAG_RX_RING_HACK;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->tx_ring) {
11459f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		if (bp->flags & B44_FLAG_TX_RING_HACK) {
114639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
114739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 DMA_TABLE_BYTES, DMA_TO_DEVICE);
11489f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			kfree(bp->tx_ring);
11499f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		} else
115039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori			dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
115139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					  bp->tx_ring, bp->tx_ring_dma);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->tx_ring = NULL;
11539f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->flags &= ~B44_FLAG_TX_RING_HACK;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must not be invoked with interrupt sources disabled and
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the hardware shutdown down.  Can sleep.
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1161753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size  = B44_RX_RING_SIZE * sizeof(struct ring_info);
1166753f492093da7a40141bfe083073400f518f4c68Michael Buesch	bp->rx_buffers = kzalloc(size, gfp);
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bp->rx_buffers)
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_err;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = B44_TX_RING_SIZE * sizeof(struct ring_info);
1171753f492093da7a40141bfe083073400f518f4c68Michael Buesch	bp->tx_buffers = kzalloc(size, gfp);
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bp->tx_buffers)
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_err;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = DMA_TABLE_BYTES;
117639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
117739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 &bp->rx_ring_dma, gfp);
11789f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (!bp->rx_ring) {
11799f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		/* Allocation may have failed due to pci_alloc_consistent
11809f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		   insisting on use of GFP_DMA, which is more restrictive
11819f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		   than necessary...  */
11829f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		struct dma_desc *rx_ring;
11839f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		dma_addr_t rx_ring_dma;
11849f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
1185753f492093da7a40141bfe083073400f518f4c68Michael Buesch		rx_ring = kzalloc(size, gfp);
1186874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu		if (!rx_ring)
11879f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			goto out_err;
11889f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
118939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
119039a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					     DMA_TABLE_BYTES,
119139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					     DMA_BIDIRECTIONAL);
11929f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
119339a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) ||
119428b767967763835d8526f6baedc25a8a86052640Yang Hongyang			rx_ring_dma + size > DMA_BIT_MASK(30)) {
11959f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			kfree(rx_ring);
11969f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			goto out_err;
11979f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		}
11989f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
11999f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->rx_ring = rx_ring;
12009f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->rx_ring_dma = rx_ring_dma;
12019f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->flags |= B44_FLAG_RX_RING_HACK;
12029f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	}
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
120539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					 &bp->tx_ring_dma, gfp);
12069f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	if (!bp->tx_ring) {
1207f225763a7d6c92c4932dbd528437997078496fccMichael Buesch		/* Allocation may have failed due to ssb_dma_alloc_consistent
12089f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		   insisting on use of GFP_DMA, which is more restrictive
12099f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		   than necessary...  */
12109f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		struct dma_desc *tx_ring;
12119f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		dma_addr_t tx_ring_dma;
12129f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
1213753f492093da7a40141bfe083073400f518f4c68Michael Buesch		tx_ring = kzalloc(size, gfp);
1214874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu		if (!tx_ring)
12159f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			goto out_err;
12169f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
121739a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
121839a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					     DMA_TABLE_BYTES,
121939a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori					     DMA_TO_DEVICE);
12209f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
122139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori		if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) ||
122228b767967763835d8526f6baedc25a8a86052640Yang Hongyang			tx_ring_dma + size > DMA_BIT_MASK(30)) {
12239f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			kfree(tx_ring);
12249f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville			goto out_err;
12259f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		}
12269f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
12279f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->tx_ring = tx_ring;
12289f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->tx_ring_dma = tx_ring_dma;
12299f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville		bp->flags |= B44_FLAG_TX_RING_HACK;
12309f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	}
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_err:
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_free_consistent(bp);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_clear_stats(struct b44 *bp)
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long reg;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL)
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		br32(bp, reg);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL)
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		br32(bp, reg);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */
1252fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botónstatic void b44_chip_reset(struct b44 *bp, int reset_kind)
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1254753f492093da7a40141bfe083073400f518f4c68Michael Buesch	struct ssb_device *sdev = bp->sdev;
1255f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch	bool was_enabled;
1256753f492093da7a40141bfe083073400f518f4c68Michael Buesch
1257f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch	was_enabled = ssb_device_is_enabled(bp->sdev);
1258f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch
1259f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch	ssb_device_enable(bp->sdev, 0);
1260f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch	ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev);
1261f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch
1262f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch	if (was_enabled) {
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_RCV_LAZY, 0);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
126540ee8c768cbb57aac7e55f7b54572afa8a9eac5aGary Zambrano		b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_DMATX_CTRL, 0);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->tx_prod = bp->tx_cons = 0;
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) {
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE,
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     100, 0);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_DMARX_CTRL, 0);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->rx_prod = bp->rx_cons = 0;
1274f8af11af85fecbfa7b95fd79c043b16ae0ee0d55Michael Buesch	}
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_clear_stats(bp);
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1278fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	/*
1279fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	 * Don't enable PHY if we are doing a partial reset
1280fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	 * we are probably going to power down
1281fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	 */
1282fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	if (reset_kind == B44_CHIP_RESET_PARTIAL)
1283fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón		return;
1284fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón
1285753f492093da7a40141bfe083073400f518f4c68Michael Buesch	switch (sdev->bus->bustype) {
1286753f492093da7a40141bfe083073400f518f4c68Michael Buesch	case SSB_BUSTYPE_SSB:
1287753f492093da7a40141bfe083073400f518f4c68Michael Buesch		bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
128839506a552b4b302540e1f9c6c93a122df353e57dJulia Lawall		     (DIV_ROUND_CLOSEST(ssb_clockspeed(sdev->bus),
128939506a552b4b302540e1f9c6c93a122df353e57dJulia Lawall					B44_MDC_RATIO)
1290753f492093da7a40141bfe083073400f518f4c68Michael Buesch		     & MDIO_CTRL_MAXF_MASK)));
1291753f492093da7a40141bfe083073400f518f4c68Michael Buesch		break;
1292753f492093da7a40141bfe083073400f518f4c68Michael Buesch	case SSB_BUSTYPE_PCI:
1293753f492093da7a40141bfe083073400f518f4c68Michael Buesch		bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
1294753f492093da7a40141bfe083073400f518f4c68Michael Buesch		     (0x0d & MDIO_CTRL_MAXF_MASK)));
1295753f492093da7a40141bfe083073400f518f4c68Michael Buesch		break;
129698a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch	case SSB_BUSTYPE_PCMCIA:
129798a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch	case SSB_BUSTYPE_SDIO:
129898a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch		WARN_ON(1); /* A device with this bus does not exist. */
129998a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch		break;
1300753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
1301753f492093da7a40141bfe083073400f518f4c68Michael Buesch
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	br32(bp, B44_MDIO_CTRL);
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL);
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		br32(bp, B44_ENET_CTRL);
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags &= ~B44_FLAG_INTERNAL_PHY;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 val = br32(bp, B44_DEVCTRL);
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val & DEVCTRL_EPR) {
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR));
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			br32(bp, B44_DEVCTRL);
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(100);
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags |= B44_FLAG_INTERNAL_PHY;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_halt(struct b44 *bp)
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_disable_ints(bp);
1324fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	/* reset PHY */
1325fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	b44_phy_reset(bp);
1326fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	/* power down PHY */
13272fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches	netdev_info(bp->dev, "powering down PHY\n");
1328fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
1329fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	/* now reset the chip, but without enabling the MAC&PHY
1330fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	 * part of it. This has to be done _after_ we shut down the PHY */
1331fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bp->lock is held. */
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_mac_addr(struct b44 *bp)
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_CAM_CTRL, 0);
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(bp->dev->flags & IFF_PROMISC)) {
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 val;
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__b44_cam_write(bp, bp->dev->dev_addr, 0);
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = br32(bp, B44_CAM_CTRL);
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_mac_addr(struct net_device *dev, void *p)
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr *addr = p;
1351753f492093da7a40141bfe083073400f518f4c68Michael Buesch	u32 val;
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_running(dev))
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1356391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano	if (!is_valid_ether_addr(addr->sa_data))
1357391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano		return -EINVAL;
1358391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
1362753f492093da7a40141bfe083073400f518f4c68Michael Buesch
1363753f492093da7a40141bfe083073400f518f4c68Michael Buesch	val = br32(bp, B44_RXCONFIG);
1364753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (!(val & RXCONFIG_CAM_ABSENT))
1365753f492093da7a40141bfe083073400f518f4c68Michael Buesch		__b44_set_mac_addr(bp);
1366753f492093da7a40141bfe083073400f518f4c68Michael Buesch
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Called at device open time to get the chip ready for
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet processing.  Invoked with bp->lock held.
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_rx_mode(struct net_device *);
13765fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chanstatic void b44_init_hw(struct b44 *bp, int reset_kind)
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1380fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
13815fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan	if (reset_kind == B44_FULL_RESET) {
138200e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		b44_phy_reset(bp);
138300e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		b44_setup_phy(bp);
138400e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano	}
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable CRC32, set proper LED modes and power on PHY */
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This sets the MAC address too.  */
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__b44_set_rx_mode(bp->dev);
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* MTU + eth header + possible VLAN tag + struct rx_header */
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
13985fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan	if (reset_kind == B44_PARTIAL_RESET) {
13995fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan		bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
140072f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger				      (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)));
14015fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan	} else {
140200e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
140300e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
140400e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
140572f4861ef9b1c1ca6e4abb49854698e80d3b684dStephen Hemminger				      (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)));
140600e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
140800e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		bw32(bp, B44_DMARX_PTR, bp->rx_pending);
140900e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		bp->rx_prod = bp->rx_pending;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141100e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano		bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
141200e8b3aa1cfd7577fd4019a24f7c3980506f83f3Gary Zambrano	}
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = br32(bp, B44_ENET_CTRL);
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_open(struct net_device *dev)
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1423753f492093da7a40141bfe083073400f518f4c68Michael Buesch	err = b44_alloc_consistent(bp, GFP_KERNEL);
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
14256c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu		goto out;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1427bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	napi_enable(&bp->napi);
1428bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_init_rings(bp);
14305fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan	b44_init_hw(bp, B44_FULL_RESET);
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1432e254e9bff5283aad1af6d74d2a312ee011b84d61John W. Linville	b44_check_phy(bp);
1433e254e9bff5283aad1af6d74d2a312ee011b84d61John W. Linville
14341fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner	err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
14356c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu	if (unlikely(err < 0)) {
1436bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger		napi_disable(&bp->napi);
1437fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón		b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
14386c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu		b44_free_rings(bp);
14396c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu		b44_free_consistent(bp);
14406c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu		goto out;
14416c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieu	}
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&bp->timer);
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->timer.expires = jiffies + HZ;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->timer.data = (unsigned long) bp;
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->timer.function = b44_timer;
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&bp->timer);
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_enable_ints(bp);
1450d9e2d185bf01e20339158f77c3fca00b02014912Mark Lord	netif_start_queue(dev);
14516c2f4267833f453156f8f439cc32eb4c92f357b4Francois Romieuout:
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_POLL_CONTROLLER
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Polling receive - used by netconsole and other diagnostic tools
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to allow network i/o with interrupts disabled.
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_poll_controller(struct net_device *dev)
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_irq(dev->irq);
14637d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells	b44_interrupt(dev->irq, dev);
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_irq(dev->irq);
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1468725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambranostatic void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset)
1469725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano{
1470725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	u32 i;
1471725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	u32 *pattern = (u32 *) pp;
1472725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1473725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	for (i = 0; i < bytes; i += sizeof(u32)) {
1474725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		bw32(bp, B44_FILT_ADDR, table_offset + i);
1475725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]);
1476725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	}
1477725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano}
1478725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1479725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambranostatic int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
1480725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano{
1481725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	int magicsync = 6;
1482725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	int k, j, len = offset;
1483725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	int ethaddr_bytes = ETH_ALEN;
1484725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1485725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	memset(ppattern + offset, 0xff, magicsync);
1486725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	for (j = 0; j < magicsync; j++)
1487725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		set_bit(len++, (unsigned long *) pmask);
1488725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1489725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	for (j = 0; j < B44_MAX_PATTERNS; j++) {
1490725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
1491725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano			ethaddr_bytes = ETH_ALEN;
1492725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		else
1493725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano			ethaddr_bytes = B44_PATTERN_SIZE - len;
1494725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		if (ethaddr_bytes <=0)
1495725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano			break;
1496725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		for (k = 0; k< ethaddr_bytes; k++) {
1497725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano			ppattern[offset + magicsync +
1498725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano				(j * ETH_ALEN) + k] = macaddr[k];
1499e0188829cb724e7d12a2d4e343b368ff1d6e1471Stanislav Brabec			set_bit(len++, (unsigned long *) pmask);
1500725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		}
1501725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	}
1502725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	return len - 1;
1503725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano}
1504725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1505725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano/* Setup magic packet patterns in the b44 WOL
1506725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano * pattern matching filter.
1507725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano */
1508725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambranostatic void b44_setup_pseudo_magicp(struct b44 *bp)
1509725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano{
1510725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1511725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	u32 val;
1512725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	int plen0, plen1, plen2;
1513725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	u8 *pwol_pattern;
1514725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	u8 pwol_mask[B44_PMASK_SIZE];
1515725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1516dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau	pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
1517725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	if (!pwol_pattern) {
15182fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		pr_err("Memory not available for WOL\n");
1519725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		return;
1520725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	}
1521725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1522725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	/* Ipv4 magic packet pattern - pattern 0.*/
1523725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	memset(pwol_mask, 0, B44_PMASK_SIZE);
1524725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
1525725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano				  B44_ETHIPV4UDP_HLEN);
1526725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1527725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano   	bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
1528725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano   	bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
1529725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1530725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	/* Raw ethernet II magic packet pattern - pattern 1 */
1531725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	memset(pwol_pattern, 0, B44_PATTERN_SIZE);
1532725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	memset(pwol_mask, 0, B44_PMASK_SIZE);
1533725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
1534725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano				  ETH_HLEN);
1535725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1536725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano   	bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
1537725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		       B44_PATTERN_BASE + B44_PATTERN_SIZE);
1538725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano  	bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
1539725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		       B44_PMASK_BASE + B44_PMASK_SIZE);
1540725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1541725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	/* Ipv6 magic packet pattern - pattern 2 */
1542725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	memset(pwol_pattern, 0, B44_PATTERN_SIZE);
1543725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	memset(pwol_mask, 0, B44_PMASK_SIZE);
1544725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
1545725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano				  B44_ETHIPV6UDP_HLEN);
1546725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1547725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano   	bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
1548725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		       B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
1549725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano  	bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
1550725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano		       B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
1551725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1552725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	kfree(pwol_pattern);
1553725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1554725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	/* set these pattern's lengths: one less than each real length */
1555725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE;
1556725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	bw32(bp, B44_WKUP_LEN, val);
1557725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1558725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	/* enable wakeup pattern matching */
1559725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	val = br32(bp, B44_DEVCTRL);
1560725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano	bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE);
1561725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano
1562725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano}
156352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
1564753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI
1565753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic void b44_setup_wol_pci(struct b44 *bp)
1566753f492093da7a40141bfe083073400f518f4c68Michael Buesch{
1567753f492093da7a40141bfe083073400f518f4c68Michael Buesch	u16 val;
1568753f492093da7a40141bfe083073400f518f4c68Michael Buesch
1569753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (bp->sdev->bus->bustype != SSB_BUSTYPE_SSB) {
1570753f492093da7a40141bfe083073400f518f4c68Michael Buesch		bw32(bp, SSB_TMSLOW, br32(bp, SSB_TMSLOW) | SSB_TMSLOW_PE);
1571753f492093da7a40141bfe083073400f518f4c68Michael Buesch		pci_read_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, &val);
1572753f492093da7a40141bfe083073400f518f4c68Michael Buesch		pci_write_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, val | SSB_PE);
1573753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
1574753f492093da7a40141bfe083073400f518f4c68Michael Buesch}
1575753f492093da7a40141bfe083073400f518f4c68Michael Buesch#else
1576753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic inline void b44_setup_wol_pci(struct b44 *bp) { }
1577753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif /* CONFIG_B44_PCI */
1578753f492093da7a40141bfe083073400f518f4c68Michael Buesch
157952cafd965507b7a7bb962486539f6d7422552692Gary Zambranostatic void b44_setup_wol(struct b44 *bp)
158052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano{
158152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	u32 val;
158252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
158352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
158452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
158552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	if (bp->flags & B44_FLAG_B0_ANDLATER) {
158652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
158752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		bw32(bp, B44_WKUP_LEN, WKUP_LEN_DISABLE);
158852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
158952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		val = bp->dev->dev_addr[2] << 24 |
159052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano			bp->dev->dev_addr[3] << 16 |
159152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano			bp->dev->dev_addr[4] << 8 |
159252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano			bp->dev->dev_addr[5];
159352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		bw32(bp, B44_ADDR_LO, val);
159452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
159552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		val = bp->dev->dev_addr[0] << 8 |
159652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano			bp->dev->dev_addr[1];
159752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		bw32(bp, B44_ADDR_HI, val);
159852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
159952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		val = br32(bp, B44_DEVCTRL);
160052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
160152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
1602725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 	} else {
1603725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 		b44_setup_pseudo_magicp(bp);
1604725ad800b73a71fe91bfd8859f928852de688ea0Gary Zambrano 	}
1605753f492093da7a40141bfe083073400f518f4c68Michael Buesch	b44_setup_wol_pci(bp);
160652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano}
160752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_close(struct net_device *dev)
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1614bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	napi_disable(&bp->napi);
1615ba5eec9c55ec4be99d21a6ea614003b65d7f37d7Francois Romieu
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&bp->timer);
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_halt(bp);
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_free_rings(bp);
1622c35ca399e09828f3f6b40c0007a95a6582d90347Stephen Hemminger	netif_carrier_off(dev);
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(dev->irq, dev);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
162852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	if (bp->flags & B44_FLAG_WOL_ENABLE) {
16295fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan		b44_init_hw(bp, B44_PARTIAL_RESET);
163052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		b44_setup_wol(bp);
163152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	}
163252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_free_consistent(bp);
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *b44_get_stats(struct net_device *dev)
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
1641553e2335625e6c96cb6d76c0d63cfc1034747614Eric Dumazet	struct net_device_stats *nstat = &dev->stats;
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44_hw_stats *hwstat = &bp->hw_stats;
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Convert HW stats into netdevice stats. */
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->rx_packets = hwstat->rx_pkts;
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->tx_packets = hwstat->tx_pkts;
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->rx_bytes   = hwstat->rx_octets;
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->tx_bytes   = hwstat->tx_octets;
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->tx_errors  = (hwstat->tx_jabber_pkts +
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     hwstat->tx_oversize_pkts +
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     hwstat->tx_underruns +
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     hwstat->tx_excessive_cols +
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     hwstat->tx_late_cols);
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->multicast  = hwstat->tx_multicast_pkts;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->collisions = hwstat->tx_total_cols;
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->rx_length_errors = (hwstat->rx_oversize_pkts +
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_undersize);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->rx_over_errors   = hwstat->rx_missed_pkts;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->rx_frame_errors  = hwstat->rx_align_errs;
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->rx_crc_errors    = hwstat->rx_crc_errs;
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->rx_errors        = (hwstat->rx_jabber_pkts +
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_oversize_pkts +
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_missed_pkts +
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_crc_align_errs +
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_undersize +
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_crc_errs +
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_align_errs +
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   hwstat->rx_symbol_errs);
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->tx_aborted_errors = hwstat->tx_underruns;
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Carrier lost counter seems to be broken for some devices */
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return nstat;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __b44_load_mcast(struct b44 *bp, struct net_device *dev)
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
168222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, num_ents;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16854cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko	num_ents = min_t(int, netdev_mc_count(dev), B44_MCAST_TABLE_SIZE);
16860ddf477b8a9b02412a6cabd51c486998811c7dd1Jiri Pirko	i = 0;
168722bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	netdev_for_each_mc_addr(ha, dev) {
16880ddf477b8a9b02412a6cabd51c486998811c7dd1Jiri Pirko		if (i == num_ents)
16890ddf477b8a9b02412a6cabd51c486998811c7dd1Jiri Pirko			break;
169022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		__b44_cam_write(bp, ha->addr, i++ + 1);
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i+1;
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __b44_set_rx_mode(struct net_device *dev)
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = br32(bp, B44_RXCONFIG);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
1702753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= RXCONFIG_PROMISC;
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_RXCONFIG, val);
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1706874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu		unsigned char zero[6] = {0, 0, 0, 0, 0, 0};
1707cda22aa94d3fe3942476b3652b8b92c653b96ee3Bill Helfinstine		int i = 1;
1708874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__b44_set_mac_addr(bp);
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17112f614fe04f4463ff22234133319067d7361f54e5Jeff Garzik		if ((dev->flags & IFF_ALLMULTI) ||
17124cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko		    (netdev_mc_count(dev) > B44_MCAST_TABLE_SIZE))
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val |= RXCONFIG_ALLMULTI;
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
1715874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu			i = __b44_load_mcast(bp, dev);
171610badc215493a435e2dbdc691386f2650a1778deJeff Garzik
17172f614fe04f4463ff22234133319067d7361f54e5Jeff Garzik		for (; i < 64; i++)
171810badc215493a435e2dbdc691386f2650a1778deJeff Garzik			__b44_cam_write(bp, zero, i);
17192f614fe04f4463ff22234133319067d7361f54e5Jeff Garzik
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bw32(bp, B44_RXCONFIG, val);
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	val = br32(bp, B44_CAM_CTRL);
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_set_rx_mode(struct net_device *dev)
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__b44_set_rx_mode(dev);
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 b44_get_msglevel(struct net_device *dev)
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return bp->msg_enable;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_set_msglevel(struct net_device *dev, u32 value)
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->msg_enable = value;
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
1750753f492093da7a40141bfe083073400f518f4c68Michael Buesch	struct ssb_bus *bus = bp->sdev->bus;
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175227e0955184a70c4bd4542ee2da18c749b4f43345roel kluin	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
175327e0955184a70c4bd4542ee2da18c749b4f43345roel kluin	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
1754753f492093da7a40141bfe083073400f518f4c68Michael Buesch	switch (bus->bustype) {
1755753f492093da7a40141bfe083073400f518f4c68Michael Buesch	case SSB_BUSTYPE_PCI:
175627e0955184a70c4bd4542ee2da18c749b4f43345roel kluin		strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
1757753f492093da7a40141bfe083073400f518f4c68Michael Buesch		break;
1758753f492093da7a40141bfe083073400f518f4c68Michael Buesch	case SSB_BUSTYPE_SSB:
175927e0955184a70c4bd4542ee2da18c749b4f43345roel kluin		strlcpy(info->bus_info, "SSB", sizeof(info->bus_info));
1760753f492093da7a40141bfe083073400f518f4c68Michael Buesch		break;
176198a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch	case SSB_BUSTYPE_PCMCIA:
176298a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch	case SSB_BUSTYPE_SDIO:
176398a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch		WARN_ON(1); /* A device with this bus does not exist. */
176498a1e2a9260d30ad691fbd1ed778a05e38fe655bMichael Buesch		break;
1765753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_nway_reset(struct net_device *dev)
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 bmcr;
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int r;
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_readphy(bp, MII_BMCR, &bmcr);
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_readphy(bp, MII_BMCR, &bmcr);
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = -EINVAL;
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bmcr & BMCR_ANENABLE) {
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_writephy(bp, MII_BMCR,
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     bmcr | BMCR_ANRESTART);
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r = 0;
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return r;
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->supported = (SUPPORTED_Autoneg);
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->supported |= (SUPPORTED_100baseT_Half |
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  SUPPORTED_100baseT_Full |
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  SUPPORTED_10baseT_Half |
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  SUPPORTED_10baseT_Full |
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  SUPPORTED_MII);
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->advertising = 0;
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->flags & B44_FLAG_ADV_10HALF)
1801adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox		cmd->advertising |= ADVERTISED_10baseT_Half;
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->flags & B44_FLAG_ADV_10FULL)
1803adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox		cmd->advertising |= ADVERTISED_10baseT_Full;
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->flags & B44_FLAG_ADV_100HALF)
1805adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox		cmd->advertising |= ADVERTISED_100baseT_Half;
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->flags & B44_FLAG_ADV_100FULL)
1807adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox		cmd->advertising |= ADVERTISED_100baseT_Full;
1808adf6e00064ebcd3d82009ba6ef66f489f0885ebdMatthew Wilcox	cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
1809707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny	ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ?
1810707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny				    SPEED_100 : SPEED_10));
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DUPLEX_FULL : DUPLEX_HALF;
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->port = 0;
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->phy_address = bp->phy_addr;
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		XCVR_INTERNAL : XCVR_EXTERNAL;
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		AUTONEG_DISABLE : AUTONEG_ENABLE;
181947b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano	if (cmd->autoneg == AUTONEG_ENABLE)
182047b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		cmd->advertising |= ADVERTISED_Autoneg;
182147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano	if (!netif_running(dev)){
1822707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny		ethtool_cmd_speed_set(cmd, 0);
182347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		cmd->duplex = 0xff;
182447b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano	}
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->maxtxpkt = 0;
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->maxrxpkt = 0;
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
183325db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny	u32 speed = ethtool_cmd_speed(cmd);
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We do not support gigabit. */
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd->autoneg == AUTONEG_ENABLE) {
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cmd->advertising &
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (ADVERTISED_1000baseT_Half |
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     ADVERTISED_1000baseT_Full))
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
184125db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny	} else if ((speed != SPEED_100 &&
184225db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny		    speed != SPEED_10) ||
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (cmd->duplex != DUPLEX_HALF &&
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    cmd->duplex != DUPLEX_FULL)) {
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd->autoneg == AUTONEG_ENABLE) {
185147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		bp->flags &= ~(B44_FLAG_FORCE_LINK |
185247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			       B44_FLAG_100_BASE_T |
185347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			       B44_FLAG_FULL_DUPLEX |
185447b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			       B44_FLAG_ADV_10HALF |
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       B44_FLAG_ADV_10FULL |
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       B44_FLAG_ADV_100HALF |
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       B44_FLAG_ADV_100FULL);
185847b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		if (cmd->advertising == 0) {
185947b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			bp->flags |= (B44_FLAG_ADV_10HALF |
186047b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano				      B44_FLAG_ADV_10FULL |
186147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano				      B44_FLAG_ADV_100HALF |
186247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano				      B44_FLAG_ADV_100FULL);
186347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		} else {
186447b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			if (cmd->advertising & ADVERTISED_10baseT_Half)
186547b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano				bp->flags |= B44_FLAG_ADV_10HALF;
186647b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			if (cmd->advertising & ADVERTISED_10baseT_Full)
186747b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano				bp->flags |= B44_FLAG_ADV_10FULL;
186847b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			if (cmd->advertising & ADVERTISED_100baseT_Half)
186947b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano				bp->flags |= B44_FLAG_ADV_100HALF;
187047b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano			if (cmd->advertising & ADVERTISED_100baseT_Full)
187147b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano				bp->flags |= B44_FLAG_ADV_100FULL;
187247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		}
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags |= B44_FLAG_FORCE_LINK;
187547b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX);
187625db0338813a8915457636b1f6abe6a28fa73f8dDavid Decotigny		if (speed == SPEED_100)
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bp->flags |= B44_FLAG_100_BASE_T;
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cmd->duplex == DUPLEX_FULL)
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bp->flags |= B44_FLAG_FULL_DUPLEX;
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188247b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano	if (netif_running(dev))
188347b9c3b1e6afa3c40e3ac1822cd13946567b5955Gary Zambrano		b44_setup_phy(bp);
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_get_ringparam(struct net_device *dev,
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct ethtool_ringparam *ering)
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ering->rx_max_pending = B44_RX_RING_SIZE - 1;
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ering->rx_pending = bp->rx_pending;
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX ethtool lacks a tx_max_pending, oops... */
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_ringparam(struct net_device *dev,
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct ethtool_ringparam *ering)
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ering->rx_pending > B44_RX_RING_SIZE - 1) ||
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (ering->rx_mini_pending != 0) ||
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (ering->rx_jumbo_pending != 0) ||
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (ering->tx_pending > B44_TX_RING_SIZE - 1))
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->rx_pending = ering->rx_pending;
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->tx_pending = ering->tx_pending;
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_halt(bp);
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_init_rings(bp);
19195fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan	b44_init_hw(bp, B44_FULL_RESET);
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(bp->dev);
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_enable_ints(bp);
192410badc215493a435e2dbdc691386f2650a1778deJeff Garzik
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void b44_get_pauseparam(struct net_device *dev,
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct ethtool_pauseparam *epause)
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epause->autoneg =
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(bp->flags & B44_FLAG_PAUSE_AUTO) != 0;
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epause->rx_pause =
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(bp->flags & B44_FLAG_RX_PAUSE) != 0;
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epause->tx_pause =
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(bp->flags & B44_FLAG_TX_PAUSE) != 0;
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_set_pauseparam(struct net_device *dev,
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct ethtool_pauseparam *epause)
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (epause->autoneg)
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags |= B44_FLAG_PAUSE_AUTO;
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags &= ~B44_FLAG_PAUSE_AUTO;
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (epause->rx_pause)
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags |= B44_FLAG_RX_PAUSE;
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags &= ~B44_FLAG_RX_PAUSE;
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (epause->tx_pause)
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags |= B44_FLAG_TX_PAUSE;
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bp->flags &= ~B44_FLAG_TX_PAUSE;
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bp->flags & B44_FLAG_PAUSE_AUTO) {
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_halt(bp);
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b44_init_rings(bp);
19625fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan		b44_init_hw(bp, B44_FULL_RESET);
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__b44_set_flow_ctrl(bp, bp->flags);
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_enable_ints(bp);
196910badc215493a435e2dbdc691386f2650a1778deJeff Garzik
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19733353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieustatic void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data)
19743353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu{
19753353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	switch(stringset) {
19763353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	case ETH_SS_STATS:
19773353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu		memcpy(data, *b44_gstrings, sizeof(b44_gstrings));
19783353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu		break;
19793353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	}
19803353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu}
19813353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
1982b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzikstatic int b44_get_sset_count(struct net_device *dev, int sset)
19833353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu{
1984b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	switch (sset) {
1985b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	case ETH_SS_STATS:
1986b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik		return ARRAY_SIZE(b44_gstrings);
1987b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	default:
1988b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik		return -EOPNOTSUPP;
1989b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	}
19903353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu}
19913353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
19923353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieustatic void b44_get_ethtool_stats(struct net_device *dev,
19933353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu				  struct ethtool_stats *stats, u64 *data)
19943353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu{
19953353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	struct b44 *bp = netdev_priv(dev);
19963353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	u32 *val = &bp->hw_stats.tx_good_octets;
19973353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	u32 i;
19983353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
19993353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	spin_lock_irq(&bp->lock);
20003353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
20013353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	b44_stats_update(bp);
20023353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
20033353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++)
20043353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu		*data++ = *val++;
20053353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
20063353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	spin_unlock_irq(&bp->lock);
20073353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu}
20083353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu
200952cafd965507b7a7bb962486539f6d7422552692Gary Zambranostatic void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
201052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano{
201152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	struct b44 *bp = netdev_priv(dev);
201252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
201352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	wol->supported = WAKE_MAGIC;
201452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	if (bp->flags & B44_FLAG_WOL_ENABLE)
201552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		wol->wolopts = WAKE_MAGIC;
201652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	else
201752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		wol->wolopts = 0;
201852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	memset(&wol->sopass, 0, sizeof(wol->sopass));
201952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano}
202052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
202152cafd965507b7a7bb962486539f6d7422552692Gary Zambranostatic int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
202252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano{
202352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	struct b44 *bp = netdev_priv(dev);
202452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
202552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	spin_lock_irq(&bp->lock);
202652cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	if (wol->wolopts & WAKE_MAGIC)
202752cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		bp->flags |= B44_FLAG_WOL_ENABLE;
202852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	else
202952cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		bp->flags &= ~B44_FLAG_WOL_ENABLE;
203052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	spin_unlock_irq(&bp->lock);
203152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
203252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	return 0;
203352cafd965507b7a7bb962486539f6d7422552692Gary Zambrano}
203452cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
20357282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops b44_ethtool_ops = {
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_drvinfo		= b44_get_drvinfo,
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_settings		= b44_get_settings,
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_settings		= b44_set_settings,
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nway_reset		= b44_nway_reset,
20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_link		= ethtool_op_get_link,
204152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	.get_wol		= b44_get_wol,
204252cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	.set_wol		= b44_set_wol,
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_ringparam		= b44_get_ringparam,
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_ringparam		= b44_set_ringparam,
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_pauseparam		= b44_get_pauseparam,
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_pauseparam		= b44_set_pauseparam,
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_msglevel		= b44_get_msglevel,
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_msglevel		= b44_set_msglevel,
20493353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	.get_strings		= b44_get_strings,
2050b9f2c0440d806e01968c3ed4def930a43be248adJeff Garzik	.get_sset_count		= b44_get_sset_count,
20513353930d9d026ca94747d0766f864b2a0a8c714bFrancois Romieu	.get_ethtool_stats	= b44_get_ethtool_stats,
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mii_ioctl_data *data = if_mii(ifr);
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
20583410572d519b6c68505f746f25033de97809eaa1Francois Romieu	int err = -EINVAL;
20593410572d519b6c68505f746f25033de97809eaa1Francois Romieu
20603410572d519b6c68505f746f25033de97809eaa1Francois Romieu	if (!netif_running(dev))
20613410572d519b6c68505f746f25033de97809eaa1Francois Romieu		goto out;
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&bp->lock);
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
20663410572d519b6c68505f746f25033de97809eaa1Francois Romieuout:
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit b44_get_invariants(struct b44 *bp)
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2072753f492093da7a40141bfe083073400f518f4c68Michael Buesch	struct ssb_device *sdev = bp->sdev;
2073753f492093da7a40141bfe083073400f518f4c68Michael Buesch	int err = 0;
2074753f492093da7a40141bfe083073400f518f4c68Michael Buesch	u8 *addr;
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2076753f492093da7a40141bfe083073400f518f4c68Michael Buesch	bp->dma_offset = ssb_dma_translation(sdev);
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2078753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (sdev->bus->bustype == SSB_BUSTYPE_SSB &&
2079753f492093da7a40141bfe083073400f518f4c68Michael Buesch	    instance > 1) {
2080458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger		addr = sdev->bus->sprom.et1mac;
2081458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger		bp->phy_addr = sdev->bus->sprom.et1phyaddr;
2082753f492093da7a40141bfe083073400f518f4c68Michael Buesch	} else {
2083458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger		addr = sdev->bus->sprom.et0mac;
2084458414b2e3d9dd7ee4510d18c119a7ccd3b43ec5Larry Finger		bp->phy_addr = sdev->bus->sprom.et0phyaddr;
2085753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
20865ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch	/* Some ROMs have buggy PHY addresses with the high
20875ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch	 * bits set (sign extension?). Truncate them to a
20885ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch	 * valid PHY address. */
20895ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch	bp->phy_addr &= 0x1F;
20905ea79631c0c47d28831a0635e8af9da539d449cdMichael Buesch
2091753f492093da7a40141bfe083073400f518f4c68Michael Buesch	memcpy(bp->dev->dev_addr, addr, 6);
2092391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano
2093391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano	if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
20942fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		pr_err("Invalid MAC address found in EEPROM\n");
2095391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano		return -EINVAL;
2096391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano	}
2097391fc09a143aac08d1a3dc37b60238612b504ad3Gary Zambrano
20982160de53cc17a40ad07bd38bf52dd0bb72dd5183John W. Linville	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->imask = IMASK_DEF;
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210210badc215493a435e2dbdc691386f2650a1778deJeff Garzik	/* XXX - really required?
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   bp->flags |= B44_FLAG_BUGGY_TXPTR;
2104753f492093da7a40141bfe083073400f518f4c68Michael Buesch	*/
210552cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
2106753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (bp->sdev->id.revision >= 7)
2107753f492093da7a40141bfe083073400f518f4c68Michael Buesch		bp->flags |= B44_FLAG_B0_ANDLATER;
210852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano
21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2112403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemmingerstatic const struct net_device_ops b44_netdev_ops = {
2113403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_open		= b44_open,
2114403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_stop		= b44_close,
2115403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_start_xmit		= b44_start_xmit,
2116403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_get_stats		= b44_get_stats,
2117afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= b44_set_rx_mode,
2118403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_set_mac_address	= b44_set_mac_addr,
2119403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_validate_addr	= eth_validate_addr,
2120403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_do_ioctl		= b44_ioctl,
2121403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_tx_timeout		= b44_tx_timeout,
2122403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_change_mtu		= b44_change_mtu,
2123403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER
2124403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	.ndo_poll_controller	= b44_poll_controller,
2125403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger#endif
2126403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger};
2127403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger
2128753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int __devinit b44_init_one(struct ssb_device *sdev,
2129753f492093da7a40141bfe083073400f518f4c68Michael Buesch				  const struct ssb_device_id *ent)
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp;
21330795af5729b18218767fab27c44b1384f72dc9adJoe Perches	int err;
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2135753f492093da7a40141bfe083073400f518f4c68Michael Buesch	instance++;
2136753f492093da7a40141bfe083073400f518f4c68Michael Buesch
21377329f0d58de01878d9ce4f0be7a76e136f223eefJoe Perches	pr_info_once("%s version %s\n", DRV_DESCRIPTION, DRV_MODULE_VERSION);
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_etherdev(sizeof(*bp));
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev) {
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
2142753f492093da7a40141bfe083073400f518f4c68Michael Buesch		goto out;
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2145753f492093da7a40141bfe083073400f518f4c68Michael Buesch	SET_NETDEV_DEV(dev, sdev->dev);
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* No interesting netdevice features in this card... */
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->features |= 0;
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp = netdev_priv(dev);
2151753f492093da7a40141bfe083073400f518f4c68Michael Buesch	bp->sdev = sdev;
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->dev = dev;
2153a58c891a53aca81c78f9cbe0572a301042470e96Eric Dumazet	bp->force_copybreak = 0;
2154874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu
2155874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu	bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&bp->lock);
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->rx_pending = B44_DEF_RX_RING_PENDING;
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->tx_pending = B44_DEF_TX_RING_PENDING;
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2162403413e50d6fc88dada28bf41262a3d0e3627827Stephen Hemminger	dev->netdev_ops = &b44_netdev_ops;
2163bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	netif_napi_add(dev, &bp->napi, b44_poll, 64);
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = B44_TX_TIMEOUT;
2165753f492093da7a40141bfe083073400f518f4c68Michael Buesch	dev->irq = sdev->irq;
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2168753f492093da7a40141bfe083073400f518f4c68Michael Buesch	err = ssb_bus_powerup(sdev->bus, 0);
2169753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (err) {
2170753f492093da7a40141bfe083073400f518f4c68Michael Buesch		dev_err(sdev->dev,
2171753f492093da7a40141bfe083073400f518f4c68Michael Buesch			"Failed to powerup the bus\n");
2172753f492093da7a40141bfe083073400f518f4c68Michael Buesch		goto err_out_free_dev;
2173753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
217439a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori
217539a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) ||
217639a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori	    dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) {
2177753f492093da7a40141bfe083073400f518f4c68Michael Buesch		dev_err(sdev->dev,
21782fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			"Required 30BIT DMA mask unsupported by the system\n");
2179753f492093da7a40141bfe083073400f518f4c68Michael Buesch		goto err_out_powerdown;
2180753f492093da7a40141bfe083073400f518f4c68Michael Buesch	}
218139a6f4bce6b437046edf042f78f7a0529e253bffFUJITA Tomonori
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = b44_get_invariants(bp);
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err) {
2184753f492093da7a40141bfe083073400f518f4c68Michael Buesch		dev_err(sdev->dev,
21852fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches			"Problem fetching invariants of chip, aborting\n");
2186753f492093da7a40141bfe083073400f518f4c68Michael Buesch		goto err_out_powerdown;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->mii_if.dev = dev;
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->mii_if.mdio_read = b44_mii_read;
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->mii_if.mdio_write = b44_mii_write;
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->mii_if.phy_id = bp->phy_addr;
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->mii_if.phy_id_mask = 0x1f;
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->mii_if.reg_num_mask = 0x1f;
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* By default, advertise all speed/duplex settings. */
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      B44_FLAG_ADV_100HALF | B44_FLAG_ADV_100FULL);
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* By default, auto-negotiate PAUSE. */
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bp->flags |= B44_FLAG_PAUSE_AUTO;
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err) {
22052fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		dev_err(sdev->dev, "Cannot register net device, aborting\n");
2206753f492093da7a40141bfe083073400f518f4c68Michael Buesch		goto err_out_powerdown;
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2209bcf64aa379fcadd074449cbf0c049da70071b06fPaul Fertser	netif_carrier_off(dev);
2210bcf64aa379fcadd074449cbf0c049da70071b06fPaul Fertser
2211753f492093da7a40141bfe083073400f518f4c68Michael Buesch	ssb_set_drvdata(sdev, dev);
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221310badc215493a435e2dbdc691386f2650a1778deJeff Garzik	/* Chip reset provides power to the b44 MAC & PCI cores, which
22145c5131297db57b501f371ab53c40343eac6f2af7Gary Zambrano	 * is necessary for MAC register access.
221510badc215493a435e2dbdc691386f2650a1778deJeff Garzik	 */
2216fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
22175c5131297db57b501f371ab53c40343eac6f2af7Gary Zambrano
22188850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens	/* do a phy reset to test if there is an active phy */
22198850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens	if (b44_phy_reset(bp) < 0)
22208850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens		bp->phy_addr = B44_PHY_ADDR_NO_PHY;
22218850dce170b460d9e46a827a62d6d7bb7e7cfcf3Hauke Mehrtens
22227329f0d58de01878d9ce4f0be7a76e136f223eefJoe Perches	netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2226753f492093da7a40141bfe083073400f518f4c68Michael Buescherr_out_powerdown:
2227753f492093da7a40141bfe083073400f518f4c68Michael Buesch	ssb_bus_may_powerdown(sdev->bus);
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_free_dev:
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2232753f492093da7a40141bfe083073400f518f4c68Michael Bueschout:
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2236753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic void __devexit b44_remove_one(struct ssb_device *sdev)
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2238753f492093da7a40141bfe083073400f518f4c68Michael Buesch	struct net_device *dev = ssb_get_drvdata(sdev);
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2240874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu	unregister_netdev(dev);
2241e92aa634a33739478958f4109d6bd35b36d13532Michael Buesch	ssb_device_disable(sdev, 0);
2242753f492093da7a40141bfe083073400f518f4c68Michael Buesch	ssb_bus_may_powerdown(sdev->bus);
2243874a6214bc1477004a0dd6f881b078d0d6b1eae9Francois Romieu	free_netdev(dev);
2244fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	ssb_pcihost_set_power_state(sdev, PCI_D3hot);
2245753f492093da7a40141bfe083073400f518f4c68Michael Buesch	ssb_set_drvdata(sdev, NULL);
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2248753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int b44_suspend(struct ssb_device *sdev, pm_message_t state)
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2250753f492093da7a40141bfe083073400f518f4c68Michael Buesch	struct net_device *dev = ssb_get_drvdata(sdev);
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2253753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (!netif_running(dev))
2254753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return 0;
22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&bp->timer);
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
225810badc215493a435e2dbdc691386f2650a1778deJeff Garzik	spin_lock_irq(&bp->lock);
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_halt(bp);
226110badc215493a435e2dbdc691386f2650a1778deJeff Garzik	netif_carrier_off(bp->dev);
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_device_detach(bp->dev);
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_free_rings(bp);
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&bp->lock);
226646e178535836dcd7ef92f179218628d101892c59Pavel Machek
226746e178535836dcd7ef92f179218628d101892c59Pavel Machek	free_irq(dev->irq, dev);
226852cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	if (bp->flags & B44_FLAG_WOL_ENABLE) {
22695fc7d61aee1a7f7d3448f8fbccaa93371ebeecb0Michael Chan		b44_init_hw(bp, B44_PARTIAL_RESET);
227052cafd965507b7a7bb962486539f6d7422552692Gary Zambrano		b44_setup_wol(bp);
227152cafd965507b7a7bb962486539f6d7422552692Gary Zambrano	}
2272753f492093da7a40141bfe083073400f518f4c68Michael Buesch
2273fedb0eefe286a6409aa2c6c6f2353c595e68d33dMiguel Botón	ssb_pcihost_set_power_state(sdev, PCI_D3hot);
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2277753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic int b44_resume(struct ssb_device *sdev)
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2279753f492093da7a40141bfe083073400f518f4c68Michael Buesch	struct net_device *dev = ssb_get_drvdata(sdev);
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct b44 *bp = netdev_priv(dev);
228190afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov	int rc = 0;
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2283753f492093da7a40141bfe083073400f518f4c68Michael Buesch	rc = ssb_bus_powerup(sdev->bus, 0);
228490afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov	if (rc) {
2285753f492093da7a40141bfe083073400f518f4c68Michael Buesch		dev_err(sdev->dev,
2286753f492093da7a40141bfe083073400f518f4c68Michael Buesch			"Failed to powerup the bus\n");
228790afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov		return rc;
228890afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov	}
228990afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!netif_running(dev))
22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2293afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	spin_lock_irq(&bp->lock);
2294afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	b44_init_rings(bp);
2295afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	b44_init_hw(bp, B44_FULL_RESET);
2296afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	spin_unlock_irq(&bp->lock);
2297afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan
2298afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	/*
2299afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	 * As a shared interrupt, the handler can be called immediately. To be
2300afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	 * able to check the interrupt status the hardware must already be
2301afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	 * powered back on (b44_init_hw).
2302afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan	 */
230390afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov	rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
230490afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov	if (rc) {
23052fc96fff4483971aa81795382c368ea7d8100ddeJoe Perches		netdev_err(dev, "request_irq failed\n");
2306afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan		spin_lock_irq(&bp->lock);
2307afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan		b44_halt(bp);
2308afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan		b44_free_rings(bp);
2309afed4ccb0d975f1d3c98880ecf19a24f3d842394James Hogan		spin_unlock_irq(&bp->lock);
231090afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov		return rc;
231190afd0e574a1a739aeb62e30d556ebf0289389e5Dmitriy Monakhov	}
231246e178535836dcd7ef92f179218628d101892c59Pavel Machek
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_device_attach(bp->dev);
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b44_enable_ints(bp);
2316d9e2d185bf01e20339158f77c3fca00b02014912Mark Lord	netif_wake_queue(dev);
2317a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger
2318a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger	mod_timer(&bp->timer, jiffies + 1);
2319a72a8179734393ca351f6ecf8cad6841ab7e1470Stephen Hemminger
23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2323753f492093da7a40141bfe083073400f518f4c68Michael Bueschstatic struct ssb_driver b44_ssb_driver = {
23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= DRV_MODULE_NAME,
2325753f492093da7a40141bfe083073400f518f4c68Michael Buesch	.id_table	= b44_ssb_tbl,
23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= b44_init_one,
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove		= __devexit_p(b44_remove_one),
2328753f492093da7a40141bfe083073400f518f4c68Michael Buesch	.suspend	= b44_suspend,
2329753f492093da7a40141bfe083073400f518f4c68Michael Buesch	.resume		= b44_resume,
23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2332cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic inline int __init b44_pci_init(void)
2333753f492093da7a40141bfe083073400f518f4c68Michael Buesch{
2334753f492093da7a40141bfe083073400f518f4c68Michael Buesch	int err = 0;
2335753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI
2336753f492093da7a40141bfe083073400f518f4c68Michael Buesch	err = ssb_pcihost_register(&b44_pci_driver);
2337753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif
2338753f492093da7a40141bfe083073400f518f4c68Michael Buesch	return err;
2339753f492093da7a40141bfe083073400f518f4c68Michael Buesch}
2340753f492093da7a40141bfe083073400f518f4c68Michael Buesch
234164f0a836f600e9c31ffd511713ab5d328aa96ac8Nikola Pajkovskystatic inline void b44_pci_exit(void)
2342753f492093da7a40141bfe083073400f518f4c68Michael Buesch{
2343753f492093da7a40141bfe083073400f518f4c68Michael Buesch#ifdef CONFIG_B44_PCI
2344753f492093da7a40141bfe083073400f518f4c68Michael Buesch	ssb_pcihost_unregister(&b44_pci_driver);
2345753f492093da7a40141bfe083073400f518f4c68Michael Buesch#endif
2346753f492093da7a40141bfe083073400f518f4c68Michael Buesch}
2347753f492093da7a40141bfe083073400f518f4c68Michael Buesch
23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init b44_init(void)
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23509f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	unsigned int dma_desc_align_size = dma_get_cache_alignment();
2351753f492093da7a40141bfe083073400f518f4c68Michael Buesch	int err;
23529f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
23539f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville	/* Setup paramaters for syncing RX/TX DMA descriptors */
235422d4d77183f0af8b3b643544a5ae64ec6105d88bAlan Cox	dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
23559f38c636ababfb41e58c9ec1e9719492ef7f0479John W. Linville
2356753f492093da7a40141bfe083073400f518f4c68Michael Buesch	err = b44_pci_init();
2357753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (err)
2358753f492093da7a40141bfe083073400f518f4c68Michael Buesch		return err;
2359753f492093da7a40141bfe083073400f518f4c68Michael Buesch	err = ssb_driver_register(&b44_ssb_driver);
2360753f492093da7a40141bfe083073400f518f4c68Michael Buesch	if (err)
2361753f492093da7a40141bfe083073400f518f4c68Michael Buesch		b44_pci_exit();
2362753f492093da7a40141bfe083073400f518f4c68Michael Buesch	return err;
23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit b44_cleanup(void)
23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2367753f492093da7a40141bfe083073400f518f4c68Michael Buesch	ssb_driver_unregister(&b44_ssb_driver);
2368753f492093da7a40141bfe083073400f518f4c68Michael Buesch	b44_pci_exit();
23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(b44_init);
23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(b44_cleanup);
23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2374