1 /*
2  * Copyright (c) 2020 DENX Software Engineering GmbH
3  *               Lukasz Majewski <lukma@denx.de>
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /** @file
8  * @brief DSA definitions and handlers
9  */
10 
11 #ifndef ZEPHYR_INCLUDE_NET_DSA_H_
12 #define ZEPHYR_INCLUDE_NET_DSA_H_
13 
14 #include <zephyr/device.h>
15 #include <zephyr/net/net_if.h>
16 
17 /**
18  * @brief DSA definitions and helpers
19  * @defgroup DSA Distributed Switch Architecture definitions and helpers
20  * @since 2.5
21  * @version 0.8.0
22  * @ingroup networking
23  * @{
24  */
25 
26 /** @cond INTERNAL_HIDDEN */
27 
28 #define NET_DSA_PORT_MAX_COUNT 8
29 #define DSA_STATUS_PERIOD_MS K_MSEC(1000)
30 
31 /*
32  * Size of the DSA TAG:
33  * - KSZ8794 - 1 byte
34  */
35 #if defined(CONFIG_DSA_KSZ8794) && defined(CONFIG_DSA_KSZ_TAIL_TAGGING)
36 #define DSA_TAG_SIZE 1
37 #else
38 #define DSA_TAG_SIZE 0
39 #endif
40 
41 /** @endcond */
42 
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46 
47 /**
48  * @brief DSA generic transmit function
49  *
50  * This is a generic function for passing packets from slave DSA interface to
51  * master.
52  *
53  * @param dev Device
54  * @param pkt Network packet
55  *
56  * Returns:
57  *  - 0 if ok (packet sent via master iface), < 0 if error
58  */
59 int dsa_tx(const struct device *dev, struct net_pkt *pkt);
60 
61 /**
62  * @brief DSA (MGMT) Receive packet callback
63  *
64  * Callback gets called upon receiving packet. It is responsible for
65  * freeing packet or indicating to the stack that it needs to free packet
66  * by returning correct net_verdict.
67  *
68  * Returns:
69  *  - NET_DROP, if packet was invalid, rejected or we want the stack to free it.
70  *    In this case the core stack will free the packet.
71  *  - NET_OK, if the packet was accepted, in this case the ownership of the
72  *    net_pkt goes to callback and core network stack will forget it.
73  */
74 typedef enum net_verdict (*dsa_net_recv_cb_t)(struct net_if *iface,
75 					      struct net_pkt *pkt);
76 
77 /**
78  * @brief Register DSA Rx callback functions
79  *
80  * @param iface Network interface
81  * @param cb Receive callback function
82  *
83  * @return 0 if ok, < 0 if error
84  */
85 int dsa_register_recv_callback(struct net_if *iface, dsa_net_recv_cb_t cb);
86 
87 /**
88  * @brief Set DSA interface to packet
89  *
90  * @param iface Network interface (master)
91  * @param pkt Network packet
92  *
93  * @return Return the slave network interface
94  */
95 struct net_if *dsa_net_recv(struct net_if *iface, struct net_pkt **pkt);
96 
97 /**
98  * @brief Pointer to master interface send function
99  */
100 typedef int (*dsa_send_t)(const struct device *dev, struct net_pkt *pkt);
101 
102 /**
103  * @brief DSA helper function to register transmit function for master
104  *
105  * @param iface Network interface (master)
106  * @param fn Pointer to master interface send method
107  *
108  * Returns:
109  *  - 0 if ok, < 0 if error
110  */
111 int dsa_register_master_tx(struct net_if *iface, dsa_send_t fn);
112 
113 /**
114  * @brief DSA helper function to check if port is master
115  *
116  * @param iface Network interface (master)
117  *
118  * Returns:
119  *  - true if ok, false otherwise
120  */
121 bool dsa_is_port_master(struct net_if *iface);
122 
123 /**
124  * @cond INTERNAL_HIDDEN
125  *
126  * These are for internal use only, so skip these in
127  * public documentation.
128  */
129 
130 /** DSA context data */
131 struct dsa_context {
132 	/** Pointers to all DSA slave network interfaces */
133 	struct net_if *iface_slave[NET_DSA_PORT_MAX_COUNT];
134 
135 	/** Pointer to DSA master network interface */
136 	struct net_if *iface_master;
137 
138 	/** DSA specific API callbacks - filled in the switch IC driver */
139 	struct dsa_api *dapi;
140 
141 	/** DSA related work (e.g. monitor if network interface is up) */
142 	struct k_work_delayable dsa_work;
143 
144 	/** Number of slave ports in the DSA switch */
145 	uint8_t num_slave_ports;
146 
147 	/** Status of each port */
148 	bool link_up[NET_DSA_PORT_MAX_COUNT];
149 
150 	/** Instance specific data */
151 	void *prv_data;
152 };
153 
154 /**
155  * @brief Structure to provide DSA switch api callbacks - it is an augmented
156  * struct ethernet_api.
157  */
158 struct dsa_api {
159 	/** Function to get proper LAN{123} interface */
160 	struct net_if *(*dsa_get_iface)(struct net_if *iface,
161 					struct net_pkt *pkt);
162 	/*
163 	 * Callbacks required for DSA switch initialization and configuration.
164 	 *
165 	 * Each switch instance (e.g. two KSZ8794 ICs) would have its own struct
166 	 * dsa_context.
167 	 */
168 	/** Read value from DSA register */
169 	int (*switch_read)(const struct device *dev, uint16_t reg_addr,
170 				uint8_t *value);
171 	/** Write value to DSA register */
172 	int (*switch_write)(const struct device *dev, uint16_t reg_addr,
173 				uint8_t value);
174 
175 	/** Program (set) mac table entry in the DSA switch */
176 	int (*switch_set_mac_table_entry)(const struct device *dev,
177 						const uint8_t *mac,
178 						uint8_t fw_port,
179 						uint16_t tbl_entry_idx,
180 						uint16_t flags);
181 
182 	/** Read mac table entry from the DSA switch */
183 	int (*switch_get_mac_table_entry)(const struct device *dev,
184 						uint8_t *buf,
185 						uint16_t tbl_entry_idx);
186 
187 	/*
188 	 * DSA helper callbacks
189 	 */
190 	struct net_pkt *(*dsa_xmit_pkt)(struct net_if *iface,
191 					struct net_pkt *pkt);
192 };
193 
194 /**
195  * @endcond
196  */
197 
198 /**
199  * @brief      Get network interface of a slave port
200  *
201  * @param      iface      Master port
202  * @param[in]  slave_num  Slave port number
203  *
204  * @return     network interface of the slave if successful
205  * @return     NULL if slave port does not exist
206  */
207 struct net_if *dsa_get_slave_port(struct net_if *iface, int slave_num);
208 
209 /**
210  * @brief      Read from DSA switch register
211  *
212  * @param      iface     The interface
213  * @param[in]  reg_addr  The register address
214  * @param      value     The value
215  *
216  * @return     0 if successful, negative if error
217  */
218 int dsa_switch_read(struct net_if *iface, uint16_t reg_addr, uint8_t *value);
219 
220 /**
221  * @brief      Write to DSA switch
222  *
223  * @param      iface     The interface
224  * @param[in]  reg_addr  The register address
225  * @param[in]  value     The value
226  *
227  * @return     { description_of_the_return_value }
228  */
229 int dsa_switch_write(struct net_if *iface, uint16_t reg_addr, uint8_t value);
230 
231 /**
232  * @brief      Write static MAC table entry
233  *
234  * @param      iface          Master DSA interface
235  * @param[in]  mac            MAC address
236  * @param[in]  fw_port        The firmware port
237  * @param[in]  tbl_entry_idx  Table entry index
238  * @param[in]  flags          Flags
239  *
240  * @return     0 if successful, negative if error
241  */
242 int dsa_switch_set_mac_table_entry(struct net_if *iface,
243 					const uint8_t *mac,
244 					uint8_t fw_port,
245 					uint16_t tbl_entry_idx,
246 					uint16_t flags);
247 
248 /**
249  * @brief      Read static MAC table entry
250  *
251  * @param      iface          Master DSA interface
252  * @param      buf            Buffer to receive MAC address
253  * @param[in]  tbl_entry_idx  Table entry index
254  *
255  * @return     0 if successful, negative if error
256  */
257 int dsa_switch_get_mac_table_entry(struct net_if *iface,
258 					uint8_t *buf,
259 					uint16_t tbl_entry_idx);
260 
261 /**
262  * @brief Structure to provide mac address for each LAN interface
263  */
264 
265 struct dsa_slave_config {
266 	/** MAC address for each LAN{123.,} ports */
267 	uint8_t mac_addr[6];
268 };
269 
270 #ifdef __cplusplus
271 }
272 #endif
273 
274 /**
275  * @}
276  */
277 #endif /* ZEPHYR_INCLUDE_NET_DSA_H_ */
278