1 /*
2 * Copyright 2025 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_dsa_port, CONFIG_NET_DSA_LOG_LEVEL);
9
10 #include <zephyr/net/ethernet.h>
11 #include <zephyr/net/phy.h>
12 #include <zephyr/net/dsa_core.h>
13 #include "dsa_tag.h"
14
15 #if defined(CONFIG_NET_INTERFACE_NAME_LEN)
16 #define INTERFACE_NAME_LEN CONFIG_NET_INTERFACE_NAME_LEN
17 #else
18 #define INTERFACE_NAME_LEN 10
19 #endif
20
dsa_port_initialize(const struct device * dev)21 int dsa_port_initialize(const struct device *dev)
22 {
23 const struct dsa_port_config *cfg = dev->config;
24 struct dsa_switch_context *dsa_switch_ctx = dev->data;
25 struct net_if *iface = net_if_lookup_by_dev(dev);
26 struct ethernet_context *eth_ctx = net_if_l2_data(iface);
27 struct ethernet_context *eth_ctx_conduit = NULL;
28 int err = 0;
29
30 dsa_switch_ctx->init_ports++;
31
32 /* Find the connection of conduit port and cpu port */
33 if (dsa_switch_ctx->iface_conduit == NULL && cfg->ethernet_connection != NULL) {
34 dsa_switch_ctx->iface_conduit = net_if_lookup_by_dev(cfg->ethernet_connection);
35 if (dsa_switch_ctx->iface_conduit == NULL) {
36 LOG_ERR("DSA: Conduit iface NOT found!");
37 }
38
39 /* Set up tag protocol on the cpu port */
40 eth_ctx->dsa_port = DSA_CPU_PORT;
41 dsa_tag_setup(dev);
42
43 /* Provide DSA information to the conduit port */
44 eth_ctx_conduit = net_if_l2_data(dsa_switch_ctx->iface_conduit);
45 eth_ctx_conduit->dsa_switch_ctx = dsa_switch_ctx;
46 eth_ctx_conduit->dsa_port = DSA_CONDUIT_PORT;
47 }
48
49 if (cfg->ethernet_connection == NULL) {
50 eth_ctx->dsa_port = DSA_USER_PORT;
51 eth_ctx->dsa_switch_ctx = dsa_switch_ctx;
52 dsa_switch_ctx->iface_user[cfg->port_idx] = iface;
53 }
54
55 if (dsa_switch_ctx->dapi->port_init != NULL) {
56 err = dsa_switch_ctx->dapi->port_init(dev);
57 if (err != 0) {
58 goto out;
59 }
60 }
61
62 out:
63 /* All ports are initialized. May need switch setup. */
64 if (dsa_switch_ctx->init_ports == dsa_switch_ctx->num_ports) {
65 if (dsa_switch_ctx->dapi->switch_setup != NULL) {
66 err = dsa_switch_ctx->dapi->switch_setup(dsa_switch_ctx);
67 }
68 }
69
70 return err;
71 }
72
dsa_port_iface_init(struct net_if * iface)73 static void dsa_port_iface_init(struct net_if *iface)
74 {
75 const struct device *dev = net_if_get_device(iface);
76 struct dsa_port_config *cfg = (struct dsa_port_config *)dev->config;
77 struct dsa_switch_context *dsa_switch_ctx = dev->data;
78 char name[INTERFACE_NAME_LEN];
79
80 /* Set interface name */
81 snprintf(name, sizeof(name), "swp%d", cfg->port_idx);
82 net_if_set_name(iface, name);
83
84 /* Use random mac address if could */
85 if (cfg->use_random_mac_addr && dsa_switch_ctx->dapi->port_generate_random_mac != NULL) {
86 dsa_switch_ctx->dapi->port_generate_random_mac(cfg->mac_addr);
87 }
88
89 net_if_set_link_addr(iface, cfg->mac_addr, sizeof(cfg->mac_addr), NET_LINK_ETHERNET);
90
91 if (cfg->ethernet_connection != NULL) {
92 net_if_carrier_off(iface);
93 return;
94 }
95
96 /*
97 * Initialize ethernet context 'work' for this iface to
98 * be able to monitor the carrier status.
99 */
100 ethernet_init(iface);
101
102 /* Do not start the interface until link is up */
103 net_if_carrier_off(iface);
104
105 if (!device_is_ready(cfg->phy_dev)) {
106 LOG_ERR("PHY device (%p) is not ready, cannot init iface", cfg->phy_dev);
107 return;
108 }
109
110 if (dsa_switch_ctx->dapi->port_phylink_change == NULL) {
111 LOG_ERR("require port_phylink_change callback");
112 return;
113 }
114
115 phy_link_callback_set(cfg->phy_dev, dsa_switch_ctx->dapi->port_phylink_change, (void *)dev);
116 }
117
dsa_port_get_phy(const struct device * dev)118 static const struct device *dsa_port_get_phy(const struct device *dev)
119 {
120 const struct dsa_port_config *cfg = dev->config;
121
122 return cfg->phy_dev;
123 }
124
125 const struct ethernet_api dsa_eth_api = {
126 .iface_api.init = dsa_port_iface_init,
127 .get_phy = dsa_port_get_phy,
128 .send = dsa_xmit,
129 };
130