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>
27 #define MDP_HDR_LEN 16
28 #define MAMAC_DATA_LEN (1024 - MDP_HDR_LEN)
32 #define PMS_TELID_UNSEGM_MAMAC 0x0A
33 #define PMS_FIFONO_MDP 0x01
34 #define PMS_FIFONO_MEP 0x04
35 #define PMS_MSGTYPE_DATA 0x04
36 #define PMS_DEF_PRIO 0
37 #define MEP_DEF_RETRY 15
39 #define PMS_FIFONO_MASK 0x07
40 #define PMS_FIFONO_SHIFT 3
41 #define PMS_RETRY_SHIFT 4
42 #define PMS_TELID_MASK 0x0F
43 #define PMS_TELID_SHIFT 4
45 #define HB(value) ((u8)((u16)(value) >> 8))
46 #define LB(value) ((u8)(value))
48 #define EXTRACT_BIT_SET(bitset_name, value) \
49 (((value) >> bitset_name##_SHIFT) & bitset_name##_MASK)
51 #define PMS_IS_MEP(buf, len) \
52 ((len) > MEP_HDR_LEN && \
53 EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MEP)
55 #define PMS_IS_MAMAC(buf, len) \
56 ((len) > MDP_HDR_LEN && \
57 EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MDP && \
58 EXTRACT_BIT_SET(PMS_TELID, (buf)[14]) == PMS_TELID_UNSEGM_MAMAC)
60 struct net_dev_channel {
65 struct net_dev_context {
66 struct most_interface *iface;
68 struct net_device *dev;
69 struct net_dev_channel rx;
70 struct net_dev_channel tx;
71 struct list_head list;
74 static struct list_head net_devices = LIST_HEAD_INIT(net_devices);
75 static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */
76 static struct spinlock list_lock; /* list_head, ch->linked = false, dev_hold */
77 static struct most_aim aim;
79 static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo)
81 u8 *buff = mbo->virt_address;
82 const u8 broadcast[] = { 0x03, 0xFF };
83 const u8 *dest_addr = skb->data + 4;
84 const u8 *eth_type = skb->data + 12;
85 unsigned int payload_len = skb->len - ETH_HLEN;
86 unsigned int mdp_len = payload_len + MDP_HDR_LEN;
88 if (mdp_len < skb->len) {
89 pr_err("drop: too large packet! (%u)\n", skb->len);
93 if (mbo->buffer_length < mdp_len) {
94 pr_err("drop: too small buffer! (%d for %d)\n",
95 mbo->buffer_length, mdp_len);
99 if (skb->len < ETH_HLEN) {
100 pr_err("drop: too small packet! (%d)\n", skb->len);
104 if (dest_addr[0] == 0xFF && dest_addr[1] == 0xFF)
105 dest_addr = broadcast;
107 *buff++ = HB(mdp_len - 2);
108 *buff++ = LB(mdp_len - 2);
111 *buff++ = (PMS_FIFONO_MDP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA;
112 *buff++ = PMS_DEF_PRIO;
113 *buff++ = dest_addr[0];
114 *buff++ = dest_addr[1];
117 *buff++ = HB(payload_len + 6);
118 *buff++ = LB(payload_len + 6);
120 /* end of FPH here */
122 *buff++ = eth_type[0];
123 *buff++ = eth_type[1];
127 *buff++ = PMS_TELID_UNSEGM_MAMAC << 4 | HB(payload_len);
128 *buff++ = LB(payload_len);
130 memcpy(buff, skb->data + ETH_HLEN, payload_len);
131 mbo->buffer_length = mdp_len;
135 static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo)
137 u8 *buff = mbo->virt_address;
138 unsigned int mep_len = skb->len + MEP_HDR_LEN;
140 if (mep_len < skb->len) {
141 pr_err("drop: too large packet! (%u)\n", skb->len);
145 if (mbo->buffer_length < mep_len) {
146 pr_err("drop: too small buffer! (%d for %d)\n",
147 mbo->buffer_length, mep_len);
151 *buff++ = HB(mep_len - 2);
152 *buff++ = LB(mep_len - 2);
155 *buff++ = (PMS_FIFONO_MEP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA;
156 *buff++ = (MEP_DEF_RETRY << PMS_RETRY_SHIFT) | PMS_DEF_PRIO;
161 memcpy(buff, skb->data, skb->len);
162 mbo->buffer_length = mep_len;
166 static int most_nd_set_mac_address(struct net_device *dev, void *p)
168 struct net_dev_context *nd = netdev_priv(dev);
169 int err = eth_mac_addr(dev, p);
175 (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0 &&
176 dev->dev_addr[2] == 0 && dev->dev_addr[3] == 0);
179 * Set default MTU for the given packet type.
180 * It is still possible to change MTU using ip tools afterwards.
182 dev->mtu = nd->is_mamac ? MAMAC_DATA_LEN : ETH_DATA_LEN;
187 static void on_netinfo(struct most_interface *iface,
188 unsigned char link_stat, unsigned char *mac_addr);
190 static int most_nd_open(struct net_device *dev)
192 struct net_dev_context *nd = netdev_priv(dev);
195 mutex_lock(&probe_disc_mt);
197 if (most_start_channel(nd->iface, nd->rx.ch_id, &aim)) {
198 netdev_err(dev, "most_start_channel() failed\n");
203 if (most_start_channel(nd->iface, nd->tx.ch_id, &aim)) {
204 netdev_err(dev, "most_start_channel() failed\n");
205 most_stop_channel(nd->iface, nd->rx.ch_id, &aim);
210 netif_carrier_off(dev);
211 if (is_valid_ether_addr(dev->dev_addr))
212 netif_dormant_off(dev);
214 netif_dormant_on(dev);
215 netif_wake_queue(dev);
216 if (nd->iface->request_netinfo)
217 nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, on_netinfo);
220 mutex_unlock(&probe_disc_mt);
224 static int most_nd_stop(struct net_device *dev)
226 struct net_dev_context *nd = netdev_priv(dev);
228 netif_stop_queue(dev);
229 if (nd->iface->request_netinfo)
230 nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, NULL);
231 most_stop_channel(nd->iface, nd->rx.ch_id, &aim);
232 most_stop_channel(nd->iface, nd->tx.ch_id, &aim);
237 static netdev_tx_t most_nd_start_xmit(struct sk_buff *skb,
238 struct net_device *dev)
240 struct net_dev_context *nd = netdev_priv(dev);
244 mbo = most_get_mbo(nd->iface, nd->tx.ch_id, &aim);
247 netif_stop_queue(dev);
248 dev->stats.tx_fifo_errors++;
249 return NETDEV_TX_BUSY;
253 ret = skb_to_mamac(skb, mbo);
255 ret = skb_to_mep(skb, mbo);
259 dev->stats.tx_dropped++;
264 most_submit_mbo(mbo);
265 dev->stats.tx_packets++;
266 dev->stats.tx_bytes += skb->len;
271 static const struct net_device_ops most_nd_ops = {
272 .ndo_open = most_nd_open,
273 .ndo_stop = most_nd_stop,
274 .ndo_start_xmit = most_nd_start_xmit,
275 .ndo_set_mac_address = most_nd_set_mac_address,
278 static void most_nd_setup(struct net_device *dev)
281 dev->netdev_ops = &most_nd_ops;
284 static struct net_dev_context *get_net_dev(struct most_interface *iface)
286 struct net_dev_context *nd;
288 list_for_each_entry(nd, &net_devices, list)
289 if (nd->iface == iface)
294 static struct net_dev_context *get_net_dev_hold(struct most_interface *iface)
296 struct net_dev_context *nd;
299 spin_lock_irqsave(&list_lock, flags);
300 nd = get_net_dev(iface);
301 if (nd && nd->rx.linked && nd->tx.linked)
305 spin_unlock_irqrestore(&list_lock, flags);
309 static int aim_probe_channel(struct most_interface *iface, int channel_idx,
310 struct most_channel_config *ccfg,
311 struct kobject *parent, char *name)
313 struct net_dev_context *nd;
314 struct net_dev_channel *ch;
315 struct net_device *dev;
322 if (ccfg->data_type != MOST_CH_ASYNC)
325 mutex_lock(&probe_disc_mt);
326 nd = get_net_dev(iface);
328 dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d",
329 NET_NAME_UNKNOWN, most_nd_setup);
335 nd = netdev_priv(dev);
339 spin_lock_irqsave(&list_lock, flags);
340 list_add(&nd->list, &net_devices);
341 spin_unlock_irqrestore(&list_lock, flags);
343 ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx;
345 ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx;
347 pr_err("direction is allocated\n");
352 if (register_netdev(nd->dev)) {
353 pr_err("register_netdev() failed\n");
358 ch->ch_id = channel_idx;
362 mutex_unlock(&probe_disc_mt);
366 static int aim_disconnect_channel(struct most_interface *iface,
369 struct net_dev_context *nd;
370 struct net_dev_channel *ch;
374 mutex_lock(&probe_disc_mt);
375 nd = get_net_dev(iface);
381 if (nd->rx.linked && channel_idx == nd->rx.ch_id) {
383 } else if (nd->tx.linked && channel_idx == nd->tx.ch_id) {
390 if (nd->rx.linked && nd->tx.linked) {
391 spin_lock_irqsave(&list_lock, flags);
393 spin_unlock_irqrestore(&list_lock, flags);
396 * do not call most_stop_channel() here, because channels are
397 * going to be closed in ndo_stop() after unregister_netdev()
399 unregister_netdev(nd->dev);
401 spin_lock_irqsave(&list_lock, flags);
403 spin_unlock_irqrestore(&list_lock, flags);
405 free_netdev(nd->dev);
409 mutex_unlock(&probe_disc_mt);
413 static int aim_resume_tx_channel(struct most_interface *iface,
416 struct net_dev_context *nd;
418 nd = get_net_dev_hold(iface);
422 if (nd->tx.ch_id != channel_idx)
425 netif_wake_queue(nd->dev);
432 static int aim_rx_data(struct mbo *mbo)
435 struct net_dev_context *nd;
436 char *buf = mbo->virt_address;
437 u32 len = mbo->processed_length;
439 struct net_device *dev;
440 unsigned int skb_len;
443 nd = get_net_dev_hold(mbo->ifp);
447 if (nd->rx.ch_id != mbo->hdm_channel_id) {
455 if (!PMS_IS_MAMAC(buf, len)) {
460 skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2);
462 if (!PMS_IS_MEP(buf, len)) {
467 skb = dev_alloc_skb(len - MEP_HDR_LEN);
471 dev->stats.rx_dropped++;
472 pr_err_once("drop packet: no memory for skb\n");
480 ether_addr_copy(skb_put(skb, ETH_ALEN), dev->dev_addr);
483 skb_put_data(skb, &zero, 4);
484 skb_put_data(skb, buf + 5, 2);
487 skb_put_data(skb, buf + 10, 2);
496 skb_put_data(skb, buf, len);
497 skb->protocol = eth_type_trans(skb, dev);
499 if (netif_rx(skb) == NET_RX_SUCCESS) {
500 dev->stats.rx_packets++;
501 dev->stats.rx_bytes += skb_len;
503 dev->stats.rx_dropped++;
514 static struct most_aim aim = {
515 .name = "networking",
516 .probe_channel = aim_probe_channel,
517 .disconnect_channel = aim_disconnect_channel,
518 .tx_completion = aim_resume_tx_channel,
519 .rx_completion = aim_rx_data,
522 static int __init most_net_init(void)
524 spin_lock_init(&list_lock);
525 mutex_init(&probe_disc_mt);
526 return most_register_aim(&aim);
529 static void __exit most_net_exit(void)
531 most_deregister_aim(&aim);
535 * on_netinfo - callback for HDM to be informed about HW's MAC
536 * @param iface - most interface instance
537 * @param link_stat - link status
538 * @param mac_addr - MAC address
540 static void on_netinfo(struct most_interface *iface,
541 unsigned char link_stat, unsigned char *mac_addr)
543 struct net_dev_context *nd;
544 struct net_device *dev;
545 const u8 *m = mac_addr;
547 nd = get_net_dev_hold(iface);
554 netif_carrier_on(dev);
556 netif_carrier_off(dev);
558 if (m && is_valid_ether_addr(m)) {
559 if (!is_valid_ether_addr(dev->dev_addr)) {
560 netdev_info(dev, "set mac %02x-%02x-%02x-%02x-%02x-%02x\n",
561 m[0], m[1], m[2], m[3], m[4], m[5]);
562 ether_addr_copy(dev->dev_addr, m);
563 netif_dormant_off(dev);
564 } else if (!ether_addr_equal(dev->dev_addr, m)) {
565 netdev_warn(dev, "reject mac %02x-%02x-%02x-%02x-%02x-%02x\n",
566 m[0], m[1], m[2], m[3], m[4], m[5]);
573 module_init(most_net_init);
574 module_exit(most_net_exit);
575 MODULE_LICENSE("GPL");
576 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
577 MODULE_DESCRIPTION("Networking Application Interface Module for MostCore");