net: eth: Add Qbv configuration support
Allow caller to either set or receive various Ethernet Qbv
configuration options defined in IEEE Std 802.1Qbv-2015
specification.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
diff --git a/include/net/ethernet.h b/include/net/ethernet.h
index 194d802..d6dcfb7 100644
--- a/include/net/ethernet.h
+++ b/include/net/ethernet.h
@@ -28,6 +28,7 @@
#include <sys/util.h>
#include <net/net_if.h>
#include <net/ethernet_vlan.h>
+#include <net/ptp_time.h>
#if defined(CONFIG_NET_DSA)
#include <net/dsa.h>
@@ -150,6 +151,9 @@
/** DSA switch */
ETHERNET_DSA_SLAVE_PORT = BIT(15),
ETHERNET_DSA_MASTER_PORT = BIT(16),
+
+ /** IEEE 802.1Qbv (scheduled traffic) supported */
+ ETHERNET_QBV = BIT(17),
};
/** @cond INTERNAL_HIDDEN */
@@ -160,9 +164,11 @@
ETHERNET_CONFIG_TYPE_DUPLEX,
ETHERNET_CONFIG_TYPE_MAC_ADDRESS,
ETHERNET_CONFIG_TYPE_QAV_PARAM,
+ ETHERNET_CONFIG_TYPE_QBV_PARAM,
ETHERNET_CONFIG_TYPE_PROMISC_MODE,
ETHERNET_CONFIG_TYPE_PRIORITY_QUEUES_NUM,
ETHERNET_CONFIG_TYPE_FILTER,
+ ETHERNET_CONFIG_TYPE_PORTS_NUM,
};
enum ethernet_qav_param_type {
@@ -196,6 +202,70 @@
/** @cond INTERNAL_HIDDEN */
+enum ethernet_qbv_param_type {
+ ETHERNET_QBV_PARAM_TYPE_STATUS,
+ ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST,
+ ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST_LEN,
+ ETHERNET_QBV_PARAM_TYPE_TIME,
+};
+
+enum ethernet_qbv_state_type {
+ ETHERNET_QBV_STATE_TYPE_ADMIN,
+ ETHERNET_QBV_STATE_TYPE_OPER,
+};
+
+enum ethernet_gate_state_operation {
+ ETHERNET_SET_GATE_STATE,
+};
+
+/** @endcond */
+
+struct ethernet_qbv_param {
+ /** Port id */
+ int port_id;
+ /** Type of Qbv parameter */
+ enum ethernet_qbv_param_type type;
+ /** What state (Admin/Oper) parameters are these */
+ enum ethernet_qbv_state_type state;
+ union {
+ /** True if Qbv is enabled or not */
+ bool enabled;
+
+ struct {
+ /** True = open, False = closed */
+ bool gate_status[NET_TC_TX_COUNT];
+
+ /** GateState operation */
+ enum ethernet_gate_state_operation operation;
+
+ /** Time interval ticks (nanoseconds) */
+ uint32_t time_interval;
+
+ /** Gate control list row */
+ uint16_t row;
+ } gate_control;
+
+ /** Number of entries in gate control list */
+ uint32_t gate_control_list_len;
+
+ /* The time values are set in one go when type is set to
+ * ETHERNET_QBV_PARAM_TYPE_TIME
+ */
+ struct {
+ /** Base time */
+ struct net_ptp_extended_time base_time;
+
+ /** Cycle time */
+ struct net_ptp_time cycle_time;
+
+ /** Extension time (nanoseconds) */
+ uint32_t extension_time;
+ };
+ };
+};
+
+/** @cond INTERNAL_HIDDEN */
+
enum ethernet_filter_type {
ETHERNET_FILTER_TYPE_SRC_MAC_ADDRESS,
ETHERNET_FILTER_TYPE_DST_MAC_ADDRESS,
@@ -228,8 +298,10 @@
struct net_eth_addr mac_address;
struct ethernet_qav_param qav_param;
+ struct ethernet_qbv_param qbv_param;
int priority_queues_num;
+ int ports_num;
struct ethernet_filter filter;
};
diff --git a/include/net/ethernet_mgmt.h b/include/net/ethernet_mgmt.h
index c9a7500..a3d84e1 100644
--- a/include/net/ethernet_mgmt.h
+++ b/include/net/ethernet_mgmt.h
@@ -41,9 +41,12 @@
NET_REQUEST_ETHERNET_CMD_SET_DUPLEX,
NET_REQUEST_ETHERNET_CMD_SET_MAC_ADDRESS,
NET_REQUEST_ETHERNET_CMD_SET_QAV_PARAM,
+ NET_REQUEST_ETHERNET_CMD_SET_QBV_PARAM,
NET_REQUEST_ETHERNET_CMD_SET_PROMISC_MODE,
NET_REQUEST_ETHERNET_CMD_GET_PRIORITY_QUEUES_NUM,
NET_REQUEST_ETHERNET_CMD_GET_QAV_PARAM,
+ NET_REQUEST_ETHERNET_CMD_GET_PORTS_NUM,
+ NET_REQUEST_ETHERNET_CMD_GET_QBV_PARAM,
};
#define NET_REQUEST_ETHERNET_SET_AUTO_NEGOTIATION \
@@ -71,6 +74,16 @@
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_QAV_PARAM);
+#define NET_REQUEST_ETHERNET_GET_PORTS_NUM \
+ (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_GET_PORTS_NUM)
+
+NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_PORTS_NUM);
+
+#define NET_REQUEST_ETHERNET_SET_QBV_PARAM \
+ (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_QBV_PARAM)
+
+NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_QBV_PARAM);
+
#define NET_REQUEST_ETHERNET_SET_PROMISC_MODE \
(_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_PROMISC_MODE)
@@ -86,8 +99,14 @@
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QAV_PARAM);
+#define NET_REQUEST_ETHERNET_GET_QBV_PARAM \
+ (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_GET_QBV_PARAM)
+
+NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBV_PARAM);
+
struct net_eth_addr;
struct ethernet_qav_param;
+struct ethernet_qbv_param;
struct ethernet_req_params {
union {
@@ -104,8 +123,10 @@
struct net_eth_addr mac_address;
struct ethernet_qav_param qav_param;
+ struct ethernet_qbv_param qbv_param;
int priority_queues_num;
+ int ports_num;
};
};
diff --git a/subsys/net/l2/ethernet/ethernet_mgmt.c b/subsys/net/l2/ethernet/ethernet_mgmt.c
index 92ab4e8..7e13f57 100644
--- a/subsys/net/l2/ethernet/ethernet_mgmt.c
+++ b/subsys/net/l2/ethernet/ethernet_mgmt.c
@@ -139,6 +139,26 @@
memcpy(&config.qav_param, ¶ms->qav_param,
sizeof(struct ethernet_qav_param));
type = ETHERNET_CONFIG_TYPE_QAV_PARAM;
+ } else if (mgmt_request == NET_REQUEST_ETHERNET_SET_QBV_PARAM) {
+ if (!is_hw_caps_supported(dev, ETHERNET_QBV)) {
+ return -ENOTSUP;
+ }
+
+ /* Validate params which need global validating */
+ if (params->qbv_param.state == ETHERNET_QBV_STATE_TYPE_OPER) {
+ /* Read-only parameters */
+ return -EINVAL;
+ }
+
+ if (params->qbv_param.type == ETHERNET_QBV_PARAM_TYPE_TIME &&
+ (params->qbv_param.cycle_time.nanosecond >= 1000000000 ||
+ params->qbv_param.base_time.fract_nsecond >= 1000000000)) {
+ return -EINVAL;
+ }
+
+ memcpy(&config.qbv_param, ¶ms->qbv_param,
+ sizeof(struct ethernet_qbv_param));
+ type = ETHERNET_CONFIG_TYPE_QBV_PARAM;
} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_PROMISC_MODE) {
if (!is_hw_caps_supported(dev, ETHERNET_PROMISC_MODE)) {
return -ENOTSUP;
@@ -168,6 +188,9 @@
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_QAV_PARAM,
ethernet_set_config);
+NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_QBV_PARAM,
+ ethernet_set_config);
+
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_PROMISC_MODE,
ethernet_set_config);
@@ -244,6 +267,63 @@
break;
}
+ } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_PORTS_NUM) {
+ type = ETHERNET_CONFIG_TYPE_PORTS_NUM;
+
+ ret = api->get_config(dev, type, &config);
+ if (ret) {
+ return ret;
+ }
+
+ params->ports_num = config.ports_num;
+
+ } else if (mgmt_request == NET_REQUEST_ETHERNET_GET_QBV_PARAM) {
+ if (!is_hw_caps_supported(dev, ETHERNET_QBV)) {
+ return -ENOTSUP;
+ }
+
+ config.qbv_param.port_id = params->qbv_param.port_id;
+ config.qbv_param.type = params->qbv_param.type;
+ config.qbv_param.state = params->qbv_param.state;
+
+ if (config.qbv_param.type ==
+ ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST) {
+ config.qbv_param.gate_control.row =
+ params->qbv_param.gate_control.row;
+ }
+
+ type = ETHERNET_CONFIG_TYPE_QBV_PARAM;
+
+ ret = api->get_config(dev, type, &config);
+ if (ret) {
+ return ret;
+ }
+
+ switch (config.qbv_param.type) {
+ case ETHERNET_QBV_PARAM_TYPE_STATUS:
+ params->qbv_param.enabled = config.qbv_param.enabled;
+ break;
+ case ETHERNET_QBV_PARAM_TYPE_TIME:
+ memcpy(¶ms->qbv_param.cycle_time,
+ &config.qbv_param.cycle_time,
+ sizeof(params->qbv_param.cycle_time));
+ memcpy(¶ms->qbv_param.base_time,
+ &config.qbv_param.base_time,
+ sizeof(params->qbv_param.base_time));
+ params->qbv_param.extension_time =
+ config.qbv_param.extension_time;
+ break;
+ case ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST_LEN:
+ params->qbv_param.gate_control_list_len =
+ config.qbv_param.gate_control_list_len;
+ break;
+ case ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST:
+ memcpy(¶ms->qbv_param.gate_control,
+ &config.qbv_param.gate_control,
+ sizeof(params->qbv_param.gate_control));
+ break;
+ }
+
} else {
return -EINVAL;
}
@@ -257,6 +337,12 @@
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QAV_PARAM,
ethernet_get_config);
+NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_PORTS_NUM,
+ ethernet_get_config);
+
+NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBV_PARAM,
+ ethernet_get_config);
+
void ethernet_mgmt_raise_carrier_on_event(struct net_if *iface)
{
net_mgmt_event_notify(NET_EVENT_ETHERNET_CARRIER_ON, iface);