1b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/*
2a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors * ks8842.c timberdale KS8842 ethernet driver
3b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * Copyright (c) 2009 Intel Corporation
4b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors *
5b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * This program is free software; you can redistribute it and/or modify
6b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * it under the terms of the GNU General Public License version 2 as
7b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * published by the Free Software Foundation.
8b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors *
9b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * This program is distributed in the hope that it will be useful,
10b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * but WITHOUT ANY WARRANTY; without even the implied warranty of
11b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * GNU General Public License for more details.
13b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors *
14b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * You should have received a copy of the GNU General Public License
15b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * along with this program; if not, write to the Free Software
16b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors */
18b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
19b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* Supports:
20b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors * The Micrel KS8842 behind the timberdale FPGA
2128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi * The genuine Micrel KS8841/42 device with ISA 16/32bit bus interface
22b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors */
23b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
240dc7d2b3cbfcf4ff20bdc68f563a2e52e6a2178fJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
250dc7d2b3cbfcf4ff20bdc68f563a2e52e6a2178fJoe Perches
26a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
27b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#include <linux/kernel.h>
28b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#include <linux/module.h>
29b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#include <linux/platform_device.h>
30b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#include <linux/netdevice.h>
31b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#include <linux/etherdevice.h>
32b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#include <linux/ethtool.h>
33a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors#include <linux/ks8842.h>
3494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors#include <linux/dmaengine.h>
3594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors#include <linux/dma-mapping.h>
3694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors#include <linux/scatterlist.h>
37b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
38b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define DRV_NAME "ks8842"
39b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
40b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* Timberdale specific Registers */
41db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors#define REG_TIMB_RST		0x1c
42db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors#define REG_TIMB_FIFO		0x20
43db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors#define REG_TIMB_ISR		0x24
44db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors#define REG_TIMB_IER		0x28
45db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors#define REG_TIMB_IAR		0x2C
46db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors#define REQ_TIMB_DMA_RESUME	0x30
47b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
48b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* KS8842 registers */
49b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
50b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_SELECT_BANK 0x0e
51b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
52b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 0 registers */
53b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_QRFCR	0x04
54b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
55b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 2 registers */
56b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_MARL	0x00
57b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_MARM	0x02
58b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_MARH	0x04
59b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
60b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 3 registers */
61b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_GRR		0x06
62b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
63b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 16 registers */
64b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_TXCR	0x00
65b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_TXSR	0x02
66b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_RXCR	0x04
67b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_TXMIR	0x08
68b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_RXMIR	0x0A
69b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
70b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 17 registers */
71b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_TXQCR	0x00
72b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_RXQCR	0x02
73b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_TXFDPR	0x04
74b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_RXFDPR	0x06
75b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_QMU_DATA_LO 0x08
76b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_QMU_DATA_HI 0x0A
77b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
78b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 18 registers */
79b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_IER		0x00
80b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define IRQ_LINK_CHANGE	0x8000
81b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define IRQ_TX		0x4000
82b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define IRQ_RX		0x2000
83b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define IRQ_RX_OVERRUN	0x0800
84b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define IRQ_TX_STOPPED	0x0200
85b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define IRQ_RX_STOPPED	0x0100
86b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define IRQ_RX_ERROR	0x0080
87b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define ENABLED_IRQS	(IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \
88b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
8994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors/* When running via timberdale in DMA mode, the RX interrupt should be
9094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors   enabled in the KS8842, but not in the FPGA IP, since the IP handles
9194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors   RX DMA internally.
9294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors   TX interrupts are not needed it is handled by the FPGA the driver is
9394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors   notified via DMA callbacks.
9494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors*/
9594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors#define ENABLED_IRQS_DMA_IP	(IRQ_LINK_CHANGE | IRQ_RX_STOPPED | \
9694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
9794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors#define ENABLED_IRQS_DMA	(ENABLED_IRQS_DMA_IP | IRQ_RX)
98b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_ISR		0x02
99b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_RXSR	0x04
100b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_VALID	0x8000
101b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_BROADCAST	0x80
102b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_MULTICAST	0x40
103b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_UNICAST	0x20
104b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_FRAMETYPE	0x08
105b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_TOO_LONG	0x04
106b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_RUNT	0x02
107b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_CRC_ERROR	0x01
108b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define RXSR_ERROR	(RXSR_TOO_LONG | RXSR_RUNT | RXSR_CRC_ERROR)
109b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
110b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 32 registers */
111b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_SW_ID_AND_ENABLE	0x00
112b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_SGCR1		0x02
113b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_SGCR2		0x04
114b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_SGCR3		0x06
115b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
116b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 39 registers */
117b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_MACAR1		0x00
118b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_MACAR2		0x02
119b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_MACAR3		0x04
120b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
121b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 45 registers */
122b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_P1MBCR		0x00
123b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_P1MBSR		0x02
124b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
125b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 46 registers */
126b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_P2MBCR		0x00
127b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_P2MBSR		0x02
128b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
129b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 48 registers */
130b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_P1CR2		0x02
131b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
132b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* bank 49 registers */
133b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_P1CR4		0x02
134b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors#define REG_P1SR		0x04
135b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
13628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi/* flags passed by platform_device for configuration */
13728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi#define	MICREL_KS884X		0x01	/* 0=Timeberdale(FPGA), 1=Micrel */
13828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi#define	KS884X_16BIT		0x02	/*  1=16bit, 0=32bit */
13928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
14094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors#define DMA_BUFFER_SIZE		2048
14194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
14294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstruct ks8842_tx_dma_ctl {
14394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct dma_chan *chan;
14494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct dma_async_tx_descriptor *adesc;
14594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	void *buf;
14694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct scatterlist sg;
14794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	int channel;
14894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors};
14994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
15094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstruct ks8842_rx_dma_ctl {
15194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct dma_chan *chan;
15294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct dma_async_tx_descriptor *adesc;
15394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct sk_buff  *skb;
15494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct scatterlist sg;
15594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct tasklet_struct tasklet;
15694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	int channel;
15794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors};
15894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
15994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors#define KS8842_USE_DMA(adapter) (((adapter)->dma_tx.channel != -1) && \
16094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	 ((adapter)->dma_rx.channel != -1))
16194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
162b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstruct ks8842_adapter {
163b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	void __iomem	*hw_addr;
164b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int		irq;
16528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	unsigned long	conf_flags;	/* copy of platform_device config */
166b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct tasklet_struct	tasklet;
167b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spinlock_t	lock; /* spinlock to be interrupt safe */
168cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	struct work_struct timeout_work;
169cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	struct net_device *netdev;
17094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct device *dev;
17194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_tx_dma_ctl	dma_tx;
17294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_rx_dma_ctl	dma_rx;
173b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors};
174b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
17594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_dma_rx_cb(void *data);
17694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_dma_tx_cb(void *data);
17794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
17894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic inline void ks8842_resume_dma(struct ks8842_adapter *adapter)
17994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
18094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	iowrite32(1, adapter->hw_addr + REQ_TIMB_DMA_RESUME);
18194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
18294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
183b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank)
184b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
185b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK);
186b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
187b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
188b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline void ks8842_write8(struct ks8842_adapter *adapter, u16 bank,
189b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u8 value, int offset)
190b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
191b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
192b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite8(value, adapter->hw_addr + offset);
193b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
194b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
195b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline void ks8842_write16(struct ks8842_adapter *adapter, u16 bank,
196b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 value, int offset)
197b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
198b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
199b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite16(value, adapter->hw_addr + offset);
200b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
201b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
202b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline void ks8842_enable_bits(struct ks8842_adapter *adapter, u16 bank,
203b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 bits, int offset)
204b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
205b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 reg;
206b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
207b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	reg = ioread16(adapter->hw_addr + offset);
208b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	reg |= bits;
209b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite16(reg, adapter->hw_addr + offset);
210b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
211b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
212b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline void ks8842_clear_bits(struct ks8842_adapter *adapter, u16 bank,
213b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 bits, int offset)
214b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
215b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 reg;
216b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
217b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	reg = ioread16(adapter->hw_addr + offset);
218b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	reg &= ~bits;
219b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite16(reg, adapter->hw_addr + offset);
220b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
221b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
222b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline void ks8842_write32(struct ks8842_adapter *adapter, u16 bank,
223b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u32 value, int offset)
224b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
225b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
226b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite32(value, adapter->hw_addr + offset);
227b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
228b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
229b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline u8 ks8842_read8(struct ks8842_adapter *adapter, u16 bank,
230b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int offset)
231b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
232b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
233b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return ioread8(adapter->hw_addr + offset);
234b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
235b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
236b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline u16 ks8842_read16(struct ks8842_adapter *adapter, u16 bank,
237b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int offset)
238b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
239b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
240b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return ioread16(adapter->hw_addr + offset);
241b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
242b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
243b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank,
244b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int offset)
245b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
246b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_select_bank(adapter, bank);
247b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return ioread32(adapter->hw_addr + offset);
248b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
249b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
250b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_reset(struct ks8842_adapter *adapter)
251b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
25228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	if (adapter->conf_flags & MICREL_KS884X) {
25328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 3, 1, REG_GRR);
25428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		msleep(10);
25528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		iowrite16(0, adapter->hw_addr + REG_GRR);
25628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	} else {
25728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		/* The KS8842 goes haywire when doing softare reset
25828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		* a work around in the timberdale IP is implemented to
25928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		* do a hardware reset instead
26028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 3, 1, REG_GRR);
26128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		msleep(10);
26228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		iowrite16(0, adapter->hw_addr + REG_GRR);
26328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		*/
26428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST);
26528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		msleep(20);
26628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	}
267b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
268b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
269b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_update_link_status(struct net_device *netdev,
270b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter)
271b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
272b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* check the status of the link */
273b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (ks8842_read16(adapter, 45, REG_P1MBSR) & 0x4) {
274b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		netif_carrier_on(netdev);
275b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		netif_wake_queue(netdev);
276b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	} else {
277b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		netif_stop_queue(netdev);
278b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		netif_carrier_off(netdev);
279b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
280b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
281b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
282b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_enable_tx(struct ks8842_adapter *adapter)
283b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
284b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_bits(adapter, 16, 0x01, REG_TXCR);
285b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
286b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
287b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_disable_tx(struct ks8842_adapter *adapter)
288b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
289b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_clear_bits(adapter, 16, 0x01, REG_TXCR);
290b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
291b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
292b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_enable_rx(struct ks8842_adapter *adapter)
293b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
294b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_bits(adapter, 16, 0x01, REG_RXCR);
295b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
296b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
297b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_disable_rx(struct ks8842_adapter *adapter)
298b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
299b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_clear_bits(adapter, 16, 0x01, REG_RXCR);
300b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
301b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
302b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_reset_hw(struct ks8842_adapter *adapter)
303b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
304b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* reset the HW */
305b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_reset(adapter);
306b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
307b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* Enable QMU Transmit flow control / transmit padding / Transmit CRC */
308b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 16, 0x000E, REG_TXCR);
309b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
310b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* enable the receiver, uni + multi + broadcast + flow ctrl
311b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		+ crc strip */
312b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400,
313b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		REG_RXCR);
314b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
315b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* TX frame pointer autoincrement */
316b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR);
317b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
318b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* RX frame pointer autoincrement */
319b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR);
320b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
321b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* RX 2 kb high watermark */
322b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 0, 0x1000, REG_QRFCR);
323b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
32425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* aggressive back off in half duplex */
325b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1);
326b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
327b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* enable no excessive collison drop */
328b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2);
329b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
330b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* Enable port 1 force flow control / back pressure / transmit / recv */
331b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2);
332b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
333b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* restart port auto-negotiation */
334b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4);
33528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
336b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* Enable the transmitter */
337b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_tx(adapter);
338b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
339b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* Enable the receiver */
340b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_rx(adapter);
341b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
342b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* clear all interrupts */
343b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 18, 0xffff, REG_ISR);
344b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
345b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* enable interrupts */
34694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter)) {
34794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		/* When running in DMA Mode the RX interrupt is not enabled in
34894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		   timberdale because RX data is received by DMA callbacks
34994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		   it must still be enabled in the KS8842 because it indicates
35094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		   to timberdale when there is RX data for it's DMA FIFOs */
35194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		iowrite16(ENABLED_IRQS_DMA_IP, adapter->hw_addr + REG_TIMB_IER);
35294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
35394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	} else {
35494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		if (!(adapter->conf_flags & MICREL_KS884X))
35594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			iowrite16(ENABLED_IRQS,
35694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors				adapter->hw_addr + REG_TIMB_IER);
35794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
35894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
359b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* enable the switch */
360b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE);
361b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
362b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
363b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest)
364b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
365b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int i;
366b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 mac;
367b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
368b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	for (i = 0; i < ETH_ALEN; i++)
369b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i);
370b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
37128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	if (adapter->conf_flags & MICREL_KS884X) {
37228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		/*
37328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		the sequence of saving mac addr between MAC and Switch is
37428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		different.
37528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		*/
37628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
37728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARL);
37828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR3);
37928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARM);
38028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR2);
38128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARH);
38228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR1);
38328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	} else {
38428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
38528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		/* make sure the switch port uses the same MAC as the QMU */
38628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARL);
38728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR1);
38828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARM);
38928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR2);
39028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARH);
39128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR3);
39228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	}
393b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
394b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
395a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjforsstatic void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
396a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors{
397a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	unsigned long flags;
398a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	unsigned i;
399a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors
400a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	spin_lock_irqsave(&adapter->lock, flags);
401a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	for (i = 0; i < ETH_ALEN; i++) {
402a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors		ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
40328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		if (!(adapter->conf_flags & MICREL_KS884X))
40428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
40528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				REG_MACAR1 + i);
40628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	}
40728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
40828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	if (adapter->conf_flags & MICREL_KS884X) {
40928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		/*
41028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		the sequence of saving mac addr between MAC and Switch is
41128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		different.
41228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		*/
41328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
41428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		u16 mac;
41528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
41628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARL);
41728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR3);
41828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARM);
41928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR2);
42028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		mac = ks8842_read16(adapter, 2, REG_MARH);
42128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 39, mac, REG_MACAR1);
422a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	}
423a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	spin_unlock_irqrestore(&adapter->lock, flags);
424a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors}
425a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors
426b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter)
427b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
428b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff;
429b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
430b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
43194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev)
43294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
43394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
43494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_tx_dma_ctl *ctl = &adapter->dma_tx;
43594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	u8 *buf = ctl->buf;
43694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
43794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (ctl->adesc) {
43894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		netdev_dbg(netdev, "%s: TX ongoing\n", __func__);
43994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		/* transfer ongoing */
44094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		return NETDEV_TX_BUSY;
44194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
44294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
44394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	sg_dma_len(&ctl->sg) = skb->len + sizeof(u32);
44494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
44594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* copy data to the TX buffer */
44694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* the control word, enable IRQ, port 1 and the length */
44794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	*buf++ = 0x00;
44894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	*buf++ = 0x01; /* Port 1 */
44994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	*buf++ = skb->len & 0xff;
45094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	*buf++ = (skb->len >> 8) & 0xff;
45194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	skb_copy_from_linear_data(skb, buf, skb->len);
45294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
45394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dma_sync_single_range_for_device(adapter->dev,
45494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_dma_address(&ctl->sg), 0, sg_dma_len(&ctl->sg),
45594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		DMA_TO_DEVICE);
45694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
45794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* make sure the length is a multiple of 4 */
45894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (sg_dma_len(&ctl->sg) % 4)
45994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4;
46094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
46116052827d98fbc13c31ebad560af4bd53e2b4dd5Alexandre Bounine	ctl->adesc = dmaengine_prep_slave_sg(ctl->chan,
4628af11fd3f013892c918a39acb691bc7469c5ad77Vinod Koul		&ctl->sg, 1, DMA_MEM_TO_DEV,
46394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
46494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (!ctl->adesc)
46594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		return NETDEV_TX_BUSY;
46694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
46794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ctl->adesc->callback_param = netdev;
46894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ctl->adesc->callback = ks8842_dma_tx_cb;
46994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ctl->adesc->tx_submit(ctl->adesc);
47094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
47194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev->stats.tx_bytes += skb->len;
47294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
47394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dev_kfree_skb(skb);
47494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
47594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	return NETDEV_TX_OK;
47694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
47794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
478b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
479b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
480b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
481b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int len = skb->len;
482b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
483a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n",
484b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		__func__, skb->len, skb->head, skb->data,
485b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		skb_tail_pointer(skb), skb_end_pointer(skb));
486b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
487b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* check FIFO buffer space, we need space for CRC and command bits */
488b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (ks8842_tx_fifo_space(adapter) < len + 8)
489b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		return NETDEV_TX_BUSY;
490b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
49128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	if (adapter->conf_flags & KS884X_16BIT) {
49228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		u16 *ptr16 = (u16 *)skb->data;
49328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 17, 0x8000 | 0x100, REG_QMU_DATA_LO);
49428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write16(adapter, 17, (u16)len, REG_QMU_DATA_HI);
49528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		netdev->stats.tx_bytes += len;
49628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
49728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		/* copy buffer */
49828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		while (len > 0) {
49928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_LO);
50028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_HI);
50128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			len -= sizeof(u32);
50228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		}
50328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	} else {
50428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
50528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		u32 *ptr = (u32 *)skb->data;
50628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		u32 ctrl;
50728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		/* the control word, enable IRQ, port 1 and the length */
50828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ctrl = 0x8000 | 0x100 | (len << 16);
50928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO);
510b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
51128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		netdev->stats.tx_bytes += len;
512b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
51328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		/* copy buffer */
51428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		while (len > 0) {
51528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO);
51628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			len -= sizeof(u32);
51728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			ptr++;
51828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		}
519b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
520b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
521b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* enqueue packet */
522b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 17, 1, REG_TXQCR);
523b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
524b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	dev_kfree_skb(skb);
525b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
526b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return NETDEV_TX_OK;
527b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
528b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
52994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_update_rx_err_counters(struct net_device *netdev, u32 status)
53094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
53194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev_dbg(netdev, "RX error, status: %x\n", status);
53294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
53394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev->stats.rx_errors++;
53494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (status & RXSR_TOO_LONG)
53594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		netdev->stats.rx_length_errors++;
53694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (status & RXSR_CRC_ERROR)
53794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		netdev->stats.rx_crc_errors++;
53894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (status & RXSR_RUNT)
53994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		netdev->stats.rx_frame_errors++;
54094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
54194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
54294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_update_rx_counters(struct net_device *netdev, u32 status,
54394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	int len)
54494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
54594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev_dbg(netdev, "RX packet, len: %d\n", len);
54694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
54794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev->stats.rx_packets++;
54894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev->stats.rx_bytes += len;
54994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (status & RXSR_MULTICAST)
55094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		netdev->stats.multicast++;
55194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
55294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
55394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic int __ks8842_start_new_rx_dma(struct net_device *netdev)
55494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
55594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
55694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
55794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct scatterlist *sg = &ctl->sg;
55894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	int err;
55994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
56094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ctl->skb = netdev_alloc_skb(netdev, DMA_BUFFER_SIZE);
56194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (ctl->skb) {
56294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_init_table(sg, 1);
56394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_dma_address(sg) = dma_map_single(adapter->dev,
56494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			ctl->skb->data, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
56594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		err = dma_mapping_error(adapter->dev, sg_dma_address(sg));
56694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		if (unlikely(err)) {
56794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			sg_dma_address(sg) = 0;
56894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			goto out;
56994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		}
57094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
57194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_dma_len(sg) = DMA_BUFFER_SIZE;
57294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
57316052827d98fbc13c31ebad560af4bd53e2b4dd5Alexandre Bounine		ctl->adesc = dmaengine_prep_slave_sg(ctl->chan,
5748af11fd3f013892c918a39acb691bc7469c5ad77Vinod Koul			sg, 1, DMA_DEV_TO_MEM,
57594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
57694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
57794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		if (!ctl->adesc)
57894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			goto out;
57994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
58094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ctl->adesc->callback_param = netdev;
58194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ctl->adesc->callback = ks8842_dma_rx_cb;
58294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ctl->adesc->tx_submit(ctl->adesc);
58394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	} else {
58494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		err = -ENOMEM;
58594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_dma_address(sg) = 0;
58694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		goto out;
58794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
58894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
58994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	return err;
59094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsout:
59194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (sg_dma_address(sg))
59294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		dma_unmap_single(adapter->dev, sg_dma_address(sg),
59394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
59494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	sg_dma_address(sg) = 0;
59594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (ctl->skb)
59694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		dev_kfree_skb(ctl->skb);
59794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
59894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ctl->skb = NULL;
59994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
60094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	printk(KERN_ERR DRV_NAME": Failed to start RX DMA: %d\n", err);
60194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	return err;
60294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
60394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
60494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_rx_frame_dma_tasklet(unsigned long arg)
60594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
60694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct net_device *netdev = (struct net_device *)arg;
60794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
60894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
60994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct sk_buff *skb = ctl->skb;
61094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dma_addr_t addr = sg_dma_address(&ctl->sg);
61194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	u32 status;
61294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
61394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ctl->adesc = NULL;
61494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
61594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* kick next transfer going */
61694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	__ks8842_start_new_rx_dma(netdev);
61794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
61894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* now handle the data we got */
61994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dma_unmap_single(adapter->dev, addr, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
62094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
62194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	status = *((u32 *)skb->data);
62294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
62394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev_dbg(netdev, "%s - rx_data: status: %x\n",
62494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		__func__, status & 0xffff);
62594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
62694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* check the status */
62794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
62894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		int len = (status >> 16) & 0x7ff;
62994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
63094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_update_rx_counters(netdev, status, len);
63194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
63294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		/* reserve 4 bytes which is the status word */
63394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		skb_reserve(skb, 4);
63494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		skb_put(skb, len);
63594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
63694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		skb->protocol = eth_type_trans(skb, netdev);
63794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		netif_rx(skb);
63894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	} else {
63994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_update_rx_err_counters(netdev, status);
64094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		dev_kfree_skb(skb);
64194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
64294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
64394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
644b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic void ks8842_rx_frame(struct net_device *netdev,
645b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter)
646b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
64728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	u32 status;
64828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	int len;
649b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
65028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	if (adapter->conf_flags & KS884X_16BIT) {
651e2df8b7f6665075f7fe93613897117743c7bf0baDavid S. Miller		status = ks8842_read16(adapter, 17, REG_QMU_DATA_LO);
652e2df8b7f6665075f7fe93613897117743c7bf0baDavid S. Miller		len = ks8842_read16(adapter, 17, REG_QMU_DATA_HI);
65328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		netdev_dbg(netdev, "%s - rx_data: status: %x\n",
654e2df8b7f6665075f7fe93613897117743c7bf0baDavid S. Miller			   __func__, status);
65528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	} else {
65628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
65728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		len = (status >> 16) & 0x7ff;
65828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		status &= 0xffff;
65928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi		netdev_dbg(netdev, "%s - rx_data: status: %x\n",
66028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			   __func__, status);
66128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	}
662b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
663b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* check the status */
664b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
665b10cec8a4e8167075b9e1ff3f05419769e7f381aDennis Aberilla		struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len + 3);
666b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
667b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		if (skb) {
668b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
66994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			ks8842_update_rx_counters(netdev, status, len);
670b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
67128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			if (adapter->conf_flags & KS884X_16BIT) {
67228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				u16 *data16 = (u16 *)skb_put(skb, len);
67328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				ks8842_select_bank(adapter, 17);
67428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				while (len > 0) {
67528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi					*data16++ = ioread16(adapter->hw_addr +
67628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi						REG_QMU_DATA_LO);
67728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi					*data16++ = ioread16(adapter->hw_addr +
67828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi						REG_QMU_DATA_HI);
67928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi					len -= sizeof(u32);
68028bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				}
68128bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi			} else {
68228bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				u32 *data = (u32 *)skb_put(skb, len);
68328bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
68428bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				ks8842_select_bank(adapter, 17);
68528bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				while (len > 0) {
68628bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi					*data++ = ioread32(adapter->hw_addr +
68728bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi						REG_QMU_DATA_LO);
68828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi					len -= sizeof(u32);
68928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi				}
690b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors			}
691b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors			skb->protocol = eth_type_trans(skb, netdev);
692b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors			netif_rx(skb);
693b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		} else
694b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors			netdev->stats.rx_dropped++;
69594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	} else
69694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_update_rx_err_counters(netdev, status);
697b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
698b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* set high watermark to 3K */
699b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR);
700b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
701b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* release the frame */
702b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 17, 0x01, REG_RXQCR);
703b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
704b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* set high watermark to 2K */
705b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_enable_bits(adapter, 0, 1 << 12, REG_QRFCR);
706b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
707b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
708b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsvoid ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter)
709b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
710b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
711a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s Entry - rx_data: %d\n", __func__, rx_data);
712b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	while (rx_data) {
713b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_rx_frame(netdev, adapter);
714b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
715b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
716b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
717b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
718b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsvoid ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter)
719b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
720b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 sr = ks8842_read16(adapter, 16, REG_TXSR);
721a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s - entry, sr: %x\n", __func__, sr);
722b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	netdev->stats.tx_packets++;
723b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (netif_queue_stopped(netdev))
724b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		netif_wake_queue(netdev);
725b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
726b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
727b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsvoid ks8842_handle_rx_overrun(struct net_device *netdev,
728b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter)
729b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
730a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s: entry\n", __func__);
731b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	netdev->stats.rx_errors++;
732b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	netdev->stats.rx_fifo_errors++;
733b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
734b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
735b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsvoid ks8842_tasklet(unsigned long arg)
736b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
737b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct net_device *netdev = (struct net_device *)arg;
738b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
739b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 isr;
740b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	unsigned long flags;
741b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 entry_bank;
742b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
743b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* read current bank to be able to set it back */
744b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spin_lock_irqsave(&adapter->lock, flags);
745b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK);
746b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spin_unlock_irqrestore(&adapter->lock, flags);
747b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
748b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	isr = ks8842_read16(adapter, 18, REG_ISR);
749a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
750b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
75194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* when running in DMA mode, do not ack RX interrupts, it is handled
75294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	   internally by timberdale, otherwise it's DMA FIFO:s would stop
75394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	*/
75494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter))
75594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		isr &= ~IRQ_RX;
75694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
757b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* Ack */
758b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 18, isr, REG_ISR);
759b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
760db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors	if (!(adapter->conf_flags & MICREL_KS884X))
761db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors		/* Ack in the timberdale IP as well */
762db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors		iowrite32(0x1, adapter->hw_addr + REG_TIMB_IAR);
763db5824dd3d632acd79094b81e07288ba05ae2cc1Richard Röjfors
764b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (!netif_running(netdev))
765b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		return;
766b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
767b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (isr & IRQ_LINK_CHANGE)
768b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_update_link_status(netdev, adapter);
769b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
77094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* should not get IRQ_RX when running DMA mode */
77194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (isr & (IRQ_RX | IRQ_RX_ERROR) && !KS8842_USE_DMA(adapter))
772b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_handle_rx(netdev, adapter);
773b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
77494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* should only happen when in PIO mode */
775b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (isr & IRQ_TX)
776b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_handle_tx(netdev, adapter);
777b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
778b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (isr & IRQ_RX_OVERRUN)
779b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_handle_rx_overrun(netdev, adapter);
780b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
781b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (isr & IRQ_TX_STOPPED) {
782b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_disable_tx(adapter);
783b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_enable_tx(adapter);
784b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
785b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
786b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (isr & IRQ_RX_STOPPED) {
787b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_disable_rx(adapter);
788b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ks8842_enable_rx(adapter);
789b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
790b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
791b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* re-enable interrupts, put back the bank selection register */
792b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spin_lock_irqsave(&adapter->lock, flags);
79394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter))
79494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
79594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	else
79694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
797b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
79894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
79994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* Make sure timberdale continues DMA operations, they are stopped while
80094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	   we are handling the ks8842 because we might change bank */
80194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter))
80294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_resume_dma(adapter);
80394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
804b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spin_unlock_irqrestore(&adapter->lock, flags);
805b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
806b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
807b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic irqreturn_t ks8842_irq(int irq, void *devid)
808b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
809a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	struct net_device *netdev = devid;
810a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
811b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 isr;
812b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK);
813b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	irqreturn_t ret = IRQ_NONE;
814b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
815b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	isr = ks8842_read16(adapter, 18, REG_ISR);
816a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
817b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
818b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (isr) {
81994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		if (KS8842_USE_DMA(adapter))
82094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			/* disable all but RX IRQ, since the FPGA relies on it*/
82194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			ks8842_write16(adapter, 18, IRQ_RX, REG_IER);
82294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		else
82394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			/* disable IRQ */
82494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			ks8842_write16(adapter, 18, 0x00, REG_IER);
825b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
826b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		/* schedule tasklet */
827b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		tasklet_schedule(&adapter->tasklet);
828b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
829b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		ret = IRQ_HANDLED;
830b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
831b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
832b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
833b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
83494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* After an interrupt, tell timberdale to continue DMA operations.
83594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	   DMA is disabled while we are handling the ks8842 because we might
83694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	   change bank */
83794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ks8842_resume_dma(adapter);
83894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
839b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return ret;
840b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
841b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
84294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_dma_rx_cb(void *data)
84394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
84494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct net_device	*netdev = data;
84594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_adapter	*adapter = netdev_priv(netdev);
84694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
84794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev_dbg(netdev, "RX DMA finished\n");
84894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* schedule tasklet */
84994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (adapter->dma_rx.adesc)
85094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		tasklet_schedule(&adapter->dma_rx.tasklet);
85194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
85294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
85394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_dma_tx_cb(void *data)
85494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
85594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct net_device		*netdev = data;
85694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_adapter		*adapter = netdev_priv(netdev);
85794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_tx_dma_ctl	*ctl = &adapter->dma_tx;
85894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
85994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev_dbg(netdev, "TX DMA finished\n");
86094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
86194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (!ctl->adesc)
86294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		return;
86394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
86494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	netdev->stats.tx_packets++;
86594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ctl->adesc = NULL;
86694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
86794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (netif_queue_stopped(netdev))
86894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		netif_wake_queue(netdev);
86994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
87094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
87194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_stop_dma(struct ks8842_adapter *adapter)
87294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
87394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
87494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
87594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
87694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	tx_ctl->adesc = NULL;
87794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (tx_ctl->chan)
87894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		tx_ctl->chan->device->device_control(tx_ctl->chan,
87994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			DMA_TERMINATE_ALL, 0);
88094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
88194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	rx_ctl->adesc = NULL;
88294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (rx_ctl->chan)
88394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		rx_ctl->chan->device->device_control(rx_ctl->chan,
88494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			DMA_TERMINATE_ALL, 0);
88594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
88694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (sg_dma_address(&rx_ctl->sg))
88794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		dma_unmap_single(adapter->dev, sg_dma_address(&rx_ctl->sg),
88894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
88994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	sg_dma_address(&rx_ctl->sg) = 0;
89094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
89194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dev_kfree_skb(rx_ctl->skb);
89294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	rx_ctl->skb = NULL;
89394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
89494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
89594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic void ks8842_dealloc_dma_bufs(struct ks8842_adapter *adapter)
89694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
89794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
89894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
89994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
90094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ks8842_stop_dma(adapter);
90194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
90294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (tx_ctl->chan)
90394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		dma_release_channel(tx_ctl->chan);
90494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	tx_ctl->chan = NULL;
90594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
90694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (rx_ctl->chan)
90794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		dma_release_channel(rx_ctl->chan);
90894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	rx_ctl->chan = NULL;
90994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
91094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	tasklet_kill(&rx_ctl->tasklet);
91194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
91294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (sg_dma_address(&tx_ctl->sg))
91394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		dma_unmap_single(adapter->dev, sg_dma_address(&tx_ctl->sg),
91494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			DMA_BUFFER_SIZE, DMA_TO_DEVICE);
91594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	sg_dma_address(&tx_ctl->sg) = 0;
91694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
91794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	kfree(tx_ctl->buf);
91894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	tx_ctl->buf = NULL;
91994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
92094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
92194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic bool ks8842_dma_filter_fn(struct dma_chan *chan, void *filter_param)
92294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
923bd280635825a2b3981da63a54e38de97e87231b3David S. Miller	return chan->chan_id == (long)filter_param;
92494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
92594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
92694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforsstatic int ks8842_alloc_dma_bufs(struct net_device *netdev)
92794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors{
92894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
92994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
93094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
93194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	int err;
93294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
93394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dma_cap_mask_t mask;
93494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
93594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dma_cap_zero(mask);
93694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dma_cap_set(DMA_SLAVE, mask);
93794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	dma_cap_set(DMA_PRIVATE, mask);
93894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
93994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	sg_init_table(&tx_ctl->sg, 1);
94094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
94194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	tx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
942bd280635825a2b3981da63a54e38de97e87231b3David S. Miller					   (void *)(long)tx_ctl->channel);
94394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (!tx_ctl->chan) {
94494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		err = -ENODEV;
94594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		goto err;
94694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
94794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
94894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* allocate DMA buffer */
94994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	tx_ctl->buf = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
95094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (!tx_ctl->buf) {
95194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		err = -ENOMEM;
95294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		goto err;
95394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
95494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
95594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev,
95694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE);
95794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	err = dma_mapping_error(adapter->dev,
95894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_dma_address(&tx_ctl->sg));
95994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (err) {
96094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		sg_dma_address(&tx_ctl->sg) = 0;
96194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		goto err;
96294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
96394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
96494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	rx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
965bd280635825a2b3981da63a54e38de97e87231b3David S. Miller					   (void *)(long)rx_ctl->channel);
96694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (!rx_ctl->chan) {
96794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		err = -ENODEV;
96894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		goto err;
96994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
97094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
97194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	tasklet_init(&rx_ctl->tasklet, ks8842_rx_frame_dma_tasklet,
97294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		(unsigned long)netdev);
97394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
97494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	return 0;
97594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjforserr:
97694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	ks8842_dealloc_dma_bufs(adapter);
97794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	return err;
97894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors}
979b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
980b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors/* Netdevice operations */
981b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
982b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic int ks8842_open(struct net_device *netdev)
983b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
984b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
985b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int err;
986b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
987a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s - entry\n", __func__);
988b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
98994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter)) {
99094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		err = ks8842_alloc_dma_bufs(netdev);
99194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
99294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		if (!err) {
99394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			/* start RX dma */
99494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			err = __ks8842_start_new_rx_dma(netdev);
99594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			if (err)
99694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors				ks8842_dealloc_dma_bufs(adapter);
99794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		}
99894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
99994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		if (err) {
100094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			printk(KERN_WARNING DRV_NAME
100194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors				": Failed to initiate DMA, running PIO\n");
100294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			ks8842_dealloc_dma_bufs(adapter);
100394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			adapter->dma_rx.channel = -1;
100494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			adapter->dma_tx.channel = -1;
100594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		}
100694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
100794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
1008b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* reset the HW */
1009b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_reset_hw(adapter);
1010b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1011a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	ks8842_write_mac_addr(adapter, netdev->dev_addr);
1012a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors
1013b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_update_link_status(netdev, adapter);
1014b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1015b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME,
1016a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors		netdev);
1017b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (err) {
10180dc7d2b3cbfcf4ff20bdc68f563a2e52e6a2178fJoe Perches		pr_err("Failed to request IRQ: %d: %d\n", adapter->irq, err);
1019b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		return err;
1020b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
1021b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1022b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return 0;
1023b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
1024b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1025b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic int ks8842_close(struct net_device *netdev)
1026b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
1027b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
1028b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1029a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s - entry\n", __func__);
1030b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1031cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	cancel_work_sync(&adapter->timeout_work);
1032cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors
103394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter))
103494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_dealloc_dma_bufs(adapter);
103594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
1036b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* free the irq */
1037a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	free_irq(adapter->irq, netdev);
1038b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1039b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* disable the switch */
1040b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE);
1041b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1042b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return 0;
1043b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
1044b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
104561357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t ks8842_xmit_frame(struct sk_buff *skb,
104661357325f377889a1daffa14962d705dc814dd0eStephen Hemminger				     struct net_device *netdev)
1047b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
1048b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int ret;
1049b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
1050b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1051a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s: entry\n", __func__);
1052b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
105394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter)) {
105494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		unsigned long flags;
105594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ret = ks8842_tx_frame_dma(skb, netdev);
105694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		/* for now only allow one transfer at the time */
105794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		spin_lock_irqsave(&adapter->lock, flags);
105894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		if (adapter->dma_tx.adesc)
105994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors			netif_stop_queue(netdev);
106094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		spin_unlock_irqrestore(&adapter->lock, flags);
106194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		return ret;
106294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
106394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
1064b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ret = ks8842_tx_frame(skb, netdev);
1065b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1066b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (ks8842_tx_fifo_space(adapter) <  netdev->mtu + 8)
1067b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		netif_stop_queue(netdev);
1068b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1069b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return ret;
1070b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
1071b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1072b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic int ks8842_set_mac(struct net_device *netdev, void *p)
1073b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
1074b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
1075b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct sockaddr *addr = p;
1076b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	char *mac = (u8 *)addr->sa_data;
1077b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1078a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s: entry\n", __func__);
1079b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1080b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (!is_valid_ether_addr(addr->sa_data))
1081b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		return -EADDRNOTAVAIL;
1082b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
10837ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka	netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
1084b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	memcpy(netdev->dev_addr, mac, netdev->addr_len);
1085b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1086a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	ks8842_write_mac_addr(adapter, mac);
1087b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return 0;
1088b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
1089b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1090cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjforsstatic void ks8842_tx_timeout_work(struct work_struct *work)
1091b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
1092cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	struct ks8842_adapter *adapter =
1093cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors		container_of(work, struct ks8842_adapter, timeout_work);
1094cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	struct net_device *netdev = adapter->netdev;
1095b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	unsigned long flags;
1096b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1097a99db196db1166a2159add4a3013e5df0ea126faRichard Röjfors	netdev_dbg(netdev, "%s: entry\n", __func__);
1098b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1099b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spin_lock_irqsave(&adapter->lock, flags);
110094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
110194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter))
110294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		ks8842_stop_dma(adapter);
110394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
1104b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	/* disable interrupts */
1105b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 18, 0, REG_IER);
1106b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
1107cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors
1108cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	netif_stop_queue(netdev);
1109cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors
1110b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spin_unlock_irqrestore(&adapter->lock, flags);
1111b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1112b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_reset_hw(adapter);
1113b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1114a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	ks8842_write_mac_addr(adapter, netdev->dev_addr);
1115a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors
1116b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	ks8842_update_link_status(netdev, adapter);
111794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
111894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (KS8842_USE_DMA(adapter))
111994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		__ks8842_start_new_rx_dma(netdev);
1120b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
1121b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1122cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjforsstatic void ks8842_tx_timeout(struct net_device *netdev)
1123cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors{
1124cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
1125cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors
1126cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	netdev_dbg(netdev, "%s: entry\n", __func__);
1127cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors
1128cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	schedule_work(&adapter->timeout_work);
1129cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors}
1130cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors
1131b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic const struct net_device_ops ks8842_netdev_ops = {
1132b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.ndo_open		= ks8842_open,
1133b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.ndo_stop		= ks8842_close,
1134b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.ndo_start_xmit		= ks8842_xmit_frame,
1135b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.ndo_set_mac_address	= ks8842_set_mac,
1136b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.ndo_tx_timeout 	= ks8842_tx_timeout,
1137b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.ndo_validate_addr	= eth_validate_addr
1138b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors};
1139b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
11400fc0b732eaa38beb93a6fb62f77c7bd9622c76ecStephen Hemmingerstatic const struct ethtool_ops ks8842_ethtool_ops = {
1141b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.get_link		= ethtool_op_get_link,
1142b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors};
1143b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1144b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic int __devinit ks8842_probe(struct platform_device *pdev)
1145b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
1146b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	int err = -ENOMEM;
1147b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct resource *iomem;
1148b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct net_device *netdev;
1149b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter;
11503271d382c3ffe61ef3d059ef47e635dbe031030eSamuel Ortiz	struct ks8842_platform_data *pdata = pdev->dev.platform_data;
1151b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	u16 id;
1152a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	unsigned i;
1153b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1154b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1155b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME))
1156b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		goto err_mem_region;
1157b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1158b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	netdev = alloc_etherdev(sizeof(struct ks8842_adapter));
1159b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (!netdev)
1160b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		goto err_alloc_etherdev;
1161b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1162b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	SET_NETDEV_DEV(netdev, &pdev->dev);
1163b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1164b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	adapter = netdev_priv(netdev);
1165cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	adapter->netdev = netdev;
1166cc88e450ad14a79fd2d083f0827607499cf1ef51Richard Röjfors	INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work);
1167b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
116828bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi	adapter->conf_flags = iomem->flags;
116928bd620c7a1244e59459d6293ca11f162e0a67b9David J. Choi
1170b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (!adapter->hw_addr)
1171b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		goto err_ioremap;
1172b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1173b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	adapter->irq = platform_get_irq(pdev, 0);
1174b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (adapter->irq < 0) {
1175b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		err = adapter->irq;
1176b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		goto err_get_irq;
1177b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	}
1178b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
117994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	adapter->dev = (pdev->dev.parent) ? pdev->dev.parent : &pdev->dev;
118094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
118194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	/* DMA is only supported when accessed via timberdale */
118294fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	if (!(adapter->conf_flags & MICREL_KS884X) && pdata &&
118394fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		(pdata->tx_dma_channel != -1) &&
118494fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		(pdata->rx_dma_channel != -1)) {
118594fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		adapter->dma_rx.channel = pdata->rx_dma_channel;
118694fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		adapter->dma_tx.channel = pdata->tx_dma_channel;
118794fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	} else {
118894fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		adapter->dma_rx.channel = -1;
118994fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors		adapter->dma_tx.channel = -1;
119094fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors	}
119194fe8c683cea97fe2c59a5f0dc206aa329c5763cRichard Röjfors
1192b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev);
1193b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	spin_lock_init(&adapter->lock);
1194b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1195b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	netdev->netdev_ops = &ks8842_netdev_ops;
1196b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	netdev->ethtool_ops = &ks8842_ethtool_ops;
1197b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1198a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	/* Check if a mac address was given */
1199a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	i = netdev->addr_len;
1200a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	if (pdata) {
1201a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors		for (i = 0; i < netdev->addr_len; i++)
1202a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors			if (pdata->macaddr[i] != 0)
1203a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors				break;
1204a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors
1205a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors		if (i < netdev->addr_len)
1206a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors			/* an address was passed, use it */
1207a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors			memcpy(netdev->dev_addr, pdata->macaddr,
1208a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors				netdev->addr_len);
1209a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	}
1210a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors
1211a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	if (i == netdev->addr_len) {
1212a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors		ks8842_read_mac_addr(adapter, netdev->dev_addr);
1213a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors
1214a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors		if (!is_valid_ether_addr(netdev->dev_addr))
12157ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka			eth_hw_addr_random(netdev);
1216a1aa8822d577c8714f8d343eea028befbab3da9dRichard Röjfors	}
1217b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1218b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	id = ks8842_read16(adapter, 32, REG_SW_ID_AND_ENABLE);
1219b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1220b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	strcpy(netdev->name, "eth%d");
1221b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	err = register_netdev(netdev);
1222b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	if (err)
1223b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		goto err_register;
1224b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1225b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	platform_set_drvdata(pdev, netdev);
1226b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
12270dc7d2b3cbfcf4ff20bdc68f563a2e52e6a2178fJoe Perches	pr_info("Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n",
1228b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		(id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7);
1229b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1230b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return 0;
1231b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1232b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforserr_register:
1233b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforserr_get_irq:
1234b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iounmap(adapter->hw_addr);
1235b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforserr_ioremap:
1236b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	free_netdev(netdev);
1237b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforserr_alloc_etherdev:
1238b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	release_mem_region(iomem->start, resource_size(iomem));
1239b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforserr_mem_region:
1240b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return err;
1241b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
1242b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1243b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic int __devexit ks8842_remove(struct platform_device *pdev)
1244b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors{
1245b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct net_device *netdev = platform_get_drvdata(pdev);
1246b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct ks8842_adapter *adapter = netdev_priv(netdev);
1247b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1248b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1249b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	unregister_netdev(netdev);
1250b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	tasklet_kill(&adapter->tasklet);
1251b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	iounmap(adapter->hw_addr);
1252b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	free_netdev(netdev);
1253b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	release_mem_region(iomem->start, resource_size(iomem));
1254b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	platform_set_drvdata(pdev, NULL);
1255b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	return 0;
1256b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors}
1257b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1258b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1259b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjforsstatic struct platform_driver ks8842_platform_driver = {
1260b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.driver = {
1261b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		.name	= DRV_NAME,
1262b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors		.owner	= THIS_MODULE,
1263b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	},
1264b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.probe		= ks8842_probe,
1265b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors	.remove		= ks8842_remove,
1266b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors};
1267b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1268db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(ks8842_platform_driver);
1269b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1270b07878e5471a8c880cb3cffee3a73048f38d2001Richard RšöjforsMODULE_DESCRIPTION("Timberdale KS8842 ethernet driver");
1271b07878e5471a8c880cb3cffee3a73048f38d2001Richard RšöjforsMODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
1272b07878e5471a8c880cb3cffee3a73048f38d2001Richard RšöjforsMODULE_LICENSE("GPL v2");
1273b07878e5471a8c880cb3cffee3a73048f38d2001Richard RšöjforsMODULE_ALIAS("platform:ks8842");
1274b07878e5471a8c880cb3cffee3a73048f38d2001Richard Ršöjfors
1275