aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoam Camus <noamc@ezchip.com>2015-06-23 04:43:53 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-23 10:16:25 -0400
commit0dd0770936363ecd4d49192782bceccb882d3a24 (patch)
tree4fabeeacedeacafb30910a5fc4609e7cd0e7dcbf
parent55dd27536671511317d80478904e4510ed1162a1 (diff)
NET: Add ezchip ethernet driver
Simple LAN device for debug or management purposes. Device supports interrupts for RX and TX(completion). Device does not have DMA ability. Signed-off-by: Noam Camus <noamc@ezchip.com> Signed-off-by: Tal Zilcer <talz@ezchip.com> Acked-by: Alexey Brodkin <abrodkin@synopsys.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/ezchip_enet.txt15
-rw-r--r--drivers/net/ethernet/Kconfig1
-rw-r--r--drivers/net/ethernet/Makefile1
-rw-r--r--drivers/net/ethernet/ezchip/Kconfig26
-rw-r--r--drivers/net/ethernet/ezchip/Makefile1
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.c658
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.h336
7 files changed, 1038 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/ezchip_enet.txt b/Documentation/devicetree/bindings/net/ezchip_enet.txt
new file mode 100644
index 000000000000..4e29b2b82873
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ezchip_enet.txt
@@ -0,0 +1,15 @@
1* EZchip NPS Management Ethernet port driver
2
3Required properties:
4- compatible: Should be "ezchip,nps-mgt-enet"
5- reg: Address and length of the register set for the device
6- interrupts: Should contain the ENET interrupt
7
8Examples:
9
10 ethernet@f0003000 {
11 compatible = "ezchip,nps-mgt-enet";
12 reg = <0xf0003000 0x44>;
13 interrupts = <7>;
14 mac-address = [ 00 11 22 33 44 55 ];
15 };
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 9a8308553520..f3bb1784066b 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -67,6 +67,7 @@ config DNET
67source "drivers/net/ethernet/dec/Kconfig" 67source "drivers/net/ethernet/dec/Kconfig"
68source "drivers/net/ethernet/dlink/Kconfig" 68source "drivers/net/ethernet/dlink/Kconfig"
69source "drivers/net/ethernet/emulex/Kconfig" 69source "drivers/net/ethernet/emulex/Kconfig"
70source "drivers/net/ethernet/ezchip/Kconfig"
70source "drivers/net/ethernet/neterion/Kconfig" 71source "drivers/net/ethernet/neterion/Kconfig"
71source "drivers/net/ethernet/faraday/Kconfig" 72source "drivers/net/ethernet/faraday/Kconfig"
72source "drivers/net/ethernet/freescale/Kconfig" 73source "drivers/net/ethernet/freescale/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 4395d99115a0..c51014b0464f 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_DNET) += dnet.o
30obj-$(CONFIG_NET_VENDOR_DEC) += dec/ 30obj-$(CONFIG_NET_VENDOR_DEC) += dec/
31obj-$(CONFIG_NET_VENDOR_DLINK) += dlink/ 31obj-$(CONFIG_NET_VENDOR_DLINK) += dlink/
32obj-$(CONFIG_NET_VENDOR_EMULEX) += emulex/ 32obj-$(CONFIG_NET_VENDOR_EMULEX) += emulex/
33obj-$(CONFIG_NET_VENDOR_EZCHIP) += ezchip/
33obj-$(CONFIG_NET_VENDOR_EXAR) += neterion/ 34obj-$(CONFIG_NET_VENDOR_EXAR) += neterion/
34obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/ 35obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/
35obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/ 36obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/
diff --git a/drivers/net/ethernet/ezchip/Kconfig b/drivers/net/ethernet/ezchip/Kconfig
new file mode 100644
index 000000000000..48ecbc8aaaea
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/Kconfig
@@ -0,0 +1,26 @@
1#
2# EZchip network device configuration
3#
4
5config NET_VENDOR_EZCHIP
6 bool "EZchip devices"
7 default y
8 ---help---
9 If you have a network (Ethernet) device belonging to this class, say Y.
10
11 Note that the answer to this question doesn't directly affect the
12 kernel: saying N will just cause the configurator to skip all
13 the questions about EZchip devices. If you say Y, you will be asked for
14 your specific device in the following questions.
15
16if NET_VENDOR_EZCHIP
17
18config EZCHIP_NPS_MANAGEMENT_ENET
19 tristate "EZchip NPS management enet support"
20 depends on OF_IRQ && OF_NET
21 ---help---
22 Simple LAN device for debug or management purposes.
23 Device supports interrupts for RX and TX(completion).
24 Device does not have DMA ability.
25
26endif
diff --git a/drivers/net/ethernet/ezchip/Makefile b/drivers/net/ethernet/ezchip/Makefile
new file mode 100644
index 000000000000..e490176a8137
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_EZCHIP_NPS_MANAGEMENT_ENET) += nps_enet.o
diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c
new file mode 100644
index 000000000000..24a85b292007
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/nps_enet.c
@@ -0,0 +1,658 @@
1/*
2 * Copyright(c) 2015 EZchip Technologies.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * The full GNU General Public License is included in this distribution in
14 * the file called "COPYING".
15 */
16
17#include <linux/module.h>
18#include <linux/etherdevice.h>
19#include <linux/of_address.h>
20#include <linux/of_irq.h>
21#include <linux/of_net.h>
22#include <linux/of_platform.h>
23#include "nps_enet.h"
24
25#define DRV_NAME "nps_mgt_enet"
26
27static void nps_enet_clean_rx_fifo(struct net_device *ndev, u32 frame_len)
28{
29 struct nps_enet_priv *priv = netdev_priv(ndev);
30 u32 i, len = DIV_ROUND_UP(frame_len, sizeof(u32));
31
32 /* Empty Rx FIFO buffer by reading all words */
33 for (i = 0; i < len; i++)
34 nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
35}
36
37static void nps_enet_read_rx_fifo(struct net_device *ndev,
38 unsigned char *dst, u32 length)
39{
40 struct nps_enet_priv *priv = netdev_priv(ndev);
41 s32 i, last = length & (sizeof(u32) - 1);
42 u32 *reg = (u32 *)dst, len = length / sizeof(u32);
43 bool dst_is_aligned = IS_ALIGNED((unsigned long)dst, sizeof(u32));
44
45 /* In case dst is not aligned we need an intermediate buffer */
46 if (dst_is_aligned)
47 for (i = 0; i < len; i++, reg++)
48 *reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
49 else { /* !dst_is_aligned */
50 for (i = 0; i < len; i++, reg++) {
51 u32 buf =
52 nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
53
54 /* to accommodate word-unaligned address of "reg"
55 * we have to do memcpy_toio() instead of simple "=".
56 */
57 memcpy_toio((void __iomem *)reg, &buf, sizeof(buf));
58 }
59 }
60
61 /* copy last bytes (if any) */
62 if (last) {
63 u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
64
65 memcpy_toio((void __iomem *)reg, &buf, last);
66 }
67}
68
69static u32 nps_enet_rx_handler(struct net_device *ndev)
70{
71 u32 frame_len, err = 0;
72 u32 work_done = 0;
73 struct nps_enet_priv *priv = netdev_priv(ndev);
74 struct sk_buff *skb;
75 struct nps_enet_rx_ctl rx_ctrl;
76
77 rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL);
78 frame_len = rx_ctrl.nr;
79
80 /* Check if we got RX */
81 if (!rx_ctrl.cr)
82 return work_done;
83
84 /* If we got here there is a work for us */
85 work_done++;
86
87 /* Check Rx error */
88 if (rx_ctrl.er) {
89 ndev->stats.rx_errors++;
90 err = 1;
91 }
92
93 /* Check Rx CRC error */
94 if (rx_ctrl.crc) {
95 ndev->stats.rx_crc_errors++;
96 ndev->stats.rx_dropped++;
97 err = 1;
98 }
99
100 /* Check Frame length Min 64b */
101 if (unlikely(frame_len < ETH_ZLEN)) {
102 ndev->stats.rx_length_errors++;
103 ndev->stats.rx_dropped++;
104 err = 1;
105 }
106
107 if (err)
108 goto rx_irq_clean;
109
110 /* Skb allocation */
111 skb = netdev_alloc_skb_ip_align(ndev, frame_len);
112 if (unlikely(!skb)) {
113 ndev->stats.rx_errors++;
114 ndev->stats.rx_dropped++;
115 goto rx_irq_clean;
116 }
117
118 /* Copy frame from Rx fifo into the skb */
119 nps_enet_read_rx_fifo(ndev, skb->data, frame_len);
120
121 skb_put(skb, frame_len);
122 skb->protocol = eth_type_trans(skb, ndev);
123 skb->ip_summed = CHECKSUM_UNNECESSARY;
124
125 ndev->stats.rx_packets++;
126 ndev->stats.rx_bytes += frame_len;
127 netif_receive_skb(skb);
128
129 goto rx_irq_frame_done;
130
131rx_irq_clean:
132 /* Clean Rx fifo */
133 nps_enet_clean_rx_fifo(ndev, frame_len);
134
135rx_irq_frame_done:
136 /* Ack Rx ctrl register */
137 nps_enet_reg_set(priv, NPS_ENET_REG_RX_CTL, 0);
138
139 return work_done;
140}
141
142static void nps_enet_tx_handler(struct net_device *ndev)
143{
144 struct nps_enet_priv *priv = netdev_priv(ndev);
145 struct nps_enet_tx_ctl tx_ctrl;
146
147 tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL);
148
149 /* Check if we got TX */
150 if (!priv->tx_packet_sent || tx_ctrl.ct)
151 return;
152
153 /* Check Tx transmit error */
154 if (unlikely(tx_ctrl.et)) {
155 ndev->stats.tx_errors++;
156 } else {
157 ndev->stats.tx_packets++;
158 ndev->stats.tx_bytes += tx_ctrl.nt;
159 }
160
161 if (priv->tx_skb) {
162 dev_kfree_skb(priv->tx_skb);
163 priv->tx_skb = NULL;
164 }
165
166 priv->tx_packet_sent = false;
167
168 if (netif_queue_stopped(ndev))
169 netif_wake_queue(ndev);
170}
171
172/**
173 * nps_enet_poll - NAPI poll handler.
174 * @napi: Pointer to napi_struct structure.
175 * @budget: How many frames to process on one call.
176 *
177 * returns: Number of processed frames
178 */
179static int nps_enet_poll(struct napi_struct *napi, int budget)
180{
181 struct net_device *ndev = napi->dev;
182 struct nps_enet_priv *priv = netdev_priv(ndev);
183 struct nps_enet_buf_int_enable buf_int_enable;
184 u32 work_done;
185
186 buf_int_enable.rx_rdy = NPS_ENET_ENABLE;
187 buf_int_enable.tx_done = NPS_ENET_ENABLE;
188 nps_enet_tx_handler(ndev);
189 work_done = nps_enet_rx_handler(ndev);
190 if (work_done < budget) {
191 napi_complete(napi);
192 nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE,
193 buf_int_enable.value);
194 }
195
196 return work_done;
197}
198
199/**
200 * nps_enet_irq_handler - Global interrupt handler for ENET.
201 * @irq: irq number.
202 * @dev_instance: device instance.
203 *
204 * returns: IRQ_HANDLED for all cases.
205 *
206 * EZchip ENET has 2 interrupt causes, and depending on bits raised in
207 * CTRL registers we may tell what is a reason for interrupt to fire up.
208 * We got one for RX and the other for TX (completion).
209 */
210static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance)
211{
212 struct net_device *ndev = dev_instance;
213 struct nps_enet_priv *priv = netdev_priv(ndev);
214 struct nps_enet_buf_int_cause buf_int_cause;
215
216 buf_int_cause.value =
217 nps_enet_reg_get(priv, NPS_ENET_REG_BUF_INT_CAUSE);
218
219 if (buf_int_cause.tx_done || buf_int_cause.rx_rdy)
220 if (likely(napi_schedule_prep(&priv->napi))) {
221 nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0);
222 __napi_schedule(&priv->napi);
223 }
224
225 return IRQ_HANDLED;
226}
227
228static void nps_enet_set_hw_mac_address(struct net_device *ndev)
229{
230 struct nps_enet_priv *priv = netdev_priv(ndev);
231 struct nps_enet_ge_mac_cfg_1 ge_mac_cfg_1;
232 struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2;
233
234 /* set MAC address in HW */
235 ge_mac_cfg_1.octet_0 = ndev->dev_addr[0];
236 ge_mac_cfg_1.octet_1 = ndev->dev_addr[1];
237 ge_mac_cfg_1.octet_2 = ndev->dev_addr[2];
238 ge_mac_cfg_1.octet_3 = ndev->dev_addr[3];
239 ge_mac_cfg_2->octet_4 = ndev->dev_addr[4];
240 ge_mac_cfg_2->octet_5 = ndev->dev_addr[5];
241
242 nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_1,
243 ge_mac_cfg_1.value);
244
245 nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2,
246 ge_mac_cfg_2->value);
247}
248
249/**
250 * nps_enet_hw_reset - Reset the network device.
251 * @ndev: Pointer to the network device.
252 *
253 * This function reset the PCS and TX fifo.
254 * The programming model is to set the relevant reset bits
255 * wait for some time for this to propagate and then unset
256 * the reset bits. This way we ensure that reset procedure
257 * is done successfully by device.
258 */
259static void nps_enet_hw_reset(struct net_device *ndev)
260{
261 struct nps_enet_priv *priv = netdev_priv(ndev);
262 struct nps_enet_ge_rst ge_rst;
263 struct nps_enet_phase_fifo_ctl phase_fifo_ctl;
264
265 ge_rst.value = 0;
266 phase_fifo_ctl.value = 0;
267 /* Pcs reset sequence*/
268 ge_rst.gmac_0 = NPS_ENET_ENABLE;
269 nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value);
270 usleep_range(10, 20);
271 ge_rst.value = 0;
272 nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value);
273
274 /* Tx fifo reset sequence */
275 phase_fifo_ctl.rst = NPS_ENET_ENABLE;
276 phase_fifo_ctl.init = NPS_ENET_ENABLE;
277 nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL,
278 phase_fifo_ctl.value);
279 usleep_range(10, 20);
280 phase_fifo_ctl.value = 0;
281 nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL,
282 phase_fifo_ctl.value);
283}
284
285static void nps_enet_hw_enable_control(struct net_device *ndev)
286{
287 struct nps_enet_priv *priv = netdev_priv(ndev);
288 struct nps_enet_ge_mac_cfg_0 ge_mac_cfg_0;
289 struct nps_enet_buf_int_enable buf_int_enable;
290 struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2;
291 struct nps_enet_ge_mac_cfg_3 *ge_mac_cfg_3 = &priv->ge_mac_cfg_3;
292 s32 max_frame_length;
293
294 ge_mac_cfg_0.value = 0;
295 buf_int_enable.value = 0;
296 /* Enable Rx and Tx statistics */
297 ge_mac_cfg_2->stat_en = NPS_ENET_GE_MAC_CFG_2_STAT_EN;
298
299 /* Discard packets with different MAC address */
300 ge_mac_cfg_2->disc_da = NPS_ENET_ENABLE;
301
302 /* Discard multicast packets */
303 ge_mac_cfg_2->disc_mc = NPS_ENET_ENABLE;
304
305 nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2,
306 ge_mac_cfg_2->value);
307
308 /* Discard Packets bigger than max frame length */
309 max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN;
310 if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) {
311 ge_mac_cfg_3->max_len = max_frame_length;
312 nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3,
313 ge_mac_cfg_3->value);
314 }
315
316 /* Enable interrupts */
317 buf_int_enable.rx_rdy = NPS_ENET_ENABLE;
318 buf_int_enable.tx_done = NPS_ENET_ENABLE;
319 nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE,
320 buf_int_enable.value);
321
322 /* Write device MAC address to HW */
323 nps_enet_set_hw_mac_address(ndev);
324
325 /* Rx and Tx HW features */
326 ge_mac_cfg_0.tx_pad_en = NPS_ENET_ENABLE;
327 ge_mac_cfg_0.tx_crc_en = NPS_ENET_ENABLE;
328 ge_mac_cfg_0.rx_crc_strip = NPS_ENET_ENABLE;
329
330 /* IFG configuration */
331 ge_mac_cfg_0.rx_ifg = NPS_ENET_GE_MAC_CFG_0_RX_IFG;
332 ge_mac_cfg_0.tx_ifg = NPS_ENET_GE_MAC_CFG_0_TX_IFG;
333
334 /* preamble configuration */
335 ge_mac_cfg_0.rx_pr_check_en = NPS_ENET_ENABLE;
336 ge_mac_cfg_0.tx_pr_len = NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN;
337
338 /* enable flow control frames */
339 ge_mac_cfg_0.tx_fc_en = NPS_ENET_ENABLE;
340 ge_mac_cfg_0.rx_fc_en = NPS_ENET_ENABLE;
341 ge_mac_cfg_0.tx_fc_retr = NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR;
342
343 /* Enable Rx and Tx */
344 ge_mac_cfg_0.rx_en = NPS_ENET_ENABLE;
345 ge_mac_cfg_0.tx_en = NPS_ENET_ENABLE;
346
347 nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0,
348 ge_mac_cfg_0.value);
349}
350
351static void nps_enet_hw_disable_control(struct net_device *ndev)
352{
353 struct nps_enet_priv *priv = netdev_priv(ndev);
354
355 /* Disable interrupts */
356 nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0);
357
358 /* Disable Rx and Tx */
359 nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 0);
360}
361
362static void nps_enet_send_frame(struct net_device *ndev,
363 struct sk_buff *skb)
364{
365 struct nps_enet_priv *priv = netdev_priv(ndev);
366 struct nps_enet_tx_ctl tx_ctrl;
367 short length = skb->len;
368 u32 i, len = DIV_ROUND_UP(length, sizeof(u32));
369 u32 *src = (u32 *)virt_to_phys(skb->data);
370 bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32));
371
372 tx_ctrl.value = 0;
373 /* In case src is not aligned we need an intermediate buffer */
374 if (src_is_aligned)
375 for (i = 0; i < len; i++, src++)
376 nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src);
377 else { /* !src_is_aligned */
378 for (i = 0; i < len; i++, src++) {
379 u32 buf;
380
381 /* to accommodate word-unaligned address of "src"
382 * we have to do memcpy_fromio() instead of simple "="
383 */
384 memcpy_fromio(&buf, (void __iomem *)src, sizeof(buf));
385 nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, buf);
386 }
387 }
388 /* Write the length of the Frame */
389 tx_ctrl.nt = length;
390
391 /* Indicate SW is done */
392 priv->tx_packet_sent = true;
393 tx_ctrl.ct = NPS_ENET_ENABLE;
394
395 /* Send Frame */
396 nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl.value);
397}
398
399/**
400 * nps_enet_set_mac_address - Set the MAC address for this device.
401 * @ndev: Pointer to net_device structure.
402 * @p: 6 byte Address to be written as MAC address.
403 *
404 * This function copies the HW address from the sockaddr structure to the
405 * net_device structure and updates the address in HW.
406 *
407 * returns: -EBUSY if the net device is busy or 0 if the address is set
408 * successfully.
409 */
410static s32 nps_enet_set_mac_address(struct net_device *ndev, void *p)
411{
412 struct sockaddr *addr = p;
413 s32 res;
414
415 if (netif_running(ndev))
416 return -EBUSY;
417
418 res = eth_mac_addr(ndev, p);
419 if (!res) {
420 ether_addr_copy(ndev->dev_addr, addr->sa_data);
421 nps_enet_set_hw_mac_address(ndev);
422 }
423
424 return res;
425}
426
427/**
428 * nps_enet_set_rx_mode - Change the receive filtering mode.
429 * @ndev: Pointer to the network device.
430 *
431 * This function enables/disables promiscuous mode
432 */
433static void nps_enet_set_rx_mode(struct net_device *ndev)
434{
435 struct nps_enet_priv *priv = netdev_priv(ndev);
436 struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2;
437
438 ge_mac_cfg_2.value = priv->ge_mac_cfg_2.value;
439
440 if (ndev->flags & IFF_PROMISC) {
441 ge_mac_cfg_2.disc_da = NPS_ENET_DISABLE;
442 ge_mac_cfg_2.disc_mc = NPS_ENET_DISABLE;
443 } else {
444 ge_mac_cfg_2.disc_da = NPS_ENET_ENABLE;
445 ge_mac_cfg_2.disc_mc = NPS_ENET_ENABLE;
446 }
447
448 nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, ge_mac_cfg_2.value);
449}
450
451/**
452 * nps_enet_open - Open the network device.
453 * @ndev: Pointer to the network device.
454 *
455 * returns: 0, on success or non-zero error value on failure.
456 *
457 * This function sets the MAC address, requests and enables an IRQ
458 * for the ENET device and starts the Tx queue.
459 */
460static s32 nps_enet_open(struct net_device *ndev)
461{
462 struct nps_enet_priv *priv = netdev_priv(ndev);
463 s32 err;
464
465 /* Reset private variables */
466 priv->tx_packet_sent = false;
467 priv->ge_mac_cfg_2.value = 0;
468 priv->ge_mac_cfg_3.value = 0;
469
470 /* ge_mac_cfg_3 default values */
471 priv->ge_mac_cfg_3.rx_ifg_th = NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH;
472 priv->ge_mac_cfg_3.max_len = NPS_ENET_GE_MAC_CFG_3_MAX_LEN;
473
474 /* Disable HW device */
475 nps_enet_hw_disable_control(ndev);
476
477 /* irq Rx allocation */
478 err = request_irq(priv->irq, nps_enet_irq_handler,
479 0, "enet-rx-tx", ndev);
480 if (err)
481 return err;
482
483 napi_enable(&priv->napi);
484
485 /* Enable HW device */
486 nps_enet_hw_reset(ndev);
487 nps_enet_hw_enable_control(ndev);
488
489 netif_start_queue(ndev);
490
491 return 0;
492}
493
494/**
495 * nps_enet_stop - Close the network device.
496 * @ndev: Pointer to the network device.
497 *
498 * This function stops the Tx queue, disables interrupts for the ENET device.
499 */
500static s32 nps_enet_stop(struct net_device *ndev)
501{
502 struct nps_enet_priv *priv = netdev_priv(ndev);
503
504 napi_disable(&priv->napi);
505 netif_stop_queue(ndev);
506 nps_enet_hw_disable_control(ndev);
507 free_irq(priv->irq, ndev);
508
509 return 0;
510}
511
512/**
513 * nps_enet_start_xmit - Starts the data transmission.
514 * @skb: sk_buff pointer that contains data to be Transmitted.
515 * @ndev: Pointer to net_device structure.
516 *
517 * returns: NETDEV_TX_OK, on success
518 * NETDEV_TX_BUSY, if any of the descriptors are not free.
519 *
520 * This function is invoked from upper layers to initiate transmission.
521 */
522static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb,
523 struct net_device *ndev)
524{
525 struct nps_enet_priv *priv = netdev_priv(ndev);
526
527 /* This driver handles one frame at a time */
528 netif_stop_queue(ndev);
529
530 nps_enet_send_frame(ndev, skb);
531
532 priv->tx_skb = skb;
533
534 return NETDEV_TX_OK;
535}
536
537#ifdef CONFIG_NET_POLL_CONTROLLER
538static void nps_enet_poll_controller(struct net_device *ndev)
539{
540 disable_irq(ndev->irq);
541 nps_enet_irq_handler(ndev->irq, ndev);
542 enable_irq(ndev->irq);
543}
544#endif
545
546static const struct net_device_ops nps_netdev_ops = {
547 .ndo_open = nps_enet_open,
548 .ndo_stop = nps_enet_stop,
549 .ndo_start_xmit = nps_enet_start_xmit,
550 .ndo_set_mac_address = nps_enet_set_mac_address,
551 .ndo_set_rx_mode = nps_enet_set_rx_mode,
552#ifdef CONFIG_NET_POLL_CONTROLLER
553 .ndo_poll_controller = nps_enet_poll_controller,
554#endif
555};
556
557static s32 nps_enet_probe(struct platform_device *pdev)
558{
559 struct device *dev = &pdev->dev;
560 struct net_device *ndev;
561 struct nps_enet_priv *priv;
562 s32 err = 0;
563 const char *mac_addr;
564 struct resource *res_regs;
565
566 if (!dev->of_node)
567 return -ENODEV;
568
569 ndev = alloc_etherdev(sizeof(struct nps_enet_priv));
570 if (!ndev)
571 return -ENOMEM;
572
573 platform_set_drvdata(pdev, ndev);
574 SET_NETDEV_DEV(ndev, dev);
575 priv = netdev_priv(ndev);
576
577 /* The EZ NET specific entries in the device structure. */
578 ndev->netdev_ops = &nps_netdev_ops;
579 ndev->watchdog_timeo = (400 * HZ / 1000);
580 /* FIXME :: no multicast support yet */
581 ndev->flags &= ~IFF_MULTICAST;
582
583 res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
584 priv->regs_base = devm_ioremap_resource(dev, res_regs);
585 if (IS_ERR(priv->regs_base)) {
586 err = PTR_ERR(priv->regs_base);
587 goto out_netdev;
588 }
589 dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs_base);
590
591 /* set kernel MAC address to dev */
592 mac_addr = of_get_mac_address(dev->of_node);
593 if (mac_addr)
594 ether_addr_copy(ndev->dev_addr, mac_addr);
595 else
596 eth_hw_addr_random(ndev);
597
598 /* Get IRQ number */
599 priv->irq = platform_get_irq(pdev, 0);
600 if (!priv->irq) {
601 dev_err(dev, "failed to retrieve <irq Rx-Tx> value from device tree\n");
602 err = -ENODEV;
603 goto out_netdev;
604 }
605
606 netif_napi_add(ndev, &priv->napi, nps_enet_poll,
607 NPS_ENET_NAPI_POLL_WEIGHT);
608
609 /* Register the driver. Should be the last thing in probe */
610 err = register_netdev(ndev);
611 if (err) {
612 dev_err(dev, "Failed to register ndev for %s, err = 0x%08x\n",
613 ndev->name, (s32)err);
614 goto out_netif_api;
615 }
616
617 dev_info(dev, "(rx/tx=%d)\n", priv->irq);
618 return 0;
619
620out_netif_api:
621 netif_napi_del(&priv->napi);
622out_netdev:
623 if (err)
624 free_netdev(ndev);
625
626 return err;
627}
628
629static s32 nps_enet_remove(struct platform_device *pdev)
630{
631 struct net_device *ndev = platform_get_drvdata(pdev);
632 struct nps_enet_priv *priv = netdev_priv(ndev);
633
634 unregister_netdev(ndev);
635 free_netdev(ndev);
636 netif_napi_del(&priv->napi);
637
638 return 0;
639}
640
641static const struct of_device_id nps_enet_dt_ids[] = {
642 { .compatible = "ezchip,nps-mgt-enet" },
643 { /* Sentinel */ }
644};
645
646static struct platform_driver nps_enet_driver = {
647 .probe = nps_enet_probe,
648 .remove = nps_enet_remove,
649 .driver = {
650 .name = DRV_NAME,
651 .of_match_table = nps_enet_dt_ids,
652 },
653};
654
655module_platform_driver(nps_enet_driver);
656
657MODULE_AUTHOR("EZchip Semiconductor");
658MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/ezchip/nps_enet.h b/drivers/net/ethernet/ezchip/nps_enet.h
new file mode 100644
index 000000000000..fc45c9daa1c2
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/nps_enet.h
@@ -0,0 +1,336 @@
1/*
2 * Copyright(c) 2015 EZchip Technologies.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * The full GNU General Public License is included in this distribution in
14 * the file called "COPYING".
15 */
16
17#ifndef _NPS_ENET_H
18#define _NPS_ENET_H
19
20/* default values */
21#define NPS_ENET_NAPI_POLL_WEIGHT 0x2
22#define NPS_ENET_MAX_FRAME_LENGTH 0x3FFF
23#define NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR 0x7
24#define NPS_ENET_GE_MAC_CFG_0_RX_IFG 0x5
25#define NPS_ENET_GE_MAC_CFG_0_TX_IFG 0xC
26#define NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN 0x7
27#define NPS_ENET_GE_MAC_CFG_2_STAT_EN 0x3
28#define NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH 0x14
29#define NPS_ENET_GE_MAC_CFG_3_MAX_LEN 0x3FFC
30#define NPS_ENET_ENABLE 1
31#define NPS_ENET_DISABLE 0
32
33/* register definitions */
34#define NPS_ENET_REG_TX_CTL 0x800
35#define NPS_ENET_REG_TX_BUF 0x808
36#define NPS_ENET_REG_RX_CTL 0x810
37#define NPS_ENET_REG_RX_BUF 0x818
38#define NPS_ENET_REG_BUF_INT_ENABLE 0x8C0
39#define NPS_ENET_REG_BUF_INT_CAUSE 0x8C4
40#define NPS_ENET_REG_GE_MAC_CFG_0 0x1000
41#define NPS_ENET_REG_GE_MAC_CFG_1 0x1004
42#define NPS_ENET_REG_GE_MAC_CFG_2 0x1008
43#define NPS_ENET_REG_GE_MAC_CFG_3 0x100C
44#define NPS_ENET_REG_GE_RST 0x1400
45#define NPS_ENET_REG_PHASE_FIFO_CTL 0x1404
46
47/* Tx control register */
48struct nps_enet_tx_ctl {
49 union {
50 /* ct: SW sets to indicate frame ready in Tx buffer for
51 * transmission. HW resets to when transmission done
52 * et: Transmit error
53 * nt: Length in bytes of Tx frame loaded to Tx buffer
54 */
55 struct {
56 u32
57 __reserved_1:16,
58 ct:1,
59 et:1,
60 __reserved_2:3,
61 nt:11;
62 };
63
64 u32 value;
65 };
66};
67
68/* Rx control register */
69struct nps_enet_rx_ctl {
70 union {
71 /* cr: HW sets to indicate frame ready in Rx buffer.
72 * SW resets to indicate host read received frame
73 * and new frames can be written to Rx buffer
74 * er: Rx error indication
75 * crc: Rx CRC error indication
76 * nr: Length in bytes of Rx frame loaded by MAC to Rx buffer
77 */
78 struct {
79 u32
80 __reserved_1:16,
81 cr:1,
82 er:1,
83 crc:1,
84 __reserved_2:2,
85 nr:11;
86 };
87
88 u32 value;
89 };
90};
91
92/* Interrupt enable for data buffer events register */
93struct nps_enet_buf_int_enable {
94 union {
95 /* tx_done: Interrupt generation in the case when new frame
96 * is ready in Rx buffer
97 * rx_rdy: Interrupt generation in the case when current frame
98 * was read from TX buffer
99 */
100 struct {
101 u32
102 __reserved:30,
103 tx_done:1,
104 rx_rdy:1;
105 };
106
107 u32 value;
108 };
109};
110
111/* Interrupt cause for data buffer events register */
112struct nps_enet_buf_int_cause {
113 union {
114 /* tx_done: Interrupt in the case when current frame was
115 * read from TX buffer.
116 * rx_rdy: Interrupt in the case when new frame is ready
117 * in RX buffer.
118 */
119 struct {
120 u32
121 __reserved:30,
122 tx_done:1,
123 rx_rdy:1;
124 };
125
126 u32 value;
127 };
128};
129
130/* Gbps Eth MAC Configuration 0 register */
131struct nps_enet_ge_mac_cfg_0 {
132 union {
133 /* tx_pr_len: Transmit preamble length in bytes
134 * tx_ifg_nib: Tx idle pattern
135 * nib_mode: Nibble (4-bit) Mode
136 * rx_pr_check_en: Receive preamble Check Enable
137 * tx_ifg: Transmit inter-Frame Gap
138 * rx_ifg: Receive inter-Frame Gap
139 * tx_fc_retr: Transmit Flow Control Retransmit Mode
140 * rx_length_check_en: Receive Length Check Enable
141 * rx_crc_ignore: Results of the CRC check are ignored
142 * rx_crc_strip: MAC strips the CRC from received frames
143 * rx_fc_en: Receive Flow Control Enable
144 * tx_crc_en: Transmit CRC Enabled
145 * tx_pad_en: Transmit Padding Enable
146 * tx_cf_en: Transmit Flow Control Enable
147 * tx_en: Transmit Enable
148 * rx_en: Receive Enable
149 */
150 struct {
151 u32
152 tx_pr_len:4,
153 tx_ifg_nib:4,
154 nib_mode:1,
155 rx_pr_check_en:1,
156 tx_ifg:6,
157 rx_ifg:4,
158 tx_fc_retr:3,
159 rx_length_check_en:1,
160 rx_crc_ignore:1,
161 rx_crc_strip:1,
162 rx_fc_en:1,
163 tx_crc_en:1,
164 tx_pad_en:1,
165 tx_fc_en:1,
166 tx_en:1,
167 rx_en:1;
168 };
169
170 u32 value;
171 };
172};
173
174/* Gbps Eth MAC Configuration 1 register */
175struct nps_enet_ge_mac_cfg_1 {
176 union {
177 /* octet_3: MAC address octet 3
178 * octet_2: MAC address octet 2
179 * octet_1: MAC address octet 1
180 * octet_0: MAC address octet 0
181 */
182 struct {
183 u32
184 octet_3:8,
185 octet_2:8,
186 octet_1:8,
187 octet_0:8;
188 };
189
190 u32 value;
191 };
192};
193
194/* Gbps Eth MAC Configuration 2 register */
195struct nps_enet_ge_mac_cfg_2 {
196 union {
197 /* transmit_flush_en: MAC flush enable
198 * stat_en: RMON statistics interface enable
199 * disc_da: Discard frames with DA different
200 * from MAC address
201 * disc_bc: Discard broadcast frames
202 * disc_mc: Discard multicast frames
203 * octet_5: MAC address octet 5
204 * octet_4: MAC address octet 4
205 */
206 struct {
207 u32
208 transmit_flush_en:1,
209 __reserved_1:5,
210 stat_en:2,
211 __reserved_2:1,
212 disc_da:1,
213 disc_bc:1,
214 disc_mc:1,
215 __reserved_3:4,
216 octet_5:8,
217 octet_4:8;
218 };
219
220 u32 value;
221 };
222};
223
224/* Gbps Eth MAC Configuration 3 register */
225struct nps_enet_ge_mac_cfg_3 {
226 union {
227 /* ext_oob_cbfc_sel: Selects one of the 4 profiles for
228 * extended OOB in-flow-control indication
229 * max_len: Maximum receive frame length in bytes
230 * tx_cbfc_en: Enable transmission of class-based
231 * flow control packets
232 * rx_ifg_th: Threshold for IFG status reporting via OOB
233 * cf_timeout: Configurable time to decrement FC counters
234 * cf_drop: Drop control frames
235 * redirect_cbfc_sel: Selects one of CBFC redirect profiles
236 * rx_cbfc_redir_en: Enable Rx class-based flow
237 * control redirect
238 * rx_cbfc_en: Enable Rx class-based flow control
239 * tm_hd_mode: TM header mode
240 */
241 struct {
242 u32
243 ext_oob_cbfc_sel:2,
244 max_len:14,
245 tx_cbfc_en:1,
246 rx_ifg_th:5,
247 cf_timeout:4,
248 cf_drop:1,
249 redirect_cbfc_sel:2,
250 rx_cbfc_redir_en:1,
251 rx_cbfc_en:1,
252 tm_hd_mode:1;
253 };
254
255 u32 value;
256 };
257};
258
259/* GE MAC, PCS reset control register */
260struct nps_enet_ge_rst {
261 union {
262 /* gmac_0: GE MAC reset
263 * spcs_0: SGMII PCS reset
264 */
265 struct {
266 u32
267 __reserved_1:23,
268 gmac_0:1,
269 __reserved_2:7,
270 spcs_0:1;
271 };
272
273 u32 value;
274 };
275};
276
277/* Tx phase sync FIFO control register */
278struct nps_enet_phase_fifo_ctl {
279 union {
280 /* init: initialize serdes TX phase sync FIFO pointers
281 * rst: reset serdes TX phase sync FIFO
282 */
283 struct {
284 u32
285 __reserved:30,
286 init:1,
287 rst:1;
288 };
289
290 u32 value;
291 };
292};
293
294/**
295 * struct nps_enet_priv - Storage of ENET's private information.
296 * @regs_base: Base address of ENET memory-mapped control registers.
297 * @irq: For RX/TX IRQ number.
298 * @tx_packet_sent: SW indication if frame is being sent.
299 * @tx_skb: socket buffer of sent frame.
300 * @napi: Structure for NAPI.
301 */
302struct nps_enet_priv {
303 void __iomem *regs_base;
304 s32 irq;
305 bool tx_packet_sent;
306 struct sk_buff *tx_skb;
307 struct napi_struct napi;
308 struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2;
309 struct nps_enet_ge_mac_cfg_3 ge_mac_cfg_3;
310};
311
312/**
313 * nps_reg_set - Sets ENET register with provided value.
314 * @priv: Pointer to EZchip ENET private data structure.
315 * @reg: Register offset from base address.
316 * @value: Value to set in register.
317 */
318static inline void nps_enet_reg_set(struct nps_enet_priv *priv,
319 s32 reg, s32 value)
320{
321 iowrite32be(value, priv->regs_base + reg);
322}
323
324/**
325 * nps_reg_get - Gets value of specified ENET register.
326 * @priv: Pointer to EZchip ENET private data structure.
327 * @reg: Register offset from base address.
328 *
329 * returns: Value of requested register.
330 */
331static inline u32 nps_enet_reg_get(struct nps_enet_priv *priv, s32 reg)
332{
333 return ioread32be(priv->regs_base + reg);
334}
335
336#endif /* _NPS_ENET_H */