aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch5113
1 files changed, 0 insertions, 5113 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch b/target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch
deleted file mode 100644
index 33de677930..0000000000
--- a/target/linux/layerscape/patches-5.4/701-net-0334-net-tsn-netlink-interface-for-APP-layer-to-config-TS.patch
+++ /dev/null
@@ -1,5113 +0,0 @@
-From e478ab518612f1a821968e1bb5b08b01b10085b0 Mon Sep 17 00:00:00 2001
-From: Po Liu <Po.Liu@nxp.com>
-Date: Tue, 15 Oct 2019 16:11:40 +0800
-Subject: [PATCH] net:tsn: netlink interface for APP layer to config TSN
- capability hardware ports
-
-This patch provids netlink method to configure the TSN protocols hardwares.
-TSN guaranteed packet transport with bounded low latency, low packet delay
-variation, and low packet loss by hardware and software methods.
-
-The three basic components of TSN are:
-
-1. Time synchronization: This was implement by 8021AS which base on the
- IEEE1588 precision Time Protocol. This is configured by the other way
- in kernel.
- 8021AS not included in this patch.
-
-2. Scheduling and traffic shaping and per-stream filter policing:
- This patch support Qbv/Qci/Qbu/8021CB/Qav etc.
-
-3. Selection of communication paths:
- This patch not support the pure software only TSN protocols(like Qcc)
- but hardware related configuration.
-
-TSN Protocols supports by this patch: Qbv/Qci/Qbu/Credit-base Shaper(Qav).
-This patch verified on NXP ls1028ardb board.
-
-Signed-off-by: Po Liu <Po.Liu@nxp.com>
----
- include/net/tsn.h | 114 ++
- include/uapi/linux/tsn.h | 1207 +++++++++++++++
- net/Kconfig | 1 +
- net/Makefile | 3 +
- net/tsn/Kconfig | 15 +
- net/tsn/Makefile | 1 +
- net/tsn/genl_tsn.c | 3696 ++++++++++++++++++++++++++++++++++++++++++++++
- 7 files changed, 5037 insertions(+)
- create mode 100644 include/net/tsn.h
- create mode 100644 include/uapi/linux/tsn.h
- create mode 100644 net/tsn/Kconfig
- create mode 100644 net/tsn/Makefile
- create mode 100644 net/tsn/genl_tsn.c
-
---- /dev/null
-+++ b/include/net/tsn.h
-@@ -0,0 +1,114 @@
-+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-+/* Copyright 2017-2019 NXP */
-+
-+#ifndef __TSN_H__
-+#define __TSN_H__
-+
-+#include <linux/notifier.h>
-+#include <uapi/linux/tsn.h>
-+
-+enum tsn_notifier_type {
-+ TSN_QBV_CONFIGCHANGETIME_ARRIVE = 1,
-+};
-+
-+struct tsn_notifier_info {
-+ struct net_device *dev;
-+ union {
-+ struct tsn_qbv_conf qbv_notify;
-+ struct tsn_qci_psfp_sgi_conf qci_notify;
-+ } ntdata;
-+};
-+
-+static inline struct net_device *
-+tsn_notifier_info_to_dev(const struct tsn_notifier_info *info)
-+{
-+ return info->dev;
-+}
-+
-+struct tsn_ops {
-+ void (*device_init)(struct net_device *ndev);
-+ void (*device_deinit)(struct net_device *ndev);
-+ u32 (*get_capability)(struct net_device *ndev);
-+ /* Qbv standard */
-+ int (*qbv_set)(struct net_device *ndev, struct tsn_qbv_conf *qbvconf);
-+ int (*qbv_get)(struct net_device *ndev, struct tsn_qbv_conf *qbvconf);
-+ int (*qbv_get_status)(struct net_device *ndev,
-+ struct tsn_qbv_status *qbvstat);
-+ int (*cb_streamid_set)(struct net_device *ndev, u32 index,
-+ bool enable, struct tsn_cb_streamid *sid);
-+ int (*cb_streamid_get)(struct net_device *ndev, u32 index,
-+ struct tsn_cb_streamid *sid);
-+ int (*cb_streamid_counters_get)(struct net_device *ndev, u32 index,
-+ struct tsn_cb_streamid_counters *sidcounter);
-+ int (*qci_get_maxcap)(struct net_device *ndev,
-+ struct tsn_qci_psfp_stream_param *qcicapa);
-+ int (*qci_sfi_set)(struct net_device *ndev, u32 index, bool enable,
-+ struct tsn_qci_psfp_sfi_conf *sficonf);
-+ /* return: 0 stream filter instance not valid
-+ * 1 stream filter instance valid
-+ * -1 error happened
-+ */
-+ int (*qci_sfi_get)(struct net_device *ndev, u32 index,
-+ struct tsn_qci_psfp_sfi_conf *sficonf);
-+ int (*qci_sfi_counters_get)(struct net_device *ndev, u32 index,
-+ struct tsn_qci_psfp_sfi_counters *sficounter);
-+ int (*qci_sgi_set)(struct net_device *ndev, u32 index,
-+ struct tsn_qci_psfp_sgi_conf *sgiconf);
-+ int (*qci_sgi_get)(struct net_device *ndev, u32 index,
-+ struct tsn_qci_psfp_sgi_conf *sgiconf);
-+ int (*qci_sgi_status_get)(struct net_device *ndev, u16 index,
-+ struct tsn_psfp_sgi_status *sgistat);
-+ int (*qci_fmi_set)(struct net_device *ndev, u32 index, bool enable,
-+ struct tsn_qci_psfp_fmi *fmi);
-+ int (*qci_fmi_get)(struct net_device *ndev, u32 index,
-+ struct tsn_qci_psfp_fmi *fmi,
-+ struct tsn_qci_psfp_fmi_counters *counters);
-+ int (*cbs_set)(struct net_device *ndev, u8 tc, u8 bw);
-+ int (*cbs_get)(struct net_device *ndev, u8 tc);
-+ /* To set a 8 bits vector shows 8 traffic classes
-+ * preemtable(1) or express(0)
-+ */
-+ int (*qbu_set)(struct net_device *ndev, u8 ptvector);
-+ /* To get port preemtion status */
-+ int (*qbu_get)(struct net_device *ndev,
-+ struct tsn_preempt_status *preemptstat);
-+ int (*tsd_set)(struct net_device *ndev, struct tsn_tsd *tsd);
-+ int (*tsd_get)(struct net_device *ndev, struct tsn_tsd_status *stats);
-+ int (*ct_set)(struct net_device *ndev, u8 cut_thru);
-+ int (*cbgen_set)(struct net_device *ndev, u32 index,
-+ struct tsn_seq_gen_conf *seqgen);
-+ int (*cbrec_set)(struct net_device *ndev, u32 index,
-+ struct tsn_seq_rec_conf *seqrec);
-+ int (*cb_get)(struct net_device *ndev, u32 index,
-+ struct tsn_cb_status *c);
-+ int (*dscp_set)(struct net_device *ndev, bool enable,
-+ const u8 dscp_ix,
-+ struct tsn_qos_switch_dscp_conf *c);
-+};
-+
-+enum ethdev_type {
-+ TSN_SWITCH,
-+ TSN_ENDPOINT,
-+};
-+
-+#define GROUP_OFFSET_SWITCH 256
-+
-+struct tsn_port {
-+ u16 groupid;
-+ struct tsn_ops *tsnops;
-+ struct net_device *netdev;
-+ struct list_head list;
-+ enum ethdev_type type;
-+ u8 tc_nums;
-+ struct tsn_notifier_info nd;
-+};
-+
-+struct tsn_port *tsn_get_port(struct net_device *ndev);
-+int register_tsn_notifier(struct notifier_block *nb);
-+int unregister_tsn_notifier(struct notifier_block *nb);
-+int call_tsn_notifiers(unsigned long val, struct net_device *dev,
-+ struct tsn_notifier_info *info);
-+int tsn_port_register(struct net_device *netdev,
-+ struct tsn_ops *tsnops, u16 groupid);
-+void tsn_port_unregister(struct net_device *netdev);
-+#endif
---- /dev/null
-+++ b/include/uapi/linux/tsn.h
-@@ -0,0 +1,1207 @@
-+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-+/* Copyright 2017-2019 NXP */
-+
-+#ifndef __UAPI_GENL_TSN_H
-+#define __UAPI_GENL_TSN_H
-+
-+#define TSN_GENL_NAME "TSN_GEN_CTRL"
-+#define TSN_GENL_VERSION 0x1
-+
-+#define MAX_USER_SIZE 0
-+#define MAX_ATTR_SIZE 3072
-+#define MAX_TOTAL_MSG_SIZE (MAX_USER_SIZE + MAX_ATTR_SIZE)
-+#define MAX_ENTRY_SIZE 2048
-+#define MAX_ENTRY_NUMBER 128
-+#define MAX_IFNAME_COUNT 64
-+
-+#define TSN_MULTICAST_GROUP_QBV "qbv"
-+#define TSN_MULTICAST_GROUP_QCI "qci"
-+
-+/* multicast groups */
-+enum tsn_multicast_groups {
-+ TSN_MCGRP_QBV,
-+ TSN_MCGRP_QCI,
-+ TSN_MCGRP_MAX
-+};
-+
-+enum tsn_capability {
-+ TSN_CAP_QBV = 0x1,
-+ TSN_CAP_QCI = 0x2,
-+ TSN_CAP_QBU = 0x4,
-+ TSN_CAP_CBS = 0x8, /* Credit-based Shapter Qav */
-+ TSN_CAP_CB = 0x10, /* 8021CB redundancy and replication */
-+ TSN_CAP_TBS = 0x20, /* Time Based schedule */
-+ TSN_CAP_CTH = 0x40, /* cut through */
-+};
-+
-+/*
-+ * Commands sent from userspace
-+ * Not versioned. New commands should only be inserted at the enum's end
-+ * prior to __TSN_CMD_MAX
-+ */
-+
-+enum {
-+ TSN_CMD_UNSPEC = 0, /* Reserved */
-+ TSN_CMD_QBV_SET,
-+ TSN_CMD_QBV_GET,
-+ TSN_CMD_QBV_GET_STATUS,
-+ TSN_CMD_CB_STREAMID_SET,
-+ TSN_CMD_CB_STREAMID_GET,
-+ TSN_CMD_CB_STREAMID_GET_COUNTS,
-+ TSN_CMD_QCI_CAP_GET, /* Qci capability get length capability get */
-+ TSN_CMD_QCI_SFI_SET,
-+ TSN_CMD_QCI_SFI_GET,
-+ TSN_CMD_QCI_SFI_GET_COUNTS,
-+ TSN_CMD_QCI_SGI_SET,
-+ TSN_CMD_QCI_SGI_GET,
-+ TSN_CMD_QCI_SGI_GET_STATUS,
-+ TSN_CMD_QCI_FMI_SET,
-+ TSN_CMD_QCI_FMI_GET,
-+ TSN_CMD_CBS_SET,
-+ TSN_CMD_CBS_GET,
-+ TSN_CMD_QBU_SET,
-+ TSN_CMD_QBU_GET_STATUS,
-+ TSN_CMD_QAV_SET_CBS,
-+ TSN_CMD_QAV_GET_CBS,
-+ TSN_CMD_TSD_SET,
-+ TSN_CMD_TSD_GET,
-+ TSN_CMD_CT_SET,
-+ TSN_CMD_CBGEN_SET,
-+ TSN_CMD_CBREC_SET,
-+ TSN_CMD_CBSTAT_GET,
-+ TSN_CMD_PCPMAP_SET_UNUSE,
-+ TSN_CMD_DSCP_SET,
-+ TSN_CMD_ECHO, /* user->kernel request/get-response */
-+ TSN_CMD_REPLY, /* kernel->user event */
-+ TSN_CMD_CAP_GET,
-+ __TSN_CMD_MAX,
-+};
-+#define TSN_CMD_MAX (__TSN_CMD_MAX - 1)
-+
-+
-+enum {
-+ TSN_CMD_ATTR_UNSPEC = 0,
-+ TSN_CMD_ATTR_MESG, /* demo message */
-+ TSN_CMD_ATTR_DATA, /* demo data */
-+ TSN_ATTR_IFNAME,
-+ TSN_ATTR_PORT_NUMBER,
-+ TSN_ATTR_QBV,
-+ TSN_ATTR_STREAM_IDENTIFY, /* stream identify */
-+ TSN_ATTR_QCI_SP, /* psfp port capbility parameters */
-+ TSN_ATTR_QCI_SFI, /* psfp stream filter instance */
-+ TSN_ATTR_QCI_SGI, /* psfp stream gate instance */
-+ TSN_ATTR_QCI_FMI, /* psfp flow meter instance */
-+ TSN_ATTR_CBS, /* credit-based shaper */
-+ TSN_ATTR_TSD, /* Time Specific Departure */
-+ TSN_ATTR_QBU, /* preemption */
-+ TSN_ATTR_CT, /* cut through */
-+ TSN_ATTR_CBGEN, /* 802.1CB sequence generate */
-+ TSN_ATTR_CBREC, /* 802.1CB sequence recover */
-+ TSN_ATTR_CBSTAT, /* 802.1CB status */
-+ TSN_ATTR_PCPMAP_UNUSE,
-+ TSN_ATTR_DSCP,
-+ TSN_ATTR_CAP, /* TSN capbility */
-+ __TSN_CMD_ATTR_MAX,
-+};
-+#define TSN_CMD_ATTR_MAX (__TSN_CMD_ATTR_MAX - 1)
-+
-+enum {
-+ TSN_CAP_ATTR_UNSPEC,
-+ TSN_CAP_ATTR_QBV,
-+ TSN_CAP_ATTR_QCI,
-+ TSN_CAP_ATTR_QBU,
-+ TSN_CAP_ATTR_CBS,
-+ TSN_CAP_ATTR_CB,
-+ TSN_CAP_ATTR_TBS,
-+ TSN_CAP_ATTR_CTH,
-+ __TSN_CAP_ATTR_MAX,
-+ TSN_CAP_ATTR_MAX = __TSN_CAP_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QBU_ATTR_UNSPEC,
-+ TSN_QBU_ATTR_ADMIN_STATE,
-+ TSN_QBU_ATTR_HOLD_ADVANCE,
-+ TSN_QBU_ATTR_RELEASE_ADVANCE,
-+ TSN_QBU_ATTR_ACTIVE,
-+ TSN_QBU_ATTR_HOLD_REQUEST,
-+ __TSN_QBU_ATTR_MAX,
-+ TSN_QBU_ATTR_MAX = __TSN_QBU_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_CBS_ATTR_UNSPEC,
-+ TSN_CBS_ATTR_TC_INDEX,
-+ TSN_CBS_ATTR_BW,
-+ __TSN_CBS_ATTR_MAX,
-+ TSN_CBS_ATTR_MAX = __TSN_CBS_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_TSD_ATTR_UNSPEC,
-+ TSN_TSD_ATTR_DISABLE,
-+ TSN_TSD_ATTR_ENABLE,
-+ TSN_TSD_ATTR_PERIOD,
-+ TSN_TSD_ATTR_MAX_FRM_NUM,
-+ TSN_TSD_ATTR_CYCLE_NUM,
-+ TSN_TSD_ATTR_LOSS_STEPS,
-+ TSN_TSD_ATTR_SYN_IMME,
-+ __TSN_TSD_ATTR_MAX,
-+ TSN_TSD_ATTR_MAX = __TSN_TSD_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_STREAMID_ATTR_UNSPEC,
-+ TSN_STREAMID_ATTR_INDEX,
-+ TSN_STREAMID_ATTR_ENABLE,
-+ TSN_STREAMID_ATTR_DISABLE,
-+ TSN_STREAMID_ATTR_STREAM_HANDLE,
-+ TSN_STREAMID_ATTR_IFOP,
-+ TSN_STREAMID_ATTR_OFOP,
-+ TSN_STREAMID_ATTR_IFIP,
-+ TSN_STREAMID_ATTR_OFIP,
-+ TSN_STREAMID_ATTR_TYPE,
-+ TSN_STREAMID_ATTR_NDMAC,
-+ TSN_STREAMID_ATTR_NTAGGED,
-+ TSN_STREAMID_ATTR_NVID,
-+ TSN_STREAMID_ATTR_SMAC,
-+ TSN_STREAMID_ATTR_STAGGED,
-+ TSN_STREAMID_ATTR_SVID,
-+ TSN_STREAMID_ATTR_COUNTERS_PSI,
-+ TSN_STREAMID_ATTR_COUNTERS_PSO,
-+ TSN_STREAMID_ATTR_COUNTERS_PSPPI,
-+ TSN_STREAMID_ATTR_COUNTERS_PSPPO,
-+ __TSN_STREAMID_ATTR_MAX,
-+ TSN_STREAMID_ATTR_MAX = __TSN_STREAMID_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QCI_STREAM_ATTR_UNSPEC = 0,
-+ TSN_QCI_STREAM_ATTR_MAX_SFI,
-+ TSN_QCI_STREAM_ATTR_MAX_SGI,
-+ TSN_QCI_STREAM_ATTR_MAX_FMI,
-+ TSN_QCI_STREAM_ATTR_SLM,
-+ __TSN_QCI_STREAM_ATTR_MAX,
-+ TSN_QCI_STREAM_ATTR_MAX = __TSN_QCI_STREAM_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QCI_SFI_ATTR_UNSPEC = 0,
-+ TSN_QCI_SFI_ATTR_INDEX,
-+ TSN_QCI_SFI_ATTR_ENABLE,
-+ TSN_QCI_SFI_ATTR_DISABLE,
-+ TSN_QCI_SFI_ATTR_STREAM_HANDLE,
-+ TSN_QCI_SFI_ATTR_PRIO_SPEC,
-+ TSN_QCI_SFI_ATTR_GATE_ID,
-+ TSN_QCI_SFI_ATTR_FILTER_TYPE,
-+ TSN_QCI_SFI_ATTR_FLOW_ID,
-+ TSN_QCI_SFI_ATTR_MAXSDU,
-+ TSN_QCI_SFI_ATTR_COUNTERS,
-+ TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE,
-+ TSN_QCI_SFI_ATTR_OVERSIZE,
-+ __TSN_QCI_SFI_ATTR_MAX,
-+ TSN_QCI_SFI_ATTR_MAX = __TSN_QCI_SFI_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QCI_SFI_ATTR_COUNTERS_UNSPEC = 0,
-+ TSN_QCI_SFI_ATTR_MATCH,
-+ TSN_QCI_SFI_ATTR_PASS,
-+ TSN_QCI_SFI_ATTR_DROP,
-+ TSN_QCI_SFI_ATTR_SDU_DROP,
-+ TSN_QCI_SFI_ATTR_SDU_PASS,
-+ TSN_QCI_SFI_ATTR_RED,
-+ __TSN_QCI_SFI_ATTR_COUNT_MAX,
-+ TSN_QCI_SFI_ATTR_COUNT_MAX = __TSN_QCI_SFI_ATTR_COUNT_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QCI_SGI_ATTR_UNSPEC = 0,
-+ TSN_QCI_SGI_ATTR_INDEX,
-+ TSN_QCI_SGI_ATTR_ENABLE,
-+ TSN_QCI_SGI_ATTR_DISABLE,
-+ TSN_QCI_SGI_ATTR_CONFCHANGE,
-+ TSN_QCI_SGI_ATTR_IRXEN, /* Invalid rx enable*/
-+ TSN_QCI_SGI_ATTR_IRX,
-+ TSN_QCI_SGI_ATTR_OEXEN, /* Octet exceed enable */
-+ TSN_QCI_SGI_ATTR_OEX,
-+ TSN_QCI_SGI_ATTR_ADMINENTRY,
-+ TSN_QCI_SGI_ATTR_OPERENTRY,
-+ TSN_QCI_SGI_ATTR_CCTIME, /* config change time */
-+ TSN_QCI_SGI_ATTR_TICKG,
-+ TSN_QCI_SGI_ATTR_CUTIME,
-+ TSN_QCI_SGI_ATTR_CPENDING,
-+ TSN_QCI_SGI_ATTR_CCERROR,
-+ __TSN_QCI_SGI_ATTR_MAX,
-+ TSN_QCI_SGI_ATTR_MAX = __TSN_QCI_SGI_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_SGI_ATTR_CTRL_UNSPEC = 0,
-+ TSN_SGI_ATTR_CTRL_INITSTATE,
-+ TSN_SGI_ATTR_CTRL_LEN,
-+ TSN_SGI_ATTR_CTRL_CYTIME,
-+ TSN_SGI_ATTR_CTRL_CYTIMEEX,
-+ TSN_SGI_ATTR_CTRL_BTIME,
-+ TSN_SGI_ATTR_CTRL_INITIPV,
-+ TSN_SGI_ATTR_CTRL_GCLENTRY,
-+ __TSN_SGI_ATTR_CTRL_MAX,
-+ TSN_SGI_ATTR_CTRL_MAX = __TSN_SGI_ATTR_CTRL_MAX - 1,
-+};
-+
-+enum {
-+ TSN_SGI_ATTR_GCL_UNSPEC = 0,
-+ TSN_SGI_ATTR_GCL_GATESTATE,
-+ TSN_SGI_ATTR_GCL_IPV,
-+ TSN_SGI_ATTR_GCL_INTERVAL,
-+ TSN_SGI_ATTR_GCL_OCTMAX,
-+ __TSN_SGI_ATTR_GCL_MAX,
-+ TSN_SGI_ATTR_GCL_MAX = __TSN_SGI_ATTR_GCL_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QCI_FMI_ATTR_UNSPEC = 0,
-+ TSN_QCI_FMI_ATTR_INDEX,
-+ TSN_QCI_FMI_ATTR_ENABLE,
-+ TSN_QCI_FMI_ATTR_DISABLE,
-+ TSN_QCI_FMI_ATTR_CIR,
-+ TSN_QCI_FMI_ATTR_CBS,
-+ TSN_QCI_FMI_ATTR_EIR,
-+ TSN_QCI_FMI_ATTR_EBS,
-+ TSN_QCI_FMI_ATTR_CF,
-+ TSN_QCI_FMI_ATTR_CM,
-+ TSN_QCI_FMI_ATTR_DROPYL,
-+ TSN_QCI_FMI_ATTR_MAREDEN,
-+ TSN_QCI_FMI_ATTR_MARED,
-+ TSN_QCI_FMI_ATTR_COUNTERS,
-+ __TSN_QCI_FMI_ATTR_MAX,
-+ TSN_QCI_FMI_ATTR_MAX = __TSN_QCI_FMI_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QBV_ATTR_UNSPEC,
-+ TSN_QBV_ATTR_ENABLE,
-+ TSN_QBV_ATTR_DISABLE,
-+ TSN_QBV_ATTR_CONFIGCHANGE,
-+ TSN_QBV_ATTR_CONFIGCHANGETIME,
-+ TSN_QBV_ATTR_MAXSDU,
-+ TSN_QBV_ATTR_GRANULARITY,
-+ TSN_QBV_ATTR_CURRENTTIME,
-+ TSN_QBV_ATTR_CONFIGPENDING,
-+ TSN_QBV_ATTR_CONFIGCHANGEERROR,
-+ TSN_QBV_ATTR_ADMINENTRY,
-+ TSN_QBV_ATTR_OPERENTRY,
-+ TSN_QBV_ATTR_LISTMAX,
-+ __TSN_QBV_ATTR_MAX,
-+ TSN_QBV_ATTR_MAX = __TSN_QBV_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QBV_ATTR_CTRL_UNSPEC,
-+ TSN_QBV_ATTR_CTRL_LISTCOUNT,
-+ TSN_QBV_ATTR_CTRL_GATESTATE,
-+ TSN_QBV_ATTR_CTRL_CYCLETIME,
-+ TSN_QBV_ATTR_CTRL_CYCLETIMEEXT,
-+ TSN_QBV_ATTR_CTRL_BASETIME,
-+ TSN_QBV_ATTR_CTRL_LISTENTRY,
-+ __TSN_QBV_ATTR_CTRL_MAX,
-+ TSN_QBV_ATTR_CTRL_MAX = __TSN_QBV_ATTR_CTRL_MAX - 1,
-+};
-+
-+enum {
-+ TSN_QBV_ATTR_ENTRY_UNSPEC,
-+ TSN_QBV_ATTR_ENTRY_ID,
-+ TSN_QBV_ATTR_ENTRY_GC,
-+ TSN_QBV_ATTR_ENTRY_TM,
-+ __TSN_QBV_ATTR_ENTRY_MAX,
-+ TSN_QBV_ATTR_ENTRY_MAX = __TSN_QBV_ATTR_ENTRY_MAX - 1,
-+};
-+
-+enum {
-+ TSN_CT_ATTR_UNSPEC,
-+ TSN_CT_ATTR_QUEUE_STATE,
-+ __TSN_CT_ATTR_MAX,
-+ TSN_CT_ATTR_MAX = __TSN_CT_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_CBGEN_ATTR_UNSPEC,
-+ TSN_CBGEN_ATTR_INDEX,
-+ TSN_CBGEN_ATTR_PORT_MASK,
-+ TSN_CBGEN_ATTR_SPLIT_MASK,
-+ TSN_CBGEN_ATTR_SEQ_LEN,
-+ TSN_CBGEN_ATTR_SEQ_NUM,
-+ __TSN_CBGEN_ATTR_MAX,
-+ TSN_CBGEN_ATTR_MAX = __TSN_CBGEN_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_CBREC_ATTR_UNSPEC,
-+ TSN_CBREC_ATTR_INDEX,
-+ TSN_CBREC_ATTR_SEQ_LEN,
-+ TSN_CBREC_ATTR_HIS_LEN,
-+ TSN_CBREC_ATTR_TAG_POP_EN,
-+ __TSN_CBREC_ATTR_MAX,
-+ TSN_CBREC_ATTR_MAX = __TSN_CBREC_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_CBSTAT_ATTR_UNSPEC,
-+ TSN_CBSTAT_ATTR_INDEX,
-+ TSN_CBSTAT_ATTR_GEN_REC,
-+ TSN_CBSTAT_ATTR_ERR,
-+ TSN_CBSTAT_ATTR_SEQ_NUM,
-+ TSN_CBSTAT_ATTR_SEQ_LEN,
-+ TSN_CBSTAT_ATTR_SPLIT_MASK,
-+ TSN_CBSTAT_ATTR_PORT_MASK,
-+ TSN_CBSTAT_ATTR_HIS_LEN,
-+ TSN_CBSTAT_ATTR_SEQ_HIS,
-+ __TSN_CBSTAT_ATTR_MAX,
-+ TSN_CBSTAT_ATTR_MAX = __TSN_CBSTAT_ATTR_MAX - 1,
-+};
-+
-+enum {
-+ TSN_DSCP_ATTR_UNSPEC,
-+ TSN_DSCP_ATTR_DISABLE,
-+ TSN_DSCP_ATTR_INDEX,
-+ TSN_DSCP_ATTR_COS,
-+ TSN_DSCP_ATTR_DPL,
-+ __TSN_DSCP_ATTR_MAX,
-+ TSN_DSCP_ATTR_MAX = __TSN_DSCP_ATTR_MAX - 1,
-+};
-+
-+#define ptptime_t __u64
-+
-+#define MAX_QUEUE_CNT 8
-+
-+struct tsn_preempt_status {
-+ /* The value of admin_state shows a 8-bits vector value for showing
-+ * the framePreemptionAdminStatus parameter and PreemptionPriority
-+ * for the traffic class. Bit-7 is the highest priority traffic class
-+ * and the bit-0 is the lowest priority traffic class.
-+ * The bit is express (0) and is preemptible (1).
-+ */
-+ __u8 admin_state;
-+ /* The value of the holdAdvance parameter for the port in nanoseconds.
-+ * There is no default value; the holdAdvance is a property of the
-+ * underlying MAC." This parameter corresponds to the holdAdvance
-+ * parameter in 802.1Qbu.
-+ */
-+ __u32 hold_advance;
-+
-+ /* The value of the releaseAdvance parameter for the port in
-+ * nanoseconds. There is no default value; the releaseAdvance is a
-+ * property of the underlying MAC." This parameter corresponds to the
-+ * releaseAdvance parameter in 802.1Qbu.
-+ */
-+ __u32 release_advance;
-+
-+ /* The value is active (TRUE) when preemption is operationally active
-+ * for the port, and idle (FALSE) otherwise. This parameter corresponds
-+ * to the preemptionActive parameter in 802.1Qbu.
-+ */
-+ __u8 preemption_active;
-+
-+ /* The value is hold (1) when the sequence of gate operations for
-+ * the port has executed a Set-And-Hold-MAC operation, and release
-+ * (2) when the sequence of gate operations has executed a
-+ * Set-And-Release-MAC operation. The value of this object is release
-+ * (FALSE) on system initialization. This parameter corresponds to the
-+ * holdRequest parameter in 802.1Qbu.
-+ */
-+ __u8 hold_request;
-+};
-+
-+enum tsn_tx_mode {
-+ TX_MODE_STRICT,
-+ TX_MODE_CBS,
-+ TX_MODE_ETS,
-+ TX_MODE_VENDOR_DEFINE = 255,
-+};
-+
-+#define QUEUE_TX_MASK ((1 << TX_MODE_STRICT) | (1 << TX_MODE_CBS) \
-+ | (1 << TX_MODE_ETS) | (1 << TX_MODE_VENDOR_DEFINE))
-+
-+struct cbs_status {
-+ __u8 delta_bw; /* percentage, 0~100 */
-+ __u32 idleslope;
-+ __s32 sendslope;
-+ __u32 maxframesize;
-+ __u32 hicredit;
-+ __s32 locredit;
-+ __u32 maxninference;
-+};
-+
-+struct tx_queue {
-+ /* tx_queue_capbility shows the queue's capability mask.
-+ * refer the enum tsn_tx_mode
-+ */
-+ __u8 capability;
-+
-+ /* tx_queue_mode is current queue working mode */
-+ __u8 mode;
-+
-+ /* prio is showing the queue priority */
-+ __u8 prio;
-+
-+ /* mstat shows the status data of cbs or priority */
-+ union {
-+ struct cbs_status cbs;
-+ };
-+};
-+
-+struct port_status {
-+ /* txqueue_cnt shows how many queues in this port */
-+ __u8 queue_cnt;
-+
-+ /* max_rate(Mbit/s) is the port transmit rate current port is setting */
-+ __u32 max_rate;
-+
-+ /* tsn_capability mask the tsn capability */
-+ __u32 tsn_capability;
-+};
-+
-+enum tsn_cb_streamid_type {
-+ STREAMID_RESERVED = 0,
-+ /* Null Stream identification */
-+ STREAMID_NULL,
-+ /* Source MAC and VLAN Stream identification */
-+ STREAMID_SMAC_VLAN,
-+ /* Active Destination MAC and VLAN stream identification */
-+ STREAMID_DMAC_VLAN,
-+ /* IP stream identification */
-+ STREAMID_IP,
-+};
-+
-+/* When instantiating an instance of the Null Stream identification function
-+ * 8021CB(6.4) for a particular input Stream, the managed objects in the
-+ * following subsections serve as the tsnStreamIdParameters managed object
-+ * 8021CB claus(9.1.1.7).
-+ */
-+struct tsn_cb_null_streamid {
-+ /* tsnCpeNullDownDestMac. Specifies the destination_address that
-+ * identifies a packet in an Enhanced Internal Sublayer Service (EISS)
-+ * indication primitive, to the Null Stream identification function.
-+ */
-+ __u64 dmac;
-+
-+ /* tsnCpeNullDownTagged. It can take the following values:
-+ * 1 tagged: A frame must have a VLAN tag to be recognized as belonging
-+ * to the Stream.
-+ * 2 priority: A frame must be untagged, or have a VLAN tag with a VLAN
-+ * ID = 0 to be recognized as belonging to the Stream.
-+ * 3 all: A frame is recognized as belonging to the Stream whether
-+ * tagged or not.
-+ */
-+ __u8 tagged;
-+
-+ /* tsnCpeNullDownVlan. Specifies the vlan_identifier parameter that
-+ * identifies a packet in an EISS indication primitive to the Null
-+ * Stream identification function. A value of 0 indicates that the vlan
-+ * _identifier parameter is ignored on EISS indication primitives.
-+ */
-+ __u16 vid;
-+};
-+
-+struct tsn_cb_source_streamid {
-+ __u64 smac;
-+ __u8 tagged;
-+ __u16 vid;
-+};
-+
-+struct tsn_cb_dest_streamid {
-+ __u64 down_dmac;
-+ __u8 down_tagged;
-+ __u16 down_vid;
-+ __u8 down_prio;
-+ __u64 up_dmac;
-+ __u8 up_tagged;
-+ __u16 up_vid;
-+ __u8 up_prio;
-+};
-+
-+struct tsn_cb_ip_streamid {
-+ __u64 dmac;
-+ __u8 tagged;
-+ __u16 vid;
-+ __u64 siph;
-+ __u64 sipl;
-+ __u64 diph;
-+ __u64 dipl;
-+ __u8 dscp;
-+ __u8 npt;
-+ __u16 sport;
-+ __u16 dport;
-+};
-+
-+/* 802.1CB stream identify table clause 9.1 */
-+struct tsn_cb_streamid {
-+ /* The objects in a given entry of the Stream identity table are used
-+ * to control packets whose stream_handle subparameter is equal to the
-+ * entry tsnStreamIdHandle object.
-+ */
-+ __s32 handle;
-+
-+ /* The list of ports on which an in-facing Stream identification
-+ * function in the output (towards the system forwarding function)
-+ * direction Only Active Destination MAC and VLAN Stream identification
-+ * (or nothing) can be configured.
-+ */
-+ __u32 ifac_oport;
-+
-+ /* The list of ports on which an out-facing Stream identification
-+ * function in the output (towards the physical interface) direction.
-+ * Only Active Destination MAC and VLAN Stream identification
-+ * (or nothing) can be configured.
-+ */
-+ __u32 ofac_oport;
-+
-+ /* The list of ports on which an in-facing Stream identification
-+ * function in the input (coming from the system forwarding function)
-+ * direction
-+ */
-+ __u32 ifac_iport;
-+
-+ /* The list of ports on which an out-facing Stream identification
-+ * function in the input (coming from the physical interface) direction
-+ * .
-+ */
-+ __u32 ofac_iport;
-+
-+ /* An enumerated value indicating the method used to identify packets
-+ * belonging to the Stream.
-+ * The Organizationally Unique Identifier (OUI) or Company Identifier
-+ * (CID) to identify the organization defining the enumerated type
-+ * should be: 00-80-C2
-+ * 1: null stream identification
-+ * 2: source mac and vlan stream identification
-+ * 3: activ destination mac and vlan stream identification
-+ * 4: ip stream identifaciton
-+ */
-+ __u8 type;
-+
-+ /* tsnStreamIdParameters The number of controlling parameters for a
-+ * Stream identification method, their types and values, are specific
-+ * to the tsnStreamIdIdentificationType
-+ */
-+ union {
-+ struct tsn_cb_null_streamid nid;
-+ struct tsn_cb_source_streamid sid;
-+ struct tsn_cb_dest_streamid did;
-+ struct tsn_cb_ip_streamid iid;
-+ } para;
-+};
-+
-+/* Following counters are instantiated for each port on which the Stream
-+ * identification function (6.2) is configured. The counters are indexed by
-+ * port number, facing (in-facing or out-facing), and stream_handle value
-+ * (tsnStreamIdHandle, 9.1.1.1).
-+ */
-+struct tsn_cb_streamid_counters {
-+ struct {
-+ __u64 input;
-+ __u64 output;
-+ } per_stream;
-+
-+ struct {
-+ __u64 input;
-+ __u64 output;
-+ } per_streamport[32];
-+};
-+
-+/* 802.1Qci Stream Parameter Table, read from port */
-+struct tsn_qci_psfp_stream_param {
-+ /* MaxStreamFilterInstances.
-+ * The maximum number of Stream Filter instances supported by this
-+ * Bridge component.
-+ */
-+ __s32 max_sf_instance;
-+
-+ /* MaxStreamGateInstances
-+ * The maximum number of Stream Gate instances supported by this Bridge
-+ * component.
-+ */
-+ __s32 max_sg_instance;
-+
-+ /* MaxFlowMeterInstances
-+ * The maximum number of Flow Meter instances supported by this Bridge
-+ * component.
-+ */
-+ __s32 max_fm_instance;
-+
-+ /* SupportedListMax
-+ * The maximum value supported by this Bridge component of the
-+ * AdminControlListLength and OperControlListLength parameters.
-+ */
-+ __s32 supported_list_max;
-+};
-+
-+/* 802.1Qci Stream Filter Instance Table, counters part only. */
-+struct tsn_qci_psfp_sfi_counters {
-+ /* The MatchingFramesCount counter counts received frames that match
-+ * this stream filter.
-+ */
-+ __u64 matching_frames_count;
-+
-+ /* The PassingFramesCount counter counts received frames that pass the
-+ * gate associated with this stream filter.
-+ */
-+ __u64 passing_frames_count;
-+
-+ /* The NotPassingFramesCount counter counts received frames that do not
-+ * pass the gate associated with this stream filter.
-+ */
-+ __u64 not_passing_frames_count;
-+
-+ /* The PassingSDUCount counter counts received frames that pass the SDU
-+ * size filter specification associated with this stream filter.
-+ */
-+ __u64 passing_sdu_count;
-+
-+ /* The NotPassingSDUCount counter counts received frames that do not
-+ * pass the SDU size filter specification associated with this stream
-+ * filter.
-+ */
-+ __u64 not_passing_sdu_count;
-+
-+ /* The REDFramesCount counter counts received random early detection
-+ * (RED) frames associated with this stream filter.
-+ */
-+ __u64 red_frames_count;
-+};
-+
-+/* 802.1Qci Stream Filter Instance Table, configuration part only. */
-+struct tsn_qci_psfp_sfi_conf {
-+
-+ /* The StreamHandleSpec parameter contains a stream identifier
-+ * specification value. A value of -1 denotes the wild card value; zero
-+ * or positive values denote stream identifier values.
-+ */
-+ __s32 stream_handle_spec;
-+
-+ /* The PrioritySpec parameter contains a priority specification value.
-+ * A value of -1 denotes the wild card value; zero or positive values
-+ * denote priority values.
-+ */
-+ __s8 priority_spec;
-+
-+ /* The StreamGateInstanceID parameter contains the index of an entry in
-+ * the Stream Gate Table.
-+ */
-+ __u32 stream_gate_instance_id;
-+
-+ /* The filter specifications. The actions specified in a filter
-+ * specification can result in a frame passing or failing the specified
-+ * filter. Frames that fail a filter are discarded.
-+ */
-+ struct {
-+ /* The MaximumSDUSize parameter specifies the maximum allowed
-+ * frame size for the stream. Any frame exceeding this value
-+ * will be dropped. A value of 0 denote that the MaximumSDUSize
-+ * filter is disabled for this stream.
-+ */
-+ __u16 maximum_sdu_size;
-+
-+ /* The FlowMeterInstanceID parameter contains the index of an
-+ * entry in the Flow Meter Table. A value of -1 denotes that
-+ * no flow meter is assigned; zero or positive values denote
-+ * flow meter IDs.
-+ */
-+ __s32 flow_meter_instance_id;
-+ } stream_filter;
-+
-+ /* The StreamBlockedDueToOversizeFrameEnable object contains a Boolean
-+ * value that indicates whether the StreamBlockedDueToOversizeFrame
-+ * function is enabled (TRUE) or disabled (FALSE).
-+ */
-+ __u8 block_oversize_enable;
-+
-+ /* The StreamBlockedDueToOversizeFrame object contains a Boolean value
-+ * that indicates whether, if the StreamBlockedDueToOversizeFrame
-+ * function is enabled, all frames are to be discarded (TRUE) or not
-+ * (FALSE).
-+ */
-+ __u8 block_oversize;
-+};
-+
-+/* 802.1Qci Stream Gate Control List Entry. */
-+struct tsn_qci_psfp_gcl {
-+ /* The GateState parameter specifies a desired state, open (true) or
-+ * closed (false), for the stream gate.
-+ */
-+ __u8 gate_state;
-+
-+ /* An IPV is encoded as a signed integer. A negative denotes the null
-+ * value; zero or positive values denote internal priority values.
-+ */
-+ __s8 ipv;
-+
-+ /* A TimeInterval is encoded in 4 octets as a 32-bit unsigned integer,
-+ * representing a number of nanoseconds.
-+ */
-+ __u32 time_interval;
-+
-+ /* The maximum number of octets that are permitted to pass the gate
-+ * during the specified TimeInterval. If zero, there is no maximum.
-+ */
-+ __u32 octet_max;
-+
-+};
-+
-+/* 802.1Qci Stream Gate Admin/Operation common list control parameters */
-+struct tsn_qci_sg_control {
-+ /* The administrative/operation value of the GateStates parameter
-+ * for the stream gate. A value of false indicates closed;
-+ * a value of true indicates open.
-+ */
-+ __u8 gate_states;
-+
-+ /* The administrative/operation value of the ListMax parameter for the
-+ * gate. The integer value indicates the number of entries (TLVs) in
-+ * the AdminControlList/OperControlList.
-+ */
-+ __u8 control_list_length;
-+
-+ /* The administrative/operation value of the CycleTime parameter for
-+ * the gate. The value is an unsigned integer number of nanoseconds.
-+ */
-+ __u32 cycle_time;
-+
-+ /* The administrative/operation value of the CycleTimeExtension
-+ * parameter for the gate. The value is an unsigned integer number
-+ * of nanoseconds.
-+ */
-+ __u32 cycle_time_extension;
-+
-+ /* The administrative/operation value of the BaseTime parameter for the
-+ * gate. The value is a representation of a PTPtime value, consisting
-+ * of a 48-bit integer number of seconds and a 32-bit integer number of
-+ * nanoseconds.
-+ */
-+ ptptime_t base_time;
-+
-+ /* The administrative/operation value of the IPV parameter for the gate.
-+ * A value of -1 denotes the null value; zero or positive values denote
-+ * internal priority values.
-+ */
-+ __s8 init_ipv;
-+
-+ /* control_list contend the gate control list of
-+ * administrative/operation
-+ */
-+ struct tsn_qci_psfp_gcl *gcl;
-+};
-+
-+/* 802.1Qci Stream Gate Instance Table, configuration part only. */
-+struct tsn_qci_psfp_sgi_conf {
-+ /* The GateEnabled parameter determines whether the stream gate is
-+ * active (true) or inactive (false).
-+ */
-+ __u8 gate_enabled;
-+
-+ /* The ConfigChange parameter signals the start of a configuration
-+ * change when it is set to TRUE. This should only be done when the
-+ * various administrative parameters are all set to appropriate values.
-+ */
-+ __u8 config_change;
-+
-+ /* admin control parameters with admin control list */
-+ struct tsn_qci_sg_control admin;
-+
-+ /* The GateClosedDueToInvalidRxEnable object contains a Boolean value
-+ * that indicates whether the GateClosedDueToInvalidRx function is
-+ * enabled (TRUE) or disabled (FALSE).
-+ */
-+ __u8 block_invalid_rx_enable;
-+
-+ /* The GateClosedDueToInvalidRx object contains a Boolean value that
-+ * indicates whether, if the GateClosedDueToInvalidRx function is
-+ * enabled, all frames are to be discarded (TRUE) or not (FALSE).
-+ */
-+ __u8 block_invalid_rx;
-+
-+ /* The GateClosedDueToOctetsExceededEnable object contains a Boolean
-+ * value that indicates whether the GateClosedDueToOctetsExceeded
-+ * function is enabled (TRUE) or disabled (FALSE).
-+ */
-+ __u8 block_octets_exceeded_enable;
-+
-+ /* The GateClosedDueToOctetsExceeded object contains a Boolean value
-+ * that indicates whether, if the GateClosedDueToOctetsExceeded
-+ * function is enabled, all frames are to be discarded (TRUE) or not
-+ * (FALSE).
-+ */
-+ __u8 block_octets_exceeded;
-+};
-+
-+/* 802.1Qci Stream Gate Instance Table, status part only. */
-+struct tsn_psfp_sgi_status {
-+
-+ /* admin control parameters with admin control list */
-+ struct tsn_qci_sg_control oper;
-+
-+ /* The PTPtime at which the next config change is scheduled to occur.
-+ * The value is a representation of a PTPtime value, consisting of a
-+ * 48-bit integer number of seconds and a 32-bit integer number of
-+ * nanoseconds.
-+ */
-+ ptptime_t config_change_time;
-+
-+ /* The granularity of the cycle time clock, represented as an unsigned
-+ * number of tenths of nanoseconds.
-+ */
-+ __u32 tick_granularity;
-+
-+ /* The current time, in PTPtime, as maintained by the local system.
-+ * The value is a representation of a PTPtime value, consisting of a
-+ * 48-bit integer number of seconds and a 32-bit integer number of
-+ * nanoseconds.
-+ */
-+ ptptime_t current_time;
-+
-+ /* The value of the ConfigPending state machine variable. The value is
-+ * TRUE if a configuration change is in progress but has not yet
-+ * completed.
-+ */
-+ __u8 config_pending;
-+
-+ /* A counter of the number of times that a re-configuration of the
-+ * traffic schedule has been requested with the old schedule still
-+ * running and the requested base time was in the past.
-+ */
-+ __u64 config_change_error;
-+
-+};
-+
-+/* 802.1Qci Flow Meter Instance Table. */
-+struct tsn_qci_psfp_fmi {
-+ /* The FlowMeterCIR parameter contains an integer value that represents
-+ * the CIR value for the flow meter, in kbit/s.
-+ */
-+ __u32 cir;
-+
-+ /* The FlowMeterCBS parameter contains an integer value that represents
-+ * the CBS value for the flow meter, in octets.
-+ */
-+ __u32 cbs;
-+
-+ /* The FlowMeterEIR parameter contains an integer value that represents
-+ * the EIR value for the flow meter, in kbit/s.
-+ */
-+ __u32 eir;
-+
-+ /* The FlowMeterEBS parameter contains an integer value that represents
-+ * the EBS value for the flow meter, in octets.
-+ */
-+ __u32 ebs;
-+
-+ /* The FlowMeterCF parameter contains a Boolean value that represents
-+ * the CF value for the flow meter, as a Boolean value indicating no
-+ * coupling (FALSE) or coupling (TRUE).
-+ */
-+ __u8 cf;
-+
-+ /* The FlowMeterCM parameter contains a Boolean value that represents
-+ * the CM value for the flow meter, as a Boolean value indicating
-+ * colorBlind (FALSE) or colorAware (TRUE).
-+ */
-+ __u8 cm;
-+
-+ /* The FlowMeterDropOnYellow parameter contains a Boolean value that
-+ * indicates whether yellow frames are dropped (TRUE) or have
-+ * drop_eligible set to TRUE (FALSE).
-+ */
-+ __u8 drop_on_yellow;
-+
-+ /* The FlowMeterMarkAllFramesRedEnable parameter contains a Boolean
-+ * value that indicates whether the MarkAllFramesRed function
-+ * is enabled (TRUE) or disabled (FALSE).
-+ */
-+ __u8 mark_red_enable;
-+
-+ /* The FlowMeterMarkAllFramesRed parameter contains a Boolean value
-+ * that indicates whether, if the MarkAllFramesRed function is enabled,
-+ * all frames are to be discarded (TRUE) or not (FALSE).
-+ */
-+ __u8 mark_red;
-+};
-+
-+struct tsn_qci_psfp_fmi_counters {
-+ __u64 bytecount;
-+ __u64 drop;
-+ __u64 dr0_green;
-+ __u64 dr1_green;
-+ __u64 dr2_yellow;
-+ __u64 remark_yellow;
-+ __u64 dr3_red;
-+ __u64 remark_red;
-+};
-+
-+/* 802.1cb */
-+struct tsn_seq_gen_conf {
-+
-+ /* The InputPortMask parameter contains a port mask.
-+ * If the packet is from input port belonging to this
-+ * port mask then it's on known stream and sequence
-+ * generation parameters can be applied.
-+ */
-+ __u8 iport_mask;
-+
-+ /* The SplitMask parameter contains a output port mask
-+ * used to add redundant paths.
-+ */
-+ __u8 split_mask;
-+
-+ /* The SequenceSpaceLenLog parameter is a value to specifies
-+ * number of bits to be used for sequence number.
-+ */
-+ __u8 seq_len;
-+
-+ /* The SequenceNumber parameter is a value to used for
-+ * outgoing packet's sequence number generation.
-+ */
-+ __u32 seq_num;
-+};
-+
-+struct tsn_seq_rec_conf {
-+
-+ /* The SequenceSpaceLenLog parameter is a value to specifies
-+ * number of bits to be used for sequence number.
-+ */
-+ __u8 seq_len;
-+
-+ /* The HistorySpaceLenLog parameter is a value to specifies
-+ * number of bits to be used for history register.
-+ */
-+ __u8 his_len;
-+
-+ /* The RTagPopEnable parameter contains a __u8 to enable removal
-+ * of redundancy tag from the packet.
-+ */
-+ __u8 rtag_pop_en;
-+};
-+
-+struct tsn_cb_status {
-+
-+ /* The GenRecover parameter contains a value specifies type
-+ * of stream sequence parameters:
-+ * 0: Stream sequence parameters are for generation.
-+ * 1: Stream sequence parameters are for recovery.
-+ */
-+ __u8 gen_rec;
-+
-+ /* The ErrStatus parameter indicates stream's error status
-+ * 1: This switch is expected to sequence the stream,
-+ * but the incoming packet has sequence number.
-+ * 2: This switch is expected to recover the stream,
-+ * but the incoming packet is NONSEQ.
-+ */
-+ __u8 err;
-+
-+ /* The SequenceNumber parameter is a value to used for
-+ * outgoing packet's sequence number generation.
-+ */
-+ __u32 seq_num;
-+
-+ /* The SequenceSpaceLenLog parameter is a value to specifies
-+ * number of bits to be used for sequence number.
-+ */
-+ __u8 seq_len;
-+
-+ /* The SplitMask parameter contains a output port mask
-+ * used to add redundant paths.
-+ */
-+ __u8 split_mask;
-+
-+ /* The InputPortMask parameter contains a port mask.
-+ * If the packet is from input port belonging to this
-+ * port mask then it's on known stream and sequence
-+ * generation parameters can be applied.
-+ */
-+ __u8 iport_mask;
-+
-+ /* The HistorySpaceLenLog parameter is a value to specifies
-+ * number of bits to be used for history register.
-+ */
-+ __u8 his_len;
-+
-+ /* The SequenceHistory parameter Maintains history of sequence
-+ * numbers of received packets.
-+ */
-+ __u32 seq_his;
-+};
-+
-+/* An entry for gate control list */
-+struct tsn_qbv_entry {
-+ /* Octet represent the gate states for the corresponding traffic
-+ * classes.
-+ * The MS bit corresponds to traffic class 7.
-+ * The LS bit to traffic class 0.
-+ * A bit value of 0 indicates closed;
-+ * A bit value of 1 indicates open.
-+ */
-+ __u8 gate_state;
-+
-+ /* A TimeInterval is encoded in 4 octets as a 32-bit unsigned integer,
-+ * representing a number of nanoseconds.
-+ */
-+ __u32 time_interval;
-+};
-+
-+/* The administrative/operation time and gate list */
-+struct tsn_qbv_basic {
-+ /* The administrative/operation value of the GateStates parameter for
-+ * the Port.
-+ * The bits of the octet represent the gate states for the
-+ * corresponding traffic classes; the MS bit corresponds to traffic
-+ * class 7, the LS bit to traffic class 0. A bit value of 0 indicates
-+ * closed; a bit value of 1 indicates open.
-+ * The value of this object MUST be retained
-+ * across reinitializations of the management system.
-+ */
-+ __u8 gate_states;
-+
-+ /* The administrative/operation value of the ListMax parameter for the
-+ * port. The integer value indicates the number of entries (TLVs) in
-+ * the AdminControlList. The value of this object MUST be retained
-+ * across reinitializations of the management system.
-+ */
-+ __u32 control_list_length;
-+
-+ /* The administrative/operation value of the AdminCycleTime
-+ * parameter for the Port. The numerator and denominator together
-+ * represent the cycle time as a rational number of seconds. The value
-+ * of this object MUST be retained across reinitializations of the
-+ * management system.
-+ */
-+ __u32 cycle_time;
-+
-+ /* The administrative/operation value of the CycleTimeExtension
-+ * parameter for the Port. The value is an unsigned integer number of
-+ * nanoseconds.
-+ * The value of this object MUST be retained across reinitializations
-+ * of the management system.
-+ */
-+
-+ __u32 cycle_time_extension;
-+
-+ /* The administrative/operation value of the BaseTime parameter for the
-+ * Port. The value is a representation of a PTPtime value, consisting
-+ * of a 48-bit integer number of seconds and a 32-bit integer number of
-+ * nanoseconds.
-+ * The value of this object MUST be retained across reinitializations of
-+ * the management system.
-+ */
-+ ptptime_t base_time;
-+
-+ /* admin_control_list represent the AdminControlList/OperControlList.
-+ * The administrative version of the gate control list for the Port.
-+ */
-+ struct tsn_qbv_entry *control_list;
-+};
-+
-+struct tsn_qbv_conf {
-+ /* The GateEnabled parameter determines whether traffic scheduling is
-+ * active (true) or inactive (false). The value of this object MUST be
-+ * retained across reinitializations of the management system.
-+ */
-+ __u8 gate_enabled;
-+
-+ /* The maxsdu parameter denoting the maximum SDU size supported by the
-+ * queue.
-+ */
-+ __u32 maxsdu;
-+
-+ /* The ConfigChange parameter signals the start of a configuration
-+ * change when it is set to TRUE. This should only be done when the
-+ * various administrative parameters are all set to appropriate values.
-+ */
-+ __u8 config_change;
-+
-+ /* The admin parameter signals the admin relate cycletime, basictime,
-+ * gatelist paraters.
-+ */
-+ struct tsn_qbv_basic admin;
-+};
-+
-+/* 802.1Qbv (Time Aware Shaper) port status */
-+struct tsn_qbv_status {
-+ /* The PTPtime at which the next config change is scheduled to occur.
-+ * The value is a representation of a PTPtime value, consisting of a
-+ * 48-bit integer number of seconds and a 32-bit integer number of
-+ * nanoseconds. The value of this object MUST be retained across
-+ * reinitializations of the management system.
-+ */
-+ ptptime_t config_change_time;
-+
-+ /* The granularity of the cycle time clock, represented as an unsigned
-+ * number of tenths of nanoseconds. The value of this object MUST be
-+ * retained across reinitializations of the management system.
-+ */
-+ __u32 tick_granularity;
-+
-+ /* The current time, in PTPtime, as maintained by the local system.
-+ * The value is a representation of a PTPtime value, consisting of a
-+ * 48-bit integer number of seconds and a 32-bit integer number of
-+ * nanoseconds.
-+ */
-+ ptptime_t current_time;
-+
-+ /* The value of the ConfigPending state machine variable. The value is
-+ * TRUE if a configuration change is in progress but has not yet
-+ * completed.
-+ */
-+ __u8 config_pending;
-+
-+ /* A counter of the number of times that a re-configuration of the
-+ * traffic schedule has been requested with the old schedule still
-+ * running and the requested base time was in the past.
-+ */
-+ __u64 config_change_error;
-+
-+ /* The maximum value supported by this Port of the
-+ * AdminControlListLength and OperControlListLength parameters.
-+ */
-+ __u32 supported_list_max;
-+
-+ /* Operation settings parameters and Oper gate list */
-+ struct tsn_qbv_basic oper;
-+};
-+
-+/* Time Specific Departure parameters */
-+struct tsn_tsd {
-+ __u8 enable;
-+
-+ /* The cycle time, in units of microsecond(us)*/
-+ __u32 period;
-+
-+ /* The maximum number of frames which could be transmitted on one cycle
-+ * The exceeding frames will be transmitted on next cycle.
-+ */
-+ __u32 maxFrameNum;
-+
-+ /* Specify the time of the first cycle begins.
-+ * 1: begin when the queue get the first frame to transmit.
-+ * 2: begin immediately at the end of setting function.
-+ */
-+ __u32 syn_flag;
-+};
-+
-+struct tsn_tsd_status {
-+ __u8 enable;
-+ __u32 period;
-+ __u32 maxFrameNum;
-+ __u32 flag;
-+ __u32 cycleNum;
-+ __u32 loss_steps;
-+};
-+
-+struct tsn_qos_switch_dscp_conf {
-+ __u8 trust;
-+ __u8 cos;
-+ __u8 dpl;
-+ __u8 remark;
-+ __u8 dscp; /* New ingress translated DSCP value */
-+};
-+
-+#endif /* _UAPI_GENL_TSN_H */
---- a/net/Kconfig
-+++ b/net/Kconfig
-@@ -240,6 +240,7 @@ source "net/ieee802154/Kconfig"
- source "net/mac802154/Kconfig"
- source "net/sched/Kconfig"
- source "net/dcb/Kconfig"
-+source "net/tsn/Kconfig"
- source "net/dns_resolver/Kconfig"
- source "net/batman-adv/Kconfig"
- source "net/openvswitch/Kconfig"
---- a/net/Makefile
-+++ b/net/Makefile
-@@ -59,6 +59,9 @@ obj-$(CONFIG_CAIF) += caif/
- ifneq ($(CONFIG_DCB),)
- obj-y += dcb/
- endif
-+ifneq ($(CONFIG_TSN),)
-+obj-y += tsn/
-+endif
- obj-$(CONFIG_6LOWPAN) += 6lowpan/
- obj-$(CONFIG_IEEE802154) += ieee802154/
- obj-$(CONFIG_MAC802154) += mac802154/
---- /dev/null
-+++ b/net/tsn/Kconfig
-@@ -0,0 +1,15 @@
-+config TSN
-+ bool "802.1 Time-Sensitive Networking support"
-+ default n
-+ depends on VLAN_8021Q && PTP_1588_CLOCK
-+ help
-+ This enables support for TSN(time sensitive networking)
-+ TSN features include:
-+ 802.1Qav:
-+ 802.1Qbv:
-+ 802.1Qci:
-+ 802.1Qbu:
-+ 802.1AS:
-+ 802.1CB:
-+
-+ If unsure, say N.
---- /dev/null
-+++ b/net/tsn/Makefile
-@@ -0,0 +1 @@
-+obj-$(CONFIG_TSN) += genl_tsn.o
---- /dev/null
-+++ b/net/tsn/genl_tsn.c
-@@ -0,0 +1,3696 @@
-+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-+/* Copyright 2017-2019 NXP */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/netdevice.h>
-+#include <linux/if_vlan.h>
-+#include <net/genetlink.h>
-+#include <net/netlink.h>
-+#include <linux/version.h>
-+#include <net/tsn.h>
-+
-+#define NLA_PARSE_NESTED(a, b, c, d) \
-+ nla_parse_nested_deprecated(a, b, c, d, NULL)
-+#define NLA_PUT_U64(a, b, c) nla_put_u64_64bit(a, b, c, NLA_U64)
-+
-+static struct genl_family tsn_family;
-+
-+LIST_HEAD(port_list);
-+
-+static const struct nla_policy tsn_cmd_policy[TSN_CMD_ATTR_MAX + 1] = {
-+ [TSN_CMD_ATTR_MESG] = { .type = NLA_STRING },
-+ [TSN_CMD_ATTR_DATA] = { .type = NLA_S32 },
-+ [TSN_ATTR_IFNAME] = { .type = NLA_STRING },
-+ [TSN_ATTR_PORT_NUMBER] = { .type = NLA_U8 },
-+ [TSN_ATTR_CAP] = { .type = NLA_NESTED },
-+ [TSN_ATTR_QBV] = { .type = NLA_NESTED },
-+ [TSN_ATTR_STREAM_IDENTIFY] = { .type = NLA_NESTED },
-+ [TSN_ATTR_QCI_SP] = { .type = NLA_NESTED },
-+ [TSN_ATTR_QCI_SFI] = { .type = NLA_NESTED },
-+ [TSN_ATTR_QCI_SGI] = { .type = NLA_NESTED },
-+ [TSN_ATTR_QCI_FMI] = { .type = NLA_NESTED },
-+ [TSN_ATTR_CBS] = { .type = NLA_NESTED },
-+ [TSN_ATTR_TSD] = { .type = NLA_NESTED },
-+ [TSN_ATTR_QBU] = { .type = NLA_NESTED },
-+ [TSN_ATTR_CT] = { .type = NLA_NESTED },
-+ [TSN_ATTR_CBGEN] = { .type = NLA_NESTED },
-+ [TSN_ATTR_CBREC] = { .type = NLA_NESTED },
-+ [TSN_ATTR_CBSTAT] = { .type = NLA_NESTED },
-+ [TSN_ATTR_DSCP] = { .type = NLA_NESTED },
-+};
-+
-+static const struct nla_policy tsn_cap_policy[TSN_CAP_ATTR_MAX + 1] = {
-+ [TSN_CAP_ATTR_QBV] = { .type = NLA_FLAG },
-+ [TSN_CAP_ATTR_QCI] = { .type = NLA_FLAG },
-+ [TSN_CAP_ATTR_QBU] = { .type = NLA_FLAG },
-+ [TSN_CAP_ATTR_CBS] = { .type = NLA_FLAG },
-+ [TSN_CAP_ATTR_CB] = { .type = NLA_FLAG },
-+ [TSN_CAP_ATTR_TBS] = { .type = NLA_FLAG },
-+ [TSN_CAP_ATTR_CTH] = { .type = NLA_FLAG },
-+};
-+
-+static const struct nla_policy qci_cap_policy[TSN_QCI_STREAM_ATTR_MAX + 1] = {
-+ [TSN_QCI_STREAM_ATTR_MAX_SFI] = { .type = NLA_U32 },
-+ [TSN_QCI_STREAM_ATTR_MAX_SGI] = { .type = NLA_U32 },
-+ [TSN_QCI_STREAM_ATTR_MAX_FMI] = { .type = NLA_U32 },
-+ [TSN_QCI_STREAM_ATTR_SLM] = { .type = NLA_U32 },
-+};
-+
-+static const struct nla_policy ct_policy[TSN_CT_ATTR_MAX + 1] = {
-+ [TSN_CT_ATTR_QUEUE_STATE] = { .type = NLA_U8 }
-+};
-+
-+static const struct nla_policy cbgen_policy[TSN_CBGEN_ATTR_MAX + 1] = {
-+ [TSN_CBGEN_ATTR_INDEX] = { .type = NLA_U32 },
-+ [TSN_CBGEN_ATTR_PORT_MASK] = { .type = NLA_U8 },
-+ [TSN_CBGEN_ATTR_SPLIT_MASK] = { .type = NLA_U8 },
-+ [TSN_CBGEN_ATTR_SEQ_LEN] = { .type = NLA_U8 },
-+ [TSN_CBGEN_ATTR_SEQ_NUM] = { .type = NLA_U32 },
-+};
-+
-+static const struct nla_policy cbrec_policy[TSN_CBREC_ATTR_MAX + 1] = {
-+ [TSN_CBREC_ATTR_INDEX] = { .type = NLA_U32 },
-+ [TSN_CBREC_ATTR_SEQ_LEN] = { .type = NLA_U8 },
-+ [TSN_CBREC_ATTR_HIS_LEN] = { .type = NLA_U8 },
-+ [TSN_CBREC_ATTR_TAG_POP_EN] = { .type = NLA_FLAG },
-+};
-+
-+static const struct nla_policy cbstat_policy[TSN_CBSTAT_ATTR_MAX + 1] = {
-+ [TSN_CBSTAT_ATTR_INDEX] = { .type = NLA_U32 },
-+ [TSN_CBSTAT_ATTR_GEN_REC] = { .type = NLA_U8 },
-+ [TSN_CBSTAT_ATTR_ERR] = { .type = NLA_U8 },
-+ [TSN_CBSTAT_ATTR_SEQ_NUM] = { .type = NLA_U32 },
-+ [TSN_CBSTAT_ATTR_SEQ_LEN] = { .type = NLA_U8 },
-+ [TSN_CBSTAT_ATTR_SPLIT_MASK] = { .type = NLA_U8 },
-+ [TSN_CBSTAT_ATTR_PORT_MASK] = { .type = NLA_U8 },
-+ [TSN_CBSTAT_ATTR_HIS_LEN] = { .type = NLA_U8 },
-+ [TSN_CBSTAT_ATTR_SEQ_HIS] = { .type = NLA_U32 },
-+};
-+
-+static const struct nla_policy qbu_policy[TSN_QBU_ATTR_MAX + 1] = {
-+ [TSN_QBU_ATTR_ADMIN_STATE] = { .type = NLA_U8 },
-+ [TSN_QBU_ATTR_HOLD_ADVANCE] = { .type = NLA_U32},
-+ [TSN_QBU_ATTR_RELEASE_ADVANCE] = { .type = NLA_U32},
-+ [TSN_QBU_ATTR_ACTIVE] = { .type = NLA_FLAG},
-+ [TSN_QBU_ATTR_HOLD_REQUEST] = { .type = NLA_U8},
-+};
-+
-+static const struct nla_policy cbs_policy[TSN_CBS_ATTR_MAX + 1] = {
-+ [TSN_CBS_ATTR_TC_INDEX] = { .type = NLA_U8},
-+ [TSN_CBS_ATTR_BW] = { .type = NLA_U8},
-+};
-+
-+static const struct nla_policy tsd_policy[TSN_TSD_ATTR_MAX + 1] = {
-+ [TSN_TSD_ATTR_ENABLE] = { .type = NLA_FLAG},
-+ [TSN_TSD_ATTR_DISABLE] = { .type = NLA_FLAG},
-+ [TSN_TSD_ATTR_PERIOD] = { .type = NLA_U32},
-+ [TSN_TSD_ATTR_MAX_FRM_NUM] = { .type = NLA_U32},
-+ [TSN_TSD_ATTR_CYCLE_NUM] = { .type = NLA_U32},
-+ [TSN_TSD_ATTR_LOSS_STEPS] = { .type = NLA_U32},
-+ [TSN_TSD_ATTR_SYN_IMME] = { .type = NLA_FLAG},
-+};
-+
-+static const struct nla_policy qbv_policy[TSN_QBV_ATTR_MAX + 1] = {
-+ [TSN_QBV_ATTR_ADMINENTRY] = { .type = NLA_NESTED},
-+ [TSN_QBV_ATTR_OPERENTRY] = { .type = NLA_NESTED},
-+ [TSN_QBV_ATTR_ENABLE] = { .type = NLA_FLAG},
-+ [TSN_QBV_ATTR_DISABLE] = { .type = NLA_FLAG},
-+ [TSN_QBV_ATTR_CONFIGCHANGE] = { .type = NLA_FLAG},
-+ [TSN_QBV_ATTR_CONFIGCHANGETIME] = { .type = NLA_U64},
-+ [TSN_QBV_ATTR_MAXSDU] = { .type = NLA_U32},
-+ [TSN_QBV_ATTR_GRANULARITY] = { .type = NLA_U32},
-+ [TSN_QBV_ATTR_CURRENTTIME] = { .type = NLA_U64},
-+ [TSN_QBV_ATTR_CONFIGPENDING] = {.type = NLA_FLAG},
-+ [TSN_QBV_ATTR_CONFIGCHANGEERROR] = { .type = NLA_U64},
-+ [TSN_QBV_ATTR_LISTMAX] = { .type = NLA_U32},
-+};
-+
-+static const struct nla_policy qbv_ctrl_policy[TSN_QBV_ATTR_CTRL_MAX + 1] = {
-+ [TSN_QBV_ATTR_CTRL_LISTCOUNT] = { .type = NLA_U32},
-+ [TSN_QBV_ATTR_CTRL_GATESTATE] = { .type = NLA_U8},
-+ [TSN_QBV_ATTR_CTRL_CYCLETIME] = { .type = NLA_U32},
-+ [TSN_QBV_ATTR_CTRL_CYCLETIMEEXT] = { .type = NLA_U32},
-+ [TSN_QBV_ATTR_CTRL_BASETIME] = { .type = NLA_U64},
-+ [TSN_QBV_ATTR_CTRL_LISTENTRY] = { .type = NLA_NESTED},
-+};
-+
-+static const struct nla_policy qbv_entry_policy[TSN_QBV_ATTR_ENTRY_MAX + 1] = {
-+ [TSN_QBV_ATTR_ENTRY_ID] = { .type = NLA_U32},
-+ [TSN_QBV_ATTR_ENTRY_GC] = { .type = NLA_U8},
-+ [TSN_QBV_ATTR_ENTRY_TM] = { .type = NLA_U32},
-+};
-+
-+static const struct nla_policy cb_streamid_policy[TSN_STREAMID_ATTR_MAX + 1] = {
-+ [TSN_STREAMID_ATTR_INDEX] = { .type = NLA_U32},
-+ [TSN_STREAMID_ATTR_ENABLE] = { .type = NLA_FLAG},
-+ [TSN_STREAMID_ATTR_DISABLE] = { .type = NLA_FLAG},
-+ [TSN_STREAMID_ATTR_STREAM_HANDLE] = { .type = NLA_S32},
-+ [TSN_STREAMID_ATTR_IFOP] = { .type = NLA_U32},
-+ [TSN_STREAMID_ATTR_OFOP] = { .type = NLA_U32},
-+ [TSN_STREAMID_ATTR_IFIP] = { .type = NLA_U32},
-+ [TSN_STREAMID_ATTR_OFIP] = { .type = NLA_U32},
-+ [TSN_STREAMID_ATTR_TYPE] = { .type = NLA_U8},
-+ [TSN_STREAMID_ATTR_NDMAC] = { .type = NLA_U64},
-+ [TSN_STREAMID_ATTR_NTAGGED] = { .type = NLA_U8},
-+ [TSN_STREAMID_ATTR_NVID] = { .type = NLA_U16},
-+ [TSN_STREAMID_ATTR_SMAC] = { .type = NLA_U64},
-+ [TSN_STREAMID_ATTR_STAGGED] = { .type = NLA_U8},
-+ [TSN_STREAMID_ATTR_SVID] = { .type = NLA_U16},
-+ [TSN_STREAMID_ATTR_COUNTERS_PSI] = { .type = NLA_U64},
-+ [TSN_STREAMID_ATTR_COUNTERS_PSO] = { .type = NLA_U64},
-+ [TSN_STREAMID_ATTR_COUNTERS_PSPPI] = { .type = NLA_U64},
-+ [TSN_STREAMID_ATTR_COUNTERS_PSPPO] = { .type = NLA_U64},
-+};
-+
-+static const struct nla_policy qci_sfi_policy[TSN_QCI_SFI_ATTR_MAX + 1] = {
-+ [TSN_QCI_SFI_ATTR_INDEX] = { .type = NLA_U32},
-+ [TSN_QCI_SFI_ATTR_ENABLE] = { .type = NLA_FLAG},
-+ [TSN_QCI_SFI_ATTR_DISABLE] = { .type = NLA_FLAG},
-+ [TSN_QCI_SFI_ATTR_STREAM_HANDLE] = { .type = NLA_S32},
-+ [TSN_QCI_SFI_ATTR_PRIO_SPEC] = { .type = NLA_S8},
-+ [TSN_QCI_SFI_ATTR_GATE_ID] = { .type = NLA_U32},
-+ [TSN_QCI_SFI_ATTR_FILTER_TYPE] = { .type = NLA_U8},
-+ [TSN_QCI_SFI_ATTR_FLOW_ID] = { .type = NLA_S32},
-+ [TSN_QCI_SFI_ATTR_MAXSDU] = { .type = NLA_U16},
-+ [TSN_QCI_SFI_ATTR_COUNTERS] = {
-+ .len = sizeof(struct tsn_qci_psfp_sfi_counters)},
-+ [TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE] = { .type = NLA_FLAG},
-+ [TSN_QCI_SFI_ATTR_OVERSIZE] = { .type = NLA_FLAG},
-+};
-+
-+static const struct nla_policy qci_sgi_policy[] = {
-+ [TSN_QCI_SGI_ATTR_INDEX] = { .type = NLA_U32},
-+ [TSN_QCI_SGI_ATTR_ENABLE] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_DISABLE] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_CONFCHANGE] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_IRXEN] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_IRX] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_OEXEN] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_OEX] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_ADMINENTRY] = { .type = NLA_NESTED},
-+ [TSN_QCI_SGI_ATTR_OPERENTRY] = { .type = NLA_NESTED},
-+ [TSN_QCI_SGI_ATTR_CCTIME] = { .type = NLA_U64},
-+ [TSN_QCI_SGI_ATTR_TICKG] = { .type = NLA_U32},
-+ [TSN_QCI_SGI_ATTR_CUTIME] = { .type = NLA_U64},
-+ [TSN_QCI_SGI_ATTR_CPENDING] = { .type = NLA_FLAG},
-+ [TSN_QCI_SGI_ATTR_CCERROR] = { .type = NLA_U64},
-+};
-+
-+static const struct nla_policy qci_sgi_ctrl_policy[] = {
-+ [TSN_SGI_ATTR_CTRL_INITSTATE] = { .type = NLA_FLAG},
-+ [TSN_SGI_ATTR_CTRL_LEN] = { .type = NLA_U8},
-+ [TSN_SGI_ATTR_CTRL_CYTIME] = { .type = NLA_U32},
-+ [TSN_SGI_ATTR_CTRL_CYTIMEEX] = { .type = NLA_U32},
-+ [TSN_SGI_ATTR_CTRL_BTIME] = { .type = NLA_U64},
-+ [TSN_SGI_ATTR_CTRL_INITIPV] = { .type = NLA_S8},
-+ [TSN_SGI_ATTR_CTRL_GCLENTRY] = { .type = NLA_NESTED},
-+};
-+
-+static const struct nla_policy qci_sgi_gcl_policy[] = {
-+ [TSN_SGI_ATTR_GCL_GATESTATE] = { .type = NLA_FLAG},
-+ [TSN_SGI_ATTR_GCL_IPV] = { .type = NLA_S8},
-+ [TSN_SGI_ATTR_GCL_INTERVAL] = { .type = NLA_U32},
-+ [TSN_SGI_ATTR_GCL_OCTMAX] = { .type = NLA_U32},
-+};
-+
-+static const struct nla_policy qci_fmi_policy[] = {
-+ [TSN_QCI_FMI_ATTR_INDEX] = { .type = NLA_U32},
-+ [TSN_QCI_FMI_ATTR_ENABLE] = { .type = NLA_FLAG},
-+ [TSN_QCI_FMI_ATTR_DISABLE] = { .type = NLA_FLAG},
-+ [TSN_QCI_FMI_ATTR_CIR] = { .type = NLA_U32},
-+ [TSN_QCI_FMI_ATTR_CBS] = { .type = NLA_U32},
-+ [TSN_QCI_FMI_ATTR_EIR] = { .type = NLA_U32},
-+ [TSN_QCI_FMI_ATTR_EBS] = { .type = NLA_U32},
-+ [TSN_QCI_FMI_ATTR_CF] = { .type = NLA_FLAG},
-+ [TSN_QCI_FMI_ATTR_CM] = { .type = NLA_FLAG},
-+ [TSN_QCI_FMI_ATTR_DROPYL] = { .type = NLA_FLAG},
-+ [TSN_QCI_FMI_ATTR_MAREDEN] = { .type = NLA_FLAG},
-+ [TSN_QCI_FMI_ATTR_MARED] = { .type = NLA_FLAG},
-+ [TSN_QCI_FMI_ATTR_COUNTERS] = {
-+ .len = sizeof(struct tsn_qci_psfp_fmi_counters)},
-+};
-+
-+static const struct nla_policy dscp_policy[] = {
-+ [TSN_DSCP_ATTR_INDEX] = { .type = NLA_U32},
-+ [TSN_DSCP_ATTR_DISABLE] = { .type = NLA_FLAG},
-+ [TSN_DSCP_ATTR_COS] = { .type = NLA_U8},
-+ [TSN_DSCP_ATTR_DPL] = { .type = NLA_U8},
-+};
-+
-+static ATOMIC_NOTIFIER_HEAD(tsn_notif_chain);
-+
-+/**
-+ * register_tsn_notifier - Register notifier
-+ * @nb: notifier_block
-+ *
-+ * Register switch device notifier.
-+ */
-+int register_tsn_notifier(struct notifier_block *nb)
-+{
-+ return atomic_notifier_chain_register(&tsn_notif_chain, nb);
-+}
-+EXPORT_SYMBOL_GPL(register_tsn_notifier);
-+
-+/**
-+ * unregister_tsn_notifier - Unregister notifier
-+ * @nb: notifier_block
-+ *
-+ * Unregister switch device notifier.
-+ */
-+int unregister_tsn_notifier(struct notifier_block *nb)
-+{
-+ return atomic_notifier_chain_unregister(&tsn_notif_chain, nb);
-+}
-+EXPORT_SYMBOL_GPL(unregister_tsn_notifier);
-+
-+/**
-+ * call_tsn_notifiers - Call notifiers
-+ * @val: value passed unmodified to notifier function
-+ * @dev: port device
-+ * @info: notifier information data
-+ *
-+ * Call all network notifier blocks.
-+ */
-+int call_tsn_notifiers(unsigned long val, struct net_device *dev,
-+ struct tsn_notifier_info *info)
-+{
-+ info->dev = dev;
-+ return atomic_notifier_call_chain(&tsn_notif_chain, val, info);
-+}
-+EXPORT_SYMBOL_GPL(call_tsn_notifiers);
-+
-+struct tsn_port *tsn_get_port(struct net_device *ndev)
-+{
-+ struct tsn_port *port;
-+ bool tsn_found = false;
-+
-+ list_for_each_entry(port, &port_list, list) {
-+ if (port->netdev == ndev) {
-+ tsn_found = true;
-+ break;
-+ }
-+ }
-+
-+ if (!tsn_found)
-+ return NULL;
-+
-+ return port;
-+}
-+EXPORT_SYMBOL_GPL(tsn_get_port);
-+
-+static int tsn_prepare_reply(struct genl_info *info, u8 cmd,
-+ struct sk_buff **skbp, size_t size)
-+{
-+ struct sk_buff *skb;
-+ void *reply;
-+
-+ /* If new attributes are added, please revisit this allocation
-+ */
-+ skb = genlmsg_new(size, GFP_KERNEL);
-+ if (!skb)
-+ return -ENOMEM;
-+
-+ if (!info) {
-+ nlmsg_free(skb);
-+ return -EINVAL;
-+ }
-+
-+ reply = genlmsg_put_reply(skb, info, &tsn_family, 0, cmd);
-+ if (!reply) {
-+ nlmsg_free(skb);
-+ return -EINVAL;
-+ }
-+
-+ *skbp = skb;
-+ return 0;
-+}
-+
-+static int tsn_mk_reply(struct sk_buff *skb, int aggr, void *data, int len)
-+{
-+ /* add a netlink attribute to a socket buffer */
-+ return nla_put(skb, aggr, len, data);
-+}
-+
-+static int tsn_send_reply(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
-+ void *reply = genlmsg_data(genlhdr);
-+
-+ genlmsg_end(skb, reply);
-+
-+ return genlmsg_reply(skb, info);
-+}
-+
-+static int cmd_attr_echo_message(struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ char *msg;
-+ struct sk_buff *rep_skb;
-+ size_t size;
-+ int ret;
-+
-+ na = info->attrs[TSN_CMD_ATTR_MESG];
-+ if (!na)
-+ return -EINVAL;
-+
-+ msg = (char *)nla_data(na);
-+ pr_info("tsn generic netlink receive echo mesg %s\n", msg);
-+
-+ size = nla_total_size(strlen(msg) + 1);
-+
-+ ret = tsn_prepare_reply(info, TSN_CMD_REPLY, &rep_skb,
-+ size + NLMSG_ALIGN(MAX_USER_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = tsn_mk_reply(rep_skb, TSN_CMD_ATTR_MESG, msg, size);
-+ if (ret < 0)
-+ goto err;
-+
-+ return tsn_send_reply(rep_skb, info);
-+
-+err:
-+ nlmsg_free(rep_skb);
-+ return ret;
-+}
-+
-+static int cmd_attr_echo_data(struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ s32 data;
-+ struct sk_buff *rep_skb;
-+ size_t size;
-+ int ret;
-+
-+ /*read data */
-+ na = info->attrs[TSN_CMD_ATTR_DATA];
-+ if (!na)
-+ return -EINVAL;
-+
-+ data = nla_get_s32(info->attrs[TSN_CMD_ATTR_DATA]);
-+ pr_info("tsn generic netlink receive echo data %d\n", data);
-+
-+ /* send back */
-+ size = nla_total_size(sizeof(s32));
-+
-+ ret = tsn_prepare_reply(info, TSN_CMD_REPLY, &rep_skb,
-+ size + NLMSG_ALIGN(MAX_USER_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ /* netlink lib func */
-+ ret = nla_put_s32(rep_skb, TSN_CMD_ATTR_DATA, data);
-+ if (ret < 0)
-+ goto err;
-+
-+ return tsn_send_reply(rep_skb, info);
-+
-+err:
-+ nlmsg_free(rep_skb);
-+ return ret;
-+}
-+
-+static int tsn_echo_cmd(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_CMD_ATTR_MESG])
-+ return cmd_attr_echo_message(info);
-+ else if (info->attrs[TSN_CMD_ATTR_DATA])
-+ return cmd_attr_echo_data(info);
-+
-+ return -EINVAL;
-+}
-+
-+static int tsn_simple_reply(struct genl_info *info, u32 cmd,
-+ char *portname, s32 retvalue)
-+{
-+ struct sk_buff *rep_skb;
-+ size_t size;
-+ int ret;
-+
-+ /* send back */
-+ size = nla_total_size(strlen(portname) + 1);
-+ size += nla_total_size(sizeof(s32));
-+
-+ ret = tsn_prepare_reply(info, cmd,
-+ &rep_skb, size + NLMSG_ALIGN(MAX_USER_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ /* netlink lib func */
-+ ret = nla_put_string(rep_skb, TSN_ATTR_IFNAME, portname);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = nla_put_s32(rep_skb, TSN_CMD_ATTR_DATA, retvalue);
-+ if (ret < 0)
-+ return ret;
-+
-+ return tsn_send_reply(rep_skb, info);
-+}
-+
-+struct tsn_port *tsn_init_check(struct genl_info *info,
-+ struct net_device **ndev)
-+{
-+ struct nlattr *na;
-+ char *portname;
-+ struct net_device *netdev;
-+ struct tsn_port *port;
-+ bool tsn_found = false;
-+
-+ if (!info->attrs[TSN_ATTR_IFNAME]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ "no portname", -EINVAL);
-+ return NULL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_IFNAME];
-+
-+ portname = (char *)nla_data(na);
-+
-+ netdev = __dev_get_by_name(genl_info_net(info), portname);
-+ if (!netdev) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ "error device", -ENODEV);
-+ return NULL;
-+ }
-+
-+ list_for_each_entry(port, &port_list, list) {
-+ if (port->netdev == netdev) {
-+ tsn_found = true;
-+ break;
-+ }
-+ }
-+
-+ if (!tsn_found) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -ENODEV);
-+ return NULL;
-+ }
-+
-+ *ndev = netdev;
-+
-+ return port;
-+}
-+
-+static int tsn_cap_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct sk_buff *rep_skb;
-+ struct nlattr *tsn_cap_attr;
-+ int ret;
-+ u32 cap = 0;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port) {
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+ tsnops = port->tsnops;
-+ genlhdr = info->genlhdr;
-+ if (!tsnops->get_capability) {
-+ ret = -EOPNOTSUPP;
-+ goto out;
-+ }
-+
-+ cap = tsnops->get_capability(netdev);
-+ if (cap < 0) {
-+ ret = cap;
-+ goto out;
-+ }
-+
-+ /* Pad netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ goto out;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name)) {
-+ ret = -EMSGSIZE;
-+ goto err;
-+ }
-+
-+ tsn_cap_attr = nla_nest_start_noflag(rep_skb, TSN_ATTR_CAP);
-+ if (!tsn_cap_attr) {
-+ ret = -EMSGSIZE;
-+ goto err;
-+ }
-+
-+ if (cap & TSN_CAP_QBV) {
-+ if (nla_put_flag(rep_skb, TSN_CAP_ATTR_QBV))
-+ goto err;
-+ }
-+
-+ if (cap & TSN_CAP_QCI) {
-+ if (nla_put_flag(rep_skb, TSN_CAP_ATTR_QCI))
-+ goto err;
-+ }
-+
-+ if (cap & TSN_CAP_QBU) {
-+ if (nla_put_flag(rep_skb, TSN_CAP_ATTR_QBU))
-+ goto err;
-+ }
-+
-+ if (cap & TSN_CAP_CBS) {
-+ if (nla_put_flag(rep_skb, TSN_CAP_ATTR_CBS))
-+ goto err;
-+ }
-+
-+ if (cap & TSN_CAP_CB) {
-+ if (nla_put_flag(rep_skb, TSN_CAP_ATTR_CB))
-+ goto err;
-+ }
-+
-+ if (cap & TSN_CAP_TBS) {
-+ if (nla_put_flag(rep_skb, TSN_CAP_ATTR_TBS))
-+ goto err;
-+ }
-+
-+ if (cap & TSN_CAP_CTH) {
-+ if (nla_put_flag(rep_skb, TSN_CAP_ATTR_CTH))
-+ goto err;
-+ }
-+
-+ nla_nest_end(rep_skb, tsn_cap_attr);
-+
-+ tsn_send_reply(rep_skb, info);
-+ return 0;
-+err:
-+ nlmsg_free(rep_skb);
-+out:
-+ if (ret < 0)
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+}
-+
-+static int cmd_cb_streamid_set(struct genl_info *info)
-+{
-+ struct nlattr *na, *sid[TSN_STREAMID_ATTR_MAX + 1];
-+ u32 sid_index;
-+ u8 iden_type = 1;
-+ bool enable;
-+ int ret;
-+ struct net_device *netdev;
-+ struct tsn_cb_streamid sidconf;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ memset(&sidconf, 0, sizeof(struct tsn_cb_streamid));
-+
-+ if (!info->attrs[TSN_ATTR_STREAM_IDENTIFY])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_STREAM_IDENTIFY];
-+
-+ ret = NLA_PARSE_NESTED(sid, TSN_STREAMID_ATTR_MAX,
-+ na, cb_streamid_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ if (!sid[TSN_STREAMID_ATTR_INDEX])
-+ return -EINVAL;
-+
-+ sid_index = nla_get_u32(sid[TSN_STREAMID_ATTR_INDEX]);
-+
-+ if (sid[TSN_STREAMID_ATTR_ENABLE])
-+ enable = true;
-+ else if (sid[TSN_STREAMID_ATTR_DISABLE])
-+ enable = false;
-+ else
-+ return -EINVAL;
-+
-+ if (!enable)
-+ goto loaddev;
-+
-+ if (sid[TSN_STREAMID_ATTR_TYPE])
-+ iden_type = nla_get_u8(sid[TSN_STREAMID_ATTR_TYPE]);
-+ else
-+ return -EINVAL;
-+
-+ sidconf.type = iden_type;
-+ switch (iden_type) {
-+ case STREAMID_NULL:
-+ if (!sid[TSN_STREAMID_ATTR_NDMAC] ||
-+ !sid[TSN_STREAMID_ATTR_NTAGGED] ||
-+ !sid[TSN_STREAMID_ATTR_NVID]) {
-+ return -EINVAL;
-+ }
-+
-+ sidconf.para.nid.dmac =
-+ nla_get_u64(sid[TSN_STREAMID_ATTR_NDMAC]);
-+ sidconf.para.nid.tagged =
-+ nla_get_u8(sid[TSN_STREAMID_ATTR_NTAGGED]);
-+ sidconf.para.nid.vid =
-+ nla_get_u16(sid[TSN_STREAMID_ATTR_NVID]);
-+ break;
-+ case STREAMID_SMAC_VLAN:
-+ /* TODO: not supportted yet */
-+ if (!sid[TSN_STREAMID_ATTR_SMAC] ||
-+ !sid[TSN_STREAMID_ATTR_STAGGED] ||
-+ !sid[TSN_STREAMID_ATTR_SVID]) {
-+ return -EINVAL;
-+ }
-+
-+ sidconf.para.sid.smac =
-+ nla_get_u64(sid[TSN_STREAMID_ATTR_SMAC]);
-+ sidconf.para.sid.tagged =
-+ nla_get_u8(sid[TSN_STREAMID_ATTR_STAGGED]);
-+ sidconf.para.sid.vid =
-+ nla_get_u16(sid[TSN_STREAMID_ATTR_SVID]);
-+ break;
-+ case STREAMID_DMAC_VLAN:
-+
-+ case STREAMID_IP:
-+
-+ default:
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (sid[TSN_STREAMID_ATTR_STREAM_HANDLE])
-+ sidconf.handle =
-+ nla_get_s32(sid[TSN_STREAMID_ATTR_STREAM_HANDLE]);
-+
-+ if (sid[TSN_STREAMID_ATTR_IFOP])
-+ sidconf.ifac_oport = nla_get_u32(sid[TSN_STREAMID_ATTR_IFOP]);
-+ if (sid[TSN_STREAMID_ATTR_OFOP])
-+ sidconf.ofac_oport = nla_get_u32(sid[TSN_STREAMID_ATTR_OFOP]);
-+ if (sid[TSN_STREAMID_ATTR_IFIP])
-+ sidconf.ifac_iport = nla_get_u32(sid[TSN_STREAMID_ATTR_IFIP]);
-+ if (sid[TSN_STREAMID_ATTR_OFIP])
-+ sidconf.ofac_iport = nla_get_u32(sid[TSN_STREAMID_ATTR_OFIP]);
-+
-+loaddev:
-+ if (!tsnops->cb_streamid_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -EOPNOTSUPP;
-+ }
-+
-+ ret = tsnops->cb_streamid_set(netdev, sid_index, enable, &sidconf);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+ }
-+
-+ /* simple reply here. To be continue */
-+ if (tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, 0))
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static int tsn_cb_streamid_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_cb_streamid_set(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_cb_streamid_get(struct genl_info *info)
-+{
-+ struct nlattr *na, *sidattr, *sid[TSN_STREAMID_ATTR_MAX + 1];
-+ u32 sid_index;
-+ struct genlmsghdr *genlhdr;
-+ struct sk_buff *rep_skb;
-+ int ret, i;
-+ int valid;
-+ struct net_device *netdev;
-+ struct tsn_cb_streamid sidconf;
-+ struct tsn_cb_streamid_counters sidcounts;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ memset(&sidconf, 0, sizeof(struct tsn_cb_streamid));
-+ memset(&sidcounts, 0, sizeof(struct tsn_cb_streamid_counters));
-+
-+ if (!info->attrs[TSN_ATTR_STREAM_IDENTIFY])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_STREAM_IDENTIFY];
-+
-+ ret = NLA_PARSE_NESTED(sid, TSN_STREAMID_ATTR_MAX,
-+ na, cb_streamid_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ if (!sid[TSN_STREAMID_ATTR_INDEX])
-+ return -EINVAL;
-+
-+ sid_index = nla_get_u32(sid[TSN_STREAMID_ATTR_INDEX]);
-+
-+ if (!tsnops->cb_streamid_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ ret = -EINVAL;
-+ goto exit;
-+ } else {
-+ valid = tsnops->cb_streamid_get(netdev, sid_index, &sidconf);
-+ if (valid < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, valid);
-+ return valid;
-+ }
-+ }
-+
-+ /* send back */
-+ genlhdr = info->genlhdr;
-+ ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
-+ NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ /* input netlink the parameters */
-+ sidattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_STREAM_IDENTIFY);
-+ if (!sidattr) {
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ if (nla_put_u32(rep_skb, TSN_STREAMID_ATTR_INDEX, sid_index))
-+ return -EMSGSIZE;
-+
-+ if (valid == 1) {
-+ nla_put_flag(rep_skb, TSN_STREAMID_ATTR_ENABLE);
-+ } else if (valid == 0) {
-+ nla_put_flag(rep_skb, TSN_STREAMID_ATTR_DISABLE);
-+ } else {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ goto err;
-+ }
-+
-+ if (nla_put_s32(rep_skb,
-+ TSN_STREAMID_ATTR_STREAM_HANDLE, sidconf.handle) ||
-+ nla_put_u32(rep_skb, TSN_STREAMID_ATTR_IFOP, sidconf.ifac_oport) ||
-+ nla_put_u32(rep_skb, TSN_STREAMID_ATTR_OFOP, sidconf.ofac_oport) ||
-+ nla_put_u32(rep_skb, TSN_STREAMID_ATTR_IFIP, sidconf.ifac_iport) ||
-+ nla_put_u32(rep_skb, TSN_STREAMID_ATTR_OFIP, sidconf.ofac_iport) ||
-+ nla_put_u8(rep_skb, TSN_STREAMID_ATTR_TYPE, sidconf.type))
-+ return -EMSGSIZE;
-+
-+ switch (sidconf.type) {
-+ case STREAMID_NULL:
-+ if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_NDMAC,
-+ sidconf.para.nid.dmac) ||
-+ nla_put_u16(rep_skb, TSN_STREAMID_ATTR_NVID,
-+ sidconf.para.nid.vid) ||
-+ nla_put_u8(rep_skb, TSN_STREAMID_ATTR_NTAGGED,
-+ sidconf.para.nid.tagged))
-+ return -EMSGSIZE;
-+ break;
-+ case STREAMID_SMAC_VLAN:
-+ if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_SMAC,
-+ sidconf.para.sid.smac) ||
-+ nla_put_u16(rep_skb, TSN_STREAMID_ATTR_SVID,
-+ sidconf.para.sid.vid) ||
-+ nla_put_u8(rep_skb, TSN_STREAMID_ATTR_STAGGED,
-+ sidconf.para.sid.tagged))
-+ return -EMSGSIZE;
-+ break;
-+ case STREAMID_DMAC_VLAN:
-+ case STREAMID_IP:
-+ default:
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ goto err;
-+ }
-+
-+ if (!tsnops->cb_streamid_counters_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ goto err;
-+ } else {
-+ ret = tsnops->cb_streamid_counters_get(netdev,
-+ sid_index,
-+ &sidcounts);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ goto err;
-+ }
-+ }
-+
-+ if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSI,
-+ sidcounts.per_stream.input) ||
-+ NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSO,
-+ sidcounts.per_stream.output))
-+ return -EMSGSIZE;
-+
-+ for (i = 0; i < 32; i++) {
-+ if (NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSPPI,
-+ sidcounts.per_streamport[i].input) ||
-+ NLA_PUT_U64(rep_skb, TSN_STREAMID_ATTR_COUNTERS_PSPPO,
-+ sidcounts.per_streamport[i].output))
-+ return -EMSGSIZE;
-+ }
-+
-+ nla_nest_end(rep_skb, sidattr);
-+ /* end netlink input the parameters */
-+
-+ /* netlink lib func */
-+ ret = nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name);
-+ if (ret < 0)
-+ goto err;
-+
-+ ret = nla_put_s32(rep_skb, TSN_CMD_ATTR_DATA, 0);
-+ if (ret < 0)
-+ goto err;
-+
-+ return tsn_send_reply(rep_skb, info);
-+
-+err:
-+ nlmsg_free(rep_skb);
-+exit:
-+ return ret;
-+}
-+
-+static int tsn_cb_streamid_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_cb_streamid_get(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmb_cb_streamid_counters_get(struct genl_info *info)
-+{
-+ return 0;
-+}
-+
-+static int tsn_cb_streamid_counters_get(struct sk_buff *skb,
-+ struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmb_cb_streamid_counters_get(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int tsn_qci_cap_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *qci_cap;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_qci_psfp_stream_param qci_cap_status;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ tsnops = port->tsnops;
-+
-+ genlhdr = info->genlhdr;
-+
-+ memset(&qci_cap_status, 0, sizeof(qci_cap_status));
-+
-+ if (!tsnops->qci_get_maxcap) {
-+ ret = -EOPNOTSUPP;
-+ goto out;
-+ }
-+
-+ ret = tsnops->qci_get_maxcap(netdev, &qci_cap_status);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* Pad netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ goto out;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name)) {
-+ ret = -EMSGSIZE;
-+ goto err;
-+ }
-+
-+ qci_cap = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SP);
-+ if (!qci_cap) {
-+ ret = -EMSGSIZE;
-+ goto err;
-+ }
-+
-+ if (nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_MAX_SFI,
-+ qci_cap_status.max_sf_instance) ||
-+ nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_MAX_SGI,
-+ qci_cap_status.max_sg_instance) ||
-+ nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_MAX_FMI,
-+ qci_cap_status.max_fm_instance) ||
-+ nla_put_u32(rep_skb, TSN_QCI_STREAM_ATTR_SLM,
-+ qci_cap_status.supported_list_max)) {
-+ ret = -EMSGSIZE;
-+ goto err;
-+ }
-+
-+ nla_nest_end(rep_skb, qci_cap);
-+
-+ tsn_send_reply(rep_skb, info);
-+
-+ return 0;
-+err:
-+ nlmsg_free(rep_skb);
-+out:
-+ if (ret < 0)
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+
-+ return ret;
-+}
-+
-+static int cmd_qci_sfi_set(struct genl_info *info)
-+{
-+ struct nlattr *na, *sfi[TSN_QCI_SFI_ATTR_MAX + 1];
-+ u32 sfi_handle;
-+ bool enable;
-+ int ret;
-+ struct net_device *netdev;
-+ struct tsn_qci_psfp_sfi_conf sficonf;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ memset(&sficonf, 0, sizeof(struct tsn_qci_psfp_sfi_conf));
-+
-+ if (!info->attrs[TSN_ATTR_QCI_SFI])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_QCI_SFI];
-+
-+ ret = NLA_PARSE_NESTED(sfi, TSN_QCI_SFI_ATTR_MAX, na, qci_sfi_policy);
-+ if (ret) {
-+ pr_info("tsn: parse value TSN_QCI_SFI_ATTR_MAX error.");
-+ return -EINVAL;
-+ }
-+
-+ if (!sfi[TSN_QCI_SFI_ATTR_INDEX])
-+ return -EINVAL;
-+
-+ sfi_handle = nla_get_u32(sfi[TSN_QCI_SFI_ATTR_INDEX]);
-+
-+ if (sfi[TSN_QCI_SFI_ATTR_ENABLE]) {
-+ enable = true;
-+ } else if (sfi[TSN_QCI_SFI_ATTR_DISABLE]) {
-+ enable = false;
-+ goto loaddrive;
-+ } else {
-+ pr_err("tsn: must provde ENABLE or DISABLE attribute.\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (!sfi[TSN_QCI_SFI_ATTR_GATE_ID]) {
-+ pr_err("tsn: must provide stream gate index\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (!sfi[TSN_QCI_SFI_ATTR_STREAM_HANDLE])
-+ sficonf.stream_handle_spec = -1;
-+ else
-+ sficonf.stream_handle_spec =
-+ nla_get_s32(sfi[TSN_QCI_SFI_ATTR_STREAM_HANDLE]);
-+
-+ if (!sfi[TSN_QCI_SFI_ATTR_PRIO_SPEC])
-+ sficonf.priority_spec = -1;
-+ else
-+ sficonf.priority_spec =
-+ nla_get_s8(sfi[TSN_QCI_SFI_ATTR_PRIO_SPEC]);
-+
-+ sficonf.stream_gate_instance_id =
-+ nla_get_u32(sfi[TSN_QCI_SFI_ATTR_GATE_ID]);
-+
-+ if (sfi[TSN_QCI_SFI_ATTR_MAXSDU])
-+ sficonf.stream_filter.maximum_sdu_size =
-+ nla_get_u16(sfi[TSN_QCI_SFI_ATTR_MAXSDU]);
-+ else
-+ sficonf.stream_filter.maximum_sdu_size = 0;
-+
-+ if (sfi[TSN_QCI_SFI_ATTR_FLOW_ID])
-+ sficonf.stream_filter.flow_meter_instance_id =
-+ nla_get_s32(sfi[TSN_QCI_SFI_ATTR_FLOW_ID]);
-+ else
-+ sficonf.stream_filter.flow_meter_instance_id = -1;
-+
-+ if (sfi[TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE])
-+ sficonf.block_oversize_enable = true;
-+
-+ if (sfi[TSN_QCI_SFI_ATTR_OVERSIZE])
-+ sficonf.block_oversize = true;
-+
-+loaddrive:
-+ if (!tsnops->qci_sfi_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -EINVAL;
-+ }
-+
-+ ret = tsnops->qci_sfi_set(netdev, sfi_handle, enable, &sficonf);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+ }
-+
-+ ret = tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, 0);
-+
-+ if (ret)
-+ return ret;
-+ return 0;
-+}
-+
-+static int tsn_qci_sfi_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_sfi_set(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qci_sfi_get(struct genl_info *info)
-+{
-+ struct nlattr *na, *sfiattr;
-+ struct nlattr *sfi[TSN_QCI_SFI_ATTR_MAX + 1];
-+ u32 sfi_handle;
-+ struct sk_buff *rep_skb;
-+ int ret, valid = 0;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_qci_psfp_sfi_conf sficonf;
-+ struct tsn_qci_psfp_sfi_counters sficount;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ genlhdr = info->genlhdr;
-+
-+ if (!info->attrs[TSN_ATTR_QCI_SFI])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_QCI_SFI];
-+
-+ ret = NLA_PARSE_NESTED(sfi, TSN_QCI_SFI_ATTR_MAX,
-+ na, qci_sfi_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ if (!sfi[TSN_QCI_SFI_ATTR_INDEX])
-+ return -EINVAL;
-+
-+ sfi_handle = nla_get_u32(sfi[TSN_QCI_SFI_ATTR_INDEX]);
-+
-+ memset(&sficonf, 0, sizeof(struct tsn_qci_psfp_sfi_conf));
-+ memset(&sficount, 0, sizeof(struct tsn_qci_psfp_sfi_counters));
-+
-+ if (!tsnops->qci_sfi_get || !tsnops->qci_sfi_counters_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ ret = -EINVAL;
-+ goto exit;
-+ } else {
-+ valid = tsnops->qci_sfi_get(netdev, sfi_handle, &sficonf);
-+ if (valid < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, valid);
-+ return valid;
-+ }
-+
-+ valid = tsnops->qci_sfi_counters_get(netdev, sfi_handle,
-+ &sficount);
-+ if (valid < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, valid);
-+ return valid;
-+ }
-+ }
-+
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ goto err;
-+
-+ sfiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SFI);
-+ if (!sfiattr) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ if (nla_put_u32(rep_skb, TSN_QCI_SFI_ATTR_INDEX, sfi_handle))
-+ return -EMSGSIZE;
-+
-+ if (valid) {
-+ if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_ENABLE))
-+ return -EMSGSIZE;
-+ } else {
-+ if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_DISABLE))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (nla_put_s32(rep_skb, TSN_QCI_SFI_ATTR_STREAM_HANDLE,
-+ sficonf.stream_handle_spec) ||
-+ nla_put_s8(rep_skb, TSN_QCI_SFI_ATTR_PRIO_SPEC,
-+ sficonf.priority_spec) ||
-+ nla_put_u32(rep_skb, TSN_QCI_SFI_ATTR_GATE_ID,
-+ sficonf.stream_gate_instance_id))
-+ return -EMSGSIZE;
-+
-+ if (sficonf.stream_filter.maximum_sdu_size)
-+ if (nla_put_u16(rep_skb, TSN_QCI_SFI_ATTR_MAXSDU,
-+ sficonf.stream_filter.maximum_sdu_size))
-+ return -EMSGSIZE;
-+
-+ if (sficonf.stream_filter.flow_meter_instance_id >= 0)
-+ if (nla_put_s32(rep_skb, TSN_QCI_SFI_ATTR_FLOW_ID,
-+ sficonf.stream_filter.flow_meter_instance_id))
-+ return -EMSGSIZE;
-+
-+ if (sficonf.block_oversize_enable)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_OVERSIZE_ENABLE))
-+ return -EMSGSIZE;
-+ if (sficonf.block_oversize)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SFI_ATTR_OVERSIZE))
-+ return -EMSGSIZE;
-+
-+ if (nla_put(rep_skb, TSN_QCI_SFI_ATTR_COUNTERS,
-+ sizeof(struct tsn_qci_psfp_sfi_counters), &sficount))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, sfiattr);
-+
-+ return tsn_send_reply(rep_skb, info);
-+err:
-+ nlmsg_free(rep_skb);
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+exit:
-+ return ret;
-+}
-+
-+static int tsn_qci_sfi_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_sfi_get(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qci_sfi_counters_get(struct genl_info *info)
-+{
-+ struct nlattr *na, *sfiattr;
-+ struct nlattr *sfi[TSN_QCI_SFI_ATTR_MAX + 1];
-+ u32 sfi_handle;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_qci_psfp_sfi_counters sficount;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ genlhdr = info->genlhdr;
-+
-+ if (!info->attrs[TSN_ATTR_QCI_SFI])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_QCI_SFI];
-+
-+ ret = NLA_PARSE_NESTED(sfi, TSN_QCI_SFI_ATTR_MAX,
-+ na, qci_sfi_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ if (!sfi[TSN_QCI_SFI_ATTR_INDEX])
-+ return -EINVAL;
-+
-+ sfi_handle = nla_get_u32(sfi[TSN_QCI_SFI_ATTR_INDEX]);
-+
-+ memset(&sficount, 0, sizeof(struct tsn_qci_psfp_sfi_counters));
-+ if (!tsnops->qci_sfi_counters_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = tsnops->qci_sfi_counters_get(netdev, sfi_handle, &sficount);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
-+ NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ goto err;
-+
-+ sfiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SFI);
-+ if (!sfiattr) {
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ if (nla_put_u32(rep_skb, TSN_QCI_SFI_ATTR_INDEX, sfi_handle))
-+ return -EMSGSIZE;
-+
-+ ret = tsnops->qci_sfi_counters_get(netdev, sfi_handle, &sficount);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+ }
-+
-+ if (nla_put(rep_skb, TSN_QCI_SFI_ATTR_COUNTERS,
-+ sizeof(struct tsn_qci_psfp_sfi_counters), &sficount))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, sfiattr);
-+
-+ return tsn_send_reply(rep_skb, info);
-+err:
-+ nlmsg_free(rep_skb);
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, -EINVAL);
-+ return ret;
-+}
-+
-+static int tsn_qci_sfi_counters_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_sfi_counters_get(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qci_sgi_set(struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *sgia[TSN_QCI_SGI_ATTR_MAX + 1];
-+ struct nlattr *admin[TSN_SGI_ATTR_CTRL_MAX + 1];
-+ int ret = 0;
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_qci_psfp_sgi_conf sgi;
-+ struct tsn_qci_psfp_gcl *gcl = NULL;
-+ u16 sgi_handle = 0;
-+ u16 listcount = 0;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ memset(&sgi, 0, sizeof(struct tsn_qci_psfp_sgi_conf));
-+
-+ if (!info->attrs[TSN_ATTR_QCI_SGI]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_QCI_SGI];
-+
-+ ret = NLA_PARSE_NESTED(sgia, TSN_QCI_SGI_ATTR_MAX,
-+ na, qci_sgi_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_ENABLE] && sgia[TSN_QCI_SGI_ATTR_DISABLE]) {
-+ pr_err("tsn: enable or disable?\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -1;
-+ }
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_INDEX])
-+ sgi_handle = nla_get_u32(sgia[TSN_QCI_SGI_ATTR_INDEX]);
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_DISABLE]) {
-+ sgi.gate_enabled = 0;
-+ goto loaddev;
-+ } else {
-+ /* set default to be enable*/
-+ sgi.gate_enabled = 1;
-+ }
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_CONFCHANGE])
-+ sgi.config_change = 1;
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_IRXEN])
-+ sgi.block_invalid_rx_enable = 1;
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_IRX])
-+ sgi.block_invalid_rx = 1;
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_OEXEN])
-+ sgi.block_octets_exceeded_enable = 1;
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_OEX])
-+ sgi.block_octets_exceeded = 1;
-+
-+ if (sgia[TSN_QCI_SGI_ATTR_ADMINENTRY]) {
-+ struct nlattr *entry;
-+ int rem;
-+ int count = 0;
-+
-+ na = sgia[TSN_QCI_SGI_ATTR_ADMINENTRY];
-+ ret = NLA_PARSE_NESTED(admin, TSN_SGI_ATTR_CTRL_MAX,
-+ na, qci_sgi_ctrl_policy);
-+
-+ /* Other parameters in admin control */
-+ if (admin[TSN_SGI_ATTR_CTRL_INITSTATE])
-+ sgi.admin.gate_states = 1;
-+
-+ if (admin[TSN_SGI_ATTR_CTRL_CYTIME])
-+ sgi.admin.cycle_time =
-+ nla_get_u32(admin[TSN_SGI_ATTR_CTRL_CYTIME]);
-+
-+ if (admin[TSN_SGI_ATTR_CTRL_CYTIMEEX])
-+ sgi.admin.cycle_time_extension =
-+ nla_get_u32(admin[TSN_SGI_ATTR_CTRL_CYTIMEEX]);
-+
-+ if (admin[TSN_SGI_ATTR_CTRL_BTIME])
-+ sgi.admin.base_time =
-+ nla_get_u64(admin[TSN_SGI_ATTR_CTRL_BTIME]);
-+
-+ if (admin[TSN_SGI_ATTR_CTRL_INITIPV])
-+ sgi.admin.init_ipv =
-+ nla_get_s8(admin[TSN_SGI_ATTR_CTRL_INITIPV]);
-+ else
-+ sgi.admin.init_ipv = -1;
-+
-+ if (admin[TSN_SGI_ATTR_CTRL_LEN]) {
-+ sgi.admin.control_list_length =
-+ nla_get_u8(admin[TSN_SGI_ATTR_CTRL_LEN]);
-+ listcount = sgi.admin.control_list_length;
-+ }
-+
-+ if (!listcount)
-+ goto loaddev;
-+
-+ gcl = kmalloc_array(listcount, sizeof(*gcl), GFP_KERNEL);
-+
-+ memset(gcl, 0, listcount * sizeof(struct tsn_qci_psfp_gcl));
-+
-+ /* Check the whole admin attrs,
-+ * checkout the TSN_SGI_ATTR_CTRL_GCLENTRY attributes
-+ */
-+ nla_for_each_nested(entry, na, rem) {
-+ struct nlattr *gcl_entry[TSN_SGI_ATTR_GCL_MAX + 1];
-+ struct nlattr *ti, *om;
-+
-+ if (nla_type(entry) != TSN_SGI_ATTR_CTRL_GCLENTRY)
-+ continue;
-+
-+ /* parse each TSN_SGI_ATTR_CTRL_GCLENTRY */
-+ ret = NLA_PARSE_NESTED(gcl_entry, TSN_SGI_ATTR_GCL_MAX,
-+ entry, qci_sgi_gcl_policy);
-+ /* Parse gate control list */
-+ if (gcl_entry[TSN_SGI_ATTR_GCL_GATESTATE])
-+ (gcl + count)->gate_state = 1;
-+
-+ if (gcl_entry[TSN_SGI_ATTR_GCL_IPV])
-+ (gcl + count)->ipv =
-+ nla_get_s8(gcl_entry[TSN_SGI_ATTR_GCL_IPV]);
-+
-+ if (gcl_entry[TSN_SGI_ATTR_GCL_INTERVAL]) {
-+ ti = gcl_entry[TSN_SGI_ATTR_GCL_INTERVAL];
-+ (gcl + count)->time_interval = nla_get_u32(ti);
-+ }
-+
-+ if (gcl_entry[TSN_SGI_ATTR_GCL_OCTMAX]) {
-+ om = gcl_entry[TSN_SGI_ATTR_GCL_OCTMAX];
-+ (gcl + count)->octet_max = nla_get_u32(om);
-+ }
-+
-+ count++;
-+
-+ if (count >= listcount)
-+ break;
-+ }
-+
-+ if (count < listcount) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ pr_err("tsn: count less than TSN_SGI_ATTR_CTRL_LEN\n");
-+ kfree(gcl);
-+ return -EINVAL;
-+ }
-+
-+ } else {
-+ pr_info("tsn: no admin list parameters setting\n");
-+ }
-+
-+loaddev:
-+ if (!tsnops->qci_sgi_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ kfree(gcl);
-+ return -EINVAL;
-+ }
-+
-+ sgi.admin.gcl = gcl;
-+
-+ ret = tsnops->qci_sgi_set(netdev, sgi_handle, &sgi);
-+ kfree(gcl);
-+ if (!ret)
-+ return tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+}
-+
-+static int tsn_qci_sgi_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_sgi_set(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qci_sgi_get(struct genl_info *info)
-+{
-+ struct nlattr *na, *sgiattr, *adminattr, *sglattr;
-+ struct nlattr *sgi[TSN_QCI_SGI_ATTR_MAX + 1];
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_qci_psfp_sgi_conf sgiadmin;
-+ struct tsn_qci_psfp_gcl *gcl = NULL;
-+ const struct tsn_ops *tsnops;
-+ u16 sgi_handle;
-+ u8 listcount, i;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_QCI_SGI]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ pr_err("tsn: no sgi handle input\n");
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_QCI_SGI];
-+
-+ ret = NLA_PARSE_NESTED(sgi, TSN_QCI_SGI_ATTR_MAX,
-+ na, qci_sgi_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ if (!sgi[TSN_QCI_SGI_ATTR_INDEX]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ pr_err("tsn: no sgi handle input\n");
-+ return -EINVAL;
-+ }
-+
-+ sgi_handle = nla_get_u32(sgi[TSN_QCI_SGI_ATTR_INDEX]);
-+
-+ /* Get config data from device */
-+ genlhdr = info->genlhdr;
-+
-+ memset(&sgiadmin, 0, sizeof(struct tsn_qci_psfp_sgi_conf));
-+
-+ if (!tsnops->qci_sgi_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = tsnops->qci_sgi_get(netdev, sgi_handle, &sgiadmin);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ /* Form netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ sgiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SGI);
-+ if (!sgiattr)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_QCI_SGI_ATTR_INDEX, sgi_handle))
-+ return -EMSGSIZE;
-+
-+ /* Gate enable? sgiadmin.gate_enabled */
-+ if (sgiadmin.gate_enabled) {
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_ENABLE))
-+ return -EMSGSIZE;
-+ } else {
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_DISABLE))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (sgiadmin.config_change)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_CONFCHANGE))
-+ return -EMSGSIZE;
-+
-+ if (sgiadmin.block_invalid_rx_enable)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_IRXEN))
-+ return -EMSGSIZE;
-+
-+ if (sgiadmin.block_invalid_rx)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_IRX))
-+ return -EMSGSIZE;
-+
-+ if (sgiadmin.block_octets_exceeded_enable)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_OEXEN))
-+ return -EMSGSIZE;
-+
-+ if (sgiadmin.block_octets_exceeded)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_OEX))
-+ return -EMSGSIZE;
-+
-+ /* Administration */
-+ adminattr = nla_nest_start_noflag(rep_skb, TSN_QCI_SGI_ATTR_ADMINENTRY);
-+ if (!adminattr)
-+ return -EMSGSIZE;
-+
-+ if (sgiadmin.admin.gate_states)
-+ if (nla_put_flag(rep_skb, TSN_SGI_ATTR_CTRL_INITSTATE))
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIME,
-+ sgiadmin.admin.cycle_time) ||
-+ nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIMEEX,
-+ sgiadmin.admin.cycle_time_extension) ||
-+ NLA_PUT_U64(rep_skb, TSN_SGI_ATTR_CTRL_BTIME,
-+ sgiadmin.admin.base_time) ||
-+ nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_INITIPV,
-+ sgiadmin.admin.init_ipv))
-+ return -EMSGSIZE;
-+
-+ listcount = sgiadmin.admin.control_list_length;
-+ if (!listcount)
-+ goto out1;
-+
-+ if (!sgiadmin.admin.gcl) {
-+ pr_err("error: no gate control list\n");
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ gcl = sgiadmin.admin.gcl;
-+
-+ /* loop list */
-+ for (i = 0; i < listcount; i++) {
-+ s8 ipv;
-+ u32 ti, omax;
-+
-+ if (!(gcl + i)) {
-+ pr_err("error: list count too big\n");
-+ ret = -EINVAL;
-+ kfree(sgiadmin.admin.gcl);
-+ goto err;
-+ }
-+
-+ /* Adminastration entry */
-+ sglattr = nla_nest_start_noflag(rep_skb,
-+ TSN_SGI_ATTR_CTRL_GCLENTRY);
-+ if (!sglattr)
-+ return -EMSGSIZE;
-+ ipv = (gcl + i)->ipv;
-+ ti = (gcl + i)->time_interval;
-+ omax = (gcl + i)->octet_max;
-+
-+ if ((gcl + i)->gate_state)
-+ if (nla_put_flag(rep_skb, TSN_SGI_ATTR_GCL_GATESTATE))
-+ return -EMSGSIZE;
-+
-+ if (nla_put_s8(rep_skb, TSN_SGI_ATTR_GCL_IPV, ipv) ||
-+ nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_INTERVAL, ti) ||
-+ nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_OCTMAX, omax))
-+ return -EMSGSIZE;
-+
-+ /* End administration entry */
-+ nla_nest_end(rep_skb, sglattr);
-+ }
-+
-+ kfree(sgiadmin.admin.gcl);
-+ if (nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_LEN, listcount))
-+ return -EMSGSIZE;
-+
-+out1:
-+ /* End adminastration */
-+ nla_nest_end(rep_skb, adminattr);
-+
-+ nla_nest_end(rep_skb, sgiattr);
-+
-+ return tsn_send_reply(rep_skb, info);
-+err:
-+ nlmsg_free(rep_skb);
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+}
-+
-+static int tsn_qci_sgi_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_sgi_get(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qci_sgi_status_get(struct genl_info *info)
-+{
-+ struct nlattr *na, *sgiattr, *operattr, *sglattr;
-+ struct nlattr *sgi[TSN_QCI_SGI_ATTR_MAX + 1];
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_psfp_sgi_status sgistat;
-+ struct tsn_qci_psfp_gcl *gcl = NULL;
-+ const struct tsn_ops *tsnops;
-+ u16 sgi_handle;
-+ u8 listcount;
-+ int valid, i;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_QCI_SGI]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ pr_err("tsn: no sgi handle input\n");
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_QCI_SGI];
-+
-+ ret = NLA_PARSE_NESTED(sgi, TSN_QCI_SGI_ATTR_MAX,
-+ na, qci_sgi_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ if (!sgi[TSN_QCI_SGI_ATTR_INDEX]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ pr_err("tsn: no sgi handle input\n");
-+ return -EINVAL;
-+ }
-+
-+ sgi_handle = nla_get_u32(sgi[TSN_QCI_SGI_ATTR_INDEX]);
-+
-+ /* Get status data from device */
-+ genlhdr = info->genlhdr;
-+
-+ memset(&sgistat, 0, sizeof(struct tsn_psfp_sgi_status));
-+
-+ if (!tsnops->qci_sgi_status_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ valid = tsnops->qci_sgi_status_get(netdev, sgi_handle, &sgistat);
-+ if (valid < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, valid);
-+ return valid;
-+ }
-+
-+ /* Form netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ /* Down one netlink attribute level */
-+ sgiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_SGI);
-+ if (!sgiattr)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_QCI_SGI_ATTR_INDEX, sgi_handle))
-+ return -EMSGSIZE;
-+
-+ /* Gate enable */
-+ if (valid == 1) {
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_ENABLE))
-+ return -EMSGSIZE;
-+ } else {
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_DISABLE))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (nla_put_u32(rep_skb, TSN_QCI_SGI_ATTR_TICKG,
-+ sgistat.tick_granularity) ||
-+ NLA_PUT_U64(rep_skb, TSN_QCI_SGI_ATTR_CCTIME,
-+ sgistat.config_change_time) ||
-+ NLA_PUT_U64(rep_skb, TSN_QCI_SGI_ATTR_CUTIME,
-+ sgistat.current_time) ||
-+ NLA_PUT_U64(rep_skb, TSN_QCI_SGI_ATTR_CCERROR,
-+ sgistat.config_change_error))
-+ return -EMSGSIZE;
-+
-+ if (sgistat.config_pending)
-+ if (nla_put_flag(rep_skb, TSN_QCI_SGI_ATTR_CPENDING))
-+ return -EMSGSIZE;
-+
-+ /* operation data */
-+ operattr = nla_nest_start_noflag(rep_skb, TSN_QCI_SGI_ATTR_OPERENTRY);
-+ if (!operattr)
-+ return -EMSGSIZE;
-+
-+ if (sgistat.oper.gate_states)
-+ if (nla_put_flag(rep_skb, TSN_SGI_ATTR_CTRL_INITSTATE))
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIME,
-+ sgistat.oper.cycle_time) ||
-+ nla_put_u32(rep_skb, TSN_SGI_ATTR_CTRL_CYTIMEEX,
-+ sgistat.oper.cycle_time_extension) ||
-+ NLA_PUT_U64(rep_skb, TSN_SGI_ATTR_CTRL_BTIME,
-+ sgistat.oper.base_time) ||
-+ nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_INITIPV,
-+ sgistat.oper.init_ipv))
-+ return -EMSGSIZE;
-+
-+ /* Loop list */
-+ listcount = sgistat.oper.control_list_length;
-+ if (!listcount)
-+ goto out1;
-+
-+ if (!sgistat.oper.gcl) {
-+ pr_err("error: list lenghth is not zero!\n");
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ gcl = sgistat.oper.gcl;
-+
-+ /* loop list */
-+ for (i = 0; i < listcount; i++) {
-+ s8 ipv;
-+ u32 ti, omax;
-+
-+ if (!(gcl + i)) {
-+ pr_err("error: list count too big\n");
-+ ret = -EINVAL;
-+ kfree(sgistat.oper.gcl);
-+ goto err;
-+ }
-+
-+ /* Operation entry */
-+ sglattr = nla_nest_start_noflag(rep_skb,
-+ TSN_SGI_ATTR_CTRL_GCLENTRY);
-+ if (!sglattr)
-+ return -EMSGSIZE;
-+ ipv = (gcl + i)->ipv;
-+ ti = (gcl + i)->time_interval;
-+ omax = (gcl + i)->octet_max;
-+
-+ if ((gcl + i)->gate_state)
-+ if (nla_put_flag(rep_skb, TSN_SGI_ATTR_GCL_GATESTATE))
-+ return -EMSGSIZE;
-+
-+ if (nla_put_s8(rep_skb, TSN_SGI_ATTR_GCL_IPV, ipv) ||
-+ nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_INTERVAL, ti) ||
-+ nla_put_u32(rep_skb, TSN_SGI_ATTR_GCL_OCTMAX, omax))
-+ return -EMSGSIZE;
-+
-+ /* End operation entry */
-+ nla_nest_end(rep_skb, sglattr);
-+ }
-+
-+ kfree(sgistat.oper.gcl);
-+ if (nla_put_u8(rep_skb, TSN_SGI_ATTR_CTRL_LEN, listcount))
-+ return -EMSGSIZE;
-+out1:
-+ /* End operation */
-+ nla_nest_end(rep_skb, operattr);
-+
-+ nla_nest_end(rep_skb, sgiattr);
-+
-+ return tsn_send_reply(rep_skb, info);
-+err:
-+ nlmsg_free(rep_skb);
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+}
-+
-+static int tsn_qci_sgi_status_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_sgi_status_get(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qci_fmi_set(struct genl_info *info)
-+{
-+ struct nlattr *na, *fmi[TSN_QCI_FMI_ATTR_MAX + 1];
-+ u32 index;
-+ int ret;
-+ struct net_device *netdev;
-+ struct tsn_qci_psfp_fmi fmiconf;
-+ const struct tsn_ops *tsnops;
-+ bool enable = 0;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ memset(&fmiconf, 0, sizeof(struct tsn_qci_psfp_fmi));
-+
-+ if (!info->attrs[TSN_ATTR_QCI_FMI])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_QCI_FMI];
-+
-+ ret = NLA_PARSE_NESTED(fmi, TSN_QCI_FMI_ATTR_MAX, na, qci_fmi_policy);
-+ if (ret) {
-+ pr_info("tsn: parse value TSN_QCI_FMI_ATTR_MAX error.");
-+ return -EINVAL;
-+ }
-+
-+ if (!fmi[TSN_QCI_FMI_ATTR_INDEX])
-+ return -EINVAL;
-+
-+ index = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_INDEX]);
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_DISABLE])
-+ goto loaddev;
-+
-+ enable = 1;
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_CIR])
-+ fmiconf.cir = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_CIR]);
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_CBS])
-+ fmiconf.cbs = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_CBS]);
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_EIR])
-+ fmiconf.eir = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_EIR]);
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_EBS])
-+ fmiconf.ebs = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_EBS]);
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_CF])
-+ fmiconf.cf = 1;
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_CM])
-+ fmiconf.cm = 1;
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_DROPYL])
-+ fmiconf.drop_on_yellow = 1;
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_MAREDEN])
-+ fmiconf.mark_red_enable = 1;
-+
-+ if (fmi[TSN_QCI_FMI_ATTR_MARED])
-+ fmiconf.mark_red = 1;
-+
-+loaddev:
-+
-+ if (!tsnops->qci_fmi_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -EINVAL;
-+ }
-+
-+ ret = tsnops->qci_fmi_set(netdev, index, enable, &fmiconf);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+ }
-+
-+ ret = tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, 0);
-+
-+ if (ret)
-+ return ret;
-+ return 0;
-+}
-+
-+static int tsn_qci_fmi_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_fmi_set(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qci_fmi_get(struct genl_info *info)
-+{
-+ struct nlattr *na, *fmi[TSN_QCI_FMI_ATTR_MAX + 1], *fmiattr;
-+ u32 index;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct net_device *netdev;
-+ struct tsn_qci_psfp_fmi fmiconf;
-+ struct tsn_qci_psfp_fmi_counters counters;
-+ const struct tsn_ops *tsnops;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_QCI_FMI])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_QCI_FMI];
-+
-+ ret = NLA_PARSE_NESTED(fmi, TSN_QCI_FMI_ATTR_MAX,
-+ na, qci_fmi_policy);
-+ if (ret) {
-+ pr_info("tsn: parse value TSN_QCI_FMI_ATTR_MAX error.");
-+ return -EINVAL;
-+ }
-+
-+ if (!fmi[TSN_QCI_FMI_ATTR_INDEX])
-+ return -EINVAL;
-+
-+ index = nla_get_u32(fmi[TSN_QCI_FMI_ATTR_INDEX]);
-+
-+ /* Get data from device */
-+ memset(&fmiconf, 0, sizeof(struct tsn_qci_psfp_fmi));
-+ memset(&counters, 0, sizeof(struct tsn_qci_psfp_fmi_counters));
-+
-+ if (!tsnops->qci_fmi_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -EINVAL;
-+ }
-+
-+ ret = tsnops->qci_fmi_get(netdev, index, &fmiconf, &counters);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, ret);
-+ return ret;
-+ }
-+
-+ genlhdr = info->genlhdr;
-+
-+ /* Form netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ fmiattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QCI_FMI);
-+ if (!fmiattr)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_INDEX, index) ||
-+ nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_CIR, fmiconf.cir) ||
-+ nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_CBS, fmiconf.cbs) ||
-+ nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_EIR, fmiconf.eir) ||
-+ nla_put_u32(rep_skb, TSN_QCI_FMI_ATTR_EBS, fmiconf.ebs))
-+ return -EMSGSIZE;
-+
-+ if (fmiconf.cf)
-+ if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_CF))
-+ return -EMSGSIZE;
-+
-+ if (fmiconf.cm)
-+ if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_CM))
-+ return -EMSGSIZE;
-+
-+ if (fmiconf.drop_on_yellow)
-+ if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_DROPYL))
-+ return -EMSGSIZE;
-+
-+ if (fmiconf.mark_red_enable)
-+ if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_MAREDEN))
-+ return -EMSGSIZE;
-+
-+ if (fmiconf.mark_red)
-+ if (nla_put_flag(rep_skb, TSN_QCI_FMI_ATTR_MAREDEN))
-+ return -EMSGSIZE;
-+
-+ if (nla_put(rep_skb, TSN_QCI_FMI_ATTR_COUNTERS,
-+ sizeof(struct tsn_qci_psfp_fmi_counters), &counters))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, fmiattr);
-+
-+ tsn_send_reply(rep_skb, info);
-+
-+ return 0;
-+}
-+
-+static int tsn_qci_fmi_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qci_fmi_get(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qbv_set(struct genl_info *info)
-+{
-+ struct nlattr *na, *na1;
-+ struct nlattr *qbv_table;
-+ struct nlattr *qbv[TSN_QBV_ATTR_MAX + 1];
-+ struct nlattr *qbvctrl[TSN_QBV_ATTR_CTRL_MAX + 1];
-+ int rem;
-+ int ret = 0;
-+ struct net_device *netdev;
-+ struct tsn_qbv_conf qbvconfig;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_qbv_entry *gatelist = NULL;
-+ int count = 0;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ memset(&qbvconfig, 0, sizeof(struct tsn_qbv_conf));
-+
-+ if (!info->attrs[TSN_ATTR_QBV])
-+ return -EINVAL;
-+
-+ na = info->attrs[TSN_ATTR_QBV];
-+
-+ ret = NLA_PARSE_NESTED(qbv, TSN_QBV_ATTR_MAX, na, qbv_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ if (qbv[TSN_QBV_ATTR_ENABLE])
-+ qbvconfig.gate_enabled = 1;
-+ else
-+ goto setdrive;
-+
-+ if (qbv[TSN_QBV_ATTR_CONFIGCHANGE])
-+ qbvconfig.config_change = 1;
-+
-+ if (!qbv[TSN_QBV_ATTR_ADMINENTRY]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -1;
-+ }
-+
-+ na1 = qbv[TSN_QBV_ATTR_ADMINENTRY];
-+ NLA_PARSE_NESTED(qbvctrl, TSN_QBV_ATTR_CTRL_MAX,
-+ na1, qbv_ctrl_policy);
-+
-+ if (qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIME]) {
-+ qbvconfig.admin.cycle_time =
-+ nla_get_u32(qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIME]);
-+ }
-+
-+ if (qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIMEEXT]) {
-+ qbvconfig.admin.cycle_time_extension =
-+ nla_get_u32(qbvctrl[TSN_QBV_ATTR_CTRL_CYCLETIMEEXT]);
-+ }
-+
-+ if (qbvctrl[TSN_QBV_ATTR_CTRL_BASETIME]) {
-+ qbvconfig.admin.base_time =
-+ nla_get_u64(qbvctrl[TSN_QBV_ATTR_CTRL_BASETIME]);
-+ }
-+
-+ if (qbvctrl[TSN_QBV_ATTR_CTRL_GATESTATE]) {
-+ qbvconfig.admin.gate_states =
-+ nla_get_u8(qbvctrl[TSN_QBV_ATTR_CTRL_GATESTATE]);
-+ }
-+
-+ if (qbvctrl[TSN_QBV_ATTR_CTRL_LISTCOUNT]) {
-+ int listcount;
-+
-+ listcount = nla_get_u32(qbvctrl[TSN_QBV_ATTR_CTRL_LISTCOUNT]);
-+
-+ qbvconfig.admin.control_list_length = listcount;
-+
-+ gatelist = kmalloc_array(listcount,
-+ sizeof(*gatelist),
-+ GFP_KERNEL);
-+
-+ nla_for_each_nested(qbv_table, na1, rem) {
-+ struct nlattr *qbv_entry[TSN_QBV_ATTR_ENTRY_MAX + 1];
-+
-+ if (nla_type(qbv_table) != TSN_QBV_ATTR_CTRL_LISTENTRY)
-+ continue;
-+
-+ ret = NLA_PARSE_NESTED(qbv_entry,
-+ TSN_QBV_ATTR_ENTRY_MAX,
-+ qbv_table, qbv_entry_policy);
-+ if (ret)
-+ return -EINVAL;
-+
-+ (gatelist + count)->gate_state =
-+ nla_get_u8(qbv_entry[TSN_QBV_ATTR_ENTRY_GC]);
-+ (gatelist + count)->time_interval =
-+ nla_get_u32(qbv_entry[TSN_QBV_ATTR_ENTRY_TM]);
-+ count++;
-+ if (count > listcount)
-+ break;
-+ }
-+ }
-+
-+ if (gatelist)
-+ qbvconfig.admin.control_list = gatelist;
-+
-+setdrive:
-+ if (!tsnops->qbv_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ goto err;
-+ }
-+
-+ ret = tsnops->qbv_set(netdev, &qbvconfig);
-+
-+ /* send back */
-+ if (ret < 0)
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ else
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+
-+err:
-+ kfree(gatelist);
-+ return ret;
-+}
-+
-+static int tsn_qbv_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME]) {
-+ cmd_qbv_set(info);
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+static int cmd_qbv_get(struct genl_info *info)
-+{
-+ struct nlattr *qbv, *qbvadminattr;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ int len = 0, i = 0;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_qbv_conf qbvconf;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ genlhdr = info->genlhdr;
-+
-+ memset(&qbvconf, 0, sizeof(struct tsn_qbv_conf));
-+
-+ if (!tsnops->qbv_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = tsnops->qbv_get(netdev, &qbvconf);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ qbv = nla_nest_start_noflag(rep_skb, TSN_ATTR_QBV);
-+ if (!qbv)
-+ return -EMSGSIZE;
-+
-+ qbvadminattr = nla_nest_start_noflag(rep_skb, TSN_QBV_ATTR_ADMINENTRY);
-+ if (!qbvadminattr)
-+ return -EMSGSIZE;
-+
-+ if (qbvconf.admin.control_list) {
-+ len = qbvconf.admin.control_list_length;
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_LISTCOUNT, len))
-+ return -EMSGSIZE;
-+
-+ for (i = 0; i < len; i++) {
-+ struct nlattr *qbv_table;
-+ u8 gs;
-+ u32 tp;
-+ int glisttype = TSN_QBV_ATTR_CTRL_LISTENTRY;
-+
-+ gs = (qbvconf.admin.control_list + i)->gate_state;
-+ tp = (qbvconf.admin.control_list + i)->time_interval;
-+
-+ qbv_table =
-+ nla_nest_start_noflag(rep_skb, glisttype);
-+ if (!qbv_table)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_ID, i) ||
-+ nla_put_u8(rep_skb, TSN_QBV_ATTR_ENTRY_GC, gs) ||
-+ nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_TM, tp))
-+ return -EMSGSIZE;
-+ nla_nest_end(rep_skb, qbv_table);
-+ }
-+
-+ if (qbvconf.admin.gate_states)
-+ if (nla_put_u8(rep_skb, TSN_QBV_ATTR_CTRL_GATESTATE,
-+ qbvconf.admin.gate_states))
-+ return -EMSGSIZE;
-+
-+ if (qbvconf.admin.cycle_time)
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIME,
-+ qbvconf.admin.cycle_time))
-+ return -EMSGSIZE;
-+
-+ if (qbvconf.admin.cycle_time_extension)
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIMEEXT,
-+ qbvconf.admin.cycle_time_extension))
-+ return -EMSGSIZE;
-+
-+ if (qbvconf.admin.base_time)
-+ if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CTRL_BASETIME,
-+ qbvconf.admin.base_time))
-+ return -EMSGSIZE;
-+
-+ kfree(qbvconf.admin.control_list);
-+
-+ } else {
-+ pr_info("tsn: error get administrator data.");
-+ }
-+
-+ nla_nest_end(rep_skb, qbvadminattr);
-+
-+ if (qbvconf.gate_enabled) {
-+ if (nla_put_flag(rep_skb, TSN_QBV_ATTR_ENABLE))
-+ return -EMSGSIZE;
-+ } else {
-+ if (nla_put_flag(rep_skb, TSN_QBV_ATTR_DISABLE))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvconf.maxsdu)
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_MAXSDU, qbvconf.maxsdu))
-+ return -EMSGSIZE;
-+
-+ if (qbvconf.config_change)
-+ if (nla_put_flag(rep_skb, TSN_QBV_ATTR_CONFIGCHANGE))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, qbv);
-+
-+ tsn_send_reply(rep_skb, info);
-+
-+ return ret;
-+}
-+
-+static int cmd_qbv_status_get(struct genl_info *info)
-+{
-+ struct nlattr *qbv, *qbvoperattr;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ int len = 0, i = 0;
-+ struct net_device *netdev;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_qbv_status qbvstatus;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ genlhdr = info->genlhdr;
-+
-+ memset(&qbvstatus, 0, sizeof(struct tsn_qbv_status));
-+
-+ if (!tsnops->qbv_get_status) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = tsnops->qbv_get_status(netdev, &qbvstatus);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ qbv = nla_nest_start_noflag(rep_skb, TSN_ATTR_QBV);
-+ if (!qbv)
-+ return -EMSGSIZE;
-+
-+ qbvoperattr = nla_nest_start_noflag(rep_skb, TSN_QBV_ATTR_OPERENTRY);
-+ if (!qbvoperattr)
-+ return -EMSGSIZE;
-+
-+ if (qbvstatus.oper.control_list) {
-+ len = qbvstatus.oper.control_list_length;
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_LISTCOUNT, len)) {
-+ nla_nest_cancel(rep_skb, qbvoperattr);
-+ return -EMSGSIZE;
-+ }
-+
-+ for (i = 0; i < len; i++) {
-+ struct nlattr *qbv_table;
-+ u8 gs;
-+ u32 tp;
-+ int glisttype = TSN_QBV_ATTR_CTRL_LISTENTRY;
-+
-+ gs = (qbvstatus.oper.control_list + i)->gate_state;
-+ tp = (qbvstatus.oper.control_list + i)->time_interval;
-+
-+ qbv_table = nla_nest_start_noflag(rep_skb, glisttype);
-+ if (!qbv_table)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_ID, i) ||
-+ nla_put_u8(rep_skb, TSN_QBV_ATTR_ENTRY_GC, gs) ||
-+ nla_put_u32(rep_skb, TSN_QBV_ATTR_ENTRY_TM, tp)) {
-+ nla_nest_cancel(rep_skb, qbv_table);
-+ return -EMSGSIZE;
-+ }
-+
-+ nla_nest_end(rep_skb, qbv_table);
-+ }
-+
-+ if (qbvstatus.oper.gate_states) {
-+ if (nla_put_u8(rep_skb, TSN_QBV_ATTR_CTRL_GATESTATE,
-+ qbvstatus.oper.gate_states))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.oper.cycle_time) {
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIME,
-+ qbvstatus.oper.cycle_time))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.oper.cycle_time_extension) {
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_CTRL_CYCLETIMEEXT,
-+ qbvstatus.oper.cycle_time_extension))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.oper.base_time) {
-+ if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CTRL_BASETIME,
-+ qbvstatus.oper.base_time))
-+ return -EMSGSIZE;
-+ }
-+
-+ kfree(qbvstatus.oper.control_list);
-+ } else {
-+ pr_info("tsn: error get operation list data.");
-+ }
-+
-+ nla_nest_end(rep_skb, qbvoperattr);
-+
-+ if (qbvstatus.config_change_time) {
-+ if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CONFIGCHANGETIME,
-+ qbvstatus.config_change_time))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.tick_granularity) {
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_GRANULARITY,
-+ qbvstatus.tick_granularity))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.current_time) {
-+ if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CURRENTTIME,
-+ qbvstatus.current_time))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.config_pending) {
-+ if (nla_put_flag(rep_skb, TSN_QBV_ATTR_CONFIGPENDING))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.config_change_error) {
-+ if (NLA_PUT_U64(rep_skb, TSN_QBV_ATTR_CONFIGCHANGEERROR,
-+ qbvstatus.config_change_error))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (qbvstatus.supported_list_max) {
-+ if (nla_put_u32(rep_skb, TSN_QBV_ATTR_LISTMAX,
-+ qbvstatus.supported_list_max))
-+ return -EMSGSIZE;
-+ }
-+
-+ nla_nest_end(rep_skb, qbv);
-+
-+ tsn_send_reply(rep_skb, info);
-+
-+ return ret;
-+}
-+
-+static int tsn_qbv_status_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME])
-+ cmd_qbv_status_get(info);
-+
-+ return 0;
-+}
-+
-+static int tsn_qbv_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME])
-+ cmd_qbv_get(info);
-+
-+ return 0;
-+}
-+
-+static int tsn_cbs_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *cbsa[TSN_CBS_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ int ret;
-+ u8 tc, bw;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_CBS]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_CBS];
-+
-+ if (!tsnops->cbs_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = NLA_PARSE_NESTED(cbsa, TSN_CBS_ATTR_MAX, na, cbs_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (!cbsa[TSN_CBS_ATTR_TC_INDEX]) {
-+ pr_err("tsn: no TSN_CBS_ATTR_TC_INDEX input\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+ tc = nla_get_u8(cbsa[TSN_CBS_ATTR_TC_INDEX]);
-+
-+ if (!cbsa[TSN_CBS_ATTR_BW]) {
-+ pr_err("tsn: no TSN_CBS_ATTR_BW input\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ bw = nla_get_u8(cbsa[TSN_CBS_ATTR_BW]);
-+ if (bw > 100) {
-+ pr_err("tsn: TSN_CBS_ATTR_BW isn't in the range of 0~100\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ ret = tsnops->cbs_set(netdev, tc, bw);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+ return 0;
-+}
-+
-+static int tsn_cbs_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na, *cbsattr;
-+ struct nlattr *cbsa[TSN_CBS_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct genlmsghdr *genlhdr;
-+ u8 tc;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_CBS]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (!tsnops->cbs_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_CBS];
-+ ret = NLA_PARSE_NESTED(cbsa, TSN_CBS_ATTR_MAX, na, cbs_policy);
-+ if (ret) {
-+ pr_err("tsn: parse value TSN_CBS_ATTR_MAX error.");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ /* Get status data from device */
-+ genlhdr = info->genlhdr;
-+
-+ /* Form netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
-+ NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ cbsattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_CBS);
-+ if (!cbsattr)
-+ return -EMSGSIZE;
-+
-+ if (!cbsa[TSN_CBS_ATTR_TC_INDEX]) {
-+ pr_err("tsn: must to specify the TSN_CBS_ATTR_TC_INDEX\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+ tc = nla_get_u8(cbsa[TSN_CBS_ATTR_TC_INDEX]);
-+
-+ ret = tsnops->cbs_get(netdev, tc);
-+ if (ret < 0) {
-+ pr_err("tsn: cbs_get return error\n");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ if (nla_put_u8(rep_skb, TSN_CBS_ATTR_BW, ret & 0XF))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, cbsattr);
-+ return tsn_send_reply(rep_skb, info);
-+}
-+
-+static int cmd_qbu_set(struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *qbua[TSN_QBU_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ int ret;
-+ u8 preemptible = 0;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_QBU]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_QBU];
-+
-+ ret = NLA_PARSE_NESTED(qbua, TSN_QBU_ATTR_MAX, na, qbu_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (qbua[TSN_QBU_ATTR_ADMIN_STATE])
-+ preemptible = nla_get_u8(qbua[TSN_QBU_ATTR_ADMIN_STATE]);
-+ else
-+ pr_info("No preemptible TSN_QBU_ATTR_ADMIN_STATE config!\n");
-+
-+ if (!tsnops->qbu_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -EINVAL;
-+ }
-+
-+ ret = tsnops->qbu_set(netdev, preemptible);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+ return 0;
-+}
-+
-+static int tsn_qbu_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME])
-+ return cmd_qbu_set(info);
-+
-+ return -1;
-+}
-+
-+static int cmd_qbu_get_status(struct genl_info *info)
-+{
-+ struct nlattr *qbuattr;
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_preempt_status pps;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ /* Get status data from device */
-+ genlhdr = info->genlhdr;
-+
-+ memset(&pps, 0, sizeof(struct tsn_preempt_status));
-+
-+ if (!tsnops->qbu_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = tsnops->qbu_get(netdev, &pps);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ /* Form netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ qbuattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_QBU);
-+ if (!qbuattr)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u8(rep_skb, TSN_QBU_ATTR_ADMIN_STATE, pps.admin_state) ||
-+ nla_put_u32(rep_skb,
-+ TSN_QBU_ATTR_HOLD_ADVANCE, pps.hold_advance) ||
-+ nla_put_u32(rep_skb,
-+ TSN_QBU_ATTR_RELEASE_ADVANCE, pps.release_advance))
-+ return -EMSGSIZE;
-+
-+ if (pps.preemption_active) {
-+ if (nla_put_flag(rep_skb, TSN_QBU_ATTR_ACTIVE))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (nla_put_u8(rep_skb, TSN_QBU_ATTR_HOLD_REQUEST, pps.hold_request))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, qbuattr);
-+
-+ return tsn_send_reply(rep_skb, info);
-+}
-+
-+static int tsn_qbu_get_status(struct sk_buff *skb, struct genl_info *info)
-+{
-+ if (info->attrs[TSN_ATTR_IFNAME])
-+ return cmd_qbu_get_status(info);
-+
-+ return -1;
-+}
-+
-+static int tsn_tsd_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *ntsd[TSN_TSD_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ struct tsn_tsd tsd;
-+ int ret;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ memset(&tsd, 0, sizeof(struct tsn_tsd));
-+
-+ if (!info->attrs[TSN_ATTR_TSD]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_TSD];
-+
-+ ret = NLA_PARSE_NESTED(ntsd, TSN_TSD_ATTR_MAX, na, tsd_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (!tsnops->tsd_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -EINVAL;
-+ }
-+
-+ if (nla_get_flag(ntsd[TSN_TSD_ATTR_DISABLE])) {
-+ tsd.enable = false;
-+ } else {
-+ if (ntsd[TSN_TSD_ATTR_PERIOD])
-+ tsd.period = nla_get_u32(ntsd[TSN_TSD_ATTR_PERIOD]);
-+
-+ if (!tsd.period) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (ntsd[TSN_TSD_ATTR_MAX_FRM_NUM])
-+ tsd.maxFrameNum =
-+ nla_get_u32(ntsd[TSN_TSD_ATTR_MAX_FRM_NUM]);
-+
-+ if (ntsd[TSN_TSD_ATTR_SYN_IMME])
-+ tsd.syn_flag = 2;
-+ else
-+ tsd.syn_flag = 1;
-+
-+ tsd.enable = true;
-+ }
-+
-+ ret = tsnops->tsd_set(netdev, &tsd);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+ return 0;
-+}
-+
-+static int tsn_tsd_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na, *tsdattr;
-+ struct nlattr *tsda[TSN_TSD_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_tsd_status tts;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_TSD]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ if (!tsnops->tsd_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = tsnops->tsd_get(netdev, &tts);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_TSD];
-+
-+ ret = NLA_PARSE_NESTED(tsda, TSN_TSD_ATTR_MAX,
-+ na, tsd_policy);
-+ if (ret) {
-+ pr_err("tsn: parse value TSN_TSD_ATTR_MAX error.");
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ /* Get status data from device */
-+ genlhdr = info->genlhdr;
-+
-+ /* Form netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd, &rep_skb,
-+ NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ tsdattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_TSD);
-+ if (!tsdattr)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u32(rep_skb, TSN_TSD_ATTR_PERIOD, tts.period) ||
-+ nla_put_u32(rep_skb, TSN_TSD_ATTR_MAX_FRM_NUM, tts.maxFrameNum) ||
-+ nla_put_u32(rep_skb, TSN_TSD_ATTR_CYCLE_NUM, tts.cycleNum) ||
-+ nla_put_u32(rep_skb, TSN_TSD_ATTR_LOSS_STEPS, tts.loss_steps) ||
-+ nla_put_u32(rep_skb, TSN_TSD_ATTR_MAX_FRM_NUM, tts.maxFrameNum))
-+ return -EMSGSIZE;
-+
-+ if (!tts.enable) {
-+ if (nla_put_flag(rep_skb, TSN_TSD_ATTR_DISABLE))
-+ return -EMSGSIZE;
-+ } else {
-+ if (nla_put_flag(rep_skb, TSN_TSD_ATTR_ENABLE))
-+ return -EMSGSIZE;
-+ }
-+
-+ if (tts.flag == 2)
-+ if (nla_put_flag(rep_skb, TSN_TSD_ATTR_SYN_IMME))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, tsdattr);
-+ return tsn_send_reply(rep_skb, info);
-+}
-+
-+static int tsn_ct_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *cta[TSN_CT_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ int ret;
-+ u8 queue_stat;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_CT]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_CT];
-+
-+ if (!tsnops->ct_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = NLA_PARSE_NESTED(cta, TSN_CT_ATTR_MAX,
-+ na, ct_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ queue_stat = nla_get_u8(cta[TSN_CT_ATTR_QUEUE_STATE]);
-+
-+ ret = tsnops->ct_set(netdev, queue_stat);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+ return 0;
-+}
-+
-+static int tsn_cbgen_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *cbgena[TSN_CBGEN_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ int ret;
-+ u32 index;
-+ struct tsn_seq_gen_conf sg_conf;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_CBGEN]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_CBGEN];
-+
-+ if (!tsnops->cbgen_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = NLA_PARSE_NESTED(cbgena, TSN_CBGEN_ATTR_MAX,
-+ na, cbgen_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ index = nla_get_u32(cbgena[TSN_CBGEN_ATTR_INDEX]);
-+
-+ memset(&sg_conf, 0, sizeof(struct tsn_seq_gen_conf));
-+ sg_conf.iport_mask = nla_get_u8(cbgena[TSN_CBGEN_ATTR_PORT_MASK]);
-+ sg_conf.split_mask = nla_get_u8(cbgena[TSN_CBGEN_ATTR_SPLIT_MASK]);
-+ sg_conf.seq_len = nla_get_u8(cbgena[TSN_CBGEN_ATTR_SEQ_LEN]);
-+ sg_conf.seq_num = nla_get_u32(cbgena[TSN_CBGEN_ATTR_SEQ_NUM]);
-+
-+ ret = tsnops->cbgen_set(netdev, index, &sg_conf);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+ return 0;
-+}
-+
-+static int tsn_cbrec_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *cbreca[TSN_CBREC_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ int ret;
-+ u32 index;
-+ struct tsn_seq_rec_conf sr_conf;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_CBREC]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_CBREC];
-+
-+ if (!tsnops->cbrec_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = NLA_PARSE_NESTED(cbreca, TSN_CBREC_ATTR_MAX,
-+ na, cbrec_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ index = nla_get_u32(cbreca[TSN_CBREC_ATTR_INDEX]);
-+
-+ memset(&sr_conf, 0, sizeof(struct tsn_seq_rec_conf));
-+ sr_conf.seq_len = nla_get_u8(cbreca[TSN_CBREC_ATTR_SEQ_LEN]);
-+ sr_conf.his_len = nla_get_u8(cbreca[TSN_CBREC_ATTR_HIS_LEN]);
-+ sr_conf.rtag_pop_en = nla_get_flag(cbreca[TSN_CBREC_ATTR_TAG_POP_EN]);
-+
-+ ret = tsnops->cbrec_set(netdev, index, &sr_conf);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+ return 0;
-+}
-+
-+static int tsn_cbstatus_get(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *cba[TSN_CBSTAT_ATTR_MAX + 1];
-+ struct nlattr *cbattr;
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ struct sk_buff *rep_skb;
-+ int ret;
-+ unsigned int index;
-+ struct genlmsghdr *genlhdr;
-+ struct tsn_cb_status cbstat;
-+ struct tsn_port *port;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ /* Get status data from device */
-+ genlhdr = info->genlhdr;
-+
-+ memset(&cbstat, 0, sizeof(struct tsn_cb_status));
-+
-+ if (!tsnops->cb_get) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_CBSTAT];
-+ ret = NLA_PARSE_NESTED(cba, TSN_CBSTAT_ATTR_MAX,
-+ na, cbstat_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ index = nla_get_u32(cba[TSN_CBSTAT_ATTR_INDEX]);
-+
-+ ret = tsnops->cb_get(netdev, index, &cbstat);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ /* Form netlink reply data */
-+ ret = tsn_prepare_reply(info, genlhdr->cmd,
-+ &rep_skb, NLMSG_ALIGN(MAX_ATTR_SIZE));
-+ if (ret < 0)
-+ return ret;
-+
-+ if (nla_put_string(rep_skb, TSN_ATTR_IFNAME, netdev->name))
-+ return -EMSGSIZE;
-+
-+ cbattr = nla_nest_start_noflag(rep_skb, TSN_ATTR_CBSTAT);
-+ if (!cbattr)
-+ return -EMSGSIZE;
-+
-+ if (nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_GEN_REC, cbstat.gen_rec) ||
-+ nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_ERR, cbstat.err) ||
-+ nla_put_u32(rep_skb, TSN_CBSTAT_ATTR_SEQ_NUM,
-+ cbstat.seq_num) ||
-+ nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_SEQ_LEN, cbstat.seq_len) ||
-+ nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_SPLIT_MASK,
-+ cbstat.split_mask) ||
-+ nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_PORT_MASK,
-+ cbstat.iport_mask) ||
-+ nla_put_u8(rep_skb, TSN_CBSTAT_ATTR_HIS_LEN, cbstat.his_len) ||
-+ nla_put_u32(rep_skb, TSN_CBSTAT_ATTR_SEQ_HIS,
-+ cbstat.seq_his))
-+ return -EMSGSIZE;
-+
-+ nla_nest_end(rep_skb, cbattr);
-+
-+ return tsn_send_reply(rep_skb, info);
-+}
-+
-+static int tsn_dscp_set(struct sk_buff *skb, struct genl_info *info)
-+{
-+ struct nlattr *na;
-+ struct nlattr *dscpa[TSN_DSCP_ATTR_MAX + 1];
-+ struct net_device *netdev;
-+ const struct tsn_ops *tsnops;
-+ int ret;
-+ bool enable = 0;
-+ struct tsn_port *port;
-+ int dscp_ix;
-+ struct tsn_qos_switch_dscp_conf dscp_conf;
-+
-+ port = tsn_init_check(info, &netdev);
-+ if (!port)
-+ return -ENODEV;
-+
-+ tsnops = port->tsnops;
-+
-+ if (!info->attrs[TSN_ATTR_DSCP]) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ na = info->attrs[TSN_ATTR_DSCP];
-+
-+ if (!tsnops->dscp_set) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EPERM);
-+ return -1;
-+ }
-+
-+ ret = NLA_PARSE_NESTED(dscpa, TSN_DSCP_ATTR_MAX,
-+ na, dscp_policy);
-+ if (ret) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ enable = 1;
-+ if (dscpa[TSN_DSCP_ATTR_DISABLE])
-+ enable = 0;
-+ dscp_ix = nla_get_u32(dscpa[TSN_DSCP_ATTR_INDEX]);
-+ dscp_conf.cos = nla_get_u32(dscpa[TSN_DSCP_ATTR_COS]);
-+ dscp_conf.dpl = nla_get_u32(dscpa[TSN_DSCP_ATTR_DPL]);
-+ ret = tsnops->dscp_set(netdev, enable, dscp_ix, &dscp_conf);
-+ if (ret < 0) {
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, ret);
-+ return ret;
-+ }
-+
-+ tsn_simple_reply(info, TSN_CMD_REPLY,
-+ netdev->name, 0);
-+
-+ return 0;
-+}
-+
-+static const struct genl_ops tsnnl_ops[] = {
-+ {
-+ .cmd = TSN_CMD_ECHO,
-+ .doit = tsn_echo_cmd,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CAP_GET,
-+ .doit = tsn_cap_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QBV_SET,
-+ .doit = tsn_qbv_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QBV_GET,
-+ .doit = tsn_qbv_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QBV_GET_STATUS,
-+ .doit = tsn_qbv_status_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CB_STREAMID_SET,
-+ .doit = tsn_cb_streamid_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CB_STREAMID_GET,
-+ .doit = tsn_cb_streamid_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CB_STREAMID_GET_COUNTS,
-+ .doit = tsn_cb_streamid_counters_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_CAP_GET,
-+ .doit = tsn_qci_cap_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_SFI_SET,
-+ .doit = tsn_qci_sfi_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_SFI_GET,
-+ .doit = tsn_qci_sfi_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_SFI_GET_COUNTS,
-+ .doit = tsn_qci_sfi_counters_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_SGI_SET,
-+ .doit = tsn_qci_sgi_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_SGI_GET,
-+ .doit = tsn_qci_sgi_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_SGI_GET_STATUS,
-+ .doit = tsn_qci_sgi_status_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_FMI_SET,
-+ .doit = tsn_qci_fmi_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QCI_FMI_GET,
-+ .doit = tsn_qci_fmi_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CBS_SET,
-+ .doit = tsn_cbs_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CBS_GET,
-+ .doit = tsn_cbs_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QBU_SET,
-+ .doit = tsn_qbu_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_QBU_GET_STATUS,
-+ .doit = tsn_qbu_get_status,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_TSD_SET,
-+ .doit = tsn_tsd_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_TSD_GET,
-+ .doit = tsn_tsd_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CT_SET,
-+ .doit = tsn_ct_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CBGEN_SET,
-+ .doit = tsn_cbgen_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CBREC_SET,
-+ .doit = tsn_cbrec_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_CBSTAT_GET,
-+ .doit = tsn_cbstatus_get,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+ {
-+ .cmd = TSN_CMD_DSCP_SET,
-+ .doit = tsn_dscp_set,
-+ .flags = GENL_ADMIN_PERM,
-+ },
-+};
-+
-+static const struct genl_multicast_group tsn_mcgrps[] = {
-+ [TSN_MCGRP_QBV] = { .name = TSN_MULTICAST_GROUP_QBV},
-+ [TSN_MCGRP_QCI] = { .name = TSN_MULTICAST_GROUP_QCI},
-+};
-+
-+static struct genl_family tsn_family = {
-+ .name = TSN_GENL_NAME,
-+ .version = TSN_GENL_VERSION,
-+ .maxattr = TSN_CMD_ATTR_MAX,
-+ .module = THIS_MODULE,
-+ .netnsok = true,
-+ .ops = tsnnl_ops,
-+ .n_ops = ARRAY_SIZE(tsnnl_ops),
-+ .mcgrps = tsn_mcgrps,
-+ .n_mcgrps = ARRAY_SIZE(tsn_mcgrps),
-+};
-+
-+int tsn_port_register(struct net_device *netdev,
-+ struct tsn_ops *tsnops, u16 groupid)
-+{
-+ struct tsn_port *port;
-+
-+ if (list_empty(&port_list)) {
-+ INIT_LIST_HEAD(&port_list);
-+ } else {
-+ list_for_each_entry(port, &port_list, list) {
-+ if (port->netdev == netdev) {
-+ pr_info("TSN device already registered!\n");
-+ return -1;
-+ }
-+ }
-+ }
-+
-+ port = kzalloc(sizeof(*port), GFP_KERNEL);
-+ if (!port)
-+ return -1;
-+
-+ port->netdev = netdev;
-+ port->groupid = groupid;
-+ port->tsnops = tsnops;
-+ port->nd.dev = netdev;
-+
-+ if (groupid < GROUP_OFFSET_SWITCH)
-+ port->type = TSN_ENDPOINT;
-+ else
-+ port->type = TSN_SWITCH;
-+
-+ list_add_tail(&port->list, &port_list);
-+
-+ if (tsnops && tsnops->device_init)
-+ port->tsnops->device_init(netdev);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(tsn_port_register);
-+
-+void tsn_port_unregister(struct net_device *netdev)
-+{
-+ struct tsn_port *p;
-+
-+ list_for_each_entry(p, &port_list, list) {
-+ if (!p || !p->netdev)
-+ continue;
-+ if (p->netdev == netdev) {
-+ if (p->tsnops->device_deinit)
-+ p->tsnops->device_deinit(netdev);
-+ list_del(&p->list);
-+ kfree(p);
-+ break;
-+ }
-+ }
-+}
-+EXPORT_SYMBOL(tsn_port_unregister);
-+
-+static int tsn_multicast_to_user(unsigned long event,
-+ struct tsn_notifier_info *tsn_info)
-+{
-+ struct sk_buff *skb;
-+ struct genlmsghdr *nlh;
-+ int res;
-+ struct tsn_qbv_conf *qbvdata;
-+
-+ /* If new attributes are added, please revisit this allocation */
-+ skb = genlmsg_new(sizeof(*tsn_info), GFP_KERNEL);
-+ if (!skb) {
-+ pr_err("Allocation failure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ switch (event) {
-+ case TSN_QBV_CONFIGCHANGETIME_ARRIVE:
-+ nlh = genlmsg_put(skb, 0, 1, &tsn_family,
-+ GFP_KERNEL, TSN_CMD_QBV_SET);
-+ qbvdata = &tsn_info->ntdata.qbv_notify;
-+ res = NLA_PUT_U64(skb, TSN_QBV_ATTR_CTRL_BASETIME,
-+ qbvdata->admin.base_time);
-+
-+ if (res) {
-+ pr_err("put data failure!\n");
-+ goto done;
-+ }
-+
-+ res = nla_put_u32(skb, TSN_QBV_ATTR_CTRL_CYCLETIME,
-+ qbvdata->admin.cycle_time);
-+ if (res) {
-+ pr_err("put data failure!\n");
-+ goto done;
-+ }
-+
-+ if (qbvdata->gate_enabled)
-+ res = nla_put_flag(skb, TSN_QBV_ATTR_ENABLE +
-+ TSN_QBV_ATTR_CTRL_MAX);
-+ else
-+ res = nla_put_flag(skb, TSN_QBV_ATTR_DISABLE +
-+ TSN_QBV_ATTR_CTRL_MAX);
-+ if (res) {
-+ pr_err("put data failure!\n");
-+ goto done;
-+ }
-+
-+ res = nla_put_u32(skb, TSN_QBV_ATTR_CTRL_UNSPEC,
-+ tsn_info->dev->ifindex);
-+ if (res) {
-+ pr_err("put data failure!\n");
-+ goto done;
-+ }
-+
-+ break;
-+ default:
-+ pr_info("event not supportted!\n");
-+ break;
-+ }
-+
-+ (void)genlmsg_end(skb, nlh);
-+
-+ res = genlmsg_multicast_allns(&tsn_family, skb, 0,
-+ TSN_MCGRP_QBV, GFP_KERNEL);
-+ skb = NULL;
-+ if (res && res != -ESRCH) {
-+ pr_err("genlmsg_multicast_allns error: %d\n", res);
-+ goto done;
-+ }
-+
-+ if (res == -ESRCH)
-+ res = 0;
-+
-+done:
-+ if (skb) {
-+ nlmsg_free(skb);
-+ skb = NULL;
-+ }
-+
-+ return res;
-+}
-+
-+/* called with RTNL or RCU */
-+static int tsn_event(struct notifier_block *unused,
-+ unsigned long event, void *ptr)
-+{
-+ struct tsn_notifier_info *tsn_info;
-+ int err = NOTIFY_DONE;
-+
-+ switch (event) {
-+ case TSN_QBV_CONFIGCHANGETIME_ARRIVE:
-+ tsn_info = ptr;
-+ err = tsn_multicast_to_user(event, tsn_info);
-+ if (err) {
-+ err = notifier_from_errno(err);
-+ break;
-+ }
-+ break;
-+ default:
-+ pr_info("event not supportted!\n");
-+ break;
-+ }
-+
-+ return err;
-+}
-+
-+static struct notifier_block tsn_notifier = {
-+ .notifier_call = tsn_event,
-+};
-+
-+static int __init tsn_genetlink_init(void)
-+{
-+ int ret;
-+
-+ pr_info("tsn generic netlink module v%d init...\n", TSN_GENL_VERSION);
-+
-+ ret = genl_register_family(&tsn_family);
-+
-+ if (ret != 0) {
-+ pr_info("failed to init tsn generic netlink example module\n");
-+ return ret;
-+ }
-+
-+ register_tsn_notifier(&tsn_notifier);
-+
-+ return 0;
-+}
-+
-+static void __exit tsn_genetlink_exit(void)
-+{
-+ int ret;
-+
-+ ret = genl_unregister_family(&tsn_family);
-+ if (ret != 0)
-+ pr_info("failed to unregister family:%i\n", ret);
-+
-+ unregister_tsn_notifier(&tsn_notifier);
-+}
-+
-+module_init(tsn_genetlink_init);
-+module_exit(tsn_genetlink_exit);
-+MODULE_LICENSE("GPL");