/* * Xilinx FPGA Xilinx TSN QCI Controller module. * * Copyright (c) 2017 Xilinx Pvt., Ltd * * Author: Saurabh Sengar * * 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 SMC_MODE_SHIFT 28 #define SMC_CBR_MASK 0x00FFFFFF #define SMC_EBR_MASK 0x00FFFFFF #define IN_PORTID_MASK 0x3 #define IN_PORT_SHIFT 14 #define MAX_FR_SIZE_MASK 0x00000FFF #define GATE_ID_SHIFT 24 #define METER_ID_SHIFT 8 #define EN_METER_SHIFT 6 #define ALLOW_STREM_SHIFT 5 #define EN_PSFP_SHIFT 4 #define WR_OP_TYPE_MASK 0x3 #define WR_OP_TYPE_SHIFT 2 #define OP_TYPE_SHIFT 1 #define PSFP_EN_CONTROL_MASK 0x1 /** * psfp_control - Configure thr control for PSFP * @data: Value to be programmed */ void psfp_control(struct psfp_config data) { u32 mask; u32 timeout = 20000; mask = data.gate_id << GATE_ID_SHIFT; mask |= data.meter_id << METER_ID_SHIFT; mask |= data.en_meter << EN_METER_SHIFT; mask |= data.allow_stream << ALLOW_STREM_SHIFT; mask |= data.en_psfp << EN_PSFP_SHIFT; mask |= (data.wr_op_type & WR_OP_TYPE_MASK) << WR_OP_TYPE_SHIFT; mask |= data.op_type << OP_TYPE_SHIFT; mask |= PSFP_EN_CONTROL_MASK; axienet_iow(&lp, PSFP_CONTROL_OFFSET, mask); /* wait for write to complete */ while ((axienet_ior(&lp, PSFP_CONTROL_OFFSET) & PSFP_EN_CONTROL_MASK) && timeout) timeout--; if (!timeout) pr_warn("PSFP control write took longer time!!"); } /** * get_stream_filter_config - Get Stream Filter Configuration * @data: Value returned */ void get_stream_filter_config(struct stream_filter *data) { u32 reg_val; reg_val = axienet_ior(&lp, STREAM_FILTER_CONFIG_OFFSET); data->max_fr_size = reg_val & MAX_FR_SIZE_MASK; data->in_pid = (reg_val >> IN_PORT_SHIFT) & IN_PORTID_MASK; } /** * config_stream_filter - Configure Stream Filter Configuration * @data: Value to be programmed */ void config_stream_filter(struct stream_filter data) { u32 mask; mask = ((data.in_pid & IN_PORTID_MASK) << IN_PORT_SHIFT) | (data.max_fr_size & MAX_FR_SIZE_MASK); axienet_iow(&lp, STREAM_FILTER_CONFIG_OFFSET, mask); } /** * get_meter_reg - Read Stream Meter Configuration registers value * @data: Value returned */ void get_meter_reg(struct meter_config *data) { u32 conf_r4; data->cir = axienet_ior(&lp, STREAM_METER_CIR_OFFSET); data->eir = axienet_ior(&lp, STREAM_METER_EIR_OFFSET); data->cbr = axienet_ior(&lp, STREAM_METER_CBR_OFFSET) & SMC_CBR_MASK; conf_r4 = axienet_ior(&lp, STREAM_METER_EBR_OFFSET); data->ebr = conf_r4 & SMC_EBR_MASK; data->mode = (conf_r4 & 0xF0000000) >> SMC_MODE_SHIFT; } /** * program_meter_reg - configure Stream Meter Configuration registers * @data: Value to be programmed */ void program_meter_reg(struct meter_config data) { u32 conf_r4; axienet_iow(&lp, STREAM_METER_CIR_OFFSET, data.cir); axienet_iow(&lp, STREAM_METER_EIR_OFFSET, data.eir); axienet_iow(&lp, STREAM_METER_CBR_OFFSET, data.cbr & SMC_CBR_MASK); conf_r4 = (data.ebr & SMC_EBR_MASK) | (data.mode << SMC_MODE_SHIFT); axienet_iow(&lp, STREAM_METER_EBR_OFFSET, conf_r4); } /** * get_psfp_static_counter - get memory static counters value * @data : return value, containing counter value */ void get_psfp_static_counter(struct psfp_static_counter *data) { int offset = (data->num) * 8; data->psfp_fr_count.lsb = axienet_ior(&lp, TOTAL_PSFP_FRAMES_OFFSET + offset); data->psfp_fr_count.msb = axienet_ior(&lp, TOTAL_PSFP_FRAMES_OFFSET + offset + 0x4); data->err_filter_ins_port.lsb = axienet_ior(&lp, FLTR_INGS_PORT_ERR_OFFSET + offset); data->err_filter_ins_port.msb = axienet_ior(&lp, FLTR_INGS_PORT_ERR_OFFSET + offset + 0x4); data->err_filtr_sdu.lsb = axienet_ior(&lp, FLTR_STDU_ERR_OFFSET + offset); data->err_filtr_sdu.msb = axienet_ior(&lp, FLTR_STDU_ERR_OFFSET + offset + 0x4); data->err_meter.lsb = axienet_ior(&lp, METER_ERR_OFFSET + offset); data->err_meter.msb = axienet_ior(&lp, METER_ERR_OFFSET + offset + 0x4); }