2 * Networking AIM - Networking Application Interface Module for MostCore
4 * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * This file is licensed under GPLv2.
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 #include <linux/module.h>
17 #include <linux/netdevice.h>
18 #include <linux/etherdevice.h>
19 #include <linux/slab.h>
20 #include <linux/init.h>
21 #include <linux/list.h>
22 #include <linux/wait.h>
23 #include <linux/kobject.h>
25 #include "networking.h"
29 #define MDP_HDR_LEN 16
30 #define MAMAC_DATA_LEN (1024 - MDP_HDR_LEN)
34 #define PMS_TELID_UNSEGM_MAMAC 0x0A
35 #define PMS_FIFONO_MDP 0x01
36 #define PMS_FIFONO_MEP 0x04
37 #define PMS_MSGTYPE_DATA 0x04
38 #define PMS_DEF_PRIO 0
39 #define MEP_DEF_RETRY 15
41 #define PMS_FIFONO_MASK 0x07
42 #define PMS_FIFONO_SHIFT 3
43 #define PMS_RETRY_SHIFT 4
44 #define PMS_TELID_MASK 0x0F
45 #define PMS_TELID_SHIFT 4
47 #define HB(value) ((u8)((u16)(value) >> 8))
48 #define LB(value) ((u8)(value))
52 #define EXTRACT_BIT_SET(bitset_name, value) \
53 (((value) >> bitset_name##_SHIFT) & bitset_name##_MASK)
55 #define PMS_IS_MEP(buf, len) \
56 ((len) > MEP_HDR_LEN && \
57 EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MEP)
59 #define PMS_IS_MAMAC(buf, len) \
60 ((len) > MDP_HDR_LEN && \
61 EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MDP && \
62 EXTRACT_BIT_SET(PMS_TELID, (buf)[14]) == PMS_TELID_UNSEGM_MAMAC)
64 struct net_dev_channel
{
69 struct net_dev_context
{
70 struct most_interface
*iface
;
73 unsigned char link_stat
;
74 struct net_device
*dev
;
75 struct net_dev_channel rx
;
76 struct net_dev_channel tx
;
77 struct list_head list
;
80 static struct list_head net_devices
= LIST_HEAD_INIT(net_devices
);
81 static struct spinlock list_lock
;
82 static struct most_aim aim
;
85 static int skb_to_mamac(const struct sk_buff
*skb
, struct mbo
*mbo
)
87 u8
*buff
= mbo
->virt_address
;
88 const u8 broadcast
[] = { 0x03, 0xFF };
89 const u8
*dest_addr
= skb
->data
+ 4;
90 const u8
*eth_type
= skb
->data
+ 12;
91 unsigned int payload_len
= skb
->len
- ETH_HLEN
;
92 unsigned int mdp_len
= payload_len
+ MDP_HDR_LEN
;
94 if (mbo
->buffer_length
< mdp_len
) {
95 pr_err("drop: too small buffer! (%d for %d)\n",
96 mbo
->buffer_length
, mdp_len
);
100 if (skb
->len
< ETH_HLEN
) {
101 pr_err("drop: too small packet! (%d)\n", skb
->len
);
105 if (dest_addr
[0] == 0xFF && dest_addr
[1] == 0xFF)
106 dest_addr
= broadcast
;
108 *buff
++ = HB(mdp_len
- 2);
109 *buff
++ = LB(mdp_len
- 2);
112 *buff
++ = (PMS_FIFONO_MDP
<< PMS_FIFONO_SHIFT
) | PMS_MSGTYPE_DATA
;
113 *buff
++ = PMS_DEF_PRIO
;
114 *buff
++ = dest_addr
[0];
115 *buff
++ = dest_addr
[1];
118 *buff
++ = HB(payload_len
+ 6);
119 *buff
++ = LB(payload_len
+ 6);
121 /* end of FPH here */
123 *buff
++ = eth_type
[0];
124 *buff
++ = eth_type
[1];
128 *buff
++ = PMS_TELID_UNSEGM_MAMAC
<< 4 | HB(payload_len
);
129 *buff
++ = LB(payload_len
);
131 memcpy(buff
, skb
->data
+ ETH_HLEN
, payload_len
);
132 mbo
->buffer_length
= mdp_len
;
136 static int skb_to_mep(const struct sk_buff
*skb
, struct mbo
*mbo
)
138 u8
*buff
= mbo
->virt_address
;
139 unsigned int mep_len
= skb
->len
+ MEP_HDR_LEN
;
141 if (mbo
->buffer_length
< mep_len
) {
142 pr_err("drop: too small buffer! (%d for %d)\n",
143 mbo
->buffer_length
, mep_len
);
147 *buff
++ = HB(mep_len
- 2);
148 *buff
++ = LB(mep_len
- 2);
151 *buff
++ = (PMS_FIFONO_MEP
<< PMS_FIFONO_SHIFT
) | PMS_MSGTYPE_DATA
;
152 *buff
++ = (MEP_DEF_RETRY
<< PMS_RETRY_SHIFT
) | PMS_DEF_PRIO
;
157 memcpy(buff
, skb
->data
, skb
->len
);
158 mbo
->buffer_length
= mep_len
;
162 static int most_nd_set_mac_address(struct net_device
*dev
, void *p
)
164 struct net_dev_context
*nd
= dev
->ml_priv
;
165 int err
= eth_mac_addr(dev
, p
);
170 BUG_ON(nd
->dev
!= dev
);
173 (dev
->dev_addr
[0] == 0 && dev
->dev_addr
[1] == 0 &&
174 dev
->dev_addr
[2] == 0 && dev
->dev_addr
[3] == 0);
177 * Set default MTU for the given packet type.
178 * It is still possible to change MTU using ip tools afterwards.
180 dev
->mtu
= nd
->is_mamac
? MAMAC_DATA_LEN
: ETH_DATA_LEN
;
185 static int most_nd_open(struct net_device
*dev
)
187 struct net_dev_context
*nd
= dev
->ml_priv
;
189 pr_info("open net device %s\n", dev
->name
);
191 BUG_ON(nd
->dev
!= dev
);
193 if (nd
->channels_opened
)
196 BUG_ON(!nd
->tx
.linked
|| !nd
->rx
.linked
);
198 if (most_start_channel(nd
->iface
, nd
->rx
.ch_id
)) {
199 pr_err("most_start_channel() failed\n");
203 if (most_start_channel(nd
->iface
, nd
->tx
.ch_id
)) {
204 pr_err("most_start_channel() failed\n");
205 most_stop_channel(nd
->iface
, nd
->rx
.ch_id
);
209 nd
->channels_opened
= true;
213 netif_wake_queue(dev
);
215 nd
->iface
->request_netinfo(nd
->iface
, nd
->tx
.ch_id
);
221 static int most_nd_stop(struct net_device
*dev
)
223 struct net_dev_context
*nd
= dev
->ml_priv
;
225 pr_info("stop net device %s\n", dev
->name
);
227 BUG_ON(nd
->dev
!= dev
);
228 netif_stop_queue(dev
);
230 if (nd
->channels_opened
) {
231 most_stop_channel(nd
->iface
, nd
->rx
.ch_id
);
232 most_stop_channel(nd
->iface
, nd
->tx
.ch_id
);
233 nd
->channels_opened
= false;
239 static netdev_tx_t
most_nd_start_xmit(struct sk_buff
*skb
,
240 struct net_device
*dev
)
242 struct net_dev_context
*nd
= dev
->ml_priv
;
246 BUG_ON(nd
->dev
!= dev
);
248 mbo
= most_get_mbo(nd
->iface
, nd
->tx
.ch_id
);
251 netif_stop_queue(dev
);
252 dev
->stats
.tx_fifo_errors
++;
253 return NETDEV_TX_BUSY
;
257 ret
= skb_to_mamac(skb
, mbo
);
259 ret
= skb_to_mep(skb
, mbo
);
263 dev
->stats
.tx_dropped
++;
268 most_submit_mbo(mbo
);
269 dev
->stats
.tx_packets
++;
270 dev
->stats
.tx_bytes
+= skb
->len
;
275 static const struct net_device_ops most_nd_ops
= {
276 .ndo_open
= most_nd_open
,
277 .ndo_stop
= most_nd_stop
,
278 .ndo_start_xmit
= most_nd_start_xmit
,
279 .ndo_set_mac_address
= most_nd_set_mac_address
,
282 static void most_nd_setup(struct net_device
*dev
)
284 pr_info("setup net device %s\n", dev
->name
);
286 dev
->netdev_ops
= &most_nd_ops
;
289 static void most_net_rm_netdev_safe(struct net_dev_context
*nd
)
294 pr_info("remove net device %p\n", nd
->dev
);
296 unregister_netdev(nd
->dev
);
297 free_netdev(nd
->dev
);
301 static struct net_dev_context
*get_net_dev_context(
302 struct most_interface
*iface
)
304 struct net_dev_context
*nd
, *tmp
;
306 spin_lock(&list_lock
);
307 list_for_each_entry_safe(nd
, tmp
, &net_devices
, list
) {
308 if (nd
->iface
== iface
) {
309 spin_unlock(&list_lock
);
313 spin_unlock(&list_lock
);
317 static int aim_probe_channel(struct most_interface
*iface
, int channel_idx
,
318 struct most_channel_config
*ccfg
,
319 struct kobject
*parent
, char *name
)
321 struct net_dev_context
*nd
;
322 struct net_dev_channel
*ch
;
327 if (ccfg
->data_type
!= MOST_CH_ASYNC
)
330 nd
= get_net_dev_context(iface
);
333 nd
= kzalloc(sizeof(*nd
), GFP_KERNEL
);
339 spin_lock(&list_lock
);
340 list_add(&nd
->list
, &net_devices
);
341 spin_unlock(&list_lock
);
344 ch
= ccfg
->direction
== MOST_CH_TX
? &nd
->tx
: &nd
->rx
;
346 pr_err("only one channel per instance & direction allowed\n");
350 if (nd
->tx
.linked
|| nd
->rx
.linked
) {
351 struct net_device
*dev
=
352 alloc_netdev(0, "meth%d", NET_NAME_UNKNOWN
, most_nd_setup
);
355 pr_err("no memory for net_device\n");
362 if (register_netdev(dev
)) {
363 pr_err("registering net device failed\n");
369 ch
->ch_id
= channel_idx
;
375 static int aim_disconnect_channel(struct most_interface
*iface
,
378 struct net_dev_context
*nd
;
379 struct net_dev_channel
*ch
;
381 nd
= get_net_dev_context(iface
);
385 if (nd
->rx
.linked
&& channel_idx
== nd
->rx
.ch_id
)
387 else if (nd
->tx
.linked
&& channel_idx
== nd
->tx
.ch_id
)
395 * do not call most_stop_channel() here, because channels are
396 * going to be closed in ndo_stop() after unregister_netdev()
398 most_net_rm_netdev_safe(nd
);
400 if (!nd
->rx
.linked
&& !nd
->tx
.linked
) {
401 spin_lock(&list_lock
);
403 spin_unlock(&list_lock
);
410 static int aim_resume_tx_channel(struct most_interface
*iface
,
413 struct net_dev_context
*nd
;
415 nd
= get_net_dev_context(iface
);
416 if (!nd
|| !nd
->channels_opened
|| nd
->tx
.ch_id
!= channel_idx
)
422 netif_wake_queue(nd
->dev
);
426 static int aim_rx_data(struct mbo
*mbo
)
429 struct net_dev_context
*nd
;
430 char *buf
= mbo
->virt_address
;
431 uint32_t len
= mbo
->processed_length
;
433 struct net_device
*dev
;
435 nd
= get_net_dev_context(mbo
->ifp
);
436 if (!nd
|| !nd
->channels_opened
|| nd
->rx
.ch_id
!= mbo
->hdm_channel_id
)
441 pr_err_once("drop packet: missing net_device\n");
446 if (!PMS_IS_MAMAC(buf
, len
))
449 skb
= dev_alloc_skb(len
- MDP_HDR_LEN
+ 2 * ETH_ALEN
+ 2);
451 if (!PMS_IS_MEP(buf
, len
))
454 skb
= dev_alloc_skb(len
- MEP_HDR_LEN
);
458 dev
->stats
.rx_dropped
++;
459 pr_err_once("drop packet: no memory for skb\n");
467 memcpy(skb_put(skb
, ETH_ALEN
), dev
->dev_addr
, ETH_ALEN
);
470 memcpy(skb_put(skb
, 4), &zero
, 4);
471 memcpy(skb_put(skb
, 2), buf
+ 5, 2);
474 memcpy(skb_put(skb
, 2), buf
+ 10, 2);
483 memcpy(skb_put(skb
, len
), buf
, len
);
484 skb
->protocol
= eth_type_trans(skb
, dev
);
485 dev
->stats
.rx_packets
++;
486 dev
->stats
.rx_bytes
+= skb
->len
;
494 static int __init
most_net_init(void)
496 pr_info("most_net_init()\n");
497 spin_lock_init(&list_lock
);
498 aim
.name
= "networking";
499 aim
.probe_channel
= aim_probe_channel
;
500 aim
.disconnect_channel
= aim_disconnect_channel
;
501 aim
.tx_completion
= aim_resume_tx_channel
;
502 aim
.rx_completion
= aim_rx_data
;
503 return most_register_aim(&aim
);
506 static void __exit
most_net_exit(void)
508 struct net_dev_context
*nd
, *tmp
;
510 spin_lock(&list_lock
);
511 list_for_each_entry_safe(nd
, tmp
, &net_devices
, list
) {
513 spin_unlock(&list_lock
);
515 * do not call most_stop_channel() here, because channels are
516 * going to be closed in ndo_stop() after unregister_netdev()
518 most_net_rm_netdev_safe(nd
);
520 spin_lock(&list_lock
);
522 spin_unlock(&list_lock
);
524 most_deregister_aim(&aim
);
525 pr_info("most_net_exit()\n");
529 * most_deliver_netinfo - callback for HDM to be informed about HW's MAC
530 * @param iface - most interface instance
531 * @param link_stat - link status
532 * @param mac_addr - MAC address
534 void most_deliver_netinfo(struct most_interface
*iface
,
535 unsigned char link_stat
, unsigned char *mac_addr
)
537 struct net_dev_context
*nd
;
538 struct net_device
*dev
;
540 pr_info("Received netinfo from %s\n", iface
->description
);
542 nd
= get_net_dev_context(iface
);
551 memcpy(dev
->dev_addr
, mac_addr
, ETH_ALEN
);
553 if (nd
->link_stat
!= link_stat
) {
554 nd
->link_stat
= link_stat
;
556 netif_wake_queue(dev
);
558 netif_stop_queue(dev
);
561 EXPORT_SYMBOL(most_deliver_netinfo
);
563 module_init(most_net_init
);
564 module_exit(most_net_exit
);
565 MODULE_LICENSE("GPL");
566 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
567 MODULE_DESCRIPTION("Networking Application Interface Module for MostCore");