| /* | 
 |  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved. | 
 |  * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. | 
 |  * All rights reserved. | 
 |  * | 
 |  * This software is available to you under a choice of one of two | 
 |  * licenses.  You may choose to be licensed under the terms of the GNU | 
 |  * General Public License (GPL) Version 2, available from the file | 
 |  * COPYING in the main directory of this source tree, or the | 
 |  * OpenIB.org BSD license below: | 
 |  * | 
 |  *     Redistribution and use in source and binary forms, with or | 
 |  *     without modification, are permitted provided that the following | 
 |  *     conditions are met: | 
 |  * | 
 |  *      - Redistributions of source code must retain the above | 
 |  *        copyright notice, this list of conditions and the following | 
 |  *        disclaimer. | 
 |  * | 
 |  *      - Redistributions in binary form must reproduce the above | 
 |  *        copyright notice, this list of conditions and the following | 
 |  *        disclaimer in the documentation and/or other materials | 
 |  *        provided with the distribution. | 
 |  * | 
 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 
 |  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 
 |  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 
 |  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | 
 |  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | 
 |  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | 
 |  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 
 |  * SOFTWARE. | 
 |  */ | 
 |  | 
 | #include <linux_compat.h> | 
 | #include "fw_qos.h" | 
 | #include "fw.h" | 
 |  | 
 | enum { | 
 | 	/* allocate vpp opcode modifiers */ | 
 | 	MLX4_ALLOCATE_VPP_ALLOCATE	= 0x0, | 
 | 	MLX4_ALLOCATE_VPP_QUERY		= 0x1 | 
 | }; | 
 |  | 
 | enum { | 
 | 	/* set vport qos opcode modifiers */ | 
 | 	MLX4_SET_VPORT_QOS_SET		= 0x0, | 
 | 	MLX4_SET_VPORT_QOS_QUERY	= 0x1 | 
 | }; | 
 |  | 
 | struct mlx4_set_port_prio2tc_context { | 
 | 	uint8_t prio2tc[4]; | 
 | }; | 
 |  | 
 | struct mlx4_port_scheduler_tc_cfg_be { | 
 | 	__be16 pg; | 
 | 	__be16 bw_precentage; | 
 | 	__be16 max_bw_units; /* 3-100Mbps, 4-1Gbps, other values - reserved */ | 
 | 	__be16 max_bw_value; | 
 | }; | 
 |  | 
 | struct mlx4_set_port_scheduler_context { | 
 | 	struct mlx4_port_scheduler_tc_cfg_be tc[MLX4_NUM_TC]; | 
 | }; | 
 |  | 
 | /* Granular Qos (per VF) section */ | 
 | struct mlx4_alloc_vpp_param { | 
 | 	__be32 availible_vpp; | 
 | 	__be32 vpp_p_up[MLX4_NUM_UP]; | 
 | }; | 
 |  | 
 | struct mlx4_prio_qos_param { | 
 | 	__be32 bw_share; | 
 | 	__be32 max_avg_bw; | 
 | 	__be32 reserved; | 
 | 	__be32 enable; | 
 | 	__be32 reserved1[4]; | 
 | }; | 
 |  | 
 | struct mlx4_set_vport_context { | 
 | 	__be32 reserved[8]; | 
 | 	struct mlx4_prio_qos_param qos_p_up[MLX4_NUM_UP]; | 
 | }; | 
 |  | 
 | int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, uint8_t port, | 
 | 			  uint8_t *prio2tc) | 
 | { | 
 | 	struct mlx4_cmd_mailbox *mailbox; | 
 | 	struct mlx4_set_port_prio2tc_context *context; | 
 | 	int err; | 
 | 	uint32_t in_mod; | 
 | 	int i; | 
 |  | 
 | 	mailbox = mlx4_alloc_cmd_mailbox(dev); | 
 | 	if (IS_ERR(mailbox)) | 
 | 		return PTR_ERR(mailbox); | 
 |  | 
 | 	context = mailbox->buf; | 
 |  | 
 | 	for (i = 0; i < MLX4_NUM_UP; i += 2) | 
 | 		context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; | 
 |  | 
 | 	in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; | 
 | 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, | 
 | 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); | 
 |  | 
 | 	mlx4_free_cmd_mailbox(dev, mailbox); | 
 | 	return err; | 
 | } | 
 | EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); | 
 |  | 
 | int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, uint8_t port, | 
 | 			    uint8_t *tc_tx_bw, | 
 | 			    uint8_t *pg, uint16_t *ratelimit) | 
 | { | 
 | 	struct mlx4_cmd_mailbox *mailbox; | 
 | 	struct mlx4_set_port_scheduler_context *context; | 
 | 	int err; | 
 | 	uint32_t in_mod; | 
 | 	int i; | 
 |  | 
 | 	mailbox = mlx4_alloc_cmd_mailbox(dev); | 
 | 	if (IS_ERR(mailbox)) | 
 | 		return PTR_ERR(mailbox); | 
 |  | 
 | 	context = mailbox->buf; | 
 |  | 
 | 	for (i = 0; i < MLX4_NUM_TC; i++) { | 
 | 		struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; | 
 | 		uint16_t r; | 
 |  | 
 | 		if (ratelimit && ratelimit[i]) { | 
 | 			if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { | 
 | 				r = ratelimit[i]; | 
 | 				tc->max_bw_units = | 
 | 					cpu_to_be16(MLX4_RATELIMIT_100M_UNITS); | 
 | 			} else { | 
 | 				r = ratelimit[i] / 10; | 
 | 				tc->max_bw_units = | 
 | 					cpu_to_be16(MLX4_RATELIMIT_1G_UNITS); | 
 | 			} | 
 | 			tc->max_bw_value = cpu_to_be16(r); | 
 | 		} else { | 
 | 			tc->max_bw_value = cpu_to_be16(MLX4_RATELIMIT_DEFAULT); | 
 | 			tc->max_bw_units = cpu_to_be16(MLX4_RATELIMIT_1G_UNITS); | 
 | 		} | 
 |  | 
 | 		tc->pg = cpu_to_be16(pg[i]); | 
 | 		tc->bw_precentage = cpu_to_be16(tc_tx_bw[i]); | 
 | 	} | 
 |  | 
 | 	in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; | 
 | 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, | 
 | 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); | 
 |  | 
 | 	mlx4_free_cmd_mailbox(dev, mailbox); | 
 | 	return err; | 
 | } | 
 | EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); | 
 |  | 
 | int mlx4_ALLOCATE_VPP_get(struct mlx4_dev *dev, uint8_t port, | 
 | 			  uint16_t *availible_vpp, uint8_t *vpp_p_up) | 
 | { | 
 | 	int i; | 
 | 	int err; | 
 | 	struct mlx4_cmd_mailbox *mailbox; | 
 | 	struct mlx4_alloc_vpp_param *out_param; | 
 |  | 
 | 	mailbox = mlx4_alloc_cmd_mailbox(dev); | 
 | 	if (IS_ERR(mailbox)) | 
 | 		return PTR_ERR(mailbox); | 
 |  | 
 | 	out_param = mailbox->buf; | 
 |  | 
 | 	err = mlx4_cmd_box(dev, 0, mailbox->dma, port, | 
 | 			   MLX4_ALLOCATE_VPP_QUERY, | 
 | 			   MLX4_CMD_ALLOCATE_VPP, | 
 | 			   MLX4_CMD_TIME_CLASS_A, | 
 | 			   MLX4_CMD_NATIVE); | 
 | 	if (err) | 
 | 		goto out; | 
 |  | 
 | 	/* Total number of supported VPPs */ | 
 | 	*availible_vpp = (uint16_t)be32_to_cpu(out_param->availible_vpp); | 
 |  | 
 | 	for (i = 0; i < MLX4_NUM_UP; i++) | 
 | 		vpp_p_up[i] = (uint8_t)be32_to_cpu(out_param->vpp_p_up[i]); | 
 |  | 
 | out: | 
 | 	mlx4_free_cmd_mailbox(dev, mailbox); | 
 |  | 
 | 	return err; | 
 | } | 
 | EXPORT_SYMBOL(mlx4_ALLOCATE_VPP_get); | 
 |  | 
 | int mlx4_ALLOCATE_VPP_set(struct mlx4_dev *dev, uint8_t port, | 
 | 			  uint8_t *vpp_p_up) | 
 | { | 
 | 	int i; | 
 | 	int err; | 
 | 	struct mlx4_cmd_mailbox *mailbox; | 
 | 	struct mlx4_alloc_vpp_param *in_param; | 
 |  | 
 | 	mailbox = mlx4_alloc_cmd_mailbox(dev); | 
 | 	if (IS_ERR(mailbox)) | 
 | 		return PTR_ERR(mailbox); | 
 |  | 
 | 	in_param = mailbox->buf; | 
 |  | 
 | 	for (i = 0; i < MLX4_NUM_UP; i++) | 
 | 		in_param->vpp_p_up[i] = cpu_to_be32(vpp_p_up[i]); | 
 |  | 
 | 	err = mlx4_cmd(dev, mailbox->dma, port, | 
 | 		       MLX4_ALLOCATE_VPP_ALLOCATE, | 
 | 		       MLX4_CMD_ALLOCATE_VPP, | 
 | 		       MLX4_CMD_TIME_CLASS_A, | 
 | 		       MLX4_CMD_NATIVE); | 
 |  | 
 | 	mlx4_free_cmd_mailbox(dev, mailbox); | 
 | 	return err; | 
 | } | 
 | EXPORT_SYMBOL(mlx4_ALLOCATE_VPP_set); | 
 |  | 
 | int mlx4_SET_VPORT_QOS_get(struct mlx4_dev *dev, uint8_t port, uint8_t vport, | 
 | 			   struct mlx4_vport_qos_param *out_param) | 
 | { | 
 | 	int i; | 
 | 	int err; | 
 | 	struct mlx4_cmd_mailbox *mailbox; | 
 | 	struct mlx4_set_vport_context *ctx; | 
 |  | 
 | 	mailbox = mlx4_alloc_cmd_mailbox(dev); | 
 | 	if (IS_ERR(mailbox)) | 
 | 		return PTR_ERR(mailbox); | 
 |  | 
 | 	ctx = mailbox->buf; | 
 |  | 
 | 	err = mlx4_cmd_box(dev, 0, mailbox->dma, (vport << 8) | port, | 
 | 			   MLX4_SET_VPORT_QOS_QUERY, | 
 | 			   MLX4_CMD_SET_VPORT_QOS, | 
 | 			   MLX4_CMD_TIME_CLASS_A, | 
 | 			   MLX4_CMD_NATIVE); | 
 | 	if (err) | 
 | 		goto out; | 
 |  | 
 | 	for (i = 0; i < MLX4_NUM_UP; i++) { | 
 | 		out_param[i].bw_share = be32_to_cpu(ctx->qos_p_up[i].bw_share); | 
 | 		out_param[i].max_avg_bw = | 
 | 			be32_to_cpu(ctx->qos_p_up[i].max_avg_bw); | 
 | 		out_param[i].enable = | 
 | 			!!(be32_to_cpu(ctx->qos_p_up[i].enable) & 31); | 
 | 	} | 
 |  | 
 | out: | 
 | 	mlx4_free_cmd_mailbox(dev, mailbox); | 
 |  | 
 | 	return err; | 
 | } | 
 | EXPORT_SYMBOL(mlx4_SET_VPORT_QOS_get); | 
 |  | 
 | int mlx4_SET_VPORT_QOS_set(struct mlx4_dev *dev, uint8_t port, uint8_t vport, | 
 | 			   struct mlx4_vport_qos_param *in_param) | 
 | { | 
 | 	int i; | 
 | 	int err; | 
 | 	struct mlx4_cmd_mailbox *mailbox; | 
 | 	struct mlx4_set_vport_context *ctx; | 
 |  | 
 | 	mailbox = mlx4_alloc_cmd_mailbox(dev); | 
 | 	if (IS_ERR(mailbox)) | 
 | 		return PTR_ERR(mailbox); | 
 |  | 
 | 	ctx = mailbox->buf; | 
 |  | 
 | 	for (i = 0; i < MLX4_NUM_UP; i++) { | 
 | 		ctx->qos_p_up[i].bw_share = cpu_to_be32(in_param[i].bw_share); | 
 | 		ctx->qos_p_up[i].max_avg_bw = | 
 | 				cpu_to_be32(in_param[i].max_avg_bw); | 
 | 		ctx->qos_p_up[i].enable = | 
 | 				cpu_to_be32(in_param[i].enable << 31); | 
 | 	} | 
 |  | 
 | 	err = mlx4_cmd(dev, mailbox->dma, (vport << 8) | port, | 
 | 		       MLX4_SET_VPORT_QOS_SET, | 
 | 		       MLX4_CMD_SET_VPORT_QOS, | 
 | 		       MLX4_CMD_TIME_CLASS_A, | 
 | 		       MLX4_CMD_NATIVE); | 
 |  | 
 | 	mlx4_free_cmd_mailbox(dev, mailbox); | 
 | 	return err; | 
 | } | 
 | EXPORT_SYMBOL(mlx4_SET_VPORT_QOS_set); |