dd368721b7277e34e9c6f61fd58dc6200465c484
[firefly-linux-kernel-4.4.55.git] / drivers / staging / most / aim-network / networking.c
1 /*
2  * Networking AIM - Networking Application Interface Module for MostCore
3  *
4  * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
5  *
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.
10  *
11  * This file is licensed under GPLv2.
12  */
13
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
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>
24 #include "mostcore.h"
25 #include "networking.h"
26
27
28 #define MEP_HDR_LEN 8
29 #define MDP_HDR_LEN 16
30 #define MAMAC_DATA_LEN (1024 - MDP_HDR_LEN)
31
32 #define PMHL 5
33
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
40
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
46
47 #define HB(value)               ((u8)((u16)(value) >> 8))
48 #define LB(value)               ((u8)(value))
49
50
51
52 #define EXTRACT_BIT_SET(bitset_name, value) \
53         (((value) >> bitset_name##_SHIFT) & bitset_name##_MASK)
54
55 #define PMS_IS_MEP(buf, len) \
56         ((len) > MEP_HDR_LEN && \
57          EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MEP)
58
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)
63
64 struct net_dev_channel {
65         bool linked;
66         int ch_id;
67 };
68
69 struct net_dev_context {
70         struct most_interface *iface;
71         bool channels_opened;
72         bool is_mamac;
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;
78 };
79
80 static struct list_head net_devices = LIST_HEAD_INIT(net_devices);
81 static struct spinlock list_lock;
82
83
84 static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo)
85 {
86         u8 *buff = mbo->virt_address;
87         const u8 broadcast[] = { 0x03, 0xFF };
88         const u8 *dest_addr = skb->data + 4;
89         const u8 *eth_type = skb->data + 12;
90         unsigned int payload_len = skb->len - ETH_HLEN;
91         unsigned int mdp_len = payload_len + MDP_HDR_LEN;
92
93         if (mbo->buffer_length < mdp_len) {
94                 pr_err("drop: too small buffer! (%d for %d)\n",
95                        mbo->buffer_length, mdp_len);
96                 return -EINVAL;
97         }
98
99         if (skb->len < ETH_HLEN) {
100                 pr_err("drop: too small packet! (%d)\n", skb->len);
101                 return -EINVAL;
102         }
103
104         if (dest_addr[0] == 0xFF && dest_addr[1] == 0xFF)
105                 dest_addr = broadcast;
106
107         *buff++ = HB(mdp_len - 2);
108         *buff++ = LB(mdp_len - 2);
109
110         *buff++ = PMHL;
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];
115         *buff++ = 0x00;
116
117         *buff++ = HB(payload_len + 6);
118         *buff++ = LB(payload_len + 6);
119
120         /* end of FPH here */
121
122         *buff++ = eth_type[0];
123         *buff++ = eth_type[1];
124         *buff++ = 0;
125         *buff++ = 0;
126
127         *buff++ = PMS_TELID_UNSEGM_MAMAC << 4 | HB(payload_len);
128         *buff++ = LB(payload_len);
129
130         memcpy(buff, skb->data + ETH_HLEN, payload_len);
131         mbo->buffer_length = mdp_len;
132         return 0;
133 }
134
135 static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo)
136 {
137         u8 *buff = mbo->virt_address;
138         unsigned int mep_len = skb->len + MEP_HDR_LEN;
139
140         if (mbo->buffer_length < mep_len) {
141                 pr_err("drop: too small buffer! (%d for %d)\n",
142                        mbo->buffer_length, mep_len);
143                 return -EINVAL;
144         }
145
146         *buff++ = HB(mep_len - 2);
147         *buff++ = LB(mep_len - 2);
148
149         *buff++ = PMHL;
150         *buff++ = (PMS_FIFONO_MEP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA;
151         *buff++ = (MEP_DEF_RETRY << PMS_RETRY_SHIFT) | PMS_DEF_PRIO;
152         *buff++ = 0;
153         *buff++ = 0;
154         *buff++ = 0;
155
156         memcpy(buff, skb->data, skb->len);
157         mbo->buffer_length = mep_len;
158         return 0;
159 }
160
161 static int most_nd_set_mac_address(struct net_device *dev, void *p)
162 {
163         struct net_dev_context *nd = dev->ml_priv;
164         int err = eth_mac_addr(dev, p);
165
166         if (err)
167                 return err;
168
169         BUG_ON(nd->dev != dev);
170
171         nd->is_mamac =
172                 (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0 &&
173                  dev->dev_addr[2] == 0 && dev->dev_addr[3] == 0);
174
175         /*
176          * Set default MTU for the given packet type.
177          * It is still possible to change MTU using ip tools afterwards.
178          */
179         dev->mtu = nd->is_mamac ? MAMAC_DATA_LEN : ETH_DATA_LEN;
180
181         return 0;
182 }
183
184 static int most_nd_open(struct net_device *dev)
185 {
186         struct net_dev_context *nd = dev->ml_priv;
187
188         netdev_info(dev, "open net device\n");
189
190         BUG_ON(nd->dev != dev);
191
192         if (nd->channels_opened)
193                 return -EFAULT;
194
195         BUG_ON(!nd->tx.linked || !nd->rx.linked);
196
197         if (most_start_channel(nd->iface, nd->rx.ch_id)) {
198                 netdev_err(dev, "most_start_channel() failed\n");
199                 return -EBUSY;
200         }
201
202         if (most_start_channel(nd->iface, nd->tx.ch_id)) {
203                 netdev_err(dev, "most_start_channel() failed\n");
204                 most_stop_channel(nd->iface, nd->rx.ch_id);
205                 return -EBUSY;
206         }
207
208         nd->channels_opened = true;
209
210         if (nd->is_mamac) {
211                 nd->link_stat = 1;
212                 netif_wake_queue(dev);
213         } else {
214                 nd->iface->request_netinfo(nd->iface, nd->tx.ch_id);
215         }
216
217         return 0;
218 }
219
220 static int most_nd_stop(struct net_device *dev)
221 {
222         struct net_dev_context *nd = dev->ml_priv;
223
224         netdev_info(dev, "stop net device\n");
225
226         BUG_ON(nd->dev != dev);
227         netif_stop_queue(dev);
228
229         if (nd->channels_opened) {
230                 most_stop_channel(nd->iface, nd->rx.ch_id);
231                 most_stop_channel(nd->iface, nd->tx.ch_id);
232                 nd->channels_opened = false;
233         }
234
235         return 0;
236 }
237
238 static netdev_tx_t most_nd_start_xmit(struct sk_buff *skb,
239                                       struct net_device *dev)
240 {
241         struct net_dev_context *nd = dev->ml_priv;
242         struct mbo *mbo;
243         int ret;
244
245         BUG_ON(nd->dev != dev);
246
247         mbo = most_get_mbo(nd->iface, nd->tx.ch_id);
248
249         if (!mbo) {
250                 netif_stop_queue(dev);
251                 dev->stats.tx_fifo_errors++;
252                 return NETDEV_TX_BUSY;
253         }
254
255         if (nd->is_mamac)
256                 ret = skb_to_mamac(skb, mbo);
257         else
258                 ret = skb_to_mep(skb, mbo);
259
260         if (ret) {
261                 most_put_mbo(mbo);
262                 dev->stats.tx_dropped++;
263                 kfree_skb(skb);
264                 return NETDEV_TX_OK;
265         }
266
267         most_submit_mbo(mbo);
268         dev->stats.tx_packets++;
269         dev->stats.tx_bytes += skb->len;
270         kfree_skb(skb);
271         return NETDEV_TX_OK;
272 }
273
274 static const struct net_device_ops most_nd_ops = {
275         .ndo_open = most_nd_open,
276         .ndo_stop = most_nd_stop,
277         .ndo_start_xmit = most_nd_start_xmit,
278         .ndo_set_mac_address = most_nd_set_mac_address,
279 };
280
281 static void most_nd_setup(struct net_device *dev)
282 {
283         netdev_info(dev, "setup net device\n");
284         ether_setup(dev);
285         dev->netdev_ops = &most_nd_ops;
286 }
287
288 static void most_net_rm_netdev_safe(struct net_dev_context *nd)
289 {
290         if (!nd->dev)
291                 return;
292
293         pr_info("remove net device %p\n", nd->dev);
294
295         unregister_netdev(nd->dev);
296         free_netdev(nd->dev);
297         nd->dev = NULL;
298 }
299
300 static struct net_dev_context *get_net_dev_context(
301         struct most_interface *iface)
302 {
303         struct net_dev_context *nd, *tmp;
304
305         spin_lock(&list_lock);
306         list_for_each_entry_safe(nd, tmp, &net_devices, list) {
307                 if (nd->iface == iface) {
308                         spin_unlock(&list_lock);
309                         return nd;
310                 }
311         }
312         spin_unlock(&list_lock);
313         return NULL;
314 }
315
316 static int aim_probe_channel(struct most_interface *iface, int channel_idx,
317                              struct most_channel_config *ccfg,
318                              struct kobject *parent, char *name)
319 {
320         struct net_dev_context *nd;
321         struct net_dev_channel *ch;
322
323         if (!iface)
324                 return -EINVAL;
325
326         if (ccfg->data_type != MOST_CH_ASYNC)
327                 return -EINVAL;
328
329         nd = get_net_dev_context(iface);
330
331         if (!nd) {
332                 nd = kzalloc(sizeof(*nd), GFP_KERNEL);
333                 if (!nd)
334                         return -ENOMEM;
335
336                 nd->iface = iface;
337
338                 spin_lock(&list_lock);
339                 list_add(&nd->list, &net_devices);
340                 spin_unlock(&list_lock);
341         }
342
343         ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx;
344         if (ch->linked) {
345                 pr_err("only one channel per instance & direction allowed\n");
346                 return -EINVAL;
347         }
348
349         if (nd->tx.linked || nd->rx.linked) {
350                 struct net_device *dev =
351                         alloc_netdev(0, "meth%d", NET_NAME_UNKNOWN, most_nd_setup);
352
353                 if (!dev) {
354                         pr_err("no memory for net_device\n");
355                         return -ENOMEM;
356                 }
357
358                 nd->dev = dev;
359
360                 dev->ml_priv = nd;
361                 if (register_netdev(dev)) {
362                         pr_err("registering net device failed\n");
363                         free_netdev(dev);
364                         return -EINVAL;
365                 }
366         }
367
368         ch->ch_id = channel_idx;
369         ch->linked = true;
370
371         return 0;
372 }
373
374 static int aim_disconnect_channel(struct most_interface *iface,
375                                   int channel_idx)
376 {
377         struct net_dev_context *nd;
378         struct net_dev_channel *ch;
379
380         nd = get_net_dev_context(iface);
381         if (!nd)
382                 return -EINVAL;
383
384         if (nd->rx.linked && channel_idx == nd->rx.ch_id)
385                 ch = &nd->rx;
386         else if (nd->tx.linked && channel_idx == nd->tx.ch_id)
387                 ch = &nd->tx;
388         else
389                 return -EINVAL;
390
391         ch->linked = false;
392
393         /*
394          * do not call most_stop_channel() here, because channels are
395          * going to be closed in ndo_stop() after unregister_netdev()
396          */
397         most_net_rm_netdev_safe(nd);
398
399         if (!nd->rx.linked && !nd->tx.linked) {
400                 spin_lock(&list_lock);
401                 list_del(&nd->list);
402                 spin_unlock(&list_lock);
403                 kfree(nd);
404         }
405
406         return 0;
407 }
408
409 static int aim_resume_tx_channel(struct most_interface *iface,
410                                  int channel_idx)
411 {
412         struct net_dev_context *nd;
413
414         nd = get_net_dev_context(iface);
415         if (!nd || !nd->channels_opened || nd->tx.ch_id != channel_idx)
416                 return 0;
417
418         if (!nd->dev)
419                 return 0;
420
421         netif_wake_queue(nd->dev);
422         return 0;
423 }
424
425 static int aim_rx_data(struct mbo *mbo)
426 {
427         const u32 zero = 0;
428         struct net_dev_context *nd;
429         char *buf = mbo->virt_address;
430         uint32_t len = mbo->processed_length;
431         struct sk_buff *skb;
432         struct net_device *dev;
433
434         nd = get_net_dev_context(mbo->ifp);
435         if (!nd || !nd->channels_opened || nd->rx.ch_id != mbo->hdm_channel_id)
436                 return -EIO;
437
438         dev = nd->dev;
439         if (!dev) {
440                 pr_err_once("drop packet: missing net_device\n");
441                 return -EIO;
442         }
443
444         if (nd->is_mamac) {
445                 if (!PMS_IS_MAMAC(buf, len))
446                         return -EIO;
447
448                 skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2);
449         } else {
450                 if (!PMS_IS_MEP(buf, len))
451                         return -EIO;
452
453                 skb = dev_alloc_skb(len - MEP_HDR_LEN);
454         }
455
456         if (!skb) {
457                 dev->stats.rx_dropped++;
458                 pr_err_once("drop packet: no memory for skb\n");
459                 goto out;
460         }
461
462         skb->dev = dev;
463
464         if (nd->is_mamac) {
465                 /* dest */
466                 memcpy(skb_put(skb, ETH_ALEN), dev->dev_addr, ETH_ALEN);
467
468                 /* src */
469                 memcpy(skb_put(skb, 4), &zero, 4);
470                 memcpy(skb_put(skb, 2), buf + 5, 2);
471
472                 /* eth type */
473                 memcpy(skb_put(skb, 2), buf + 10, 2);
474
475                 buf += MDP_HDR_LEN;
476                 len -= MDP_HDR_LEN;
477         } else {
478                 buf += MEP_HDR_LEN;
479                 len -= MEP_HDR_LEN;
480         }
481
482         memcpy(skb_put(skb, len), buf, len);
483         skb->protocol = eth_type_trans(skb, dev);
484         dev->stats.rx_packets++;
485         dev->stats.rx_bytes += skb->len;
486         netif_rx(skb);
487
488 out:
489         most_put_mbo(mbo);
490         return 0;
491 }
492
493 static struct most_aim aim = {
494         .name = "networking",
495         .probe_channel = aim_probe_channel,
496         .disconnect_channel = aim_disconnect_channel,
497         .tx_completion = aim_resume_tx_channel,
498         .rx_completion = aim_rx_data,
499 };
500
501 static int __init most_net_init(void)
502 {
503         pr_info("most_net_init()\n");
504         spin_lock_init(&list_lock);
505         return most_register_aim(&aim);
506 }
507
508 static void __exit most_net_exit(void)
509 {
510         struct net_dev_context *nd, *tmp;
511
512         spin_lock(&list_lock);
513         list_for_each_entry_safe(nd, tmp, &net_devices, list) {
514                 list_del(&nd->list);
515                 spin_unlock(&list_lock);
516                 /*
517                  * do not call most_stop_channel() here, because channels are
518                  * going to be closed in ndo_stop() after unregister_netdev()
519                  */
520                 most_net_rm_netdev_safe(nd);
521                 kfree(nd);
522                 spin_lock(&list_lock);
523         }
524         spin_unlock(&list_lock);
525
526         most_deregister_aim(&aim);
527         pr_info("most_net_exit()\n");
528 }
529
530 /**
531  * most_deliver_netinfo - callback for HDM to be informed about HW's MAC
532  * @param iface - most interface instance
533  * @param link_stat - link status
534  * @param mac_addr - MAC address
535  */
536 void most_deliver_netinfo(struct most_interface *iface,
537                           unsigned char link_stat, unsigned char *mac_addr)
538 {
539         struct net_dev_context *nd;
540         struct net_device *dev;
541
542         pr_info("Received netinfo from %s\n", iface->description);
543
544         nd = get_net_dev_context(iface);
545         if (!nd)
546                 return;
547
548         dev = nd->dev;
549         if (!dev)
550                 return;
551
552         if (mac_addr)
553                 memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
554
555         if (nd->link_stat != link_stat) {
556                 nd->link_stat = link_stat;
557                 if (nd->link_stat)
558                         netif_wake_queue(dev);
559                 else
560                         netif_stop_queue(dev);
561         }
562 }
563 EXPORT_SYMBOL(most_deliver_netinfo);
564
565 module_init(most_net_init);
566 module_exit(most_net_exit);
567 MODULE_LICENSE("GPL");
568 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
569 MODULE_DESCRIPTION("Networking Application Interface Module for MostCore");