1 // SPDX-License-Identifier: GPL-2.0
3 * net.c - Networking component for Mostcore
5 * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 #include <linux/module.h>
11 #include <linux/netdevice.h>
12 #include <linux/etherdevice.h>
13 #include <linux/slab.h>
14 #include <linux/init.h>
15 #include <linux/list.h>
16 #include <linux/wait.h>
17 #include <linux/kobject.h>
18 #include <linux/most.h>
21 #define MDP_HDR_LEN 16
22 #define MAMAC_DATA_LEN (1024 - MDP_HDR_LEN)
26 #define PMS_TELID_UNSEGM_MAMAC 0x0A
27 #define PMS_FIFONO_MDP 0x01
28 #define PMS_FIFONO_MEP 0x04
29 #define PMS_MSGTYPE_DATA 0x04
30 #define PMS_DEF_PRIO 0
31 #define MEP_DEF_RETRY 15
33 #define PMS_FIFONO_MASK 0x07
34 #define PMS_FIFONO_SHIFT 3
35 #define PMS_RETRY_SHIFT 4
36 #define PMS_TELID_MASK 0x0F
37 #define PMS_TELID_SHIFT 4
39 #define HB(value) ((u8)((u16)(value) >> 8))
40 #define LB(value) ((u8)(value))
42 #define EXTRACT_BIT_SET(bitset_name, value) \
43 (((value) >> bitset_name##_SHIFT) & bitset_name##_MASK)
45 #define PMS_IS_MEP(buf, len) \
46 ((len) > MEP_HDR_LEN && \
47 EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MEP)
49 static inline bool pms_is_mamac(char *buf, u32 len)
51 return (len > MDP_HDR_LEN &&
52 EXTRACT_BIT_SET(PMS_FIFONO, buf[3]) == PMS_FIFONO_MDP &&
53 EXTRACT_BIT_SET(PMS_TELID, buf[14]) == PMS_TELID_UNSEGM_MAMAC);
56 struct net_dev_channel {
61 struct net_dev_context {
62 struct most_interface *iface;
64 struct net_device *dev;
65 struct net_dev_channel rx;
66 struct net_dev_channel tx;
67 struct list_head list;
70 static struct list_head net_devices = LIST_HEAD_INIT(net_devices);
71 static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */
72 static DEFINE_SPINLOCK(list_lock); /* list_head, ch->linked = false, dev_hold */
73 static struct most_component comp;
75 static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo)
77 u8 *buff = mbo->virt_address;
78 static const u8 broadcast[] = { 0x03, 0xFF };
79 const u8 *dest_addr = skb->data + 4;
80 const u8 *eth_type = skb->data + 12;
81 unsigned int payload_len = skb->len - ETH_HLEN;
82 unsigned int mdp_len = payload_len + MDP_HDR_LEN;
84 if (mdp_len < skb->len) {
85 pr_err("drop: too large packet! (%u)\n", skb->len);
89 if (mbo->buffer_length < mdp_len) {
90 pr_err("drop: too small buffer! (%d for %d)\n",
91 mbo->buffer_length, mdp_len);
95 if (skb->len < ETH_HLEN) {
96 pr_err("drop: too small packet! (%d)\n", skb->len);
100 if (dest_addr[0] == 0xFF && dest_addr[1] == 0xFF)
101 dest_addr = broadcast;
103 *buff++ = HB(mdp_len - 2);
104 *buff++ = LB(mdp_len - 2);
107 *buff++ = (PMS_FIFONO_MDP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA;
108 *buff++ = PMS_DEF_PRIO;
109 *buff++ = dest_addr[0];
110 *buff++ = dest_addr[1];
113 *buff++ = HB(payload_len + 6);
114 *buff++ = LB(payload_len + 6);
116 /* end of FPH here */
118 *buff++ = eth_type[0];
119 *buff++ = eth_type[1];
123 *buff++ = PMS_TELID_UNSEGM_MAMAC << 4 | HB(payload_len);
124 *buff++ = LB(payload_len);
126 memcpy(buff, skb->data + ETH_HLEN, payload_len);
127 mbo->buffer_length = mdp_len;
131 static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo)
133 u8 *buff = mbo->virt_address;
134 unsigned int mep_len = skb->len + MEP_HDR_LEN;
136 if (mep_len < skb->len) {
137 pr_err("drop: too large packet! (%u)\n", skb->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 = netdev_priv(dev);
165 int err = eth_mac_addr(dev, p);
171 (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0 &&
172 dev->dev_addr[2] == 0 && dev->dev_addr[3] == 0);
175 * Set default MTU for the given packet type.
176 * It is still possible to change MTU using ip tools afterwards.
178 dev->mtu = nd->is_mamac ? MAMAC_DATA_LEN : ETH_DATA_LEN;
183 static void on_netinfo(struct most_interface *iface,
184 unsigned char link_stat, unsigned char *mac_addr);
186 static int most_nd_open(struct net_device *dev)
188 struct net_dev_context *nd = netdev_priv(dev);
191 mutex_lock(&probe_disc_mt);
193 if (most_start_channel(nd->iface, nd->rx.ch_id, &comp)) {
194 netdev_err(dev, "most_start_channel() failed\n");
199 if (most_start_channel(nd->iface, nd->tx.ch_id, &comp)) {
200 netdev_err(dev, "most_start_channel() failed\n");
201 most_stop_channel(nd->iface, nd->rx.ch_id, &comp);
206 netif_carrier_off(dev);
207 if (is_valid_ether_addr(dev->dev_addr))
208 netif_dormant_off(dev);
210 netif_dormant_on(dev);
211 netif_wake_queue(dev);
212 if (nd->iface->request_netinfo)
213 nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, on_netinfo);
216 mutex_unlock(&probe_disc_mt);
220 static int most_nd_stop(struct net_device *dev)
222 struct net_dev_context *nd = netdev_priv(dev);
224 netif_stop_queue(dev);
225 if (nd->iface->request_netinfo)
226 nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, NULL);
227 most_stop_channel(nd->iface, nd->rx.ch_id, &comp);
228 most_stop_channel(nd->iface, nd->tx.ch_id, &comp);
233 static netdev_tx_t most_nd_start_xmit(struct sk_buff *skb,
234 struct net_device *dev)
236 struct net_dev_context *nd = netdev_priv(dev);
240 mbo = most_get_mbo(nd->iface, nd->tx.ch_id, &comp);
243 netif_stop_queue(dev);
244 dev->stats.tx_fifo_errors++;
245 return NETDEV_TX_BUSY;
249 ret = skb_to_mamac(skb, mbo);
251 ret = skb_to_mep(skb, mbo);
255 dev->stats.tx_dropped++;
260 most_submit_mbo(mbo);
261 dev->stats.tx_packets++;
262 dev->stats.tx_bytes += skb->len;
267 static const struct net_device_ops most_nd_ops = {
268 .ndo_open = most_nd_open,
269 .ndo_stop = most_nd_stop,
270 .ndo_start_xmit = most_nd_start_xmit,
271 .ndo_set_mac_address = most_nd_set_mac_address,
274 static void most_nd_setup(struct net_device *dev)
277 dev->netdev_ops = &most_nd_ops;
280 static struct net_dev_context *get_net_dev(struct most_interface *iface)
282 struct net_dev_context *nd;
284 list_for_each_entry(nd, &net_devices, list)
285 if (nd->iface == iface)
290 static struct net_dev_context *get_net_dev_hold(struct most_interface *iface)
292 struct net_dev_context *nd;
295 spin_lock_irqsave(&list_lock, flags);
296 nd = get_net_dev(iface);
297 if (nd && nd->rx.linked && nd->tx.linked)
301 spin_unlock_irqrestore(&list_lock, flags);
305 static int comp_probe_channel(struct most_interface *iface, int channel_idx,
306 struct most_channel_config *ccfg, char *name,
309 struct net_dev_context *nd;
310 struct net_dev_channel *ch;
311 struct net_device *dev;
318 if (ccfg->data_type != MOST_CH_ASYNC)
321 mutex_lock(&probe_disc_mt);
322 nd = get_net_dev(iface);
324 dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d",
325 NET_NAME_UNKNOWN, most_nd_setup);
331 nd = netdev_priv(dev);
335 spin_lock_irqsave(&list_lock, flags);
336 list_add(&nd->list, &net_devices);
337 spin_unlock_irqrestore(&list_lock, flags);
339 ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx;
341 ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx;
343 pr_err("direction is allocated\n");
348 if (register_netdev(nd->dev)) {
349 pr_err("register_netdev() failed\n");
354 ch->ch_id = channel_idx;
358 mutex_unlock(&probe_disc_mt);
362 static int comp_disconnect_channel(struct most_interface *iface,
365 struct net_dev_context *nd;
366 struct net_dev_channel *ch;
370 mutex_lock(&probe_disc_mt);
371 nd = get_net_dev(iface);
377 if (nd->rx.linked && channel_idx == nd->rx.ch_id) {
379 } else if (nd->tx.linked && channel_idx == nd->tx.ch_id) {
386 if (nd->rx.linked && nd->tx.linked) {
387 spin_lock_irqsave(&list_lock, flags);
389 spin_unlock_irqrestore(&list_lock, flags);
392 * do not call most_stop_channel() here, because channels are
393 * going to be closed in ndo_stop() after unregister_netdev()
395 unregister_netdev(nd->dev);
397 spin_lock_irqsave(&list_lock, flags);
399 spin_unlock_irqrestore(&list_lock, flags);
401 free_netdev(nd->dev);
405 mutex_unlock(&probe_disc_mt);
409 static int comp_resume_tx_channel(struct most_interface *iface,
412 struct net_dev_context *nd;
414 nd = get_net_dev_hold(iface);
418 if (nd->tx.ch_id != channel_idx)
421 netif_wake_queue(nd->dev);
428 static int comp_rx_data(struct mbo *mbo)
431 struct net_dev_context *nd;
432 char *buf = mbo->virt_address;
433 u32 len = mbo->processed_length;
435 struct net_device *dev;
436 unsigned int skb_len;
439 nd = get_net_dev_hold(mbo->ifp);
443 if (nd->rx.ch_id != mbo->hdm_channel_id) {
451 if (!pms_is_mamac(buf, len)) {
456 skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2);
458 if (!PMS_IS_MEP(buf, len)) {
463 skb = dev_alloc_skb(len - MEP_HDR_LEN);
467 dev->stats.rx_dropped++;
468 pr_err_once("drop packet: no memory for skb\n");
476 ether_addr_copy(skb_put(skb, ETH_ALEN), dev->dev_addr);
479 skb_put_data(skb, &zero, 4);
480 skb_put_data(skb, buf + 5, 2);
483 skb_put_data(skb, buf + 10, 2);
492 skb_put_data(skb, buf, len);
493 skb->protocol = eth_type_trans(skb, dev);
495 if (netif_rx(skb) == NET_RX_SUCCESS) {
496 dev->stats.rx_packets++;
497 dev->stats.rx_bytes += skb_len;
499 dev->stats.rx_dropped++;
510 static struct most_component comp = {
513 .probe_channel = comp_probe_channel,
514 .disconnect_channel = comp_disconnect_channel,
515 .tx_completion = comp_resume_tx_channel,
516 .rx_completion = comp_rx_data,
519 static int __init most_net_init(void)
523 mutex_init(&probe_disc_mt);
524 err = most_register_component(&comp);
527 err = most_register_configfs_subsys(&comp);
529 most_deregister_component(&comp);
535 static void __exit most_net_exit(void)
537 most_deregister_configfs_subsys(&comp);
538 most_deregister_component(&comp);
542 * on_netinfo - callback for HDM to be informed about HW's MAC
543 * @param iface - most interface instance
544 * @param link_stat - link status
545 * @param mac_addr - MAC address
547 static void on_netinfo(struct most_interface *iface,
548 unsigned char link_stat, unsigned char *mac_addr)
550 struct net_dev_context *nd;
551 struct net_device *dev;
552 const u8 *m = mac_addr;
554 nd = get_net_dev_hold(iface);
561 netif_carrier_on(dev);
563 netif_carrier_off(dev);
565 if (m && is_valid_ether_addr(m)) {
566 if (!is_valid_ether_addr(dev->dev_addr)) {
567 netdev_info(dev, "set mac %02x-%02x-%02x-%02x-%02x-%02x\n",
568 m[0], m[1], m[2], m[3], m[4], m[5]);
569 ether_addr_copy(dev->dev_addr, m);
570 netif_dormant_off(dev);
571 } else if (!ether_addr_equal(dev->dev_addr, m)) {
572 netdev_warn(dev, "reject mac %02x-%02x-%02x-%02x-%02x-%02x\n",
573 m[0], m[1], m[2], m[3], m[4], m[5]);
580 module_init(most_net_init);
581 module_exit(most_net_exit);
582 MODULE_LICENSE("GPL");
583 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
584 MODULE_DESCRIPTION("Networking Component Module for Mostcore");