blob: 235f2f22d9aa93ac8bdea0dd71837cf74eb42ebf [file] [log] [blame]
Claudiu Manoild9eaa922021-03-14 20:14:57 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
Vladimir Oltean5041e422021-09-17 14:27:13 +03003 * Copyright 2019-2021 NXP
Claudiu Manoild9eaa922021-03-14 20:14:57 +08004 */
5
6#include <asm/eth.h>
7#include <net/dsa.h>
8#include <net.h>
9
10#define DSA_SANDBOX_MAGIC 0x00415344
11#define DSA_SANDBOX_TAG_LEN sizeof(struct dsa_sandbox_tag)
12
13struct dsa_sandbox_priv {
14 struct eth_sandbox_priv *master_priv;
15 int port_en_mask;
16};
17
18struct dsa_sandbox_tag {
19 u32 magic;
20 u32 port;
21};
22
23static bool sb_dsa_port_enabled(struct udevice *dev, int port)
24{
25 struct dsa_sandbox_priv *priv = dev_get_priv(dev);
26
27 return priv->port_en_mask & BIT(port);
28}
29
30static bool sb_dsa_master_enabled(struct udevice *dev)
31{
32 struct dsa_sandbox_priv *priv = dev_get_priv(dev);
33
34 return !priv->master_priv->disabled;
35}
36
37static int dsa_sandbox_port_enable(struct udevice *dev, int port,
38 struct phy_device *phy)
39{
40 struct dsa_sandbox_priv *priv = dev_get_priv(dev);
41
42 if (!sb_dsa_master_enabled(dev))
43 return -EFAULT;
44
45 priv->port_en_mask |= BIT(port);
46
47 return 0;
48}
49
50static void dsa_sandbox_port_disable(struct udevice *dev, int port,
51 struct phy_device *phy)
52{
53 struct dsa_sandbox_priv *priv = dev_get_priv(dev);
54
55 priv->port_en_mask &= ~BIT(port);
56}
57
58static int dsa_sandbox_xmit(struct udevice *dev, int port, void *packet,
59 int length)
60{
61 struct dsa_sandbox_tag *tag = packet;
62
63 if (!sb_dsa_master_enabled(dev))
64 return -EFAULT;
65
66 if (!sb_dsa_port_enabled(dev, port))
67 return -EFAULT;
68
69 tag->magic = DSA_SANDBOX_MAGIC;
70 tag->port = port;
71
72 return 0;
73}
74
75static int dsa_sandbox_rcv(struct udevice *dev, int *port, void *packet,
76 int length)
77{
78 struct dsa_sandbox_tag *tag = packet;
79
80 if (!sb_dsa_master_enabled(dev))
81 return -EFAULT;
82
83 if (tag->magic != DSA_SANDBOX_MAGIC)
84 return -EFAULT;
85
86 *port = tag->port;
87 if (!sb_dsa_port_enabled(dev, tag->port))
88 return -EFAULT;
89
90 return 0;
91}
92
93static const struct dsa_ops dsa_sandbox_ops = {
94 .port_enable = dsa_sandbox_port_enable,
95 .port_disable = dsa_sandbox_port_disable,
96 .xmit = dsa_sandbox_xmit,
97 .rcv = dsa_sandbox_rcv,
98};
99
100static int sb_dsa_handler(struct udevice *dev, void *packet,
101 unsigned int len)
102{
103 struct eth_sandbox_priv *master_priv;
104 struct dsa_sandbox_tag *tag = packet;
105 struct udevice *dsa_dev;
106 u32 port_index;
107 void *rx_buf;
108 int i;
109
110 /* this emulates the switch hw and the network side */
111 if (tag->magic != DSA_SANDBOX_MAGIC)
112 return -EFAULT;
113
114 port_index = tag->port;
115 master_priv = dev_get_priv(dev);
116 dsa_dev = master_priv->priv;
117 if (!sb_dsa_port_enabled(dsa_dev, port_index))
118 return -EFAULT;
119
120 packet += DSA_SANDBOX_TAG_LEN;
121 len -= DSA_SANDBOX_TAG_LEN;
122
123 if (!sandbox_eth_arp_req_to_reply(dev, packet, len))
124 goto dsa_tagging;
125 if (!sandbox_eth_ping_req_to_reply(dev, packet, len))
126 goto dsa_tagging;
127
128 return 0;
129
130dsa_tagging:
131 master_priv->recv_packets--;
132 i = master_priv->recv_packets;
133 rx_buf = master_priv->recv_packet_buffer[i];
134 len = master_priv->recv_packet_length[i];
135 memmove(rx_buf + DSA_SANDBOX_TAG_LEN, rx_buf, len);
136
137 tag = rx_buf;
138 tag->magic = DSA_SANDBOX_MAGIC;
139 tag->port = port_index;
140 len += DSA_SANDBOX_TAG_LEN;
141 master_priv->recv_packet_length[i] = len;
142 master_priv->recv_packets++;
143
144 return 0;
145}
146
147static int dsa_sandbox_probe(struct udevice *dev)
148{
149 struct dsa_sandbox_priv *priv = dev_get_priv(dev);
150 struct udevice *master = dsa_get_master(dev);
151 struct eth_sandbox_priv *master_priv;
152
153 if (!master)
154 return -ENODEV;
155
156 dsa_set_tagging(dev, DSA_SANDBOX_TAG_LEN, 0);
157
158 master_priv = dev_get_priv(master);
159 master_priv->priv = dev;
160 master_priv->tx_handler = sb_dsa_handler;
161
162 priv->master_priv = master_priv;
163
164 return 0;
165}
166
167static const struct udevice_id dsa_sandbox_ids[] = {
168 { .compatible = "sandbox,dsa" },
169 { }
170};
171
172U_BOOT_DRIVER(dsa_sandbox) = {
173 .name = "dsa_sandbox",
174 .id = UCLASS_DSA,
175 .of_match = dsa_sandbox_ids,
176 .probe = dsa_sandbox_probe,
177 .ops = &dsa_sandbox_ops,
178 .priv_auto = sizeof(struct dsa_sandbox_priv),
179};