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