]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
drivers: net: ethernet: TSN: Adding TSN switch CB APIs
authorSaurabh Sengar <saurabh.singh@xilinx.com>
Thu, 20 Apr 2017 13:46:06 +0000 (19:16 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Fri, 12 May 2017 08:00:05 +0000 (10:00 +0200)
Adding 802.1CB - Frame Replication and Elimination for Reliability
APIs in existing TSN switch driver.

Signed-off-by: Saurabh Sengar <saurabhs@xilinx.com>
Acked-by: Syed Syed <syeds@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/net/ethernet/xilinx/xilinx_tsn_cb.c [new file with mode: 0644]

diff --git a/drivers/net/ethernet/xilinx/xilinx_tsn_cb.c b/drivers/net/ethernet/xilinx/xilinx_tsn_cb.c
new file mode 100644 (file)
index 0000000..044c285
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Xilinx FPGA Xilinx TSN QCI Controller module.
+ *
+ * Copyright (c) 2017 Xilinx Pvt., Ltd
+ *
+ * Author: Saurabh Sengar <saurabhs@xilinx.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include "xilinx_tsn_switch.h"
+
+#define IN_PORTID_MASK                         0x3
+#define IN_PORTID_SHIFT                                24
+#define MAX_SEQID_MASK                         0x0000FFFF
+
+#define SEQ_REC_HIST_LEN_MASK                  0x000000FF
+#define SEQ_REC_HIST_LEN_SHIFT                 16
+#define SPLIT_STREAM_INPORTID_SHIFT            12
+#define SPLIT_STREAM_INPORTID_MASK             0x3
+#define SPLIT_STREAM_VLANID_MASK               0x00000FFF
+
+#define GATE_ID_SHIFT                          24
+#define MEMBER_ID_SHIFT                                8
+#define SEQ_RESET_SHIFT                                7
+#define REC_TIMEOUT_SHIFT                      6
+#define GATE_STATE_SHIFT                       5
+#define FRER_VALID_SHIFT                       4
+#define WR_OP_TYPE_SHIFT                       2
+#define OP_TYPE_SHIFT                          1
+#define WR_OP_TYPE_MASK                                0x3
+#define FRER_EN_CONTROL_MASK                   0x1
+
+/**
+ * frer_control - Configure thr control for frer
+ * @data:      Value to be programmed
+ */
+void frer_control(struct frer_ctrl data)
+{
+       u32 mask = 0;
+
+       mask = data.gate_id << GATE_ID_SHIFT;
+       mask |= data.memb_id << MEMBER_ID_SHIFT;
+       mask |= data.seq_reset << SEQ_RESET_SHIFT;
+       mask |= data.gate_state << GATE_STATE_SHIFT;
+       mask |= data.rcvry_tmout << REC_TIMEOUT_SHIFT;
+       mask |= data.frer_valid << FRER_VALID_SHIFT;
+       mask |= (data.wr_op_type & WR_OP_TYPE_MASK) << WR_OP_TYPE_SHIFT;
+       mask |= data.op_type << OP_TYPE_SHIFT;
+       mask |= FRER_EN_CONTROL_MASK;
+
+       axienet_iow(&lp, FRER_CONTROL_OFFSET, mask);
+
+       /* wait for write to complete */
+       while ((axienet_ior(&lp, FRER_CONTROL_OFFSET) & FRER_EN_CONTROL_MASK))
+               ;
+}
+
+/**
+ * get_ingress_filter_config -  Get Ingress Filter Configuration
+ * @data:      Value returned
+ */
+void get_ingress_filter_config(struct in_fltr *data)
+{
+       u32 reg_val = 0;
+
+       reg_val = axienet_ior(&lp, INGRESS_FILTER_OFFSET);
+
+       data->max_seq_id = reg_val & MAX_SEQID_MASK;
+       data->in_port_id = (reg_val >> IN_PORTID_SHIFT) & IN_PORTID_MASK;
+}
+
+/**
+ * config_stream_filter -  Configure Ingress Filter Configuration
+ * @data:      Value to be programmed
+ */
+void config_ingress_filter(struct in_fltr data)
+{
+       u32 mask = 0;
+
+       mask = ((data.in_port_id & IN_PORTID_MASK) << IN_PORTID_SHIFT) |
+                                       (data.max_seq_id & MAX_SEQID_MASK);
+       axienet_iow(&lp, INGRESS_FILTER_OFFSET, mask);
+}
+
+/**
+ * get_member_reg -  Read frer member Configuration registers value
+ * @data:      Value returned
+ */
+void get_member_reg(struct frer_memb_config *data)
+{
+       u32 conf_r1 = 0;
+
+       conf_r1 = axienet_ior(&lp, FRER_CONFIG_REG1);
+       data->rem_ticks = axienet_ior(&lp, FRER_CONFIG_REG2);
+
+       data->seq_rec_hist_len = (conf_r1 >> SEQ_REC_HIST_LEN_SHIFT)
+                                               & SEQ_REC_HIST_LEN_MASK;
+       data->split_strm_egport_id = (conf_r1 >> SPLIT_STREAM_INPORTID_SHIFT)
+                                               & SPLIT_STREAM_INPORTID_MASK;
+       data->split_strm_vlan_id = conf_r1 & SPLIT_STREAM_VLANID_MASK;
+}
+
+/**
+ * program_member_reg -  configure frer member Configuration registers
+ * @data:      Value to be programmed
+ */
+void program_member_reg(struct frer_memb_config data)
+{
+       u32 conf_r1 = 0;
+
+       conf_r1 = (data.seq_rec_hist_len & SEQ_REC_HIST_LEN_MASK)
+                                               << SEQ_REC_HIST_LEN_SHIFT;
+       conf_r1 = conf_r1 | ((data.split_strm_egport_id
+                                       & SPLIT_STREAM_INPORTID_MASK)
+                                       << SPLIT_STREAM_INPORTID_SHIFT);
+       conf_r1 = conf_r1 | (data.split_strm_vlan_id
+                                       & SPLIT_STREAM_VLANID_MASK);
+
+       axienet_iow(&lp, FRER_CONFIG_REG1, conf_r1);
+       axienet_iow(&lp, FRER_CONFIG_REG2, data.rem_ticks);
+}
+
+/**
+ * get_frer_static_counter -  get frer static counters value
+ * @data:      return value, containing counter value
+ */
+void get_frer_static_counter(struct frer_static_counter *data)
+{
+       int offset = (data->num) * 8;
+
+       data->frer_fr_count.lsb = axienet_ior(&lp, TOTAL_FRER_FRAMES_OFFSET +
+                                                                       offset);
+       data->frer_fr_count.msb = axienet_ior(&lp, TOTAL_FRER_FRAMES_OFFSET +
+                                                               offset + 0x4);
+
+       data->disc_frames_in_portid.lsb = axienet_ior(&lp,
+                               FRER_DISCARD_INGS_FLTR_OFFSET + offset);
+       data->disc_frames_in_portid.msb = axienet_ior(&lp,
+                               FRER_DISCARD_INGS_FLTR_OFFSET + offset + 0x4);
+
+       data->pass_frames_ind_recv.lsb = axienet_ior(&lp,
+                               FRER_PASS_FRAMES_INDV_OFFSET + offset);
+       data->pass_frames_ind_recv.msb = axienet_ior(&lp,
+                               FRER_PASS_FRAMES_INDV_OFFSET + offset + 0x4);
+
+       data->disc_frames_ind_recv.lsb = axienet_ior(&lp,
+                               FRER_DISCARD_FRAMES_INDV_OFFSET + offset);
+       data->disc_frames_ind_recv.msb = axienet_ior(&lp,
+                               FRER_DISCARD_FRAMES_INDV_OFFSET + offset + 0x4);
+
+       data->pass_frames_seq_recv.lsb = axienet_ior(&lp,
+                               FRER_PASS_FRAMES_SEQ_OFFSET + offset);
+       data->pass_frames_seq_recv.msb = axienet_ior(&lp,
+                               FRER_PASS_FRAMES_SEQ_OFFSET + offset + 0x4);
+
+       data->disc_frames_seq_recv.lsb = axienet_ior(&lp,
+                               FRER_DISCARD_FRAMES_SEQ_OFFSET + offset);
+       data->disc_frames_seq_recv.msb = axienet_ior(&lp,
+                               FRER_DISCARD_FRAMES_SEQ_OFFSET + offset + 0x4);
+
+       data->rogue_frames_seq_recv.lsb = axienet_ior(&lp,
+                               FRER_ROGUE_FRAMES_SEQ_OFFSET + offset);
+       data->rogue_frames_seq_recv.msb = axienet_ior(&lp,
+                               FRER_ROGUE_FRAMES_SEQ_OFFSET + offset + 0x4);
+
+       data->seq_recv_rst.lsb = axienet_ior(&lp,
+                               SEQ_RECV_RESETS_OFFSET + offset);
+       data->seq_recv_rst.msb = axienet_ior(&lp,
+                               SEQ_RECV_RESETS_OFFSET + offset + 0x4);
+}