diff options
-rw-r--r-- | drivers/net/ethernet/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/wiznet/Kconfig | 65 | ||||
-rw-r--r-- | drivers/net/ethernet/wiznet/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/wiznet/w5300.c | 722 | ||||
-rw-r--r-- | include/linux/platform_data/wiznet.h | 24 |
6 files changed, 814 insertions, 0 deletions
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index c63a64cb6085..a11af5cc4844 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig | |||
@@ -174,6 +174,7 @@ source "drivers/net/ethernet/tile/Kconfig" | |||
174 | source "drivers/net/ethernet/toshiba/Kconfig" | 174 | source "drivers/net/ethernet/toshiba/Kconfig" |
175 | source "drivers/net/ethernet/tundra/Kconfig" | 175 | source "drivers/net/ethernet/tundra/Kconfig" |
176 | source "drivers/net/ethernet/via/Kconfig" | 176 | source "drivers/net/ethernet/via/Kconfig" |
177 | source "drivers/net/ethernet/wiznet/Kconfig" | ||
177 | source "drivers/net/ethernet/xilinx/Kconfig" | 178 | source "drivers/net/ethernet/xilinx/Kconfig" |
178 | source "drivers/net/ethernet/xircom/Kconfig" | 179 | source "drivers/net/ethernet/xircom/Kconfig" |
179 | 180 | ||
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 9676a5109d94..878ad32b93f2 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile | |||
@@ -73,5 +73,6 @@ obj-$(CONFIG_TILE_NET) += tile/ | |||
73 | obj-$(CONFIG_NET_VENDOR_TOSHIBA) += toshiba/ | 73 | obj-$(CONFIG_NET_VENDOR_TOSHIBA) += toshiba/ |
74 | obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundra/ | 74 | obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundra/ |
75 | obj-$(CONFIG_NET_VENDOR_VIA) += via/ | 75 | obj-$(CONFIG_NET_VENDOR_VIA) += via/ |
76 | obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/ | ||
76 | obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ | 77 | obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ |
77 | obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ | 78 | obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ |
diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig new file mode 100644 index 000000000000..f45cef16bfda --- /dev/null +++ b/drivers/net/ethernet/wiznet/Kconfig | |||
@@ -0,0 +1,65 @@ | |||
1 | # | ||
2 | # WIZnet devices configuration | ||
3 | # | ||
4 | |||
5 | config NET_VENDOR_WIZNET | ||
6 | bool "WIZnet devices" | ||
7 | default y | ||
8 | ---help--- | ||
9 | If you have a network (Ethernet) card belonging to this class, say Y | ||
10 | and read the Ethernet-HOWTO, available from | ||
11 | <http://www.tldp.org/docs.html#howto>. | ||
12 | |||
13 | Note that the answer to this question doesn't directly affect the | ||
14 | kernel: saying N will just cause the configurator to skip all | ||
15 | the questions about WIZnet devices. If you say Y, you will be asked | ||
16 | for your specific card in the following questions. | ||
17 | |||
18 | if NET_VENDOR_WIZNET | ||
19 | |||
20 | config WIZNET_W5300 | ||
21 | tristate "WIZnet W5300 Ethernet support" | ||
22 | ---help--- | ||
23 | Support for WIZnet W5300 chips. | ||
24 | |||
25 | W5300 is a single chip with integrated 10/100 Ethernet MAC, | ||
26 | PHY and hardware TCP/IP stack, but this driver is limited to | ||
27 | the MAC and PHY functions only, onchip TCP/IP is unused. | ||
28 | |||
29 | To compile this driver as a module, choose M here: the module | ||
30 | will be called w5300. | ||
31 | |||
32 | choice | ||
33 | prompt "WIZnet interface mode" | ||
34 | default WIZNET_BUS_ANY | ||
35 | |||
36 | config WIZNET_BUS_DIRECT | ||
37 | bool "Direct address bus mode" | ||
38 | ---help--- | ||
39 | In direct address mode host system can directly access all registers | ||
40 | after mapping to Memory-Mapped I/O space. | ||
41 | |||
42 | config WIZNET_BUS_INDIRECT | ||
43 | bool "Indirect address bus mode" | ||
44 | ---help--- | ||
45 | In indirect address mode host system indirectly accesses registers | ||
46 | using Indirect Mode Address Register and Indirect Mode Data Register, | ||
47 | which are directly mapped to Memory-Mapped I/O space. | ||
48 | |||
49 | config WIZNET_BUS_ANY | ||
50 | bool "Select interface mode in runtime" | ||
51 | ---help--- | ||
52 | If interface mode is unknown in compile time, it can be selected | ||
53 | in runtime from board/platform resources configuration. | ||
54 | |||
55 | Performance may decrease compared to explicitly selected bus mode. | ||
56 | endchoice | ||
57 | |||
58 | config WIZNET_TX_FLOW | ||
59 | bool "Use transmit flow control" | ||
60 | default y | ||
61 | help | ||
62 | This enables transmit flow control for WIZnet chips. | ||
63 | If unsure, say Y. | ||
64 | |||
65 | endif # NET_VENDOR_WIZNET | ||
diff --git a/drivers/net/ethernet/wiznet/Makefile b/drivers/net/ethernet/wiznet/Makefile new file mode 100644 index 000000000000..88e0a3e62ba7 --- /dev/null +++ b/drivers/net/ethernet/wiznet/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_WIZNET_W5300) += w5300.o | |||
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c new file mode 100644 index 000000000000..88afde99de8d --- /dev/null +++ b/drivers/net/ethernet/wiznet/w5300.c | |||
@@ -0,0 +1,722 @@ | |||
1 | /* | ||
2 | * Ethernet driver for the WIZnet W5300 chip. | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 WIZnet Co.,Ltd. | ||
5 | * Copyright (C) 2011 Taehun Kim <kth3321 <at> gmail.com> | ||
6 | * Copyright (C) 2012 Mike Sinkovsky <msink@permonline.ru> | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kconfig.h> | ||
14 | #include <linux/netdevice.h> | ||
15 | #include <linux/etherdevice.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/platform_data/wiznet.h> | ||
18 | #include <linux/ethtool.h> | ||
19 | #include <linux/skbuff.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/gpio.h> | ||
29 | |||
30 | #define DRV_NAME "w5300" | ||
31 | #define DRV_VERSION "2012-04-04" | ||
32 | |||
33 | MODULE_DESCRIPTION("WIZnet W5300 Ethernet driver v"DRV_VERSION); | ||
34 | MODULE_AUTHOR("Mike Sinkovsky <msink@permonline.ru>"); | ||
35 | MODULE_ALIAS("platform:"DRV_NAME); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | /* | ||
39 | * Registers | ||
40 | */ | ||
41 | #define W5300_MR 0x0000 /* Mode Register */ | ||
42 | #define MR_DBW (1 << 15) /* Data bus width */ | ||
43 | #define MR_MPF (1 << 14) /* Mac layer pause frame */ | ||
44 | #define MR_WDF(n) (((n)&7)<<11) /* Write data fetch time */ | ||
45 | #define MR_RDH (1 << 10) /* Read data hold time */ | ||
46 | #define MR_FS (1 << 8) /* FIFO swap */ | ||
47 | #define MR_RST (1 << 7) /* S/W reset */ | ||
48 | #define MR_PB (1 << 4) /* Ping block */ | ||
49 | #define MR_DBS (1 << 2) /* Data bus swap */ | ||
50 | #define MR_IND (1 << 0) /* Indirect mode */ | ||
51 | #define W5300_IR 0x0002 /* Interrupt Register */ | ||
52 | #define W5300_IMR 0x0004 /* Interrupt Mask Register */ | ||
53 | #define IR_S0 0x0001 /* S0 interrupt */ | ||
54 | #define W5300_SHARL 0x0008 /* Source MAC address (0123) */ | ||
55 | #define W5300_SHARH 0x000c /* Source MAC address (45) */ | ||
56 | #define W5300_TMSRL 0x0020 /* Transmit Memory Size (0123) */ | ||
57 | #define W5300_TMSRH 0x0024 /* Transmit Memory Size (4567) */ | ||
58 | #define W5300_RMSRL 0x0028 /* Receive Memory Size (0123) */ | ||
59 | #define W5300_RMSRH 0x002c /* Receive Memory Size (4567) */ | ||
60 | #define W5300_MTYPE 0x0030 /* Memory Type */ | ||
61 | #define W5300_IDR 0x00fe /* Chip ID register */ | ||
62 | #define IDR_W5300 0x5300 /* =0x5300 for WIZnet W5300 */ | ||
63 | #define W5300_S0_MR 0x0200 /* S0 Mode Register */ | ||
64 | #define S0_MR_CLOSED 0x0000 /* Close mode */ | ||
65 | #define S0_MR_MACRAW 0x0004 /* MAC RAW mode (promiscous) */ | ||
66 | #define S0_MR_MACRAW_MF 0x0044 /* MAC RAW mode (filtered) */ | ||
67 | #define W5300_S0_CR 0x0202 /* S0 Command Register */ | ||
68 | #define S0_CR_OPEN 0x0001 /* OPEN command */ | ||
69 | #define S0_CR_CLOSE 0x0010 /* CLOSE command */ | ||
70 | #define S0_CR_SEND 0x0020 /* SEND command */ | ||
71 | #define S0_CR_RECV 0x0040 /* RECV command */ | ||
72 | #define W5300_S0_IMR 0x0204 /* S0 Interrupt Mask Register */ | ||
73 | #define W5300_S0_IR 0x0206 /* S0 Interrupt Register */ | ||
74 | #define S0_IR_RECV 0x0004 /* Receive interrupt */ | ||
75 | #define S0_IR_SENDOK 0x0010 /* Send OK interrupt */ | ||
76 | #define W5300_S0_SSR 0x0208 /* S0 Socket Status Register */ | ||
77 | #define W5300_S0_TX_WRSR 0x0220 /* S0 TX Write Size Register */ | ||
78 | #define W5300_S0_TX_FSR 0x0224 /* S0 TX Free Size Register */ | ||
79 | #define W5300_S0_RX_RSR 0x0228 /* S0 Received data Size */ | ||
80 | #define W5300_S0_TX_FIFO 0x022e /* S0 Transmit FIFO */ | ||
81 | #define W5300_S0_RX_FIFO 0x0230 /* S0 Receive FIFO */ | ||
82 | #define W5300_REGS_LEN 0x0400 | ||
83 | |||
84 | /* | ||
85 | * Device driver private data structure | ||
86 | */ | ||
87 | struct w5300_priv { | ||
88 | void __iomem *base; | ||
89 | spinlock_t reg_lock; | ||
90 | bool indirect; | ||
91 | u16 (*read) (struct w5300_priv *priv, u16 addr); | ||
92 | void (*write)(struct w5300_priv *priv, u16 addr, u16 data); | ||
93 | int irq; | ||
94 | int link_irq; | ||
95 | int link_gpio; | ||
96 | |||
97 | struct napi_struct napi; | ||
98 | struct net_device *ndev; | ||
99 | bool promisc; | ||
100 | u32 msg_enable; | ||
101 | }; | ||
102 | |||
103 | /************************************************************************ | ||
104 | * | ||
105 | * Lowlevel I/O functions | ||
106 | * | ||
107 | ***********************************************************************/ | ||
108 | |||
109 | /* | ||
110 | * In direct address mode host system can directly access W5300 registers | ||
111 | * after mapping to Memory-Mapped I/O space. | ||
112 | * | ||
113 | * 0x400 bytes are required for memory space. | ||
114 | */ | ||
115 | static inline u16 w5300_read_direct(struct w5300_priv *priv, u16 addr) | ||
116 | { | ||
117 | return ioread16(priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT)); | ||
118 | } | ||
119 | |||
120 | static inline void w5300_write_direct(struct w5300_priv *priv, | ||
121 | u16 addr, u16 data) | ||
122 | { | ||
123 | iowrite16(data, priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT)); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * In indirect address mode host system indirectly accesses registers by | ||
128 | * using Indirect Mode Address Register (IDM_AR) and Indirect Mode Data | ||
129 | * Register (IDM_DR), which are directly mapped to Memory-Mapped I/O space. | ||
130 | * Mode Register (MR) is directly accessible. | ||
131 | * | ||
132 | * Only 0x06 bytes are required for memory space. | ||
133 | */ | ||
134 | #define W5300_IDM_AR 0x0002 /* Indirect Mode Address */ | ||
135 | #define W5300_IDM_DR 0x0004 /* Indirect Mode Data */ | ||
136 | |||
137 | static u16 w5300_read_indirect(struct w5300_priv *priv, u16 addr) | ||
138 | { | ||
139 | unsigned long flags; | ||
140 | u16 data; | ||
141 | |||
142 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
143 | w5300_write_direct(priv, W5300_IDM_AR, addr); | ||
144 | mmiowb(); | ||
145 | data = w5300_read_direct(priv, W5300_IDM_DR); | ||
146 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
147 | |||
148 | return data; | ||
149 | } | ||
150 | |||
151 | static void w5300_write_indirect(struct w5300_priv *priv, u16 addr, u16 data) | ||
152 | { | ||
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
156 | w5300_write_direct(priv, W5300_IDM_AR, addr); | ||
157 | mmiowb(); | ||
158 | w5300_write_direct(priv, W5300_IDM_DR, data); | ||
159 | mmiowb(); | ||
160 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
161 | } | ||
162 | |||
163 | #if defined(CONFIG_WIZNET_BUS_DIRECT) | ||
164 | #define w5300_read w5300_read_direct | ||
165 | #define w5300_write w5300_write_direct | ||
166 | |||
167 | #elif defined(CONFIG_WIZNET_BUS_INDIRECT) | ||
168 | #define w5300_read w5300_read_indirect | ||
169 | #define w5300_write w5300_write_indirect | ||
170 | |||
171 | #else /* CONFIG_WIZNET_BUS_ANY */ | ||
172 | #define w5300_read priv->read | ||
173 | #define w5300_write priv->write | ||
174 | #endif | ||
175 | |||
176 | static u32 w5300_read32(struct w5300_priv *priv, u16 addr) | ||
177 | { | ||
178 | u32 data; | ||
179 | data = w5300_read(priv, addr) << 16; | ||
180 | data |= w5300_read(priv, addr + 2); | ||
181 | return data; | ||
182 | } | ||
183 | |||
184 | static void w5300_write32(struct w5300_priv *priv, u16 addr, u32 data) | ||
185 | { | ||
186 | w5300_write(priv, addr, data >> 16); | ||
187 | w5300_write(priv, addr + 2, data); | ||
188 | } | ||
189 | |||
190 | static int w5300_command(struct w5300_priv *priv, u16 cmd) | ||
191 | { | ||
192 | unsigned long timeout = jiffies + msecs_to_jiffies(100); | ||
193 | |||
194 | w5300_write(priv, W5300_S0_CR, cmd); | ||
195 | mmiowb(); | ||
196 | |||
197 | while (w5300_read(priv, W5300_S0_CR) != 0) { | ||
198 | if (time_after(jiffies, timeout)) | ||
199 | return -EIO; | ||
200 | cpu_relax(); | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static void w5300_read_frame(struct w5300_priv *priv, u8 *buf, int len) | ||
207 | { | ||
208 | u16 fifo; | ||
209 | int i; | ||
210 | |||
211 | for (i = 0; i < len; i += 2) { | ||
212 | fifo = w5300_read(priv, W5300_S0_RX_FIFO); | ||
213 | *buf++ = fifo >> 8; | ||
214 | *buf++ = fifo; | ||
215 | } | ||
216 | fifo = w5300_read(priv, W5300_S0_RX_FIFO); | ||
217 | fifo = w5300_read(priv, W5300_S0_RX_FIFO); | ||
218 | } | ||
219 | |||
220 | static void w5300_write_frame(struct w5300_priv *priv, u8 *buf, int len) | ||
221 | { | ||
222 | u16 fifo; | ||
223 | int i; | ||
224 | |||
225 | for (i = 0; i < len; i += 2) { | ||
226 | fifo = *buf++ << 8; | ||
227 | fifo |= *buf++; | ||
228 | w5300_write(priv, W5300_S0_TX_FIFO, fifo); | ||
229 | } | ||
230 | w5300_write32(priv, W5300_S0_TX_WRSR, len); | ||
231 | } | ||
232 | |||
233 | static void w5300_write_macaddr(struct w5300_priv *priv) | ||
234 | { | ||
235 | struct net_device *ndev = priv->ndev; | ||
236 | w5300_write32(priv, W5300_SHARL, | ||
237 | ndev->dev_addr[0] << 24 | | ||
238 | ndev->dev_addr[1] << 16 | | ||
239 | ndev->dev_addr[2] << 8 | | ||
240 | ndev->dev_addr[3]); | ||
241 | w5300_write(priv, W5300_SHARH, | ||
242 | ndev->dev_addr[4] << 8 | | ||
243 | ndev->dev_addr[5]); | ||
244 | mmiowb(); | ||
245 | } | ||
246 | |||
247 | static void w5300_hw_reset(struct w5300_priv *priv) | ||
248 | { | ||
249 | w5300_write_direct(priv, W5300_MR, MR_RST); | ||
250 | mmiowb(); | ||
251 | mdelay(5); | ||
252 | w5300_write_direct(priv, W5300_MR, priv->indirect ? | ||
253 | MR_WDF(7) | MR_PB | MR_IND : | ||
254 | MR_WDF(7) | MR_PB); | ||
255 | mmiowb(); | ||
256 | w5300_write(priv, W5300_IMR, 0); | ||
257 | w5300_write_macaddr(priv); | ||
258 | |||
259 | /* Configure 128K of internal memory | ||
260 | * as 64K RX fifo and 64K TX fifo | ||
261 | */ | ||
262 | w5300_write32(priv, W5300_RMSRL, 64 << 24); | ||
263 | w5300_write32(priv, W5300_RMSRH, 0); | ||
264 | w5300_write32(priv, W5300_TMSRL, 64 << 24); | ||
265 | w5300_write32(priv, W5300_TMSRH, 0); | ||
266 | w5300_write(priv, W5300_MTYPE, 0x00ff); | ||
267 | mmiowb(); | ||
268 | } | ||
269 | |||
270 | static void w5300_hw_start(struct w5300_priv *priv) | ||
271 | { | ||
272 | w5300_write(priv, W5300_S0_MR, priv->promisc ? | ||
273 | S0_MR_MACRAW : S0_MR_MACRAW_MF); | ||
274 | mmiowb(); | ||
275 | w5300_command(priv, S0_CR_OPEN); | ||
276 | w5300_write(priv, W5300_S0_IMR, IS_ENABLED(CONFIG_WIZNET_TX_FLOW) ? | ||
277 | S0_IR_RECV | S0_IR_SENDOK : | ||
278 | S0_IR_RECV); | ||
279 | w5300_write(priv, W5300_IMR, IR_S0); | ||
280 | mmiowb(); | ||
281 | } | ||
282 | |||
283 | static void w5300_hw_close(struct w5300_priv *priv) | ||
284 | { | ||
285 | w5300_write(priv, W5300_IMR, 0); | ||
286 | mmiowb(); | ||
287 | w5300_command(priv, S0_CR_CLOSE); | ||
288 | } | ||
289 | |||
290 | /*********************************************************************** | ||
291 | * | ||
292 | * Device driver functions / callbacks | ||
293 | * | ||
294 | ***********************************************************************/ | ||
295 | |||
296 | static void w5300_get_drvinfo(struct net_device *ndev, | ||
297 | struct ethtool_drvinfo *info) | ||
298 | { | ||
299 | strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); | ||
300 | strlcpy(info->version, DRV_VERSION, sizeof(info->version)); | ||
301 | strlcpy(info->bus_info, dev_name(ndev->dev.parent), | ||
302 | sizeof(info->bus_info)); | ||
303 | } | ||
304 | |||
305 | static u32 w5300_get_link(struct net_device *ndev) | ||
306 | { | ||
307 | struct w5300_priv *priv = netdev_priv(ndev); | ||
308 | |||
309 | if (gpio_is_valid(priv->link_gpio)) | ||
310 | return !!gpio_get_value(priv->link_gpio); | ||
311 | |||
312 | return 1; | ||
313 | } | ||
314 | |||
315 | static u32 w5300_get_msglevel(struct net_device *ndev) | ||
316 | { | ||
317 | struct w5300_priv *priv = netdev_priv(ndev); | ||
318 | |||
319 | return priv->msg_enable; | ||
320 | } | ||
321 | |||
322 | static void w5300_set_msglevel(struct net_device *ndev, u32 value) | ||
323 | { | ||
324 | struct w5300_priv *priv = netdev_priv(ndev); | ||
325 | |||
326 | priv->msg_enable = value; | ||
327 | } | ||
328 | |||
329 | static int w5300_get_regs_len(struct net_device *ndev) | ||
330 | { | ||
331 | return W5300_REGS_LEN; | ||
332 | } | ||
333 | |||
334 | static void w5300_get_regs(struct net_device *ndev, | ||
335 | struct ethtool_regs *regs, void *_buf) | ||
336 | { | ||
337 | struct w5300_priv *priv = netdev_priv(ndev); | ||
338 | u8 *buf = _buf; | ||
339 | u16 addr; | ||
340 | u16 data; | ||
341 | |||
342 | regs->version = 1; | ||
343 | for (addr = 0; addr < W5300_REGS_LEN; addr += 2) { | ||
344 | switch (addr & 0x23f) { | ||
345 | case W5300_S0_TX_FIFO: /* cannot read TX_FIFO */ | ||
346 | case W5300_S0_RX_FIFO: /* cannot read RX_FIFO */ | ||
347 | data = 0xffff; | ||
348 | break; | ||
349 | default: | ||
350 | data = w5300_read(priv, addr); | ||
351 | break; | ||
352 | } | ||
353 | *buf++ = data >> 8; | ||
354 | *buf++ = data; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | static void w5300_tx_timeout(struct net_device *ndev) | ||
359 | { | ||
360 | struct w5300_priv *priv = netdev_priv(ndev); | ||
361 | |||
362 | netif_stop_queue(ndev); | ||
363 | w5300_hw_reset(priv); | ||
364 | w5300_hw_start(priv); | ||
365 | ndev->stats.tx_errors++; | ||
366 | ndev->trans_start = jiffies; | ||
367 | netif_wake_queue(ndev); | ||
368 | } | ||
369 | |||
370 | static int w5300_start_tx(struct sk_buff *skb, struct net_device *ndev) | ||
371 | { | ||
372 | struct w5300_priv *priv = netdev_priv(ndev); | ||
373 | |||
374 | if (IS_ENABLED(CONFIG_WIZNET_TX_FLOW)) | ||
375 | netif_stop_queue(ndev); | ||
376 | |||
377 | w5300_write_frame(priv, skb->data, skb->len); | ||
378 | mmiowb(); | ||
379 | ndev->stats.tx_packets++; | ||
380 | ndev->stats.tx_bytes += skb->len; | ||
381 | dev_kfree_skb(skb); | ||
382 | netif_dbg(priv, tx_queued, ndev, "tx queued\n"); | ||
383 | |||
384 | w5300_command(priv, S0_CR_SEND); | ||
385 | |||
386 | return NETDEV_TX_OK; | ||
387 | } | ||
388 | |||
389 | static int w5300_napi_poll(struct napi_struct *napi, int budget) | ||
390 | { | ||
391 | struct w5300_priv *priv = container_of(napi, struct w5300_priv, napi); | ||
392 | struct net_device *ndev = priv->ndev; | ||
393 | struct sk_buff *skb; | ||
394 | int rx_count; | ||
395 | u16 rx_len; | ||
396 | |||
397 | for (rx_count = 0; rx_count < budget; rx_count++) { | ||
398 | u32 rx_fifo_len = w5300_read32(priv, W5300_S0_RX_RSR); | ||
399 | if (rx_fifo_len == 0) | ||
400 | break; | ||
401 | |||
402 | rx_len = w5300_read(priv, W5300_S0_RX_FIFO); | ||
403 | |||
404 | skb = netdev_alloc_skb_ip_align(ndev, roundup(rx_len, 2)); | ||
405 | if (unlikely(!skb)) { | ||
406 | u32 i; | ||
407 | for (i = 0; i < rx_fifo_len; i += 2) | ||
408 | w5300_read(priv, W5300_S0_RX_FIFO); | ||
409 | ndev->stats.rx_dropped++; | ||
410 | return -ENOMEM; | ||
411 | } | ||
412 | |||
413 | skb_put(skb, rx_len); | ||
414 | w5300_read_frame(priv, skb->data, rx_len); | ||
415 | skb->protocol = eth_type_trans(skb, ndev); | ||
416 | |||
417 | netif_receive_skb(skb); | ||
418 | ndev->stats.rx_packets++; | ||
419 | ndev->stats.rx_bytes += rx_len; | ||
420 | } | ||
421 | |||
422 | if (rx_count < budget) { | ||
423 | w5300_write(priv, W5300_IMR, IR_S0); | ||
424 | mmiowb(); | ||
425 | napi_complete(napi); | ||
426 | } | ||
427 | |||
428 | return rx_count; | ||
429 | } | ||
430 | |||
431 | static irqreturn_t w5300_interrupt(int irq, void *ndev_instance) | ||
432 | { | ||
433 | struct net_device *ndev = ndev_instance; | ||
434 | struct w5300_priv *priv = netdev_priv(ndev); | ||
435 | |||
436 | int ir = w5300_read(priv, W5300_S0_IR); | ||
437 | if (!ir) | ||
438 | return IRQ_NONE; | ||
439 | w5300_write(priv, W5300_S0_IR, ir); | ||
440 | mmiowb(); | ||
441 | |||
442 | if (IS_ENABLED(CONFIG_WIZNET_TX_FLOW) && (ir & S0_IR_SENDOK)) { | ||
443 | netif_dbg(priv, tx_done, ndev, "tx done\n"); | ||
444 | netif_wake_queue(ndev); | ||
445 | } | ||
446 | |||
447 | if (ir & S0_IR_RECV) { | ||
448 | if (napi_schedule_prep(&priv->napi)) { | ||
449 | w5300_write(priv, W5300_IMR, 0); | ||
450 | mmiowb(); | ||
451 | __napi_schedule(&priv->napi); | ||
452 | } | ||
453 | } | ||
454 | |||
455 | return IRQ_HANDLED; | ||
456 | } | ||
457 | |||
458 | static irqreturn_t w5300_detect_link(int irq, void *ndev_instance) | ||
459 | { | ||
460 | struct net_device *ndev = ndev_instance; | ||
461 | struct w5300_priv *priv = netdev_priv(ndev); | ||
462 | |||
463 | if (netif_running(ndev)) { | ||
464 | if (gpio_get_value(priv->link_gpio) != 0) { | ||
465 | netif_info(priv, link, ndev, "link is up\n"); | ||
466 | netif_carrier_on(ndev); | ||
467 | } else { | ||
468 | netif_info(priv, link, ndev, "link is down\n"); | ||
469 | netif_carrier_off(ndev); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | return IRQ_HANDLED; | ||
474 | } | ||
475 | |||
476 | static void w5300_set_rx_mode(struct net_device *ndev) | ||
477 | { | ||
478 | struct w5300_priv *priv = netdev_priv(ndev); | ||
479 | bool set_promisc = (ndev->flags & IFF_PROMISC) != 0; | ||
480 | |||
481 | if (priv->promisc != set_promisc) { | ||
482 | priv->promisc = set_promisc; | ||
483 | w5300_hw_start(priv); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | static int w5300_set_macaddr(struct net_device *ndev, void *addr) | ||
488 | { | ||
489 | struct w5300_priv *priv = netdev_priv(ndev); | ||
490 | struct sockaddr *sock_addr = addr; | ||
491 | |||
492 | if (!is_valid_ether_addr(sock_addr->sa_data)) | ||
493 | return -EADDRNOTAVAIL; | ||
494 | memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN); | ||
495 | ndev->addr_assign_type &= ~NET_ADDR_RANDOM; | ||
496 | w5300_write_macaddr(priv); | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int w5300_open(struct net_device *ndev) | ||
501 | { | ||
502 | struct w5300_priv *priv = netdev_priv(ndev); | ||
503 | |||
504 | netif_info(priv, ifup, ndev, "enabling\n"); | ||
505 | if (!is_valid_ether_addr(ndev->dev_addr)) | ||
506 | return -EINVAL; | ||
507 | w5300_hw_start(priv); | ||
508 | napi_enable(&priv->napi); | ||
509 | netif_start_queue(ndev); | ||
510 | if (!gpio_is_valid(priv->link_gpio) || | ||
511 | gpio_get_value(priv->link_gpio) != 0) | ||
512 | netif_carrier_on(ndev); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int w5300_stop(struct net_device *ndev) | ||
517 | { | ||
518 | struct w5300_priv *priv = netdev_priv(ndev); | ||
519 | |||
520 | netif_info(priv, ifdown, ndev, "shutting down\n"); | ||
521 | w5300_hw_close(priv); | ||
522 | netif_carrier_off(ndev); | ||
523 | netif_stop_queue(ndev); | ||
524 | napi_disable(&priv->napi); | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static const struct ethtool_ops w5300_ethtool_ops = { | ||
529 | .get_drvinfo = w5300_get_drvinfo, | ||
530 | .get_msglevel = w5300_get_msglevel, | ||
531 | .set_msglevel = w5300_set_msglevel, | ||
532 | .get_link = w5300_get_link, | ||
533 | .get_regs_len = w5300_get_regs_len, | ||
534 | .get_regs = w5300_get_regs, | ||
535 | }; | ||
536 | |||
537 | static const struct net_device_ops w5300_netdev_ops = { | ||
538 | .ndo_open = w5300_open, | ||
539 | .ndo_stop = w5300_stop, | ||
540 | .ndo_start_xmit = w5300_start_tx, | ||
541 | .ndo_tx_timeout = w5300_tx_timeout, | ||
542 | .ndo_set_rx_mode = w5300_set_rx_mode, | ||
543 | .ndo_set_mac_address = w5300_set_macaddr, | ||
544 | .ndo_validate_addr = eth_validate_addr, | ||
545 | .ndo_change_mtu = eth_change_mtu, | ||
546 | }; | ||
547 | |||
548 | static int __devinit w5300_hw_probe(struct platform_device *pdev) | ||
549 | { | ||
550 | struct wiznet_platform_data *data = pdev->dev.platform_data; | ||
551 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
552 | struct w5300_priv *priv = netdev_priv(ndev); | ||
553 | const char *name = netdev_name(ndev); | ||
554 | struct resource *mem; | ||
555 | int mem_size; | ||
556 | int irq; | ||
557 | int ret; | ||
558 | |||
559 | if (data && is_valid_ether_addr(data->mac_addr)) { | ||
560 | memcpy(ndev->dev_addr, data->mac_addr, ETH_ALEN); | ||
561 | } else { | ||
562 | random_ether_addr(ndev->dev_addr); | ||
563 | ndev->addr_assign_type |= NET_ADDR_RANDOM; | ||
564 | } | ||
565 | |||
566 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
567 | if (!mem) | ||
568 | return -ENXIO; | ||
569 | mem_size = resource_size(mem); | ||
570 | if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name)) | ||
571 | return -EBUSY; | ||
572 | priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size); | ||
573 | if (!priv->base) | ||
574 | return -EBUSY; | ||
575 | |||
576 | spin_lock_init(&priv->reg_lock); | ||
577 | priv->indirect = mem_size < W5300_BUS_DIRECT_SIZE; | ||
578 | if (priv->indirect) { | ||
579 | priv->read = w5300_read_indirect; | ||
580 | priv->write = w5300_write_indirect; | ||
581 | } else { | ||
582 | priv->read = w5300_read_direct; | ||
583 | priv->write = w5300_write_direct; | ||
584 | } | ||
585 | |||
586 | w5300_hw_reset(priv); | ||
587 | if (w5300_read(priv, W5300_IDR) != IDR_W5300) | ||
588 | return -ENODEV; | ||
589 | |||
590 | irq = platform_get_irq(pdev, 0); | ||
591 | if (irq < 0) | ||
592 | return irq; | ||
593 | ret = request_irq(irq, w5300_interrupt, | ||
594 | IRQ_TYPE_LEVEL_LOW, name, ndev); | ||
595 | if (ret < 0) | ||
596 | return ret; | ||
597 | priv->irq = irq; | ||
598 | |||
599 | priv->link_gpio = data->link_gpio; | ||
600 | if (gpio_is_valid(priv->link_gpio)) { | ||
601 | char *link_name = devm_kzalloc(&pdev->dev, 16, GFP_KERNEL); | ||
602 | if (!link_name) | ||
603 | return -ENOMEM; | ||
604 | snprintf(link_name, 16, "%s-link", name); | ||
605 | priv->link_irq = gpio_to_irq(priv->link_gpio); | ||
606 | if (request_any_context_irq(priv->link_irq, w5300_detect_link, | ||
607 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
608 | link_name, priv->ndev) < 0) | ||
609 | priv->link_gpio = -EINVAL; | ||
610 | } | ||
611 | |||
612 | netdev_info(ndev, "at 0x%llx irq %d\n", (u64)mem->start, irq); | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int __devinit w5300_probe(struct platform_device *pdev) | ||
617 | { | ||
618 | struct w5300_priv *priv; | ||
619 | struct net_device *ndev; | ||
620 | int err; | ||
621 | |||
622 | ndev = alloc_etherdev(sizeof(*priv)); | ||
623 | if (!ndev) | ||
624 | return -ENOMEM; | ||
625 | SET_NETDEV_DEV(ndev, &pdev->dev); | ||
626 | platform_set_drvdata(pdev, ndev); | ||
627 | priv = netdev_priv(ndev); | ||
628 | priv->ndev = ndev; | ||
629 | |||
630 | ether_setup(ndev); | ||
631 | ndev->netdev_ops = &w5300_netdev_ops; | ||
632 | ndev->ethtool_ops = &w5300_ethtool_ops; | ||
633 | ndev->watchdog_timeo = HZ; | ||
634 | netif_napi_add(ndev, &priv->napi, w5300_napi_poll, 16); | ||
635 | |||
636 | /* This chip doesn't support VLAN packets with normal MTU, | ||
637 | * so disable VLAN for this device. | ||
638 | */ | ||
639 | ndev->features |= NETIF_F_VLAN_CHALLENGED; | ||
640 | |||
641 | err = register_netdev(ndev); | ||
642 | if (err < 0) | ||
643 | goto err_register; | ||
644 | |||
645 | err = w5300_hw_probe(pdev); | ||
646 | if (err < 0) | ||
647 | goto err_hw_probe; | ||
648 | |||
649 | return 0; | ||
650 | |||
651 | err_hw_probe: | ||
652 | unregister_netdev(ndev); | ||
653 | err_register: | ||
654 | free_netdev(ndev); | ||
655 | platform_set_drvdata(pdev, NULL); | ||
656 | return err; | ||
657 | } | ||
658 | |||
659 | static int __devexit w5300_remove(struct platform_device *pdev) | ||
660 | { | ||
661 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
662 | struct w5300_priv *priv = netdev_priv(ndev); | ||
663 | |||
664 | w5300_hw_reset(priv); | ||
665 | free_irq(priv->irq, ndev); | ||
666 | if (gpio_is_valid(priv->link_gpio)) | ||
667 | free_irq(priv->link_irq, ndev); | ||
668 | |||
669 | unregister_netdev(ndev); | ||
670 | free_netdev(ndev); | ||
671 | platform_set_drvdata(pdev, NULL); | ||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | #ifdef CONFIG_PM | ||
676 | static int w5300_suspend(struct device *dev) | ||
677 | { | ||
678 | struct platform_device *pdev = to_platform_device(dev); | ||
679 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
680 | struct w5300_priv *priv = netdev_priv(ndev); | ||
681 | |||
682 | if (netif_running(ndev)) { | ||
683 | netif_carrier_off(ndev); | ||
684 | netif_device_detach(ndev); | ||
685 | |||
686 | w5300_hw_close(priv); | ||
687 | } | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int w5300_resume(struct device *dev) | ||
692 | { | ||
693 | struct platform_device *pdev = to_platform_device(dev); | ||
694 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
695 | struct w5300_priv *priv = netdev_priv(ndev); | ||
696 | |||
697 | if (!netif_running(ndev)) { | ||
698 | w5300_hw_reset(priv); | ||
699 | w5300_hw_start(priv); | ||
700 | |||
701 | netif_device_attach(ndev); | ||
702 | if (!gpio_is_valid(priv->link_gpio) || | ||
703 | gpio_get_value(priv->link_gpio) != 0) | ||
704 | netif_carrier_on(ndev); | ||
705 | } | ||
706 | return 0; | ||
707 | } | ||
708 | #endif /* CONFIG_PM */ | ||
709 | |||
710 | static SIMPLE_DEV_PM_OPS(w5300_pm_ops, w5300_suspend, w5300_resume); | ||
711 | |||
712 | static struct platform_driver w5300_driver = { | ||
713 | .driver = { | ||
714 | .name = DRV_NAME, | ||
715 | .owner = THIS_MODULE, | ||
716 | .pm = &w5300_pm_ops, | ||
717 | }, | ||
718 | .probe = w5300_probe, | ||
719 | .remove = __devexit_p(w5300_remove), | ||
720 | }; | ||
721 | |||
722 | module_platform_driver(w5300_driver); | ||
diff --git a/include/linux/platform_data/wiznet.h b/include/linux/platform_data/wiznet.h new file mode 100644 index 000000000000..b5d8c192d84d --- /dev/null +++ b/include/linux/platform_data/wiznet.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * Ethernet driver for the WIZnet W5x00 chip. | ||
3 | * | ||
4 | * Licensed under the GPL-2 or later. | ||
5 | */ | ||
6 | |||
7 | #ifndef PLATFORM_DATA_WIZNET_H | ||
8 | #define PLATFORM_DATA_WIZNET_H | ||
9 | |||
10 | #include <linux/if_ether.h> | ||
11 | |||
12 | struct wiznet_platform_data { | ||
13 | int link_gpio; | ||
14 | u8 mac_addr[ETH_ALEN]; | ||
15 | }; | ||
16 | |||
17 | #ifndef CONFIG_WIZNET_BUS_SHIFT | ||
18 | #define CONFIG_WIZNET_BUS_SHIFT 0 | ||
19 | #endif | ||
20 | |||
21 | #define W5100_BUS_DIRECT_SIZE (0x8000 << CONFIG_WIZNET_BUS_SHIFT) | ||
22 | #define W5300_BUS_DIRECT_SIZE (0x0400 << CONFIG_WIZNET_BUS_SHIFT) | ||
23 | |||
24 | #endif /* PLATFORM_DATA_WIZNET_H */ | ||