|  | /* | 
|  | * 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); |