diff options
author | Hans Petter Selasky <hselasky@FreeBSD.org> | 2016-09-30 08:23:06 +0000 |
---|---|---|
committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2016-09-30 08:23:06 +0000 |
commit | 97549c34ecaf74580941fdc9c5bd1050e4b1f6ce (patch) | |
tree | c542eb2e05b98297ac84daafc3f3380d44fa0bf6 /sys/ofed | |
parent | 1a3c881209ce7c8a83bdb6a97ad8dd56c6f2ffa8 (diff) | |
download | src-97549c34ecaf74580941fdc9c5bd1050e4b1f6ce.tar.gz src-97549c34ecaf74580941fdc9c5bd1050e4b1f6ce.zip |
Move the ConnectX-3 and ConnectX-2 driver from sys/ofed into sys/dev/mlx4
like other PCI network drivers. The sys/ofed directory is now mainly
reserved for generic infiniband code, with exception of the mthca driver.
- Add new manual page, mlx4en(4), describing how to configure and load
mlx4en.
- All relevant driver C-files are now prefixed mlx4, mlx4_en and
mlx4_ib respectivly to avoid object filename collisions when compiling
the kernel. This also fixes an issue with proper dependency file
generation for the C-files in question.
- Device mlxen is now device mlx4en and depends on device mlx4, see
mlx4en(4). Only the network device name remains unchanged.
- The mlx4 and mlx4en modules are now built by default on i386 and
amd64 targets. Only building the mlx4ib module depends on
WITH_OFED=YES .
Sponsored by: Mellanox Technologies
Notes
Notes:
svn path=/head/; revision=306486
Diffstat (limited to 'sys/ofed')
60 files changed, 0 insertions, 50118 deletions
diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/Kconfig b/sys/ofed/drivers/infiniband/hw/mlx4/Kconfig deleted file mode 100644 index 24ab11a9ad1e..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config MLX4_INFINIBAND - tristate "Mellanox ConnectX HCA support" - depends on NETDEVICES && ETHERNET && PCI - select NET_VENDOR_MELLANOX - select MLX4_CORE - ---help--- - This driver provides low-level InfiniBand support for - Mellanox ConnectX PCI Express host channel adapters (HCAs). - This is required to use InfiniBand protocols such as - IP-over-IB or SRP with these devices. diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/ah.c b/sys/ofed/drivers/infiniband/hw/mlx4/ah.c deleted file mode 100644 index 1c30fa996796..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/ah.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. 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 <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <rdma/ib_addr.h> -#include <rdma/ib_cache.h> - -#include <linux/slab.h> -#include <linux/string.h> - -#include "mlx4_ib.h" - -int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, - u8 *mac, int *is_mcast, u8 port) -{ - struct in6_addr in6; - - *is_mcast = 0; - - memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6); - if (rdma_link_local_addr(&in6)) - rdma_get_ll_mac(&in6, mac); - else if (rdma_is_multicast_addr(&in6)) { - rdma_get_mcast_mac(&in6, mac); - *is_mcast = 1; - } else - return -EINVAL; - - return 0; -} - -static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, - struct mlx4_ib_ah *ah) -{ - struct mlx4_dev *dev = to_mdev(pd->device)->dev; - - ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); - ah->av.ib.g_slid = ah_attr->src_path_bits; - if (ah_attr->ah_flags & IB_AH_GRH) { - ah->av.ib.g_slid |= 0x80; - ah->av.ib.gid_index = ah_attr->grh.sgid_index; - ah->av.ib.hop_limit = ah_attr->grh.hop_limit; - ah->av.ib.sl_tclass_flowlabel |= - cpu_to_be32((ah_attr->grh.traffic_class << 20) | - ah_attr->grh.flow_label); - memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); - } - - ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); - if (ah_attr->static_rate) { - ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; - while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && - !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) - --ah->av.ib.stat_rate; - } - ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); - - return &ah->ibah; -} - -static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, - struct mlx4_ib_ah *ah) -{ - struct mlx4_ib_dev *ibdev = to_mdev(pd->device); - struct mlx4_dev *dev = ibdev->dev; - int is_mcast = 0; - struct in6_addr in6; - u16 vlan_tag; - - memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(in6)); - if (rdma_is_multicast_addr(&in6)) { - is_mcast = 1; - resolve_mcast_mac(&in6, ah->av.eth.mac); - } else { - memcpy(ah->av.eth.mac, ah_attr->dmac, 6); - } - vlan_tag = ah_attr->vlan_id; - if (vlan_tag < 0x1000) - vlan_tag |= (ah_attr->sl & 7) << 13; - ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); - ah->av.eth.gid_index = ah_attr->grh.sgid_index; - ah->av.eth.vlan = cpu_to_be16(vlan_tag); - if (ah_attr->static_rate) { - ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; - while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && - !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support)) - --ah->av.eth.stat_rate; - } - - /* - * HW requires multicast LID so we just choose one. - */ - if (is_mcast) - ah->av.ib.dlid = cpu_to_be16(0xc000); - - memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); - ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 29); - - return &ah->ibah; -} - -struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) -{ - struct mlx4_ib_ah *ah; - struct ib_ah *ret; - - ah = kzalloc(sizeof *ah, GFP_ATOMIC); - if (!ah) - return ERR_PTR(-ENOMEM); - - if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) { - if (!(ah_attr->ah_flags & IB_AH_GRH)) { - ret = ERR_PTR(-EINVAL); - } else { - /* - * TBD: need to handle the case when we get - * called in an atomic context and there we - * might sleep. We don't expect this - * currently since we're working with link - * local addresses which we can translate - * without going to sleep. - */ - ret = create_iboe_ah(pd, ah_attr, ah); - } - - if (IS_ERR(ret)) - kfree(ah); - - return ret; - } else - return create_ib_ah(pd, ah_attr, ah); /* never fails */ -} - -int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) -{ - struct mlx4_ib_ah *ah = to_mah(ibah); - enum rdma_link_layer ll; - - memset(ah_attr, 0, sizeof *ah_attr); - ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; - ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24; - ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num); - ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0; - if (ah->av.ib.stat_rate) - ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; - ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F; - - if (mlx4_ib_ah_grh_present(ah)) { - ah_attr->ah_flags = IB_AH_GRH; - - ah_attr->grh.traffic_class = - be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20; - ah_attr->grh.flow_label = - be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff; - ah_attr->grh.hop_limit = ah->av.ib.hop_limit; - ah_attr->grh.sgid_index = ah->av.ib.gid_index; - memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); - } - - return 0; -} - -int mlx4_ib_destroy_ah(struct ib_ah *ah) -{ - kfree(to_mah(ah)); - return 0; -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/alias_GUID.c b/sys/ofed/drivers/infiniband/hw/mlx4/alias_GUID.c deleted file mode 100644 index 17e646a02805..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/alias_GUID.c +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright (c) 2012 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. - */ - /***********************************************************/ -/*This file support the handling of the Alias GUID feature. */ -/***********************************************************/ -#include <rdma/ib_mad.h> -#include <rdma/ib_smi.h> -#include <rdma/ib_cache.h> -#include <rdma/ib_sa.h> -#include <rdma/ib_pack.h> -#include <linux/mlx4/cmd.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <rdma/ib_user_verbs.h> -#include <linux/delay.h> -#include "mlx4_ib.h" - -/* -The driver keeps the current state of all guids, as they are in the HW. -Whenever we receive an smp mad GUIDInfo record, the data will be cached. -*/ - -struct mlx4_alias_guid_work_context { - u8 port; - struct mlx4_ib_dev *dev ; - struct ib_sa_query *sa_query; - struct completion done; - int query_id; - struct list_head list; - int block_num; - u8 method; -}; - -struct mlx4_next_alias_guid_work { - u8 port; - u8 block_num; - struct mlx4_sriov_alias_guid_info_rec_det rec_det; -}; - - -void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num, - u8 port_num, u8 *p_data) -{ - int i; - u64 guid_indexes; - int slave_id; - int port_index = port_num - 1; - - if (!mlx4_is_master(dev->dev)) - return; - - guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid. - ports_guid[port_num - 1]. - all_rec_per_port[block_num].guid_indexes); - pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, - (unsigned long long)guid_indexes); - - for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { - /* The location of the specific index starts from bit number 4 - * until bit num 11 */ - if (test_bit(i + 4, (unsigned long *)&guid_indexes)) { - slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ; - if (slave_id >= dev->dev->num_slaves) { - pr_debug("The last slave: %d\n", slave_id); - return; - } - - /* cache the guid: */ - memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id], - &p_data[i * GUID_REC_SIZE], - GUID_REC_SIZE); - } else - pr_debug("Guid number: %d in block: %d" - " was not updated\n", i, block_num); - } -} - -static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index) -{ - if (index >= NUM_ALIAS_GUID_PER_PORT) { - pr_err("%s: ERROR: asked for index:%d\n", __func__, index); - return (__force __be64) -1; - } - return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index]; -} - - -ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index) -{ - return IB_SA_COMP_MASK(4 + index); -} - -/* - * Whenever new GUID is set/unset (guid table change) create event and - * notify the relevant slave (master also should be notified). - * If the GUID value is not as we have in the cache the slave will not be - * updated; in this case it waits for the smp_snoop or the port management - * event to call the function and to update the slave. - * block_number - the index of the block (16 blocks available) - * port_number - 1 or 2 - */ -void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev, - int block_num, u8 port_num, - u8 *p_data) -{ - int i; - u64 guid_indexes; - int slave_id; - enum slave_port_state new_state; - enum slave_port_state prev_state; - __be64 tmp_cur_ag, form_cache_ag; - enum slave_port_gen_event gen_event; - - if (!mlx4_is_master(dev->dev)) - return; - - guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid. - ports_guid[port_num - 1]. - all_rec_per_port[block_num].guid_indexes); - pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, - (unsigned long long)guid_indexes); - - /*calculate the slaves and notify them*/ - for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { - /* the location of the specific index runs from bits 4..11 */ - if (!(test_bit(i + 4, (unsigned long *)&guid_indexes))) - continue; - - slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ; - if (slave_id >= dev->dev->num_slaves) - return; - tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE]; - form_cache_ag = get_cached_alias_guid(dev, port_num, - (NUM_ALIAS_GUID_IN_REC * block_num) + i); - /* - * Check if guid is not the same as in the cache, - * If it is different, wait for the snoop_smp or the port mgmt - * change event to update the slave on its port state change - */ - if (tmp_cur_ag != form_cache_ag) - continue; - mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num); - - /*2 cases: Valid GUID, and Invalid Guid*/ - - if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/ - prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num); - new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num, - MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID, - &gen_event); - pr_debug("slave: %d, port: %d prev_port_state: %d," - " new_port_state: %d, gen_event: %d\n", - slave_id, port_num, prev_state, new_state, gen_event); - if (gen_event == SLAVE_PORT_GEN_EVENT_UP) { - pr_debug("sending PORT_UP event to slave: %d, port: %d\n", - slave_id, port_num); - mlx4_gen_port_state_change_eqe(dev->dev, slave_id, - port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE); - } - } else { /* request to invalidate GUID */ - set_and_calc_slave_port_state(dev->dev, slave_id, port_num, - MLX4_PORT_STATE_IB_EVENT_GID_INVALID, - &gen_event); - pr_debug("sending PORT DOWN event to slave: %d, port: %d\n", - slave_id, port_num); - mlx4_gen_port_state_change_eqe(dev->dev, slave_id, port_num, - MLX4_PORT_CHANGE_SUBTYPE_DOWN); - } - } -} - -static void aliasguid_query_handler(int status, - struct ib_sa_guidinfo_rec *guid_rec, - void *context) -{ - struct mlx4_ib_dev *dev; - struct mlx4_alias_guid_work_context *cb_ctx = context; - u8 port_index; - int i; - struct mlx4_sriov_alias_guid_info_rec_det *rec; - unsigned long flags, flags1; - - if (!context) - return; - - dev = cb_ctx->dev; - port_index = cb_ctx->port - 1; - rec = &dev->sriov.alias_guid.ports_guid[port_index]. - all_rec_per_port[cb_ctx->block_num]; - - if (status) { - rec->status = MLX4_GUID_INFO_STATUS_IDLE; - pr_debug("(port: %d) failed: status = %d\n", - cb_ctx->port, status); - goto out; - } - - if (guid_rec->block_num != cb_ctx->block_num) { - pr_err("block num mismatch: %d != %d\n", - cb_ctx->block_num, guid_rec->block_num); - goto out; - } - - pr_debug("lid/port: %d/%d, block_num: %d\n", - be16_to_cpu(guid_rec->lid), cb_ctx->port, - guid_rec->block_num); - - rec = &dev->sriov.alias_guid.ports_guid[port_index]. - all_rec_per_port[guid_rec->block_num]; - - rec->status = MLX4_GUID_INFO_STATUS_SET; - rec->method = MLX4_GUID_INFO_RECORD_SET; - - for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) { - __be64 tmp_cur_ag; - tmp_cur_ag = *(__be64 *)&guid_rec->guid_info_list[i * GUID_REC_SIZE]; - if ((cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) - && (MLX4_NOT_SET_GUID == tmp_cur_ag)) { - pr_debug("%s:Record num %d in block_num:%d " - "was deleted by SM,ownership by %d " - "(0 = driver, 1=sysAdmin, 2=None)\n", - __func__, i, guid_rec->block_num, - rec->ownership); - rec->guid_indexes = rec->guid_indexes & - ~mlx4_ib_get_aguid_comp_mask_from_ix(i); - continue; - } - - /* check if the SM didn't assign one of the records. - * if it didn't, if it was not sysadmin request: - * ask the SM to give a new GUID, (instead of the driver request). - */ - if (tmp_cur_ag == MLX4_NOT_SET_GUID) { - mlx4_ib_warn(&dev->ib_dev, "%s:Record num %d in " - "block_num: %d was declined by SM, " - "ownership by %d (0 = driver, 1=sysAdmin," - " 2=None)\n", __func__, i, - guid_rec->block_num, rec->ownership); - if (rec->ownership == MLX4_GUID_DRIVER_ASSIGN) { - /* if it is driver assign, asks for new GUID from SM*/ - *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] = - MLX4_NOT_SET_GUID; - - /* Mark the record as not assigned, and let it - * be sent again in the next work sched.*/ - rec->status = MLX4_GUID_INFO_STATUS_IDLE; - rec->guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i); - } - } else { - /* properly assigned record. */ - /* We save the GUID we just got from the SM in the - * admin_guid in order to be persistent, and in the - * request from the sm the process will ask for the same GUID */ - if (rec->ownership == MLX4_GUID_SYSADMIN_ASSIGN && - tmp_cur_ag != *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]) { - /* the sysadmin assignment failed.*/ - mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set" - " admin guid after SysAdmin " - "configuration. " - "Record num %d in block_num:%d " - "was declined by SM, " - "new val(0x%llx) was kept\n", - __func__, i, - guid_rec->block_num, - (long long)be64_to_cpu(*(__be64 *) & - rec->all_recs[i * GUID_REC_SIZE])); - } else { - memcpy(&rec->all_recs[i * GUID_REC_SIZE], - &guid_rec->guid_info_list[i * GUID_REC_SIZE], - GUID_REC_SIZE); - } - } - } - /* - The func is call here to close the cases when the - sm doesn't send smp, so in the sa response the driver - notifies the slave. - */ - mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num, - cb_ctx->port, - guid_rec->guid_info_list); -out: - spin_lock_irqsave(&dev->sriov.going_down_lock, flags); - spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); - if (!dev->sriov.is_going_down) - queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq, - &dev->sriov.alias_guid.ports_guid[port_index]. - alias_guid_work, 0); - if (cb_ctx->sa_query) { - list_del(&cb_ctx->list); - kfree(cb_ctx); - } else - complete(&cb_ctx->done); - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); - spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); -} - -static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index) -{ - int i; - u64 cur_admin_val; - ib_sa_comp_mask comp_mask = 0; - - dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status - = MLX4_GUID_INFO_STATUS_IDLE; - dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].method - = MLX4_GUID_INFO_RECORD_SET; - - /* calculate the comp_mask for that record.*/ - for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { - cur_admin_val = - *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. - all_rec_per_port[index].all_recs[GUID_REC_SIZE * i]; - /* - check the admin value: if it's for delete (~00LL) or - it is the first guid of the first record (hw guid) or - the records is not in ownership of the sysadmin and the sm doesn't - need to assign GUIDs, then don't put it up for assignment. - */ - if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val || - (!index && !i) || - MLX4_GUID_NONE_ASSIGN == dev->sriov.alias_guid. - ports_guid[port - 1].all_rec_per_port[index].ownership) - continue; - comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i); - } - dev->sriov.alias_guid.ports_guid[port - 1]. - all_rec_per_port[index].guid_indexes = comp_mask; -} - -static int set_guid_rec(struct ib_device *ibdev, - u8 port, int index, - struct mlx4_sriov_alias_guid_info_rec_det *rec_det) -{ - int err; - struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct ib_sa_guidinfo_rec guid_info_rec; - ib_sa_comp_mask comp_mask; - struct ib_port_attr attr; - struct mlx4_alias_guid_work_context *callback_context; - unsigned long resched_delay, flags, flags1; - struct list_head *head = - &dev->sriov.alias_guid.ports_guid[port - 1].cb_list; - - err = __mlx4_ib_query_port(ibdev, port, &attr, 1); - if (err) { - pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n", - err, port); - return err; - } - /*check the port was configured by the sm, otherwise no need to send */ - if (attr.state != IB_PORT_ACTIVE) { - pr_debug("port %d not active...rescheduling\n", port); - resched_delay = 5 * HZ; - err = -EAGAIN; - goto new_schedule; - } - - callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL); - if (!callback_context) { - err = -ENOMEM; - resched_delay = HZ * 5; - goto new_schedule; - } - callback_context->port = port; - callback_context->dev = dev; - callback_context->block_num = index; - callback_context->method = rec_det->method; - memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec)); - - guid_info_rec.lid = cpu_to_be16(attr.lid); - guid_info_rec.block_num = index; - - memcpy(guid_info_rec.guid_info_list, rec_det->all_recs, - GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC); - comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM | - rec_det->guid_indexes; - - init_completion(&callback_context->done); - spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); - list_add_tail(&callback_context->list, head); - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); - - callback_context->query_id = - ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client, - ibdev, port, &guid_info_rec, - comp_mask, rec_det->method, 1000, - GFP_KERNEL, aliasguid_query_handler, - callback_context, - &callback_context->sa_query); - if (callback_context->query_id < 0) { - pr_debug("ib_sa_guid_info_rec_query failed, query_id: " - "%d. will reschedule to the next 1 sec.\n", - callback_context->query_id); - spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); - list_del(&callback_context->list); - kfree(callback_context); - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); - resched_delay = 1 * HZ; - err = -EAGAIN; - goto new_schedule; - } - err = 0; - goto out; - -new_schedule: - spin_lock_irqsave(&dev->sriov.going_down_lock, flags); - spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); - invalidate_guid_record(dev, port, index); - if (!dev->sriov.is_going_down) { - queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, - &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, - resched_delay); - } - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); - spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); - -out: - return err; -} - -void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port) -{ - int i; - unsigned long flags, flags1; - - pr_debug("port %d\n", port); - - spin_lock_irqsave(&dev->sriov.going_down_lock, flags); - spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); - for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++) - invalidate_guid_record(dev, port, i); - - if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) { - /* - make sure no work waits in the queue, if the work is already - queued(not on the timer) the cancel will fail. That is not a problem - because we just want the work started. - */ - cancel_delayed_work(&dev->sriov.alias_guid. - ports_guid[port - 1].alias_guid_work); - queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, - &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, - 0); - } - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); - spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); -} - -/* The function returns the next record that was - * not configured (or failed to be configured) */ -static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port, - struct mlx4_next_alias_guid_work *rec) -{ - int j; - unsigned long flags; - - for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { - spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); - if (dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j].status == - MLX4_GUID_INFO_STATUS_IDLE) { - memcpy(&rec->rec_det, - &dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j], - sizeof (struct mlx4_sriov_alias_guid_info_rec_det)); - rec->port = port; - rec->block_num = j; - dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[j].status = - MLX4_GUID_INFO_STATUS_PENDING; - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); - return 0; - } - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); - } - return -ENOENT; -} - -static void set_administratively_guid_record(struct mlx4_ib_dev *dev, int port, - int rec_index, - struct mlx4_sriov_alias_guid_info_rec_det *rec_det) -{ - dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].guid_indexes = - rec_det->guid_indexes; - memcpy(dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].all_recs, - rec_det->all_recs, NUM_ALIAS_GUID_IN_REC * GUID_REC_SIZE); - dev->sriov.alias_guid.ports_guid[port].all_rec_per_port[rec_index].status = - rec_det->status; -} - -static void set_all_slaves_guids(struct mlx4_ib_dev *dev, int port) -{ - int j; - struct mlx4_sriov_alias_guid_info_rec_det rec_det ; - - for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT ; j++) { - memset(rec_det.all_recs, 0, NUM_ALIAS_GUID_IN_REC * GUID_REC_SIZE); - rec_det.guid_indexes = (!j ? 0 : IB_SA_GUIDINFO_REC_GID0) | - IB_SA_GUIDINFO_REC_GID1 | IB_SA_GUIDINFO_REC_GID2 | - IB_SA_GUIDINFO_REC_GID3 | IB_SA_GUIDINFO_REC_GID4 | - IB_SA_GUIDINFO_REC_GID5 | IB_SA_GUIDINFO_REC_GID6 | - IB_SA_GUIDINFO_REC_GID7; - rec_det.status = MLX4_GUID_INFO_STATUS_IDLE; - set_administratively_guid_record(dev, port, j, &rec_det); - } -} - -static void alias_guid_work(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - int ret = 0; - struct mlx4_next_alias_guid_work *rec; - struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port = - container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det, - alias_guid_work); - struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent; - struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid, - struct mlx4_ib_sriov, - alias_guid); - struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov); - - rec = kzalloc(sizeof *rec, GFP_KERNEL); - if (!rec) { - pr_err("alias_guid_work: No Memory\n"); - return; - } - - pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1); - ret = get_next_record_to_update(dev, sriov_alias_port->port, rec); - if (ret) { - pr_debug("No more records to update.\n"); - goto out; - } - - set_guid_rec(&dev->ib_dev, rec->port + 1, rec->block_num, - &rec->rec_det); - -out: - kfree(rec); -} - - -void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port) -{ - unsigned long flags, flags1; - - if (!mlx4_is_master(dev->dev)) - return; - spin_lock_irqsave(&dev->sriov.going_down_lock, flags); - spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); - if (!dev->sriov.is_going_down) { - queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq, - &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0); - } - spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); - spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); -} - -void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev) -{ - int i; - struct mlx4_ib_sriov *sriov = &dev->sriov; - struct mlx4_alias_guid_work_context *cb_ctx; - struct mlx4_sriov_alias_guid_port_rec_det *det; - struct ib_sa_query *sa_query; - unsigned long flags; - - for (i = 0 ; i < dev->num_ports; i++) { - cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work); - det = &sriov->alias_guid.ports_guid[i]; - spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); - while (!list_empty(&det->cb_list)) { - cb_ctx = list_entry(det->cb_list.next, - struct mlx4_alias_guid_work_context, - list); - sa_query = cb_ctx->sa_query; - cb_ctx->sa_query = NULL; - list_del(&cb_ctx->list); - spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); - ib_sa_cancel_query(cb_ctx->query_id, sa_query); - wait_for_completion(&cb_ctx->done); - kfree(cb_ctx); - spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); - } - spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); - } - for (i = 0 ; i < dev->num_ports; i++) { - flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); - destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); - } - ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); - kfree(dev->sriov.alias_guid.sa_client); -} - -int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev) -{ - char alias_wq_name[15]; - int ret = 0; - int i, j, k; - union ib_gid gid; - - if (!mlx4_is_master(dev->dev)) - return 0; - dev->sriov.alias_guid.sa_client = - kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL); - if (!dev->sriov.alias_guid.sa_client) - return -ENOMEM; - - ib_sa_register_client(dev->sriov.alias_guid.sa_client); - - spin_lock_init(&dev->sriov.alias_guid.ag_work_lock); - - for (i = 1; i <= dev->num_ports; ++i) { - if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) { - ret = -EFAULT; - goto err_unregister; - } - } - - for (i = 0 ; i < dev->num_ports; i++) { - memset(&dev->sriov.alias_guid.ports_guid[i], 0, - sizeof (struct mlx4_sriov_alias_guid_port_rec_det)); - /*Check if the SM doesn't need to assign the GUIDs*/ - for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { - if (mlx4_ib_sm_guid_assign) { - dev->sriov.alias_guid.ports_guid[i]. - all_rec_per_port[j]. - ownership = MLX4_GUID_DRIVER_ASSIGN; - continue; - } - dev->sriov.alias_guid.ports_guid[i].all_rec_per_port[j]. - ownership = MLX4_GUID_NONE_ASSIGN; - /*mark each val as it was deleted, - till the sysAdmin will give it valid val*/ - for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) { - *(__be64 *)&dev->sriov.alias_guid.ports_guid[i]. - all_rec_per_port[j].all_recs[GUID_REC_SIZE * k] = - cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL); - } - } - INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list); - /*prepare the records, set them to be allocated by sm*/ - for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) - invalidate_guid_record(dev, i + 1, j); - - dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid; - dev->sriov.alias_guid.ports_guid[i].port = i; - if (mlx4_ib_sm_guid_assign) - set_all_slaves_guids(dev, i); - - snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i); - dev->sriov.alias_guid.ports_guid[i].wq = - create_singlethread_workqueue(alias_wq_name); - if (!dev->sriov.alias_guid.ports_guid[i].wq) { - ret = -ENOMEM; - goto err_thread; - } - INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work, - alias_guid_work); - } - return 0; - -err_thread: - for (--i; i >= 0; i--) { - destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); - dev->sriov.alias_guid.ports_guid[i].wq = NULL; - } - -err_unregister: - ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); - kfree(dev->sriov.alias_guid.sa_client); - dev->sriov.alias_guid.sa_client = NULL; - pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret); - return ret; -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/cm.c b/sys/ofed/drivers/infiniband/hw/mlx4/cm.c deleted file mode 100644 index bab54ca2ff55..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/cm.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (c) 2012 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 <rdma/ib_mad.h> - -#include <linux/mlx4/cmd.h> -#include <linux/rbtree.h> -#include <linux/idr.h> -#include <rdma/ib_cm.h> - -#include "mlx4_ib.h" - -#define CM_CLEANUP_CACHE_TIMEOUT (5 * HZ) - -struct id_map_entry { - struct rb_node node; - - u32 sl_cm_id; - u32 pv_cm_id; - int slave_id; - int scheduled_delete; - struct mlx4_ib_dev *dev; - - struct list_head list; - struct delayed_work timeout; -}; - -struct cm_generic_msg { - struct ib_mad_hdr hdr; - - __be32 local_comm_id; - __be32 remote_comm_id; -}; - -struct cm_sidr_generic_msg { - struct ib_mad_hdr hdr; - __be32 request_id; -}; - -struct cm_req_msg { - unsigned char unused[0x60]; - union ib_gid primary_path_sgid; -}; - - -static void set_local_comm_id(struct ib_mad *mad, u32 cm_id) -{ - if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { - struct cm_sidr_generic_msg *msg = - (struct cm_sidr_generic_msg *)mad; - msg->request_id = cpu_to_be32(cm_id); - } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { - pr_err("trying to set local_comm_id in SIDR_REP\n"); - return; - } else { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - msg->local_comm_id = cpu_to_be32(cm_id); - } -} - -static u32 get_local_comm_id(struct ib_mad *mad) -{ - if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { - struct cm_sidr_generic_msg *msg = - (struct cm_sidr_generic_msg *)mad; - return be32_to_cpu(msg->request_id); - } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { - pr_err("trying to set local_comm_id in SIDR_REP\n"); - return -1; - } else { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - return be32_to_cpu(msg->local_comm_id); - } -} - -static void set_remote_comm_id(struct ib_mad *mad, u32 cm_id) -{ - if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { - struct cm_sidr_generic_msg *msg = - (struct cm_sidr_generic_msg *)mad; - msg->request_id = cpu_to_be32(cm_id); - } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { - pr_err("trying to set remote_comm_id in SIDR_REQ\n"); - return; - } else { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - msg->remote_comm_id = cpu_to_be32(cm_id); - } -} - -static u32 get_remote_comm_id(struct ib_mad *mad) -{ - if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { - struct cm_sidr_generic_msg *msg = - (struct cm_sidr_generic_msg *)mad; - return be32_to_cpu(msg->request_id); - } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { - pr_err("trying to set remote_comm_id in SIDR_REQ\n"); - return -1; - } else { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - return be32_to_cpu(msg->remote_comm_id); - } -} - -static union ib_gid gid_from_req_msg(struct ib_device *ibdev, struct ib_mad *mad) -{ - struct cm_req_msg *msg = (struct cm_req_msg *)mad; - - return msg->primary_path_sgid; -} - -/* Lock should be taken before called */ -static struct id_map_entry * -id_map_find_by_sl_id(struct ib_device *ibdev, u32 slave_id, u32 sl_cm_id) -{ - struct rb_root *sl_id_map = &to_mdev(ibdev)->sriov.sl_id_map; - struct rb_node *node = sl_id_map->rb_node; - - while (node) { - struct id_map_entry *id_map_entry = - rb_entry(node, struct id_map_entry, node); - - if (id_map_entry->sl_cm_id > sl_cm_id) - node = node->rb_left; - else if (id_map_entry->sl_cm_id < sl_cm_id) - node = node->rb_right; - else if (id_map_entry->slave_id > slave_id) - node = node->rb_left; - else if (id_map_entry->slave_id < slave_id) - node = node->rb_right; - else - return id_map_entry; - } - return NULL; -} - -static void id_map_ent_timeout(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct id_map_entry *ent = container_of(delay, struct id_map_entry, timeout); - struct id_map_entry *db_ent, *found_ent; - struct mlx4_ib_dev *dev = ent->dev; - struct mlx4_ib_sriov *sriov = &dev->sriov; - struct rb_root *sl_id_map = &sriov->sl_id_map; - int pv_id = (int) ent->pv_cm_id; - - spin_lock(&sriov->id_map_lock); - db_ent = (struct id_map_entry *)idr_find(&sriov->pv_id_table, pv_id); - if (!db_ent) - goto out; - found_ent = id_map_find_by_sl_id(&dev->ib_dev, ent->slave_id, ent->sl_cm_id); - if (found_ent && found_ent == ent) - rb_erase(&found_ent->node, sl_id_map); - idr_remove(&sriov->pv_id_table, pv_id); - -out: - list_del(&ent->list); - spin_unlock(&sriov->id_map_lock); - kfree(ent); -} - -static void id_map_find_del(struct ib_device *ibdev, int pv_cm_id) -{ - struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov; - struct rb_root *sl_id_map = &sriov->sl_id_map; - struct id_map_entry *ent, *found_ent; - - spin_lock(&sriov->id_map_lock); - ent = (struct id_map_entry *)idr_find(&sriov->pv_id_table, pv_cm_id); - if (!ent) - goto out; - found_ent = id_map_find_by_sl_id(ibdev, ent->slave_id, ent->sl_cm_id); - if (found_ent && found_ent == ent) - rb_erase(&found_ent->node, sl_id_map); - idr_remove(&sriov->pv_id_table, pv_cm_id); -out: - spin_unlock(&sriov->id_map_lock); -} - -static void sl_id_map_add(struct ib_device *ibdev, struct id_map_entry *new) -{ - struct rb_root *sl_id_map = &to_mdev(ibdev)->sriov.sl_id_map; - struct rb_node **link = &sl_id_map->rb_node, *parent = NULL; - struct id_map_entry *ent; - int slave_id = new->slave_id; - int sl_cm_id = new->sl_cm_id; - - ent = id_map_find_by_sl_id(ibdev, slave_id, sl_cm_id); - if (ent) { - pr_debug("overriding existing sl_id_map entry (cm_id = %x)\n", - sl_cm_id); - - rb_replace_node(&ent->node, &new->node, sl_id_map); - return; - } - - /* Go to the bottom of the tree */ - while (*link) { - parent = *link; - ent = rb_entry(parent, struct id_map_entry, node); - - if (ent->sl_cm_id > sl_cm_id || (ent->sl_cm_id == sl_cm_id && ent->slave_id > slave_id)) - link = &(*link)->rb_left; - else - link = &(*link)->rb_right; - } - - rb_link_node(&new->node, parent, link); - rb_insert_color(&new->node, sl_id_map); -} - -static struct id_map_entry * -id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id) -{ - int ret, id; - static int next_id; - struct id_map_entry *ent; - struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov; - - ent = kmalloc(sizeof (struct id_map_entry), GFP_KERNEL); - if (!ent) { - mlx4_ib_warn(ibdev, "Couldn't allocate id cache entry - out of memory\n"); - return ERR_PTR(-ENOMEM); - } - - ent->sl_cm_id = sl_cm_id; - ent->slave_id = slave_id; - ent->scheduled_delete = 0; - ent->dev = to_mdev(ibdev); - INIT_DELAYED_WORK(&ent->timeout, id_map_ent_timeout); - - do { - spin_lock(&to_mdev(ibdev)->sriov.id_map_lock); - ret = idr_get_new_above(&sriov->pv_id_table, ent, - next_id, &id); - if (!ret) { - next_id = ((unsigned) id + 1) & MAX_IDR_MASK; - ent->pv_cm_id = (u32)id; - sl_id_map_add(ibdev, ent); - } - - spin_unlock(&sriov->id_map_lock); - } while (ret == -EAGAIN && idr_pre_get(&sriov->pv_id_table, GFP_KERNEL)); - /*the function idr_get_new_above can return -ENOSPC, so don't insert in that case.*/ - if (!ret) { - spin_lock(&sriov->id_map_lock); - list_add_tail(&ent->list, &sriov->cm_list); - spin_unlock(&sriov->id_map_lock); - return ent; - } - /*error flow*/ - kfree(ent); - mlx4_ib_warn(ibdev, "No more space in the idr (err:0x%x)\n", ret); - return ERR_PTR(-ENOMEM); -} - -static struct id_map_entry * -id_map_get(struct ib_device *ibdev, int *pv_cm_id, int sl_cm_id, int slave_id) -{ - struct id_map_entry *ent; - struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov; - - spin_lock(&sriov->id_map_lock); - if (*pv_cm_id == -1) { - ent = id_map_find_by_sl_id(ibdev, sl_cm_id, slave_id); - if (ent) - *pv_cm_id = (int) ent->pv_cm_id; - } else - ent = (struct id_map_entry *)idr_find(&sriov->pv_id_table, *pv_cm_id); - spin_unlock(&sriov->id_map_lock); - - return ent; -} - -static void schedule_delayed(struct ib_device *ibdev, struct id_map_entry *id) -{ - struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov; - unsigned long flags; - - spin_lock(&sriov->id_map_lock); - spin_lock_irqsave(&sriov->going_down_lock, flags); - /*make sure that there is no schedule inside the scheduled work.*/ - if (!sriov->is_going_down) { - id->scheduled_delete = 1; - schedule_delayed_work(&id->timeout, CM_CLEANUP_CACHE_TIMEOUT); - } - spin_unlock_irqrestore(&sriov->going_down_lock, flags); - spin_unlock(&sriov->id_map_lock); -} - -int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id, - struct ib_mad *mad) -{ - struct id_map_entry *id; - u32 sl_cm_id; - int pv_cm_id = -1; - - if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID || - mad->mad_hdr.attr_id == CM_REP_ATTR_ID || - mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID || - mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { - sl_cm_id = get_local_comm_id(mad); - id = id_map_alloc(ibdev, slave_id, sl_cm_id); - if (IS_ERR(id)) { - mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n", - __func__, slave_id, sl_cm_id); - return PTR_ERR(id); - } - } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID || - mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { - return 0; - } else { - sl_cm_id = get_local_comm_id(mad); - id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id); - } - - if (!id) { - pr_debug("id{slave: %d, sl_cm_id: 0x%x} is NULL!\n", - slave_id, sl_cm_id); - return -EINVAL; - } - - set_local_comm_id(mad, id->pv_cm_id); - - if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID) - schedule_delayed(ibdev, id); - else if (mad->mad_hdr.attr_id == CM_DREP_ATTR_ID) - id_map_find_del(ibdev, pv_cm_id); - - return 0; -} - -int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, - struct ib_mad *mad, int is_eth) -{ - u32 pv_cm_id; - struct id_map_entry *id; - - if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID || - mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { - union ib_gid gid; - - if (is_eth) - return 0; - - gid = gid_from_req_msg(ibdev, mad); - *slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id); - if (*slave < 0) { - mlx4_ib_warn(ibdev, "failed matching slave_id by gid (0x%llx)\n", - (unsigned long long)gid.global.interface_id); - return -ENOENT; - } - return 0; - } - - pv_cm_id = get_remote_comm_id(mad); - id = id_map_get(ibdev, (int *)&pv_cm_id, -1, -1); - - if (!id) { - pr_debug("Couldn't find an entry for pv_cm_id 0x%x\n", pv_cm_id); - return -ENOENT; - } - - if (!is_eth) - *slave = id->slave_id; - set_remote_comm_id(mad, id->sl_cm_id); - - if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID) - schedule_delayed(ibdev, id); - else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID || - mad->mad_hdr.attr_id == CM_DREP_ATTR_ID) { - id_map_find_del(ibdev, (int) pv_cm_id); - } - - return 0; -} - -void mlx4_ib_cm_paravirt_init(struct mlx4_ib_dev *dev) -{ - spin_lock_init(&dev->sriov.id_map_lock); - INIT_LIST_HEAD(&dev->sriov.cm_list); - dev->sriov.sl_id_map = RB_ROOT; - idr_init(&dev->sriov.pv_id_table); - idr_pre_get(&dev->sriov.pv_id_table, GFP_KERNEL); -} - -/* slave = -1 ==> all slaves */ -/* TBD -- call paravirt clean for single slave. Need for slave RESET event */ -void mlx4_ib_cm_paravirt_clean(struct mlx4_ib_dev *dev, int slave) -{ - struct mlx4_ib_sriov *sriov = &dev->sriov; - struct rb_root *sl_id_map = &sriov->sl_id_map; - struct list_head lh; - struct rb_node *nd; - int need_flush = 1; - struct id_map_entry *map, *tmp_map; - /* cancel all delayed work queue entries */ - INIT_LIST_HEAD(&lh); - spin_lock(&sriov->id_map_lock); - list_for_each_entry_safe(map, tmp_map, &dev->sriov.cm_list, list) { - if (slave < 0 || slave == map->slave_id) { - if (map->scheduled_delete) - need_flush &= !!cancel_delayed_work(&map->timeout); - } - } - - spin_unlock(&sriov->id_map_lock); - - if (!need_flush) - flush_scheduled_work(); /* make sure all timers were flushed */ - - /* now, remove all leftover entries from databases*/ - spin_lock(&sriov->id_map_lock); - if (slave < 0) { - while (rb_first(sl_id_map)) { - struct id_map_entry *ent = - rb_entry(rb_first(sl_id_map), - struct id_map_entry, node); - - rb_erase(&ent->node, sl_id_map); - idr_remove(&sriov->pv_id_table, (int) ent->pv_cm_id); - } - list_splice_init(&dev->sriov.cm_list, &lh); - } else { - /* first, move nodes belonging to slave to db remove list */ - nd = rb_first(sl_id_map); - while (nd) { - struct id_map_entry *ent = - rb_entry(nd, struct id_map_entry, node); - nd = rb_next(nd); - if (ent->slave_id == slave) - list_move_tail(&ent->list, &lh); - } - /* remove those nodes from databases */ - list_for_each_entry_safe(map, tmp_map, &lh, list) { - rb_erase(&map->node, sl_id_map); - idr_remove(&sriov->pv_id_table, (int) map->pv_cm_id); - } - - /* add remaining nodes from cm_list */ - list_for_each_entry_safe(map, tmp_map, &dev->sriov.cm_list, list) { - if (slave == map->slave_id) - list_move_tail(&map->list, &lh); - } - } - - spin_unlock(&sriov->id_map_lock); - - /* free any map entries left behind due to cancel_delayed_work above */ - list_for_each_entry_safe(map, tmp_map, &lh, list) { - list_del(&map->list); - kfree(map); - } -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/cq.c b/sys/ofed/drivers/infiniband/hw/mlx4/cq.c deleted file mode 100644 index 43bd9012a8d6..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/cq.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 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/mlx4/cq.h> -#include <linux/mlx4/qp.h> -#include <linux/mlx4/srq.h> -#include <linux/slab.h> - -#include "mlx4_ib.h" -#include "user.h" - -/* Which firmware version adds support for Resize CQ */ -#define MLX4_FW_VER_RESIZE_CQ mlx4_fw_ver(2, 5, 0) -#define MLX4_FW_VER_IGNORE_OVERRUN_CQ mlx4_fw_ver(2, 7, 8200) - -static void mlx4_ib_cq_comp(struct mlx4_cq *cq) -{ - struct ib_cq *ibcq = &to_mibcq(cq)->ibcq; - ibcq->comp_handler(ibcq, ibcq->cq_context); -} - -static void mlx4_ib_cq_event(struct mlx4_cq *cq, enum mlx4_event type) -{ - struct ib_event event; - struct ib_cq *ibcq; - - if (type != MLX4_EVENT_TYPE_CQ_ERROR) { - pr_warn("Unexpected event type %d " - "on CQ %06x\n", type, cq->cqn); - return; - } - - ibcq = &to_mibcq(cq)->ibcq; - if (ibcq->event_handler) { - event.device = ibcq->device; - event.event = IB_EVENT_CQ_ERR; - event.element.cq = ibcq; - ibcq->event_handler(&event, ibcq->cq_context); - } -} - -static void *get_cqe_from_buf(struct mlx4_ib_cq_buf *buf, int n) -{ - return mlx4_buf_offset(&buf->buf, n * buf->entry_size); -} - -static void *get_cqe(struct mlx4_ib_cq *cq, int n) -{ - return get_cqe_from_buf(&cq->buf, n); -} - -static void *get_sw_cqe(struct mlx4_ib_cq *cq, int n) -{ - struct mlx4_cqe *cqe = get_cqe(cq, n & cq->ibcq.cqe); - struct mlx4_cqe *tcqe = ((cq->buf.entry_size == 64) ? (cqe + 1) : cqe); - - return (!!(tcqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^ - !!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe; -} - -static struct mlx4_cqe *next_cqe_sw(struct mlx4_ib_cq *cq) -{ - return get_sw_cqe(cq, cq->mcq.cons_index); -} - -int mlx4_ib_modify_cq(struct ib_cq *cq, - struct ib_cq_attr *cq_attr, - int cq_attr_mask) -{ - int err = 0; - struct mlx4_ib_cq *mcq = to_mcq(cq); - struct mlx4_ib_dev *dev = to_mdev(cq->device); - - if (cq_attr_mask & IB_CQ_CAP_FLAGS) { - if (cq_attr->cq_cap_flags & IB_CQ_TIMESTAMP) - return -ENOTSUPP; - - if (cq_attr->cq_cap_flags & IB_CQ_IGNORE_OVERRUN) { - if (dev->dev->caps.cq_flags & MLX4_DEV_CAP_CQ_FLAG_IO) - err = mlx4_cq_ignore_overrun(dev->dev, &mcq->mcq); - else - err = -ENOSYS; - } - } - - if (!err) - if (cq_attr_mask & IB_CQ_MODERATION) - err = mlx4_cq_modify(dev->dev, &mcq->mcq, - cq_attr->moderation.cq_count, - cq_attr->moderation.cq_period); - - return err; -} - -static int mlx4_ib_alloc_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *buf, int nent) -{ - int err; - - err = mlx4_buf_alloc(dev->dev, nent * dev->dev->caps.cqe_size, - PAGE_SIZE * 2, &buf->buf); - - if (err) - goto out; - - buf->entry_size = dev->dev->caps.cqe_size; - err = mlx4_mtt_init(dev->dev, buf->buf.npages, buf->buf.page_shift, - &buf->mtt); - if (err) - goto err_buf; - - err = mlx4_buf_write_mtt(dev->dev, &buf->mtt, &buf->buf); - if (err) - goto err_mtt; - - return 0; - -err_mtt: - mlx4_mtt_cleanup(dev->dev, &buf->mtt); - -err_buf: - mlx4_buf_free(dev->dev, nent * buf->entry_size, &buf->buf); - -out: - return err; -} - -static void mlx4_ib_free_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *buf, int cqe) -{ - mlx4_buf_free(dev->dev, (cqe + 1) * buf->entry_size, &buf->buf); -} - -static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *context, - struct mlx4_ib_cq_buf *buf, struct ib_umem **umem, - u64 buf_addr, int cqe) -{ - int err; - int cqe_size = dev->dev->caps.cqe_size; - int shift; - int n; - - *umem = ib_umem_get(context, buf_addr, cqe * cqe_size, - IB_ACCESS_LOCAL_WRITE, 1); - if (IS_ERR(*umem)) - return PTR_ERR(*umem); - - n = ib_umem_page_count(*umem); - shift = mlx4_ib_umem_calc_optimal_mtt_size(*umem, 0, &n); - err = mlx4_mtt_init(dev->dev, n, shift, &buf->mtt); - - if (err) - goto err_buf; - - err = mlx4_ib_umem_write_mtt(dev, &buf->mtt, *umem); - if (err) - goto err_mtt; - - return 0; - -err_mtt: - mlx4_mtt_cleanup(dev->dev, &buf->mtt); - -err_buf: - ib_umem_release(*umem); - - return err; -} - -/* we don't support system timestamping */ -#define CQ_CREATE_FLAGS_SUPPORTED IB_CQ_TIMESTAMP - -struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, - struct ib_cq_init_attr *attr, - struct ib_ucontext *context, - struct ib_udata *udata) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct mlx4_ib_cq *cq; - struct mlx4_uar *uar; - int err; - int entries = attr->cqe; - int vector = attr->comp_vector; - - if (entries < 1 || entries > dev->dev->caps.max_cqes) - return ERR_PTR(-EINVAL); - - if (attr->flags & ~CQ_CREATE_FLAGS_SUPPORTED) - return ERR_PTR(-EINVAL); - - cq = kzalloc(sizeof(*cq), GFP_KERNEL); - if (!cq) - return ERR_PTR(-ENOMEM); - - entries = roundup_pow_of_two(entries + 1); - cq->ibcq.cqe = entries - 1; - mutex_init(&cq->resize_mutex); - spin_lock_init(&cq->lock); - cq->resize_buf = NULL; - cq->resize_umem = NULL; - cq->create_flags = attr->flags; - - if (context) { - struct mlx4_ib_create_cq ucmd; - - if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { - err = -EFAULT; - goto err_cq; - } - - err = mlx4_ib_get_cq_umem(dev, context, &cq->buf, &cq->umem, - ucmd.buf_addr, entries); - if (err) - goto err_cq; - - err = mlx4_ib_db_map_user(to_mucontext(context), ucmd.db_addr, - &cq->db); - if (err) - goto err_mtt; - - uar = &to_mucontext(context)->uar; - } else { - err = mlx4_db_alloc(dev->dev, &cq->db, 1); - if (err) - goto err_cq; - - cq->mcq.set_ci_db = cq->db.db; - cq->mcq.arm_db = cq->db.db + 1; - *cq->mcq.set_ci_db = 0; - *cq->mcq.arm_db = 0; - - err = mlx4_ib_alloc_cq_buf(dev, &cq->buf, entries); - if (err) - goto err_db; - - uar = &dev->priv_uar; - } - - if (dev->eq_table) - vector = dev->eq_table[vector % ibdev->num_comp_vectors]; - - err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, - cq->db.dma, &cq->mcq, vector, 0, - !!(cq->create_flags & IB_CQ_TIMESTAMP)); - if (err) - goto err_dbmap; - - cq->mcq.comp = mlx4_ib_cq_comp; - cq->mcq.event = mlx4_ib_cq_event; - - if (context) - if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof (__u32))) { - err = -EFAULT; - goto err_dbmap; - } - - return &cq->ibcq; - -err_dbmap: - if (context) - mlx4_ib_db_unmap_user(to_mucontext(context), &cq->db); - -err_mtt: - mlx4_mtt_cleanup(dev->dev, &cq->buf.mtt); - - if (context) - ib_umem_release(cq->umem); - else - mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); - -err_db: - if (!context) - mlx4_db_free(dev->dev, &cq->db); - -err_cq: - kfree(cq); - - return ERR_PTR(err); -} - -static int mlx4_alloc_resize_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq, - int entries) -{ - int err; - - if (cq->resize_buf) - return -EBUSY; - - cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); - if (!cq->resize_buf) - return -ENOMEM; - - err = mlx4_ib_alloc_cq_buf(dev, &cq->resize_buf->buf, entries); - if (err) { - kfree(cq->resize_buf); - cq->resize_buf = NULL; - return err; - } - - cq->resize_buf->cqe = entries - 1; - - return 0; -} - -static int mlx4_alloc_resize_umem(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq, - int entries, struct ib_udata *udata) -{ - struct mlx4_ib_resize_cq ucmd; - int err; - - if (cq->resize_umem) - return -EBUSY; - - if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) - return -EFAULT; - - cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); - if (!cq->resize_buf) - return -ENOMEM; - - err = mlx4_ib_get_cq_umem(dev, cq->umem->context, &cq->resize_buf->buf, - &cq->resize_umem, ucmd.buf_addr, entries); - if (err) { - kfree(cq->resize_buf); - cq->resize_buf = NULL; - return err; - } - - cq->resize_buf->cqe = entries - 1; - - return 0; -} - -static int mlx4_ib_get_outstanding_cqes(struct mlx4_ib_cq *cq) -{ - u32 i; - - i = cq->mcq.cons_index; - while (get_sw_cqe(cq, i)) - ++i; - - return i - cq->mcq.cons_index; -} - -static int mlx4_ib_cq_resize_copy_cqes(struct mlx4_ib_cq *cq) -{ - struct mlx4_cqe *cqe, *new_cqe; - int i; - int cqe_size = cq->buf.entry_size; - int cqe_inc = cqe_size == 64 ? 1 : 0; - struct mlx4_cqe *start_cqe; - - i = cq->mcq.cons_index; - cqe = get_cqe(cq, i & cq->ibcq.cqe); - start_cqe = cqe; - cqe += cqe_inc; - - while ((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) != MLX4_CQE_OPCODE_RESIZE) { - new_cqe = get_cqe_from_buf(&cq->resize_buf->buf, - (i + 1) & cq->resize_buf->cqe); - memcpy(new_cqe, get_cqe(cq, i & cq->ibcq.cqe), cqe_size); - new_cqe += cqe_inc; - - new_cqe->owner_sr_opcode = (cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK) | - (((i + 1) & (cq->resize_buf->cqe + 1)) ? MLX4_CQE_OWNER_MASK : 0); - cqe = get_cqe(cq, ++i & cq->ibcq.cqe); - if (cqe == start_cqe) { - pr_warn("resize CQ failed to get resize CQE, CQN 0x%x\n", cq->mcq.cqn); - return -ENOMEM; - } - cqe += cqe_inc; - - } - ++cq->mcq.cons_index; - return 0; -} - -int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) -{ - struct mlx4_ib_dev *dev = to_mdev(ibcq->device); - struct mlx4_ib_cq *cq = to_mcq(ibcq); - struct mlx4_mtt mtt; - int outst_cqe; - int err; - - if (dev->dev->caps.fw_ver < MLX4_FW_VER_RESIZE_CQ) - return -ENOSYS; - - mutex_lock(&cq->resize_mutex); - if (entries < 1 || entries > dev->dev->caps.max_cqes) { - err = -EINVAL; - goto out; - } - - entries = roundup_pow_of_two(entries + 1); - if (entries == ibcq->cqe + 1) { - err = 0; - goto out; - } - - if (entries > dev->dev->caps.max_cqes + 1) { - err = -EINVAL; - goto out; - } - - if (ibcq->uobject) { - err = mlx4_alloc_resize_umem(dev, cq, entries, udata); - if (err) - goto out; - } else { - /* Can't be smaller than the number of outstanding CQEs */ - outst_cqe = mlx4_ib_get_outstanding_cqes(cq); - if (entries < outst_cqe + 1) { - err = 0; - goto out; - } - - err = mlx4_alloc_resize_buf(dev, cq, entries); - if (err) - goto out; - } - - mtt = cq->buf.mtt; - - err = mlx4_cq_resize(dev->dev, &cq->mcq, entries, &cq->resize_buf->buf.mtt); - if (err) - goto err_buf; - - mlx4_mtt_cleanup(dev->dev, &mtt); - if (ibcq->uobject) { - cq->buf = cq->resize_buf->buf; - cq->ibcq.cqe = cq->resize_buf->cqe; - ib_umem_release(cq->umem); - cq->umem = cq->resize_umem; - - kfree(cq->resize_buf); - cq->resize_buf = NULL; - cq->resize_umem = NULL; - } else { - struct mlx4_ib_cq_buf tmp_buf; - int tmp_cqe = 0; - - spin_lock_irq(&cq->lock); - if (cq->resize_buf) { - err = mlx4_ib_cq_resize_copy_cqes(cq); - tmp_buf = cq->buf; - tmp_cqe = cq->ibcq.cqe; - cq->buf = cq->resize_buf->buf; - cq->ibcq.cqe = cq->resize_buf->cqe; - - kfree(cq->resize_buf); - cq->resize_buf = NULL; - } - spin_unlock_irq(&cq->lock); - - if (tmp_cqe) - mlx4_ib_free_cq_buf(dev, &tmp_buf, tmp_cqe); - } - - goto out; - -err_buf: - mlx4_mtt_cleanup(dev->dev, &cq->resize_buf->buf.mtt); - if (!ibcq->uobject) - mlx4_ib_free_cq_buf(dev, &cq->resize_buf->buf, - cq->resize_buf->cqe); - - kfree(cq->resize_buf); - cq->resize_buf = NULL; - - if (cq->resize_umem) { - ib_umem_release(cq->resize_umem); - cq->resize_umem = NULL; - } - -out: - mutex_unlock(&cq->resize_mutex); - - return err; -} - -int mlx4_ib_ignore_overrun_cq(struct ib_cq *ibcq) -{ - struct mlx4_ib_dev *dev = to_mdev(ibcq->device); - struct mlx4_ib_cq *cq = to_mcq(ibcq); - - if (dev->dev->caps.fw_ver < MLX4_FW_VER_IGNORE_OVERRUN_CQ) - return -ENOSYS; - - return mlx4_cq_ignore_overrun(dev->dev, &cq->mcq); -} - -int mlx4_ib_destroy_cq(struct ib_cq *cq) -{ - struct mlx4_ib_dev *dev = to_mdev(cq->device); - struct mlx4_ib_cq *mcq = to_mcq(cq); - - mlx4_cq_free(dev->dev, &mcq->mcq); - mlx4_mtt_cleanup(dev->dev, &mcq->buf.mtt); - - if (cq->uobject) { - mlx4_ib_db_unmap_user(to_mucontext(cq->uobject->context), &mcq->db); - ib_umem_release(mcq->umem); - } else { - mlx4_ib_free_cq_buf(dev, &mcq->buf, cq->cqe); - mlx4_db_free(dev->dev, &mcq->db); - } - - kfree(mcq); - - return 0; -} - -static void dump_cqe(void *cqe) -{ - __be32 *buf = cqe; - - pr_debug("CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n", - be32_to_cpu(buf[0]), be32_to_cpu(buf[1]), be32_to_cpu(buf[2]), - be32_to_cpu(buf[3]), be32_to_cpu(buf[4]), be32_to_cpu(buf[5]), - be32_to_cpu(buf[6]), be32_to_cpu(buf[7])); -} - -static void mlx4_ib_handle_error_cqe(struct mlx4_err_cqe *cqe, - struct ib_wc *wc) -{ - if (cqe->syndrome == MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR) { - pr_debug("local QP operation err " - "(QPN %06x, WQE index %x, vendor syndrome %02x, " - "opcode = %02x)\n", - be32_to_cpu(cqe->my_qpn), be16_to_cpu(cqe->wqe_index), - cqe->vendor_err_syndrome, - cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); - dump_cqe(cqe); - } - - switch (cqe->syndrome) { - case MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR: - wc->status = IB_WC_LOC_LEN_ERR; - break; - case MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR: - wc->status = IB_WC_LOC_QP_OP_ERR; - break; - case MLX4_CQE_SYNDROME_LOCAL_PROT_ERR: - wc->status = IB_WC_LOC_PROT_ERR; - break; - case MLX4_CQE_SYNDROME_WR_FLUSH_ERR: - wc->status = IB_WC_WR_FLUSH_ERR; - break; - case MLX4_CQE_SYNDROME_MW_BIND_ERR: - wc->status = IB_WC_MW_BIND_ERR; - break; - case MLX4_CQE_SYNDROME_BAD_RESP_ERR: - wc->status = IB_WC_BAD_RESP_ERR; - break; - case MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR: - wc->status = IB_WC_LOC_ACCESS_ERR; - break; - case MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR: - wc->status = IB_WC_REM_INV_REQ_ERR; - break; - case MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR: - wc->status = IB_WC_REM_ACCESS_ERR; - break; - case MLX4_CQE_SYNDROME_REMOTE_OP_ERR: - wc->status = IB_WC_REM_OP_ERR; - break; - case MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR: - wc->status = IB_WC_RETRY_EXC_ERR; - break; - case MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR: - wc->status = IB_WC_RNR_RETRY_EXC_ERR; - break; - case MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR: - wc->status = IB_WC_REM_ABORT_ERR; - break; - default: - wc->status = IB_WC_GENERAL_ERR; - break; - } - - wc->vendor_err = cqe->vendor_err_syndrome; -} - -static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum) -{ - return ((status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 | - MLX4_CQE_STATUS_IPV4F | - MLX4_CQE_STATUS_IPV4OPT | - MLX4_CQE_STATUS_IPV6 | - MLX4_CQE_STATUS_IPOK)) == - cpu_to_be16(MLX4_CQE_STATUS_IPV4 | - MLX4_CQE_STATUS_IPOK)) && - (status & cpu_to_be16(MLX4_CQE_STATUS_UDP | - MLX4_CQE_STATUS_TCP)) && - checksum == cpu_to_be16(0xffff); -} - -static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct ib_wc *wc, - unsigned tail, struct mlx4_cqe *cqe, int is_eth) -{ - struct mlx4_ib_proxy_sqp_hdr *hdr; - - ib_dma_sync_single_for_cpu(qp->ibqp.device, - qp->sqp_proxy_rcv[tail].map, - sizeof (struct mlx4_ib_proxy_sqp_hdr), - DMA_FROM_DEVICE); - hdr = (struct mlx4_ib_proxy_sqp_hdr *) (qp->sqp_proxy_rcv[tail].addr); - wc->pkey_index = be16_to_cpu(hdr->tun.pkey_index); - wc->src_qp = be32_to_cpu(hdr->tun.flags_src_qp) & 0xFFFFFF; - wc->wc_flags |= (hdr->tun.g_ml_path & 0x80) ? (IB_WC_GRH) : 0; - wc->dlid_path_bits = 0; - - if (is_eth) { - wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); - memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); - memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); - } else { - wc->slid = be16_to_cpu(hdr->tun.slid_mac_47_32); - wc->sl = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12); - } - - return 0; -} - -static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, - struct mlx4_ib_qp **cur_qp, - struct ib_wc *wc) -{ - struct mlx4_cqe *cqe; - struct mlx4_qp *mqp; - struct mlx4_ib_wq *wq; - struct mlx4_ib_srq *srq; - struct mlx4_srq *msrq = NULL; - int is_send; - int is_error; - u32 g_mlpath_rqpn; - u16 wqe_ctr; - unsigned tail = 0; - int timestamp_en = !!(cq->create_flags & IB_CQ_TIMESTAMP); - - -repoll: - cqe = next_cqe_sw(cq); - if (!cqe) - return -EAGAIN; - - if (cq->buf.entry_size == 64) - cqe++; - - ++cq->mcq.cons_index; - - /* - * Make sure we read CQ entry contents after we've checked the - * ownership bit. - */ - rmb(); - - is_send = cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK; - is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == - MLX4_CQE_OPCODE_ERROR; - - if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_OPCODE_NOP && - is_send)) { - pr_warn("Completion for NOP opcode detected!\n"); - return -EINVAL; - } - - /* Resize CQ in progress */ - if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_RESIZE)) { - if (cq->resize_buf) { - struct mlx4_ib_dev *dev = to_mdev(cq->ibcq.device); - - mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); - cq->buf = cq->resize_buf->buf; - cq->ibcq.cqe = cq->resize_buf->cqe; - - kfree(cq->resize_buf); - cq->resize_buf = NULL; - } - - goto repoll; - } - - if (!*cur_qp || - (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK) != (*cur_qp)->mqp.qpn) { - /* - * We do not have to take the QP table lock here, - * because CQs will be locked while QPs are removed - * from the table. - */ - mqp = __mlx4_qp_lookup(to_mdev(cq->ibcq.device)->dev, - be32_to_cpu(cqe->vlan_my_qpn)); - if (unlikely(!mqp)) { - pr_warn("CQ %06x with entry for unknown QPN %06x\n", - cq->mcq.cqn, be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK); - return -EINVAL; - } - - *cur_qp = to_mibqp(mqp); - } - - wc->qp = &(*cur_qp)->ibqp; - - if (wc->qp->qp_type == IB_QPT_XRC_TGT) { - u32 srq_num; - g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); - srq_num = g_mlpath_rqpn & 0xffffff; - /* SRQ is also in the radix tree */ - msrq = mlx4_srq_lookup(to_mdev(cq->ibcq.device)->dev, - srq_num); - if (unlikely(!msrq)) { - pr_warn("CQ %06x with entry for unknown SRQN %06x\n", - cq->mcq.cqn, srq_num); - return -EINVAL; - } - } - - if (is_send) { - wq = &(*cur_qp)->sq; - if (!(*cur_qp)->sq_signal_bits) { - wqe_ctr = be16_to_cpu(cqe->wqe_index); - wq->tail += (u16) (wqe_ctr - (u16) wq->tail); - } - wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; - ++wq->tail; - } else if ((*cur_qp)->ibqp.srq) { - srq = to_msrq((*cur_qp)->ibqp.srq); - wqe_ctr = be16_to_cpu(cqe->wqe_index); - wc->wr_id = srq->wrid[wqe_ctr]; - mlx4_ib_free_srq_wqe(srq, wqe_ctr); - } else if (msrq) { - srq = to_mibsrq(msrq); - wqe_ctr = be16_to_cpu(cqe->wqe_index); - wc->wr_id = srq->wrid[wqe_ctr]; - mlx4_ib_free_srq_wqe(srq, wqe_ctr); - } else { - wq = &(*cur_qp)->rq; - tail = wq->tail & (wq->wqe_cnt - 1); - wc->wr_id = wq->wrid[tail]; - ++wq->tail; - } - - if (unlikely(is_error)) { - mlx4_ib_handle_error_cqe((struct mlx4_err_cqe *) cqe, wc); - return 0; - } - - wc->status = IB_WC_SUCCESS; - - if (is_send) { - wc->wc_flags = 0; - switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { - case MLX4_OPCODE_RDMA_WRITE_IMM: - wc->wc_flags |= IB_WC_WITH_IMM; - /* fall through */ - case MLX4_OPCODE_RDMA_WRITE: - wc->opcode = IB_WC_RDMA_WRITE; - break; - case MLX4_OPCODE_SEND_IMM: - wc->wc_flags |= IB_WC_WITH_IMM; - case MLX4_OPCODE_SEND: - case MLX4_OPCODE_SEND_INVAL: - wc->opcode = IB_WC_SEND; - break; - case MLX4_OPCODE_RDMA_READ: - wc->opcode = IB_WC_RDMA_READ; - wc->byte_len = be32_to_cpu(cqe->byte_cnt); - break; - case MLX4_OPCODE_ATOMIC_CS: - wc->opcode = IB_WC_COMP_SWAP; - wc->byte_len = 8; - break; - case MLX4_OPCODE_ATOMIC_FA: - wc->opcode = IB_WC_FETCH_ADD; - wc->byte_len = 8; - break; - case MLX4_OPCODE_MASKED_ATOMIC_CS: - wc->opcode = IB_WC_MASKED_COMP_SWAP; - wc->byte_len = 8; - break; - case MLX4_OPCODE_MASKED_ATOMIC_FA: - wc->opcode = IB_WC_MASKED_FETCH_ADD; - wc->byte_len = 8; - break; - case MLX4_OPCODE_BIND_MW: - wc->opcode = IB_WC_BIND_MW; - break; - case MLX4_OPCODE_LSO: - wc->opcode = IB_WC_LSO; - break; - case MLX4_OPCODE_FMR: - wc->opcode = IB_WC_FAST_REG_MR; - break; - case MLX4_OPCODE_LOCAL_INVAL: - wc->opcode = IB_WC_LOCAL_INV; - break; - } - } else { - wc->byte_len = be32_to_cpu(cqe->byte_cnt); - - switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { - case MLX4_RECV_OPCODE_RDMA_WRITE_IMM: - wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; - wc->wc_flags = IB_WC_WITH_IMM; - wc->ex.imm_data = cqe->immed_rss_invalid; - break; - case MLX4_RECV_OPCODE_SEND_INVAL: - wc->opcode = IB_WC_RECV; - wc->wc_flags = IB_WC_WITH_INVALIDATE; - wc->ex.invalidate_rkey = be32_to_cpu(cqe->immed_rss_invalid); - break; - case MLX4_RECV_OPCODE_SEND: - wc->opcode = IB_WC_RECV; - wc->wc_flags = 0; - break; - case MLX4_RECV_OPCODE_SEND_IMM: - wc->opcode = IB_WC_RECV; - wc->wc_flags = IB_WC_WITH_IMM; - wc->ex.imm_data = cqe->immed_rss_invalid; - break; - } - - if (mlx4_is_mfunc(to_mdev(cq->ibcq.device)->dev)) { - if ((*cur_qp)->mlx4_ib_qp_type & - (MLX4_IB_QPT_PROXY_SMI_OWNER | - MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) - return use_tunnel_data - (*cur_qp, cq, wc, tail, cqe, - rdma_port_get_link_layer - (wc->qp->device, - (*cur_qp)->port) == - IB_LINK_LAYER_ETHERNET); - } - - if (timestamp_en) { - /* currently, only CQ_CREATE_WITH_TIMESTAMPING_RAW is - * supported. CQ_CREATE_WITH_TIMESTAMPING_SYS isn't - * supported */ - if (cq->create_flags & IB_CQ_TIMESTAMP_TO_SYS_TIME) { - wc->ts.timestamp = 0; - } else { - wc->ts.timestamp = - ((u64)(be32_to_cpu(cqe->timestamp_16_47) - + !cqe->timestamp_0_15) << 16) - | be16_to_cpu(cqe->timestamp_0_15); - wc->wc_flags |= IB_WC_WITH_TIMESTAMP; - } - } else { - wc->wc_flags |= IB_WC_WITH_SLID; - wc->slid = be16_to_cpu(cqe->rlid); - } - g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); - wc->src_qp = g_mlpath_rqpn & 0xffffff; - wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; - wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; - wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; - wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, - cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; - if (!timestamp_en) { - if (rdma_port_get_link_layer(wc->qp->device, - (*cur_qp)->port) == - IB_LINK_LAYER_ETHERNET) - wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; - else - wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; - wc->wc_flags |= IB_WC_WITH_SL; - } - if ((be32_to_cpu(cqe->vlan_my_qpn) & - MLX4_CQE_VLAN_PRESENT_MASK) && !timestamp_en) { - wc->vlan_id = be16_to_cpu(cqe->sl_vid) & - MLX4_CQE_VID_MASK; - wc->wc_flags |= IB_WC_WITH_VLAN; - } else { - wc->vlan_id = 0xffff; - } - if (!timestamp_en) { - memcpy(wc->smac, cqe->smac, 6); - wc->wc_flags |= IB_WC_WITH_SMAC; - } - } - - return 0; -} - -int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) -{ - struct mlx4_ib_cq *cq = to_mcq(ibcq); - struct mlx4_ib_qp *cur_qp = NULL; - unsigned long flags; - int npolled; - int err = 0; - - spin_lock_irqsave(&cq->lock, flags); - - for (npolled = 0; npolled < num_entries; ++npolled) { - err = mlx4_ib_poll_one(cq, &cur_qp, wc + npolled); - if (err) - break; - } - - mlx4_cq_set_ci(&cq->mcq); - - spin_unlock_irqrestore(&cq->lock, flags); - - if (err == 0 || err == -EAGAIN) - return npolled; - else - return err; -} - -int mlx4_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) -{ - mlx4_cq_arm(&to_mcq(ibcq)->mcq, - (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? - MLX4_CQ_DB_REQ_NOT_SOL : MLX4_CQ_DB_REQ_NOT, - to_mdev(ibcq->device)->priv_uar.map, - MLX4_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->uar_lock)); - - return 0; -} - -void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq) -{ - u32 prod_index; - int nfreed = 0; - struct mlx4_cqe *cqe, *dest; - u8 owner_bit; - int cqe_inc = cq->buf.entry_size == 64 ? 1 : 0; - - /* - * First we need to find the current producer index, so we - * know where to start cleaning from. It doesn't matter if HW - * adds new entries after this loop -- the QP we're worried - * about is already in RESET, so the new entries won't come - * from our QP and therefore don't need to be checked. - */ - for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); ++prod_index) - if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe) - break; - - /* - * Now sweep backwards through the CQ, removing CQ entries - * that match our QP by copying older entries on top of them. - */ - while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) { - cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); - cqe += cqe_inc; - - if ((be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK) == qpn) { - if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) - mlx4_ib_free_srq_wqe(srq, be16_to_cpu(cqe->wqe_index)); - ++nfreed; - } else if (nfreed) { - dest = get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe); - dest += cqe_inc; - - owner_bit = dest->owner_sr_opcode & MLX4_CQE_OWNER_MASK; - memcpy(dest, cqe, sizeof *cqe); - dest->owner_sr_opcode = owner_bit | - (dest->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); - } - } - - if (nfreed) { - cq->mcq.cons_index += nfreed; - /* - * Make sure update of buffer contents is done before - * updating consumer index. - */ - wmb(); - mlx4_cq_set_ci(&cq->mcq); - } -} - -void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq) -{ - spin_lock_irq(&cq->lock); - __mlx4_ib_cq_clean(cq, qpn, srq); - spin_unlock_irq(&cq->lock); -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/doorbell.c b/sys/ofed/drivers/infiniband/hw/mlx4/doorbell.c deleted file mode 100644 index c51740986367..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/doorbell.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. 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/slab.h> - -#include "mlx4_ib.h" - -struct mlx4_ib_user_db_page { - struct list_head list; - struct ib_umem *umem; - unsigned long user_virt; - int refcnt; -}; - -int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, - struct mlx4_db *db) -{ - struct mlx4_ib_user_db_page *page; - int err = 0; - - mutex_lock(&context->db_page_mutex); - - list_for_each_entry(page, &context->db_page_list, list) - if (page->user_virt == (virt & PAGE_MASK)) - goto found; - - page = kmalloc(sizeof *page, GFP_KERNEL); - if (!page) { - err = -ENOMEM; - goto out; - } - - page->user_virt = (virt & PAGE_MASK); - page->refcnt = 0; - page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, - PAGE_SIZE, 0, 0); - if (IS_ERR(page->umem)) { - err = PTR_ERR(page->umem); - kfree(page); - goto out; - } - - list_add(&page->list, &context->db_page_list); - -found: - db->dma = sg_dma_address(page->umem->sg_head.sgl) + (virt & ~PAGE_MASK); - db->u.user_page = page; - ++page->refcnt; - -out: - mutex_unlock(&context->db_page_mutex); - - return err; -} - -void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db) -{ - mutex_lock(&context->db_page_mutex); - - if (!--db->u.user_page->refcnt) { - list_del(&db->u.user_page->list); - ib_umem_release(db->u.user_page->umem); - kfree(db->u.user_page); - } - - mutex_unlock(&context->db_page_mutex); -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mad.c b/sys/ofed/drivers/infiniband/hw/mlx4/mad.c deleted file mode 100644 index 9c5b1402c739..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/mad.c +++ /dev/null @@ -1,2350 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. 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 <rdma/ib_mad.h> -#include <rdma/ib_smi.h> -#include <rdma/ib_sa.h> -#include <rdma/ib_cache.h> - -#include <linux/random.h> -#include <linux/mlx4/cmd.h> -#include <linux/gfp.h> -#include <rdma/ib_pma.h> - -#include "mlx4_ib.h" - -enum { - MLX4_IB_VENDOR_CLASS1 = 0x9, - MLX4_IB_VENDOR_CLASS2 = 0xa -}; - -#define MLX4_TUN_SEND_WRID_SHIFT 34 -#define MLX4_TUN_QPN_SHIFT 32 -#define MLX4_TUN_WRID_RECV (((u64) 1) << MLX4_TUN_SEND_WRID_SHIFT) -#define MLX4_TUN_SET_WRID_QPN(a) (((u64) ((a) & 0x3)) << MLX4_TUN_QPN_SHIFT) - -#define MLX4_TUN_IS_RECV(a) (((a) >> MLX4_TUN_SEND_WRID_SHIFT) & 0x1) -#define MLX4_TUN_WRID_QPN(a) (((a) >> MLX4_TUN_QPN_SHIFT) & 0x3) - - /* Port mgmt change event handling */ - -#define GET_BLK_PTR_FROM_EQE(eqe) be32_to_cpu(eqe->event.port_mgmt_change.params.tbl_change_info.block_ptr) -#define GET_MASK_FROM_EQE(eqe) be32_to_cpu(eqe->event.port_mgmt_change.params.tbl_change_info.tbl_entries_mask) -#define NUM_IDX_IN_PKEY_TBL_BLK 32 -#define GUID_TBL_ENTRY_SIZE 8 /* size in bytes */ -#define GUID_TBL_BLK_NUM_ENTRIES 8 -#define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES) - -struct mlx4_mad_rcv_buf { - struct ib_grh grh; - u8 payload[256]; -} __packed; - -struct mlx4_mad_snd_buf { - u8 payload[256]; -} __packed; - -struct mlx4_tunnel_mad { - struct ib_grh grh; - struct mlx4_ib_tunnel_header hdr; - struct ib_mad mad; -} __packed; - -struct mlx4_rcv_tunnel_mad { - struct mlx4_rcv_tunnel_hdr hdr; - struct ib_grh grh; - struct ib_mad mad; -} __packed; - -static void handle_client_rereg_event(struct mlx4_ib_dev *dev, u8 port_num); -static void handle_lid_change_event(struct mlx4_ib_dev *dev, u8 port_num); -static void __propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, - int block, u32 change_bitmap); - -__be64 mlx4_ib_gen_node_guid(void) -{ -#define NODE_GUID_HI ((u64) (((u64)IB_OPENIB_OUI) << 40)) - return cpu_to_be64(NODE_GUID_HI | random()); -} - -__be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx) -{ - return cpu_to_be64(atomic_inc_return(&ctx->tid)) | - cpu_to_be64(0xff00000000000000LL); -} - -int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int mad_ifc_flags, - int port, struct ib_wc *in_wc, struct ib_grh *in_grh, - void *in_mad, void *response_mad) -{ - struct mlx4_cmd_mailbox *inmailbox, *outmailbox; - void *inbox; - int err; - u32 in_modifier = port; - u8 op_modifier = 0; - - inmailbox = mlx4_alloc_cmd_mailbox(dev->dev); - if (IS_ERR(inmailbox)) - return PTR_ERR(inmailbox); - inbox = inmailbox->buf; - - outmailbox = mlx4_alloc_cmd_mailbox(dev->dev); - if (IS_ERR(outmailbox)) { - mlx4_free_cmd_mailbox(dev->dev, inmailbox); - return PTR_ERR(outmailbox); - } - - memcpy(inbox, in_mad, 256); - - /* - * Key check traps can't be generated unless we have in_wc to - * tell us where to send the trap. - */ - if ((mad_ifc_flags & MLX4_MAD_IFC_IGNORE_MKEY) || !in_wc) - op_modifier |= 0x1; - if ((mad_ifc_flags & MLX4_MAD_IFC_IGNORE_BKEY) || !in_wc) - op_modifier |= 0x2; - if (mlx4_is_mfunc(dev->dev) && - (mad_ifc_flags & MLX4_MAD_IFC_NET_VIEW || in_wc)) - op_modifier |= 0x8; - - if (in_wc) { - struct { - __be32 my_qpn; - u32 reserved1; - __be32 rqpn; - u8 sl; - u8 g_path; - u16 reserved2[2]; - __be16 pkey; - u32 reserved3[11]; - u8 grh[40]; - } *ext_info; - - memset(inbox + 256, 0, 256); - ext_info = inbox + 256; - - ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num); - ext_info->rqpn = cpu_to_be32(in_wc->src_qp); - ext_info->sl = in_wc->sl << 4; - ext_info->g_path = in_wc->dlid_path_bits | - (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0); - ext_info->pkey = cpu_to_be16(in_wc->pkey_index); - - if (in_grh) - memcpy(ext_info->grh, in_grh, 40); - - op_modifier |= 0x4; - - in_modifier |= in_wc->slid << 16; - } - - err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma, in_modifier, - mlx4_is_master(dev->dev) ? (op_modifier & ~0x8) : op_modifier, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, - (op_modifier & 0x8) ? MLX4_CMD_NATIVE : MLX4_CMD_WRAPPED); - - if (!err) - memcpy(response_mad, outmailbox->buf, 256); - - mlx4_free_cmd_mailbox(dev->dev, inmailbox); - mlx4_free_cmd_mailbox(dev->dev, outmailbox); - - return err; -} - -static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl) -{ - struct ib_ah *new_ah; - struct ib_ah_attr ah_attr; - unsigned long flags; - - if (!dev->send_agent[port_num - 1][0]) - return; - - memset(&ah_attr, 0, sizeof ah_attr); - ah_attr.dlid = lid; - ah_attr.sl = sl; - ah_attr.port_num = port_num; - - new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, - &ah_attr); - if (IS_ERR(new_ah)) - return; - - spin_lock_irqsave(&dev->sm_lock, flags); - if (dev->sm_ah[port_num - 1]) - ib_destroy_ah(dev->sm_ah[port_num - 1]); - dev->sm_ah[port_num - 1] = new_ah; - spin_unlock_irqrestore(&dev->sm_lock, flags); -} - -/* - * Snoop SM MADs for port info, GUID info, and P_Key table sets, so we can - * synthesize LID change, Client-Rereg, GID change, and P_Key change events. - */ -static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad, - u16 prev_lid) -{ - struct ib_port_info *pinfo; - u16 lid; - __be16 *base; - u32 bn, pkey_change_bitmap; - int i; - - - struct mlx4_ib_dev *dev = to_mdev(ibdev); - if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || - mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && - mad->mad_hdr.method == IB_MGMT_METHOD_SET) - switch (mad->mad_hdr.attr_id) { - case IB_SMP_ATTR_PORT_INFO: - pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data; - lid = be16_to_cpu(pinfo->lid); - - update_sm_ah(dev, port_num, - be16_to_cpu(pinfo->sm_lid), - pinfo->neighbormtu_mastersmsl & 0xf); - - if (pinfo->clientrereg_resv_subnetto & 0x80) - handle_client_rereg_event(dev, port_num); - - if (prev_lid != lid) - handle_lid_change_event(dev, port_num); - break; - - case IB_SMP_ATTR_PKEY_TABLE: - if (!mlx4_is_mfunc(dev->dev)) { - mlx4_ib_dispatch_event(dev, port_num, - IB_EVENT_PKEY_CHANGE); - break; - } - - /* at this point, we are running in the master. - * Slaves do not receive SMPs. - */ - bn = be32_to_cpu(((struct ib_smp *)mad)->attr_mod) & 0xFFFF; - base = (__be16 *) &(((struct ib_smp *)mad)->data[0]); - pkey_change_bitmap = 0; - for (i = 0; i < 32; i++) { - pr_debug("PKEY[%d] = x%x\n", - i + bn*32, be16_to_cpu(base[i])); - if (be16_to_cpu(base[i]) != - dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32]) { - pkey_change_bitmap |= (1 << i); - dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32] = - be16_to_cpu(base[i]); - } - } - pr_debug("PKEY Change event: port=%d, " - "block=0x%x, change_bitmap=0x%x\n", - port_num, bn, pkey_change_bitmap); - - if (pkey_change_bitmap) { - mlx4_ib_dispatch_event(dev, port_num, - IB_EVENT_PKEY_CHANGE); - if (!dev->sriov.is_going_down) - __propagate_pkey_ev(dev, port_num, bn, - pkey_change_bitmap); - } - break; - - case IB_SMP_ATTR_GUID_INFO: - /* paravirtualized master's guid is guid 0 -- does not change */ - if (!mlx4_is_master(dev->dev)) - mlx4_ib_dispatch_event(dev, port_num, - IB_EVENT_GID_CHANGE); - /*if master, notify relevant slaves*/ - if (mlx4_is_master(dev->dev) && - !dev->sriov.is_going_down) { - bn = be32_to_cpu(((struct ib_smp *)mad)->attr_mod); - mlx4_ib_update_cache_on_guid_change(dev, bn, port_num, - (u8 *)(&((struct ib_smp *)mad)->data)); - mlx4_ib_notify_slaves_on_guid_change(dev, bn, port_num, - (u8 *)(&((struct ib_smp *)mad)->data)); - } - break; - - default: - break; - } -} - -static void __propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, - int block, u32 change_bitmap) -{ - int i, ix, slave, err; - int have_event = 0; - - for (slave = 0; slave < dev->dev->caps.sqp_demux; slave++) { - if (slave == mlx4_master_func_num(dev->dev)) - continue; - if (!mlx4_is_slave_active(dev->dev, slave)) - continue; - - have_event = 0; - for (i = 0; i < 32; i++) { - if (!(change_bitmap & (1 << i))) - continue; - for (ix = 0; - ix < dev->dev->caps.pkey_table_len[port_num]; ix++) { - if (dev->pkeys.virt2phys_pkey[slave][port_num - 1] - [ix] == i + 32 * block) { - err = mlx4_gen_pkey_eqe(dev->dev, slave, port_num); - pr_debug("propagate_pkey_ev: slave %d," - " port %d, ix %d (%d)\n", - slave, port_num, ix, err); - have_event = 1; - break; - } - } - if (have_event) - break; - } - } -} - -static void node_desc_override(struct ib_device *dev, - struct ib_mad *mad) -{ - unsigned long flags; - - if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || - mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && - mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && - mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { - spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags); - memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); - spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags); - } -} - -static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *mad) -{ - int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; - struct ib_mad_send_buf *send_buf; - struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; - int ret; - unsigned long flags; - - if (agent) { - send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, - IB_MGMT_MAD_DATA, GFP_ATOMIC); - if (IS_ERR(send_buf)) - return; - /* - * We rely here on the fact that MLX QPs don't use the - * address handle after the send is posted (this is - * wrong following the IB spec strictly, but we know - * it's OK for our devices). - */ - spin_lock_irqsave(&dev->sm_lock, flags); - memcpy(send_buf->mad, mad, sizeof *mad); - if ((send_buf->ah = dev->sm_ah[port_num - 1])) - ret = ib_post_send_mad(send_buf, NULL); - else - ret = -EINVAL; - spin_unlock_irqrestore(&dev->sm_lock, flags); - - if (ret) - ib_free_send_mad(send_buf); - } -} - -static int mlx4_ib_demux_sa_handler(struct ib_device *ibdev, int port, int slave, - struct ib_sa_mad *sa_mad) -{ - int ret = 0; - - /* dispatch to different sa handlers */ - switch (be16_to_cpu(sa_mad->mad_hdr.attr_id)) { - case IB_SA_ATTR_MC_MEMBER_REC: - ret = mlx4_ib_mcg_demux_handler(ibdev, port, slave, sa_mad); - break; - default: - break; - } - return ret; -} - -int mlx4_ib_find_real_gid(struct ib_device *ibdev, u8 port, __be64 guid) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - int i; - - for (i = 0; i < dev->dev->caps.sqp_demux; i++) { - if (dev->sriov.demux[port - 1].guid_cache[i] == guid) - return i; - } - return -1; -} - - -static int find_slave_port_pkey_ix(struct mlx4_ib_dev *dev, int slave, - u8 port, u16 pkey, u16 *ix) -{ - int i, ret; - u8 unassigned_pkey_ix, pkey_ix, partial_ix = 0xFF; - u16 slot_pkey; - - if (slave == mlx4_master_func_num(dev->dev)) - return ib_find_cached_pkey(&dev->ib_dev, port, pkey, ix); - - unassigned_pkey_ix = dev->dev->phys_caps.pkey_phys_table_len[port] - 1; - - for (i = 0; i < dev->dev->caps.pkey_table_len[port]; i++) { - if (dev->pkeys.virt2phys_pkey[slave][port - 1][i] == unassigned_pkey_ix) - continue; - - pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][i]; - - ret = ib_get_cached_pkey(&dev->ib_dev, port, pkey_ix, &slot_pkey); - if (ret) - continue; - if ((slot_pkey & 0x7FFF) == (pkey & 0x7FFF)) { - if (slot_pkey & 0x8000) { - *ix = (u16) pkey_ix; - return 0; - } else { - /* take first partial pkey index found */ - if (partial_ix == 0xFF) - partial_ix = pkey_ix; - } - } - } - - if (partial_ix < 0xFF) { - *ix = (u16) partial_ix; - return 0; - } - - return -EINVAL; -} - -int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, - enum ib_qp_type dest_qpt, struct ib_wc *wc, - struct ib_grh *grh, struct ib_mad *mad) -{ - struct ib_sge list; - struct ib_send_wr wr, *bad_wr; - struct mlx4_ib_demux_pv_ctx *tun_ctx; - struct mlx4_ib_demux_pv_qp *tun_qp; - struct mlx4_rcv_tunnel_mad *tun_mad; - struct ib_ah_attr attr; - struct ib_ah *ah; - struct ib_qp *src_qp = NULL; - unsigned tun_tx_ix = 0; - int dqpn; - int ret = 0; - u16 tun_pkey_ix; - u16 cached_pkey; - u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH; - - if (dest_qpt > IB_QPT_GSI) - return -EINVAL; - - tun_ctx = dev->sriov.demux[port-1].tun[slave]; - - /* check if proxy qp created */ - if (!tun_ctx || tun_ctx->state != DEMUX_PV_STATE_ACTIVE) - return -EAGAIN; - - /* QP0 forwarding only for Dom0 */ - if (!dest_qpt && (mlx4_master_func_num(dev->dev) != slave)) - return -EINVAL; - - if (!dest_qpt) - tun_qp = &tun_ctx->qp[0]; - else - tun_qp = &tun_ctx->qp[1]; - - /* compute P_Key index to put in tunnel header for slave */ - if (dest_qpt) { - u16 pkey_ix; - ret = ib_get_cached_pkey(&dev->ib_dev, port, wc->pkey_index, &cached_pkey); - if (ret) - return -EINVAL; - - ret = find_slave_port_pkey_ix(dev, slave, port, cached_pkey, &pkey_ix); - if (ret) - return -EINVAL; - tun_pkey_ix = pkey_ix; - } else - tun_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][0]; - - dqpn = dev->dev->phys_caps.base_proxy_sqpn + 8 * slave + port + (dest_qpt * 2) - 1; - - /* get tunnel tx data buf for slave */ - src_qp = tun_qp->qp; - - /* create ah. Just need an empty one with the port num for the post send. - * The driver will set the force loopback bit in post_send */ - memset(&attr, 0, sizeof attr); - attr.port_num = port; - if (is_eth) { - memcpy(&attr.grh.dgid.raw[0], &grh->dgid.raw[0], 16); - attr.ah_flags = IB_AH_GRH; - } - ah = ib_create_ah(tun_ctx->pd, &attr); - if (IS_ERR(ah)) - return -ENOMEM; - - /* allocate tunnel tx buf after pass failure returns */ - spin_lock(&tun_qp->tx_lock); - if (tun_qp->tx_ix_head - tun_qp->tx_ix_tail >= - (MLX4_NUM_TUNNEL_BUFS - 1)) - ret = -EAGAIN; - else - tun_tx_ix = (++tun_qp->tx_ix_head) & (MLX4_NUM_TUNNEL_BUFS - 1); - spin_unlock(&tun_qp->tx_lock); - if (ret) - goto out; - - tun_mad = (struct mlx4_rcv_tunnel_mad *) (tun_qp->tx_ring[tun_tx_ix].buf.addr); - if (tun_qp->tx_ring[tun_tx_ix].ah) - ib_destroy_ah(tun_qp->tx_ring[tun_tx_ix].ah); - tun_qp->tx_ring[tun_tx_ix].ah = ah; - ib_dma_sync_single_for_cpu(&dev->ib_dev, - tun_qp->tx_ring[tun_tx_ix].buf.map, - sizeof (struct mlx4_rcv_tunnel_mad), - DMA_TO_DEVICE); - - /* copy over to tunnel buffer */ - if (grh) - memcpy(&tun_mad->grh, grh, sizeof *grh); - memcpy(&tun_mad->mad, mad, sizeof *mad); - - /* adjust tunnel data */ - tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix); - tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF); - tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0; - - if (is_eth) { - u16 vlan = 0; - if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan, - NULL)) { - if (vlan != wc->vlan_id) - /* VST and default vlan is not the packet vlan drop the - * packet*/ - goto out; - else - /* VST , remove hide the vlan from the VF */ - vlan = 0; - } else { - vlan = wc->vlan_id; - } - - tun_mad->hdr.sl_vid = cpu_to_be16(vlan); - memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4); - memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2); - } else { - tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12); - tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid); - } - - ib_dma_sync_single_for_device(&dev->ib_dev, - tun_qp->tx_ring[tun_tx_ix].buf.map, - sizeof (struct mlx4_rcv_tunnel_mad), - DMA_TO_DEVICE); - - list.addr = tun_qp->tx_ring[tun_tx_ix].buf.map; - list.length = sizeof (struct mlx4_rcv_tunnel_mad); - list.lkey = tun_ctx->mr->lkey; - - wr.wr.ud.ah = ah; - wr.wr.ud.port_num = port; - wr.wr.ud.remote_qkey = IB_QP_SET_QKEY; - wr.wr.ud.remote_qpn = dqpn; - wr.next = NULL; - wr.wr_id = ((u64) tun_tx_ix) | MLX4_TUN_SET_WRID_QPN(dest_qpt); - wr.sg_list = &list; - wr.num_sge = 1; - wr.opcode = IB_WR_SEND; - wr.send_flags = IB_SEND_SIGNALED; - - ret = ib_post_send(src_qp, &wr, &bad_wr); -out: - if (ret) - ib_destroy_ah(ah); - return ret; -} - -static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port, - struct ib_wc *wc, struct ib_grh *grh, - struct ib_mad *mad) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - int err; - int slave; - u8 *slave_id; - int is_eth = 0; - - if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) - is_eth = 0; - else - is_eth = 1; - - if (is_eth) { - if (!wc->wc_flags & IB_WC_GRH) { - mlx4_ib_warn(ibdev, "RoCE grh not present.\n"); - return -EINVAL; - } - if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) { - mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n"); - return -EINVAL; - } - if (mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave)) { - mlx4_ib_warn(ibdev, "failed matching grh\n"); - return -ENOENT; - } - if (slave >= dev->dev->caps.sqp_demux) { - mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", - slave, dev->dev->caps.sqp_demux); - return -ENOENT; - } - - if (mlx4_ib_demux_cm_handler(ibdev, port, &slave, mad, is_eth)) - return 0; - - err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); - if (err) - pr_debug("failed sending to slave %d via tunnel qp (%d)\n", - slave, err); - return 0; - } - - /* Initially assume that this mad is for us */ - slave = mlx4_master_func_num(dev->dev); - - /* See if the slave id is encoded in a response mad */ - if (mad->mad_hdr.method & 0x80) { - slave_id = (u8 *) &mad->mad_hdr.tid; - slave = *slave_id; - if (slave != 255) /*255 indicates the dom0*/ - *slave_id = 0; /* remap tid */ - } - - /* If a grh is present, we demux according to it */ - if (wc->wc_flags & IB_WC_GRH) { - slave = mlx4_ib_find_real_gid(ibdev, port, grh->dgid.global.interface_id); - if (slave < 0) { - mlx4_ib_warn(ibdev, "failed matching grh\n"); - return -ENOENT; - } - } - /* Class-specific handling */ - switch (mad->mad_hdr.mgmt_class) { - case IB_MGMT_CLASS_SUBN_ADM: - if (mlx4_ib_demux_sa_handler(ibdev, port, slave, - (struct ib_sa_mad *) mad)) - return 0; - break; - case IB_MGMT_CLASS_CM: - if (mlx4_ib_demux_cm_handler(ibdev, port, &slave, mad, is_eth)) - return 0; - break; - case IB_MGMT_CLASS_DEVICE_MGMT: - if (mad->mad_hdr.method != IB_MGMT_METHOD_GET_RESP) - return 0; - break; - default: - /* Drop unsupported classes for slaves in tunnel mode */ - if (slave != mlx4_master_func_num(dev->dev)) { - pr_debug("dropping unsupported ingress mad from class:%d " - "for slave:%d\n", mad->mad_hdr.mgmt_class, slave); - return 0; - } - } - /*make sure that no slave==255 was not handled yet.*/ - if (slave >= dev->dev->caps.sqp_demux) { - mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", - slave, dev->dev->caps.sqp_demux); - return -ENOENT; - } - - err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); - if (err) - pr_debug("failed sending to slave %d via tunnel qp (%d)\n", - slave, err); - return 0; -} - -static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, - struct ib_wc *in_wc, struct ib_grh *in_grh, - struct ib_mad *in_mad, struct ib_mad *out_mad) -{ - u16 slid, prev_lid = 0; - int err; - struct ib_port_attr pattr; - - if (in_wc && in_wc->qp->qp_num) { - pr_debug("received MAD: slid:%d sqpn:%d " - "dlid_bits:%d dqpn:%d wc_flags:0x%x, cls %x, mtd %x, atr %x\n", - in_wc->slid, in_wc->src_qp, - in_wc->dlid_path_bits, - in_wc->qp->qp_num, - in_wc->wc_flags, - in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method, - be16_to_cpu(in_mad->mad_hdr.attr_id)); - if (in_wc->wc_flags & IB_WC_GRH) { - pr_debug("sgid_hi:0x%016llx sgid_lo:0x%016llx\n", - (unsigned long long)be64_to_cpu(in_grh->sgid.global.subnet_prefix), - (unsigned long long)be64_to_cpu(in_grh->sgid.global.interface_id)); - pr_debug("dgid_hi:0x%016llx dgid_lo:0x%016llx\n", - (unsigned long long)be64_to_cpu(in_grh->dgid.global.subnet_prefix), - (unsigned long long)be64_to_cpu(in_grh->dgid.global.interface_id)); - } - } - - slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); - - if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) { - forward_trap(to_mdev(ibdev), port_num, in_mad); - return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; - } - - if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || - in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { - if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && - in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && - in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) - return IB_MAD_RESULT_SUCCESS; - - /* - * Don't process SMInfo queries -- the SMA can't handle them. - */ - if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) - return IB_MAD_RESULT_SUCCESS; - } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || - in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || - in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2 || - in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) { - if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && - in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) - return IB_MAD_RESULT_SUCCESS; - } else - return IB_MAD_RESULT_SUCCESS; - - if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || - in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && - in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && - in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && - !ib_query_port(ibdev, port_num, &pattr)) - prev_lid = pattr.lid; - - err = mlx4_MAD_IFC(to_mdev(ibdev), - (mad_flags & IB_MAD_IGNORE_MKEY ? MLX4_MAD_IFC_IGNORE_MKEY : 0) | - (mad_flags & IB_MAD_IGNORE_BKEY ? MLX4_MAD_IFC_IGNORE_BKEY : 0) | - MLX4_MAD_IFC_NET_VIEW, - port_num, in_wc, in_grh, in_mad, out_mad); - if (err) - return IB_MAD_RESULT_FAILURE; - - if (!out_mad->mad_hdr.status) { - if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)) - smp_snoop(ibdev, port_num, in_mad, prev_lid); - /* slaves get node desc from FW */ - if (!mlx4_is_slave(to_mdev(ibdev)->dev)) - node_desc_override(ibdev, out_mad); - } - - /* set return bit in status of directed route responses */ - if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) - out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); - - if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) - /* no response for trap repress */ - return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; - - return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; -} - -static void edit_counter_ext(struct mlx4_if_stat_extended *cnt, void *counters, - __be16 attr_id) -{ - switch (attr_id) { - case IB_PMA_PORT_COUNTERS: - { - struct ib_pma_portcounters *pma_cnt = - (struct ib_pma_portcounters *)counters; - pma_cnt->port_xmit_data = - cpu_to_be32((be64_to_cpu(cnt->counters[0]. - IfTxUnicastOctets) + - be64_to_cpu(cnt->counters[0]. - IfTxMulticastOctets) + - be64_to_cpu(cnt->counters[0]. - IfTxBroadcastOctets) + - be64_to_cpu(cnt->counters[0]. - IfTxDroppedOctets)) >> 2); - pma_cnt->port_rcv_data = - cpu_to_be32((be64_to_cpu(cnt->counters[0]. - IfRxUnicastOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxMulticastOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxBroadcastOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxNoBufferOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxErrorOctets)) >> 2); - pma_cnt->port_xmit_packets = - cpu_to_be32(be64_to_cpu(cnt->counters[0]. - IfTxUnicastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxMulticastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxBroadcastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxDroppedFrames)); - pma_cnt->port_rcv_packets = - cpu_to_be32(be64_to_cpu(cnt->counters[0]. - IfRxUnicastFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxMulticastFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxBroadcastFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxNoBufferFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxErrorFrames)); - pma_cnt->port_rcv_errors = cpu_to_be32(be64_to_cpu(cnt-> - counters[0]. - IfRxErrorFrames)); - break; - } - - case IB_PMA_PORT_COUNTERS_EXT: - { - struct ib_pma_portcounters_ext *pma_cnt_ext = - (struct ib_pma_portcounters_ext *)counters; - - pma_cnt_ext->port_xmit_data = - cpu_to_be64((be64_to_cpu(cnt->counters[0]. - IfTxUnicastOctets) + - be64_to_cpu(cnt->counters[0]. - IfTxMulticastOctets) + - be64_to_cpu(cnt->counters[0]. - IfTxBroadcastOctets) + - be64_to_cpu(cnt->counters[0]. - IfTxDroppedOctets)) >> 2); - pma_cnt_ext->port_rcv_data = - cpu_to_be64((be64_to_cpu(cnt->counters[0]. - IfRxUnicastOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxMulticastOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxBroadcastOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxNoBufferOctets) + - be64_to_cpu(cnt->counters[0]. - IfRxErrorOctets)) >> 2); - pma_cnt_ext->port_xmit_packets = - cpu_to_be64(be64_to_cpu(cnt->counters[0]. - IfTxUnicastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxMulticastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxBroadcastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxDroppedFrames)); - pma_cnt_ext->port_rcv_packets = - cpu_to_be64(be64_to_cpu(cnt->counters[0]. - IfRxUnicastFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxMulticastFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxBroadcastFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxNoBufferFrames) + - be64_to_cpu(cnt->counters[0]. - IfRxErrorFrames)); - pma_cnt_ext->port_unicast_xmit_packets = cnt->counters[0]. - IfTxUnicastFrames; - pma_cnt_ext->port_unicast_rcv_packets = cnt->counters[0]. - IfRxUnicastFrames; - pma_cnt_ext->port_multicast_xmit_packets = - cpu_to_be64(be64_to_cpu(cnt->counters[0]. - IfTxMulticastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxBroadcastFrames)); - pma_cnt_ext->port_multicast_rcv_packets = - cpu_to_be64(be64_to_cpu(cnt->counters[0]. - IfTxMulticastFrames) + - be64_to_cpu(cnt->counters[0]. - IfTxBroadcastFrames)); - - break; - } - - default: - pr_warn("Unsupported attr_id 0x%x\n", attr_id); - break; - } - -} - -static void edit_counter(struct mlx4_if_stat_basic *cnt, void *counters, - __be16 attr_id) -{ - switch (attr_id) { - case IB_PMA_PORT_COUNTERS: - { - struct ib_pma_portcounters *pma_cnt = - (struct ib_pma_portcounters *) counters; - pma_cnt->port_xmit_data = - cpu_to_be32(be64_to_cpu( - cnt->counters[0].IfTxOctets) >> 2); - pma_cnt->port_rcv_data = - cpu_to_be32(be64_to_cpu( - cnt->counters[0].IfRxOctets) >> 2); - pma_cnt->port_xmit_packets = - cpu_to_be32(be64_to_cpu(cnt->counters[0].IfTxFrames)); - pma_cnt->port_rcv_packets = - cpu_to_be32(be64_to_cpu(cnt->counters[0].IfRxFrames)); - break; - } - case IB_PMA_PORT_COUNTERS_EXT: - { - struct ib_pma_portcounters_ext *pma_cnt_ext = - (struct ib_pma_portcounters_ext *) counters; - - pma_cnt_ext->port_xmit_data = - cpu_to_be64((be64_to_cpu(cnt->counters[0]. - IfTxOctets) >> 2)); - pma_cnt_ext->port_rcv_data = - cpu_to_be64((be64_to_cpu(cnt->counters[0]. - IfRxOctets) >> 2)); - pma_cnt_ext->port_xmit_packets = cnt->counters[0].IfTxFrames; - pma_cnt_ext->port_rcv_packets = cnt->counters[0].IfRxFrames; - break; - } - default: - pr_warn("Unsupported attr_id 0x%x\n", attr_id); - break; - } -} - -int mlx4_ib_query_if_stat(struct mlx4_ib_dev *dev, u32 counter_index, - union mlx4_counter *counter, u8 clear) -{ - struct mlx4_cmd_mailbox *mailbox; - int err; - u32 inmod = counter_index | ((clear & 1) << 31); - - mailbox = mlx4_alloc_cmd_mailbox(dev->dev); - if (IS_ERR(mailbox)) - return IB_MAD_RESULT_FAILURE; - - err = mlx4_cmd_box(dev->dev, 0, mailbox->dma, inmod, 0, - MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - if (!err) - memcpy(counter, mailbox->buf, MLX4_IF_STAT_SZ(1)); - - mlx4_free_cmd_mailbox(dev->dev, mailbox); - - return err; -} - -static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, - struct ib_wc *in_wc, struct ib_grh *in_grh, - struct ib_mad *in_mad, struct ib_mad *out_mad) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - int err; - u32 counter_index = dev->counters[port_num - 1].counter_index & 0xffff; - u8 mode; - char counter_buf[MLX4_IF_STAT_SZ(1)]; - union mlx4_counter *counter = (union mlx4_counter *) - counter_buf; - - if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT) - return -EINVAL; - - /* in case of default counter IB shares the counter with ETH */ - /* the state could be -EEXIST or -ENOSPC */ - if (dev->counters[port_num - 1].status) { - memset(out_mad->data, 0, sizeof out_mad->data); - err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; - } else { - if (mlx4_ib_query_if_stat(dev, counter_index, counter, 0)) - return IB_MAD_RESULT_FAILURE; - - memset(out_mad->data, 0, sizeof(out_mad->data)); - mode = counter->control.cnt_mode & 0xFF; - err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; - switch (mode & 0xf) { - case 0: - edit_counter((void *)counter, - (void *)(out_mad->data + 40), - in_mad->mad_hdr.attr_id); - break; - case 1: - edit_counter_ext((void *)counter, - (void *)(out_mad->data + 40), - in_mad->mad_hdr.attr_id); - break; - default: - err = IB_MAD_RESULT_FAILURE; - } - } - - return err; -} - -int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, - struct ib_wc *in_wc, struct ib_grh *in_grh, - struct ib_mad *in_mad, struct ib_mad *out_mad) -{ - switch (rdma_port_get_link_layer(ibdev, port_num)) { - case IB_LINK_LAYER_INFINIBAND: - return ib_process_mad(ibdev, mad_flags, port_num, in_wc, - in_grh, in_mad, out_mad); - case IB_LINK_LAYER_ETHERNET: - return iboe_process_mad(ibdev, mad_flags, port_num, in_wc, - in_grh, in_mad, out_mad); - default: - return -EINVAL; - } -} - -static void send_handler(struct ib_mad_agent *agent, - struct ib_mad_send_wc *mad_send_wc) -{ - if (mad_send_wc->send_buf->context[0]) - ib_destroy_ah(mad_send_wc->send_buf->context[0]); - ib_free_send_mad(mad_send_wc->send_buf); -} - -int mlx4_ib_mad_init(struct mlx4_ib_dev *dev) -{ - struct ib_mad_agent *agent; - int p, q; - int ret; - enum rdma_link_layer ll; - - for (p = 0; p < dev->num_ports; ++p) { - ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1); - for (q = 0; q <= 1; ++q) { - if (ll == IB_LINK_LAYER_INFINIBAND) { - agent = ib_register_mad_agent(&dev->ib_dev, p + 1, - q ? IB_QPT_GSI : IB_QPT_SMI, - NULL, 0, send_handler, - NULL, NULL); - if (IS_ERR(agent)) { - ret = PTR_ERR(agent); - goto err; - } - dev->send_agent[p][q] = agent; - } else - dev->send_agent[p][q] = NULL; - } - } - - return 0; - -err: - for (p = 0; p < dev->num_ports; ++p) - for (q = 0; q <= 1; ++q) - if (dev->send_agent[p][q]) - ib_unregister_mad_agent(dev->send_agent[p][q]); - - return ret; -} - -void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev) -{ - struct ib_mad_agent *agent; - int p, q; - - for (p = 0; p < dev->num_ports; ++p) { - for (q = 0; q <= 1; ++q) { - agent = dev->send_agent[p][q]; - if (agent) { - dev->send_agent[p][q] = NULL; - ib_unregister_mad_agent(agent); - } - } - - if (dev->sm_ah[p]) - ib_destroy_ah(dev->sm_ah[p]); - } -} - -static void handle_lid_change_event(struct mlx4_ib_dev *dev, u8 port_num) -{ - mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_LID_CHANGE); - - if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) - mlx4_gen_slaves_port_mgt_ev(dev->dev, port_num, - MLX4_EQ_PORT_INFO_LID_CHANGE_MASK, 0, 0); -} - -static void handle_client_rereg_event(struct mlx4_ib_dev *dev, u8 port_num) -{ - /* re-configure the alias-guid and mcg's */ - if (mlx4_is_master(dev->dev)) { - mlx4_ib_invalidate_all_guid_record(dev, port_num); - - if (!dev->sriov.is_going_down) { - mlx4_ib_mcg_port_cleanup(&dev->sriov.demux[port_num - 1], 0); - mlx4_gen_slaves_port_mgt_ev(dev->dev, port_num, - MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK, 0, 0); - } - } - mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_CLIENT_REREGISTER); -} - -static void propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, - struct mlx4_eqe *eqe) -{ - __propagate_pkey_ev(dev, port_num, GET_BLK_PTR_FROM_EQE(eqe), - GET_MASK_FROM_EQE(eqe)); -} - -static void handle_slaves_guid_change(struct mlx4_ib_dev *dev, u8 port_num, - u32 guid_tbl_blk_num, u32 change_bitmap) -{ - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; - u16 i; - - if (!mlx4_is_mfunc(dev->dev) || !mlx4_is_master(dev->dev)) - return; - - in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); - out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) { - mlx4_ib_warn(&dev->ib_dev, "failed to allocate memory for guid info mads\n"); - goto out; - } - - guid_tbl_blk_num *= 4; - - for (i = 0; i < 4; i++) { - if (change_bitmap && (!((change_bitmap >> (8 * i)) & 0xff))) - continue; - memset(in_mad, 0, sizeof *in_mad); - memset(out_mad, 0, sizeof *out_mad); - - in_mad->base_version = 1; - in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - in_mad->class_version = 1; - in_mad->method = IB_MGMT_METHOD_GET; - in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; - in_mad->attr_mod = cpu_to_be32(guid_tbl_blk_num + i); - - if (mlx4_MAD_IFC(dev, - MLX4_MAD_IFC_IGNORE_KEYS | MLX4_MAD_IFC_NET_VIEW, - port_num, NULL, NULL, in_mad, out_mad)) { - mlx4_ib_warn(&dev->ib_dev, "Failed in get GUID INFO MAD_IFC\n"); - goto out; - } - - mlx4_ib_update_cache_on_guid_change(dev, guid_tbl_blk_num + i, - port_num, - (u8 *)(&((struct ib_smp *)out_mad)->data)); - mlx4_ib_notify_slaves_on_guid_change(dev, guid_tbl_blk_num + i, - port_num, - (u8 *)(&((struct ib_smp *)out_mad)->data)); - } - -out: - kfree(in_mad); - kfree(out_mad); - return; -} - -void handle_port_mgmt_change_event(struct work_struct *work) -{ - struct ib_event_work *ew = container_of(work, struct ib_event_work, work); - struct mlx4_ib_dev *dev = ew->ib_dev; - struct mlx4_eqe *eqe = &(ew->ib_eqe); - u8 port = eqe->event.port_mgmt_change.port; - u32 changed_attr; - u32 tbl_block; - u32 change_bitmap; - - switch (eqe->subtype) { - case MLX4_DEV_PMC_SUBTYPE_PORT_INFO: - changed_attr = be32_to_cpu(eqe->event.port_mgmt_change.params.port_info.changed_attr); - - /* Update the SM ah - This should be done before handling - the other changed attributes so that MADs can be sent to the SM */ - if (changed_attr & MSTR_SM_CHANGE_MASK) { - u16 lid = be16_to_cpu(eqe->event.port_mgmt_change.params.port_info.mstr_sm_lid); - u8 sl = eqe->event.port_mgmt_change.params.port_info.mstr_sm_sl & 0xf; - update_sm_ah(dev, port, lid, sl); - mlx4_ib_dispatch_event(dev, port, IB_EVENT_SM_CHANGE); - if (mlx4_is_master(dev->dev)) - mlx4_gen_slaves_port_mgt_ev(dev->dev, port, - changed_attr & MSTR_SM_CHANGE_MASK, - lid, sl); - } - - /* Check if it is a lid change event */ - if (changed_attr & MLX4_EQ_PORT_INFO_LID_CHANGE_MASK) - handle_lid_change_event(dev, port); - - /* Generate GUID changed event */ - if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK) { - mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); - /*if master, notify all slaves*/ - if (mlx4_is_master(dev->dev)) - mlx4_gen_slaves_port_mgt_ev(dev->dev, port, - MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK, 0, 0); - } - - if (changed_attr & MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK) - handle_client_rereg_event(dev, port); - break; - - case MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE: - mlx4_ib_dispatch_event(dev, port, IB_EVENT_PKEY_CHANGE); - if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) - propagate_pkey_ev(dev, port, eqe); - break; - case MLX4_DEV_PMC_SUBTYPE_GUID_INFO: - /* paravirtualized master's guid is guid 0 -- does not change */ - if (!mlx4_is_master(dev->dev)) - mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); - /*if master, notify relevant slaves*/ - else if (!dev->sriov.is_going_down) { - tbl_block = GET_BLK_PTR_FROM_EQE(eqe); - change_bitmap = GET_MASK_FROM_EQE(eqe); - handle_slaves_guid_change(dev, port, tbl_block, change_bitmap); - } - break; - default: - pr_warn("Unsupported subtype 0x%x for " - "Port Management Change event\n", eqe->subtype); - } - - kfree(ew); -} - -void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num, - enum ib_event_type type) -{ - struct ib_event event; - - event.device = &dev->ib_dev; - event.element.port_num = port_num; - event.event = type; - - ib_dispatch_event(&event); -} - -static void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg) -{ - unsigned long flags; - struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; - struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); - spin_lock_irqsave(&dev->sriov.going_down_lock, flags); - if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) - queue_work(ctx->wq, &ctx->work); - spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); -} - -static int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx, - struct mlx4_ib_demux_pv_qp *tun_qp, - int index) -{ - struct ib_sge sg_list; - struct ib_recv_wr recv_wr, *bad_recv_wr; - int size; - - size = (tun_qp->qp->qp_type == IB_QPT_UD) ? - sizeof (struct mlx4_tunnel_mad) : sizeof (struct mlx4_mad_rcv_buf); - - sg_list.addr = tun_qp->ring[index].map; - sg_list.length = size; - sg_list.lkey = ctx->mr->lkey; - - recv_wr.next = NULL; - recv_wr.sg_list = &sg_list; - recv_wr.num_sge = 1; - recv_wr.wr_id = (u64) index | MLX4_TUN_WRID_RECV | - MLX4_TUN_SET_WRID_QPN(tun_qp->proxy_qpt); - ib_dma_sync_single_for_device(ctx->ib_dev, tun_qp->ring[index].map, - size, DMA_FROM_DEVICE); - return ib_post_recv(tun_qp->qp, &recv_wr, &bad_recv_wr); -} - -static int mlx4_ib_multiplex_sa_handler(struct ib_device *ibdev, int port, - int slave, struct ib_sa_mad *sa_mad) -{ - int ret = 0; - - /* dispatch to different sa handlers */ - switch (be16_to_cpu(sa_mad->mad_hdr.attr_id)) { - case IB_SA_ATTR_MC_MEMBER_REC: - ret = mlx4_ib_mcg_multiplex_handler(ibdev, port, slave, sa_mad); - break; - default: - break; - } - return ret; -} - -static int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave) -{ - int proxy_start = dev->dev->phys_caps.base_proxy_sqpn + 8 * slave; - - return (qpn >= proxy_start && qpn <= proxy_start + 1); -} - - -int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, - enum ib_qp_type dest_qpt, u16 pkey_index, - u32 remote_qpn, u32 qkey, struct ib_ah_attr *attr, - u8 *s_mac, struct ib_mad *mad) -{ - struct ib_sge list; - struct ib_send_wr wr, *bad_wr; - struct mlx4_ib_demux_pv_ctx *sqp_ctx; - struct mlx4_ib_demux_pv_qp *sqp; - struct mlx4_mad_snd_buf *sqp_mad; - struct ib_ah *ah; - struct ib_qp *send_qp = NULL; - unsigned wire_tx_ix = 0; - int ret = 0; - u16 wire_pkey_ix; - int src_qpnum; - u8 sgid_index; - - - sqp_ctx = dev->sriov.sqps[port-1]; - - /* check if proxy qp created */ - if (!sqp_ctx || sqp_ctx->state != DEMUX_PV_STATE_ACTIVE) - return -EAGAIN; - - /* QP0 forwarding only for Dom0 */ - if (dest_qpt == IB_QPT_SMI && (mlx4_master_func_num(dev->dev) != slave)) - return -EINVAL; - - if (dest_qpt == IB_QPT_SMI) { - src_qpnum = 0; - sqp = &sqp_ctx->qp[0]; - wire_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][0]; - } else { - src_qpnum = 1; - sqp = &sqp_ctx->qp[1]; - wire_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][pkey_index]; - } - - send_qp = sqp->qp; - - /* create ah */ - sgid_index = attr->grh.sgid_index; - attr->grh.sgid_index = 0; - ah = ib_create_ah(sqp_ctx->pd, attr); - if (IS_ERR(ah)) - return -ENOMEM; - attr->grh.sgid_index = sgid_index; - to_mah(ah)->av.ib.gid_index = sgid_index; - /* get rid of force-loopback bit */ - to_mah(ah)->av.ib.port_pd &= cpu_to_be32(0x7FFFFFFF); - spin_lock(&sqp->tx_lock); - if (sqp->tx_ix_head - sqp->tx_ix_tail >= - (MLX4_NUM_TUNNEL_BUFS - 1)) - ret = -EAGAIN; - else - wire_tx_ix = (++sqp->tx_ix_head) & (MLX4_NUM_TUNNEL_BUFS - 1); - spin_unlock(&sqp->tx_lock); - if (ret) - goto out; - - sqp_mad = (struct mlx4_mad_snd_buf *) (sqp->tx_ring[wire_tx_ix].buf.addr); - if (sqp->tx_ring[wire_tx_ix].ah) - ib_destroy_ah(sqp->tx_ring[wire_tx_ix].ah); - sqp->tx_ring[wire_tx_ix].ah = ah; - ib_dma_sync_single_for_cpu(&dev->ib_dev, - sqp->tx_ring[wire_tx_ix].buf.map, - sizeof (struct mlx4_mad_snd_buf), - DMA_TO_DEVICE); - - memcpy(&sqp_mad->payload, mad, sizeof *mad); - - ib_dma_sync_single_for_device(&dev->ib_dev, - sqp->tx_ring[wire_tx_ix].buf.map, - sizeof (struct mlx4_mad_snd_buf), - DMA_TO_DEVICE); - - list.addr = sqp->tx_ring[wire_tx_ix].buf.map; - list.length = sizeof (struct mlx4_mad_snd_buf); - list.lkey = sqp_ctx->mr->lkey; - - wr.wr.ud.ah = ah; - wr.wr.ud.port_num = port; - wr.wr.ud.pkey_index = wire_pkey_ix; - wr.wr.ud.remote_qkey = qkey; - wr.wr.ud.remote_qpn = remote_qpn; - wr.next = NULL; - wr.wr_id = ((u64) wire_tx_ix) | MLX4_TUN_SET_WRID_QPN(src_qpnum); - wr.sg_list = &list; - wr.num_sge = 1; - wr.opcode = IB_WR_SEND; - wr.send_flags = IB_SEND_SIGNALED; - if (s_mac) - memcpy(to_mah(ah)->av.eth.s_mac, s_mac, 6); - - - ret = ib_post_send(send_qp, &wr, &bad_wr); -out: - if (ret) - ib_destroy_ah(ah); - return ret; -} - -static int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port) -{ - int gids; - int vfs; - - if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) - return slave; - - gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; - vfs = dev->dev->num_vfs; - - if (slave == 0) - return 0; - if (slave <= gids % vfs) - return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); - - return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); -} - -static int get_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port, - struct ib_ah_attr *ah_attr) -{ - if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) { - ah_attr->grh.sgid_index = slave; - return 0; - } - ah_attr->grh.sgid_index += get_slave_base_gid_ix(dev, slave, port); - return 0; -} - -static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc) -{ - struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); - struct mlx4_ib_demux_pv_qp *tun_qp = &ctx->qp[MLX4_TUN_WRID_QPN(wc->wr_id)]; - int wr_ix = wc->wr_id & (MLX4_NUM_TUNNEL_BUFS - 1); - struct mlx4_tunnel_mad *tunnel = tun_qp->ring[wr_ix].addr; - struct mlx4_ib_ah ah; - struct ib_ah_attr ah_attr; - u8 *slave_id; - int slave; - - /* Get slave that sent this packet */ - if (wc->src_qp < dev->dev->phys_caps.base_proxy_sqpn || - wc->src_qp >= dev->dev->phys_caps.base_proxy_sqpn + 8 * MLX4_MFUNC_MAX || - (wc->src_qp & 0x1) != ctx->port - 1 || - wc->src_qp & 0x4) { - mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d\n", wc->src_qp); - return; - } - slave = ((wc->src_qp & ~0x7) - dev->dev->phys_caps.base_proxy_sqpn) / 8; - if (slave != ctx->slave) { - mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d: " - "belongs to another slave\n", wc->src_qp); - return; - } - if (slave != mlx4_master_func_num(dev->dev) && !(wc->src_qp & 0x2)) { - mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d: " - "non-master trying to send QP0 packets\n", wc->src_qp); - return; - } - - /* Map transaction ID */ - ib_dma_sync_single_for_cpu(ctx->ib_dev, tun_qp->ring[wr_ix].map, - sizeof (struct mlx4_tunnel_mad), - DMA_FROM_DEVICE); - switch (tunnel->mad.mad_hdr.method) { - case IB_MGMT_METHOD_SET: - case IB_MGMT_METHOD_GET: - case IB_MGMT_METHOD_REPORT: - case IB_SA_METHOD_GET_TABLE: - case IB_SA_METHOD_DELETE: - case IB_SA_METHOD_GET_MULTI: - case IB_SA_METHOD_GET_TRACE_TBL: - slave_id = (u8 *) &tunnel->mad.mad_hdr.tid; - if (*slave_id) { - mlx4_ib_warn(ctx->ib_dev, "egress mad has non-null tid msb:%d " - "class:%d slave:%d\n", *slave_id, - tunnel->mad.mad_hdr.mgmt_class, slave); - return; - } else - *slave_id = slave; - default: - /* nothing */; - } - - /* Class-specific handling */ - switch (tunnel->mad.mad_hdr.mgmt_class) { - case IB_MGMT_CLASS_SUBN_ADM: - if (mlx4_ib_multiplex_sa_handler(ctx->ib_dev, ctx->port, slave, - (struct ib_sa_mad *) &tunnel->mad)) - return; - break; - case IB_MGMT_CLASS_CM: - if (mlx4_ib_multiplex_cm_handler(ctx->ib_dev, ctx->port, slave, - (struct ib_mad *) &tunnel->mad)) - return; - break; - case IB_MGMT_CLASS_DEVICE_MGMT: - if (tunnel->mad.mad_hdr.method != IB_MGMT_METHOD_GET && - tunnel->mad.mad_hdr.method != IB_MGMT_METHOD_SET) - return; - break; - default: - /* Drop unsupported classes for slaves in tunnel mode */ - if (slave != mlx4_master_func_num(dev->dev)) { - mlx4_ib_warn(ctx->ib_dev, "dropping unsupported egress mad from class:%d " - "for slave:%d\n", tunnel->mad.mad_hdr.mgmt_class, slave); - return; - } - } - - /* We are using standard ib_core services to send the mad, so generate a - * stadard address handle by decoding the tunnelled mlx4_ah fields */ - memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av)); - ah.ibah.device = ctx->ib_dev; - mlx4_ib_query_ah(&ah.ibah, &ah_attr); - if (ah_attr.ah_flags & IB_AH_GRH) - if (get_real_sgid_index(dev, slave, ctx->port, &ah_attr)) - return; - memcpy(ah_attr.dmac, tunnel->hdr.mac, 6); - ah_attr.vlan_id = tunnel->hdr.vlan; - /* if slave have default vlan use it */ - mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave, - &ah_attr.vlan_id, &ah_attr.sl); - - mlx4_ib_send_to_wire(dev, slave, ctx->port, - is_proxy_qp0(dev, wc->src_qp, slave) ? - IB_QPT_SMI : IB_QPT_GSI, - be16_to_cpu(tunnel->hdr.pkey_index), - be32_to_cpu(tunnel->hdr.remote_qpn), - be32_to_cpu(tunnel->hdr.qkey), - &ah_attr, wc->smac, &tunnel->mad); -} - -static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, - enum ib_qp_type qp_type, int is_tun) -{ - int i; - struct mlx4_ib_demux_pv_qp *tun_qp; - int rx_buf_size, tx_buf_size; - - if (qp_type > IB_QPT_GSI) - return -EINVAL; - - tun_qp = &ctx->qp[qp_type]; - - tun_qp->ring = kzalloc(sizeof (struct mlx4_ib_buf) * MLX4_NUM_TUNNEL_BUFS, - GFP_KERNEL); - if (!tun_qp->ring) - return -ENOMEM; - - tun_qp->tx_ring = kcalloc(MLX4_NUM_TUNNEL_BUFS, - sizeof (struct mlx4_ib_tun_tx_buf), - GFP_KERNEL); - if (!tun_qp->tx_ring) { - kfree(tun_qp->ring); - tun_qp->ring = NULL; - return -ENOMEM; - } - - if (is_tun) { - rx_buf_size = sizeof (struct mlx4_tunnel_mad); - tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); - } else { - rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); - tx_buf_size = sizeof (struct mlx4_mad_snd_buf); - } - - for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { - tun_qp->ring[i].addr = kmalloc(rx_buf_size, GFP_KERNEL); - if (!tun_qp->ring[i].addr) - goto err; - tun_qp->ring[i].map = ib_dma_map_single(ctx->ib_dev, - tun_qp->ring[i].addr, - rx_buf_size, - DMA_FROM_DEVICE); - if (unlikely(ib_dma_mapping_error(ctx->ib_dev, - tun_qp->ring[i].map))) { - mlx4_ib_warn(ctx->ib_dev, "ib_dma_map_single failed\n"); - kfree(tun_qp->ring[i].addr); - goto err; - } - } - - for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { - tun_qp->tx_ring[i].buf.addr = - kmalloc(tx_buf_size, GFP_KERNEL); - if (!tun_qp->tx_ring[i].buf.addr) - goto tx_err; - tun_qp->tx_ring[i].buf.map = - ib_dma_map_single(ctx->ib_dev, - tun_qp->tx_ring[i].buf.addr, - tx_buf_size, - DMA_TO_DEVICE); - if (unlikely(ib_dma_mapping_error(ctx->ib_dev, - tun_qp->tx_ring[i].buf.map))) { - mlx4_ib_warn(ctx->ib_dev, "ib_dma_map_single failed\n"); - kfree(tun_qp->tx_ring[i].buf.addr); - goto tx_err; - } - tun_qp->tx_ring[i].ah = NULL; - } - spin_lock_init(&tun_qp->tx_lock); - tun_qp->tx_ix_head = 0; - tun_qp->tx_ix_tail = 0; - tun_qp->proxy_qpt = qp_type; - - return 0; - -tx_err: - while (i > 0) { - --i; - ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, - tx_buf_size, DMA_TO_DEVICE); - kfree(tun_qp->tx_ring[i].buf.addr); - } - kfree(tun_qp->tx_ring); - tun_qp->tx_ring = NULL; - i = MLX4_NUM_TUNNEL_BUFS; -err: - while (i > 0) { - --i; - ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, - rx_buf_size, DMA_FROM_DEVICE); - kfree(tun_qp->ring[i].addr); - } - kfree(tun_qp->ring); - tun_qp->ring = NULL; - return -ENOMEM; -} - -static void mlx4_ib_free_pv_qp_bufs(struct mlx4_ib_demux_pv_ctx *ctx, - enum ib_qp_type qp_type, int is_tun) -{ - int i; - struct mlx4_ib_demux_pv_qp *tun_qp; - int rx_buf_size, tx_buf_size; - - if (qp_type > IB_QPT_GSI) - return; - - tun_qp = &ctx->qp[qp_type]; - if (is_tun) { - rx_buf_size = sizeof (struct mlx4_tunnel_mad); - tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); - } else { - rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); - tx_buf_size = sizeof (struct mlx4_mad_snd_buf); - } - - - for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { - ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, - rx_buf_size, DMA_FROM_DEVICE); - kfree(tun_qp->ring[i].addr); - } - - for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { - ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, - tx_buf_size, DMA_TO_DEVICE); - kfree(tun_qp->tx_ring[i].buf.addr); - if (tun_qp->tx_ring[i].ah) - ib_destroy_ah(tun_qp->tx_ring[i].ah); - } - kfree(tun_qp->tx_ring); - kfree(tun_qp->ring); -} - -static void mlx4_ib_tunnel_comp_worker(struct work_struct *work) -{ - struct mlx4_ib_demux_pv_ctx *ctx; - struct mlx4_ib_demux_pv_qp *tun_qp; - struct ib_wc wc; - int ret; - ctx = container_of(work, struct mlx4_ib_demux_pv_ctx, work); - ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); - - while (ib_poll_cq(ctx->cq, 1, &wc) == 1) { - tun_qp = &ctx->qp[MLX4_TUN_WRID_QPN(wc.wr_id)]; - if (wc.status == IB_WC_SUCCESS) { - switch (wc.opcode) { - case IB_WC_RECV: - mlx4_ib_multiplex_mad(ctx, &wc); - ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, - wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1)); - if (ret) - pr_err("Failed reposting tunnel " - "buf:%lld\n", (unsigned long long)wc.wr_id); - break; - case IB_WC_SEND: - pr_debug("received tunnel send completion:" - "wrid=0x%llx, status=0x%x\n", - (unsigned long long)wc.wr_id, wc.status); - ib_destroy_ah(tun_qp->tx_ring[wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1)].ah); - tun_qp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah - = NULL; - spin_lock(&tun_qp->tx_lock); - tun_qp->tx_ix_tail++; - spin_unlock(&tun_qp->tx_lock); - - break; - default: - break; - } - } else { - pr_debug("mlx4_ib: completion error in tunnel: %d." - " status = %d, wrid = 0x%llx\n", - ctx->slave, wc.status, (unsigned long long)wc.wr_id); - if (!MLX4_TUN_IS_RECV(wc.wr_id)) { - ib_destroy_ah(tun_qp->tx_ring[wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1)].ah); - tun_qp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah - = NULL; - spin_lock(&tun_qp->tx_lock); - tun_qp->tx_ix_tail++; - spin_unlock(&tun_qp->tx_lock); - } - } - } -} - -static void pv_qp_event_handler(struct ib_event *event, void *qp_context) -{ - struct mlx4_ib_demux_pv_ctx *sqp = qp_context; - - /* It's worse than that! He's dead, Jim! */ - pr_err("Fatal error (%d) on a MAD QP on port %d\n", - event->event, sqp->port); -} - -static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx, - enum ib_qp_type qp_type, int create_tun) -{ - int i, ret; - struct mlx4_ib_demux_pv_qp *tun_qp; - struct mlx4_ib_qp_tunnel_init_attr qp_init_attr; - struct ib_qp_attr attr; - int qp_attr_mask_INIT; - - if (qp_type > IB_QPT_GSI) - return -EINVAL; - - tun_qp = &ctx->qp[qp_type]; - - memset(&qp_init_attr, 0, sizeof qp_init_attr); - qp_init_attr.init_attr.send_cq = ctx->cq; - qp_init_attr.init_attr.recv_cq = ctx->cq; - qp_init_attr.init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; - qp_init_attr.init_attr.cap.max_send_wr = MLX4_NUM_TUNNEL_BUFS; - qp_init_attr.init_attr.cap.max_recv_wr = MLX4_NUM_TUNNEL_BUFS; - qp_init_attr.init_attr.cap.max_send_sge = 1; - qp_init_attr.init_attr.cap.max_recv_sge = 1; - if (create_tun) { - qp_init_attr.init_attr.qp_type = IB_QPT_UD; - qp_init_attr.init_attr.create_flags = (enum ib_qp_create_flags)MLX4_IB_SRIOV_TUNNEL_QP; - qp_init_attr.port = ctx->port; - qp_init_attr.slave = ctx->slave; - qp_init_attr.proxy_qp_type = qp_type; - qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | - IB_QP_QKEY | IB_QP_PORT; - } else { - qp_init_attr.init_attr.qp_type = qp_type; - qp_init_attr.init_attr.create_flags = (enum ib_qp_create_flags)MLX4_IB_SRIOV_SQP; - qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY; - } - qp_init_attr.init_attr.port_num = ctx->port; - qp_init_attr.init_attr.qp_context = ctx; - qp_init_attr.init_attr.event_handler = pv_qp_event_handler; - tun_qp->qp = ib_create_qp(ctx->pd, &qp_init_attr.init_attr); - if (IS_ERR(tun_qp->qp)) { - ret = PTR_ERR(tun_qp->qp); - tun_qp->qp = NULL; - pr_err("Couldn't create %s QP (%d)\n", - create_tun ? "tunnel" : "special", ret); - return ret; - } - - memset(&attr, 0, sizeof attr); - attr.qp_state = IB_QPS_INIT; - ret = 0; - if (create_tun) - ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave, - ctx->port, 0xFFFF, &attr.pkey_index); - if (ret || !create_tun) - attr.pkey_index = - to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0]; - attr.qkey = IB_QP1_QKEY; - attr.port_num = ctx->port; - ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT); - if (ret) { - pr_err("Couldn't change %s qp state to INIT (%d)\n", - create_tun ? "tunnel" : "special", ret); - goto err_qp; - } - attr.qp_state = IB_QPS_RTR; - ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE); - if (ret) { - pr_err("Couldn't change %s qp state to RTR (%d)\n", - create_tun ? "tunnel" : "special", ret); - goto err_qp; - } - attr.qp_state = IB_QPS_RTS; - attr.sq_psn = 0; - ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN); - if (ret) { - pr_err("Couldn't change %s qp state to RTS (%d)\n", - create_tun ? "tunnel" : "special", ret); - goto err_qp; - } - - for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { - ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, i); - if (ret) { - pr_err(" mlx4_ib_post_pv_buf error" - " (err = %d, i = %d)\n", ret, i); - goto err_qp; - } - } - return 0; - -err_qp: - ib_destroy_qp(tun_qp->qp); - tun_qp->qp = NULL; - return ret; -} - -/* - * IB MAD completion callback for real SQPs - */ -static void mlx4_ib_sqp_comp_worker(struct work_struct *work) -{ - struct mlx4_ib_demux_pv_ctx *ctx; - struct mlx4_ib_demux_pv_qp *sqp; - struct ib_wc wc; - struct ib_grh *grh; - struct ib_mad *mad; - - ctx = container_of(work, struct mlx4_ib_demux_pv_ctx, work); - ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); - - while (mlx4_ib_poll_cq(ctx->cq, 1, &wc) == 1) { - sqp = &ctx->qp[MLX4_TUN_WRID_QPN(wc.wr_id)]; - if (wc.status == IB_WC_SUCCESS) { - switch (wc.opcode) { - case IB_WC_SEND: - ib_destroy_ah(sqp->tx_ring[wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1)].ah); - sqp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah - = NULL; - spin_lock(&sqp->tx_lock); - sqp->tx_ix_tail++; - spin_unlock(&sqp->tx_lock); - break; - case IB_WC_RECV: - mad = (struct ib_mad *) &(((struct mlx4_mad_rcv_buf *) - (sqp->ring[wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1)].addr))->payload); - grh = &(((struct mlx4_mad_rcv_buf *) - (sqp->ring[wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1)].addr))->grh); - mlx4_ib_demux_mad(ctx->ib_dev, ctx->port, &wc, grh, mad); - if (mlx4_ib_post_pv_qp_buf(ctx, sqp, wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1))) - pr_err("Failed reposting SQP " - "buf:%lld\n", (unsigned long long)wc.wr_id); - break; - default: - BUG_ON(1); - break; - } - } else { - pr_debug("mlx4_ib: completion error in tunnel: %d." - " status = %d, wrid = 0x%llx\n", - ctx->slave, wc.status, (unsigned long long)wc.wr_id); - if (!MLX4_TUN_IS_RECV(wc.wr_id)) { - ib_destroy_ah(sqp->tx_ring[wc.wr_id & - (MLX4_NUM_TUNNEL_BUFS - 1)].ah); - sqp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah - = NULL; - spin_lock(&sqp->tx_lock); - sqp->tx_ix_tail++; - spin_unlock(&sqp->tx_lock); - } - } - } -} - -static int alloc_pv_object(struct mlx4_ib_dev *dev, int slave, int port, - struct mlx4_ib_demux_pv_ctx **ret_ctx) -{ - struct mlx4_ib_demux_pv_ctx *ctx; - - *ret_ctx = NULL; - ctx = kzalloc(sizeof (struct mlx4_ib_demux_pv_ctx), GFP_KERNEL); - if (!ctx) { - pr_err("failed allocating pv resource context " - "for port %d, slave %d\n", port, slave); - return -ENOMEM; - } - - ctx->ib_dev = &dev->ib_dev; - ctx->port = port; - ctx->slave = slave; - *ret_ctx = ctx; - return 0; -} - -static void free_pv_object(struct mlx4_ib_dev *dev, int slave, int port) -{ - if (dev->sriov.demux[port - 1].tun[slave]) { - kfree(dev->sriov.demux[port - 1].tun[slave]); - dev->sriov.demux[port - 1].tun[slave] = NULL; - } -} - -static int create_pv_resources(struct ib_device *ibdev, int slave, int port, - int create_tun, struct mlx4_ib_demux_pv_ctx *ctx) -{ - int ret, cq_size; - - if (ctx->state != DEMUX_PV_STATE_DOWN) - return -EEXIST; - - ctx->state = DEMUX_PV_STATE_STARTING; - /* have QP0 only on port owner, and only if link layer is IB */ - if (ctx->slave == mlx4_master_func_num(to_mdev(ctx->ib_dev)->dev) && - rdma_port_get_link_layer(ibdev, ctx->port) == IB_LINK_LAYER_INFINIBAND) - ctx->has_smi = 1; - - if (ctx->has_smi) { - ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_SMI, create_tun); - if (ret) { - pr_err("Failed allocating qp0 tunnel bufs (%d)\n", ret); - goto err_out; - } - } - - ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_GSI, create_tun); - if (ret) { - pr_err("Failed allocating qp1 tunnel bufs (%d)\n", ret); - goto err_out_qp0; - } - - cq_size = 2 * MLX4_NUM_TUNNEL_BUFS; - if (ctx->has_smi) - cq_size *= 2; - - ctx->cq = ib_create_cq(ctx->ib_dev, mlx4_ib_tunnel_comp_handler, - NULL, ctx, cq_size, 0); - if (IS_ERR(ctx->cq)) { - ret = PTR_ERR(ctx->cq); - pr_err("Couldn't create tunnel CQ (%d)\n", ret); - goto err_buf; - } - - ctx->pd = ib_alloc_pd(ctx->ib_dev); - if (IS_ERR(ctx->pd)) { - ret = PTR_ERR(ctx->pd); - pr_err("Couldn't create tunnel PD (%d)\n", ret); - goto err_cq; - } - - ctx->mr = ib_get_dma_mr(ctx->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(ctx->mr)) { - ret = PTR_ERR(ctx->mr); - pr_err("Couldn't get tunnel DMA MR (%d)\n", ret); - goto err_pd; - } - - if (ctx->has_smi) { - ret = create_pv_sqp(ctx, IB_QPT_SMI, create_tun); - if (ret) { - pr_err("Couldn't create %s QP0 (%d)\n", - create_tun ? "tunnel for" : "", ret); - goto err_mr; - } - } - - ret = create_pv_sqp(ctx, IB_QPT_GSI, create_tun); - if (ret) { - pr_err("Couldn't create %s QP1 (%d)\n", - create_tun ? "tunnel for" : "", ret); - goto err_qp0; - } - - if (create_tun) - INIT_WORK(&ctx->work, mlx4_ib_tunnel_comp_worker); - else - INIT_WORK(&ctx->work, mlx4_ib_sqp_comp_worker); - - ctx->wq = to_mdev(ibdev)->sriov.demux[port - 1].wq; - - ret = ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); - if (ret) { - pr_err("Couldn't arm tunnel cq (%d)\n", ret); - goto err_wq; - } - ctx->state = DEMUX_PV_STATE_ACTIVE; - return 0; - -err_wq: - ctx->wq = NULL; - ib_destroy_qp(ctx->qp[1].qp); - ctx->qp[1].qp = NULL; - - -err_qp0: - if (ctx->has_smi) - ib_destroy_qp(ctx->qp[0].qp); - ctx->qp[0].qp = NULL; - -err_mr: - ib_dereg_mr(ctx->mr); - ctx->mr = NULL; - -err_pd: - ib_dealloc_pd(ctx->pd); - ctx->pd = NULL; - -err_cq: - ib_destroy_cq(ctx->cq); - ctx->cq = NULL; - -err_buf: - mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, create_tun); - -err_out_qp0: - if (ctx->has_smi) - mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, create_tun); -err_out: - ctx->state = DEMUX_PV_STATE_DOWN; - return ret; -} - -static void destroy_pv_resources(struct mlx4_ib_dev *dev, int slave, int port, - struct mlx4_ib_demux_pv_ctx *ctx, int flush) -{ - if (!ctx) - return; - if (ctx->state > DEMUX_PV_STATE_DOWN) { - ctx->state = DEMUX_PV_STATE_DOWNING; - if (flush) - flush_workqueue(ctx->wq); - if (ctx->has_smi) { - ib_destroy_qp(ctx->qp[0].qp); - ctx->qp[0].qp = NULL; - mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, 1); - } - ib_destroy_qp(ctx->qp[1].qp); - ctx->qp[1].qp = NULL; - mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, 1); - ib_dereg_mr(ctx->mr); - ctx->mr = NULL; - ib_dealloc_pd(ctx->pd); - ctx->pd = NULL; - ib_destroy_cq(ctx->cq); - ctx->cq = NULL; - ctx->state = DEMUX_PV_STATE_DOWN; - } -} - -static int mlx4_ib_tunnels_update(struct mlx4_ib_dev *dev, int slave, - int port, int do_init) -{ - int ret = 0; - - if (!do_init) { - clean_vf_mcast(&dev->sriov.demux[port - 1], slave); - /* for master, destroy real sqp resources */ - if (slave == mlx4_master_func_num(dev->dev)) - destroy_pv_resources(dev, slave, port, - dev->sriov.sqps[port - 1], 1); - /* destroy the tunnel qp resources */ - destroy_pv_resources(dev, slave, port, - dev->sriov.demux[port - 1].tun[slave], 1); - return 0; - } - - /* create the tunnel qp resources */ - ret = create_pv_resources(&dev->ib_dev, slave, port, 1, - dev->sriov.demux[port - 1].tun[slave]); - - /* for master, create the real sqp resources */ - if (!ret && slave == mlx4_master_func_num(dev->dev)) - ret = create_pv_resources(&dev->ib_dev, slave, port, 0, - dev->sriov.sqps[port - 1]); - return ret; -} - -void mlx4_ib_tunnels_update_work(struct work_struct *work) -{ - struct mlx4_ib_demux_work *dmxw; - - dmxw = container_of(work, struct mlx4_ib_demux_work, work); - mlx4_ib_tunnels_update(dmxw->dev, dmxw->slave, (int) dmxw->port, - dmxw->do_init); - kfree(dmxw); - return; -} - -static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, - struct mlx4_ib_demux_ctx *ctx, - int port) -{ - char name[12]; - int ret = 0; - int i; - - ctx->tun = kcalloc(dev->dev->caps.sqp_demux, - sizeof (struct mlx4_ib_demux_pv_ctx *), GFP_KERNEL); - if (!ctx->tun) - return -ENOMEM; - - ctx->dev = dev; - ctx->port = port; - ctx->ib_dev = &dev->ib_dev; - - for (i = 0; i < dev->dev->caps.sqp_demux; i++) { - ret = alloc_pv_object(dev, i, port, &ctx->tun[i]); - if (ret) { - ret = -ENOMEM; - goto err_mcg; - } - } - - ret = mlx4_ib_mcg_port_init(ctx); - if (ret) { - pr_err("Failed initializing mcg para-virt (%d)\n", ret); - goto err_mcg; - } - - snprintf(name, sizeof name, "mlx4_ibt%d", port); - ctx->wq = create_singlethread_workqueue(name); - if (!ctx->wq) { - pr_err("Failed to create tunnelling WQ for port %d\n", port); - ret = -ENOMEM; - goto err_wq; - } - - snprintf(name, sizeof name, "mlx4_ibud%d", port); - ctx->ud_wq = create_singlethread_workqueue(name); - if (!ctx->ud_wq) { - pr_err("Failed to create up/down WQ for port %d\n", port); - ret = -ENOMEM; - goto err_udwq; - } - - return 0; - -err_udwq: - destroy_workqueue(ctx->wq); - ctx->wq = NULL; - -err_wq: - mlx4_ib_mcg_port_cleanup(ctx, 1); -err_mcg: - for (i = 0; i < dev->dev->caps.sqp_demux; i++) - free_pv_object(dev, i, port); - kfree(ctx->tun); - ctx->tun = NULL; - return ret; -} - -static void mlx4_ib_free_sqp_ctx(struct mlx4_ib_demux_pv_ctx *sqp_ctx) -{ - if (sqp_ctx->state > DEMUX_PV_STATE_DOWN) { - sqp_ctx->state = DEMUX_PV_STATE_DOWNING; - flush_workqueue(sqp_ctx->wq); - if (sqp_ctx->has_smi) { - ib_destroy_qp(sqp_ctx->qp[0].qp); - sqp_ctx->qp[0].qp = NULL; - mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_SMI, 0); - } - ib_destroy_qp(sqp_ctx->qp[1].qp); - sqp_ctx->qp[1].qp = NULL; - mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_GSI, 0); - ib_dereg_mr(sqp_ctx->mr); - sqp_ctx->mr = NULL; - ib_dealloc_pd(sqp_ctx->pd); - sqp_ctx->pd = NULL; - ib_destroy_cq(sqp_ctx->cq); - sqp_ctx->cq = NULL; - sqp_ctx->state = DEMUX_PV_STATE_DOWN; - } -} - -static void mlx4_ib_free_demux_ctx(struct mlx4_ib_demux_ctx *ctx) -{ - int i; - if (ctx) { - struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); - mlx4_ib_mcg_port_cleanup(ctx, 1); - for (i = 0; i < dev->dev->caps.sqp_demux; i++) { - if (!ctx->tun[i]) - continue; - if (ctx->tun[i]->state > DEMUX_PV_STATE_DOWN) - ctx->tun[i]->state = DEMUX_PV_STATE_DOWNING; - } - flush_workqueue(ctx->wq); - for (i = 0; i < dev->dev->caps.sqp_demux; i++) { - destroy_pv_resources(dev, i, ctx->port, ctx->tun[i], 0); - free_pv_object(dev, i, ctx->port); - } - kfree(ctx->tun); - destroy_workqueue(ctx->ud_wq); - destroy_workqueue(ctx->wq); - } -} - -static void mlx4_ib_master_tunnels(struct mlx4_ib_dev *dev, int do_init) -{ - int i; - - if (!mlx4_is_master(dev->dev)) - return; - /* initialize or tear down tunnel QPs for the master */ - for (i = 0; i < dev->dev->caps.num_ports; i++) - mlx4_ib_tunnels_update(dev, mlx4_master_func_num(dev->dev), i + 1, do_init); - return; -} - -int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev) -{ - int i = 0; - int err; - - if (!mlx4_is_mfunc(dev->dev)) - return 0; - - dev->sriov.is_going_down = 0; - spin_lock_init(&dev->sriov.going_down_lock); - mlx4_ib_cm_paravirt_init(dev); - - mlx4_ib_warn(&dev->ib_dev, "multi-function enabled\n"); - - if (mlx4_is_slave(dev->dev)) { - mlx4_ib_warn(&dev->ib_dev, "operating in qp1 tunnel mode\n"); - return 0; - } - - for (i = 0; i < dev->dev->caps.sqp_demux; i++) { - if (i == mlx4_master_func_num(dev->dev)) - mlx4_put_slave_node_guid(dev->dev, i, dev->ib_dev.node_guid); - else - mlx4_put_slave_node_guid(dev->dev, i, mlx4_ib_gen_node_guid()); - } - - err = mlx4_ib_init_alias_guid_service(dev); - if (err) { - mlx4_ib_warn(&dev->ib_dev, "Failed init alias guid process.\n"); - goto paravirt_err; - } - err = mlx4_ib_device_register_sysfs(dev); - if (err) { - mlx4_ib_warn(&dev->ib_dev, "Failed to register sysfs\n"); - goto sysfs_err; - } - - mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n", - dev->dev->caps.sqp_demux); - for (i = 0; i < dev->num_ports; i++) { - union ib_gid gid; - err = __mlx4_ib_query_gid(&dev->ib_dev, i + 1, 0, &gid, 1); - if (err) - goto demux_err; - dev->sriov.demux[i].guid_cache[0] = gid.global.interface_id; - err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1, - &dev->sriov.sqps[i]); - if (err) - goto demux_err; - err = mlx4_ib_alloc_demux_ctx(dev, &dev->sriov.demux[i], i + 1); - if (err) - goto demux_err; - } - mlx4_ib_master_tunnels(dev, 1); - return 0; - -demux_err: - while (i > 0) { - free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1); - mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); - --i; - } - mlx4_ib_device_unregister_sysfs(dev); - -sysfs_err: - mlx4_ib_destroy_alias_guid_service(dev); - -paravirt_err: - mlx4_ib_cm_paravirt_clean(dev, -1); - - return err; -} - -void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev) -{ - int i; - unsigned long flags; - - if (!mlx4_is_mfunc(dev->dev)) - return; - - spin_lock_irqsave(&dev->sriov.going_down_lock, flags); - dev->sriov.is_going_down = 1; - spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); - if (mlx4_is_master(dev->dev)) { - for (i = 0; i < dev->num_ports; i++) { - flush_workqueue(dev->sriov.demux[i].ud_wq); - mlx4_ib_free_sqp_ctx(dev->sriov.sqps[i]); - kfree(dev->sriov.sqps[i]); - dev->sriov.sqps[i] = NULL; - mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); - } - - mlx4_ib_cm_paravirt_clean(dev, -1); - mlx4_ib_destroy_alias_guid_service(dev); - mlx4_ib_device_unregister_sysfs(dev); - } -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/main.c b/sys/ofed/drivers/infiniband/hw/mlx4/main.c deleted file mode 100644 index da5ec04ccb0a..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/main.c +++ /dev/null @@ -1,2896 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 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. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/inetdevice.h> -#include <linux/if_vlan.h> -#include <linux/fs.h> -#include <net/ipv6.h> - -#include <rdma/ib_smi.h> -#include <rdma/ib_user_verbs.h> -#include <rdma/ib_user_verbs_exp.h> -#include <rdma/ib_addr.h> - -#include <linux/mlx4/driver.h> -#include <linux/mlx4/cmd.h> -#include <linux/sched.h> -#include <linux/page.h> -#include <linux/printk.h> -#include "mlx4_ib.h" -#include "mlx4_exp.h" -#include "user.h" -#include "wc.h" - -#define DRV_NAME MLX4_IB_DRV_NAME -#define DRV_VERSION "1.0" -#define DRV_RELDATE __DATE__ - -#define MLX4_IB_DRIVER_PROC_DIR_NAME "driver/mlx4_ib" -#define MLX4_IB_MRS_PROC_DIR_NAME "mrs" -#define MLX4_IB_FLOW_MAX_PRIO 0xFFF -#define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF - -MODULE_AUTHOR("Roland Dreier"); -MODULE_DESCRIPTION("Mellanox ConnectX HCA InfiniBand driver"); -MODULE_LICENSE("Dual BSD/GPL"); -#ifdef __linux__ -MODULE_VERSION(DRV_VERSION); -#endif - -int mlx4_ib_sm_guid_assign = 1; - -module_param_named(sm_guid_assign, mlx4_ib_sm_guid_assign, int, 0444); -MODULE_PARM_DESC(sm_guid_assign, "Enable SM alias_GUID assignment if sm_guid_assign > 0 (Default: 1)"); - -enum { - MAX_NUM_STR_BITMAP = 1 << 15, - DEFAULT_TBL_VAL = -1 -}; - -static struct mlx4_dbdf2val_lst dev_assign_str = { - .name = "dev_assign_str param", - .num_vals = 1, - .def_val = {DEFAULT_TBL_VAL}, - .range = {0, MAX_NUM_STR_BITMAP - 1} -}; -module_param_string(dev_assign_str, dev_assign_str.str, - sizeof(dev_assign_str.str), 0444); -MODULE_PARM_DESC(dev_assign_str, - "Map device function numbers to IB device numbers (e.g. '0000:04:00.0-0,002b:1c:0b.a-1,...').\n" - "\t\tHexadecimal digits for the device function (e.g. 002b:1c:0b.a) and decimal for IB device numbers (e.g. 1).\n" - "\t\tMax supported devices - 32"); - - -static unsigned long *dev_num_str_bitmap; -static spinlock_t dev_num_str_lock; - -static const char mlx4_ib_version[] = - DRV_NAME ": Mellanox ConnectX InfiniBand driver v" - DRV_VERSION " (" DRV_RELDATE ")\n"; - -struct update_gid_work { - struct work_struct work; - union ib_gid gids[128]; - struct mlx4_ib_dev *dev; - int port; -}; - -struct dev_rec { - int bus; - int dev; - int func; - int nr; -}; - -static int dr_active; - -static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init); - -static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev, struct net_device*, - unsigned long); - -static u8 mlx4_ib_get_dev_port(struct net_device *dev, - struct mlx4_ib_dev *ibdev); - -static struct workqueue_struct *wq; - -static void init_query_mad(struct ib_smp *mad) -{ - mad->base_version = 1; - mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - mad->class_version = 1; - mad->method = IB_MGMT_METHOD_GET; -} - -static union ib_gid zgid; - -static int check_flow_steering_support(struct mlx4_dev *dev) -{ - int eth_num_ports = 0; - int ib_num_ports = 0; - int dmfs = dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED; - - if (dmfs) { - int i; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) - eth_num_ports++; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) - ib_num_ports++; - dmfs &= (!ib_num_ports || - (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB)) && - (!eth_num_ports || - (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FS_EN)); - if (ib_num_ports && mlx4_is_mfunc(dev)) { - dmfs = 0; - } - } - return dmfs; -} - -int mlx4_ib_query_device(struct ib_device *ibdev, - struct ib_device_attr *props) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; - int err = -ENOMEM; - - in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); - out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) - goto out; - - init_query_mad(in_mad); - in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; - - err = mlx4_MAD_IFC(to_mdev(ibdev), MLX4_MAD_IFC_IGNORE_KEYS, - 1, NULL, NULL, in_mad, out_mad); - if (err) - goto out; - - memset(props, 0, sizeof *props); - - props->fw_ver = dev->dev->caps.fw_ver; - props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | - IB_DEVICE_PORT_ACTIVE_EVENT | - IB_DEVICE_SYS_IMAGE_GUID | - IB_DEVICE_RC_RNR_NAK_GEN | - IB_DEVICE_BLOCK_MULTICAST_LOOPBACK | - IB_DEVICE_SHARED_MR; - - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR) - props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR) - props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_APM) - props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UD_AV_PORT) - props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) - props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM; - if (dev->dev->caps.max_gso_sz && dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BLH) - props->device_cap_flags |= IB_DEVICE_UD_TSO; - if (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_RESERVED_LKEY) - props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY; - if ((dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_LOCAL_INV) && - (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_REMOTE_INV) && - (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_FAST_REG_WR)) - props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) - props->device_cap_flags |= IB_DEVICE_XRC; - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_CROSS_CHANNEL) - props->device_cap_flags |= IB_DEVICE_CROSS_CHANNEL; - - if (check_flow_steering_support(dev->dev)) - props->device_cap_flags |= IB_DEVICE_MANAGED_FLOW_STEERING; - - - props->device_cap_flags |= IB_DEVICE_QPG; - if (dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS) { - props->device_cap_flags |= IB_DEVICE_UD_RSS; - props->max_rss_tbl_sz = dev->dev->caps.max_rss_tbl_sz; - } - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW) - props->device_cap_flags |= IB_DEVICE_MEM_WINDOW; - if (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_TYPE_2_WIN) { - if (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_WIN_TYPE_2B) - props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2B; - else - props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2A; - } - props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & - 0xffffff; - props->vendor_part_id = dev->dev->pdev->device; - props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32)); - memcpy(&props->sys_image_guid, out_mad->data + 4, 8); - - props->max_mr_size = ~0ull; - props->page_size_cap = dev->dev->caps.page_size_cap; - props->max_qp = dev->dev->quotas.qp; - props->max_qp_wr = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE; - props->max_sge = min(dev->dev->caps.max_sq_sg, - dev->dev->caps.max_rq_sg); - props->max_cq = dev->dev->quotas.cq; - props->max_cqe = dev->dev->caps.max_cqes; - props->max_mr = dev->dev->quotas.mpt; - props->max_pd = dev->dev->caps.num_pds - dev->dev->caps.reserved_pds; - props->max_qp_rd_atom = dev->dev->caps.max_qp_dest_rdma; - props->max_qp_init_rd_atom = dev->dev->caps.max_qp_init_rdma; - props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; - props->max_srq = dev->dev->quotas.srq; - props->max_srq_wr = dev->dev->caps.max_srq_wqes - 1; - props->max_srq_sge = dev->dev->caps.max_srq_sge; - props->max_fast_reg_page_list_len = MLX4_MAX_FAST_REG_PAGES; - props->local_ca_ack_delay = dev->dev->caps.local_ca_ack_delay; - props->atomic_cap = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ? - IB_ATOMIC_HCA : IB_ATOMIC_NONE; - props->masked_atomic_cap = props->atomic_cap; - props->max_pkeys = dev->dev->caps.pkey_table_len[1]; - props->max_mcast_grp = dev->dev->caps.num_mgms + dev->dev->caps.num_amgms; - props->max_mcast_qp_attach = dev->dev->caps.num_qp_per_mgm; - props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * - props->max_mcast_grp; - props->max_map_per_fmr = dev->dev->caps.max_fmr_maps; - props->hca_core_clock = dev->dev->caps.hca_core_clock; - if (dev->dev->caps.hca_core_clock > 0) - props->comp_mask |= IB_DEVICE_ATTR_WITH_HCA_CORE_CLOCK; - if (dev->dev->caps.cq_timestamp) { - props->timestamp_mask = 0xFFFFFFFFFFFF; - props->comp_mask |= IB_DEVICE_ATTR_WITH_TIMESTAMP_MASK; - } - -out: - kfree(in_mad); - kfree(out_mad); - - return err; -} - -static enum rdma_link_layer -mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num) -{ - struct mlx4_dev *dev = to_mdev(device)->dev; - - return dev->caps.port_mask[port_num] == MLX4_PORT_TYPE_IB ? - IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET; -} - -static int ib_link_query_port(struct ib_device *ibdev, u8 port, - struct ib_port_attr *props, int netw_view) -{ - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; - int ext_active_speed; - int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; - int err = -ENOMEM; - - in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); - out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) - goto out; - - init_query_mad(in_mad); - in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; - in_mad->attr_mod = cpu_to_be32(port); - - if (mlx4_is_mfunc(to_mdev(ibdev)->dev) && netw_view) - mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW; - - err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port, NULL, NULL, - in_mad, out_mad); - if (err) - goto out; - - - props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); - props->lmc = out_mad->data[34] & 0x7; - props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); - props->sm_sl = out_mad->data[36] & 0xf; - props->state = out_mad->data[32] & 0xf; - props->phys_state = out_mad->data[33] >> 4; - props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); - if (netw_view) - props->gid_tbl_len = out_mad->data[50]; - else - props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port]; - props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz; - props->pkey_tbl_len = to_mdev(ibdev)->dev->caps.pkey_table_len[port]; - props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); - props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); - props->active_width = out_mad->data[31] & 0xf; - props->active_speed = out_mad->data[35] >> 4; - props->max_mtu = out_mad->data[41] & 0xf; - props->active_mtu = out_mad->data[36] >> 4; - props->subnet_timeout = out_mad->data[51] & 0x1f; - props->max_vl_num = out_mad->data[37] >> 4; - props->init_type_reply = out_mad->data[41] >> 4; - - /* Check if extended speeds (EDR/FDR/...) are supported */ - if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) { - ext_active_speed = out_mad->data[62] >> 4; - - switch (ext_active_speed) { - case 1: - props->active_speed = IB_SPEED_FDR; - break; - case 2: - props->active_speed = IB_SPEED_EDR; - break; - } - } - - /* If reported active speed is QDR, check if is FDR-10 */ - if (props->active_speed == IB_SPEED_QDR) { - init_query_mad(in_mad); - in_mad->attr_id = MLX4_ATTR_EXTENDED_PORT_INFO; - in_mad->attr_mod = cpu_to_be32(port); - - err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port, - NULL, NULL, in_mad, out_mad); - if (err) - goto out; - - /* Checking LinkSpeedActive for FDR-10 */ - if (out_mad->data[15] & 0x1) - props->active_speed = IB_SPEED_FDR10; - } - - /* Avoid wrong speed value returned by FW if the IB link is down. */ - if (props->state == IB_PORT_DOWN) - props->active_speed = IB_SPEED_SDR; - -out: - kfree(in_mad); - kfree(out_mad); - return err; -} - -static u8 state_to_phys_state(enum ib_port_state state) -{ - return state == IB_PORT_ACTIVE ? 5 : 3; -} - -static int eth_link_query_port(struct ib_device *ibdev, u8 port, - struct ib_port_attr *props, int netw_view) -{ - - struct mlx4_ib_dev *mdev = to_mdev(ibdev); - struct mlx4_ib_iboe *iboe = &mdev->iboe; - struct net_device *ndev; - enum ib_mtu tmp; - struct mlx4_cmd_mailbox *mailbox; - unsigned long flags; - int err = 0; - - mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0, - MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - goto out; - - props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) ? - IB_WIDTH_4X : IB_WIDTH_1X; - props->active_speed = IB_SPEED_QDR; - props->port_cap_flags = IB_PORT_CM_SUP; - if (netw_view) - props->gid_tbl_len = MLX4_ROCE_MAX_GIDS; - else - props->gid_tbl_len = mdev->dev->caps.gid_table_len[port]; - - props->max_msg_sz = mdev->dev->caps.max_msg_sz; - props->pkey_tbl_len = 1; - props->max_mtu = IB_MTU_4096; - props->max_vl_num = 2; - props->state = IB_PORT_DOWN; - props->phys_state = state_to_phys_state(props->state); - props->active_mtu = IB_MTU_256; - spin_lock_irqsave(&iboe->lock, flags); - ndev = iboe->netdevs[port - 1]; - if (!ndev) - goto out_unlock; - - tmp = iboe_get_mtu(ndev->if_mtu); - props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256; - - props->state = (netif_running(ndev) && netif_carrier_ok(ndev)) ? - IB_PORT_ACTIVE : IB_PORT_DOWN; - props->phys_state = state_to_phys_state(props->state); -out_unlock: - spin_unlock_irqrestore(&iboe->lock, flags); -out: - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - return err; -} - -int __mlx4_ib_query_port(struct ib_device *ibdev, u8 port, - struct ib_port_attr *props, int netw_view) -{ - int err; - - memset(props, 0, sizeof *props); - - err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ? - ib_link_query_port(ibdev, port, props, netw_view) : - eth_link_query_port(ibdev, port, props, netw_view); - - return err; -} - -static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port, - struct ib_port_attr *props) -{ - /* returns host view */ - return __mlx4_ib_query_port(ibdev, port, props, 0); -} - -int __mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index, - union ib_gid *gid, int netw_view) -{ - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; - int err = -ENOMEM; - struct mlx4_ib_dev *dev = to_mdev(ibdev); - int clear = 0; - int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; - - in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); - out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) - goto out; - - init_query_mad(in_mad); - in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; - in_mad->attr_mod = cpu_to_be32(port); - - if (mlx4_is_mfunc(dev->dev) && netw_view) - mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW; - - err = mlx4_MAD_IFC(dev, mad_ifc_flags, port, NULL, NULL, in_mad, out_mad); - if (err) - goto out; - - memcpy(gid->raw, out_mad->data + 8, 8); - - if (mlx4_is_mfunc(dev->dev) && !netw_view) { - if (index) { - /* For any index > 0, return the null guid */ - err = 0; - clear = 1; - goto out; - } - } - - init_query_mad(in_mad); - in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; - in_mad->attr_mod = cpu_to_be32(index / 8); - - err = mlx4_MAD_IFC(dev, mad_ifc_flags, port, - NULL, NULL, in_mad, out_mad); - if (err) - goto out; - - memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); - -out: - if (clear) - memset(gid->raw + 8, 0, 8); - kfree(in_mad); - kfree(out_mad); - return err; -} - -static int iboe_query_gid(struct ib_device *ibdev, u8 port, int index, - union ib_gid *gid) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - - *gid = dev->iboe.gid_table[port - 1][index]; - - return 0; -} - -static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index, - union ib_gid *gid) -{ - if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) - return __mlx4_ib_query_gid(ibdev, port, index, gid, 0); - else - return iboe_query_gid(ibdev, port, index, gid); -} - -int __mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, - u16 *pkey, int netw_view) -{ - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; - int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; - int err = -ENOMEM; - - in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); - out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) - goto out; - - init_query_mad(in_mad); - in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; - in_mad->attr_mod = cpu_to_be32(index / 32); - - if (mlx4_is_mfunc(to_mdev(ibdev)->dev) && netw_view) - mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW; - - err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port, NULL, NULL, - in_mad, out_mad); - if (err) - goto out; - - *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]); - -out: - kfree(in_mad); - kfree(out_mad); - return err; -} - -static int mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) -{ - return __mlx4_ib_query_pkey(ibdev, port, index, pkey, 0); -} - -static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask, - struct ib_device_modify *props) -{ - struct mlx4_cmd_mailbox *mailbox; - unsigned long flags; - - if (mask & ~IB_DEVICE_MODIFY_NODE_DESC) - return -EOPNOTSUPP; - - if (!(mask & IB_DEVICE_MODIFY_NODE_DESC)) - return 0; - - if (mlx4_is_slave(to_mdev(ibdev)->dev)) - return -EOPNOTSUPP; - - spin_lock_irqsave(&to_mdev(ibdev)->sm_lock, flags); - memcpy(ibdev->node_desc, props->node_desc, 64); - spin_unlock_irqrestore(&to_mdev(ibdev)->sm_lock, flags); - - /* - * If possible, pass node desc to FW, so it can generate - * a 144 trap. If cmd fails, just ignore. - */ - mailbox = mlx4_alloc_cmd_mailbox(to_mdev(ibdev)->dev); - if (IS_ERR(mailbox)) - return 0; - - memset(mailbox->buf, 0, 256); - memcpy(mailbox->buf, props->node_desc, 64); - mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0, - MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(to_mdev(ibdev)->dev, mailbox); - - return 0; -} - -static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols, - u32 cap_mask) -{ - struct mlx4_cmd_mailbox *mailbox; - int err; - u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH; - - mailbox = mlx4_alloc_cmd_mailbox(dev->dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memset(mailbox->buf, 0, 256); - - if (dev->dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - *(u8 *) mailbox->buf = !!reset_qkey_viols << 6; - ((__be32 *) mailbox->buf)[2] = cpu_to_be32(cap_mask); - } else { - ((u8 *) mailbox->buf)[3] = !!reset_qkey_viols; - ((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask); - } - - err = mlx4_cmd(dev->dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev->dev, mailbox); - return err; -} - -static int mlx4_ib_modify_port(struct ib_device *ibdev, u8 port, int mask, - struct ib_port_modify *props) -{ - struct ib_port_attr attr; - u32 cap_mask; - int err; - - mutex_lock(&to_mdev(ibdev)->cap_mask_mutex); - - err = mlx4_ib_query_port(ibdev, port, &attr); - if (err) - goto out; - - cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & - ~props->clr_port_cap_mask; - - err = mlx4_SET_PORT(to_mdev(ibdev), port, - !!(mask & IB_PORT_RESET_QKEY_CNTR), - cap_mask); - -out: - mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); - return err; -} - -static struct ib_ucontext *mlx4_ib_alloc_ucontext(struct ib_device *ibdev, - struct ib_udata *udata) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct mlx4_ib_ucontext *context; - struct mlx4_ib_alloc_ucontext_resp_v3 resp_v3; - struct mlx4_ib_alloc_ucontext_resp resp; - int err; - - if (!dev->ib_active) - return ERR_PTR(-EAGAIN); - - if (ibdev->uverbs_abi_ver == MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION) { - resp_v3.qp_tab_size = dev->dev->caps.num_qps; - if (mlx4_wc_enabled()) { - resp_v3.bf_reg_size = dev->dev->caps.bf_reg_size; - resp_v3.bf_regs_per_page = dev->dev->caps.bf_regs_per_page; - } else { - resp_v3.bf_reg_size = 0; - resp_v3.bf_regs_per_page = 0; - } - } else { - resp.dev_caps = dev->dev->caps.userspace_caps; - resp.qp_tab_size = dev->dev->caps.num_qps; - if (mlx4_wc_enabled()) { - resp.bf_reg_size = dev->dev->caps.bf_reg_size; - resp.bf_regs_per_page = dev->dev->caps.bf_regs_per_page; - } else { - resp.bf_reg_size = 0; - resp.bf_regs_per_page = 0; - } - resp.cqe_size = dev->dev->caps.cqe_size; - } - - context = kmalloc(sizeof *context, GFP_KERNEL); - if (!context) - return ERR_PTR(-ENOMEM); - - err = mlx4_uar_alloc(to_mdev(ibdev)->dev, &context->uar); - if (err) { - kfree(context); - return ERR_PTR(err); - } - - INIT_LIST_HEAD(&context->db_page_list); - mutex_init(&context->db_page_mutex); - - if (ibdev->uverbs_abi_ver == MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION) - err = ib_copy_to_udata(udata, &resp_v3, sizeof(resp_v3)); - else - err = ib_copy_to_udata(udata, &resp, sizeof(resp)); - - if (err) { - mlx4_uar_free(to_mdev(ibdev)->dev, &context->uar); - kfree(context); - return ERR_PTR(-EFAULT); - } - - return &context->ibucontext; -} - -static int mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) -{ - struct mlx4_ib_ucontext *context = to_mucontext(ibcontext); - - mlx4_uar_free(to_mdev(ibcontext->device)->dev, &context->uar); - kfree(context); - - return 0; -} - -/* XXX FBSD has no support for get_unmapped_area function */ -#if 0 -static unsigned long mlx4_ib_get_unmapped_area(struct file *file, - unsigned long addr, - unsigned long len, unsigned long pgoff, - unsigned long flags) -{ - struct mm_struct *mm; - struct vm_area_struct *vma; - unsigned long start_addr; - unsigned long page_size_order; - unsigned long command; - - mm = current->mm; - if (addr) - return current->mm->get_unmapped_area(file, addr, len, - pgoff, flags); - - /* Last 8 bits hold the command others are data per that command */ - command = pgoff & MLX4_IB_MMAP_CMD_MASK; - if (command != MLX4_IB_MMAP_GET_CONTIGUOUS_PAGES) - return current->mm->get_unmapped_area(file, addr, len, - pgoff, flags); - - page_size_order = pgoff >> MLX4_IB_MMAP_CMD_BITS; - /* code is based on the huge-pages get_unmapped_area code */ - start_addr = mm->free_area_cache; - - if (len <= mm->cached_hole_size) - start_addr = TASK_UNMAPPED_BASE; - - -full_search: - addr = ALIGN(start_addr, 1 << page_size_order); - - for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { - /* At this point: (!vma || addr < vma->vm_end). */ - if (TASK_SIZE - len < addr) { - /* - * Start a new search - just in case we missed - * some holes. - */ - if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = TASK_UNMAPPED_BASE; - goto full_search; - } - return -ENOMEM; - } - - if (!vma || addr + len <= vma->vm_start) - return addr; - addr = ALIGN(vma->vm_end, 1 << page_size_order); - } -} -#endif - -static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) -{ - struct mlx4_ib_dev *dev = to_mdev(context->device); - - /* Last 8 bits hold the command others are data per that command */ - unsigned long command = vma->vm_pgoff & MLX4_IB_MMAP_CMD_MASK; - - if (command < MLX4_IB_MMAP_GET_CONTIGUOUS_PAGES) { - /* compatibility handling for commands 0 & 1*/ - if (vma->vm_end - vma->vm_start != PAGE_SIZE) - return -EINVAL; - } - if (command == MLX4_IB_MMAP_UAR_PAGE) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - if (io_remap_pfn_range(vma, vma->vm_start, - to_mucontext(context)->uar.pfn, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - } else if (command == MLX4_IB_MMAP_BLUE_FLAME_PAGE && - dev->dev->caps.bf_reg_size != 0) { - vma->vm_page_prot = pgprot_wc(vma->vm_page_prot); - - if (io_remap_pfn_range(vma, vma->vm_start, - to_mucontext(context)->uar.pfn + - dev->dev->caps.num_uars, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - } else if (command == MLX4_IB_MMAP_GET_HW_CLOCK) { - struct mlx4_clock_params params; - int ret; - - ret = mlx4_get_internal_clock_params(dev->dev, ¶ms); - if (ret) - return ret; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - if (io_remap_pfn_range(vma, vma->vm_start, - (pci_resource_start(dev->dev->pdev, - params.bar) + params.offset) - >> PAGE_SHIFT, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - } else - return -EINVAL; - - return 0; -} - -static int mlx4_ib_ioctl(struct ib_ucontext *context, unsigned int cmd, - unsigned long arg) -{ - struct mlx4_ib_dev *dev = to_mdev(context->device); - int ret; - int offset; - - switch (cmd) { - case MLX4_IOCHWCLOCKOFFSET: { - struct mlx4_clock_params params; - int ret; - ret = mlx4_get_internal_clock_params(dev->dev, ¶ms); - if (!ret) { - offset = params.offset % PAGE_SIZE; - ret = put_user(offset, - (int *)arg); - return sizeof(int); - } else { - return ret; - } - } - default: { - pr_err("mlx4_ib: invalid ioctl %u command with arg %lX\n", - cmd, arg); - return -ENOTTY; - } - } - - return ret; -} - -static int mlx4_ib_query_values(struct ib_device *device, int q_values, - struct ib_device_values *values) -{ - struct mlx4_ib_dev *dev = to_mdev(device); - cycle_t cycles; - - values->values_mask = 0; - if (q_values & IBV_VALUES_HW_CLOCK) { - cycles = mlx4_read_clock(dev->dev); - if (cycles < 0) { - values->hwclock = cycles & CORE_CLOCK_MASK; - values->values_mask |= IBV_VALUES_HW_CLOCK; - } - q_values &= ~IBV_VALUES_HW_CLOCK; - } - - if (q_values) - return -ENOTTY; - - return 0; -} - -static struct ib_pd *mlx4_ib_alloc_pd(struct ib_device *ibdev, - struct ib_ucontext *context, - struct ib_udata *udata) -{ - struct mlx4_ib_pd *pd; - int err; - - pd = kmalloc(sizeof *pd, GFP_KERNEL); - if (!pd) - return ERR_PTR(-ENOMEM); - - err = mlx4_pd_alloc(to_mdev(ibdev)->dev, &pd->pdn); - if (err) { - kfree(pd); - return ERR_PTR(err); - } - - if (context) - if (ib_copy_to_udata(udata, &pd->pdn, sizeof (__u32))) { - mlx4_pd_free(to_mdev(ibdev)->dev, pd->pdn); - kfree(pd); - return ERR_PTR(-EFAULT); - } - - return &pd->ibpd; -} - -static int mlx4_ib_dealloc_pd(struct ib_pd *pd) -{ - mlx4_pd_free(to_mdev(pd->device)->dev, to_mpd(pd)->pdn); - kfree(pd); - - return 0; -} - -static struct ib_xrcd *mlx4_ib_alloc_xrcd(struct ib_device *ibdev, - struct ib_ucontext *context, - struct ib_udata *udata) -{ - struct mlx4_ib_xrcd *xrcd; - int err; - - if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)) - return ERR_PTR(-ENOSYS); - - xrcd = kmalloc(sizeof *xrcd, GFP_KERNEL); - if (!xrcd) - return ERR_PTR(-ENOMEM); - - err = mlx4_xrcd_alloc(to_mdev(ibdev)->dev, &xrcd->xrcdn); - if (err) - goto err1; - - xrcd->pd = ib_alloc_pd(ibdev); - if (IS_ERR(xrcd->pd)) { - err = PTR_ERR(xrcd->pd); - goto err2; - } - - xrcd->cq = ib_create_cq(ibdev, NULL, NULL, xrcd, 1, 0); - if (IS_ERR(xrcd->cq)) { - err = PTR_ERR(xrcd->cq); - goto err3; - } - - return &xrcd->ibxrcd; - -err3: - ib_dealloc_pd(xrcd->pd); -err2: - mlx4_xrcd_free(to_mdev(ibdev)->dev, xrcd->xrcdn); -err1: - kfree(xrcd); - return ERR_PTR(err); -} - -static int mlx4_ib_dealloc_xrcd(struct ib_xrcd *xrcd) -{ - ib_destroy_cq(to_mxrcd(xrcd)->cq); - ib_dealloc_pd(to_mxrcd(xrcd)->pd); - mlx4_xrcd_free(to_mdev(xrcd->device)->dev, to_mxrcd(xrcd)->xrcdn); - kfree(xrcd); - - return 0; -} - -static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid) -{ - struct mlx4_ib_qp *mqp = to_mqp(ibqp); - struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); - struct mlx4_ib_gid_entry *ge; - - ge = kzalloc(sizeof *ge, GFP_KERNEL); - if (!ge) - return -ENOMEM; - - ge->gid = *gid; - if (mlx4_ib_add_mc(mdev, mqp, gid)) { - ge->port = mqp->port; - ge->added = 1; - } - - mutex_lock(&mqp->mutex); - list_add_tail(&ge->list, &mqp->gid_list); - mutex_unlock(&mqp->mutex); - - return 0; -} - -int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, - union ib_gid *gid) -{ - u8 mac[6]; - struct net_device *ndev; - int ret = 0; - - if (!mqp->port) - return 0; - - spin_lock(&mdev->iboe.lock); - ndev = mdev->iboe.netdevs[mqp->port - 1]; - if (ndev) - dev_hold(ndev); - spin_unlock(&mdev->iboe.lock); - - if (ndev) { - rdma_get_mcast_mac((struct in6_addr *)gid, mac); - rtnl_lock(); - dev_mc_add(mdev->iboe.netdevs[mqp->port - 1], mac, 6, 0); - ret = 1; - rtnl_unlock(); - dev_put(ndev); - } - - return ret; -} - -struct mlx4_ib_steering { - struct list_head list; - u64 reg_id; - union ib_gid gid; -}; - -static int parse_flow_attr(struct mlx4_dev *dev, - union ib_flow_spec *ib_spec, - struct _rule_hw *mlx4_spec) -{ - enum mlx4_net_trans_rule_id type; - - switch (ib_spec->type) { - case IB_FLOW_SPEC_ETH: - type = MLX4_NET_TRANS_RULE_ID_ETH; - memcpy(mlx4_spec->eth.dst_mac, ib_spec->eth.val.dst_mac, - ETH_ALEN); - memcpy(mlx4_spec->eth.dst_mac_msk, ib_spec->eth.mask.dst_mac, - ETH_ALEN); - mlx4_spec->eth.vlan_tag = ib_spec->eth.val.vlan_tag; - mlx4_spec->eth.vlan_tag_msk = ib_spec->eth.mask.vlan_tag; - break; - - case IB_FLOW_SPEC_IB: - type = MLX4_NET_TRANS_RULE_ID_IB; - mlx4_spec->ib.l3_qpn = ib_spec->ib.val.l3_type_qpn; - mlx4_spec->ib.qpn_mask = ib_spec->ib.mask.l3_type_qpn; - memcpy(&mlx4_spec->ib.dst_gid, ib_spec->ib.val.dst_gid, 16); - memcpy(&mlx4_spec->ib.dst_gid_msk, - ib_spec->ib.mask.dst_gid, 16); - break; - - case IB_FLOW_SPEC_IPV4: - type = MLX4_NET_TRANS_RULE_ID_IPV4; - mlx4_spec->ipv4.src_ip = ib_spec->ipv4.val.src_ip; - mlx4_spec->ipv4.src_ip_msk = ib_spec->ipv4.mask.src_ip; - mlx4_spec->ipv4.dst_ip = ib_spec->ipv4.val.dst_ip; - mlx4_spec->ipv4.dst_ip_msk = ib_spec->ipv4.mask.dst_ip; - break; - - case IB_FLOW_SPEC_TCP: - case IB_FLOW_SPEC_UDP: - type = ib_spec->type == IB_FLOW_SPEC_TCP ? - MLX4_NET_TRANS_RULE_ID_TCP : - MLX4_NET_TRANS_RULE_ID_UDP; - mlx4_spec->tcp_udp.dst_port = ib_spec->tcp_udp.val.dst_port; - mlx4_spec->tcp_udp.dst_port_msk = - ib_spec->tcp_udp.mask.dst_port; - mlx4_spec->tcp_udp.src_port = ib_spec->tcp_udp.val.src_port; - mlx4_spec->tcp_udp.src_port_msk = - ib_spec->tcp_udp.mask.src_port; - break; - - default: - return -EINVAL; - } - if (map_sw_to_hw_steering_id(dev, type) < 0 || - hw_rule_sz(dev, type) < 0) - return -EINVAL; - mlx4_spec->id = cpu_to_be16(map_sw_to_hw_steering_id(dev, type)); - mlx4_spec->size = hw_rule_sz(dev, type) >> 2; - return hw_rule_sz(dev, type); -} - -static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_attr, - int domain, - enum mlx4_net_trans_promisc_mode flow_type, - u64 *reg_id) -{ - int ret, i; - int size = 0; - void *ib_flow; - struct mlx4_ib_dev *mdev = to_mdev(qp->device); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_net_trans_rule_hw_ctrl *ctrl; - size_t rule_size = sizeof(struct mlx4_net_trans_rule_hw_ctrl) + - (sizeof(struct _rule_hw) * flow_attr->num_of_specs); - - static const u16 __mlx4_domain[] = { - [IB_FLOW_DOMAIN_USER] = MLX4_DOMAIN_UVERBS, - [IB_FLOW_DOMAIN_ETHTOOL] = MLX4_DOMAIN_ETHTOOL, - [IB_FLOW_DOMAIN_RFS] = MLX4_DOMAIN_RFS, - [IB_FLOW_DOMAIN_NIC] = MLX4_DOMAIN_NIC, - }; - - if (flow_attr->priority > MLX4_IB_FLOW_MAX_PRIO) { - pr_err("Invalid priority value.\n"); - return -EINVAL; - } - if (domain >= IB_FLOW_DOMAIN_NUM) { - pr_err("Invalid domain value.\n"); - return -EINVAL; - } - if (map_sw_to_hw_steering_mode(mdev->dev, flow_type) < 0) - return -EINVAL; - - mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - memset(mailbox->buf, 0, rule_size); - ctrl = mailbox->buf; - - ctrl->prio = cpu_to_be16(__mlx4_domain[domain] | - flow_attr->priority); - ctrl->type = map_sw_to_hw_steering_mode(mdev->dev, flow_type); - ctrl->port = flow_attr->port; - ctrl->qpn = cpu_to_be32(qp->qp_num); - - if (flow_attr->flags & IB_FLOW_ATTR_FLAGS_ALLOW_LOOP_BACK) - ctrl->flags = (1 << 3); - - ib_flow = flow_attr + 1; - size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); - for (i = 0; i < flow_attr->num_of_specs; i++) { - ret = parse_flow_attr(mdev->dev, ib_flow, mailbox->buf + size); - if (ret < 0) { - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - return -EINVAL; - } - ib_flow += ((union ib_flow_spec *)ib_flow)->size; - size += ret; - } - - ret = mlx4_cmd_imm(mdev->dev, mailbox->dma, reg_id, size >> 2, 0, - MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (ret == -ENOMEM) - pr_err("mcg table is full. Fail to register network rule.\n"); - else if (ret == -ENXIO) - pr_err("Device managed flow steering is disabled. Fail to register network rule.\n"); - else if (ret) - pr_err("Invalid argumant. Fail to register network rule.\n"); - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - return ret; -} - -static int __mlx4_ib_destroy_flow(struct mlx4_dev *dev, u64 reg_id) -{ - int err; - err = mlx4_cmd(dev, reg_id, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - pr_err("Fail to detach network rule. registration id = 0x%llx\n", - (unsigned long long)reg_id); - return err; -} - -static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp, - struct ib_flow_attr *flow_attr, - int domain) -{ - int err = 0, i = 0; - struct mlx4_ib_flow *mflow; - enum mlx4_net_trans_promisc_mode type[2]; - - memset(type, 0, sizeof(type)); - - mflow = kzalloc(sizeof(struct mlx4_ib_flow), GFP_KERNEL); - if (!mflow) { - err = -ENOMEM; - goto err_free; - } - - switch (flow_attr->type) { - case IB_FLOW_ATTR_NORMAL: - type[0] = MLX4_FS_REGULAR; - break; - - case IB_FLOW_ATTR_ALL_DEFAULT: - type[0] = MLX4_FS_ALL_DEFAULT; - break; - - case IB_FLOW_ATTR_MC_DEFAULT: - type[0] = MLX4_FS_MC_DEFAULT; - break; - - case IB_FLOW_ATTR_SNIFFER: - type[0] = MLX4_FS_UC_SNIFFER; - type[1] = MLX4_FS_MC_SNIFFER; - break; - - default: - err = -EINVAL; - goto err_free; - } - - while (i < ARRAY_SIZE(type) && type[i]) { - err = __mlx4_ib_create_flow(qp, flow_attr, domain, type[i], - &mflow->reg_id[i]); - if (err) - goto err_free; - i++; - } - - return &mflow->ibflow; - -err_free: - kfree(mflow); - return ERR_PTR(err); -} - -static int mlx4_ib_destroy_flow(struct ib_flow *flow_id) -{ - int err, ret = 0; - int i = 0; - struct mlx4_ib_dev *mdev = to_mdev(flow_id->qp->device); - struct mlx4_ib_flow *mflow = to_mflow(flow_id); - - while (i < ARRAY_SIZE(mflow->reg_id) && mflow->reg_id[i]) { - err = __mlx4_ib_destroy_flow(mdev->dev, mflow->reg_id[i]); - if (err) - ret = err; - i++; - } - - kfree(mflow); - return ret; -} - -static struct mlx4_ib_gid_entry *find_gid_entry(struct mlx4_ib_qp *qp, u8 *raw) -{ - struct mlx4_ib_gid_entry *ge; - struct mlx4_ib_gid_entry *tmp; - struct mlx4_ib_gid_entry *ret = NULL; - - list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) { - if (!memcmp(raw, ge->gid.raw, 16)) { - ret = ge; - break; - } - } - - return ret; -} - - -static int del_gid_entry(struct ib_qp *ibqp, union ib_gid *gid) -{ - struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); - struct mlx4_ib_qp *mqp = to_mqp(ibqp); - struct mlx4_ib_gid_entry *ge; - struct net_device *ndev; - u8 mac[6]; - - mutex_lock(&mqp->mutex); - ge = find_gid_entry(mqp, gid->raw); - if (ge) { - spin_lock(&mdev->iboe.lock); - ndev = ge->added ? mdev->iboe.netdevs[ge->port - 1] : NULL; - if (ndev) - dev_hold(ndev); - spin_unlock(&mdev->iboe.lock); - rdma_get_mcast_mac((struct in6_addr *)gid, mac); - if (ndev) { - rtnl_lock(); - dev_mc_delete(mdev->iboe.netdevs[ge->port - 1], mac, 6, 0); - rtnl_unlock(); - dev_put(ndev); - } - list_del(&ge->list); - kfree(ge); - } else - pr_warn("could not find mgid entry\n"); - - mutex_unlock(&mqp->mutex); - return ge != NULL ? 0 : -EINVAL; -} - -static int _mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid, - int count) -{ - int err; - struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); - struct mlx4_ib_qp *mqp = to_mqp(ibqp); - u64 reg_id = 0; - int record_err = 0; - - if (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - struct mlx4_ib_steering *ib_steering; - struct mlx4_ib_steering *tmp; - LIST_HEAD(temp); - - mutex_lock(&mqp->mutex); - list_for_each_entry_safe(ib_steering, tmp, &mqp->steering_rules, - list) { - if (memcmp(ib_steering->gid.raw, gid->raw, 16)) - continue; - - if (--count < 0) - break; - - list_del(&ib_steering->list); - list_add(&ib_steering->list, &temp); - } - mutex_unlock(&mqp->mutex); - list_for_each_entry_safe(ib_steering, tmp, &temp, - list) { - reg_id = ib_steering->reg_id; - - err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, - gid->raw, - (ibqp->qp_type == IB_QPT_RAW_PACKET) ? - MLX4_PROT_ETH : MLX4_PROT_IB_IPV6, - reg_id); - if (err) { - record_err = record_err ?: err; - continue; - } - - err = del_gid_entry(ibqp, gid); - if (err) { - record_err = record_err ?: err; - continue; - } - - list_del(&ib_steering->list); - kfree(ib_steering); - } - mutex_lock(&mqp->mutex); - list_for_each_entry(ib_steering, &temp, list) { - list_add(&ib_steering->list, &mqp->steering_rules); - } - mutex_unlock(&mqp->mutex); - if (count) { - pr_warn("Couldn't release all reg_ids for mgid. Steering rule is left attached\n"); - return -EINVAL; - } - - } else { - if (mdev->dev->caps.steering_mode == MLX4_STEERING_MODE_B0 && - ibqp->qp_type == IB_QPT_RAW_PACKET) - gid->raw[5] = mqp->port; - - err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, - (ibqp->qp_type == IB_QPT_RAW_PACKET) ? - MLX4_PROT_ETH : MLX4_PROT_IB_IPV6, - reg_id); - if (err) - return err; - - err = del_gid_entry(ibqp, gid); - - if (err) - return err; - } - - return record_err; -} - -static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) -{ - struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); - int count = (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) ? - mdev->dev->caps.num_ports : 1; - - return _mlx4_ib_mcg_detach(ibqp, gid, lid, count); -} - -static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) -{ - int err = -ENODEV; - struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); - struct mlx4_ib_qp *mqp = to_mqp(ibqp); - DECLARE_BITMAP(ports, MLX4_MAX_PORTS); - int i = 0; - - if (mdev->dev->caps.steering_mode == MLX4_STEERING_MODE_B0 && - ibqp->qp_type == IB_QPT_RAW_PACKET) - gid->raw[5] = mqp->port; - - if (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - bitmap_fill(ports, mdev->dev->caps.num_ports); - } else { - if (mqp->port <= mdev->dev->caps.num_ports) { - bitmap_zero(ports, mdev->dev->caps.num_ports); - set_bit(0, ports); - } else { - return -EINVAL; - } - } - - for (; i < mdev->dev->caps.num_ports; i++) { - u64 reg_id; - struct mlx4_ib_steering *ib_steering = NULL; - if (!test_bit(i, ports)) - continue; - if (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - ib_steering = kmalloc(sizeof(*ib_steering), GFP_KERNEL); - if (!ib_steering) - goto err_add; - } - - err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, - gid->raw, i + 1, - !!(mqp->flags & - MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), - (ibqp->qp_type == IB_QPT_RAW_PACKET) ? - MLX4_PROT_ETH : MLX4_PROT_IB_IPV6, - ®_id); - if (err) { - kfree(ib_steering); - goto err_add; - } - - err = add_gid_entry(ibqp, gid); - if (err) { - mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, - MLX4_PROT_IB_IPV6, reg_id); - kfree(ib_steering); - goto err_add; - } - - if (ib_steering) { - memcpy(ib_steering->gid.raw, gid->raw, 16); - mutex_lock(&mqp->mutex); - list_add(&ib_steering->list, &mqp->steering_rules); - mutex_unlock(&mqp->mutex); - ib_steering->reg_id = reg_id; - } - } - - - return 0; - -err_add: - if (i > 0) - _mlx4_ib_mcg_detach(ibqp, gid, lid, i); - - return err; -} - -static int init_node_data(struct mlx4_ib_dev *dev) -{ - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; - int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; - int err = -ENOMEM; - - in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); - out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) - goto out; - - init_query_mad(in_mad); - in_mad->attr_id = IB_SMP_ATTR_NODE_DESC; - if (mlx4_is_master(dev->dev)) - mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW; - - err = mlx4_MAD_IFC(dev, mad_ifc_flags, 1, NULL, NULL, in_mad, out_mad); - if (err) - goto out; - - memcpy(dev->ib_dev.node_desc, out_mad->data, 64); - - in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; - - err = mlx4_MAD_IFC(dev, mad_ifc_flags, 1, NULL, NULL, in_mad, out_mad); - if (err) - goto out; - - dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); - memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); - -out: - kfree(in_mad); - kfree(out_mad); - return err; -} - -static ssize_t show_hca(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); - return sprintf(buf, "MT%d\n", dev->dev->pdev->device); -} - -static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); - return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32), - (int) (dev->dev->caps.fw_ver >> 16) & 0xffff, - (int) dev->dev->caps.fw_ver & 0xffff); -} - -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); - return sprintf(buf, "%x\n", dev->dev->rev_id); -} - -static ssize_t show_board(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); - return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, - dev->dev->board_id); -} - -static ssize_t show_vsd(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_ib_dev *dev = - container_of(device, struct mlx4_ib_dev, ib_dev.dev); - ssize_t len = MLX4_VSD_LEN; - - if (dev->dev->vsd_vendor_id == PCI_VENDOR_ID_MELLANOX) - len = sprintf(buf, "%.*s\n", MLX4_VSD_LEN, dev->dev->vsd); - else - memcpy(buf, dev->dev->vsd, MLX4_VSD_LEN); - - return len; -} - -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); -static DEVICE_ATTR(vsd, S_IRUGO, show_vsd, NULL); - -static struct device_attribute *mlx4_class_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_fw_ver, - &dev_attr_hca_type, - &dev_attr_board_id, - &dev_attr_vsd -}; - -static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, struct net_device *dev, u8 port) -{ - memcpy(eui, IF_LLADDR(dev), 3); - memcpy(eui + 5, IF_LLADDR(dev) + 3, 3); - if (vlan_id < 0x1000) { - eui[3] = vlan_id >> 8; - eui[4] = vlan_id & 0xff; - } else { - eui[3] = 0xff; - eui[4] = 0xfe; - } - eui[0] ^= 2; -} - -static void update_gids_task(struct work_struct *work) -{ - struct update_gid_work *gw = container_of(work, struct update_gid_work, work); - struct mlx4_cmd_mailbox *mailbox; - union ib_gid *gids; - int err; - struct mlx4_dev *dev = gw->dev->dev; - - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - pr_warn("update gid table failed %ld\n", PTR_ERR(mailbox)); - goto free; - } - - gids = mailbox->buf; - memcpy(gids, gw->gids, sizeof gw->gids); - - if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, gw->port) == - IB_LINK_LAYER_ETHERNET) { - err = mlx4_cmd(dev, mailbox->dma, - MLX4_SET_PORT_GID_TABLE << 8 | gw->port, - 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - - if (err) - pr_warn("set port command failed\n"); - else - mlx4_ib_dispatch_event(gw->dev, gw->port, - IB_EVENT_GID_CHANGE); - } - - mlx4_free_cmd_mailbox(dev, mailbox); -free: - kfree(gw); -} - -static struct net_device *mlx4_ib_get_netdev(struct ib_device *device, u8 port_num) -{ - struct mlx4_ib_dev *ibdev = to_mdev(device); - return mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port_num); -} - -static void reset_gids_task(struct work_struct *work) -{ - struct update_gid_work *gw = - container_of(work, struct update_gid_work, work); - struct mlx4_cmd_mailbox *mailbox; - union ib_gid *gids; - int err; - struct mlx4_dev *dev = gw->dev->dev; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - pr_warn("reset gid table failed\n"); - goto free; - } - - gids = mailbox->buf; - memcpy(gids, gw->gids, sizeof(gw->gids)); - - if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, 1) == - IB_LINK_LAYER_ETHERNET && - dev->caps.num_ports > 0) { - err = mlx4_cmd(dev, mailbox->dma, - MLX4_SET_PORT_GID_TABLE << 8 | 1, - 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - pr_warn("set port 1 command failed\n"); - } - - if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, 2) == - IB_LINK_LAYER_ETHERNET && - dev->caps.num_ports > 1) { - err = mlx4_cmd(dev, mailbox->dma, - MLX4_SET_PORT_GID_TABLE << 8 | 2, - 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - pr_warn("set port 2 command failed\n"); - } - - mlx4_free_cmd_mailbox(dev, mailbox); -free: - kfree(gw); -} - -static int update_gid_table(struct mlx4_ib_dev *dev, int port, - union ib_gid *gid, int clear, int default_gid) -{ - struct update_gid_work *work; - int i; - int need_update = 0; - int free = -1; - int found = -1; - int max_gids; - int start_index = !default_gid; - - max_gids = dev->dev->caps.gid_table_len[port]; - for (i = start_index; i < max_gids; ++i) { - if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid, - sizeof(*gid))) - found = i; - - if (clear) { - if (found >= 0) { - need_update = 1; - dev->iboe.gid_table[port - 1][found] = zgid; - break; - } - } else { - if (found >= 0) - break; - - if (free < 0 && - !memcmp(&dev->iboe.gid_table[port - 1][i], - &zgid, sizeof(*gid))) - free = i; - } - } - - if (found == -1 && !clear && free < 0) { - pr_err("GID table of port %d is full. Can't add "GID_PRINT_FMT"\n", - port, GID_PRINT_ARGS(gid)); - return -ENOMEM; - } - if (found == -1 && clear) { - pr_err(GID_PRINT_FMT" is not in GID table of port %d\n", GID_PRINT_ARGS(gid), port); - return -EINVAL; - } - if (found == -1 && !clear && free >= 0) { - dev->iboe.gid_table[port - 1][free] = *gid; - need_update = 1; - } - - if (!need_update) - return 0; - - work = kzalloc(sizeof *work, GFP_ATOMIC); - if (!work) - return -ENOMEM; - - memcpy(work->gids, dev->iboe.gid_table[port - 1], sizeof(work->gids)); - INIT_WORK(&work->work, update_gids_task); - work->port = port; - work->dev = dev; - queue_work(wq, &work->work); - - return 0; -} - -static int reset_gid_table(struct mlx4_ib_dev *dev) -{ - struct update_gid_work *work; - - - work = kzalloc(sizeof(*work), GFP_ATOMIC); - if (!work) - return -ENOMEM; - - memset(dev->iboe.gid_table, 0, sizeof(dev->iboe.gid_table)); - memset(work->gids, 0, sizeof(work->gids)); - INIT_WORK(&work->work, reset_gids_task); - work->dev = dev; - queue_work(wq, &work->work); - return 0; -} - -/* XXX BOND Related - stub (no support for these flags in FBSD)*/ -static inline int netif_is_bond_master(struct net_device *dev) -{ -#if 0 - return (dev->flags & IFF_MASTER) && (dev->priv_flags & IFF_BONDING); -#endif - return 0; -} - -static void mlx4_make_default_gid(struct net_device *dev, union ib_gid *gid, u8 port) -{ - gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); - mlx4_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev, port); -} - -static u8 mlx4_ib_get_dev_port(struct net_device *dev, struct mlx4_ib_dev *ibdev) -{ - u8 port = 0; - struct mlx4_ib_iboe *iboe; - struct net_device *real_dev = rdma_vlan_dev_real_dev(dev) ? - rdma_vlan_dev_real_dev(dev) : dev; - - iboe = &ibdev->iboe; - - for (port = 1; port <= MLX4_MAX_PORTS; ++port) - if ((netif_is_bond_master(real_dev) && (real_dev == iboe->masters[port - 1])) || - (!netif_is_bond_master(real_dev) && (real_dev == iboe->netdevs[port - 1]))) - break; - - return port > MLX4_MAX_PORTS ? 0 : port; -} - -static void mlx4_ib_get_dev_addr(struct net_device *dev, struct mlx4_ib_dev *ibdev, u8 port) -{ - struct ifaddr *ifa; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct inet6_dev *in6_dev; - union ib_gid *pgid; - struct inet6_ifaddr *ifp; -#endif - union ib_gid gid; - - - if ((port == 0) || (port > MLX4_MAX_PORTS)) - return; - - /* IPv4 gids */ - TAILQ_FOREACH(ifa, &dev->if_addrhead, ifa_link) { - if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET){ - ipv6_addr_set_v4mapped( - ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr, - (struct in6_addr *)&gid); - update_gid_table(ibdev, port, &gid, 0, 0); - } - - } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - /* IPv6 gids */ - in6_dev = in6_dev_get(dev); - if (in6_dev) { - read_lock_bh(&in6_dev->lock); - list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { - pgid = (union ib_gid *)&ifp->addr; - update_gid_table(ibdev, port, pgid, 0, 0); - } - read_unlock_bh(&in6_dev->lock); - in6_dev_put(in6_dev); - } -#endif -} - -static void mlx4_set_default_gid(struct mlx4_ib_dev *ibdev, - struct net_device *dev, u8 port) -{ - union ib_gid gid; - mlx4_make_default_gid(dev, &gid, port); - update_gid_table(ibdev, port, &gid, 0, 1); -} - -static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev) -{ - struct net_device *dev; - - if (reset_gid_table(ibdev)) - return -1; - - IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(dev, &V_ifnet, if_link) { - u8 port = mlx4_ib_get_dev_port(dev, ibdev); - if (port) { - if (!rdma_vlan_dev_real_dev(dev) && - !netif_is_bond_master(dev)) - mlx4_set_default_gid(ibdev, dev, port); - mlx4_ib_get_dev_addr(dev, ibdev, port); - } - } - - IFNET_RUNLOCK_NOSLEEP(); - - return 0; -} - -static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev, - struct net_device *dev, unsigned long event) -{ - struct mlx4_ib_iboe *iboe; - int port; - int init = 0; - unsigned long flags; - - iboe = &ibdev->iboe; - - spin_lock_irqsave(&iboe->lock, flags); - mlx4_foreach_ib_transport_port(port, ibdev->dev) { - struct net_device *old_netdev = iboe->netdevs[port - 1]; -/* XXX BOND related */ -#if 0 - struct net_device *old_master = iboe->masters[port - 1]; -#endif - iboe->masters[port - 1] = NULL; - iboe->netdevs[port - 1] = - mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port); - - - if (old_netdev != iboe->netdevs[port - 1]) - init = 1; - if (dev == iboe->netdevs[port - 1] && - event == NETDEV_CHANGEADDR) - init = 1; -/* XXX BOND related */ -#if 0 - if (iboe->netdevs[port - 1] && netif_is_bond_slave(iboe->netdevs[port - 1])) - iboe->masters[port - 1] = iboe->netdevs[port - 1]->master; - - /* if bonding is used it is possible that we add it to masters only after - IP address is assigned to the net bonding interface */ - if (old_master != iboe->masters[port - 1]) - init = 1; -#endif - } - - spin_unlock_irqrestore(&iboe->lock, flags); - - if (init) - if (mlx4_ib_init_gid_table(ibdev)) - pr_warn("Fail to reset gid table\n"); -} - -static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *dev = ptr; - struct mlx4_ib_dev *ibdev; - - ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb); - - mlx4_ib_scan_netdevs(ibdev, dev, event); - - return NOTIFY_DONE; -} - -/* This function initializes the gid table only if the event_netdev real device is an iboe - * device, will be invoked by the inet/inet6 events */ -static int mlx4_ib_inet_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *event_netdev = ptr; - struct mlx4_ib_dev *ibdev; - struct mlx4_ib_iboe *ibdev_iboe; - int port = 0; - - ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb_inet); - - struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ? - rdma_vlan_dev_real_dev(event_netdev) : - event_netdev; - - ibdev_iboe = &ibdev->iboe; - - port = mlx4_ib_get_dev_port(real_dev, ibdev); - - /* Perform init_gid_table if the event real_dev is the net_device which represents this port, - * otherwise this event is not related and would be ignored.*/ - if(port && (real_dev == ibdev_iboe->netdevs[port - 1])) - if (mlx4_ib_init_gid_table(ibdev)) - pr_warn("Fail to reset gid table\n"); - - return NOTIFY_DONE; -} - - -static void init_pkeys(struct mlx4_ib_dev *ibdev) -{ - int port; - int slave; - int i; - - if (mlx4_is_master(ibdev->dev)) { - for (slave = 0; slave <= ibdev->dev->num_vfs; ++slave) { - for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) { - for (i = 0; - i < ibdev->dev->phys_caps.pkey_phys_table_len[port]; - ++i) { - ibdev->pkeys.virt2phys_pkey[slave][port - 1][i] = - /* master has the identity virt2phys pkey mapping */ - (slave == mlx4_master_func_num(ibdev->dev) || !i) ? i : - ibdev->dev->phys_caps.pkey_phys_table_len[port] - 1; - mlx4_sync_pkey_table(ibdev->dev, slave, port, i, - ibdev->pkeys.virt2phys_pkey[slave][port - 1][i]); - } - } - } - /* initialize pkey cache */ - for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) { - for (i = 0; - i < ibdev->dev->phys_caps.pkey_phys_table_len[port]; - ++i) - ibdev->pkeys.phys_pkey_cache[port-1][i] = - (i) ? 0 : 0xFFFF; - } - } -} - -static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) -{ - char name[32]; - int eq_per_port = 0; - int added_eqs = 0; - int total_eqs = 0; - int i, j, eq; - - /* Legacy mode or comp_pool is not large enough */ - if (dev->caps.comp_pool == 0 || - dev->caps.num_ports > dev->caps.comp_pool) - return; - - eq_per_port = rounddown_pow_of_two(dev->caps.comp_pool/ - dev->caps.num_ports); - - /* Init eq table */ - added_eqs = 0; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) - added_eqs += eq_per_port; - - total_eqs = dev->caps.num_comp_vectors + added_eqs; - - ibdev->eq_table = kzalloc(total_eqs * sizeof(int), GFP_KERNEL); - if (!ibdev->eq_table) - return; - - ibdev->eq_added = added_eqs; - - eq = 0; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) { - for (j = 0; j < eq_per_port; j++) { - sprintf(name, "mlx4-ib-%d-%d@%d:%d:%d:%d", i, j, - pci_get_domain(dev->pdev->dev.bsddev), - pci_get_bus(dev->pdev->dev.bsddev), - PCI_SLOT(dev->pdev->devfn), - PCI_FUNC(dev->pdev->devfn)); - - /* Set IRQ for specific name (per ring) */ - if (mlx4_assign_eq(dev, name, - &ibdev->eq_table[eq])) { - /* Use legacy (same as mlx4_en driver) */ - pr_warn("Can't allocate EQ %d; reverting to legacy\n", eq); - ibdev->eq_table[eq] = - (eq % dev->caps.num_comp_vectors); - } - eq++; - } - } - - /* Fill the reset of the vector with legacy EQ */ - for (i = 0, eq = added_eqs; i < dev->caps.num_comp_vectors; i++) - ibdev->eq_table[eq++] = i; - - /* Advertise the new number of EQs to clients */ - ibdev->ib_dev.num_comp_vectors = total_eqs; -} - -static void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) -{ - int i; - - /* no additional eqs were added */ - if (!ibdev->eq_table) - return; - - /* Reset the advertised EQ number */ - ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; - - /* Free only the added eqs */ - for (i = 0; i < ibdev->eq_added; i++) { - /* Don't free legacy eqs if used */ - if (ibdev->eq_table[i] <= dev->caps.num_comp_vectors) - continue; - mlx4_release_eq(dev, ibdev->eq_table[i]); - } - - kfree(ibdev->eq_table); -} - -/* - * create show function and a device_attribute struct pointing to - * the function for _name - */ -#define DEVICE_DIAG_RPRT_ATTR(_name, _offset, _op_mod) \ -static ssize_t show_rprt_##_name(struct device *dev, \ - struct device_attribute *attr, \ - char *buf){ \ - return show_diag_rprt(dev, buf, _offset, _op_mod); \ -} \ -static DEVICE_ATTR(_name, S_IRUGO, show_rprt_##_name, NULL); - -#define MLX4_DIAG_RPRT_CLEAR_DIAGS 3 - -static size_t show_diag_rprt(struct device *device, char *buf, - u32 offset, u8 op_modifier) -{ - size_t ret; - u32 counter_offset = offset; - u32 diag_counter = 0; - struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, - ib_dev.dev); - - ret = mlx4_query_diag_counters(dev->dev, 1, op_modifier, - &counter_offset, &diag_counter); - if (ret) - return ret; - - return sprintf(buf, "%d\n", diag_counter); -} - -static ssize_t clear_diag_counters(struct device *device, - struct device_attribute *attr, - const char *buf, size_t length) -{ - size_t ret; - struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, - ib_dev.dev); - - ret = mlx4_query_diag_counters(dev->dev, 0, MLX4_DIAG_RPRT_CLEAR_DIAGS, - NULL, NULL); - if (ret) - return ret; - - return length; -} - -DEVICE_DIAG_RPRT_ATTR(rq_num_lle , 0x00, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_lle , 0x04, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_lqpoe , 0x08, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_lqpoe , 0x0C, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_lpe , 0x18, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_lpe , 0x1C, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_wrfe , 0x20, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_wrfe , 0x24, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_mwbe , 0x2C, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_bre , 0x34, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_lae , 0x38, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_rire , 0x44, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_rire , 0x48, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_rae , 0x4C, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_rae , 0x50, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_roe , 0x54, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_tree , 0x5C, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_rree , 0x64, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_rnr , 0x68, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_rnr , 0x6C, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_oos , 0x100, 2); -DEVICE_DIAG_RPRT_ATTR(sq_num_oos , 0x104, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_mce , 0x108, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_udsdprd , 0x118, 2); -DEVICE_DIAG_RPRT_ATTR(rq_num_ucsdprd , 0x120, 2); -DEVICE_DIAG_RPRT_ATTR(num_cqovf , 0x1A0, 2); -DEVICE_DIAG_RPRT_ATTR(num_eqovf , 0x1A4, 2); -DEVICE_DIAG_RPRT_ATTR(num_baddb , 0x1A8, 2); - -static DEVICE_ATTR(clear_diag, S_IWUSR, NULL, clear_diag_counters); - -static struct attribute *diag_rprt_attrs[] = { - &dev_attr_rq_num_lle.attr, - &dev_attr_sq_num_lle.attr, - &dev_attr_rq_num_lqpoe.attr, - &dev_attr_sq_num_lqpoe.attr, - &dev_attr_rq_num_lpe.attr, - &dev_attr_sq_num_lpe.attr, - &dev_attr_rq_num_wrfe.attr, - &dev_attr_sq_num_wrfe.attr, - &dev_attr_sq_num_mwbe.attr, - &dev_attr_sq_num_bre.attr, - &dev_attr_rq_num_lae.attr, - &dev_attr_sq_num_rire.attr, - &dev_attr_rq_num_rire.attr, - &dev_attr_sq_num_rae.attr, - &dev_attr_rq_num_rae.attr, - &dev_attr_sq_num_roe.attr, - &dev_attr_sq_num_tree.attr, - &dev_attr_sq_num_rree.attr, - &dev_attr_rq_num_rnr.attr, - &dev_attr_sq_num_rnr.attr, - &dev_attr_rq_num_oos.attr, - &dev_attr_sq_num_oos.attr, - &dev_attr_rq_num_mce.attr, - &dev_attr_rq_num_udsdprd.attr, - &dev_attr_rq_num_ucsdprd.attr, - &dev_attr_num_cqovf.attr, - &dev_attr_num_eqovf.attr, - &dev_attr_num_baddb.attr, - &dev_attr_clear_diag.attr, - NULL -}; - -static struct attribute_group diag_counters_group = { - .name = "diag_counters", - .attrs = diag_rprt_attrs -}; - -static void init_dev_assign(void) -{ - int i = 1; - - spin_lock_init(&dev_num_str_lock); - if (mlx4_fill_dbdf2val_tbl(&dev_assign_str)) - return; - dev_num_str_bitmap = - kmalloc(BITS_TO_LONGS(MAX_NUM_STR_BITMAP) * sizeof(long), - GFP_KERNEL); - if (!dev_num_str_bitmap) { - pr_warn("bitmap alloc failed -- cannot apply dev_assign_str parameter\n"); - return; - } - bitmap_zero(dev_num_str_bitmap, MAX_NUM_STR_BITMAP); - while ((i < MLX4_DEVS_TBL_SIZE) && (dev_assign_str.tbl[i].dbdf != - MLX4_ENDOF_TBL)) { - if (bitmap_allocate_region(dev_num_str_bitmap, - dev_assign_str.tbl[i].val[0], 0)) - goto err; - i++; - } - dr_active = 1; - return; - -err: - kfree(dev_num_str_bitmap); - dev_num_str_bitmap = NULL; - pr_warn("mlx4_ib: The value of 'dev_assign_str' parameter " - "is incorrect. The parameter value is discarded!"); -} - -static int mlx4_ib_dev_idx(struct mlx4_dev *dev) -{ - int i, val; - - if (!dr_active) - return -1; - if (!dev) - return -1; - if (mlx4_get_val(dev_assign_str.tbl, dev->pdev, 0, &val)) - return -1; - - if (val != DEFAULT_TBL_VAL) { - dev->flags |= MLX4_FLAG_DEV_NUM_STR; - return val; - } - - spin_lock(&dev_num_str_lock); - i = bitmap_find_free_region(dev_num_str_bitmap, MAX_NUM_STR_BITMAP, 0); - spin_unlock(&dev_num_str_lock); - if (i >= 0) - return i; - - return -1; -} - -static void *mlx4_ib_add(struct mlx4_dev *dev) -{ - struct mlx4_ib_dev *ibdev; - int num_ports = 0; - int i, j; - int err; - struct mlx4_ib_iboe *iboe; - int dev_idx; - - pr_info_once("%s", mlx4_ib_version); - - mlx4_foreach_ib_transport_port(i, dev) - num_ports++; - - /* No point in registering a device with no ports... */ - if (num_ports == 0) - return NULL; - - ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev); - if (!ibdev) { - dev_err(&dev->pdev->dev, "Device struct alloc failed\n"); - return NULL; - } - - iboe = &ibdev->iboe; - - if (mlx4_pd_alloc(dev, &ibdev->priv_pdn)) - goto err_dealloc; - - if (mlx4_uar_alloc(dev, &ibdev->priv_uar)) - goto err_pd; - - ibdev->priv_uar.map = ioremap(ibdev->priv_uar.pfn << PAGE_SHIFT, - PAGE_SIZE); - - if (!ibdev->priv_uar.map) - goto err_uar; - - MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock); - - ibdev->dev = dev; - - dev_idx = mlx4_ib_dev_idx(dev); - if (dev_idx >= 0) - sprintf(ibdev->ib_dev.name, "mlx4_%d", dev_idx); - else - strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX); - - ibdev->ib_dev.owner = THIS_MODULE; - ibdev->ib_dev.node_type = RDMA_NODE_IB_CA; - ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey; - ibdev->num_ports = num_ports; - ibdev->ib_dev.phys_port_cnt = ibdev->num_ports; - ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; - ibdev->ib_dev.dma_device = &dev->pdev->dev; - - if (dev->caps.userspace_caps) - ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION; - else - ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION; - - ibdev->ib_dev.uverbs_cmd_mask = - (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | - (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | - (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | - (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | - (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | - (1ull << IB_USER_VERBS_CMD_REG_MR) | - (1ull << IB_USER_VERBS_CMD_DEREG_MR) | - (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | - (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | - (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | - (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | - (1ull << IB_USER_VERBS_CMD_CREATE_QP) | - (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | - (1ull << IB_USER_VERBS_CMD_QUERY_QP) | - (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | - (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | - (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | - (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | - (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | - (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | - (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | - (1ull << IB_USER_VERBS_CMD_CREATE_XSRQ) | - (1ull << IB_USER_VERBS_CMD_OPEN_QP); - - ibdev->ib_dev.query_device = mlx4_ib_query_device; - ibdev->ib_dev.query_port = mlx4_ib_query_port; - ibdev->ib_dev.get_link_layer = mlx4_ib_port_link_layer; - ibdev->ib_dev.query_gid = mlx4_ib_query_gid; - ibdev->ib_dev.query_pkey = mlx4_ib_query_pkey; - ibdev->ib_dev.modify_device = mlx4_ib_modify_device; - ibdev->ib_dev.modify_port = mlx4_ib_modify_port; - ibdev->ib_dev.alloc_ucontext = mlx4_ib_alloc_ucontext; - ibdev->ib_dev.dealloc_ucontext = mlx4_ib_dealloc_ucontext; - ibdev->ib_dev.mmap = mlx4_ib_mmap; -/* XXX FBSD has no support for get_unmapped_area function */ -#if 0 - ibdev->ib_dev.get_unmapped_area = mlx4_ib_get_unmapped_area; -#endif - ibdev->ib_dev.alloc_pd = mlx4_ib_alloc_pd; - ibdev->ib_dev.dealloc_pd = mlx4_ib_dealloc_pd; - ibdev->ib_dev.create_ah = mlx4_ib_create_ah; - ibdev->ib_dev.query_ah = mlx4_ib_query_ah; - ibdev->ib_dev.destroy_ah = mlx4_ib_destroy_ah; - ibdev->ib_dev.create_srq = mlx4_ib_create_srq; - ibdev->ib_dev.modify_srq = mlx4_ib_modify_srq; - ibdev->ib_dev.query_srq = mlx4_ib_query_srq; - ibdev->ib_dev.destroy_srq = mlx4_ib_destroy_srq; - ibdev->ib_dev.post_srq_recv = mlx4_ib_post_srq_recv; - ibdev->ib_dev.create_qp = mlx4_ib_create_qp; - ibdev->ib_dev.modify_qp = mlx4_ib_modify_qp; - ibdev->ib_dev.query_qp = mlx4_ib_query_qp; - ibdev->ib_dev.destroy_qp = mlx4_ib_destroy_qp; - ibdev->ib_dev.post_send = mlx4_ib_post_send; - ibdev->ib_dev.post_recv = mlx4_ib_post_recv; - ibdev->ib_dev.create_cq = mlx4_ib_create_cq; - ibdev->ib_dev.modify_cq = mlx4_ib_modify_cq; - ibdev->ib_dev.resize_cq = mlx4_ib_resize_cq; - ibdev->ib_dev.destroy_cq = mlx4_ib_destroy_cq; - ibdev->ib_dev.poll_cq = mlx4_ib_poll_cq; - ibdev->ib_dev.req_notify_cq = mlx4_ib_arm_cq; - ibdev->ib_dev.get_dma_mr = mlx4_ib_get_dma_mr; - ibdev->ib_dev.reg_user_mr = mlx4_ib_reg_user_mr; - ibdev->ib_dev.dereg_mr = mlx4_ib_dereg_mr; - ibdev->ib_dev.alloc_fast_reg_mr = mlx4_ib_alloc_fast_reg_mr; - ibdev->ib_dev.alloc_fast_reg_page_list = mlx4_ib_alloc_fast_reg_page_list; - ibdev->ib_dev.free_fast_reg_page_list = mlx4_ib_free_fast_reg_page_list; - ibdev->ib_dev.attach_mcast = mlx4_ib_mcg_attach; - ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach; - ibdev->ib_dev.process_mad = mlx4_ib_process_mad; - ibdev->ib_dev.get_netdev = mlx4_ib_get_netdev; - ibdev->ib_dev.ioctl = mlx4_ib_ioctl; - ibdev->ib_dev.query_values = mlx4_ib_query_values; - - if (!mlx4_is_slave(ibdev->dev)) { - ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc; - ibdev->ib_dev.map_phys_fmr = mlx4_ib_map_phys_fmr; - ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr; - ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc; - } - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW) { - ibdev->ib_dev.alloc_mw = mlx4_ib_alloc_mw; - ibdev->ib_dev.bind_mw = mlx4_ib_bind_mw; - ibdev->ib_dev.dealloc_mw = mlx4_ib_dealloc_mw; - - ibdev->ib_dev.uverbs_cmd_mask |= - (1ull << IB_USER_VERBS_CMD_ALLOC_MW) | - (1ull << IB_USER_VERBS_CMD_DEALLOC_MW); - } - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) { - ibdev->ib_dev.alloc_xrcd = mlx4_ib_alloc_xrcd; - ibdev->ib_dev.dealloc_xrcd = mlx4_ib_dealloc_xrcd; - ibdev->ib_dev.uverbs_cmd_mask |= - (1ull << IB_USER_VERBS_CMD_OPEN_XRCD) | - (1ull << IB_USER_VERBS_CMD_CLOSE_XRCD); - } - - /* - * Set experimental data - */ - ibdev->ib_dev.uverbs_exp_cmd_mask = - (1ull << IB_USER_VERBS_EXP_CMD_CREATE_QP) | - (1ull << IB_USER_VERBS_EXP_CMD_MODIFY_CQ) | - (1ull << IB_USER_VERBS_EXP_CMD_QUERY_DEVICE) | - (1ull << IB_USER_VERBS_EXP_CMD_CREATE_CQ); - ibdev->ib_dev.exp_create_qp = mlx4_ib_exp_create_qp; - ibdev->ib_dev.exp_query_device = mlx4_ib_exp_query_device; - if (check_flow_steering_support(dev)) { - ibdev->ib_dev.uverbs_ex_cmd_mask |= - (1ull << IB_USER_VERBS_EX_CMD_CREATE_FLOW) | - (1ull << IB_USER_VERBS_EX_CMD_DESTROY_FLOW); - ibdev->ib_dev.create_flow = mlx4_ib_create_flow; - ibdev->ib_dev.destroy_flow = mlx4_ib_destroy_flow; - } else { - pr_debug("Device managed flow steering is unavailable for this configuration.\n"); - } - /* - * End of experimental data - */ - - mlx4_ib_alloc_eqs(dev, ibdev); - - spin_lock_init(&iboe->lock); - - if (init_node_data(ibdev)) - goto err_map; - - for (i = 0; i < ibdev->num_ports; ++i) { - if (mlx4_ib_port_link_layer(&ibdev->ib_dev, i + 1) == - IB_LINK_LAYER_ETHERNET) { - if (mlx4_is_slave(dev)) { - ibdev->counters[i].status = mlx4_counter_alloc(ibdev->dev, - i + 1, - &ibdev->counters[i].counter_index); - } else {/* allocating the PF IB default counter indices reserved in mlx4_init_counters_table */ - ibdev->counters[i].counter_index = ((i + 1) << 1) - 1; - ibdev->counters[i].status = 0; - } - - dev_info(&dev->pdev->dev, - "%s: allocated counter index %d for port %d\n", - __func__, ibdev->counters[i].counter_index, i+1); - } else { - ibdev->counters[i].counter_index = MLX4_SINK_COUNTER_INDEX; - ibdev->counters[i].status = -ENOSPC; - } - } - - spin_lock_init(&ibdev->sm_lock); - mutex_init(&ibdev->cap_mask_mutex); - - if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED && - !mlx4_is_mfunc(dev)) { - ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS; - err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count, - MLX4_IB_UC_STEER_QPN_ALIGN, &ibdev->steer_qpn_base, 0); - if (err) - goto err_counter; - - ibdev->ib_uc_qpns_bitmap = - kmalloc(BITS_TO_LONGS(ibdev->steer_qpn_count) * - sizeof(long), - GFP_KERNEL); - if (!ibdev->ib_uc_qpns_bitmap) { - dev_err(&dev->pdev->dev, "bit map alloc failed\n"); - goto err_steer_qp_release; - } - - bitmap_zero(ibdev->ib_uc_qpns_bitmap, ibdev->steer_qpn_count); - - err = mlx4_FLOW_STEERING_IB_UC_QP_RANGE(dev, ibdev->steer_qpn_base, - ibdev->steer_qpn_base + ibdev->steer_qpn_count - 1); - if (err) - goto err_steer_free_bitmap; - } - - if (ib_register_device(&ibdev->ib_dev, NULL)) - goto err_steer_free_bitmap; - - if (mlx4_ib_mad_init(ibdev)) - goto err_reg; - - if (mlx4_ib_init_sriov(ibdev)) - goto err_mad; - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE) { - if (!iboe->nb.notifier_call) { - iboe->nb.notifier_call = mlx4_ib_netdev_event; - err = register_netdevice_notifier(&iboe->nb); - if (err) { - iboe->nb.notifier_call = NULL; - goto err_notify; - } - } - if (!iboe->nb_inet.notifier_call) { - iboe->nb_inet.notifier_call = mlx4_ib_inet_event; - err = register_inetaddr_notifier(&iboe->nb_inet); - if (err) { - iboe->nb_inet.notifier_call = NULL; - goto err_notify; - } - } - mlx4_ib_scan_netdevs(ibdev, NULL, 0); - } - for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) { - if (device_create_file(&ibdev->ib_dev.dev, - mlx4_class_attributes[j])) - goto err_notify; - } - if (sysfs_create_group(&ibdev->ib_dev.dev.kobj, &diag_counters_group)) - goto err_notify; - - ibdev->ib_active = true; - - if (mlx4_is_mfunc(ibdev->dev)) - init_pkeys(ibdev); - - /* create paravirt contexts for any VFs which are active */ - if (mlx4_is_master(ibdev->dev)) { - for (j = 0; j < MLX4_MFUNC_MAX; j++) { - if (j == mlx4_master_func_num(ibdev->dev)) - continue; - if (mlx4_is_slave_active(ibdev->dev, j)) - do_slave_init(ibdev, j, 1); - } - } - return ibdev; - -err_notify: - for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) { - device_remove_file(&ibdev->ib_dev.dev, - mlx4_class_attributes[j]); - } - - if (ibdev->iboe.nb.notifier_call) { - if (unregister_netdevice_notifier(&ibdev->iboe.nb)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb.notifier_call = NULL; - } - if (ibdev->iboe.nb_inet.notifier_call) { - if (unregister_inetaddr_notifier(&ibdev->iboe.nb_inet)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb_inet.notifier_call = NULL; - } - flush_workqueue(wq); - - mlx4_ib_close_sriov(ibdev); - -err_mad: - mlx4_ib_mad_cleanup(ibdev); - -err_reg: - ib_unregister_device(&ibdev->ib_dev); - -err_steer_free_bitmap: - kfree(ibdev->ib_uc_qpns_bitmap); - -err_steer_qp_release: - if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) - mlx4_qp_release_range(dev, ibdev->steer_qpn_base, - ibdev->steer_qpn_count); -err_counter: - for (; i; --i) { - if (mlx4_ib_port_link_layer(&ibdev->ib_dev, i) == - IB_LINK_LAYER_ETHERNET) { - mlx4_counter_free(ibdev->dev, - i, - ibdev->counters[i - 1].counter_index); - } - } - -err_map: - iounmap(ibdev->priv_uar.map); - mlx4_ib_free_eqs(dev, ibdev); - -err_uar: - mlx4_uar_free(dev, &ibdev->priv_uar); - -err_pd: - mlx4_pd_free(dev, ibdev->priv_pdn); - -err_dealloc: - ib_dealloc_device(&ibdev->ib_dev); - - return NULL; -} - -int mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn) -{ - int offset; - - WARN_ON(!dev->ib_uc_qpns_bitmap); - - offset = bitmap_find_free_region(dev->ib_uc_qpns_bitmap, - dev->steer_qpn_count, - get_count_order(count)); - if (offset < 0) - return offset; - - *qpn = dev->steer_qpn_base + offset; - return 0; -} - -void mlx4_ib_steer_qp_free(struct mlx4_ib_dev *dev, u32 qpn, int count) -{ - if (!qpn || - dev->dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) - return; - - BUG_ON(qpn < dev->steer_qpn_base); - - bitmap_release_region(dev->ib_uc_qpns_bitmap, - qpn - dev->steer_qpn_base, get_count_order(count)); -} - -int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, - int is_attach) -{ - int err; - size_t flow_size; - struct ib_flow_attr *flow = NULL; - struct ib_flow_spec_ib *ib_spec; - - if (is_attach) { - flow_size = sizeof(struct ib_flow_attr) + - sizeof(struct ib_flow_spec_ib); - flow = kzalloc(flow_size, GFP_KERNEL); - if (!flow) - return -ENOMEM; - flow->port = mqp->port; - flow->num_of_specs = 1; - flow->size = flow_size; - ib_spec = (struct ib_flow_spec_ib *)(flow + 1); - ib_spec->type = IB_FLOW_SPEC_IB; - ib_spec->size = sizeof(struct ib_flow_spec_ib); - ib_spec->val.l3_type_qpn = mqp->ibqp.qp_num; - ib_spec->mask.l3_type_qpn = MLX4_IB_FLOW_QPN_MASK; - - err = __mlx4_ib_create_flow(&mqp->ibqp, flow, - IB_FLOW_DOMAIN_NIC, - MLX4_FS_REGULAR, - &mqp->reg_id); - } else { - err = __mlx4_ib_destroy_flow(mdev->dev, mqp->reg_id); - } - kfree(flow); - return err; -} - -static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) -{ - struct mlx4_ib_dev *ibdev = ibdev_ptr; - int p, j; - int dev_idx, ret; - - if (ibdev->iboe.nb_inet.notifier_call) { - if (unregister_inetaddr_notifier(&ibdev->iboe.nb_inet)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb_inet.notifier_call = NULL; - } - - mlx4_ib_close_sriov(ibdev); - sysfs_remove_group(&ibdev->ib_dev.dev.kobj, &diag_counters_group); - mlx4_ib_mad_cleanup(ibdev); - - for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) { - device_remove_file(&ibdev->ib_dev.dev, - mlx4_class_attributes[j]); - } - - - dev_idx = -1; - if (dr_active && !(ibdev->dev->flags & MLX4_FLAG_DEV_NUM_STR)) { - ret = sscanf(ibdev->ib_dev.name, "mlx4_%d", &dev_idx); - if (ret != 1) - dev_idx = -1; - } - ib_unregister_device(&ibdev->ib_dev); - if (dev_idx >= 0) { - spin_lock(&dev_num_str_lock); - bitmap_release_region(dev_num_str_bitmap, dev_idx, 0); - spin_unlock(&dev_num_str_lock); - } - - if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { - mlx4_qp_release_range(dev, ibdev->steer_qpn_base, - ibdev->steer_qpn_count); - kfree(ibdev->ib_uc_qpns_bitmap); - } - - if (ibdev->iboe.nb.notifier_call) { - if (unregister_netdevice_notifier(&ibdev->iboe.nb)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb.notifier_call = NULL; - } - iounmap(ibdev->priv_uar.map); - - for (p = 0; p < ibdev->num_ports; ++p) { - if (mlx4_ib_port_link_layer(&ibdev->ib_dev, p + 1) == - IB_LINK_LAYER_ETHERNET) { - mlx4_counter_free(ibdev->dev, - p + 1, - ibdev->counters[p].counter_index); - } - } - - mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB) - mlx4_CLOSE_PORT(dev, p); - - mlx4_ib_free_eqs(dev, ibdev); - - mlx4_uar_free(dev, &ibdev->priv_uar); - mlx4_pd_free(dev, ibdev->priv_pdn); - ib_dealloc_device(&ibdev->ib_dev); -} - -static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init) -{ - struct mlx4_ib_demux_work **dm = NULL; - struct mlx4_dev *dev = ibdev->dev; - int i; - unsigned long flags; - - if (!mlx4_is_master(dev)) - return; - - dm = kcalloc(dev->caps.num_ports, sizeof *dm, GFP_ATOMIC); - if (!dm) { - pr_err("failed to allocate memory for tunneling qp update\n"); - goto out; - } - - for (i = 0; i < dev->caps.num_ports; i++) { - dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC); - if (!dm[i]) { - pr_err("failed to allocate memory for tunneling qp update work struct\n"); - for (i = 0; i < dev->caps.num_ports; i++) { - if (dm[i]) - kfree(dm[i]); - } - goto out; - } - } - /* initialize or tear down tunnel QPs for the slave */ - for (i = 0; i < dev->caps.num_ports; i++) { - INIT_WORK(&dm[i]->work, mlx4_ib_tunnels_update_work); - dm[i]->port = i + 1; - dm[i]->slave = slave; - dm[i]->do_init = do_init; - dm[i]->dev = ibdev; - spin_lock_irqsave(&ibdev->sriov.going_down_lock, flags); - if (!ibdev->sriov.is_going_down) - queue_work(ibdev->sriov.demux[i].ud_wq, &dm[i]->work); - spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags); - } -out: - if (dm) - kfree(dm); - return; -} - -static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, - enum mlx4_dev_event event, unsigned long param) -{ - struct ib_event ibev; - struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr); - struct mlx4_eqe *eqe = NULL; - struct ib_event_work *ew; - int p = 0; - - if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE) - eqe = (struct mlx4_eqe *)param; - else - p = (int) param; - - switch (event) { - case MLX4_DEV_EVENT_PORT_UP: - if (p > ibdev->num_ports) - return; - if (mlx4_is_master(dev) && - rdma_port_get_link_layer(&ibdev->ib_dev, p) == - IB_LINK_LAYER_INFINIBAND) { - mlx4_ib_invalidate_all_guid_record(ibdev, p); - } - mlx4_ib_info((struct ib_device *) ibdev_ptr, - "Port %d logical link is up\n", p); - ibev.event = IB_EVENT_PORT_ACTIVE; - break; - - case MLX4_DEV_EVENT_PORT_DOWN: - if (p > ibdev->num_ports) - return; - mlx4_ib_info((struct ib_device *) ibdev_ptr, - "Port %d logical link is down\n", p); - ibev.event = IB_EVENT_PORT_ERR; - break; - - case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: - ibdev->ib_active = false; - ibev.event = IB_EVENT_DEVICE_FATAL; - break; - - case MLX4_DEV_EVENT_PORT_MGMT_CHANGE: - ew = kmalloc(sizeof *ew, GFP_ATOMIC); - if (!ew) { - pr_err("failed to allocate memory for events work\n"); - break; - } - - INIT_WORK(&ew->work, handle_port_mgmt_change_event); - memcpy(&ew->ib_eqe, eqe, sizeof *eqe); - ew->ib_dev = ibdev; - /* need to queue only for port owner, which uses GEN_EQE */ - if (mlx4_is_master(dev)) - queue_work(wq, &ew->work); - else - handle_port_mgmt_change_event(&ew->work); - return; - - case MLX4_DEV_EVENT_SLAVE_INIT: - /* here, p is the slave id */ - do_slave_init(ibdev, p, 1); - return; - - case MLX4_DEV_EVENT_SLAVE_SHUTDOWN: - /* here, p is the slave id */ - do_slave_init(ibdev, p, 0); - return; - - default: - return; - } - - ibev.device = ibdev_ptr; - ibev.element.port_num = (u8) p; - - ib_dispatch_event(&ibev); -} - -static struct mlx4_interface mlx4_ib_interface = { - .add = mlx4_ib_add, - .remove = mlx4_ib_remove, - .event = mlx4_ib_event, - .protocol = MLX4_PROT_IB_IPV6 -}; - -static int __init mlx4_ib_init(void) -{ - int err; - - wq = create_singlethread_workqueue("mlx4_ib"); - if (!wq) - return -ENOMEM; - - err = mlx4_ib_mcg_init(); - if (err) - goto clean_proc; - - init_dev_assign(); - - err = mlx4_register_interface(&mlx4_ib_interface); - if (err) - goto clean_mcg; - - return 0; - -clean_mcg: - mlx4_ib_mcg_destroy(); - -clean_proc: - destroy_workqueue(wq); - return err; -} - -static void __exit mlx4_ib_cleanup(void) -{ - mlx4_unregister_interface(&mlx4_ib_interface); - mlx4_ib_mcg_destroy(); - destroy_workqueue(wq); - - kfree(dev_num_str_bitmap); -} - -module_init_order(mlx4_ib_init, SI_ORDER_MIDDLE); -module_exit(mlx4_ib_cleanup); - -static int -mlx4ib_evhand(module_t mod, int event, void *arg) -{ - return (0); -} - -static moduledata_t mlx4ib_mod = { - .name = "mlx4ib", - .evhand = mlx4ib_evhand, -}; - -DECLARE_MODULE(mlx4ib, mlx4ib_mod, SI_SUB_LAST, SI_ORDER_ANY); -MODULE_DEPEND(mlx4ib, mlx4, 1, 1, 1); -MODULE_DEPEND(mlx4ib, ibcore, 1, 1, 1); -MODULE_DEPEND(mlx4ib, linuxkpi, 1, 1, 1); diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mcg.c b/sys/ofed/drivers/infiniband/hw/mlx4/mcg.c deleted file mode 100644 index 85199e7f33ce..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/mcg.c +++ /dev/null @@ -1,1260 +0,0 @@ -/* - * Copyright (c) 2012 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 <rdma/ib_mad.h> -#include <rdma/ib_smi.h> -#include <rdma/ib_cache.h> -#include <rdma/ib_sa.h> - -#include <linux/mlx4/cmd.h> -#include <linux/rbtree.h> -#include <linux/delay.h> - -#include "mlx4_ib.h" - -#define MAX_VFS 80 -#define MAX_PEND_REQS_PER_FUNC 4 -#define MAD_TIMEOUT_MS 2000 - -#define mcg_warn(fmt, arg...) pr_warn("MCG WARNING: " fmt, ##arg) -#define mcg_error(fmt, arg...) pr_err(fmt, ##arg) -#define mcg_warn_group(group, format, arg...) \ - pr_warn("%s-%d: %16s (port %d): WARNING: " format, __func__, __LINE__,\ - (group)->name, group->demux->port, ## arg) - -#define mcg_error_group(group, format, arg...) \ - pr_err(" %16s: " format, (group)->name, ## arg) - - -static union ib_gid mgid0; - -static struct workqueue_struct *clean_wq; - -enum mcast_state { - MCAST_NOT_MEMBER = 0, - MCAST_MEMBER, -}; - -enum mcast_group_state { - MCAST_IDLE, - MCAST_JOIN_SENT, - MCAST_LEAVE_SENT, - MCAST_RESP_READY -}; - -struct mcast_member { - enum mcast_state state; - uint8_t join_state; - int num_pend_reqs; - struct list_head pending; -}; - -struct ib_sa_mcmember_data { - union ib_gid mgid; - union ib_gid port_gid; - __be32 qkey; - __be16 mlid; - u8 mtusel_mtu; - u8 tclass; - __be16 pkey; - u8 ratesel_rate; - u8 lifetmsel_lifetm; - __be32 sl_flowlabel_hoplimit; - u8 scope_join_state; - u8 proxy_join; - u8 reserved[2]; -}; - -struct mcast_group { - struct ib_sa_mcmember_data rec; - struct rb_node node; - struct list_head mgid0_list; - struct mlx4_ib_demux_ctx *demux; - struct mcast_member func[MAX_VFS]; - struct mutex lock; - struct work_struct work; - struct list_head pending_list; - int members[3]; - enum mcast_group_state state; - enum mcast_group_state prev_state; - struct ib_sa_mad response_sa_mad; - __be64 last_req_tid; - - char name[33]; /* MGID string */ - struct device_attribute dentry; - - /* refcount is the reference count for the following: - 1. Each queued request - 2. Each invocation of the worker thread - 3. Membership of the port at the SA - */ - atomic_t refcount; - - /* delayed work to clean pending SM request */ - struct delayed_work timeout_work; - struct list_head cleanup_list; -}; - -struct mcast_req { - int func; - struct ib_sa_mad sa_mad; - struct list_head group_list; - struct list_head func_list; - struct mcast_group *group; - int clean; -}; - - -#define safe_atomic_dec(ref) \ - do {\ - if (atomic_dec_and_test(ref)) \ - mcg_warn_group(group, "did not expect to reach zero\n"); \ - } while (0) - -static const char *get_state_string(enum mcast_group_state state) -{ - switch (state) { - case MCAST_IDLE: - return "MCAST_IDLE"; - case MCAST_JOIN_SENT: - return "MCAST_JOIN_SENT"; - case MCAST_LEAVE_SENT: - return "MCAST_LEAVE_SENT"; - case MCAST_RESP_READY: - return "MCAST_RESP_READY"; - } - return "Invalid State"; -} - -static struct mcast_group *mcast_find(struct mlx4_ib_demux_ctx *ctx, - union ib_gid *mgid) -{ - struct rb_node *node = ctx->mcg_table.rb_node; - struct mcast_group *group; - int ret; - - while (node) { - group = rb_entry(node, struct mcast_group, node); - ret = memcmp(mgid->raw, group->rec.mgid.raw, sizeof *mgid); - if (!ret) - return group; - - if (ret < 0) - node = node->rb_left; - else - node = node->rb_right; - } - return NULL; -} - -static struct mcast_group *mcast_insert(struct mlx4_ib_demux_ctx *ctx, - struct mcast_group *group) -{ - struct rb_node **link = &ctx->mcg_table.rb_node; - struct rb_node *parent = NULL; - struct mcast_group *cur_group; - int ret; - - while (*link) { - parent = *link; - cur_group = rb_entry(parent, struct mcast_group, node); - - ret = memcmp(group->rec.mgid.raw, cur_group->rec.mgid.raw, - sizeof group->rec.mgid); - if (ret < 0) - link = &(*link)->rb_left; - else if (ret > 0) - link = &(*link)->rb_right; - else - return cur_group; - } - rb_link_node(&group->node, parent, link); - rb_insert_color(&group->node, &ctx->mcg_table); - return NULL; -} - -static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad) -{ - struct mlx4_ib_dev *dev = ctx->dev; - struct ib_ah_attr ah_attr; - - spin_lock(&dev->sm_lock); - if (!dev->sm_ah[ctx->port - 1]) { - /* port is not yet Active, sm_ah not ready */ - spin_unlock(&dev->sm_lock); - return -EAGAIN; - } - mlx4_ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr); - spin_unlock(&dev->sm_lock); - return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), ctx->port, - IB_QPT_GSI, 0, 1, IB_QP1_QKEY, &ah_attr, 0, mad); -} - -static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx, - struct ib_mad *mad) -{ - struct mlx4_ib_dev *dev = ctx->dev; - struct ib_mad_agent *agent = dev->send_agent[ctx->port - 1][1]; - struct ib_wc wc; - struct ib_ah_attr ah_attr; - - /* Our agent might not yet be registered when mads start to arrive */ - if (!agent) - return -EAGAIN; - - ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr); - - if (ib_find_cached_pkey(&dev->ib_dev, ctx->port, IB_DEFAULT_PKEY_FULL, &wc.pkey_index)) - return -EINVAL; - wc.sl = 0; - wc.dlid_path_bits = 0; - wc.port_num = ctx->port; - wc.slid = ah_attr.dlid; /* opensm lid */ - wc.src_qp = 1; - return mlx4_ib_send_to_slave(dev, slave, ctx->port, IB_QPT_GSI, &wc, NULL, mad); -} - -static int send_join_to_wire(struct mcast_group *group, struct ib_sa_mad *sa_mad) -{ - struct ib_sa_mad mad; - struct ib_sa_mcmember_data *sa_mad_data = (struct ib_sa_mcmember_data *)&mad.data; - int ret; - - /* we rely on a mad request as arrived from a VF */ - memcpy(&mad, sa_mad, sizeof mad); - - /* fix port GID to be the real one (slave 0) */ - sa_mad_data->port_gid.global.interface_id = group->demux->guid_cache[0]; - - /* assign our own TID */ - mad.mad_hdr.tid = mlx4_ib_get_new_demux_tid(group->demux); - group->last_req_tid = mad.mad_hdr.tid; /* keep it for later validation */ - - ret = send_mad_to_wire(group->demux, (struct ib_mad *)&mad); - /* set timeout handler */ - if (!ret) { - /* calls mlx4_ib_mcg_timeout_handler */ - queue_delayed_work(group->demux->mcg_wq, &group->timeout_work, - msecs_to_jiffies(MAD_TIMEOUT_MS)); - } - - return ret; -} - -static int send_leave_to_wire(struct mcast_group *group, u8 join_state) -{ - struct ib_sa_mad mad; - struct ib_sa_mcmember_data *sa_data = (struct ib_sa_mcmember_data *)&mad.data; - int ret; - - memset(&mad, 0, sizeof mad); - mad.mad_hdr.base_version = 1; - mad.mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; - mad.mad_hdr.class_version = 2; - mad.mad_hdr.method = IB_SA_METHOD_DELETE; - mad.mad_hdr.status = cpu_to_be16(0); - mad.mad_hdr.class_specific = cpu_to_be16(0); - mad.mad_hdr.tid = mlx4_ib_get_new_demux_tid(group->demux); - group->last_req_tid = mad.mad_hdr.tid; /* keep it for later validation */ - mad.mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); - mad.mad_hdr.attr_mod = cpu_to_be32(0); - mad.sa_hdr.sm_key = 0x0; - mad.sa_hdr.attr_offset = cpu_to_be16(7); - mad.sa_hdr.comp_mask = IB_SA_MCMEMBER_REC_MGID | - IB_SA_MCMEMBER_REC_PORT_GID | IB_SA_MCMEMBER_REC_JOIN_STATE; - - *sa_data = group->rec; - sa_data->scope_join_state = join_state; - - ret = send_mad_to_wire(group->demux, (struct ib_mad *)&mad); - if (ret) - group->state = MCAST_IDLE; - - /* set timeout handler */ - if (!ret) { - /* calls mlx4_ib_mcg_timeout_handler */ - queue_delayed_work(group->demux->mcg_wq, &group->timeout_work, - msecs_to_jiffies(MAD_TIMEOUT_MS)); - } - - return ret; -} - -static int send_reply_to_slave(int slave, struct mcast_group *group, - struct ib_sa_mad *req_sa_mad, u16 status) -{ - struct ib_sa_mad mad; - struct ib_sa_mcmember_data *sa_data = (struct ib_sa_mcmember_data *)&mad.data; - struct ib_sa_mcmember_data *req_sa_data = (struct ib_sa_mcmember_data *)&req_sa_mad->data; - int ret; - - memset(&mad, 0, sizeof mad); - mad.mad_hdr.base_version = 1; - mad.mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; - mad.mad_hdr.class_version = 2; - mad.mad_hdr.method = IB_MGMT_METHOD_GET_RESP; - mad.mad_hdr.status = cpu_to_be16(status); - mad.mad_hdr.class_specific = cpu_to_be16(0); - mad.mad_hdr.tid = req_sa_mad->mad_hdr.tid; - *(u8 *)&mad.mad_hdr.tid = 0; /* resetting tid to 0 */ - mad.mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); - mad.mad_hdr.attr_mod = cpu_to_be32(0); - mad.sa_hdr.sm_key = req_sa_mad->sa_hdr.sm_key; - mad.sa_hdr.attr_offset = cpu_to_be16(7); - mad.sa_hdr.comp_mask = 0; /* ignored on responses, see IBTA spec */ - - *sa_data = group->rec; - - /* reconstruct VF's requested join_state and port_gid */ - sa_data->scope_join_state &= 0xf0; - sa_data->scope_join_state |= (group->func[slave].join_state & 0x0f); - memcpy(&sa_data->port_gid, &req_sa_data->port_gid, sizeof req_sa_data->port_gid); - - ret = send_mad_to_slave(slave, group->demux, (struct ib_mad *)&mad); - return ret; -} - -static int check_selector(ib_sa_comp_mask comp_mask, - ib_sa_comp_mask selector_mask, - ib_sa_comp_mask value_mask, - u8 src_value, u8 dst_value) -{ - int err; - u8 selector = dst_value >> 6; - dst_value &= 0x3f; - src_value &= 0x3f; - - if (!(comp_mask & selector_mask) || !(comp_mask & value_mask)) - return 0; - - switch (selector) { - case IB_SA_GT: - err = (src_value <= dst_value); - break; - case IB_SA_LT: - err = (src_value >= dst_value); - break; - case IB_SA_EQ: - err = (src_value != dst_value); - break; - default: - err = 0; - break; - } - - return err; -} - -static u16 cmp_rec(struct ib_sa_mcmember_data *src, - struct ib_sa_mcmember_data *dst, ib_sa_comp_mask comp_mask) -{ - /* src is group record, dst is request record */ - /* MGID must already match */ - /* Port_GID we always replace to our Port_GID, so it is a match */ - -#define MAD_STATUS_REQ_INVALID 0x0200 - if (comp_mask & IB_SA_MCMEMBER_REC_QKEY && src->qkey != dst->qkey) - return MAD_STATUS_REQ_INVALID; - if (comp_mask & IB_SA_MCMEMBER_REC_MLID && src->mlid != dst->mlid) - return MAD_STATUS_REQ_INVALID; - if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_MTU_SELECTOR, - IB_SA_MCMEMBER_REC_MTU, - src->mtusel_mtu, dst->mtusel_mtu)) - return MAD_STATUS_REQ_INVALID; - if (comp_mask & IB_SA_MCMEMBER_REC_TRAFFIC_CLASS && - src->tclass != dst->tclass) - return MAD_STATUS_REQ_INVALID; - if (comp_mask & IB_SA_MCMEMBER_REC_PKEY && src->pkey != dst->pkey) - return MAD_STATUS_REQ_INVALID; - if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_RATE_SELECTOR, - IB_SA_MCMEMBER_REC_RATE, - src->ratesel_rate, dst->ratesel_rate)) - return MAD_STATUS_REQ_INVALID; - if (check_selector(comp_mask, - IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR, - IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME, - src->lifetmsel_lifetm, dst->lifetmsel_lifetm)) - return MAD_STATUS_REQ_INVALID; - if (comp_mask & IB_SA_MCMEMBER_REC_SL && - (be32_to_cpu(src->sl_flowlabel_hoplimit) & 0xf0000000) != - (be32_to_cpu(dst->sl_flowlabel_hoplimit) & 0xf0000000)) - return MAD_STATUS_REQ_INVALID; - if (comp_mask & IB_SA_MCMEMBER_REC_FLOW_LABEL && - (be32_to_cpu(src->sl_flowlabel_hoplimit) & 0x0fffff00) != - (be32_to_cpu(dst->sl_flowlabel_hoplimit) & 0x0fffff00)) - return MAD_STATUS_REQ_INVALID; - if (comp_mask & IB_SA_MCMEMBER_REC_HOP_LIMIT && - (be32_to_cpu(src->sl_flowlabel_hoplimit) & 0x000000ff) != - (be32_to_cpu(dst->sl_flowlabel_hoplimit) & 0x000000ff)) - return MAD_STATUS_REQ_INVALID; - if (comp_mask & IB_SA_MCMEMBER_REC_SCOPE && - (src->scope_join_state & 0xf0) != - (dst->scope_join_state & 0xf0)) - return MAD_STATUS_REQ_INVALID; - - /* join_state checked separately, proxy_join ignored */ - - return 0; -} - -/* release group, return 1 if this was last release and group is destroyed - * timout work is canceled sync */ -static int release_group(struct mcast_group *group, int from_timeout_handler) -{ - struct mlx4_ib_demux_ctx *ctx = group->demux; - int nzgroup; - - mutex_lock(&ctx->mcg_table_lock); - mutex_lock(&group->lock); - if (atomic_dec_and_test(&group->refcount)) { - if (!from_timeout_handler) { - if (group->state != MCAST_IDLE && - !cancel_delayed_work(&group->timeout_work)) { - atomic_inc(&group->refcount); - mutex_unlock(&group->lock); - mutex_unlock(&ctx->mcg_table_lock); - return 0; - } - } - - nzgroup = memcmp(&group->rec.mgid, &mgid0, sizeof mgid0); - if (nzgroup) - del_sysfs_port_mcg_attr(ctx->dev, ctx->port, &group->dentry.attr); - if (!list_empty(&group->pending_list)) - mcg_warn_group(group, "releasing a group with non empty pending list\n"); - if (nzgroup) - rb_erase(&group->node, &ctx->mcg_table); - list_del_init(&group->mgid0_list); - mutex_unlock(&group->lock); - mutex_unlock(&ctx->mcg_table_lock); - kfree(group); - return 1; - } else { - mutex_unlock(&group->lock); - mutex_unlock(&ctx->mcg_table_lock); - } - return 0; -} - -static void adjust_membership(struct mcast_group *group, u8 join_state, int inc) -{ - int i; - - for (i = 0; i < 3; i++, join_state >>= 1) - if (join_state & 0x1) - group->members[i] += inc; -} - -static u8 get_leave_state(struct mcast_group *group) -{ - u8 leave_state = 0; - int i; - - for (i = 0; i < 3; i++) - if (!group->members[i]) - leave_state |= (1 << i); - - return leave_state & (group->rec.scope_join_state & 7); -} - -static int join_group(struct mcast_group *group, int slave, u8 join_mask) -{ - int ret = 0; - u8 join_state; - - /* remove bits that slave is already member of, and adjust */ - join_state = join_mask & (~group->func[slave].join_state); - adjust_membership(group, join_state, 1); - group->func[slave].join_state |= join_state; - if (group->func[slave].state != MCAST_MEMBER && join_state) { - group->func[slave].state = MCAST_MEMBER; - ret = 1; - } - return ret; -} - -static int leave_group(struct mcast_group *group, int slave, u8 leave_state) -{ - int ret = 0; - - adjust_membership(group, leave_state, -1); - group->func[slave].join_state &= ~leave_state; - if (!group->func[slave].join_state) { - group->func[slave].state = MCAST_NOT_MEMBER; - ret = 1; - } - return ret; -} - -static int check_leave(struct mcast_group *group, int slave, u8 leave_mask) -{ - if (group->func[slave].state != MCAST_MEMBER) - return MAD_STATUS_REQ_INVALID; - - /* make sure we're not deleting unset bits */ - if (~group->func[slave].join_state & leave_mask) - return MAD_STATUS_REQ_INVALID; - - if (!leave_mask) - return MAD_STATUS_REQ_INVALID; - - return 0; -} - -static void mlx4_ib_mcg_timeout_handler(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mcast_group *group; - struct mcast_req *req = NULL; - - group = container_of(delay, typeof(*group), timeout_work); - - mutex_lock(&group->lock); - if (group->state == MCAST_JOIN_SENT) { - if (!list_empty(&group->pending_list)) { - req = list_first_entry(&group->pending_list, struct mcast_req, group_list); - list_del(&req->group_list); - list_del(&req->func_list); - --group->func[req->func].num_pend_reqs; - mutex_unlock(&group->lock); - kfree(req); - if (memcmp(&group->rec.mgid, &mgid0, sizeof mgid0)) { - if (release_group(group, 1)) - return; - } else { - kfree(group); - return; - } - mutex_lock(&group->lock); - } else - mcg_warn_group(group, "DRIVER BUG\n"); - } else if (group->state == MCAST_LEAVE_SENT) { - if (group->rec.scope_join_state & 7) - group->rec.scope_join_state &= 0xf8; - group->state = MCAST_IDLE; - mutex_unlock(&group->lock); - if (release_group(group, 1)) - return; - mutex_lock(&group->lock); - } else - mcg_warn_group(group, "invalid state %s\n", get_state_string(group->state)); - group->state = MCAST_IDLE; - atomic_inc(&group->refcount); - if (!queue_work(group->demux->mcg_wq, &group->work)) - safe_atomic_dec(&group->refcount); - - mutex_unlock(&group->lock); -} - -static int handle_leave_req(struct mcast_group *group, u8 leave_mask, - struct mcast_req *req) -{ - u16 status; - - if (req->clean) - leave_mask = group->func[req->func].join_state; - - status = check_leave(group, req->func, leave_mask); - if (!status) - leave_group(group, req->func, leave_mask); - - if (!req->clean) - send_reply_to_slave(req->func, group, &req->sa_mad, status); - --group->func[req->func].num_pend_reqs; - list_del(&req->group_list); - list_del(&req->func_list); - kfree(req); - return 1; -} - -static int handle_join_req(struct mcast_group *group, u8 join_mask, - struct mcast_req *req) -{ - u8 group_join_state = group->rec.scope_join_state & 7; - int ref = 0; - u16 status; - struct ib_sa_mcmember_data *sa_data = (struct ib_sa_mcmember_data *)req->sa_mad.data; - - if (join_mask == (group_join_state & join_mask)) { - /* port's membership need not change */ - status = cmp_rec(&group->rec, sa_data, req->sa_mad.sa_hdr.comp_mask); - if (!status) - join_group(group, req->func, join_mask); - - --group->func[req->func].num_pend_reqs; - send_reply_to_slave(req->func, group, &req->sa_mad, status); - list_del(&req->group_list); - list_del(&req->func_list); - kfree(req); - ++ref; - } else { - /* port's membership needs to be updated */ - group->prev_state = group->state; - if (send_join_to_wire(group, &req->sa_mad)) { - --group->func[req->func].num_pend_reqs; - list_del(&req->group_list); - list_del(&req->func_list); - kfree(req); - ref = 1; - group->state = group->prev_state; - } else - group->state = MCAST_JOIN_SENT; - } - - return ref; -} - -static void mlx4_ib_mcg_work_handler(struct work_struct *work) -{ - struct mcast_group *group; - struct mcast_req *req = NULL; - struct ib_sa_mcmember_data *sa_data; - u8 req_join_state; - int rc = 1; /* release_count - this is for the scheduled work */ - u16 status; - u8 method; - - group = container_of(work, typeof(*group), work); - - mutex_lock(&group->lock); - - /* First, let's see if a response from SM is waiting regarding this group. - * If so, we need to update the group's REC. If this is a bad response, we - * may need to send a bad response to a VF waiting for it. If VF is waiting - * and this is a good response, the VF will be answered later in this func. */ - if (group->state == MCAST_RESP_READY) { - /* cancels mlx4_ib_mcg_timeout_handler */ - cancel_delayed_work(&group->timeout_work); - status = be16_to_cpu(group->response_sa_mad.mad_hdr.status); - method = group->response_sa_mad.mad_hdr.method; - if (group->last_req_tid != group->response_sa_mad.mad_hdr.tid) { - mcg_warn_group(group, "Got MAD response to existing MGID but wrong TID, dropping. Resp TID=%llx, group TID=%llx\n", - (long long)be64_to_cpu( - group->response_sa_mad.mad_hdr.tid), - (long long)be64_to_cpu(group->last_req_tid)); - group->state = group->prev_state; - goto process_requests; - } - if (status) { - if (!list_empty(&group->pending_list)) - req = list_first_entry(&group->pending_list, - struct mcast_req, group_list); - if (method == IB_MGMT_METHOD_GET_RESP) { - if (req) { - send_reply_to_slave(req->func, group, &req->sa_mad, status); - --group->func[req->func].num_pend_reqs; - list_del(&req->group_list); - list_del(&req->func_list); - kfree(req); - ++rc; - } else - mcg_warn_group(group, "no request for failed join\n"); - } else if (method == IB_SA_METHOD_DELETE_RESP && group->demux->flushing) - ++rc; - } else { - u8 resp_join_state; - u8 cur_join_state; - - resp_join_state = ((struct ib_sa_mcmember_data *) - group->response_sa_mad.data)->scope_join_state & 7; - cur_join_state = group->rec.scope_join_state & 7; - - if (method == IB_MGMT_METHOD_GET_RESP) { - /* successful join */ - if (!cur_join_state && resp_join_state) - --rc; - } else if (!resp_join_state) - ++rc; - memcpy(&group->rec, group->response_sa_mad.data, sizeof group->rec); - } - group->state = MCAST_IDLE; - } - -process_requests: - /* We should now go over pending join/leave requests, as long as we are idle. */ - while (!list_empty(&group->pending_list) && group->state == MCAST_IDLE) { - req = list_first_entry(&group->pending_list, struct mcast_req, - group_list); - sa_data = (struct ib_sa_mcmember_data *)req->sa_mad.data; - req_join_state = sa_data->scope_join_state & 0x7; - - /* For a leave request, we will immediately answer the VF, and - * update our internal counters. The actual leave will be sent - * to SM later, if at all needed. We dequeue the request now. */ - if (req->sa_mad.mad_hdr.method == IB_SA_METHOD_DELETE) - rc += handle_leave_req(group, req_join_state, req); - else - rc += handle_join_req(group, req_join_state, req); - } - - /* Handle leaves */ - if (group->state == MCAST_IDLE) { - req_join_state = get_leave_state(group); - if (req_join_state) { - group->rec.scope_join_state &= ~req_join_state; - group->prev_state = group->state; - if (send_leave_to_wire(group, req_join_state)) { - group->state = group->prev_state; - ++rc; - } else - group->state = MCAST_LEAVE_SENT; - } - } - - if (!list_empty(&group->pending_list) && group->state == MCAST_IDLE) - goto process_requests; - mutex_unlock(&group->lock); - - while (rc--) - release_group(group, 0); -} - -static struct mcast_group *search_relocate_mgid0_group(struct mlx4_ib_demux_ctx *ctx, - __be64 tid, - union ib_gid *new_mgid) -{ - struct mcast_group *group = NULL, *cur_group; - struct mcast_req *req; - struct list_head *pos; - struct list_head *n; - - mutex_lock(&ctx->mcg_table_lock); - list_for_each_safe(pos, n, &ctx->mcg_mgid0_list) { - group = list_entry(pos, struct mcast_group, mgid0_list); - mutex_lock(&group->lock); - if (group->last_req_tid == tid) { - if (memcmp(new_mgid, &mgid0, sizeof mgid0)) { - group->rec.mgid = *new_mgid; - sprintf(group->name, "%016llx%016llx", - (long long)be64_to_cpu(group->rec.mgid.global.subnet_prefix), - (long long)be64_to_cpu(group->rec.mgid.global.interface_id)); - list_del_init(&group->mgid0_list); - cur_group = mcast_insert(ctx, group); - if (cur_group) { - /* A race between our code and SM. Silently cleaning the new one */ - req = list_first_entry(&group->pending_list, - struct mcast_req, group_list); - --group->func[req->func].num_pend_reqs; - list_del(&req->group_list); - list_del(&req->func_list); - kfree(req); - mutex_unlock(&group->lock); - mutex_unlock(&ctx->mcg_table_lock); - release_group(group, 0); - return NULL; - } - - atomic_inc(&group->refcount); - add_sysfs_port_mcg_attr(ctx->dev, ctx->port, &group->dentry.attr); - mutex_unlock(&group->lock); - mutex_unlock(&ctx->mcg_table_lock); - return group; - } else { - struct mcast_req *tmp1, *tmp2; - - list_del(&group->mgid0_list); - if (!list_empty(&group->pending_list) && group->state != MCAST_IDLE) - cancel_delayed_work_sync(&group->timeout_work); - - list_for_each_entry_safe(tmp1, tmp2, &group->pending_list, group_list) { - list_del(&tmp1->group_list); - kfree(tmp1); - } - mutex_unlock(&group->lock); - mutex_unlock(&ctx->mcg_table_lock); - kfree(group); - return NULL; - } - } - mutex_unlock(&group->lock); - } - mutex_unlock(&ctx->mcg_table_lock); - - return NULL; -} - -static ssize_t sysfs_show_group(struct device *dev, - struct device_attribute *attr, char *buf); - -static struct mcast_group *acquire_group(struct mlx4_ib_demux_ctx *ctx, - union ib_gid *mgid, int create, - gfp_t gfp_mask) -{ - struct mcast_group *group, *cur_group; - int is_mgid0; - int i; - - is_mgid0 = !memcmp(&mgid0, mgid, sizeof mgid0); - if (!is_mgid0) { - group = mcast_find(ctx, mgid); - if (group) - goto found; - } - - if (!create) - return ERR_PTR(-ENOENT); - - group = kzalloc(sizeof *group, gfp_mask); - if (!group) - return ERR_PTR(-ENOMEM); - - group->demux = ctx; - group->rec.mgid = *mgid; - INIT_LIST_HEAD(&group->pending_list); - INIT_LIST_HEAD(&group->mgid0_list); - for (i = 0; i < MAX_VFS; ++i) - INIT_LIST_HEAD(&group->func[i].pending); - INIT_WORK(&group->work, mlx4_ib_mcg_work_handler); - INIT_DELAYED_WORK(&group->timeout_work, mlx4_ib_mcg_timeout_handler); - mutex_init(&group->lock); - sprintf(group->name, "%016llx%016llx", - (long long)be64_to_cpu( - group->rec.mgid.global.subnet_prefix), - (long long)be64_to_cpu( - group->rec.mgid.global.interface_id)); - sysfs_attr_init(&group->dentry.attr); - group->dentry.show = sysfs_show_group; - group->dentry.store = NULL; - group->dentry.attr.name = group->name; - group->dentry.attr.mode = 0400; - group->state = MCAST_IDLE; - - if (is_mgid0) { - list_add(&group->mgid0_list, &ctx->mcg_mgid0_list); - goto found; - } - - cur_group = mcast_insert(ctx, group); - if (cur_group) { - mcg_warn("group just showed up %s - confused\n", cur_group->name); - kfree(group); - return ERR_PTR(-EINVAL); - } - - add_sysfs_port_mcg_attr(ctx->dev, ctx->port, &group->dentry.attr); - -found: - atomic_inc(&group->refcount); - return group; -} - -static void queue_req(struct mcast_req *req) -{ - struct mcast_group *group = req->group; - - atomic_inc(&group->refcount); /* for the request */ - atomic_inc(&group->refcount); /* for scheduling the work */ - list_add_tail(&req->group_list, &group->pending_list); - list_add_tail(&req->func_list, &group->func[req->func].pending); - /* calls mlx4_ib_mcg_work_handler */ - if (!queue_work(group->demux->mcg_wq, &group->work)) - safe_atomic_dec(&group->refcount); -} - -int mlx4_ib_mcg_demux_handler(struct ib_device *ibdev, int port, int slave, - struct ib_sa_mad *mad) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct ib_sa_mcmember_data *rec = (struct ib_sa_mcmember_data *)mad->data; - struct mlx4_ib_demux_ctx *ctx = &dev->sriov.demux[port - 1]; - struct mcast_group *group; - - switch (mad->mad_hdr.method) { - case IB_MGMT_METHOD_GET_RESP: - case IB_SA_METHOD_DELETE_RESP: - mutex_lock(&ctx->mcg_table_lock); - group = acquire_group(ctx, &rec->mgid, 0, GFP_KERNEL); - mutex_unlock(&ctx->mcg_table_lock); - if (IS_ERR(group)) { - if (mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP) { - __be64 tid = mad->mad_hdr.tid; - *(u8 *)(&tid) = (u8)slave; /* in group we kept the modified TID */ - group = search_relocate_mgid0_group(ctx, tid, &rec->mgid); - } else - group = NULL; - } - - if (!group) - return 1; - - mutex_lock(&group->lock); - group->response_sa_mad = *mad; - group->prev_state = group->state; - group->state = MCAST_RESP_READY; - /* calls mlx4_ib_mcg_work_handler */ - atomic_inc(&group->refcount); - if (!queue_work(ctx->mcg_wq, &group->work)) - safe_atomic_dec(&group->refcount); - mutex_unlock(&group->lock); - release_group(group, 0); - return 1; /* consumed */ - case IB_MGMT_METHOD_SET: - case IB_SA_METHOD_GET_TABLE: - case IB_SA_METHOD_GET_TABLE_RESP: - case IB_SA_METHOD_DELETE: - return 0; /* not consumed, pass-through to guest over tunnel */ - default: - mcg_warn("In demux, port %d: unexpected MCMember method: 0x%x, dropping\n", - port, mad->mad_hdr.method); - return 1; /* consumed */ - } -} - -int mlx4_ib_mcg_multiplex_handler(struct ib_device *ibdev, int port, - int slave, struct ib_sa_mad *sa_mad) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct ib_sa_mcmember_data *rec = (struct ib_sa_mcmember_data *)sa_mad->data; - struct mlx4_ib_demux_ctx *ctx = &dev->sriov.demux[port - 1]; - struct mcast_group *group; - struct mcast_req *req; - int may_create = 0; - - if (ctx->flushing) - return -EAGAIN; - - switch (sa_mad->mad_hdr.method) { - case IB_MGMT_METHOD_SET: - may_create = 1; - case IB_SA_METHOD_DELETE: - req = kzalloc(sizeof *req, GFP_KERNEL); - if (!req) - return -ENOMEM; - - req->func = slave; - req->sa_mad = *sa_mad; - - mutex_lock(&ctx->mcg_table_lock); - group = acquire_group(ctx, &rec->mgid, may_create, GFP_KERNEL); - mutex_unlock(&ctx->mcg_table_lock); - if (IS_ERR(group)) { - kfree(req); - return PTR_ERR(group); - } - mutex_lock(&group->lock); - if (group->func[slave].num_pend_reqs > MAX_PEND_REQS_PER_FUNC) { - mutex_unlock(&group->lock); - mcg_warn_group(group, "Port %d, Func %d has too many pending requests (%d), dropping\n", - port, slave, MAX_PEND_REQS_PER_FUNC); - release_group(group, 0); - kfree(req); - return -ENOMEM; - } - ++group->func[slave].num_pend_reqs; - req->group = group; - queue_req(req); - mutex_unlock(&group->lock); - release_group(group, 0); - return 1; /* consumed */ - case IB_SA_METHOD_GET_TABLE: - case IB_MGMT_METHOD_GET_RESP: - case IB_SA_METHOD_GET_TABLE_RESP: - case IB_SA_METHOD_DELETE_RESP: - return 0; /* not consumed, pass-through */ - default: - mcg_warn("In multiplex, port %d, func %d: unexpected MCMember method: 0x%x, dropping\n", - port, slave, sa_mad->mad_hdr.method); - return 1; /* consumed */ - } -} - -static ssize_t sysfs_show_group(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mcast_group *group = - container_of(attr, struct mcast_group, dentry); - struct mcast_req *req = NULL; - char pending_str[40]; - char state_str[40]; - ssize_t len = 0; - int f; - - if (group->state == MCAST_IDLE) - sprintf(state_str, "%s", get_state_string(group->state)); - else - sprintf(state_str, "%s(TID=0x%llx)", - get_state_string(group->state), - (long long)be64_to_cpu(group->last_req_tid)); - if (list_empty(&group->pending_list)) { - sprintf(pending_str, "No"); - } else { - req = list_first_entry(&group->pending_list, struct mcast_req, group_list); - sprintf(pending_str, "Yes(TID=0x%llx)", - (long long)be64_to_cpu( - req->sa_mad.mad_hdr.tid)); - } - len += sprintf(buf + len, "%1d [%02d,%02d,%02d] %4d %4s %5s ", - group->rec.scope_join_state & 0xf, - group->members[2], group->members[1], group->members[0], - atomic_read(&group->refcount), - pending_str, - state_str); - for (f = 0; f < MAX_VFS; ++f) - if (group->func[f].state == MCAST_MEMBER) - len += sprintf(buf + len, "%d[%1x] ", - f, group->func[f].join_state); - - len += sprintf(buf + len, "\t\t(%4hx %4x %2x %2x %2x %2x %2x " - "%4x %4x %2x %2x)\n", - be16_to_cpu(group->rec.pkey), - be32_to_cpu(group->rec.qkey), - (group->rec.mtusel_mtu & 0xc0) >> 6, - group->rec.mtusel_mtu & 0x3f, - group->rec.tclass, - (group->rec.ratesel_rate & 0xc0) >> 6, - group->rec.ratesel_rate & 0x3f, - (be32_to_cpu(group->rec.sl_flowlabel_hoplimit) & 0xf0000000) >> 28, - (be32_to_cpu(group->rec.sl_flowlabel_hoplimit) & 0x0fffff00) >> 8, - be32_to_cpu(group->rec.sl_flowlabel_hoplimit) & 0x000000ff, - group->rec.proxy_join); - - return len; -} - -int mlx4_ib_mcg_port_init(struct mlx4_ib_demux_ctx *ctx) -{ - char name[20]; - - atomic_set(&ctx->tid, 0); - sprintf(name, "mlx4_ib_mcg%d", ctx->port); - ctx->mcg_wq = create_singlethread_workqueue(name); - if (!ctx->mcg_wq) - return -ENOMEM; - - mutex_init(&ctx->mcg_table_lock); - ctx->mcg_table = RB_ROOT; - INIT_LIST_HEAD(&ctx->mcg_mgid0_list); - ctx->flushing = 0; - - return 0; -} - -static void force_clean_group(struct mcast_group *group) -{ - struct mcast_req *req, *tmp - ; - list_for_each_entry_safe(req, tmp, &group->pending_list, group_list) { - list_del(&req->group_list); - kfree(req); - } - del_sysfs_port_mcg_attr(group->demux->dev, group->demux->port, &group->dentry.attr); - rb_erase(&group->node, &group->demux->mcg_table); - kfree(group); -} - -static void _mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy_wq) -{ - int i; - struct rb_node *p; - struct mcast_group *group; - unsigned long end; - int count; - - for (i = 0; i < MAX_VFS; ++i) - clean_vf_mcast(ctx, i); - - end = jiffies + msecs_to_jiffies(MAD_TIMEOUT_MS + 3000); - do { - count = 0; - mutex_lock(&ctx->mcg_table_lock); - for (p = rb_first(&ctx->mcg_table); p; p = rb_next(p)) - ++count; - mutex_unlock(&ctx->mcg_table_lock); - if (!count) - break; - - msleep(1); - } while (time_after(end, jiffies)); - - flush_workqueue(ctx->mcg_wq); - if (destroy_wq) - destroy_workqueue(ctx->mcg_wq); - - mutex_lock(&ctx->mcg_table_lock); - while ((p = rb_first(&ctx->mcg_table)) != NULL) { - group = rb_entry(p, struct mcast_group, node); - if (atomic_read(&group->refcount)) - mcg_warn_group(group, "group refcount %d!!! (pointer %p)\n", atomic_read(&group->refcount), group); - - force_clean_group(group); - } - mutex_unlock(&ctx->mcg_table_lock); -} - -struct clean_work { - struct work_struct work; - struct mlx4_ib_demux_ctx *ctx; - int destroy_wq; -}; - -static void mcg_clean_task(struct work_struct *work) -{ - struct clean_work *cw = container_of(work, struct clean_work, work); - - _mlx4_ib_mcg_port_cleanup(cw->ctx, cw->destroy_wq); - cw->ctx->flushing = 0; - kfree(cw); -} - -void mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy_wq) -{ - struct clean_work *work; - - if (ctx->flushing) - return; - - ctx->flushing = 1; - - if (destroy_wq) { - _mlx4_ib_mcg_port_cleanup(ctx, destroy_wq); - ctx->flushing = 0; - return; - } - - work = kmalloc(sizeof *work, GFP_KERNEL); - if (!work) { - ctx->flushing = 0; - mcg_warn("failed allocating work for cleanup\n"); - return; - } - - work->ctx = ctx; - work->destroy_wq = destroy_wq; - INIT_WORK(&work->work, mcg_clean_task); - queue_work(clean_wq, &work->work); -} - -static void build_leave_mad(struct mcast_req *req) -{ - struct ib_sa_mad *mad = &req->sa_mad; - - mad->mad_hdr.method = IB_SA_METHOD_DELETE; -} - - -static void clear_pending_reqs(struct mcast_group *group, int vf) -{ - struct mcast_req *req, *tmp, *group_first = NULL; - int clear; - int pend = 0; - - if (!list_empty(&group->pending_list)) - group_first = list_first_entry(&group->pending_list, struct mcast_req, group_list); - - list_for_each_entry_safe(req, tmp, &group->func[vf].pending, func_list) { - clear = 1; - if (group_first == req && - (group->state == MCAST_JOIN_SENT || - group->state == MCAST_LEAVE_SENT)) { - clear = cancel_delayed_work(&group->timeout_work); - pend = !clear; - group->state = MCAST_IDLE; - } - if (clear) { - --group->func[vf].num_pend_reqs; - list_del(&req->group_list); - list_del(&req->func_list); - kfree(req); - atomic_dec(&group->refcount); - } - } - - if (!pend && (!list_empty(&group->func[vf].pending) || group->func[vf].num_pend_reqs)) { - mcg_warn_group(group, "DRIVER BUG: list_empty %d, num_pend_reqs %d\n", - list_empty(&group->func[vf].pending), group->func[vf].num_pend_reqs); - } -} - -static int push_deleteing_req(struct mcast_group *group, int slave) -{ - struct mcast_req *req; - struct mcast_req *pend_req; - - if (!group->func[slave].join_state) - return 0; - - req = kzalloc(sizeof *req, GFP_KERNEL); - if (!req) { - mcg_warn_group(group, "failed allocation - may leave stall groups\n"); - return -ENOMEM; - } - - if (!list_empty(&group->func[slave].pending)) { - pend_req = list_entry(group->func[slave].pending.prev, struct mcast_req, group_list); - if (pend_req->clean) { - kfree(req); - return 0; - } - } - - req->clean = 1; - req->func = slave; - req->group = group; - ++group->func[slave].num_pend_reqs; - build_leave_mad(req); - queue_req(req); - return 0; -} - -void clean_vf_mcast(struct mlx4_ib_demux_ctx *ctx, int slave) -{ - struct mcast_group *group; - struct rb_node *p; - - mutex_lock(&ctx->mcg_table_lock); - for (p = rb_first(&ctx->mcg_table); p; p = rb_next(p)) { - group = rb_entry(p, struct mcast_group, node); - mutex_lock(&group->lock); - if (atomic_read(&group->refcount)) { - /* clear pending requests of this VF */ - clear_pending_reqs(group, slave); - push_deleteing_req(group, slave); - } - mutex_unlock(&group->lock); - } - mutex_unlock(&ctx->mcg_table_lock); -} - - -int mlx4_ib_mcg_init(void) -{ - clean_wq = create_singlethread_workqueue("mlx4_ib_mcg"); - if (!clean_wq) - return -ENOMEM; - - return 0; -} - -void mlx4_ib_mcg_destroy(void) -{ - destroy_workqueue(clean_wq); -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_exp.c b/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_exp.c deleted file mode 100644 index b6a6962addf6..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_exp.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 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 "mlx4_ib.h" -#include "mlx4_exp.h" -#include <linux/mlx4/qp.h> - -int mlx4_ib_exp_query_device(struct ib_device *ibdev, - struct ib_exp_device_attr *props) -{ - struct ib_device_attr *base = &props->base; - struct mlx4_ib_dev *dev = to_mdev(ibdev); - int ret = mlx4_ib_query_device(ibdev, &props->base); - - props->exp_comp_mask = IB_EXP_DEVICE_ATTR_INLINE_RECV_SZ; - props->inline_recv_sz = dev->dev->caps.max_rq_sg * sizeof(struct mlx4_wqe_data_seg); - props->device_cap_flags2 = 0; - - /* move RSS device cap from device_cap to device_cap_flags2 */ - if (base->device_cap_flags & IB_DEVICE_QPG) { - props->device_cap_flags2 |= IB_EXP_DEVICE_QPG; - if (base->device_cap_flags & IB_DEVICE_UD_RSS) - props->device_cap_flags2 |= IB_EXP_DEVICE_UD_RSS; - } - base->device_cap_flags &= ~(IB_DEVICE_QPG | - IB_DEVICE_UD_RSS | - IB_DEVICE_UD_TSS); - - if (base->max_rss_tbl_sz > 0) { - props->max_rss_tbl_sz = base->max_rss_tbl_sz; - props->exp_comp_mask |= IB_EXP_DEVICE_ATTR_RSS_TBL_SZ; - } else { - props->max_rss_tbl_sz = 0; - props->exp_comp_mask &= ~IB_EXP_DEVICE_ATTR_RSS_TBL_SZ; - } - - if (props->device_cap_flags2) - props->exp_comp_mask |= IB_EXP_DEVICE_ATTR_CAP_FLAGS2; - - return ret; -} - -/* - * Experimental functions - */ -struct ib_qp *mlx4_ib_exp_create_qp(struct ib_pd *pd, - struct ib_exp_qp_init_attr *init_attr, - struct ib_udata *udata) -{ - int rwqe_size; - struct ib_qp *qp; - struct mlx4_ib_qp *mqp; - int use_inlr; - struct mlx4_ib_dev *dev; - - if (init_attr->max_inl_recv && !udata) - return ERR_PTR(-EINVAL); - - use_inlr = mlx4_ib_qp_has_rq((struct ib_qp_init_attr *)init_attr) && - init_attr->max_inl_recv && pd; - if (use_inlr) { - rwqe_size = roundup_pow_of_two(max(1U, init_attr->cap.max_recv_sge)) * - sizeof(struct mlx4_wqe_data_seg); - if (rwqe_size < init_attr->max_inl_recv) { - dev = to_mdev(pd->device); - init_attr->max_inl_recv = min(init_attr->max_inl_recv, - (u32)(dev->dev->caps.max_rq_sg * - sizeof(struct mlx4_wqe_data_seg))); - init_attr->cap.max_recv_sge = roundup_pow_of_two(init_attr->max_inl_recv) / - sizeof(struct mlx4_wqe_data_seg); - } - } else { - init_attr->max_inl_recv = 0; - } - qp = mlx4_ib_create_qp(pd, (struct ib_qp_init_attr *)init_attr, udata); - if (IS_ERR(qp)) - return qp; - - if (use_inlr) { - mqp = to_mqp(qp); - mqp->max_inlr_data = 1 << mqp->rq.wqe_shift; - init_attr->max_inl_recv = mqp->max_inlr_data; - } - - return qp; -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_exp.h b/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_exp.h deleted file mode 100644 index 58675a4add73..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_exp.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. - * Copyright (c) 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. - */ - -#ifndef MLX4_EXP_H -#define MLX4_EXP_H - -#include <rdma/ib_verbs_exp.h> -#include "mlx4_ib.h" - -struct ib_qp *mlx4_ib_exp_create_qp(struct ib_pd *pd, - struct ib_exp_qp_init_attr *init_attr, - struct ib_udata *udata); -int mlx4_ib_exp_query_device(struct ib_device *ibdev, - struct ib_exp_device_attr *props); - -#endif /* MLX4_EXP_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_ib.h b/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_ib.h deleted file mode 100644 index d825f5da03a0..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ /dev/null @@ -1,865 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. - * Copyright (c) 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. - */ - -#ifndef MLX4_IB_H -#define MLX4_IB_H - -#include <linux/compiler.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/idr.h> -#include <linux/rbtree.h> -#include <linux/notifier.h> - -#include <rdma/ib_verbs.h> -#include <rdma/ib_umem.h> -#include <rdma/ib_mad.h> -#include <rdma/ib_sa.h> - -#include <linux/mlx4/device.h> -#include <linux/mlx4/doorbell.h> - -#define MLX4_IB_DRV_NAME "mlx4_ib" - -#ifdef pr_fmt -#undef pr_fmt -#endif -#define pr_fmt(fmt) "<" MLX4_IB_DRV_NAME "> %s: " fmt, __func__ - -#define mlx4_ib_warn(ibdev, format, arg...) \ - dev_warn((ibdev)->dma_device, MLX4_IB_DRV_NAME ": " format, ## arg) - -#define mlx4_ib_info(ibdev, format, arg...) \ - dev_info((ibdev)->dma_device, MLX4_IB_DRV_NAME ": " format, ## arg) - -enum { - MLX4_IB_SQ_MIN_WQE_SHIFT = 6, - MLX4_IB_MAX_HEADROOM = 2048 -}; - -#define MLX4_IB_SQ_HEADROOM(shift) ((MLX4_IB_MAX_HEADROOM >> (shift)) + 1) -#define MLX4_IB_SQ_MAX_SPARE (MLX4_IB_SQ_HEADROOM(MLX4_IB_SQ_MIN_WQE_SHIFT)) - -/*module param to indicate if SM assigns the alias_GUID*/ -extern int mlx4_ib_sm_guid_assign; -extern struct proc_dir_entry *mlx4_mrs_dir_entry; - -#define MLX4_IB_UC_STEER_QPN_ALIGN 1 -#define MLX4_IB_UC_MAX_NUM_QPS (256 * 1024) - - -#define MLX4_IB_MMAP_CMD_MASK 0xFF -#define MLX4_IB_MMAP_CMD_BITS 8 - -struct mlx4_ib_ucontext { - struct ib_ucontext ibucontext; - struct mlx4_uar uar; - struct list_head db_page_list; - struct mutex db_page_mutex; -}; - -struct mlx4_ib_pd { - struct ib_pd ibpd; - u32 pdn; -}; - -struct mlx4_ib_xrcd { - struct ib_xrcd ibxrcd; - u32 xrcdn; - struct ib_pd *pd; - struct ib_cq *cq; -}; - -struct mlx4_ib_cq_buf { - struct mlx4_buf buf; - struct mlx4_mtt mtt; - int entry_size; -}; - -struct mlx4_ib_cq_resize { - struct mlx4_ib_cq_buf buf; - int cqe; -}; - -struct mlx4_shared_mr_info { - int mr_id; - struct ib_umem *umem; -}; - -struct mlx4_ib_cq { - struct ib_cq ibcq; - struct mlx4_cq mcq; - struct mlx4_ib_cq_buf buf; - struct mlx4_ib_cq_resize *resize_buf; - struct mlx4_db db; - spinlock_t lock; - struct mutex resize_mutex; - struct ib_umem *umem; - struct ib_umem *resize_umem; - int create_flags; -}; - -struct mlx4_ib_mr { - struct ib_mr ibmr; - struct mlx4_mr mmr; - struct ib_umem *umem; - struct mlx4_shared_mr_info *smr_info; - atomic_t invalidated; - struct completion invalidation_comp; -}; - -struct mlx4_ib_mw { - struct ib_mw ibmw; - struct mlx4_mw mmw; -}; - -struct mlx4_ib_fast_reg_page_list { - struct ib_fast_reg_page_list ibfrpl; - __be64 *mapped_page_list; - dma_addr_t map; -}; - -struct mlx4_ib_fmr { - struct ib_fmr ibfmr; - struct mlx4_fmr mfmr; -}; - -struct mlx4_ib_flow { - struct ib_flow ibflow; - /* translating DMFS verbs sniffer rule to FW API requires two reg IDs */ - u64 reg_id[2]; -}; - -struct mlx4_ib_wq { - u64 *wrid; - spinlock_t lock; - int wqe_cnt; - int max_post; - int max_gs; - int offset; - int wqe_shift; - unsigned head; - unsigned tail; -}; - -enum mlx4_ib_qp_flags { - MLX4_IB_QP_LSO = IB_QP_CREATE_IPOIB_UD_LSO, - MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK, - MLX4_IB_QP_CAP_CROSS_CHANNEL = IB_QP_CREATE_CROSS_CHANNEL, - MLX4_IB_QP_CAP_MANAGED_SEND = IB_QP_CREATE_MANAGED_SEND, - MLX4_IB_QP_CAP_MANAGED_RECV = IB_QP_CREATE_MANAGED_RECV, - MLX4_IB_QP_NETIF = IB_QP_CREATE_NETIF_QP, - MLX4_IB_SRIOV_TUNNEL_QP = 1 << 30, - MLX4_IB_SRIOV_SQP = 1 << 31, -}; - -struct mlx4_ib_gid_entry { - struct list_head list; - union ib_gid gid; - int added; - u8 port; -}; - -enum mlx4_ib_mmap_cmd { - MLX4_IB_MMAP_UAR_PAGE = 0, - MLX4_IB_MMAP_BLUE_FLAME_PAGE = 1, - MLX4_IB_MMAP_GET_CONTIGUOUS_PAGES = 2, - MLX4_IB_MMAP_GET_HW_CLOCK = 3, -}; - -enum mlx4_ib_qp_type { - /* - * IB_QPT_SMI and IB_QPT_GSI have to be the first two entries - * here (and in that order) since the MAD layer uses them as - * indices into a 2-entry table. - */ - MLX4_IB_QPT_SMI = IB_QPT_SMI, - MLX4_IB_QPT_GSI = IB_QPT_GSI, - - MLX4_IB_QPT_RC = IB_QPT_RC, - MLX4_IB_QPT_UC = IB_QPT_UC, - MLX4_IB_QPT_UD = IB_QPT_UD, - MLX4_IB_QPT_RAW_IPV6 = IB_QPT_RAW_IPV6, - MLX4_IB_QPT_RAW_ETHERTYPE = IB_QPT_RAW_ETHERTYPE, - MLX4_IB_QPT_RAW_PACKET = IB_QPT_RAW_PACKET, - MLX4_IB_QPT_XRC_INI = IB_QPT_XRC_INI, - MLX4_IB_QPT_XRC_TGT = IB_QPT_XRC_TGT, - - MLX4_IB_QPT_PROXY_SMI_OWNER = 1 << 16, - MLX4_IB_QPT_PROXY_SMI = 1 << 17, - MLX4_IB_QPT_PROXY_GSI = 1 << 18, - MLX4_IB_QPT_TUN_SMI_OWNER = 1 << 19, - MLX4_IB_QPT_TUN_SMI = 1 << 20, - MLX4_IB_QPT_TUN_GSI = 1 << 21, -}; - -#define MLX4_IB_QPT_ANY_SRIOV (MLX4_IB_QPT_PROXY_SMI_OWNER | \ - MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER | \ - MLX4_IB_QPT_TUN_SMI | MLX4_IB_QPT_TUN_GSI) - -enum mlx4_ib_mad_ifc_flags { - MLX4_MAD_IFC_IGNORE_MKEY = 1, - MLX4_MAD_IFC_IGNORE_BKEY = 2, - MLX4_MAD_IFC_IGNORE_KEYS = (MLX4_MAD_IFC_IGNORE_MKEY | - MLX4_MAD_IFC_IGNORE_BKEY), - MLX4_MAD_IFC_NET_VIEW = 4, -}; - -enum { - MLX4_NUM_TUNNEL_BUFS = 256, -}; - -struct mlx4_ib_tunnel_header { - struct mlx4_av av; - __be32 remote_qpn; - __be32 qkey; - __be16 vlan; - u8 mac[6]; - __be16 pkey_index; - u8 reserved[6]; -}; - -struct mlx4_ib_buf { - void *addr; - dma_addr_t map; -}; - -struct mlx4_rcv_tunnel_hdr { - __be32 flags_src_qp; /* flags[6:5] is defined for VLANs: - * 0x0 - no vlan was in the packet - * 0x01 - C-VLAN was in the packet */ - u8 g_ml_path; /* gid bit stands for ipv6/4 header in RoCE */ - u8 reserved; - __be16 pkey_index; - __be16 sl_vid; - __be16 slid_mac_47_32; - __be32 mac_31_0; -}; - -struct mlx4_ib_proxy_sqp_hdr { - struct ib_grh grh; - struct mlx4_rcv_tunnel_hdr tun; -} __packed; - -struct mlx4_roce_smac_vlan_info { - u64 smac; - int smac_index; - int smac_port; - u64 candidate_smac; - int candidate_smac_index; - int candidate_smac_port; - u16 vid; - int vlan_index; - int vlan_port; - u16 candidate_vid; - int candidate_vlan_index; - int candidate_vlan_port; - int update_vid; -}; - -struct mlx4_ib_qpg_data { - unsigned long *tss_bitmap; - unsigned long *rss_bitmap; - struct mlx4_ib_qp *qpg_parent; - int tss_qpn_base; - int rss_qpn_base; - u32 tss_child_count; - u32 rss_child_count; - u32 qpg_tss_mask_sz; -}; - -struct mlx4_ib_qp { - struct ib_qp ibqp; - struct mlx4_qp mqp; - struct mlx4_buf buf; - - struct mlx4_db db; - struct mlx4_ib_wq rq; - - u32 doorbell_qpn; - __be32 sq_signal_bits; - unsigned sq_next_wqe; - int sq_max_wqes_per_wr; - int sq_spare_wqes; - struct mlx4_ib_wq sq; - - enum mlx4_ib_qp_type mlx4_ib_qp_type; - struct ib_umem *umem; - struct mlx4_mtt mtt; - int buf_size; - struct mutex mutex; - u16 xrcdn; - u32 flags; - u8 port; - u8 alt_port; - u8 atomic_rd_en; - u8 resp_depth; - u8 sq_no_prefetch; - u8 state; - int mlx_type; - enum ib_qpg_type qpg_type; - struct mlx4_ib_qpg_data *qpg_data; - struct list_head gid_list; - struct list_head steering_rules; - struct mlx4_ib_buf *sqp_proxy_rcv; - struct mlx4_roce_smac_vlan_info pri; - struct mlx4_roce_smac_vlan_info alt; - struct list_head rules_list; - u64 reg_id; - int max_inline_data; - struct mlx4_bf bf; - - /* - * Experimental data - */ - int max_inlr_data; -}; - -struct mlx4_ib_srq { - struct ib_srq ibsrq; - struct mlx4_srq msrq; - struct mlx4_buf buf; - struct mlx4_db db; - u64 *wrid; - spinlock_t lock; - int head; - int tail; - u16 wqe_ctr; - struct ib_umem *umem; - struct mlx4_mtt mtt; - struct mutex mutex; -}; - -struct mlx4_ib_ah { - struct ib_ah ibah; - union mlx4_ext_av av; -}; - -/****************************************/ -/* alias guid support */ -/****************************************/ -#define NUM_PORT_ALIAS_GUID 2 -#define NUM_ALIAS_GUID_IN_REC 8 -#define NUM_ALIAS_GUID_REC_IN_PORT 16 -#define GUID_REC_SIZE 8 -#define NUM_ALIAS_GUID_PER_PORT 128 -#define MLX4_NOT_SET_GUID (0x00LL) -#define MLX4_GUID_FOR_DELETE_VAL (~(0x00LL)) - -/****************************************/ -/* ioctl codes */ -/****************************************/ -#define MLX4_IOC_MAGIC 'm' -#define MLX4_IOCHWCLOCKOFFSET _IOR(MLX4_IOC_MAGIC, 1, int) - -enum mlx4_guid_alias_rec_status { - MLX4_GUID_INFO_STATUS_IDLE, - MLX4_GUID_INFO_STATUS_SET, - MLX4_GUID_INFO_STATUS_PENDING, -}; - -enum mlx4_guid_alias_rec_ownership { - MLX4_GUID_DRIVER_ASSIGN, - MLX4_GUID_SYSADMIN_ASSIGN, - MLX4_GUID_NONE_ASSIGN, /*init state of each record*/ -}; - -enum mlx4_guid_alias_rec_method { - MLX4_GUID_INFO_RECORD_SET = IB_MGMT_METHOD_SET, - MLX4_GUID_INFO_RECORD_DELETE = IB_SA_METHOD_DELETE, -}; - -struct mlx4_sriov_alias_guid_info_rec_det { - u8 all_recs[GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC]; - ib_sa_comp_mask guid_indexes; /*indicates what from the 8 records are valid*/ - enum mlx4_guid_alias_rec_status status; /*indicates the administraively status of the record.*/ - u8 method; /*set or delete*/ - enum mlx4_guid_alias_rec_ownership ownership; /*indicates who assign that alias_guid record*/ -}; - -struct mlx4_sriov_alias_guid_port_rec_det { - struct mlx4_sriov_alias_guid_info_rec_det all_rec_per_port[NUM_ALIAS_GUID_REC_IN_PORT]; - struct workqueue_struct *wq; - struct delayed_work alias_guid_work; - u8 port; - struct mlx4_sriov_alias_guid *parent; - struct list_head cb_list; -}; - -struct mlx4_sriov_alias_guid { - struct mlx4_sriov_alias_guid_port_rec_det ports_guid[MLX4_MAX_PORTS]; - spinlock_t ag_work_lock; - struct ib_sa_client *sa_client; -}; - -struct mlx4_ib_demux_work { - struct work_struct work; - struct mlx4_ib_dev *dev; - int slave; - int do_init; - u8 port; - -}; - -struct mlx4_ib_tun_tx_buf { - struct mlx4_ib_buf buf; - struct ib_ah *ah; -}; - -struct mlx4_ib_demux_pv_qp { - struct ib_qp *qp; - enum ib_qp_type proxy_qpt; - struct mlx4_ib_buf *ring; - struct mlx4_ib_tun_tx_buf *tx_ring; - spinlock_t tx_lock; - unsigned tx_ix_head; - unsigned tx_ix_tail; -}; - -enum mlx4_ib_demux_pv_state { - DEMUX_PV_STATE_DOWN, - DEMUX_PV_STATE_STARTING, - DEMUX_PV_STATE_ACTIVE, - DEMUX_PV_STATE_DOWNING, -}; - -struct mlx4_ib_demux_pv_ctx { - int port; - int slave; - enum mlx4_ib_demux_pv_state state; - int has_smi; - struct ib_device *ib_dev; - struct ib_cq *cq; - struct ib_pd *pd; - struct ib_mr *mr; - struct work_struct work; - struct workqueue_struct *wq; - struct mlx4_ib_demux_pv_qp qp[2]; -}; - -struct mlx4_ib_demux_ctx { - struct ib_device *ib_dev; - int port; - struct workqueue_struct *wq; - struct workqueue_struct *ud_wq; - spinlock_t ud_lock; - __be64 subnet_prefix; - __be64 guid_cache[128]; - struct mlx4_ib_dev *dev; - /* the following lock protects both mcg_table and mcg_mgid0_list */ - struct mutex mcg_table_lock; - struct rb_root mcg_table; - struct list_head mcg_mgid0_list; - struct workqueue_struct *mcg_wq; - struct mlx4_ib_demux_pv_ctx **tun; - atomic_t tid; - int flushing; /* flushing the work queue */ -}; - -struct mlx4_ib_sriov { - struct mlx4_ib_demux_ctx demux[MLX4_MAX_PORTS]; - struct mlx4_ib_demux_pv_ctx *sqps[MLX4_MAX_PORTS]; - /* when using this spinlock you should use "irq" because - * it may be called from interrupt context.*/ - spinlock_t going_down_lock; - int is_going_down; - - struct mlx4_sriov_alias_guid alias_guid; - - /* CM paravirtualization fields */ - struct list_head cm_list; - spinlock_t id_map_lock; - struct rb_root sl_id_map; - struct idr pv_id_table; -}; - -struct mlx4_ib_iboe { - spinlock_t lock; - struct net_device *netdevs[MLX4_MAX_PORTS]; - struct net_device *masters[MLX4_MAX_PORTS]; - struct notifier_block nb; - struct notifier_block nb_inet; - union ib_gid gid_table[MLX4_MAX_PORTS][128]; -}; - -struct pkey_mgt { - u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; - u16 phys_pkey_cache[MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; - struct list_head pkey_port_list[MLX4_MFUNC_MAX]; - struct kobject *device_parent[MLX4_MFUNC_MAX]; -}; - -struct mlx4_ib_iov_sysfs_attr { - void *ctx; - struct kobject *kobj; - unsigned long data; - u32 entry_num; - char name[15]; - struct device_attribute dentry; - struct device *dev; -}; - -struct mlx4_ib_iov_sysfs_attr_ar { - struct mlx4_ib_iov_sysfs_attr dentries[3 * NUM_ALIAS_GUID_PER_PORT + 1]; -}; - -struct mlx4_ib_iov_port { - char name[100]; - u8 num; - struct mlx4_ib_dev *dev; - struct list_head list; - struct mlx4_ib_iov_sysfs_attr_ar *dentr_ar; - struct ib_port_attr attr; - struct kobject *cur_port; - struct kobject *admin_alias_parent; - struct kobject *gids_parent; - struct kobject *pkeys_parent; - struct kobject *mcgs_parent; - struct mlx4_ib_iov_sysfs_attr mcg_dentry; -}; - -struct mlx4_ib_counter { - int counter_index; - int status; -}; - -struct mlx4_ib_dev { - struct ib_device ib_dev; - struct mlx4_dev *dev; - int num_ports; - struct mlx4_uar priv_uar; - u32 priv_pdn; - MLX4_DECLARE_DOORBELL_LOCK(uar_lock); - - struct ib_mad_agent *send_agent[MLX4_MAX_PORTS][2]; - struct ib_ah *sm_ah[MLX4_MAX_PORTS]; - spinlock_t sm_lock; - struct mlx4_ib_sriov sriov; - - struct mutex cap_mask_mutex; - bool ib_active; - struct mlx4_ib_iboe iboe; - struct mlx4_ib_counter counters[MLX4_MAX_PORTS]; - int *eq_table; - int eq_added; - struct kobject *iov_parent; - struct kobject *ports_parent; - struct kobject *dev_ports_parent[MLX4_MFUNC_MAX]; - struct mlx4_ib_iov_port iov_ports[MLX4_MAX_PORTS]; - struct pkey_mgt pkeys; - unsigned long *ib_uc_qpns_bitmap; - int steer_qpn_count; - int steer_qpn_base; -}; - -struct ib_event_work { - struct work_struct work; - struct mlx4_ib_dev *ib_dev; - struct mlx4_eqe ib_eqe; -}; - -struct mlx4_ib_qp_tunnel_init_attr { - struct ib_qp_init_attr init_attr; - int slave; - enum ib_qp_type proxy_qp_type; - u8 port; -}; - -static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev) -{ - return container_of(ibdev, struct mlx4_ib_dev, ib_dev); -} - -static inline struct mlx4_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext) -{ - return container_of(ibucontext, struct mlx4_ib_ucontext, ibucontext); -} - -static inline struct mlx4_ib_pd *to_mpd(struct ib_pd *ibpd) -{ - return container_of(ibpd, struct mlx4_ib_pd, ibpd); -} - -static inline struct mlx4_ib_xrcd *to_mxrcd(struct ib_xrcd *ibxrcd) -{ - return container_of(ibxrcd, struct mlx4_ib_xrcd, ibxrcd); -} - -static inline struct mlx4_ib_cq *to_mcq(struct ib_cq *ibcq) -{ - return container_of(ibcq, struct mlx4_ib_cq, ibcq); -} - -static inline struct mlx4_ib_cq *to_mibcq(struct mlx4_cq *mcq) -{ - return container_of(mcq, struct mlx4_ib_cq, mcq); -} - -static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr) -{ - return container_of(ibmr, struct mlx4_ib_mr, ibmr); -} - -static inline struct mlx4_ib_mw *to_mmw(struct ib_mw *ibmw) -{ - return container_of(ibmw, struct mlx4_ib_mw, ibmw); -} - -static inline struct mlx4_ib_fast_reg_page_list *to_mfrpl(struct ib_fast_reg_page_list *ibfrpl) -{ - return container_of(ibfrpl, struct mlx4_ib_fast_reg_page_list, ibfrpl); -} - -static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr) -{ - return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr); -} - -static inline struct mlx4_ib_flow *to_mflow(struct ib_flow *ibflow) -{ - return container_of(ibflow, struct mlx4_ib_flow, ibflow); -} - -static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp) -{ - return container_of(ibqp, struct mlx4_ib_qp, ibqp); -} - -static inline struct mlx4_ib_qp *to_mibqp(struct mlx4_qp *mqp) -{ - return container_of(mqp, struct mlx4_ib_qp, mqp); -} - -static inline struct mlx4_ib_srq *to_msrq(struct ib_srq *ibsrq) -{ - return container_of(ibsrq, struct mlx4_ib_srq, ibsrq); -} - -static inline struct mlx4_ib_srq *to_mibsrq(struct mlx4_srq *msrq) -{ - return container_of(msrq, struct mlx4_ib_srq, msrq); -} - -static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah) -{ - return container_of(ibah, struct mlx4_ib_ah, ibah); -} - -int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev); -void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev); - -int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, - struct mlx4_db *db); -void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db); - -struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc); -int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, - struct ib_umem *umem); -int mlx4_ib_umem_calc_optimal_mtt_size(struct ib_umem *umem, - u64 start_va, - int *num_of_mtts); -struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, - u64 virt_addr, int access_flags, - struct ib_udata *udata, int mr_id); -int mlx4_ib_dereg_mr(struct ib_mr *mr); -struct ib_mw *mlx4_ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type); -int mlx4_ib_bind_mw(struct ib_qp *qp, struct ib_mw *mw, - struct ib_mw_bind *mw_bind); -int mlx4_ib_dealloc_mw(struct ib_mw *mw); -struct ib_mr *mlx4_ib_alloc_fast_reg_mr(struct ib_pd *pd, - int max_page_list_len); -struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, - int page_list_len); -void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list); - -int mlx4_ib_modify_cq(struct ib_cq *cq, - struct ib_cq_attr *cq_attr, - int cq_attr_mask); -int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata); -int mlx4_ib_ignore_overrun_cq(struct ib_cq *ibcq); -struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, - struct ib_cq_init_attr *attr, - struct ib_ucontext *context, - struct ib_udata *udata); -int mlx4_ib_destroy_cq(struct ib_cq *cq); -int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); -int mlx4_ib_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); -void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); -void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); - -struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); -int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); -int mlx4_ib_destroy_ah(struct ib_ah *ah); - -struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, - struct ib_srq_init_attr *init_attr, - struct ib_udata *udata); -int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, - enum ib_srq_attr_mask attr_mask, struct ib_udata *udata); -int mlx4_ib_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr); -int mlx4_ib_destroy_srq(struct ib_srq *srq); -void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index); -int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, - struct ib_recv_wr **bad_wr); - -struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, - struct ib_qp_init_attr *init_attr, - struct ib_udata *udata); -int mlx4_ib_destroy_qp(struct ib_qp *qp); -int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, - int attr_mask, struct ib_udata *udata); -int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, - struct ib_qp_init_attr *qp_init_attr); -int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, - struct ib_send_wr **bad_wr); -int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, - struct ib_recv_wr **bad_wr); - -int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int mad_ifc_flags, - int port, struct ib_wc *in_wc, struct ib_grh *in_grh, - void *in_mad, void *response_mad); -int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, - struct ib_wc *in_wc, struct ib_grh *in_grh, - struct ib_mad *in_mad, struct ib_mad *out_mad); -int mlx4_ib_mad_init(struct mlx4_ib_dev *dev); -void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev); - -struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags, - struct ib_fmr_attr *fmr_attr); -int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages, - u64 iova); -int mlx4_ib_unmap_fmr(struct list_head *fmr_list); -int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr); -int __mlx4_ib_query_port(struct ib_device *ibdev, u8 port, - struct ib_port_attr *props, int netw_view); -int __mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, - u16 *pkey, int netw_view); - -int __mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index, - union ib_gid *gid, int netw_view); - -int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, - u8 *mac, int *is_mcast, u8 port); - -int mlx4_ib_query_if_stat(struct mlx4_ib_dev *dev, u32 counter_index, - union mlx4_counter *counter, u8 clear); - -static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah) -{ - u8 port = be32_to_cpu(ah->av.ib.port_pd) >> 24 & 3; - - if (rdma_port_get_link_layer(ah->ibah.device, port) == IB_LINK_LAYER_ETHERNET) - return 1; - - return !!(ah->av.ib.g_slid & 0x80); -} -static inline int mlx4_ib_qp_has_rq(struct ib_qp_init_attr *attr) -{ - if (attr->qp_type == IB_QPT_XRC_INI || attr->qp_type == IB_QPT_XRC_TGT) - return 0; - - return !attr->srq; -} - -int mlx4_ib_mcg_port_init(struct mlx4_ib_demux_ctx *ctx); -void mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy_wq); -void clean_vf_mcast(struct mlx4_ib_demux_ctx *ctx, int slave); -int mlx4_ib_mcg_init(void); -void mlx4_ib_mcg_destroy(void); - -int mlx4_ib_find_real_gid(struct ib_device *ibdev, u8 port, __be64 guid); - -int mlx4_ib_mcg_multiplex_handler(struct ib_device *ibdev, int port, int slave, - struct ib_sa_mad *sa_mad); -int mlx4_ib_mcg_demux_handler(struct ib_device *ibdev, int port, int slave, - struct ib_sa_mad *mad); - -int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, - union ib_gid *gid); - -void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num, - enum ib_event_type type); - -void mlx4_ib_tunnels_update_work(struct work_struct *work); - -int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, - enum ib_qp_type qpt, struct ib_wc *wc, - struct ib_grh *grh, struct ib_mad *mad); -int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, - enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn, - u32 qkey, struct ib_ah_attr *attr, u8 *s_mac, struct ib_mad *mad); -__be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx); - -int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, - struct ib_mad *mad, int is_eth); - -int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id, - struct ib_mad *mad); - -void mlx4_ib_cm_paravirt_init(struct mlx4_ib_dev *dev); -void mlx4_ib_cm_paravirt_clean(struct mlx4_ib_dev *dev, int slave_id); - -/* alias guid support */ -void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port); -int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev); -void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev); -void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port); - -void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev, - int block_num, - u8 port_num, u8 *p_data); - -void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, - int block_num, u8 port_num, - u8 *p_data); - -int add_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, - struct attribute *attr); -void del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, - struct attribute *attr); -ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index); - -int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *device) ; - -void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device); - -__be64 mlx4_ib_gen_node_guid(void); - -int mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn); -void mlx4_ib_steer_qp_free(struct mlx4_ib_dev *dev, u32 qpn, int count); -int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, - int is_attach); -int mlx4_ib_query_device(struct ib_device *ibdev, - struct ib_device_attr *props); - -#endif /* MLX4_IB_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mr.c b/sys/ofed/drivers/infiniband/hw/mlx4/mr.c deleted file mode 100644 index f531a03a3681..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/mr.c +++ /dev/null @@ -1,885 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 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/slab.h> -#include <linux/module.h> -#include <linux/sched.h> - -#include "mlx4_ib.h" - -static u32 convert_access(int acc) -{ - return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX4_PERM_ATOMIC : 0) | - (acc & IB_ACCESS_REMOTE_WRITE ? MLX4_PERM_REMOTE_WRITE : 0) | - (acc & IB_ACCESS_REMOTE_READ ? MLX4_PERM_REMOTE_READ : 0) | - (acc & IB_ACCESS_LOCAL_WRITE ? MLX4_PERM_LOCAL_WRITE : 0) | - (acc & IB_ACCESS_MW_BIND ? MLX4_PERM_BIND_MW : 0) | - MLX4_PERM_LOCAL_READ; -} -/* No suuport for Shared MR feature */ -#if 0 -static ssize_t shared_mr_proc_read(struct file *file, - char __user *buffer, - size_t len, - loff_t *offset) -{ - - return -ENOSYS; - -} - -static ssize_t shared_mr_proc_write(struct file *file, - const char __user *buffer, - size_t len, - loff_t *offset) -{ - - return -ENOSYS; -} - -static int shared_mr_mmap(struct file *filep, struct vm_area_struct *vma) -{ - - struct proc_dir_entry *pde = PDE(filep->f_path.dentry->d_inode); - struct mlx4_shared_mr_info *smr_info = - (struct mlx4_shared_mr_info *)pde->data; - - /* Prevent any mapping not on start of area */ - if (vma->vm_pgoff != 0) - return -EINVAL; - - return ib_umem_map_to_vma(smr_info->umem, - vma); - -} - -static const struct file_operations shared_mr_proc_ops = { - .owner = THIS_MODULE, - .read = shared_mr_proc_read, - .write = shared_mr_proc_write, - .mmap = shared_mr_mmap -}; - -static mode_t convert_shared_access(int acc) -{ - - return (acc & IB_ACCESS_SHARED_MR_USER_READ ? S_IRUSR : 0) | - (acc & IB_ACCESS_SHARED_MR_USER_WRITE ? S_IWUSR : 0) | - (acc & IB_ACCESS_SHARED_MR_GROUP_READ ? S_IRGRP : 0) | - (acc & IB_ACCESS_SHARED_MR_GROUP_WRITE ? S_IWGRP : 0) | - (acc & IB_ACCESS_SHARED_MR_OTHER_READ ? S_IROTH : 0) | - (acc & IB_ACCESS_SHARED_MR_OTHER_WRITE ? S_IWOTH : 0); - -} -#endif -struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc) -{ - struct mlx4_ib_mr *mr; - int err; - - mr = kzalloc(sizeof *mr, GFP_KERNEL); - if (!mr) - return ERR_PTR(-ENOMEM); - - err = mlx4_mr_alloc(to_mdev(pd->device)->dev, to_mpd(pd)->pdn, 0, - ~0ull, convert_access(acc), 0, 0, &mr->mmr); - if (err) - goto err_free; - - err = mlx4_mr_enable(to_mdev(pd->device)->dev, &mr->mmr); - if (err) - goto err_mr; - - mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; - mr->umem = NULL; - - return &mr->ibmr; - -err_mr: - (void) mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr); - -err_free: - kfree(mr); - - return ERR_PTR(err); -} - -static int mlx4_ib_umem_write_mtt_block(struct mlx4_ib_dev *dev, - struct mlx4_mtt *mtt, - u64 mtt_size, - u64 mtt_shift, - u64 len, - u64 cur_start_addr, - u64 *pages, - int *start_index, - int *npages) -{ - int k; - int err = 0; - u64 mtt_entries; - u64 cur_end_addr = cur_start_addr + len; - u64 cur_end_addr_aligned = 0; - - len += (cur_start_addr & (mtt_size-1ULL)); - cur_end_addr_aligned = round_up(cur_end_addr, mtt_size); - len += (cur_end_addr_aligned - cur_end_addr); - if (len & (mtt_size-1ULL)) { - WARN(1 , - "write_block: len %llx is not aligned to mtt_size %llx\n", - (unsigned long long)len, (unsigned long long)mtt_size); - return -EINVAL; - } - - - mtt_entries = (len >> mtt_shift); - - /* Align the MTT start address to - the mtt_size. - Required to handle cases when the MR - starts in the middle of an MTT record. - Was not required in old code since - the physical addresses provided by - the dma subsystem were page aligned, - which was also the MTT size. - */ - cur_start_addr = round_down(cur_start_addr, mtt_size); - /* A new block is started ...*/ - for (k = 0; k < mtt_entries; ++k) { - pages[*npages] = cur_start_addr + (mtt_size * k); - (*npages)++; - /* - * Be friendly to mlx4_write_mtt() and - * pass it chunks of appropriate size. - */ - if (*npages == PAGE_SIZE / sizeof(u64)) { - err = mlx4_write_mtt(dev->dev, - mtt, *start_index, - *npages, pages); - if (err) - return err; - - (*start_index) += *npages; - *npages = 0; - } - } - - return 0; -} - -int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, - struct ib_umem *umem) -{ - u64 *pages; - u64 len = 0; - int err = 0; - u64 mtt_size; - u64 cur_start_addr = 0; - u64 mtt_shift; - int start_index = 0; - int npages = 0; - struct scatterlist *sg; - int i; - - pages = (u64 *) __get_free_page(GFP_KERNEL); - if (!pages) - return -ENOMEM; - - mtt_shift = mtt->page_shift; - mtt_size = 1ULL << mtt_shift; - - for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) { - if (cur_start_addr + len == - sg_dma_address(sg)) { - /* still the same block */ - len += sg_dma_len(sg); - continue; - } - /* A new block is started ...*/ - /* If len is malaligned, write an extra mtt entry to - cover the misaligned area (round up the division) - */ - err = mlx4_ib_umem_write_mtt_block(dev, - mtt, mtt_size, mtt_shift, - len, cur_start_addr, - pages, - &start_index, - &npages); - if (err) - goto out; - - cur_start_addr = - sg_dma_address(sg); - len = sg_dma_len(sg); - } - - /* Handle the last block */ - if (len > 0) { - /* If len is malaligned, write an extra mtt entry to cover - the misaligned area (round up the division) - */ - err = mlx4_ib_umem_write_mtt_block(dev, - mtt, mtt_size, mtt_shift, - len, cur_start_addr, - pages, - &start_index, - &npages); - if (err) - goto out; - } - - - if (npages) - err = mlx4_write_mtt(dev->dev, mtt, start_index, npages, pages); - -out: - free_page((unsigned long) pages); - return err; -} - -static inline u64 alignment_of(u64 ptr) -{ - return ilog2(ptr & (~(ptr-1))); -} - -static int mlx4_ib_umem_calc_block_mtt(u64 next_block_start, - u64 current_block_end, - u64 block_shift) -{ - /* Check whether the alignment of the new block - is aligned as well as the previous block. - Block address must start with zeros till size of entity_size. - */ - if ((next_block_start & ((1ULL << block_shift) - 1ULL)) != 0) - /* It is not as well aligned as the - previous block-reduce the mtt size - accordingly. - Here we take the last right bit - which is 1. - */ - block_shift = alignment_of(next_block_start); - - /* Check whether the alignment of the - end of previous block - is it aligned - as well as the start of the block - */ - if (((current_block_end) & ((1ULL << block_shift) - 1ULL)) != 0) - /* It is not as well aligned as - the start of the block - reduce the - mtt size accordingly. - */ - block_shift = alignment_of(current_block_end); - - return block_shift; -} - -/* Calculate optimal mtt size based on contiguous pages. -* Function will return also the number of pages that are not aligned to the - calculated mtt_size to be added to total number - of pages. For that we should check the first chunk length & last chunk - length and if not aligned to mtt_size we should increment - the non_aligned_pages number. - All chunks in the middle already handled as part of mtt shift calculation - for both their start & end addresses. -*/ -int mlx4_ib_umem_calc_optimal_mtt_size(struct ib_umem *umem, - u64 start_va, - int *num_of_mtts) -{ - u64 block_shift = MLX4_MAX_MTT_SHIFT; - u64 current_block_len = 0; - u64 current_block_start = 0; - u64 misalignment_bits; - u64 first_block_start = 0; - u64 last_block_end = 0; - u64 total_len = 0; - u64 last_block_aligned_end = 0; - u64 min_shift = ilog2(umem->page_size); - struct scatterlist *sg; - int i; - u64 next_block_start; - u64 current_block_end; - - for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) { - /* Initialization - save the first chunk start as - the current_block_start - block means contiguous pages. - */ - if (current_block_len == 0 && current_block_start == 0) { - first_block_start = current_block_start = - sg_dma_address(sg); - /* Find the bits that are different between - the physical address and the virtual - address for the start of the MR. - */ - /* umem_get aligned the start_va to a page - boundary. Therefore, we need to align the - start va to the same boundary */ - /* misalignment_bits is needed to handle the - case of a single memory region. In this - case, the rest of the logic will not reduce - the block size. If we use a block size - which is bigger than the alignment of the - misalignment bits, we might use the virtual - page number instead of the physical page - number, resulting in access to the wrong - data. */ - misalignment_bits = - (start_va & (~(((u64)(umem->page_size))-1ULL))) - ^ current_block_start; - block_shift = min(alignment_of(misalignment_bits) - , block_shift); - } - - /* Go over the scatter entries and check - if they continue the previous scatter entry. - */ - next_block_start = - sg_dma_address(sg); - current_block_end = current_block_start - + current_block_len; - /* If we have a split (non-contig.) between two block*/ - if (current_block_end != next_block_start) { - block_shift = mlx4_ib_umem_calc_block_mtt( - next_block_start, - current_block_end, - block_shift); - - /* If we reached the minimum shift for 4k - page we stop the loop. - */ - if (block_shift <= min_shift) - goto end; - - /* If not saved yet we are in first block - - we save the length of first block to - calculate the non_aligned_pages number at - * the end. - */ - total_len += current_block_len; - - /* Start a new block */ - current_block_start = next_block_start; - current_block_len = - sg_dma_len(sg); - continue; - } - /* The scatter entry is another part of - the current block, increase the block size - * An entry in the scatter can be larger than - 4k (page) as of dma mapping - which merge some blocks together. - */ - current_block_len += - sg_dma_len(sg); - } - - /* Account for the last block in the total len */ - total_len += current_block_len; - /* Add to the first block the misalignment that it suffers from.*/ - total_len += (first_block_start & ((1ULL<<block_shift)-1ULL)); - last_block_end = current_block_start+current_block_len; - last_block_aligned_end = round_up(last_block_end, 1<<block_shift); - total_len += (last_block_aligned_end - last_block_end); - - WARN((total_len & ((1ULL<<block_shift)-1ULL)), - " misaligned total length detected (%llu, %llu)!", - (unsigned long long)total_len, (unsigned long long)block_shift); - - *num_of_mtts = total_len >> block_shift; -end: - if (block_shift < min_shift) { - /* If shift is less than the min we set a WARN and - return the min shift. - */ - WARN(1, - "mlx4_ib_umem_calc_optimal_mtt_size - unexpected shift %lld\n", - (unsigned long long)block_shift); - - block_shift = min_shift; - } - return block_shift; - -} - -/* No suuport for Shared MR */ -#if 0 -static int prepare_shared_mr(struct mlx4_ib_mr *mr, int access_flags, int mr_id) -{ - - struct proc_dir_entry *mr_proc_entry; - mode_t mode = S_IFREG; - char name_buff[16]; - - mode |= convert_shared_access(access_flags); - sprintf(name_buff, "%X", mr_id); - mr->smr_info = kmalloc(sizeof(struct mlx4_shared_mr_info), GFP_KERNEL); - mr->smr_info->mr_id = mr_id; - mr->smr_info->umem = mr->umem; - - mr_proc_entry = proc_create_data(name_buff, mode, - mlx4_mrs_dir_entry, - &shared_mr_proc_ops, - mr->smr_info); - - if (!mr_proc_entry) { - pr_err("prepare_shared_mr failed via proc\n"); - kfree(mr->smr_info); - return -ENODEV; - } - - current_uid_gid(&(mr_proc_entry->uid), &(mr_proc_entry->gid)); - mr_proc_entry->size = mr->umem->length; - return 0; - -} -static int is_shared_mr(int access_flags) -{ - /* We should check whether IB_ACCESS_SHARED_MR_USER_READ or - other shared bits were turned on. - */ - return !!(access_flags & (IB_ACCESS_SHARED_MR_USER_READ | - IB_ACCESS_SHARED_MR_USER_WRITE | - IB_ACCESS_SHARED_MR_GROUP_READ | - IB_ACCESS_SHARED_MR_GROUP_WRITE | - IB_ACCESS_SHARED_MR_OTHER_READ | - IB_ACCESS_SHARED_MR_OTHER_WRITE)); - -} - -static void free_smr_info(struct mlx4_ib_mr *mr) -{ - /* When master/parent shared mr is dereged there is - no ability to share this mr any more - its mr_id will be - returned to the kernel as part of ib_uverbs_dereg_mr - and may be allocated again as part of other reg_mr. - */ - char name_buff[16]; - - sprintf(name_buff, "%X", mr->smr_info->mr_id); - /* Remove proc entry is checking internally that no operation - was strated on that proc fs file and if in the middle - current process will wait till end of operation. - That's why no sync mechanism is needed when we release - below the shared umem. - */ - remove_proc_entry(name_buff, mlx4_mrs_dir_entry); - kfree(mr->smr_info); - mr->smr_info = NULL; -} -#endif - -static void mlx4_invalidate_umem(void *invalidation_cookie, - struct ib_umem *umem, - unsigned long addr, size_t size) -{ - struct mlx4_ib_mr *mr = (struct mlx4_ib_mr *)invalidation_cookie; - - /* This function is called under client peer lock so its resources are race protected */ - if (atomic_inc_return(&mr->invalidated) > 1) { - umem->invalidation_ctx->inflight_invalidation = 1; - goto end; - } - - umem->invalidation_ctx->peer_callback = 1; - mlx4_mr_free(to_mdev(mr->ibmr.device)->dev, &mr->mmr); - ib_umem_release(umem); - complete(&mr->invalidation_comp); - -end: - return; - -} - -struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, - u64 virt_addr, int access_flags, - struct ib_udata *udata, - int mr_id) -{ - struct mlx4_ib_dev *dev = to_mdev(pd->device); - struct mlx4_ib_mr *mr; - int shift; - int err; - int n; - struct ib_peer_memory_client *ib_peer_mem; - - mr = kzalloc(sizeof *mr, GFP_KERNEL); - if (!mr) - return ERR_PTR(-ENOMEM); - - mr->umem = ib_umem_get_ex(pd->uobject->context, start, length, - access_flags, 0, 1); - if (IS_ERR(mr->umem)) { - err = PTR_ERR(mr->umem); - goto err_free; - } - - ib_peer_mem = mr->umem->ib_peer_mem; - n = ib_umem_page_count(mr->umem); - shift = mlx4_ib_umem_calc_optimal_mtt_size(mr->umem, start, - &n); - err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, virt_addr, length, - convert_access(access_flags), n, shift, &mr->mmr); - if (err) - goto err_umem; - - err = mlx4_ib_umem_write_mtt(dev, &mr->mmr.mtt, mr->umem); - if (err) - goto err_mr; - - err = mlx4_mr_enable(dev->dev, &mr->mmr); - if (err) - goto err_mr; - - mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; -/* No suuport for Shared MR */ -#if 0 - /* Check whether MR should be shared */ - if (is_shared_mr(access_flags)) { - /* start address and length must be aligned to page size in order - to map a full page and preventing leakage of data */ - if (mr->umem->offset || (length & ~PAGE_MASK)) { - err = -EINVAL; - goto err_mr; - } - - err = prepare_shared_mr(mr, access_flags, mr_id); - if (err) - goto err_mr; - } -#endif - if (ib_peer_mem) { - if (access_flags & IB_ACCESS_MW_BIND) { - /* Prevent binding MW on peer clients. - * mlx4_invalidate_umem must be void, - * therefore, mlx4_mr_free should not fail - * when using peer clients. */ - err = -ENOSYS; - pr_err("MW is not supported with peer memory client"); - goto err_smr; - } - init_completion(&mr->invalidation_comp); - ib_umem_activate_invalidation_notifier(mr->umem, - mlx4_invalidate_umem, mr); - } - - atomic_set(&mr->invalidated, 0); - return &mr->ibmr; - -err_smr: -/* No suuport for Shared MR */ -#if 0 - if (mr->smr_info) - free_smr_info(mr); -#endif -err_mr: - (void) mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr); - -err_umem: - ib_umem_release(mr->umem); - -err_free: - kfree(mr); - - return ERR_PTR(err); -} - -int mlx4_ib_dereg_mr(struct ib_mr *ibmr) -{ - struct mlx4_ib_mr *mr = to_mmr(ibmr); - struct ib_umem *umem = mr->umem; - int ret; - -/* No suuport for Shared MR */ -#if 0 - if (mr->smr_info) - free_smr_info(mr); -#endif - - if (atomic_inc_return(&mr->invalidated) > 1) { - wait_for_completion(&mr->invalidation_comp); - goto end; - } - - ret = mlx4_mr_free(to_mdev(ibmr->device)->dev, &mr->mmr); - if (ret) { - /* Error is not expected here, except when memory windows - * are bound to MR which is not supported with - * peer memory clients */ - atomic_set(&mr->invalidated, 0); - return ret; - } - - if (!umem) - goto end; - - ib_umem_release(mr->umem); -end: - - kfree(mr); - - return 0; -} - -struct ib_mw *mlx4_ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type) -{ - struct mlx4_ib_dev *dev = to_mdev(pd->device); - struct mlx4_ib_mw *mw; - int err; - - mw = kmalloc(sizeof(*mw), GFP_KERNEL); - if (!mw) - return ERR_PTR(-ENOMEM); - - err = mlx4_mw_alloc(dev->dev, to_mpd(pd)->pdn, (enum mlx4_mw_type)type, &mw->mmw); - if (err) - goto err_free; - - err = mlx4_mw_enable(dev->dev, &mw->mmw); - if (err) - goto err_mw; - - mw->ibmw.rkey = mw->mmw.key; - - return &mw->ibmw; - -err_mw: - mlx4_mw_free(dev->dev, &mw->mmw); - -err_free: - kfree(mw); - - return ERR_PTR(err); -} - -int mlx4_ib_bind_mw(struct ib_qp *qp, struct ib_mw *mw, - struct ib_mw_bind *mw_bind) -{ - struct ib_send_wr wr; - struct ib_send_wr *bad_wr; - int ret; - - memset(&wr, 0, sizeof(wr)); - wr.opcode = IB_WR_BIND_MW; - wr.wr_id = mw_bind->wr_id; - wr.send_flags = mw_bind->send_flags; - wr.wr.bind_mw.mw = mw; - wr.wr.bind_mw.bind_info = mw_bind->bind_info; - wr.wr.bind_mw.rkey = ib_inc_rkey(mw->rkey); - - ret = mlx4_ib_post_send(qp, &wr, &bad_wr); - if (!ret) - mw->rkey = wr.wr.bind_mw.rkey; - - return ret; -} - -int mlx4_ib_dealloc_mw(struct ib_mw *ibmw) -{ - struct mlx4_ib_mw *mw = to_mmw(ibmw); - - mlx4_mw_free(to_mdev(ibmw->device)->dev, &mw->mmw); - kfree(mw); - - return 0; -} - -struct ib_mr *mlx4_ib_alloc_fast_reg_mr(struct ib_pd *pd, - int max_page_list_len) -{ - struct mlx4_ib_dev *dev = to_mdev(pd->device); - struct mlx4_ib_mr *mr; - int err; - - mr = kzalloc(sizeof *mr, GFP_KERNEL); - if (!mr) - return ERR_PTR(-ENOMEM); - - err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, 0, 0, 0, - max_page_list_len, 0, &mr->mmr); - if (err) - goto err_free; - - err = mlx4_mr_enable(dev->dev, &mr->mmr); - if (err) - goto err_mr; - - mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; - mr->umem = NULL; - - return &mr->ibmr; - -err_mr: - (void) mlx4_mr_free(dev->dev, &mr->mmr); - -err_free: - kfree(mr); - return ERR_PTR(err); -} - -struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, - int page_list_len) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct mlx4_ib_fast_reg_page_list *mfrpl; - int size = page_list_len * sizeof (u64); - - if (page_list_len > MLX4_MAX_FAST_REG_PAGES) - return ERR_PTR(-EINVAL); - - mfrpl = kmalloc(sizeof *mfrpl, GFP_KERNEL); - if (!mfrpl) - return ERR_PTR(-ENOMEM); - - mfrpl->ibfrpl.page_list = kmalloc(size, GFP_KERNEL); - if (!mfrpl->ibfrpl.page_list) - goto err_free; - - mfrpl->mapped_page_list = dma_alloc_coherent(&dev->dev->pdev->dev, - size, &mfrpl->map, - GFP_KERNEL); - if (!mfrpl->mapped_page_list) - goto err_free; - - WARN_ON(mfrpl->map & 0x3f); - - return &mfrpl->ibfrpl; - -err_free: - kfree(mfrpl->ibfrpl.page_list); - kfree(mfrpl); - return ERR_PTR(-ENOMEM); -} - -void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list) -{ - struct mlx4_ib_dev *dev = to_mdev(page_list->device); - struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list); - int size = page_list->max_page_list_len * sizeof (u64); - - dma_free_coherent(&dev->dev->pdev->dev, size, mfrpl->mapped_page_list, - mfrpl->map); - kfree(mfrpl->ibfrpl.page_list); - kfree(mfrpl); -} - -struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc, - struct ib_fmr_attr *fmr_attr) -{ - struct mlx4_ib_dev *dev = to_mdev(pd->device); - struct mlx4_ib_fmr *fmr; - int err = -ENOMEM; - - fmr = kmalloc(sizeof *fmr, GFP_KERNEL); - if (!fmr) - return ERR_PTR(-ENOMEM); - - err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc), - fmr_attr->max_pages, fmr_attr->max_maps, - fmr_attr->page_shift, &fmr->mfmr); - if (err) - goto err_free; - - err = mlx4_fmr_enable(to_mdev(pd->device)->dev, &fmr->mfmr); - if (err) - goto err_mr; - - fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key; - - return &fmr->ibfmr; - -err_mr: - (void) mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr); - -err_free: - kfree(fmr); - - return ERR_PTR(err); -} - -int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, - int npages, u64 iova) -{ - struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); - struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device); - - return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova, - &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); -} - -int mlx4_ib_unmap_fmr(struct list_head *fmr_list) -{ - struct ib_fmr *ibfmr; - int err; - struct mlx4_dev *mdev = NULL; - - list_for_each_entry(ibfmr, fmr_list, list) { - if (mdev && to_mdev(ibfmr->device)->dev != mdev) - return -EINVAL; - mdev = to_mdev(ibfmr->device)->dev; - } - - if (!mdev) - return 0; - - list_for_each_entry(ibfmr, fmr_list, list) { - struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); - - mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); - } - - /* - * Make sure all MPT status updates are visible before issuing - * SYNC_TPT firmware command. - */ - wmb(); - - err = mlx4_SYNC_TPT(mdev); - if (err) - pr_warn("SYNC_TPT error %d when " - "unmapping FMRs\n", err); - - return 0; -} - -int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr) -{ - struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); - struct mlx4_ib_dev *dev = to_mdev(ibfmr->device); - int err; - - err = mlx4_fmr_free(dev->dev, &ifmr->mfmr); - - if (!err) - kfree(ifmr); - - return err; -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/qp.c b/sys/ofed/drivers/infiniband/hw/mlx4/qp.c deleted file mode 100644 index 69af398dc087..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/qp.c +++ /dev/null @@ -1,3687 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 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/log2.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/bitops.h> - -#include <rdma/ib_cache.h> -#include <rdma/ib_pack.h> -#include <rdma/ib_addr.h> -#include <rdma/ib_mad.h> - -#include <linux/mlx4/qp.h> -#include <linux/mlx4/driver.h> -#include <linux/io.h> - -#include "mlx4_ib.h" -#include "user.h" - -#define asm __asm - -enum { - MLX4_IB_ACK_REQ_FREQ = 8, -}; - -enum { - MLX4_IB_DEFAULT_SCHED_QUEUE = 0x83, - MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f, - MLX4_IB_LINK_TYPE_IB = 0, - MLX4_IB_LINK_TYPE_ETH = 1 -}; - -enum { - /* - * Largest possible UD header: send with GRH and immediate - * data plus 18 bytes for an Ethernet header with VLAN/802.1Q - * tag. (LRH would only use 8 bytes, so Ethernet is the - * biggest case) - */ - MLX4_IB_UD_HEADER_SIZE = 82, - MLX4_IB_LSO_HEADER_SPARE = 128, -}; - -enum { - MLX4_IB_IBOE_ETHERTYPE = 0x8915 -}; - -struct mlx4_ib_sqp { - struct mlx4_ib_qp qp; - int pkey_index; - u32 qkey; - u32 send_psn; - struct ib_ud_header ud_header; - u8 header_buf[MLX4_IB_UD_HEADER_SIZE]; -}; - -enum { - MLX4_IB_MIN_SQ_STRIDE = 6, - MLX4_IB_CACHE_LINE_SIZE = 64, -}; - -enum { - MLX4_RAW_QP_MTU = 7, - MLX4_RAW_QP_MSGMAX = 31, -}; - -static const __be32 mlx4_ib_opcode[] = { - [IB_WR_SEND] = cpu_to_be32(MLX4_OPCODE_SEND), - [IB_WR_LSO] = cpu_to_be32(MLX4_OPCODE_LSO), - [IB_WR_SEND_WITH_IMM] = cpu_to_be32(MLX4_OPCODE_SEND_IMM), - [IB_WR_RDMA_WRITE] = cpu_to_be32(MLX4_OPCODE_RDMA_WRITE), - [IB_WR_RDMA_WRITE_WITH_IMM] = cpu_to_be32(MLX4_OPCODE_RDMA_WRITE_IMM), - [IB_WR_RDMA_READ] = cpu_to_be32(MLX4_OPCODE_RDMA_READ), - [IB_WR_ATOMIC_CMP_AND_SWP] = cpu_to_be32(MLX4_OPCODE_ATOMIC_CS), - [IB_WR_ATOMIC_FETCH_AND_ADD] = cpu_to_be32(MLX4_OPCODE_ATOMIC_FA), - [IB_WR_SEND_WITH_INV] = cpu_to_be32(MLX4_OPCODE_SEND_INVAL), - [IB_WR_LOCAL_INV] = cpu_to_be32(MLX4_OPCODE_LOCAL_INVAL), - [IB_WR_FAST_REG_MR] = cpu_to_be32(MLX4_OPCODE_FMR), - [IB_WR_MASKED_ATOMIC_CMP_AND_SWP] = cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_CS), - [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD] = cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_FA), - [IB_WR_BIND_MW] = cpu_to_be32( - MLX4_OPCODE_BIND_MW), -}; - -#ifndef wc_wmb - #if defined(__i386__) - #define wc_wmb() asm volatile("lock; addl $0,0(%%esp) " ::: "memory") - #elif defined(__x86_64__) - #define wc_wmb() asm volatile("sfence" ::: "memory") - #elif defined(__ia64__) - #define wc_wmb() asm volatile("fwb" ::: "memory") - #else - #define wc_wmb() wmb() - #endif -#endif - -static struct mlx4_ib_sqp *to_msqp(struct mlx4_ib_qp *mqp) -{ - return container_of(mqp, struct mlx4_ib_sqp, qp); -} - -static int is_tunnel_qp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) -{ - if (!mlx4_is_master(dev->dev)) - return 0; - - return qp->mqp.qpn >= dev->dev->phys_caps.base_tunnel_sqpn && - qp->mqp.qpn < dev->dev->phys_caps.base_tunnel_sqpn + - 8 * MLX4_MFUNC_MAX; -} - -static int is_sqp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) -{ - int proxy_sqp = 0; - int real_sqp = 0; - int i; - /* PPF or Native -- real SQP */ - real_sqp = ((mlx4_is_master(dev->dev) || !mlx4_is_mfunc(dev->dev)) && - qp->mqp.qpn >= dev->dev->phys_caps.base_sqpn && - qp->mqp.qpn <= dev->dev->phys_caps.base_sqpn + 3); - if (real_sqp) - return 1; - /* VF or PF -- proxy SQP */ - if (mlx4_is_mfunc(dev->dev)) { - for (i = 0; i < dev->dev->caps.num_ports; i++) { - if (qp->mqp.qpn == dev->dev->caps.qp0_proxy[i] || - qp->mqp.qpn == dev->dev->caps.qp1_proxy[i]) { - proxy_sqp = 1; - break; - } - } - } - return proxy_sqp; -} - -/* used for INIT/CLOSE port logic */ -static int is_qp0(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) -{ - int proxy_qp0 = 0; - int real_qp0 = 0; - int i; - /* PPF or Native -- real QP0 */ - real_qp0 = ((mlx4_is_master(dev->dev) || !mlx4_is_mfunc(dev->dev)) && - qp->mqp.qpn >= dev->dev->phys_caps.base_sqpn && - qp->mqp.qpn <= dev->dev->phys_caps.base_sqpn + 1); - if (real_qp0) - return 1; - /* VF or PF -- proxy QP0 */ - if (mlx4_is_mfunc(dev->dev)) { - for (i = 0; i < dev->dev->caps.num_ports; i++) { - if (qp->mqp.qpn == dev->dev->caps.qp0_proxy[i]) { - proxy_qp0 = 1; - break; - } - } - } - return proxy_qp0; -} - -static void *get_wqe(struct mlx4_ib_qp *qp, int offset) -{ - return mlx4_buf_offset(&qp->buf, offset); -} - -static void *get_recv_wqe(struct mlx4_ib_qp *qp, int n) -{ - return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift)); -} - -static void *get_send_wqe(struct mlx4_ib_qp *qp, int n) -{ - return get_wqe(qp, qp->sq.offset + (n << qp->sq.wqe_shift)); -} - -/* - * Stamp a SQ WQE so that it is invalid if prefetched by marking the - * first four bytes of every 64 byte chunk with - * 0x7FFFFFF | (invalid_ownership_value << 31). - * - * When the max work request size is less than or equal to the WQE - * basic block size, as an optimization, we can stamp all WQEs with - * 0xffffffff, and skip the very first chunk of each WQE. - */ -static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n, int size) -{ - __be32 *wqe; - int i; - int s; - int ind; - void *buf; - __be32 stamp; - struct mlx4_wqe_ctrl_seg *ctrl; - - if (qp->sq_max_wqes_per_wr > 1) { - s = roundup(size, 1U << qp->sq.wqe_shift); - for (i = 0; i < s; i += 64) { - ind = (i >> qp->sq.wqe_shift) + n; - stamp = ind & qp->sq.wqe_cnt ? cpu_to_be32(0x7fffffff) : - cpu_to_be32(0xffffffff); - buf = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); - wqe = buf + (i & ((1 << qp->sq.wqe_shift) - 1)); - *wqe = stamp; - } - } else { - ctrl = buf = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1)); - s = (ctrl->fence_size & 0x3f) << 4; - for (i = 64; i < s; i += 64) { - wqe = buf + i; - *wqe = cpu_to_be32(0xffffffff); - } - } -} - -static void post_nop_wqe(struct mlx4_ib_qp *qp, int n, int size) -{ - struct mlx4_wqe_ctrl_seg *ctrl; - struct mlx4_wqe_inline_seg *inl; - void *wqe; - int s; - - ctrl = wqe = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1)); - s = sizeof(struct mlx4_wqe_ctrl_seg); - - if (qp->ibqp.qp_type == IB_QPT_UD) { - struct mlx4_wqe_datagram_seg *dgram = wqe + sizeof *ctrl; - struct mlx4_av *av = (struct mlx4_av *)dgram->av; - memset(dgram, 0, sizeof *dgram); - av->port_pd = cpu_to_be32((qp->port << 24) | to_mpd(qp->ibqp.pd)->pdn); - s += sizeof(struct mlx4_wqe_datagram_seg); - } - - /* Pad the remainder of the WQE with an inline data segment. */ - if (size > s) { - inl = wqe + s; - inl->byte_count = cpu_to_be32(1 << 31 | (size - s - sizeof *inl)); - } - ctrl->srcrb_flags = 0; - ctrl->fence_size = size / 16; - /* - * Make sure descriptor is fully written before setting ownership bit - * (because HW can start executing as soon as we do). - */ - wmb(); - - ctrl->owner_opcode = cpu_to_be32(MLX4_OPCODE_NOP | MLX4_WQE_CTRL_NEC) | - (n & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0); - - stamp_send_wqe(qp, n + qp->sq_spare_wqes, size); -} - -/* Post NOP WQE to prevent wrap-around in the middle of WR */ -static inline unsigned pad_wraparound(struct mlx4_ib_qp *qp, int ind) -{ - unsigned s = qp->sq.wqe_cnt - (ind & (qp->sq.wqe_cnt - 1)); - if (unlikely(s < qp->sq_max_wqes_per_wr)) { - post_nop_wqe(qp, ind, s << qp->sq.wqe_shift); - ind += s; - } - return ind; -} - -static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type) -{ - struct ib_event event; - struct ib_qp *ibqp = &to_mibqp(qp)->ibqp; - - if (type == MLX4_EVENT_TYPE_PATH_MIG) - to_mibqp(qp)->port = to_mibqp(qp)->alt_port; - - if (ibqp->event_handler) { - event.device = ibqp->device; - event.element.qp = ibqp; - switch (type) { - case MLX4_EVENT_TYPE_PATH_MIG: - event.event = IB_EVENT_PATH_MIG; - break; - case MLX4_EVENT_TYPE_COMM_EST: - event.event = IB_EVENT_COMM_EST; - break; - case MLX4_EVENT_TYPE_SQ_DRAINED: - event.event = IB_EVENT_SQ_DRAINED; - break; - case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: - event.event = IB_EVENT_QP_LAST_WQE_REACHED; - break; - case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: - event.event = IB_EVENT_QP_FATAL; - break; - case MLX4_EVENT_TYPE_PATH_MIG_FAILED: - event.event = IB_EVENT_PATH_MIG_ERR; - break; - case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: - event.event = IB_EVENT_QP_REQ_ERR; - break; - case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: - event.event = IB_EVENT_QP_ACCESS_ERR; - break; - default: - pr_warn("Unexpected event type %d " - "on QP %06x\n", type, qp->qpn); - return; - } - - ibqp->event_handler(&event, ibqp->qp_context); - } -} - -static int send_wqe_overhead(enum mlx4_ib_qp_type type, u32 flags) -{ - /* - * UD WQEs must have a datagram segment. - * RC and UC WQEs might have a remote address segment. - * MLX WQEs need two extra inline data segments (for the UD - * header and space for the ICRC). - */ - switch (type) { - case MLX4_IB_QPT_UD: - return sizeof (struct mlx4_wqe_ctrl_seg) + - sizeof (struct mlx4_wqe_datagram_seg) + - ((flags & MLX4_IB_QP_LSO) ? MLX4_IB_LSO_HEADER_SPARE : 0); - case MLX4_IB_QPT_PROXY_SMI_OWNER: - case MLX4_IB_QPT_PROXY_SMI: - case MLX4_IB_QPT_PROXY_GSI: - return sizeof (struct mlx4_wqe_ctrl_seg) + - sizeof (struct mlx4_wqe_datagram_seg) + 64; - case MLX4_IB_QPT_TUN_SMI_OWNER: - case MLX4_IB_QPT_TUN_GSI: - return sizeof (struct mlx4_wqe_ctrl_seg) + - sizeof (struct mlx4_wqe_datagram_seg); - - case MLX4_IB_QPT_UC: - return sizeof (struct mlx4_wqe_ctrl_seg) + - sizeof (struct mlx4_wqe_raddr_seg); - case MLX4_IB_QPT_RC: - return sizeof (struct mlx4_wqe_ctrl_seg) + - sizeof (struct mlx4_wqe_masked_atomic_seg) + - sizeof (struct mlx4_wqe_raddr_seg); - case MLX4_IB_QPT_SMI: - case MLX4_IB_QPT_GSI: - return sizeof (struct mlx4_wqe_ctrl_seg) + - ALIGN(MLX4_IB_UD_HEADER_SIZE + - DIV_ROUND_UP(MLX4_IB_UD_HEADER_SIZE, - MLX4_INLINE_ALIGN) * - sizeof (struct mlx4_wqe_inline_seg), - sizeof (struct mlx4_wqe_data_seg)) + - ALIGN(4 + - sizeof (struct mlx4_wqe_inline_seg), - sizeof (struct mlx4_wqe_data_seg)); - default: - return sizeof (struct mlx4_wqe_ctrl_seg); - } -} - -static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, - int is_user, int has_rq, struct mlx4_ib_qp *qp) -{ - /* Sanity check RQ size before proceeding */ - if (cap->max_recv_wr > dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE || - cap->max_recv_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg)) - return -EINVAL; - - if (!has_rq) { - if (cap->max_recv_wr) - return -EINVAL; - - qp->rq.wqe_cnt = qp->rq.max_gs = 0; - } else { - /* HW requires >= 1 RQ entry with >= 1 gather entry */ - if (is_user && (!cap->max_recv_wr || !cap->max_recv_sge)) - return -EINVAL; - - qp->rq.wqe_cnt = roundup_pow_of_two(max(1U, cap->max_recv_wr)); - qp->rq.max_gs = roundup_pow_of_two(max(1U, cap->max_recv_sge)); - qp->rq.wqe_shift = ilog2(qp->rq.max_gs * sizeof (struct mlx4_wqe_data_seg)); - } - - /* leave userspace return values as they were, so as not to break ABI */ - if (is_user) { - cap->max_recv_wr = qp->rq.max_post = qp->rq.wqe_cnt; - cap->max_recv_sge = qp->rq.max_gs; - } else { - cap->max_recv_wr = qp->rq.max_post = - min(dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE, qp->rq.wqe_cnt); - cap->max_recv_sge = min(qp->rq.max_gs, - min(dev->dev->caps.max_sq_sg, - dev->dev->caps.max_rq_sg)); - } - - return 0; -} - -static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, - enum mlx4_ib_qp_type type, struct mlx4_ib_qp *qp) -{ - int s; - - /* Sanity check SQ size before proceeding */ - if (cap->max_send_wr > (dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE) || - cap->max_send_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg) || - cap->max_inline_data + send_wqe_overhead(type, qp->flags) + - sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz) - return -EINVAL; - - /* - * For MLX transport we need 2 extra S/G entries: - * one for the header and one for the checksum at the end - */ - if ((type == MLX4_IB_QPT_SMI || type == MLX4_IB_QPT_GSI || - type & (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER)) && - cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg) - return -EINVAL; - - s = max(cap->max_send_sge * sizeof (struct mlx4_wqe_data_seg), - cap->max_inline_data + sizeof (struct mlx4_wqe_inline_seg)) + - send_wqe_overhead(type, qp->flags); - - if (s > dev->dev->caps.max_sq_desc_sz) - return -EINVAL; - - /* - * Hermon supports shrinking WQEs, such that a single work - * request can include multiple units of 1 << wqe_shift. This - * way, work requests can differ in size, and do not have to - * be a power of 2 in size, saving memory and speeding up send - * WR posting. Unfortunately, if we do this then the - * wqe_index field in CQEs can't be used to look up the WR ID - * anymore, so we do this only if selective signaling is off. - * - * Further, on 32-bit platforms, we can't use vmap() to make - * the QP buffer virtually contiguous. Thus we have to use - * constant-sized WRs to make sure a WR is always fully within - * a single page-sized chunk. - * - * Finally, we use NOP work requests to pad the end of the - * work queue, to avoid wrap-around in the middle of WR. We - * set NEC bit to avoid getting completions with error for - * these NOP WRs, but since NEC is only supported starting - * with firmware 2.2.232, we use constant-sized WRs for older - * firmware. - * - * And, since MLX QPs only support SEND, we use constant-sized - * WRs in this case. - * - * We look for the smallest value of wqe_shift such that the - * resulting number of wqes does not exceed device - * capabilities. - * - * We set WQE size to at least 64 bytes, this way stamping - * invalidates each WQE. - */ - if (dev->dev->caps.fw_ver >= MLX4_FW_VER_WQE_CTRL_NEC && - qp->sq_signal_bits && BITS_PER_LONG == 64 && - type != MLX4_IB_QPT_SMI && type != MLX4_IB_QPT_GSI && - !(type & (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_PROXY_SMI | - MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER))) - qp->sq.wqe_shift = ilog2(64); - else - qp->sq.wqe_shift = ilog2(roundup_pow_of_two(s)); - - for (;;) { - qp->sq_max_wqes_per_wr = DIV_ROUND_UP(s, 1U << qp->sq.wqe_shift); - - /* - * We need to leave 2 KB + 1 WR of headroom in the SQ to - * allow HW to prefetch. - */ - qp->sq_spare_wqes = (2048 >> qp->sq.wqe_shift) + qp->sq_max_wqes_per_wr; - qp->sq.wqe_cnt = roundup_pow_of_two(cap->max_send_wr * - qp->sq_max_wqes_per_wr + - qp->sq_spare_wqes); - - if (qp->sq.wqe_cnt <= dev->dev->caps.max_wqes) - break; - - if (qp->sq_max_wqes_per_wr <= 1) - return -EINVAL; - - ++qp->sq.wqe_shift; - } - - qp->sq.max_gs = (min(dev->dev->caps.max_sq_desc_sz, - (qp->sq_max_wqes_per_wr << qp->sq.wqe_shift)) - - send_wqe_overhead(type, qp->flags)) / - sizeof (struct mlx4_wqe_data_seg); - - qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + - (qp->sq.wqe_cnt << qp->sq.wqe_shift); - if (qp->rq.wqe_shift > qp->sq.wqe_shift) { - qp->rq.offset = 0; - qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; - } else { - qp->rq.offset = qp->sq.wqe_cnt << qp->sq.wqe_shift; - qp->sq.offset = 0; - } - - cap->max_send_wr = qp->sq.max_post = - (qp->sq.wqe_cnt - qp->sq_spare_wqes) / qp->sq_max_wqes_per_wr; - cap->max_send_sge = min(qp->sq.max_gs, - min(dev->dev->caps.max_sq_sg, - dev->dev->caps.max_rq_sg)); - qp->max_inline_data = cap->max_inline_data; - - return 0; -} - -static int set_user_sq_size(struct mlx4_ib_dev *dev, - struct mlx4_ib_qp *qp, - struct mlx4_ib_create_qp *ucmd) -{ - /* Sanity check SQ size before proceeding */ - if ((1 << ucmd->log_sq_bb_count) > dev->dev->caps.max_wqes || - ucmd->log_sq_stride > - ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) || - ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE) - return -EINVAL; - - qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count; - qp->sq.wqe_shift = ucmd->log_sq_stride; - - qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + - (qp->sq.wqe_cnt << qp->sq.wqe_shift); - - return 0; -} - -static int alloc_proxy_bufs(struct ib_device *dev, struct mlx4_ib_qp *qp) -{ - int i; - - qp->sqp_proxy_rcv = - kmalloc(sizeof (struct mlx4_ib_buf) * qp->rq.wqe_cnt, - GFP_KERNEL); - if (!qp->sqp_proxy_rcv) - return -ENOMEM; - for (i = 0; i < qp->rq.wqe_cnt; i++) { - qp->sqp_proxy_rcv[i].addr = - kmalloc(sizeof (struct mlx4_ib_proxy_sqp_hdr), - GFP_KERNEL); - if (!qp->sqp_proxy_rcv[i].addr) - goto err; - qp->sqp_proxy_rcv[i].map = - ib_dma_map_single(dev, qp->sqp_proxy_rcv[i].addr, - sizeof (struct mlx4_ib_proxy_sqp_hdr), - DMA_FROM_DEVICE); - if (unlikely(ib_dma_mapping_error(dev, - qp->sqp_proxy_rcv[i].map))) { - pr_warn("ib_dma_map_single failed\n"); - kfree(qp->sqp_proxy_rcv[i].addr); - goto err; - } - } - return 0; - -err: - while (i > 0) { - --i; - ib_dma_unmap_single(dev, qp->sqp_proxy_rcv[i].map, - sizeof (struct mlx4_ib_proxy_sqp_hdr), - DMA_FROM_DEVICE); - kfree(qp->sqp_proxy_rcv[i].addr); - } - kfree(qp->sqp_proxy_rcv); - qp->sqp_proxy_rcv = NULL; - return -ENOMEM; -} - -static void free_proxy_bufs(struct ib_device *dev, struct mlx4_ib_qp *qp) -{ - int i; - - for (i = 0; i < qp->rq.wqe_cnt; i++) { - ib_dma_unmap_single(dev, qp->sqp_proxy_rcv[i].map, - sizeof (struct mlx4_ib_proxy_sqp_hdr), - DMA_FROM_DEVICE); - kfree(qp->sqp_proxy_rcv[i].addr); - } - kfree(qp->sqp_proxy_rcv); -} - -static int init_qpg_parent(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *pqp, - struct ib_qp_init_attr *attr, int *qpn) -{ - struct mlx4_ib_qpg_data *qpg_data; - int tss_num, rss_num; - int tss_align_num, rss_align_num; - int tss_base, rss_base = 0; - int err; - - /* Parent is part of the TSS range (in SW TSS ARP is sent via parent) */ - tss_num = 1 + attr->parent_attrib.tss_child_count; - tss_align_num = roundup_pow_of_two(tss_num); - rss_num = attr->parent_attrib.rss_child_count; - rss_align_num = roundup_pow_of_two(rss_num); - - if (rss_num > 1) { - /* RSS is requested */ - if (!(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS)) - return -ENOSYS; - if (rss_align_num > dev->dev->caps.max_rss_tbl_sz) - return -EINVAL; - /* We must work with power of two */ - attr->parent_attrib.rss_child_count = rss_align_num; - } - - qpg_data = kzalloc(sizeof *qpg_data, GFP_KERNEL); - if (!qpg_data) - return -ENOMEM; - - if(pqp->flags & MLX4_IB_QP_NETIF) - err = mlx4_ib_steer_qp_alloc(dev, tss_align_num, &tss_base); - else - err = mlx4_qp_reserve_range(dev->dev, tss_align_num, - tss_align_num, &tss_base, MLX4_RESERVE_BF_QP); - if (err) - goto err1; - - if (tss_num > 1) { - u32 alloc = BITS_TO_LONGS(tss_align_num) * sizeof(long); - qpg_data->tss_bitmap = kzalloc(alloc, GFP_KERNEL); - if (qpg_data->tss_bitmap == NULL) { - err = -ENOMEM; - goto err2; - } - bitmap_fill(qpg_data->tss_bitmap, tss_num); - /* Note parent takes first index */ - clear_bit(0, qpg_data->tss_bitmap); - } - - if (rss_num > 1) { - u32 alloc = BITS_TO_LONGS(rss_align_num) * sizeof(long); - err = mlx4_qp_reserve_range(dev->dev, rss_align_num, - 1, &rss_base, 0); - if (err) - goto err3; - qpg_data->rss_bitmap = kzalloc(alloc, GFP_KERNEL); - if (qpg_data->rss_bitmap == NULL) { - err = -ENOMEM; - goto err4; - } - bitmap_fill(qpg_data->rss_bitmap, rss_align_num); - } - - qpg_data->tss_child_count = attr->parent_attrib.tss_child_count; - qpg_data->rss_child_count = attr->parent_attrib.rss_child_count; - qpg_data->qpg_parent = pqp; - qpg_data->qpg_tss_mask_sz = ilog2(tss_align_num); - qpg_data->tss_qpn_base = tss_base; - qpg_data->rss_qpn_base = rss_base; - - pqp->qpg_data = qpg_data; - *qpn = tss_base; - - return 0; - -err4: - mlx4_qp_release_range(dev->dev, rss_base, rss_align_num); - -err3: - if (tss_num > 1) - kfree(qpg_data->tss_bitmap); - -err2: - if(pqp->flags & MLX4_IB_QP_NETIF) - mlx4_ib_steer_qp_free(dev, tss_base, tss_align_num); - else - mlx4_qp_release_range(dev->dev, tss_base, tss_align_num); - -err1: - kfree(qpg_data); - return err; -} - -static void free_qpg_parent(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *pqp) -{ - struct mlx4_ib_qpg_data *qpg_data = pqp->qpg_data; - int align_num; - - if (qpg_data->tss_child_count > 1) - kfree(qpg_data->tss_bitmap); - - align_num = roundup_pow_of_two(1 + qpg_data->tss_child_count); - if(pqp->flags & MLX4_IB_QP_NETIF) - mlx4_ib_steer_qp_free(dev, qpg_data->tss_qpn_base, align_num); - else - mlx4_qp_release_range(dev->dev, qpg_data->tss_qpn_base, align_num); - - if (qpg_data->rss_child_count > 1) { - kfree(qpg_data->rss_bitmap); - align_num = roundup_pow_of_two(qpg_data->rss_child_count); - mlx4_qp_release_range(dev->dev, qpg_data->rss_qpn_base, - align_num); - } - - kfree(qpg_data); -} - -static int alloc_qpg_qpn(struct ib_qp_init_attr *init_attr, - struct mlx4_ib_qp *pqp, int *qpn) -{ - struct mlx4_ib_qp *mqp = to_mqp(init_attr->qpg_parent); - struct mlx4_ib_qpg_data *qpg_data = mqp->qpg_data; - u32 idx, old; - - switch (init_attr->qpg_type) { - case IB_QPG_CHILD_TX: - if (qpg_data->tss_child_count == 0) - return -EINVAL; - do { - /* Parent took index 0 */ - idx = find_first_bit(qpg_data->tss_bitmap, - qpg_data->tss_child_count + 1); - if (idx >= qpg_data->tss_child_count + 1) - return -ENOMEM; - old = test_and_clear_bit(idx, qpg_data->tss_bitmap); - } while (old == 0); - idx += qpg_data->tss_qpn_base; - break; - case IB_QPG_CHILD_RX: - if (qpg_data->rss_child_count == 0) - return -EINVAL; - do { - idx = find_first_bit(qpg_data->rss_bitmap, - qpg_data->rss_child_count); - if (idx >= qpg_data->rss_child_count) - return -ENOMEM; - old = test_and_clear_bit(idx, qpg_data->rss_bitmap); - } while (old == 0); - idx += qpg_data->rss_qpn_base; - break; - default: - return -EINVAL; - } - - pqp->qpg_data = qpg_data; - *qpn = idx; - - return 0; -} - -static void free_qpg_qpn(struct mlx4_ib_qp *mqp, int qpn) -{ - struct mlx4_ib_qpg_data *qpg_data = mqp->qpg_data; - - switch (mqp->qpg_type) { - case IB_QPG_CHILD_TX: - /* Do range check */ - qpn -= qpg_data->tss_qpn_base; - set_bit(qpn, qpg_data->tss_bitmap); - break; - case IB_QPG_CHILD_RX: - qpn -= qpg_data->rss_qpn_base; - set_bit(qpn, qpg_data->rss_bitmap); - break; - default: - /* error */ - pr_warn("wrong qpg type (%d)\n", mqp->qpg_type); - break; - } -} - -static int alloc_qpn_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, - struct ib_qp_init_attr *attr, int *qpn) -{ - int err = 0; - - switch (attr->qpg_type) { - case IB_QPG_NONE: - /* Raw packet QPNs may not have bits 6,7 set in their qp_num; - * otherwise, the WQE BlueFlame setup flow wrongly causes - * VLAN insertion. */ - if (attr->qp_type == IB_QPT_RAW_PACKET) { - err = mlx4_qp_reserve_range(dev->dev, 1, 1, qpn, - MLX4_RESERVE_BF_QP); - } else { - if(qp->flags & MLX4_IB_QP_NETIF) - err = mlx4_ib_steer_qp_alloc(dev, 1, qpn); - else - err = mlx4_qp_reserve_range(dev->dev, 1, 1, qpn, 0); - } - break; - case IB_QPG_PARENT: - err = init_qpg_parent(dev, qp, attr, qpn); - break; - case IB_QPG_CHILD_TX: - case IB_QPG_CHILD_RX: - err = alloc_qpg_qpn(attr, qp, qpn); - break; - default: - qp->qpg_type = IB_QPG_NONE; - err = -EINVAL; - break; - } - if (err) - return err; - qp->qpg_type = attr->qpg_type; - return 0; -} - -static void free_qpn_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, - enum ib_qpg_type qpg_type, int qpn) -{ - switch (qpg_type) { - case IB_QPG_NONE: - if (qp->flags & MLX4_IB_QP_NETIF) - mlx4_ib_steer_qp_free(dev, qpn, 1); - else - mlx4_qp_release_range(dev->dev, qpn, 1); - break; - case IB_QPG_PARENT: - free_qpg_parent(dev, qp); - break; - case IB_QPG_CHILD_TX: - case IB_QPG_CHILD_RX: - free_qpg_qpn(qp, qpn); - break; - default: - break; - } -} - -/* Revert allocation on create_qp_common */ -static void unalloc_qpn_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, - struct ib_qp_init_attr *attr, int qpn) -{ - free_qpn_common(dev, qp, attr->qpg_type, qpn); -} - -static void release_qpn_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) -{ - free_qpn_common(dev, qp, qp->qpg_type, qp->mqp.qpn); -} - -static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, - struct ib_qp_init_attr *init_attr, - struct ib_udata *udata, int sqpn, struct mlx4_ib_qp **caller_qp) -{ - int qpn; - int err; - struct mlx4_ib_sqp *sqp; - struct mlx4_ib_qp *qp; - enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type; - - /* When tunneling special qps, we use a plain UD qp */ - if (sqpn) { - if (mlx4_is_mfunc(dev->dev) && - (!mlx4_is_master(dev->dev) || - !(init_attr->create_flags & MLX4_IB_SRIOV_SQP))) { - if (init_attr->qp_type == IB_QPT_GSI) - qp_type = MLX4_IB_QPT_PROXY_GSI; - else if (mlx4_is_master(dev->dev)) - qp_type = MLX4_IB_QPT_PROXY_SMI_OWNER; - else - qp_type = MLX4_IB_QPT_PROXY_SMI; - } - qpn = sqpn; - /* add extra sg entry for tunneling */ - init_attr->cap.max_recv_sge++; - } else if (init_attr->create_flags & MLX4_IB_SRIOV_TUNNEL_QP) { - struct mlx4_ib_qp_tunnel_init_attr *tnl_init = - container_of(init_attr, - struct mlx4_ib_qp_tunnel_init_attr, init_attr); - if ((tnl_init->proxy_qp_type != IB_QPT_SMI && - tnl_init->proxy_qp_type != IB_QPT_GSI) || - !mlx4_is_master(dev->dev)) - return -EINVAL; - if (tnl_init->proxy_qp_type == IB_QPT_GSI) - qp_type = MLX4_IB_QPT_TUN_GSI; - else if (tnl_init->slave == mlx4_master_func_num(dev->dev)) - qp_type = MLX4_IB_QPT_TUN_SMI_OWNER; - else - qp_type = MLX4_IB_QPT_TUN_SMI; - /* we are definitely in the PPF here, since we are creating - * tunnel QPs. base_tunnel_sqpn is therefore valid. */ - qpn = dev->dev->phys_caps.base_tunnel_sqpn + 8 * tnl_init->slave - + tnl_init->proxy_qp_type * 2 + tnl_init->port - 1; - sqpn = qpn; - } - - if (!*caller_qp) { - if (qp_type == MLX4_IB_QPT_SMI || qp_type == MLX4_IB_QPT_GSI || - (qp_type & (MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_SMI_OWNER | - MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER))) { - sqp = kzalloc(sizeof (struct mlx4_ib_sqp), GFP_KERNEL); - if (!sqp) - return -ENOMEM; - qp = &sqp->qp; - qp->pri.vid = qp->alt.vid = 0xFFFF; - } else { - qp = kzalloc(sizeof (struct mlx4_ib_qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - qp->pri.vid = qp->alt.vid = 0xFFFF; - } - } else - qp = *caller_qp; - - qp->mlx4_ib_qp_type = qp_type; - - if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) - qp->flags |= MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK; - - if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) - qp->flags |= MLX4_IB_QP_LSO; - - if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) { - if (dev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED && - !mlx4_is_mfunc(dev->dev)) - qp->flags |= MLX4_IB_QP_NETIF; - else { - err = -EINVAL; - goto err; - } - } - - mutex_init(&qp->mutex); - spin_lock_init(&qp->sq.lock); - spin_lock_init(&qp->rq.lock); - INIT_LIST_HEAD(&qp->gid_list); - INIT_LIST_HEAD(&qp->steering_rules); - INIT_LIST_HEAD(&qp->rules_list); - - qp->state = IB_QPS_RESET; - if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) - qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); - - err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, mlx4_ib_qp_has_rq(init_attr), qp); - if (err) - goto err; - - if (pd->uobject) { - struct mlx4_ib_create_qp ucmd; - int shift; - int n; - - if (!udata || ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { - err = -EFAULT; - goto err; - } - - if (init_attr->create_flags & IB_QP_CREATE_CROSS_CHANNEL) - qp->flags |= MLX4_IB_QP_CAP_CROSS_CHANNEL; - - if (init_attr->create_flags & IB_QP_CREATE_MANAGED_SEND) - qp->flags |= MLX4_IB_QP_CAP_MANAGED_SEND; - - if (init_attr->create_flags & IB_QP_CREATE_MANAGED_RECV) - qp->flags |= MLX4_IB_QP_CAP_MANAGED_RECV; - - qp->sq_no_prefetch = ucmd.sq_no_prefetch; - - err = set_user_sq_size(dev, qp, &ucmd); - if (err) - goto err; - - qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - qp->buf_size, 0, 0); - if (IS_ERR(qp->umem)) { - err = PTR_ERR(qp->umem); - goto err; - } - - n = ib_umem_page_count(qp->umem); - shift = mlx4_ib_umem_calc_optimal_mtt_size(qp->umem, 0, &n); - err = mlx4_mtt_init(dev->dev, n, shift, &qp->mtt); - - if (err) - goto err_buf; - - err = mlx4_ib_umem_write_mtt(dev, &qp->mtt, qp->umem); - if (err) - goto err_mtt; - - if (mlx4_ib_qp_has_rq(init_attr)) { - err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context), - ucmd.db_addr, &qp->db); - if (err) - goto err_mtt; - } - } else { - qp->sq_no_prefetch = 0; - - err = set_kernel_sq_size(dev, &init_attr->cap, qp_type, qp); - if (err) - goto err; - - if (mlx4_ib_qp_has_rq(init_attr)) { - err = mlx4_db_alloc(dev->dev, &qp->db, 0); - if (err) - goto err; - - *qp->db.db = 0; - } - - if (qp->max_inline_data) { - err = mlx4_bf_alloc(dev->dev, &qp->bf, 0); - if (err) { - pr_debug("failed to allocate blue flame" - " register (%d)", err); - qp->bf.uar = &dev->priv_uar; - } - } else - qp->bf.uar = &dev->priv_uar; - - if (mlx4_buf_alloc(dev->dev, qp->buf_size, PAGE_SIZE * 2, &qp->buf)) { - err = -ENOMEM; - goto err_db; - } - - err = mlx4_mtt_init(dev->dev, qp->buf.npages, qp->buf.page_shift, - &qp->mtt); - if (err) - goto err_buf; - - err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf); - if (err) - goto err_mtt; - - qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof (u64), GFP_KERNEL); - qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof (u64), GFP_KERNEL); - - if (!qp->sq.wrid || !qp->rq.wrid) { - err = -ENOMEM; - goto err_wrid; - } - } - - if (sqpn) { - if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER | - MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) { - if (alloc_proxy_bufs(pd->device, qp)) { - err = -ENOMEM; - goto err_wrid; - } - } - } else { - err = alloc_qpn_common(dev, qp, init_attr, &qpn); - if (err) - goto err_proxy; - } - - err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp); - if (err) - goto err_qpn; - - if (init_attr->qp_type == IB_QPT_XRC_TGT) - qp->mqp.qpn |= (1 << 23); - - /* - * Hardware wants QPN written in big-endian order (after - * shifting) for send doorbell. Precompute this value to save - * a little bit when posting sends. - */ - qp->doorbell_qpn = swab32(qp->mqp.qpn << 8); - - qp->mqp.event = mlx4_ib_qp_event; - if (!*caller_qp) - *caller_qp = qp; - return 0; - -err_qpn: - unalloc_qpn_common(dev, qp, init_attr, qpn); - -err_proxy: - if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI) - free_proxy_bufs(pd->device, qp); -err_wrid: - if (pd->uobject) { - if (mlx4_ib_qp_has_rq(init_attr)) - mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db); - } else { - kfree(qp->sq.wrid); - kfree(qp->rq.wrid); - } - -err_mtt: - mlx4_mtt_cleanup(dev->dev, &qp->mtt); - -err_buf: - if (pd->uobject) - ib_umem_release(qp->umem); - else - mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); - -err_db: - if (!pd->uobject && mlx4_ib_qp_has_rq(init_attr)) - mlx4_db_free(dev->dev, &qp->db); - - if (qp->max_inline_data) - mlx4_bf_free(dev->dev, &qp->bf); - -err: - if (!*caller_qp) - kfree(qp); - return err; -} - -static enum mlx4_qp_state to_mlx4_state(enum ib_qp_state state) -{ - switch (state) { - case IB_QPS_RESET: return MLX4_QP_STATE_RST; - case IB_QPS_INIT: return MLX4_QP_STATE_INIT; - case IB_QPS_RTR: return MLX4_QP_STATE_RTR; - case IB_QPS_RTS: return MLX4_QP_STATE_RTS; - case IB_QPS_SQD: return MLX4_QP_STATE_SQD; - case IB_QPS_SQE: return MLX4_QP_STATE_SQER; - case IB_QPS_ERR: return MLX4_QP_STATE_ERR; - default: return -1; - } -} - -static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) - __acquires(&send_cq->lock) __acquires(&recv_cq->lock) -{ - if (send_cq == recv_cq) { - spin_lock_irq(&send_cq->lock); - __acquire(&recv_cq->lock); - } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { - spin_lock_irq(&send_cq->lock); - spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); - } else { - spin_lock_irq(&recv_cq->lock); - spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); - } -} - -static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) - __releases(&send_cq->lock) __releases(&recv_cq->lock) -{ - if (send_cq == recv_cq) { - __release(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); - } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { - spin_unlock(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); - } else { - spin_unlock(&send_cq->lock); - spin_unlock_irq(&recv_cq->lock); - } -} - -static void del_gid_entries(struct mlx4_ib_qp *qp) -{ - struct mlx4_ib_gid_entry *ge, *tmp; - - list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) { - list_del(&ge->list); - kfree(ge); - } -} - -static struct mlx4_ib_pd *get_pd(struct mlx4_ib_qp *qp) -{ - if (qp->ibqp.qp_type == IB_QPT_XRC_TGT) - return to_mpd(to_mxrcd(qp->ibqp.xrcd)->pd); - else - return to_mpd(qp->ibqp.pd); -} - -static void get_cqs(struct mlx4_ib_qp *qp, - struct mlx4_ib_cq **send_cq, struct mlx4_ib_cq **recv_cq) -{ - switch (qp->ibqp.qp_type) { - case IB_QPT_XRC_TGT: - *send_cq = to_mcq(to_mxrcd(qp->ibqp.xrcd)->cq); - *recv_cq = *send_cq; - break; - case IB_QPT_XRC_INI: - *send_cq = to_mcq(qp->ibqp.send_cq); - *recv_cq = *send_cq; - break; - default: - *send_cq = to_mcq(qp->ibqp.send_cq); - *recv_cq = to_mcq(qp->ibqp.recv_cq); - break; - } -} - -static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, - int is_user) -{ - struct mlx4_ib_cq *send_cq, *recv_cq; - - if (qp->state != IB_QPS_RESET) { - if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), - MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp)) - pr_warn("modify QP %06x to RESET failed.\n", - qp->mqp.qpn); - if (qp->pri.smac) { - mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); - qp->pri.smac = 0; - } - if (qp->alt.smac) { - mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); - qp->alt.smac = 0; - } - if (qp->pri.vid < 0x1000) { - mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid); - qp->pri.vid = 0xFFFF; - qp->pri.candidate_vid = 0xFFFF; - qp->pri.update_vid = 0; - } - if (qp->alt.vid < 0x1000) { - mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid); - qp->alt.vid = 0xFFFF; - qp->alt.candidate_vid = 0xFFFF; - qp->alt.update_vid = 0; - } - } - - get_cqs(qp, &send_cq, &recv_cq); - - mlx4_ib_lock_cqs(send_cq, recv_cq); - - if (!is_user) { - __mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, - qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL); - if (send_cq != recv_cq) - __mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); - } - - mlx4_qp_remove(dev->dev, &qp->mqp); - - mlx4_ib_unlock_cqs(send_cq, recv_cq); - - mlx4_qp_free(dev->dev, &qp->mqp); - - if (!is_sqp(dev, qp) && !is_tunnel_qp(dev, qp)) - release_qpn_common(dev, qp); - - mlx4_mtt_cleanup(dev->dev, &qp->mtt); - - if (is_user) { - if (qp->rq.wqe_cnt) - mlx4_ib_db_unmap_user(to_mucontext(qp->ibqp.uobject->context), - &qp->db); - ib_umem_release(qp->umem); - } else { - kfree(qp->sq.wrid); - kfree(qp->rq.wrid); - if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER | - MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) - free_proxy_bufs(&dev->ib_dev, qp); - mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); - if (qp->max_inline_data) - mlx4_bf_free(dev->dev, &qp->bf); - - if (qp->rq.wqe_cnt) - mlx4_db_free(dev->dev, &qp->db); - } - - del_gid_entries(qp); -} - -static u32 get_sqp_num(struct mlx4_ib_dev *dev, struct ib_qp_init_attr *attr) -{ - /* Native or PPF */ - if (!mlx4_is_mfunc(dev->dev) || - (mlx4_is_master(dev->dev) && - attr->create_flags & MLX4_IB_SRIOV_SQP)) { - return dev->dev->phys_caps.base_sqpn + - (attr->qp_type == IB_QPT_SMI ? 0 : 2) + - attr->port_num - 1; - } - /* PF or VF -- creating proxies */ - if (attr->qp_type == IB_QPT_SMI) - return dev->dev->caps.qp0_proxy[attr->port_num - 1]; - else - return dev->dev->caps.qp1_proxy[attr->port_num - 1]; -} - -static int check_qpg_attr(struct mlx4_ib_dev *dev, - struct ib_qp_init_attr *attr) -{ - if (attr->qpg_type == IB_QPG_NONE) - return 0; - - if (attr->qp_type != IB_QPT_UD && - attr->qp_type != IB_QPT_RAW_PACKET) - return -EINVAL; - - if (attr->qpg_type == IB_QPG_PARENT) { - if (attr->parent_attrib.tss_child_count == 1) - return -EINVAL; /* Doesn't make sense */ - if (attr->parent_attrib.rss_child_count == 1) - return -EINVAL; /* Doesn't make sense */ - if ((attr->parent_attrib.tss_child_count == 0) && - (attr->parent_attrib.rss_child_count == 0)) - /* Should be called with IP_QPG_NONE */ - return -EINVAL; - if (attr->parent_attrib.rss_child_count > 1) { - int rss_align_num; - if (!(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS)) - return -ENOSYS; - rss_align_num = roundup_pow_of_two( - attr->parent_attrib.rss_child_count); - if (rss_align_num > dev->dev->caps.max_rss_tbl_sz) - return -EINVAL; - } - } else { - struct mlx4_ib_qpg_data *qpg_data; - if (attr->qpg_parent == NULL) - return -EINVAL; - if (IS_ERR(attr->qpg_parent)) - return -EINVAL; - qpg_data = to_mqp(attr->qpg_parent)->qpg_data; - if (qpg_data == NULL) - return -EINVAL; - if (attr->qpg_type == IB_QPG_CHILD_TX && - !qpg_data->tss_child_count) - return -EINVAL; - if (attr->qpg_type == IB_QPG_CHILD_RX && - !qpg_data->rss_child_count) - return -EINVAL; - } - return 0; -} - -#define RESERVED_FLAGS_MASK ((((unsigned int)IB_QP_CREATE_RESERVED_END - 1) | IB_QP_CREATE_RESERVED_END) \ - & ~(IB_QP_CREATE_RESERVED_START - 1)) - -static enum mlx4_ib_qp_flags to_mlx4_ib_qp_flags(enum ib_qp_create_flags ib_qp_flags) -{ - enum mlx4_ib_qp_flags mlx4_ib_qp_flags = 0; - - if (ib_qp_flags & IB_QP_CREATE_IPOIB_UD_LSO) - mlx4_ib_qp_flags |= MLX4_IB_QP_LSO; - - if (ib_qp_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) - mlx4_ib_qp_flags |= MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK; - - if (ib_qp_flags & IB_QP_CREATE_NETIF_QP) - mlx4_ib_qp_flags |= MLX4_IB_QP_NETIF; - - if (ib_qp_flags & IB_QP_CREATE_CROSS_CHANNEL) - mlx4_ib_qp_flags |= MLX4_IB_QP_CAP_CROSS_CHANNEL; - - if (ib_qp_flags & IB_QP_CREATE_MANAGED_SEND) - mlx4_ib_qp_flags |= MLX4_IB_QP_CAP_MANAGED_SEND; - - if (ib_qp_flags & IB_QP_CREATE_MANAGED_RECV) - mlx4_ib_qp_flags |= MLX4_IB_QP_CAP_MANAGED_RECV; - - /* reserved flags */ - mlx4_ib_qp_flags |= (ib_qp_flags & RESERVED_FLAGS_MASK); - - return mlx4_ib_qp_flags; -} - -struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, - struct ib_qp_init_attr *init_attr, - struct ib_udata *udata) -{ - struct mlx4_ib_qp *qp = NULL; - int err; - u16 xrcdn = 0; - enum mlx4_ib_qp_flags mlx4_qp_flags = to_mlx4_ib_qp_flags(init_attr->create_flags); - struct ib_device *device; - - /* see ib_core::ib_create_qp same handling */ - device = pd ? pd->device : init_attr->xrcd->device; - /* - * We only support LSO, vendor flag1, and multicast loopback blocking, - * and only for kernel UD QPs. - */ - if (mlx4_qp_flags & ~(MLX4_IB_QP_LSO | - MLX4_IB_QP_CAP_CROSS_CHANNEL | - MLX4_IB_QP_CAP_MANAGED_SEND | - MLX4_IB_QP_CAP_MANAGED_RECV | - MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK | - MLX4_IB_SRIOV_TUNNEL_QP | MLX4_IB_SRIOV_SQP | - MLX4_IB_QP_NETIF)) - return ERR_PTR(-EINVAL); - - if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) { - if (init_attr->qp_type != IB_QPT_UD) - return ERR_PTR(-EINVAL); - } - - if ((mlx4_qp_flags & - (MLX4_IB_QP_CAP_CROSS_CHANNEL | - MLX4_IB_QP_CAP_MANAGED_SEND | - MLX4_IB_QP_CAP_MANAGED_RECV)) && - !(to_mdev(device)->dev->caps.flags & - MLX4_DEV_CAP_FLAG_CROSS_CHANNEL)) { - pr_debug("%s Does not support cross-channel operations\n", - to_mdev(device)->ib_dev.name); - return ERR_PTR(-EINVAL); - } - - if ((init_attr->create_flags & - ~(IB_QP_CREATE_CROSS_CHANNEL | - IB_QP_CREATE_MANAGED_SEND | - IB_QP_CREATE_MANAGED_RECV)) && - (((mlx4_qp_flags & ~MLX4_IB_SRIOV_SQP) && - init_attr->qp_type != IB_QPT_UD) || - ((mlx4_qp_flags & MLX4_IB_SRIOV_SQP) && - init_attr->qp_type > IB_QPT_GSI))) - return ERR_PTR(-EINVAL); - - err = check_qpg_attr(to_mdev(device), init_attr); - if (err) - return ERR_PTR(err); - - switch (init_attr->qp_type) { - case IB_QPT_XRC_TGT: - pd = to_mxrcd(init_attr->xrcd)->pd; - xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn; - init_attr->send_cq = to_mxrcd(init_attr->xrcd)->cq; - /* fall through */ - case IB_QPT_XRC_INI: - if (!(to_mdev(device)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)) - return ERR_PTR(-ENOSYS); - init_attr->recv_cq = init_attr->send_cq; - /* fall through */ - case IB_QPT_RC: - case IB_QPT_UC: - case IB_QPT_RAW_PACKET: - qp = kzalloc(sizeof *qp, GFP_KERNEL); - if (!qp) - return ERR_PTR(-ENOMEM); - qp->pri.vid = qp->alt.vid = 0xFFFF; - /* fall through */ - case IB_QPT_UD: - { - err = create_qp_common(to_mdev(device), pd, init_attr, udata, 0, &qp); - if (err) { - kfree(qp); - return ERR_PTR(err); - } - - qp->ibqp.qp_num = qp->mqp.qpn; - qp->xrcdn = xrcdn; - - break; - } - case IB_QPT_SMI: - case IB_QPT_GSI: - { - /* Userspace is not allowed to create special QPs: */ - if (udata) - return ERR_PTR(-EINVAL); - - err = create_qp_common(to_mdev(device), pd, init_attr, udata, - get_sqp_num(to_mdev(device), init_attr), - &qp); - if (err) - return ERR_PTR(err); - - qp->port = init_attr->port_num; - qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; - - break; - } - default: - /* Don't support raw QPs */ - return ERR_PTR(-EINVAL); - } - - return &qp->ibqp; -} - -int mlx4_ib_destroy_qp(struct ib_qp *qp) -{ - struct mlx4_ib_dev *dev = to_mdev(qp->device); - struct mlx4_ib_qp *mqp = to_mqp(qp); - struct mlx4_ib_pd *pd; - - if (is_qp0(dev, mqp)) - mlx4_CLOSE_PORT(dev->dev, mqp->port); - - pd = get_pd(mqp); - destroy_qp_common(dev, mqp, !!pd->ibpd.uobject); - - if (is_sqp(dev, mqp)) - kfree(to_msqp(mqp)); - else - kfree(mqp); - - return 0; -} - -static int to_mlx4_st(struct mlx4_ib_dev *dev, enum mlx4_ib_qp_type type) -{ - switch (type) { - case MLX4_IB_QPT_RC: return MLX4_QP_ST_RC; - case MLX4_IB_QPT_UC: return MLX4_QP_ST_UC; - case MLX4_IB_QPT_UD: return MLX4_QP_ST_UD; - case MLX4_IB_QPT_XRC_INI: - case MLX4_IB_QPT_XRC_TGT: return MLX4_QP_ST_XRC; - case MLX4_IB_QPT_SMI: - case MLX4_IB_QPT_GSI: - case MLX4_IB_QPT_RAW_PACKET: return MLX4_QP_ST_MLX; - - case MLX4_IB_QPT_PROXY_SMI_OWNER: - case MLX4_IB_QPT_TUN_SMI_OWNER: return (mlx4_is_mfunc(dev->dev) ? - MLX4_QP_ST_MLX : -1); - case MLX4_IB_QPT_PROXY_SMI: - case MLX4_IB_QPT_TUN_SMI: - case MLX4_IB_QPT_PROXY_GSI: - case MLX4_IB_QPT_TUN_GSI: return (mlx4_is_mfunc(dev->dev) ? - MLX4_QP_ST_UD : -1); - default: return -1; - } -} - -static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, const struct ib_qp_attr *attr, - int attr_mask) -{ - u8 dest_rd_atomic; - u32 access_flags; - u32 hw_access_flags = 0; - - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) - dest_rd_atomic = attr->max_dest_rd_atomic; - else - dest_rd_atomic = qp->resp_depth; - - if (attr_mask & IB_QP_ACCESS_FLAGS) - access_flags = attr->qp_access_flags; - else - access_flags = qp->atomic_rd_en; - - if (!dest_rd_atomic) - access_flags &= IB_ACCESS_REMOTE_WRITE; - - if (access_flags & IB_ACCESS_REMOTE_READ) - hw_access_flags |= MLX4_QP_BIT_RRE; - if (access_flags & IB_ACCESS_REMOTE_ATOMIC) - hw_access_flags |= MLX4_QP_BIT_RAE; - if (access_flags & IB_ACCESS_REMOTE_WRITE) - hw_access_flags |= MLX4_QP_BIT_RWE; - - return cpu_to_be32(hw_access_flags); -} - -static void store_sqp_attrs(struct mlx4_ib_sqp *sqp, const struct ib_qp_attr *attr, - int attr_mask) -{ - if (attr_mask & IB_QP_PKEY_INDEX) - sqp->pkey_index = attr->pkey_index; - if (attr_mask & IB_QP_QKEY) - sqp->qkey = attr->qkey; - if (attr_mask & IB_QP_SQ_PSN) - sqp->send_psn = attr->sq_psn; -} - -static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port) -{ - path->sched_queue = (path->sched_queue & 0xbf) | ((port - 1) << 6); -} - -static int ib_rate_to_mlx4(struct mlx4_ib_dev *dev, u8 rate) -{ - if (rate == IB_RATE_PORT_CURRENT) { - return 0; - } else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) { - return -EINVAL; - } else { - while (rate != IB_RATE_2_5_GBPS && - !(1 << (rate + MLX4_STAT_RATE_OFFSET) & - dev->dev->caps.stat_rate_support)) - --rate; - } - - return rate + MLX4_STAT_RATE_OFFSET; -} - -static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, - u8 *smac, u16 vlan_id, struct mlx4_ib_qp *qp, - struct mlx4_qp_path *path, u8 port, int is_primary) -{ - int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) == - IB_LINK_LAYER_ETHERNET; - u16 vlan_tag; - int vidx; - int smac_index; - int err; - u64 u64_mac; - struct mlx4_roce_smac_vlan_info *smac_info; - - path->grh_mylmc = ah->src_path_bits & 0x7f; - path->rlid = cpu_to_be16(ah->dlid); - - err = ib_rate_to_mlx4(dev, ah->static_rate); - if (err < 0) - return err; - path->static_rate = err; - - if (ah->ah_flags & IB_AH_GRH) { - if (ah->grh.sgid_index >= dev->dev->caps.gid_table_len[port]) { - pr_err("sgid_index (%u) too large. max is %d\n", - ah->grh.sgid_index, dev->dev->caps.gid_table_len[port] - 1); - return -1; - } - - path->grh_mylmc |= 1 << 7; - path->mgid_index = ah->grh.sgid_index; - path->hop_limit = ah->grh.hop_limit; - path->tclass_flowlabel = - cpu_to_be32((ah->grh.traffic_class << 20) | - (ah->grh.flow_label)); - memcpy(path->rgid, ah->grh.dgid.raw, 16); - } - - if (is_eth) { - if (!(ah->ah_flags & IB_AH_GRH)) - return -1; - - path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | - ((port - 1) << 6) | ((ah->sl & 7) << 3); - - if (is_primary) - smac_info = &qp->pri; - else - smac_info = &qp->alt; - - vlan_tag = vlan_id; - if (vlan_tag < 0x1000) { - if (smac_info->vid < 0x1000) { - /* both valid vlan ids */ - if (smac_info->vid != vlan_tag) { - /* different VIDs. unreg old and reg new */ - err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx); - if (err) - return err; - smac_info->candidate_vid = vlan_tag; - smac_info->candidate_vlan_index = vidx; - smac_info->candidate_vlan_port = port; - smac_info->update_vid = 1; - path->vlan_index = vidx; - path->fl = 1 << 6; - } else { - path->vlan_index = smac_info->vlan_index; - path->fl = 1 << 6; - } - } else { - /* no current vlan tag in qp */ - err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx); - if (err) - return err; - smac_info->candidate_vid = vlan_tag; - smac_info->candidate_vlan_index = vidx; - smac_info->candidate_vlan_port = port; - smac_info->update_vid = 1; - path->vlan_index = vidx; - path->fl = 1 << 6; - } - } else { - /* have current vlan tag. unregister it at modify-qp success */ - if (smac_info->vid < 0x1000) { - smac_info->candidate_vid = 0xFFFF; - smac_info->update_vid = 1; - } - } - - - /* get smac_index for RoCE use. - * If no smac was yet assigned, register one. - * If one was already assigned, but the new mac differs, - * unregister the old one and register the new one. - */ - u64_mac = mlx4_mac_to_u64(smac); - - if (!smac_info->smac || smac_info->smac != u64_mac) { - /* register candidate now, unreg if needed, after success */ - smac_index = mlx4_register_mac(dev->dev, port, u64_mac); - if (smac_index >= 0) { - smac_info->candidate_smac_index = smac_index; - smac_info->candidate_smac = u64_mac; - smac_info->candidate_smac_port = port; - } else - return -EINVAL; - } else - smac_index = smac_info->smac_index; - - memcpy(path->dmac, ah->dmac, 6); - path->ackto = MLX4_IB_LINK_TYPE_ETH; - /* put MAC table smac index for IBoE */ - path->grh_mylmc = (u8) (smac_index) | 0x80 ; - - } else - path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | - ((port - 1) << 6) | ((ah->sl & 0xf) << 2); - - return 0; -} - -static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) -{ - struct mlx4_ib_gid_entry *ge, *tmp; - - list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) { - if (!ge->added && mlx4_ib_add_mc(dev, qp, &ge->gid)) { - ge->added = 1; - ge->port = qp->port; - } - } -} - -static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, const u8 *smac, - struct mlx4_qp_context *context) -{ - struct net_device *ndev; - u64 u64_mac; - int smac_index; - - - ndev = dev->iboe.netdevs[qp->port - 1]; - if (ndev) { - smac = IF_LLADDR(ndev); - u64_mac = mlx4_mac_to_u64(smac); - } else { - u64_mac = dev->dev->caps.def_mac[qp->port]; - } - - context->pri_path.sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((qp->port - 1) << 6); - if (!qp->pri.smac) { - smac_index = mlx4_register_mac(dev->dev, qp->port, u64_mac); - if (smac_index >= 0) { - qp->pri.candidate_smac_index = smac_index; - qp->pri.candidate_smac = u64_mac; - qp->pri.candidate_smac_port = qp->port; - context->pri_path.grh_mylmc = 0x80 | (u8) smac_index; - } else - return -ENOENT; - } - return 0; -} -static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, - const struct ib_qp_attr *attr, int attr_mask, - enum ib_qp_state cur_state, enum ib_qp_state new_state) -{ - struct mlx4_ib_dev *dev = to_mdev(ibqp->device); - struct mlx4_ib_qp *qp = to_mqp(ibqp); - struct mlx4_ib_pd *pd; - struct mlx4_ib_cq *send_cq, *recv_cq; - struct mlx4_qp_context *context; - enum mlx4_qp_optpar optpar = 0; - int sqd_event; - int steer_qp = 0; - int err = -EINVAL; - int is_eth = -1; - - context = kzalloc(sizeof *context, GFP_KERNEL); - if (!context) - return -ENOMEM; - - context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) | - (to_mlx4_st(dev, qp->mlx4_ib_qp_type) << 16)); - - if (!(attr_mask & IB_QP_PATH_MIG_STATE)) - context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); - else { - optpar |= MLX4_QP_OPTPAR_PM_STATE; - switch (attr->path_mig_state) { - case IB_MIG_MIGRATED: - context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); - break; - case IB_MIG_REARM: - context->flags |= cpu_to_be32(MLX4_QP_PM_REARM << 11); - break; - case IB_MIG_ARMED: - context->flags |= cpu_to_be32(MLX4_QP_PM_ARMED << 11); - break; - } - } - - if (qp->max_inlr_data) - context->param3 |= cpu_to_be32(1 << 25); - - if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) - context->mtu_msgmax = (IB_MTU_4096 << 5) | 11; - else if (ibqp->qp_type == IB_QPT_RAW_PACKET) - context->mtu_msgmax = (MLX4_RAW_QP_MTU << 5) | MLX4_RAW_QP_MSGMAX; - else if (ibqp->qp_type == IB_QPT_UD) { - if (qp->flags & MLX4_IB_QP_LSO) - context->mtu_msgmax = (IB_MTU_4096 << 5) | - ilog2(dev->dev->caps.max_gso_sz); - else - context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; - } else if (attr_mask & IB_QP_PATH_MTU) { - if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { - pr_err("path MTU (%u) is invalid\n", - attr->path_mtu); - goto out; - } - context->mtu_msgmax = (attr->path_mtu << 5) | - ilog2(dev->dev->caps.max_msg_sz); - } - - if (qp->rq.wqe_cnt) - context->rq_size_stride = ilog2(qp->rq.wqe_cnt) << 3; - context->rq_size_stride |= qp->rq.wqe_shift - 4; - - if (qp->sq.wqe_cnt) - context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3; - context->sq_size_stride |= qp->sq.wqe_shift - 4; - - if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { - context->sq_size_stride |= !!qp->sq_no_prefetch << 7; - context->xrcd = cpu_to_be32((u32) qp->xrcdn); - context->param3 |= cpu_to_be32(1 << 30); - } - - if (qp->ibqp.uobject) - context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index); - else - context->usr_page = cpu_to_be32(qp->bf.uar->index); - - if (attr_mask & IB_QP_DEST_QPN) - context->remote_qpn = cpu_to_be32(attr->dest_qp_num); - - if (attr_mask & IB_QP_PORT) { - if (cur_state == IB_QPS_SQD && new_state == IB_QPS_SQD && - !(attr_mask & IB_QP_AV)) { - mlx4_set_sched(&context->pri_path, attr->port_num); - optpar |= MLX4_QP_OPTPAR_SCHED_QUEUE; - } - } - - if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) { - if (dev->counters[qp->port - 1].counter_index != -1) { - context->pri_path.counter_index = - dev->counters[qp->port - 1].counter_index; - optpar |= MLX4_QP_OPTPAR_COUNTER_INDEX; - } else { - context->pri_path.counter_index = 0xff; - } - - if (qp->flags & MLX4_IB_QP_NETIF && - (qp->qpg_type == IB_QPG_NONE || qp->qpg_type == IB_QPG_PARENT)) { - mlx4_ib_steer_qp_reg(dev, qp, 1); - steer_qp = 1; - } - } - - if (attr_mask & IB_QP_PKEY_INDEX) { - if (qp->mlx4_ib_qp_type & MLX4_IB_QPT_ANY_SRIOV) - context->pri_path.disable_pkey_check = 0x40; - context->pri_path.pkey_index = attr->pkey_index; - optpar |= MLX4_QP_OPTPAR_PKEY_INDEX; - } - - if ((attr_mask & IB_QP_AV) && (ibqp->qp_type != IB_QPT_RAW_PACKET)) { - if (mlx4_set_path(dev, &attr->ah_attr, (u8 *)attr->smac, - attr_mask & IB_QP_VID ? - attr->vlan_id : 0xffff , - qp, &context->pri_path, - attr_mask & IB_QP_PORT ? - attr->port_num : qp->port, 1)) - goto out; - - optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | - MLX4_QP_OPTPAR_SCHED_QUEUE); - } - - if (attr_mask & IB_QP_TIMEOUT) { - context->pri_path.ackto |= attr->timeout << 3; - optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT; - } - - if (attr_mask & IB_QP_ALT_PATH) { - if (attr->alt_port_num == 0 || - attr->alt_port_num > dev->dev->caps.num_ports) - goto out; - - if (attr->alt_pkey_index >= - dev->dev->caps.pkey_table_len[attr->alt_port_num]) - goto out; - - if (mlx4_set_path(dev, &attr->alt_ah_attr, (u8 *)attr->smac, - attr_mask & IB_QP_ALT_VID ? - attr->alt_vlan_id : 0xffff, - qp, &context->alt_path, - attr->alt_port_num, 0)) - goto out; - - context->alt_path.pkey_index = attr->alt_pkey_index; - context->alt_path.ackto = attr->alt_timeout << 3; - context->alt_path.counter_index = dev->counters[attr->alt_port_num - 1].counter_index; - optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH; - } - - pd = get_pd(qp); - get_cqs(qp, &send_cq, &recv_cq); - context->pd = cpu_to_be32(pd->pdn); - context->cqn_send = cpu_to_be32(send_cq->mcq.cqn); - context->cqn_recv = cpu_to_be32(recv_cq->mcq.cqn); - context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28); - - /* Set "fast registration enabled" for all kernel QPs */ - if (!qp->ibqp.uobject) - context->params1 |= cpu_to_be32(1 << 11); - - if (attr_mask & IB_QP_RNR_RETRY) { - context->params1 |= cpu_to_be32(attr->rnr_retry << 13); - optpar |= MLX4_QP_OPTPAR_RNR_RETRY; - } - - if (attr_mask & IB_QP_RETRY_CNT) { - context->params1 |= cpu_to_be32(attr->retry_cnt << 16); - optpar |= MLX4_QP_OPTPAR_RETRY_COUNT; - } - - if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { - if (attr->max_rd_atomic) - context->params1 |= - cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); - optpar |= MLX4_QP_OPTPAR_SRA_MAX; - } - - if (attr_mask & IB_QP_SQ_PSN) - context->next_send_psn = cpu_to_be32(attr->sq_psn); - - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { - if (attr->max_dest_rd_atomic) - context->params2 |= - cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); - optpar |= MLX4_QP_OPTPAR_RRA_MAX; - } - - if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { - context->params2 |= to_mlx4_access_flags(qp, attr, attr_mask); - optpar |= MLX4_QP_OPTPAR_RWE | MLX4_QP_OPTPAR_RRE | MLX4_QP_OPTPAR_RAE; - } - - if (attr_mask & IB_M_EXT_CLASS_1) - context->params2 |= cpu_to_be32(MLX4_QP_BIT_COLL_MASTER); - - /* for now we enable also sqe on send */ - if (attr_mask & IB_M_EXT_CLASS_2) { - context->params2 |= cpu_to_be32(MLX4_QP_BIT_COLL_SYNC_SQ); - context->params2 |= cpu_to_be32(MLX4_QP_BIT_COLL_MASTER); - } - - if (attr_mask & IB_M_EXT_CLASS_3) - context->params2 |= cpu_to_be32(MLX4_QP_BIT_COLL_SYNC_RQ); - - if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { - context->params2 |= (qp->flags & MLX4_IB_QP_CAP_CROSS_CHANNEL ? - cpu_to_be32(MLX4_QP_BIT_COLL_MASTER) : 0); - context->params2 |= (qp->flags & MLX4_IB_QP_CAP_MANAGED_SEND ? - cpu_to_be32(MLX4_QP_BIT_COLL_MASTER | MLX4_QP_BIT_COLL_SYNC_SQ) : 0); - context->params2 |= (qp->flags & MLX4_IB_QP_CAP_MANAGED_RECV ? - cpu_to_be32(MLX4_QP_BIT_COLL_MASTER | MLX4_QP_BIT_COLL_SYNC_RQ) : 0); - } - - if (ibqp->srq) - context->params2 |= cpu_to_be32(MLX4_QP_BIT_RIC); - - if (attr_mask & IB_QP_MIN_RNR_TIMER) { - context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24); - optpar |= MLX4_QP_OPTPAR_RNR_TIMEOUT; - } - if (attr_mask & IB_QP_RQ_PSN) - context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn); - - /* proxy and tunnel qp qkeys will be changed in modify-qp wrappers */ - if (attr_mask & IB_QP_QKEY) { - if (qp->mlx4_ib_qp_type & - (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER)) - context->qkey = cpu_to_be32(IB_QP_SET_QKEY); - else { - if (mlx4_is_mfunc(dev->dev) && - !(qp->mlx4_ib_qp_type & MLX4_IB_QPT_ANY_SRIOV) && - (attr->qkey & MLX4_RESERVED_QKEY_MASK) == - MLX4_RESERVED_QKEY_BASE) { - pr_err("Cannot use reserved QKEY" - " 0x%x (range 0xffff0000..0xffffffff" - " is reserved)\n", attr->qkey); - err = -EINVAL; - goto out; - } - context->qkey = cpu_to_be32(attr->qkey); - } - optpar |= MLX4_QP_OPTPAR_Q_KEY; - } - - if (ibqp->srq) - context->srqn = cpu_to_be32(1 << 24 | to_msrq(ibqp->srq)->msrq.srqn); - - if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) - context->db_rec_addr = cpu_to_be64(qp->db.dma); - - if (cur_state == IB_QPS_INIT && - new_state == IB_QPS_RTR && - (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI || - ibqp->qp_type == IB_QPT_UD || - ibqp->qp_type == IB_QPT_RAW_PACKET)) { - context->pri_path.sched_queue = (qp->port - 1) << 6; - if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_SMI || - qp->mlx4_ib_qp_type & - (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER)) { - context->pri_path.sched_queue |= MLX4_IB_DEFAULT_QP0_SCHED_QUEUE; - if (qp->mlx4_ib_qp_type != MLX4_IB_QPT_SMI) - context->pri_path.fl = 0x80; - } else { - if (qp->mlx4_ib_qp_type & MLX4_IB_QPT_ANY_SRIOV) - context->pri_path.fl = 0x80; - context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE; - } - if (ibqp->qp_type == IB_QPT_RAW_PACKET && - (attr_mask & IB_QP_AV)) { - context->pri_path.sched_queue |= - ((attr->ah_attr.sl & 0xf) << 3); - context->pri_path.feup = 1 << 6; - } - is_eth = rdma_port_get_link_layer(&dev->ib_dev, qp->port) == - IB_LINK_LAYER_ETHERNET; - if (is_eth) { - if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI || - qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI) - context->pri_path.feup = 1 << 7; /* don't fsm */ - /* handle smac_index */ - if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD || - qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI || - qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) { - err = handle_eth_ud_smac_index(dev, qp, (const u8 *)attr->smac, context); - if (err) - return -EINVAL; - } - } - } - - if (ibqp->qp_type == IB_QPT_UD) - if (is_eth && (new_state == IB_QPS_RTR)) { - context->pri_path.ackto = MLX4_IB_LINK_TYPE_ETH; - optpar |= MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH; - } - - if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD && - attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify) - sqd_event = 1; - else - sqd_event = 0; - - if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) - context->rlkey |= (1 << 4); - - if ((attr_mask & IB_QP_GROUP_RSS) && - (qp->qpg_data->rss_child_count > 1)) { - struct mlx4_ib_qpg_data *qpg_data = qp->qpg_data; - void *rss_context_base = &context->pri_path; - struct mlx4_rss_context *rss_context = - (struct mlx4_rss_context *) (rss_context_base - + MLX4_RSS_OFFSET_IN_QPC_PRI_PATH); - - context->flags |= cpu_to_be32(1 << MLX4_RSS_QPC_FLAG_OFFSET); - - /* This should be tbl_sz_base_qpn */ - rss_context->base_qpn = cpu_to_be32(qpg_data->rss_qpn_base | - (ilog2(qpg_data->rss_child_count) << 24)); - rss_context->default_qpn = cpu_to_be32(qpg_data->rss_qpn_base); - /* This should be flags_hash_fn */ - rss_context->flags = MLX4_RSS_TCP_IPV6 | - MLX4_RSS_TCP_IPV4; - if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UDP_RSS) { - rss_context->base_qpn_udp = rss_context->default_qpn; - rss_context->flags |= MLX4_RSS_IPV6 | - MLX4_RSS_IPV4 | - MLX4_RSS_UDP_IPV6 | - MLX4_RSS_UDP_IPV4; - } - if (dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP) { - static const u32 rsskey[10] = { 0xD181C62C, 0xF7F4DB5B, - 0x1983A2FC, 0x943E1ADB, 0xD9389E6B, 0xD1039C2C, - 0xA74499AD, 0x593D56D9, 0xF3253C06, 0x2ADC1FFC}; - rss_context->hash_fn = MLX4_RSS_HASH_TOP; - memcpy(rss_context->rss_key, rsskey, - sizeof(rss_context->rss_key)); - } else { - rss_context->hash_fn = MLX4_RSS_HASH_XOR; - memset(rss_context->rss_key, 0, - sizeof(rss_context->rss_key)); - } - } - /* - * Before passing a kernel QP to the HW, make sure that the - * ownership bits of the send queue are set and the SQ - * headroom is stamped so that the hardware doesn't start - * processing stale work requests. - */ - if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { - struct mlx4_wqe_ctrl_seg *ctrl; - int i; - - for (i = 0; i < qp->sq.wqe_cnt; ++i) { - ctrl = get_send_wqe(qp, i); - ctrl->owner_opcode = cpu_to_be32(1 << 31); - if (qp->sq_max_wqes_per_wr == 1) - ctrl->fence_size = 1 << (qp->sq.wqe_shift - 4); - - stamp_send_wqe(qp, i, 1 << qp->sq.wqe_shift); - } - } - - if ((qp->port && rdma_port_get_link_layer(&dev->ib_dev, qp->port) == - IB_LINK_LAYER_ETHERNET) && (qp->ibqp.qp_type == IB_QPT_RAW_PACKET)) - context->pri_path.ackto = (context->pri_path.ackto & 0xf8) | - MLX4_IB_LINK_TYPE_ETH; - - err = mlx4_qp_modify(dev->dev, &qp->mtt, to_mlx4_state(cur_state), - to_mlx4_state(new_state), context, optpar, - sqd_event, &qp->mqp); - if (err) - goto out; - - qp->state = new_state; - - if (attr_mask & IB_QP_ACCESS_FLAGS) - qp->atomic_rd_en = attr->qp_access_flags; - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) - qp->resp_depth = attr->max_dest_rd_atomic; - if (attr_mask & IB_QP_PORT) { - qp->port = attr->port_num; - update_mcg_macs(dev, qp); - } - if (attr_mask & IB_QP_ALT_PATH) - qp->alt_port = attr->alt_port_num; - - if (is_sqp(dev, qp)) - store_sqp_attrs(to_msqp(qp), attr, attr_mask); - - /* Set 'ignore_cq_overrun' bits for collectives offload */ - if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { - if (attr_mask & (IB_M_EXT_CLASS_2 | IB_M_EXT_CLASS_3)) { - err = mlx4_ib_ignore_overrun_cq(ibqp->send_cq); - if (err) { - pr_err("Failed to set ignore CQ " - "overrun for QP 0x%x's send CQ\n", - ibqp->qp_num); - goto out; - } - - if (ibqp->recv_cq != ibqp->send_cq) { - err = mlx4_ib_ignore_overrun_cq(ibqp->recv_cq); - if (err) { - pr_err("Failed to set ignore " - "CQ overrun for QP 0x%x's recv " - "CQ\n", ibqp->qp_num); - goto out; - } - } - } - } - - /* - * If we moved QP0 to RTR, bring the IB link up; if we moved - * QP0 to RESET or ERROR, bring the link back down. - */ - if (is_qp0(dev, qp)) { - if (cur_state != IB_QPS_RTR && new_state == IB_QPS_RTR) - if (mlx4_INIT_PORT(dev->dev, qp->port)) - pr_warn("INIT_PORT failed for port %d\n", - qp->port); - - if (cur_state != IB_QPS_RESET && cur_state != IB_QPS_ERR && - (new_state == IB_QPS_RESET || new_state == IB_QPS_ERR)) - mlx4_CLOSE_PORT(dev->dev, qp->port); - } - - /* - * If we moved a kernel QP to RESET, clean up all old CQ - * entries and reinitialize the QP. - */ - if (new_state == IB_QPS_RESET) { - if (!ibqp->uobject) { - mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, - ibqp->srq ? to_msrq(ibqp->srq) : NULL); - if (send_cq != recv_cq) - mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); - - qp->rq.head = 0; - qp->rq.tail = 0; - qp->sq.head = 0; - qp->sq.tail = 0; - qp->sq_next_wqe = 0; - if (qp->rq.wqe_cnt) - *qp->db.db = 0; - - if (qp->flags & MLX4_IB_QP_NETIF && - (qp->qpg_type == IB_QPG_NONE || - qp->qpg_type == IB_QPG_PARENT)) - mlx4_ib_steer_qp_reg(dev, qp, 0); - } - if (qp->pri.smac) { - mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); - qp->pri.smac = 0; - } - if (qp->alt.smac) { - mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); - qp->alt.smac = 0; - } - if (qp->pri.vid < 0x1000) { - mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid); - qp->pri.vid = 0xFFFF; - qp->pri.candidate_vid = 0xFFFF; - qp->pri.update_vid = 0; - } - - if (qp->alt.vid < 0x1000) { - mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid); - qp->alt.vid = 0xFFFF; - qp->alt.candidate_vid = 0xFFFF; - qp->alt.update_vid = 0; - } - } - -out: - if (err && steer_qp) - mlx4_ib_steer_qp_reg(dev, qp, 0); - kfree(context); - if (qp->pri.candidate_smac) { - if (err) - mlx4_unregister_mac(dev->dev, qp->pri.candidate_smac_port, qp->pri.candidate_smac); - else { - if (qp->pri.smac) { - mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); - } - qp->pri.smac = qp->pri.candidate_smac; - qp->pri.smac_index = qp->pri.candidate_smac_index; - qp->pri.smac_port = qp->pri.candidate_smac_port; - - } - qp->pri.candidate_smac = 0; - qp->pri.candidate_smac_index = 0; - qp->pri.candidate_smac_port = 0; - } - if (qp->alt.candidate_smac) { - if (err) - mlx4_unregister_mac(dev->dev, qp->alt.candidate_smac_port, qp->pri.candidate_smac); - else { - if (qp->pri.smac) { - mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); - } - qp->alt.smac = qp->alt.candidate_smac; - qp->alt.smac_index = qp->alt.candidate_smac_index; - qp->alt.smac_port = qp->alt.candidate_smac_port; - - } - qp->pri.candidate_smac = 0; - qp->pri.candidate_smac_index = 0; - qp->pri.candidate_smac_port = 0; - } - - if (qp->pri.update_vid) { - if (err) { - if (qp->pri.candidate_vid < 0x1000) - mlx4_unregister_vlan(dev->dev, qp->pri.candidate_vlan_port, - qp->pri.candidate_vid); - } else { - if (qp->pri.vid < 0x1000) - mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, - qp->pri.vid); - qp->pri.vid = qp->pri.candidate_vid; - qp->pri.vlan_port = qp->pri.candidate_vlan_port; - qp->pri.vlan_index = qp->pri.candidate_vlan_index; - } - qp->pri.candidate_vid = 0xFFFF; - qp->pri.update_vid = 0; - } - - if (qp->alt.update_vid) { - if (err) { - if (qp->alt.candidate_vid < 0x1000) - mlx4_unregister_vlan(dev->dev, qp->alt.candidate_vlan_port, - qp->alt.candidate_vid); - } else { - if (qp->alt.vid < 0x1000) - mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, - qp->alt.vid); - qp->alt.vid = qp->alt.candidate_vid; - qp->alt.vlan_port = qp->alt.candidate_vlan_port; - qp->alt.vlan_index = qp->alt.candidate_vlan_index; - } - qp->alt.candidate_vid = 0xFFFF; - qp->alt.update_vid = 0; - } - - return err; -} - -int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, - int attr_mask, struct ib_udata *udata) -{ - struct mlx4_ib_dev *dev = to_mdev(ibqp->device); - struct mlx4_ib_qp *qp = to_mqp(ibqp); - enum ib_qp_state cur_state, new_state; - int err = -EINVAL; - int ll; - - mutex_lock(&qp->mutex); - - cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; - new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; - - if (cur_state == new_state && cur_state == IB_QPS_RESET) { - ll = IB_LINK_LAYER_UNSPECIFIED; - } else { - int port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; - ll = rdma_port_get_link_layer(&dev->ib_dev, port); - } - - if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, - attr_mask & ~IB_M_QP_MOD_VEND_MASK, ll)) { - pr_debug("qpn 0x%x: invalid attribute mask specified " - "for transition %d to %d. qp_type %d," - " attr_mask 0x%x\n", - ibqp->qp_num, cur_state, new_state, - ibqp->qp_type, attr_mask); - goto out; - } - - if ((attr_mask & IB_M_QP_MOD_VEND_MASK) && !dev->dev->caps.sync_qp) { - pr_err("extended verbs are not supported by %s\n", - dev->ib_dev.name); - goto out; - } - - if ((attr_mask & IB_QP_PORT) && - (attr->port_num == 0 || attr->port_num > dev->num_ports)) { - pr_debug("qpn 0x%x: invalid port number (%d) specified " - "for transition %d to %d. qp_type %d\n", - ibqp->qp_num, attr->port_num, cur_state, - new_state, ibqp->qp_type); - goto out; - } - - if (attr_mask & IB_QP_PKEY_INDEX) { - int p = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; - if (attr->pkey_index >= dev->dev->caps.pkey_table_len[p]) { - pr_debug("qpn 0x%x: invalid pkey index (%d) specified " - "for transition %d to %d. qp_type %d\n", - ibqp->qp_num, attr->pkey_index, cur_state, - new_state, ibqp->qp_type); - goto out; - } - } - - if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && - attr->max_rd_atomic > dev->dev->caps.max_qp_init_rdma) { - pr_debug("qpn 0x%x: max_rd_atomic (%d) too large. " - "Transition %d to %d. qp_type %d\n", - ibqp->qp_num, attr->max_rd_atomic, cur_state, - new_state, ibqp->qp_type); - goto out; - } - - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && - attr->max_dest_rd_atomic > dev->dev->caps.max_qp_dest_rdma) { - pr_debug("qpn 0x%x: max_dest_rd_atomic (%d) too large. " - "Transition %d to %d. qp_type %d\n", - ibqp->qp_num, attr->max_dest_rd_atomic, cur_state, - new_state, ibqp->qp_type); - goto out; - } - - if (cur_state == new_state && cur_state == IB_QPS_RESET) { - err = 0; - goto out; - } - - err = __mlx4_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state); - -out: - mutex_unlock(&qp->mutex); - return err; -} - -static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp, - struct ib_send_wr *wr, - void *wqe, unsigned *mlx_seg_len) -{ - struct mlx4_ib_dev *mdev = to_mdev(sqp->qp.ibqp.device); - struct ib_device *ib_dev = &mdev->ib_dev; - struct mlx4_wqe_mlx_seg *mlx = wqe; - struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; - struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); - u16 pkey; - u32 qkey; - int send_size; - int header_size; - int spc; - int i; - - if (wr->opcode != IB_WR_SEND) - return -EINVAL; - - send_size = 0; - - for (i = 0; i < wr->num_sge; ++i) - send_size += wr->sg_list[i].length; - - /* for proxy-qp0 sends, need to add in size of tunnel header */ - /* for tunnel-qp0 sends, tunnel header is already in s/g list */ - if (sqp->qp.mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_SMI_OWNER) - send_size += sizeof (struct mlx4_ib_tunnel_header); - - ib_ud_header_init(send_size, 1, 0, 0, 0, 0, &sqp->ud_header); - - if (sqp->qp.mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_SMI_OWNER) { - sqp->ud_header.lrh.service_level = - be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; - sqp->ud_header.lrh.destination_lid = - cpu_to_be16(ah->av.ib.g_slid & 0x7f); - sqp->ud_header.lrh.source_lid = - cpu_to_be16(ah->av.ib.g_slid & 0x7f); - } - - mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); - - /* force loopback */ - mlx->flags |= cpu_to_be32(MLX4_WQE_MLX_VL15 | 0x1 | MLX4_WQE_MLX_SLR); - mlx->rlid = sqp->ud_header.lrh.destination_lid; - - sqp->ud_header.lrh.virtual_lane = 0; - sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED); - ib_get_cached_pkey(ib_dev, sqp->qp.port, 0, &pkey); - sqp->ud_header.bth.pkey = cpu_to_be16(pkey); - if (sqp->qp.mlx4_ib_qp_type == MLX4_IB_QPT_TUN_SMI_OWNER) - sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); - else - sqp->ud_header.bth.destination_qpn = - cpu_to_be32(mdev->dev->caps.qp0_tunnel[sqp->qp.port - 1]); - - sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1)); - if (mlx4_get_parav_qkey(mdev->dev, sqp->qp.mqp.qpn, &qkey)) - return -EINVAL; - sqp->ud_header.deth.qkey = cpu_to_be32(qkey); - sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.mqp.qpn); - - sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY; - sqp->ud_header.immediate_present = 0; - - header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf); - - /* - * Inline data segments may not cross a 64 byte boundary. If - * our UD header is bigger than the space available up to the - * next 64 byte boundary in the WQE, use two inline data - * segments to hold the UD header. - */ - spc = MLX4_INLINE_ALIGN - - ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1)); - if (header_size <= spc) { - inl->byte_count = cpu_to_be32(1 << 31 | header_size); - memcpy(inl + 1, sqp->header_buf, header_size); - i = 1; - } else { - inl->byte_count = cpu_to_be32(1 << 31 | spc); - memcpy(inl + 1, sqp->header_buf, spc); - - inl = (void *) (inl + 1) + spc; - memcpy(inl + 1, sqp->header_buf + spc, header_size - spc); - /* - * Need a barrier here to make sure all the data is - * visible before the byte_count field is set. - * Otherwise the HCA prefetcher could grab the 64-byte - * chunk with this inline segment and get a valid (!= - * 0xffffffff) byte count but stale data, and end up - * generating a packet with bad headers. - * - * The first inline segment's byte_count field doesn't - * need a barrier, because it comes after a - * control/MLX segment and therefore is at an offset - * of 16 mod 64. - */ - wmb(); - inl->byte_count = cpu_to_be32(1 << 31 | (header_size - spc)); - i = 2; - } - - *mlx_seg_len = - ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + header_size, 16); - return 0; -} - -static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, - void *wqe, unsigned *mlx_seg_len) -{ - struct ib_device *ib_dev = sqp->qp.ibqp.device; - struct mlx4_wqe_mlx_seg *mlx = wqe; - struct mlx4_wqe_ctrl_seg *ctrl = wqe; - struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; - struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); - union ib_gid sgid; - u16 pkey; - int send_size; - int header_size; - int spc; - int i; - int is_eth; - int is_vlan = 0; - int is_grh; - u16 uninitialized_var(vlan); - int err = 0; - - send_size = 0; - for (i = 0; i < wr->num_sge; ++i) - send_size += wr->sg_list[i].length; - - is_eth = rdma_port_get_link_layer(sqp->qp.ibqp.device, sqp->qp.port) == IB_LINK_LAYER_ETHERNET; - is_grh = mlx4_ib_ah_grh_present(ah); - if (is_eth) { - if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) { - /* When multi-function is enabled, the ib_core gid - * indexes don't necessarily match the hw ones, so - * we must use our own cache */ - err = mlx4_get_roce_gid_from_slave(to_mdev(ib_dev)->dev, - be32_to_cpu(ah->av.ib.port_pd) >> 24, - ah->av.ib.gid_index, &sgid.raw[0]); - if (err) - return err; - } else { - err = ib_get_cached_gid(ib_dev, - be32_to_cpu(ah->av.ib.port_pd) >> 24, - ah->av.ib.gid_index, &sgid); - if (err) - return err; - } - - if (is_eth && ah->av.eth.vlan != 0xffff) { - vlan = cpu_to_be16(ah->av.eth.vlan) & 0x0fff; - is_vlan = 1; - } - } - ib_ud_header_init(send_size, !is_eth, is_eth, is_vlan, is_grh, 0, &sqp->ud_header); - - if (!is_eth) { - sqp->ud_header.lrh.service_level = - be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; - sqp->ud_header.lrh.destination_lid = ah->av.ib.dlid; - sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.ib.g_slid & 0x7f); - } - - if (is_grh) { - sqp->ud_header.grh.traffic_class = - (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff; - sqp->ud_header.grh.flow_label = - ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff); - sqp->ud_header.grh.hop_limit = ah->av.ib.hop_limit; - if (is_eth) - memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16); - else { - if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) { - /* When multi-function is enabled, the ib_core gid - * indexes don't necessarily match the hw ones, so - * we must use our own cache */ - sqp->ud_header.grh.source_gid.global.subnet_prefix = - to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1]. - subnet_prefix; - sqp->ud_header.grh.source_gid.global.interface_id = - to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1]. - guid_cache[ah->av.ib.gid_index]; - } else - ib_get_cached_gid(ib_dev, - be32_to_cpu(ah->av.ib.port_pd) >> 24, - ah->av.ib.gid_index, - &sqp->ud_header.grh.source_gid); - } - memcpy(sqp->ud_header.grh.destination_gid.raw, - ah->av.ib.dgid, 16); - } - - mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); - - if (!is_eth) { - mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) | - (sqp->ud_header.lrh.destination_lid == - IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) | - (sqp->ud_header.lrh.service_level << 8)); - if (ah->av.ib.port_pd & cpu_to_be32(0x80000000)) - mlx->flags |= cpu_to_be32(0x1); /* force loopback */ - mlx->rlid = sqp->ud_header.lrh.destination_lid; - } - - switch (wr->opcode) { - case IB_WR_SEND: - sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY; - sqp->ud_header.immediate_present = 0; - break; - case IB_WR_SEND_WITH_IMM: - sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; - sqp->ud_header.immediate_present = 1; - sqp->ud_header.immediate_data = wr->ex.imm_data; - break; - default: - return -EINVAL; - } - - if (is_eth) { - u8 *smac; - struct in6_addr in6; - - u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13; - - mlx->sched_prio = cpu_to_be16(pcp); - - memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6); - /* FIXME: cache smac value? */ - memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2); - memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4); - memcpy(&in6, sgid.raw, sizeof(in6)); - - if (!mlx4_is_mfunc(to_mdev(ib_dev)->dev)) - smac = IF_LLADDR(to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]); - else - smac = ah->av.eth.s_mac; /* use the src mac of the tunnel */ - memcpy(sqp->ud_header.eth.smac_h, smac, 6); - - if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6)) - mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); - if (!is_vlan) { - sqp->ud_header.eth.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE); - } else { - sqp->ud_header.vlan.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE); - sqp->ud_header.vlan.tag = cpu_to_be16(vlan | pcp); - } - } else { - sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0; - if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE) - sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE; - } - sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED); - if (!sqp->qp.ibqp.qp_num) - ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey); - else - ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->wr.ud.pkey_index, &pkey); - sqp->ud_header.bth.pkey = cpu_to_be16(pkey); - sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); - sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1)); - sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ? - sqp->qkey : wr->wr.ud.remote_qkey); - sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num); - - header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf); - - if (0) { - pr_err("built UD header of size %d:\n", header_size); - for (i = 0; i < header_size / 4; ++i) { - if (i % 8 == 0) - pr_err(" [%02x] ", i * 4); - pr_cont(" %08x", - be32_to_cpu(((__be32 *) sqp->header_buf)[i])); - if ((i + 1) % 8 == 0) - pr_cont("\n"); - } - pr_err("\n"); - } - - /* - * Inline data segments may not cross a 64 byte boundary. If - * our UD header is bigger than the space available up to the - * next 64 byte boundary in the WQE, use two inline data - * segments to hold the UD header. - */ - spc = MLX4_INLINE_ALIGN - - ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1)); - if (header_size <= spc) { - inl->byte_count = cpu_to_be32(1 << 31 | header_size); - memcpy(inl + 1, sqp->header_buf, header_size); - i = 1; - } else { - inl->byte_count = cpu_to_be32(1 << 31 | spc); - memcpy(inl + 1, sqp->header_buf, spc); - - inl = (void *) (inl + 1) + spc; - memcpy(inl + 1, sqp->header_buf + spc, header_size - spc); - /* - * Need a barrier here to make sure all the data is - * visible before the byte_count field is set. - * Otherwise the HCA prefetcher could grab the 64-byte - * chunk with this inline segment and get a valid (!= - * 0xffffffff) byte count but stale data, and end up - * generating a packet with bad headers. - * - * The first inline segment's byte_count field doesn't - * need a barrier, because it comes after a - * control/MLX segment and therefore is at an offset - * of 16 mod 64. - */ - wmb(); - inl->byte_count = cpu_to_be32(1 << 31 | (header_size - spc)); - i = 2; - } - - *mlx_seg_len = - ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + header_size, 16); - return 0; -} - -static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq) -{ - unsigned cur; - struct mlx4_ib_cq *cq; - - cur = wq->head - wq->tail; - if (likely(cur + nreq < wq->max_post)) - return 0; - - cq = to_mcq(ib_cq); - spin_lock(&cq->lock); - cur = wq->head - wq->tail; - spin_unlock(&cq->lock); - - return cur + nreq >= wq->max_post; -} - -static __be32 convert_access(int acc) -{ - return (acc & IB_ACCESS_REMOTE_ATOMIC ? - cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_ATOMIC) : 0) | - (acc & IB_ACCESS_REMOTE_WRITE ? - cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_WRITE) : 0) | - (acc & IB_ACCESS_REMOTE_READ ? - cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_READ) : 0) | - (acc & IB_ACCESS_LOCAL_WRITE ? cpu_to_be32(MLX4_WQE_FMR_PERM_LOCAL_WRITE) : 0) | - cpu_to_be32(MLX4_WQE_FMR_PERM_LOCAL_READ); -} - -static void set_fmr_seg(struct mlx4_wqe_fmr_seg *fseg, struct ib_send_wr *wr) -{ - struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list); - int i; - - for (i = 0; i < wr->wr.fast_reg.page_list_len; ++i) - mfrpl->mapped_page_list[i] = - cpu_to_be64(wr->wr.fast_reg.page_list->page_list[i] | - MLX4_MTT_FLAG_PRESENT); - - fseg->flags = convert_access(wr->wr.fast_reg.access_flags); - fseg->mem_key = cpu_to_be32(wr->wr.fast_reg.rkey); - fseg->buf_list = cpu_to_be64(mfrpl->map); - fseg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start); - fseg->reg_len = cpu_to_be64(wr->wr.fast_reg.length); - fseg->offset = 0; /* XXX -- is this just for ZBVA? */ - fseg->page_size = cpu_to_be32(wr->wr.fast_reg.page_shift); - fseg->reserved[0] = 0; - fseg->reserved[1] = 0; -} - -static void set_bind_seg(struct mlx4_wqe_bind_seg *bseg, struct ib_send_wr *wr) -{ - bseg->flags1 = - convert_access(wr->wr.bind_mw.bind_info.mw_access_flags) & - cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_READ | - MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_WRITE | - MLX4_WQE_FMR_AND_BIND_PERM_ATOMIC); - bseg->flags2 = 0; - if (wr->wr.bind_mw.mw->type == IB_MW_TYPE_2) - bseg->flags2 |= cpu_to_be32(MLX4_WQE_BIND_TYPE_2); - if (wr->wr.bind_mw.bind_info.mw_access_flags & IB_ZERO_BASED) - bseg->flags2 |= cpu_to_be32(MLX4_WQE_BIND_ZERO_BASED); - bseg->new_rkey = cpu_to_be32(wr->wr.bind_mw.rkey); - bseg->lkey = cpu_to_be32(wr->wr.bind_mw.bind_info.mr->lkey); - bseg->addr = cpu_to_be64(wr->wr.bind_mw.bind_info.addr); - bseg->length = cpu_to_be64(wr->wr.bind_mw.bind_info.length); -} - -static void set_local_inv_seg(struct mlx4_wqe_local_inval_seg *iseg, u32 rkey) -{ - iseg->mem_key = cpu_to_be32(rkey); - - iseg->reserved1 = 0; - iseg->reserved2 = 0; - iseg->reserved3[0] = 0; - iseg->reserved3[1] = 0; -} - -static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg, - u64 remote_addr, u32 rkey) -{ - rseg->raddr = cpu_to_be64(remote_addr); - rseg->rkey = cpu_to_be32(rkey); - rseg->reserved = 0; -} - -static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr) -{ - if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { - aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); - aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); - } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) { - aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); - aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add_mask); - } else { - aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); - aseg->compare = 0; - } - -} - -static void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg, - struct ib_send_wr *wr) -{ - aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); - aseg->swap_add_mask = cpu_to_be64(wr->wr.atomic.swap_mask); - aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); - aseg->compare_mask = cpu_to_be64(wr->wr.atomic.compare_add_mask); -} - -static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, - struct ib_send_wr *wr) -{ - memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av)); - dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); - dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); - dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan; - memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6); -} - -static void set_tunnel_datagram_seg(struct mlx4_ib_dev *dev, - struct mlx4_wqe_datagram_seg *dseg, - struct ib_send_wr *wr, enum ib_qp_type qpt) -{ - union mlx4_ext_av *av = &to_mah(wr->wr.ud.ah)->av; - struct mlx4_av sqp_av = {0}; - int port = *((u8 *) &av->ib.port_pd) & 0x3; - - /* force loopback */ - sqp_av.port_pd = av->ib.port_pd | cpu_to_be32(0x80000000); - sqp_av.g_slid = av->ib.g_slid & 0x7f; /* no GRH */ - sqp_av.sl_tclass_flowlabel = av->ib.sl_tclass_flowlabel & - cpu_to_be32(0xf0000000); - - memcpy(dseg->av, &sqp_av, sizeof (struct mlx4_av)); - /* This function used only for sending on QP1 proxies */ - dseg->dqpn = cpu_to_be32(dev->dev->caps.qp1_tunnel[port - 1]); - /* Use QKEY from the QP context, which is set by master */ - dseg->qkey = cpu_to_be32(IB_QP_SET_QKEY); -} - -static void build_tunnel_header(struct ib_send_wr *wr, void *wqe, unsigned *mlx_seg_len) -{ - struct mlx4_wqe_inline_seg *inl = wqe; - struct mlx4_ib_tunnel_header hdr; - struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); - int spc; - int i; - - memcpy(&hdr.av, &ah->av, sizeof hdr.av); - hdr.remote_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); - hdr.pkey_index = cpu_to_be16(wr->wr.ud.pkey_index); - hdr.qkey = cpu_to_be32(wr->wr.ud.remote_qkey); - memcpy(hdr.mac, ah->av.eth.mac, 6); - hdr.vlan = cpu_to_be16(ah->av.eth.vlan); - - spc = MLX4_INLINE_ALIGN - - ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1)); - if (sizeof (hdr) <= spc) { - memcpy(inl + 1, &hdr, sizeof (hdr)); - wmb(); - inl->byte_count = cpu_to_be32(1 << 31 | sizeof (hdr)); - i = 1; - } else { - memcpy(inl + 1, &hdr, spc); - wmb(); - inl->byte_count = cpu_to_be32(1 << 31 | spc); - - inl = (void *) (inl + 1) + spc; - memcpy(inl + 1, (void *) &hdr + spc, sizeof (hdr) - spc); - wmb(); - inl->byte_count = cpu_to_be32(1 << 31 | (sizeof (hdr) - spc)); - i = 2; - } - - *mlx_seg_len = - ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + sizeof (hdr), 16); -} - -static void set_mlx_icrc_seg(void *dseg) -{ - u32 *t = dseg; - struct mlx4_wqe_inline_seg *iseg = dseg; - - t[1] = 0; - - /* - * Need a barrier here before writing the byte_count field to - * make sure that all the data is visible before the - * byte_count field is set. Otherwise, if the segment begins - * a new cacheline, the HCA prefetcher could grab the 64-byte - * chunk and get a valid (!= * 0xffffffff) byte count but - * stale data, and end up sending the wrong data. - */ - wmb(); - - iseg->byte_count = cpu_to_be32((1 << 31) | 4); -} - -static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) -{ - dseg->lkey = cpu_to_be32(sg->lkey); - dseg->addr = cpu_to_be64(sg->addr); - - /* - * Need a barrier here before writing the byte_count field to - * make sure that all the data is visible before the - * byte_count field is set. Otherwise, if the segment begins - * a new cacheline, the HCA prefetcher could grab the 64-byte - * chunk and get a valid (!= * 0xffffffff) byte count but - * stale data, and end up sending the wrong data. - */ - wmb(); - - dseg->byte_count = cpu_to_be32(sg->length); -} - -static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) -{ - dseg->byte_count = cpu_to_be32(sg->length); - dseg->lkey = cpu_to_be32(sg->lkey); - dseg->addr = cpu_to_be64(sg->addr); -} - -static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_send_wr *wr, - struct mlx4_ib_qp *qp, unsigned *lso_seg_len, - __be32 *lso_hdr_sz, __be32 *blh) -{ - unsigned halign = ALIGN(sizeof *wqe + wr->wr.ud.hlen, 16); - - if (unlikely(halign > MLX4_IB_CACHE_LINE_SIZE)) - *blh = cpu_to_be32(1 << 6); - - if (unlikely(!(qp->flags & MLX4_IB_QP_LSO) && - wr->num_sge > qp->sq.max_gs - (halign >> 4))) - return -EINVAL; - - memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen); - - *lso_hdr_sz = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 | - wr->wr.ud.hlen); - *lso_seg_len = halign; - return 0; -} - -static __be32 send_ieth(struct ib_send_wr *wr) -{ - switch (wr->opcode) { - case IB_WR_SEND_WITH_IMM: - case IB_WR_RDMA_WRITE_WITH_IMM: - return wr->ex.imm_data; - - case IB_WR_SEND_WITH_INV: - return cpu_to_be32(wr->ex.invalidate_rkey); - - default: - return 0; - } -} - -static void add_zero_len_inline(void *wqe) -{ - struct mlx4_wqe_inline_seg *inl = wqe; - memset(wqe, 0, 16); - inl->byte_count = cpu_to_be32(1 << 31); -} - -static int lay_inline_data(struct mlx4_ib_qp *qp, struct ib_send_wr *wr, - void *wqe, int *sz) -{ - struct mlx4_wqe_inline_seg *seg; - void *addr; - int len, seg_len; - int num_seg; - int off, to_copy; - int i; - int inl = 0; - - seg = wqe; - wqe += sizeof *seg; - off = ((unsigned long)wqe) & (unsigned long)(MLX4_INLINE_ALIGN - 1); - num_seg = 0; - seg_len = 0; - - for (i = 0; i < wr->num_sge; ++i) { - addr = (void *) (unsigned long)(wr->sg_list[i].addr); - len = wr->sg_list[i].length; - inl += len; - - if (inl > qp->max_inline_data) { - inl = 0; - return -1; - } - - while (len >= MLX4_INLINE_ALIGN - off) { - to_copy = MLX4_INLINE_ALIGN - off; - memcpy(wqe, addr, to_copy); - len -= to_copy; - wqe += to_copy; - addr += to_copy; - seg_len += to_copy; - wmb(); /* see comment below */ - seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); - seg_len = 0; - seg = wqe; - wqe += sizeof *seg; - off = sizeof *seg; - ++num_seg; - } - - memcpy(wqe, addr, len); - wqe += len; - seg_len += len; - off += len; - } - - if (seg_len) { - ++num_seg; - /* - * Need a barrier here to make sure - * all the data is visible before the - * byte_count field is set. Otherwise - * the HCA prefetcher could grab the - * 64-byte chunk with this inline - * segment and get a valid (!= - * 0xffffffff) byte count but stale - * data, and end up sending the wrong - * data. - */ - wmb(); - seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); - } - - *sz = (inl + num_seg * sizeof *seg + 15) / 16; - - return 0; -} - -/* - * Avoid using memcpy() to copy to BlueFlame page, since memcpy() - * implementations may use move-string-buffer assembler instructions, - * which do not guarantee order of copying. - */ -static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, - unsigned bytecnt) -{ - __iowrite64_copy(dst, src, bytecnt / 8); -} - -int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, - struct ib_send_wr **bad_wr) -{ - struct mlx4_ib_qp *qp = to_mqp(ibqp); - void *wqe; - struct mlx4_wqe_ctrl_seg *uninitialized_var(ctrl); - struct mlx4_wqe_data_seg *dseg; - unsigned long flags; - int nreq; - int err = 0; - unsigned ind; - int uninitialized_var(stamp); - int uninitialized_var(size); - unsigned uninitialized_var(seglen); - __be32 dummy; - __be32 *lso_wqe; - __be32 uninitialized_var(lso_hdr_sz); - __be32 blh; - int i; - int inl = 0; - spin_lock_irqsave(&qp->sq.lock, flags); - - ind = qp->sq_next_wqe; - - for (nreq = 0; wr; ++nreq, wr = wr->next) { - lso_wqe = &dummy; - blh = 0; - - if (mlx4_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { - err = -ENOMEM; - *bad_wr = wr; - goto out; - } - - if (unlikely(wr->num_sge > qp->sq.max_gs)) { - err = -EINVAL; - *bad_wr = wr; - goto out; - } - - ctrl = wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); - *((u32 *) (&ctrl->vlan_tag)) = 0; - qp->sq.wrid[(qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1)] = wr->wr_id; - - ctrl->srcrb_flags = - (wr->send_flags & IB_SEND_SIGNALED ? - cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | - (wr->send_flags & IB_SEND_SOLICITED ? - cpu_to_be32(MLX4_WQE_CTRL_SOLICITED) : 0) | - ((wr->send_flags & IB_SEND_IP_CSUM) ? - cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM | - MLX4_WQE_CTRL_TCP_UDP_CSUM) : 0) | - qp->sq_signal_bits; - - ctrl->imm = send_ieth(wr); - - wqe += sizeof *ctrl; - size = sizeof *ctrl / 16; - - switch (qp->mlx4_ib_qp_type) { - case MLX4_IB_QPT_RC: - case MLX4_IB_QPT_UC: - switch (wr->opcode) { - case IB_WR_ATOMIC_CMP_AND_SWP: - case IB_WR_ATOMIC_FETCH_AND_ADD: - case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: - set_raddr_seg(wqe, wr->wr.atomic.remote_addr, - wr->wr.atomic.rkey); - wqe += sizeof (struct mlx4_wqe_raddr_seg); - - set_atomic_seg(wqe, wr); - wqe += sizeof (struct mlx4_wqe_atomic_seg); - - size += (sizeof (struct mlx4_wqe_raddr_seg) + - sizeof (struct mlx4_wqe_atomic_seg)) / 16; - - break; - - case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: - set_raddr_seg(wqe, wr->wr.atomic.remote_addr, - wr->wr.atomic.rkey); - wqe += sizeof (struct mlx4_wqe_raddr_seg); - - set_masked_atomic_seg(wqe, wr); - wqe += sizeof (struct mlx4_wqe_masked_atomic_seg); - - size += (sizeof (struct mlx4_wqe_raddr_seg) + - sizeof (struct mlx4_wqe_masked_atomic_seg)) / 16; - - break; - - case IB_WR_RDMA_READ: - case IB_WR_RDMA_WRITE: - case IB_WR_RDMA_WRITE_WITH_IMM: - set_raddr_seg(wqe, wr->wr.rdma.remote_addr, - wr->wr.rdma.rkey); - wqe += sizeof (struct mlx4_wqe_raddr_seg); - size += sizeof (struct mlx4_wqe_raddr_seg) / 16; - break; - - case IB_WR_LOCAL_INV: - ctrl->srcrb_flags |= - cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER); - set_local_inv_seg(wqe, wr->ex.invalidate_rkey); - wqe += sizeof (struct mlx4_wqe_local_inval_seg); - size += sizeof (struct mlx4_wqe_local_inval_seg) / 16; - break; - - case IB_WR_FAST_REG_MR: - ctrl->srcrb_flags |= - cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER); - set_fmr_seg(wqe, wr); - wqe += sizeof (struct mlx4_wqe_fmr_seg); - size += sizeof (struct mlx4_wqe_fmr_seg) / 16; - break; - - case IB_WR_BIND_MW: - ctrl->srcrb_flags |= - cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER); - set_bind_seg(wqe, wr); - wqe += sizeof(struct mlx4_wqe_bind_seg); - size += sizeof(struct mlx4_wqe_bind_seg) / 16; - default: - /* No extra segments required for sends */ - break; - } - break; - - case MLX4_IB_QPT_TUN_SMI_OWNER: - err = build_sriov_qp0_header(to_msqp(qp), wr, ctrl, &seglen); - if (unlikely(err)) { - *bad_wr = wr; - goto out; - } - wqe += seglen; - size += seglen / 16; - break; - case MLX4_IB_QPT_TUN_SMI: - case MLX4_IB_QPT_TUN_GSI: - /* this is a UD qp used in MAD responses to slaves. */ - set_datagram_seg(wqe, wr); - /* set the forced-loopback bit in the data seg av */ - *(__be32 *) wqe |= cpu_to_be32(0x80000000); - wqe += sizeof (struct mlx4_wqe_datagram_seg); - size += sizeof (struct mlx4_wqe_datagram_seg) / 16; - break; - case MLX4_IB_QPT_UD: - set_datagram_seg(wqe, wr); - wqe += sizeof (struct mlx4_wqe_datagram_seg); - size += sizeof (struct mlx4_wqe_datagram_seg) / 16; - - if (wr->opcode == IB_WR_LSO) { - err = build_lso_seg(wqe, wr, qp, &seglen, &lso_hdr_sz, &blh); - if (unlikely(err)) { - *bad_wr = wr; - goto out; - } - lso_wqe = (__be32 *) wqe; - wqe += seglen; - size += seglen / 16; - } - break; - - case MLX4_IB_QPT_PROXY_SMI_OWNER: - if (unlikely(!mlx4_is_master(to_mdev(ibqp->device)->dev))) { - err = -ENOSYS; - *bad_wr = wr; - goto out; - } - err = build_sriov_qp0_header(to_msqp(qp), wr, ctrl, &seglen); - if (unlikely(err)) { - *bad_wr = wr; - goto out; - } - wqe += seglen; - size += seglen / 16; - /* to start tunnel header on a cache-line boundary */ - add_zero_len_inline(wqe); - wqe += 16; - size++; - build_tunnel_header(wr, wqe, &seglen); - wqe += seglen; - size += seglen / 16; - break; - case MLX4_IB_QPT_PROXY_SMI: - /* don't allow QP0 sends on guests */ - err = -ENOSYS; - *bad_wr = wr; - goto out; - case MLX4_IB_QPT_PROXY_GSI: - /* If we are tunneling special qps, this is a UD qp. - * In this case we first add a UD segment targeting - * the tunnel qp, and then add a header with address - * information */ - set_tunnel_datagram_seg(to_mdev(ibqp->device), wqe, wr, ibqp->qp_type); - wqe += sizeof (struct mlx4_wqe_datagram_seg); - size += sizeof (struct mlx4_wqe_datagram_seg) / 16; - build_tunnel_header(wr, wqe, &seglen); - wqe += seglen; - size += seglen / 16; - break; - - case MLX4_IB_QPT_SMI: - case MLX4_IB_QPT_GSI: - err = build_mlx_header(to_msqp(qp), wr, ctrl, &seglen); - if (unlikely(err)) { - *bad_wr = wr; - goto out; - } - wqe += seglen; - size += seglen / 16; - break; - - default: - break; - } - - /* - * Write data segments in reverse order, so as to - * overwrite cacheline stamp last within each - * cacheline. This avoids issues with WQE - * prefetching. - */ - dseg = wqe; - dseg += wr->num_sge - 1; - - /* Add one more inline data segment for ICRC for MLX sends */ - if (unlikely(qp->mlx4_ib_qp_type == MLX4_IB_QPT_SMI || - qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI || - qp->mlx4_ib_qp_type & - (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER))) { - set_mlx_icrc_seg(dseg + 1); - size += sizeof (struct mlx4_wqe_data_seg) / 16; - } - - if (wr->send_flags & IB_SEND_INLINE && wr->num_sge) { - int sz; - err = lay_inline_data(qp, wr, wqe, &sz); - if (!err) { - inl = 1; - size += sz; - } - } else { - size += wr->num_sge * - (sizeof(struct mlx4_wqe_data_seg) / 16); - for (i = wr->num_sge - 1; i >= 0; --i, --dseg) - set_data_seg(dseg, wr->sg_list + i); - } - - /* - * Possibly overwrite stamping in cacheline with LSO - * segment only after making sure all data segments - * are written. - */ - wmb(); - *lso_wqe = lso_hdr_sz; - ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ? - MLX4_WQE_CTRL_FENCE : 0) | size; - - /* - * Make sure descriptor is fully written before - * setting ownership bit (because HW can start - * executing as soon as we do). - */ - wmb(); - - if (wr->opcode < 0 || wr->opcode >= ARRAY_SIZE(mlx4_ib_opcode)) { - *bad_wr = wr; - err = -EINVAL; - goto out; - } - - ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] | - (ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | blh; - - stamp = ind + qp->sq_spare_wqes; - ind += DIV_ROUND_UP(size * 16, 1U << qp->sq.wqe_shift); - - /* - * We can improve latency by not stamping the last - * send queue WQE until after ringing the doorbell, so - * only stamp here if there are still more WQEs to post. - * - * Same optimization applies to padding with NOP wqe - * in case of WQE shrinking (used to prevent wrap-around - * in the middle of WR). - */ - if (wr->next) { - stamp_send_wqe(qp, stamp, size * 16); - ind = pad_wraparound(qp, ind); - } - } - -out: - if (nreq == 1 && inl && size > 1 && size < qp->bf.buf_size / 16) { - ctrl->owner_opcode |= htonl((qp->sq_next_wqe & 0xffff) << 8); - /* We set above doorbell_qpn bits to 0 as part of vlan - * tag initialization, so |= should be correct. - */ - *(u32 *) (&ctrl->vlan_tag) |= qp->doorbell_qpn; - /* - * Make sure that descriptor is written to memory - * before writing to BlueFlame page. - */ - wmb(); - - ++qp->sq.head; - - mlx4_bf_copy(qp->bf.reg + qp->bf.offset, (unsigned long *) ctrl, - ALIGN(size * 16, 64)); - wc_wmb(); - - qp->bf.offset ^= qp->bf.buf_size; - - } else if (nreq) { - qp->sq.head += nreq; - - /* - * Make sure that descriptors are written before - * doorbell record. - */ - wmb(); - - writel(qp->doorbell_qpn, qp->bf.uar->map + MLX4_SEND_DOORBELL); - - /* - * Make sure doorbells don't leak out of SQ spinlock - * and reach the HCA out of order. - */ - mmiowb(); - - } - - if (likely(nreq)) { - stamp_send_wqe(qp, stamp, size * 16); - ind = pad_wraparound(qp, ind); - qp->sq_next_wqe = ind; - } - - spin_unlock_irqrestore(&qp->sq.lock, flags); - - return err; -} - -int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, - struct ib_recv_wr **bad_wr) -{ - struct mlx4_ib_qp *qp = to_mqp(ibqp); - struct mlx4_wqe_data_seg *scat; - unsigned long flags; - int err = 0; - int nreq; - int ind; - int max_gs; - int i; - - max_gs = qp->rq.max_gs; - spin_lock_irqsave(&qp->rq.lock, flags); - - ind = qp->rq.head & (qp->rq.wqe_cnt - 1); - - for (nreq = 0; wr; ++nreq, wr = wr->next) { - if (mlx4_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { - err = -ENOMEM; - *bad_wr = wr; - goto out; - } - - if (unlikely(wr->num_sge > qp->rq.max_gs)) { - err = -EINVAL; - *bad_wr = wr; - goto out; - } - - scat = get_recv_wqe(qp, ind); - - if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER | - MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) { - ib_dma_sync_single_for_device(ibqp->device, - qp->sqp_proxy_rcv[ind].map, - sizeof (struct mlx4_ib_proxy_sqp_hdr), - DMA_FROM_DEVICE); - scat->byte_count = - cpu_to_be32(sizeof (struct mlx4_ib_proxy_sqp_hdr)); - /* use dma lkey from upper layer entry */ - scat->lkey = cpu_to_be32(wr->sg_list->lkey); - scat->addr = cpu_to_be64(qp->sqp_proxy_rcv[ind].map); - scat++; - max_gs--; - } - - for (i = 0; i < wr->num_sge; ++i) - __set_data_seg(scat + i, wr->sg_list + i); - - if (i < max_gs) { - scat[i].byte_count = 0; - scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY); - scat[i].addr = 0; - } - - qp->rq.wrid[ind] = wr->wr_id; - - ind = (ind + 1) & (qp->rq.wqe_cnt - 1); - } - -out: - if (likely(nreq)) { - qp->rq.head += nreq; - - /* - * Make sure that descriptors are written before - * doorbell record. - */ - wmb(); - - *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff); - } - - spin_unlock_irqrestore(&qp->rq.lock, flags); - - return err; -} - -static inline enum ib_qp_state to_ib_qp_state(enum mlx4_qp_state mlx4_state) -{ - switch (mlx4_state) { - case MLX4_QP_STATE_RST: return IB_QPS_RESET; - case MLX4_QP_STATE_INIT: return IB_QPS_INIT; - case MLX4_QP_STATE_RTR: return IB_QPS_RTR; - case MLX4_QP_STATE_RTS: return IB_QPS_RTS; - case MLX4_QP_STATE_SQ_DRAINING: - case MLX4_QP_STATE_SQD: return IB_QPS_SQD; - case MLX4_QP_STATE_SQER: return IB_QPS_SQE; - case MLX4_QP_STATE_ERR: return IB_QPS_ERR; - default: return -1; - } -} - -static inline enum ib_mig_state to_ib_mig_state(int mlx4_mig_state) -{ - switch (mlx4_mig_state) { - case MLX4_QP_PM_ARMED: return IB_MIG_ARMED; - case MLX4_QP_PM_REARM: return IB_MIG_REARM; - case MLX4_QP_PM_MIGRATED: return IB_MIG_MIGRATED; - default: return -1; - } -} - -static int to_ib_qp_access_flags(int mlx4_flags) -{ - int ib_flags = 0; - - if (mlx4_flags & MLX4_QP_BIT_RRE) - ib_flags |= IB_ACCESS_REMOTE_READ; - if (mlx4_flags & MLX4_QP_BIT_RWE) - ib_flags |= IB_ACCESS_REMOTE_WRITE; - if (mlx4_flags & MLX4_QP_BIT_RAE) - ib_flags |= IB_ACCESS_REMOTE_ATOMIC; - - return ib_flags; -} - -static void to_ib_ah_attr(struct mlx4_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr, - struct mlx4_qp_path *path) -{ - struct mlx4_dev *dev = ibdev->dev; - int is_eth; - - memset(ib_ah_attr, 0, sizeof *ib_ah_attr); - ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1; - - if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports) - return; - - is_eth = rdma_port_get_link_layer(&ibdev->ib_dev, ib_ah_attr->port_num) == - IB_LINK_LAYER_ETHERNET; - if (is_eth) - ib_ah_attr->sl = ((path->sched_queue >> 3) & 0x7) | - ((path->sched_queue & 4) << 1); - else - ib_ah_attr->sl = (path->sched_queue >> 2) & 0xf; - - ib_ah_attr->dlid = be16_to_cpu(path->rlid); - ib_ah_attr->src_path_bits = path->grh_mylmc & 0x7f; - ib_ah_attr->static_rate = path->static_rate ? path->static_rate - 5 : 0; - ib_ah_attr->ah_flags = (path->grh_mylmc & (1 << 7)) ? IB_AH_GRH : 0; - if (ib_ah_attr->ah_flags) { - ib_ah_attr->grh.sgid_index = path->mgid_index; - ib_ah_attr->grh.hop_limit = path->hop_limit; - ib_ah_attr->grh.traffic_class = - (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff; - ib_ah_attr->grh.flow_label = - be32_to_cpu(path->tclass_flowlabel) & 0xfffff; - memcpy(ib_ah_attr->grh.dgid.raw, - path->rgid, sizeof ib_ah_attr->grh.dgid.raw); - } -} - -int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, - struct ib_qp_init_attr *qp_init_attr) -{ - struct mlx4_ib_dev *dev = to_mdev(ibqp->device); - struct mlx4_ib_qp *qp = to_mqp(ibqp); - struct mlx4_qp_context context; - int mlx4_state; - int err = 0; - - mutex_lock(&qp->mutex); - - if (qp->state == IB_QPS_RESET) { - qp_attr->qp_state = IB_QPS_RESET; - goto done; - } - - err = mlx4_qp_query(dev->dev, &qp->mqp, &context); - if (err) { - err = -EINVAL; - goto out; - } - - mlx4_state = be32_to_cpu(context.flags) >> 28; - - qp->state = to_ib_qp_state(mlx4_state); - qp_attr->qp_state = qp->state; - qp_attr->path_mtu = context.mtu_msgmax >> 5; - qp_attr->path_mig_state = - to_ib_mig_state((be32_to_cpu(context.flags) >> 11) & 0x3); - qp_attr->qkey = be32_to_cpu(context.qkey); - qp_attr->rq_psn = be32_to_cpu(context.rnr_nextrecvpsn) & 0xffffff; - qp_attr->sq_psn = be32_to_cpu(context.next_send_psn) & 0xffffff; - qp_attr->dest_qp_num = be32_to_cpu(context.remote_qpn) & 0xffffff; - qp_attr->qp_access_flags = - to_ib_qp_access_flags(be32_to_cpu(context.params2)); - - if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) { - to_ib_ah_attr(dev, &qp_attr->ah_attr, &context.pri_path); - to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context.alt_path); - qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f; - qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; - } - - qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f; - if (qp_attr->qp_state == IB_QPS_INIT) - qp_attr->port_num = qp->port; - else - qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1; - - /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ - qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING; - - qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context.params1) >> 21) & 0x7); - - qp_attr->max_dest_rd_atomic = - 1 << ((be32_to_cpu(context.params2) >> 21) & 0x7); - qp_attr->min_rnr_timer = - (be32_to_cpu(context.rnr_nextrecvpsn) >> 24) & 0x1f; - qp_attr->timeout = context.pri_path.ackto >> 3; - qp_attr->retry_cnt = (be32_to_cpu(context.params1) >> 16) & 0x7; - qp_attr->rnr_retry = (be32_to_cpu(context.params1) >> 13) & 0x7; - qp_attr->alt_timeout = context.alt_path.ackto >> 3; - -done: - qp_attr->cur_qp_state = qp_attr->qp_state; - qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt; - qp_attr->cap.max_recv_sge = qp->rq.max_gs; - - if (!ibqp->uobject) { - qp_attr->cap.max_send_wr = qp->sq.wqe_cnt; - qp_attr->cap.max_send_sge = qp->sq.max_gs; - } else { - qp_attr->cap.max_send_wr = 0; - qp_attr->cap.max_send_sge = 0; - } - - /* - * We don't support inline sends for kernel QPs (yet), and we - * don't know what userspace's value should be. - */ - qp_attr->cap.max_inline_data = 0; - - qp_init_attr->cap = qp_attr->cap; - - qp_init_attr->create_flags = 0; - if (qp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK) - qp_init_attr->create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK; - - if (qp->flags & MLX4_IB_QP_LSO) - qp_init_attr->create_flags |= IB_QP_CREATE_IPOIB_UD_LSO; - - if (qp->flags & MLX4_IB_QP_NETIF) - qp_init_attr->create_flags |= IB_QP_CREATE_NETIF_QP; - - qp_init_attr->sq_sig_type = - qp->sq_signal_bits == cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) ? - IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; - - if (qp->flags & MLX4_IB_QP_CAP_CROSS_CHANNEL) - qp_init_attr->create_flags |= IB_QP_CREATE_CROSS_CHANNEL; - - if (qp->flags & MLX4_IB_QP_CAP_MANAGED_SEND) - qp_init_attr->create_flags |= IB_QP_CREATE_MANAGED_SEND; - - if (qp->flags & MLX4_IB_QP_CAP_MANAGED_RECV) - qp_init_attr->create_flags |= IB_QP_CREATE_MANAGED_RECV; - - qp_init_attr->qpg_type = ibqp->qpg_type; - if (ibqp->qpg_type == IB_QPG_PARENT) - qp_init_attr->cap.qpg_tss_mask_sz = qp->qpg_data->qpg_tss_mask_sz; - else - qp_init_attr->cap.qpg_tss_mask_sz = 0; - -out: - mutex_unlock(&qp->mutex); - return err; -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/srq.c b/sys/ofed/drivers/infiniband/hw/mlx4/srq.c deleted file mode 100644 index 60c5fb025fc7..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/srq.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 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/mlx4/qp.h> -#include <linux/mlx4/srq.h> -#include <linux/slab.h> - -#include "mlx4_ib.h" -#include "user.h" - -static void *get_wqe(struct mlx4_ib_srq *srq, int n) -{ - return mlx4_buf_offset(&srq->buf, n << srq->msrq.wqe_shift); -} - -static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type) -{ - struct ib_event event; - struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq; - - if (ibsrq->event_handler) { - event.device = ibsrq->device; - event.element.srq = ibsrq; - switch (type) { - case MLX4_EVENT_TYPE_SRQ_LIMIT: - event.event = IB_EVENT_SRQ_LIMIT_REACHED; - break; - case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: - event.event = IB_EVENT_SRQ_ERR; - break; - default: - pr_warn("Unexpected event type %d " - "on SRQ %06x\n", type, srq->srqn); - return; - } - - ibsrq->event_handler(&event, ibsrq->srq_context); - } -} - -struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, - struct ib_srq_init_attr *init_attr, - struct ib_udata *udata) -{ - struct mlx4_ib_dev *dev = to_mdev(pd->device); - struct mlx4_ib_srq *srq; - struct mlx4_wqe_srq_next_seg *next; - struct mlx4_wqe_data_seg *scatter; - u32 cqn; - u16 xrcdn; - int desc_size; - int buf_size; - int err; - int i; - - /* Sanity check SRQ size before proceeding */ - if (init_attr->attr.max_wr >= dev->dev->caps.max_srq_wqes || - init_attr->attr.max_sge > dev->dev->caps.max_srq_sge) - return ERR_PTR(-EINVAL); - - srq = kmalloc(sizeof *srq, GFP_KERNEL); - if (!srq) - return ERR_PTR(-ENOMEM); - - mutex_init(&srq->mutex); - spin_lock_init(&srq->lock); - srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1); - srq->msrq.max_gs = init_attr->attr.max_sge; - - desc_size = max(32UL, - roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) + - srq->msrq.max_gs * - sizeof (struct mlx4_wqe_data_seg))); - srq->msrq.wqe_shift = ilog2(desc_size); - - buf_size = srq->msrq.max * desc_size; - - if (pd->uobject) { - struct mlx4_ib_create_srq ucmd; - - if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { - err = -EFAULT; - goto err_srq; - } - - srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - buf_size, 0, 0); - if (IS_ERR(srq->umem)) { - err = PTR_ERR(srq->umem); - goto err_srq; - } - - err = mlx4_mtt_init(dev->dev, ib_umem_page_count(srq->umem), - ilog2(srq->umem->page_size), &srq->mtt); - if (err) - goto err_buf; - - err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem); - if (err) - goto err_mtt; - - err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context), - ucmd.db_addr, &srq->db); - if (err) - goto err_mtt; - } else { - err = mlx4_db_alloc(dev->dev, &srq->db, 0); - if (err) - goto err_srq; - - *srq->db.db = 0; - - if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf)) { - err = -ENOMEM; - goto err_db; - } - - srq->head = 0; - srq->tail = srq->msrq.max - 1; - srq->wqe_ctr = 0; - - for (i = 0; i < srq->msrq.max; ++i) { - next = get_wqe(srq, i); - next->next_wqe_index = - cpu_to_be16((i + 1) & (srq->msrq.max - 1)); - - for (scatter = (void *) (next + 1); - (void *) scatter < (void *) next + desc_size; - ++scatter) - scatter->lkey = cpu_to_be32(MLX4_INVALID_LKEY); - } - - err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift, - &srq->mtt); - if (err) - goto err_buf; - - err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf); - if (err) - goto err_mtt; - - srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL); - if (!srq->wrid) { - err = -ENOMEM; - goto err_mtt; - } - } - - cqn = (init_attr->srq_type == IB_SRQT_XRC) ? - to_mcq(init_attr->ext.xrc.cq)->mcq.cqn : 0; - xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ? - to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn : - (u16) dev->dev->caps.reserved_xrcds; - err = mlx4_srq_alloc(dev->dev, to_mpd(pd)->pdn, cqn, xrcdn, &srq->mtt, - srq->db.dma, &srq->msrq); - if (err) - goto err_wrid; - - srq->msrq.event = mlx4_ib_srq_event; - srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn; - - if (pd->uobject) - if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) { - err = -EFAULT; - goto err_wrid; - } - - init_attr->attr.max_wr = srq->msrq.max - 1; - - return &srq->ibsrq; - -err_wrid: - if (pd->uobject) - mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db); - else - kfree(srq->wrid); - -err_mtt: - mlx4_mtt_cleanup(dev->dev, &srq->mtt); - -err_buf: - if (pd->uobject) - ib_umem_release(srq->umem); - else - mlx4_buf_free(dev->dev, buf_size, &srq->buf); - -err_db: - if (!pd->uobject) - mlx4_db_free(dev->dev, &srq->db); - -err_srq: - kfree(srq); - - return ERR_PTR(err); -} - -int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, - enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) -{ - struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); - struct mlx4_ib_srq *srq = to_msrq(ibsrq); - int ret; - - /* We don't support resizing SRQs (yet?) */ - if (attr_mask & IB_SRQ_MAX_WR) - return -EINVAL; - - if (attr_mask & IB_SRQ_LIMIT) { - if (attr->srq_limit >= srq->msrq.max) - return -EINVAL; - - mutex_lock(&srq->mutex); - ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit); - mutex_unlock(&srq->mutex); - - if (ret) - return ret; - } - - return 0; -} - -int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) -{ - struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); - struct mlx4_ib_srq *srq = to_msrq(ibsrq); - int ret; - int limit_watermark; - - ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark); - if (ret) - return ret; - - srq_attr->srq_limit = limit_watermark; - srq_attr->max_wr = srq->msrq.max - 1; - srq_attr->max_sge = srq->msrq.max_gs; - - return 0; -} - -int mlx4_ib_destroy_srq(struct ib_srq *srq) -{ - struct mlx4_ib_dev *dev = to_mdev(srq->device); - struct mlx4_ib_srq *msrq = to_msrq(srq); - - mlx4_srq_free(dev->dev, &msrq->msrq); - mlx4_mtt_cleanup(dev->dev, &msrq->mtt); - - if (srq->uobject) { - mlx4_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db); - ib_umem_release(msrq->umem); - } else { - kfree(msrq->wrid); - mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift, - &msrq->buf); - mlx4_db_free(dev->dev, &msrq->db); - } - - kfree(msrq); - - return 0; -} - -void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index) -{ - struct mlx4_wqe_srq_next_seg *next; - - /* always called with interrupts disabled. */ - spin_lock(&srq->lock); - - next = get_wqe(srq, srq->tail); - next->next_wqe_index = cpu_to_be16(wqe_index); - srq->tail = wqe_index; - - spin_unlock(&srq->lock); -} - -int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, - struct ib_recv_wr **bad_wr) -{ - struct mlx4_ib_srq *srq = to_msrq(ibsrq); - struct mlx4_wqe_srq_next_seg *next; - struct mlx4_wqe_data_seg *scat; - unsigned long flags; - int err = 0; - int nreq; - int i; - - spin_lock_irqsave(&srq->lock, flags); - - for (nreq = 0; wr; ++nreq, wr = wr->next) { - if (unlikely(wr->num_sge > srq->msrq.max_gs)) { - err = -EINVAL; - *bad_wr = wr; - break; - } - - if (unlikely(srq->head == srq->tail)) { - err = -ENOMEM; - *bad_wr = wr; - break; - } - - srq->wrid[srq->head] = wr->wr_id; - - next = get_wqe(srq, srq->head); - srq->head = be16_to_cpu(next->next_wqe_index); - scat = (struct mlx4_wqe_data_seg *) (next + 1); - - for (i = 0; i < wr->num_sge; ++i) { - scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length); - scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey); - scat[i].addr = cpu_to_be64(wr->sg_list[i].addr); - } - - if (i < srq->msrq.max_gs) { - scat[i].byte_count = 0; - scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY); - scat[i].addr = 0; - } - } - - if (likely(nreq)) { - srq->wqe_ctr += nreq; - - /* - * Make sure that descriptors are written before - * doorbell record. - */ - wmb(); - - *srq->db.db = cpu_to_be32(srq->wqe_ctr); - } - - spin_unlock_irqrestore(&srq->lock, flags); - - return err; -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/sysfs.c b/sys/ofed/drivers/infiniband/hw/mlx4/sysfs.c deleted file mode 100644 index df4549ff3f29..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/sysfs.c +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Copyright (c) 2012 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 "core_priv.h"*/ -#include "mlx4_ib.h" -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/fs.h> - -#include <rdma/ib_mad.h> -/*show_admin_alias_guid returns the administratively assigned value of that GUID. - * Values returned in buf parameter string: - * 0 - requests opensm to assign a value. - * ffffffffffffffff - delete this entry. - * other - value assigned by administrator. - */ -static ssize_t show_admin_alias_guid(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int record_num;/*0-15*/ - int guid_index_in_rec; /*0 - 7*/ - struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = - container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); - struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; - struct mlx4_ib_dev *mdev = port->dev; - - record_num = mlx4_ib_iov_dentry->entry_num / 8 ; - guid_index_in_rec = mlx4_ib_iov_dentry->entry_num % 8 ; - - return sprintf(buf, "%llx\n", - (long long)be64_to_cpu(*(__be64 *)&mdev->sriov.alias_guid. - ports_guid[port->num - 1]. - all_rec_per_port[record_num]. - all_recs[8 * guid_index_in_rec])); -} - -/* store_admin_alias_guid stores the (new) administratively assigned value of that GUID. - * Values in buf parameter string: - * 0 - requests opensm to assign a value. - * 0xffffffffffffffff - delete this entry. - * other - guid value assigned by the administrator. - */ -static ssize_t store_admin_alias_guid(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int record_num;/*0-15*/ - int guid_index_in_rec; /*0 - 7*/ - struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = - container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); - struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; - struct mlx4_ib_dev *mdev = port->dev; - u64 sysadmin_ag_val; - - record_num = mlx4_ib_iov_dentry->entry_num / 8; - guid_index_in_rec = mlx4_ib_iov_dentry->entry_num % 8; - if (0 == record_num && 0 == guid_index_in_rec) { - pr_err("GUID 0 block 0 is RO\n"); - return count; - } - sscanf(buf, "%llx", &sysadmin_ag_val); - *(__be64 *)&mdev->sriov.alias_guid.ports_guid[port->num - 1]. - all_rec_per_port[record_num]. - all_recs[GUID_REC_SIZE * guid_index_in_rec] = - cpu_to_be64(sysadmin_ag_val); - - /* Change the state to be pending for update */ - mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].status - = MLX4_GUID_INFO_STATUS_IDLE ; - - mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].method - = MLX4_GUID_INFO_RECORD_SET; - - switch (sysadmin_ag_val) { - case MLX4_GUID_FOR_DELETE_VAL: - mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].method - = MLX4_GUID_INFO_RECORD_DELETE; - mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].ownership - = MLX4_GUID_SYSADMIN_ASSIGN; - break; - /* The sysadmin requests the SM to re-assign */ - case MLX4_NOT_SET_GUID: - mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].ownership - = MLX4_GUID_DRIVER_ASSIGN; - break; - /* The sysadmin requests a specific value.*/ - default: - mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].ownership - = MLX4_GUID_SYSADMIN_ASSIGN; - break; - } - - /* set the record index */ - mdev->sriov.alias_guid.ports_guid[port->num - 1].all_rec_per_port[record_num].guid_indexes - = mlx4_ib_get_aguid_comp_mask_from_ix(guid_index_in_rec); - - mlx4_ib_init_alias_guid_work(mdev, port->num - 1); - - return count; -} - -static ssize_t show_port_gid(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = - container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); - struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; - struct mlx4_ib_dev *mdev = port->dev; - union ib_gid gid; - ssize_t ret; - - ret = __mlx4_ib_query_gid(&mdev->ib_dev, port->num, - mlx4_ib_iov_dentry->entry_num, &gid, 1); - if (ret) - return ret; - ret = sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - be16_to_cpu(((__be16 *) gid.raw)[0]), - be16_to_cpu(((__be16 *) gid.raw)[1]), - be16_to_cpu(((__be16 *) gid.raw)[2]), - be16_to_cpu(((__be16 *) gid.raw)[3]), - be16_to_cpu(((__be16 *) gid.raw)[4]), - be16_to_cpu(((__be16 *) gid.raw)[5]), - be16_to_cpu(((__be16 *) gid.raw)[6]), - be16_to_cpu(((__be16 *) gid.raw)[7])); - return ret; -} - -static ssize_t show_phys_port_pkey(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_ib_iov_sysfs_attr *mlx4_ib_iov_dentry = - container_of(attr, struct mlx4_ib_iov_sysfs_attr, dentry); - struct mlx4_ib_iov_port *port = mlx4_ib_iov_dentry->ctx; - struct mlx4_ib_dev *mdev = port->dev; - u16 pkey; - ssize_t ret; - - ret = __mlx4_ib_query_pkey(&mdev->ib_dev, port->num, - mlx4_ib_iov_dentry->entry_num, &pkey, 1); - if (ret) - return ret; - - return sprintf(buf, "0x%04x\n", pkey); -} - -#define DENTRY_REMOVE(_dentry) \ -do { \ - sysfs_remove_file((_dentry)->kobj, &(_dentry)->dentry.attr); \ -} while (0); - -static int create_sysfs_entry(void *_ctx, struct mlx4_ib_iov_sysfs_attr *_dentry, - char *_name, struct kobject *_kobj, - ssize_t (*show)(struct device *dev, - struct device_attribute *attr, - char *buf), - ssize_t (*store)(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) - ) -{ - int ret = 0; - struct mlx4_ib_iov_sysfs_attr *vdentry = _dentry; - - vdentry->ctx = _ctx; - vdentry->dentry.show = show; - vdentry->dentry.store = store; - sysfs_attr_init(&vdentry->dentry.attr); - vdentry->dentry.attr.name = vdentry->name; - vdentry->dentry.attr.mode = 0; - vdentry->kobj = _kobj; - snprintf(vdentry->name, 15, "%s", _name); - - if (vdentry->dentry.store) - vdentry->dentry.attr.mode |= S_IWUSR; - - if (vdentry->dentry.show) - vdentry->dentry.attr.mode |= S_IRUGO; - - ret = sysfs_create_file(vdentry->kobj, &vdentry->dentry.attr); - if (ret) { - pr_err("failed to create %s\n", vdentry->dentry.attr.name); - vdentry->ctx = NULL; - return ret; - } - - return ret; -} - -int add_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, - struct attribute *attr) -{ - struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1]; - int ret; - - ret = sysfs_create_file(port->mcgs_parent, attr); - if (ret) - pr_err("failed to create %s\n", attr->name); - - return ret; -} - -void del_sysfs_port_mcg_attr(struct mlx4_ib_dev *device, int port_num, - struct attribute *attr) -{ - struct mlx4_ib_iov_port *port = &device->iov_ports[port_num - 1]; - - sysfs_remove_file(port->mcgs_parent, attr); -} - -static int add_port_entries(struct mlx4_ib_dev *device, int port_num) -{ - int i; - char buff[10]; - struct mlx4_ib_iov_port *port = NULL; - int ret = 0 ; - struct ib_port_attr attr; - - /* get the physical gid and pkey table sizes.*/ - ret = __mlx4_ib_query_port(&device->ib_dev, port_num, &attr, 1); - if (ret) - goto err; - - port = &device->iov_ports[port_num - 1]; - port->dev = device; - port->num = port_num; - /* Directory structure: - * iov - - * port num - - * admin_guids - * gids (operational) - * mcg_table - */ - port->dentr_ar = kzalloc(sizeof (struct mlx4_ib_iov_sysfs_attr_ar), - GFP_KERNEL); - if (!port->dentr_ar) { - ret = -ENOMEM; - goto err; - } - sprintf(buff, "%d", port_num); - port->cur_port = kobject_create_and_add(buff, - kobject_get(device->ports_parent)); - if (!port->cur_port) { - ret = -ENOMEM; - goto kobj_create_err; - } - /* admin GUIDs */ - port->admin_alias_parent = kobject_create_and_add("admin_guids", - kobject_get(port->cur_port)); - if (!port->admin_alias_parent) { - ret = -ENOMEM; - goto err_admin_guids; - } - for (i = 0 ; i < attr.gid_tbl_len; i++) { - sprintf(buff, "%d", i); - port->dentr_ar->dentries[i].entry_num = i; - ret = create_sysfs_entry(port, &port->dentr_ar->dentries[i], - buff, port->admin_alias_parent, - show_admin_alias_guid, store_admin_alias_guid); - if (ret) - goto err_admin_alias_parent; - } - - /* gids subdirectory (operational gids) */ - port->gids_parent = kobject_create_and_add("gids", - kobject_get(port->cur_port)); - if (!port->gids_parent) { - ret = -ENOMEM; - goto err_gids; - } - - for (i = 0 ; i < attr.gid_tbl_len; i++) { - sprintf(buff, "%d", i); - port->dentr_ar->dentries[attr.gid_tbl_len + i].entry_num = i; - ret = create_sysfs_entry(port, - &port->dentr_ar->dentries[attr.gid_tbl_len + i], - buff, - port->gids_parent, show_port_gid, NULL); - if (ret) - goto err_gids_parent; - } - - /* physical port pkey table */ - port->pkeys_parent = - kobject_create_and_add("pkeys", kobject_get(port->cur_port)); - if (!port->pkeys_parent) { - ret = -ENOMEM; - goto err_pkeys; - } - - for (i = 0 ; i < attr.pkey_tbl_len; i++) { - sprintf(buff, "%d", i); - port->dentr_ar->dentries[2 * attr.gid_tbl_len + i].entry_num = i; - ret = create_sysfs_entry(port, - &port->dentr_ar->dentries[2 * attr.gid_tbl_len + i], - buff, port->pkeys_parent, - show_phys_port_pkey, NULL); - if (ret) - goto err_pkeys_parent; - } - - /* MCGs table */ - port->mcgs_parent = - kobject_create_and_add("mcgs", kobject_get(port->cur_port)); - if (!port->mcgs_parent) { - ret = -ENOMEM; - goto err_mcgs; - } - return 0; - -err_mcgs: - kobject_put(port->cur_port); - -err_pkeys_parent: - kobject_put(port->pkeys_parent); - -err_pkeys: - kobject_put(port->cur_port); - -err_gids_parent: - kobject_put(port->gids_parent); - -err_gids: - kobject_put(port->cur_port); - -err_admin_alias_parent: - kobject_put(port->admin_alias_parent); - -err_admin_guids: - kobject_put(port->cur_port); - kobject_put(port->cur_port); /* once more for create_and_add buff */ - -kobj_create_err: - kobject_put(device->ports_parent); - kfree(port->dentr_ar); - -err: - pr_err("add_port_entries FAILED: for port:%d, error: %d\n", - port_num, ret); - return ret; -} - -static void get_name(struct mlx4_ib_dev *dev, char *name, int i, int max) -{ - char base_name[9]; - - /* pci_name format is: bus:dev:func -> xxxx:yy:zz.n */ - strlcpy(name, pci_name(dev->dev->pdev), max); - strncpy(base_name, name, 8); /*till xxxx:yy:*/ - base_name[8] = '\0'; - /* with no ARI only 3 last bits are used so when the fn is higher than 8 - * need to add it to the dev num, so count in the last number will be - * modulo 8 */ - sprintf(name, "%s%.2d.%d", base_name, (i/8), (i%8)); -} - -struct mlx4_port { - struct kobject kobj; - struct mlx4_ib_dev *dev; - struct attribute_group pkey_group; - struct attribute_group gid_group; - u8 port_num; - int slave; -}; - - -static void mlx4_port_release(struct kobject *kobj) -{ - struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj); - struct attribute *a; - int i; - - for (i = 0; (a = p->pkey_group.attrs[i]); ++i) - kfree(a); - kfree(p->pkey_group.attrs); - for (i = 0; (a = p->gid_group.attrs[i]); ++i) - kfree(a); - kfree(p->gid_group.attrs); - kfree(p); -} - -struct port_attribute { - struct attribute attr; - ssize_t (*show)(struct mlx4_port *, struct port_attribute *, char *buf); - ssize_t (*store)(struct mlx4_port *, struct port_attribute *, - const char *buf, size_t count); -}; - -static ssize_t port_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct port_attribute *port_attr = - container_of(attr, struct port_attribute, attr); - struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj); - - if (!port_attr->show) - return -EIO; - return port_attr->show(p, port_attr, buf); -} - -static ssize_t port_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t size) -{ - struct port_attribute *port_attr = - container_of(attr, struct port_attribute, attr); - struct mlx4_port *p = container_of(kobj, struct mlx4_port, kobj); - - if (!port_attr->store) - return -EIO; - return port_attr->store(p, port_attr, buf, size); -} - -static const struct sysfs_ops port_sysfs_ops = { - .show = port_attr_show, - .store = port_attr_store, -}; - -static struct kobj_type port_type = { - .release = mlx4_port_release, - .sysfs_ops = &port_sysfs_ops, -}; - -struct port_table_attribute { - struct port_attribute attr; - char name[8]; - int index; -}; - -static ssize_t show_port_pkey(struct mlx4_port *p, struct port_attribute *attr, - char *buf) -{ - struct port_table_attribute *tab_attr = - container_of(attr, struct port_table_attribute, attr); - ssize_t ret = -ENODEV; - - if (p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1][tab_attr->index] >= - (p->dev->dev->caps.pkey_table_len[p->port_num])) - ret = sprintf(buf, "none\n"); - else - ret = sprintf(buf, "%d\n", - p->dev->pkeys.virt2phys_pkey[p->slave] - [p->port_num - 1][tab_attr->index]); - return ret; -} - -static ssize_t store_port_pkey(struct mlx4_port *p, struct port_attribute *attr, - const char *buf, size_t count) -{ - struct port_table_attribute *tab_attr = - container_of(attr, struct port_table_attribute, attr); - int idx; - int err; - - /* do not allow remapping Dom0 virtual pkey table */ - if (p->slave == mlx4_master_func_num(p->dev->dev)) - return -EINVAL; - - if (!strncasecmp(buf, "no", 2)) - idx = p->dev->dev->phys_caps.pkey_phys_table_len[p->port_num] - 1; - else if (sscanf(buf, "%i", &idx) != 1 || - idx >= p->dev->dev->caps.pkey_table_len[p->port_num] || - idx < 0) - return -EINVAL; - - p->dev->pkeys.virt2phys_pkey[p->slave][p->port_num - 1] - [tab_attr->index] = idx; - mlx4_sync_pkey_table(p->dev->dev, p->slave, p->port_num, - tab_attr->index, idx); - err = mlx4_gen_pkey_eqe(p->dev->dev, p->slave, p->port_num); - if (err) { - pr_err("mlx4_gen_pkey_eqe failed for slave %d," - " port %d, index %d\n", p->slave, p->port_num, idx); - return err; - } - return count; -} - -static ssize_t show_port_gid_idx(struct mlx4_port *p, - struct port_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", p->slave); -} - -static struct attribute ** -alloc_group_attrs(ssize_t (*show)(struct mlx4_port *, - struct port_attribute *, char *buf), - ssize_t (*store)(struct mlx4_port *, struct port_attribute *, - const char *buf, size_t count), - int len) -{ - struct attribute **tab_attr; - struct port_table_attribute *element; - int i; - - tab_attr = kcalloc(1 + len, sizeof (struct attribute *), GFP_KERNEL); - if (!tab_attr) - return NULL; - - for (i = 0; i < len; i++) { - element = kzalloc(sizeof (struct port_table_attribute), - GFP_KERNEL); - if (!element) - goto err; - if (snprintf(element->name, sizeof (element->name), - "%d", i) >= sizeof (element->name)) { - kfree(element); - goto err; - } - sysfs_attr_init(&element->attr.attr); - element->attr.attr.name = element->name; - if (store) { - element->attr.attr.mode = S_IWUSR | S_IRUGO; - element->attr.store = store; - } else - element->attr.attr.mode = S_IRUGO; - - element->attr.show = show; - element->index = i; - tab_attr[i] = &element->attr.attr; - } - return tab_attr; - -err: - while (--i >= 0) - kfree(tab_attr[i]); - kfree(tab_attr); - return NULL; -} - -static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave) -{ - struct mlx4_port *p; - int i; - int ret; - int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port_num) == - IB_LINK_LAYER_ETHERNET; - - p = kzalloc(sizeof *p, GFP_KERNEL); - if (!p) - return -ENOMEM; - - p->dev = dev; - p->port_num = port_num; - p->slave = slave; - - ret = kobject_init_and_add(&p->kobj, &port_type, - kobject_get(dev->dev_ports_parent[slave]), - "%d", port_num); - if (ret) - goto err_alloc; - - p->pkey_group.name = "pkey_idx"; - if (is_eth) - p->pkey_group.attrs = - alloc_group_attrs(show_port_pkey, NULL, - dev->dev->caps.pkey_table_len[port_num]); - else - p->pkey_group.attrs = - alloc_group_attrs(show_port_pkey, store_port_pkey, - dev->dev->caps.pkey_table_len[port_num]); - if (!p->pkey_group.attrs) - goto err_alloc; - - ret = sysfs_create_group(&p->kobj, &p->pkey_group); - if (ret) - goto err_free_pkey; - - p->gid_group.name = "gid_idx"; - p->gid_group.attrs = alloc_group_attrs(show_port_gid_idx, NULL, 1); - if (!p->gid_group.attrs) - goto err_free_pkey; - - ret = sysfs_create_group(&p->kobj, &p->gid_group); - if (ret) - goto err_free_gid; - - list_add_tail(&p->kobj.entry, &dev->pkeys.pkey_port_list[slave]); - return 0; - -err_free_gid: - kfree(p->gid_group.attrs[0]); - kfree(p->gid_group.attrs); - -err_free_pkey: - for (i = 0; i < dev->dev->caps.pkey_table_len[port_num]; ++i) - kfree(p->pkey_group.attrs[i]); - kfree(p->pkey_group.attrs); - -err_alloc: - kobject_put(dev->dev_ports_parent[slave]); - kfree(p); - return ret; -} - -static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave) -{ - char name[32]; - int err; - int port; - struct kobject *p, *t; - struct mlx4_port *mport; - - get_name(dev, name, slave, sizeof name); - - dev->pkeys.device_parent[slave] = - kobject_create_and_add(name, kobject_get(dev->iov_parent)); - - if (!dev->pkeys.device_parent[slave]) { - err = -ENOMEM; - goto fail_dev; - } - - INIT_LIST_HEAD(&dev->pkeys.pkey_port_list[slave]); - - dev->dev_ports_parent[slave] = - kobject_create_and_add("ports", - kobject_get(dev->pkeys.device_parent[slave])); - - if (!dev->dev_ports_parent[slave]) { - err = -ENOMEM; - goto err_ports; - } - - for (port = 1; port <= dev->dev->caps.num_ports; ++port) { - err = add_port(dev, port, slave); - if (err) - goto err_add; - } - return 0; - -err_add: - list_for_each_entry_safe(p, t, - &dev->pkeys.pkey_port_list[slave], - entry) { - list_del(&p->entry); - mport = container_of(p, struct mlx4_port, kobj); - sysfs_remove_group(p, &mport->pkey_group); - sysfs_remove_group(p, &mport->gid_group); - kobject_put(p); - } - kobject_put(dev->dev_ports_parent[slave]); - -err_ports: - kobject_put(dev->pkeys.device_parent[slave]); - /* extra put for the device_parent create_and_add */ - kobject_put(dev->pkeys.device_parent[slave]); - -fail_dev: - kobject_put(dev->iov_parent); - return err; -} - -static int register_pkey_tree(struct mlx4_ib_dev *device) -{ - int i; - - if (!mlx4_is_master(device->dev)) - return 0; - - for (i = 0; i <= device->dev->num_vfs; ++i) - register_one_pkey_tree(device, i); - - return 0; -} - -static void unregister_pkey_tree(struct mlx4_ib_dev *device) -{ - int slave; - struct kobject *p, *t; - struct mlx4_port *port; - - if (!mlx4_is_master(device->dev)) - return; - - for (slave = device->dev->num_vfs; slave >= 0; --slave) { - list_for_each_entry_safe(p, t, - &device->pkeys.pkey_port_list[slave], - entry) { - list_del(&p->entry); - port = container_of(p, struct mlx4_port, kobj); - sysfs_remove_group(p, &port->pkey_group); - sysfs_remove_group(p, &port->gid_group); - kobject_put(p); - kobject_put(device->dev_ports_parent[slave]); - } - kobject_put(device->dev_ports_parent[slave]); - kobject_put(device->pkeys.device_parent[slave]); - kobject_put(device->pkeys.device_parent[slave]); - kobject_put(device->iov_parent); - } -} - -int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *dev) -{ - int i; - int ret = 0; - - if (!mlx4_is_master(dev->dev)) - return 0; - - dev->iov_parent = - kobject_create_and_add("iov", - kobject_get(dev->ib_dev.ports_parent->parent)); - if (!dev->iov_parent) { - ret = -ENOMEM; - goto err; - } - dev->ports_parent = - kobject_create_and_add("ports", - kobject_get(dev->iov_parent)); - if (!dev->iov_parent) { - ret = -ENOMEM; - goto err_ports; - } - - for (i = 1; i <= dev->ib_dev.phys_port_cnt; ++i) { - ret = add_port_entries(dev, i); - if (ret) - goto err_add_entries; - } - - ret = register_pkey_tree(dev); - if (ret) - goto err_add_entries; - return 0; - -err_add_entries: - kobject_put(dev->ports_parent); - -err_ports: - kobject_put(dev->iov_parent); -err: - kobject_put(dev->ib_dev.ports_parent->parent); - pr_err("mlx4_ib_device_register_sysfs error (%d)\n", ret); - return ret; -} - -static void unregister_alias_guid_tree(struct mlx4_ib_dev *device) -{ - struct mlx4_ib_iov_port *p; - int i; - - if (!mlx4_is_master(device->dev)) - return; - - for (i = 0; i < device->dev->caps.num_ports; i++) { - p = &device->iov_ports[i]; - kobject_put(p->admin_alias_parent); - kobject_put(p->gids_parent); - kobject_put(p->pkeys_parent); - kobject_put(p->mcgs_parent); - kobject_put(p->cur_port); - kobject_put(p->cur_port); - kobject_put(p->cur_port); - kobject_put(p->cur_port); - kobject_put(p->cur_port); - kobject_put(p->dev->ports_parent); - kfree(p->dentr_ar); - } -} - -void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device) -{ - unregister_alias_guid_tree(device); - unregister_pkey_tree(device); - kobject_put(device->ports_parent); - kobject_put(device->iov_parent); - kobject_put(device->iov_parent); - kobject_put(device->ib_dev.ports_parent->parent); -} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/user.h b/sys/ofed/drivers/infiniband/hw/mlx4/user.h deleted file mode 100644 index 07e6769ef43b..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/user.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 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. - */ - -#ifndef MLX4_IB_USER_H -#define MLX4_IB_USER_H - -#include <linux/types.h> - -/* - * Increment this value if any changes that break userspace ABI - * compatibility are made. - */ - -#define MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION 3 -#define MLX4_IB_UVERBS_ABI_VERSION 4 - -/* - * Make sure that all structs defined in this file remain laid out so - * that they pack the same way on 32-bit and 64-bit architectures (to - * avoid incompatibility between 32-bit userspace and 64-bit kernels). - * In particular do not use pointer types -- pass pointers in __u64 - * instead. - */ - -struct mlx4_ib_alloc_ucontext_resp_v3 { - __u32 qp_tab_size; - __u16 bf_reg_size; - __u16 bf_regs_per_page; -}; - -struct mlx4_ib_alloc_ucontext_resp { - __u32 dev_caps; - __u32 qp_tab_size; - __u16 bf_reg_size; - __u16 bf_regs_per_page; - __u32 cqe_size; -}; - -struct mlx4_ib_alloc_pd_resp { - __u32 pdn; - __u32 reserved; -}; - -struct mlx4_ib_create_cq { - __u64 buf_addr; - __u64 db_addr; -}; - -struct mlx4_ib_create_cq_resp { - __u32 cqn; - __u32 reserved; -}; - -struct mlx4_ib_resize_cq { - __u64 buf_addr; -}; - -struct mlx4_ib_create_srq { - __u64 buf_addr; - __u64 db_addr; -}; - -struct mlx4_ib_create_srq_resp { - __u32 srqn; - __u32 reserved; -}; - -struct mlx4_ib_create_qp { - __u64 buf_addr; - __u64 db_addr; - __u8 log_sq_bb_count; - __u8 log_sq_stride; - __u8 sq_no_prefetch; - __u8 reserved[5]; -}; - -#endif /* MLX4_IB_USER_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/wc.c b/sys/ofed/drivers/infiniband/hw/mlx4/wc.c deleted file mode 100644 index c73a61c2ece3..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/wc.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2006-2007 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/pci.h> -#include "wc.h" - -#if defined(__i386__) || defined(__x86_64__) - -pgprot_t pgprot_wc(pgprot_t _prot) -{ - return pgprot_writecombine(_prot); -} - -int mlx4_wc_enabled(void) -{ - return 1; -} - -#elif defined(CONFIG_PPC64) - -pgprot_t pgprot_wc(pgprot_t _prot) -{ - return __pgprot((pgprot_val(_prot) | _PAGE_NO_CACHE) & - ~(pgprot_t)_PAGE_GUARDED); -} - -int mlx4_wc_enabled(void) -{ - return 1; -} - -#else /* !(defined(__i386__) || defined(__x86_64__)) */ - -pgprot_t pgprot_wc(pgprot_t _prot) -{ - return pgprot_noncached(_prot); -} - -int mlx4_wc_enabled(void) -{ - return 0; -} - -#endif diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/wc.h b/sys/ofed/drivers/infiniband/hw/mlx4/wc.h deleted file mode 100644 index f32fe1ee55e7..000000000000 --- a/sys/ofed/drivers/infiniband/hw/mlx4/wc.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2006-2007 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. - */ - -#ifndef mlx4_WC_H -#define mlx4_WC_H - -#include <asm/pgtable.h> - -int mlx4_wc_enabled(void); -pgprot_t pgprot_wc(pgprot_t _prot); - -#endif diff --git a/sys/ofed/drivers/net/mlx4/Makefile b/sys/ofed/drivers/net/mlx4/Makefile deleted file mode 100644 index 05338e804fa2..000000000000 --- a/sys/ofed/drivers/net/mlx4/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# $FreeBSD$ -#.PATH: ${.CURDIR}/../../ofed/drivers/net/mlx4:${.CURDIR}/../../ofed/include/linux -.PATH: ${.CURDIR}/../../../../../include/linux - -.include <src.opts.mk> - - -KMOD = mlx4 -SRCS = device_if.h bus_if.h pci_if.h vnode_if.h -SRCS+= alloc.c catas.c cmd.c cq.c eq.c fw.c icm.c intf.c main.c mcg.c mr.c linux_compat.c linux_radix.c -SRCS+= pd.c port.c profile.c qp.c reset.c sense.c srq.c resource_tracker.c sys_tune.c -SRCS+= opt_inet.h opt_inet6.h - - -#CFLAGS+= -I${.CURDIR}/../../ofed/drivers/net/mlx4 -#CFLAGS+= -I${.CURDIR}/../../ofed/include/ -CFLAGS+= -I${.CURDIR}/../../../../../include - -.if !defined(KERNBUILDDIR) -.if ${MK_INET_SUPPORT} != "no" -opt_inet.h: - @echo "#define INET 1" > ${.TARGET} -.endif - -.if ${MK_INET6_SUPPORT} != "no" -opt_inet6.h: - @echo "#define INET6 1" > ${.TARGET} -.endif -.endif - -.include <bsd.kmod.mk> - -CFLAGS+= -Wno-cast-qual -Wno-pointer-arith diff --git a/sys/ofed/drivers/net/mlx4/alloc.c b/sys/ofed/drivers/net/mlx4/alloc.c deleted file mode 100644 index da36b34d98b5..000000000000 --- a/sys/ofed/drivers/net/mlx4/alloc.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 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/errno.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/vmalloc.h> - -#include "mlx4.h" - -u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) -{ - u32 obj; - - spin_lock(&bitmap->lock); - - obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last); - if (obj >= bitmap->max) { - bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) - & bitmap->mask; - obj = find_first_zero_bit(bitmap->table, bitmap->max); - } - - if (obj < bitmap->max) { - set_bit(obj, bitmap->table); - bitmap->last = (obj + 1); - if (bitmap->last == bitmap->max) - bitmap->last = 0; - obj |= bitmap->top; - } else - obj = -1; - - if (obj != -1) - --bitmap->avail; - - spin_unlock(&bitmap->lock); - - return obj; -} - -void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr) -{ - mlx4_bitmap_free_range(bitmap, obj, 1, use_rr); -} - -static unsigned long find_aligned_range(unsigned long *bitmap, - u32 start, u32 nbits, - int len, int align, u32 skip_mask) -{ - unsigned long end, i; - -again: - start = ALIGN(start, align); - - while ((start < nbits) && (test_bit(start, bitmap) || - (start & skip_mask))) - start += align; - - if (start >= nbits) - return -1; - - end = start+len; - if (end > nbits) - return -1; - - for (i = start + 1; i < end; i++) { - if (test_bit(i, bitmap) || ((u32)i & skip_mask)) { - start = i + 1; - goto again; - } - } - - return start; -} - -u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, - int align, u32 skip_mask) -{ - u32 obj; - - if (likely(cnt == 1 && align == 1 && !skip_mask)) - return mlx4_bitmap_alloc(bitmap); - - spin_lock(&bitmap->lock); - - obj = find_aligned_range(bitmap->table, bitmap->last, - bitmap->max, cnt, align, skip_mask); - if (obj >= bitmap->max) { - bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) - & bitmap->mask; - obj = find_aligned_range(bitmap->table, 0, bitmap->max, - cnt, align, skip_mask); - } - - if (obj < bitmap->max) { - bitmap_set(bitmap->table, obj, cnt); - if (obj == bitmap->last) { - bitmap->last = (obj + cnt); - if (bitmap->last >= bitmap->max) - bitmap->last = 0; - } - obj |= bitmap->top; - } else - obj = -1; - - if (obj != -1) - bitmap->avail -= cnt; - - spin_unlock(&bitmap->lock); - - return obj; -} - -u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap) -{ - return bitmap->avail; -} - -void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt, - int use_rr) -{ - obj &= bitmap->max + bitmap->reserved_top - 1; - - spin_lock(&bitmap->lock); - if (!use_rr) { - bitmap->last = min(bitmap->last, obj); - bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) - & bitmap->mask; - } - bitmap_clear(bitmap->table, obj, cnt); - bitmap->avail += cnt; - spin_unlock(&bitmap->lock); -} - -int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, - u32 reserved_bot, u32 reserved_top) -{ - /* sanity check */ - if (num <= (u64)reserved_top + reserved_bot) - return -EINVAL; - - /* num must be a power of 2 */ - if (num != roundup_pow_of_two(num)) - return -EINVAL; - - if (reserved_bot + reserved_top >= num) - return -EINVAL; - - bitmap->last = 0; - bitmap->top = 0; - bitmap->max = num - reserved_top; - bitmap->mask = mask; - bitmap->reserved_top = reserved_top; - bitmap->avail = num - reserved_top - reserved_bot; - spin_lock_init(&bitmap->lock); - bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * - sizeof (long), GFP_KERNEL); - if (!bitmap->table) - return -ENOMEM; - - bitmap_set(bitmap->table, 0, reserved_bot); - - return 0; -} - -void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap) -{ - kfree(bitmap->table); -} - -/* - * Handling for queue buffers -- we allocate a bunch of memory and - * register it in a memory region at HCA virtual address 0. If the - * requested size is > max_direct, we split the allocation into - * multiple pages, so we don't require too much contiguous memory. - */ - -int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, - struct mlx4_buf *buf) -{ - dma_addr_t t; - - if (size <= max_direct) { - buf->nbufs = 1; - buf->npages = 1; - buf->page_shift = get_order(size) + PAGE_SHIFT; - buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev, - size, &t, GFP_KERNEL); - if (!buf->direct.buf) - return -ENOMEM; - - buf->direct.map = t; - - while (t & ((1 << buf->page_shift) - 1)) { - --buf->page_shift; - buf->npages *= 2; - } - - memset(buf->direct.buf, 0, size); - } else { - int i; - - buf->direct.buf = NULL; - buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; - buf->npages = buf->nbufs; - buf->page_shift = PAGE_SHIFT; - buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list), - GFP_KERNEL); - if (!buf->page_list) - return -ENOMEM; - - for (i = 0; i < buf->nbufs; ++i) { - buf->page_list[i].buf = - dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, - &t, GFP_KERNEL); - if (!buf->page_list[i].buf) - goto err_free; - - buf->page_list[i].map = t; - - memset(buf->page_list[i].buf, 0, PAGE_SIZE); - } - - if (BITS_PER_LONG == 64) { - struct page **pages; - pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); - if (!pages) - goto err_free; - for (i = 0; i < buf->nbufs; ++i) - pages[i] = virt_to_page(buf->page_list[i].buf); - buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); - kfree(pages); - if (!buf->direct.buf) - goto err_free; - } - } - - return 0; - -err_free: - mlx4_buf_free(dev, size, buf); - - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(mlx4_buf_alloc); - -void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) -{ - int i; - - if (buf->nbufs == 1) - dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf, - buf->direct.map); - else { - if (BITS_PER_LONG == 64 && buf->direct.buf) - vunmap(buf->direct.buf); - - for (i = 0; i < buf->nbufs; ++i) - if (buf->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - buf->page_list[i].buf, - buf->page_list[i].map); - kfree(buf->page_list); - } -} -EXPORT_SYMBOL_GPL(mlx4_buf_free); - -static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device) -{ - struct mlx4_db_pgdir *pgdir; - - pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL); - if (!pgdir) - return NULL; - - bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2); - pgdir->bits[0] = pgdir->order0; - pgdir->bits[1] = pgdir->order1; - pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE, - &pgdir->db_dma, GFP_KERNEL); - if (!pgdir->db_page) { - kfree(pgdir); - return NULL; - } - - return pgdir; -} - -static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, - struct mlx4_db *db, int order) -{ - int o; - int i; - - for (o = order; o <= 1; ++o) { - i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o); - if (i < MLX4_DB_PER_PAGE >> o) - goto found; - } - - return -ENOMEM; - -found: - clear_bit(i, pgdir->bits[o]); - - i <<= o; - - if (o > order) - set_bit(i ^ 1, pgdir->bits[order]); - - db->u.pgdir = pgdir; - db->index = i; - db->db = pgdir->db_page + db->index; - db->dma = pgdir->db_dma + db->index * 4; - db->order = order; - - return 0; -} - -int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_db_pgdir *pgdir; - int ret = 0; - - mutex_lock(&priv->pgdir_mutex); - - list_for_each_entry(pgdir, &priv->pgdir_list, list) - if (!mlx4_alloc_db_from_pgdir(pgdir, db, order)) - goto out; - - pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev)); - if (!pgdir) { - ret = -ENOMEM; - goto out; - } - - list_add(&pgdir->list, &priv->pgdir_list); - - /* This should never fail -- we just allocated an empty page: */ - WARN_ON(mlx4_alloc_db_from_pgdir(pgdir, db, order)); - -out: - mutex_unlock(&priv->pgdir_mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_db_alloc); - -void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int o; - int i; - - mutex_lock(&priv->pgdir_mutex); - - o = db->order; - i = db->index; - - if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) { - clear_bit(i ^ 1, db->u.pgdir->order0); - ++o; - } - i >>= o; - set_bit(i, db->u.pgdir->bits[o]); - - if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) { - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - db->u.pgdir->db_page, db->u.pgdir->db_dma); - list_del(&db->u.pgdir->list); - kfree(db->u.pgdir); - } - - mutex_unlock(&priv->pgdir_mutex); -} -EXPORT_SYMBOL_GPL(mlx4_db_free); - -int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, - int size, int max_direct) -{ - int err; - - err = mlx4_db_alloc(dev, &wqres->db, 1); - if (err) - return err; - - *wqres->db.db = 0; - - err = mlx4_buf_alloc(dev, size, max_direct, &wqres->buf); - if (err) - goto err_db; - - err = mlx4_mtt_init(dev, wqres->buf.npages, wqres->buf.page_shift, - &wqres->mtt); - if (err) - goto err_buf; - - err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf); - if (err) - goto err_mtt; - - return 0; - -err_mtt: - mlx4_mtt_cleanup(dev, &wqres->mtt); -err_buf: - mlx4_buf_free(dev, size, &wqres->buf); -err_db: - mlx4_db_free(dev, &wqres->db); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_alloc_hwq_res); - -void mlx4_free_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, - int size) -{ - mlx4_mtt_cleanup(dev, &wqres->mtt); - mlx4_buf_free(dev, size, &wqres->buf); - mlx4_db_free(dev, &wqres->db); -} -EXPORT_SYMBOL_GPL(mlx4_free_hwq_res); diff --git a/sys/ofed/drivers/net/mlx4/catas.c b/sys/ofed/drivers/net/mlx4/catas.c deleted file mode 100644 index 497e0ddb8956..000000000000 --- a/sys/ofed/drivers/net/mlx4/catas.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 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. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/workqueue.h> -#include <linux/module.h> - -#include <asm/byteorder.h> - -#include "mlx4.h" - -#define MLX4_CATAS_POLL_INTERVAL (5 * HZ) - -static DEFINE_SPINLOCK(catas_lock); - -static LIST_HEAD(catas_list); -static struct work_struct catas_work; - -static int internal_err_reset = 1; -module_param(internal_err_reset, int, 0644); -MODULE_PARM_DESC(internal_err_reset, - "Reset device on internal errors if non-zero" - " (default 1, in SRIOV mode default is 0)"); - -static void dump_err_buf(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - int i; - - mlx4_err(dev, "Internal error detected:\n"); - for (i = 0; i < priv->fw.catas_size; ++i) - mlx4_err(dev, " buf[%02x]: %08x\n", - i, swab32(readl(priv->catas_err.map + i))); -} - -static void poll_catas(unsigned long dev_ptr) -{ - struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr; - struct mlx4_priv *priv = mlx4_priv(dev); - - if (readl(priv->catas_err.map)) { - /* If the device is off-line, we cannot try to recover it */ - if (pci_channel_offline(dev->pdev)) - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); - else { - dump_err_buf(dev); - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); - - if (internal_err_reset) { - spin_lock(&catas_lock); - list_add(&priv->catas_err.list, &catas_list); - spin_unlock(&catas_lock); - - queue_work(mlx4_wq, &catas_work); - } - } - } else - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); -} - -static void catas_reset(struct work_struct *work) -{ - struct mlx4_priv *priv, *tmppriv; - struct mlx4_dev *dev; - - LIST_HEAD(tlist); - int ret; - - spin_lock_irq(&catas_lock); - list_splice_init(&catas_list, &tlist); - spin_unlock_irq(&catas_lock); - - list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { - struct pci_dev *pdev = priv->dev.pdev; - - /* If the device is off-line, we cannot reset it */ - if (pci_channel_offline(pdev)) - continue; - - ret = mlx4_restart_one(priv->dev.pdev); - /* 'priv' now is not valid */ - if (ret) - pr_err("mlx4 %s: Reset failed (%d)\n", - pci_name(pdev), ret); - else { - dev = pci_get_drvdata(pdev); - mlx4_dbg(dev, "Reset succeeded\n"); - } - } -} - -void mlx4_start_catas_poll(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - phys_addr_t addr; - - /*If we are in SRIOV the default of the module param must be 0*/ - if (mlx4_is_mfunc(dev)) - internal_err_reset = 0; - - INIT_LIST_HEAD(&priv->catas_err.list); - init_timer(&priv->catas_err.timer); - priv->catas_err.map = NULL; - - addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + - priv->fw.catas_offset; - - priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); - if (!priv->catas_err.map) { - mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", - (unsigned long long) addr); - return; - } - - priv->catas_err.timer.data = (unsigned long) dev; - priv->catas_err.timer.function = poll_catas; - priv->catas_err.timer.expires = - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL); - add_timer(&priv->catas_err.timer); -} - -void mlx4_stop_catas_poll(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - del_timer_sync(&priv->catas_err.timer); - - if (priv->catas_err.map) { - iounmap(priv->catas_err.map); - priv->catas_err.map = NULL; - } - - spin_lock_irq(&catas_lock); - list_del_init(&priv->catas_err.list); - spin_unlock_irq(&catas_lock); -} - -void __init mlx4_catas_init(void) -{ - INIT_WORK(&catas_work, catas_reset); -} diff --git a/sys/ofed/drivers/net/mlx4/cmd.c b/sys/ofed/drivers/net/mlx4/cmd.c deleted file mode 100644 index 9d5177965162..000000000000 --- a/sys/ofed/drivers/net/mlx4/cmd.c +++ /dev/null @@ -1,2606 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. 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/sched.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/errno.h> - -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/device.h> -#include <linux/semaphore.h> -#include <rdma/ib_smi.h> - -#include <asm/io.h> -#include <linux/ktime.h> - -#include "mlx4.h" -#include "fw.h" - -#define CMD_POLL_TOKEN 0xffff -#define INBOX_MASK 0xffffffffffffff00ULL - -#define CMD_CHAN_VER 1 -#define CMD_CHAN_IF_REV 1 - -enum { - /* command completed successfully: */ - CMD_STAT_OK = 0x00, - /* Internal error (such as a bus error) occurred while processing command: */ - CMD_STAT_INTERNAL_ERR = 0x01, - /* Operation/command not supported or opcode modifier not supported: */ - CMD_STAT_BAD_OP = 0x02, - /* Parameter not supported or parameter out of range: */ - CMD_STAT_BAD_PARAM = 0x03, - /* System not enabled or bad system state: */ - CMD_STAT_BAD_SYS_STATE = 0x04, - /* Attempt to access reserved or unallocaterd resource: */ - CMD_STAT_BAD_RESOURCE = 0x05, - /* Requested resource is currently executing a command, or is otherwise busy: */ - CMD_STAT_RESOURCE_BUSY = 0x06, - /* Required capability exceeds device limits: */ - CMD_STAT_EXCEED_LIM = 0x08, - /* Resource is not in the appropriate state or ownership: */ - CMD_STAT_BAD_RES_STATE = 0x09, - /* Index out of range: */ - CMD_STAT_BAD_INDEX = 0x0a, - /* FW image corrupted: */ - CMD_STAT_BAD_NVMEM = 0x0b, - /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ - CMD_STAT_ICM_ERROR = 0x0c, - /* Attempt to modify a QP/EE which is not in the presumed state: */ - CMD_STAT_BAD_QP_STATE = 0x10, - /* Bad segment parameters (Address/Size): */ - CMD_STAT_BAD_SEG_PARAM = 0x20, - /* Memory Region has Memory Windows bound to: */ - CMD_STAT_REG_BOUND = 0x21, - /* HCA local attached memory not present: */ - CMD_STAT_LAM_NOT_PRE = 0x22, - /* Bad management packet (silently discarded): */ - CMD_STAT_BAD_PKT = 0x30, - /* More outstanding CQEs in CQ than new CQ size: */ - CMD_STAT_BAD_SIZE = 0x40, - /* Multi Function device support required: */ - CMD_STAT_MULTI_FUNC_REQ = 0x50, -}; - -enum { - HCR_IN_PARAM_OFFSET = 0x00, - HCR_IN_MODIFIER_OFFSET = 0x08, - HCR_OUT_PARAM_OFFSET = 0x0c, - HCR_TOKEN_OFFSET = 0x14, - HCR_STATUS_OFFSET = 0x18, - - HCR_OPMOD_SHIFT = 12, - HCR_T_BIT = 21, - HCR_E_BIT = 22, - HCR_GO_BIT = 23 -}; - -enum { - GO_BIT_TIMEOUT_MSECS = 10000 -}; - -enum mlx4_vlan_transition { - MLX4_VLAN_TRANSITION_VST_VST = 0, - MLX4_VLAN_TRANSITION_VST_VGT = 1, - MLX4_VLAN_TRANSITION_VGT_VST = 2, - MLX4_VLAN_TRANSITION_VGT_VGT = 3, -}; - - -struct mlx4_cmd_context { - struct completion done; - int result; - int next; - u64 out_param; - u16 token; - u8 fw_status; -}; - -static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr_cmd *in_vhcr); - -static int mlx4_status_to_errno(u8 status) -{ - static const int trans_table[] = { - [CMD_STAT_INTERNAL_ERR] = -EIO, - [CMD_STAT_BAD_OP] = -EPERM, - [CMD_STAT_BAD_PARAM] = -EINVAL, - [CMD_STAT_BAD_SYS_STATE] = -ENXIO, - [CMD_STAT_BAD_RESOURCE] = -EBADF, - [CMD_STAT_RESOURCE_BUSY] = -EBUSY, - [CMD_STAT_EXCEED_LIM] = -ENOMEM, - [CMD_STAT_BAD_RES_STATE] = -EBADF, - [CMD_STAT_BAD_INDEX] = -EBADF, - [CMD_STAT_BAD_NVMEM] = -EFAULT, - [CMD_STAT_ICM_ERROR] = -ENFILE, - [CMD_STAT_BAD_QP_STATE] = -EINVAL, - [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, - [CMD_STAT_REG_BOUND] = -EBUSY, - [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, - [CMD_STAT_BAD_PKT] = -EINVAL, - [CMD_STAT_BAD_SIZE] = -ENOMEM, - [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, - }; - - if (status >= ARRAY_SIZE(trans_table) || - (status != CMD_STAT_OK && trans_table[status] == 0)) - return -EIO; - - return trans_table[status]; -} - -static const char *cmd_to_str(u16 cmd) -{ - switch (cmd) { - case MLX4_CMD_SYS_EN: return "SYS_EN"; - case MLX4_CMD_SYS_DIS: return "SYS_DIS"; - case MLX4_CMD_MAP_FA: return "MAP_FA"; - case MLX4_CMD_UNMAP_FA: return "UNMAP_FA"; - case MLX4_CMD_RUN_FW: return "RUN_FW"; - case MLX4_CMD_MOD_STAT_CFG: return "MOD_STAT_CFG"; - case MLX4_CMD_QUERY_DEV_CAP: return "QUERY_DEV_CAP"; - case MLX4_CMD_QUERY_FW: return "QUERY_FW"; - case MLX4_CMD_ENABLE_LAM: return "ENABLE_LAM"; - case MLX4_CMD_DISABLE_LAM: return "DISABLE_LAM"; - case MLX4_CMD_QUERY_DDR: return "QUERY_DDR"; - case MLX4_CMD_QUERY_ADAPTER: return "QUERY_ADAPTER"; - case MLX4_CMD_INIT_HCA: return "INIT_HCA"; - case MLX4_CMD_CLOSE_HCA: return "CLOSE_HCA"; - case MLX4_CMD_INIT_PORT: return "INIT_PORT"; - case MLX4_CMD_CLOSE_PORT: return "CLOSE_PORT"; - case MLX4_CMD_QUERY_HCA: return "QUERY_HCA"; - case MLX4_CMD_QUERY_PORT: return "QUERY_PORT"; - case MLX4_CMD_SENSE_PORT: return "SENSE_PORT"; - case MLX4_CMD_HW_HEALTH_CHECK: return "HW_HEALTH_CHECK"; - case MLX4_CMD_SET_PORT: return "SET_PORT"; - case MLX4_CMD_SET_NODE: return "SET_NODE"; - case MLX4_CMD_QUERY_FUNC: return "QUERY_FUNC"; - case MLX4_CMD_MAP_ICM: return "MAP_ICM"; - case MLX4_CMD_UNMAP_ICM: return "UNMAP_ICM"; - case MLX4_CMD_MAP_ICM_AUX: return "MAP_ICM_AUX"; - case MLX4_CMD_UNMAP_ICM_AUX: return "UNMAP_ICM_AUX"; - case MLX4_CMD_SET_ICM_SIZE: return "SET_ICM_SIZE"; - /*master notify fw on finish for slave's flr*/ - case MLX4_CMD_INFORM_FLR_DONE: return "INFORM_FLR_DONE"; - case MLX4_CMD_GET_OP_REQ: return "GET_OP_REQ"; - - /* TPT commands */ - case MLX4_CMD_SW2HW_MPT: return "SW2HW_MPT"; - case MLX4_CMD_QUERY_MPT: return "QUERY_MPT"; - case MLX4_CMD_HW2SW_MPT: return "HW2SW_MPT"; - case MLX4_CMD_READ_MTT: return "READ_MTT"; - case MLX4_CMD_WRITE_MTT: return "WRITE_MTT"; - case MLX4_CMD_SYNC_TPT: return "SYNC_TPT"; - - /* EQ commands */ - case MLX4_CMD_MAP_EQ: return "MAP_EQ"; - case MLX4_CMD_SW2HW_EQ: return "SW2HW_EQ"; - case MLX4_CMD_HW2SW_EQ: return "HW2SW_EQ"; - case MLX4_CMD_QUERY_EQ: return "QUERY_EQ"; - - /* CQ commands */ - case MLX4_CMD_SW2HW_CQ: return "SW2HW_CQ"; - case MLX4_CMD_HW2SW_CQ: return "HW2SW_CQ"; - case MLX4_CMD_QUERY_CQ: return "QUERY_CQ:"; - case MLX4_CMD_MODIFY_CQ: return "MODIFY_CQ:"; - - /* SRQ commands */ - case MLX4_CMD_SW2HW_SRQ: return "SW2HW_SRQ"; - case MLX4_CMD_HW2SW_SRQ: return "HW2SW_SRQ"; - case MLX4_CMD_QUERY_SRQ: return "QUERY_SRQ"; - case MLX4_CMD_ARM_SRQ: return "ARM_SRQ"; - - /* QP/EE commands */ - case MLX4_CMD_RST2INIT_QP: return "RST2INIT_QP"; - case MLX4_CMD_INIT2RTR_QP: return "INIT2RTR_QP"; - case MLX4_CMD_RTR2RTS_QP: return "RTR2RTS_QP"; - case MLX4_CMD_RTS2RTS_QP: return "RTS2RTS_QP"; - case MLX4_CMD_SQERR2RTS_QP: return "SQERR2RTS_QP"; - case MLX4_CMD_2ERR_QP: return "2ERR_QP"; - case MLX4_CMD_RTS2SQD_QP: return "RTS2SQD_QP"; - case MLX4_CMD_SQD2SQD_QP: return "SQD2SQD_QP"; - case MLX4_CMD_SQD2RTS_QP: return "SQD2RTS_QP"; - case MLX4_CMD_2RST_QP: return "2RST_QP"; - case MLX4_CMD_QUERY_QP: return "QUERY_QP"; - case MLX4_CMD_INIT2INIT_QP: return "INIT2INIT_QP"; - case MLX4_CMD_SUSPEND_QP: return "SUSPEND_QP"; - case MLX4_CMD_UNSUSPEND_QP: return "UNSUSPEND_QP"; - /* special QP and management commands */ - case MLX4_CMD_CONF_SPECIAL_QP: return "CONF_SPECIAL_QP"; - case MLX4_CMD_MAD_IFC: return "MAD_IFC"; - - /* multicast commands */ - case MLX4_CMD_READ_MCG: return "READ_MCG"; - case MLX4_CMD_WRITE_MCG: return "WRITE_MCG"; - case MLX4_CMD_MGID_HASH: return "MGID_HASH"; - - /* miscellaneous commands */ - case MLX4_CMD_DIAG_RPRT: return "DIAG_RPRT"; - case MLX4_CMD_NOP: return "NOP"; - case MLX4_CMD_ACCESS_MEM: return "ACCESS_MEM"; - case MLX4_CMD_SET_VEP: return "SET_VEP"; - - /* Ethernet specific commands */ - case MLX4_CMD_SET_VLAN_FLTR: return "SET_VLAN_FLTR"; - case MLX4_CMD_SET_MCAST_FLTR: return "SET_MCAST_FLTR"; - case MLX4_CMD_DUMP_ETH_STATS: return "DUMP_ETH_STATS"; - - /* Communication channel commands */ - case MLX4_CMD_ARM_COMM_CHANNEL: return "ARM_COMM_CHANNEL"; - case MLX4_CMD_GEN_EQE: return "GEN_EQE"; - - /* virtual commands */ - case MLX4_CMD_ALLOC_RES: return "ALLOC_RES"; - case MLX4_CMD_FREE_RES: return "FREE_RES"; - case MLX4_CMD_MCAST_ATTACH: return "MCAST_ATTACH"; - case MLX4_CMD_UCAST_ATTACH: return "UCAST_ATTACH"; - case MLX4_CMD_PROMISC: return "PROMISC"; - case MLX4_CMD_QUERY_FUNC_CAP: return "QUERY_FUNC_CAP"; - case MLX4_CMD_QP_ATTACH: return "QP_ATTACH"; - - /* debug commands */ - case MLX4_CMD_QUERY_DEBUG_MSG: return "QUERY_DEBUG_MSG"; - case MLX4_CMD_SET_DEBUG_MSG: return "SET_DEBUG_MSG"; - - /* statistics commands */ - case MLX4_CMD_QUERY_IF_STAT: return "QUERY_IF_STAT"; - case MLX4_CMD_SET_IF_STAT: return "SET_IF_STAT"; - - /* register/delete flow steering network rules */ - case MLX4_QP_FLOW_STEERING_ATTACH: return "QP_FLOW_STEERING_ATTACH"; - case MLX4_QP_FLOW_STEERING_DETACH: return "QP_FLOW_STEERING_DETACH"; - case MLX4_FLOW_STEERING_IB_UC_QP_RANGE: return "FLOW_STEERING_IB_UC_QP_RANGE"; - default: return "OTHER"; - } -} - -static u8 mlx4_errno_to_status(int errno) -{ - switch (errno) { - case -EPERM: - return CMD_STAT_BAD_OP; - case -EINVAL: - return CMD_STAT_BAD_PARAM; - case -ENXIO: - return CMD_STAT_BAD_SYS_STATE; - case -EBUSY: - return CMD_STAT_RESOURCE_BUSY; - case -ENOMEM: - return CMD_STAT_EXCEED_LIM; - case -ENFILE: - return CMD_STAT_ICM_ERROR; - default: - return CMD_STAT_INTERNAL_ERR; - } -} - -static int comm_pending(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u32 status = readl(&priv->mfunc.comm->slave_read); - - return (swab32(status) >> 31) != priv->cmd.comm_toggle; -} - -static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u32 val; - - priv->cmd.comm_toggle ^= 1; - val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); - __raw_writel((__force u32) cpu_to_be32(val), - &priv->mfunc.comm->slave_write); - mmiowb(); -} - -static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - unsigned long end; - int err = 0; - int ret_from_pending = 0; - - /* First, verify that the master reports correct status */ - if (comm_pending(dev)) { - mlx4_warn(dev, "Communication channel is not idle." - "my toggle is %d (cmd:0x%x)\n", - priv->cmd.comm_toggle, cmd); - return -EAGAIN; - } - - /* Write command */ - down(&priv->cmd.poll_sem); - mlx4_comm_cmd_post(dev, cmd, param); - - end = msecs_to_jiffies(timeout) + jiffies; - while (comm_pending(dev) && time_before(jiffies, end)) - cond_resched(); - ret_from_pending = comm_pending(dev); - if (ret_from_pending) { - /* check if the slave is trying to boot in the middle of - * FLR process. The only non-zero result in the RESET command - * is MLX4_DELAY_RESET_SLAVE*/ - if ((MLX4_COMM_CMD_RESET == cmd)) { - mlx4_warn(dev, "Got slave FLRed from Communication" - " channel (ret:0x%x)\n", ret_from_pending); - err = MLX4_DELAY_RESET_SLAVE; - } else { - mlx4_warn(dev, "Communication channel timed out\n"); - err = -ETIMEDOUT; - } - } - - up(&priv->cmd.poll_sem); - return err; -} - -static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, - u16 param, unsigned long timeout) -{ - struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; - struct mlx4_cmd_context *context; - unsigned long end; - int err = 0; - - down(&cmd->event_sem); - - end = msecs_to_jiffies(timeout) + jiffies; - while (comm_pending(dev) && time_before(jiffies, end)) - cond_resched(); - if (comm_pending(dev)) { - mlx4_warn(dev, "mlx4_comm_cmd_wait: Comm channel " - "is not idle. My toggle is %d (op: 0x%x)\n", - mlx4_priv(dev)->cmd.comm_toggle, op); - up(&cmd->event_sem); - return -EAGAIN; - } - - spin_lock(&cmd->context_lock); - BUG_ON(cmd->free_head < 0); - context = &cmd->context[cmd->free_head]; - context->token += cmd->token_mask + 1; - cmd->free_head = context->next; - spin_unlock(&cmd->context_lock); - - init_completion(&context->done); - - mlx4_comm_cmd_post(dev, op, param); - - /* In slave, wait unconditionally for completion */ - wait_for_completion(&context->done); - - err = context->result; - if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { - mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", - op, context->fw_status); - goto out; - } - -out: - /* wait for comm channel ready - * this is necessary for prevention the race - * when switching between event to polling mode - */ - end = msecs_to_jiffies(timeout) + jiffies; - while (comm_pending(dev) && time_before(jiffies, end)) - cond_resched(); - - spin_lock(&cmd->context_lock); - context->next = cmd->free_head; - cmd->free_head = context - cmd->context; - spin_unlock(&cmd->context_lock); - - up(&cmd->event_sem); - return err; -} - -int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout) -{ - if (mlx4_priv(dev)->cmd.use_events) - return mlx4_comm_cmd_wait(dev, cmd, param, timeout); - return mlx4_comm_cmd_poll(dev, cmd, param, timeout); -} - -static int cmd_pending(struct mlx4_dev *dev) -{ - u32 status; - - if (pci_channel_offline(dev->pdev)) - return -EIO; - - status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); - - return (status & swab32(1 << HCR_GO_BIT)) || - (mlx4_priv(dev)->cmd.toggle == - !!(status & swab32(1 << HCR_T_BIT))); -} - -static int get_status(struct mlx4_dev *dev, u32 *status, int *go_bit, - int *t_bit) -{ - if (pci_channel_offline(dev->pdev)) - return -EIO; - - *status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); - *t_bit = !!(*status & swab32(1 << HCR_T_BIT)); - *go_bit = !!(*status & swab32(1 << HCR_GO_BIT)); - - return 0; -} - -static int mlx4_cmd_post(struct mlx4_dev *dev, struct timespec *ts1, - u64 in_param, u64 out_param, u32 in_modifier, - u8 op_modifier, u16 op, u16 token, int event) -{ - struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; - u32 __iomem *hcr = cmd->hcr; - int ret = -EAGAIN; - unsigned long end; - int err, go_bit = 0, t_bit = 0; - u32 status = 0; - - mutex_lock(&cmd->hcr_mutex); - - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - ret = -EIO; - goto out; - } - - end = jiffies; - if (event) - end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); - - while (cmd_pending(dev)) { - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - ret = -EIO; - goto out; - } - - if (time_after_eq(jiffies, end)) { - mlx4_err(dev, "%s:cmd_pending failed\n", __func__); - goto out; - } - cond_resched(); - } - - /* - * We use writel (instead of something like memcpy_toio) - * because writes of less than 32 bits to the HCR don't work - * (and some architectures such as ia64 implement memcpy_toio - * in terms of writeb). - */ - __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); - __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); - __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); - __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); - __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); - __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); - - if (ts1) - ktime_get_ts(ts1); - - /* __raw_writel may not order writes. */ - wmb(); - - __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | - (cmd->toggle << HCR_T_BIT) | - (event ? (1 << HCR_E_BIT) : 0) | - (op_modifier << HCR_OPMOD_SHIFT) | - op), hcr + 6); - - /* - * Make sure that our HCR writes don't get mixed in with - * writes from another CPU starting a FW command. - */ - mmiowb(); - - cmd->toggle = cmd->toggle ^ 1; - - ret = 0; - -out: - if (ret) { - err = get_status(dev, &status, &go_bit, &t_bit); - mlx4_warn(dev, "Could not post command %s (0x%x): ret=%d, " - "in_param=0x%llx, in_mod=0x%x, op_mod=0x%x, " - "get_status err=%d, status_reg=0x%x, go_bit=%d, " - "t_bit=%d, toggle=0x%x\n", cmd_to_str(op), op, ret, - (unsigned long long) in_param, in_modifier, op_modifier, err, status, - go_bit, t_bit, cmd->toggle); - } - mutex_unlock(&cmd->hcr_mutex); - return ret; -} - -static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, - int out_is_imm, u32 in_modifier, u8 op_modifier, - u16 op, unsigned long timeout) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; - int ret; - - mutex_lock(&priv->cmd.slave_cmd_mutex); - - vhcr->in_param = cpu_to_be64(in_param); - vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; - vhcr->in_modifier = cpu_to_be32(in_modifier); - vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff)); - vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); - vhcr->status = 0; - vhcr->flags = !!(priv->cmd.use_events) << 6; - - if (mlx4_is_master(dev)) { - ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); - if (!ret) { - if (out_is_imm) { - if (out_param) - *out_param = - be64_to_cpu(vhcr->out_param); - else { - mlx4_err(dev, "response expected while" - "output mailbox is NULL for " - "command 0x%x\n", op); - vhcr->status = CMD_STAT_BAD_PARAM; - } - } - ret = mlx4_status_to_errno(vhcr->status); - } - } else { - ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, - MLX4_COMM_TIME + timeout); - if (!ret) { - if (out_is_imm) { - if (out_param) - *out_param = - be64_to_cpu(vhcr->out_param); - else { - mlx4_err(dev, "response expected while" - "output mailbox is NULL for " - "command 0x%x\n", op); - vhcr->status = CMD_STAT_BAD_PARAM; - } - } - ret = mlx4_status_to_errno(vhcr->status); - } else - mlx4_err(dev, "failed execution of VHCR_POST command" - "opcode %s (0x%x)\n", cmd_to_str(op), op); - } - - mutex_unlock(&priv->cmd.slave_cmd_mutex); - return ret; -} - -static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, - int out_is_imm, u32 in_modifier, u8 op_modifier, - u16 op, unsigned long timeout) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - void __iomem *hcr = priv->cmd.hcr; - int err = 0; - unsigned long end; - u32 stat; - - down(&priv->cmd.poll_sem); - - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - err = -EIO; - goto out; - } - - err = mlx4_cmd_post(dev, NULL, in_param, out_param ? *out_param : 0, - in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); - if (err) - goto out; - - end = msecs_to_jiffies(timeout) + jiffies; - while (cmd_pending(dev) && time_before(jiffies, end)) { - if (pci_channel_offline(dev->pdev)) { - /* - * Device is going through error recovery - * and cannot accept commands. - */ - err = -EIO; - goto out; - } - - cond_resched(); - } - - if (cmd_pending(dev)) { - mlx4_warn(dev, "command %s (0x%x) timed out (go bit not cleared)\n", - cmd_to_str(op), op); - err = -ETIMEDOUT; - goto out; - } - - if (out_is_imm) - *out_param = - (u64) be32_to_cpu((__force __be32) - __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | - (u64) be32_to_cpu((__force __be32) - __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); - stat = be32_to_cpu((__force __be32) - __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; - err = mlx4_status_to_errno(stat); - if (err) - mlx4_err(dev, "command %s (0x%x) failed: fw status = 0x%x\n", - cmd_to_str(op), op, stat); - -out: - up(&priv->cmd.poll_sem); - return err; -} - -void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_context *context = - &priv->cmd.context[token & priv->cmd.token_mask]; - - /* previously timed out command completing at long last */ - if (token != context->token) - return; - - context->fw_status = status; - context->result = mlx4_status_to_errno(status); - context->out_param = out_param; - - complete(&context->done); -} - -static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, - int out_is_imm, u32 in_modifier, u8 op_modifier, - u16 op, unsigned long timeout) -{ - struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; - struct mlx4_cmd_context *context; - int err = 0; - int go_bit = 0, t_bit = 0, stat_err; - u32 status = 0; - struct timespec ts1, ts2; - ktime_t t1, t2, delta; - s64 ds; - - if (out_is_imm && !out_param) - return -EINVAL; - - down(&cmd->event_sem); - - spin_lock(&cmd->context_lock); - BUG_ON(cmd->free_head < 0); - context = &cmd->context[cmd->free_head]; - context->token += cmd->token_mask + 1; - cmd->free_head = context->next; - spin_unlock(&cmd->context_lock); - - init_completion(&context->done); - - err = mlx4_cmd_post(dev, &ts1, in_param, out_param ? *out_param : 0, - in_modifier, op_modifier, op, context->token, 1); - if (err) - goto out; - - if (!wait_for_completion_timeout(&context->done, - msecs_to_jiffies(timeout))) { - stat_err = get_status(dev, &status, &go_bit, &t_bit); - mlx4_warn(dev, "command %s (0x%x) timed out: in_param=0x%llx, " - "in_mod=0x%x, op_mod=0x%x, get_status err=%d, " - "status_reg=0x%x, go_bit=%d, t_bit=%d, toggle=0x%x\n" - , cmd_to_str(op), op, (unsigned long long) in_param, in_modifier, - op_modifier, stat_err, status, go_bit, t_bit, - mlx4_priv(dev)->cmd.toggle); - err = -EBUSY; - goto out; - } - if (mlx4_debug_level & MLX4_DEBUG_MASK_CMD_TIME) { - ktime_get_ts(&ts2); - t1 = timespec_to_ktime(ts1); - t2 = timespec_to_ktime(ts2); - delta = ktime_sub(t2, t1); - ds = ktime_to_ns(delta); - pr_info("mlx4: fw exec time for %s is %lld nsec\n", cmd_to_str(op), (long long) ds); - } - - err = context->result; - if (err) { - mlx4_err(dev, "command %s (0x%x) failed: in_param=0x%llx, " - "in_mod=0x%x, op_mod=0x%x, fw status = 0x%x\n", - cmd_to_str(op), op, (unsigned long long) in_param, in_modifier, - op_modifier, context->fw_status); - - switch(context->fw_status) { - case CMD_STAT_BAD_PARAM: - mlx4_err(dev, "Parameter is not supported, " - "parameter is out of range\n"); - break; - case CMD_STAT_EXCEED_LIM: - mlx4_err(dev, "Required capability exceeded " - "device limits\n"); - break; - default: - break; - } - goto out; - } - - if (out_is_imm) - *out_param = context->out_param; - -out: - spin_lock(&cmd->context_lock); - context->next = cmd->free_head; - cmd->free_head = context - cmd->context; - spin_unlock(&cmd->context_lock); - - up(&cmd->event_sem); - return err; -} - -int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, - int out_is_imm, u32 in_modifier, u8 op_modifier, - u16 op, unsigned long timeout, int native) -{ - if (pci_channel_offline(dev->pdev)) - return -EIO; - - if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { - if (mlx4_priv(dev)->cmd.use_events) - return mlx4_cmd_wait(dev, in_param, out_param, - out_is_imm, in_modifier, - op_modifier, op, timeout); - else - return mlx4_cmd_poll(dev, in_param, out_param, - out_is_imm, in_modifier, - op_modifier, op, timeout); - } - return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, - in_modifier, op_modifier, op, timeout); -} -EXPORT_SYMBOL_GPL(__mlx4_cmd); - - -static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - -static int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, - int slave, u64 slave_addr, - int size, int is_read) -{ - u64 in_param; - u64 out_param; - - if ((slave_addr & 0xfff) | (master_addr & 0xfff) | - (slave & ~0x7f) | (size & 0xff)) { - mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx " - "master_addr:0x%llx slave_id:%d size:%d\n", - (unsigned long long) slave_addr, (unsigned long long) master_addr, slave, size); - return -EINVAL; - } - - if (is_read) { - in_param = (u64) slave | slave_addr; - out_param = (u64) dev->caps.function | master_addr; - } else { - in_param = (u64) dev->caps.function | master_addr; - out_param = (u64) slave | slave_addr; - } - - return mlx4_cmd_imm(dev, in_param, &out_param, size, 0, - MLX4_CMD_ACCESS_MEM, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -static int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox) -{ - struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf); - struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf); - int err; - int i; - - if (index & 0x1f) - return -EINVAL; - - in_mad->attr_mod = cpu_to_be32(index / 32); - - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - if (err) - return err; - - for (i = 0; i < 32; ++i) - pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]); - - return err; -} - -static int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox) -{ - int i; - int err; - - for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) { - err = query_pkey_block(dev, port, i, table + i, inbox, outbox); - if (err) - return err; - } - - return 0; -} -#define PORT_CAPABILITY_LOCATION_IN_SMP 20 -#define PORT_STATE_OFFSET 32 - -static enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf) -{ - if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP) - return IB_PORT_ACTIVE; - else - return IB_PORT_DOWN; -} - -static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct ib_smp *smp = inbox->buf; - u32 index; - u8 port; - u16 *table; - int err; - int vidx, pidx; - struct mlx4_priv *priv = mlx4_priv(dev); - struct ib_smp *outsmp = outbox->buf; - __be16 *outtab = (__be16 *)(outsmp->data); - __be32 slave_cap_mask; - __be64 slave_node_guid; - port = vhcr->in_modifier; - - if (smp->base_version == 1 && - smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && - smp->class_version == 1) { - if (smp->method == IB_MGMT_METHOD_GET) { - if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) { - index = be32_to_cpu(smp->attr_mod); - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - table = kcalloc(dev->caps.pkey_table_len[port], sizeof *table, GFP_KERNEL); - if (!table) - return -ENOMEM; - /* need to get the full pkey table because the paravirtualized - * pkeys may be scattered among several pkey blocks. - */ - err = get_full_pkey_table(dev, port, table, inbox, outbox); - if (!err) { - for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) { - pidx = priv->virt2phys_pkey[slave][port - 1][vidx]; - outtab[vidx % 32] = cpu_to_be16(table[pidx]); - } - } - kfree(table); - return err; - } - if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) { - /*get the slave specific caps:*/ - /*do the command */ - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - /* modify the response for slaves */ - if (!err && slave != mlx4_master_func_num(dev)) { - u8 *state = outsmp->data + PORT_STATE_OFFSET; - - *state = (*state & 0xf0) | vf_port_state(dev, port, slave); - slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; - memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4); - } - return err; - } - if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) { - /* compute slave's gid block */ - smp->attr_mod = cpu_to_be32(slave / 8); - /* execute cmd */ - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (!err) { - /* if needed, move slave gid to index 0 */ - if (slave % 8) - memcpy(outsmp->data, - outsmp->data + (slave % 8) * 8, 8); - /* delete all other gids */ - memset(outsmp->data + 8, 0, 56); - } - return err; - } - if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) { - err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (!err) { - slave_node_guid = mlx4_get_slave_node_guid(dev, slave); - memcpy(outsmp->data + 12, &slave_node_guid, 8); - } - return err; - } - } - } - if (slave != mlx4_master_func_num(dev) && - ((smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) || - (smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && - smp->method == IB_MGMT_METHOD_SET))) { - mlx4_err(dev, "slave %d is trying to execute a Subnet MGMT MAD, " - "class 0x%x, method 0x%x for attr 0x%x. Rejecting\n", - slave, smp->method, smp->mgmt_class, - be16_to_cpu(smp->attr_id)); - return -EPERM; - } - /*default:*/ - return mlx4_cmd_box(dev, inbox->dma, outbox->dma, - vhcr->in_modifier, vhcr->op_modifier, - vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); -} - -static int MLX4_CMD_DIAG_RPRT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return -EPERM; -} - -static int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return -EPERM; -} - -int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u64 in_param; - u64 out_param; - int err; - - in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param; - out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param; - if (cmd->encode_slave_id) { - in_param &= 0xffffffffffffff00ll; - in_param |= slave; - } - - err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm, - vhcr->in_modifier, vhcr->op_modifier, vhcr->op, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - if (cmd->out_is_imm) - vhcr->out_param = out_param; - - return err; -} - -static struct mlx4_cmd_info cmd_info[] = { - { - .opcode = MLX4_CMD_QUERY_FW, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_FW_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_HCA, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_QUERY_DEV_CAP, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_DEV_CAP_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_FUNC_CAP, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_FUNC_CAP_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_ADAPTER, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_INIT_PORT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_INIT_PORT_wrapper - }, - { - .opcode = MLX4_CMD_CLOSE_PORT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_CLOSE_PORT_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_PORT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_PORT_wrapper - }, - { - .opcode = MLX4_CMD_SET_PORT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SET_PORT_wrapper - }, - { - .opcode = MLX4_CMD_MAP_EQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_MAP_EQ_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_EQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_EQ_wrapper - }, - { - .opcode = MLX4_CMD_HW_HEALTH_CHECK, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_DIAG_RPRT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .skip_err_print = true, - .verify = NULL, - .wrapper = MLX4_CMD_DIAG_RPRT_wrapper - }, - { - .opcode = MLX4_CMD_NOP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_ALLOC_RES, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = true, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_ALLOC_RES_wrapper - }, - { - .opcode = MLX4_CMD_FREE_RES, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_FREE_RES_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_MPT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_MPT_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_MPT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_MPT_wrapper - }, - { - .opcode = MLX4_CMD_HW2SW_MPT, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_HW2SW_MPT_wrapper - }, - { - .opcode = MLX4_CMD_READ_MTT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_WRITE_MTT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_WRITE_MTT_wrapper - }, - { - .opcode = MLX4_CMD_SYNC_TPT, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_HW2SW_EQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_HW2SW_EQ_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_EQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_QUERY_EQ_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_CQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_CQ_wrapper - }, - { - .opcode = MLX4_CMD_HW2SW_CQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_HW2SW_CQ_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_CQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_CQ_wrapper - }, - { - .opcode = MLX4_CMD_MODIFY_CQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = true, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_MODIFY_CQ_wrapper - }, - { - .opcode = MLX4_CMD_SW2HW_SRQ, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_SW2HW_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_HW2SW_SRQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_HW2SW_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_SRQ, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_ARM_SRQ, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_ARM_SRQ_wrapper - }, - { - .opcode = MLX4_CMD_RST2INIT_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = true, - .verify = NULL, - .wrapper = mlx4_RST2INIT_QP_wrapper - }, - { - .opcode = MLX4_CMD_INIT2INIT_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_INIT2INIT_QP_wrapper - }, - { - .opcode = MLX4_CMD_INIT2RTR_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_INIT2RTR_QP_wrapper - }, - { - .opcode = MLX4_CMD_RTR2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_RTR2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_RTS2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_RTS2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_SQERR2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SQERR2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_2ERR_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_RTS2SQD_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_SQD2SQD_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SQD2SQD_QP_wrapper - }, - { - .opcode = MLX4_CMD_SQD2RTS_QP, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SQD2RTS_QP_wrapper - }, - { - .opcode = MLX4_CMD_2RST_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_2RST_QP_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_QP, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_SUSPEND_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_UNSUSPEND_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_GEN_QP_wrapper - }, - { - .opcode = MLX4_CMD_UPDATE_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .skip_err_print = true, - .verify = NULL, - .wrapper = MLX4_CMD_UPDATE_QP_wrapper - }, - { - .opcode = MLX4_CMD_CONF_SPECIAL_QP, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, /* XXX verify: only demux can do this */ - .wrapper = NULL - }, - { - .opcode = MLX4_CMD_MAD_IFC, - .has_inbox = true, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_MAD_IFC_wrapper - }, - { - .opcode = MLX4_CMD_QUERY_IF_STAT, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QUERY_IF_STAT_wrapper - }, - /* Native multicast commands are not available for guests */ - { - .opcode = MLX4_CMD_QP_ATTACH, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QP_ATTACH_wrapper - }, - { - .opcode = MLX4_CMD_PROMISC, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_PROMISC_wrapper - }, - /* Ethernet specific commands */ - { - .opcode = MLX4_CMD_SET_VLAN_FLTR, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SET_VLAN_FLTR_wrapper - }, - { - .opcode = MLX4_CMD_SET_MCAST_FLTR, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_SET_MCAST_FLTR_wrapper - }, - { - .opcode = MLX4_CMD_DUMP_ETH_STATS, - .has_inbox = false, - .has_outbox = true, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_DUMP_ETH_STATS_wrapper - }, - { - .opcode = MLX4_CMD_INFORM_FLR_DONE, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = NULL - }, - /* flow steering commands */ - { - .opcode = MLX4_QP_FLOW_STEERING_ATTACH, - .has_inbox = true, - .has_outbox = false, - .out_is_imm = true, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper - }, - { - .opcode = MLX4_QP_FLOW_STEERING_DETACH, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .verify = NULL, - .wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper - }, - /* wol commands */ - { - .opcode = MLX4_CMD_MOD_STAT_CFG, - .has_inbox = false, - .has_outbox = false, - .out_is_imm = false, - .encode_slave_id = false, - .skip_err_print = true, - .verify = NULL, - .wrapper = mlx4_MOD_STAT_CFG_wrapper - }, -}; - -static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr_cmd *in_vhcr) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_info *cmd = NULL; - struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; - struct mlx4_vhcr *vhcr; - struct mlx4_cmd_mailbox *inbox = NULL; - struct mlx4_cmd_mailbox *outbox = NULL; - u64 in_param; - u64 out_param; - int ret = 0; - int i; - int err = 0; - - /* Create sw representation of Virtual HCR */ - vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); - if (!vhcr) - return -ENOMEM; - - /* DMA in the vHCR */ - if (!in_vhcr) { - ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, - priv->mfunc.master.slave_state[slave].vhcr_dma, - ALIGN(sizeof(struct mlx4_vhcr_cmd), - MLX4_ACCESS_MEM_ALIGN), 1); - if (ret) { - mlx4_err(dev, "%s:Failed reading vhcr" - "ret: 0x%x\n", __func__, ret); - kfree(vhcr); - return ret; - } - } - - /* Fill SW VHCR fields */ - vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); - vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); - vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); - vhcr->token = be16_to_cpu(vhcr_cmd->token); - vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; - vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); - vhcr->e_bit = vhcr_cmd->flags & (1 << 6); - - /* Lookup command */ - for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { - if (vhcr->op == cmd_info[i].opcode) { - cmd = &cmd_info[i]; - break; - } - } - if (!cmd) { - mlx4_err(dev, "unparavirt command: %s (0x%x) accepted from slave:%d\n", - cmd_to_str(vhcr->op), vhcr->op, slave); - vhcr_cmd->status = CMD_STAT_BAD_PARAM; - goto out_status; - } - - /* Read inbox */ - if (cmd->has_inbox) { - vhcr->in_param &= INBOX_MASK; - inbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(inbox)) { - vhcr_cmd->status = CMD_STAT_BAD_SIZE; - inbox = NULL; - goto out_status; - } - - if (mlx4_ACCESS_MEM(dev, inbox->dma, slave, - vhcr->in_param, - MLX4_MAILBOX_SIZE, 1)) { - mlx4_err(dev, "%s: Failed reading inbox for cmd %s (0x%x)\n", - __func__, cmd_to_str(cmd->opcode), cmd->opcode); - vhcr_cmd->status = CMD_STAT_INTERNAL_ERR; - goto out_status; - } - } - - /* Apply permission and bound checks if applicable */ - if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { - mlx4_warn(dev, "Command %s (0x%x) from slave: %d failed protection " - "checks for resource_id: %d\n", cmd_to_str(vhcr->op), - vhcr->op, slave, vhcr->in_modifier); - vhcr_cmd->status = CMD_STAT_BAD_OP; - goto out_status; - } - - /* Allocate outbox */ - if (cmd->has_outbox) { - outbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(outbox)) { - vhcr_cmd->status = CMD_STAT_BAD_SIZE; - outbox = NULL; - goto out_status; - } - } - - /* Execute the command! */ - if (cmd->wrapper) { - err = cmd->wrapper(dev, slave, vhcr, inbox, outbox, - cmd); - if (cmd->out_is_imm) - vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); - } else { - in_param = cmd->has_inbox ? (u64) inbox->dma : - vhcr->in_param; - out_param = cmd->has_outbox ? (u64) outbox->dma : - vhcr->out_param; - err = __mlx4_cmd(dev, in_param, &out_param, - cmd->out_is_imm, vhcr->in_modifier, - vhcr->op_modifier, vhcr->op, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - if (cmd->out_is_imm) { - vhcr->out_param = out_param; - vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); - } - } - - if (err) { - if (!cmd->skip_err_print) - mlx4_warn(dev, "vhcr command %s (0x%x) slave:%d " - "in_param 0x%llx in_mod=0x%x, op_mod=0x%x " - "failed with error:%d, status %d\n", - cmd_to_str(vhcr->op), vhcr->op, slave, - (unsigned long long) vhcr->in_param, vhcr->in_modifier, - vhcr->op_modifier, vhcr->errno, err); - vhcr_cmd->status = mlx4_errno_to_status(err); - goto out_status; - } - - - /* Write outbox if command completed successfully */ - if (cmd->has_outbox && !vhcr_cmd->status) { - ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, - vhcr->out_param, - MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); - if (ret) { - /* If we failed to write back the outbox after the - *command was successfully executed, we must fail this - * slave, as it is now in undefined state */ - mlx4_err(dev, "%s: Failed writing outbox\n", __func__); - goto out; - } - } - -out_status: - /* DMA back vhcr result */ - if (!in_vhcr) { - ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, - priv->mfunc.master.slave_state[slave].vhcr_dma, - ALIGN(sizeof(struct mlx4_vhcr), - MLX4_ACCESS_MEM_ALIGN), - MLX4_CMD_WRAPPED); - if (ret) - mlx4_err(dev, "%s:Failed writing vhcr result\n", - __func__); - else if (vhcr->e_bit && - mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) - mlx4_warn(dev, "Failed to generate command completion " - "eqe for slave %d\n", slave); - } - -out: - kfree(vhcr); - mlx4_free_cmd_mailbox(dev, inbox); - mlx4_free_cmd_mailbox(dev, outbox); - return ret; -} - -static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, - int slave, int port) -{ - struct mlx4_vport_oper_state *vp_oper; - struct mlx4_vport_state *vp_admin; - struct mlx4_vf_immed_vlan_work *work; - int err; - int admin_vlan_ix = NO_INDX; - - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; - - if (vp_oper->state.default_vlan == vp_admin->default_vlan && - vp_oper->state.default_qos == vp_admin->default_qos) - return 0; - - work = kzalloc(sizeof(*work), GFP_KERNEL); - if (!work) - return -ENOMEM; - - if (vp_oper->state.default_vlan != vp_admin->default_vlan) { - if (MLX4_VGT != vp_admin->default_vlan) { - err = __mlx4_register_vlan(&priv->dev, port, - vp_admin->default_vlan, - &admin_vlan_ix); - if (err) { - mlx4_warn((&priv->dev), - "No vlan resources slave %d, port %d\n", - slave, port); - kfree(work); - return err; - } - } else { - admin_vlan_ix = NO_INDX; - } - work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN; - mlx4_dbg((&(priv->dev)), - "alloc vlan %d idx %d slave %d port %d\n", - (int)(vp_admin->default_vlan), - admin_vlan_ix, slave, port); - } - - /* save original vlan ix and vlan id */ - work->orig_vlan_id = vp_oper->state.default_vlan; - work->orig_vlan_ix = vp_oper->vlan_idx; - - /* handle new qos */ - if (vp_oper->state.default_qos != vp_admin->default_qos) - work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS; - - if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN) - vp_oper->vlan_idx = admin_vlan_ix; - - vp_oper->state.default_vlan = vp_admin->default_vlan; - vp_oper->state.default_qos = vp_admin->default_qos; - - /* iterate over QPs owned by this slave, using UPDATE_QP */ - work->port = port; - work->slave = slave; - work->qos = vp_oper->state.default_qos; - work->vlan_id = vp_oper->state.default_vlan; - work->vlan_ix = vp_oper->vlan_idx; - work->priv = priv; - INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler); - queue_work(priv->mfunc.master.comm_wq, &work->work); - - return 0; -} - - -static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) -{ - int port, err; - struct mlx4_vport_state *vp_admin; - struct mlx4_vport_oper_state *vp_oper; - - for (port = 1; port <= MLX4_MAX_PORTS; port++) { - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; - vp_oper->state = *vp_admin; - if (MLX4_VGT != vp_admin->default_vlan) { - err = __mlx4_register_vlan(&priv->dev, port, - vp_admin->default_vlan, &(vp_oper->vlan_idx)); - if (err) { - vp_oper->vlan_idx = NO_INDX; - mlx4_warn((&priv->dev), - "No vlan resorces slave %d, port %d\n", - slave, port); - return err; - } - mlx4_dbg((&(priv->dev)), "alloc vlan %d idx %d slave %d port %d\n", - (int)(vp_oper->state.default_vlan), - vp_oper->vlan_idx, slave, port); - } - if (vp_admin->spoofchk) { - vp_oper->mac_idx = __mlx4_register_mac(&priv->dev, - port, - vp_admin->mac); - if (0 > vp_oper->mac_idx) { - err = vp_oper->mac_idx; - vp_oper->mac_idx = NO_INDX; - mlx4_warn((&priv->dev), - "No mac resources slave %d, port %d\n", - slave, port); - return err; - } - mlx4_dbg((&(priv->dev)), "alloc mac %llx idx %d slave %d port %d\n", - (unsigned long long) vp_oper->state.mac, vp_oper->mac_idx, slave, port); - } - } - return 0; -} - -static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave) -{ - int port; - struct mlx4_vport_oper_state *vp_oper; - - for (port = 1; port <= MLX4_MAX_PORTS; port++) { - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - if (NO_INDX != vp_oper->vlan_idx) { - __mlx4_unregister_vlan(&priv->dev, - port, vp_oper->state.default_vlan); - vp_oper->vlan_idx = NO_INDX; - } - if (NO_INDX != vp_oper->mac_idx) { - __mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac); - vp_oper->mac_idx = NO_INDX; - } - } - return; -} - -static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, - u16 param, u8 toggle) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; - u32 reply; - u8 is_going_down = 0; - int i; - unsigned long flags; - - slave_state[slave].comm_toggle ^= 1; - reply = (u32) slave_state[slave].comm_toggle << 31; - if (toggle != slave_state[slave].comm_toggle) { - mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER" - "STATE COMPROMISIED ***\n", toggle, slave); - goto reset_slave; - } - if (cmd == MLX4_COMM_CMD_RESET) { - mlx4_warn(dev, "Received reset from slave:%d\n", slave); - slave_state[slave].active = false; - slave_state[slave].old_vlan_api = false; - mlx4_master_deactivate_admin_state(priv, slave); - for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) { - slave_state[slave].event_eq[i].eqn = -1; - slave_state[slave].event_eq[i].token = 0; - } - /*check if we are in the middle of FLR process, - if so return "retry" status to the slave*/ - if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) - goto inform_slave_state; - - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave); - - /* write the version in the event field */ - reply |= mlx4_comm_get_version(); - - goto reset_slave; - } - /*command from slave in the middle of FLR*/ - if (cmd != MLX4_COMM_CMD_RESET && - MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { - mlx4_warn(dev, "slave:%d is Trying to run cmd (0x%x) " - "in the middle of FLR\n", slave, cmd); - return; - } - - switch (cmd) { - case MLX4_COMM_CMD_VHCR0: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) - goto reset_slave; - slave_state[slave].vhcr_dma = ((u64) param) << 48; - priv->mfunc.master.slave_state[slave].cookie = 0; - break; - case MLX4_COMM_CMD_VHCR1: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) - goto reset_slave; - slave_state[slave].vhcr_dma |= ((u64) param) << 32; - break; - case MLX4_COMM_CMD_VHCR2: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) - goto reset_slave; - slave_state[slave].vhcr_dma |= ((u64) param) << 16; - break; - case MLX4_COMM_CMD_VHCR_EN: - if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) - goto reset_slave; - slave_state[slave].vhcr_dma |= param; - if (mlx4_master_activate_admin_state(priv, slave)) - goto reset_slave; - slave_state[slave].active = true; - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave); - break; - case MLX4_COMM_CMD_VHCR_POST: - if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && - (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) - goto reset_slave; - - mutex_lock(&priv->cmd.slave_cmd_mutex); - if (mlx4_master_process_vhcr(dev, slave, NULL)) { - mlx4_err(dev, "Failed processing vhcr for slave: %d," - " resetting slave.\n", slave); - mutex_unlock(&priv->cmd.slave_cmd_mutex); - goto reset_slave; - } - mutex_unlock(&priv->cmd.slave_cmd_mutex); - break; - default: - mlx4_warn(dev, "Bad comm cmd: %d from slave: %d\n", cmd, slave); - goto reset_slave; - } - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - if (!slave_state[slave].is_slave_going_down) - slave_state[slave].last_cmd = cmd; - else - is_going_down = 1; - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - if (is_going_down) { - mlx4_warn(dev, "Slave is going down aborting command (%d)" - " executing from slave: %d\n", - cmd, slave); - return; - } - __raw_writel((__force u32) cpu_to_be32(reply), - &priv->mfunc.comm[slave].slave_read); - mmiowb(); - - return; - -reset_slave: - /* cleanup any slave resources */ - mlx4_delete_all_resources_for_slave(dev, slave); - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - if (!slave_state[slave].is_slave_going_down) - slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - /*with slave in the middle of flr, no need to clean resources again.*/ -inform_slave_state: - __raw_writel((__force u32) cpu_to_be32(reply), - &priv->mfunc.comm[slave].slave_read); - wmb(); -} - -/* master command processing */ -void mlx4_master_comm_channel(struct work_struct *work) -{ - struct mlx4_mfunc_master_ctx *master = - container_of(work, - struct mlx4_mfunc_master_ctx, - comm_work); - struct mlx4_mfunc *mfunc = - container_of(master, struct mlx4_mfunc, master); - struct mlx4_priv *priv = - container_of(mfunc, struct mlx4_priv, mfunc); - struct mlx4_dev *dev = &priv->dev; - __be32 *bit_vec; - u32 comm_cmd; - u32 vec; - int i, j, slave; - int toggle; - int served = 0; - int reported = 0; - u32 slt; - - bit_vec = master->comm_arm_bit_vector; - for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) { - vec = be32_to_cpu(bit_vec[i]); - for (j = 0; j < 32; j++) { - if (!(vec & (1 << j))) - continue; - ++reported; - slave = (i * 32) + j; - comm_cmd = swab32(readl( - &mfunc->comm[slave].slave_write)); - slt = swab32(readl(&mfunc->comm[slave].slave_read)) - >> 31; - toggle = comm_cmd >> 31; - if (toggle != slt) { - if (master->slave_state[slave].comm_toggle - != slt) { - mlx4_info(dev, "slave %d out of sync." - " read toggle %d, state toggle %d. " - "Resynching.\n", slave, slt, - master->slave_state[slave].comm_toggle); - master->slave_state[slave].comm_toggle = - slt; - } - mlx4_master_do_cmd(dev, slave, - comm_cmd >> 16 & 0xff, - comm_cmd & 0xffff, toggle); - ++served; - } else - mlx4_err(dev, "slave %d out of sync." - " read toggle %d, write toggle %d.\n", slave, slt, - toggle); - } - } - - if (reported && reported != served) - mlx4_warn(dev, "Got command event with bitmask from %d slaves" - " but %d were served\n", - reported, served); -} -/* master command processing */ -void mlx4_master_arm_comm_channel(struct work_struct *work) -{ - struct mlx4_mfunc_master_ctx *master = - container_of(work, - struct mlx4_mfunc_master_ctx, - arm_comm_work); - struct mlx4_mfunc *mfunc = - container_of(master, struct mlx4_mfunc, master); - struct mlx4_priv *priv = - container_of(mfunc, struct mlx4_priv, mfunc); - struct mlx4_dev *dev = &priv->dev; - - if (mlx4_ARM_COMM_CHANNEL(dev)) - mlx4_warn(dev, "Failed to arm comm channel events\n"); -} - -static int sync_toggles(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int wr_toggle; - int rd_toggle; - unsigned long end; - - wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)) >> 31; - end = jiffies + msecs_to_jiffies(5000); - - while (time_before(jiffies, end)) { - rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)) >> 31; - if (rd_toggle == wr_toggle) { - priv->cmd.comm_toggle = rd_toggle; - return 0; - } - - cond_resched(); - } - - /* - * we could reach here if for example the previous VM using this - * function misbehaved and left the channel with unsynced state. We - * should fix this here and give this VM a chance to use a properly - * synced channel - */ - mlx4_warn(dev, "recovering from previously mis-behaved VM\n"); - __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read); - __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write); - priv->cmd.comm_toggle = 0; - - return 0; -} - -int mlx4_multi_func_init(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state; - int i, j, err, port; - - if (mlx4_is_master(dev)) - priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) + - priv->fw.comm_base, MLX4_COMM_PAGESIZE); - else - priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, 2) + - MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE); - if (!priv->mfunc.comm) { - mlx4_err(dev, "Couldn't map communication vector.\n"); - goto err_vhcr; - } - - if (mlx4_is_master(dev)) { - priv->mfunc.master.slave_state = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_slave_state), GFP_KERNEL); - if (!priv->mfunc.master.slave_state) - goto err_comm; - - priv->mfunc.master.vf_admin = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_vf_admin_state), GFP_KERNEL); - if (!priv->mfunc.master.vf_admin) - goto err_comm_admin; - - priv->mfunc.master.vf_oper = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_vf_oper_state), GFP_KERNEL); - if (!priv->mfunc.master.vf_oper) - goto err_comm_oper; - - for (i = 0; i < dev->num_slaves; ++i) { - s_state = &priv->mfunc.master.slave_state[i]; - s_state->last_cmd = MLX4_COMM_CMD_RESET; - mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]); - for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j) - s_state->event_eq[j].eqn = -1; - __raw_writel((__force u32) 0, - &priv->mfunc.comm[i].slave_write); - __raw_writel((__force u32) 0, - &priv->mfunc.comm[i].slave_read); - mmiowb(); - for (port = 1; port <= MLX4_MAX_PORTS; port++) { - s_state->vlan_filter[port] = - kzalloc(sizeof(struct mlx4_vlan_fltr), - GFP_KERNEL); - if (!s_state->vlan_filter[port]) { - if (--port) - kfree(s_state->vlan_filter[port]); - goto err_slaves; - } - INIT_LIST_HEAD(&s_state->mcast_filters[port]); - priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT; - priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT; - priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX; - priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX; - } - spin_lock_init(&s_state->lock); - } - - memset(&priv->mfunc.master.cmd_eqe, 0, dev->caps.eqe_size); - priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD; - INIT_WORK(&priv->mfunc.master.comm_work, - mlx4_master_comm_channel); - INIT_WORK(&priv->mfunc.master.arm_comm_work, - mlx4_master_arm_comm_channel); - INIT_WORK(&priv->mfunc.master.slave_event_work, - mlx4_gen_slave_eqe); - INIT_WORK(&priv->mfunc.master.slave_flr_event_work, - mlx4_master_handle_slave_flr); - spin_lock_init(&priv->mfunc.master.slave_state_lock); - spin_lock_init(&priv->mfunc.master.slave_eq.event_lock); - priv->mfunc.master.comm_wq = - create_singlethread_workqueue("mlx4_comm"); - if (!priv->mfunc.master.comm_wq) - goto err_slaves; - - if (mlx4_init_resource_tracker(dev)) - goto err_thread; - - err = mlx4_ARM_COMM_CHANNEL(dev); - if (err) { - mlx4_err(dev, " Failed to arm comm channel eq: %x\n", - err); - goto err_resource; - } - - } else { - err = sync_toggles(dev); - if (err) { - mlx4_err(dev, "Couldn't sync toggles\n"); - goto err_comm; - } - } - return 0; - -err_resource: - mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL); -err_thread: - flush_workqueue(priv->mfunc.master.comm_wq); - destroy_workqueue(priv->mfunc.master.comm_wq); -err_slaves: - while (--i) { - for (port = 1; port <= MLX4_MAX_PORTS; port++) - kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); - } - kfree(priv->mfunc.master.vf_oper); -err_comm_oper: - kfree(priv->mfunc.master.vf_admin); -err_comm_admin: - kfree(priv->mfunc.master.slave_state); -err_comm: - iounmap(priv->mfunc.comm); -err_vhcr: - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, - priv->mfunc.vhcr_dma); - priv->mfunc.vhcr = NULL; - return -ENOMEM; -} - -int mlx4_cmd_init(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mutex_init(&priv->cmd.hcr_mutex); - mutex_init(&priv->cmd.slave_cmd_mutex); - sema_init(&priv->cmd.poll_sem, 1); - priv->cmd.use_events = 0; - priv->cmd.toggle = 1; - - priv->cmd.hcr = NULL; - priv->mfunc.vhcr = NULL; - - if (!mlx4_is_slave(dev)) { - priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + - MLX4_HCR_BASE, MLX4_HCR_SIZE); - if (!priv->cmd.hcr) { - mlx4_err(dev, "Couldn't map command register.\n"); - return -ENOMEM; - } - } - - if (mlx4_is_mfunc(dev)) { - priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, - &priv->mfunc.vhcr_dma, - GFP_KERNEL); - if (!priv->mfunc.vhcr) { - mlx4_err(dev, "Couldn't allocate VHCR.\n"); - goto err_hcr; - } - } - - priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, - MLX4_MAILBOX_SIZE, - MLX4_MAILBOX_SIZE, 0); - if (!priv->cmd.pool) - goto err_vhcr; - - return 0; - -err_vhcr: - if (mlx4_is_mfunc(dev)) - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, priv->mfunc.vhcr_dma); - priv->mfunc.vhcr = NULL; - -err_hcr: - if (!mlx4_is_slave(dev)) - iounmap(priv->cmd.hcr); - return -ENOMEM; -} - -void mlx4_multi_func_cleanup(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, port; - - if (mlx4_is_master(dev)) { - flush_workqueue(priv->mfunc.master.comm_wq); - destroy_workqueue(priv->mfunc.master.comm_wq); - for (i = 0; i < dev->num_slaves; i++) { - for (port = 1; port <= MLX4_MAX_PORTS; port++) - kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); - } - kfree(priv->mfunc.master.slave_state); - kfree(priv->mfunc.master.vf_admin); - kfree(priv->mfunc.master.vf_oper); - } - - iounmap(priv->mfunc.comm); -} - -void mlx4_cmd_cleanup(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - pci_pool_destroy(priv->cmd.pool); - - if (!mlx4_is_slave(dev)) - iounmap(priv->cmd.hcr); - if (mlx4_is_mfunc(dev)) - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, priv->mfunc.vhcr_dma); - priv->mfunc.vhcr = NULL; -} - -/* - * Switch to using events to issue FW commands (can only be called - * after event queue for command events has been initialized). - */ -int mlx4_cmd_use_events(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - int err = 0; - - priv->cmd.context = kmalloc(priv->cmd.max_cmds * - sizeof (struct mlx4_cmd_context), - GFP_KERNEL); - if (!priv->cmd.context) - return -ENOMEM; - - for (i = 0; i < priv->cmd.max_cmds; ++i) { - priv->cmd.context[i].token = i; - priv->cmd.context[i].next = i + 1; - } - - priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; - priv->cmd.free_head = 0; - - sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); - spin_lock_init(&priv->cmd.context_lock); - - for (priv->cmd.token_mask = 1; - priv->cmd.token_mask < priv->cmd.max_cmds; - priv->cmd.token_mask <<= 1) - ; /* nothing */ - --priv->cmd.token_mask; - - down(&priv->cmd.poll_sem); - priv->cmd.use_events = 1; - - return err; -} - -/* - * Switch back to polling (used when shutting down the device) - */ -void mlx4_cmd_use_polling(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - priv->cmd.use_events = 0; - - for (i = 0; i < priv->cmd.max_cmds; ++i) - down(&priv->cmd.event_sem); - - kfree(priv->cmd.context); - - up(&priv->cmd.poll_sem); -} - -struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) -{ - struct mlx4_cmd_mailbox *mailbox; - - mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); - if (!mailbox) - return ERR_PTR(-ENOMEM); - - mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, - &mailbox->dma); - if (!mailbox->buf) { - kfree(mailbox); - return ERR_PTR(-ENOMEM); - } - - memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); - - return mailbox; -} -EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); - -void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *mailbox) -{ - if (!mailbox) - return; - - pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); - kfree(mailbox); -} -EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); - -u32 mlx4_comm_get_version(void) -{ - return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; -} - -static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) -{ - if ((vf < 0) || (vf >= dev->num_vfs)) { - mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs); - return -EINVAL; - } - return (vf+1); -} - -int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - int slave; - - if (!mlx4_is_master(dev)) - return -EPROTONOSUPPORT; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - s_info->mac = mlx4_mac_to_u64(mac); - mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n", - vf, port, (unsigned long long) s_info->mac); - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); - -int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_oper_state *vf_oper; - struct mlx4_vport_state *vf_admin; - int slave; - - if ((!mlx4_is_master(dev)) || - !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) - return -EPROTONOSUPPORT; - - if ((vlan > 4095) || (qos > 7)) - return -EINVAL; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; - vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - - if ((0 == vlan) && (0 == qos)) - vf_admin->default_vlan = MLX4_VGT; - else - vf_admin->default_vlan = vlan; - vf_admin->default_qos = qos; - - if (priv->mfunc.master.slave_state[slave].active && - dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) { - mlx4_info(dev, "updating vf %d port %d config params immediately\n", - vf, port); - mlx4_master_immediate_activate_vlan_qos(priv, slave, port); - } - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); - - /* mlx4_get_slave_default_vlan - - * retrun true if VST ( default vlan) - * if VST will fill vlan & qos (if not NULL) */ -bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, u16 *vlan, u8 *qos) -{ - struct mlx4_vport_oper_state *vp_oper; - struct mlx4_priv *priv; - - priv = mlx4_priv(dev); - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - - if (MLX4_VGT != vp_oper->state.default_vlan) { - if (vlan) - *vlan = vp_oper->state.default_vlan; - if (qos) - *qos = vp_oper->state.default_qos; - return true; - } - return false; -} -EXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan); - -int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - int slave; - - if ((!mlx4_is_master(dev)) || - !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM)) - return -EPROTONOSUPPORT; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - s_info->spoofchk = setting; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk); - -int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - struct mlx4_vport_oper_state *vp_oper; - int slave; - u8 link_stat_event; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - switch (link_state) { - case IFLA_VF_LINK_STATE_AUTO: - /* get link curent state */ - if (!priv->sense.do_sense_port[port]) - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; - else - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; - break; - - case IFLA_VF_LINK_STATE_ENABLE: - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; - break; - - case IFLA_VF_LINK_STATE_DISABLE: - link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; - break; - - default: - mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n", - link_state, slave, port); - return -EINVAL; - } - /* update the admin & oper state on the link state */ - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - s_info->link_state = link_state; - vp_oper->state.link_state = link_state; - - /* send event */ - mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event); - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state); - -int mlx4_get_vf_link_state(struct mlx4_dev *dev, int port, int vf) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_vport_state *s_info; - int slave; - - if (!mlx4_is_master(dev)) - return -EPROTONOSUPPORT; - - slave = mlx4_get_slave_indx(dev, vf); - if (slave < 0) - return -EINVAL; - - s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; - - return s_info->link_state; -} -EXPORT_SYMBOL_GPL(mlx4_get_vf_link_state); - diff --git a/sys/ofed/drivers/net/mlx4/cq.c b/sys/ofed/drivers/net/mlx4/cq.c deleted file mode 100644 index b133ae615ea4..000000000000 --- a/sys/ofed/drivers/net/mlx4/cq.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2004 Voltaire, Inc. 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/hardirq.h> -#include <linux/module.h> -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/cq.h> - -#include "mlx4.h" -#include "icm.h" - -#define MLX4_CQ_STATUS_OK ( 0 << 28) -#define MLX4_CQ_STATUS_OVERFLOW ( 9 << 28) -#define MLX4_CQ_STATUS_WRITE_FAIL (10 << 28) -#define MLX4_CQ_FLAG_CC ( 1 << 18) -#define MLX4_CQ_FLAG_OI ( 1 << 17) -#define MLX4_CQ_STATE_ARMED ( 9 << 8) -#define MLX4_CQ_STATE_ARMED_SOL ( 6 << 8) -#define MLX4_EQ_STATE_FIRED (10 << 8) - -void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn) -{ - struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; - struct mlx4_cq *cq; - - read_lock(&cq_table->cq_table_lock); - - cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree, - cqn & (dev->caps.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); - - read_unlock(&cq_table->cq_table_lock); - - if (!cq) { - mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn); - return; - } - - ++cq->arm_sn; - - cq->comp(cq); - - if (atomic_dec_and_test(&cq->refcount)) - complete(&cq->free); -} - -void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type) -{ - struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; - struct mlx4_cq *cq; - - read_lock(&cq_table->cq_table_lock); - - cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); - - read_unlock(&cq_table->cq_table_lock); - - if (!cq) { - mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn); - return; - } - - cq->event(cq, event_type); - - if (atomic_dec_and_test(&cq->refcount)) - complete(&cq->free); -} - -static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int cq_num) -{ - return mlx4_cmd(dev, mailbox->dma, cq_num, 0, - MLX4_CMD_SW2HW_CQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_MODIFY_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int cq_num, u32 opmod) -{ - return mlx4_cmd(dev, mailbox->dma, cq_num, opmod, MLX4_CMD_MODIFY_CQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int cq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, - cq_num, mailbox ? 0 : 1, MLX4_CMD_HW2SW_CQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, - u16 count, u16 period) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->cq_max_count = cpu_to_be16(count); - cq_context->cq_period = cpu_to_be16(period); - - err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 1); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_modify); - -int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, - int entries, struct mlx4_mtt *mtt) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - u64 mtt_addr; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->logsize_usrpage = cpu_to_be32(ilog2(entries) << 24); - cq_context->log_page_size = mtt->page_shift - 12; - mtt_addr = mlx4_mtt_addr(dev, mtt); - cq_context->mtt_base_addr_h = mtt_addr >> 32; - cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - - err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 0); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_resize); - -int mlx4_cq_ignore_overrun(struct mlx4_dev *dev, struct mlx4_cq *cq) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->flags |= cpu_to_be32(MLX4_CQ_FLAG_OI); - - err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 3); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_ignore_overrun); - -int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - int err; - - *cqn = mlx4_bitmap_alloc(&cq_table->bitmap); - if (*cqn == -1) - return -ENOMEM; - - err = mlx4_table_get(dev, &cq_table->table, *cqn); - if (err) - goto err_out; - - err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn); - if (err) - goto err_put; - return 0; - -err_put: - mlx4_table_put(dev, &cq_table->table, *cqn); - -err_out: - mlx4_bitmap_free(&cq_table->bitmap, *cqn, MLX4_NO_RR); - return err; -} - -static int mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn) -{ - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, RES_CQ, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - return err; - else { - *cqn = get_param_l(&out_param); - return 0; - } - } - return __mlx4_cq_alloc_icm(dev, cqn); -} - -void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - - mlx4_table_put(dev, &cq_table->cmpt_table, cqn); - mlx4_table_put(dev, &cq_table->table, cqn); - mlx4_bitmap_free(&cq_table->bitmap, cqn, MLX4_NO_RR); -} - -static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, cqn); - err = mlx4_cmd(dev, in_param, RES_CQ, RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed freeing cq:%d\n", cqn); - } else - __mlx4_cq_free_icm(dev, cqn); -} - -int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, - struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec, - struct mlx4_cq *cq, unsigned vector, int collapsed, - int timestamp_en) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_cq_context *cq_context; - u64 mtt_addr; - int err; - - if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool) - return -EINVAL; - - cq->vector = vector; - - err = mlx4_cq_alloc_icm(dev, &cq->cqn); - if (err) - return err; - - spin_lock_irq(&cq_table->lock); - err = radix_tree_insert(&cq_table->tree, cq->cqn, cq); - spin_unlock_irq(&cq_table->lock); - if (err) - goto err_icm; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_radix; - } - - cq_context = mailbox->buf; - memset(cq_context, 0, sizeof *cq_context); - - cq_context->flags = cpu_to_be32(!!collapsed << 18); - if (timestamp_en) - cq_context->flags |= cpu_to_be32(1 << 19); - - cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); - cq_context->comp_eqn = priv->eq_table.eq[vector].eqn; - cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; - - mtt_addr = mlx4_mtt_addr(dev, mtt); - cq_context->mtt_base_addr_h = mtt_addr >> 32; - cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - cq_context->db_rec_addr = cpu_to_be64(db_rec); - - err = mlx4_SW2HW_CQ(dev, mailbox, cq->cqn); - mlx4_free_cmd_mailbox(dev, mailbox); - if (err) - goto err_radix; - - cq->cons_index = 0; - cq->arm_sn = 1; - cq->uar = uar; - atomic_set(&cq->refcount, 1); - init_completion(&cq->free); - - cq->eqn = priv->eq_table.eq[cq->vector].eqn; - cq->irq = priv->eq_table.eq[cq->vector].irq; - - return 0; - -err_radix: - spin_lock_irq(&cq_table->lock); - radix_tree_delete(&cq_table->tree, cq->cqn); - spin_unlock_irq(&cq_table->lock); - -err_icm: - mlx4_cq_free_icm(dev, cq->cqn); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_cq_alloc); - -void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cq_table *cq_table = &priv->cq_table; - int err; - - err = mlx4_HW2SW_CQ(dev, NULL, cq->cqn); - if (err) - mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn); - - synchronize_irq(priv->eq_table.eq[cq->vector].irq); - - spin_lock_irq(&cq_table->lock); - radix_tree_delete(&cq_table->tree, cq->cqn); - spin_unlock_irq(&cq_table->lock); - - if (atomic_dec_and_test(&cq->refcount)) - complete(&cq->free); - wait_for_completion(&cq->free); - - mlx4_cq_free_icm(dev, cq->cqn); -} -EXPORT_SYMBOL_GPL(mlx4_cq_free); - -int mlx4_init_cq_table(struct mlx4_dev *dev) -{ - struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; - int err; - - spin_lock_init(&cq_table->lock); - rwlock_init(&cq_table->cq_table_lock); - INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC); - if (mlx4_is_slave(dev)) - return 0; - - err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs, - dev->caps.num_cqs - 1, dev->caps.reserved_cqs, 0); - if (err) - return err; - - return 0; -} - -void mlx4_cleanup_cq_table(struct mlx4_dev *dev) -{ - if (mlx4_is_slave(dev)) - return; - /* Nothing to do to clean up radix_tree */ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->cq_table.bitmap); -} diff --git a/sys/ofed/drivers/net/mlx4/en_cq.c b/sys/ofed/drivers/net/mlx4/en_cq.c deleted file mode 100644 index 591404d0a83c..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_cq.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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/mlx4/cq.h> -#include <linux/mlx4/qp.h> -#include <linux/mlx4/cmd.h> - -#include "mlx4_en.h" - - -static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event) -{ - return; -} - - -int mlx4_en_create_cq(struct mlx4_en_priv *priv, - struct mlx4_en_cq **pcq, - int entries, int ring, enum cq_type mode, - int node) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_cq *cq; - int err; - - cq = kzalloc_node(sizeof(struct mlx4_en_cq), GFP_KERNEL, node); - if (!cq) { - cq = kzalloc(sizeof(struct mlx4_en_cq), GFP_KERNEL); - if (!cq) { - en_err(priv, "Failed to allocate CW struture\n"); - return -ENOMEM; - } - } - - cq->size = entries; - cq->buf_size = cq->size * mdev->dev->caps.cqe_size; - - cq->tq = taskqueue_create_fast("mlx4_en_que", M_NOWAIT, - taskqueue_thread_enqueue, &cq->tq); - if (mode == RX) { - TASK_INIT(&cq->cq_task, 0, mlx4_en_rx_que, cq); - taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s rx cq", - if_name(priv->dev)); - - } else { - TASK_INIT(&cq->cq_task, 0, mlx4_en_tx_que, cq); - taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s tx cq", - if_name(priv->dev)); - } - - cq->ring = ring; - cq->is_tx = mode; - spin_lock_init(&cq->lock); - - err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, - cq->buf_size, 2 * PAGE_SIZE); - if (err) - goto err_cq; - - err = mlx4_en_map_buffer(&cq->wqres.buf); - if (err) - goto err_res; - - cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; - *pcq = cq; - - return 0; - -err_res: - mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); -err_cq: - kfree(cq); - return err; -} - - -int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, - int cq_idx) -{ - struct mlx4_en_dev *mdev = priv->mdev; - int err = 0; - char name[25]; - int timestamp_en = 0; - - cq->dev = mdev->pndev[priv->port]; - cq->mcq.set_ci_db = cq->wqres.db.db; - cq->mcq.arm_db = cq->wqres.db.db + 1; - *cq->mcq.set_ci_db = 0; - *cq->mcq.arm_db = 0; - memset(cq->buf, 0, cq->buf_size); - - if (cq->is_tx == RX) { - if (mdev->dev->caps.comp_pool) { - if (!cq->vector) { - sprintf(name, "%s-%d", if_name(priv->dev), - cq->ring); - /* Set IRQ for specific name (per ring) */ - if (mlx4_assign_eq(mdev->dev, name, &cq->vector)) { - cq->vector = (cq->ring + 1 + priv->port) - % mdev->dev->caps.num_comp_vectors; - mlx4_warn(mdev, "Failed Assigning an EQ to " - "%s ,Falling back to legacy EQ's\n", - name); - } - } - } else { - cq->vector = (cq->ring + 1 + priv->port) % - mdev->dev->caps.num_comp_vectors; - } - } else { - struct mlx4_en_cq *rx_cq; - /* - * For TX we use the same irq per - * ring we assigned for the RX - */ - cq_idx = cq_idx % priv->rx_ring_num; - rx_cq = priv->rx_cq[cq_idx]; - cq->vector = rx_cq->vector; - } - - if (!cq->is_tx) - cq->size = priv->rx_ring[cq->ring]->actual_size; - err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, - &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, - cq->vector, 0, timestamp_en); - if (err) - return err; - - cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; - cq->mcq.event = mlx4_en_cq_event; - - if (cq->is_tx) { - init_timer(&cq->timer); - cq->timer.function = mlx4_en_poll_tx_cq; - cq->timer.data = (unsigned long) cq; - } - - - return 0; -} - -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_cq *cq = *pcq; - - taskqueue_drain(cq->tq, &cq->cq_task); - taskqueue_free(cq->tq); - mlx4_en_unmap_buffer(&cq->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); - if (priv->mdev->dev->caps.comp_pool && cq->vector) - mlx4_release_eq(priv->mdev->dev, cq->vector); - kfree(cq); - *pcq = NULL; -} - -void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) -{ - struct mlx4_en_dev *mdev = priv->mdev; - - taskqueue_drain(cq->tq, &cq->cq_task); - if (cq->is_tx) - del_timer_sync(&cq->timer); - - mlx4_cq_free(mdev->dev, &cq->mcq); -} - - -/* Set rx cq moderation parameters */ -int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) -{ - return mlx4_cq_modify(priv->mdev->dev, &cq->mcq, - cq->moder_cnt, cq->moder_time); -} - -int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) -{ - mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, - &priv->mdev->uar_lock); - - return 0; -} - - diff --git a/sys/ofed/drivers/net/mlx4/en_main.c b/sys/ofed/drivers/net/mlx4/en_main.c deleted file mode 100644 index 7cff16bbba27..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_main.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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. - * - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/slab.h> - -#include <linux/mlx4/driver.h> -#include <linux/mlx4/device.h> -#include <linux/mlx4/cmd.h> - -#include "mlx4_en.h" - -/* Mellanox ConnectX HCA Ethernet driver */ - -#define MLX4_EN_PARM_INT(X, def_val, desc) \ - static unsigned int X = def_val;\ - module_param(X , uint, 0444); \ - MODULE_PARM_DESC(X, desc); - - -/* - * Device scope module parameters - */ - -/* Enable RSS UDP traffic */ -MLX4_EN_PARM_INT(udp_rss, 1, - "Enable RSS for incoming UDP traffic"); - -/* Priority pausing */ -MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." - " Per priority bit mask"); -MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." - " Per priority bit mask"); - -#define MAX_PFC_TX 0xff -#define MAX_PFC_RX 0xff - - -static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) -{ - struct mlx4_en_profile *params = &mdev->profile; - int i; - - params->udp_rss = udp_rss; - params->num_tx_rings_p_up = min_t(int, mp_ncpus, - MLX4_EN_MAX_TX_RING_P_UP); - if (params->udp_rss && !(mdev->dev->caps.flags - & MLX4_DEV_CAP_FLAG_UDP_RSS)) { - mlx4_warn(mdev, "UDP RSS is not supported on this device.\n"); - params->udp_rss = 0; - } - for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = 1; - params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = 1; - params->prof[i].tx_ppp = pfctx; - params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; - params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - params->prof[i].tx_ring_num = params->num_tx_rings_p_up * - MLX4_EN_NUM_UP; - params->prof[i].rss_rings = 0; - } - - return 0; -} - -static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port) -{ - struct mlx4_en_dev *endev = ctx; - - return endev->pndev[port]; -} - -static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, - enum mlx4_dev_event event, unsigned long port) -{ - struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr; - struct mlx4_en_priv *priv; - - switch (event) { - case MLX4_DEV_EVENT_PORT_UP: - case MLX4_DEV_EVENT_PORT_DOWN: - if (!mdev->pndev[port]) - return; - priv = netdev_priv(mdev->pndev[port]); - /* To prevent races, we poll the link state in a separate - task rather than changing it here */ - priv->link_state = event; - queue_work(mdev->workqueue, &priv->linkstate_task); - break; - - case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: - mlx4_err(mdev, "Internal error detected, restarting device\n"); - break; - - case MLX4_DEV_EVENT_SLAVE_INIT: - case MLX4_DEV_EVENT_SLAVE_SHUTDOWN: - break; - default: - if (port < 1 || port > dev->caps.num_ports || - !mdev->pndev[port]) - return; - mlx4_warn(mdev, "Unhandled event %d for port %d\n", event, - (int) port); - } -} - -static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) -{ - struct mlx4_en_dev *mdev = endev_ptr; - int i, ret; - - mutex_lock(&mdev->state_lock); - mdev->device_up = false; - mutex_unlock(&mdev->state_lock); - - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) - if (mdev->pndev[i]) - mlx4_en_destroy_netdev(mdev->pndev[i]); - - flush_workqueue(mdev->workqueue); - destroy_workqueue(mdev->workqueue); - ret = mlx4_mr_free(dev, &mdev->mr); - if (ret) - mlx4_err(mdev, "Error deregistering MR. The system may have become unstable."); - iounmap(mdev->uar_map); - mlx4_uar_free(dev, &mdev->priv_uar); - mlx4_pd_free(dev, mdev->priv_pdn); - kfree(mdev); -} - -static void *mlx4_en_add(struct mlx4_dev *dev) -{ - struct mlx4_en_dev *mdev; - int i; - int err; - - mdev = kzalloc(sizeof *mdev, GFP_KERNEL); - if (!mdev) { - dev_err(&dev->pdev->dev, "Device struct alloc failed, " - "aborting.\n"); - err = -ENOMEM; - goto err_free_res; - } - - if (mlx4_pd_alloc(dev, &mdev->priv_pdn)) - goto err_free_dev; - - if (mlx4_uar_alloc(dev, &mdev->priv_uar)) - goto err_pd; - - mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT, - PAGE_SIZE); - if (!mdev->uar_map) - goto err_uar; - spin_lock_init(&mdev->uar_lock); - - mdev->dev = dev; - mdev->dma_device = &(dev->pdev->dev); - mdev->pdev = dev->pdev; - mdev->device_up = false; - - mdev->LSO_support = !!(dev->caps.flags & (1 << 15)); - if (!mdev->LSO_support) - mlx4_warn(mdev, "LSO not supported, please upgrade to later " - "FW version to enable LSO\n"); - - if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull, - MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ, - 0, 0, &mdev->mr)) { - mlx4_err(mdev, "Failed allocating memory region\n"); - goto err_map; - } - if (mlx4_mr_enable(mdev->dev, &mdev->mr)) { - mlx4_err(mdev, "Failed enabling memory region\n"); - goto err_mr; - } - - /* Build device profile according to supplied module parameters */ - err = mlx4_en_get_profile(mdev); - if (err) { - mlx4_err(mdev, "Bad module parameters, aborting.\n"); - goto err_mr; - } - - /* Configure which ports to start according to module parameters */ - mdev->port_cnt = 0; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) - mdev->port_cnt++; - - - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - if (!dev->caps.comp_pool) { - mdev->profile.prof[i].rx_ring_num = - rounddown_pow_of_two(max_t(int, MIN_RX_RINGS, - min_t(int, - dev->caps.num_comp_vectors, - DEF_RX_RINGS))); - } else { - mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two( - min_t(int, dev->caps.comp_pool / - dev->caps.num_ports, MAX_MSIX_P_PORT)); - } - } - - /* Create our own workqueue for reset/multicast tasks - * Note: we cannot use the shared workqueue because of deadlocks caused - * by the rtnl lock */ - mdev->workqueue = create_singlethread_workqueue("mlx4_en"); - if (!mdev->workqueue) { - err = -ENOMEM; - goto err_mr; - } - - /* At this stage all non-port specific tasks are complete: - * mark the card state as up */ - mutex_init(&mdev->state_lock); - mdev->device_up = true; - - /* Setup ports */ - - /* Create a netdev for each port */ - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - mlx4_info(mdev, "Activating port:%d\n", i); - if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) - mdev->pndev[i] = NULL; - } - - return mdev; - -err_mr: - err = mlx4_mr_free(dev, &mdev->mr); - if (err) - mlx4_err(mdev, "Error deregistering MR. The system may have become unstable."); -err_map: - if (mdev->uar_map) - iounmap(mdev->uar_map); -err_uar: - mlx4_uar_free(dev, &mdev->priv_uar); -err_pd: - mlx4_pd_free(dev, mdev->priv_pdn); -err_free_dev: - kfree(mdev); -err_free_res: - return NULL; -} - -static struct mlx4_interface mlx4_en_interface = { - .add = mlx4_en_add, - .remove = mlx4_en_remove, - .event = mlx4_en_event, - .get_dev = mlx4_en_get_netdev, - .protocol = MLX4_PROT_ETH, -}; - -static void mlx4_en_verify_params(void) -{ - if (pfctx > MAX_PFC_TX) { - pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - " - "should be in range 0-0x%x, will be changed to default (0)\n", - pfctx, MAX_PFC_TX); - pfctx = 0; - } - - if (pfcrx > MAX_PFC_RX) { - pr_warn("mlx4_en: WARNING: illegal module parameter pfcrx 0x%x - " - "should be in range 0-0x%x, will be changed to default (0)\n", - pfcrx, MAX_PFC_RX); - pfcrx = 0; - } -} - - -static int __init mlx4_en_init(void) -{ - mlx4_en_verify_params(); - -#ifdef CONFIG_DEBUG_FS - int err = 0; - err = mlx4_en_register_debugfs(); - if (err) - pr_err(KERN_ERR "Failed to register debugfs\n"); -#endif - return mlx4_register_interface(&mlx4_en_interface); -} - -static void __exit mlx4_en_cleanup(void) -{ - mlx4_unregister_interface(&mlx4_en_interface); -#ifdef CONFIG_DEBUG_FS - mlx4_en_unregister_debugfs(); -#endif -} - -module_init(mlx4_en_init); -module_exit(mlx4_en_cleanup); - -static int -mlxen_evhand(module_t mod, int event, void *arg) -{ - return (0); -} -static moduledata_t mlxen_mod = { - .name = "mlxen", - .evhand = mlxen_evhand, -}; -DECLARE_MODULE(mlxen, mlxen_mod, SI_SUB_OFED_PREINIT, SI_ORDER_ANY); -MODULE_DEPEND(mlxen, mlx4, 1, 1, 1); -MODULE_DEPEND(mlxen, linuxkpi, 1, 1, 1); diff --git a/sys/ofed/drivers/net/mlx4/en_netdev.c b/sys/ofed/drivers/net/mlx4/en_netdev.c deleted file mode 100644 index 26a0c6ce7336..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_netdev.c +++ /dev/null @@ -1,2818 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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/etherdevice.h> -#include <linux/delay.h> -#include <linux/slab.h> -#ifdef CONFIG_NET_RX_BUSY_POLL -#include <net/busy_poll.h> -#endif - -#include <linux/list.h> -#include <linux/if_ether.h> - -#include <linux/mlx4/driver.h> -#include <linux/mlx4/device.h> -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/cq.h> - -#include <sys/sockio.h> -#include <sys/sysctl.h> - -#include "mlx4_en.h" -#include "en_port.h" - -static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv); -static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv); -static int mlx4_en_unit; - -#ifdef CONFIG_NET_RX_BUSY_POLL -/* must be called with local_bh_disable()d */ -static int mlx4_en_low_latency_recv(struct napi_struct *napi) -{ - struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi); - struct net_device *dev = cq->dev; - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring]; - int done; - - if (!priv->port_up) - return LL_FLUSH_FAILED; - - if (!mlx4_en_cq_lock_poll(cq)) - return LL_FLUSH_BUSY; - - done = mlx4_en_process_rx_cq(dev, cq, 4); -#ifdef LL_EXTENDED_STATS - if (done) - rx_ring->cleaned += done; - else - rx_ring->misses++; -#endif - - mlx4_en_cq_unlock_poll(cq); - - return done; -} -#endif /* CONFIG_NET_RX_BUSY_POLL */ - -#ifdef CONFIG_RFS_ACCEL - -struct mlx4_en_filter { - struct list_head next; - struct work_struct work; - - u8 ip_proto; - __be32 src_ip; - __be32 dst_ip; - __be16 src_port; - __be16 dst_port; - - int rxq_index; - struct mlx4_en_priv *priv; - u32 flow_id; /* RFS infrastructure id */ - int id; /* mlx4_en driver id */ - u64 reg_id; /* Flow steering API id */ - u8 activated; /* Used to prevent expiry before filter - * is attached - */ - struct hlist_node filter_chain; -}; - -static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); - -static enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto) -{ - switch (ip_proto) { - case IPPROTO_UDP: - return MLX4_NET_TRANS_RULE_ID_UDP; - case IPPROTO_TCP: - return MLX4_NET_TRANS_RULE_ID_TCP; - default: - return -EPROTONOSUPPORT; - } -}; - -static void mlx4_en_filter_work(struct work_struct *work) -{ - struct mlx4_en_filter *filter = container_of(work, - struct mlx4_en_filter, - work); - struct mlx4_en_priv *priv = filter->priv; - struct mlx4_spec_list spec_tcp_udp = { - .id = mlx4_ip_proto_to_trans_rule_id(filter->ip_proto), - { - .tcp_udp = { - .dst_port = filter->dst_port, - .dst_port_msk = (__force __be16)-1, - .src_port = filter->src_port, - .src_port_msk = (__force __be16)-1, - }, - }, - }; - struct mlx4_spec_list spec_ip = { - .id = MLX4_NET_TRANS_RULE_ID_IPV4, - { - .ipv4 = { - .dst_ip = filter->dst_ip, - .dst_ip_msk = (__force __be32)-1, - .src_ip = filter->src_ip, - .src_ip_msk = (__force __be32)-1, - }, - }, - }; - struct mlx4_spec_list spec_eth = { - .id = MLX4_NET_TRANS_RULE_ID_ETH, - }; - struct mlx4_net_trans_rule rule = { - .list = LIST_HEAD_INIT(rule.list), - .queue_mode = MLX4_NET_TRANS_Q_LIFO, - .exclusive = 1, - .allow_loopback = 1, - .promisc_mode = MLX4_FS_REGULAR, - .port = priv->port, - .priority = MLX4_DOMAIN_RFS, - }; - int rc; - __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); - - if (spec_tcp_udp.id < 0) { - en_warn(priv, "RFS: ignoring unsupported ip protocol (%d)\n", - filter->ip_proto); - goto ignore; - } - list_add_tail(&spec_eth.list, &rule.list); - list_add_tail(&spec_ip.list, &rule.list); - list_add_tail(&spec_tcp_udp.list, &rule.list); - - rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; - memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); - memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); - - filter->activated = 0; - - if (filter->reg_id) { - rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); - if (rc && rc != -ENOENT) - en_err(priv, "Error detaching flow. rc = %d\n", rc); - } - - rc = mlx4_flow_attach(priv->mdev->dev, &rule, &filter->reg_id); - if (rc) - en_err(priv, "Error attaching flow. err = %d\n", rc); - -ignore: - mlx4_en_filter_rfs_expire(priv); - - filter->activated = 1; -} - -static inline struct hlist_head * -filter_hash_bucket(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, - __be16 src_port, __be16 dst_port) -{ - unsigned long l; - int bucket_idx; - - l = (__force unsigned long)src_port | - ((__force unsigned long)dst_port << 2); - l ^= (__force unsigned long)(src_ip ^ dst_ip); - - bucket_idx = hash_long(l, MLX4_EN_FILTER_HASH_SHIFT); - - return &priv->filter_hash[bucket_idx]; -} - -static struct mlx4_en_filter * -mlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, - __be32 dst_ip, u8 ip_proto, __be16 src_port, - __be16 dst_port, u32 flow_id) -{ - struct mlx4_en_filter *filter = NULL; - - filter = kzalloc(sizeof(struct mlx4_en_filter), GFP_ATOMIC); - if (!filter) - return NULL; - - filter->priv = priv; - filter->rxq_index = rxq_index; - INIT_WORK(&filter->work, mlx4_en_filter_work); - - filter->src_ip = src_ip; - filter->dst_ip = dst_ip; - filter->ip_proto = ip_proto; - filter->src_port = src_port; - filter->dst_port = dst_port; - - filter->flow_id = flow_id; - - filter->id = priv->last_filter_id++ % RPS_NO_FILTER; - - list_add_tail(&filter->next, &priv->filters); - hlist_add_head(&filter->filter_chain, - filter_hash_bucket(priv, src_ip, dst_ip, src_port, - dst_port)); - - return filter; -} - -static void mlx4_en_filter_free(struct mlx4_en_filter *filter) -{ - struct mlx4_en_priv *priv = filter->priv; - int rc; - - list_del(&filter->next); - - rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); - if (rc && rc != -ENOENT) - en_err(priv, "Error detaching flow. rc = %d\n", rc); - - kfree(filter); -} - -static inline struct mlx4_en_filter * -mlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, - u8 ip_proto, __be16 src_port, __be16 dst_port) -{ - struct mlx4_en_filter *filter; - struct mlx4_en_filter *ret = NULL; - - hlist_for_each_entry(filter, - filter_hash_bucket(priv, src_ip, dst_ip, - src_port, dst_port), - filter_chain) { - if (filter->src_ip == src_ip && - filter->dst_ip == dst_ip && - filter->ip_proto == ip_proto && - filter->src_port == src_port && - filter->dst_port == dst_port) { - ret = filter; - break; - } - } - - return ret; -} - -static int -mlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, - u16 rxq_index, u32 flow_id) -{ - struct mlx4_en_priv *priv = netdev_priv(net_dev); - struct mlx4_en_filter *filter; - const struct iphdr *ip; - const __be16 *ports; - u8 ip_proto; - __be32 src_ip; - __be32 dst_ip; - __be16 src_port; - __be16 dst_port; - int nhoff = skb_network_offset(skb); - int ret = 0; - - if (skb->protocol != htons(ETH_P_IP)) - return -EPROTONOSUPPORT; - - ip = (const struct iphdr *)(skb->data + nhoff); - if (ip_is_fragment(ip)) - return -EPROTONOSUPPORT; - - if ((ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP)) - return -EPROTONOSUPPORT; - ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); - - ip_proto = ip->protocol; - src_ip = ip->saddr; - dst_ip = ip->daddr; - src_port = ports[0]; - dst_port = ports[1]; - - spin_lock_bh(&priv->filters_lock); - filter = mlx4_en_filter_find(priv, src_ip, dst_ip, ip_proto, - src_port, dst_port); - if (filter) { - if (filter->rxq_index == rxq_index) - goto out; - - filter->rxq_index = rxq_index; - } else { - filter = mlx4_en_filter_alloc(priv, rxq_index, - src_ip, dst_ip, ip_proto, - src_port, dst_port, flow_id); - if (!filter) { - ret = -ENOMEM; - goto err; - } - } - - queue_work(priv->mdev->workqueue, &filter->work); - -out: - ret = filter->id; -err: - spin_unlock_bh(&priv->filters_lock); - - return ret; -} - -void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *rx_ring) -{ - struct mlx4_en_filter *filter, *tmp; - LIST_HEAD(del_list); - - spin_lock_bh(&priv->filters_lock); - list_for_each_entry_safe(filter, tmp, &priv->filters, next) { - list_move(&filter->next, &del_list); - hlist_del(&filter->filter_chain); - } - spin_unlock_bh(&priv->filters_lock); - - list_for_each_entry_safe(filter, tmp, &del_list, next) { - cancel_work_sync(&filter->work); - mlx4_en_filter_free(filter); - } -} - -static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv) -{ - struct mlx4_en_filter *filter = NULL, *tmp, *last_filter = NULL; - LIST_HEAD(del_list); - int i = 0; - - spin_lock_bh(&priv->filters_lock); - list_for_each_entry_safe(filter, tmp, &priv->filters, next) { - if (i > MLX4_EN_FILTER_EXPIRY_QUOTA) - break; - - if (filter->activated && - !work_pending(&filter->work) && - rps_may_expire_flow(priv->dev, - filter->rxq_index, filter->flow_id, - filter->id)) { - list_move(&filter->next, &del_list); - hlist_del(&filter->filter_chain); - } else - last_filter = filter; - - i++; - } - - if (last_filter && (&last_filter->next != priv->filters.next)) - list_move(&priv->filters, &last_filter->next); - - spin_unlock_bh(&priv->filters_lock); - - list_for_each_entry_safe(filter, tmp, &del_list, next) - mlx4_en_filter_free(filter); -} -#endif - -static void mlx4_en_vlan_rx_add_vid(void *arg, struct net_device *dev, u16 vid) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int err; - int idx; - - if (arg != priv) - return; - - en_dbg(HW, priv, "adding VLAN:%d\n", vid); - - set_bit(vid, priv->active_vlans); - - /* Add VID to port VLAN filter */ - mutex_lock(&mdev->state_lock); - if (mdev->device_up && priv->port_up) { - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); - if (err) - en_err(priv, "Failed configuring VLAN filter\n"); - } - if (mlx4_register_vlan(mdev->dev, priv->port, vid, &idx)) - en_dbg(HW, priv, "failed adding vlan %d\n", vid); - mutex_unlock(&mdev->state_lock); - -} - -static void mlx4_en_vlan_rx_kill_vid(void *arg, struct net_device *dev, u16 vid) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int err; - - if (arg != priv) - return; - - en_dbg(HW, priv, "Killing VID:%d\n", vid); - - clear_bit(vid, priv->active_vlans); - - /* Remove VID from port VLAN filter */ - mutex_lock(&mdev->state_lock); - mlx4_unregister_vlan(mdev->dev, priv->port, vid); - - if (mdev->device_up && priv->port_up) { - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); - if (err) - en_err(priv, "Failed configuring VLAN filter\n"); - } - mutex_unlock(&mdev->state_lock); - -} - -static int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv, - unsigned char *mac, int *qpn, u64 *reg_id) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - int err; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_B0: { - struct mlx4_qp qp; - u8 gid[16] = {0}; - - qp.qpn = *qpn; - memcpy(&gid[10], mac, ETH_ALEN); - gid[5] = priv->port; - - err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH); - break; - } - case MLX4_STEERING_MODE_DEVICE_MANAGED: { - struct mlx4_spec_list spec_eth = { {NULL} }; - __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); - - struct mlx4_net_trans_rule rule = { - .queue_mode = MLX4_NET_TRANS_Q_FIFO, - .exclusive = 0, - .allow_loopback = 1, - .promisc_mode = MLX4_FS_REGULAR, - .priority = MLX4_DOMAIN_NIC, - }; - - rule.port = priv->port; - rule.qpn = *qpn; - INIT_LIST_HEAD(&rule.list); - - spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH; - memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN); - memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); - list_add_tail(&spec_eth.list, &rule.list); - - err = mlx4_flow_attach(dev, &rule, reg_id); - break; - } - default: - return -EINVAL; - } - if (err) - en_warn(priv, "Failed Attaching Unicast\n"); - - return err; -} - -static void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv, - unsigned char *mac, int qpn, u64 reg_id) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_B0: { - struct mlx4_qp qp; - u8 gid[16] = {0}; - - qp.qpn = qpn; - memcpy(&gid[10], mac, ETH_ALEN); - gid[5] = priv->port; - - mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH); - break; - } - case MLX4_STEERING_MODE_DEVICE_MANAGED: { - mlx4_flow_detach(dev, reg_id); - break; - } - default: - en_err(priv, "Invalid steering mode.\n"); - } -} - -static int mlx4_en_get_qp(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - struct mlx4_mac_entry *entry; - int index = 0; - int err = 0; - u64 reg_id; - int *qpn = &priv->base_qpn; - u64 mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); - - en_dbg(DRV, priv, "Registering MAC: %pM for adding\n", - IF_LLADDR(priv->dev)); - index = mlx4_register_mac(dev, priv->port, mac); - if (index < 0) { - err = index; - en_err(priv, "Failed adding MAC: %pM\n", - IF_LLADDR(priv->dev)); - return err; - } - - if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { - int base_qpn = mlx4_get_base_qpn(dev, priv->port); - *qpn = base_qpn + index; - return 0; - } - - err = mlx4_qp_reserve_range(dev, 1, 1, qpn, 0); - en_dbg(DRV, priv, "Reserved qp %d\n", *qpn); - if (err) { - en_err(priv, "Failed to reserve qp for mac registration\n"); - goto qp_err; - } - - err = mlx4_en_uc_steer_add(priv, IF_LLADDR(priv->dev), qpn, ®_id); - if (err) - goto steer_err; - - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - err = -ENOMEM; - goto alloc_err; - } - memcpy(entry->mac, IF_LLADDR(priv->dev), sizeof(entry->mac)); - entry->reg_id = reg_id; - - hlist_add_head(&entry->hlist, - &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]); - - return 0; - -alloc_err: - mlx4_en_uc_steer_release(priv, IF_LLADDR(priv->dev), *qpn, reg_id); - -steer_err: - mlx4_qp_release_range(dev, *qpn, 1); - -qp_err: - mlx4_unregister_mac(dev, priv->port, mac); - return err; -} - -static void mlx4_en_put_qp(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_dev *dev = mdev->dev; - int qpn = priv->base_qpn; - u64 mac; - - if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { - mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); - en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", - IF_LLADDR(priv->dev)); - mlx4_unregister_mac(dev, priv->port, mac); - } else { - struct mlx4_mac_entry *entry; - struct hlist_node *tmp; - struct hlist_head *bucket; - unsigned int i; - - for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { - bucket = &priv->mac_hash[i]; - hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { - mac = mlx4_mac_to_u64(entry->mac); - en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", - entry->mac); - mlx4_en_uc_steer_release(priv, entry->mac, - qpn, entry->reg_id); - - mlx4_unregister_mac(dev, priv->port, mac); - hlist_del(&entry->hlist); - kfree(entry); - } - } - - en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n", - priv->port, qpn); - mlx4_qp_release_range(dev, qpn, 1); - priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; - } -} - -static void mlx4_en_clear_list(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_mc_list *tmp, *mc_to_del; - - list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) { - list_del(&mc_to_del->list); - kfree(mc_to_del); - } -} - -static void mlx4_en_cache_mclist(struct net_device *dev) -{ - struct ifmultiaddr *ifma; - struct mlx4_en_mc_list *tmp; - struct mlx4_en_priv *priv = netdev_priv(dev); - - if_maddr_rlock(dev); - TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen != - ETHER_ADDR_LEN) - continue; - /* Make sure the list didn't grow. */ - tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC); - if (tmp == NULL) { - en_err(priv, "Failed to allocate multicast list\n"); - break; - } - memcpy(tmp->addr, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETH_ALEN); - list_add_tail(&tmp->list, &priv->mc_list); - } - if_maddr_runlock(dev); -} - -static void update_mclist_flags(struct mlx4_en_priv *priv, - struct list_head *dst, - struct list_head *src) -{ - struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc; - bool found; - - /* Find all the entries that should be removed from dst, - * These are the entries that are not found in src - */ - list_for_each_entry(dst_tmp, dst, list) { - found = false; - list_for_each_entry(src_tmp, src, list) { - if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { - found = true; - break; - } - } - if (!found) - dst_tmp->action = MCLIST_REM; - } - - /* Add entries that exist in src but not in dst - * mark them as need to add - */ - list_for_each_entry(src_tmp, src, list) { - found = false; - list_for_each_entry(dst_tmp, dst, list) { - if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { - dst_tmp->action = MCLIST_NONE; - found = true; - break; - } - } - if (!found) { - new_mc = kmalloc(sizeof(struct mlx4_en_mc_list), - GFP_KERNEL); - if (!new_mc) { - en_err(priv, "Failed to allocate current multicast list\n"); - return; - } - memcpy(new_mc, src_tmp, - sizeof(struct mlx4_en_mc_list)); - new_mc->action = MCLIST_ADD; - list_add_tail(&new_mc->list, dst); - } - } -} - -static void mlx4_en_set_rx_mode(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - if (!priv->port_up) - return; - - queue_work(priv->mdev->workqueue, &priv->rx_mode_task); -} - -static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, - struct mlx4_en_dev *mdev) -{ - int err = 0; - if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { - priv->flags |= MLX4_EN_FLAG_PROMISC; - - /* Enable promiscouos mode */ - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_add(mdev->dev, - priv->port, - priv->base_qpn, - MLX4_FS_ALL_DEFAULT); - if (err) - en_err(priv, "Failed enabling promiscuous mode\n"); - priv->flags |= MLX4_EN_FLAG_MC_PROMISC; - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_unicast_promisc_add(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed enabling unicast promiscuous mode\n"); - - /* Add the default qp number as multicast - * promisc - */ - if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { - err = mlx4_multicast_promisc_add(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed enabling multicast promiscuous mode\n"); - priv->flags |= MLX4_EN_FLAG_MC_PROMISC; - } - break; - - case MLX4_STEERING_MODE_A0: - err = mlx4_SET_PORT_qpn_calc(mdev->dev, - priv->port, - priv->base_qpn, - 1); - if (err) - en_err(priv, "Failed enabling promiscuous mode\n"); - break; - } - - /* Disable port multicast filter (unconditionally) */ - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_DISABLE); - if (err) - en_err(priv, "Failed disabling multicast filter\n"); - } -} - -static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, - struct mlx4_en_dev *mdev) -{ - int err = 0; - - priv->flags &= ~MLX4_EN_FLAG_PROMISC; - - /* Disable promiscouos mode */ - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_ALL_DEFAULT); - if (err) - en_err(priv, "Failed disabling promiscuous mode\n"); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_unicast_promisc_remove(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed disabling unicast promiscuous mode\n"); - /* Disable Multicast promisc */ - if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { - err = mlx4_multicast_promisc_remove(mdev->dev, - priv->base_qpn, - priv->port); - if (err) - en_err(priv, "Failed disabling multicast promiscuous mode\n"); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - } - break; - - case MLX4_STEERING_MODE_A0: - err = mlx4_SET_PORT_qpn_calc(mdev->dev, - priv->port, - priv->base_qpn, 0); - if (err) - en_err(priv, "Failed disabling promiscuous mode\n"); - break; - } -} - -static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, - struct net_device *dev, - struct mlx4_en_dev *mdev) -{ - struct mlx4_en_mc_list *mclist, *tmp; - u8 mc_list[16] = {0}; - int err = 0; - u64 mcast_addr = 0; - - - /* Enable/disable the multicast filter according to IFF_ALLMULTI */ - if (dev->if_flags & IFF_ALLMULTI) { - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_DISABLE); - if (err) - en_err(priv, "Failed disabling multicast filter\n"); - - /* Add the default qp number as multicast promisc */ - if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_add(mdev->dev, - priv->port, - priv->base_qpn, - MLX4_FS_MC_DEFAULT); - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_multicast_promisc_add(mdev->dev, - priv->base_qpn, - priv->port); - break; - - case MLX4_STEERING_MODE_A0: - break; - } - if (err) - en_err(priv, "Failed entering multicast promisc mode\n"); - priv->flags |= MLX4_EN_FLAG_MC_PROMISC; - } - } else { - /* Disable Multicast promisc */ - if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { - switch (mdev->dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - err = mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_MC_DEFAULT); - break; - - case MLX4_STEERING_MODE_B0: - err = mlx4_multicast_promisc_remove(mdev->dev, - priv->base_qpn, - priv->port); - break; - - case MLX4_STEERING_MODE_A0: - break; - } - if (err) - en_err(priv, "Failed disabling multicast promiscuous mode\n"); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - } - - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_DISABLE); - if (err) - en_err(priv, "Failed disabling multicast filter\n"); - - /* Flush mcast filter and init it with broadcast address */ - mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, - 1, MLX4_MCAST_CONFIG); - - /* Update multicast list - we cache all addresses so they won't - * change while HW is updated holding the command semaphor */ - mlx4_en_cache_mclist(dev); - list_for_each_entry(mclist, &priv->mc_list, list) { - mcast_addr = mlx4_mac_to_u64(mclist->addr); - mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, - mcast_addr, 0, MLX4_MCAST_CONFIG); - } - err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, - 0, MLX4_MCAST_ENABLE); - if (err) - en_err(priv, "Failed enabling multicast filter\n"); - - update_mclist_flags(priv, &priv->curr_list, &priv->mc_list); - list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { - if (mclist->action == MCLIST_REM) { - /* detach this address and delete from list */ - memcpy(&mc_list[10], mclist->addr, ETH_ALEN); - mc_list[5] = priv->port; - err = mlx4_multicast_detach(mdev->dev, - &priv->rss_map.indir_qp, - mc_list, - MLX4_PROT_ETH, - mclist->reg_id); - if (err) - en_err(priv, "Fail to detach multicast address\n"); - - /* remove from list */ - list_del(&mclist->list); - kfree(mclist); - } else if (mclist->action == MCLIST_ADD) { - /* attach the address */ - memcpy(&mc_list[10], mclist->addr, ETH_ALEN); - /* needed for B0 steering support */ - mc_list[5] = priv->port; - err = mlx4_multicast_attach(mdev->dev, - &priv->rss_map.indir_qp, - mc_list, - priv->port, 0, - MLX4_PROT_ETH, - &mclist->reg_id); - if (err) - en_err(priv, "Fail to attach multicast address\n"); - - } - } - } -} - -static void mlx4_en_do_set_rx_mode(struct work_struct *work) -{ - struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, - rx_mode_task); - struct mlx4_en_dev *mdev = priv->mdev; - struct net_device *dev = priv->dev; - - - mutex_lock(&mdev->state_lock); - if (!mdev->device_up) { - en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n"); - goto out; - } - if (!priv->port_up) { - en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n"); - goto out; - } - if (!mlx4_en_QUERY_PORT(mdev, priv->port)) { - if (priv->port_state.link_state) { - priv->last_link_state = MLX4_DEV_EVENT_PORT_UP; - /* update netif baudrate */ - priv->dev->if_baudrate = - IF_Mbps(priv->port_state.link_speed); - /* Important note: the following call for if_link_state_change - * is needed for interface up scenario (start port, link state - * change) */ - if_link_state_change(priv->dev, LINK_STATE_UP); - en_dbg(HW, priv, "Link Up\n"); - } - } - - /* Promsicuous mode: disable all filters */ - if ((dev->if_flags & IFF_PROMISC) || - (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) { - mlx4_en_set_promisc_mode(priv, mdev); - goto out; - } - - /* Not in promiscuous mode */ - if (priv->flags & MLX4_EN_FLAG_PROMISC) - mlx4_en_clear_promisc_mode(priv, mdev); - - mlx4_en_do_multicast(priv, dev, mdev); -out: - mutex_unlock(&mdev->state_lock); -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void mlx4_en_netpoll(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_cq *cq; - unsigned long flags; - int i; - - for (i = 0; i < priv->rx_ring_num; i++) { - cq = priv->rx_cq[i]; - spin_lock_irqsave(&cq->lock, flags); - napi_synchronize(&cq->napi); - mlx4_en_process_rx_cq(dev, cq, 0); - spin_unlock_irqrestore(&cq->lock, flags); - } -} -#endif - -static void mlx4_en_watchdog_timeout(void *arg) -{ - struct mlx4_en_priv *priv = arg; - struct mlx4_en_dev *mdev = priv->mdev; - - en_dbg(DRV, priv, "Scheduling watchdog\n"); - queue_work(mdev->workqueue, &priv->watchdog_task); - if (priv->port_up) - callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, - mlx4_en_watchdog_timeout, priv); -} - - - -static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) -{ - struct mlx4_en_cq *cq; - int i; - - /* If we haven't received a specific coalescing setting - * (module param), we set the moderation parameters as follows: - * - moder_cnt is set to the number of mtu sized packets to - * satisfy our coelsing target. - * - moder_time is set to a fixed value. - */ - priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->if_mtu + 1; - priv->rx_usecs = MLX4_EN_RX_COAL_TIME; - priv->tx_frames = MLX4_EN_TX_COAL_PKTS; - priv->tx_usecs = MLX4_EN_TX_COAL_TIME; - en_dbg(INTR, priv, "Default coalesing params for mtu: %u - " - "rx_frames:%d rx_usecs:%d\n", - (unsigned)priv->dev->if_mtu, priv->rx_frames, priv->rx_usecs); - - /* Setup cq moderation params */ - for (i = 0; i < priv->rx_ring_num; i++) { - cq = priv->rx_cq[i]; - cq->moder_cnt = priv->rx_frames; - cq->moder_time = priv->rx_usecs; - priv->last_moder_time[i] = MLX4_EN_AUTO_CONF; - priv->last_moder_packets[i] = 0; - priv->last_moder_bytes[i] = 0; - } - - for (i = 0; i < priv->tx_ring_num; i++) { - cq = priv->tx_cq[i]; - cq->moder_cnt = priv->tx_frames; - cq->moder_time = priv->tx_usecs; - } - - /* Reset auto-moderation params */ - priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW; - priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW; - priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; - priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; - priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; - priv->adaptive_rx_coal = 1; - priv->last_moder_jiffies = 0; - priv->last_moder_tx_packets = 0; -} - -static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) -{ - unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); - struct mlx4_en_cq *cq; - unsigned long packets; - unsigned long rate; - unsigned long avg_pkt_size; - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long rx_pkt_diff; - int moder_time; - int ring, err; - - if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ) - return; - - for (ring = 0; ring < priv->rx_ring_num; ring++) { - spin_lock(&priv->stats_lock); - rx_packets = priv->rx_ring[ring]->packets; - rx_bytes = priv->rx_ring[ring]->bytes; - spin_unlock(&priv->stats_lock); - - rx_pkt_diff = ((unsigned long) (rx_packets - - priv->last_moder_packets[ring])); - packets = rx_pkt_diff; - rate = packets * HZ / period; - avg_pkt_size = packets ? ((unsigned long) (rx_bytes - - priv->last_moder_bytes[ring])) / packets : 0; - - /* Apply auto-moderation only when packet rate - * exceeds a rate that it matters */ - if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) && - avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { - if (rate < priv->pkt_rate_low) - moder_time = priv->rx_usecs_low; - else if (rate > priv->pkt_rate_high) - moder_time = priv->rx_usecs_high; - else - moder_time = (rate - priv->pkt_rate_low) * - (priv->rx_usecs_high - priv->rx_usecs_low) / - (priv->pkt_rate_high - priv->pkt_rate_low) + - priv->rx_usecs_low; - } else { - moder_time = priv->rx_usecs_low; - } - - if (moder_time != priv->last_moder_time[ring]) { - priv->last_moder_time[ring] = moder_time; - cq = priv->rx_cq[ring]; - cq->moder_time = moder_time; - err = mlx4_en_set_cq_moder(priv, cq); - if (err) - en_err(priv, "Failed modifying moderation for cq:%d\n", - ring); - } - priv->last_moder_packets[ring] = rx_packets; - priv->last_moder_bytes[ring] = rx_bytes; - } - - priv->last_moder_jiffies = jiffies; -} - -static void mlx4_en_do_get_stats(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, - stats_task); - struct mlx4_en_dev *mdev = priv->mdev; - int err; - - mutex_lock(&mdev->state_lock); - if (mdev->device_up) { - if (priv->port_up) { - err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); - if (err) - en_dbg(HW, priv, "Could not update stats\n"); - - mlx4_en_auto_moderation(priv); - } - - queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); - } - mutex_unlock(&mdev->state_lock); -} - -/* mlx4_en_service_task - Run service task for tasks that needed to be done - * periodically - */ -static void mlx4_en_service_task(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, - service_task); - struct mlx4_en_dev *mdev = priv->mdev; - - mutex_lock(&mdev->state_lock); - if (mdev->device_up) { - queue_delayed_work(mdev->workqueue, &priv->service_task, - SERVICE_TASK_DELAY); - } - mutex_unlock(&mdev->state_lock); -} - -static void mlx4_en_linkstate(struct work_struct *work) -{ - struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, - linkstate_task); - struct mlx4_en_dev *mdev = priv->mdev; - int linkstate = priv->link_state; - - mutex_lock(&mdev->state_lock); - /* If observable port state changed set carrier state and - * report to system log */ - if (priv->last_link_state != linkstate) { - if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { - en_info(priv, "Link Down\n"); - if_link_state_change(priv->dev, LINK_STATE_DOWN); - /* update netif baudrate */ - priv->dev->if_baudrate = 0; - - /* make sure the port is up before notifying the OS. - * This is tricky since we get here on INIT_PORT and - * in such case we can't tell the OS the port is up. - * To solve this there is a call to if_link_state_change - * in set_rx_mode. - * */ - } else if (priv->port_up && (linkstate == MLX4_DEV_EVENT_PORT_UP)){ - if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) - en_info(priv, "Query port failed\n"); - priv->dev->if_baudrate = - IF_Mbps(priv->port_state.link_speed); - en_info(priv, "Link Up\n"); - if_link_state_change(priv->dev, LINK_STATE_UP); - } - } - priv->last_link_state = linkstate; - mutex_unlock(&mdev->state_lock); -} - - -int mlx4_en_start_port(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_cq *cq; - struct mlx4_en_tx_ring *tx_ring; - int rx_index = 0; - int tx_index = 0; - int err = 0; - int i; - int j; - u8 mc_list[16] = {0}; - - - if (priv->port_up) { - en_dbg(DRV, priv, "start port called while port already up\n"); - return 0; - } - - INIT_LIST_HEAD(&priv->mc_list); - INIT_LIST_HEAD(&priv->curr_list); - INIT_LIST_HEAD(&priv->ethtool_list); - - /* Calculate Rx buf size */ - dev->if_mtu = min(dev->if_mtu, priv->max_mtu); - mlx4_en_calc_rx_buf(dev); - en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_mb_size); - - /* Configure rx cq's and rings */ - err = mlx4_en_activate_rx_rings(priv); - if (err) { - en_err(priv, "Failed to activate RX rings\n"); - return err; - } - for (i = 0; i < priv->rx_ring_num; i++) { - cq = priv->rx_cq[i]; - - mlx4_en_cq_init_lock(cq); - err = mlx4_en_activate_cq(priv, cq, i); - if (err) { - en_err(priv, "Failed activating Rx CQ\n"); - goto cq_err; - } - for (j = 0; j < cq->size; j++) - cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; - err = mlx4_en_set_cq_moder(priv, cq); - if (err) { - en_err(priv, "Failed setting cq moderation parameters"); - mlx4_en_deactivate_cq(priv, cq); - goto cq_err; - } - mlx4_en_arm_cq(priv, cq); - priv->rx_ring[i]->cqn = cq->mcq.cqn; - ++rx_index; - } - - /* Set qp number */ - en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port); - err = mlx4_en_get_qp(priv); - if (err) { - en_err(priv, "Failed getting eth qp\n"); - goto cq_err; - } - mdev->mac_removed[priv->port] = 0; - - /* gets default allocated counter index from func cap */ - /* or sink counter index if no resources */ - priv->counter_index = mdev->dev->caps.def_counter_index[priv->port - 1]; - - en_dbg(DRV, priv, "%s: default counter index %d for port %d\n", - __func__, priv->counter_index, priv->port); - - err = mlx4_en_config_rss_steer(priv); - if (err) { - en_err(priv, "Failed configuring rss steering\n"); - goto mac_err; - } - - err = mlx4_en_create_drop_qp(priv); - if (err) - goto rss_err; - - /* Configure tx cq's and rings */ - for (i = 0; i < priv->tx_ring_num; i++) { - /* Configure cq */ - cq = priv->tx_cq[i]; - err = mlx4_en_activate_cq(priv, cq, i); - if (err) { - en_err(priv, "Failed activating Tx CQ\n"); - goto tx_err; - } - err = mlx4_en_set_cq_moder(priv, cq); - if (err) { - en_err(priv, "Failed setting cq moderation parameters"); - mlx4_en_deactivate_cq(priv, cq); - goto tx_err; - } - en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); - cq->buf->wqe_index = cpu_to_be16(0xffff); - - /* Configure ring */ - tx_ring = priv->tx_ring[i]; - - err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, - i / priv->num_tx_rings_p_up); - if (err) { - en_err(priv, "Failed activating Tx ring %d\n", i); - mlx4_en_deactivate_cq(priv, cq); - goto tx_err; - } - - /* Arm CQ for TX completions */ - mlx4_en_arm_cq(priv, cq); - - /* Set initial ownership of all Tx TXBBs to SW (1) */ - for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) - *((u32 *) (tx_ring->buf + j)) = 0xffffffff; - ++tx_index; - } - - /* Configure port */ - err = mlx4_SET_PORT_general(mdev->dev, priv->port, - priv->rx_mb_size, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - if (err) { - en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", - priv->port, err); - goto tx_err; - } - /* Set default qp number */ - err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); - if (err) { - en_err(priv, "Failed setting default qp numbers\n"); - goto tx_err; - } - - /* Init port */ - en_dbg(HW, priv, "Initializing port\n"); - err = mlx4_INIT_PORT(mdev->dev, priv->port); - if (err) { - en_err(priv, "Failed Initializing port\n"); - goto tx_err; - } - - /* Attach rx QP to bradcast address */ - memset(&mc_list[10], 0xff, ETH_ALEN); - mc_list[5] = priv->port; /* needed for B0 steering support */ - if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, - priv->port, 0, MLX4_PROT_ETH, - &priv->broadcast_id)) - mlx4_warn(mdev, "Failed Attaching Broadcast\n"); - - /* Must redo promiscuous mode setup. */ - priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); - - /* Schedule multicast task to populate multicast list */ - queue_work(mdev->workqueue, &priv->rx_mode_task); - - mlx4_set_stats_bitmap(mdev->dev, priv->stats_bitmap); - - priv->port_up = true; - - /* Enable the queues. */ - dev->if_drv_flags &= ~IFF_DRV_OACTIVE; - dev->if_drv_flags |= IFF_DRV_RUNNING; -#ifdef CONFIG_DEBUG_FS - mlx4_en_create_debug_files(priv); -#endif - callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, - mlx4_en_watchdog_timeout, priv); - - - return 0; - -tx_err: - while (tx_index--) { - mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[tx_index]); - mlx4_en_deactivate_cq(priv, priv->tx_cq[tx_index]); - } - mlx4_en_destroy_drop_qp(priv); -rss_err: - mlx4_en_release_rss_steer(priv); -mac_err: - mlx4_en_put_qp(priv); -cq_err: - while (rx_index--) - mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]); - for (i = 0; i < priv->rx_ring_num; i++) - mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); - - return err; /* need to close devices */ -} - - -void mlx4_en_stop_port(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_mc_list *mclist, *tmp; - int i; - u8 mc_list[16] = {0}; - - if (!priv->port_up) { - en_dbg(DRV, priv, "stop port called while port already down\n"); - return; - } - -#ifdef CONFIG_DEBUG_FS - mlx4_en_delete_debug_files(priv); -#endif - - /* close port*/ - mlx4_CLOSE_PORT(mdev->dev, priv->port); - - /* Set port as not active */ - priv->port_up = false; - if (priv->counter_index != 0xff) { - mlx4_counter_free(mdev->dev, priv->port, priv->counter_index); - priv->counter_index = 0xff; - } - - /* Promsicuous mode */ - if (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - priv->flags &= ~(MLX4_EN_FLAG_PROMISC | - MLX4_EN_FLAG_MC_PROMISC); - mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_ALL_DEFAULT); - mlx4_flow_steer_promisc_remove(mdev->dev, - priv->port, - MLX4_FS_MC_DEFAULT); - } else if (priv->flags & MLX4_EN_FLAG_PROMISC) { - priv->flags &= ~MLX4_EN_FLAG_PROMISC; - - /* Disable promiscouos mode */ - mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, - priv->port); - - /* Disable Multicast promisc */ - if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { - mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, - priv->port); - priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; - } - } - - /* Detach All multicasts */ - memset(&mc_list[10], 0xff, ETH_ALEN); - mc_list[5] = priv->port; /* needed for B0 steering support */ - mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, - MLX4_PROT_ETH, priv->broadcast_id); - list_for_each_entry(mclist, &priv->curr_list, list) { - memcpy(&mc_list[10], mclist->addr, ETH_ALEN); - mc_list[5] = priv->port; - mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, - mc_list, MLX4_PROT_ETH, mclist->reg_id); - } - mlx4_en_clear_list(dev); - list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { - list_del(&mclist->list); - kfree(mclist); - } - - /* Flush multicast filter */ - mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); - mlx4_en_destroy_drop_qp(priv); - - /* Free TX Rings */ - for (i = 0; i < priv->tx_ring_num; i++) { - mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[i]); - mlx4_en_deactivate_cq(priv, priv->tx_cq[i]); - } - msleep(10); - - for (i = 0; i < priv->tx_ring_num; i++) - mlx4_en_free_tx_buf(dev, priv->tx_ring[i]); - - /* Free RSS qps */ - mlx4_en_release_rss_steer(priv); - - /* Unregister Mac address for the port */ - mlx4_en_put_qp(priv); - mdev->mac_removed[priv->port] = 1; - - /* Free RX Rings */ - for (i = 0; i < priv->rx_ring_num; i++) { - struct mlx4_en_cq *cq = priv->rx_cq[i]; - mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); - mlx4_en_deactivate_cq(priv, cq); - } - - callout_stop(&priv->watchdog_timer); - - dev->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -} - -static void mlx4_en_restart(struct work_struct *work) -{ - struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, - watchdog_task); - struct mlx4_en_dev *mdev = priv->mdev; - struct net_device *dev = priv->dev; - struct mlx4_en_tx_ring *ring; - int i; - - - if (priv->blocked == 0 || priv->port_up == 0) - return; - for (i = 0; i < priv->tx_ring_num; i++) { - ring = priv->tx_ring[i]; - if (ring->blocked && - ring->watchdog_time + MLX4_EN_WATCHDOG_TIMEOUT < ticks) - goto reset; - } - return; - -reset: - priv->port_stats.tx_timeout++; - en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); - - mutex_lock(&mdev->state_lock); - if (priv->port_up) { - mlx4_en_stop_port(dev); - //for (i = 0; i < priv->tx_ring_num; i++) - // netdev_tx_reset_queue(priv->tx_ring[i]->tx_queue); - if (mlx4_en_start_port(dev)) - en_err(priv, "Failed restarting port %d\n", priv->port); - } - mutex_unlock(&mdev->state_lock); -} - -static void mlx4_en_clear_stats(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int i; - - if (!mlx4_is_slave(mdev->dev)) - if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) - en_dbg(HW, priv, "Failed dumping statistics\n"); - - memset(&priv->pstats, 0, sizeof(priv->pstats)); - memset(&priv->pkstats, 0, sizeof(priv->pkstats)); - memset(&priv->port_stats, 0, sizeof(priv->port_stats)); - memset(&priv->vport_stats, 0, sizeof(priv->vport_stats)); - - for (i = 0; i < priv->tx_ring_num; i++) { - priv->tx_ring[i]->bytes = 0; - priv->tx_ring[i]->packets = 0; - priv->tx_ring[i]->tx_csum = 0; - priv->tx_ring[i]->oversized_packets = 0; - } - for (i = 0; i < priv->rx_ring_num; i++) { - priv->rx_ring[i]->bytes = 0; - priv->rx_ring[i]->packets = 0; - priv->rx_ring[i]->csum_ok = 0; - priv->rx_ring[i]->csum_none = 0; - } -} - -static void mlx4_en_open(void* arg) -{ - - struct mlx4_en_priv *priv; - struct mlx4_en_dev *mdev; - struct net_device *dev; - int err = 0; - - priv = arg; - mdev = priv->mdev; - dev = priv->dev; - - - mutex_lock(&mdev->state_lock); - - if (!mdev->device_up) { - en_err(priv, "Cannot open - device down/disabled\n"); - goto out; - } - - /* Reset HW statistics and SW counters */ - mlx4_en_clear_stats(dev); - - err = mlx4_en_start_port(dev); - if (err) - en_err(priv, "Failed starting port:%d\n", priv->port); - -out: - mutex_unlock(&mdev->state_lock); - return; -} - -void mlx4_en_free_resources(struct mlx4_en_priv *priv) -{ - int i; - -#ifdef CONFIG_RFS_ACCEL - if (priv->dev->rx_cpu_rmap) { - free_irq_cpu_rmap(priv->dev->rx_cpu_rmap); - priv->dev->rx_cpu_rmap = NULL; - } -#endif - - for (i = 0; i < priv->tx_ring_num; i++) { - if (priv->tx_ring && priv->tx_ring[i]) - mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); - if (priv->tx_cq && priv->tx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); - } - - for (i = 0; i < priv->rx_ring_num; i++) { - if (priv->rx_ring[i]) - mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], - priv->prof->rx_ring_size, priv->stride); - if (priv->rx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); - } - - if (priv->sysctl) - sysctl_ctx_free(&priv->stat_ctx); -} - -int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) -{ - struct mlx4_en_port_profile *prof = priv->prof; - int i; - int node = 0; - - /* Create rx Rings */ - for (i = 0; i < priv->rx_ring_num; i++) { - if (mlx4_en_create_cq(priv, &priv->rx_cq[i], - prof->rx_ring_size, i, RX, node)) - goto err; - - if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i], - prof->rx_ring_size, node)) - goto err; - } - - /* Create tx Rings */ - for (i = 0; i < priv->tx_ring_num; i++) { - if (mlx4_en_create_cq(priv, &priv->tx_cq[i], - prof->tx_ring_size, i, TX, node)) - goto err; - - if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], - prof->tx_ring_size, TXBB_SIZE, node, i)) - goto err; - } - -#ifdef CONFIG_RFS_ACCEL - priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->rx_ring_num); - if (!priv->dev->rx_cpu_rmap) - goto err; -#endif - /* Re-create stat sysctls in case the number of rings changed. */ - mlx4_en_sysctl_stat(priv); - return 0; - -err: - en_err(priv, "Failed to allocate NIC resources\n"); - for (i = 0; i < priv->rx_ring_num; i++) { - if (priv->rx_ring[i]) - mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], - prof->rx_ring_size, - priv->stride); - if (priv->rx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); - } - for (i = 0; i < priv->tx_ring_num; i++) { - if (priv->tx_ring[i]) - mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); - if (priv->tx_cq[i]) - mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); - } - priv->port_up = false; - return -ENOMEM; -} - -struct en_port_attribute { - struct attribute attr; - ssize_t (*show)(struct en_port *, struct en_port_attribute *, char *buf); - ssize_t (*store)(struct en_port *, struct en_port_attribute *, char *buf, size_t count); -}; - -#define PORT_ATTR_RO(_name) \ -struct en_port_attribute en_port_attr_##_name = __ATTR_RO(_name) - -#define EN_PORT_ATTR(_name, _mode, _show, _store) \ -struct en_port_attribute en_port_attr_##_name = __ATTR(_name, _mode, _show, _store) - -void mlx4_en_destroy_netdev(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - - en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); - - if (priv->vlan_attach != NULL) - EVENTHANDLER_DEREGISTER(vlan_config, priv->vlan_attach); - if (priv->vlan_detach != NULL) - EVENTHANDLER_DEREGISTER(vlan_unconfig, priv->vlan_detach); - - /* Unregister device - this will close the port if it was up */ - if (priv->registered) { - mutex_lock(&mdev->state_lock); - ether_ifdetach(dev); - mutex_unlock(&mdev->state_lock); - } - - if (priv->allocated) - mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); - - mutex_lock(&mdev->state_lock); - mlx4_en_stop_port(dev); - mutex_unlock(&mdev->state_lock); - - - cancel_delayed_work(&priv->stats_task); - cancel_delayed_work(&priv->service_task); - /* flush any pending task for this netdev */ - flush_workqueue(mdev->workqueue); - callout_drain(&priv->watchdog_timer); - - /* Detach the netdev so tasks would not attempt to access it */ - mutex_lock(&mdev->state_lock); - mdev->pndev[priv->port] = NULL; - mutex_unlock(&mdev->state_lock); - - - mlx4_en_free_resources(priv); - - /* freeing the sysctl conf cannot be called from within mlx4_en_free_resources */ - if (priv->sysctl) - sysctl_ctx_free(&priv->conf_ctx); - - kfree(priv->tx_ring); - kfree(priv->tx_cq); - - kfree(priv); - if_free(dev); - -} - -static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int err = 0; - - en_dbg(DRV, priv, "Change MTU called - current:%u new:%u\n", - (unsigned)dev->if_mtu, (unsigned)new_mtu); - - if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { - en_err(priv, "Bad MTU size:%d.\n", new_mtu); - return -EPERM; - } - mutex_lock(&mdev->state_lock); - dev->if_mtu = new_mtu; - if (dev->if_drv_flags & IFF_DRV_RUNNING) { - if (!mdev->device_up) { - /* NIC is probably restarting - let watchdog task reset - * * the port */ - en_dbg(DRV, priv, "Change MTU called with card down!?\n"); - } else { - mlx4_en_stop_port(dev); - err = mlx4_en_start_port(dev); - if (err) { - en_err(priv, "Failed restarting port:%d\n", - priv->port); - queue_work(mdev->workqueue, &priv->watchdog_task); - } - } - } - mutex_unlock(&mdev->state_lock); - return 0; -} - -static int mlx4_en_calc_media(struct mlx4_en_priv *priv) -{ - int trans_type; - int active; - - active = IFM_ETHER; - if (priv->last_link_state == MLX4_DEV_EVENT_PORT_DOWN) - return (active); - active |= IFM_FDX; - trans_type = priv->port_state.transciver; - /* XXX I don't know all of the transceiver values. */ - switch (priv->port_state.link_speed) { - case 1000: - active |= IFM_1000_T; - break; - case 10000: - if (trans_type > 0 && trans_type <= 0xC) - active |= IFM_10G_SR; - else if (trans_type == 0x80 || trans_type == 0) - active |= IFM_10G_CX4; - break; - case 40000: - active |= IFM_40G_CR4; - break; - } - if (priv->prof->tx_pause) - active |= IFM_ETH_TXPAUSE; - if (priv->prof->rx_pause) - active |= IFM_ETH_RXPAUSE; - - return (active); -} - -static void mlx4_en_media_status(struct ifnet *dev, struct ifmediareq *ifmr) -{ - struct mlx4_en_priv *priv; - - priv = dev->if_softc; - ifmr->ifm_status = IFM_AVALID; - if (priv->last_link_state != MLX4_DEV_EVENT_PORT_DOWN) - ifmr->ifm_status |= IFM_ACTIVE; - ifmr->ifm_active = mlx4_en_calc_media(priv); - - return; -} - -static int mlx4_en_media_change(struct ifnet *dev) -{ - struct mlx4_en_priv *priv; - struct ifmedia *ifm; - int rxpause; - int txpause; - int error; - - priv = dev->if_softc; - ifm = &priv->media; - rxpause = txpause = 0; - error = 0; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return (EINVAL); - switch (IFM_SUBTYPE(ifm->ifm_media)) { - case IFM_AUTO: - break; - case IFM_10G_SR: - case IFM_10G_CX4: - case IFM_1000_T: - case IFM_40G_CR4: - if ((IFM_SUBTYPE(ifm->ifm_media) - == IFM_SUBTYPE(mlx4_en_calc_media(priv))) - && (ifm->ifm_media & IFM_FDX)) - break; - /* Fallthrough */ - default: - printf("%s: Only auto media type\n", if_name(dev)); - return (EINVAL); - } - /* Allow user to set/clear pause */ - if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE) - rxpause = 1; - if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE) - txpause = 1; - if (priv->prof->tx_pause != txpause || priv->prof->rx_pause != rxpause) { - priv->prof->tx_pause = txpause; - priv->prof->rx_pause = rxpause; - error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, - priv->rx_mb_size + ETHER_CRC_LEN, priv->prof->tx_pause, - priv->prof->tx_ppp, priv->prof->rx_pause, - priv->prof->rx_ppp); - } - return (error); -} - -static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) -{ - struct mlx4_en_priv *priv; - struct mlx4_en_dev *mdev; - struct ifreq *ifr; - int error; - int mask; - - error = 0; - mask = 0; - priv = dev->if_softc; - mdev = priv->mdev; - ifr = (struct ifreq *) data; - switch (command) { - - case SIOCSIFMTU: - error = -mlx4_en_change_mtu(dev, ifr->ifr_mtu); - break; - case SIOCSIFFLAGS: - if (dev->if_flags & IFF_UP) { - if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) { - mutex_lock(&mdev->state_lock); - mlx4_en_start_port(dev); - mutex_unlock(&mdev->state_lock); - } else { - mlx4_en_set_rx_mode(dev); - } - } else { - mutex_lock(&mdev->state_lock); - if (dev->if_drv_flags & IFF_DRV_RUNNING) { - mlx4_en_stop_port(dev); - if_link_state_change(dev, LINK_STATE_DOWN); - } - mutex_unlock(&mdev->state_lock); - } - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - mlx4_en_set_rx_mode(dev); - break; - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - error = ifmedia_ioctl(dev, ifr, &priv->media, command); - break; - case SIOCSIFCAP: - mutex_lock(&mdev->state_lock); - mask = ifr->ifr_reqcap ^ dev->if_capenable; - if (mask & IFCAP_TXCSUM) { - dev->if_capenable ^= IFCAP_TXCSUM; - dev->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); - - if (IFCAP_TSO4 & dev->if_capenable && - !(IFCAP_TXCSUM & dev->if_capenable)) { - dev->if_capenable &= ~IFCAP_TSO4; - dev->if_hwassist &= ~CSUM_IP_TSO; - if_printf(dev, - "tso4 disabled due to -txcsum.\n"); - } - } - if (mask & IFCAP_TXCSUM_IPV6) { - dev->if_capenable ^= IFCAP_TXCSUM_IPV6; - dev->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); - - if (IFCAP_TSO6 & dev->if_capenable && - !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { - dev->if_capenable &= ~IFCAP_TSO6; - dev->if_hwassist &= ~CSUM_IP6_TSO; - if_printf(dev, - "tso6 disabled due to -txcsum6.\n"); - } - } - if (mask & IFCAP_RXCSUM) - dev->if_capenable ^= IFCAP_RXCSUM; - if (mask & IFCAP_RXCSUM_IPV6) - dev->if_capenable ^= IFCAP_RXCSUM_IPV6; - - if (mask & IFCAP_TSO4) { - if (!(IFCAP_TSO4 & dev->if_capenable) && - !(IFCAP_TXCSUM & dev->if_capenable)) { - if_printf(dev, "enable txcsum first.\n"); - error = EAGAIN; - goto out; - } - dev->if_capenable ^= IFCAP_TSO4; - dev->if_hwassist ^= CSUM_IP_TSO; - } - if (mask & IFCAP_TSO6) { - if (!(IFCAP_TSO6 & dev->if_capenable) && - !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { - if_printf(dev, "enable txcsum6 first.\n"); - error = EAGAIN; - goto out; - } - dev->if_capenable ^= IFCAP_TSO6; - dev->if_hwassist ^= CSUM_IP6_TSO; - } - if (mask & IFCAP_LRO) - dev->if_capenable ^= IFCAP_LRO; - if (mask & IFCAP_VLAN_HWTAGGING) - dev->if_capenable ^= IFCAP_VLAN_HWTAGGING; - if (mask & IFCAP_VLAN_HWFILTER) - dev->if_capenable ^= IFCAP_VLAN_HWFILTER; - if (mask & IFCAP_WOL_MAGIC) - dev->if_capenable ^= IFCAP_WOL_MAGIC; - if (dev->if_drv_flags & IFF_DRV_RUNNING) - mlx4_en_start_port(dev); -out: - mutex_unlock(&mdev->state_lock); - VLAN_CAPABILITIES(dev); - break; -#if __FreeBSD_version >= 1100036 - case SIOCGI2C: { - struct ifi2creq i2c; - - error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); - if (error) - break; - if (i2c.len > sizeof(i2c.data)) { - error = EINVAL; - break; - } - /* - * Note that we ignore i2c.addr here. The driver hardcodes - * the address to 0x50, while standard expects it to be 0xA0. - */ - error = mlx4_get_module_info(mdev->dev, priv->port, - i2c.offset, i2c.len, i2c.data); - if (error < 0) { - error = -error; - break; - } - error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); - break; - } -#endif - default: - error = ether_ioctl(dev, command, data); - break; - } - - return (error); -} - - -int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, - struct mlx4_en_port_profile *prof) -{ - struct net_device *dev; - struct mlx4_en_priv *priv; - uint8_t dev_addr[ETHER_ADDR_LEN]; - int err; - int i; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - dev = priv->dev = if_alloc(IFT_ETHER); - if (dev == NULL) { - en_err(priv, "Net device allocation failed\n"); - kfree(priv); - return -ENOMEM; - } - dev->if_softc = priv; - if_initname(dev, "mlxen", atomic_fetchadd_int(&mlx4_en_unit, 1)); - dev->if_mtu = ETHERMTU; - dev->if_init = mlx4_en_open; - dev->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - dev->if_ioctl = mlx4_en_ioctl; - dev->if_transmit = mlx4_en_transmit; - dev->if_qflush = mlx4_en_qflush; - dev->if_snd.ifq_maxlen = prof->tx_ring_size; - - /* - * Initialize driver private data - */ - priv->counter_index = 0xff; - spin_lock_init(&priv->stats_lock); - INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); - INIT_WORK(&priv->watchdog_task, mlx4_en_restart); - INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); - INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); - INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task); - callout_init(&priv->watchdog_timer, 1); -#ifdef CONFIG_RFS_ACCEL - INIT_LIST_HEAD(&priv->filters); - spin_lock_init(&priv->filters_lock); -#endif - - priv->msg_enable = MLX4_EN_MSG_LEVEL; - priv->dev = dev; - priv->mdev = mdev; - priv->ddev = &mdev->pdev->dev; - priv->prof = prof; - priv->port = port; - priv->port_up = false; - priv->flags = prof->flags; - - priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up; - priv->tx_ring_num = prof->tx_ring_num; - priv->tx_ring = kcalloc(MAX_TX_RINGS, - sizeof(struct mlx4_en_tx_ring *), GFP_KERNEL); - if (!priv->tx_ring) { - err = -ENOMEM; - goto out; - } - priv->tx_cq = kcalloc(sizeof(struct mlx4_en_cq *), MAX_TX_RINGS, - GFP_KERNEL); - if (!priv->tx_cq) { - err = -ENOMEM; - goto out; - } - - priv->rx_ring_num = prof->rx_ring_num; - priv->cqe_factor = (mdev->dev->caps.cqe_size == 64) ? 1 : 0; - priv->mac_index = -1; - priv->last_ifq_jiffies = 0; - priv->if_counters_rx_errors = 0; - priv->if_counters_rx_no_buffer = 0; -#ifdef CONFIG_MLX4_EN_DCB - if (!mlx4_is_slave(priv->mdev->dev)) { - priv->dcbx_cap = DCB_CAP_DCBX_HOST; - priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; - if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { - dev->dcbnl_ops = &mlx4_en_dcbnl_ops; - } else { - en_info(priv, "QoS disabled - no HW support\n"); - dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops; - } - } -#endif - - for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) - INIT_HLIST_HEAD(&priv->mac_hash[i]); - - /* Query for default mac and max mtu */ - priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; - priv->mac = mdev->dev->caps.def_mac[priv->port]; - if (ILLEGAL_MAC(priv->mac)) { -#if BITS_PER_LONG == 64 - en_err(priv, "Port: %d, invalid mac burned: 0x%lx, quiting\n", - priv->port, priv->mac); -#elif BITS_PER_LONG == 32 - en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", - priv->port, priv->mac); -#endif - err = -EINVAL; - goto out; - } - - priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + - DS_SIZE); - - mlx4_en_sysctl_conf(priv); - - err = mlx4_en_alloc_resources(priv); - if (err) - goto out; - - /* Allocate page for receive rings */ - err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, - MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); - if (err) { - en_err(priv, "Failed to allocate page for rx qps\n"); - goto out; - } - priv->allocated = 1; - - /* - * Set driver features - */ - dev->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6; - dev->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; - dev->if_capabilities |= IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWFILTER; - dev->if_capabilities |= IFCAP_LINKSTATE | IFCAP_JUMBO_MTU; - dev->if_capabilities |= IFCAP_LRO; - dev->if_capabilities |= IFCAP_HWSTATS; - - if (mdev->LSO_support) - dev->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTSO; - -#if __FreeBSD_version >= 1100000 - /* set TSO limits so that we don't have to drop TX packets */ - dev->if_hw_tsomax = MLX4_EN_TX_MAX_PAYLOAD_SIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN) /* hdr */; - dev->if_hw_tsomaxsegcount = MLX4_EN_TX_MAX_MBUF_FRAGS - 1 /* hdr */; - dev->if_hw_tsomaxsegsize = MLX4_EN_TX_MAX_MBUF_SIZE; -#endif - - dev->if_capenable = dev->if_capabilities; - - dev->if_hwassist = 0; - if (dev->if_capenable & (IFCAP_TSO4 | IFCAP_TSO6)) - dev->if_hwassist |= CSUM_TSO; - if (dev->if_capenable & IFCAP_TXCSUM) - dev->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP); - if (dev->if_capenable & IFCAP_TXCSUM_IPV6) - dev->if_hwassist |= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); - - - /* Register for VLAN events */ - priv->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, - mlx4_en_vlan_rx_add_vid, priv, EVENTHANDLER_PRI_FIRST); - priv->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, - mlx4_en_vlan_rx_kill_vid, priv, EVENTHANDLER_PRI_FIRST); - - mdev->pndev[priv->port] = dev; - - priv->last_link_state = MLX4_DEV_EVENT_PORT_DOWN; - mlx4_en_set_default_moderation(priv); - - /* Set default MAC */ - for (i = 0; i < ETHER_ADDR_LEN; i++) - dev_addr[ETHER_ADDR_LEN - 1 - i] = (u8) (priv->mac >> (8 * i)); - - - ether_ifattach(dev, dev_addr); - if_link_state_change(dev, LINK_STATE_DOWN); - ifmedia_init(&priv->media, IFM_IMASK | IFM_ETH_FMASK, - mlx4_en_media_change, mlx4_en_media_status); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_1000_T, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_SR, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_CX4, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_40G_CR4, 0, NULL); - ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); - ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); - - en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); - en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); - - priv->registered = 1; - - en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); - en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); - - - priv->rx_mb_size = dev->if_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; - err = mlx4_SET_PORT_general(mdev->dev, priv->port, - priv->rx_mb_size, - prof->tx_pause, prof->tx_ppp, - prof->rx_pause, prof->rx_ppp); - if (err) { - en_err(priv, "Failed setting port general configurations " - "for port %d, with error %d\n", priv->port, err); - goto out; - } - - /* Init port */ - en_warn(priv, "Initializing port\n"); - err = mlx4_INIT_PORT(mdev->dev, priv->port); - if (err) { - en_err(priv, "Failed Initializing port\n"); - goto out; - } - - queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); - - if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) - queue_delayed_work(mdev->workqueue, &priv->service_task, SERVICE_TASK_DELAY); - - return 0; - -out: - mlx4_en_destroy_netdev(dev); - return err; -} - -static int mlx4_en_set_ring_size(struct net_device *dev, - int rx_size, int tx_size) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int port_up = 0; - int err = 0; - - rx_size = roundup_pow_of_two(rx_size); - rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); - rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); - tx_size = roundup_pow_of_two(tx_size); - tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); - tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); - - if (rx_size == (priv->port_up ? - priv->rx_ring[0]->actual_size : priv->rx_ring[0]->size) && - tx_size == priv->tx_ring[0]->size) - return 0; - mutex_lock(&mdev->state_lock); - if (priv->port_up) { - port_up = 1; - mlx4_en_stop_port(dev); - } - mlx4_en_free_resources(priv); - priv->prof->tx_ring_size = tx_size; - priv->prof->rx_ring_size = rx_size; - err = mlx4_en_alloc_resources(priv); - if (err) { - en_err(priv, "Failed reallocating port resources\n"); - goto out; - } - if (port_up) { - err = mlx4_en_start_port(dev); - if (err) - en_err(priv, "Failed starting port\n"); - } -out: - mutex_unlock(&mdev->state_lock); - return err; -} -static int mlx4_en_set_rx_ring_size(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - int size; - int error; - - priv = arg1; - size = priv->prof->rx_ring_size; - error = sysctl_handle_int(oidp, &size, 0, req); - if (error || !req->newptr) - return (error); - error = -mlx4_en_set_ring_size(priv->dev, size, - priv->prof->tx_ring_size); - return (error); -} - -static int mlx4_en_set_tx_ring_size(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - int size; - int error; - - priv = arg1; - size = priv->prof->tx_ring_size; - error = sysctl_handle_int(oidp, &size, 0, req); - if (error || !req->newptr) - return (error); - error = -mlx4_en_set_ring_size(priv->dev, priv->prof->rx_ring_size, - size); - - return (error); -} - -static int mlx4_en_get_module_info(struct net_device *dev, - struct ethtool_modinfo *modinfo) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int ret; - u8 data[4]; - - /* Read first 2 bytes to get Module & REV ID */ - ret = mlx4_get_module_info(mdev->dev, priv->port, - 0/*offset*/, 2/*size*/, data); - - if (ret < 2) { - en_err(priv, "Failed to read eeprom module first two bytes, error: 0x%x\n", -ret); - return -EIO; - } - - switch (data[0] /* identifier */) { - case MLX4_MODULE_ID_QSFP: - modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; - break; - case MLX4_MODULE_ID_QSFP_PLUS: - if (data[1] >= 0x3) { /* revision id */ - modinfo->type = ETH_MODULE_SFF_8636; - modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; - } else { - modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; - } - break; - case MLX4_MODULE_ID_QSFP28: - modinfo->type = ETH_MODULE_SFF_8636; - modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; - break; - case MLX4_MODULE_ID_SFP: - modinfo->type = ETH_MODULE_SFF_8472; - modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; - break; - default: - en_err(priv, "mlx4_en_get_module_info : Not recognized cable type\n"); - return -EINVAL; - } - - return 0; -} - -static int mlx4_en_get_module_eeprom(struct net_device *dev, - struct ethtool_eeprom *ee, - u8 *data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int offset = ee->offset; - int i = 0, ret; - - if (ee->len == 0) - return -EINVAL; - - memset(data, 0, ee->len); - - while (i < ee->len) { - en_dbg(DRV, priv, - "mlx4_get_module_info i(%d) offset(%d) len(%d)\n", - i, offset, ee->len - i); - - ret = mlx4_get_module_info(mdev->dev, priv->port, - offset, ee->len - i, data + i); - - if (!ret) /* Done reading */ - return 0; - - if (ret < 0) { - en_err(priv, - "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n", - i, offset, ee->len - i, ret); - return -1; - } - - i += ret; - offset += ret; - } - return 0; -} - -static void mlx4_en_print_eeprom(u8 *data, __u32 len) -{ - int i; - int j = 0; - int row = 0; - const int NUM_OF_BYTES = 16; - - printf("\nOffset\t\tValues\n"); - printf("------\t\t------\n"); - while(row < len){ - printf("0x%04x\t\t",row); - for(i=0; i < NUM_OF_BYTES; i++){ - printf("%02x ", data[j]); - row++; - j++; - } - printf("\n"); - } -} - -/* Read cable EEPROM module information by first inspecting the first - * two bytes to get the length and then read the rest of the information. - * The information is printed to dmesg. */ -static int mlx4_en_read_eeprom(SYSCTL_HANDLER_ARGS) -{ - - u8* data; - int error; - int result = 0; - struct mlx4_en_priv *priv; - struct net_device *dev; - struct ethtool_modinfo modinfo; - struct ethtool_eeprom ee; - - error = sysctl_handle_int(oidp, &result, 0, req); - if (error || !req->newptr) - return (error); - - if (result == 1) { - priv = arg1; - dev = priv->dev; - data = kmalloc(PAGE_SIZE, GFP_KERNEL); - - error = mlx4_en_get_module_info(dev, &modinfo); - if (error) { - en_err(priv, - "mlx4_en_get_module_info returned with error - FAILED (0x%x)\n", - -error); - goto out; - } - - ee.len = modinfo.eeprom_len; - ee.offset = 0; - - error = mlx4_en_get_module_eeprom(dev, &ee, data); - if (error) { - en_err(priv, - "mlx4_en_get_module_eeprom returned with error - FAILED (0x%x)\n", - -error); - /* Continue printing partial information in case of an error */ - } - - /* EEPROM information will be printed in dmesg */ - mlx4_en_print_eeprom(data, ee.len); -out: - kfree(data); - } - /* Return zero to prevent sysctl failure. */ - return (0); -} - -static int mlx4_en_set_tx_ppp(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - int ppp; - int error; - - priv = arg1; - ppp = priv->prof->tx_ppp; - error = sysctl_handle_int(oidp, &ppp, 0, req); - if (error || !req->newptr) - return (error); - if (ppp > 0xff || ppp < 0) - return (-EINVAL); - priv->prof->tx_ppp = ppp; - error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, - priv->rx_mb_size + ETHER_CRC_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - - return (error); -} - -static int mlx4_en_set_rx_ppp(SYSCTL_HANDLER_ARGS) -{ - struct mlx4_en_priv *priv; - struct mlx4_en_dev *mdev; - int ppp; - int error; - int port_up; - - port_up = 0; - priv = arg1; - mdev = priv->mdev; - ppp = priv->prof->rx_ppp; - error = sysctl_handle_int(oidp, &ppp, 0, req); - if (error || !req->newptr) - return (error); - if (ppp > 0xff || ppp < 0) - return (-EINVAL); - /* See if we have to change the number of tx queues. */ - if (!ppp != !priv->prof->rx_ppp) { - mutex_lock(&mdev->state_lock); - if (priv->port_up) { - port_up = 1; - mlx4_en_stop_port(priv->dev); - } - mlx4_en_free_resources(priv); - priv->prof->rx_ppp = ppp; - error = -mlx4_en_alloc_resources(priv); - if (error) - en_err(priv, "Failed reallocating port resources\n"); - if (error == 0 && port_up) { - error = -mlx4_en_start_port(priv->dev); - if (error) - en_err(priv, "Failed starting port\n"); - } - mutex_unlock(&mdev->state_lock); - return (error); - - } - priv->prof->rx_ppp = ppp; - error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, - priv->rx_mb_size + ETHER_CRC_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - - return (error); -} - -static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv) -{ - struct net_device *dev; - struct sysctl_ctx_list *ctx; - struct sysctl_oid *node; - struct sysctl_oid_list *node_list; - struct sysctl_oid *coal; - struct sysctl_oid_list *coal_list; - const char *pnameunit; - - dev = priv->dev; - ctx = &priv->conf_ctx; - pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); - - sysctl_ctx_init(ctx); - priv->sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), - OID_AUTO, dev->if_xname, CTLFLAG_RD, 0, "mlx4 10gig ethernet"); - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, - "conf", CTLFLAG_RD, NULL, "Configuration"); - node_list = SYSCTL_CHILDREN(node); - - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "msg_enable", - CTLFLAG_RW, &priv->msg_enable, 0, - "Driver message enable bitfield"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_rings", - CTLFLAG_RD, &priv->rx_ring_num, 0, - "Number of receive rings"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_rings", - CTLFLAG_RD, &priv->tx_ring_num, 0, - "Number of transmit rings"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_size", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_rx_ring_size, "I", "Receive ring size"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_size", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_tx_ring_size, "I", "Transmit ring size"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_ppp", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_tx_ppp, "I", "TX Per-priority pause"); - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_ppp", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_set_rx_ppp, "I", "RX Per-priority pause"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "port_num", - CTLFLAG_RD, &priv->port, 0, - "Port Number"); - SYSCTL_ADD_STRING(ctx, node_list, OID_AUTO, "device_name", - CTLFLAG_RD, __DECONST(void *, pnameunit), 0, - "PCI device name"); - - /* Add coalescer configuration. */ - coal = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, - "coalesce", CTLFLAG_RD, NULL, "Interrupt coalesce configuration"); - coal_list = SYSCTL_CHILDREN(coal); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_low", - CTLFLAG_RW, &priv->pkt_rate_low, 0, - "Packets per-second for minimum delay"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_low", - CTLFLAG_RW, &priv->rx_usecs_low, 0, - "Minimum RX delay in micro-seconds"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_high", - CTLFLAG_RW, &priv->pkt_rate_high, 0, - "Packets per-second for maximum delay"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_high", - CTLFLAG_RW, &priv->rx_usecs_high, 0, - "Maximum RX delay in micro-seconds"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "sample_interval", - CTLFLAG_RW, &priv->sample_interval, 0, - "adaptive frequency in units of HZ ticks"); - SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "adaptive_rx_coal", - CTLFLAG_RW, &priv->adaptive_rx_coal, 0, - "Enable adaptive rx coalescing"); - /* EEPROM support */ - SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "eeprom_info", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, - mlx4_en_read_eeprom, "I", "EEPROM information"); -} - -static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv) -{ - struct sysctl_ctx_list *ctx; - struct sysctl_oid *node; - struct sysctl_oid_list *node_list; - struct sysctl_oid *ring_node; - struct sysctl_oid_list *ring_list; - struct mlx4_en_tx_ring *tx_ring; - struct mlx4_en_rx_ring *rx_ring; - char namebuf[128]; - int i; - - ctx = &priv->stat_ctx; - sysctl_ctx_init(ctx); - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, - "stat", CTLFLAG_RD, NULL, "Statistics"); - node_list = SYSCTL_CHILDREN(node); - -#ifdef MLX4_EN_PERF_STAT - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_poll", CTLFLAG_RD, - &priv->pstats.tx_poll, "TX Poll calls"); - SYSCTL_ADD_QUAD(ctx, node_list, OID_AUTO, "tx_pktsz_avg", CTLFLAG_RD, - &priv->pstats.tx_pktsz_avg, "TX average packet size"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "inflight_avg", CTLFLAG_RD, - &priv->pstats.inflight_avg, "TX average packets in-flight"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_coal_avg", CTLFLAG_RD, - &priv->pstats.tx_coal_avg, "TX average coalesced completions"); - SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_coal_avg", CTLFLAG_RD, - &priv->pstats.rx_coal_avg, "RX average coalesced completions"); -#endif - - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tso_packets", CTLFLAG_RD, - &priv->port_stats.tso_packets, "TSO packets sent"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "queue_stopped", CTLFLAG_RD, - &priv->port_stats.queue_stopped, "Queue full"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "wake_queue", CTLFLAG_RD, - &priv->port_stats.wake_queue, "Queue resumed after full"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_timeout", CTLFLAG_RD, - &priv->port_stats.tx_timeout, "Transmit timeouts"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_oversized_packets", CTLFLAG_RD, - &priv->port_stats.oversized_packets, "TX oversized packets, m_defrag failed"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_alloc_failed", CTLFLAG_RD, - &priv->port_stats.rx_alloc_failed, "RX failed to allocate mbuf"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_good", CTLFLAG_RD, - &priv->port_stats.rx_chksum_good, "RX checksum offload success"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_none", CTLFLAG_RD, - &priv->port_stats.rx_chksum_none, "RX without checksum offload"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_chksum_offload", - CTLFLAG_RD, &priv->port_stats.tx_chksum_offload, - "TX checksum offloads"); - - /* Could strdup the names and add in a loop. This is simpler. */ - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_bytes", CTLFLAG_RD, - &priv->pkstats.rx_bytes, "RX Bytes"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_packets", CTLFLAG_RD, - &priv->pkstats.rx_packets, "RX packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_multicast_packets", CTLFLAG_RD, - &priv->pkstats.rx_multicast_packets, "RX Multicast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_broadcast_packets", CTLFLAG_RD, - &priv->pkstats.rx_broadcast_packets, "RX Broadcast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_errors", CTLFLAG_RD, - &priv->pkstats.rx_errors, "RX Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_dropped", CTLFLAG_RD, - &priv->pkstats.rx_dropped, "RX Dropped"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_length_errors", CTLFLAG_RD, - &priv->pkstats.rx_length_errors, "RX Length Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_over_errors", CTLFLAG_RD, - &priv->pkstats.rx_over_errors, "RX Over Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_crc_errors", CTLFLAG_RD, - &priv->pkstats.rx_crc_errors, "RX CRC Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_jabbers", CTLFLAG_RD, - &priv->pkstats.rx_jabbers, "RX Jabbers"); - - - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_in_range_length_error", CTLFLAG_RD, - &priv->pkstats.rx_in_range_length_error, "RX IN_Range Length Error"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_out_range_length_error", - CTLFLAG_RD, &priv->pkstats.rx_out_range_length_error, - "RX Out Range Length Error"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_lt_64_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_lt_64_bytes_packets, "RX Lt 64 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_127_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_127_bytes_packets, "RX 127 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_255_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_255_bytes_packets, "RX 255 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_511_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_511_bytes_packets, "RX 511 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1023_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1023_bytes_packets, "RX 1023 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1518_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1518_bytes_packets, "RX 1518 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1522_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1522_bytes_packets, "RX 1522 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_1548_bytes_packets, "RX 1548 bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_gt_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.rx_gt_1548_bytes_packets, - "RX Greater Then 1548 bytes Packets"); - -struct mlx4_en_pkt_stats { - unsigned long tx_packets; - unsigned long tx_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_broadcast_packets; - unsigned long tx_errors; - unsigned long tx_dropped; - unsigned long tx_lt_64_bytes_packets; - unsigned long tx_127_bytes_packets; - unsigned long tx_255_bytes_packets; - unsigned long tx_511_bytes_packets; - unsigned long tx_1023_bytes_packets; - unsigned long tx_1518_bytes_packets; - unsigned long tx_1522_bytes_packets; - unsigned long tx_1548_bytes_packets; - unsigned long tx_gt_1548_bytes_packets; - unsigned long rx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; - unsigned long tx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; -#define NUM_PKT_STATS 72 -}; - - - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_packets", CTLFLAG_RD, - &priv->pkstats.tx_packets, "TX packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_bytes", CTLFLAG_RD, - &priv->pkstats.tx_bytes, "TX Bytes"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_multicast_packets", CTLFLAG_RD, - &priv->pkstats.tx_multicast_packets, "TX Multicast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_broadcast_packets", CTLFLAG_RD, - &priv->pkstats.tx_broadcast_packets, "TX Broadcast Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_errors", CTLFLAG_RD, - &priv->pkstats.tx_errors, "TX Errors"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_dropped", CTLFLAG_RD, - &priv->pkstats.tx_dropped, "TX Dropped"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_lt_64_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_lt_64_bytes_packets, "TX Less Then 64 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_127_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_127_bytes_packets, "TX 127 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_255_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_255_bytes_packets, "TX 255 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_511_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_511_bytes_packets, "TX 511 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1023_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1023_bytes_packets, "TX 1023 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1518_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1518_bytes_packets, "TX 1518 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1522_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1522_bytes_packets, "TX 1522 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_1548_bytes_packets, "TX 1548 Bytes Packets"); - SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_gt_1548_bytes_packets", CTLFLAG_RD, - &priv->pkstats.tx_gt_1548_bytes_packets, - "TX Greater Then 1548 Bytes Packets"); - - - - for (i = 0; i < priv->tx_ring_num; i++) { - tx_ring = priv->tx_ring[i]; - snprintf(namebuf, sizeof(namebuf), "tx_ring%d", i); - ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "TX Ring"); - ring_list = SYSCTL_CHILDREN(ring_node); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", - CTLFLAG_RD, &tx_ring->packets, "TX packets"); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", - CTLFLAG_RD, &tx_ring->bytes, "TX bytes"); - } - - for (i = 0; i < priv->rx_ring_num; i++) { - rx_ring = priv->rx_ring[i]; - snprintf(namebuf, sizeof(namebuf), "rx_ring%d", i); - ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "RX Ring"); - ring_list = SYSCTL_CHILDREN(ring_node); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", - CTLFLAG_RD, &rx_ring->packets, "RX packets"); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", - CTLFLAG_RD, &rx_ring->bytes, "RX bytes"); - SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "error", - CTLFLAG_RD, &rx_ring->errors, "RX soft errors"); - } -} diff --git a/sys/ofed/drivers/net/mlx4/en_port.c b/sys/ofed/drivers/net/mlx4/en_port.c deleted file mode 100644 index 2a1c4ba406a9..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_port.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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 <sys/types.h> -#include <linux/if_vlan.h> - -#include <linux/mlx4/device.h> -#include <linux/mlx4/cmd.h> - -#include "en_port.h" -#include "mlx4_en.h" -#define EN_IFQ_MIN_INTERVAL 3000 - - -int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_vlan_fltr_mbox *filter; - int i; - int j; - int index = 0; - u32 entry; - int err = 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - filter = mailbox->buf; - memset(filter, 0, sizeof(*filter)); - for (i = VLAN_FLTR_SIZE - 1; i >= 0; i--) { - entry = 0; - for (j = 0; j < 32; j++) { - if (test_bit(index, priv->active_vlans)) - entry |= 1 << j; - index++; - } - filter->entry[i] = cpu_to_be32(entry); - } - err = mlx4_cmd(dev, mailbox->dma, priv->port, 0, MLX4_CMD_SET_VLAN_FLTR, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port) -{ - struct mlx4_en_query_port_context *qport_context; - struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]); - struct mlx4_en_port_state *state = &priv->port_state; - struct mlx4_cmd_mailbox *mailbox; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - memset(mailbox->buf, 0, sizeof(*qport_context)); - err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0, - MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - goto out; - qport_context = mailbox->buf; - - /* This command is always accessed from Ethtool context - * already synchronized, no need in locking */ - state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK); - switch (qport_context->link_speed & MLX4_EN_SPEED_MASK) { - case MLX4_EN_1G_SPEED: - state->link_speed = 1000; - break; - case MLX4_EN_10G_SPEED_XAUI: - case MLX4_EN_10G_SPEED_XFI: - state->link_speed = 10000; - break; - case MLX4_EN_20G_SPEED: - state->link_speed = 20000; - break; - case MLX4_EN_40G_SPEED: - state->link_speed = 40000; - break; - case MLX4_EN_56G_SPEED: - state->link_speed = 56000; - break; - default: - state->link_speed = -1; - break; - } - state->transciver = qport_context->transceiver; - state->autoneg = !!(qport_context->autoneg & MLX4_EN_AUTONEG_MASK); - -out: - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - return err; -} - -int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) -{ - struct mlx4_en_stat_out_mbox *mlx4_en_stats; - struct mlx4_en_stat_out_flow_control_mbox *flowstats; - struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]); - struct mlx4_en_vport_stats *vport_stats = &priv->vport_stats; - struct mlx4_cmd_mailbox *mailbox = NULL; - struct mlx4_cmd_mailbox *mailbox_flow = NULL; - u64 in_mod = reset << 8 | port; - int err; - int i; - int do_if_stat = 1; - unsigned long period = (unsigned long) (jiffies - priv->last_ifq_jiffies); - struct mlx4_en_vport_stats tmp_vport_stats; - struct net_device *dev; - - if (jiffies_to_msecs(period) < EN_IFQ_MIN_INTERVAL || - priv->counter_index == 0xff) - do_if_stat = 0; - - mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto mailbox_out; - } - - mailbox_flow = mlx4_alloc_cmd_mailbox(mdev->dev); - if (IS_ERR(mailbox_flow)) { - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - err = PTR_ERR(mailbox_flow); - goto mailbox_out; - } - - /* 0xffs indicates invalid value */ - memset(mailbox_flow->buf, 0xff, sizeof(*flowstats) * - MLX4_NUM_PRIORITIES); - - if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) { - memset(mailbox_flow->buf, 0, sizeof(*flowstats)); - err = mlx4_cmd_box(mdev->dev, 0, mailbox_flow->dma, - in_mod | 1<<12, 0, MLX4_CMD_DUMP_ETH_STATS, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - if (err) - goto out; - } - - err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0, - MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - if (err) - goto out; - - mlx4_en_stats = mailbox->buf; - - spin_lock(&priv->stats_lock); - - priv->port_stats.rx_chksum_good = 0; - priv->port_stats.rx_chksum_none = 0; - for (i = 0; i < priv->rx_ring_num; i++) { - priv->port_stats.rx_chksum_good += priv->rx_ring[i]->csum_ok; - priv->port_stats.rx_chksum_none += priv->rx_ring[i]->csum_none; - } - - priv->port_stats.tx_chksum_offload = 0; - priv->port_stats.queue_stopped = 0; - priv->port_stats.wake_queue = 0; - for (i = 0; i < priv->tx_ring_num; i++) { - priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum; - priv->port_stats.queue_stopped += priv->tx_ring[i]->queue_stopped; - priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue; - priv->port_stats.oversized_packets += priv->tx_ring[i]->oversized_packets; - } - /* RX Statistics */ - priv->pkstats.rx_packets = be64_to_cpu(mlx4_en_stats->RTOT_prio_0) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_1) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_2) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_3) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_4) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_5) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_6) + - be64_to_cpu(mlx4_en_stats->RTOT_prio_7) + - be64_to_cpu(mlx4_en_stats->RTOT_novlan); - priv->pkstats.rx_bytes = be64_to_cpu(mlx4_en_stats->ROCT_prio_0) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_1) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_2) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_3) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_4) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_5) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_6) + - be64_to_cpu(mlx4_en_stats->ROCT_prio_7) + - be64_to_cpu(mlx4_en_stats->ROCT_novlan); - priv->pkstats.rx_multicast_packets = be64_to_cpu(mlx4_en_stats->MCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->MCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->MCAST_novlan); - priv->pkstats.rx_broadcast_packets = be64_to_cpu(mlx4_en_stats->RBCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->RBCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->RBCAST_novlan); - priv->pkstats.rx_errors = be64_to_cpu(mlx4_en_stats->PCS) + - be32_to_cpu(mlx4_en_stats->RJBBR) + - be32_to_cpu(mlx4_en_stats->RCRC) + - be32_to_cpu(mlx4_en_stats->RRUNT) + - be64_to_cpu(mlx4_en_stats->RInRangeLengthErr) + - be64_to_cpu(mlx4_en_stats->ROutRangeLengthErr) + - be32_to_cpu(mlx4_en_stats->RSHORT) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_0) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_1) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_2) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_3) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_4) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_5) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_6) + - be64_to_cpu(mlx4_en_stats->RGIANT_prio_7) + - be64_to_cpu(mlx4_en_stats->RGIANT_novlan); - priv->pkstats.rx_dropped = be32_to_cpu(mlx4_en_stats->RdropOvflw); - priv->pkstats.rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength); - priv->pkstats.rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); - priv->pkstats.rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC); - priv->pkstats.rx_jabbers = be32_to_cpu(mlx4_en_stats->RJBBR); - priv->pkstats.rx_in_range_length_error = be64_to_cpu(mlx4_en_stats->RInRangeLengthErr); - priv->pkstats.rx_out_range_length_error = be64_to_cpu(mlx4_en_stats->ROutRangeLengthErr); - priv->pkstats.rx_lt_64_bytes_packets = be64_to_cpu(mlx4_en_stats->R64_prio_0) + - be64_to_cpu(mlx4_en_stats->R64_prio_1) + - be64_to_cpu(mlx4_en_stats->R64_prio_2) + - be64_to_cpu(mlx4_en_stats->R64_prio_3) + - be64_to_cpu(mlx4_en_stats->R64_prio_4) + - be64_to_cpu(mlx4_en_stats->R64_prio_5) + - be64_to_cpu(mlx4_en_stats->R64_prio_6) + - be64_to_cpu(mlx4_en_stats->R64_prio_7) + - be64_to_cpu(mlx4_en_stats->R64_novlan); - priv->pkstats.rx_127_bytes_packets = be64_to_cpu(mlx4_en_stats->R127_prio_0) + - be64_to_cpu(mlx4_en_stats->R127_prio_1) + - be64_to_cpu(mlx4_en_stats->R127_prio_2) + - be64_to_cpu(mlx4_en_stats->R127_prio_3) + - be64_to_cpu(mlx4_en_stats->R127_prio_4) + - be64_to_cpu(mlx4_en_stats->R127_prio_5) + - be64_to_cpu(mlx4_en_stats->R127_prio_6) + - be64_to_cpu(mlx4_en_stats->R127_prio_7) + - be64_to_cpu(mlx4_en_stats->R127_novlan); - priv->pkstats.rx_255_bytes_packets = be64_to_cpu(mlx4_en_stats->R255_prio_0) + - be64_to_cpu(mlx4_en_stats->R255_prio_1) + - be64_to_cpu(mlx4_en_stats->R255_prio_2) + - be64_to_cpu(mlx4_en_stats->R255_prio_3) + - be64_to_cpu(mlx4_en_stats->R255_prio_4) + - be64_to_cpu(mlx4_en_stats->R255_prio_5) + - be64_to_cpu(mlx4_en_stats->R255_prio_6) + - be64_to_cpu(mlx4_en_stats->R255_prio_7) + - be64_to_cpu(mlx4_en_stats->R255_novlan); - priv->pkstats.rx_511_bytes_packets = be64_to_cpu(mlx4_en_stats->R511_prio_0) + - be64_to_cpu(mlx4_en_stats->R511_prio_1) + - be64_to_cpu(mlx4_en_stats->R511_prio_2) + - be64_to_cpu(mlx4_en_stats->R511_prio_3) + - be64_to_cpu(mlx4_en_stats->R511_prio_4) + - be64_to_cpu(mlx4_en_stats->R511_prio_5) + - be64_to_cpu(mlx4_en_stats->R511_prio_6) + - be64_to_cpu(mlx4_en_stats->R511_prio_7) + - be64_to_cpu(mlx4_en_stats->R511_novlan); - priv->pkstats.rx_1023_bytes_packets = be64_to_cpu(mlx4_en_stats->R1023_prio_0) + - be64_to_cpu(mlx4_en_stats->R1023_prio_1) + - be64_to_cpu(mlx4_en_stats->R1023_prio_2) + - be64_to_cpu(mlx4_en_stats->R1023_prio_3) + - be64_to_cpu(mlx4_en_stats->R1023_prio_4) + - be64_to_cpu(mlx4_en_stats->R1023_prio_5) + - be64_to_cpu(mlx4_en_stats->R1023_prio_6) + - be64_to_cpu(mlx4_en_stats->R1023_prio_7) + - be64_to_cpu(mlx4_en_stats->R1023_novlan); - priv->pkstats.rx_1518_bytes_packets = be64_to_cpu(mlx4_en_stats->R1518_prio_0) + - be64_to_cpu(mlx4_en_stats->R1518_prio_1) + - be64_to_cpu(mlx4_en_stats->R1518_prio_2) + - be64_to_cpu(mlx4_en_stats->R1518_prio_3) + - be64_to_cpu(mlx4_en_stats->R1518_prio_4) + - be64_to_cpu(mlx4_en_stats->R1518_prio_5) + - be64_to_cpu(mlx4_en_stats->R1518_prio_6) + - be64_to_cpu(mlx4_en_stats->R1518_prio_7) + - be64_to_cpu(mlx4_en_stats->R1518_novlan); - priv->pkstats.rx_1522_bytes_packets = be64_to_cpu(mlx4_en_stats->R1522_prio_0) + - be64_to_cpu(mlx4_en_stats->R1522_prio_1) + - be64_to_cpu(mlx4_en_stats->R1522_prio_2) + - be64_to_cpu(mlx4_en_stats->R1522_prio_3) + - be64_to_cpu(mlx4_en_stats->R1522_prio_4) + - be64_to_cpu(mlx4_en_stats->R1522_prio_5) + - be64_to_cpu(mlx4_en_stats->R1522_prio_6) + - be64_to_cpu(mlx4_en_stats->R1522_prio_7) + - be64_to_cpu(mlx4_en_stats->R1522_novlan); - priv->pkstats.rx_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->R1548_prio_0) + - be64_to_cpu(mlx4_en_stats->R1548_prio_1) + - be64_to_cpu(mlx4_en_stats->R1548_prio_2) + - be64_to_cpu(mlx4_en_stats->R1548_prio_3) + - be64_to_cpu(mlx4_en_stats->R1548_prio_4) + - be64_to_cpu(mlx4_en_stats->R1548_prio_5) + - be64_to_cpu(mlx4_en_stats->R1548_prio_6) + - be64_to_cpu(mlx4_en_stats->R1548_prio_7) + - be64_to_cpu(mlx4_en_stats->R1548_novlan); - priv->pkstats.rx_gt_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->R2MTU_prio_0) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_1) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_2) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_3) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_4) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_5) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_6) + - be64_to_cpu(mlx4_en_stats->R2MTU_prio_7) + - be64_to_cpu(mlx4_en_stats->R2MTU_novlan); - - /* Tx Stats */ - priv->pkstats.tx_packets = be64_to_cpu(mlx4_en_stats->TTOT_prio_0) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_1) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_2) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_3) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_4) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_5) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_6) + - be64_to_cpu(mlx4_en_stats->TTOT_prio_7) + - be64_to_cpu(mlx4_en_stats->TTOT_novlan); - priv->pkstats.tx_bytes = be64_to_cpu(mlx4_en_stats->TOCT_prio_0) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_1) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_2) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_3) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_4) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_5) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_6) + - be64_to_cpu(mlx4_en_stats->TOCT_prio_7) + - be64_to_cpu(mlx4_en_stats->TOCT_novlan); - priv->pkstats.tx_multicast_packets = be64_to_cpu(mlx4_en_stats->TMCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->TMCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->TMCAST_novlan); - priv->pkstats.tx_broadcast_packets = be64_to_cpu(mlx4_en_stats->TBCAST_prio_0) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_1) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_2) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_3) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_4) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_5) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_6) + - be64_to_cpu(mlx4_en_stats->TBCAST_prio_7) + - be64_to_cpu(mlx4_en_stats->TBCAST_novlan); - priv->pkstats.tx_errors = be64_to_cpu(mlx4_en_stats->TGIANT_prio_0) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_1) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_2) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_3) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_4) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_5) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_6) + - be64_to_cpu(mlx4_en_stats->TGIANT_prio_7) + - be64_to_cpu(mlx4_en_stats->TGIANT_novlan); - priv->pkstats.tx_dropped = be32_to_cpu(mlx4_en_stats->TDROP) - - priv->pkstats.tx_errors; - priv->pkstats.tx_lt_64_bytes_packets = be64_to_cpu(mlx4_en_stats->T64_prio_0) + - be64_to_cpu(mlx4_en_stats->T64_prio_1) + - be64_to_cpu(mlx4_en_stats->T64_prio_2) + - be64_to_cpu(mlx4_en_stats->T64_prio_3) + - be64_to_cpu(mlx4_en_stats->T64_prio_4) + - be64_to_cpu(mlx4_en_stats->T64_prio_5) + - be64_to_cpu(mlx4_en_stats->T64_prio_6) + - be64_to_cpu(mlx4_en_stats->T64_prio_7) + - be64_to_cpu(mlx4_en_stats->T64_novlan); - priv->pkstats.tx_127_bytes_packets = be64_to_cpu(mlx4_en_stats->T127_prio_0) + - be64_to_cpu(mlx4_en_stats->T127_prio_1) + - be64_to_cpu(mlx4_en_stats->T127_prio_2) + - be64_to_cpu(mlx4_en_stats->T127_prio_3) + - be64_to_cpu(mlx4_en_stats->T127_prio_4) + - be64_to_cpu(mlx4_en_stats->T127_prio_5) + - be64_to_cpu(mlx4_en_stats->T127_prio_6) + - be64_to_cpu(mlx4_en_stats->T127_prio_7) + - be64_to_cpu(mlx4_en_stats->T127_novlan); - priv->pkstats.tx_255_bytes_packets = be64_to_cpu(mlx4_en_stats->T255_prio_0) + - be64_to_cpu(mlx4_en_stats->T255_prio_1) + - be64_to_cpu(mlx4_en_stats->T255_prio_2) + - be64_to_cpu(mlx4_en_stats->T255_prio_3) + - be64_to_cpu(mlx4_en_stats->T255_prio_4) + - be64_to_cpu(mlx4_en_stats->T255_prio_5) + - be64_to_cpu(mlx4_en_stats->T255_prio_6) + - be64_to_cpu(mlx4_en_stats->T255_prio_7) + - be64_to_cpu(mlx4_en_stats->T255_novlan); - priv->pkstats.tx_511_bytes_packets = be64_to_cpu(mlx4_en_stats->T511_prio_0) + - be64_to_cpu(mlx4_en_stats->T511_prio_1) + - be64_to_cpu(mlx4_en_stats->T511_prio_2) + - be64_to_cpu(mlx4_en_stats->T511_prio_3) + - be64_to_cpu(mlx4_en_stats->T511_prio_4) + - be64_to_cpu(mlx4_en_stats->T511_prio_5) + - be64_to_cpu(mlx4_en_stats->T511_prio_6) + - be64_to_cpu(mlx4_en_stats->T511_prio_7) + - be64_to_cpu(mlx4_en_stats->T511_novlan); - priv->pkstats.tx_1023_bytes_packets = be64_to_cpu(mlx4_en_stats->T1023_prio_0) + - be64_to_cpu(mlx4_en_stats->T1023_prio_1) + - be64_to_cpu(mlx4_en_stats->T1023_prio_2) + - be64_to_cpu(mlx4_en_stats->T1023_prio_3) + - be64_to_cpu(mlx4_en_stats->T1023_prio_4) + - be64_to_cpu(mlx4_en_stats->T1023_prio_5) + - be64_to_cpu(mlx4_en_stats->T1023_prio_6) + - be64_to_cpu(mlx4_en_stats->T1023_prio_7) + - be64_to_cpu(mlx4_en_stats->T1023_novlan); - priv->pkstats.tx_1518_bytes_packets = be64_to_cpu(mlx4_en_stats->T1518_prio_0) + - be64_to_cpu(mlx4_en_stats->T1518_prio_1) + - be64_to_cpu(mlx4_en_stats->T1518_prio_2) + - be64_to_cpu(mlx4_en_stats->T1518_prio_3) + - be64_to_cpu(mlx4_en_stats->T1518_prio_4) + - be64_to_cpu(mlx4_en_stats->T1518_prio_5) + - be64_to_cpu(mlx4_en_stats->T1518_prio_6) + - be64_to_cpu(mlx4_en_stats->T1518_prio_7) + - be64_to_cpu(mlx4_en_stats->T1518_novlan); - priv->pkstats.tx_1522_bytes_packets = be64_to_cpu(mlx4_en_stats->T1522_prio_0) + - be64_to_cpu(mlx4_en_stats->T1522_prio_1) + - be64_to_cpu(mlx4_en_stats->T1522_prio_2) + - be64_to_cpu(mlx4_en_stats->T1522_prio_3) + - be64_to_cpu(mlx4_en_stats->T1522_prio_4) + - be64_to_cpu(mlx4_en_stats->T1522_prio_5) + - be64_to_cpu(mlx4_en_stats->T1522_prio_6) + - be64_to_cpu(mlx4_en_stats->T1522_prio_7) + - be64_to_cpu(mlx4_en_stats->T1522_novlan); - priv->pkstats.tx_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->T1548_prio_0) + - be64_to_cpu(mlx4_en_stats->T1548_prio_1) + - be64_to_cpu(mlx4_en_stats->T1548_prio_2) + - be64_to_cpu(mlx4_en_stats->T1548_prio_3) + - be64_to_cpu(mlx4_en_stats->T1548_prio_4) + - be64_to_cpu(mlx4_en_stats->T1548_prio_5) + - be64_to_cpu(mlx4_en_stats->T1548_prio_6) + - be64_to_cpu(mlx4_en_stats->T1548_prio_7) + - be64_to_cpu(mlx4_en_stats->T1548_novlan); - priv->pkstats.tx_gt_1548_bytes_packets = be64_to_cpu(mlx4_en_stats->T2MTU_prio_0) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_1) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_2) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_3) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_4) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_5) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_6) + - be64_to_cpu(mlx4_en_stats->T2MTU_prio_7) + - be64_to_cpu(mlx4_en_stats->T2MTU_novlan); - - priv->pkstats.rx_prio[0][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_0); - priv->pkstats.rx_prio[0][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_0); - priv->pkstats.rx_prio[1][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_1); - priv->pkstats.rx_prio[1][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_1); - priv->pkstats.rx_prio[2][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_2); - priv->pkstats.rx_prio[2][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_2); - priv->pkstats.rx_prio[3][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_3); - priv->pkstats.rx_prio[3][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_3); - priv->pkstats.rx_prio[4][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_4); - priv->pkstats.rx_prio[4][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_4); - priv->pkstats.rx_prio[5][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_5); - priv->pkstats.rx_prio[5][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_5); - priv->pkstats.rx_prio[6][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_6); - priv->pkstats.rx_prio[6][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_6); - priv->pkstats.rx_prio[7][0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_7); - priv->pkstats.rx_prio[7][1] = be64_to_cpu(mlx4_en_stats->ROCT_prio_7); - priv->pkstats.rx_prio[8][0] = be64_to_cpu(mlx4_en_stats->RTOT_novlan); - priv->pkstats.rx_prio[8][1] = be64_to_cpu(mlx4_en_stats->ROCT_novlan); - priv->pkstats.tx_prio[0][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_0); - priv->pkstats.tx_prio[0][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_0); - priv->pkstats.tx_prio[1][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_1); - priv->pkstats.tx_prio[1][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_1); - priv->pkstats.tx_prio[2][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_2); - priv->pkstats.tx_prio[2][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_2); - priv->pkstats.tx_prio[3][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_3); - priv->pkstats.tx_prio[3][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_3); - priv->pkstats.tx_prio[4][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_4); - priv->pkstats.tx_prio[4][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_4); - priv->pkstats.tx_prio[5][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_5); - priv->pkstats.tx_prio[5][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_5); - priv->pkstats.tx_prio[6][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_6); - priv->pkstats.tx_prio[6][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_6); - priv->pkstats.tx_prio[7][0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_7); - priv->pkstats.tx_prio[7][1] = be64_to_cpu(mlx4_en_stats->TOCT_prio_7); - priv->pkstats.tx_prio[8][0] = be64_to_cpu(mlx4_en_stats->TTOT_novlan); - priv->pkstats.tx_prio[8][1] = be64_to_cpu(mlx4_en_stats->TOCT_novlan); - - flowstats = mailbox_flow->buf; - - for (i = 0; i < MLX4_NUM_PRIORITIES; i++) { - priv->flowstats[i].rx_pause = - be64_to_cpu(flowstats[i].rx_pause); - priv->flowstats[i].rx_pause_duration = - be64_to_cpu(flowstats[i].rx_pause_duration); - priv->flowstats[i].rx_pause_transition = - be64_to_cpu(flowstats[i].rx_pause_transition); - priv->flowstats[i].tx_pause = - be64_to_cpu(flowstats[i].tx_pause); - priv->flowstats[i].tx_pause_duration = - be64_to_cpu(flowstats[i].tx_pause_duration); - priv->flowstats[i].tx_pause_transition = - be64_to_cpu(flowstats[i].tx_pause_transition); - } - - memset(&tmp_vport_stats, 0, sizeof(tmp_vport_stats)); - spin_unlock(&priv->stats_lock); - err = mlx4_get_vport_ethtool_stats(mdev->dev, port, - &tmp_vport_stats, reset); - spin_lock(&priv->stats_lock); - if (!err) { - /* ethtool stats format */ - vport_stats->rx_unicast_packets = tmp_vport_stats.rx_unicast_packets; - vport_stats->rx_unicast_bytes = tmp_vport_stats.rx_unicast_bytes; - vport_stats->rx_multicast_packets = tmp_vport_stats.rx_multicast_packets; - vport_stats->rx_multicast_bytes = tmp_vport_stats.rx_multicast_bytes; - vport_stats->rx_broadcast_packets = tmp_vport_stats.rx_broadcast_packets; - vport_stats->rx_broadcast_bytes = tmp_vport_stats.rx_broadcast_bytes; - vport_stats->rx_dropped = tmp_vport_stats.rx_dropped; - vport_stats->rx_errors = tmp_vport_stats.rx_errors; - vport_stats->tx_unicast_packets = tmp_vport_stats.tx_unicast_packets; - vport_stats->tx_unicast_bytes = tmp_vport_stats.tx_unicast_bytes; - vport_stats->tx_multicast_packets = tmp_vport_stats.tx_multicast_packets; - vport_stats->tx_multicast_bytes = tmp_vport_stats.tx_multicast_bytes; - vport_stats->tx_broadcast_packets = tmp_vport_stats.tx_broadcast_packets; - vport_stats->tx_broadcast_bytes = tmp_vport_stats.tx_broadcast_bytes; - vport_stats->tx_errors = tmp_vport_stats.tx_errors; - } - - if (!mlx4_is_mfunc(mdev->dev)) { -/* netdevice stats format */ -#if __FreeBSD_version >= 1100000 - if (reset == 0) { - dev = mdev->pndev[port]; - if_inc_counter(dev, IFCOUNTER_IPACKETS, - priv->pkstats.rx_packets - priv->pkstats_last.rx_packets); - if_inc_counter(dev, IFCOUNTER_OPACKETS, - priv->pkstats.tx_packets - priv->pkstats_last.tx_packets); - if_inc_counter(dev, IFCOUNTER_IBYTES, - priv->pkstats.rx_bytes - priv->pkstats_last.rx_bytes); - if_inc_counter(dev, IFCOUNTER_OBYTES, - priv->pkstats.tx_bytes - priv->pkstats_last.tx_bytes); - if_inc_counter(dev, IFCOUNTER_IERRORS, - priv->pkstats.rx_errors - priv->pkstats_last.rx_errors); - if_inc_counter(dev, IFCOUNTER_IQDROPS, - priv->pkstats.rx_dropped - priv->pkstats_last.rx_dropped); - if_inc_counter(dev, IFCOUNTER_IMCASTS, - priv->pkstats.rx_multicast_packets - priv->pkstats_last.rx_multicast_packets); - if_inc_counter(dev, IFCOUNTER_OMCASTS, - priv->pkstats.tx_multicast_packets - priv->pkstats_last.tx_multicast_packets); - } - priv->pkstats_last = priv->pkstats; -#else - dev = mdev->pndev[port]; - dev->if_ipackets = priv->pkstats.rx_packets; - dev->if_opackets = priv->pkstats.tx_packets; - dev->if_ibytes = priv->pkstats.rx_bytes; - dev->if_obytes = priv->pkstats.tx_bytes; - dev->if_ierrors = priv->pkstats.rx_errors; - dev->if_iqdrops = priv->pkstats.rx_dropped; - dev->if_imcasts = priv->pkstats.rx_multicast_packets; - dev->if_omcasts = priv->pkstats.tx_multicast_packets; - dev->if_collisions = 0; -#endif - } - - spin_unlock(&priv->stats_lock); - -out: - mlx4_free_cmd_mailbox(mdev->dev, mailbox_flow); - mlx4_free_cmd_mailbox(mdev->dev, mailbox); - -mailbox_out: - if (do_if_stat) - priv->last_ifq_jiffies = jiffies; - - return err; -} diff --git a/sys/ofed/drivers/net/mlx4/en_port.h b/sys/ofed/drivers/net/mlx4/en_port.h deleted file mode 100644 index 6301717e1814..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_port.h +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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. - * - */ - -#ifndef _MLX4_EN_PORT_H_ -#define _MLX4_EN_PORT_H_ - - -#define SET_PORT_GEN_ALL_VALID 0x7 -#define SET_PORT_PROMISC_SHIFT 31 -#define SET_PORT_MC_PROMISC_SHIFT 30 - -#define MLX4_EN_NUM_TC 8 - -#define VLAN_FLTR_SIZE 128 -struct mlx4_set_vlan_fltr_mbox { - __be32 entry[VLAN_FLTR_SIZE]; -}; - - -enum { - MLX4_MCAST_CONFIG = 0, - MLX4_MCAST_DISABLE = 1, - MLX4_MCAST_ENABLE = 2, -}; - -enum { - MLX4_EN_10G_SPEED_XAUI = 0x00, - MLX4_EN_10G_SPEED_XFI = 0x01, - MLX4_EN_1G_SPEED = 0x02, - MLX4_EN_20G_SPEED = 0x08, - MLX4_EN_40G_SPEED = 0x40, - MLX4_EN_56G_SPEED = 0x20, - MLX4_EN_OTHER_SPEED = 0x0f, -}; - -struct mlx4_en_query_port_context { - u8 link_up; -#define MLX4_EN_LINK_UP_MASK 0x80 - u8 autoneg; -#define MLX4_EN_AUTONEG_MASK 0x80 - __be16 mtu; - u8 reserved2; - u8 link_speed; -#define MLX4_EN_SPEED_MASK 0x6b - u16 reserved3[5]; - __be64 mac; - u8 transceiver; -}; - - -struct mlx4_en_stat_out_mbox { - /* Received frames with a length of 64 octets */ - __be64 R64_prio_0; - __be64 R64_prio_1; - __be64 R64_prio_2; - __be64 R64_prio_3; - __be64 R64_prio_4; - __be64 R64_prio_5; - __be64 R64_prio_6; - __be64 R64_prio_7; - __be64 R64_novlan; - /* Received frames with a length of 127 octets */ - __be64 R127_prio_0; - __be64 R127_prio_1; - __be64 R127_prio_2; - __be64 R127_prio_3; - __be64 R127_prio_4; - __be64 R127_prio_5; - __be64 R127_prio_6; - __be64 R127_prio_7; - __be64 R127_novlan; - /* Received frames with a length of 255 octets */ - __be64 R255_prio_0; - __be64 R255_prio_1; - __be64 R255_prio_2; - __be64 R255_prio_3; - __be64 R255_prio_4; - __be64 R255_prio_5; - __be64 R255_prio_6; - __be64 R255_prio_7; - __be64 R255_novlan; - /* Received frames with a length of 511 octets */ - __be64 R511_prio_0; - __be64 R511_prio_1; - __be64 R511_prio_2; - __be64 R511_prio_3; - __be64 R511_prio_4; - __be64 R511_prio_5; - __be64 R511_prio_6; - __be64 R511_prio_7; - __be64 R511_novlan; - /* Received frames with a length of 1023 octets */ - __be64 R1023_prio_0; - __be64 R1023_prio_1; - __be64 R1023_prio_2; - __be64 R1023_prio_3; - __be64 R1023_prio_4; - __be64 R1023_prio_5; - __be64 R1023_prio_6; - __be64 R1023_prio_7; - __be64 R1023_novlan; - /* Received frames with a length of 1518 octets */ - __be64 R1518_prio_0; - __be64 R1518_prio_1; - __be64 R1518_prio_2; - __be64 R1518_prio_3; - __be64 R1518_prio_4; - __be64 R1518_prio_5; - __be64 R1518_prio_6; - __be64 R1518_prio_7; - __be64 R1518_novlan; - /* Received frames with a length of 1522 octets */ - __be64 R1522_prio_0; - __be64 R1522_prio_1; - __be64 R1522_prio_2; - __be64 R1522_prio_3; - __be64 R1522_prio_4; - __be64 R1522_prio_5; - __be64 R1522_prio_6; - __be64 R1522_prio_7; - __be64 R1522_novlan; - /* Received frames with a length of 1548 octets */ - __be64 R1548_prio_0; - __be64 R1548_prio_1; - __be64 R1548_prio_2; - __be64 R1548_prio_3; - __be64 R1548_prio_4; - __be64 R1548_prio_5; - __be64 R1548_prio_6; - __be64 R1548_prio_7; - __be64 R1548_novlan; - /* Received frames with a length of 1548 < octets < MTU */ - __be64 R2MTU_prio_0; - __be64 R2MTU_prio_1; - __be64 R2MTU_prio_2; - __be64 R2MTU_prio_3; - __be64 R2MTU_prio_4; - __be64 R2MTU_prio_5; - __be64 R2MTU_prio_6; - __be64 R2MTU_prio_7; - __be64 R2MTU_novlan; - /* Received frames with a length of MTU< octets and good CRC */ - __be64 RGIANT_prio_0; - __be64 RGIANT_prio_1; - __be64 RGIANT_prio_2; - __be64 RGIANT_prio_3; - __be64 RGIANT_prio_4; - __be64 RGIANT_prio_5; - __be64 RGIANT_prio_6; - __be64 RGIANT_prio_7; - __be64 RGIANT_novlan; - /* Received broadcast frames with good CRC */ - __be64 RBCAST_prio_0; - __be64 RBCAST_prio_1; - __be64 RBCAST_prio_2; - __be64 RBCAST_prio_3; - __be64 RBCAST_prio_4; - __be64 RBCAST_prio_5; - __be64 RBCAST_prio_6; - __be64 RBCAST_prio_7; - __be64 RBCAST_novlan; - /* Received multicast frames with good CRC */ - __be64 MCAST_prio_0; - __be64 MCAST_prio_1; - __be64 MCAST_prio_2; - __be64 MCAST_prio_3; - __be64 MCAST_prio_4; - __be64 MCAST_prio_5; - __be64 MCAST_prio_6; - __be64 MCAST_prio_7; - __be64 MCAST_novlan; - /* Received unicast not short or GIANT frames with good CRC */ - __be64 RTOTG_prio_0; - __be64 RTOTG_prio_1; - __be64 RTOTG_prio_2; - __be64 RTOTG_prio_3; - __be64 RTOTG_prio_4; - __be64 RTOTG_prio_5; - __be64 RTOTG_prio_6; - __be64 RTOTG_prio_7; - __be64 RTOTG_novlan; - - /* Count of total octets of received frames, includes framing characters */ - __be64 RTTLOCT_prio_0; - /* Count of total octets of received frames, not including framing - characters */ - __be64 RTTLOCT_NOFRM_prio_0; - /* Count of Total number of octets received - (only for frames without errors) */ - __be64 ROCT_prio_0; - - __be64 RTTLOCT_prio_1; - __be64 RTTLOCT_NOFRM_prio_1; - __be64 ROCT_prio_1; - - __be64 RTTLOCT_prio_2; - __be64 RTTLOCT_NOFRM_prio_2; - __be64 ROCT_prio_2; - - __be64 RTTLOCT_prio_3; - __be64 RTTLOCT_NOFRM_prio_3; - __be64 ROCT_prio_3; - - __be64 RTTLOCT_prio_4; - __be64 RTTLOCT_NOFRM_prio_4; - __be64 ROCT_prio_4; - - __be64 RTTLOCT_prio_5; - __be64 RTTLOCT_NOFRM_prio_5; - __be64 ROCT_prio_5; - - __be64 RTTLOCT_prio_6; - __be64 RTTLOCT_NOFRM_prio_6; - __be64 ROCT_prio_6; - - __be64 RTTLOCT_prio_7; - __be64 RTTLOCT_NOFRM_prio_7; - __be64 ROCT_prio_7; - - __be64 RTTLOCT_novlan; - __be64 RTTLOCT_NOFRM_novlan; - __be64 ROCT_novlan; - - /* Count of Total received frames including bad frames */ - __be64 RTOT_prio_0; - /* Count of Total number of received frames with 802.1Q encapsulation */ - __be64 R1Q_prio_0; - __be64 reserved1; - - __be64 RTOT_prio_1; - __be64 R1Q_prio_1; - __be64 reserved2; - - __be64 RTOT_prio_2; - __be64 R1Q_prio_2; - __be64 reserved3; - - __be64 RTOT_prio_3; - __be64 R1Q_prio_3; - __be64 reserved4; - - __be64 RTOT_prio_4; - __be64 R1Q_prio_4; - __be64 reserved5; - - __be64 RTOT_prio_5; - __be64 R1Q_prio_5; - __be64 reserved6; - - __be64 RTOT_prio_6; - __be64 R1Q_prio_6; - __be64 reserved7; - - __be64 RTOT_prio_7; - __be64 R1Q_prio_7; - __be64 reserved8; - - __be64 RTOT_novlan; - __be64 R1Q_novlan; - __be64 reserved9; - - /* Total number of Successfully Received Control Frames */ - __be64 RCNTL; - __be64 reserved10; - __be64 reserved11; - __be64 reserved12; - /* Count of received frames with a length/type field value between 46 - (42 for VLANtagged frames) and 1500 (also 1500 for VLAN-tagged frames), - inclusive */ - __be64 RInRangeLengthErr; - /* Count of received frames with length/type field between 1501 and 1535 - decimal, inclusive */ - __be64 ROutRangeLengthErr; - /* Count of received frames that are longer than max allowed size for - 802.3 frames (1518/1522) */ - __be64 RFrmTooLong; - /* Count frames received with PCS error */ - __be64 PCS; - - /* Transmit frames with a length of 64 octets */ - __be64 T64_prio_0; - __be64 T64_prio_1; - __be64 T64_prio_2; - __be64 T64_prio_3; - __be64 T64_prio_4; - __be64 T64_prio_5; - __be64 T64_prio_6; - __be64 T64_prio_7; - __be64 T64_novlan; - __be64 T64_loopbk; - /* Transmit frames with a length of 65 to 127 octets. */ - __be64 T127_prio_0; - __be64 T127_prio_1; - __be64 T127_prio_2; - __be64 T127_prio_3; - __be64 T127_prio_4; - __be64 T127_prio_5; - __be64 T127_prio_6; - __be64 T127_prio_7; - __be64 T127_novlan; - __be64 T127_loopbk; - /* Transmit frames with a length of 128 to 255 octets */ - __be64 T255_prio_0; - __be64 T255_prio_1; - __be64 T255_prio_2; - __be64 T255_prio_3; - __be64 T255_prio_4; - __be64 T255_prio_5; - __be64 T255_prio_6; - __be64 T255_prio_7; - __be64 T255_novlan; - __be64 T255_loopbk; - /* Transmit frames with a length of 256 to 511 octets */ - __be64 T511_prio_0; - __be64 T511_prio_1; - __be64 T511_prio_2; - __be64 T511_prio_3; - __be64 T511_prio_4; - __be64 T511_prio_5; - __be64 T511_prio_6; - __be64 T511_prio_7; - __be64 T511_novlan; - __be64 T511_loopbk; - /* Transmit frames with a length of 512 to 1023 octets */ - __be64 T1023_prio_0; - __be64 T1023_prio_1; - __be64 T1023_prio_2; - __be64 T1023_prio_3; - __be64 T1023_prio_4; - __be64 T1023_prio_5; - __be64 T1023_prio_6; - __be64 T1023_prio_7; - __be64 T1023_novlan; - __be64 T1023_loopbk; - /* Transmit frames with a length of 1024 to 1518 octets */ - __be64 T1518_prio_0; - __be64 T1518_prio_1; - __be64 T1518_prio_2; - __be64 T1518_prio_3; - __be64 T1518_prio_4; - __be64 T1518_prio_5; - __be64 T1518_prio_6; - __be64 T1518_prio_7; - __be64 T1518_novlan; - __be64 T1518_loopbk; - /* Counts transmit frames with a length of 1519 to 1522 bytes */ - __be64 T1522_prio_0; - __be64 T1522_prio_1; - __be64 T1522_prio_2; - __be64 T1522_prio_3; - __be64 T1522_prio_4; - __be64 T1522_prio_5; - __be64 T1522_prio_6; - __be64 T1522_prio_7; - __be64 T1522_novlan; - __be64 T1522_loopbk; - /* Transmit frames with a length of 1523 to 1548 octets */ - __be64 T1548_prio_0; - __be64 T1548_prio_1; - __be64 T1548_prio_2; - __be64 T1548_prio_3; - __be64 T1548_prio_4; - __be64 T1548_prio_5; - __be64 T1548_prio_6; - __be64 T1548_prio_7; - __be64 T1548_novlan; - __be64 T1548_loopbk; - /* Counts transmit frames with a length of 1549 to MTU bytes */ - __be64 T2MTU_prio_0; - __be64 T2MTU_prio_1; - __be64 T2MTU_prio_2; - __be64 T2MTU_prio_3; - __be64 T2MTU_prio_4; - __be64 T2MTU_prio_5; - __be64 T2MTU_prio_6; - __be64 T2MTU_prio_7; - __be64 T2MTU_novlan; - __be64 T2MTU_loopbk; - /* Transmit frames with a length greater than MTU octets and a good CRC. */ - __be64 TGIANT_prio_0; - __be64 TGIANT_prio_1; - __be64 TGIANT_prio_2; - __be64 TGIANT_prio_3; - __be64 TGIANT_prio_4; - __be64 TGIANT_prio_5; - __be64 TGIANT_prio_6; - __be64 TGIANT_prio_7; - __be64 TGIANT_novlan; - __be64 TGIANT_loopbk; - /* Transmit broadcast frames with a good CRC */ - __be64 TBCAST_prio_0; - __be64 TBCAST_prio_1; - __be64 TBCAST_prio_2; - __be64 TBCAST_prio_3; - __be64 TBCAST_prio_4; - __be64 TBCAST_prio_5; - __be64 TBCAST_prio_6; - __be64 TBCAST_prio_7; - __be64 TBCAST_novlan; - __be64 TBCAST_loopbk; - /* Transmit multicast frames with a good CRC */ - __be64 TMCAST_prio_0; - __be64 TMCAST_prio_1; - __be64 TMCAST_prio_2; - __be64 TMCAST_prio_3; - __be64 TMCAST_prio_4; - __be64 TMCAST_prio_5; - __be64 TMCAST_prio_6; - __be64 TMCAST_prio_7; - __be64 TMCAST_novlan; - __be64 TMCAST_loopbk; - /* Transmit good frames that are neither broadcast nor multicast */ - __be64 TTOTG_prio_0; - __be64 TTOTG_prio_1; - __be64 TTOTG_prio_2; - __be64 TTOTG_prio_3; - __be64 TTOTG_prio_4; - __be64 TTOTG_prio_5; - __be64 TTOTG_prio_6; - __be64 TTOTG_prio_7; - __be64 TTOTG_novlan; - __be64 TTOTG_loopbk; - - /* total octets of transmitted frames, including framing characters */ - __be64 TTTLOCT_prio_0; - /* total octets of transmitted frames, not including framing characters */ - __be64 TTTLOCT_NOFRM_prio_0; - /* ifOutOctets */ - __be64 TOCT_prio_0; - - __be64 TTTLOCT_prio_1; - __be64 TTTLOCT_NOFRM_prio_1; - __be64 TOCT_prio_1; - - __be64 TTTLOCT_prio_2; - __be64 TTTLOCT_NOFRM_prio_2; - __be64 TOCT_prio_2; - - __be64 TTTLOCT_prio_3; - __be64 TTTLOCT_NOFRM_prio_3; - __be64 TOCT_prio_3; - - __be64 TTTLOCT_prio_4; - __be64 TTTLOCT_NOFRM_prio_4; - __be64 TOCT_prio_4; - - __be64 TTTLOCT_prio_5; - __be64 TTTLOCT_NOFRM_prio_5; - __be64 TOCT_prio_5; - - __be64 TTTLOCT_prio_6; - __be64 TTTLOCT_NOFRM_prio_6; - __be64 TOCT_prio_6; - - __be64 TTTLOCT_prio_7; - __be64 TTTLOCT_NOFRM_prio_7; - __be64 TOCT_prio_7; - - __be64 TTTLOCT_novlan; - __be64 TTTLOCT_NOFRM_novlan; - __be64 TOCT_novlan; - - __be64 TTTLOCT_loopbk; - __be64 TTTLOCT_NOFRM_loopbk; - __be64 TOCT_loopbk; - - /* Total frames transmitted with a good CRC that are not aborted */ - __be64 TTOT_prio_0; - /* Total number of frames transmitted with 802.1Q encapsulation */ - __be64 T1Q_prio_0; - __be64 reserved13; - - __be64 TTOT_prio_1; - __be64 T1Q_prio_1; - __be64 reserved14; - - __be64 TTOT_prio_2; - __be64 T1Q_prio_2; - __be64 reserved15; - - __be64 TTOT_prio_3; - __be64 T1Q_prio_3; - __be64 reserved16; - - __be64 TTOT_prio_4; - __be64 T1Q_prio_4; - __be64 reserved17; - - __be64 TTOT_prio_5; - __be64 T1Q_prio_5; - __be64 reserved18; - - __be64 TTOT_prio_6; - __be64 T1Q_prio_6; - __be64 reserved19; - - __be64 TTOT_prio_7; - __be64 T1Q_prio_7; - __be64 reserved20; - - __be64 TTOT_novlan; - __be64 T1Q_novlan; - __be64 reserved21; - - __be64 TTOT_loopbk; - __be64 T1Q_loopbk; - __be64 reserved22; - - /* Received frames with a length greater than MTU octets and a bad CRC */ - __be32 RJBBR; - /* Received frames with a bad CRC that are not runts, jabbers, - or alignment errors */ - __be32 RCRC; - /* Received frames with SFD with a length of less than 64 octets and a - bad CRC */ - __be32 RRUNT; - /* Received frames with a length less than 64 octets and a good CRC */ - __be32 RSHORT; - /* Total Number of Received Packets Dropped */ - __be32 RDROP; - /* Drop due to overflow */ - __be32 RdropOvflw; - /* Drop due to overflow */ - __be32 RdropLength; - /* Total of good frames. Does not include frames received with - frame-too-long, FCS, or length errors */ - __be32 RTOTFRMS; - /* Total dropped Xmited packets */ - __be32 TDROP; -}; - - -#endif diff --git a/sys/ofed/drivers/net/mlx4/en_resources.c b/sys/ofed/drivers/net/mlx4/en_resources.c deleted file mode 100644 index 669ecbd11843..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_resources.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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/slab.h> -#include <linux/vmalloc.h> -#include <linux/mlx4/qp.h> - -#include "mlx4_en.h" - - -void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, - int user_prio, struct mlx4_qp_context *context) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct net_device *dev = priv->dev; - - memset(context, 0, sizeof *context); - context->flags = cpu_to_be32(7 << 16 | rss << MLX4_RSS_QPC_FLAG_OFFSET); - context->pd = cpu_to_be32(mdev->priv_pdn); - context->mtu_msgmax = 0xff; - if (!is_tx && !rss) - context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - if (is_tx) - context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - else - context->sq_size_stride = ilog2(TXBB_SIZE) - 4; - context->usr_page = cpu_to_be32(mdev->priv_uar.index); - context->local_qpn = cpu_to_be32(qpn); - context->pri_path.ackto = 1 & 0x07; - context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6; - if (user_prio >= 0) { - context->pri_path.sched_queue |= user_prio << 3; - context->pri_path.feup = 1 << 6; - } - context->pri_path.counter_index = (u8)(priv->counter_index); - if (!rss && - (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK) && - context->pri_path.counter_index != 0xFF) { - /* disable multicast loopback to qp with same counter */ - context->pri_path.fl |= MLX4_FL_ETH_SRC_CHECK_MC_LB; - context->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; - } - - context->cqn_send = cpu_to_be32(cqn); - context->cqn_recv = cpu_to_be32(cqn); - context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); - if (!(dev->if_capabilities & IFCAP_VLAN_HWCSUM)) - context->param3 |= cpu_to_be32(1 << 30); -} - - -int mlx4_en_map_buffer(struct mlx4_buf *buf) -{ - struct page **pages; - int i; - - // if nbufs == 1 - there is no need to vmap - // if buf->direct.buf is not NULL it means that vmap was already done by mlx4_alloc_buff - if (buf->direct.buf != NULL || buf->nbufs == 1) - return 0; - - pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); - if (!pages) - return -ENOMEM; - - for (i = 0; i < buf->nbufs; ++i) - pages[i] = virt_to_page(buf->page_list[i].buf); - - buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); - kfree(pages); - if (!buf->direct.buf) - return -ENOMEM; - - return 0; -} - -void mlx4_en_unmap_buffer(struct mlx4_buf *buf) -{ - if (BITS_PER_LONG == 64 || buf->nbufs == 1) - return; - - vunmap(buf->direct.buf); -} - -void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event) -{ - return; -} - diff --git a/sys/ofed/drivers/net/mlx4/en_rx.c b/sys/ofed/drivers/net/mlx4/en_rx.c deleted file mode 100644 index 2711b22b8667..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_rx.c +++ /dev/null @@ -1,922 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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 "opt_inet.h" -#include <linux/mlx4/cq.h> -#include <linux/slab.h> -#include <linux/mlx4/qp.h> -#include <linux/if_ether.h> -#include <linux/if_vlan.h> -#include <linux/vmalloc.h> -#include <linux/mlx4/driver.h> -#ifdef CONFIG_NET_RX_BUSY_POLL -#include <net/busy_poll.h> -#endif - -#include "mlx4_en.h" - - -static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring, - int index) -{ - struct mlx4_en_rx_desc *rx_desc = (struct mlx4_en_rx_desc *) - (ring->buf + (ring->stride * index)); - int possible_frags; - int i; - - /* Set size and memtype fields */ - rx_desc->data[0].byte_count = cpu_to_be32(priv->rx_mb_size - MLX4_NET_IP_ALIGN); - rx_desc->data[0].lkey = cpu_to_be32(priv->mdev->mr.key); - - /* - * If the number of used fragments does not fill up the ring - * stride, remaining (unused) fragments must be padded with - * null address/size and a special memory key: - */ - possible_frags = (ring->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE; - for (i = 1; i < possible_frags; i++) { - rx_desc->data[i].byte_count = 0; - rx_desc->data[i].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD); - rx_desc->data[i].addr = 0; - } -} - -static int -mlx4_en_alloc_buf(struct mlx4_en_rx_ring *ring, - __be64 *pdma, struct mlx4_en_rx_mbuf *mb_list) -{ - bus_dma_segment_t segs[1]; - bus_dmamap_t map; - struct mbuf *mb; - int nsegs; - int err; - - /* try to allocate a new spare mbuf */ - if (unlikely(ring->spare.mbuf == NULL)) { - mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ring->rx_mb_size); - if (unlikely(mb == NULL)) - return (-ENOMEM); - /* setup correct length */ - mb->m_pkthdr.len = mb->m_len = ring->rx_mb_size; - - /* make sure IP header gets aligned */ - m_adj(mb, MLX4_NET_IP_ALIGN); - - /* load spare mbuf into BUSDMA */ - err = -bus_dmamap_load_mbuf_sg(ring->dma_tag, ring->spare.dma_map, - mb, segs, &nsegs, BUS_DMA_NOWAIT); - if (unlikely(err != 0)) { - m_freem(mb); - return (err); - } - - /* store spare info */ - ring->spare.mbuf = mb; - ring->spare.paddr_be = cpu_to_be64(segs[0].ds_addr); - - bus_dmamap_sync(ring->dma_tag, ring->spare.dma_map, - BUS_DMASYNC_PREREAD); - } - - /* synchronize and unload the current mbuf, if any */ - if (likely(mb_list->mbuf != NULL)) { - bus_dmamap_sync(ring->dma_tag, mb_list->dma_map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(ring->dma_tag, mb_list->dma_map); - } - - mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ring->rx_mb_size); - if (unlikely(mb == NULL)) - goto use_spare; - - /* setup correct length */ - mb->m_pkthdr.len = mb->m_len = ring->rx_mb_size; - - /* make sure IP header gets aligned */ - m_adj(mb, MLX4_NET_IP_ALIGN); - - err = -bus_dmamap_load_mbuf_sg(ring->dma_tag, mb_list->dma_map, - mb, segs, &nsegs, BUS_DMA_NOWAIT); - if (unlikely(err != 0)) { - m_freem(mb); - goto use_spare; - } - - *pdma = cpu_to_be64(segs[0].ds_addr); - mb_list->mbuf = mb; - - bus_dmamap_sync(ring->dma_tag, mb_list->dma_map, BUS_DMASYNC_PREREAD); - return (0); - -use_spare: - /* swap DMA maps */ - map = mb_list->dma_map; - mb_list->dma_map = ring->spare.dma_map; - ring->spare.dma_map = map; - - /* swap MBUFs */ - mb_list->mbuf = ring->spare.mbuf; - ring->spare.mbuf = NULL; - - /* store physical address */ - *pdma = ring->spare.paddr_be; - return (0); -} - -static void -mlx4_en_free_buf(struct mlx4_en_rx_ring *ring, struct mlx4_en_rx_mbuf *mb_list) -{ - bus_dmamap_t map = mb_list->dma_map; - bus_dmamap_sync(ring->dma_tag, map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(ring->dma_tag, map); - m_freem(mb_list->mbuf); - mb_list->mbuf = NULL; /* safety clearing */ -} - -static int -mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring, int index) -{ - struct mlx4_en_rx_desc *rx_desc = (struct mlx4_en_rx_desc *) - (ring->buf + (index * ring->stride)); - struct mlx4_en_rx_mbuf *mb_list = ring->mbuf + index; - - mb_list->mbuf = NULL; - - if (mlx4_en_alloc_buf(ring, &rx_desc->data[0].addr, mb_list)) { - priv->port_stats.rx_alloc_failed++; - return (-ENOMEM); - } - return (0); -} - -static inline void -mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) -{ - *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); -} - -static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) -{ - struct mlx4_en_rx_ring *ring; - int ring_ind; - int buf_ind; - int new_size; - int err; - - for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) { - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - - err = mlx4_en_prepare_rx_desc(priv, ring, - ring->actual_size); - if (err) { - if (ring->actual_size == 0) { - en_err(priv, "Failed to allocate " - "enough rx buffers\n"); - return -ENOMEM; - } else { - new_size = - rounddown_pow_of_two(ring->actual_size); - en_warn(priv, "Only %d buffers allocated " - "reducing ring size to %d\n", - ring->actual_size, new_size); - goto reduce_rings; - } - } - ring->actual_size++; - ring->prod++; - } - } - return 0; - -reduce_rings: - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - while (ring->actual_size > new_size) { - ring->actual_size--; - ring->prod--; - mlx4_en_free_buf(ring, - ring->mbuf + ring->actual_size); - } - } - - return 0; -} - -static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring) -{ - int index; - - en_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", - ring->cons, ring->prod); - - /* Unmap and free Rx buffers */ - BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); - while (ring->cons != ring->prod) { - index = ring->cons & ring->size_mask; - en_dbg(DRV, priv, "Processing descriptor:%d\n", index); - mlx4_en_free_buf(ring, ring->mbuf + index); - ++ring->cons; - } -} - -void mlx4_en_calc_rx_buf(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int eff_mtu = dev->if_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN + - MLX4_NET_IP_ALIGN; - - if (eff_mtu > MJUM16BYTES) { - en_err(priv, "MTU(%d) is too big\n", dev->if_mtu); - eff_mtu = MJUM16BYTES; - } else if (eff_mtu > MJUM9BYTES) { - eff_mtu = MJUM16BYTES; - } else if (eff_mtu > MJUMPAGESIZE) { - eff_mtu = MJUM9BYTES; - } else if (eff_mtu > MCLBYTES) { - eff_mtu = MJUMPAGESIZE; - } else { - eff_mtu = MCLBYTES; - } - - priv->rx_mb_size = eff_mtu; - - en_dbg(DRV, priv, "Effective RX MTU: %d bytes\n", eff_mtu); -} - -int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, int node) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rx_ring *ring; - int err; - int tmp; - uint32_t x; - - ring = kzalloc(sizeof(struct mlx4_en_rx_ring), GFP_KERNEL); - if (!ring) { - en_err(priv, "Failed to allocate RX ring structure\n"); - return -ENOMEM; - } - - /* Create DMA descriptor TAG */ - if ((err = -bus_dma_tag_create( - bus_get_dma_tag(mdev->pdev->dev.bsddev), - 1, /* any alignment */ - 0, /* no boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MJUM16BYTES, /* maxsize */ - 1, /* nsegments */ - MJUM16BYTES, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockfuncarg */ - &ring->dma_tag))) { - en_err(priv, "Failed to create DMA tag\n"); - goto err_ring; - } - - ring->prod = 0; - ring->cons = 0; - ring->size = size; - ring->size_mask = size - 1; - ring->stride = roundup_pow_of_two( - sizeof(struct mlx4_en_rx_desc) + DS_SIZE); - ring->log_stride = ffs(ring->stride) - 1; - ring->buf_size = ring->size * ring->stride + TXBB_SIZE; - - tmp = size * sizeof(struct mlx4_en_rx_mbuf); - - ring->mbuf = kzalloc(tmp, GFP_KERNEL); - if (ring->mbuf == NULL) { - err = -ENOMEM; - goto err_dma_tag; - } - - err = -bus_dmamap_create(ring->dma_tag, 0, &ring->spare.dma_map); - if (err != 0) - goto err_info; - - for (x = 0; x != size; x++) { - err = -bus_dmamap_create(ring->dma_tag, 0, - &ring->mbuf[x].dma_map); - if (err != 0) { - while (x--) - bus_dmamap_destroy(ring->dma_tag, - ring->mbuf[x].dma_map); - goto err_info; - } - } - en_dbg(DRV, priv, "Allocated MBUF ring at addr:%p size:%d\n", - ring->mbuf, tmp); - - err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, - ring->buf_size, 2 * PAGE_SIZE); - if (err) - goto err_dma_map; - - err = mlx4_en_map_buffer(&ring->wqres.buf); - if (err) { - en_err(priv, "Failed to map RX buffer\n"); - goto err_hwq; - } - ring->buf = ring->wqres.buf.direct.buf; - *pring = ring; - return 0; - -err_hwq: - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); -err_dma_map: - for (x = 0; x != size; x++) { - bus_dmamap_destroy(ring->dma_tag, - ring->mbuf[x].dma_map); - } - bus_dmamap_destroy(ring->dma_tag, ring->spare.dma_map); -err_info: - vfree(ring->mbuf); -err_dma_tag: - bus_dma_tag_destroy(ring->dma_tag); -err_ring: - kfree(ring); - return (err); -} - -int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) -{ - struct mlx4_en_rx_ring *ring; - int i; - int ring_ind; - int err; - int stride = roundup_pow_of_two( - sizeof(struct mlx4_en_rx_desc) + DS_SIZE); - - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - - ring->prod = 0; - ring->cons = 0; - ring->actual_size = 0; - ring->cqn = priv->rx_cq[ring_ind]->mcq.cqn; - ring->rx_mb_size = priv->rx_mb_size; - - ring->stride = stride; - if (ring->stride <= TXBB_SIZE) - ring->buf += TXBB_SIZE; - - ring->log_stride = ffs(ring->stride) - 1; - ring->buf_size = ring->size * ring->stride; - - memset(ring->buf, 0, ring->buf_size); - mlx4_en_update_rx_prod_db(ring); - - /* Initialize all descriptors */ - for (i = 0; i < ring->size; i++) - mlx4_en_init_rx_desc(priv, ring, i); - -#ifdef INET - /* Configure lro mngr */ - if (priv->dev->if_capenable & IFCAP_LRO) { - if (tcp_lro_init(&ring->lro)) - priv->dev->if_capenable &= ~IFCAP_LRO; - else - ring->lro.ifp = priv->dev; - } -#endif - } - - - err = mlx4_en_fill_rx_buffers(priv); - if (err) - goto err_buffers; - - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { - ring = priv->rx_ring[ring_ind]; - - ring->size_mask = ring->actual_size - 1; - mlx4_en_update_rx_prod_db(ring); - } - - return 0; - -err_buffers: - for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) - mlx4_en_free_rx_buf(priv, priv->rx_ring[ring_ind]); - - ring_ind = priv->rx_ring_num - 1; - - while (ring_ind >= 0) { - ring = priv->rx_ring[ring_ind]; - if (ring->stride <= TXBB_SIZE) - ring->buf -= TXBB_SIZE; - ring_ind--; - } - - return err; -} - - -void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, u16 stride) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rx_ring *ring = *pring; - uint32_t x; - - mlx4_en_unmap_buffer(&ring->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &ring->wqres, size * stride + TXBB_SIZE); - for (x = 0; x != size; x++) - bus_dmamap_destroy(ring->dma_tag, ring->mbuf[x].dma_map); - /* free spare mbuf, if any */ - if (ring->spare.mbuf != NULL) { - bus_dmamap_sync(ring->dma_tag, ring->spare.dma_map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(ring->dma_tag, ring->spare.dma_map); - m_freem(ring->spare.mbuf); - } - bus_dmamap_destroy(ring->dma_tag, ring->spare.dma_map); - vfree(ring->mbuf); - bus_dma_tag_destroy(ring->dma_tag); - kfree(ring); - *pring = NULL; -#ifdef CONFIG_RFS_ACCEL - mlx4_en_cleanup_filters(priv, ring); -#endif -} - -void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring) -{ -#ifdef INET - tcp_lro_free(&ring->lro); -#endif - mlx4_en_free_rx_buf(priv, ring); - if (ring->stride <= TXBB_SIZE) - ring->buf -= TXBB_SIZE; -} - - -static void validate_loopback(struct mlx4_en_priv *priv, struct mbuf *mb) -{ - int i; - int offset = ETHER_HDR_LEN; - - for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) { - if (*(mb->m_data + offset) != (unsigned char) (i & 0xff)) - goto out_loopback; - } - /* Loopback found */ - priv->loopback_ok = 1; - -out_loopback: - m_freem(mb); -} - - -static inline int invalid_cqe(struct mlx4_en_priv *priv, - struct mlx4_cqe *cqe) -{ - /* Drop packet on bad receive or bad checksum */ - if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == - MLX4_CQE_OPCODE_ERROR)) { - en_err(priv, "CQE completed in error - vendor syndrom:%d syndrom:%d\n", - ((struct mlx4_err_cqe *)cqe)->vendor_err_syndrome, - ((struct mlx4_err_cqe *)cqe)->syndrome); - return 1; - } - if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) { - en_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); - return 1; - } - - return 0; -} - -static struct mbuf * -mlx4_en_rx_mb(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring, - struct mlx4_en_rx_desc *rx_desc, struct mlx4_en_rx_mbuf *mb_list, - int length) -{ - struct mbuf *mb; - - /* get mbuf */ - mb = mb_list->mbuf; - - /* collect used fragment while atomically replacing it */ - if (mlx4_en_alloc_buf(ring, &rx_desc->data[0].addr, mb_list)) - return (NULL); - - /* range check hardware computed value */ - if (unlikely(length > mb->m_len)) - length = mb->m_len; - - /* update total packet length in packet header */ - mb->m_len = mb->m_pkthdr.len = length; - return (mb); -} - -/* For cpu arch with cache line of 64B the performance is better when cqe size==64B - * To enlarge cqe size from 32B to 64B --> 32B of garbage (i.e. 0xccccccc) - * was added in the beginning of each cqe (the real data is in the corresponding 32B). - * The following calc ensures that when factor==1, it means we are aligned to 64B - * and we get the real cqe data*/ -#define CQE_FACTOR_INDEX(index, factor) ((index << factor) + factor) -int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_cqe *cqe; - struct mlx4_en_rx_ring *ring = priv->rx_ring[cq->ring]; - struct mlx4_en_rx_mbuf *mb_list; - struct mlx4_en_rx_desc *rx_desc; - struct mbuf *mb; - struct mlx4_cq *mcq = &cq->mcq; - struct mlx4_cqe *buf = cq->buf; - int index; - unsigned int length; - int polled = 0; - u32 cons_index = mcq->cons_index; - u32 size_mask = ring->size_mask; - int size = cq->size; - int factor = priv->cqe_factor; - - if (!priv->port_up) - return 0; - - /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx - * descriptor offset can be deducted from the CQE index instead of - * reading 'cqe->index' */ - index = cons_index & size_mask; - cqe = &buf[CQE_FACTOR_INDEX(index, factor)]; - - /* Process all completed CQEs */ - while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, - cons_index & size)) { - mb_list = ring->mbuf + index; - rx_desc = (struct mlx4_en_rx_desc *) - (ring->buf + (index << ring->log_stride)); - - /* - * make sure we read the CQE after we read the ownership bit - */ - rmb(); - - if (invalid_cqe(priv, cqe)) { - goto next; - } - /* - * Packet is OK - process it. - */ - length = be32_to_cpu(cqe->byte_cnt); - length -= ring->fcs_del; - - mb = mlx4_en_rx_mb(priv, ring, rx_desc, mb_list, length); - if (unlikely(!mb)) { - ring->errors++; - goto next; - } - - ring->bytes += length; - ring->packets++; - - if (unlikely(priv->validate_loopback)) { - validate_loopback(priv, mb); - goto next; - } - - /* forward Toeplitz compatible hash value */ - mb->m_pkthdr.flowid = be32_to_cpu(cqe->immed_rss_invalid); - M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE_HASH); - mb->m_pkthdr.rcvif = dev; - if (be32_to_cpu(cqe->vlan_my_qpn) & - MLX4_CQE_VLAN_PRESENT_MASK) { - mb->m_pkthdr.ether_vtag = be16_to_cpu(cqe->sl_vid); - mb->m_flags |= M_VLANTAG; - } - if (likely(dev->if_capenable & - (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) && - (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && - (cqe->checksum == cpu_to_be16(0xffff))) { - priv->port_stats.rx_chksum_good++; - mb->m_pkthdr.csum_flags = - CSUM_IP_CHECKED | CSUM_IP_VALID | - CSUM_DATA_VALID | CSUM_PSEUDO_HDR; - mb->m_pkthdr.csum_data = htons(0xffff); - /* This packet is eligible for LRO if it is: - * - DIX Ethernet (type interpretation) - * - TCP/IP (v4) - * - without IP options - * - not an IP fragment - */ -#ifdef INET - if (mlx4_en_can_lro(cqe->status) && - (dev->if_capenable & IFCAP_LRO)) { - if (ring->lro.lro_cnt != 0 && - tcp_lro_rx(&ring->lro, mb, 0) == 0) - goto next; - } - -#endif - /* LRO not possible, complete processing here */ - INC_PERF_COUNTER(priv->pstats.lro_misses); - } else { - mb->m_pkthdr.csum_flags = 0; - priv->port_stats.rx_chksum_none++; - } - - /* Push it up the stack */ - dev->if_input(dev, mb); - -next: - ++cons_index; - index = cons_index & size_mask; - cqe = &buf[CQE_FACTOR_INDEX(index, factor)]; - if (++polled == budget) - goto out; - } - /* Flush all pending IP reassembly sessions */ -out: -#ifdef INET - tcp_lro_flush_all(&ring->lro); -#endif - AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); - mcq->cons_index = cons_index; - mlx4_cq_set_ci(mcq); - wmb(); /* ensure HW sees CQ consumer before we post new buffers */ - ring->cons = mcq->cons_index; - ring->prod += polled; /* Polled descriptors were realocated in place */ - mlx4_en_update_rx_prod_db(ring); - return polled; - -} - -/* Rx CQ polling - called by NAPI */ -static int mlx4_en_poll_rx_cq(struct mlx4_en_cq *cq, int budget) -{ - struct net_device *dev = cq->dev; - int done; - - done = mlx4_en_process_rx_cq(dev, cq, budget); - cq->tot_rx += done; - - return done; - -} -void mlx4_en_rx_irq(struct mlx4_cq *mcq) -{ - struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); - struct mlx4_en_priv *priv = netdev_priv(cq->dev); - int done; - - // Shoot one within the irq context - // Because there is no NAPI in freeBSD - done = mlx4_en_poll_rx_cq(cq, MLX4_EN_RX_BUDGET); - if (priv->port_up && (done == MLX4_EN_RX_BUDGET) ) { - cq->curr_poll_rx_cpu_id = curcpu; - taskqueue_enqueue(cq->tq, &cq->cq_task); - } - else { - mlx4_en_arm_cq(priv, cq); - } -} - -void mlx4_en_rx_que(void *context, int pending) -{ - struct mlx4_en_cq *cq; - struct thread *td; - - cq = context; - td = curthread; - - thread_lock(td); - sched_bind(td, cq->curr_poll_rx_cpu_id); - thread_unlock(td); - - while (mlx4_en_poll_rx_cq(cq, MLX4_EN_RX_BUDGET) - == MLX4_EN_RX_BUDGET); - mlx4_en_arm_cq(cq->dev->if_softc, cq); -} - - -/* RSS related functions */ - -static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, - struct mlx4_en_rx_ring *ring, - enum mlx4_qp_state *state, - struct mlx4_qp *qp) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_qp_context *context; - int err = 0; - - context = kmalloc(sizeof *context , GFP_KERNEL); - if (!context) { - en_err(priv, "Failed to allocate qp context\n"); - return -ENOMEM; - } - - err = mlx4_qp_alloc(mdev->dev, qpn, qp); - if (err) { - en_err(priv, "Failed to allocate qp #%x\n", qpn); - goto out; - } - qp->event = mlx4_en_sqp_event; - - memset(context, 0, sizeof *context); - mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0, - qpn, ring->cqn, -1, context); - context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); - - /* Cancel FCS removal if FW allows */ - if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) { - context->param3 |= cpu_to_be32(1 << 29); - ring->fcs_del = ETH_FCS_LEN; - } else - ring->fcs_del = 0; - - err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state); - if (err) { - mlx4_qp_remove(mdev->dev, qp); - mlx4_qp_free(mdev->dev, qp); - } - mlx4_en_update_rx_prod_db(ring); -out: - kfree(context); - return err; -} - -int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv) -{ - int err; - u32 qpn; - - err = mlx4_qp_reserve_range(priv->mdev->dev, 1, 1, &qpn, 0); - if (err) { - en_err(priv, "Failed reserving drop qpn\n"); - return err; - } - err = mlx4_qp_alloc(priv->mdev->dev, qpn, &priv->drop_qp); - if (err) { - en_err(priv, "Failed allocating drop qp\n"); - mlx4_qp_release_range(priv->mdev->dev, qpn, 1); - return err; - } - - return 0; -} - -void mlx4_en_destroy_drop_qp(struct mlx4_en_priv *priv) -{ - u32 qpn; - - qpn = priv->drop_qp.qpn; - mlx4_qp_remove(priv->mdev->dev, &priv->drop_qp); - mlx4_qp_free(priv->mdev->dev, &priv->drop_qp); - mlx4_qp_release_range(priv->mdev->dev, qpn, 1); -} - -/* Allocate rx qp's and configure them according to rss map */ -int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rss_map *rss_map = &priv->rss_map; - struct mlx4_qp_context context; - struct mlx4_rss_context *rss_context; - int rss_rings; - void *ptr; - u8 rss_mask = (MLX4_RSS_IPV4 | MLX4_RSS_TCP_IPV4 | MLX4_RSS_IPV6 | - MLX4_RSS_TCP_IPV6); - int i; - int err = 0; - int good_qps = 0; - static const u32 rsskey[10] = { 0xD181C62C, 0xF7F4DB5B, 0x1983A2FC, - 0x943E1ADB, 0xD9389E6B, 0xD1039C2C, 0xA74499AD, - 0x593D56D9, 0xF3253C06, 0x2ADC1FFC}; - - en_dbg(DRV, priv, "Configuring rss steering\n"); - err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num, - priv->rx_ring_num, - &rss_map->base_qpn, 0); - if (err) { - en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num); - return err; - } - - for (i = 0; i < priv->rx_ring_num; i++) { - priv->rx_ring[i]->qpn = rss_map->base_qpn + i; - err = mlx4_en_config_rss_qp(priv, priv->rx_ring[i]->qpn, - priv->rx_ring[i], - &rss_map->state[i], - &rss_map->qps[i]); - if (err) - goto rss_err; - - ++good_qps; - } - - /* Configure RSS indirection qp */ - err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); - if (err) { - en_err(priv, "Failed to allocate RSS indirection QP\n"); - goto rss_err; - } - rss_map->indir_qp.event = mlx4_en_sqp_event; - mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, - priv->rx_ring[0]->cqn, -1, &context); - - if (!priv->prof->rss_rings || priv->prof->rss_rings > priv->rx_ring_num) - rss_rings = priv->rx_ring_num; - else - rss_rings = priv->prof->rss_rings; - - ptr = ((u8 *)&context) + offsetof(struct mlx4_qp_context, pri_path) + - MLX4_RSS_OFFSET_IN_QPC_PRI_PATH; - rss_context = ptr; - rss_context->base_qpn = cpu_to_be32(ilog2(rss_rings) << 24 | - (rss_map->base_qpn)); - rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); - if (priv->mdev->profile.udp_rss) { - rss_mask |= MLX4_RSS_UDP_IPV4 | MLX4_RSS_UDP_IPV6; - rss_context->base_qpn_udp = rss_context->default_qpn; - } - rss_context->flags = rss_mask; - rss_context->hash_fn = MLX4_RSS_HASH_TOP; - for (i = 0; i < 10; i++) - rss_context->rss_key[i] = cpu_to_be32(rsskey[i]); - - err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, - &rss_map->indir_qp, &rss_map->indir_state); - if (err) - goto indir_err; - - return 0; - -indir_err: - mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); - mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); - mlx4_qp_free(mdev->dev, &rss_map->indir_qp); -rss_err: - for (i = 0; i < good_qps; i++) { - mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); - mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); - mlx4_qp_free(mdev->dev, &rss_map->qps[i]); - } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); - return err; -} - -void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_rss_map *rss_map = &priv->rss_map; - int i; - - mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); - mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); - mlx4_qp_free(mdev->dev, &rss_map->indir_qp); - - for (i = 0; i < priv->rx_ring_num; i++) { - mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); - mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); - mlx4_qp_free(mdev->dev, &rss_map->qps[i]); - } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); -} - diff --git a/sys/ofed/drivers/net/mlx4/en_tx.c b/sys/ofed/drivers/net/mlx4/en_tx.c deleted file mode 100644 index 9090c51679dd..000000000000 --- a/sys/ofed/drivers/net/mlx4/en_tx.c +++ /dev/null @@ -1,1119 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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. - * - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/page.h> -#include <linux/mlx4/cq.h> -#include <linux/slab.h> -#include <linux/mlx4/qp.h> -#include <linux/if_vlan.h> -#include <linux/vmalloc.h> -#include <linux/moduleparam.h> - -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/if_ether.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> -#include <netinet/tcp.h> -#include <netinet/tcp_lro.h> -#include <netinet/udp.h> - -#include "mlx4_en.h" - -enum { - MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ - MAX_BF = 256, - MIN_PKT_LEN = 17, -}; - -static int inline_thold __read_mostly = MAX_INLINE; - -module_param_named(inline_thold, inline_thold, uint, 0444); -MODULE_PARM_DESC(inline_thold, "threshold for using inline data"); - -int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring, u32 size, - u16 stride, int node, int queue_idx) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_tx_ring *ring; - uint32_t x; - int tmp; - int err; - - ring = kzalloc_node(sizeof(struct mlx4_en_tx_ring), GFP_KERNEL, node); - if (!ring) { - ring = kzalloc(sizeof(struct mlx4_en_tx_ring), GFP_KERNEL); - if (!ring) { - en_err(priv, "Failed allocating TX ring\n"); - return -ENOMEM; - } - } - - /* Create DMA descriptor TAG */ - if ((err = -bus_dma_tag_create( - bus_get_dma_tag(mdev->pdev->dev.bsddev), - 1, /* any alignment */ - 0, /* no boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MLX4_EN_TX_MAX_PAYLOAD_SIZE, /* maxsize */ - MLX4_EN_TX_MAX_MBUF_FRAGS, /* nsegments */ - MLX4_EN_TX_MAX_MBUF_SIZE, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockfuncarg */ - &ring->dma_tag))) - goto done; - - ring->size = size; - ring->size_mask = size - 1; - ring->stride = stride; - ring->inline_thold = MAX(MIN_PKT_LEN, MIN(inline_thold, MAX_INLINE)); - mtx_init(&ring->tx_lock.m, "mlx4 tx", NULL, MTX_DEF); - mtx_init(&ring->comp_lock.m, "mlx4 comp", NULL, MTX_DEF); - - /* Allocate the buf ring */ - ring->br = buf_ring_alloc(MLX4_EN_DEF_TX_QUEUE_SIZE, M_DEVBUF, - M_WAITOK, &ring->tx_lock.m); - if (ring->br == NULL) { - en_err(priv, "Failed allocating tx_info ring\n"); - err = -ENOMEM; - goto err_free_dma_tag; - } - - tmp = size * sizeof(struct mlx4_en_tx_info); - ring->tx_info = kzalloc_node(tmp, GFP_KERNEL, node); - if (!ring->tx_info) { - ring->tx_info = kzalloc(tmp, GFP_KERNEL); - if (!ring->tx_info) { - err = -ENOMEM; - goto err_ring; - } - } - - /* Create DMA descriptor MAPs */ - for (x = 0; x != size; x++) { - err = -bus_dmamap_create(ring->dma_tag, 0, - &ring->tx_info[x].dma_map); - if (err != 0) { - while (x--) { - bus_dmamap_destroy(ring->dma_tag, - ring->tx_info[x].dma_map); - } - goto err_info; - } - } - - en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", - ring->tx_info, tmp); - - ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE); - - /* Allocate HW buffers on provided NUMA node */ - err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, - 2 * PAGE_SIZE); - if (err) { - en_err(priv, "Failed allocating hwq resources\n"); - goto err_dma_map; - } - - err = mlx4_en_map_buffer(&ring->wqres.buf); - if (err) { - en_err(priv, "Failed to map TX buffer\n"); - goto err_hwq_res; - } - - ring->buf = ring->wqres.buf.direct.buf; - - en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " - "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, - ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); - - err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn, - MLX4_RESERVE_BF_QP); - if (err) { - en_err(priv, "failed reserving qp for TX ring\n"); - goto err_map; - } - - err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); - if (err) { - en_err(priv, "Failed allocating qp %d\n", ring->qpn); - goto err_reserve; - } - ring->qp.event = mlx4_en_sqp_event; - - err = mlx4_bf_alloc(mdev->dev, &ring->bf, node); - if (err) { - en_dbg(DRV, priv, "working without blueflame (%d)", err); - ring->bf.uar = &mdev->priv_uar; - ring->bf.uar->map = mdev->uar_map; - ring->bf_enabled = false; - } else - ring->bf_enabled = true; - ring->queue_index = queue_idx; - if (queue_idx < priv->num_tx_rings_p_up ) - CPU_SET(queue_idx, &ring->affinity_mask); - - *pring = ring; - return 0; - -err_reserve: - mlx4_qp_release_range(mdev->dev, ring->qpn, 1); -err_map: - mlx4_en_unmap_buffer(&ring->wqres.buf); -err_hwq_res: - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); -err_dma_map: - for (x = 0; x != size; x++) - bus_dmamap_destroy(ring->dma_tag, ring->tx_info[x].dma_map); -err_info: - vfree(ring->tx_info); -err_ring: - buf_ring_free(ring->br, M_DEVBUF); -err_free_dma_tag: - bus_dma_tag_destroy(ring->dma_tag); -done: - kfree(ring); - return err; -} - -void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring) -{ - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_en_tx_ring *ring = *pring; - uint32_t x; - en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); - - buf_ring_free(ring->br, M_DEVBUF); - if (ring->bf_enabled) - mlx4_bf_free(mdev->dev, &ring->bf); - mlx4_qp_remove(mdev->dev, &ring->qp); - mlx4_qp_free(mdev->dev, &ring->qp); - mlx4_qp_release_range(priv->mdev->dev, ring->qpn, 1); - mlx4_en_unmap_buffer(&ring->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); - for (x = 0; x != ring->size; x++) - bus_dmamap_destroy(ring->dma_tag, ring->tx_info[x].dma_map); - vfree(ring->tx_info); - mtx_destroy(&ring->tx_lock.m); - mtx_destroy(&ring->comp_lock.m); - bus_dma_tag_destroy(ring->dma_tag); - kfree(ring); - *pring = NULL; -} - -int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, - int cq, int user_prio) -{ - struct mlx4_en_dev *mdev = priv->mdev; - int err; - - ring->cqn = cq; - ring->prod = 0; - ring->cons = 0xffffffff; - ring->last_nr_txbb = 1; - ring->poll_cnt = 0; - ring->blocked = 0; - memset(ring->buf, 0, ring->buf_size); - - ring->qp_state = MLX4_QP_STATE_RST; - ring->doorbell_qpn = ring->qp.qpn << 8; - - mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, - ring->cqn, user_prio, &ring->context); - if (ring->bf_enabled) - ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); - - err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, - &ring->qp, &ring->qp_state); - return err; -} - -void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring) -{ - struct mlx4_en_dev *mdev = priv->mdev; - - mlx4_qp_modify(mdev->dev, NULL, ring->qp_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp); -} - -static volatile struct mlx4_wqe_data_seg * -mlx4_en_store_inline_lso_data(volatile struct mlx4_wqe_data_seg *dseg, - struct mbuf *mb, int len, __be32 owner_bit) -{ - uint8_t *inl = __DEVOLATILE(uint8_t *, dseg); - - /* copy data into place */ - m_copydata(mb, 0, len, inl + 4); - dseg += DIV_ROUND_UP(4 + len, DS_SIZE_ALIGNMENT); - return (dseg); -} - -static void -mlx4_en_store_inline_lso_header(volatile struct mlx4_wqe_data_seg *dseg, - int len, __be32 owner_bit) -{ -} - -static void -mlx4_en_stamp_wqe(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 index, u8 owner) -{ - struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; - struct mlx4_en_tx_desc *tx_desc = (struct mlx4_en_tx_desc *) - (ring->buf + (index * TXBB_SIZE)); - volatile __be32 *ptr = (__be32 *)tx_desc; - const __be32 stamp = cpu_to_be32(STAMP_VAL | - ((u32)owner << STAMP_SHIFT)); - u32 i; - - /* Stamp the freed descriptor */ - for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { - *ptr = stamp; - ptr += STAMP_DWORDS; - } -} - -static u32 -mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 index) -{ - struct mlx4_en_tx_info *tx_info; - struct mbuf *mb; - - tx_info = &ring->tx_info[index]; - mb = tx_info->mb; - - if (mb == NULL) - goto done; - - bus_dmamap_sync(ring->dma_tag, tx_info->dma_map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(ring->dma_tag, tx_info->dma_map); - - m_freem(mb); -done: - return (tx_info->nr_txbb); -} - -int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int cnt = 0; - - /* Skip last polled descriptor */ - ring->cons += ring->last_nr_txbb; - en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", - ring->cons, ring->prod); - - if ((u32) (ring->prod - ring->cons) > ring->size) { - en_warn(priv, "Tx consumer passed producer!\n"); - return 0; - } - - while (ring->cons != ring->prod) { - ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring, - ring->cons & ring->size_mask); - ring->cons += ring->last_nr_txbb; - cnt++; - } - - if (cnt) - en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); - - return cnt; -} - -static bool -mlx4_en_tx_ring_is_full(struct mlx4_en_tx_ring *ring) -{ - int wqs; - wqs = ring->size - (ring->prod - ring->cons); - return (wqs < (HEADROOM + (2 * MLX4_EN_TX_WQE_MAX_WQEBBS))); -} - -static int mlx4_en_process_tx_cq(struct net_device *dev, - struct mlx4_en_cq *cq) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_cq *mcq = &cq->mcq; - struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->ring]; - struct mlx4_cqe *cqe; - u16 index; - u16 new_index, ring_index, stamp_index; - u32 txbbs_skipped = 0; - u32 txbbs_stamp = 0; - u32 cons_index = mcq->cons_index; - int size = cq->size; - u32 size_mask = ring->size_mask; - struct mlx4_cqe *buf = cq->buf; - int factor = priv->cqe_factor; - - if (!priv->port_up) - return 0; - - index = cons_index & size_mask; - cqe = &buf[(index << factor) + factor]; - ring_index = ring->cons & size_mask; - stamp_index = ring_index; - - /* Process all completed CQEs */ - while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, - cons_index & size)) { - /* - * make sure we read the CQE after we read the - * ownership bit - */ - rmb(); - - if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == - MLX4_CQE_OPCODE_ERROR)) { - en_err(priv, "CQE completed in error - vendor syndrom: 0x%x syndrom: 0x%x\n", - ((struct mlx4_err_cqe *)cqe)-> - vendor_err_syndrome, - ((struct mlx4_err_cqe *)cqe)->syndrome); - } - - /* Skip over last polled CQE */ - new_index = be16_to_cpu(cqe->wqe_index) & size_mask; - - do { - txbbs_skipped += ring->last_nr_txbb; - ring_index = (ring_index + ring->last_nr_txbb) & size_mask; - /* free next descriptor */ - ring->last_nr_txbb = mlx4_en_free_tx_desc( - priv, ring, ring_index); - mlx4_en_stamp_wqe(priv, ring, stamp_index, - !!((ring->cons + txbbs_stamp) & - ring->size)); - stamp_index = ring_index; - txbbs_stamp = txbbs_skipped; - } while (ring_index != new_index); - - ++cons_index; - index = cons_index & size_mask; - cqe = &buf[(index << factor) + factor]; - } - - - /* - * To prevent CQ overflow we first update CQ consumer and only then - * the ring consumer. - */ - mcq->cons_index = cons_index; - mlx4_cq_set_ci(mcq); - wmb(); - ring->cons += txbbs_skipped; - - /* Wakeup Tx queue if it was stopped and ring is not full */ - if (unlikely(ring->blocked) && !mlx4_en_tx_ring_is_full(ring)) { - ring->blocked = 0; - if (atomic_fetchadd_int(&priv->blocked, -1) == 1) - atomic_clear_int(&dev->if_drv_flags ,IFF_DRV_OACTIVE); - ring->wake_queue++; - priv->port_stats.wake_queue++; - } - return (0); -} - -void mlx4_en_tx_irq(struct mlx4_cq *mcq) -{ - struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); - struct mlx4_en_priv *priv = netdev_priv(cq->dev); - struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->ring]; - - if (priv->port_up == 0 || !spin_trylock(&ring->comp_lock)) - return; - mlx4_en_process_tx_cq(cq->dev, cq); - mod_timer(&cq->timer, jiffies + 1); - spin_unlock(&ring->comp_lock); -} - -void mlx4_en_poll_tx_cq(unsigned long data) -{ - struct mlx4_en_cq *cq = (struct mlx4_en_cq *) data; - struct mlx4_en_priv *priv = netdev_priv(cq->dev); - struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->ring]; - u32 inflight; - - INC_PERF_COUNTER(priv->pstats.tx_poll); - - if (priv->port_up == 0) - return; - if (!spin_trylock(&ring->comp_lock)) { - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - return; - } - mlx4_en_process_tx_cq(cq->dev, cq); - inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb); - - /* If there are still packets in flight and the timer has not already - * been scheduled by the Tx routine then schedule it here to guarantee - * completion processing of these packets */ - if (inflight && priv->port_up) - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - - spin_unlock(&ring->comp_lock); -} - -static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) -{ - struct mlx4_en_cq *cq = priv->tx_cq[tx_ind]; - struct mlx4_en_tx_ring *ring = priv->tx_ring[tx_ind]; - - if (priv->port_up == 0) - return; - - /* If we don't have a pending timer, set one up to catch our recent - post in case the interface becomes idle */ - if (!timer_pending(&cq->timer)) - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - - /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ - if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) - if (spin_trylock(&ring->comp_lock)) { - mlx4_en_process_tx_cq(priv->dev, cq); - spin_unlock(&ring->comp_lock); - } -} - -static u16 -mlx4_en_get_inline_hdr_size(struct mlx4_en_tx_ring *ring, struct mbuf *mb) -{ - u16 retval; - - /* only copy from first fragment, if possible */ - retval = MIN(ring->inline_thold, mb->m_len); - - /* check for too little data */ - if (unlikely(retval < MIN_PKT_LEN)) - retval = MIN(ring->inline_thold, mb->m_pkthdr.len); - return (retval); -} - -static int -mlx4_en_get_header_size(struct mbuf *mb) -{ - struct ether_vlan_header *eh; - struct tcphdr *th; - struct ip *ip; - int ip_hlen, tcp_hlen; - struct ip6_hdr *ip6; - uint16_t eth_type; - int eth_hdr_len; - - eh = mtod(mb, struct ether_vlan_header *); - if (mb->m_len < ETHER_HDR_LEN) - return (0); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - eth_type = ntohs(eh->evl_proto); - eth_hdr_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - eth_type = ntohs(eh->evl_encap_proto); - eth_hdr_len = ETHER_HDR_LEN; - } - if (mb->m_len < eth_hdr_len) - return (0); - switch (eth_type) { - case ETHERTYPE_IP: - ip = (struct ip *)(mb->m_data + eth_hdr_len); - if (mb->m_len < eth_hdr_len + sizeof(*ip)) - return (0); - if (ip->ip_p != IPPROTO_TCP) - return (0); - ip_hlen = ip->ip_hl << 2; - eth_hdr_len += ip_hlen; - break; - case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mb->m_data + eth_hdr_len); - if (mb->m_len < eth_hdr_len + sizeof(*ip6)) - return (0); - if (ip6->ip6_nxt != IPPROTO_TCP) - return (0); - eth_hdr_len += sizeof(*ip6); - break; - default: - return (0); - } - if (mb->m_len < eth_hdr_len + sizeof(*th)) - return (0); - th = (struct tcphdr *)(mb->m_data + eth_hdr_len); - tcp_hlen = th->th_off << 2; - eth_hdr_len += tcp_hlen; - if (mb->m_len < eth_hdr_len) - return (0); - return (eth_hdr_len); -} - -static volatile struct mlx4_wqe_data_seg * -mlx4_en_store_inline_data(volatile struct mlx4_wqe_data_seg *dseg, - struct mbuf *mb, int len, __be32 owner_bit) -{ - uint8_t *inl = __DEVOLATILE(uint8_t *, dseg); - const int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - 4; - - if (unlikely(len < MIN_PKT_LEN)) { - m_copydata(mb, 0, len, inl + 4); - memset(inl + 4 + len, 0, MIN_PKT_LEN - len); - dseg += DIV_ROUND_UP(4 + MIN_PKT_LEN, DS_SIZE_ALIGNMENT); - } else if (len <= spc) { - m_copydata(mb, 0, len, inl + 4); - dseg += DIV_ROUND_UP(4 + len, DS_SIZE_ALIGNMENT); - } else { - m_copydata(mb, 0, spc, inl + 4); - m_copydata(mb, spc, len - spc, inl + 8 + spc); - dseg += DIV_ROUND_UP(8 + len, DS_SIZE_ALIGNMENT); - } - return (dseg); -} - -static void -mlx4_en_store_inline_header(volatile struct mlx4_wqe_data_seg *dseg, - int len, __be32 owner_bit) -{ - uint8_t *inl = __DEVOLATILE(uint8_t *, dseg); - const int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - 4; - - if (unlikely(len < MIN_PKT_LEN)) { - *(volatile uint32_t *)inl = - SET_BYTE_COUNT((1 << 31) | MIN_PKT_LEN); - } else if (len <= spc) { - *(volatile uint32_t *)inl = - SET_BYTE_COUNT((1 << 31) | len); - } else { - *(volatile uint32_t *)(inl + 4 + spc) = - SET_BYTE_COUNT((1 << 31) | (len - spc)); - wmb(); - *(volatile uint32_t *)inl = - SET_BYTE_COUNT((1 << 31) | spc); - } -} - -static uint32_t hashrandom; -static void hashrandom_init(void *arg) -{ - /* - * It is assumed that the random subsystem has been - * initialized when this function is called: - */ - hashrandom = m_ether_tcpip_hash_init(); -} -SYSINIT(hashrandom_init, SI_SUB_RANDOM, SI_ORDER_ANY, &hashrandom_init, NULL); - -u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - u32 rings_p_up = priv->num_tx_rings_p_up; - u32 up = 0; - u32 queue_index; - -#if (MLX4_EN_NUM_UP > 1) - /* Obtain VLAN information if present */ - if (mb->m_flags & M_VLANTAG) { - u32 vlan_tag = mb->m_pkthdr.ether_vtag; - up = (vlan_tag >> 13) % MLX4_EN_NUM_UP; - } -#endif - queue_index = m_ether_tcpip_hash(MBUF_HASHFLAG_L3 | MBUF_HASHFLAG_L4, mb, hashrandom); - - return ((queue_index % rings_p_up) + (up * rings_p_up)); -} - -static void mlx4_bf_copy(void __iomem *dst, volatile unsigned long *src, unsigned bytecnt) -{ - __iowrite64_copy(dst, __DEVOLATILE(void *, src), bytecnt / 8); -} - -static u64 mlx4_en_mac_to_u64(u8 *addr) -{ - u64 mac = 0; - int i; - - for (i = 0; i < ETHER_ADDR_LEN; i++) { - mac <<= 8; - mac |= addr[i]; - } - return mac; -} - -static int mlx4_en_xmit(struct mlx4_en_priv *priv, int tx_ind, struct mbuf **mbp) -{ - enum { - DS_FACT = TXBB_SIZE / DS_SIZE_ALIGNMENT, - CTRL_FLAGS = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | - MLX4_WQE_CTRL_SOLICITED), - }; - bus_dma_segment_t segs[MLX4_EN_TX_MAX_MBUF_FRAGS]; - volatile struct mlx4_wqe_data_seg *dseg; - volatile struct mlx4_wqe_data_seg *dseg_inline; - volatile struct mlx4_en_tx_desc *tx_desc; - struct mlx4_en_tx_ring *ring = priv->tx_ring[tx_ind]; - struct ifnet *ifp = priv->dev; - struct mlx4_en_tx_info *tx_info; - struct mbuf *mb = *mbp; - struct mbuf *m; - __be32 owner_bit; - int nr_segs; - int pad; - int err; - u32 bf_size; - u32 bf_prod; - u32 opcode; - u16 index; - u16 ds_cnt; - u16 ihs; - - if (unlikely(!priv->port_up)) { - err = EINVAL; - goto tx_drop; - } - - /* check if TX ring is full */ - if (unlikely(mlx4_en_tx_ring_is_full(ring))) { - /* every full native Tx ring stops queue */ - if (ring->blocked == 0) - atomic_add_int(&priv->blocked, 1); - /* Set HW-queue-is-full flag */ - atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); - priv->port_stats.queue_stopped++; - ring->blocked = 1; - priv->port_stats.queue_stopped++; - ring->queue_stopped++; - - /* Use interrupts to find out when queue opened */ - mlx4_en_arm_cq(priv, priv->tx_cq[tx_ind]); - return (ENOBUFS); - } - - /* sanity check we are not wrapping around */ - KASSERT(((~ring->prod) & ring->size_mask) >= - (MLX4_EN_TX_WQE_MAX_WQEBBS - 1), ("Wrapping around TX ring")); - - /* Track current inflight packets for performance analysis */ - AVG_PERF_COUNTER(priv->pstats.inflight_avg, - (u32) (ring->prod - ring->cons - 1)); - - /* Track current mbuf packet header length */ - AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, mb->m_pkthdr.len); - - /* Grab an index and try to transmit packet */ - owner_bit = (ring->prod & ring->size) ? - cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0; - index = ring->prod & ring->size_mask; - tx_desc = (volatile struct mlx4_en_tx_desc *) - (ring->buf + index * TXBB_SIZE); - tx_info = &ring->tx_info[index]; - dseg = &tx_desc->data; - - /* send a copy of the frame to the BPF listener, if any */ - if (ifp != NULL && ifp->if_bpf != NULL) - ETHER_BPF_MTAP(ifp, mb); - - /* get default flags */ - tx_desc->ctrl.srcrb_flags = CTRL_FLAGS; - - if (mb->m_pkthdr.csum_flags & (CSUM_IP | CSUM_TSO)) - tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM); - - if (mb->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP | - CSUM_UDP_IPV6 | CSUM_TCP_IPV6 | CSUM_TSO)) - tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_TCP_UDP_CSUM); - - /* do statistics */ - if (likely(tx_desc->ctrl.srcrb_flags != CTRL_FLAGS)) { - priv->port_stats.tx_chksum_offload++; - ring->tx_csum++; - } - - /* check for VLAN tag */ - if (mb->m_flags & M_VLANTAG) { - tx_desc->ctrl.vlan_tag = cpu_to_be16(mb->m_pkthdr.ether_vtag); - tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN; - } else { - tx_desc->ctrl.vlan_tag = 0; - tx_desc->ctrl.ins_vlan = 0; - } - - /* clear immediate field */ - tx_desc->ctrl.imm = 0; - - /* Handle LSO (TSO) packets */ - if (mb->m_pkthdr.csum_flags & CSUM_TSO) { - u32 payload_len; - u32 mss = mb->m_pkthdr.tso_segsz; - u32 num_pkts; - - opcode = cpu_to_be32(MLX4_OPCODE_LSO | MLX4_WQE_CTRL_RR) | - owner_bit; - ihs = mlx4_en_get_header_size(mb); - if (unlikely(ihs > MAX_INLINE)) { - ring->oversized_packets++; - err = EINVAL; - goto tx_drop; - } - tx_desc->lso.mss_hdr_size = cpu_to_be32((mss << 16) | ihs); - payload_len = mb->m_pkthdr.len - ihs; - if (unlikely(payload_len == 0)) - num_pkts = 1; - else - num_pkts = DIV_ROUND_UP(payload_len, mss); - ring->bytes += payload_len + (num_pkts * ihs); - ring->packets += num_pkts; - priv->port_stats.tso_packets++; - /* store pointer to inline header */ - dseg_inline = dseg; - /* copy data inline */ - dseg = mlx4_en_store_inline_lso_data(dseg, - mb, ihs, owner_bit); - } else { - opcode = cpu_to_be32(MLX4_OPCODE_SEND) | - owner_bit; - ihs = mlx4_en_get_inline_hdr_size(ring, mb); - ring->bytes += max_t (unsigned int, - mb->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN); - ring->packets++; - /* store pointer to inline header */ - dseg_inline = dseg; - /* copy data inline */ - dseg = mlx4_en_store_inline_data(dseg, - mb, ihs, owner_bit); - } - m_adj(mb, ihs); - - /* trim off empty mbufs */ - while (mb->m_len == 0) { - mb = m_free(mb); - /* check if all data has been inlined */ - if (mb == NULL) { - nr_segs = 0; - goto skip_dma; - } - } - - err = bus_dmamap_load_mbuf_sg(ring->dma_tag, tx_info->dma_map, - mb, segs, &nr_segs, BUS_DMA_NOWAIT); - if (unlikely(err == EFBIG)) { - /* Too many mbuf fragments */ - m = m_defrag(mb, M_NOWAIT); - if (m == NULL) { - ring->oversized_packets++; - goto tx_drop; - } - mb = m; - /* Try again */ - err = bus_dmamap_load_mbuf_sg(ring->dma_tag, tx_info->dma_map, - mb, segs, &nr_segs, BUS_DMA_NOWAIT); - } - /* catch errors */ - if (unlikely(err != 0)) { - ring->oversized_packets++; - goto tx_drop; - } - /* make sure all mbuf data is written to RAM */ - bus_dmamap_sync(ring->dma_tag, tx_info->dma_map, - BUS_DMASYNC_PREWRITE); - -skip_dma: - /* compute number of DS needed */ - ds_cnt = (dseg - ((volatile struct mlx4_wqe_data_seg *)tx_desc)) + nr_segs; - - /* - * Check if the next request can wrap around and fill the end - * of the current request with zero immediate data: - */ - pad = DIV_ROUND_UP(ds_cnt, DS_FACT); - pad = (~(ring->prod + pad)) & ring->size_mask; - - if (unlikely(pad < (MLX4_EN_TX_WQE_MAX_WQEBBS - 1))) { - /* - * Compute the least number of DS blocks we need to - * pad in order to achieve a TX ring wraparound: - */ - pad = (DS_FACT * (pad + 1)); - } else { - /* - * The hardware will automatically jump to the next - * TXBB. No need for padding. - */ - pad = 0; - } - - /* compute total number of DS blocks */ - ds_cnt += pad; - /* - * When modifying this code, please ensure that the following - * computation is always less than or equal to 0x3F: - * - * ((MLX4_EN_TX_WQE_MAX_WQEBBS - 1) * DS_FACT) + - * (MLX4_EN_TX_WQE_MAX_WQEBBS * DS_FACT) - * - * Else the "ds_cnt" variable can become too big. - */ - tx_desc->ctrl.fence_size = (ds_cnt & 0x3f); - - /* store pointer to mbuf */ - tx_info->mb = mb; - tx_info->nr_txbb = DIV_ROUND_UP(ds_cnt, DS_FACT); - bf_size = ds_cnt * DS_SIZE_ALIGNMENT; - bf_prod = ring->prod; - - /* compute end of "dseg" array */ - dseg += nr_segs + pad; - - /* pad using zero immediate dseg */ - while (pad--) { - dseg--; - dseg->addr = 0; - dseg->lkey = 0; - wmb(); - dseg->byte_count = SET_BYTE_COUNT((1 << 31)|0); - } - - /* fill segment list */ - while (nr_segs--) { - if (unlikely(segs[nr_segs].ds_len == 0)) { - dseg--; - dseg->addr = 0; - dseg->lkey = 0; - wmb(); - dseg->byte_count = SET_BYTE_COUNT((1 << 31)|0); - } else { - dseg--; - dseg->addr = cpu_to_be64((uint64_t)segs[nr_segs].ds_addr); - dseg->lkey = cpu_to_be32(priv->mdev->mr.key); - wmb(); - dseg->byte_count = SET_BYTE_COUNT((uint32_t)segs[nr_segs].ds_len); - } - } - - wmb(); - - /* write owner bits in reverse order */ - if ((opcode & cpu_to_be32(0x1F)) == cpu_to_be32(MLX4_OPCODE_LSO)) - mlx4_en_store_inline_lso_header(dseg_inline, ihs, owner_bit); - else - mlx4_en_store_inline_header(dseg_inline, ihs, owner_bit); - - if (unlikely(priv->validate_loopback)) { - /* Copy dst mac address to wqe */ - struct ether_header *ethh; - u64 mac; - u32 mac_l, mac_h; - - ethh = mtod(mb, struct ether_header *); - mac = mlx4_en_mac_to_u64(ethh->ether_dhost); - if (mac) { - mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16); - mac_l = (u32) (mac & 0xffffffff); - tx_desc->ctrl.srcrb_flags |= cpu_to_be32(mac_h); - tx_desc->ctrl.imm = cpu_to_be32(mac_l); - } - } - - /* update producer counter */ - ring->prod += tx_info->nr_txbb; - - if (ring->bf_enabled && bf_size <= MAX_BF && - (tx_desc->ctrl.ins_vlan != MLX4_WQE_CTRL_INS_VLAN)) { - - /* store doorbell number */ - *(volatile __be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn); - - /* or in producer number for this WQE */ - opcode |= cpu_to_be32((bf_prod & 0xffff) << 8); - - /* - * Ensure the new descriptor hits memory before - * setting ownership of this descriptor to HW: - */ - wmb(); - tx_desc->ctrl.owner_opcode = opcode; - wmb(); - mlx4_bf_copy(((u8 *)ring->bf.reg) + ring->bf.offset, - (volatile unsigned long *) &tx_desc->ctrl, bf_size); - wmb(); - ring->bf.offset ^= ring->bf.buf_size; - } else { - /* - * Ensure the new descriptor hits memory before - * setting ownership of this descriptor to HW: - */ - wmb(); - tx_desc->ctrl.owner_opcode = opcode; - wmb(); - writel(cpu_to_be32(ring->doorbell_qpn), - ((u8 *)ring->bf.uar->map) + MLX4_SEND_DOORBELL); - } - - return (0); -tx_drop: - *mbp = NULL; - m_freem(mb); - return (err); -} - -static int -mlx4_en_transmit_locked(struct ifnet *dev, int tx_ind, struct mbuf *m) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_tx_ring *ring; - struct mbuf *next; - int enqueued, err = 0; - - ring = priv->tx_ring[tx_ind]; - if ((dev->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != - IFF_DRV_RUNNING || priv->port_up == 0) { - if (m != NULL) - err = drbr_enqueue(dev, ring->br, m); - return (err); - } - - enqueued = 0; - if (m != NULL) - /* - * If we can't insert mbuf into drbr, try to xmit anyway. - * We keep the error we got so we could return that after xmit. - */ - err = drbr_enqueue(dev, ring->br, m); - - /* Process the queue */ - while ((next = drbr_peek(dev, ring->br)) != NULL) { - if (mlx4_en_xmit(priv, tx_ind, &next) != 0) { - if (next == NULL) { - drbr_advance(dev, ring->br); - } else { - drbr_putback(dev, ring->br, next); - } - break; - } - drbr_advance(dev, ring->br); - enqueued++; - if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) - break; - } - - if (enqueued > 0) - ring->watchdog_time = ticks; - - return (err); -} - -void -mlx4_en_tx_que(void *context, int pending) -{ - struct mlx4_en_tx_ring *ring; - struct mlx4_en_priv *priv; - struct net_device *dev; - struct mlx4_en_cq *cq; - int tx_ind; - cq = context; - dev = cq->dev; - priv = dev->if_softc; - tx_ind = cq->ring; - ring = priv->tx_ring[tx_ind]; - - if (priv->port_up != 0 && - (dev->if_drv_flags & IFF_DRV_RUNNING) != 0) { - mlx4_en_xmit_poll(priv, tx_ind); - spin_lock(&ring->tx_lock); - if (!drbr_empty(dev, ring->br)) - mlx4_en_transmit_locked(dev, tx_ind, NULL); - spin_unlock(&ring->tx_lock); - } -} - -int -mlx4_en_transmit(struct ifnet *dev, struct mbuf *m) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_tx_ring *ring; - struct mlx4_en_cq *cq; - int i, err = 0; - - if (priv->port_up == 0) { - m_freem(m); - return (ENETDOWN); - } - - /* Compute which queue to use */ - if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { - i = (m->m_pkthdr.flowid % 128) % priv->tx_ring_num; - } - else { - i = mlx4_en_select_queue(dev, m); - } - - ring = priv->tx_ring[i]; - if (spin_trylock(&ring->tx_lock)) { - err = mlx4_en_transmit_locked(dev, i, m); - spin_unlock(&ring->tx_lock); - /* Poll CQ here */ - mlx4_en_xmit_poll(priv, i); - } else { - err = drbr_enqueue(dev, ring->br, m); - cq = priv->tx_cq[i]; - taskqueue_enqueue(cq->tq, &cq->cq_task); - } - - return (err); -} - -/* - * Flush ring buffers. - */ -void -mlx4_en_qflush(struct ifnet *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_tx_ring *ring; - struct mbuf *m; - - if (priv->port_up == 0) - return; - - for (int i = 0; i < priv->tx_ring_num; i++) { - ring = priv->tx_ring[i]; - spin_lock(&ring->tx_lock); - while ((m = buf_ring_dequeue_sc(ring->br)) != NULL) - m_freem(m); - spin_unlock(&ring->tx_lock); - } - if_qflush(dev); -} diff --git a/sys/ofed/drivers/net/mlx4/eq.c b/sys/ofed/drivers/net/mlx4/eq.c deleted file mode 100644 index 145b9bc55909..000000000000 --- a/sys/ofed/drivers/net/mlx4/eq.c +++ /dev/null @@ -1,1406 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. 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/interrupt.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/dma-mapping.h> - -#include <linux/mlx4/cmd.h> - -#include "mlx4.h" -#include "fw.h" - -enum { - MLX4_IRQNAME_SIZE = 32 -}; - -enum { - MLX4_NUM_ASYNC_EQE = 0x100, - MLX4_NUM_SPARE_EQE = 0x80, - MLX4_EQ_ENTRY_SIZE = 0x20 -}; - -#define MLX4_EQ_STATUS_OK ( 0 << 28) -#define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28) -#define MLX4_EQ_OWNER_SW ( 0 << 24) -#define MLX4_EQ_OWNER_HW ( 1 << 24) -#define MLX4_EQ_FLAG_EC ( 1 << 18) -#define MLX4_EQ_FLAG_OI ( 1 << 17) -#define MLX4_EQ_STATE_ARMED ( 9 << 8) -#define MLX4_EQ_STATE_FIRED (10 << 8) -#define MLX4_EQ_STATE_ALWAYS_ARMED (11 << 8) - -#define MLX4_ASYNC_EVENT_MASK ((1ull << MLX4_EVENT_TYPE_PATH_MIG) | \ - (1ull << MLX4_EVENT_TYPE_COMM_EST) | \ - (1ull << MLX4_EVENT_TYPE_SQ_DRAINED) | \ - (1ull << MLX4_EVENT_TYPE_CQ_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_WQ_CATAS_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_EEC_CATAS_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \ - (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \ - (1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \ - (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \ - (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ - (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ - (1ull << MLX4_EVENT_TYPE_CMD) | \ - (1ull << MLX4_EVENT_TYPE_OP_REQUIRED) | \ - (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL) | \ - (1ull << MLX4_EVENT_TYPE_FLR_EVENT) | \ - (1ull << MLX4_EVENT_TYPE_FATAL_WARNING)) - -static u64 get_async_ev_mask(struct mlx4_dev *dev) -{ - u64 async_ev_mask = MLX4_ASYNC_EVENT_MASK; - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) - async_ev_mask |= (1ull << MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT); - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) - async_ev_mask |= (1ull << MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT); - - return async_ev_mask; -} - -static void eq_set_ci(struct mlx4_eq *eq, int req_not) -{ - __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) | - req_not << 31), - eq->doorbell); - /* We still want ordering, just not swabbing, so add a barrier */ - mb(); -} - -static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry, u8 eqe_factor) -{ - /* (entry & (eq->nent - 1)) gives us a cyclic array */ - unsigned long offset = (entry & (eq->nent - 1)) * (MLX4_EQ_ENTRY_SIZE << eqe_factor); - /* CX3 is capable of extending the EQE from 32 to 64 bytes. - * When this feature is enabled, the first (in the lower addresses) - * 32 bytes in the 64 byte EQE are reserved and the next 32 bytes - * contain the legacy EQE information. - */ - return eq->page_list[offset / PAGE_SIZE].buf + (offset + (eqe_factor ? MLX4_EQ_ENTRY_SIZE : 0)) % PAGE_SIZE; -} - -static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq, u8 eqe_factor) -{ - struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index, eqe_factor); - return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe; -} - -static struct mlx4_eqe *next_slave_event_eqe(struct mlx4_slave_event_eq *slave_eq) -{ - struct mlx4_eqe *eqe = - &slave_eq->event_eqe[slave_eq->cons & (SLAVE_EVENT_EQ_SIZE - 1)]; - return (!!(eqe->owner & 0x80) ^ - !!(slave_eq->cons & SLAVE_EVENT_EQ_SIZE)) ? - eqe : NULL; -} - -void mlx4_gen_slave_eqe(struct work_struct *work) -{ - struct mlx4_mfunc_master_ctx *master = - container_of(work, struct mlx4_mfunc_master_ctx, - slave_event_work); - struct mlx4_mfunc *mfunc = - container_of(master, struct mlx4_mfunc, master); - struct mlx4_priv *priv = container_of(mfunc, struct mlx4_priv, mfunc); - struct mlx4_dev *dev = &priv->dev; - struct mlx4_slave_event_eq *slave_eq = &mfunc->master.slave_eq; - struct mlx4_eqe *eqe; - u8 slave; - int i; - - for (eqe = next_slave_event_eqe(slave_eq); eqe; - eqe = next_slave_event_eqe(slave_eq)) { - slave = eqe->slave_id; - - /* All active slaves need to receive the event */ - if (slave == ALL_SLAVES) { - for (i = 0; i < dev->num_slaves; i++) { - if (mlx4_GEN_EQE(dev, i, eqe)) - mlx4_warn(dev, "Failed to generate " - "event for slave %d\n", i); - } - } else { - if (mlx4_GEN_EQE(dev, slave, eqe)) - mlx4_warn(dev, "Failed to generate event " - "for slave %d\n", slave); - } - ++slave_eq->cons; - } -} - - -static void slave_event(struct mlx4_dev *dev, u8 slave, struct mlx4_eqe *eqe) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_event_eq *slave_eq = &priv->mfunc.master.slave_eq; - struct mlx4_eqe *s_eqe; - unsigned long flags; - - spin_lock_irqsave(&slave_eq->event_lock, flags); - s_eqe = &slave_eq->event_eqe[slave_eq->prod & (SLAVE_EVENT_EQ_SIZE - 1)]; - if ((!!(s_eqe->owner & 0x80)) ^ - (!!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE))) { - mlx4_warn(dev, "Master failed to generate an EQE for slave: %d. " - "No free EQE on slave events queue\n", slave); - spin_unlock_irqrestore(&slave_eq->event_lock, flags); - return; - } - - memcpy(s_eqe, eqe, dev->caps.eqe_size - 1); - s_eqe->slave_id = slave; - /* ensure all information is written before setting the ownersip bit */ - wmb(); - s_eqe->owner = !!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE) ? 0x0 : 0x80; - ++slave_eq->prod; - - queue_work(priv->mfunc.master.comm_wq, - &priv->mfunc.master.slave_event_work); - spin_unlock_irqrestore(&slave_eq->event_lock, flags); -} - -static void mlx4_slave_event(struct mlx4_dev *dev, int slave, - struct mlx4_eqe *eqe) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (slave < 0 || slave >= dev->num_slaves || - slave == dev->caps.function) - return; - - if (!priv->mfunc.master.slave_state[slave].active) - return; - - slave_event(dev, slave, eqe); -} - -int mlx4_gen_pkey_eqe(struct mlx4_dev *dev, int slave, u8 port) -{ - struct mlx4_eqe eqe; - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_slave = &priv->mfunc.master.slave_state[slave]; - - if (!s_slave->active) - return 0; - - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; - eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE; - eqe.event.port_mgmt_change.port = port; - - return mlx4_GEN_EQE(dev, slave, &eqe); -} -EXPORT_SYMBOL(mlx4_gen_pkey_eqe); - -int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port) -{ - struct mlx4_eqe eqe; - - /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) - return 0; - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; - eqe.subtype = MLX4_DEV_PMC_SUBTYPE_GUID_INFO; - eqe.event.port_mgmt_change.port = port; - - return mlx4_GEN_EQE(dev, slave, &eqe); -} -EXPORT_SYMBOL(mlx4_gen_guid_change_eqe); - -int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port, - u8 port_subtype_change) -{ - struct mlx4_eqe eqe; - - /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) - return 0; - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_CHANGE; - eqe.subtype = port_subtype_change; - eqe.event.port_change.port = cpu_to_be32(port << 28); - - mlx4_dbg(dev, "%s: sending: %d to slave: %d on port: %d\n", __func__, - port_subtype_change, slave, port); - return mlx4_GEN_EQE(dev, slave, &eqe); -} -EXPORT_SYMBOL(mlx4_gen_port_state_change_eqe); - -enum slave_port_state mlx4_get_slave_port_state(struct mlx4_dev *dev, int slave, u8 port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state; - if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS) { - pr_err("%s: Error: asking for slave:%d, port:%d\n", - __func__, slave, port); - return SLAVE_PORT_DOWN; - } - return s_state[slave].port_state[port]; -} -EXPORT_SYMBOL(mlx4_get_slave_port_state); - -static int mlx4_set_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, - enum slave_port_state state) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state; - - if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) { - pr_err("%s: Error: asking for slave:%d, port:%d\n", - __func__, slave, port); - return -1; - } - s_state[slave].port_state[port] = state; - - return 0; -} - -static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event) -{ - int i; - enum slave_port_gen_event gen_event; - - for (i = 0; i < dev->num_slaves; i++) - set_and_calc_slave_port_state(dev, i, port, event, &gen_event); -} -/************************************************************************** - The function get as input the new event to that port, - and according to the prev state change the slave's port state. - The events are: - MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN, - MLX4_PORT_STATE_DEV_EVENT_PORT_UP - MLX4_PORT_STATE_IB_EVENT_GID_VALID - MLX4_PORT_STATE_IB_EVENT_GID_INVALID -***************************************************************************/ -int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, - u8 port, int event, - enum slave_port_gen_event *gen_event) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *ctx = NULL; - unsigned long flags; - int ret = -1; - enum slave_port_state cur_state = - mlx4_get_slave_port_state(dev, slave, port); - - *gen_event = SLAVE_PORT_GEN_EVENT_NONE; - - if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) { - pr_err("%s: Error: asking for slave:%d, port:%d\n", - __func__, slave, port); - return ret; - } - - ctx = &priv->mfunc.master.slave_state[slave]; - spin_lock_irqsave(&ctx->lock, flags); - - switch (cur_state) { - case SLAVE_PORT_DOWN: - if (MLX4_PORT_STATE_DEV_EVENT_PORT_UP == event) - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PENDING_UP); - break; - case SLAVE_PENDING_UP: - if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event) - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PORT_DOWN); - else if (MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID == event) { - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PORT_UP); - *gen_event = SLAVE_PORT_GEN_EVENT_UP; - } - break; - case SLAVE_PORT_UP: - if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event) { - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PORT_DOWN); - *gen_event = SLAVE_PORT_GEN_EVENT_DOWN; - } else if (MLX4_PORT_STATE_IB_EVENT_GID_INVALID == - event) { - mlx4_set_slave_port_state(dev, slave, port, - SLAVE_PENDING_UP); - *gen_event = SLAVE_PORT_GEN_EVENT_DOWN; - } - break; - default: - pr_err("%s: BUG!!! UNKNOWN state: " - "slave:%d, port:%d\n", __func__, slave, port); - goto out; - } - ret = mlx4_get_slave_port_state(dev, slave, port); - -out: - spin_unlock_irqrestore(&ctx->lock, flags); - return ret; -} - -EXPORT_SYMBOL(set_and_calc_slave_port_state); - -int mlx4_gen_slaves_port_mgt_ev(struct mlx4_dev *dev, u8 port, int attr, u16 sm_lid, u8 sm_sl) -{ - struct mlx4_eqe eqe; - - memset(&eqe, 0, sizeof eqe); - - eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; - eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PORT_INFO; - eqe.event.port_mgmt_change.port = port; - eqe.event.port_mgmt_change.params.port_info.changed_attr = - cpu_to_be32((u32) attr); - if (attr & MSTR_SM_CHANGE_MASK) { - eqe.event.port_mgmt_change.params.port_info.mstr_sm_lid = - cpu_to_be16(sm_lid); - eqe.event.port_mgmt_change.params.port_info.mstr_sm_sl = - sm_sl; - } - - slave_event(dev, ALL_SLAVES, &eqe); - return 0; -} -EXPORT_SYMBOL(mlx4_gen_slaves_port_mgt_ev); - -void mlx4_master_handle_slave_flr(struct work_struct *work) -{ - struct mlx4_mfunc_master_ctx *master = - container_of(work, struct mlx4_mfunc_master_ctx, - slave_flr_event_work); - struct mlx4_mfunc *mfunc = - container_of(master, struct mlx4_mfunc, master); - struct mlx4_priv *priv = - container_of(mfunc, struct mlx4_priv, mfunc); - struct mlx4_dev *dev = &priv->dev; - struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; - int i; - int err; - unsigned long flags; - - mlx4_dbg(dev, "mlx4_handle_slave_flr\n"); - - for (i = 0 ; i < dev->num_slaves; i++) { - - if (MLX4_COMM_CMD_FLR == slave_state[i].last_cmd) { - mlx4_dbg(dev, "mlx4_handle_slave_flr: " - "clean slave: %d\n", i); - - mlx4_delete_all_resources_for_slave(dev, i); - /*return the slave to running mode*/ - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - slave_state[i].last_cmd = MLX4_COMM_CMD_RESET; - slave_state[i].is_slave_going_down = 0; - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - /*notify the FW:*/ - err = mlx4_cmd(dev, 0, i, 0, MLX4_CMD_INFORM_FLR_DONE, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed to notify FW on " - "FLR done (slave:%d)\n", i); - } - } -} - -static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_eqe *eqe; - int cqn; - int eqes_found = 0; - int set_ci = 0; - int port; - int slave = 0; - int ret; - u32 flr_slave; - u8 update_slave_state; - int i; - enum slave_port_gen_event gen_event; - unsigned long flags; - struct mlx4_vport_state *s_info; - - while ((eqe = next_eqe_sw(eq, dev->caps.eqe_factor))) { - /* - * Make sure we read EQ entry contents after we've - * checked the ownership bit. - */ - rmb(); - - switch (eqe->type) { - case MLX4_EVENT_TYPE_COMP: - cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff; - mlx4_cq_completion(dev, cqn); - break; - - case MLX4_EVENT_TYPE_PATH_MIG: - case MLX4_EVENT_TYPE_COMM_EST: - case MLX4_EVENT_TYPE_SQ_DRAINED: - case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: - case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: - case MLX4_EVENT_TYPE_PATH_MIG_FAILED: - case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: - case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: - mlx4_dbg(dev, "event %d arrived\n", eqe->type); - if (mlx4_is_master(dev)) { - /* forward only to slave owning the QP */ - ret = mlx4_get_slave_from_resource_id(dev, - RES_QP, - be32_to_cpu(eqe->event.qp.qpn) - & 0xffffff, &slave); - if (ret && ret != -ENOENT) { - mlx4_dbg(dev, "QP event %02x(%02x) on " - "EQ %d at index %u: could " - "not get slave id (%d)\n", - eqe->type, eqe->subtype, - eq->eqn, eq->cons_index, ret); - break; - } - - if (!ret && slave != dev->caps.function) { - mlx4_slave_event(dev, slave, eqe); - break; - } - - } - mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & - 0xffffff, eqe->type); - break; - - case MLX4_EVENT_TYPE_SRQ_LIMIT: - mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n", - __func__); - /* fall through */ - case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: - if (mlx4_is_master(dev)) { - /* forward only to slave owning the SRQ */ - ret = mlx4_get_slave_from_resource_id(dev, - RES_SRQ, - be32_to_cpu(eqe->event.srq.srqn) - & 0xffffff, - &slave); - if (ret && ret != -ENOENT) { - mlx4_warn(dev, "SRQ event %02x(%02x) " - "on EQ %d at index %u: could" - " not get slave id (%d)\n", - eqe->type, eqe->subtype, - eq->eqn, eq->cons_index, ret); - break; - } - mlx4_dbg(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n", - __func__, slave, - be32_to_cpu(eqe->event.srq.srqn), - eqe->type, eqe->subtype); - - if (!ret && slave != dev->caps.function) { - mlx4_dbg(dev, "%s: sending event %02x(%02x) to slave:%d\n", - __func__, eqe->type, - eqe->subtype, slave); - mlx4_slave_event(dev, slave, eqe); - break; - } - } - mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & - 0xffffff, eqe->type); - break; - - case MLX4_EVENT_TYPE_CMD: - mlx4_cmd_event(dev, - be16_to_cpu(eqe->event.cmd.token), - eqe->event.cmd.status, - be64_to_cpu(eqe->event.cmd.out_param)); - break; - - case MLX4_EVENT_TYPE_PORT_CHANGE: - port = be32_to_cpu(eqe->event.port_change.port) >> 28; - if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) { - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN, - port); - mlx4_priv(dev)->sense.do_sense_port[port] = 1; - if (!mlx4_is_master(dev)) - break; - for (i = 0; i < dev->num_slaves; i++) { - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { - if (i == mlx4_master_func_num(dev)) - continue; - mlx4_dbg(dev, "%s: Sending MLX4_PORT_CHANGE_SUBTYPE_DOWN" - " to slave: %d, port:%d\n", - __func__, i, port); - s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state; - if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) - mlx4_slave_event(dev, i, eqe); - } else { /* IB port */ - set_and_calc_slave_port_state(dev, i, port, - MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN, - &gen_event); - /*we can be in pending state, then do not send port_down event*/ - if (SLAVE_PORT_GEN_EVENT_DOWN == gen_event) { - if (i == mlx4_master_func_num(dev)) - continue; - mlx4_slave_event(dev, i, eqe); - } - } - } - } else { - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, port); - - mlx4_priv(dev)->sense.do_sense_port[port] = 0; - - if (!mlx4_is_master(dev)) - break; - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) - for (i = 0; i < dev->num_slaves; i++) { - if (i == mlx4_master_func_num(dev)) - continue; - s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state; - if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) - mlx4_slave_event(dev, i, eqe); - } - else /* IB port */ - /* port-up event will be sent to a slave when the - * slave's alias-guid is set. This is done in alias_GUID.c - */ - set_all_slave_state(dev, port, MLX4_DEV_EVENT_PORT_UP); - } - break; - - case MLX4_EVENT_TYPE_CQ_ERROR: - mlx4_warn(dev, "CQ %s on CQN %06x\n", - eqe->event.cq_err.syndrome == 1 ? - "overrun" : "access violation", - be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff); - if (mlx4_is_master(dev)) { - ret = mlx4_get_slave_from_resource_id(dev, - RES_CQ, - be32_to_cpu(eqe->event.cq_err.cqn) - & 0xffffff, &slave); - if (ret && ret != -ENOENT) { - mlx4_dbg(dev, "CQ event %02x(%02x) on " - "EQ %d at index %u: could " - "not get slave id (%d)\n", - eqe->type, eqe->subtype, - eq->eqn, eq->cons_index, ret); - break; - } - - if (!ret && slave != dev->caps.function) { - mlx4_slave_event(dev, slave, eqe); - break; - } - } - mlx4_cq_event(dev, - be32_to_cpu(eqe->event.cq_err.cqn) - & 0xffffff, - eqe->type); - break; - - case MLX4_EVENT_TYPE_EQ_OVERFLOW: - mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); - break; - - case MLX4_EVENT_TYPE_OP_REQUIRED: - atomic_inc(&priv->opreq_count); - /* FW commands can't be executed from interrupt context - working in deferred task */ - queue_work(mlx4_wq, &priv->opreq_task); - break; - - case MLX4_EVENT_TYPE_COMM_CHANNEL: - if (!mlx4_is_master(dev)) { - mlx4_warn(dev, "Received comm channel event " - "for non master device\n"); - break; - } - - memcpy(&priv->mfunc.master.comm_arm_bit_vector, - eqe->event.comm_channel_arm.bit_vec, - sizeof eqe->event.comm_channel_arm.bit_vec); - - if (!queue_work(priv->mfunc.master.comm_wq, - &priv->mfunc.master.comm_work)) - mlx4_warn(dev, "Failed to queue comm channel work\n"); - - if (!queue_work(priv->mfunc.master.comm_wq, - &priv->mfunc.master.arm_comm_work)) - mlx4_warn(dev, "Failed to queue arm comm channel work\n"); - break; - - case MLX4_EVENT_TYPE_FLR_EVENT: - flr_slave = be32_to_cpu(eqe->event.flr_event.slave_id); - if (!mlx4_is_master(dev)) { - mlx4_warn(dev, "Non-master function received" - "FLR event\n"); - break; - } - - mlx4_dbg(dev, "FLR event for slave: %d\n", flr_slave); - - if (flr_slave >= dev->num_slaves) { - mlx4_warn(dev, - "Got FLR for unknown function: %d\n", - flr_slave); - update_slave_state = 0; - } else - update_slave_state = 1; - - spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); - if (update_slave_state) { - priv->mfunc.master.slave_state[flr_slave].active = false; - priv->mfunc.master.slave_state[flr_slave].last_cmd = MLX4_COMM_CMD_FLR; - priv->mfunc.master.slave_state[flr_slave].is_slave_going_down = 1; - } - spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); - queue_work(priv->mfunc.master.comm_wq, - &priv->mfunc.master.slave_flr_event_work); - break; - - case MLX4_EVENT_TYPE_FATAL_WARNING: - if (eqe->subtype == MLX4_FATAL_WARNING_SUBTYPE_WARMING) { - if (mlx4_is_master(dev)) - for (i = 0; i < dev->num_slaves; i++) { - mlx4_dbg(dev, "%s: Sending " - "MLX4_FATAL_WARNING_SUBTYPE_WARMING" - " to slave: %d\n", __func__, i); - if (i == dev->caps.function) - continue; - mlx4_slave_event(dev, i, eqe); - } - mlx4_err(dev, "Temperature Threshold was reached! " - "Threshold: %d celsius degrees; " - "Current Temperature: %d\n", - be16_to_cpu(eqe->event.warming.warning_threshold), - be16_to_cpu(eqe->event.warming.current_temperature)); - } else - mlx4_warn(dev, "Unhandled event FATAL WARNING (%02x), " - "subtype %02x on EQ %d at index %u. owner=%x, " - "nent=0x%x, slave=%x, ownership=%s\n", - eqe->type, eqe->subtype, eq->eqn, - eq->cons_index, eqe->owner, eq->nent, - eqe->slave_id, - !!(eqe->owner & 0x80) ^ - !!(eq->cons_index & eq->nent) ? "HW" : "SW"); - - break; - - case MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT: - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE, - (unsigned long) eqe); - break; - - case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT: - switch (eqe->subtype) { - case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_BAD_CABLE: - mlx4_warn(dev, "Bad cable detected on port %u\n", - eqe->event.bad_cable.port); - break; - case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_UNSUPPORTED_CABLE: - mlx4_warn(dev, "Unsupported cable detected\n"); - break; - default: - mlx4_dbg(dev, "Unhandled recoverable error event " - "detected: %02x(%02x) on EQ %d at index %u. " - "owner=%x, nent=0x%x, ownership=%s\n", - eqe->type, eqe->subtype, eq->eqn, - eq->cons_index, eqe->owner, eq->nent, - !!(eqe->owner & 0x80) ^ - !!(eq->cons_index & eq->nent) ? "HW" : "SW"); - break; - } - break; - - case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: - case MLX4_EVENT_TYPE_ECC_DETECT: - default: - mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at " - "index %u. owner=%x, nent=0x%x, slave=%x, " - "ownership=%s\n", - eqe->type, eqe->subtype, eq->eqn, - eq->cons_index, eqe->owner, eq->nent, - eqe->slave_id, - !!(eqe->owner & 0x80) ^ - !!(eq->cons_index & eq->nent) ? "HW" : "SW"); - break; - } - - ++eq->cons_index; - eqes_found = 1; - ++set_ci; - - /* - * The HCA will think the queue has overflowed if we - * don't tell it we've been processing events. We - * create our EQs with MLX4_NUM_SPARE_EQE extra - * entries, so we must update our consumer index at - * least that often. - */ - if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) { - eq_set_ci(eq, 0); - set_ci = 0; - } - } - - eq_set_ci(eq, 1); - - return eqes_found; -} - -static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr) -{ - struct mlx4_dev *dev = dev_ptr; - struct mlx4_priv *priv = mlx4_priv(dev); - int work = 0; - int i; - - writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); - - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) - work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]); - - return IRQ_RETVAL(work); -} - -static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr) -{ - struct mlx4_eq *eq = eq_ptr; - struct mlx4_dev *dev = eq->dev; - - mlx4_eq_int(dev, eq); - - /* MSI-X vectors always belong to us */ - return IRQ_HANDLED; -} - -int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_event_eq_info *event_eq = - priv->mfunc.master.slave_state[slave].event_eq; - u32 in_modifier = vhcr->in_modifier; - u32 eqn = in_modifier & 0x3FF; - u64 in_param = vhcr->in_param; - int err = 0; - int i; - - if (slave == dev->caps.function) - err = mlx4_cmd(dev, in_param, (in_modifier & 0x80000000) | eqn, - 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - if (!err) - for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) - if (in_param & (1LL << i)) - event_eq[i].eqn = in_modifier >> 31 ? -1 : eqn; - - return err; -} - -static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, - int eq_num) -{ - return mlx4_cmd(dev, event_mask, (unmap << 31) | eq_num, - 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); -} - -static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int eq_num) -{ - return mlx4_cmd(dev, mailbox->dma, eq_num, 0, - MLX4_CMD_SW2HW_EQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int eq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, - 0, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_num_eq_uar(struct mlx4_dev *dev) -{ - /* - * Each UAR holds 4 EQ doorbells. To figure out how many UARs - * we need to map, take the difference of highest index and - * the lowest index we'll use and add 1. - */ - return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + - dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; -} - -static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int index; - - index = eq->eqn / 4 - dev->caps.reserved_eqs / 4; - - if (!priv->eq_table.uar_map[index]) { - priv->eq_table.uar_map[index] = - ioremap(pci_resource_start(dev->pdev, 2) + - ((eq->eqn / 4) << PAGE_SHIFT), - PAGE_SIZE); - if (!priv->eq_table.uar_map[index]) { - mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n", - eq->eqn); - return NULL; - } - } - - return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4); -} - -static void mlx4_unmap_uar(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - for (i = 0; i < mlx4_num_eq_uar(dev); ++i) - if (priv->eq_table.uar_map[i]) { - iounmap(priv->eq_table.uar_map[i]); - priv->eq_table.uar_map[i] = NULL; - } -} - -static int mlx4_create_eq(struct mlx4_dev *dev, int nent, - u8 intr, struct mlx4_eq *eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_eq_context *eq_context; - int npages; - u64 *dma_list = NULL; - dma_addr_t t; - u64 mtt_addr; - int err = -ENOMEM; - int i; - - eq->dev = dev; - eq->nent = roundup_pow_of_two(max(nent, 2)); - /* CX3 is capable of extending the CQE\EQE from 32 to 64 bytes */ - npages = PAGE_ALIGN(eq->nent * (MLX4_EQ_ENTRY_SIZE << dev->caps.eqe_factor)) / PAGE_SIZE; - - eq->page_list = kmalloc(npages * sizeof *eq->page_list, - GFP_KERNEL); - if (!eq->page_list) - goto err_out; - - for (i = 0; i < npages; ++i) - eq->page_list[i].buf = NULL; - - dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); - if (!dma_list) - goto err_out_free; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - goto err_out_free; - eq_context = mailbox->buf; - - for (i = 0; i < npages; ++i) { - eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, - PAGE_SIZE, &t, GFP_KERNEL); - if (!eq->page_list[i].buf) - goto err_out_free_pages; - - dma_list[i] = t; - eq->page_list[i].map = t; - - memset(eq->page_list[i].buf, 0, PAGE_SIZE); - } - - eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap); - if (eq->eqn == -1) - goto err_out_free_pages; - - eq->doorbell = mlx4_get_eq_uar(dev, eq); - if (!eq->doorbell) { - err = -ENOMEM; - goto err_out_free_eq; - } - - err = mlx4_mtt_init(dev, npages, PAGE_SHIFT, &eq->mtt); - if (err) - goto err_out_free_eq; - - err = mlx4_write_mtt(dev, &eq->mtt, 0, npages, dma_list); - if (err) - goto err_out_free_mtt; - - memset(eq_context, 0, sizeof *eq_context); - eq_context->flags = cpu_to_be32(MLX4_EQ_STATUS_OK | - MLX4_EQ_STATE_ARMED); - eq_context->log_eq_size = ilog2(eq->nent); - eq_context->intr = intr; - eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT; - - mtt_addr = mlx4_mtt_addr(dev, &eq->mtt); - eq_context->mtt_base_addr_h = mtt_addr >> 32; - eq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - - err = mlx4_SW2HW_EQ(dev, mailbox, eq->eqn); - if (err) { - mlx4_warn(dev, "SW2HW_EQ failed (%d)\n", err); - goto err_out_free_mtt; - } - - kfree(dma_list); - mlx4_free_cmd_mailbox(dev, mailbox); - - eq->cons_index = 0; - - return err; - -err_out_free_mtt: - mlx4_mtt_cleanup(dev, &eq->mtt); - -err_out_free_eq: - mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); - -err_out_free_pages: - for (i = 0; i < npages; ++i) - if (eq->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - eq->page_list[i].buf, - eq->page_list[i].map); - - mlx4_free_cmd_mailbox(dev, mailbox); - -err_out_free: - kfree(eq->page_list); - kfree(dma_list); - -err_out: - return err; -} - -static void mlx4_free_eq(struct mlx4_dev *dev, - struct mlx4_eq *eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - int err; - int i; - /* CX3 is capable of extending the CQE\EQE from 32 to 64 bytes */ - int npages = PAGE_ALIGN((MLX4_EQ_ENTRY_SIZE << dev->caps.eqe_factor) * eq->nent) / PAGE_SIZE; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return; - - err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn); - if (err) - mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err); - - if (0) { - mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); - for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) { - if (i % 4 == 0) - pr_cont("[%02x] ", i * 4); - pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4)); - if ((i + 1) % 4 == 0) - pr_cont("\n"); - } - } - - mlx4_mtt_cleanup(dev, &eq->mtt); - for (i = 0; i < npages; ++i) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - eq->page_list[i].buf, - eq->page_list[i].map); - - kfree(eq->page_list); - mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); - mlx4_free_cmd_mailbox(dev, mailbox); -} - -static void mlx4_free_irqs(struct mlx4_dev *dev) -{ - struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; - struct mlx4_priv *priv = mlx4_priv(dev); - int i, vec; - - if (eq_table->have_irq) - free_irq(dev->pdev->irq, dev); - - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) - if (eq_table->eq[i].have_irq) { - free_irq(eq_table->eq[i].irq, eq_table->eq + i); - eq_table->eq[i].have_irq = 0; - } - - for (i = 0; i < dev->caps.comp_pool; i++) { - /* - * Freeing the assigned irq's - * all bits should be 0, but we need to validate - */ - if (priv->msix_ctl.pool_bm & 1ULL << i) { - /* NO need protecting*/ - vec = dev->caps.num_comp_vectors + 1 + i; - free_irq(priv->eq_table.eq[vec].irq, - &priv->eq_table.eq[vec]); - } - } - - - kfree(eq_table->irq_names); -} - -static int mlx4_map_clr_int(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) + - priv->fw.clr_int_base, MLX4_CLR_INT_SIZE); - if (!priv->clr_base) { - mlx4_err(dev, "Couldn't map interrupt clear register, aborting.\n"); - return -ENOMEM; - } - - return 0; -} - -static void mlx4_unmap_clr_int(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - iounmap(priv->clr_base); -} - -int mlx4_alloc_eq_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - priv->eq_table.eq = kcalloc(dev->caps.num_eqs - dev->caps.reserved_eqs, - sizeof *priv->eq_table.eq, GFP_KERNEL); - if (!priv->eq_table.eq) - return -ENOMEM; - - return 0; -} - -void mlx4_free_eq_table(struct mlx4_dev *dev) -{ - kfree(mlx4_priv(dev)->eq_table.eq); -} - -int mlx4_init_eq_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - int i; - - priv->eq_table.uar_map = kcalloc(mlx4_num_eq_uar(dev), - sizeof *priv->eq_table.uar_map, - GFP_KERNEL); - if (!priv->eq_table.uar_map) { - err = -ENOMEM; - goto err_out_free; - } - - err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs, - dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0); - if (err) - goto err_out_free; - - for (i = 0; i < mlx4_num_eq_uar(dev); ++i) - priv->eq_table.uar_map[i] = NULL; - - if (!mlx4_is_slave(dev)) { - err = mlx4_map_clr_int(dev); - if (err) - goto err_out_bitmap; - - priv->eq_table.clr_mask = - swab32(1 << (priv->eq_table.inta_pin & 31)); - priv->eq_table.clr_int = priv->clr_base + - (priv->eq_table.inta_pin < 32 ? 4 : 0); - } - - priv->eq_table.irq_names = - kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + - dev->caps.comp_pool), - GFP_KERNEL); - if (!priv->eq_table.irq_names) { - err = -ENOMEM; - goto err_out_clr_int; - } - - for (i = 0; i < dev->caps.num_comp_vectors; ++i) { - err = mlx4_create_eq(dev, dev->caps.num_cqs - - dev->caps.reserved_cqs + - MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, - &priv->eq_table.eq[i]); - if (err) { - --i; - goto err_out_unmap; - } - } - - err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0, - &priv->eq_table.eq[dev->caps.num_comp_vectors]); - if (err) - goto err_out_comp; - - /*if additional completion vectors poolsize is 0 this loop will not run*/ - for (i = dev->caps.num_comp_vectors + 1; - i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { - - err = mlx4_create_eq(dev, dev->caps.num_cqs - - dev->caps.reserved_cqs + - MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, - &priv->eq_table.eq[i]); - if (err) { - --i; - goto err_out_unmap; - } - } - - - if (dev->flags & MLX4_FLAG_MSI_X) { - const char *eq_name; - - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { - if (i < dev->caps.num_comp_vectors) { - snprintf(priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, - "mlx4-comp-%d@pci:%s", i, - pci_name(dev->pdev)); - } else { - snprintf(priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, - "mlx4-async@pci:%s", - pci_name(dev->pdev)); - } - - eq_name = priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE; - err = request_irq(priv->eq_table.eq[i].irq, - mlx4_msi_x_interrupt, 0, eq_name, - priv->eq_table.eq + i); - if (err) - goto err_out_async; - - priv->eq_table.eq[i].have_irq = 1; - } - } else { - snprintf(priv->eq_table.irq_names, - MLX4_IRQNAME_SIZE, - DRV_NAME "@pci:%s", - pci_name(dev->pdev)); - err = request_irq(dev->pdev->irq, mlx4_interrupt, - IRQF_SHARED, priv->eq_table.irq_names, dev); - if (err) - goto err_out_async; - - priv->eq_table.have_irq = 1; - } - - err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); - if (err) - mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err); - - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) - eq_set_ci(&priv->eq_table.eq[i], 1); - - return 0; - -err_out_async: - mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); - -err_out_comp: - i = dev->caps.num_comp_vectors - 1; - -err_out_unmap: - while (i >= 0) { - mlx4_free_eq(dev, &priv->eq_table.eq[i]); - --i; - } - mlx4_free_irqs(dev); - -err_out_clr_int: - if (!mlx4_is_slave(dev)) - mlx4_unmap_clr_int(dev); - -err_out_bitmap: - mlx4_unmap_uar(dev); - mlx4_bitmap_cleanup(&priv->eq_table.bitmap); - -err_out_free: - kfree(priv->eq_table.uar_map); - - return err; -} - -void mlx4_cleanup_eq_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 1, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); - - mlx4_free_irqs(dev); - - for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) - mlx4_free_eq(dev, &priv->eq_table.eq[i]); - - if (!mlx4_is_slave(dev)) - mlx4_unmap_clr_int(dev); - - mlx4_unmap_uar(dev); - mlx4_bitmap_cleanup(&priv->eq_table.bitmap); - - kfree(priv->eq_table.uar_map); -} - -/* A test that verifies that we can accept interrupts on all - * the irq vectors of the device. - * Interrupts are checked using the NOP command. - */ -int mlx4_test_interrupts(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - int err; - - err = mlx4_NOP(dev); - /* When not in MSI_X, there is only one irq to check */ - if (!(dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(dev)) - return err; - - /* A loop over all completion vectors, for each vector we will check - * whether it works by mapping command completions to that vector - * and performing a NOP command - */ - for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) { - /* Temporary use polling for command completions */ - mlx4_cmd_use_polling(dev); - - /* Map the new eq to handle all asyncronous events */ - err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[i].eqn); - if (err) { - mlx4_warn(dev, "Failed mapping eq for interrupt test\n"); - mlx4_cmd_use_events(dev); - break; - } - - /* Go back to using events */ - mlx4_cmd_use_events(dev); - err = mlx4_NOP(dev); - } - - /* Return to default */ - mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); - return err; -} -EXPORT_SYMBOL(mlx4_test_interrupts); - -int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector) -{ - - struct mlx4_priv *priv = mlx4_priv(dev); - int vec = 0, err = 0, i; - - mutex_lock(&priv->msix_ctl.pool_lock); - for (i = 0; !vec && i < dev->caps.comp_pool; i++) { - if (~priv->msix_ctl.pool_bm & 1ULL << i) { - priv->msix_ctl.pool_bm |= 1ULL << i; - vec = dev->caps.num_comp_vectors + 1 + i; - snprintf(priv->eq_table.irq_names + - vec * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, "%s", name); - err = request_irq(priv->eq_table.eq[vec].irq, - mlx4_msi_x_interrupt, 0, - &priv->eq_table.irq_names[vec<<5], - priv->eq_table.eq + vec); - if (err) { - /*zero out bit by fliping it*/ - priv->msix_ctl.pool_bm ^= 1 << i; - vec = 0; - continue; - /*we dont want to break here*/ - } - eq_set_ci(&priv->eq_table.eq[vec], 1); - } - } - mutex_unlock(&priv->msix_ctl.pool_lock); - - if (vec) { - *vector = vec; - } else { - *vector = 0; - err = (i == dev->caps.comp_pool) ? -ENOSPC : err; - } - return err; -} -EXPORT_SYMBOL(mlx4_assign_eq); - -void mlx4_release_eq(struct mlx4_dev *dev, int vec) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - /*bm index*/ - int i = vec - dev->caps.num_comp_vectors - 1; - - if (likely(i >= 0)) { - /*sanity check , making sure were not trying to free irq's - Belonging to a legacy EQ*/ - mutex_lock(&priv->msix_ctl.pool_lock); - if (priv->msix_ctl.pool_bm & 1ULL << i) { - free_irq(priv->eq_table.eq[vec].irq, - &priv->eq_table.eq[vec]); - priv->msix_ctl.pool_bm &= ~(1ULL << i); - } - mutex_unlock(&priv->msix_ctl.pool_lock); - } - -} -EXPORT_SYMBOL(mlx4_release_eq); - diff --git a/sys/ofed/drivers/net/mlx4/fw.c b/sys/ofed/drivers/net/mlx4/fw.c deleted file mode 100644 index e2909fa60f89..000000000000 --- a/sys/ofed/drivers/net/mlx4/fw.c +++ /dev/null @@ -1,1956 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. 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. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/etherdevice.h> -#include <linux/mlx4/cmd.h> -#include <linux/module.h> -#include <linux/cache.h> - -#include "fw.h" -#include "icm.h" - -enum { - MLX4_COMMAND_INTERFACE_MIN_REV = 2, - MLX4_COMMAND_INTERFACE_MAX_REV = 3, - MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS = 3, -}; - -extern void __buggy_use_of_MLX4_GET(void); -extern void __buggy_use_of_MLX4_PUT(void); - -static u8 enable_qos; -module_param(enable_qos, byte, 0444); -MODULE_PARM_DESC(enable_qos, "Enable Quality of Service support in the HCA (default: off)"); - -#define MLX4_GET(dest, source, offset) \ - do { \ - void *__p = (char *) (source) + (offset); \ - switch (sizeof (dest)) { \ - case 1: (dest) = *(u8 *) __p; break; \ - case 2: (dest) = be16_to_cpup(__p); break; \ - case 4: (dest) = be32_to_cpup(__p); break; \ - case 8: (dest) = be64_to_cpup(__p); break; \ - default: __buggy_use_of_MLX4_GET(); \ - } \ - } while (0) - -#define MLX4_PUT(dest, source, offset) \ - do { \ - void *__d = ((char *) (dest) + (offset)); \ - switch (sizeof(source)) { \ - case 1: *(u8 *) __d = (source); break; \ - case 2: *(__be16 *) __d = cpu_to_be16(source); break; \ - case 4: *(__be32 *) __d = cpu_to_be32(source); break; \ - case 8: *(__be64 *) __d = cpu_to_be64(source); break; \ - default: __buggy_use_of_MLX4_PUT(); \ - } \ - } while (0) - -static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) -{ - static const char *fname[] = { - [ 0] = "RC transport", - [ 1] = "UC transport", - [ 2] = "UD transport", - [ 3] = "XRC transport", - [ 4] = "reliable multicast", - [ 5] = "FCoIB support", - [ 6] = "SRQ support", - [ 7] = "IPoIB checksum offload", - [ 8] = "P_Key violation counter", - [ 9] = "Q_Key violation counter", - [10] = "VMM", - [12] = "DPDP", - [15] = "Big LSO headers", - [16] = "MW support", - [17] = "APM support", - [18] = "Atomic ops support", - [19] = "Raw multicast support", - [20] = "Address vector port checking support", - [21] = "UD multicast support", - [24] = "Demand paging support", - [25] = "Router support", - [30] = "IBoE support", - [32] = "Unicast loopback support", - [34] = "FCS header control", - [38] = "Wake On LAN support", - [40] = "UDP RSS support", - [41] = "Unicast VEP steering support", - [42] = "Multicast VEP steering support", - [44] = "Cross-channel (sync_qp) operations support", - [48] = "Counters support", - [59] = "Port management change event support", - [60] = "eSwitch support", - [61] = "64 byte EQE support", - [62] = "64 byte CQE support", - }; - int i; - - mlx4_dbg(dev, "DEV_CAP flags:\n"); - for (i = 0; i < ARRAY_SIZE(fname); ++i) - if (fname[i] && (flags & (1LL << i))) - mlx4_dbg(dev, " %s\n", fname[i]); -} - -static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) -{ - static const char * const fname[] = { - [0] = "RSS support", - [1] = "RSS Toeplitz Hash Function support", - [2] = "RSS XOR Hash Function support", - [3] = "Device manage flow steering support", - [4] = "FSM (MAC unti-spoofing) support", - [5] = "VST (control vlan insertion/stripping) support", - [6] = "Dynamic QP updates support", - [7] = "Loopback source checks support", - [8] = "Device managed flow steering IPoIB support", - [9] = "ETS configuration support", - [10] = "ETH backplane autoneg report", - [11] = "Ethernet Flow control statistics support", - [12] = "Recoverable error events support", - [13] = "Time stamping support", - [14] = "Report driver version to FW support" - }; - int i; - - for (i = 0; i < ARRAY_SIZE(fname); ++i) - if (fname[i] && (flags & (1LL << i))) - mlx4_dbg(dev, " %s\n", fname[i]); -} - -int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *inbox; - int err = 0; - -#define MOD_STAT_CFG_IN_SIZE 0x100 - -#define MOD_STAT_CFG_PG_SZ_M_OFFSET 0x002 -#define MOD_STAT_CFG_PG_SZ_OFFSET 0x003 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - memset(inbox, 0, MOD_STAT_CFG_IN_SIZE); - - MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET); - MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET); - - err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_MOD_STAT_CFG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u8 field, port; - u32 size; - int err = 0; - -#define QUERY_FUNC_CAP_FLAGS_OFFSET 0x0 -#define QUERY_FUNC_CAP_NUM_PORTS_OFFSET 0x1 -#define QUERY_FUNC_CAP_PF_BHVR_OFFSET 0x4 -#define QUERY_FUNC_CAP_FMR_OFFSET 0x8 -#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP 0x10 -#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP 0x14 -#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP 0x18 -#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP 0x20 -#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP 0x24 -#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP 0x28 -#define QUERY_FUNC_CAP_MAX_EQ_OFFSET 0x2c -#define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET 0x30 - -#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET 0x50 -#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET 0x54 -#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET 0x58 -#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET 0x60 -#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET 0x64 -#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET 0x68 - -#define QUERY_FUNC_CAP_FMR_FLAG 0x80 -#define QUERY_FUNC_CAP_FLAG_RDMA 0x40 -#define QUERY_FUNC_CAP_FLAG_ETH 0x80 -#define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10 - -/* when opcode modifier = 1 */ -#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET 0x3 -#define QUERY_FUNC_CAP_FLAGS0_OFFSET 0x8 -#define QUERY_FUNC_CAP_FLAGS1_OFFSET 0xc -#define QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET 0xd - -#define QUERY_FUNC_CAP_QP0_TUNNEL 0x10 -#define QUERY_FUNC_CAP_QP0_PROXY 0x14 -#define QUERY_FUNC_CAP_QP1_TUNNEL 0x18 -#define QUERY_FUNC_CAP_QP1_PROXY 0x1c - -#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC 0x40 -#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN 0x80 -#define QUERY_FUNC_CAP_PROPS_DEF_COUNTER 0x20 - -#define QUERY_FUNC_CAP_RDMA_PROPS_FORCE_PHY_WQE_GID 0x80 - - if (vhcr->op_modifier == 1) { - port = vhcr->in_modifier; /* phys-port = logical-port */ - MLX4_PUT(outbox->buf, port, QUERY_FUNC_CAP_PHYS_PORT_OFFSET); - - field = 0; - /* ensure that phy_wqe_gid bit is not set */ - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS0_OFFSET); - - /* ensure force vlan and force mac bits are not set - * and that default counter bit is set - */ - field = QUERY_FUNC_CAP_PROPS_DEF_COUNTER; /* def counter */ - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET); - - /* There is always default counter legal or sink counter */ - field = mlx4_get_default_counter_index(dev, slave, vhcr->in_modifier); - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET); - - /* size is now the QP number */ - size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + port - 1; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL); - - size += 2; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL); - - size = dev->phys_caps.base_proxy_sqpn + 8 * slave + port - 1; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_PROXY); - - size += 2; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_PROXY); - - } else if (vhcr->op_modifier == 0) { - /* enable rdma and ethernet interfaces, and new quota locations */ - field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA | - QUERY_FUNC_CAP_FLAG_QUOTAS); - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET); - - field = dev->caps.num_ports; - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); - - size = dev->caps.function_caps; /* set PF behaviours */ - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_PF_BHVR_OFFSET); - - field = 0; /* protected FMR support not available as yet */ - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FMR_OFFSET); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET); - size = dev->caps.num_qps; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET); - size = dev->caps.num_srqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET); - size = dev->caps.num_cqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP); - - size = dev->caps.num_eqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET); - - size = dev->caps.reserved_eqs; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET); - size = dev->caps.num_mpts; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP); - - size = priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[slave]; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET); - size = dev->caps.num_mtts; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP); - - size = dev->caps.num_mgms + dev->caps.num_amgms; - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET); - MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP); - - } else - err = -EINVAL; - - return err; -} - -int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port, - struct mlx4_func_cap *func_cap) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - u8 field, op_modifier; - u32 size; - int err = 0, quotas = 0; - - op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */ - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - err = mlx4_cmd_box(dev, 0, mailbox->dma, gen_or_port, op_modifier, - MLX4_CMD_QUERY_FUNC_CAP, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - goto out; - - outbox = mailbox->buf; - - if (!op_modifier) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS_OFFSET); - if (!(field & (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA))) { - mlx4_err(dev, "The host supports neither eth nor rdma interfaces\n"); - err = -EPROTONOSUPPORT; - goto out; - } - func_cap->flags = field; - quotas = !!(func_cap->flags & QUERY_FUNC_CAP_FLAG_QUOTAS); - - MLX4_GET(field, outbox, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); - func_cap->num_ports = field; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_PF_BHVR_OFFSET); - func_cap->pf_context_behaviour = size; - - if (quotas) { - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET); - func_cap->qp_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET); - func_cap->srq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET); - func_cap->cq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET); - func_cap->mpt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET); - func_cap->mtt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET); - func_cap->mcg_quota = size & 0xFFFFFF; - - } else { - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP); - func_cap->qp_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP); - func_cap->srq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP); - func_cap->cq_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP); - func_cap->mpt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP); - func_cap->mtt_quota = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP); - func_cap->mcg_quota = size & 0xFFFFFF; - } - MLX4_GET(size, outbox, QUERY_FUNC_CAP_MAX_EQ_OFFSET); - func_cap->max_eq = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); - func_cap->reserved_eq = size & 0xFFFFFF; - - goto out; - } - - /* logical port query */ - if (gen_or_port > dev->caps.num_ports) { - err = -EINVAL; - goto out; - } - - if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET); - if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN) { - mlx4_err(dev, "VLAN is enforced on this port\n"); - err = -EPROTONOSUPPORT; - goto out; - } - - if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC) { - mlx4_err(dev, "Force mac is enabled on this port\n"); - err = -EPROTONOSUPPORT; - goto out; - } - } else if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_IB) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET); - if (field & QUERY_FUNC_CAP_RDMA_PROPS_FORCE_PHY_WQE_GID) { - mlx4_err(dev, "phy_wqe_gid is " - "enforced on this ib port\n"); - err = -EPROTONOSUPPORT; - goto out; - } - } - - MLX4_GET(field, outbox, QUERY_FUNC_CAP_PHYS_PORT_OFFSET); - func_cap->physical_port = field; - if (func_cap->physical_port != gen_or_port) { - err = -ENOSYS; - goto out; - } - - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET); - if (field & QUERY_FUNC_CAP_PROPS_DEF_COUNTER) { - MLX4_GET(field, outbox, QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET); - func_cap->def_counter_index = field; - } else { - func_cap->def_counter_index = MLX4_SINK_COUNTER_INDEX; - } - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL); - func_cap->qp0_tunnel_qpn = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_PROXY); - func_cap->qp0_proxy_qpn = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_TUNNEL); - func_cap->qp1_tunnel_qpn = size & 0xFFFFFF; - - MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_PROXY); - func_cap->qp1_proxy_qpn = size & 0xFFFFFF; - - /* All other resources are allocated by the master, but we still report - * 'num' and 'reserved' capabilities as follows: - * - num remains the maximum resource index - * - 'num - reserved' is the total available objects of a resource, but - * resource indices may be less than 'reserved' - * TODO: set per-resource quotas */ - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - - return err; -} - -int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - u8 field; - u32 field32, flags, ext_flags; - u16 size; - u16 stat_rate; - int err; - int i; - -#define QUERY_DEV_CAP_OUT_SIZE 0x100 -#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET 0x10 -#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET 0x11 -#define QUERY_DEV_CAP_RSVD_QP_OFFSET 0x12 -#define QUERY_DEV_CAP_MAX_QP_OFFSET 0x13 -#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET 0x14 -#define QUERY_DEV_CAP_MAX_SRQ_OFFSET 0x15 -#define QUERY_DEV_CAP_RSVD_EEC_OFFSET 0x16 -#define QUERY_DEV_CAP_MAX_EEC_OFFSET 0x17 -#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET 0x19 -#define QUERY_DEV_CAP_RSVD_CQ_OFFSET 0x1a -#define QUERY_DEV_CAP_MAX_CQ_OFFSET 0x1b -#define QUERY_DEV_CAP_MAX_MPT_OFFSET 0x1d -#define QUERY_DEV_CAP_RSVD_EQ_OFFSET 0x1e -#define QUERY_DEV_CAP_MAX_EQ_OFFSET 0x1f -#define QUERY_DEV_CAP_RSVD_MTT_OFFSET 0x20 -#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET 0x21 -#define QUERY_DEV_CAP_RSVD_MRW_OFFSET 0x22 -#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET 0x23 -#define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27 -#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 -#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b -#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d -#define QUERY_DEV_CAP_RSS_OFFSET 0x2e -#define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f -#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 -#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 -#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET 0x36 -#define QUERY_DEV_CAP_VL_PORT_OFFSET 0x37 -#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET 0x38 -#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b -#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c -#define QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET 0x3e -#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f -#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET 0x40 -#define QUERY_DEV_CAP_SYNC_QP_OFFSET 0x42 -#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 -#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 -#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 -#define QUERY_DEV_CAP_PAGE_SZ_OFFSET 0x4b -#define QUERY_DEV_CAP_BF_OFFSET 0x4c -#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET 0x4d -#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET 0x4e -#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET 0x4f -#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET 0x51 -#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET 0x52 -#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET 0x55 -#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET 0x56 -#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET 0x61 -#define QUERY_DEV_CAP_RSVD_MCG_OFFSET 0x62 -#define QUERY_DEV_CAP_MAX_MCG_OFFSET 0x63 -#define QUERY_DEV_CAP_RSVD_PD_OFFSET 0x64 -#define QUERY_DEV_CAP_MAX_PD_OFFSET 0x65 -#define QUERY_DEV_CAP_RSVD_XRC_OFFSET 0x66 -#define QUERY_DEV_CAP_MAX_XRC_OFFSET 0x67 -#define QUERY_DEV_CAP_MAX_BASIC_COUNTERS_OFFSET 0x68 -#define QUERY_DEV_CAP_MAX_EXTENDED_COUNTERS_OFFSET 0x6c -#define QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET 0x70 -#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76 -#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET 0x70 -#define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET 0x74 -#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77 -#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80 -#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82 -#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET 0x84 -#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET 0x86 -#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET 0x88 -#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET 0x8a -#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET 0x8c -#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET 0x8e -#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET 0x90 -#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92 -#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94 -#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 -#define QUERY_DEV_CAP_ETS_CFG_OFFSET 0x9c -#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 - - dev_cap->flags2 = 0; - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET); - dev_cap->reserved_qps = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET); - dev_cap->max_qps = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET); - dev_cap->reserved_srqs = 1 << (field >> 4); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET); - dev_cap->max_srqs = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET); - dev_cap->max_cq_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET); - dev_cap->reserved_cqs = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET); - dev_cap->max_cqs = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET); - dev_cap->max_mpts = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET); - dev_cap->reserved_eqs = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET); - dev_cap->max_eqs = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET); - dev_cap->reserved_mtts = 1 << (field >> 4); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET); - dev_cap->max_mrw_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET); - dev_cap->reserved_mrws = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET); - dev_cap->max_mtt_seg = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET); - dev_cap->max_requester_per_qp = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET); - dev_cap->max_responder_per_qp = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET); - field &= 0x1f; - if (!field) - dev_cap->max_gso_sz = 0; - else - dev_cap->max_gso_sz = 1 << field; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET); - if (field & 0x20) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR; - if (field & 0x10) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP; - field &= 0xf; - if (field) { - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS; - dev_cap->max_rss_tbl_sz = 1 << field; - } else - dev_cap->max_rss_tbl_sz = 0; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); - dev_cap->max_rdma_global = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); - dev_cap->local_ca_ack_delay = field & 0x1f; - MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); - dev_cap->num_ports = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET); - dev_cap->max_msg_sz = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET); - if (field & 0x10) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN; - MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); - if (field & 0x80) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FS_EN; - MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET); - if (field & 0x80) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB; - dev_cap->fs_log_max_ucast_qp_range_size = field & 0x1f; - MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET); - dev_cap->fs_max_num_qp_per_entry = field; - MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); - dev_cap->stat_rate_support = stat_rate; - MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET); - if (field & 0x80) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_TS; - MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); - MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); - dev_cap->flags = flags | (u64)ext_flags << 32; - MLX4_GET(field, outbox, QUERY_DEV_CAP_SYNC_QP_OFFSET); - dev_cap->sync_qp = field & 0x10; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); - dev_cap->reserved_uars = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET); - dev_cap->uar_size = 1 << ((field & 0x3f) + 20); - MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET); - dev_cap->min_page_sz = 1 << field; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET); - if (field & 0x80) { - MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET); - dev_cap->bf_reg_size = 1 << (field & 0x1f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET); - if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) - field = 3; - dev_cap->bf_regs_per_page = 1 << (field & 0x3f); - mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n", - dev_cap->bf_reg_size, dev_cap->bf_regs_per_page); - } else { - dev_cap->bf_reg_size = 0; - mlx4_dbg(dev, "BlueFlame not available\n"); - } - - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET); - dev_cap->max_sq_sg = field; - MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET); - dev_cap->max_sq_desc_sz = size; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET); - dev_cap->max_qp_per_mcg = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET); - dev_cap->reserved_mgms = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET); - dev_cap->max_mcgs = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET); - dev_cap->reserved_pds = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET); - dev_cap->max_pds = 1 << (field & 0x3f); - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_XRC_OFFSET); - dev_cap->reserved_xrcds = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_XRC_OFFSET); - dev_cap->max_xrcds = 1 << (field & 0x1f); - - MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET); - dev_cap->rdmarc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET); - dev_cap->qpc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET); - dev_cap->aux_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET); - dev_cap->altc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET); - dev_cap->eqc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET); - dev_cap->cqc_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET); - dev_cap->srq_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET); - dev_cap->cmpt_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET); - dev_cap->mtt_entry_sz = size; - MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET); - dev_cap->dmpt_entry_sz = size; - - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET); - dev_cap->max_srq_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET); - dev_cap->max_qp_sz = 1 << field; - MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET); - dev_cap->resize_srq = field & 1; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET); - dev_cap->max_rq_sg = field; - MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET); - dev_cap->max_rq_desc_sz = size; - - MLX4_GET(dev_cap->bmme_flags, outbox, - QUERY_DEV_CAP_BMME_FLAGS_OFFSET); - MLX4_GET(dev_cap->reserved_lkey, outbox, - QUERY_DEV_CAP_RSVD_LKEY_OFFSET); - MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETS_CFG_OFFSET); - if (field32 & (1 << 0)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP; - if (field32 & (1 << 7)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT; - if (field32 & (1 << 8)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW; - if (field32 & (1 << 13)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG; - - MLX4_GET(dev_cap->max_icm_sz, outbox, - QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET); - if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS) - MLX4_GET(dev_cap->max_basic_counters, outbox, - QUERY_DEV_CAP_MAX_BASIC_COUNTERS_OFFSET); - /* FW reports 256 however real value is 255 */ - dev_cap->max_basic_counters = min_t(u32, dev_cap->max_basic_counters, 255); - if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS_EXT) - MLX4_GET(dev_cap->max_extended_counters, outbox, - QUERY_DEV_CAP_MAX_EXTENDED_COUNTERS_OFFSET); - - MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); - if (field32 & (1 << 16)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP; - if (field32 & (1 << 19)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_LB_SRC_CHK; - if (field32 & (1 << 20)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM; - if (field32 & (1 << 26)) - dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL; - - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - for (i = 1; i <= dev_cap->num_ports; ++i) { - MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); - dev_cap->max_vl[i] = field >> 4; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET); - dev_cap->ib_mtu[i] = field >> 4; - dev_cap->max_port_width[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET); - dev_cap->max_gids[i] = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET); - dev_cap->max_pkeys[i] = 1 << (field & 0xf); - } - } else { -#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00 -#define QUERY_PORT_MTU_OFFSET 0x01 -#define QUERY_PORT_ETH_MTU_OFFSET 0x02 -#define QUERY_PORT_WIDTH_OFFSET 0x06 -#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07 -#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a -#define QUERY_PORT_MAX_VL_OFFSET 0x0b -#define QUERY_PORT_MAC_OFFSET 0x10 -#define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18 -#define QUERY_PORT_WAVELENGTH_OFFSET 0x1c -#define QUERY_PORT_TRANS_CODE_OFFSET 0x20 - - for (i = 1; i <= dev_cap->num_ports; ++i) { - err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET); - dev_cap->supported_port_types[i] = field & 3; - dev_cap->suggested_type[i] = (field >> 3) & 1; - dev_cap->default_sense[i] = (field >> 4) & 1; - MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET); - dev_cap->ib_mtu[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET); - dev_cap->max_port_width[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET); - dev_cap->max_gids[i] = 1 << (field >> 4); - dev_cap->max_pkeys[i] = 1 << (field & 0xf); - MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET); - dev_cap->max_vl[i] = field & 0xf; - MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET); - dev_cap->log_max_macs[i] = field & 0xf; - dev_cap->log_max_vlans[i] = field >> 4; - MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET); - MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET); - MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET); - dev_cap->trans_type[i] = field32 >> 24; - dev_cap->vendor_oui[i] = field32 & 0xffffff; - MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET); - MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET); - } - } - - mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n", - dev_cap->bmme_flags, dev_cap->reserved_lkey); - - /* - * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then - * we can't use any EQs whose doorbell falls on that page, - * even if the EQ itself isn't reserved. - */ - dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4, - dev_cap->reserved_eqs); - - mlx4_dbg(dev, "Max ICM size %lld MB\n", - (unsigned long long) dev_cap->max_icm_sz >> 20); - mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n", - dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz); - mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n", - dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz); - mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n", - dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz); - mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n", - dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz); - mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n", - dev_cap->reserved_mrws, dev_cap->reserved_mtts); - mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n", - dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars); - mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", - dev_cap->max_pds, dev_cap->reserved_mgms); - mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", - dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz); - mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n", - dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1], - dev_cap->max_port_width[1]); - mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n", - dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg); - mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n", - dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); - mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); - mlx4_dbg(dev, "Max basic counters: %d\n", dev_cap->max_basic_counters); - mlx4_dbg(dev, "Max extended counters: %d\n", dev_cap->max_extended_counters); - mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz); - - dump_dev_cap_flags(dev, dev_cap->flags); - dump_dev_cap_flags2(dev, dev_cap->flags2); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u64 flags; - int err = 0; - u8 field; - - err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - - /* add port mng change event capability unconditionally to slaves */ - MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); - flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV; - MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); - - /* For guests, report Blueflame disabled */ - MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET); - field &= 0x7f; - MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET); - - /* turn off device-managed steering capability if not enabled */ - if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) { - MLX4_GET(field, outbox->buf, - QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); - field &= 0x7f; - MLX4_PUT(outbox->buf, field, - QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); - } - return 0; -} - -int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u64 def_mac; - u8 port_type; - u16 short_field; - int err; - int admin_link_state; - -#define MLX4_VF_PORT_NO_LINK_SENSE_MASK 0xE0 -#define MLX4_PORT_LINK_UP_MASK 0x80 -#define QUERY_PORT_CUR_MAX_PKEY_OFFSET 0x0c -#define QUERY_PORT_CUR_MAX_GID_OFFSET 0x0e - - err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0, - MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - - if (!err && dev->caps.function != slave) { - /* set slave default_mac address to be zero MAC */ - def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; - MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET); - - /* get port type - currently only eth is enabled */ - MLX4_GET(port_type, outbox->buf, - QUERY_PORT_SUPPORTED_TYPE_OFFSET); - - /* No link sensing allowed */ - port_type &= MLX4_VF_PORT_NO_LINK_SENSE_MASK; - /* set port type to currently operating port type */ - port_type |= (dev->caps.port_type[vhcr->in_modifier] & 0x3); - - admin_link_state = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.link_state; - if (IFLA_VF_LINK_STATE_ENABLE == admin_link_state) - port_type |= MLX4_PORT_LINK_UP_MASK; - else if (IFLA_VF_LINK_STATE_DISABLE == admin_link_state) - port_type &= ~MLX4_PORT_LINK_UP_MASK; - - MLX4_PUT(outbox->buf, port_type, - QUERY_PORT_SUPPORTED_TYPE_OFFSET); - - if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH) - short_field = mlx4_get_slave_num_gids(dev, slave); - else - short_field = 1; /* slave max gids */ - MLX4_PUT(outbox->buf, short_field, - QUERY_PORT_CUR_MAX_GID_OFFSET); - - short_field = dev->caps.pkey_table_len[vhcr->in_modifier]; - MLX4_PUT(outbox->buf, short_field, - QUERY_PORT_CUR_MAX_PKEY_OFFSET); - } - - return err; -} - -int mlx4_get_slave_pkey_gid_tbl_len(struct mlx4_dev *dev, u8 port, - int *gid_tbl_len, int *pkey_tbl_len) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - u16 field; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - err = mlx4_cmd_box(dev, 0, mailbox->dma, port, 0, - MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - goto out; - - outbox = mailbox->buf; - - MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_GID_OFFSET); - *gid_tbl_len = field; - - MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_PKEY_OFFSET); - *pkey_tbl_len = field; - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_get_slave_pkey_gid_tbl_len); - -int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_icm_iter iter; - __be64 *pages; - int lg; - int nent = 0; - int i; - int err = 0; - int ts = 0, tc = 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); - pages = mailbox->buf; - - for (mlx4_icm_first(icm, &iter); - !mlx4_icm_last(&iter); - mlx4_icm_next(&iter)) { - /* - * We have to pass pages that are aligned to their - * size, so find the least significant 1 in the - * address or size and use that as our log2 size. - */ - lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1; - if (lg < MLX4_ICM_PAGE_SHIFT) { - mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n", - MLX4_ICM_PAGE_SIZE, - (unsigned long long) mlx4_icm_addr(&iter), - mlx4_icm_size(&iter)); - err = -EINVAL; - goto out; - } - - for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) { - if (virt != -1) { - pages[nent * 2] = cpu_to_be64(virt); - virt += 1 << lg; - } - - pages[nent * 2 + 1] = - cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) | - (lg - MLX4_ICM_PAGE_SHIFT)); - ts += 1 << (lg - 10); - ++tc; - - if (++nent == MLX4_MAILBOX_SIZE / 16) { - err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, - MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - if (err) - goto out; - nent = 0; - } - } - } - - if (nent) - err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - if (err) - goto out; - - switch (op) { - case MLX4_CMD_MAP_FA: - mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts); - break; - case MLX4_CMD_MAP_ICM_AUX: - mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts); - break; - case MLX4_CMD_MAP_ICM: - mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n", - tc, ts, (unsigned long long) virt - (ts << 10)); - break; - } - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm) -{ - return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1); -} - -int mlx4_UNMAP_FA(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - - -int mlx4_RUN_FW(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -int mlx4_QUERY_FW(struct mlx4_dev *dev) -{ - struct mlx4_fw *fw = &mlx4_priv(dev)->fw; - struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - int err = 0; - u64 fw_ver; - u16 cmd_if_rev; - u8 lg; - -#define QUERY_FW_OUT_SIZE 0x100 -#define QUERY_FW_VER_OFFSET 0x00 -#define QUERY_FW_PPF_ID 0x09 -#define QUERY_FW_CMD_IF_REV_OFFSET 0x0a -#define QUERY_FW_MAX_CMD_OFFSET 0x0f -#define QUERY_FW_ERR_START_OFFSET 0x30 -#define QUERY_FW_ERR_SIZE_OFFSET 0x38 -#define QUERY_FW_ERR_BAR_OFFSET 0x3c - -#define QUERY_FW_SIZE_OFFSET 0x00 -#define QUERY_FW_CLR_INT_BASE_OFFSET 0x20 -#define QUERY_FW_CLR_INT_BAR_OFFSET 0x28 - -#define QUERY_FW_COMM_BASE_OFFSET 0x40 -#define QUERY_FW_COMM_BAR_OFFSET 0x48 - -#define QUERY_FW_CLOCK_OFFSET 0x50 -#define QUERY_FW_CLOCK_BAR 0x58 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET); - /* - * FW subminor version is at more significant bits than minor - * version, so swap here. - */ - dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) | - ((fw_ver & 0xffff0000ull) >> 16) | - ((fw_ver & 0x0000ffffull) << 16); - - MLX4_GET(lg, outbox, QUERY_FW_PPF_ID); - dev->caps.function = lg; - - if (mlx4_is_slave(dev)) - goto out; - - - MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET); - if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV || - cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) { - mlx4_err(dev, "Installed FW has unsupported " - "command interface revision %d.\n", - cmd_if_rev); - mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n", - (int) (dev->caps.fw_ver >> 32), - (int) (dev->caps.fw_ver >> 16) & 0xffff, - (int) dev->caps.fw_ver & 0xffff); - mlx4_err(dev, "This driver version supports only revisions %d to %d.\n", - MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV); - err = -ENODEV; - goto out; - } - - if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS) - dev->flags |= MLX4_FLAG_OLD_PORT_CMDS; - - MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); - cmd->max_cmds = 1 << lg; - - mlx4_dbg(dev, "FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n", - (int) (dev->caps.fw_ver >> 32), - (int) (dev->caps.fw_ver >> 16) & 0xffff, - (int) dev->caps.fw_ver & 0xffff, - cmd_if_rev, cmd->max_cmds); - - MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET); - MLX4_GET(fw->catas_size, outbox, QUERY_FW_ERR_SIZE_OFFSET); - MLX4_GET(fw->catas_bar, outbox, QUERY_FW_ERR_BAR_OFFSET); - fw->catas_bar = (fw->catas_bar >> 6) * 2; - - mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n", - (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar); - - MLX4_GET(fw->fw_pages, outbox, QUERY_FW_SIZE_OFFSET); - MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); - MLX4_GET(fw->clr_int_bar, outbox, QUERY_FW_CLR_INT_BAR_OFFSET); - fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2; - - MLX4_GET(fw->comm_base, outbox, QUERY_FW_COMM_BASE_OFFSET); - MLX4_GET(fw->comm_bar, outbox, QUERY_FW_COMM_BAR_OFFSET); - fw->comm_bar = (fw->comm_bar >> 6) * 2; - mlx4_dbg(dev, "Communication vector bar:%d offset:0x%llx\n", - fw->comm_bar, (unsigned long long)fw->comm_base); - mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2); - - MLX4_GET(fw->clock_offset, outbox, QUERY_FW_CLOCK_OFFSET); - MLX4_GET(fw->clock_bar, outbox, QUERY_FW_CLOCK_BAR); - fw->clock_bar = (fw->clock_bar >> 6) * 2; - mlx4_dbg(dev, "Internal clock bar:%d offset:0x%llx\n", - fw->comm_bar, (unsigned long long)fw->comm_base); - - /* - * Round up number of system pages needed in case - * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. - */ - fw->fw_pages = - ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> - (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); - - mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n", - (unsigned long long) fw->clr_int_base, fw->clr_int_bar); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_FW_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u8 *outbuf; - int err; - - outbuf = outbox->buf; - err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_FW, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - - /* for slaves, set pci PPF ID to invalid and zero out everything - * else except FW version */ - outbuf[0] = outbuf[1] = 0; - memset(&outbuf[8], 0, QUERY_FW_OUT_SIZE - 8); - outbuf[QUERY_FW_PPF_ID] = MLX4_INVALID_SLAVE_ID; - - return 0; -} - -static void get_board_id(void *vsd, char *board_id, char *vsdstr) -{ - int i; - -#define VSD_OFFSET_SIG1 0x00 -#define VSD_OFFSET_SIG2 0xde -#define VSD_OFFSET_MLX_BOARD_ID 0xd0 -#define VSD_OFFSET_TS_BOARD_ID 0x20 -#define VSD_LEN 0xd0 - -#define VSD_SIGNATURE_TOPSPIN 0x5ad - - memset(vsdstr, 0, MLX4_VSD_LEN); - - for (i = 0; i < VSD_LEN / 4; i++) - ((u32 *)vsdstr)[i] = - swab32(*(u32 *)(vsd + i * 4)); - - memset(board_id, 0, MLX4_BOARD_ID_LEN); - - if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN && - be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) { - strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN); - } else { - /* - * The board ID is a string but the firmware byte - * swaps each 4-byte word before passing it back to - * us. Therefore we need to swab it before printing. - */ - for (i = 0; i < 4; ++i) - ((u32 *) board_id)[i] = - swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4)); - } -} - -int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - int err; - -#define QUERY_ADAPTER_OUT_SIZE 0x100 -#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10 -#define QUERY_ADAPTER_VSD_OFFSET 0x20 -#define QUERY_ADAPTER_VSD_VENDOR_ID_OFFSET 0x1e - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - goto out; - - MLX4_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET); - - adapter->vsd_vendor_id = be16_to_cpup((u16 *)outbox + - QUERY_ADAPTER_VSD_VENDOR_ID_OFFSET / 2); - - get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4, - adapter->board_id, adapter->vsd); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) -{ - struct mlx4_cmd_mailbox *mailbox; - __be32 *inbox; - u32 mw_enable; - int err; - -#define INIT_HCA_IN_SIZE 0x200 -#define INIT_HCA_DRV_NAME_FOR_FW_MAX_SIZE 64 -#define INIT_HCA_VERSION_OFFSET 0x000 -#define INIT_HCA_VERSION 2 -#define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e -#define INIT_HCA_FLAGS_OFFSET 0x014 -#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018 -#define INIT_HCA_QPC_OFFSET 0x020 -#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) -#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) -#define INIT_HCA_SRQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x28) -#define INIT_HCA_LOG_SRQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x2f) -#define INIT_HCA_CQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x30) -#define INIT_HCA_LOG_CQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x37) -#define INIT_HCA_EQE_CQE_OFFSETS (INIT_HCA_QPC_OFFSET + 0x38) -#define INIT_HCA_ALTC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x40) -#define INIT_HCA_AUXC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50) -#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60) -#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67) -#define INIT_HCA_RDMARC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70) -#define INIT_HCA_LOG_RD_OFFSET (INIT_HCA_QPC_OFFSET + 0x77) -#define INIT_HCA_MCAST_OFFSET 0x0c0 -#define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) -#define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) -#define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) -#define INIT_HCA_UC_STEERING_OFFSET (INIT_HCA_MCAST_OFFSET + 0x18) -#define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) -#define INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN 0x6 -#define INIT_HCA_DRIVER_VERSION_OFFSET 0x140 -#define INIT_HCA_FS_PARAM_OFFSET 0x1d0 -#define INIT_HCA_FS_BASE_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x00) -#define INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x12) -#define INIT_HCA_FS_LOG_TABLE_SZ_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x1b) -#define INIT_HCA_FS_ETH_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x21) -#define INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22) -#define INIT_HCA_FS_IB_BITS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x25) -#define INIT_HCA_FS_IB_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x26) -#define INIT_HCA_TPT_OFFSET 0x0f0 -#define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) -#define INIT_HCA_TPT_MW_OFFSET (INIT_HCA_TPT_OFFSET + 0x08) -#define INIT_HCA_TPT_MW_ENABLE (1 << 31) -#define INIT_HCA_LOG_MPT_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x0b) -#define INIT_HCA_MTT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x10) -#define INIT_HCA_CMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x18) -#define INIT_HCA_UAR_OFFSET 0x120 -#define INIT_HCA_LOG_UAR_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0a) -#define INIT_HCA_UAR_PAGE_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0b) - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - memset(inbox, 0, INIT_HCA_IN_SIZE); - - *((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION; - - *((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) = - ((ilog2(cache_line_size()) - 4) << 5) | (1 << 4); - -#if defined(__LITTLE_ENDIAN) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1); -#elif defined(__BIG_ENDIAN) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1); -#else -#error Host endianness not defined -#endif - /* Check port for UD address vector: */ - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1); - - /* Enable IPoIB checksumming if we can: */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); - - /* Enable QoS support if module parameter set */ - if (enable_qos) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2); - - /* Enable fast drop performance optimization */ - if (dev->caps.fast_drop) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 7); - - /* enable counters */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS) - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4); - - /* CX3 is capable of extending CQEs\EQEs from 32 to 64 bytes */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_EQE) { - *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 29); - dev->caps.eqe_size = 64; - dev->caps.eqe_factor = 1; - } else { - dev->caps.eqe_size = 32; - dev->caps.eqe_factor = 0; - } - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_CQE) { - *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 30); - dev->caps.cqe_size = 64; - dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_64B_CQE; - } else { - dev->caps.cqe_size = 32; - } - - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) - *(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31); - - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW) { - strncpy((u8 *)mailbox->buf + INIT_HCA_DRIVER_VERSION_OFFSET, - DRV_NAME_FOR_FW, - INIT_HCA_DRV_NAME_FOR_FW_MAX_SIZE - 1); - mlx4_dbg(dev, "Reporting Driver Version to FW: %s\n", - (u8 *)mailbox->buf + INIT_HCA_DRIVER_VERSION_OFFSET); - } - - /* QPC/EEC/CQC/EQC/RDMARC attributes */ - - MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_qps, INIT_HCA_LOG_QP_OFFSET); - MLX4_PUT(inbox, param->srqc_base, INIT_HCA_SRQC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET); - MLX4_PUT(inbox, param->cqc_base, INIT_HCA_CQC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_cqs, INIT_HCA_LOG_CQ_OFFSET); - MLX4_PUT(inbox, param->altc_base, INIT_HCA_ALTC_BASE_OFFSET); - MLX4_PUT(inbox, param->auxc_base, INIT_HCA_AUXC_BASE_OFFSET); - MLX4_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET); - MLX4_PUT(inbox, param->rdmarc_base, INIT_HCA_RDMARC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET); - - /* steering attributes */ - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= - cpu_to_be32(1 << - INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN); - - MLX4_PUT(inbox, param->mc_base, INIT_HCA_FS_BASE_OFFSET); - MLX4_PUT(inbox, param->log_mc_entry_sz, - INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); - MLX4_PUT(inbox, param->log_mc_table_sz, - INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); - /* Enable Ethernet flow steering - * with udp unicast and tcp unicast - */ - MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN), - INIT_HCA_FS_ETH_BITS_OFFSET); - MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR, - INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET); - /* Enable IPoIB flow steering - * with udp unicast and tcp unicast - */ - MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN), - INIT_HCA_FS_IB_BITS_OFFSET); - MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR, - INIT_HCA_FS_IB_NUM_ADDRS_OFFSET); - } else { - MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); - MLX4_PUT(inbox, param->log_mc_entry_sz, - INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); - MLX4_PUT(inbox, param->log_mc_hash_sz, - INIT_HCA_LOG_MC_HASH_SZ_OFFSET); - MLX4_PUT(inbox, param->log_mc_table_sz, - INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); - if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0) - MLX4_PUT(inbox, (u8) (1 << 3), - INIT_HCA_UC_STEERING_OFFSET); - } - - /* TPT attributes */ - - MLX4_PUT(inbox, param->dmpt_base, INIT_HCA_DMPT_BASE_OFFSET); - mw_enable = param->mw_enable ? INIT_HCA_TPT_MW_ENABLE : 0; - MLX4_PUT(inbox, mw_enable, INIT_HCA_TPT_MW_OFFSET); - MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET); - MLX4_PUT(inbox, param->mtt_base, INIT_HCA_MTT_BASE_OFFSET); - MLX4_PUT(inbox, param->cmpt_base, INIT_HCA_CMPT_BASE_OFFSET); - - /* UAR attributes */ - - MLX4_PUT(inbox, param->uar_page_sz, INIT_HCA_UAR_PAGE_SZ_OFFSET); - MLX4_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); - - err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000, - MLX4_CMD_NATIVE); - - if (err) - mlx4_err(dev, "INIT_HCA returns %d\n", err); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_QUERY_HCA(struct mlx4_dev *dev, - struct mlx4_init_hca_param *param) -{ - struct mlx4_cmd_mailbox *mailbox; - __be32 *outbox; - u32 dword_field; - u32 mw_enable; - int err; - u8 byte_field; - -#define QUERY_HCA_GLOBAL_CAPS_OFFSET 0x04 -#define QUERY_HCA_CORE_CLOCK_OFFSET 0x0c - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, - MLX4_CMD_QUERY_HCA, - MLX4_CMD_TIME_CLASS_B, - !mlx4_is_slave(dev)); - if (err) - goto out; - - MLX4_GET(param->global_caps, outbox, QUERY_HCA_GLOBAL_CAPS_OFFSET); - MLX4_GET(param->hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET); - - /* QPC/EEC/CQC/EQC/RDMARC attributes */ - - MLX4_GET(param->qpc_base, outbox, INIT_HCA_QPC_BASE_OFFSET); - MLX4_GET(param->log_num_qps, outbox, INIT_HCA_LOG_QP_OFFSET); - MLX4_GET(param->srqc_base, outbox, INIT_HCA_SRQC_BASE_OFFSET); - MLX4_GET(param->log_num_srqs, outbox, INIT_HCA_LOG_SRQ_OFFSET); - MLX4_GET(param->cqc_base, outbox, INIT_HCA_CQC_BASE_OFFSET); - MLX4_GET(param->log_num_cqs, outbox, INIT_HCA_LOG_CQ_OFFSET); - MLX4_GET(param->altc_base, outbox, INIT_HCA_ALTC_BASE_OFFSET); - MLX4_GET(param->auxc_base, outbox, INIT_HCA_AUXC_BASE_OFFSET); - MLX4_GET(param->eqc_base, outbox, INIT_HCA_EQC_BASE_OFFSET); - MLX4_GET(param->log_num_eqs, outbox, INIT_HCA_LOG_EQ_OFFSET); - MLX4_GET(param->rdmarc_base, outbox, INIT_HCA_RDMARC_BASE_OFFSET); - MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET); - - MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET); - if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) { - param->steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED; - } else { - MLX4_GET(byte_field, outbox, INIT_HCA_UC_STEERING_OFFSET); - if (byte_field & 0x8) - param->steering_mode = MLX4_STEERING_MODE_B0; - else - param->steering_mode = MLX4_STEERING_MODE_A0; - } - /* steering attributes */ - if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { - MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET); - MLX4_GET(param->log_mc_entry_sz, outbox, - INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); - MLX4_GET(param->log_mc_table_sz, outbox, - INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); - } else { - MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET); - MLX4_GET(param->log_mc_entry_sz, outbox, - INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); - MLX4_GET(param->log_mc_hash_sz, outbox, - INIT_HCA_LOG_MC_HASH_SZ_OFFSET); - MLX4_GET(param->log_mc_table_sz, outbox, - INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); - } - - /* CX3 is capable of extending CQEs\EQEs from 32 to 64 bytes */ - MLX4_GET(byte_field, outbox, INIT_HCA_EQE_CQE_OFFSETS); - if (byte_field & 0x20) /* 64-bytes eqe enabled */ - param->dev_cap_enabled |= MLX4_DEV_CAP_64B_EQE_ENABLED; - if (byte_field & 0x40) /* 64-bytes cqe enabled */ - param->dev_cap_enabled |= MLX4_DEV_CAP_64B_CQE_ENABLED; - - /* TPT attributes */ - - MLX4_GET(param->dmpt_base, outbox, INIT_HCA_DMPT_BASE_OFFSET); - MLX4_GET(mw_enable, outbox, INIT_HCA_TPT_MW_OFFSET); - param->mw_enable = (mw_enable & INIT_HCA_TPT_MW_ENABLE) == - INIT_HCA_TPT_MW_ENABLE; - MLX4_GET(param->log_mpt_sz, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET); - MLX4_GET(param->mtt_base, outbox, INIT_HCA_MTT_BASE_OFFSET); - MLX4_GET(param->cmpt_base, outbox, INIT_HCA_CMPT_BASE_OFFSET); - - /* UAR attributes */ - - MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET); - MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET); - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - - return err; -} - -/* for IB-type ports only in SRIOV mode. Checks that both proxy QP0 - * and real QP0 are active, so that the paravirtualized QP0 is ready - * to operate */ -static int check_qp0_state(struct mlx4_dev *dev, int function, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - /* irrelevant if not infiniband */ - if (priv->mfunc.master.qp0_state[port].proxy_qp0_active && - priv->mfunc.master.qp0_state[port].qp0_active) - return 1; - return 0; -} - -int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int port = vhcr->in_modifier; - int err; - - if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port)) - return 0; - - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { - /* Enable port only if it was previously disabled */ - if (!priv->mfunc.master.init_port_ref[port]) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - } - priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); - } else { - if (slave == mlx4_master_func_num(dev)) { - if (check_qp0_state(dev, slave, port) && - !priv->mfunc.master.qp0_state[port].port_active) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (err) - return err; - priv->mfunc.master.qp0_state[port].port_active = 1; - priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); - } - } else - priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); - } - ++priv->mfunc.master.init_port_ref[port]; - return 0; -} - -int mlx4_INIT_PORT(struct mlx4_dev *dev, int port) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *inbox; - int err; - u32 flags; - u16 field; - - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { -#define INIT_PORT_IN_SIZE 256 -#define INIT_PORT_FLAGS_OFFSET 0x00 -#define INIT_PORT_FLAG_SIG (1 << 18) -#define INIT_PORT_FLAG_NG (1 << 17) -#define INIT_PORT_FLAG_G0 (1 << 16) -#define INIT_PORT_VL_SHIFT 4 -#define INIT_PORT_PORT_WIDTH_SHIFT 8 -#define INIT_PORT_MTU_OFFSET 0x04 -#define INIT_PORT_MAX_GID_OFFSET 0x06 -#define INIT_PORT_MAX_PKEY_OFFSET 0x0a -#define INIT_PORT_GUID0_OFFSET 0x10 -#define INIT_PORT_NODE_GUID_OFFSET 0x18 -#define INIT_PORT_SI_GUID_OFFSET 0x20 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - memset(inbox, 0, INIT_PORT_IN_SIZE); - - flags = 0; - flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT; - flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT; - MLX4_PUT(inbox, flags, INIT_PORT_FLAGS_OFFSET); - - field = 128 << dev->caps.ib_mtu_cap[port]; - MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET); - field = dev->caps.gid_table_len[port]; - MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET); - field = dev->caps.pkey_table_len[port]; - MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET); - - err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - } else - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_INIT_PORT); - -int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int port = vhcr->in_modifier; - int err; - - if (!(priv->mfunc.master.slave_state[slave].init_port_mask & - (1 << port))) - return 0; - - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { - if (priv->mfunc.master.init_port_ref[port] == 1) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); - if (err) - return err; - } - priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); - } else { - /* infiniband port */ - if (slave == mlx4_master_func_num(dev)) { - if (!priv->mfunc.master.qp0_state[port].qp0_active && - priv->mfunc.master.qp0_state[port].port_active) { - err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); - if (err) - return err; - priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); - priv->mfunc.master.qp0_state[port].port_active = 0; - } - } else - priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); - } - --priv->mfunc.master.init_port_ref[port]; - return 0; -} - -int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port) -{ - return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000, - MLX4_CMD_WRAPPED); -} -EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT); - -int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic) -{ - return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000, - MLX4_CMD_NATIVE); -} - -int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) -{ - int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0, - MLX4_CMD_SET_ICM_SIZE, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (ret) - return ret; - - /* - * Round up number of system pages needed in case - * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. - */ - *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> - (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); - - return 0; -} - -int mlx4_NOP(struct mlx4_dev *dev) -{ - /* Input modifier of 0x1f means "finish as soon as possible." */ - return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -int mlx4_query_diag_counters(struct mlx4_dev *dev, int array_length, - u8 op_modifier, u32 in_offset[], - u32 counter_out[]) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 *outbox; - int ret; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - outbox = mailbox->buf; - - ret = mlx4_cmd_box(dev, 0, mailbox->dma, 0, op_modifier, - MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (ret) - goto out; - - for (i = 0; i < array_length; i++) { - if (in_offset[i] > MLX4_MAILBOX_SIZE) { - ret = -EINVAL; - goto out; - } - - MLX4_GET(counter_out[i], outbox, in_offset[i]); - } - -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_query_diag_counters); - -int mlx4_MOD_STAT_CFG_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return -EPERM; -} - -#define MLX4_WOL_SETUP_MODE (5 << 28) -int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) -{ - u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; - - return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3, - MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); -} -EXPORT_SYMBOL_GPL(mlx4_wol_read); - -int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) -{ - u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; - - return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} -EXPORT_SYMBOL_GPL(mlx4_wol_write); - -enum { - ADD_TO_MCG = 0x26, -}; - - -void mlx4_opreq_action(struct work_struct *work) -{ - struct mlx4_priv *priv = container_of(work, struct mlx4_priv, opreq_task); - struct mlx4_dev *dev = &priv->dev; - int num_tasks = atomic_read(&priv->opreq_count); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 *outbox; - u32 modifier; - u16 token; - u16 type_m; - u16 type; - int err; - u32 num_qps; - struct mlx4_qp qp; - int i; - u8 rem_mcg; - u8 prot; - -#define GET_OP_REQ_MODIFIER_OFFSET 0x08 -#define GET_OP_REQ_TOKEN_OFFSET 0x14 -#define GET_OP_REQ_TYPE_OFFSET 0x1a -#define GET_OP_REQ_DATA_OFFSET 0x20 - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n"); - return; - } - outbox = mailbox->buf; - - while (num_tasks) { - err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, - MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) { - mlx4_err(dev, "Failed to retrieve required operation: %d\n", err); - return; - } - MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET); - MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET); - MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET); - type_m = type >> 12; - type &= 0xfff; - - switch (type) { - case ADD_TO_MCG: - if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { - mlx4_warn(dev, "ADD MCG operation is not supported in " - "DEVICE_MANAGED steerign mode\n"); - err = EPERM; - break; - } - mgm = (struct mlx4_mgm *) ((u8 *) (outbox) + GET_OP_REQ_DATA_OFFSET); - num_qps = be32_to_cpu(mgm->members_count) & MGM_QPN_MASK; - rem_mcg = ((u8 *) (&mgm->members_count))[0] & 1; - prot = ((u8 *) (&mgm->members_count))[0] >> 6; - - for (i = 0; i < num_qps; i++) { - qp.qpn = be32_to_cpu(mgm->qp[i]); - if (rem_mcg) - err = mlx4_multicast_detach(dev, &qp, mgm->gid, prot, 0); - else - err = mlx4_multicast_attach(dev, &qp, mgm->gid, mgm->gid[5] ,0, prot, NULL); - if (err) - break; - } - break; - default: - mlx4_warn(dev, "Bad type for required operation\n"); - err = EINVAL; - break; - } - err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16), 1, - MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) { - mlx4_err(dev, "Failed to acknowledge required request: %d\n", err); - goto out; - } - memset(outbox, 0, 0xffc); - num_tasks = atomic_dec_return(&priv->opreq_count); - } - -out: - mlx4_free_cmd_mailbox(dev, mailbox); -} diff --git a/sys/ofed/drivers/net/mlx4/fw.h b/sys/ofed/drivers/net/mlx4/fw.h deleted file mode 100644 index 0efd047ec3ad..000000000000 --- a/sys/ofed/drivers/net/mlx4/fw.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems. 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. - */ - -#ifndef MLX4_FW_H -#define MLX4_FW_H - -#include "mlx4.h" -#include "icm.h" - -struct mlx4_mod_stat_cfg { - u8 log_pg_sz; - u8 log_pg_sz_m; -}; - -struct mlx4_dev_cap { - int max_srq_sz; - int max_qp_sz; - int reserved_qps; - int max_qps; - int reserved_srqs; - int max_srqs; - int max_cq_sz; - int reserved_cqs; - int max_cqs; - int max_mpts; - int reserved_eqs; - int max_eqs; - int reserved_mtts; - int max_mrw_sz; - int reserved_mrws; - int max_mtt_seg; - int max_requester_per_qp; - int max_responder_per_qp; - int max_rdma_global; - int local_ca_ack_delay; - int num_ports; - u32 max_msg_sz; - int ib_mtu[MLX4_MAX_PORTS + 1]; - int max_port_width[MLX4_MAX_PORTS + 1]; - int max_vl[MLX4_MAX_PORTS + 1]; - int max_gids[MLX4_MAX_PORTS + 1]; - int max_pkeys[MLX4_MAX_PORTS + 1]; - u64 def_mac[MLX4_MAX_PORTS + 1]; - u16 eth_mtu[MLX4_MAX_PORTS + 1]; - int trans_type[MLX4_MAX_PORTS + 1]; - int vendor_oui[MLX4_MAX_PORTS + 1]; - u16 wavelength[MLX4_MAX_PORTS + 1]; - u64 trans_code[MLX4_MAX_PORTS + 1]; - u16 stat_rate_support; - int fs_log_max_ucast_qp_range_size; - int fs_max_num_qp_per_entry; - u64 flags; - u64 flags2; - int reserved_uars; - int uar_size; - int min_page_sz; - int bf_reg_size; - int bf_regs_per_page; - int max_sq_sg; - int max_sq_desc_sz; - int max_rq_sg; - int max_rq_desc_sz; - int max_qp_per_mcg; - int reserved_mgms; - int max_mcgs; - int reserved_pds; - int max_pds; - int reserved_xrcds; - int max_xrcds; - int qpc_entry_sz; - int rdmarc_entry_sz; - int altc_entry_sz; - int aux_entry_sz; - int srq_entry_sz; - int cqc_entry_sz; - int eqc_entry_sz; - int dmpt_entry_sz; - int cmpt_entry_sz; - int mtt_entry_sz; - int resize_srq; - u32 bmme_flags; - u32 reserved_lkey; - u64 max_icm_sz; - int max_gso_sz; - int max_rss_tbl_sz; - u8 supported_port_types[MLX4_MAX_PORTS + 1]; - u8 suggested_type[MLX4_MAX_PORTS + 1]; - u8 default_sense[MLX4_MAX_PORTS + 1]; - u8 log_max_macs[MLX4_MAX_PORTS + 1]; - u8 log_max_vlans[MLX4_MAX_PORTS + 1]; - u32 max_basic_counters; - u32 sync_qp; - u8 timestamp_support; - u32 max_extended_counters; -}; - -struct mlx4_func_cap { - u8 num_ports; - u8 flags; - u32 pf_context_behaviour; - int qp_quota; - int cq_quota; - int srq_quota; - int mpt_quota; - int mtt_quota; - int max_eq; - int reserved_eq; - int mcg_quota; - u32 qp0_tunnel_qpn; - u32 qp0_proxy_qpn; - u32 qp1_tunnel_qpn; - u32 qp1_proxy_qpn; - u8 physical_port; - u8 port_flags; - u8 def_counter_index; -}; - -struct mlx4_adapter { - u16 vsd_vendor_id; - char board_id[MLX4_BOARD_ID_LEN]; - char vsd[MLX4_VSD_LEN]; - u8 inta_pin; -}; - -struct mlx4_init_hca_param { - u64 qpc_base; - u64 rdmarc_base; - u64 auxc_base; - u64 altc_base; - u64 srqc_base; - u64 cqc_base; - u64 eqc_base; - u64 mc_base; - u64 dmpt_base; - u64 cmpt_base; - u64 mtt_base; - u64 global_caps; - u16 log_mc_entry_sz; - u16 log_mc_hash_sz; - u16 hca_core_clock; - u8 log_num_qps; - u8 log_num_srqs; - u8 log_num_cqs; - u8 log_num_eqs; - u8 log_rd_per_qp; - u8 log_mc_table_sz; - u8 log_mpt_sz; - u8 log_uar_sz; - u8 uar_page_sz; /* log pg sz in 4k chunks */ - u8 mw_enable; /* Enable memory windows */ - u8 fs_hash_enable_bits; - u8 steering_mode; /* for QUERY_HCA */ - u64 dev_cap_enabled; -}; - -struct mlx4_init_ib_param { - int port_width; - int vl_cap; - int mtu_cap; - u16 gid_cap; - u16 pkey_cap; - int set_guid0; - u64 guid0; - int set_node_guid; - u64 node_guid; - int set_si_guid; - u64 si_guid; -}; - -struct mlx4_set_ib_param { - int set_si_guid; - int reset_qkey_viol; - u64 si_guid; - u32 cap_mask; -}; - -int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap); -int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port, - struct mlx4_func_cap *func_cap); -int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm); -int mlx4_UNMAP_FA(struct mlx4_dev *dev); -int mlx4_RUN_FW(struct mlx4_dev *dev); -int mlx4_QUERY_FW(struct mlx4_dev *dev); -int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter); -int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param); -int mlx4_QUERY_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param); -int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic); -int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt); -int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages); -int mlx4_NOP(struct mlx4_dev *dev); -int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg); -void mlx4_opreq_action(struct work_struct *work); - -#endif /* MLX4_FW_H */ diff --git a/sys/ofed/drivers/net/mlx4/icm.c b/sys/ofed/drivers/net/mlx4/icm.c deleted file mode 100644 index 25ae7b7fb8cc..000000000000 --- a/sys/ofed/drivers/net/mlx4/icm.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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/errno.h> -#include <linux/mm.h> -#include <linux/scatterlist.h> -#include <linux/slab.h> -#include <linux/math64.h> - -#include <linux/mlx4/cmd.h> - -#include "mlx4.h" -#include "icm.h" -#include "fw.h" - -/* - * We allocate in as big chunks as we can, up to a maximum of 256 KB - * per chunk. - */ -enum { - MLX4_ICM_ALLOC_SIZE = 1 << 18, - MLX4_TABLE_CHUNK_SIZE = 1 << 18 -}; - -static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) -{ - int i; - - if (chunk->nsg > 0) - pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, - PCI_DMA_BIDIRECTIONAL); - - for (i = 0; i < chunk->npages; ++i) - __free_pages(sg_page(&chunk->mem[i]), - get_order(chunk->mem[i].length)); -} - -static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) -{ - int i; - - for (i = 0; i < chunk->npages; ++i) - dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, - lowmem_page_address(sg_page(&chunk->mem[i])), - sg_dma_address(&chunk->mem[i])); -} - -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent) -{ - struct mlx4_icm_chunk *chunk, *tmp; - - if (!icm) - return; - - list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { - if (coherent) - mlx4_free_icm_coherent(dev, chunk); - else - mlx4_free_icm_pages(dev, chunk); - - kfree(chunk); - } - - kfree(icm); -} - -static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, - gfp_t gfp_mask, int node) -{ - struct page *page; - - page = alloc_pages_node(node, gfp_mask, order); - if (!page) { - page = alloc_pages(gfp_mask, order); - if (!page) - return -ENOMEM; - } - - sg_set_page(mem, page, PAGE_SIZE << order, 0); - return 0; -} - -static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, - int order, gfp_t gfp_mask) -{ - void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, - &sg_dma_address(mem), gfp_mask); - if (!buf) - return -ENOMEM; - - sg_set_buf(mem, buf, PAGE_SIZE << order); - BUG_ON(mem->offset); - sg_dma_len(mem) = PAGE_SIZE << order; - return 0; -} - -struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, - gfp_t gfp_mask, int coherent) -{ - struct mlx4_icm *icm; - struct mlx4_icm_chunk *chunk = NULL; - int cur_order; - int ret; - - /* We use sg_set_buf for coherent allocs, which assumes low memory */ - BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); - - icm = kmalloc_node(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN), - dev->numa_node); - if (!icm) { - icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); - if (!icm) - return NULL; - } - - icm->refcount = 0; - INIT_LIST_HEAD(&icm->chunk_list); - - cur_order = get_order(MLX4_ICM_ALLOC_SIZE); - - while (npages > 0) { - if (!chunk) { - chunk = kmalloc_node(sizeof *chunk, - gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN), - dev->numa_node); - if (!chunk) { - chunk = kmalloc(sizeof *chunk, - gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); - if (!chunk) - goto fail; - } - - sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN); - chunk->npages = 0; - chunk->nsg = 0; - list_add_tail(&chunk->list, &icm->chunk_list); - } - - while (1 << cur_order > npages) - --cur_order; - - if (coherent) - ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, - &chunk->mem[chunk->npages], - cur_order, gfp_mask); - else - ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages], - cur_order, gfp_mask, - dev->numa_node); - - if (ret) { - if (--cur_order < 0) - goto fail; - else - continue; - } - - ++chunk->npages; - - if (coherent) - ++chunk->nsg; - else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, - chunk->npages, - PCI_DMA_BIDIRECTIONAL); - - if (chunk->nsg <= 0) - goto fail; - } - - if (chunk->npages == MLX4_ICM_CHUNK_LEN) - chunk = NULL; - - npages -= 1 << cur_order; - } - - if (!coherent && chunk) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, - chunk->npages, - PCI_DMA_BIDIRECTIONAL); - - if (chunk->nsg <= 0) - goto fail; - } - - return icm; - -fail: - mlx4_free_icm(dev, icm, coherent); - return NULL; -} - -static int mlx4_MAP_ICM(struct mlx4_dev *dev, struct mlx4_icm *icm, u64 virt) -{ - return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM, icm, virt); -} - -static int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count) -{ - return mlx4_cmd(dev, virt, page_count, 0, MLX4_CMD_UNMAP_ICM, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - -int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm) -{ - return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM_AUX, icm, -1); -} - -int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_ICM_AUX, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - -int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj) -{ - u32 i = (obj & (table->num_obj - 1)) / - (MLX4_TABLE_CHUNK_SIZE / table->obj_size); - int ret = 0; - - mutex_lock(&table->mutex); - - if (table->icm[i]) { - ++table->icm[i]->refcount; - goto out; - } - - table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT, - (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN, table->coherent); - if (!table->icm[i]) { - ret = -ENOMEM; - goto out; - } - - if (mlx4_MAP_ICM(dev, table->icm[i], table->virt + - (u64) i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i], table->coherent); - table->icm[i] = NULL; - ret = -ENOMEM; - goto out; - } - - ++table->icm[i]->refcount; - -out: - mutex_unlock(&table->mutex); - return ret; -} - -void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj) -{ - u32 i; - u64 offset; - - i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); - - mutex_lock(&table->mutex); - - if (--table->icm[i]->refcount == 0) { - offset = (u64) i * MLX4_TABLE_CHUNK_SIZE; - - if (!mlx4_UNMAP_ICM(dev, table->virt + offset, - MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE)) { - mlx4_free_icm(dev, table->icm[i], table->coherent); - table->icm[i] = NULL; - } else { - pr_warn("mlx4_core: mlx4_UNMAP_ICM failed.\n"); - } - } - - mutex_unlock(&table->mutex); -} - -void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, - dma_addr_t *dma_handle) -{ - int offset, dma_offset, i; - u64 idx; - struct mlx4_icm_chunk *chunk; - struct mlx4_icm *icm; - struct page *page = NULL; - - if (!table->lowmem) - return NULL; - - mutex_lock(&table->mutex); - - idx = (u64) (obj & (table->num_obj - 1)) * table->obj_size; - icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; - dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; - - if (!icm) - goto out; - - list_for_each_entry(chunk, &icm->chunk_list, list) { - for (i = 0; i < chunk->npages; ++i) { - if (dma_handle && dma_offset >= 0) { - if (sg_dma_len(&chunk->mem[i]) > dma_offset) - *dma_handle = sg_dma_address(&chunk->mem[i]) + - dma_offset; - dma_offset -= sg_dma_len(&chunk->mem[i]); - } - /* - * DMA mapping can merge pages but not split them, - * so if we found the page, dma_handle has already - * been assigned to. - */ - if (chunk->mem[i].length > offset) { - page = sg_page(&chunk->mem[i]); - goto out; - } - offset -= chunk->mem[i].length; - } - } - -out: - mutex_unlock(&table->mutex); - return page ? lowmem_page_address(page) + offset : NULL; -} - -int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end) -{ - int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size; - int err; - u32 i; - - for (i = start; i <= end; i += inc) { - err = mlx4_table_get(dev, table, i); - if (err) - goto fail; - } - - return 0; - -fail: - while (i > start) { - i -= inc; - mlx4_table_put(dev, table, i); - } - - return err; -} - -void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end) -{ - u32 i; - - for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size) - mlx4_table_put(dev, table, i); -} - -int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u64 virt, int obj_size, u64 nobj, int reserved, - int use_lowmem, int use_coherent) -{ - int obj_per_chunk; - int num_icm; - unsigned chunk_size; - int i; - u64 size; - - obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size; - num_icm = div_u64((nobj + obj_per_chunk - 1), obj_per_chunk); - - table->icm = kcalloc(num_icm, sizeof *table->icm, GFP_KERNEL); - if (!table->icm) - return -ENOMEM; - table->virt = virt; - table->num_icm = num_icm; - table->num_obj = nobj; - table->obj_size = obj_size; - table->lowmem = use_lowmem; - table->coherent = use_coherent; - mutex_init(&table->mutex); - - size = (u64) nobj * obj_size; - for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { - chunk_size = MLX4_TABLE_CHUNK_SIZE; - if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > size) - chunk_size = PAGE_ALIGN(size - - i * MLX4_TABLE_CHUNK_SIZE); - - table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT, - (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN, use_coherent); - if (!table->icm[i]) - goto err; - if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i], use_coherent); - table->icm[i] = NULL; - goto err; - } - - /* - * Add a reference to this ICM chunk so that it never - * gets freed (since it contains reserved firmware objects). - */ - ++table->icm[i]->refcount; - } - - return 0; - -err: - for (i = 0; i < num_icm; ++i) - if (table->icm[i]) { - if (!mlx4_UNMAP_ICM(dev, - virt + i * MLX4_TABLE_CHUNK_SIZE, - MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE)) { - mlx4_free_icm(dev, table->icm[i], use_coherent); - } else { - pr_warn("mlx4_core: mlx4_UNMAP_ICM failed.\n"); - return -ENOMEM; - } - } - kfree(table->icm); - - return -ENOMEM; -} - -void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table) -{ - int i, err = 0; - - for (i = 0; i < table->num_icm; ++i) - if (table->icm[i]) { - err = mlx4_UNMAP_ICM(dev, - table->virt + i * MLX4_TABLE_CHUNK_SIZE, - MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - if (!err) { - mlx4_free_icm(dev, table->icm[i], - table->coherent); - } else { - pr_warn("mlx4_core: mlx4_UNMAP_ICM failed.\n"); - break; - } - } - - if (!err) - kfree(table->icm); -} diff --git a/sys/ofed/drivers/net/mlx4/icm.h b/sys/ofed/drivers/net/mlx4/icm.h deleted file mode 100644 index f7a2537bfbc0..000000000000 --- a/sys/ofed/drivers/net/mlx4/icm.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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. - */ - -#ifndef MLX4_ICM_H -#define MLX4_ICM_H - -#include <linux/list.h> -#include <linux/pci.h> -#include <linux/mutex.h> -#include <linux/scatterlist.h> - -#define MLX4_ICM_CHUNK_LEN \ - ((256 - sizeof (struct list_head) - 2 * sizeof (int)) / \ - (sizeof (struct scatterlist))) - -enum { - MLX4_ICM_PAGE_SHIFT = 12, - MLX4_ICM_PAGE_SIZE = 1 << MLX4_ICM_PAGE_SHIFT, -}; - -struct mlx4_icm_chunk { - struct list_head list; - int npages; - int nsg; - struct scatterlist mem[MLX4_ICM_CHUNK_LEN]; -}; - -struct mlx4_icm { - struct list_head chunk_list; - int refcount; -}; - -struct mlx4_icm_iter { - struct mlx4_icm *icm; - struct mlx4_icm_chunk *chunk; - int page_idx; -}; - -struct mlx4_dev; - -struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, - gfp_t gfp_mask, int coherent); -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); - -int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); -void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); -int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end); -void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u32 start, u32 end); -int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, - u64 virt, int obj_size, u64 nobj, int reserved, - int use_lowmem, int use_coherent); -void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); -void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, dma_addr_t *dma_handle); - -static inline void mlx4_icm_first(struct mlx4_icm *icm, - struct mlx4_icm_iter *iter) -{ - iter->icm = icm; - iter->chunk = list_empty(&icm->chunk_list) ? - NULL : list_entry(icm->chunk_list.next, - struct mlx4_icm_chunk, list); - iter->page_idx = 0; -} - -static inline int mlx4_icm_last(struct mlx4_icm_iter *iter) -{ - return !iter->chunk; -} - -static inline void mlx4_icm_next(struct mlx4_icm_iter *iter) -{ - if (++iter->page_idx >= iter->chunk->nsg) { - if (iter->chunk->list.next == &iter->icm->chunk_list) { - iter->chunk = NULL; - return; - } - - iter->chunk = list_entry(iter->chunk->list.next, - struct mlx4_icm_chunk, list); - iter->page_idx = 0; - } -} - -static inline dma_addr_t mlx4_icm_addr(struct mlx4_icm_iter *iter) -{ - return sg_dma_address(&iter->chunk->mem[iter->page_idx]); -} - -static inline unsigned long mlx4_icm_size(struct mlx4_icm_iter *iter) -{ - return sg_dma_len(&iter->chunk->mem[iter->page_idx]); -} - -int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm); -int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev); - -#endif /* MLX4_ICM_H */ diff --git a/sys/ofed/drivers/net/mlx4/intf.c b/sys/ofed/drivers/net/mlx4/intf.c deleted file mode 100644 index 141629801d2f..000000000000 --- a/sys/ofed/drivers/net/mlx4/intf.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 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/slab.h> -#include <linux/module.h> - -#include "mlx4.h" - -struct mlx4_device_context { - struct list_head list; - struct mlx4_interface *intf; - void *context; -}; - -static LIST_HEAD(intf_list); -static LIST_HEAD(dev_list); -static DEFINE_MUTEX(intf_mutex); - -static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv) -{ - struct mlx4_device_context *dev_ctx; - - dev_ctx = kmalloc(sizeof *dev_ctx, GFP_KERNEL); - if (!dev_ctx) - return; - - dev_ctx->intf = intf; - dev_ctx->context = intf->add(&priv->dev); - - if (dev_ctx->context) { - spin_lock_irq(&priv->ctx_lock); - list_add_tail(&dev_ctx->list, &priv->ctx_list); - spin_unlock_irq(&priv->ctx_lock); - } else - kfree(dev_ctx); -} - -static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv) -{ - struct mlx4_device_context *dev_ctx; - - list_for_each_entry(dev_ctx, &priv->ctx_list, list) - if (dev_ctx->intf == intf) { - spin_lock_irq(&priv->ctx_lock); - list_del(&dev_ctx->list); - spin_unlock_irq(&priv->ctx_lock); - - intf->remove(&priv->dev, dev_ctx->context); - kfree(dev_ctx); - return; - } -} - -int mlx4_register_interface(struct mlx4_interface *intf) -{ - struct mlx4_priv *priv; - - if (!intf->add || !intf->remove) - return -EINVAL; - - mutex_lock(&intf_mutex); - - list_add_tail(&intf->list, &intf_list); - list_for_each_entry(priv, &dev_list, dev_list) - mlx4_add_device(intf, priv); - - mutex_unlock(&intf_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_register_interface); - -void mlx4_unregister_interface(struct mlx4_interface *intf) -{ - struct mlx4_priv *priv; - - mutex_lock(&intf_mutex); - - list_for_each_entry(priv, &dev_list, dev_list) - mlx4_remove_device(intf, priv); - - list_del(&intf->list); - - mutex_unlock(&intf_mutex); -} -EXPORT_SYMBOL_GPL(mlx4_unregister_interface); - -void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, - unsigned long param) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_device_context *dev_ctx; - unsigned long flags; - - spin_lock_irqsave(&priv->ctx_lock, flags); - - list_for_each_entry(dev_ctx, &priv->ctx_list, list) - if (dev_ctx->intf->event) - dev_ctx->intf->event(dev, dev_ctx->context, type, param); - - spin_unlock_irqrestore(&priv->ctx_lock, flags); -} - -int mlx4_register_device(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_interface *intf; - - mutex_lock(&intf_mutex); - - list_add_tail(&priv->dev_list, &dev_list); - list_for_each_entry(intf, &intf_list, list) - mlx4_add_device(intf, priv); - - mutex_unlock(&intf_mutex); - if (!mlx4_is_slave(dev)) - mlx4_start_catas_poll(dev); - - return 0; -} - -void mlx4_unregister_device(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_interface *intf; - - if (!mlx4_is_slave(dev)) - mlx4_stop_catas_poll(dev); - mutex_lock(&intf_mutex); - - list_for_each_entry(intf, &intf_list, list) - mlx4_remove_device(intf, priv); - - list_del_init(&priv->dev_list); - - mutex_unlock(&intf_mutex); -} - -void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_device_context *dev_ctx; - unsigned long flags; - void *result = NULL; - - spin_lock_irqsave(&priv->ctx_lock, flags); - - list_for_each_entry(dev_ctx, &priv->ctx_list, list) - if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) { - result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port); - break; - } - - spin_unlock_irqrestore(&priv->ctx_lock, flags); - - return result; -} -EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev); diff --git a/sys/ofed/drivers/net/mlx4/main.c b/sys/ofed/drivers/net/mlx4/main.c deleted file mode 100644 index 78e8f1bb585e..000000000000 --- a/sys/ofed/drivers/net/mlx4/main.c +++ /dev/null @@ -1,3883 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/kmod.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/io-mapping.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/string.h> -#include <linux/fs.h> - -#include <linux/mlx4/device.h> -#include <linux/mlx4/doorbell.h> - -#include "mlx4.h" -#include "fw.h" -#include "icm.h" -#include "mlx4_stats.h" - -/* Mellanox ConnectX HCA low-level driver */ - -struct workqueue_struct *mlx4_wq; - -#ifdef CONFIG_MLX4_DEBUG - -int mlx4_debug_level = 0; -module_param_named(debug_level, mlx4_debug_level, int, 0644); -MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); - -#endif /* CONFIG_MLX4_DEBUG */ - -#ifdef CONFIG_PCI_MSI - -static int msi_x = 1; -module_param(msi_x, int, 0444); -MODULE_PARM_DESC(msi_x, "0 - don't use MSI-X, 1 - use MSI-X, >1 - limit number of MSI-X irqs to msi_x (non-SRIOV only)"); - -#else /* CONFIG_PCI_MSI */ - -#define msi_x (0) - -#endif /* CONFIG_PCI_MSI */ - -static int enable_sys_tune = 0; -module_param(enable_sys_tune, int, 0444); -MODULE_PARM_DESC(enable_sys_tune, "Tune the cpu's for better performance (default 0)"); - -int mlx4_blck_lb = 1; -module_param_named(block_loopback, mlx4_blck_lb, int, 0644); -MODULE_PARM_DESC(block_loopback, "Block multicast loopback packets if > 0 " - "(default: 1)"); -enum { - DEFAULT_DOMAIN = 0, - BDF_STR_SIZE = 8, /* bb:dd.f- */ - DBDF_STR_SIZE = 13 /* mmmm:bb:dd.f- */ -}; - -enum { - NUM_VFS, - PROBE_VF, - PORT_TYPE_ARRAY -}; - -enum { - VALID_DATA, - INVALID_DATA, - INVALID_STR -}; - -struct param_data { - int id; - struct mlx4_dbdf2val_lst dbdf2val; -}; - -static struct param_data num_vfs = { - .id = NUM_VFS, - .dbdf2val = { - .name = "num_vfs param", - .num_vals = 1, - .def_val = {0}, - .range = {0, MLX4_MAX_NUM_VF} - } -}; -module_param_string(num_vfs, num_vfs.dbdf2val.str, - sizeof(num_vfs.dbdf2val.str), 0444); -MODULE_PARM_DESC(num_vfs, - "Either single value (e.g. '5') to define uniform num_vfs value for all devices functions\n" - "\t\tor a string to map device function numbers to their num_vfs values (e.g. '0000:04:00.0-5,002b:1c:0b.a-15').\n" - "\t\tHexadecimal digits for the device function (e.g. 002b:1c:0b.a) and decimal for num_vfs value (e.g. 15)."); - -static struct param_data probe_vf = { - .id = PROBE_VF, - .dbdf2val = { - .name = "probe_vf param", - .num_vals = 1, - .def_val = {0}, - .range = {0, MLX4_MAX_NUM_VF} - } -}; -module_param_string(probe_vf, probe_vf.dbdf2val.str, - sizeof(probe_vf.dbdf2val.str), 0444); -MODULE_PARM_DESC(probe_vf, - "Either single value (e.g. '3') to define uniform number of VFs to probe by the pf driver for all devices functions\n" - "\t\tor a string to map device function numbers to their probe_vf values (e.g. '0000:04:00.0-3,002b:1c:0b.a-13').\n" - "\t\tHexadecimal digits for the device function (e.g. 002b:1c:0b.a) and decimal for probe_vf value (e.g. 13)."); - -int mlx4_log_num_mgm_entry_size = MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE; - -module_param_named(log_num_mgm_entry_size, - mlx4_log_num_mgm_entry_size, int, 0444); -MODULE_PARM_DESC(log_num_mgm_entry_size, "log mgm size, that defines the num" - " of qp per mcg, for example:" - " 10 gives 248.range: 7 <=" - " log_num_mgm_entry_size <= 12." - " To activate device managed" - " flow steering when available, set to -1"); - -static int high_rate_steer; -module_param(high_rate_steer, int, 0444); -MODULE_PARM_DESC(high_rate_steer, "Enable steering mode for higher packet rate" - " (default off)"); - -static int fast_drop; -module_param_named(fast_drop, fast_drop, int, 0444); -MODULE_PARM_DESC(fast_drop, - "Enable fast packet drop when no receive WQEs are posted"); - -int mlx4_enable_64b_cqe_eqe = 1; -module_param_named(enable_64b_cqe_eqe, mlx4_enable_64b_cqe_eqe, int, 0644); -MODULE_PARM_DESC(enable_64b_cqe_eqe, - "Enable 64 byte CQEs/EQEs when the FW supports this if non-zero (default: 1)"); - -#define HCA_GLOBAL_CAP_MASK 0 - -#define PF_CONTEXT_BEHAVIOUR_MASK MLX4_FUNC_CAP_64B_EQE_CQE - -static char mlx4_version[] __devinitdata = - DRV_NAME ": Mellanox ConnectX VPI driver v" - DRV_VERSION " (" DRV_RELDATE ")\n"; - -static int log_num_mac = 7; -module_param_named(log_num_mac, log_num_mac, int, 0444); -MODULE_PARM_DESC(log_num_mac, "Log2 max number of MACs per ETH port (1-7)"); - -static int log_num_vlan; -module_param_named(log_num_vlan, log_num_vlan, int, 0444); -MODULE_PARM_DESC(log_num_vlan, - "(Obsolete) Log2 max number of VLANs per ETH port (0-7)"); -/* Log2 max number of VLANs per ETH port (0-7) */ -#define MLX4_LOG_NUM_VLANS 7 - -int log_mtts_per_seg = ilog2(1); -module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444); -MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment " - "(0-7) (default: 0)"); - -static struct param_data port_type_array = { - .id = PORT_TYPE_ARRAY, - .dbdf2val = { - .name = "port_type_array param", - .num_vals = 2, - .def_val = {MLX4_PORT_TYPE_ETH, MLX4_PORT_TYPE_ETH}, - .range = {MLX4_PORT_TYPE_IB, MLX4_PORT_TYPE_NA} - } -}; -module_param_string(port_type_array, port_type_array.dbdf2val.str, - sizeof(port_type_array.dbdf2val.str), 0444); -MODULE_PARM_DESC(port_type_array, - "Either pair of values (e.g. '1,2') to define uniform port1/port2 types configuration for all devices functions\n" - "\t\tor a string to map device function numbers to their pair of port types values (e.g. '0000:04:00.0-1;2,002b:1c:0b.a-1;1').\n" - "\t\tValid port types: 1-ib, 2-eth, 3-auto, 4-N/A\n" - "\t\tIn case that only one port is available use the N/A port type for port2 (e.g '1,4')."); - - -struct mlx4_port_config { - struct list_head list; - enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; - struct pci_dev *pdev; -}; - -#define MLX4_LOG_NUM_MTT 20 -/* We limit to 30 as of a bit map issue which uses int and not uint. - see mlx4_buddy_init -> bitmap_zero which gets int. -*/ -#define MLX4_MAX_LOG_NUM_MTT 30 -static struct mlx4_profile mod_param_profile = { - .num_qp = 19, - .num_srq = 16, - .rdmarc_per_qp = 4, - .num_cq = 16, - .num_mcg = 13, - .num_mpt = 19, - .num_mtt_segs = 0, /* max(20, 2*MTTs for host memory)) */ -}; - -module_param_named(log_num_qp, mod_param_profile.num_qp, int, 0444); -MODULE_PARM_DESC(log_num_qp, "log maximum number of QPs per HCA (default: 19)"); - -module_param_named(log_num_srq, mod_param_profile.num_srq, int, 0444); -MODULE_PARM_DESC(log_num_srq, "log maximum number of SRQs per HCA " - "(default: 16)"); - -module_param_named(log_rdmarc_per_qp, mod_param_profile.rdmarc_per_qp, int, - 0444); -MODULE_PARM_DESC(log_rdmarc_per_qp, "log number of RDMARC buffers per QP " - "(default: 4)"); - -module_param_named(log_num_cq, mod_param_profile.num_cq, int, 0444); -MODULE_PARM_DESC(log_num_cq, "log maximum number of CQs per HCA (default: 16)"); - -module_param_named(log_num_mcg, mod_param_profile.num_mcg, int, 0444); -MODULE_PARM_DESC(log_num_mcg, "log maximum number of multicast groups per HCA " - "(default: 13)"); - -module_param_named(log_num_mpt, mod_param_profile.num_mpt, int, 0444); -MODULE_PARM_DESC(log_num_mpt, - "log maximum number of memory protection table entries per " - "HCA (default: 19)"); - -module_param_named(log_num_mtt, mod_param_profile.num_mtt_segs, int, 0444); -MODULE_PARM_DESC(log_num_mtt, - "log maximum number of memory translation table segments per " - "HCA (default: max(20, 2*MTTs for register all of the host memory limited to 30))"); - -enum { - MLX4_IF_STATE_BASIC, - MLX4_IF_STATE_EXTENDED -}; - -static inline u64 dbdf_to_u64(int domain, int bus, int dev, int fn) -{ - return (domain << 20) | (bus << 12) | (dev << 4) | fn; -} - -static inline void pr_bdf_err(const char *dbdf, const char *pname) -{ - pr_warn("mlx4_core: '%s' is not valid bdf in '%s'\n", dbdf, pname); -} - -static inline void pr_val_err(const char *dbdf, const char *pname, - const char *val) -{ - pr_warn("mlx4_core: value '%s' of bdf '%s' in '%s' is not valid\n" - , val, dbdf, pname); -} - -static inline void pr_out_of_range_bdf(const char *dbdf, int val, - struct mlx4_dbdf2val_lst *dbdf2val) -{ - pr_warn("mlx4_core: value %d in bdf '%s' of '%s' is out of its valid range (%d,%d)\n" - , val, dbdf, dbdf2val->name , dbdf2val->range.min, - dbdf2val->range.max); -} - -static inline void pr_out_of_range(struct mlx4_dbdf2val_lst *dbdf2val) -{ - pr_warn("mlx4_core: value of '%s' is out of its valid range (%d,%d)\n" - , dbdf2val->name , dbdf2val->range.min, dbdf2val->range.max); -} - -static inline int is_in_range(int val, struct mlx4_range *r) -{ - return (val >= r->min && val <= r->max); -} - -static int update_defaults(struct param_data *pdata) -{ - long int val[MLX4_MAX_BDF_VALS]; - int ret; - char *t, *p = pdata->dbdf2val.str; - char sval[32]; - int val_len; - - if (!strlen(p) || strchr(p, ':') || strchr(p, '.') || strchr(p, ';')) - return INVALID_STR; - - switch (pdata->id) { - case PORT_TYPE_ARRAY: - t = strchr(p, ','); - if (!t || t == p || (t - p) > sizeof(sval)) - return INVALID_STR; - - val_len = t - p; - strncpy(sval, p, val_len); - sval[val_len] = 0; - - ret = kstrtol(sval, 0, &val[0]); - if (ret == -EINVAL) - return INVALID_STR; - if (ret || !is_in_range(val[0], &pdata->dbdf2val.range)) { - pr_out_of_range(&pdata->dbdf2val); - return INVALID_DATA; - } - - ret = kstrtol(t + 1, 0, &val[1]); - if (ret == -EINVAL) - return INVALID_STR; - if (ret || !is_in_range(val[1], &pdata->dbdf2val.range)) { - pr_out_of_range(&pdata->dbdf2val); - return INVALID_DATA; - } - - pdata->dbdf2val.tbl[0].val[0] = val[0]; - pdata->dbdf2val.tbl[0].val[1] = val[1]; - break; - - case NUM_VFS: - case PROBE_VF: - ret = kstrtol(p, 0, &val[0]); - if (ret == -EINVAL) - return INVALID_STR; - if (ret || !is_in_range(val[0], &pdata->dbdf2val.range)) { - pr_out_of_range(&pdata->dbdf2val); - return INVALID_DATA; - } - pdata->dbdf2val.tbl[0].val[0] = val[0]; - break; - } - pdata->dbdf2val.tbl[1].dbdf = MLX4_ENDOF_TBL; - - return VALID_DATA; -} - -int mlx4_fill_dbdf2val_tbl(struct mlx4_dbdf2val_lst *dbdf2val_lst) -{ - int domain, bus, dev, fn; - u64 dbdf; - char *p, *t, *v; - char tmp[32]; - char sbdf[32]; - char sep = ','; - int j, k, str_size, i = 1; - int prfx_size; - - p = dbdf2val_lst->str; - - for (j = 0; j < dbdf2val_lst->num_vals; j++) - dbdf2val_lst->tbl[0].val[j] = dbdf2val_lst->def_val[j]; - dbdf2val_lst->tbl[1].dbdf = MLX4_ENDOF_TBL; - - str_size = strlen(dbdf2val_lst->str); - - if (str_size == 0) - return 0; - - while (strlen(p)) { - prfx_size = BDF_STR_SIZE; - sbdf[prfx_size] = 0; - strncpy(sbdf, p, prfx_size); - domain = DEFAULT_DOMAIN; - if (sscanf(sbdf, "%02x:%02x.%x-", &bus, &dev, &fn) != 3) { - prfx_size = DBDF_STR_SIZE; - sbdf[prfx_size] = 0; - strncpy(sbdf, p, prfx_size); - if (sscanf(sbdf, "%04x:%02x:%02x.%x-", &domain, &bus, - &dev, &fn) != 4) { - pr_bdf_err(sbdf, dbdf2val_lst->name); - goto err; - } - sprintf(tmp, "%04x:%02x:%02x.%x-", domain, bus, dev, - fn); - } else { - sprintf(tmp, "%02x:%02x.%x-", bus, dev, fn); - } - - if (strnicmp(sbdf, tmp, sizeof(tmp))) { - pr_bdf_err(sbdf, dbdf2val_lst->name); - goto err; - } - - dbdf = dbdf_to_u64(domain, bus, dev, fn); - - for (j = 1; j < i; j++) - if (dbdf2val_lst->tbl[j].dbdf == dbdf) { - pr_warn("mlx4_core: in '%s', %s appears multiple times\n" - , dbdf2val_lst->name, sbdf); - goto err; - } - - if (i >= MLX4_DEVS_TBL_SIZE) { - pr_warn("mlx4_core: Too many devices in '%s'\n" - , dbdf2val_lst->name); - goto err; - } - - p += prfx_size; - t = strchr(p, sep); - t = t ? t : p + strlen(p); - if (p >= t) { - pr_val_err(sbdf, dbdf2val_lst->name, ""); - goto err; - } - - for (k = 0; k < dbdf2val_lst->num_vals; k++) { - char sval[32]; - long int val; - int ret, val_len; - char vsep = ';'; - - v = (k == dbdf2val_lst->num_vals - 1) ? t : strchr(p, vsep); - if (!v || v > t || v == p || (v - p) > sizeof(sval)) { - pr_val_err(sbdf, dbdf2val_lst->name, p); - goto err; - } - val_len = v - p; - strncpy(sval, p, val_len); - sval[val_len] = 0; - - ret = kstrtol(sval, 0, &val); - if (ret) { - if (strchr(p, vsep)) - pr_warn("mlx4_core: too many vals in bdf '%s' of '%s'\n" - , sbdf, dbdf2val_lst->name); - else - pr_val_err(sbdf, dbdf2val_lst->name, - sval); - goto err; - } - if (!is_in_range(val, &dbdf2val_lst->range)) { - pr_out_of_range_bdf(sbdf, val, dbdf2val_lst); - goto err; - } - - dbdf2val_lst->tbl[i].val[k] = val; - p = v; - if (p[0] == vsep) - p++; - } - - dbdf2val_lst->tbl[i].dbdf = dbdf; - if (strlen(p)) { - if (p[0] != sep) { - pr_warn("mlx4_core: expect separator '%c' before '%s' in '%s'\n" - , sep, p, dbdf2val_lst->name); - goto err; - } - p++; - } - i++; - if (i < MLX4_DEVS_TBL_SIZE) - dbdf2val_lst->tbl[i].dbdf = MLX4_ENDOF_TBL; - } - - return 0; - -err: - dbdf2val_lst->tbl[1].dbdf = MLX4_ENDOF_TBL; - pr_warn("mlx4_core: The value of '%s' is incorrect. The value is discarded!\n" - , dbdf2val_lst->name); - - return -EINVAL; -} -EXPORT_SYMBOL(mlx4_fill_dbdf2val_tbl); - -int mlx4_get_val(struct mlx4_dbdf2val *tbl, struct pci_dev *pdev, int idx, - int *val) -{ - u64 dbdf; - int i = 1; - - *val = tbl[0].val[idx]; - if (!pdev) - return -EINVAL; - - dbdf = dbdf_to_u64(pci_get_domain(pdev->dev.bsddev), pci_get_bus(pdev->dev.bsddev), - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - while ((i < MLX4_DEVS_TBL_SIZE) && (tbl[i].dbdf != MLX4_ENDOF_TBL)) { - if (tbl[i].dbdf == dbdf) { - *val = tbl[i].val[idx]; - return 0; - } - i++; - } - - return 0; -} -EXPORT_SYMBOL(mlx4_get_val); - -static void process_mod_param_profile(struct mlx4_profile *profile) -{ - vm_size_t hwphyssz; - hwphyssz = 0; - TUNABLE_ULONG_FETCH("hw.realmem", (u_long *) &hwphyssz); - - profile->num_qp = 1 << mod_param_profile.num_qp; - profile->num_srq = 1 << mod_param_profile.num_srq; - profile->rdmarc_per_qp = 1 << mod_param_profile.rdmarc_per_qp; - profile->num_cq = 1 << mod_param_profile.num_cq; - profile->num_mcg = 1 << mod_param_profile.num_mcg; - profile->num_mpt = 1 << mod_param_profile.num_mpt; - /* - * We want to scale the number of MTTs with the size of the - * system memory, since it makes sense to register a lot of - * memory on a system with a lot of memory. As a heuristic, - * make sure we have enough MTTs to register twice the system - * memory (with PAGE_SIZE entries). - * - * This number has to be a power of two and fit into 32 bits - * due to device limitations. We cap this at 2^30 as of bit map - * limitation to work with int instead of uint (mlx4_buddy_init -> bitmap_zero) - * That limits us to 4TB of memory registration per HCA with - * 4KB pages, which is probably OK for the next few months. - */ - if (mod_param_profile.num_mtt_segs) - profile->num_mtt_segs = 1 << mod_param_profile.num_mtt_segs; - else { - profile->num_mtt_segs = - roundup_pow_of_two(max_t(unsigned, - 1 << (MLX4_LOG_NUM_MTT - log_mtts_per_seg), - min(1UL << - (MLX4_MAX_LOG_NUM_MTT - - log_mtts_per_seg), - (hwphyssz << 1) - >> log_mtts_per_seg))); - /* set the actual value, so it will be reflected to the user - using the sysfs */ - mod_param_profile.num_mtt_segs = ilog2(profile->num_mtt_segs); - } -} - -int mlx4_check_port_params(struct mlx4_dev *dev, - enum mlx4_port_type *port_type) -{ - int i; - - for (i = 0; i < dev->caps.num_ports - 1; i++) { - if (port_type[i] != port_type[i + 1]) { - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) { - mlx4_err(dev, "Only same port types supported " - "on this HCA, aborting.\n"); - return -EINVAL; - } - } - } - - for (i = 0; i < dev->caps.num_ports; i++) { - if (!(port_type[i] & dev->caps.supported_type[i+1])) { - mlx4_err(dev, "Requested port type for port %d is not " - "supported on this HCA\n", i + 1); - return -EINVAL; - } - } - return 0; -} - -static void mlx4_set_port_mask(struct mlx4_dev *dev) -{ - int i; - - for (i = 1; i <= dev->caps.num_ports; ++i) - dev->caps.port_mask[i] = dev->caps.port_type[i]; -} - -static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) -{ - int err; - int i; - - err = mlx4_QUERY_DEV_CAP(dev, dev_cap); - if (err) { - mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); - return err; - } - - if (dev_cap->min_page_sz > PAGE_SIZE) { - mlx4_err(dev, "HCA minimum page size of %d bigger than " - "kernel PAGE_SIZE of %d, aborting.\n", - dev_cap->min_page_sz, (int)PAGE_SIZE); - return -ENODEV; - } - if (dev_cap->num_ports > MLX4_MAX_PORTS) { - mlx4_err(dev, "HCA has %d ports, but we only support %d, " - "aborting.\n", - dev_cap->num_ports, MLX4_MAX_PORTS); - return -ENODEV; - } - - if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) { - mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than " - "PCI resource 2 size of 0x%llx, aborting.\n", - dev_cap->uar_size, - (unsigned long long) pci_resource_len(dev->pdev, 2)); - return -ENODEV; - } - - dev->caps.num_ports = dev_cap->num_ports; - dev->phys_caps.num_phys_eqs = MLX4_MAX_EQ_NUM; - for (i = 1; i <= dev->caps.num_ports; ++i) { - dev->caps.vl_cap[i] = dev_cap->max_vl[i]; - dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i]; - dev->phys_caps.gid_phys_table_len[i] = dev_cap->max_gids[i]; - dev->phys_caps.pkey_phys_table_len[i] = dev_cap->max_pkeys[i]; - /* set gid and pkey table operating lengths by default - * to non-sriov values */ - dev->caps.gid_table_len[i] = dev_cap->max_gids[i]; - dev->caps.pkey_table_len[i] = dev_cap->max_pkeys[i]; - dev->caps.port_width_cap[i] = dev_cap->max_port_width[i]; - dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i]; - dev->caps.def_mac[i] = dev_cap->def_mac[i]; - dev->caps.supported_type[i] = dev_cap->supported_port_types[i]; - dev->caps.suggested_type[i] = dev_cap->suggested_type[i]; - dev->caps.default_sense[i] = dev_cap->default_sense[i]; - dev->caps.trans_type[i] = dev_cap->trans_type[i]; - dev->caps.vendor_oui[i] = dev_cap->vendor_oui[i]; - dev->caps.wavelength[i] = dev_cap->wavelength[i]; - dev->caps.trans_code[i] = dev_cap->trans_code[i]; - } - - dev->caps.uar_page_size = PAGE_SIZE; - dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE; - dev->caps.local_ca_ack_delay = dev_cap->local_ca_ack_delay; - dev->caps.bf_reg_size = dev_cap->bf_reg_size; - dev->caps.bf_regs_per_page = dev_cap->bf_regs_per_page; - dev->caps.max_sq_sg = dev_cap->max_sq_sg; - dev->caps.max_rq_sg = dev_cap->max_rq_sg; - dev->caps.max_wqes = dev_cap->max_qp_sz; - dev->caps.max_qp_init_rdma = dev_cap->max_requester_per_qp; - dev->caps.max_srq_wqes = dev_cap->max_srq_sz; - dev->caps.max_srq_sge = dev_cap->max_rq_sg - 1; - dev->caps.reserved_srqs = dev_cap->reserved_srqs; - dev->caps.max_sq_desc_sz = dev_cap->max_sq_desc_sz; - dev->caps.max_rq_desc_sz = dev_cap->max_rq_desc_sz; - /* - * Subtract 1 from the limit because we need to allocate a - * spare CQE to enable resizing the CQ - */ - dev->caps.max_cqes = dev_cap->max_cq_sz - 1; - dev->caps.reserved_cqs = dev_cap->reserved_cqs; - dev->caps.reserved_eqs = dev_cap->reserved_eqs; - dev->caps.reserved_mtts = dev_cap->reserved_mtts; - dev->caps.reserved_mrws = dev_cap->reserved_mrws; - - /* The first 128 UARs are used for EQ doorbells */ - dev->caps.reserved_uars = max_t(int, 128, dev_cap->reserved_uars); - dev->caps.reserved_pds = dev_cap->reserved_pds; - dev->caps.reserved_xrcds = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ? - dev_cap->reserved_xrcds : 0; - dev->caps.max_xrcds = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ? - dev_cap->max_xrcds : 0; - dev->caps.mtt_entry_sz = dev_cap->mtt_entry_sz; - - dev->caps.max_msg_sz = dev_cap->max_msg_sz; - dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); - dev->caps.flags = dev_cap->flags; - dev->caps.flags2 = dev_cap->flags2; - dev->caps.bmme_flags = dev_cap->bmme_flags; - dev->caps.reserved_lkey = dev_cap->reserved_lkey; - dev->caps.stat_rate_support = dev_cap->stat_rate_support; - dev->caps.cq_timestamp = dev_cap->timestamp_support; - dev->caps.max_gso_sz = dev_cap->max_gso_sz; - dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz; - - /* Sense port always allowed on supported devices for ConnectX-1 and -2 */ - if (mlx4_priv(dev)->pci_dev_data & MLX4_PCI_DEV_FORCE_SENSE_PORT) - dev->caps.flags |= MLX4_DEV_CAP_FLAG_SENSE_SUPPORT; - /* Don't do sense port on multifunction devices (for now at least) */ - if (mlx4_is_mfunc(dev)) - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_SENSE_SUPPORT; - - dev->caps.log_num_macs = log_num_mac; - dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS; - - dev->caps.fast_drop = fast_drop ? - !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_FAST_DROP) : - 0; - - for (i = 1; i <= dev->caps.num_ports; ++i) { - dev->caps.port_type[i] = MLX4_PORT_TYPE_NONE; - if (dev->caps.supported_type[i]) { - /* if only ETH is supported - assign ETH */ - if (dev->caps.supported_type[i] == MLX4_PORT_TYPE_ETH) - dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH; - /* if only IB is supported, assign IB */ - else if (dev->caps.supported_type[i] == - MLX4_PORT_TYPE_IB) - dev->caps.port_type[i] = MLX4_PORT_TYPE_IB; - else { - /* - * if IB and ETH are supported, we set the port - * type according to user selection of port type; - * if there is no user selection, take the FW hint - */ - int pta; - mlx4_get_val(port_type_array.dbdf2val.tbl, - pci_physfn(dev->pdev), i - 1, - &pta); - if (pta == MLX4_PORT_TYPE_NONE) { - dev->caps.port_type[i] = dev->caps.suggested_type[i] ? - MLX4_PORT_TYPE_ETH : MLX4_PORT_TYPE_IB; - } else if (pta == MLX4_PORT_TYPE_NA) { - mlx4_err(dev, "Port %d is valid port. " - "It is not allowed to configure its type to N/A(%d)\n", - i, MLX4_PORT_TYPE_NA); - return -EINVAL; - } else { - dev->caps.port_type[i] = pta; - } - } - } - /* - * Link sensing is allowed on the port if 3 conditions are true: - * 1. Both protocols are supported on the port. - * 2. Different types are supported on the port - * 3. FW declared that it supports link sensing - */ - mlx4_priv(dev)->sense.sense_allowed[i] = - ((dev->caps.supported_type[i] == MLX4_PORT_TYPE_AUTO) && - (dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP) && - (dev->caps.flags & MLX4_DEV_CAP_FLAG_SENSE_SUPPORT)); - - /* Disablling auto sense for default Eth ports support */ - mlx4_priv(dev)->sense.sense_allowed[i] = 0; - - /* - * If "default_sense" bit is set, we move the port to "AUTO" mode - * and perform sense_port FW command to try and set the correct - * port type from beginning - */ - if (mlx4_priv(dev)->sense.sense_allowed[i] && dev->caps.default_sense[i]) { - enum mlx4_port_type sensed_port = MLX4_PORT_TYPE_NONE; - dev->caps.possible_type[i] = MLX4_PORT_TYPE_AUTO; - mlx4_SENSE_PORT(dev, i, &sensed_port); - if (sensed_port != MLX4_PORT_TYPE_NONE) - dev->caps.port_type[i] = sensed_port; - } else { - dev->caps.possible_type[i] = dev->caps.port_type[i]; - } - - if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) { - dev->caps.log_num_macs = dev_cap->log_max_macs[i]; - mlx4_warn(dev, "Requested number of MACs is too much " - "for port %d, reducing to %d.\n", - i, 1 << dev->caps.log_num_macs); - } - if (dev->caps.log_num_vlans > dev_cap->log_max_vlans[i]) { - dev->caps.log_num_vlans = dev_cap->log_max_vlans[i]; - mlx4_warn(dev, "Requested number of VLANs is too much " - "for port %d, reducing to %d.\n", - i, 1 << dev->caps.log_num_vlans); - } - } - - dev->caps.max_basic_counters = dev_cap->max_basic_counters; - dev->caps.max_extended_counters = dev_cap->max_extended_counters; - /* support extended counters if available */ - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS_EXT) - dev->caps.max_counters = dev->caps.max_extended_counters; - else - dev->caps.max_counters = dev->caps.max_basic_counters; - - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps; - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] = - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] = - (1 << dev->caps.log_num_macs) * - (1 << dev->caps.log_num_vlans) * - dev->caps.num_ports; - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH] = MLX4_NUM_FEXCH; - - dev->caps.reserved_qps = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] + - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] + - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] + - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_EXCH]; - - dev->caps.sync_qp = dev_cap->sync_qp; - if (dev->pdev->device == 0x1003) - dev->caps.cq_flags |= MLX4_DEV_CAP_CQ_FLAG_IO; - - dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0; - - if (!mlx4_enable_64b_cqe_eqe && !mlx4_is_slave(dev)) { - if (dev_cap->flags & - (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) { - mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n"); - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_64B_CQE; - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_64B_EQE; - } - } - - if ((dev->caps.flags & - (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) && - mlx4_is_master(dev)) - dev->caps.function_caps |= MLX4_FUNC_CAP_64B_EQE_CQE; - - if (!mlx4_is_slave(dev)) { - for (i = 0; i < dev->caps.num_ports; ++i) - dev->caps.def_counter_index[i] = i << 1; - } - - return 0; -} -/*The function checks if there are live vf, return the num of them*/ -static int mlx4_how_many_lives_vf(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_state; - int i; - int ret = 0; - - for (i = 1/*the ppf is 0*/; i < dev->num_slaves; ++i) { - s_state = &priv->mfunc.master.slave_state[i]; - if (s_state->active && s_state->last_cmd != - MLX4_COMM_CMD_RESET) { - mlx4_warn(dev, "%s: slave: %d is still active\n", - __func__, i); - ret++; - } - } - return ret; -} - -int mlx4_get_parav_qkey(struct mlx4_dev *dev, u32 qpn, u32 *qkey) -{ - u32 qk = MLX4_RESERVED_QKEY_BASE; - - if (qpn >= dev->phys_caps.base_tunnel_sqpn + 8 * MLX4_MFUNC_MAX || - qpn < dev->phys_caps.base_proxy_sqpn) - return -EINVAL; - - if (qpn >= dev->phys_caps.base_tunnel_sqpn) - /* tunnel qp */ - qk += qpn - dev->phys_caps.base_tunnel_sqpn; - else - qk += qpn - dev->phys_caps.base_proxy_sqpn; - *qkey = qk; - return 0; -} -EXPORT_SYMBOL(mlx4_get_parav_qkey); - -void mlx4_sync_pkey_table(struct mlx4_dev *dev, int slave, int port, int i, int val) -{ - struct mlx4_priv *priv = container_of(dev, struct mlx4_priv, dev); - - if (!mlx4_is_master(dev)) - return; - - priv->virt2phys_pkey[slave][port - 1][i] = val; -} -EXPORT_SYMBOL(mlx4_sync_pkey_table); - -void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid) -{ - struct mlx4_priv *priv = container_of(dev, struct mlx4_priv, dev); - - if (!mlx4_is_master(dev)) - return; - - priv->slave_node_guids[slave] = guid; -} -EXPORT_SYMBOL(mlx4_put_slave_node_guid); - -__be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = container_of(dev, struct mlx4_priv, dev); - - if (!mlx4_is_master(dev)) - return 0; - - return priv->slave_node_guids[slave]; -} -EXPORT_SYMBOL(mlx4_get_slave_node_guid); - -int mlx4_is_slave_active(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_slave; - - if (!mlx4_is_master(dev)) - return 0; - - s_slave = &priv->mfunc.master.slave_state[slave]; - return !!s_slave->active; -} -EXPORT_SYMBOL(mlx4_is_slave_active); - -static void slave_adjust_steering_mode(struct mlx4_dev *dev, - struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *hca_param) -{ - dev->caps.steering_mode = hca_param->steering_mode; - if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) - dev->caps.num_qp_per_mgm = dev_cap->fs_max_num_qp_per_entry; - else - dev->caps.num_qp_per_mgm = - 4 * ((1 << hca_param->log_mc_entry_sz)/16 - 2); - - mlx4_dbg(dev, "Steering mode is: %s\n", - mlx4_steering_mode_str(dev->caps.steering_mode)); -} - -static int mlx4_slave_cap(struct mlx4_dev *dev) -{ - int err; - u32 page_size; - struct mlx4_dev_cap dev_cap; - struct mlx4_func_cap func_cap; - struct mlx4_init_hca_param hca_param; - int i; - - memset(&hca_param, 0, sizeof(hca_param)); - err = mlx4_QUERY_HCA(dev, &hca_param); - if (err) { - mlx4_err(dev, "QUERY_HCA command failed, aborting.\n"); - return err; - } - - /*fail if the hca has an unknown capability */ - if ((hca_param.global_caps | HCA_GLOBAL_CAP_MASK) != - HCA_GLOBAL_CAP_MASK) { - mlx4_err(dev, "Unknown hca global capabilities\n"); - return -ENOSYS; - } - - mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz; - - dev->caps.hca_core_clock = hca_param.hca_core_clock; - - memset(&dev_cap, 0, sizeof(dev_cap)); - dev->caps.max_qp_dest_rdma = 1 << hca_param.log_rd_per_qp; - err = mlx4_dev_cap(dev, &dev_cap); - if (err) { - mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); - return err; - } - - err = mlx4_QUERY_FW(dev); - if (err) - mlx4_err(dev, "QUERY_FW command failed: could not get FW version.\n"); - - if (!hca_param.mw_enable) { - dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW; - dev->caps.bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN; - } - - page_size = ~dev->caps.page_size_cap + 1; - mlx4_warn(dev, "HCA minimum page size:%d\n", page_size); - if (page_size > PAGE_SIZE) { - mlx4_err(dev, "HCA minimum page size of %d bigger than " - "kernel PAGE_SIZE of %d, aborting.\n", - page_size, (int)PAGE_SIZE); - return -ENODEV; - } - - /* slave gets uar page size from QUERY_HCA fw command */ - dev->caps.uar_page_size = 1 << (hca_param.uar_page_sz + 12); - - /* TODO: relax this assumption */ - if (dev->caps.uar_page_size != PAGE_SIZE) { - mlx4_err(dev, "UAR size:%d != kernel PAGE_SIZE of %d\n", - dev->caps.uar_page_size, (int)PAGE_SIZE); - return -ENODEV; - } - - memset(&func_cap, 0, sizeof(func_cap)); - err = mlx4_QUERY_FUNC_CAP(dev, 0, &func_cap); - if (err) { - mlx4_err(dev, "QUERY_FUNC_CAP general command failed, aborting (%d).\n", - err); - return err; - } - - if ((func_cap.pf_context_behaviour | PF_CONTEXT_BEHAVIOUR_MASK) != - PF_CONTEXT_BEHAVIOUR_MASK) { - mlx4_err(dev, "Unknown pf context behaviour\n"); - return -ENOSYS; - } - - dev->caps.num_ports = func_cap.num_ports; - dev->quotas.qp = func_cap.qp_quota; - dev->quotas.srq = func_cap.srq_quota; - dev->quotas.cq = func_cap.cq_quota; - dev->quotas.mpt = func_cap.mpt_quota; - dev->quotas.mtt = func_cap.mtt_quota; - dev->caps.num_qps = 1 << hca_param.log_num_qps; - dev->caps.num_srqs = 1 << hca_param.log_num_srqs; - dev->caps.num_cqs = 1 << hca_param.log_num_cqs; - dev->caps.num_mpts = 1 << hca_param.log_mpt_sz; - dev->caps.num_eqs = func_cap.max_eq; - dev->caps.reserved_eqs = func_cap.reserved_eq; - dev->caps.num_pds = MLX4_NUM_PDS; - dev->caps.num_mgms = 0; - dev->caps.num_amgms = 0; - - if (dev->caps.num_ports > MLX4_MAX_PORTS) { - mlx4_err(dev, "HCA has %d ports, but we only support %d, " - "aborting.\n", dev->caps.num_ports, MLX4_MAX_PORTS); - return -ENODEV; - } - - dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - - if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy || - !dev->caps.qp1_tunnel || !dev->caps.qp1_proxy) { - err = -ENOMEM; - goto err_mem; - } - - for (i = 1; i <= dev->caps.num_ports; ++i) { - err = mlx4_QUERY_FUNC_CAP(dev, (u32) i, &func_cap); - if (err) { - mlx4_err(dev, "QUERY_FUNC_CAP port command failed for" - " port %d, aborting (%d).\n", i, err); - goto err_mem; - } - dev->caps.qp0_tunnel[i - 1] = func_cap.qp0_tunnel_qpn; - dev->caps.qp0_proxy[i - 1] = func_cap.qp0_proxy_qpn; - dev->caps.qp1_tunnel[i - 1] = func_cap.qp1_tunnel_qpn; - dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn; - dev->caps.def_counter_index[i - 1] = func_cap.def_counter_index; - - dev->caps.port_mask[i] = dev->caps.port_type[i]; - err = mlx4_get_slave_pkey_gid_tbl_len(dev, i, - &dev->caps.gid_table_len[i], - &dev->caps.pkey_table_len[i]); - if (err) - goto err_mem; - } - - if (dev->caps.uar_page_size * (dev->caps.num_uars - - dev->caps.reserved_uars) > - pci_resource_len(dev->pdev, 2)) { - mlx4_err(dev, "HCA reported UAR region size of 0x%x bigger than " - "PCI resource 2 size of 0x%llx, aborting.\n", - dev->caps.uar_page_size * dev->caps.num_uars, - (unsigned long long) pci_resource_len(dev->pdev, 2)); - err = -ENOMEM; - goto err_mem; - } - - if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_64B_EQE_ENABLED) { - dev->caps.eqe_size = 64; - dev->caps.eqe_factor = 1; - } else { - dev->caps.eqe_size = 32; - dev->caps.eqe_factor = 0; - } - - if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_64B_CQE_ENABLED) { - dev->caps.cqe_size = 64; - dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_64B_CQE; - } else { - dev->caps.cqe_size = 32; - } - - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - mlx4_warn(dev, "Timestamping is not supported in slave mode.\n"); - - slave_adjust_steering_mode(dev, &dev_cap, &hca_param); - - return 0; - -err_mem: - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - dev->caps.qp0_tunnel = dev->caps.qp0_proxy = - dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL; - - return err; -} - -static void mlx4_request_modules(struct mlx4_dev *dev) -{ - int port; - int has_ib_port = false; - int has_eth_port = false; -#define EN_DRV_NAME "mlx4_en" -#define IB_DRV_NAME "mlx4_ib" - - for (port = 1; port <= dev->caps.num_ports; port++) { - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB) - has_ib_port = true; - else if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) - has_eth_port = true; - } - - if (has_ib_port) - request_module_nowait(IB_DRV_NAME); - if (has_eth_port) - request_module_nowait(EN_DRV_NAME); -} - -/* - * Change the port configuration of the device. - * Every user of this function must hold the port mutex. - */ -int mlx4_change_port_types(struct mlx4_dev *dev, - enum mlx4_port_type *port_types) -{ - int err = 0; - int change = 0; - int port; - - for (port = 0; port < dev->caps.num_ports; port++) { - /* Change the port type only if the new type is different - * from the current, and not set to Auto */ - if (port_types[port] != dev->caps.port_type[port + 1]) - change = 1; - } - if (change) { - mlx4_unregister_device(dev); - for (port = 1; port <= dev->caps.num_ports; port++) { - mlx4_CLOSE_PORT(dev, port); - dev->caps.port_type[port] = port_types[port - 1]; - err = mlx4_SET_PORT(dev, port, -1); - if (err) { - mlx4_err(dev, "Failed to set port %d, " - "aborting\n", port); - goto out; - } - } - mlx4_set_port_mask(dev); - err = mlx4_register_device(dev); - if (err) { - mlx4_err(dev, "Failed to register device\n"); - goto out; - } - mlx4_request_modules(dev); - } - -out: - return err; -} - -static ssize_t show_port_type(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_attr); - struct mlx4_dev *mdev = info->dev; - char type[8]; - - sprintf(type, "%s", - (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB) ? - "ib" : "eth"); - if (mdev->caps.possible_type[info->port] == MLX4_PORT_TYPE_AUTO) - sprintf(buf, "auto (%s)\n", type); - else - sprintf(buf, "%s\n", type); - - return strlen(buf); -} - -static ssize_t set_port_type(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_attr); - struct mlx4_dev *mdev = info->dev; - struct mlx4_priv *priv = mlx4_priv(mdev); - enum mlx4_port_type types[MLX4_MAX_PORTS]; - enum mlx4_port_type new_types[MLX4_MAX_PORTS]; - int i; - int err = 0; - - if (!strcmp(buf, "ib\n")) - info->tmp_type = MLX4_PORT_TYPE_IB; - else if (!strcmp(buf, "eth\n")) - info->tmp_type = MLX4_PORT_TYPE_ETH; - else if (!strcmp(buf, "auto\n")) - info->tmp_type = MLX4_PORT_TYPE_AUTO; - else { - mlx4_err(mdev, "%s is not supported port type\n", buf); - return -EINVAL; - } - - if ((info->tmp_type & mdev->caps.supported_type[info->port]) != - info->tmp_type) { - mlx4_err(mdev, "Requested port type for port %d is not supported on this HCA\n", - info->port); - return -EINVAL; - } - - mlx4_stop_sense(mdev); - mutex_lock(&priv->port_mutex); - /* Possible type is always the one that was delivered */ - mdev->caps.possible_type[info->port] = info->tmp_type; - - for (i = 0; i < mdev->caps.num_ports; i++) { - types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type : - mdev->caps.possible_type[i+1]; - if (types[i] == MLX4_PORT_TYPE_AUTO) - types[i] = mdev->caps.port_type[i+1]; - } - - if (!(mdev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP) && - !(mdev->caps.flags & MLX4_DEV_CAP_FLAG_SENSE_SUPPORT)) { - for (i = 1; i <= mdev->caps.num_ports; i++) { - if (mdev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { - mdev->caps.possible_type[i] = mdev->caps.port_type[i]; - err = -EINVAL; - } - } - } - if (err) { - mlx4_err(mdev, "Auto sensing is not supported on this HCA. " - "Set only 'eth' or 'ib' for both ports " - "(should be the same)\n"); - goto out; - } - - mlx4_do_sense_ports(mdev, new_types, types); - - err = mlx4_check_port_params(mdev, new_types); - if (err) - goto out; - - /* We are about to apply the changes after the configuration - * was verified, no need to remember the temporary types - * any more */ - for (i = 0; i < mdev->caps.num_ports; i++) - priv->port[i + 1].tmp_type = 0; - - err = mlx4_change_port_types(mdev, new_types); - -out: - mlx4_start_sense(mdev); - mutex_unlock(&priv->port_mutex); - return err ? err : count; -} - -enum ibta_mtu { - IB_MTU_256 = 1, - IB_MTU_512 = 2, - IB_MTU_1024 = 3, - IB_MTU_2048 = 4, - IB_MTU_4096 = 5 -}; - -static inline int int_to_ibta_mtu(int mtu) -{ - switch (mtu) { - case 256: return IB_MTU_256; - case 512: return IB_MTU_512; - case 1024: return IB_MTU_1024; - case 2048: return IB_MTU_2048; - case 4096: return IB_MTU_4096; - default: return -1; - } -} - -static inline int ibta_mtu_to_int(enum ibta_mtu mtu) -{ - switch (mtu) { - case IB_MTU_256: return 256; - case IB_MTU_512: return 512; - case IB_MTU_1024: return 1024; - case IB_MTU_2048: return 2048; - case IB_MTU_4096: return 4096; - default: return -1; - } -} - -static ssize_t -show_board(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info, - board_attr); - struct mlx4_dev *mdev = info->dev; - - return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, - mdev->board_id); -} - -static ssize_t -show_hca(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info, - hca_attr); - struct mlx4_dev *mdev = info->dev; - - return sprintf(buf, "MT%d\n", mdev->pdev->device); -} - -static ssize_t -show_firmware_version(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info, - firmware_attr); - struct mlx4_dev *mdev = info->dev; - - return sprintf(buf, "%d.%d.%d\n", (int)(mdev->caps.fw_ver >> 32), - (int)(mdev->caps.fw_ver >> 16) & 0xffff, - (int)mdev->caps.fw_ver & 0xffff); -} - -static ssize_t show_port_ib_mtu(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_mtu_attr); - struct mlx4_dev *mdev = info->dev; - - /* When port type is eth, port mtu value isn't used. */ - if (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_ETH) - return -EINVAL; - - sprintf(buf, "%d\n", - ibta_mtu_to_int(mdev->caps.port_ib_mtu[info->port])); - return strlen(buf); -} - -static ssize_t set_port_ib_mtu(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, - port_mtu_attr); - struct mlx4_dev *mdev = info->dev; - struct mlx4_priv *priv = mlx4_priv(mdev); - int err, port, mtu, ibta_mtu = -1; - - if (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_ETH) { - mlx4_warn(mdev, "port level mtu is only used for IB ports\n"); - return -EINVAL; - } - - mtu = (int) simple_strtol(buf, NULL, 0); - ibta_mtu = int_to_ibta_mtu(mtu); - - if (ibta_mtu < 0) { - mlx4_err(mdev, "%s is invalid IBTA mtu\n", buf); - return -EINVAL; - } - - mdev->caps.port_ib_mtu[info->port] = ibta_mtu; - - mlx4_stop_sense(mdev); - mutex_lock(&priv->port_mutex); - mlx4_unregister_device(mdev); - for (port = 1; port <= mdev->caps.num_ports; port++) { - mlx4_CLOSE_PORT(mdev, port); - err = mlx4_SET_PORT(mdev, port, -1); - if (err) { - mlx4_err(mdev, "Failed to set port %d, " - "aborting\n", port); - goto err_set_port; - } - } - err = mlx4_register_device(mdev); -err_set_port: - mutex_unlock(&priv->port_mutex); - mlx4_start_sense(mdev); - return err ? err : count; -} - -static int mlx4_load_fw(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err, unmap_flag = 0; - - priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages, - GFP_HIGHUSER | __GFP_NOWARN, 0); - if (!priv->fw.fw_icm) { - mlx4_err(dev, "Couldn't allocate FW area, aborting.\n"); - return -ENOMEM; - } - - err = mlx4_MAP_FA(dev, priv->fw.fw_icm); - if (err) { - mlx4_err(dev, "MAP_FA command failed, aborting.\n"); - goto err_free; - } - - err = mlx4_RUN_FW(dev); - if (err) { - mlx4_err(dev, "RUN_FW command failed, aborting.\n"); - goto err_unmap_fa; - } - - return 0; - -err_unmap_fa: - unmap_flag = mlx4_UNMAP_FA(dev); - if (unmap_flag) - pr_warn("mlx4_core: mlx4_UNMAP_FA failed.\n"); - -err_free: - if (!unmap_flag) - mlx4_free_icm(dev, priv->fw.fw_icm, 0); - return err; -} - -static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, - int cmpt_entry_sz) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - int num_eqs; - - err = mlx4_init_icm_table(dev, &priv->qp_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_QP * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) - goto err; - - err = mlx4_init_icm_table(dev, &priv->srq_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_SRQ * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, dev->caps.num_srqs, - dev->caps.reserved_srqs, 0, 0); - if (err) - goto err_qp; - - err = mlx4_init_icm_table(dev, &priv->cq_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_CQ * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, dev->caps.num_cqs, - dev->caps.reserved_cqs, 0, 0); - if (err) - goto err_srq; - - num_eqs = (mlx4_is_master(dev)) ? dev->phys_caps.num_phys_eqs : - dev->caps.num_eqs; - err = mlx4_init_icm_table(dev, &priv->eq_table.cmpt_table, - cmpt_base + - ((u64) (MLX4_CMPT_TYPE_EQ * - cmpt_entry_sz) << MLX4_CMPT_SHIFT), - cmpt_entry_sz, num_eqs, num_eqs, 0, 0); - if (err) - goto err_cq; - - return 0; - -err_cq: - mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); - -err_srq: - mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); - -err_qp: - mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - -err: - return err; -} - -static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *init_hca, u64 icm_size) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u64 aux_pages; - int num_eqs; - int err, unmap_flag = 0; - - err = mlx4_SET_ICM_SIZE(dev, icm_size, &aux_pages); - if (err) { - mlx4_err(dev, "SET_ICM_SIZE command failed, aborting.\n"); - return err; - } - - mlx4_dbg(dev, "%lld KB of HCA context requires %lld KB aux memory.\n", - (unsigned long long) icm_size >> 10, - (unsigned long long) aux_pages << 2); - - priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages, - GFP_HIGHUSER | __GFP_NOWARN, 0); - if (!priv->fw.aux_icm) { - mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n"); - return -ENOMEM; - } - - err = mlx4_MAP_ICM_AUX(dev, priv->fw.aux_icm); - if (err) { - mlx4_err(dev, "MAP_ICM_AUX command failed, aborting.\n"); - goto err_free_aux; - } - - err = mlx4_init_cmpt_table(dev, init_hca->cmpt_base, dev_cap->cmpt_entry_sz); - if (err) { - mlx4_err(dev, "Failed to map cMPT context memory, aborting.\n"); - goto err_unmap_aux; - } - - - num_eqs = (mlx4_is_master(dev)) ? dev->phys_caps.num_phys_eqs : - dev->caps.num_eqs; - err = mlx4_init_icm_table(dev, &priv->eq_table.table, - init_hca->eqc_base, dev_cap->eqc_entry_sz, - num_eqs, num_eqs, 0, 0); - if (err) { - mlx4_err(dev, "Failed to map EQ context memory, aborting.\n"); - goto err_unmap_cmpt; - } - - /* - * Reserved MTT entries must be aligned up to a cacheline - * boundary, since the FW will write to them, while the driver - * writes to all other MTT entries. (The variable - * dev->caps.mtt_entry_sz below is really the MTT segment - * size, not the raw entry size) - */ - dev->caps.reserved_mtts = - ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz, - dma_get_cache_alignment()) / dev->caps.mtt_entry_sz; - - err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table, - init_hca->mtt_base, - dev->caps.mtt_entry_sz, - dev->caps.num_mtts, - dev->caps.reserved_mtts, 1, 0); - if (err) { - mlx4_err(dev, "Failed to map MTT context memory, aborting.\n"); - goto err_unmap_eq; - } - - err = mlx4_init_icm_table(dev, &priv->mr_table.dmpt_table, - init_hca->dmpt_base, - dev_cap->dmpt_entry_sz, - dev->caps.num_mpts, - dev->caps.reserved_mrws, 1, 1); - if (err) { - mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n"); - goto err_unmap_mtt; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.qp_table, - init_hca->qpc_base, - dev_cap->qpc_entry_sz, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map QP context memory, aborting.\n"); - goto err_unmap_dmpt; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.auxc_table, - init_hca->auxc_base, - dev_cap->aux_entry_sz, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n"); - goto err_unmap_qp; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.altc_table, - init_hca->altc_base, - dev_cap->altc_entry_sz, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n"); - goto err_unmap_auxc; - } - - err = mlx4_init_icm_table(dev, &priv->qp_table.rdmarc_table, - init_hca->rdmarc_base, - dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift, - dev->caps.num_qps, - dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n"); - goto err_unmap_altc; - } - - err = mlx4_init_icm_table(dev, &priv->cq_table.table, - init_hca->cqc_base, - dev_cap->cqc_entry_sz, - dev->caps.num_cqs, - dev->caps.reserved_cqs, 0, 0); - if (err) { - mlx4_err(dev, "Failed to map CQ context memory, aborting.\n"); - goto err_unmap_rdmarc; - } - - err = mlx4_init_icm_table(dev, &priv->srq_table.table, - init_hca->srqc_base, - dev_cap->srq_entry_sz, - dev->caps.num_srqs, - dev->caps.reserved_srqs, 0, 0); - if (err) { - mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n"); - goto err_unmap_cq; - } - - /* - * For flow steering device managed mode it is required to use - * mlx4_init_icm_table. For B0 steering mode it's not strictly - * required, but for simplicity just map the whole multicast - * group table now. The table isn't very big and it's a lot - * easier than trying to track ref counts. - */ - err = mlx4_init_icm_table(dev, &priv->mcg_table.table, - init_hca->mc_base, - mlx4_get_mgm_entry_size(dev), - dev->caps.num_mgms + dev->caps.num_amgms, - dev->caps.num_mgms + dev->caps.num_amgms, - 0, 0); - if (err) { - mlx4_err(dev, "Failed to map MCG context memory, aborting.\n"); - goto err_unmap_srq; - } - - return 0; - -err_unmap_srq: - mlx4_cleanup_icm_table(dev, &priv->srq_table.table); - -err_unmap_cq: - mlx4_cleanup_icm_table(dev, &priv->cq_table.table); - -err_unmap_rdmarc: - mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); - -err_unmap_altc: - mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); - -err_unmap_auxc: - mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); - -err_unmap_qp: - mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); - -err_unmap_dmpt: - mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); - -err_unmap_mtt: - mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); - -err_unmap_eq: - mlx4_cleanup_icm_table(dev, &priv->eq_table.table); - -err_unmap_cmpt: - mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - -err_unmap_aux: - unmap_flag = mlx4_UNMAP_ICM_AUX(dev); - if (unmap_flag) - pr_warn("mlx4_core: mlx4_UNMAP_ICM_AUX failed.\n"); - -err_free_aux: - if (!unmap_flag) - mlx4_free_icm(dev, priv->fw.aux_icm, 0); - - return err; -} - -static void mlx4_free_icms(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mlx4_cleanup_icm_table(dev, &priv->mcg_table.table); - mlx4_cleanup_icm_table(dev, &priv->srq_table.table); - mlx4_cleanup_icm_table(dev, &priv->cq_table.table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); - mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); - mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); - mlx4_cleanup_icm_table(dev, &priv->eq_table.table); - mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); - mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - - if (!mlx4_UNMAP_ICM_AUX(dev)) - mlx4_free_icm(dev, priv->fw.aux_icm, 0); - else - pr_warn("mlx4_core: mlx4_UNMAP_ICM_AUX failed.\n"); -} - -static void mlx4_slave_exit(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mutex_lock(&priv->cmd.slave_cmd_mutex); - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) - mlx4_warn(dev, "Failed to close slave function.\n"); - mutex_unlock(&priv->cmd.slave_cmd_mutex); -} - -static int map_bf_area(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - resource_size_t bf_start; - resource_size_t bf_len; - int err = 0; - - if (!dev->caps.bf_reg_size) - return -ENXIO; - - bf_start = pci_resource_start(dev->pdev, 2) + - (dev->caps.num_uars << PAGE_SHIFT); - bf_len = pci_resource_len(dev->pdev, 2) - - (dev->caps.num_uars << PAGE_SHIFT); - priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); - if (!priv->bf_mapping) - err = -ENOMEM; - - return err; -} - -static void unmap_bf_area(struct mlx4_dev *dev) -{ - if (mlx4_priv(dev)->bf_mapping) - io_mapping_free(mlx4_priv(dev)->bf_mapping); -} - -int mlx4_read_clock(struct mlx4_dev *dev) -{ - u32 clockhi, clocklo, clockhi1; - cycle_t cycles; - int i; - struct mlx4_priv *priv = mlx4_priv(dev); - - if (!priv->clock_mapping) - return -ENOTSUPP; - - for (i = 0; i < 10; i++) { - clockhi = swab32(readl(priv->clock_mapping)); - clocklo = swab32(readl(priv->clock_mapping + 4)); - clockhi1 = swab32(readl(priv->clock_mapping)); - if (clockhi == clockhi1) - break; - } - - cycles = (u64) clockhi << 32 | (u64) clocklo; - - return cycles; -} -EXPORT_SYMBOL_GPL(mlx4_read_clock); - - -static int map_internal_clock(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - priv->clock_mapping = ioremap(pci_resource_start(dev->pdev, - priv->fw.clock_bar) + - priv->fw.clock_offset, MLX4_CLOCK_SIZE); - - if (!priv->clock_mapping) - return -ENOMEM; - - return 0; -} - - -int mlx4_get_internal_clock_params(struct mlx4_dev *dev, - struct mlx4_clock_params *params) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (mlx4_is_slave(dev)) - return -ENOTSUPP; - if (!params) - return -EINVAL; - - params->bar = priv->fw.clock_bar; - params->offset = priv->fw.clock_offset; - params->size = MLX4_CLOCK_SIZE; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_get_internal_clock_params); - -static void unmap_internal_clock(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (priv->clock_mapping) - iounmap(priv->clock_mapping); -} - -static void mlx4_close_hca(struct mlx4_dev *dev) -{ - unmap_internal_clock(dev); - unmap_bf_area(dev); - if (mlx4_is_slave(dev)) { - mlx4_slave_exit(dev); - } else { - mlx4_CLOSE_HCA(dev, 0); - mlx4_free_icms(dev); - - if (!mlx4_UNMAP_FA(dev)) - mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); - else - pr_warn("mlx4_core: mlx4_UNMAP_FA failed.\n"); - } -} - -static int mlx4_init_slave(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - u64 dma = (u64) priv->mfunc.vhcr_dma; - int num_of_reset_retries = NUM_OF_RESET_RETRIES; - int ret_from_reset = 0; - u32 slave_read; - u32 cmd_channel_ver; - - mutex_lock(&priv->cmd.slave_cmd_mutex); - priv->cmd.max_cmds = 1; - mlx4_warn(dev, "Sending reset\n"); - ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, - MLX4_COMM_TIME); - /* if we are in the middle of flr the slave will try - * NUM_OF_RESET_RETRIES times before leaving.*/ - if (ret_from_reset) { - if (MLX4_DELAY_RESET_SLAVE == ret_from_reset) { - msleep(SLEEP_TIME_IN_RESET); - while (ret_from_reset && num_of_reset_retries) { - mlx4_warn(dev, "slave is currently in the" - "middle of FLR. retrying..." - "(try num:%d)\n", - (NUM_OF_RESET_RETRIES - - num_of_reset_retries + 1)); - ret_from_reset = - mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, - 0, MLX4_COMM_TIME); - num_of_reset_retries = num_of_reset_retries - 1; - } - } else - goto err; - } - - /* check the driver version - the slave I/F revision - * must match the master's */ - slave_read = swab32(readl(&priv->mfunc.comm->slave_read)); - cmd_channel_ver = mlx4_comm_get_version(); - - if (MLX4_COMM_GET_IF_REV(cmd_channel_ver) != - MLX4_COMM_GET_IF_REV(slave_read)) { - mlx4_err(dev, "slave driver version is not supported" - " by the master\n"); - goto err; - } - - mlx4_warn(dev, "Sending vhcr0\n"); - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR0, dma >> 48, - MLX4_COMM_TIME)) - goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR1, dma >> 32, - MLX4_COMM_TIME)) - goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR2, dma >> 16, - MLX4_COMM_TIME)) - goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME)) - goto err; - - mutex_unlock(&priv->cmd.slave_cmd_mutex); - return 0; - -err: - mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); - mutex_unlock(&priv->cmd.slave_cmd_mutex); - return -EIO; -} - -static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev) -{ - int i; - - for (i = 1; i <= dev->caps.num_ports; i++) { - if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) - dev->caps.gid_table_len[i] = - mlx4_get_slave_num_gids(dev, 0); - else - dev->caps.gid_table_len[i] = 1; - dev->caps.pkey_table_len[i] = - dev->phys_caps.pkey_phys_table_len[i] - 1; - } -} - -static int choose_log_fs_mgm_entry_size(int qp_per_entry) -{ - int i = MLX4_MIN_MGM_LOG_ENTRY_SIZE; - - for (i = MLX4_MIN_MGM_LOG_ENTRY_SIZE; i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE; - i++) { - if (qp_per_entry <= 4 * ((1 << i) / 16 - 2)) - break; - } - - return (i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE) ? i : -1; -} - -static void choose_steering_mode(struct mlx4_dev *dev, - struct mlx4_dev_cap *dev_cap) -{ - int nvfs; - - mlx4_get_val(num_vfs.dbdf2val.tbl, pci_physfn(dev->pdev), 0, &nvfs); - if (high_rate_steer && !mlx4_is_mfunc(dev)) { - dev->caps.flags &= ~(MLX4_DEV_CAP_FLAG_VEP_MC_STEER | - MLX4_DEV_CAP_FLAG_VEP_UC_STEER); - dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_FS_EN; - } - - if (mlx4_log_num_mgm_entry_size == -1 && - dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN && - (!mlx4_is_mfunc(dev) || - (dev_cap->fs_max_num_qp_per_entry >= (nvfs + 1))) && - choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >= - MLX4_MIN_MGM_LOG_ENTRY_SIZE) { - dev->oper_log_mgm_entry_size = - choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry); - dev->caps.steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED; - dev->caps.num_qp_per_mgm = dev_cap->fs_max_num_qp_per_entry; - } else { - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER && - dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) - dev->caps.steering_mode = MLX4_STEERING_MODE_B0; - else { - dev->caps.steering_mode = MLX4_STEERING_MODE_A0; - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER || - dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) - mlx4_warn(dev, "Must have both UC_STEER and MC_STEER flags " - "set to use B0 steering. Falling back to A0 steering mode.\n"); - } - dev->oper_log_mgm_entry_size = - mlx4_log_num_mgm_entry_size > 0 ? - mlx4_log_num_mgm_entry_size : - MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE; - dev->caps.num_qp_per_mgm = mlx4_get_qp_per_mgm(dev); - } - mlx4_dbg(dev, "Steering mode is: %s, oper_log_mgm_entry_size = %d, " - "log_num_mgm_entry_size = %d\n", - mlx4_steering_mode_str(dev->caps.steering_mode), - dev->oper_log_mgm_entry_size, mlx4_log_num_mgm_entry_size); -} - -static int mlx4_init_hca(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_dev_cap *dev_cap = NULL; - struct mlx4_adapter adapter; - struct mlx4_mod_stat_cfg mlx4_cfg; - struct mlx4_profile profile; - struct mlx4_init_hca_param init_hca; - u64 icm_size; - int err; - - if (!mlx4_is_slave(dev)) { - err = mlx4_QUERY_FW(dev); - if (err) { - if (err == -EACCES) - mlx4_info(dev, "non-primary physical function, skipping.\n"); - else - mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); - return err; - } - - err = mlx4_load_fw(dev); - if (err) { - mlx4_err(dev, "Failed to start FW, aborting.\n"); - return err; - } - - mlx4_cfg.log_pg_sz_m = 1; - mlx4_cfg.log_pg_sz = 0; - err = mlx4_MOD_STAT_CFG(dev, &mlx4_cfg); - if (err) - mlx4_warn(dev, "Failed to override log_pg_sz parameter\n"); - - dev_cap = kzalloc(sizeof *dev_cap, GFP_KERNEL); - if (!dev_cap) { - mlx4_err(dev, "Failed to allocate memory for dev_cap\n"); - err = -ENOMEM; - goto err_stop_fw; - } - - err = mlx4_dev_cap(dev, dev_cap); - if (err) { - mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); - goto err_stop_fw; - } - - choose_steering_mode(dev, dev_cap); - - if (mlx4_is_master(dev)) - mlx4_parav_master_pf_caps(dev); - - process_mod_param_profile(&profile); - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) - profile.num_mcg = MLX4_FS_NUM_MCG; - - icm_size = mlx4_make_profile(dev, &profile, dev_cap, - &init_hca); - if ((long long) icm_size < 0) { - err = icm_size; - goto err_stop_fw; - } - - dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1; - - init_hca.log_uar_sz = ilog2(dev->caps.num_uars); - init_hca.uar_page_sz = PAGE_SHIFT - 12; - - err = mlx4_init_icm(dev, dev_cap, &init_hca, icm_size); - if (err) - goto err_stop_fw; - - init_hca.mw_enable = 1; - - err = mlx4_INIT_HCA(dev, &init_hca); - if (err) { - mlx4_err(dev, "INIT_HCA command failed, aborting.\n"); - goto err_free_icm; - } - - /* - * Read HCA frequency by QUERY_HCA command - */ - if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) { - memset(&init_hca, 0, sizeof(init_hca)); - err = mlx4_QUERY_HCA(dev, &init_hca); - if (err) { - mlx4_err(dev, "QUERY_HCA command failed, disable timestamp.\n"); - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - } else { - dev->caps.hca_core_clock = - init_hca.hca_core_clock; - } - - /* In case we got HCA frequency 0 - disable timestamping - * to avoid dividing by zero - */ - if (!dev->caps.hca_core_clock) { - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - mlx4_err(dev, "HCA frequency is 0. Timestamping is not supported."); - } else if (map_internal_clock(dev)) { - /* Map internal clock, - * in case of failure disable timestamping - */ - dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS; - mlx4_err(dev, "Failed to map internal clock. Timestamping is not supported.\n"); - } - } - } else { - err = mlx4_init_slave(dev); - if (err) { - mlx4_err(dev, "Failed to initialize slave\n"); - return err; - } - - err = mlx4_slave_cap(dev); - if (err) { - mlx4_err(dev, "Failed to obtain slave caps\n"); - goto err_close; - } - } - - if (map_bf_area(dev)) - mlx4_dbg(dev, "Failed to map blue flame area\n"); - - /* Only the master set the ports, all the rest got it from it.*/ - if (!mlx4_is_slave(dev)) - mlx4_set_port_mask(dev); - - err = mlx4_QUERY_ADAPTER(dev, &adapter); - if (err) { - mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n"); - goto unmap_bf; - } - - priv->eq_table.inta_pin = adapter.inta_pin; - memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id); - memcpy(dev->vsd, adapter.vsd, sizeof(dev->vsd)); - dev->vsd_vendor_id = adapter.vsd_vendor_id; - - if (!mlx4_is_slave(dev)) - kfree(dev_cap); - - return 0; - -unmap_bf: - if (!mlx4_is_slave(dev)) - unmap_internal_clock(dev); - unmap_bf_area(dev); - - if (mlx4_is_slave(dev)) { - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - } - -err_close: - if (mlx4_is_slave(dev)) - mlx4_slave_exit(dev); - else - mlx4_CLOSE_HCA(dev, 0); - -err_free_icm: - if (!mlx4_is_slave(dev)) - mlx4_free_icms(dev); - -err_stop_fw: - if (!mlx4_is_slave(dev)) { - if (!mlx4_UNMAP_FA(dev)) - mlx4_free_icm(dev, priv->fw.fw_icm, 0); - else - pr_warn("mlx4_core: mlx4_UNMAP_FA failed.\n"); - kfree(dev_cap); - } - return err; -} - -static int mlx4_init_counters_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int nent_pow2, port_indx, vf_index, num_counters; - int res, index = 0; - struct counter_index *new_counter_index; - - - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)) - return -ENOENT; - - if (!mlx4_is_slave(dev) && - dev->caps.max_counters == dev->caps.max_extended_counters) { - res = mlx4_cmd(dev, MLX4_IF_STATE_EXTENDED, 0, 0, - MLX4_CMD_SET_IF_STAT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - if (res) { - mlx4_err(dev, "Failed to set extended counters (err=%d)\n", res); - return res; - } - } - - mutex_init(&priv->counters_table.mutex); - - if (mlx4_is_slave(dev)) { - for (port_indx = 0; port_indx < dev->caps.num_ports; port_indx++) { - INIT_LIST_HEAD(&priv->counters_table.global_port_list[port_indx]); - if (dev->caps.def_counter_index[port_indx] != 0xFF) { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - return -ENOMEM; - new_counter_index->index = dev->caps.def_counter_index[port_indx]; - list_add_tail(&new_counter_index->list, &priv->counters_table.global_port_list[port_indx]); - } - } - mlx4_dbg(dev, "%s: slave allocated %d counters for %d ports\n", - __func__, dev->caps.num_ports, dev->caps.num_ports); - return 0; - } - - nent_pow2 = roundup_pow_of_two(dev->caps.max_counters); - - for (port_indx = 0; port_indx < dev->caps.num_ports; port_indx++) { - INIT_LIST_HEAD(&priv->counters_table.global_port_list[port_indx]); - /* allocating 2 counters per port for PFs */ - /* For the PF, the ETH default counters are 0,2; */ - /* and the RoCE default counters are 1,3 */ - for (num_counters = 0; num_counters < 2; num_counters++, index++) { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - return -ENOMEM; - new_counter_index->index = index; - list_add_tail(&new_counter_index->list, - &priv->counters_table.global_port_list[port_indx]); - } - } - - if (mlx4_is_master(dev)) { - for (vf_index = 0; vf_index < dev->num_vfs; vf_index++) { - for (port_indx = 0; port_indx < dev->caps.num_ports; port_indx++) { - INIT_LIST_HEAD(&priv->counters_table.vf_list[vf_index][port_indx]); - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - return -ENOMEM; - if (index < nent_pow2 - 2) { - new_counter_index->index = index; - index++; - } else { - new_counter_index->index = MLX4_SINK_COUNTER_INDEX; - } - - list_add_tail(&new_counter_index->list, - &priv->counters_table.vf_list[vf_index][port_indx]); - } - } - - res = mlx4_bitmap_init(&priv->counters_table.bitmap, - nent_pow2, nent_pow2 - 1, - index, 1); - mlx4_dbg(dev, "%s: master allocated %d counters for %d VFs\n", - __func__, index, dev->num_vfs); - } else { - res = mlx4_bitmap_init(&priv->counters_table.bitmap, - nent_pow2, nent_pow2 - 1, - index, 1); - mlx4_dbg(dev, "%s: native allocated %d counters for %d ports\n", - __func__, index, dev->caps.num_ports); - } - - return 0; - -} - -static void mlx4_cleanup_counters_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, j; - struct counter_index *port, *tmp_port; - struct counter_index *vf, *tmp_vf; - - mutex_lock(&priv->counters_table.mutex); - - if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS) { - for (i = 0; i < dev->caps.num_ports; i++) { - list_for_each_entry_safe(port, tmp_port, - &priv->counters_table.global_port_list[i], - list) { - list_del(&port->list); - kfree(port); - } - } - if (!mlx4_is_slave(dev)) { - for (i = 0; i < dev->num_vfs; i++) { - for (j = 0; j < dev->caps.num_ports; j++) { - list_for_each_entry_safe(vf, tmp_vf, - &priv->counters_table.vf_list[i][j], - list) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, vf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, vf->index); - list_del(&vf->list); - kfree(vf); - } - } - } - mlx4_bitmap_cleanup(&priv->counters_table.bitmap); - } - } - mutex_unlock(&priv->counters_table.mutex); -} - -int __mlx4_slave_counters_free(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, first; - struct counter_index *vf, *tmp_vf; - - /* clean VF's counters for the next useg */ - if (slave > 0 && slave <= dev->num_vfs) { - mlx4_dbg(dev, "%s: free counters of slave(%d)\n" - , __func__, slave); - - mutex_lock(&priv->counters_table.mutex); - for (i = 0; i < dev->caps.num_ports; i++) { - first = 0; - list_for_each_entry_safe(vf, tmp_vf, - &priv->counters_table.vf_list[slave - 1][i], - list) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, vf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, vf->index); - if (first++ && vf->index != MLX4_SINK_COUNTER_INDEX) { - mlx4_dbg(dev, "%s: delete counter index %d for slave %d and port %d\n" - , __func__, vf->index, slave, i + 1); - mlx4_bitmap_free(&priv->counters_table.bitmap, vf->index, MLX4_USE_RR); - list_del(&vf->list); - kfree(vf); - } else { - mlx4_dbg(dev, "%s: can't delete default counter index %d for slave %d and port %d\n" - , __func__, vf->index, slave, i + 1); - } - } - } - mutex_unlock(&priv->counters_table.mutex); - } - - return 0; -} - -int __mlx4_counter_alloc(struct mlx4_dev *dev, int slave, int port, u32 *idx) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *new_counter_index; - - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)) - return -ENOENT; - - if ((slave > MLX4_MAX_NUM_VF) || (slave < 0) || - (port < 0) || (port > MLX4_MAX_PORTS)) { - mlx4_dbg(dev, "%s: invalid slave(%d) or port(%d) index\n", - __func__, slave, port); - return -EINVAL; - } - - /* handle old guest request does not support request by port index */ - if (port == 0) { - *idx = MLX4_SINK_COUNTER_INDEX; - mlx4_dbg(dev, "%s: allocated default counter index %d for slave %d port %d\n" - , __func__, *idx, slave, port); - return 0; - } - - mutex_lock(&priv->counters_table.mutex); - - *idx = mlx4_bitmap_alloc(&priv->counters_table.bitmap); - /* if no resources return the default counter of the slave and port */ - if (*idx == -1) { - if (slave == 0) { /* its the ethernet counter ?????? */ - new_counter_index = list_entry(priv->counters_table.global_port_list[port - 1].next, - struct counter_index, - list); - } else { - new_counter_index = list_entry(priv->counters_table.vf_list[slave - 1][port - 1].next, - struct counter_index, - list); - } - - *idx = new_counter_index->index; - mlx4_dbg(dev, "%s: allocated defualt counter index %d for slave %d port %d\n" - , __func__, *idx, slave, port); - goto out; - } - - if (slave == 0) { /* native or master */ - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - goto no_mem; - new_counter_index->index = *idx; - list_add_tail(&new_counter_index->list, &priv->counters_table.global_port_list[port - 1]); - } else { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) - goto no_mem; - new_counter_index->index = *idx; - list_add_tail(&new_counter_index->list, &priv->counters_table.vf_list[slave - 1][port - 1]); - } - - mlx4_dbg(dev, "%s: allocated counter index %d for slave %d port %d\n" - , __func__, *idx, slave, port); -out: - mutex_unlock(&priv->counters_table.mutex); - return 0; - -no_mem: - mlx4_bitmap_free(&priv->counters_table.bitmap, *idx, MLX4_USE_RR); - mutex_unlock(&priv->counters_table.mutex); - *idx = MLX4_SINK_COUNTER_INDEX; - mlx4_dbg(dev, "%s: failed err (%d)\n" - , __func__, -ENOMEM); - return -ENOMEM; -} - -int mlx4_counter_alloc(struct mlx4_dev *dev, u8 port, u32 *idx) -{ - u64 out_param; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *new_counter_index, *c_index; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, - ((u32) port) << 8 | (u32) RES_COUNTER, - RES_OP_RESERVE, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) { - *idx = get_param_l(&out_param); - if (*idx == MLX4_SINK_COUNTER_INDEX) - return -ENOSPC; - - mutex_lock(&priv->counters_table.mutex); - c_index = list_entry(priv->counters_table.global_port_list[port - 1].next, - struct counter_index, - list); - mutex_unlock(&priv->counters_table.mutex); - if (c_index->index == *idx) - return -EEXIST; - - if (mlx4_is_slave(dev)) { - new_counter_index = kmalloc(sizeof(struct counter_index), GFP_KERNEL); - if (!new_counter_index) { - mlx4_counter_free(dev, port, *idx); - return -ENOMEM; - } - new_counter_index->index = *idx; - mutex_lock(&priv->counters_table.mutex); - list_add_tail(&new_counter_index->list, &priv->counters_table.global_port_list[port - 1]); - mutex_unlock(&priv->counters_table.mutex); - mlx4_dbg(dev, "%s: allocated counter index %d for port %d\n" - , __func__, *idx, port); - } - } - return err; - } - return __mlx4_counter_alloc(dev, 0, port, idx); -} -EXPORT_SYMBOL_GPL(mlx4_counter_alloc); - -void __mlx4_counter_free(struct mlx4_dev *dev, int slave, int port, u32 idx) -{ - /* check if native or slave and deletes accordingly */ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *pf, *tmp_pf; - struct counter_index *vf, *tmp_vf; - int first; - - - if (idx == MLX4_SINK_COUNTER_INDEX) { - mlx4_dbg(dev, "%s: try to delete default counter index %d for port %d\n" - , __func__, idx, port); - return; - } - - if ((slave > MLX4_MAX_NUM_VF) || (slave < 0) || - (port < 0) || (port > MLX4_MAX_PORTS)) { - mlx4_warn(dev, "%s: deletion failed due to invalid slave(%d) or port(%d) index\n" - , __func__, slave, idx); - return; - } - - mutex_lock(&priv->counters_table.mutex); - if (slave == 0) { - first = 0; - list_for_each_entry_safe(pf, tmp_pf, - &priv->counters_table.global_port_list[port - 1], - list) { - /* the first 2 counters are reserved */ - if (pf->index == idx) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, pf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, pf->index); - if (1 < first && idx != MLX4_SINK_COUNTER_INDEX) { - list_del(&pf->list); - kfree(pf); - mlx4_dbg(dev, "%s: delete counter index %d for native device (%d) port %d\n" - , __func__, idx, slave, port); - mlx4_bitmap_free(&priv->counters_table.bitmap, idx, MLX4_USE_RR); - goto out; - } else { - mlx4_dbg(dev, "%s: can't delete default counter index %d for native device (%d) port %d\n" - , __func__, idx, slave, port); - goto out; - } - } - first++; - } - mlx4_dbg(dev, "%s: can't delete counter index %d for native device (%d) port %d\n" - , __func__, idx, slave, port); - } else { - first = 0; - list_for_each_entry_safe(vf, tmp_vf, - &priv->counters_table.vf_list[slave - 1][port - 1], - list) { - /* the first element is reserved */ - if (vf->index == idx) { - /* clear the counter statistic */ - if (__mlx4_clear_if_stat(dev, vf->index)) - mlx4_dbg(dev, "%s: reset counter %d failed\n", - __func__, vf->index); - if (first) { - list_del(&vf->list); - kfree(vf); - mlx4_dbg(dev, "%s: delete counter index %d for slave %d port %d\n", - __func__, idx, slave, port); - mlx4_bitmap_free(&priv->counters_table.bitmap, idx, MLX4_USE_RR); - goto out; - } else { - mlx4_dbg(dev, "%s: can't delete default slave (%d) counter index %d for port %d\n" - , __func__, slave, idx, port); - goto out; - } - } - first++; - } - mlx4_dbg(dev, "%s: can't delete slave (%d) counter index %d for port %d\n" - , __func__, slave, idx, port); - } - -out: - mutex_unlock(&priv->counters_table.mutex); -} - -void mlx4_counter_free(struct mlx4_dev *dev, u8 port, u32 idx) -{ - u64 in_param = 0; - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *counter, *tmp_counter; - int first = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, idx); - mlx4_cmd(dev, in_param, - ((u32) port) << 8 | (u32) RES_COUNTER, - RES_OP_RESERVE, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - - if (mlx4_is_slave(dev) && idx != MLX4_SINK_COUNTER_INDEX) { - mutex_lock(&priv->counters_table.mutex); - list_for_each_entry_safe(counter, tmp_counter, - &priv->counters_table.global_port_list[port - 1], - list) { - if (counter->index == idx && first++) { - list_del(&counter->list); - kfree(counter); - mlx4_dbg(dev, "%s: delete counter index %d for port %d\n" - , __func__, idx, port); - mutex_unlock(&priv->counters_table.mutex); - return; - } - } - mutex_unlock(&priv->counters_table.mutex); - } - - return; - } - __mlx4_counter_free(dev, 0, port, idx); -} -EXPORT_SYMBOL_GPL(mlx4_counter_free); - -int __mlx4_clear_if_stat(struct mlx4_dev *dev, - u8 counter_index) -{ - struct mlx4_cmd_mailbox *if_stat_mailbox = NULL; - int err = 0; - u32 if_stat_in_mod = (counter_index & 0xff) | (1 << 31); - - if (counter_index == MLX4_SINK_COUNTER_INDEX) - return -EINVAL; - - if (mlx4_is_slave(dev)) - return 0; - - if_stat_mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(if_stat_mailbox)) { - err = PTR_ERR(if_stat_mailbox); - return err; - } - - err = mlx4_cmd_box(dev, 0, if_stat_mailbox->dma, if_stat_in_mod, 0, - MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, if_stat_mailbox); - return err; -} - -u8 mlx4_get_default_counter_index(struct mlx4_dev *dev, int slave, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *new_counter_index; - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB) { - mlx4_dbg(dev, "%s: return counter index %d for slave %d port (MLX4_PORT_TYPE_IB) %d\n", - __func__, MLX4_SINK_COUNTER_INDEX, slave, port); - return (u8)MLX4_SINK_COUNTER_INDEX; - } - - mutex_lock(&priv->counters_table.mutex); - if (slave == 0) { - new_counter_index = list_entry(priv->counters_table.global_port_list[port - 1].next, - struct counter_index, - list); - } else { - new_counter_index = list_entry(priv->counters_table.vf_list[slave - 1][port - 1].next, - struct counter_index, - list); - } - mutex_unlock(&priv->counters_table.mutex); - - mlx4_dbg(dev, "%s: return counter index %d for slave %d port %d\n", - __func__, new_counter_index->index, slave, port); - - - return (u8)new_counter_index->index; -} - -int mlx4_get_vport_ethtool_stats(struct mlx4_dev *dev, int port, - struct mlx4_en_vport_stats *vport_stats, - int reset) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *if_stat_mailbox = NULL; - union mlx4_counter *counter; - int err = 0; - u32 if_stat_in_mod; - struct counter_index *vport, *tmp_vport; - - if (!vport_stats) - return -EINVAL; - - if_stat_mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(if_stat_mailbox)) { - err = PTR_ERR(if_stat_mailbox); - return err; - } - - mutex_lock(&priv->counters_table.mutex); - list_for_each_entry_safe(vport, tmp_vport, - &priv->counters_table.global_port_list[port - 1], - list) { - if (vport->index == MLX4_SINK_COUNTER_INDEX) - continue; - - memset(if_stat_mailbox->buf, 0, sizeof(union mlx4_counter)); - if_stat_in_mod = (vport->index & 0xff) | ((reset & 1) << 31); - err = mlx4_cmd_box(dev, 0, if_stat_mailbox->dma, - if_stat_in_mod, 0, - MLX4_CMD_QUERY_IF_STAT, - MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - if (err) { - mlx4_dbg(dev, "%s: failed to read statistics for counter index %d\n", - __func__, vport->index); - goto if_stat_out; - } - counter = (union mlx4_counter *)if_stat_mailbox->buf; - if ((counter->control.cnt_mode & 0xf) == 1) { - vport_stats->rx_broadcast_packets += be64_to_cpu(counter->ext.counters[0].IfRxBroadcastFrames); - vport_stats->rx_unicast_packets += be64_to_cpu(counter->ext.counters[0].IfRxUnicastFrames); - vport_stats->rx_multicast_packets += be64_to_cpu(counter->ext.counters[0].IfRxMulticastFrames); - vport_stats->tx_broadcast_packets += be64_to_cpu(counter->ext.counters[0].IfTxBroadcastFrames); - vport_stats->tx_unicast_packets += be64_to_cpu(counter->ext.counters[0].IfTxUnicastFrames); - vport_stats->tx_multicast_packets += be64_to_cpu(counter->ext.counters[0].IfTxMulticastFrames); - vport_stats->rx_broadcast_bytes += be64_to_cpu(counter->ext.counters[0].IfRxBroadcastOctets); - vport_stats->rx_unicast_bytes += be64_to_cpu(counter->ext.counters[0].IfRxUnicastOctets); - vport_stats->rx_multicast_bytes += be64_to_cpu(counter->ext.counters[0].IfRxMulticastOctets); - vport_stats->tx_broadcast_bytes += be64_to_cpu(counter->ext.counters[0].IfTxBroadcastOctets); - vport_stats->tx_unicast_bytes += be64_to_cpu(counter->ext.counters[0].IfTxUnicastOctets); - vport_stats->tx_multicast_bytes += be64_to_cpu(counter->ext.counters[0].IfTxMulticastOctets); - vport_stats->rx_errors += be64_to_cpu(counter->ext.counters[0].IfRxErrorFrames); - vport_stats->rx_dropped += be64_to_cpu(counter->ext.counters[0].IfRxNoBufferFrames); - vport_stats->tx_errors += be64_to_cpu(counter->ext.counters[0].IfTxDroppedFrames); - } - } - -if_stat_out: - mutex_unlock(&priv->counters_table.mutex); - mlx4_free_cmd_mailbox(dev, if_stat_mailbox); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_get_vport_ethtool_stats); - -static int mlx4_setup_hca(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - int port; - __be32 ib_port_default_caps; - - err = mlx4_init_uar_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "user access region table (err=%d), aborting.\n", - err); - return err; - } - - err = mlx4_uar_alloc(dev, &priv->driver_uar); - if (err) { - mlx4_err(dev, "Failed to allocate driver access region " - "(err=%d), aborting.\n", err); - goto err_uar_table_free; - } - - priv->kar = ioremap((phys_addr_t) priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); - if (!priv->kar) { - mlx4_err(dev, "Couldn't map kernel access region, " - "aborting.\n"); - err = -ENOMEM; - goto err_uar_free; - } - - err = mlx4_init_pd_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "protection domain table (err=%d), aborting.\n", err); - goto err_kar_unmap; - } - - err = mlx4_init_xrcd_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "reliable connection domain table (err=%d), " - "aborting.\n", err); - goto err_pd_table_free; - } - - err = mlx4_init_mr_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "memory region table (err=%d), aborting.\n", err); - goto err_xrcd_table_free; - } - - if (!mlx4_is_slave(dev)) { - err = mlx4_init_mcg_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "multicast group table (err=%d), aborting.\n", - err); - goto err_mr_table_free; - } - } - - err = mlx4_init_eq_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "event queue table (err=%d), aborting.\n", err); - goto err_mcg_table_free; - } - - err = mlx4_cmd_use_events(dev); - if (err) { - mlx4_err(dev, "Failed to switch to event-driven " - "firmware commands (err=%d), aborting.\n", err); - goto err_eq_table_free; - } - - err = mlx4_NOP(dev); - if (err) { - if (dev->flags & MLX4_FLAG_MSI_X) { - mlx4_warn(dev, "NOP command failed to generate MSI-X " - "interrupt IRQ %d).\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].irq); - mlx4_warn(dev, "Trying again without MSI-X.\n"); - } else { - mlx4_err(dev, "NOP command failed to generate interrupt " - "(IRQ %d), aborting.\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].irq); - mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); - } - - goto err_cmd_poll; - } - - mlx4_dbg(dev, "NOP command IRQ test passed\n"); - - err = mlx4_init_cq_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "completion queue table (err=%d), aborting.\n", err); - goto err_cmd_poll; - } - - err = mlx4_init_srq_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "shared receive queue table (err=%d), aborting.\n", - err); - goto err_cq_table_free; - } - - err = mlx4_init_qp_table(dev); - if (err) { - mlx4_err(dev, "Failed to initialize " - "queue pair table (err=%d), aborting.\n", err); - goto err_srq_table_free; - } - - err = mlx4_init_counters_table(dev); - if (err && err != -ENOENT) { - mlx4_err(dev, "Failed to initialize counters table (err=%d), " - "aborting.\n", err); - goto err_qp_table_free; - } - - if (!mlx4_is_slave(dev)) { - for (port = 1; port <= dev->caps.num_ports; port++) { - ib_port_default_caps = 0; - err = mlx4_get_port_ib_caps(dev, port, - &ib_port_default_caps); - if (err) - mlx4_warn(dev, "failed to get port %d default " - "ib capabilities (%d). Continuing " - "with caps = 0\n", port, err); - dev->caps.ib_port_def_cap[port] = ib_port_default_caps; - - /* initialize per-slave default ib port capabilities */ - if (mlx4_is_master(dev)) { - int i; - for (i = 0; i < dev->num_slaves; i++) { - if (i == mlx4_master_func_num(dev)) - continue; - priv->mfunc.master.slave_state[i].ib_cap_mask[port] = - ib_port_default_caps; - } - } - - dev->caps.port_ib_mtu[port] = IB_MTU_4096; - - err = mlx4_SET_PORT(dev, port, mlx4_is_master(dev) ? - dev->caps.pkey_table_len[port] : -1); - if (err) { - mlx4_err(dev, "Failed to set port %d (err=%d), " - "aborting\n", port, err); - goto err_counters_table_free; - } - } - } - - return 0; - -err_counters_table_free: - mlx4_cleanup_counters_table(dev); - -err_qp_table_free: - mlx4_cleanup_qp_table(dev); - -err_srq_table_free: - mlx4_cleanup_srq_table(dev); - -err_cq_table_free: - mlx4_cleanup_cq_table(dev); - -err_cmd_poll: - mlx4_cmd_use_polling(dev); - -err_eq_table_free: - mlx4_cleanup_eq_table(dev); - -err_mcg_table_free: - if (!mlx4_is_slave(dev)) - mlx4_cleanup_mcg_table(dev); - -err_mr_table_free: - mlx4_cleanup_mr_table(dev); - -err_xrcd_table_free: - mlx4_cleanup_xrcd_table(dev); - -err_pd_table_free: - mlx4_cleanup_pd_table(dev); - -err_kar_unmap: - iounmap(priv->kar); - -err_uar_free: - mlx4_uar_free(dev, &priv->driver_uar); - -err_uar_table_free: - mlx4_cleanup_uar_table(dev); - return err; -} - -static void mlx4_enable_msi_x(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct msix_entry *entries; - int nreq = min_t(int, dev->caps.num_ports * - min_t(int, num_possible_cpus() + 1, MAX_MSIX_P_PORT) - + MSIX_LEGACY_SZ, MAX_MSIX); - int err; - int i; - - if (msi_x) { - nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, - nreq); - - if (msi_x > 1 && !mlx4_is_mfunc(dev)) - nreq = min_t(int, nreq, msi_x); - - entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); - if (!entries) - goto no_msi; - - for (i = 0; i < nreq; ++i) - entries[i].entry = i; - - retry: - err = pci_enable_msix(dev->pdev, entries, nreq); - if (err) { - /* Try again if at least 2 vectors are available */ - if (err > 1) { - mlx4_info(dev, "Requested %d vectors, " - "but only %d MSI-X vectors available, " - "trying again\n", nreq, err); - nreq = err; - goto retry; - } - kfree(entries); - /* if error, or can't alloc even 1 IRQ */ - if (err < 0) { - mlx4_err(dev, "No IRQs left, device can't " - "be started.\n"); - goto no_irq; - } - goto no_msi; - } - - if (nreq < - MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) { - /*Working in legacy mode , all EQ's shared*/ - dev->caps.comp_pool = 0; - dev->caps.num_comp_vectors = nreq - 1; - } else { - dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ; - dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1; - } - for (i = 0; i < nreq; ++i) - priv->eq_table.eq[i].irq = entries[i].vector; - - dev->flags |= MLX4_FLAG_MSI_X; - - kfree(entries); - return; - } - -no_msi: - dev->caps.num_comp_vectors = 1; - dev->caps.comp_pool = 0; - - for (i = 0; i < 2; ++i) - priv->eq_table.eq[i].irq = dev->pdev->irq; - return; -no_irq: - dev->caps.num_comp_vectors = 0; - dev->caps.comp_pool = 0; - return; -} - -static void -mlx4_init_hca_info(struct mlx4_dev *dev) -{ - struct mlx4_hca_info *info = &mlx4_priv(dev)->hca_info; - - info->dev = dev; - - info->firmware_attr = (struct device_attribute)__ATTR(fw_ver, S_IRUGO, - show_firmware_version, NULL); - if (device_create_file(&dev->pdev->dev, &info->firmware_attr)) - mlx4_err(dev, "Failed to add file firmware version"); - - info->hca_attr = (struct device_attribute)__ATTR(hca, S_IRUGO, show_hca, - NULL); - if (device_create_file(&dev->pdev->dev, &info->hca_attr)) - mlx4_err(dev, "Failed to add file hca type"); - - info->board_attr = (struct device_attribute)__ATTR(board_id, S_IRUGO, - show_board, NULL); - if (device_create_file(&dev->pdev->dev, &info->board_attr)) - mlx4_err(dev, "Failed to add file board id type"); -} - -static int mlx4_init_port_info(struct mlx4_dev *dev, int port) -{ - struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; - int err = 0; - - info->dev = dev; - info->port = port; - if (!mlx4_is_slave(dev)) { - mlx4_init_mac_table(dev, &info->mac_table); - mlx4_init_vlan_table(dev, &info->vlan_table); - info->base_qpn = mlx4_get_base_qpn(dev, port); - } - - sprintf(info->dev_name, "mlx4_port%d", port); - info->port_attr.attr.name = info->dev_name; - if (mlx4_is_mfunc(dev)) - info->port_attr.attr.mode = S_IRUGO; - else { - info->port_attr.attr.mode = S_IRUGO | S_IWUSR; - info->port_attr.store = set_port_type; - } - info->port_attr.show = show_port_type; - sysfs_attr_init(&info->port_attr.attr); - - err = device_create_file(&dev->pdev->dev, &info->port_attr); - if (err) { - mlx4_err(dev, "Failed to create file for port %d\n", port); - info->port = -1; - } - - sprintf(info->dev_mtu_name, "mlx4_port%d_mtu", port); - info->port_mtu_attr.attr.name = info->dev_mtu_name; - if (mlx4_is_mfunc(dev)) - info->port_mtu_attr.attr.mode = S_IRUGO; - else { - info->port_mtu_attr.attr.mode = S_IRUGO | S_IWUSR; - info->port_mtu_attr.store = set_port_ib_mtu; - } - info->port_mtu_attr.show = show_port_ib_mtu; - sysfs_attr_init(&info->port_mtu_attr.attr); - - err = device_create_file(&dev->pdev->dev, &info->port_mtu_attr); - if (err) { - mlx4_err(dev, "Failed to create mtu file for port %d\n", port); - device_remove_file(&info->dev->pdev->dev, &info->port_attr); - info->port = -1; - } - - return err; -} - -static void -mlx4_cleanup_hca_info(struct mlx4_hca_info *info) -{ - device_remove_file(&info->dev->pdev->dev, &info->firmware_attr); - device_remove_file(&info->dev->pdev->dev, &info->board_attr); - device_remove_file(&info->dev->pdev->dev, &info->hca_attr); -} - -static void mlx4_cleanup_port_info(struct mlx4_port_info *info) -{ - if (info->port < 0) - return; - - device_remove_file(&info->dev->pdev->dev, &info->port_attr); - device_remove_file(&info->dev->pdev->dev, &info->port_mtu_attr); -} - -static int mlx4_init_steering(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int num_entries = dev->caps.num_ports; - int i, j; - - priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL); - if (!priv->steer) - return -ENOMEM; - - for (i = 0; i < num_entries; i++) - for (j = 0; j < MLX4_NUM_STEERS; j++) { - INIT_LIST_HEAD(&priv->steer[i].promisc_qps[j]); - INIT_LIST_HEAD(&priv->steer[i].steer_entries[j]); - } - return 0; -} - -static void mlx4_clear_steering(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_steer_index *entry, *tmp_entry; - struct mlx4_promisc_qp *pqp, *tmp_pqp; - int num_entries = dev->caps.num_ports; - int i, j; - - for (i = 0; i < num_entries; i++) { - for (j = 0; j < MLX4_NUM_STEERS; j++) { - list_for_each_entry_safe(pqp, tmp_pqp, - &priv->steer[i].promisc_qps[j], - list) { - list_del(&pqp->list); - kfree(pqp); - } - list_for_each_entry_safe(entry, tmp_entry, - &priv->steer[i].steer_entries[j], - list) { - list_del(&entry->list); - list_for_each_entry_safe(pqp, tmp_pqp, - &entry->duplicates, - list) { - list_del(&pqp->list); - kfree(pqp); - } - kfree(entry); - } - } - } - kfree(priv->steer); -} - -static int extended_func_num(struct pci_dev *pdev) -{ - return PCI_SLOT(pdev->devfn) * 8 + PCI_FUNC(pdev->devfn); -} - -#define MLX4_OWNER_BASE 0x8069c -#define MLX4_OWNER_SIZE 4 - -static int mlx4_get_ownership(struct mlx4_dev *dev) -{ - void __iomem *owner; - u32 ret; - - if (pci_channel_offline(dev->pdev)) - return -EIO; - - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, - MLX4_OWNER_SIZE); - if (!owner) { - mlx4_err(dev, "Failed to obtain ownership bit\n"); - return -ENOMEM; - } - - ret = readl(owner); - iounmap(owner); - return (int) !!ret; -} - -static void mlx4_free_ownership(struct mlx4_dev *dev) -{ - void __iomem *owner; - - if (pci_channel_offline(dev->pdev)) - return; - - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, - MLX4_OWNER_SIZE); - if (!owner) { - mlx4_err(dev, "Failed to obtain ownership bit\n"); - return; - } - writel(0, owner); - msleep(1000); - iounmap(owner); -} - -static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data) -{ - struct mlx4_priv *priv; - struct mlx4_dev *dev; - int err; - int port; - int nvfs, prb_vf; - - pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev)); - - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "Cannot enable PCI device, " - "aborting.\n"); - return err; - } - - mlx4_get_val(num_vfs.dbdf2val.tbl, pci_physfn(pdev), 0, &nvfs); - mlx4_get_val(probe_vf.dbdf2val.tbl, pci_physfn(pdev), 0, &prb_vf); - if (nvfs > MLX4_MAX_NUM_VF) { - dev_err(&pdev->dev, "There are more VF's (%d) than allowed(%d)\n", - nvfs, MLX4_MAX_NUM_VF); - return -EINVAL; - } - - if (nvfs < 0) { - dev_err(&pdev->dev, "num_vfs module parameter cannot be negative\n"); - return -EINVAL; - } - /* - * Check for BARs. - */ - if (!(pci_dev_data & MLX4_PCI_DEV_IS_VF) && - !(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "Missing DCS, aborting." - "(driver_data: 0x%x, pci_resource_flags(pdev, 0):0x%x)\n", - pci_dev_data, pci_resource_flags(pdev, 0)); - err = -ENODEV; - goto err_disable_pdev; - } - if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "Missing UAR, aborting.\n"); - err = -ENODEV; - goto err_disable_pdev; - } - - err = pci_request_regions(pdev, DRV_NAME); - if (err) { - dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n"); - goto err_disable_pdev; - } - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); - goto err_release_regions; - } - } - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " - "consistent PCI DMA mask.\n"); - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " - "aborting.\n"); - goto err_release_regions; - } - } - - /* Allow large DMA segments, up to the firmware limit of 1 GB */ - dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); - - priv = kzalloc(sizeof *priv, GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "Device struct alloc failed, " - "aborting.\n"); - err = -ENOMEM; - goto err_release_regions; - } - - dev = &priv->dev; - dev->pdev = pdev; - INIT_LIST_HEAD(&priv->dev_list); - INIT_LIST_HEAD(&priv->ctx_list); - spin_lock_init(&priv->ctx_lock); - - mutex_init(&priv->port_mutex); - - INIT_LIST_HEAD(&priv->pgdir_list); - mutex_init(&priv->pgdir_mutex); - - INIT_LIST_HEAD(&priv->bf_list); - mutex_init(&priv->bf_mutex); - - dev->rev_id = pdev->revision; - dev->numa_node = dev_to_node(&pdev->dev); - /* Detect if this device is a virtual function */ - if (pci_dev_data & MLX4_PCI_DEV_IS_VF) { - /* When acting as pf, we normally skip vfs unless explicitly - * requested to probe them. */ - if (nvfs && extended_func_num(pdev) > prb_vf) { - mlx4_warn(dev, "Skipping virtual function:%d\n", - extended_func_num(pdev)); - err = -ENODEV; - goto err_free_dev; - } - mlx4_warn(dev, "Detected virtual function - running in slave mode\n"); - dev->flags |= MLX4_FLAG_SLAVE; - } else { - /* We reset the device and enable SRIOV only for physical - * devices. Try to claim ownership on the device; - * if already taken, skip -- do not allow multiple PFs */ - err = mlx4_get_ownership(dev); - if (err) { - if (err < 0) - goto err_free_dev; - else { - mlx4_warn(dev, "Multiple PFs not yet supported." - " Skipping PF.\n"); - err = -EINVAL; - goto err_free_dev; - } - } - - if (nvfs) { - mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", nvfs); - err = pci_enable_sriov(pdev, nvfs); - if (err) { - mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n", - err); - err = 0; - } else { - mlx4_warn(dev, "Running in master mode\n"); - dev->flags |= MLX4_FLAG_SRIOV | - MLX4_FLAG_MASTER; - dev->num_vfs = nvfs; - } - } - - atomic_set(&priv->opreq_count, 0); - INIT_WORK(&priv->opreq_task, mlx4_opreq_action); - - /* - * Now reset the HCA before we touch the PCI capabilities or - * attempt a firmware command, since a boot ROM may have left - * the HCA in an undefined state. - */ - err = mlx4_reset(dev); - if (err) { - mlx4_err(dev, "Failed to reset HCA, aborting.\n"); - goto err_sriov; - } - } - -slave_start: - err = mlx4_cmd_init(dev); - if (err) { - mlx4_err(dev, "Failed to init command interface, aborting.\n"); - goto err_sriov; - } - - /* In slave functions, the communication channel must be initialized - * before posting commands. Also, init num_slaves before calling - * mlx4_init_hca */ - if (mlx4_is_mfunc(dev)) { - if (mlx4_is_master(dev)) - dev->num_slaves = MLX4_MAX_NUM_SLAVES; - else { - dev->num_slaves = 0; - err = mlx4_multi_func_init(dev); - if (err) { - mlx4_err(dev, "Failed to init slave mfunc" - " interface, aborting.\n"); - goto err_cmd; - } - } - } - - err = mlx4_init_hca(dev); - if (err) { - if (err == -EACCES) { - /* Not primary Physical function - * Running in slave mode */ - mlx4_cmd_cleanup(dev); - dev->flags |= MLX4_FLAG_SLAVE; - dev->flags &= ~MLX4_FLAG_MASTER; - goto slave_start; - } else - goto err_mfunc; - } - - /* In master functions, the communication channel must be initialized - * after obtaining its address from fw */ - if (mlx4_is_master(dev)) { - err = mlx4_multi_func_init(dev); - if (err) { - mlx4_err(dev, "Failed to init master mfunc" - "interface, aborting.\n"); - goto err_close; - } - } - - err = mlx4_alloc_eq_table(dev); - if (err) - goto err_master_mfunc; - - priv->msix_ctl.pool_bm = 0; - mutex_init(&priv->msix_ctl.pool_lock); - - mlx4_enable_msi_x(dev); - - /* no MSIX and no shared IRQ */ - if (!dev->caps.num_comp_vectors && !dev->caps.comp_pool) { - err = -ENOSPC; - goto err_free_eq; - } - - if ((mlx4_is_mfunc(dev)) && - !(dev->flags & MLX4_FLAG_MSI_X)) { - err = -ENOSYS; - mlx4_err(dev, "INTx is not supported in multi-function mode." - " aborting.\n"); - goto err_free_eq; - } - - if (!mlx4_is_slave(dev)) { - err = mlx4_init_steering(dev); - if (err) - goto err_free_eq; - } - - err = mlx4_setup_hca(dev); - if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X) && - !mlx4_is_mfunc(dev)) { - dev->flags &= ~MLX4_FLAG_MSI_X; - dev->caps.num_comp_vectors = 1; - dev->caps.comp_pool = 0; - pci_disable_msix(pdev); - err = mlx4_setup_hca(dev); - } - - if (err) - goto err_steer; - - mlx4_init_quotas(dev); - mlx4_init_hca_info(dev); - - for (port = 1; port <= dev->caps.num_ports; port++) { - err = mlx4_init_port_info(dev, port); - if (err) - goto err_port; - } - - err = mlx4_register_device(dev); - if (err) - goto err_port; - - mlx4_request_modules(dev); - - mlx4_sense_init(dev); - mlx4_start_sense(dev); - - priv->pci_dev_data = pci_dev_data; - pci_set_drvdata(pdev, dev); - - return 0; - -err_port: - for (--port; port >= 1; --port) - mlx4_cleanup_port_info(&priv->port[port]); - - mlx4_cleanup_counters_table(dev); - mlx4_cleanup_qp_table(dev); - mlx4_cleanup_srq_table(dev); - mlx4_cleanup_cq_table(dev); - mlx4_cmd_use_polling(dev); - mlx4_cleanup_eq_table(dev); - mlx4_cleanup_mcg_table(dev); - mlx4_cleanup_mr_table(dev); - mlx4_cleanup_xrcd_table(dev); - mlx4_cleanup_pd_table(dev); - mlx4_cleanup_uar_table(dev); - -err_steer: - if (!mlx4_is_slave(dev)) - mlx4_clear_steering(dev); - -err_free_eq: - mlx4_free_eq_table(dev); - -err_master_mfunc: - if (mlx4_is_master(dev)) { - mlx4_free_resource_tracker(dev, RES_TR_FREE_STRUCTS_ONLY); - mlx4_multi_func_cleanup(dev); - } - - if (mlx4_is_slave(dev)) { - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - } - -err_close: - if (dev->flags & MLX4_FLAG_MSI_X) - pci_disable_msix(pdev); - - mlx4_close_hca(dev); - -err_mfunc: - if (mlx4_is_slave(dev)) - mlx4_multi_func_cleanup(dev); - -err_cmd: - mlx4_cmd_cleanup(dev); - -err_sriov: - if (dev->flags & MLX4_FLAG_SRIOV) - pci_disable_sriov(pdev); - - if (!mlx4_is_slave(dev)) - mlx4_free_ownership(dev); - -err_free_dev: - kfree(priv); - -err_release_regions: - pci_release_regions(pdev); - -err_disable_pdev: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - return err; -} - -static int __devinit mlx4_init_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - device_set_desc(pdev->dev.bsddev, mlx4_version); - return __mlx4_init_one(pdev, id->driver_data); -} - -static void mlx4_remove_one(struct pci_dev *pdev) -{ - struct mlx4_dev *dev = pci_get_drvdata(pdev); - struct mlx4_priv *priv = mlx4_priv(dev); - int p; - - if (dev) { - /* in SRIOV it is not allowed to unload the pf's - * driver while there are alive vf's */ - if (mlx4_is_master(dev)) { - if (mlx4_how_many_lives_vf(dev)) - mlx4_err(dev, "Removing PF when there are assigned VF's !!!\n"); - } - mlx4_stop_sense(dev); - mlx4_unregister_device(dev); - - mlx4_cleanup_hca_info(&priv->hca_info); - for (p = 1; p <= dev->caps.num_ports; p++) { - mlx4_cleanup_port_info(&priv->port[p]); - mlx4_CLOSE_PORT(dev, p); - } - - if (mlx4_is_master(dev)) - mlx4_free_resource_tracker(dev, - RES_TR_FREE_SLAVES_ONLY); - - mlx4_cleanup_counters_table(dev); - mlx4_cleanup_qp_table(dev); - mlx4_cleanup_srq_table(dev); - mlx4_cleanup_cq_table(dev); - mlx4_cmd_use_polling(dev); - mlx4_cleanup_eq_table(dev); - mlx4_cleanup_mcg_table(dev); - mlx4_cleanup_mr_table(dev); - mlx4_cleanup_xrcd_table(dev); - mlx4_cleanup_pd_table(dev); - - if (mlx4_is_master(dev)) - mlx4_free_resource_tracker(dev, - RES_TR_FREE_STRUCTS_ONLY); - - iounmap(priv->kar); - mlx4_uar_free(dev, &priv->driver_uar); - mlx4_cleanup_uar_table(dev); - if (!mlx4_is_slave(dev)) - mlx4_clear_steering(dev); - mlx4_free_eq_table(dev); - if (mlx4_is_master(dev)) - mlx4_multi_func_cleanup(dev); - mlx4_close_hca(dev); - if (mlx4_is_slave(dev)) - mlx4_multi_func_cleanup(dev); - mlx4_cmd_cleanup(dev); - - if (dev->flags & MLX4_FLAG_MSI_X) - pci_disable_msix(pdev); - if (dev->flags & MLX4_FLAG_SRIOV) { - mlx4_warn(dev, "Disabling SR-IOV\n"); - pci_disable_sriov(pdev); - } - - if (!mlx4_is_slave(dev)) - mlx4_free_ownership(dev); - - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - - kfree(priv); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - } -} - -static int restore_current_port_types(struct mlx4_dev *dev, - enum mlx4_port_type *types, - enum mlx4_port_type *poss_types) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err, i; - - mlx4_stop_sense(dev); - mutex_lock(&priv->port_mutex); - for (i = 0; i < dev->caps.num_ports; i++) - dev->caps.possible_type[i + 1] = poss_types[i]; - err = mlx4_change_port_types(dev, types); - mlx4_start_sense(dev); - mutex_unlock(&priv->port_mutex); - return err; -} - -int mlx4_restart_one(struct pci_dev *pdev) -{ - struct mlx4_dev *dev = pci_get_drvdata(pdev); - struct mlx4_priv *priv = mlx4_priv(dev); - enum mlx4_port_type curr_type[MLX4_MAX_PORTS]; - enum mlx4_port_type poss_type[MLX4_MAX_PORTS]; - int pci_dev_data, err, i; - - pci_dev_data = priv->pci_dev_data; - for (i = 0; i < dev->caps.num_ports; i++) { - curr_type[i] = dev->caps.port_type[i + 1]; - poss_type[i] = dev->caps.possible_type[i + 1]; - } - - mlx4_remove_one(pdev); - err = __mlx4_init_one(pdev, pci_dev_data); - if (err) - return err; - - dev = pci_get_drvdata(pdev); - err = restore_current_port_types(dev, curr_type, poss_type); - if (err) - mlx4_err(dev, "mlx4_restart_one: could not restore original port types (%d)\n", - err); - return 0; -} - -static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = { - /* MT25408 "Hermon" SDR */ - { PCI_VDEVICE(MELLANOX, 0x6340), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" DDR */ - { PCI_VDEVICE(MELLANOX, 0x634a), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" QDR */ - { PCI_VDEVICE(MELLANOX, 0x6354), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" DDR PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x6732), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" QDR PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x673c), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" EN 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x6368), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x6750), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25458 ConnectX EN 10GBASE-T 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x6372), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x675a), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26468 ConnectX EN 10GigE PCIe gen2*/ - { PCI_VDEVICE(MELLANOX, 0x6764), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */ - { PCI_VDEVICE(MELLANOX, 0x6746), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26478 ConnectX2 40GigE PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x676e), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25400 Family [ConnectX-2 Virtual Function] */ - { PCI_VDEVICE(MELLANOX, 0x1002), MLX4_PCI_DEV_IS_VF }, - /* MT27500 Family [ConnectX-3] */ - { PCI_VDEVICE(MELLANOX, 0x1003), 0 }, - /* MT27500 Family [ConnectX-3 Virtual Function] */ - { PCI_VDEVICE(MELLANOX, 0x1004), MLX4_PCI_DEV_IS_VF }, - { PCI_VDEVICE(MELLANOX, 0x1005), 0 }, /* MT27510 Family */ - { PCI_VDEVICE(MELLANOX, 0x1006), 0 }, /* MT27511 Family */ - { PCI_VDEVICE(MELLANOX, 0x1007), 0 }, /* MT27520 Family */ - { PCI_VDEVICE(MELLANOX, 0x1008), 0 }, /* MT27521 Family */ - { PCI_VDEVICE(MELLANOX, 0x1009), 0 }, /* MT27530 Family */ - { PCI_VDEVICE(MELLANOX, 0x100a), 0 }, /* MT27531 Family */ - { PCI_VDEVICE(MELLANOX, 0x100b), 0 }, /* MT27540 Family */ - { PCI_VDEVICE(MELLANOX, 0x100c), 0 }, /* MT27541 Family */ - { PCI_VDEVICE(MELLANOX, 0x100d), 0 }, /* MT27550 Family */ - { PCI_VDEVICE(MELLANOX, 0x100e), 0 }, /* MT27551 Family */ - { PCI_VDEVICE(MELLANOX, 0x100f), 0 }, /* MT27560 Family */ - { PCI_VDEVICE(MELLANOX, 0x1010), 0 }, /* MT27561 Family */ - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, mlx4_pci_table); - -static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - mlx4_remove_one(pdev); - - return state == pci_channel_io_perm_failure ? - PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; -} - -static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) -{ - int ret = __mlx4_init_one(pdev, 0); - - return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; -} - -static const struct pci_error_handlers mlx4_err_handler = { - .error_detected = mlx4_pci_err_detected, - .slot_reset = mlx4_pci_slot_reset, -}; - -static int suspend(struct pci_dev *pdev, pm_message_t state) -{ - mlx4_remove_one(pdev); - - return 0; -} - -static int resume(struct pci_dev *pdev) -{ - return __mlx4_init_one(pdev, 0); -} - -static struct pci_driver mlx4_driver = { - .name = DRV_NAME, - .id_table = mlx4_pci_table, - .probe = mlx4_init_one, - .remove = __devexit_p(mlx4_remove_one), - .suspend = suspend, - .resume = resume, - .err_handler = &mlx4_err_handler, -}; - -static int __init mlx4_verify_params(void) -{ - int status; - - status = update_defaults(&port_type_array); - if (status == INVALID_STR) { - if (mlx4_fill_dbdf2val_tbl(&port_type_array.dbdf2val)) - return -1; - } else if (status == INVALID_DATA) { - return -1; - } - - status = update_defaults(&num_vfs); - if (status == INVALID_STR) { - if (mlx4_fill_dbdf2val_tbl(&num_vfs.dbdf2val)) - return -1; - } else if (status == INVALID_DATA) { - return -1; - } - - status = update_defaults(&probe_vf); - if (status == INVALID_STR) { - if (mlx4_fill_dbdf2val_tbl(&probe_vf.dbdf2val)) - return -1; - } else if (status == INVALID_DATA) { - return -1; - } - - if (msi_x < 0) { - pr_warn("mlx4_core: bad msi_x: %d\n", msi_x); - return -1; - } - - if ((log_num_mac < 0) || (log_num_mac > 7)) { - pr_warning("mlx4_core: bad num_mac: %d\n", log_num_mac); - return -1; - } - - if (log_num_vlan != 0) - pr_warning("mlx4_core: log_num_vlan - obsolete module param, using %d\n", - MLX4_LOG_NUM_VLANS); - - if (mlx4_set_4k_mtu != -1) - pr_warning("mlx4_core: set_4k_mtu - obsolete module param\n"); - - if ((log_mtts_per_seg < 0) || (log_mtts_per_seg > 7)) { - pr_warning("mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg); - return -1; - } - - if (mlx4_log_num_mgm_entry_size != -1 && - (mlx4_log_num_mgm_entry_size < MLX4_MIN_MGM_LOG_ENTRY_SIZE || - mlx4_log_num_mgm_entry_size > MLX4_MAX_MGM_LOG_ENTRY_SIZE)) { - pr_warning("mlx4_core: mlx4_log_num_mgm_entry_size (%d) not " - "in legal range (-1 or %d..%d)\n", - mlx4_log_num_mgm_entry_size, - MLX4_MIN_MGM_LOG_ENTRY_SIZE, - MLX4_MAX_MGM_LOG_ENTRY_SIZE); - return -1; - } - - if (mod_param_profile.num_qp < 18 || mod_param_profile.num_qp > 23) { - pr_warning("mlx4_core: bad log_num_qp: %d\n", - mod_param_profile.num_qp); - return -1; - } - - if (mod_param_profile.num_srq < 10) { - pr_warning("mlx4_core: too low log_num_srq: %d\n", - mod_param_profile.num_srq); - return -1; - } - - if (mod_param_profile.num_cq < 10) { - pr_warning("mlx4_core: too low log_num_cq: %d\n", - mod_param_profile.num_cq); - return -1; - } - - if (mod_param_profile.num_mpt < 10) { - pr_warning("mlx4_core: too low log_num_mpt: %d\n", - mod_param_profile.num_mpt); - return -1; - } - - if (mod_param_profile.num_mtt_segs && - mod_param_profile.num_mtt_segs < 15) { - pr_warning("mlx4_core: too low log_num_mtt: %d\n", - mod_param_profile.num_mtt_segs); - return -1; - } - - if (mod_param_profile.num_mtt_segs > MLX4_MAX_LOG_NUM_MTT) { - pr_warning("mlx4_core: too high log_num_mtt: %d\n", - mod_param_profile.num_mtt_segs); - return -1; - } - return 0; -} - -static int __init mlx4_init(void) -{ - int ret; - - if (mlx4_verify_params()) - return -EINVAL; - - mlx4_catas_init(); - - mlx4_wq = create_singlethread_workqueue("mlx4"); - if (!mlx4_wq) - return -ENOMEM; - - if (enable_sys_tune) - sys_tune_init(); - - ret = pci_register_driver(&mlx4_driver); - if (ret < 0) - goto err; - - return 0; - -err: - if (enable_sys_tune) - sys_tune_fini(); - - destroy_workqueue(mlx4_wq); - - return ret; -} - -static void __exit mlx4_cleanup(void) -{ - if (enable_sys_tune) - sys_tune_fini(); - - pci_unregister_driver(&mlx4_driver); - destroy_workqueue(mlx4_wq); -} - -module_init_order(mlx4_init, SI_ORDER_MIDDLE); -module_exit(mlx4_cleanup); - -static int -mlx4_evhand(module_t mod, int event, void *arg) -{ - return (0); -} - -static moduledata_t mlx4_mod = { - .name = "mlx4", - .evhand = mlx4_evhand, -}; -MODULE_VERSION(mlx4, 1); -DECLARE_MODULE(mlx4, mlx4_mod, SI_SUB_OFED_PREINIT, SI_ORDER_ANY); -MODULE_DEPEND(mlx4, linuxkpi, 1, 1, 1); - diff --git a/sys/ofed/drivers/net/mlx4/mcg.c b/sys/ofed/drivers/net/mlx4/mcg.c deleted file mode 100644 index 71c1c838564c..000000000000 --- a/sys/ofed/drivers/net/mlx4/mcg.c +++ /dev/null @@ -1,1543 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 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/string.h> -#include <linux/etherdevice.h> - -#include <linux/mlx4/cmd.h> -#include <linux/module.h> -#include <linux/printk.h> - -#include "mlx4.h" - -int mlx4_get_mgm_entry_size(struct mlx4_dev *dev) -{ - return 1 << dev->oper_log_mgm_entry_size; -} - -int mlx4_get_qp_per_mgm(struct mlx4_dev *dev) -{ - return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2); -} - -static int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *mailbox, - u32 size, - u64 *reg_id) -{ - u64 imm; - int err = 0; - - err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0, - MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - return err; - *reg_id = imm; - - return err; -} - -static int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid) -{ - int err = 0; - - err = mlx4_cmd(dev, regid, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - return err; -} - -static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) -{ - return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) -{ - return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); -} - -static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer, - struct mlx4_cmd_mailbox *mailbox) -{ - u32 in_mod; - - in_mod = (u32) port << 16 | steer << 1; - return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, - MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); -} - -static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - u16 *hash, u8 op_mod) -{ - u64 imm; - int err; - - err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, - MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - if (!err) - *hash = imm; - - return err; -} - -static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_promisc_qp *pqp; - - if (port < 1 || port > dev->caps.num_ports) - return NULL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { - if (pqp->qpn == qpn) - return pqp; - } - /* not found */ - return NULL; -} - -/* - * Add new entry to steering data structure. - * All promisc QPs should be added as well - */ -static int new_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 members_count; - struct mlx4_steer_index *new_entry; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp = NULL; - u32 prot; - int err; - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); - if (!new_entry) - return -ENOMEM; - - INIT_LIST_HEAD(&new_entry->duplicates); - new_entry->index = index; - list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); - - /* If the given qpn is also a promisc qp, - * it should be inserted to duplicates list - */ - pqp = get_promisc_qp(dev, port, steer, qpn); - if (pqp) { - dqp = kmalloc(sizeof *dqp, GFP_KERNEL); - if (!dqp) { - err = -ENOMEM; - goto out_alloc; - } - dqp->qpn = qpn; - list_add_tail(&dqp->list, &new_entry->duplicates); - } - - /* if no promisc qps for this vep, we are done */ - if (list_empty(&s_steer->promisc_qps[steer])) - return 0; - - /* now need to add all the promisc qps to the new - * steering entry, as they should also receive the packets - * destined to this address */ - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = -ENOMEM; - goto out_alloc; - } - mgm = mailbox->buf; - - err = mlx4_READ_ENTRY(dev, index, mailbox); - if (err) - goto out_mailbox; - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - prot = be32_to_cpu(mgm->members_count) >> 30; - list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { - /* don't add already existing qpn */ - if (pqp->qpn == qpn) - continue; - if (members_count == dev->caps.num_qp_per_mgm) { - /* out of space */ - err = -ENOMEM; - goto out_mailbox; - } - - /* add the qpn */ - mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); - } - /* update the qps count and update the entry with all the promisc qps*/ - mgm->members_count = cpu_to_be32(members_count | (prot << 30)); - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - -out_mailbox: - mlx4_free_cmd_mailbox(dev, mailbox); - if (!err) - return 0; -out_alloc: - if (dqp) { - list_del(&dqp->list); - kfree(dqp); - } - list_del(&new_entry->list); - kfree(new_entry); - return err; -} - -/* update the data structures with existing steering entry */ -static int existing_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_steer_index *tmp_entry, *entry = NULL; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp; - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - pqp = get_promisc_qp(dev, port, steer, qpn); - if (!pqp) - return 0; /* nothing to do */ - - list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { - if (tmp_entry->index == index) { - entry = tmp_entry; - break; - } - } - if (unlikely(!entry)) { - mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); - return -EINVAL; - } - - /* the given qpn is listed as a promisc qpn - * we need to add it as a duplicate to this entry - * for future references */ - list_for_each_entry(dqp, &entry->duplicates, list) { - if (qpn == dqp->qpn) - return 0; /* qp is already duplicated */ - } - - /* add the qp as a duplicate on this index */ - dqp = kmalloc(sizeof *dqp, GFP_KERNEL); - if (!dqp) - return -ENOMEM; - dqp->qpn = qpn; - list_add_tail(&dqp->list, &entry->duplicates); - - return 0; -} - -/* Check whether a qpn is a duplicate on steering entry - * If so, it should not be removed from mgm */ -static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_steer_index *tmp_entry, *entry = NULL; - struct mlx4_promisc_qp *dqp, *tmp_dqp; - - if (port < 1 || port > dev->caps.num_ports) - return NULL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - /* if qp is not promisc, it cannot be duplicated */ - if (!get_promisc_qp(dev, port, steer, qpn)) - return false; - - /* The qp is promisc qp so it is a duplicate on this index - * Find the index entry, and remove the duplicate */ - list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { - if (tmp_entry->index == index) { - entry = tmp_entry; - break; - } - } - if (unlikely(!entry)) { - mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); - return false; - } - list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { - if (dqp->qpn == qpn) { - list_del(&dqp->list); - kfree(dqp); - } - } - return true; -} - -/* - * returns true if all the QPs != tqpn contained in this entry - * are Promisc QPs. return false otherwise. - */ -static bool promisc_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 tqpn, u32 *members_count) -{ - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 m_count; - bool ret = false; - int i; - - if (port < 1 || port > dev->caps.num_ports) - return false; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return false; - mgm = mailbox->buf; - - if (mlx4_READ_ENTRY(dev, index, mailbox)) - goto out; - m_count = be32_to_cpu(mgm->members_count) & 0xffffff; - if (members_count) - *members_count = m_count; - - for (i = 0; i < m_count; i++) { - u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; - if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) { - /* the qp is not promisc, the entry can't be removed */ - goto out; - } - } - ret = true; -out: - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; -} - -/* IF a steering entry contains only promisc QPs, it can be removed. */ -static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 tqpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_steer_index *entry = NULL, *tmp_entry; - u32 members_count; - bool ret = false; - - if (port < 1 || port > dev->caps.num_ports) - return NULL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - if (!promisc_steering_entry(dev, port, steer, index, tqpn, &members_count)) - goto out; - - /* All the qps currently registered for this entry are promiscuous, - * Checking for duplicates */ - ret = true; - list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { - if (entry->index == index) { - if (list_empty(&entry->duplicates) || members_count == 1) { - struct mlx4_promisc_qp *pqp, *tmp_pqp; - /* - * If there is only 1 entry in duplicates than - * this is the QP we want to delete, going over - * the list and deleting the entry. - */ - list_del(&entry->list); - list_for_each_entry_safe(pqp, tmp_pqp, - &entry->duplicates, - list) { - list_del(&pqp->list); - kfree(pqp); - } - kfree(entry); - } else { - /* This entry contains duplicates so it shouldn't be removed */ - ret = false; - goto out; - } - } - } - -out: - return ret; -} - -static int add_promisc_qp(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, u32 qpn) -{ - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - struct mlx4_steer_index *entry; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp; - u32 members_count; - u32 prot; - int i; - bool found; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - - mutex_lock(&priv->mcg_table.mutex); - - if (get_promisc_qp(dev, port, steer, qpn)) { - err = 0; /* Noting to do, already exists */ - goto out_mutex; - } - - pqp = kmalloc(sizeof *pqp, GFP_KERNEL); - if (!pqp) { - err = -ENOMEM; - goto out_mutex; - } - pqp->qpn = qpn; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = -ENOMEM; - goto out_alloc; - } - mgm = mailbox->buf; - - if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { - /* the promisc qp needs to be added for each one of the steering - * entries, if it already exists, needs to be added as a duplicate - * for this entry */ - list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { - err = mlx4_READ_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - prot = be32_to_cpu(mgm->members_count) >> 30; - found = false; - for (i = 0; i < members_count; i++) { - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { - /* Entry already exists, add to duplicates */ - dqp = kmalloc(sizeof *dqp, GFP_KERNEL); - if (!dqp) { - err = -ENOMEM; - goto out_mailbox; - } - dqp->qpn = qpn; - list_add_tail(&dqp->list, &entry->duplicates); - found = true; - } - } - if (!found) { - /* Need to add the qpn to mgm */ - if (members_count == dev->caps.num_qp_per_mgm) { - /* entry is full */ - err = -ENOMEM; - goto out_mailbox; - } - mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | (prot << 30)); - err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - } - } - } - - /* add the new qpn to list of promisc qps */ - list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); - /* now need to add all the promisc qps to default entry */ - memset(mgm, 0, sizeof *mgm); - members_count = 0; - list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) { - if (members_count == dev->caps.num_qp_per_mgm) { - /* entry is full */ - err = -ENOMEM; - goto out_list; - } - mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); - } - mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); - - err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); - if (err) - goto out_list; - - mlx4_free_cmd_mailbox(dev, mailbox); - mutex_unlock(&priv->mcg_table.mutex); - return 0; - -out_list: - list_del(&pqp->list); -out_mailbox: - mlx4_free_cmd_mailbox(dev, mailbox); -out_alloc: - kfree(pqp); -out_mutex: - mutex_unlock(&priv->mcg_table.mutex); - return err; -} - -static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, u32 qpn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_steer *s_steer; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - struct mlx4_steer_index *entry, *tmp_entry; - struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp; - u32 members_count; - bool found; - bool back_to_list = false; - int i, loc = -1; - int err; - - if (port < 1 || port > dev->caps.num_ports) - return -EINVAL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; - mutex_lock(&priv->mcg_table.mutex); - - pqp = get_promisc_qp(dev, port, steer, qpn); - if (unlikely(!pqp)) { - mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); - /* nothing to do */ - err = 0; - goto out_mutex; - } - - /*remove from list of promisc qps */ - list_del(&pqp->list); - - /* set the default entry not to include the removed one */ - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = -ENOMEM; - back_to_list = true; - goto out_list; - } - mgm = mailbox->buf; - memset(mgm, 0, sizeof *mgm); - members_count = 0; - list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) - mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); - - err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); - if (err) - goto out_mailbox; - - if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { - /* remove the qp from all the steering entries*/ - list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { - found = false; - list_for_each_entry(dqp, &entry->duplicates, list) { - if (dqp->qpn == qpn) { - found = true; - break; - } - } - if (found) { - /* a duplicate, no need to change the mgm, - * only update the duplicates list */ - list_del(&dqp->list); - kfree(dqp); - } else { - err = mlx4_READ_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - if (!members_count) { - mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0." - " deleting entry...\n", qpn, entry->index); - list_del(&entry->list); - kfree(entry); - continue; - } - - for (i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { - loc = i; - break; - } - - if (loc < 0) { - mlx4_err(dev, "QP %06x wasn't found in entry %d\n", - qpn, entry->index); - err = -EINVAL; - goto out_mailbox; - } - - /* copy the last QP in this MGM over removed QP */ - mgm->qp[loc] = mgm->qp[members_count - 1]; - mgm->qp[members_count - 1] = 0; - mgm->members_count = cpu_to_be32(--members_count | - (MLX4_PROT_ETH << 30)); - - err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - } - } - } - -out_mailbox: - mlx4_free_cmd_mailbox(dev, mailbox); -out_list: - if (back_to_list) - list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); - else - kfree(pqp); -out_mutex: - mutex_unlock(&priv->mcg_table.mutex); - return err; -} - -/* - * Caller must hold MCG table semaphore. gid and mgm parameters must - * be properly aligned for command interface. - * - * Returns 0 unless a firmware command error occurs. - * - * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 - * and *mgm holds MGM entry. - * - * if GID is found in AMGM, *index = index in AMGM, *prev = index of - * previous entry in hash chain and *mgm holds AMGM entry. - * - * If no AMGM exists for given gid, *index = -1, *prev = index of last - * entry in hash chain and *mgm holds end of hash chain. - */ -static int find_entry(struct mlx4_dev *dev, u8 port, - u8 *gid, enum mlx4_protocol prot, - struct mlx4_cmd_mailbox *mgm_mailbox, - int *prev, int *index) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm = mgm_mailbox->buf; - u8 *mgid; - int err; - u16 hash; - u8 op_mod = (prot == MLX4_PROT_ETH) ? - !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return -ENOMEM; - mgid = mailbox->buf; - - memcpy(mgid, gid, 16); - - err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod); - mlx4_free_cmd_mailbox(dev, mailbox); - if (err) - return err; - - if (0) { - mlx4_dbg(dev, "Hash for "GID_PRINT_FMT" is %04x\n", - GID_PRINT_ARGS(gid), hash); - } - - *index = hash; - *prev = -1; - - do { - err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); - if (err) - return err; - - if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { - if (*index != hash) { - mlx4_err(dev, "Found zero MGID in AMGM.\n"); - err = -EINVAL; - } - return err; - } - - if (!memcmp(mgm->gid, gid, 16) && - be32_to_cpu(mgm->members_count) >> 30 == prot) - return err; - - *prev = *index; - *index = be32_to_cpu(mgm->next_gid_index) >> 6; - } while (*index); - - *index = -1; - return err; -} - -static const u8 __promisc_mode[] = { - [MLX4_FS_REGULAR] = 0x0, - [MLX4_FS_ALL_DEFAULT] = 0x1, - [MLX4_FS_MC_DEFAULT] = 0x3, - [MLX4_FS_UC_SNIFFER] = 0x4, - [MLX4_FS_MC_SNIFFER] = 0x5, -}; - -int map_sw_to_hw_steering_mode(struct mlx4_dev *dev, - enum mlx4_net_trans_promisc_mode flow_type) -{ - if (flow_type >= MLX4_FS_MODE_NUM || flow_type < 0) { - mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type); - return -EINVAL; - } - return __promisc_mode[flow_type]; -} -EXPORT_SYMBOL_GPL(map_sw_to_hw_steering_mode); - -static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, - struct mlx4_net_trans_rule_hw_ctrl *hw) -{ - u8 flags = 0; - - flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0; - flags |= ctrl->exclusive ? (1 << 2) : 0; - flags |= ctrl->allow_loopback ? (1 << 3) : 0; - - hw->flags = flags; - hw->type = __promisc_mode[ctrl->promisc_mode]; - hw->prio = cpu_to_be16(ctrl->priority); - hw->port = ctrl->port; - hw->qpn = cpu_to_be32(ctrl->qpn); -} - -const u16 __sw_id_hw[] = { - [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001, - [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005, - [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003, - [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002, - [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004, - [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006 -}; - -int map_sw_to_hw_steering_id(struct mlx4_dev *dev, - enum mlx4_net_trans_rule_id id) -{ - if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { - mlx4_err(dev, "Invalid network rule id. id = %d\n", id); - return -EINVAL; - } - return __sw_id_hw[id]; -} -EXPORT_SYMBOL_GPL(map_sw_to_hw_steering_id); - -static const int __rule_hw_sz[] = { - [MLX4_NET_TRANS_RULE_ID_ETH] = - sizeof(struct mlx4_net_trans_rule_hw_eth), - [MLX4_NET_TRANS_RULE_ID_IB] = - sizeof(struct mlx4_net_trans_rule_hw_ib), - [MLX4_NET_TRANS_RULE_ID_IPV6] = 0, - [MLX4_NET_TRANS_RULE_ID_IPV4] = - sizeof(struct mlx4_net_trans_rule_hw_ipv4), - [MLX4_NET_TRANS_RULE_ID_TCP] = - sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), - [MLX4_NET_TRANS_RULE_ID_UDP] = - sizeof(struct mlx4_net_trans_rule_hw_tcp_udp) -}; - -int hw_rule_sz(struct mlx4_dev *dev, - enum mlx4_net_trans_rule_id id) -{ - if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { - mlx4_err(dev, "Invalid network rule id. id = %d\n", id); - return -EINVAL; - } - - return __rule_hw_sz[id]; -} -EXPORT_SYMBOL_GPL(hw_rule_sz); - -static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, - struct _rule_hw *rule_hw) -{ - if (hw_rule_sz(dev, spec->id) < 0) - return -EINVAL; - memset(rule_hw, 0, hw_rule_sz(dev, spec->id)); - rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]); - rule_hw->size = hw_rule_sz(dev, spec->id) >> 2; - - switch (spec->id) { - case MLX4_NET_TRANS_RULE_ID_ETH: - memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN); - memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk, - ETH_ALEN); - memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN); - memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk, - ETH_ALEN); - if (spec->eth.ether_type_enable) { - rule_hw->eth.ether_type_enable = 1; - rule_hw->eth.ether_type = spec->eth.ether_type; - } - rule_hw->eth.vlan_tag = spec->eth.vlan_id; - rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk; - break; - - case MLX4_NET_TRANS_RULE_ID_IB: - rule_hw->ib.l3_qpn = spec->ib.l3_qpn; - rule_hw->ib.qpn_mask = spec->ib.qpn_msk; - memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16); - memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16); - break; - - case MLX4_NET_TRANS_RULE_ID_IPV6: - return -EOPNOTSUPP; - - case MLX4_NET_TRANS_RULE_ID_IPV4: - rule_hw->ipv4.src_ip = spec->ipv4.src_ip; - rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk; - rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip; - rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk; - break; - - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port; - rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk; - rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port; - rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk; - break; - - default: - return -EINVAL; - } - - return __rule_hw_sz[spec->id]; -} - -static void mlx4_err_rule(struct mlx4_dev *dev, char *str, - struct mlx4_net_trans_rule *rule) -{ -#define BUF_SIZE 256 - struct mlx4_spec_list *cur; - char buf[BUF_SIZE]; - int len = 0; - - mlx4_err(dev, "%s", str); - len += snprintf(buf + len, BUF_SIZE - len, - "port = %d prio = 0x%x qp = 0x%x ", - rule->port, rule->priority, rule->qpn); - - list_for_each_entry(cur, &rule->list, list) { - switch (cur->id) { - case MLX4_NET_TRANS_RULE_ID_ETH: - len += snprintf(buf + len, BUF_SIZE - len, - "dmac = %pM ", &cur->eth.dst_mac); - if (cur->eth.ether_type) - len += snprintf(buf + len, BUF_SIZE - len, - "ethertype = 0x%x ", - be16_to_cpu(cur->eth.ether_type)); - if (cur->eth.vlan_id) - len += snprintf(buf + len, BUF_SIZE - len, - "vlan-id = %d ", - be16_to_cpu(cur->eth.vlan_id)); - break; - - case MLX4_NET_TRANS_RULE_ID_IPV4: - if (cur->ipv4.src_ip) - len += snprintf(buf + len, BUF_SIZE - len, - "src-ip = %pI4 ", - &cur->ipv4.src_ip); - if (cur->ipv4.dst_ip) - len += snprintf(buf + len, BUF_SIZE - len, - "dst-ip = %pI4 ", - &cur->ipv4.dst_ip); - break; - - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - if (cur->tcp_udp.src_port) - len += snprintf(buf + len, BUF_SIZE - len, - "src-port = %d ", - be16_to_cpu(cur->tcp_udp.src_port)); - if (cur->tcp_udp.dst_port) - len += snprintf(buf + len, BUF_SIZE - len, - "dst-port = %d ", - be16_to_cpu(cur->tcp_udp.dst_port)); - break; - - case MLX4_NET_TRANS_RULE_ID_IB: - len += snprintf(buf + len, BUF_SIZE - len, - "dst-gid = "GID_PRINT_FMT"\n", - GID_PRINT_ARGS(cur->ib.dst_gid)); - len += snprintf(buf + len, BUF_SIZE - len, - "dst-gid-mask = "GID_PRINT_FMT"\n", - GID_PRINT_ARGS(cur->ib.dst_gid_msk)); - break; - - case MLX4_NET_TRANS_RULE_ID_IPV6: - break; - - default: - break; - } - } - len += snprintf(buf + len, BUF_SIZE - len, "\n"); - mlx4_err(dev, "%s", buf); - - if (len >= BUF_SIZE) - mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n"); -} - -int mlx4_flow_attach(struct mlx4_dev *dev, - struct mlx4_net_trans_rule *rule, u64 *reg_id) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_spec_list *cur; - u32 size = 0; - int ret; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl)); - trans_rule_ctrl_to_hw(rule, mailbox->buf); - - size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); - - list_for_each_entry(cur, &rule->list, list) { - ret = parse_trans_rule(dev, cur, mailbox->buf + size); - if (ret < 0) { - mlx4_free_cmd_mailbox(dev, mailbox); - return -EINVAL; - } - size += ret; - } - - ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id); - if (ret == -ENOMEM) - mlx4_err_rule(dev, - "mcg table is full. Fail to register network rule.\n", - rule); - else if (ret) - mlx4_err_rule(dev, "Fail to register network rule.\n", rule); - - mlx4_free_cmd_mailbox(dev, mailbox); - - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_flow_attach); - -int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id) -{ - int err; - - err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id); - if (err) - mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n", - (unsigned long long)reg_id); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_flow_detach); - -int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn) -{ - int err; - u64 in_param; - - in_param = ((u64) min_range_qpn) << 32; - in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF; - - err = mlx4_cmd(dev, in_param, 0, 0, - MLX4_FLOW_STEERING_IB_UC_QP_RANGE, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE); - -int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol prot, - enum mlx4_steer_type steer) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 members_count; - int index, prev; - int link = 0; - int i; - int err; - u8 port = gid[5]; - u8 new_entry = 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - mgm = mailbox->buf; - - mutex_lock(&priv->mcg_table.mutex); - err = find_entry(dev, port, gid, prot, - mailbox, &prev, &index); - if (err) - goto out; - - if (index != -1) { - if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { - new_entry = 1; - memcpy(mgm->gid, gid, 16); - } - } else { - link = 1; - - index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); - if (index == -1) { - mlx4_err(dev, "No AMGM entries left\n"); - err = -ENOMEM; - goto out; - } - index += dev->caps.num_mgms; - - new_entry = 1; - memset(mgm, 0, sizeof *mgm); - memcpy(mgm->gid, gid, 16); - } - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - if (members_count == dev->caps.num_qp_per_mgm) { - mlx4_err(dev, "MGM at index %x is full.\n", index); - err = -ENOMEM; - goto out; - } - - for (i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { - mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); - err = 0; - goto out; - } - - mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | - (!!mlx4_blck_lb << MGM_BLCK_LB_BIT)); - - mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); - - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - if (err) - goto out; - - /* if !link, still add the new entry. */ - if (!link) - goto skip_link; - - err = mlx4_READ_ENTRY(dev, prev, mailbox); - if (err) - goto out; - - mgm->next_gid_index = cpu_to_be32(index << 6); - - err = mlx4_WRITE_ENTRY(dev, prev, mailbox); - if (err) - goto out; - -skip_link: - if (prot == MLX4_PROT_ETH) { - /* manage the steering entry for promisc mode */ - if (new_entry) - new_steering_entry(dev, port, steer, index, qp->qpn); - else - existing_steering_entry(dev, port, steer, - index, qp->qpn); - } - -out: - if (err && link && index != -1) { - if (index < dev->caps.num_mgms) - mlx4_warn(dev, "Got AMGM index %d < %d", - index, dev->caps.num_mgms); - else - mlx4_bitmap_free(&priv->mcg_table.bitmap, - index - dev->caps.num_mgms, MLX4_USE_RR); - } - mutex_unlock(&priv->mcg_table.mutex); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, enum mlx4_steer_type steer) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mgm *mgm; - u32 members_count; - int prev, index; - int i, loc = -1; - int err; - u8 port = gid[5]; - bool removed_entry = false; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - mgm = mailbox->buf; - - mutex_lock(&priv->mcg_table.mutex); - - err = find_entry(dev, port, gid, prot, - mailbox, &prev, &index); - if (err) - goto out; - - if (index == -1) { - mlx4_err(dev, "MGID "GID_PRINT_FMT" not found\n", - GID_PRINT_ARGS(gid)); - err = -EINVAL; - goto out; - } - - /* - if this QP is also a promisc QP, it shouldn't be removed only if - at least one none promisc QP is also attached to this MCG - */ - if (prot == MLX4_PROT_ETH && - check_duplicate_entry(dev, port, steer, index, qp->qpn) && - !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL)) - goto out; - - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - for (i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { - loc = i; - break; - } - - if (loc == -1) { - mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); - err = -EINVAL; - goto out; - } - - /* copy the last QP in this MGM over removed QP */ - mgm->qp[loc] = mgm->qp[members_count - 1]; - mgm->qp[members_count - 1] = 0; - mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); - - if (prot == MLX4_PROT_ETH) - removed_entry = can_remove_steering_entry(dev, port, steer, - index, qp->qpn); - if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) { - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - goto out; - } - - /* We are going to delete the entry, members count should be 0 */ - mgm->members_count = cpu_to_be32((u32) prot << 30); - - if (prev == -1) { - /* Remove entry from MGM */ - int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; - if (amgm_index) { - err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); - if (err) - goto out; - } else - memset(mgm->gid, 0, 16); - - err = mlx4_WRITE_ENTRY(dev, index, mailbox); - if (err) - goto out; - - if (amgm_index) { - if (amgm_index < dev->caps.num_mgms) - mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", - index, amgm_index, dev->caps.num_mgms); - else - mlx4_bitmap_free(&priv->mcg_table.bitmap, - amgm_index - dev->caps.num_mgms, MLX4_USE_RR); - } - } else { - /* Remove entry from AMGM */ - int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; - err = mlx4_READ_ENTRY(dev, prev, mailbox); - if (err) - goto out; - - mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); - - err = mlx4_WRITE_ENTRY(dev, prev, mailbox); - if (err) - goto out; - - if (index < dev->caps.num_mgms) - mlx4_warn(dev, "entry %d had next AMGM index %d < %d", - prev, index, dev->caps.num_mgms); - else - mlx4_bitmap_free(&priv->mcg_table.bitmap, - index - dev->caps.num_mgms, MLX4_USE_RR); - } - -out: - mutex_unlock(&priv->mcg_table.mutex); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], u8 attach, u8 block_loopback, - enum mlx4_protocol prot) -{ - struct mlx4_cmd_mailbox *mailbox; - int err = 0; - int qpn; - - if (!mlx4_is_mfunc(dev)) - return -EBADF; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memcpy(mailbox->buf, gid, 16); - qpn = qp->qpn; - qpn |= (prot << 28); - if (attach && block_loopback) - qpn |= (1 << 31); - - err = mlx4_cmd(dev, mailbox->dma, qpn, attach, - MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], u8 port, - int block_mcast_loopback, - enum mlx4_protocol prot, u64 *reg_id) -{ - struct mlx4_spec_list spec = { {NULL} }; - __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); - - struct mlx4_net_trans_rule rule = { - .queue_mode = MLX4_NET_TRANS_Q_FIFO, - .exclusive = 0, - .promisc_mode = MLX4_FS_REGULAR, - .priority = MLX4_DOMAIN_NIC, - }; - - rule.allow_loopback = !block_mcast_loopback; - rule.port = port; - rule.qpn = qp->qpn; - INIT_LIST_HEAD(&rule.list); - - switch (prot) { - case MLX4_PROT_ETH: - spec.id = MLX4_NET_TRANS_RULE_ID_ETH; - memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN); - memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN); - break; - - case MLX4_PROT_IB_IPV6: - spec.id = MLX4_NET_TRANS_RULE_ID_IB; - memcpy(spec.ib.dst_gid, gid, 16); - memset(&spec.ib.dst_gid_msk, 0xff, 16); - break; - default: - return -EINVAL; - } - list_add_tail(&spec.list, &rule.list); - - return mlx4_flow_attach(dev, &rule, reg_id); -} - -int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - u8 port, int block_mcast_loopback, - enum mlx4_protocol prot, u64 *reg_id) -{ - enum mlx4_steer_type steer; - steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_A0: - if (prot == MLX4_PROT_ETH) - return 0; - - case MLX4_STEERING_MODE_B0: - if (prot == MLX4_PROT_ETH) - gid[7] |= (steer << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 1, - block_mcast_loopback, prot); - return mlx4_qp_attach_common(dev, qp, gid, - block_mcast_loopback, prot, - MLX4_MC_STEER); - - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_trans_to_dmfs_attach(dev, qp, gid, port, - block_mcast_loopback, - prot, reg_id); - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(mlx4_multicast_attach); - -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, u64 reg_id) -{ - enum mlx4_steer_type steer; - steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; - - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_A0: - if (prot == MLX4_PROT_ETH) - return 0; - - case MLX4_STEERING_MODE_B0: - if (prot == MLX4_PROT_ETH) - gid[7] |= (steer << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); - - return mlx4_qp_detach_common(dev, qp, gid, prot, - MLX4_MC_STEER); - - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_flow_detach(dev, reg_id); - - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(mlx4_multicast_detach); - -int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, - u32 qpn, enum mlx4_net_trans_promisc_mode mode) -{ - struct mlx4_net_trans_rule rule; - u64 *regid_p; - - switch (mode) { - case MLX4_FS_ALL_DEFAULT: - regid_p = &dev->regid_promisc_array[port]; - break; - case MLX4_FS_MC_DEFAULT: - regid_p = &dev->regid_allmulti_array[port]; - break; - default: - return -1; - } - - if (*regid_p != 0) - return -1; - - rule.promisc_mode = mode; - rule.port = port; - rule.qpn = qpn; - INIT_LIST_HEAD(&rule.list); - mlx4_err(dev, "going promisc on %x\n", port); - - return mlx4_flow_attach(dev, &rule, regid_p); -} -EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add); - -int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port, - enum mlx4_net_trans_promisc_mode mode) -{ - int ret; - u64 *regid_p; - - switch (mode) { - case MLX4_FS_ALL_DEFAULT: - regid_p = &dev->regid_promisc_array[port]; - break; - case MLX4_FS_MC_DEFAULT: - regid_p = &dev->regid_allmulti_array[port]; - break; - default: - return -1; - } - - if (*regid_p == 0) - return -1; - - ret = mlx4_flow_detach(dev, *regid_p); - if (ret == 0) - *regid_p = 0; - - return ret; -} -EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove); - -int mlx4_unicast_attach(struct mlx4_dev *dev, - struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol prot) -{ - if (prot == MLX4_PROT_ETH) - gid[7] |= (MLX4_UC_STEER << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 1, - block_mcast_loopback, prot); - - return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback, - prot, MLX4_UC_STEER); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_attach); - -int mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], enum mlx4_protocol prot) -{ - if (prot == MLX4_PROT_ETH) - gid[7] |= (MLX4_UC_STEER << 1); - - if (mlx4_is_mfunc(dev)) - return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); - - return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_detach); - -int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - u32 qpn = (u32) vhcr->in_param & 0xffffffff; - u8 port = vhcr->in_param >> 62; - enum mlx4_steer_type steer = vhcr->in_modifier; - - /* Promiscuous unicast is not allowed in mfunc for VFs */ - if ((slave != dev->caps.function) && (steer == MLX4_UC_STEER)) - return 0; - - if (vhcr->op_modifier) - return add_promisc_qp(dev, port, steer, qpn); - else - return remove_promisc_qp(dev, port, steer, qpn); -} - -static int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn, - enum mlx4_steer_type steer, u8 add, u8 port) -{ - return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add, - MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port); - - return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); - -int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port); - - return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); - -int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port); - - return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); - -int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) -{ - if (mlx4_is_mfunc(dev)) - return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port); - - return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn); -} -EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); - -int mlx4_init_mcg_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - - /* No need for mcg_table when fw managed the mcg table*/ - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) - return 0; - err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, - dev->caps.num_amgms - 1, 0, 0); - if (err) - return err; - - mutex_init(&priv->mcg_table.mutex); - - return 0; -} - -void mlx4_cleanup_mcg_table(struct mlx4_dev *dev) -{ - if (dev->caps.steering_mode != - MLX4_STEERING_MODE_DEVICE_MANAGED) - mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); -} diff --git a/sys/ofed/drivers/net/mlx4/mlx4.h b/sys/ofed/drivers/net/mlx4/mlx4.h deleted file mode 100644 index e23e461fd022..000000000000 --- a/sys/ofed/drivers/net/mlx4/mlx4.h +++ /dev/null @@ -1,1328 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2004 Voltaire, Inc. 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. - */ - -#ifndef MLX4_H -#define MLX4_H - -#include <linux/mutex.h> -#include <linux/radix-tree.h> -#include <linux/rbtree.h> -#include <linux/timer.h> -#include <linux/semaphore.h> -#include <linux/workqueue.h> -#include <linux/device.h> -#include <linux/mlx4/device.h> -#include <linux/mlx4/driver.h> -#include <linux/mlx4/doorbell.h> -#include <linux/mlx4/cmd.h> - -#define DRV_NAME "mlx4_core" -#define PFX DRV_NAME ": " -#define DRV_VERSION "2.1.6" -#define DRV_RELDATE __DATE__ - -#define DRV_STACK_NAME "Linux-MLNX_OFED" -#define DRV_STACK_VERSION "2.1" -#define DRV_NAME_FOR_FW DRV_STACK_NAME","DRV_STACK_VERSION - -#define MLX4_FS_UDP_UC_EN (1 << 1) -#define MLX4_FS_TCP_UC_EN (1 << 2) -#define MLX4_FS_NUM_OF_L2_ADDR 8 -#define MLX4_FS_MGM_LOG_ENTRY_SIZE 7 -#define MLX4_FS_NUM_MCG (1 << 17) - -struct mlx4_set_port_prio2tc_context { - u8 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]; -}; - -enum { - MLX4_HCR_BASE = 0x80680, - MLX4_HCR_SIZE = 0x0001c, - MLX4_CLR_INT_SIZE = 0x00008, - MLX4_SLAVE_COMM_BASE = 0x0, - MLX4_COMM_PAGESIZE = 0x1000, - MLX4_CLOCK_SIZE = 0x00008 -}; - -enum { - MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE = 10, - MLX4_MIN_MGM_LOG_ENTRY_SIZE = 7, - MLX4_MAX_MGM_LOG_ENTRY_SIZE = 12, - MLX4_MAX_QP_PER_MGM = 4 * ((1 << MLX4_MAX_MGM_LOG_ENTRY_SIZE)/16 - 2), -}; - -enum { - MLX4_NUM_PDS = 1 << 15 -}; - -enum { - MLX4_CMPT_TYPE_QP = 0, - MLX4_CMPT_TYPE_SRQ = 1, - MLX4_CMPT_TYPE_CQ = 2, - MLX4_CMPT_TYPE_EQ = 3, - MLX4_CMPT_NUM_TYPE -}; - -enum { - MLX4_CMPT_SHIFT = 24, - MLX4_NUM_CMPTS = MLX4_CMPT_NUM_TYPE << MLX4_CMPT_SHIFT -}; - -enum mlx4_mpt_state { - MLX4_MPT_DISABLED = 0, - MLX4_MPT_EN_HW, - MLX4_MPT_EN_SW -}; - -#define MLX4_COMM_TIME 10000 -enum { - MLX4_COMM_CMD_RESET, - MLX4_COMM_CMD_VHCR0, - MLX4_COMM_CMD_VHCR1, - MLX4_COMM_CMD_VHCR2, - MLX4_COMM_CMD_VHCR_EN, - MLX4_COMM_CMD_VHCR_POST, - MLX4_COMM_CMD_FLR = 254 -}; - -/*The flag indicates that the slave should delay the RESET cmd*/ -#define MLX4_DELAY_RESET_SLAVE 0xbbbbbbb -/*indicates how many retries will be done if we are in the middle of FLR*/ -#define NUM_OF_RESET_RETRIES 10 -#define SLEEP_TIME_IN_RESET (2 * 1000) -enum mlx4_resource { - RES_QP, - RES_CQ, - RES_SRQ, - RES_XRCD, - RES_MPT, - RES_MTT, - RES_MAC, - RES_VLAN, - RES_NPORT_ID, - RES_COUNTER, - RES_FS_RULE, - RES_EQ, - MLX4_NUM_OF_RESOURCE_TYPE -}; - -enum mlx4_alloc_mode { - RES_OP_RESERVE, - RES_OP_RESERVE_AND_MAP, - RES_OP_MAP_ICM, -}; - -enum mlx4_res_tracker_free_type { - RES_TR_FREE_ALL, - RES_TR_FREE_SLAVES_ONLY, - RES_TR_FREE_STRUCTS_ONLY, -}; - -/* - *Virtual HCR structures. - * mlx4_vhcr is the sw representation, in machine endianness - * - * mlx4_vhcr_cmd is the formalized structure, the one that is passed - * to FW to go through communication channel. - * It is big endian, and has the same structure as the physical HCR - * used by command interface - */ -struct mlx4_vhcr { - u64 in_param; - u64 out_param; - u32 in_modifier; - u32 errno; - u16 op; - u16 token; - u8 op_modifier; - u8 e_bit; -}; - -struct mlx4_vhcr_cmd { - __be64 in_param; - __be32 in_modifier; - u32 reserved1; - __be64 out_param; - __be16 token; - u16 reserved; - u8 status; - u8 flags; - __be16 opcode; -} __packed; - -struct mlx4_cmd_info { - u16 opcode; - bool has_inbox; - bool has_outbox; - bool out_is_imm; - bool encode_slave_id; - bool skip_err_print; - int (*verify)(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox); - int (*wrapper)(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -}; - -enum { - MLX4_DEBUG_MASK_CMD_TIME = 0x100, -}; - -#ifdef CONFIG_MLX4_DEBUG -extern int mlx4_debug_level; -#else /* CONFIG_MLX4_DEBUG */ -#define mlx4_debug_level (0) -#endif /* CONFIG_MLX4_DEBUG */ - -#define mlx4_dbg(mdev, format, arg...) \ -do { \ - if (mlx4_debug_level) \ - dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ##arg); \ -} while (0) - -#define mlx4_err(mdev, format, arg...) \ - dev_err(&mdev->pdev->dev, format, ##arg) -#define mlx4_info(mdev, format, arg...) \ - dev_info(&mdev->pdev->dev, format, ##arg) -#define mlx4_warn(mdev, format, arg...) \ - dev_warn(&mdev->pdev->dev, format, ##arg) - -extern int mlx4_log_num_mgm_entry_size; -extern int log_mtts_per_seg; -extern int mlx4_blck_lb; -extern int mlx4_set_4k_mtu; - -#define MLX4_MAX_NUM_SLAVES (MLX4_MAX_NUM_PF + MLX4_MAX_NUM_VF) -#define ALL_SLAVES 0xff - -struct mlx4_bitmap { - u32 last; - u32 top; - u32 max; - u32 reserved_top; - u32 mask; - u32 avail; - spinlock_t lock; - unsigned long *table; -}; - -struct mlx4_buddy { - unsigned long **bits; - unsigned int *num_free; - u32 max_order; - spinlock_t lock; -}; - -struct mlx4_icm; - -struct mlx4_icm_table { - u64 virt; - int num_icm; - u32 num_obj; - int obj_size; - int lowmem; - int coherent; - struct mutex mutex; - struct mlx4_icm **icm; -}; - -#define MLX4_MPT_FLAG_SW_OWNS (0xfUL << 28) -#define MLX4_MPT_FLAG_FREE (0x3UL << 28) -#define MLX4_MPT_FLAG_MIO (1 << 17) -#define MLX4_MPT_FLAG_BIND_ENABLE (1 << 15) -#define MLX4_MPT_FLAG_PHYSICAL (1 << 9) -#define MLX4_MPT_FLAG_REGION (1 << 8) - -#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 27) -#define MLX4_MPT_PD_FLAG_RAE (1 << 28) -#define MLX4_MPT_PD_FLAG_EN_INV (3 << 24) - -#define MLX4_MPT_QP_FLAG_BOUND_QP (1 << 7) - -#define MLX4_MPT_STATUS_SW 0xF0 -#define MLX4_MPT_STATUS_HW 0x00 - -/* - * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. - */ -struct mlx4_mpt_entry { - __be32 flags; - __be32 qpn; - __be32 key; - __be32 pd_flags; - __be64 start; - __be64 length; - __be32 lkey; - __be32 win_cnt; - u8 reserved1[3]; - u8 mtt_rep; - __be64 mtt_addr; - __be32 mtt_sz; - __be32 entity_size; - __be32 first_byte_offset; -} __packed; - -/* - * Must be packed because start is 64 bits but only aligned to 32 bits. - */ -struct mlx4_eq_context { - __be32 flags; - u16 reserved1[3]; - __be16 page_offset; - u8 log_eq_size; - u8 reserved2[4]; - u8 eq_period; - u8 reserved3; - u8 eq_max_count; - u8 reserved4[3]; - u8 intr; - u8 log_page_size; - u8 reserved5[2]; - u8 mtt_base_addr_h; - __be32 mtt_base_addr_l; - u32 reserved6[2]; - __be32 consumer_index; - __be32 producer_index; - u32 reserved7[4]; -}; - -struct mlx4_cq_context { - __be32 flags; - u16 reserved1[3]; - __be16 page_offset; - __be32 logsize_usrpage; - __be16 cq_period; - __be16 cq_max_count; - u8 reserved2[3]; - u8 comp_eqn; - u8 log_page_size; - u8 reserved3[2]; - u8 mtt_base_addr_h; - __be32 mtt_base_addr_l; - __be32 last_notified_index; - __be32 solicit_producer_index; - __be32 consumer_index; - __be32 producer_index; - u32 reserved4[2]; - __be64 db_rec_addr; -}; - -struct mlx4_srq_context { - __be32 state_logsize_srqn; - u8 logstride; - u8 reserved1; - __be16 xrcd; - __be32 pg_offset_cqn; - u32 reserved2; - u8 log_page_size; - u8 reserved3[2]; - u8 mtt_base_addr_h; - __be32 mtt_base_addr_l; - __be32 pd; - __be16 limit_watermark; - __be16 wqe_cnt; - u16 reserved4; - __be16 wqe_counter; - u32 reserved5; - __be64 db_rec_addr; -}; - -struct mlx4_eq { - struct mlx4_dev *dev; - void __iomem *doorbell; - int eqn; - u32 cons_index; - u16 irq; - u16 have_irq; - int nent; - struct mlx4_buf_list *page_list; - struct mlx4_mtt mtt; -}; - -struct mlx4_slave_eqe { - u8 type; - u8 port; - u32 param; -}; - -struct mlx4_slave_event_eq_info { - int eqn; - u16 token; -}; - -struct mlx4_profile { - int num_qp; - int rdmarc_per_qp; - int num_srq; - int num_cq; - int num_mcg; - int num_mpt; - unsigned num_mtt_segs; -}; - -struct mlx4_fw { - u64 clr_int_base; - u64 catas_offset; - u64 comm_base; - u64 clock_offset; - struct mlx4_icm *fw_icm; - struct mlx4_icm *aux_icm; - u32 catas_size; - u16 fw_pages; - u8 clr_int_bar; - u8 catas_bar; - u8 comm_bar; - u8 clock_bar; -}; - -struct mlx4_comm { - u32 slave_write; - u32 slave_read; -}; - -enum { - MLX4_MCAST_CONFIG = 0, - MLX4_MCAST_DISABLE = 1, - MLX4_MCAST_ENABLE = 2, -}; - -#define VLAN_FLTR_SIZE 128 - -struct mlx4_vlan_fltr { - __be32 entry[VLAN_FLTR_SIZE]; -}; - -struct mlx4_mcast_entry { - struct list_head list; - u64 addr; -}; - -struct mlx4_promisc_qp { - struct list_head list; - u32 qpn; -}; - -struct mlx4_steer_index { - struct list_head list; - unsigned int index; - struct list_head duplicates; -}; - -#define MLX4_EVENT_TYPES_NUM 64 - -struct mlx4_slave_state { - u8 comm_toggle; - u8 last_cmd; - u8 init_port_mask; - bool active; - bool old_vlan_api; - u8 function; - dma_addr_t vhcr_dma; - u16 mtu[MLX4_MAX_PORTS + 1]; - __be32 ib_cap_mask[MLX4_MAX_PORTS + 1]; - struct mlx4_slave_eqe eq[MLX4_MFUNC_MAX_EQES]; - struct list_head mcast_filters[MLX4_MAX_PORTS + 1]; - struct mlx4_vlan_fltr *vlan_filter[MLX4_MAX_PORTS + 1]; - /* event type to eq number lookup */ - struct mlx4_slave_event_eq_info event_eq[MLX4_EVENT_TYPES_NUM]; - u16 eq_pi; - u16 eq_ci; - spinlock_t lock; - /*initialized via the kzalloc*/ - u8 is_slave_going_down; - u32 cookie; - enum slave_port_state port_state[MLX4_MAX_PORTS + 1]; -}; - -#define MLX4_VGT 4095 -#define NO_INDX (-1) - - -struct mlx4_vport_state { - u64 mac; - u16 default_vlan; - u8 default_qos; - u32 tx_rate; - bool spoofchk; - u32 link_state; -}; - -struct mlx4_vf_admin_state { - struct mlx4_vport_state vport[MLX4_MAX_PORTS + 1]; -}; - -struct mlx4_vport_oper_state { - struct mlx4_vport_state state; - int mac_idx; - int vlan_idx; -}; -struct mlx4_vf_oper_state { - struct mlx4_vport_oper_state vport[MLX4_MAX_PORTS + 1]; -}; - -struct slave_list { - struct mutex mutex; - struct list_head res_list[MLX4_NUM_OF_RESOURCE_TYPE]; -}; - -struct resource_allocator { - spinlock_t alloc_lock; - union { - int res_reserved; - int res_port_rsvd[MLX4_MAX_PORTS]; - }; - union { - int res_free; - int res_port_free[MLX4_MAX_PORTS]; - }; - int *quota; - int *allocated; - int *guaranteed; -}; - -struct mlx4_resource_tracker { - spinlock_t lock; - /* tree for each resources */ - struct rb_root res_tree[MLX4_NUM_OF_RESOURCE_TYPE]; - /* num_of_slave's lists, one per slave */ - struct slave_list *slave_list; - struct resource_allocator res_alloc[MLX4_NUM_OF_RESOURCE_TYPE]; -}; - -#define SLAVE_EVENT_EQ_SIZE 128 -struct mlx4_slave_event_eq { - u32 eqn; - u32 cons; - u32 prod; - spinlock_t event_lock; - struct mlx4_eqe event_eqe[SLAVE_EVENT_EQ_SIZE]; -}; - -struct mlx4_master_qp0_state { - int proxy_qp0_active; - int qp0_active; - int port_active; -}; - -struct mlx4_mfunc_master_ctx { - struct mlx4_slave_state *slave_state; - struct mlx4_vf_admin_state *vf_admin; - struct mlx4_vf_oper_state *vf_oper; - struct mlx4_master_qp0_state qp0_state[MLX4_MAX_PORTS + 1]; - int init_port_ref[MLX4_MAX_PORTS + 1]; - u16 max_mtu[MLX4_MAX_PORTS + 1]; - int disable_mcast_ref[MLX4_MAX_PORTS + 1]; - struct mlx4_resource_tracker res_tracker; - struct workqueue_struct *comm_wq; - struct work_struct comm_work; - struct work_struct arm_comm_work; - struct work_struct slave_event_work; - struct work_struct slave_flr_event_work; - spinlock_t slave_state_lock; - __be32 comm_arm_bit_vector[4]; - struct mlx4_eqe cmd_eqe; - struct mlx4_slave_event_eq slave_eq; - struct mutex gen_eqe_mutex[MLX4_MFUNC_MAX]; -}; - -struct mlx4_mfunc { - struct mlx4_comm __iomem *comm; - struct mlx4_vhcr_cmd *vhcr; - dma_addr_t vhcr_dma; - - struct mlx4_mfunc_master_ctx master; -}; - -#define MGM_QPN_MASK 0x00FFFFFF -#define MGM_BLCK_LB_BIT 30 - -struct mlx4_mgm { - __be32 next_gid_index; - __be32 members_count; - u32 reserved[2]; - u8 gid[16]; - __be32 qp[MLX4_MAX_QP_PER_MGM]; -}; - -struct mlx4_cmd { - struct pci_pool *pool; - void __iomem *hcr; - struct mutex hcr_mutex; - struct mutex slave_cmd_mutex; - struct semaphore poll_sem; - struct semaphore event_sem; - int max_cmds; - spinlock_t context_lock; - int free_head; - struct mlx4_cmd_context *context; - u16 token_mask; - u8 use_events; - u8 toggle; - u8 comm_toggle; -}; - -enum { - MLX4_VF_IMMED_VLAN_FLAG_VLAN = 1 << 0, - MLX4_VF_IMMED_VLAN_FLAG_QOS = 1 << 1, -}; -struct mlx4_vf_immed_vlan_work { - struct work_struct work; - struct mlx4_priv *priv; - int flags; - int slave; - int vlan_ix; - int orig_vlan_ix; - u8 port; - u8 qos; - u16 vlan_id; - u16 orig_vlan_id; -}; - - -struct mlx4_uar_table { - struct mlx4_bitmap bitmap; -}; - -struct mlx4_mr_table { - struct mlx4_bitmap mpt_bitmap; - struct mlx4_buddy mtt_buddy; - u64 mtt_base; - u64 mpt_base; - struct mlx4_icm_table mtt_table; - struct mlx4_icm_table dmpt_table; -}; - -struct mlx4_cq_table { - struct mlx4_bitmap bitmap; - spinlock_t lock; - rwlock_t cq_table_lock; - struct radix_tree_root tree; - struct mlx4_icm_table table; - struct mlx4_icm_table cmpt_table; -}; - -struct mlx4_eq_table { - struct mlx4_bitmap bitmap; - char *irq_names; - void __iomem *clr_int; - void __iomem **uar_map; - u32 clr_mask; - struct mlx4_eq *eq; - struct mlx4_icm_table table; - struct mlx4_icm_table cmpt_table; - int have_irq; - u8 inta_pin; -}; - -struct mlx4_srq_table { - struct mlx4_bitmap bitmap; - spinlock_t lock; - struct radix_tree_root tree; - struct mlx4_icm_table table; - struct mlx4_icm_table cmpt_table; -}; - -struct mlx4_qp_table { - struct mlx4_bitmap bitmap; - u32 rdmarc_base; - int rdmarc_shift; - spinlock_t lock; - struct mlx4_icm_table qp_table; - struct mlx4_icm_table auxc_table; - struct mlx4_icm_table altc_table; - struct mlx4_icm_table rdmarc_table; - struct mlx4_icm_table cmpt_table; -}; - -struct mlx4_mcg_table { - struct mutex mutex; - struct mlx4_bitmap bitmap; - struct mlx4_icm_table table; -}; - -struct mlx4_catas_err { - u32 __iomem *map; - struct timer_list timer; - struct list_head list; -}; - -#define MLX4_MAX_MAC_NUM 128 -#define MLX4_MAC_TABLE_SIZE (MLX4_MAX_MAC_NUM << 3) - -struct mlx4_mac_table { - __be64 entries[MLX4_MAX_MAC_NUM]; - int refs[MLX4_MAX_MAC_NUM]; - struct mutex mutex; - int total; - int max; -}; - -#define MLX4_MAX_VLAN_NUM 128 -#define MLX4_VLAN_TABLE_SIZE (MLX4_MAX_VLAN_NUM << 2) - -struct mlx4_vlan_table { - __be32 entries[MLX4_MAX_VLAN_NUM]; - int refs[MLX4_MAX_VLAN_NUM]; - struct mutex mutex; - int total; - int max; -}; - -#define SET_PORT_GEN_ALL_VALID 0x7 -#define SET_PORT_PROMISC_SHIFT 31 -#define SET_PORT_MC_PROMISC_SHIFT 30 - -enum { - MCAST_DIRECT_ONLY = 0, - MCAST_DIRECT = 1, - MCAST_DEFAULT = 2 -}; - - -struct mlx4_set_port_general_context { - u8 reserved[3]; - u8 flags; - u16 reserved2; - __be16 mtu; - u8 pptx; - u8 pfctx; - u16 reserved3; - u8 pprx; - u8 pfcrx; - u16 reserved4; -}; - -struct mlx4_set_port_rqp_calc_context { - __be32 base_qpn; - u8 rererved; - u8 n_mac; - u8 n_vlan; - u8 n_prio; - u8 reserved2[3]; - u8 mac_miss; - u8 intra_no_vlan; - u8 no_vlan; - u8 intra_vlan_miss; - u8 vlan_miss; - u8 reserved3[3]; - u8 no_vlan_prio; - __be32 promisc; - __be32 mcast; -}; - -struct mlx4_hca_info { - struct mlx4_dev *dev; - struct device_attribute firmware_attr; - struct device_attribute hca_attr; - struct device_attribute board_attr; -}; - -struct mlx4_port_info { - struct mlx4_dev *dev; - int port; - char dev_name[16]; - struct device_attribute port_attr; - enum mlx4_port_type tmp_type; - char dev_mtu_name[16]; - struct device_attribute port_mtu_attr; - struct mlx4_mac_table mac_table; - struct mlx4_vlan_table vlan_table; - int base_qpn; -}; - -struct mlx4_sense { - struct mlx4_dev *dev; - u8 do_sense_port[MLX4_MAX_PORTS + 1]; - u8 sense_allowed[MLX4_MAX_PORTS + 1]; - struct delayed_work sense_poll; -}; - -struct mlx4_msix_ctl { - u64 pool_bm; - struct mutex pool_lock; -}; - -struct mlx4_steer { - struct list_head promisc_qps[MLX4_NUM_STEERS]; - struct list_head steer_entries[MLX4_NUM_STEERS]; -}; - -enum { - MLX4_PCI_DEV_IS_VF = 1 << 0, - MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1, -}; - -struct mlx4_roce_gid_entry { - u8 raw[16]; -}; - -struct counter_index { - struct list_head list; - u32 index; -}; - -struct mlx4_counters { - struct mlx4_bitmap bitmap; - struct list_head global_port_list[MLX4_MAX_PORTS]; - struct list_head vf_list[MLX4_MAX_NUM_VF][MLX4_MAX_PORTS]; - struct mutex mutex; -}; - -enum { - MLX4_NO_RR = 0, - MLX4_USE_RR = 1, -}; - -struct mlx4_priv { - struct mlx4_dev dev; - - struct list_head dev_list; - struct list_head ctx_list; - spinlock_t ctx_lock; - - int pci_dev_data; - - struct list_head pgdir_list; - struct mutex pgdir_mutex; - - struct mlx4_fw fw; - struct mlx4_cmd cmd; - struct mlx4_mfunc mfunc; - - struct mlx4_bitmap pd_bitmap; - struct mlx4_bitmap xrcd_bitmap; - struct mlx4_uar_table uar_table; - struct mlx4_mr_table mr_table; - struct mlx4_cq_table cq_table; - struct mlx4_eq_table eq_table; - struct mlx4_srq_table srq_table; - struct mlx4_qp_table qp_table; - struct mlx4_mcg_table mcg_table; - struct mlx4_counters counters_table; - - struct mlx4_catas_err catas_err; - - void __iomem *clr_base; - - struct mlx4_uar driver_uar; - void __iomem *kar; - struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; - struct mlx4_hca_info hca_info; - struct mlx4_sense sense; - struct mutex port_mutex; - struct mlx4_msix_ctl msix_ctl; - struct mlx4_steer *steer; - struct list_head bf_list; - struct mutex bf_mutex; - struct io_mapping *bf_mapping; - void __iomem *clock_mapping; - int reserved_mtts; - int fs_hash_mode; - u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; - __be64 slave_node_guids[MLX4_MFUNC_MAX]; - struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][128]; - atomic_t opreq_count; - struct work_struct opreq_task; -}; - -static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) -{ - return container_of(dev, struct mlx4_priv, dev); -} - -#define MLX4_SENSE_RANGE (HZ * 3) - -extern struct workqueue_struct *mlx4_wq; - -u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); -void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj, int use_rr); -u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, - int align, u32 skip_mask); -void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt, - int use_rr); -u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap); -int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, - u32 reserved_bot, u32 resetrved_top); -void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); - -int mlx4_reset(struct mlx4_dev *dev); - -int mlx4_alloc_eq_table(struct mlx4_dev *dev); -void mlx4_free_eq_table(struct mlx4_dev *dev); - -int mlx4_init_pd_table(struct mlx4_dev *dev); -int mlx4_init_xrcd_table(struct mlx4_dev *dev); -int mlx4_init_uar_table(struct mlx4_dev *dev); -int mlx4_init_mr_table(struct mlx4_dev *dev); -int mlx4_init_eq_table(struct mlx4_dev *dev); -int mlx4_init_cq_table(struct mlx4_dev *dev); -int mlx4_init_qp_table(struct mlx4_dev *dev); -int mlx4_init_srq_table(struct mlx4_dev *dev); -int mlx4_init_mcg_table(struct mlx4_dev *dev); - -void mlx4_cleanup_pd_table(struct mlx4_dev *dev); -void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev); -void mlx4_cleanup_uar_table(struct mlx4_dev *dev); -void mlx4_cleanup_mr_table(struct mlx4_dev *dev); -void mlx4_cleanup_eq_table(struct mlx4_dev *dev); -void mlx4_cleanup_cq_table(struct mlx4_dev *dev); -void mlx4_cleanup_qp_table(struct mlx4_dev *dev); -void mlx4_cleanup_srq_table(struct mlx4_dev *dev); -void mlx4_cleanup_mcg_table(struct mlx4_dev *dev); -int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn); -void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn); -int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn); -void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn); -int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn); -void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn); -int __mlx4_mpt_reserve(struct mlx4_dev *dev); -void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index); -int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index); -void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index); -u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order); -void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order); - -int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SYNC_TPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, - int *base, u8 flags); -void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt); -int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac); -void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac); -int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list); -int __mlx4_counter_alloc(struct mlx4_dev *dev, int slave, int port, u32 *idx); -void __mlx4_counter_free(struct mlx4_dev *dev, int slave, int port, u32 idx); - -int __mlx4_slave_counters_free(struct mlx4_dev *dev, int slave); -int __mlx4_clear_if_stat(struct mlx4_dev *dev, - u8 counter_index); -u8 mlx4_get_default_counter_index(struct mlx4_dev *dev, int slave, int port); - -int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn); -void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn); - -void mlx4_start_catas_poll(struct mlx4_dev *dev); -void mlx4_stop_catas_poll(struct mlx4_dev *dev); -void mlx4_catas_init(void); -int mlx4_restart_one(struct pci_dev *pdev); -int mlx4_register_device(struct mlx4_dev *dev); -void mlx4_unregister_device(struct mlx4_dev *dev); -void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, - unsigned long param); - -struct mlx4_dev_cap; -struct mlx4_init_hca_param; - -u64 mlx4_make_profile(struct mlx4_dev *dev, - struct mlx4_profile *request, - struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *init_hca); -void mlx4_master_comm_channel(struct work_struct *work); -void mlx4_master_arm_comm_channel(struct work_struct *work); -void mlx4_gen_slave_eqe(struct work_struct *work); -void mlx4_master_handle_slave_flr(struct work_struct *work); - -int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_COMM_INT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_2ERR_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_RTS2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); - -int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe); - -int mlx4_cmd_init(struct mlx4_dev *dev); -void mlx4_cmd_cleanup(struct mlx4_dev *dev); -int mlx4_multi_func_init(struct mlx4_dev *dev); -void mlx4_multi_func_cleanup(struct mlx4_dev *dev); -void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); -int mlx4_cmd_use_events(struct mlx4_dev *dev); -void mlx4_cmd_use_polling(struct mlx4_dev *dev); - -int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout); - -void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn); -void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type); - -void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type); - -void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); - -void mlx4_handle_catas_err(struct mlx4_dev *dev); - -int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, - enum mlx4_port_type *type); -void mlx4_do_sense_ports(struct mlx4_dev *dev, - enum mlx4_port_type *stype, - enum mlx4_port_type *defaults); -void mlx4_start_sense(struct mlx4_dev *dev); -void mlx4_stop_sense(struct mlx4_dev *dev); -void mlx4_sense_init(struct mlx4_dev *dev); -int mlx4_check_port_params(struct mlx4_dev *dev, - enum mlx4_port_type *port_type); -int mlx4_change_port_types(struct mlx4_dev *dev, - enum mlx4_port_type *port_types); - -void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table); -void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); -void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan); -int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); - -int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz); -/* resource tracker functions*/ -int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, - enum mlx4_resource resource_type, - u64 resource_id, int *slave); -void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave_id); -int mlx4_init_resource_tracker(struct mlx4_dev *dev); - -void mlx4_free_resource_tracker(struct mlx4_dev *dev, - enum mlx4_res_tracker_free_type type); - -int mlx4_QUERY_FW_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); - -int mlx4_get_slave_pkey_gid_tbl_len(struct mlx4_dev *dev, u8 port, - int *gid_tbl_len, int *pkey_tbl_len); - -int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); - -int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, enum mlx4_steer_type steer); -int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol prot, - enum mlx4_steer_type steer); -int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, - u8 gid[16], u8 port, - int block_mcast_loopback, - enum mlx4_protocol prot, u64 *reg_id); -int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode); -int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_common_set_vlan_fltr(struct mlx4_dev *dev, int function, - int port, void *buf); -int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_PKEY_TABLE_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); -int mlx4_MOD_STAT_CFG_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd); - -int mlx4_get_mgm_entry_size(struct mlx4_dev *dev); -int mlx4_get_qp_per_mgm(struct mlx4_dev *dev); - -static inline void set_param_l(u64 *arg, u32 val) -{ - *arg = (*arg & 0xffffffff00000000ULL) | (u64) val; -} - -static inline void set_param_h(u64 *arg, u32 val) -{ - *arg = (*arg & 0xffffffff) | ((u64) val << 32); -} - -static inline u32 get_param_l(u64 *arg) -{ - return (u32) (*arg & 0xffffffff); -} - -static inline u32 get_param_h(u64 *arg) -{ - return (u32)(*arg >> 32); -} - -static inline spinlock_t *mlx4_tlock(struct mlx4_dev *dev) -{ - return &mlx4_priv(dev)->mfunc.master.res_tracker.lock; -} - -#define NOT_MASKED_PD_BITS 17 - -void sys_tune_init(void); -void sys_tune_fini(void); - -void mlx4_init_quotas(struct mlx4_dev *dev); - -int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave); -int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave); -void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work); - -#endif /* MLX4_H */ diff --git a/sys/ofed/drivers/net/mlx4/mlx4_en.h b/sys/ofed/drivers/net/mlx4/mlx4_en.h deleted file mode 100644 index 17afa9e44022..000000000000 --- a/sys/ofed/drivers/net/mlx4/mlx4_en.h +++ /dev/null @@ -1,912 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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. - * - */ - -#ifndef _MLX4_EN_H_ -#define _MLX4_EN_H_ - -#include <linux/bitops.h> -#include <linux/compiler.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/kobject.h> -#include <linux/netdevice.h> -#include <linux/if_vlan.h> -#include <linux/if_ether.h> -#ifdef CONFIG_MLX4_EN_DCB -#include <linux/dcbnl.h> -#endif - -#include <linux/mlx4/device.h> -#include <linux/mlx4/qp.h> -#include <linux/mlx4/cq.h> -#include <linux/mlx4/srq.h> -#include <linux/mlx4/doorbell.h> -#include <linux/mlx4/cmd.h> - -#include <netinet/tcp_lro.h> - -#include "en_port.h" -#include "mlx4_stats.h" - -#define DRV_NAME "mlx4_en" - -#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) - -/* - * Device constants - */ - - -#define MLX4_EN_PAGE_SHIFT 12 -#define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) -#define MLX4_NET_IP_ALIGN 2 /* bytes */ -#define DEF_RX_RINGS 16 -#define MAX_RX_RINGS 128 -#define MIN_RX_RINGS 4 -#define TXBB_SIZE 64 -#define HEADROOM (2048 / TXBB_SIZE + 1) -#define STAMP_STRIDE 64 -#define STAMP_DWORDS (STAMP_STRIDE / 4) -#define STAMP_SHIFT 31 -#define STAMP_VAL 0x7fffffff -#define STATS_DELAY (HZ / 4) -#define SERVICE_TASK_DELAY (HZ / 4) -#define MAX_NUM_OF_FS_RULES 256 - -#define MLX4_EN_FILTER_HASH_SHIFT 4 -#define MLX4_EN_FILTER_EXPIRY_QUOTA 60 - -#ifdef CONFIG_NET_RX_BUSY_POLL -#define LL_EXTENDED_STATS -#endif - -/* vlan valid range */ -#define VLAN_MIN_VALUE 1 -#define VLAN_MAX_VALUE 4094 - -/* - * OS related constants and tunables - */ - -#define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ) - -#define MLX4_EN_ALLOC_SIZE PAGE_ALIGN(PAGE_SIZE) -#define MLX4_EN_ALLOC_ORDER get_order(MLX4_EN_ALLOC_SIZE) - -enum mlx4_en_alloc_type { - MLX4_EN_ALLOC_NEW = 0, - MLX4_EN_ALLOC_REPLACEMENT = 1, -}; - -/* Maximum ring sizes */ -#define MLX4_EN_DEF_TX_QUEUE_SIZE 4096 - -/* Minimum packet number till arming the CQ */ -#define MLX4_EN_MIN_RX_ARM 2048 -#define MLX4_EN_MIN_TX_ARM 2048 - -/* Maximum ring sizes */ -#define MLX4_EN_MAX_TX_SIZE 8192 -#define MLX4_EN_MAX_RX_SIZE 8192 - -/* Minimum ring sizes */ -#define MLX4_EN_MIN_RX_SIZE (4096 / TXBB_SIZE) -#define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) - -#define MLX4_EN_SMALL_PKT_SIZE 64 - -#define MLX4_EN_MAX_TX_RING_P_UP 32 -#define MLX4_EN_NUM_UP 1 - -#define MAX_TX_RINGS (MLX4_EN_MAX_TX_RING_P_UP * \ - MLX4_EN_NUM_UP) - -#define MLX4_EN_DEF_TX_RING_SIZE 1024 -#define MLX4_EN_DEF_RX_RING_SIZE 1024 - -/* Target number of bytes to coalesce with interrupt moderation */ -#define MLX4_EN_RX_COAL_TARGET 0x20000 -#define MLX4_EN_RX_COAL_TIME 0x10 - -#define MLX4_EN_TX_COAL_PKTS 64 -#define MLX4_EN_TX_COAL_TIME 64 - -#define MLX4_EN_RX_RATE_LOW 400000 -#define MLX4_EN_RX_COAL_TIME_LOW 0 -#define MLX4_EN_RX_RATE_HIGH 450000 -#define MLX4_EN_RX_COAL_TIME_HIGH 128 -#define MLX4_EN_RX_SIZE_THRESH 1024 -#define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH) -#define MLX4_EN_SAMPLE_INTERVAL 0 -#define MLX4_EN_AVG_PKT_SMALL 256 - -#define MLX4_EN_AUTO_CONF 0xffff - -#define MLX4_EN_DEF_RX_PAUSE 1 -#define MLX4_EN_DEF_TX_PAUSE 1 - -/* Interval between successive polls in the Tx routine when polling is used - instead of interrupts (in per-core Tx rings) - should be power of 2 */ -#define MLX4_EN_TX_POLL_MODER 16 -#define MLX4_EN_TX_POLL_TIMEOUT (HZ / 4) - -#define MLX4_EN_64_ALIGN (64 - NET_SKB_PAD) -#define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN) -#define HEADER_COPY_SIZE (128) -#define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETHER_HDR_LEN) - -#define MLX4_EN_MIN_MTU 46 -#define ETH_BCAST 0xffffffffffffULL - -#define MLX4_EN_LOOPBACK_RETRIES 5 -#define MLX4_EN_LOOPBACK_TIMEOUT 100 - -#ifdef MLX4_EN_PERF_STAT -/* Number of samples to 'average' */ -#define AVG_SIZE 128 -#define AVG_FACTOR 1024 - -#define INC_PERF_COUNTER(cnt) (++(cnt)) -#define ADD_PERF_COUNTER(cnt, add) ((cnt) += (add)) -#define AVG_PERF_COUNTER(cnt, sample) \ - ((cnt) = ((cnt) * (AVG_SIZE - 1) + (sample) * AVG_FACTOR) / AVG_SIZE) -#define GET_PERF_COUNTER(cnt) (cnt) -#define GET_AVG_PERF_COUNTER(cnt) ((cnt) / AVG_FACTOR) - -#else - -#define INC_PERF_COUNTER(cnt) do {} while (0) -#define ADD_PERF_COUNTER(cnt, add) do {} while (0) -#define AVG_PERF_COUNTER(cnt, sample) do {} while (0) -#define GET_PERF_COUNTER(cnt) (0) -#define GET_AVG_PERF_COUNTER(cnt) (0) -#endif /* MLX4_EN_PERF_STAT */ - -/* - * Configurables - */ - -enum cq_type { - RX = 0, - TX = 1, -}; - - -/* - * Useful macros - */ -#define ROUNDUP_LOG2(x) ilog2(roundup_pow_of_two(x)) -#define XNOR(x, y) (!(x) == !(y)) -#define ILLEGAL_MAC(addr) (addr == 0xffffffffffffULL || addr == 0x0) - -struct mlx4_en_tx_info { - bus_dmamap_t dma_map; - struct mbuf *mb; - u32 nr_txbb; - u32 nr_bytes; -}; - - -#define MLX4_EN_BIT_DESC_OWN 0x80000000 -#define CTRL_SIZE sizeof(struct mlx4_wqe_ctrl_seg) -#define MLX4_EN_MEMTYPE_PAD 0x100 -#define DS_SIZE sizeof(struct mlx4_wqe_data_seg) - - -struct mlx4_en_tx_desc { - struct mlx4_wqe_ctrl_seg ctrl; - union { - struct mlx4_wqe_data_seg data; /* at least one data segment */ - struct mlx4_wqe_lso_seg lso; - struct mlx4_wqe_inline_seg inl; - }; -}; - -#define MLX4_EN_USE_SRQ 0x01000000 - -#define MLX4_EN_RX_BUDGET 64 - -#define MLX4_EN_TX_MAX_DESC_SIZE 512 /* bytes */ -#define MLX4_EN_TX_MAX_MBUF_SIZE 65536 /* bytes */ -#define MLX4_EN_TX_MAX_PAYLOAD_SIZE 65536 /* bytes */ -#define MLX4_EN_TX_MAX_MBUF_FRAGS \ - ((MLX4_EN_TX_MAX_DESC_SIZE - 128) / DS_SIZE_ALIGNMENT) /* units */ -#define MLX4_EN_TX_WQE_MAX_WQEBBS \ - (MLX4_EN_TX_MAX_DESC_SIZE / TXBB_SIZE) /* units */ - -#define MLX4_EN_CX3_LOW_ID 0x1000 -#define MLX4_EN_CX3_HIGH_ID 0x1005 - -struct mlx4_en_tx_ring { - spinlock_t tx_lock; - bus_dma_tag_t dma_tag; - struct mlx4_hwq_resources wqres; - u32 size ; /* number of TXBBs */ - u32 size_mask; - u16 stride; - u16 cqn; /* index of port CQ associated with this ring */ - u32 prod; - u32 cons; - u32 buf_size; - u32 doorbell_qpn; - u8 *buf; - u16 poll_cnt; - int blocked; - struct mlx4_en_tx_info *tx_info; - u8 queue_index; - cpuset_t affinity_mask; - struct buf_ring *br; - u32 last_nr_txbb; - struct mlx4_qp qp; - struct mlx4_qp_context context; - int qpn; - enum mlx4_qp_state qp_state; - struct mlx4_srq dummy; - unsigned long bytes; - unsigned long packets; - unsigned long tx_csum; - unsigned long queue_stopped; - unsigned long oversized_packets; - unsigned long wake_queue; - struct mlx4_bf bf; - bool bf_enabled; - int hwtstamp_tx_type; - spinlock_t comp_lock; - int inline_thold; - u64 watchdog_time; -}; - -struct mlx4_en_rx_desc { - /* actual number of entries depends on rx ring stride */ - struct mlx4_wqe_data_seg data[0]; -}; - -struct mlx4_en_rx_mbuf { - bus_dmamap_t dma_map; - struct mbuf *mbuf; -}; - -struct mlx4_en_rx_spare { - bus_dmamap_t dma_map; - struct mbuf *mbuf; - u64 paddr_be; -}; - -struct mlx4_en_rx_ring { - struct mlx4_hwq_resources wqres; - bus_dma_tag_t dma_tag; - struct mlx4_en_rx_spare spare; - u32 size ; /* number of Rx descs*/ - u32 actual_size; - u32 size_mask; - u16 stride; - u16 log_stride; - u16 cqn; /* index of port CQ associated with this ring */ - u32 prod; - u32 cons; - u32 buf_size; - u8 fcs_del; - u32 rx_mb_size; - int qpn; - u8 *buf; - struct mlx4_en_rx_mbuf *mbuf; - unsigned long errors; - unsigned long bytes; - unsigned long packets; -#ifdef LL_EXTENDED_STATS - unsigned long yields; - unsigned long misses; - unsigned long cleaned; -#endif - unsigned long csum_ok; - unsigned long csum_none; - int hwtstamp_rx_filter; - int numa_node; - struct lro_ctrl lro; -}; - -static inline int mlx4_en_can_lro(__be16 status) -{ - const __be16 status_all = cpu_to_be16( - MLX4_CQE_STATUS_IPV4 | - MLX4_CQE_STATUS_IPV4F | - MLX4_CQE_STATUS_IPV6 | - MLX4_CQE_STATUS_IPV4OPT | - MLX4_CQE_STATUS_TCP | - MLX4_CQE_STATUS_UDP | - MLX4_CQE_STATUS_IPOK); - const __be16 status_ipv4_ipok_tcp = cpu_to_be16( - MLX4_CQE_STATUS_IPV4 | - MLX4_CQE_STATUS_IPOK | - MLX4_CQE_STATUS_TCP); - const __be16 status_ipv6_ipok_tcp = cpu_to_be16( - MLX4_CQE_STATUS_IPV6 | - MLX4_CQE_STATUS_IPOK | - MLX4_CQE_STATUS_TCP); - - status &= status_all; - return (status == status_ipv4_ipok_tcp || - status == status_ipv6_ipok_tcp); -} - -struct mlx4_en_cq { - struct mlx4_cq mcq; - struct mlx4_hwq_resources wqres; - int ring; - spinlock_t lock; - struct net_device *dev; - /* Per-core Tx cq processing support */ - struct timer_list timer; - int size; - int buf_size; - unsigned vector; - enum cq_type is_tx; - u16 moder_time; - u16 moder_cnt; - struct mlx4_cqe *buf; - struct task cq_task; - struct taskqueue *tq; -#define MLX4_EN_OPCODE_ERROR 0x1e - u32 tot_rx; - u32 tot_tx; - u32 curr_poll_rx_cpu_id; - -#ifdef CONFIG_NET_RX_BUSY_POLL - unsigned int state; -#define MLX4_EN_CQ_STATEIDLE 0 -#define MLX4_EN_CQ_STATENAPI 1 /* NAPI owns this CQ */ -#define MLX4_EN_CQ_STATEPOLL 2 /* poll owns this CQ */ -#define MLX4_CQ_LOCKED (MLX4_EN_CQ_STATENAPI | MLX4_EN_CQ_STATEPOLL) -#define MLX4_EN_CQ_STATENAPI_YIELD 4 /* NAPI yielded this CQ */ -#define MLX4_EN_CQ_STATEPOLL_YIELD 8 /* poll yielded this CQ */ -#define CQ_YIELD (MLX4_EN_CQ_STATENAPI_YIELD | MLX4_EN_CQ_STATEPOLL_YIELD) -#define CQ_USER_PEND (MLX4_EN_CQ_STATEPOLL | MLX4_EN_CQ_STATEPOLL_YIELD) - spinlock_t poll_lock; /* protects from LLS/napi conflicts */ -#endif /* CONFIG_NET_RX_BUSY_POLL */ -}; - -struct mlx4_en_port_profile { - u32 flags; - u32 tx_ring_num; - u32 rx_ring_num; - u32 tx_ring_size; - u32 rx_ring_size; - u8 rx_pause; - u8 rx_ppp; - u8 tx_pause; - u8 tx_ppp; - int rss_rings; -}; - -struct mlx4_en_profile { - int rss_xor; - int udp_rss; - u8 rss_mask; - u32 active_ports; - u32 small_pkt_int; - u8 no_reset; - u8 num_tx_rings_p_up; - struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1]; -}; - -struct mlx4_en_dev { - struct mlx4_dev *dev; - struct pci_dev *pdev; - struct mutex state_lock; - struct net_device *pndev[MLX4_MAX_PORTS + 1]; - u32 port_cnt; - bool device_up; - struct mlx4_en_profile profile; - u32 LSO_support; - struct workqueue_struct *workqueue; - struct device *dma_device; - void __iomem *uar_map; - struct mlx4_uar priv_uar; - struct mlx4_mr mr; - u32 priv_pdn; - spinlock_t uar_lock; - u8 mac_removed[MLX4_MAX_PORTS + 1]; - unsigned long last_overflow_check; - unsigned long overflow_period; -}; - - -struct mlx4_en_rss_map { - int base_qpn; - struct mlx4_qp qps[MAX_RX_RINGS]; - enum mlx4_qp_state state[MAX_RX_RINGS]; - struct mlx4_qp indir_qp; - enum mlx4_qp_state indir_state; -}; - -struct mlx4_en_port_state { - int link_state; - int link_speed; - int transciver; - int autoneg; -}; - -enum mlx4_en_mclist_act { - MCLIST_NONE, - MCLIST_REM, - MCLIST_ADD, -}; - -struct mlx4_en_mc_list { - struct list_head list; - enum mlx4_en_mclist_act action; - u8 addr[ETH_ALEN]; - u64 reg_id; -}; - -#ifdef CONFIG_MLX4_EN_DCB -/* Minimal TC BW - setting to 0 will block traffic */ -#define MLX4_EN_BW_MIN 1 -#define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */ - -#define MLX4_EN_TC_ETS 7 - -#endif - - -enum { - MLX4_EN_FLAG_PROMISC = (1 << 0), - MLX4_EN_FLAG_MC_PROMISC = (1 << 1), - /* whether we need to enable hardware loopback by putting dmac - * in Tx WQE - */ - MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2), - /* whether we need to drop packets that hardware loopback-ed */ - MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3), - MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4), -#ifdef CONFIG_MLX4_EN_DCB - MLX4_EN_FLAG_DCB_ENABLED = (1 << 5) -#endif -}; - -#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE) -#define MLX4_EN_MAC_HASH_IDX 5 - -struct en_port { - struct kobject kobj; - struct mlx4_dev *dev; - u8 port_num; - u8 vport_num; -}; - -struct mlx4_en_priv { - struct mlx4_en_dev *mdev; - struct mlx4_en_port_profile *prof; - struct net_device *dev; - unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct mlx4_en_port_state port_state; - spinlock_t stats_lock; - /* To allow rules removal while port is going down */ - struct list_head ethtool_list; - - unsigned long last_moder_packets[MAX_RX_RINGS]; - unsigned long last_moder_tx_packets; - unsigned long last_moder_bytes[MAX_RX_RINGS]; - unsigned long last_moder_jiffies; - int last_moder_time[MAX_RX_RINGS]; - u16 rx_usecs; - u16 rx_frames; - u16 tx_usecs; - u16 tx_frames; - u32 pkt_rate_low; - u32 rx_usecs_low; - u32 pkt_rate_high; - u32 rx_usecs_high; - u32 sample_interval; - u32 adaptive_rx_coal; - u32 msg_enable; - u32 loopback_ok; - u32 validate_loopback; - - struct mlx4_hwq_resources res; - int link_state; - int last_link_state; - bool port_up; - int port; - int registered; - int allocated; - int stride; - unsigned char current_mac[ETH_ALEN + 2]; - u64 mac; - int mac_index; - unsigned max_mtu; - int base_qpn; - int cqe_factor; - - struct mlx4_en_rss_map rss_map; - u32 flags; - u8 num_tx_rings_p_up; - u32 tx_ring_num; - u32 rx_ring_num; - u32 rx_mb_size; - - struct mlx4_en_tx_ring **tx_ring; - struct mlx4_en_rx_ring *rx_ring[MAX_RX_RINGS]; - struct mlx4_en_cq **tx_cq; - struct mlx4_en_cq *rx_cq[MAX_RX_RINGS]; - struct mlx4_qp drop_qp; - struct work_struct rx_mode_task; - struct work_struct watchdog_task; - struct work_struct linkstate_task; - struct delayed_work stats_task; - struct delayed_work service_task; - struct mlx4_en_perf_stats pstats; - struct mlx4_en_pkt_stats pkstats; - struct mlx4_en_pkt_stats pkstats_last; - struct mlx4_en_flow_stats flowstats[MLX4_NUM_PRIORITIES]; - struct mlx4_en_port_stats port_stats; - struct mlx4_en_vport_stats vport_stats; - struct mlx4_en_vf_stats vf_stats; - DECLARE_BITMAP(stats_bitmap, NUM_ALL_STATS); - struct list_head mc_list; - struct list_head curr_list; - u64 broadcast_id; - struct mlx4_en_stat_out_mbox hw_stats; - int vids[128]; - bool wol; - struct device *ddev; - struct dentry *dev_root; - u32 counter_index; - eventhandler_tag vlan_attach; - eventhandler_tag vlan_detach; - struct callout watchdog_timer; - struct ifmedia media; - volatile int blocked; - struct sysctl_oid *sysctl; - struct sysctl_ctx_list conf_ctx; - struct sysctl_ctx_list stat_ctx; -#define MLX4_EN_MAC_HASH_IDX 5 - struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE]; - -#ifdef CONFIG_MLX4_EN_DCB - struct ieee_ets ets; - u16 maxrate[IEEE_8021QAZ_MAX_TCS]; - u8 dcbx_cap; -#endif -#ifdef CONFIG_RFS_ACCEL - spinlock_t filters_lock; - int last_filter_id; - struct list_head filters; - struct hlist_head filter_hash[1 << MLX4_EN_FILTER_HASH_SHIFT]; -#endif - struct en_port *vf_ports[MLX4_MAX_NUM_VF]; - unsigned long last_ifq_jiffies; - u64 if_counters_rx_errors; - u64 if_counters_rx_no_buffer; -}; - -enum mlx4_en_wol { - MLX4_EN_WOL_MAGIC = (1ULL << 61), - MLX4_EN_WOL_ENABLED = (1ULL << 62), -}; - -struct mlx4_mac_entry { - struct hlist_node hlist; - unsigned char mac[ETH_ALEN + 2]; - u64 reg_id; -}; - -#ifdef CONFIG_NET_RX_BUSY_POLL -static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq) -{ - spin_lock_init(&cq->poll_lock); - cq->state = MLX4_EN_CQ_STATEIDLE; -} - -/* called from the device poll rutine to get ownership of a cq */ -static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq) -{ - int rc = true; - spin_lock(&cq->poll_lock); - if (cq->state & MLX4_CQ_LOCKED) { - WARN_ON(cq->state & MLX4_EN_CQ_STATENAPI); - cq->state |= MLX4_EN_CQ_STATENAPI_YIELD; - rc = false; - } else - /* we don't care if someone yielded */ - cq->state = MLX4_EN_CQ_STATENAPI; - spin_unlock(&cq->poll_lock); - return rc; -} - -/* returns true is someone tried to get the cq while napi had it */ -static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq) -{ - int rc = false; - spin_lock(&cq->poll_lock); - WARN_ON(cq->state & (MLX4_EN_CQ_STATEPOLL | - MLX4_EN_CQ_STATENAPI_YIELD)); - - if (cq->state & MLX4_EN_CQ_STATEPOLL_YIELD) - rc = true; - cq->state = MLX4_EN_CQ_STATEIDLE; - spin_unlock(&cq->poll_lock); - return rc; -} - -/* called from mlx4_en_low_latency_poll() */ -static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq) -{ - int rc = true; - spin_lock_bh(&cq->poll_lock); - if ((cq->state & MLX4_CQ_LOCKED)) { - struct net_device *dev = cq->dev; - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring]; - - cq->state |= MLX4_EN_CQ_STATEPOLL_YIELD; - rc = false; -#ifdef LL_EXTENDED_STATS - rx_ring->yields++; -#endif - } else - /* preserve yield marks */ - cq->state |= MLX4_EN_CQ_STATEPOLL; - spin_unlock_bh(&cq->poll_lock); - return rc; -} - -/* returns true if someone tried to get the cq while it was locked */ -static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq) -{ - int rc = false; - spin_lock_bh(&cq->poll_lock); - WARN_ON(cq->state & (MLX4_EN_CQ_STATENAPI)); - - if (cq->state & MLX4_EN_CQ_STATEPOLL_YIELD) - rc = true; - cq->state = MLX4_EN_CQ_STATEIDLE; - spin_unlock_bh(&cq->poll_lock); - return rc; -} - -/* true if a socket is polling, even if it did not get the lock */ -static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) -{ - WARN_ON(!(cq->state & MLX4_CQ_LOCKED)); - return cq->state & CQ_USER_PEND; -} -#else -static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq) -{ -} - -static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq) -{ - return true; -} - -static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq) -{ - return false; -} - -static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq) -{ - return false; -} - -static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq) -{ - return false; -} - -static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) -{ - return false; -} -#endif /* CONFIG_NET_RX_BUSY_POLL */ - -#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) - -void mlx4_en_destroy_netdev(struct net_device *dev); -int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, - struct mlx4_en_port_profile *prof); - -int mlx4_en_start_port(struct net_device *dev); -void mlx4_en_stop_port(struct net_device *dev); - -void mlx4_en_free_resources(struct mlx4_en_priv *priv); -int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); - -int mlx4_en_pre_config(struct mlx4_en_priv *priv); -int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq, - int entries, int ring, enum cq_type mode, int node); -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq); -int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, - int cq_idx); -void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); -int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); -int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); - -void mlx4_en_tx_irq(struct mlx4_cq *mcq); -u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb); - -int mlx4_en_transmit(struct ifnet *dev, struct mbuf *m); -int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring, - u32 size, u16 stride, int node, int queue_idx); -void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring **pring); -int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, - int cq, int user_prio); -void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring); -void mlx4_en_qflush(struct ifnet *dev); - -int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, int node); -void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring **pring, - u32 size, u16 stride); -void mlx4_en_tx_que(void *context, int pending); -void mlx4_en_rx_que(void *context, int pending); -int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv); -void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring); -int mlx4_en_process_rx_cq(struct net_device *dev, - struct mlx4_en_cq *cq, - int budget); -void mlx4_en_poll_tx_cq(unsigned long data); -void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, int user_prio, - struct mlx4_qp_context *context); -void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event); -int mlx4_en_map_buffer(struct mlx4_buf *buf); -void mlx4_en_unmap_buffer(struct mlx4_buf *buf); -void mlx4_en_calc_rx_buf(struct net_device *dev); - -int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); -void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); -int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv); -void mlx4_en_destroy_drop_qp(struct mlx4_en_priv *priv); -int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); -void mlx4_en_rx_irq(struct mlx4_cq *mcq); - -int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode); -int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv); - -int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); -int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port); -int mlx4_en_get_vport_stats(struct mlx4_en_dev *mdev, u8 port); -void mlx4_en_create_debug_files(struct mlx4_en_priv *priv); -void mlx4_en_delete_debug_files(struct mlx4_en_priv *priv); -int mlx4_en_register_debugfs(void); -void mlx4_en_unregister_debugfs(void); - -#ifdef CONFIG_MLX4_EN_DCB -extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops; -extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_pfc_ops; -#endif - -int mlx4_en_setup_tc(struct net_device *dev, u8 up); - -#ifdef CONFIG_RFS_ACCEL -void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *rx_ring); -#endif - -#define MLX4_EN_NUM_SELF_TEST 5 -void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); -void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev); - -/* - * Functions for time stamping - */ -#define SKBTX_HW_TSTAMP (1 << 0) -#define SKBTX_IN_PROGRESS (1 << 2) - -u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe); - -/* Functions for caching and restoring statistics */ -int mlx4_en_get_sset_count(struct net_device *dev, int sset); -void mlx4_en_restore_ethtool_stats(struct mlx4_en_priv *priv, - u64 *data); - -/* - * Globals - */ -extern const struct ethtool_ops mlx4_en_ethtool_ops; - -/* - * Defines for link speed - needed by selftest - */ -#define MLX4_EN_LINK_SPEED_1G 1000 -#define MLX4_EN_LINK_SPEED_10G 10000 -#define MLX4_EN_LINK_SPEED_40G 40000 - -enum { - NETIF_MSG_DRV = 0x0001, - NETIF_MSG_PROBE = 0x0002, - NETIF_MSG_LINK = 0x0004, - NETIF_MSG_TIMER = 0x0008, - NETIF_MSG_IFDOWN = 0x0010, - NETIF_MSG_IFUP = 0x0020, - NETIF_MSG_RX_ERR = 0x0040, - NETIF_MSG_TX_ERR = 0x0080, - NETIF_MSG_TX_QUEUED = 0x0100, - NETIF_MSG_INTR = 0x0200, - NETIF_MSG_TX_DONE = 0x0400, - NETIF_MSG_RX_STATUS = 0x0800, - NETIF_MSG_PKTDATA = 0x1000, - NETIF_MSG_HW = 0x2000, - NETIF_MSG_WOL = 0x4000, -}; - - -/* - * printk / logging functions - */ - -#define en_print(level, priv, format, arg...) \ - { \ - if ((priv)->registered) \ - printk(level "%s: %s: " format, DRV_NAME, \ - (priv->dev)->if_xname, ## arg); \ - else \ - printk(level "%s: %s: Port %d: " format, \ - DRV_NAME, dev_name(&priv->mdev->pdev->dev), \ - (priv)->port, ## arg); \ - } - - -#define en_dbg(mlevel, priv, format, arg...) \ -do { \ - if (NETIF_MSG_##mlevel & priv->msg_enable) \ - en_print(KERN_DEBUG, priv, format, ##arg); \ -} while (0) -#define en_warn(priv, format, arg...) \ - en_print(KERN_WARNING, priv, format, ##arg) -#define en_err(priv, format, arg...) \ - en_print(KERN_ERR, priv, format, ##arg) -#define en_info(priv, format, arg...) \ - en_print(KERN_INFO, priv, format, ## arg) - -#define mlx4_err(mdev, format, arg...) \ - pr_err("%s %s: " format, DRV_NAME, \ - dev_name(&mdev->pdev->dev), ##arg) -#define mlx4_info(mdev, format, arg...) \ - pr_info("%s %s: " format, DRV_NAME, \ - dev_name(&mdev->pdev->dev), ##arg) -#define mlx4_warn(mdev, format, arg...) \ - pr_warning("%s %s: " format, DRV_NAME, \ - dev_name(&mdev->pdev->dev), ##arg) - -#endif diff --git a/sys/ofed/drivers/net/mlx4/mlx4_stats.h b/sys/ofed/drivers/net/mlx4/mlx4_stats.h deleted file mode 100644 index ef0b1c0a679b..000000000000 --- a/sys/ofed/drivers/net/mlx4/mlx4_stats.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2014 Mellanox Technologies Ltd. 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. - */ - -#ifndef _MLX4_STATS_ -#define _MLX4_STATS_ - - -#ifdef MLX4_EN_PERF_STAT -#define NUM_PERF_STATS NUM_PERF_COUNTERS -#else -#define NUM_PERF_STATS 0 -#endif - -#define NUM_PRIORITIES 9 -#define NUM_PRIORITY_STATS 2 - -struct mlx4_en_pkt_stats { - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long rx_multicast_packets; - unsigned long rx_broadcast_packets; - unsigned long rx_errors; - unsigned long rx_dropped; - unsigned long rx_length_errors; - unsigned long rx_over_errors; - unsigned long rx_crc_errors; - unsigned long rx_jabbers; - unsigned long rx_in_range_length_error; - unsigned long rx_out_range_length_error; - unsigned long rx_lt_64_bytes_packets; - unsigned long rx_127_bytes_packets; - unsigned long rx_255_bytes_packets; - unsigned long rx_511_bytes_packets; - unsigned long rx_1023_bytes_packets; - unsigned long rx_1518_bytes_packets; - unsigned long rx_1522_bytes_packets; - unsigned long rx_1548_bytes_packets; - unsigned long rx_gt_1548_bytes_packets; - unsigned long tx_packets; - unsigned long tx_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_broadcast_packets; - unsigned long tx_errors; - unsigned long tx_dropped; - unsigned long tx_lt_64_bytes_packets; - unsigned long tx_127_bytes_packets; - unsigned long tx_255_bytes_packets; - unsigned long tx_511_bytes_packets; - unsigned long tx_1023_bytes_packets; - unsigned long tx_1518_bytes_packets; - unsigned long tx_1522_bytes_packets; - unsigned long tx_1548_bytes_packets; - unsigned long tx_gt_1548_bytes_packets; - unsigned long rx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; - unsigned long tx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; -#define NUM_PKT_STATS 72 -}; - -struct mlx4_en_vf_stats { - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long rx_multicast_packets; - unsigned long rx_broadcast_packets; - unsigned long rx_errors; - unsigned long rx_dropped; - unsigned long tx_packets; - unsigned long tx_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_broadcast_packets; - unsigned long tx_errors; -#define NUM_VF_STATS 11 -}; - -struct mlx4_en_vport_stats { - unsigned long rx_unicast_packets; - unsigned long rx_unicast_bytes; - unsigned long rx_multicast_packets; - unsigned long rx_multicast_bytes; - unsigned long rx_broadcast_packets; - unsigned long rx_broadcast_bytes; - unsigned long rx_dropped; - unsigned long rx_errors; - unsigned long tx_unicast_packets; - unsigned long tx_unicast_bytes; - unsigned long tx_multicast_packets; - unsigned long tx_multicast_bytes; - unsigned long tx_broadcast_packets; - unsigned long tx_broadcast_bytes; - unsigned long tx_errors; -#define NUM_VPORT_STATS 15 -}; - -struct mlx4_en_port_stats { - unsigned long tso_packets; - unsigned long queue_stopped; - unsigned long wake_queue; - unsigned long tx_timeout; - unsigned long oversized_packets; - unsigned long rx_alloc_failed; - unsigned long rx_chksum_good; - unsigned long rx_chksum_none; - unsigned long tx_chksum_offload; -#define NUM_PORT_STATS 8 -}; - -struct mlx4_en_perf_stats { - u32 tx_poll; - u64 tx_pktsz_avg; - u32 inflight_avg; - u16 tx_coal_avg; - u16 rx_coal_avg; - u32 napi_quota; -#define NUM_PERF_COUNTERS 6 -}; - -struct mlx4_en_flow_stats { - u64 rx_pause; - u64 rx_pause_duration; - u64 rx_pause_transition; - u64 tx_pause; - u64 tx_pause_duration; - u64 tx_pause_transition; -}; -#define MLX4_NUM_PRIORITIES 8 -#define NUM_FLOW_PRIORITY_STATS 6 -#define NUM_FLOW_STATS (NUM_FLOW_PRIORITY_STATS*MLX4_NUM_PRIORITIES) - - -struct mlx4_en_stat_out_flow_control_mbox { - /* Total number of PAUSE frames received from the far-end port */ - __be64 rx_pause; - /* Total number of microseconds that far-end port requested to pause - * transmission of packets - */ - __be64 rx_pause_duration; - /* Number of received transmission from XOFF state to XON state */ - __be64 rx_pause_transition; - /* Total number of PAUSE frames sent from the far-end port */ - __be64 tx_pause; - /* Total time in microseconds that transmission of packets has been - * paused - */ - __be64 tx_pause_duration; - /* Number of transmitter transitions from XOFF state to XON state */ - __be64 tx_pause_transition; - /* Reserverd */ - __be64 reserved[2]; -}; - -int mlx4_get_vport_ethtool_stats(struct mlx4_dev *dev, int port, - struct mlx4_en_vport_stats *vport_stats, - int reset); - -#define NUM_ALL_STATS (NUM_PKT_STATS + NUM_FLOW_STATS + NUM_VPORT_STATS + \ - NUM_VF_STATS + NUM_PORT_STATS + NUM_PERF_STATS) -#endif diff --git a/sys/ofed/drivers/net/mlx4/mr.c b/sys/ofed/drivers/net/mlx4/mr.c deleted file mode 100644 index 876d16dba1a3..000000000000 --- a/sys/ofed/drivers/net/mlx4/mr.c +++ /dev/null @@ -1,996 +0,0 @@ -/* - * Copyright (c) 2004 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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/err.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/vmalloc.h> - -#include <linux/mlx4/cmd.h> - -#include <linux/math64.h> - -#include "mlx4.h" -#include "icm.h" - -static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order) -{ - int o; - int m; - u32 seg; - - spin_lock(&buddy->lock); - - for (o = order; o <= buddy->max_order; ++o) - if (buddy->num_free[o]) { - m = 1 << (buddy->max_order - o); - seg = find_first_bit(buddy->bits[o], m); - if (seg < m) - goto found; - } - - spin_unlock(&buddy->lock); - return -1; - - found: - clear_bit(seg, buddy->bits[o]); - --buddy->num_free[o]; - - while (o > order) { - --o; - seg <<= 1; - set_bit(seg ^ 1, buddy->bits[o]); - ++buddy->num_free[o]; - } - - spin_unlock(&buddy->lock); - - seg <<= order; - - return seg; -} - -static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order) -{ - seg >>= order; - - spin_lock(&buddy->lock); - - while (test_bit(seg ^ 1, buddy->bits[order])) { - clear_bit(seg ^ 1, buddy->bits[order]); - --buddy->num_free[order]; - seg >>= 1; - ++order; - } - - set_bit(seg, buddy->bits[order]); - ++buddy->num_free[order]; - - spin_unlock(&buddy->lock); -} - -static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order) -{ - int i, s; - - buddy->max_order = max_order; - spin_lock_init(&buddy->lock); - - buddy->bits = kcalloc(buddy->max_order + 1, sizeof (long *), - GFP_KERNEL); - buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free, - GFP_KERNEL); - if (!buddy->bits || !buddy->num_free) - goto err_out; - - for (i = 0; i <= buddy->max_order; ++i) { - s = BITS_TO_LONGS(1 << (buddy->max_order - i)); - buddy->bits[i] = kcalloc(s, sizeof (long), GFP_KERNEL | __GFP_NOWARN); - if (!buddy->bits[i]) - goto err_out_free; - } - - set_bit(0, buddy->bits[buddy->max_order]); - buddy->num_free[buddy->max_order] = 1; - - return 0; - -err_out_free: - for (i = 0; i <= buddy->max_order; ++i) - kfree(buddy->bits[i]); - -err_out: - kfree(buddy->bits); - kfree(buddy->num_free); - - return -ENOMEM; -} - -static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy) -{ - int i; - - for (i = 0; i <= buddy->max_order; ++i) - kfree(buddy->bits[i]); - - kfree(buddy->bits); - kfree(buddy->num_free); -} - -u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) -{ - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - u32 seg; - int seg_order; - u32 offset; - - seg_order = max_t(int, order - log_mtts_per_seg, 0); - - seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, seg_order); - if (seg == -1) - return -1; - - offset = seg * (1 << log_mtts_per_seg); - - if (mlx4_table_get_range(dev, &mr_table->mtt_table, offset, - offset + (1 << order) - 1)) { - mlx4_buddy_free(&mr_table->mtt_buddy, seg, seg_order); - return -1; - } - - return offset; -} - -static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) -{ - u64 in_param = 0; - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, order); - err = mlx4_cmd_imm(dev, in_param, &out_param, RES_MTT, - RES_OP_RESERVE_AND_MAP, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - if (err) - return -1; - return get_param_l(&out_param); - } - return __mlx4_alloc_mtt_range(dev, order); -} - -int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, - struct mlx4_mtt *mtt) -{ - int i; - - if (!npages) { - mtt->order = -1; - mtt->page_shift = MLX4_ICM_PAGE_SHIFT; - return 0; - } else - mtt->page_shift = page_shift; - - for (mtt->order = 0, i = 1; i < npages; i <<= 1) - ++mtt->order; - - mtt->offset = mlx4_alloc_mtt_range(dev, mtt->order); - if (mtt->offset == -1) { - mlx4_err(dev, "Failed to allocate mtts for %d pages(order %d)\n", - npages, mtt->order); - return -ENOMEM; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_mtt_init); - -void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 offset, int order) -{ - u32 first_seg; - int seg_order; - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - - seg_order = max_t(int, order - log_mtts_per_seg, 0); - first_seg = offset / (1 << log_mtts_per_seg); - - mlx4_buddy_free(&mr_table->mtt_buddy, first_seg, seg_order); - mlx4_table_put_range(dev, &mr_table->mtt_table, offset, - offset + (1 << order) - 1); -} - -static void mlx4_free_mtt_range(struct mlx4_dev *dev, u32 offset, int order) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, offset); - set_param_h(&in_param, order); - err = mlx4_cmd(dev, in_param, RES_MTT, RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed to free mtt range at:" - "%d order:%d\n", offset, order); - return; - } - __mlx4_free_mtt_range(dev, offset, order); -} - -void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt) -{ - if (mtt->order < 0) - return; - - mlx4_free_mtt_range(dev, mtt->offset, mtt->order); -} -EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup); - -u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt) -{ - return (u64) mtt->offset * dev->caps.mtt_entry_sz; -} -EXPORT_SYMBOL_GPL(mlx4_mtt_addr); - -static u32 hw_index_to_key(u32 ind) -{ - return (ind >> 24) | (ind << 8); -} - -static u32 key_to_hw_index(u32 key) -{ - return (key << 24) | (key >> 8); -} - -static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int mpt_index) -{ - return mlx4_cmd(dev, mailbox->dma, mpt_index, - 0, MLX4_CMD_SW2HW_MPT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int mpt_index) -{ - return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index, - !mailbox, MLX4_CMD_HW2SW_MPT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); -} - -static int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, - u64 iova, u64 size, u32 access, int npages, - int page_shift, struct mlx4_mr *mr) -{ - mr->iova = iova; - mr->size = size; - mr->pd = pd; - mr->access = access; - mr->enabled = MLX4_MPT_DISABLED; - mr->key = hw_index_to_key(mridx); - - return mlx4_mtt_init(dev, npages, page_shift, &mr->mtt); -} - -static int mlx4_WRITE_MTT(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *mailbox, - int num_entries) -{ - return mlx4_cmd(dev, mailbox->dma, num_entries, 0, MLX4_CMD_WRITE_MTT, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -int __mlx4_mpt_reserve(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap); -} - -static int mlx4_mpt_reserve(struct mlx4_dev *dev) -{ - u64 out_param; - - if (mlx4_is_mfunc(dev)) { - if (mlx4_cmd_imm(dev, 0, &out_param, RES_MPT, RES_OP_RESERVE, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) - return -1; - return get_param_l(&out_param); - } - return __mlx4_mpt_reserve(dev); -} - -void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index, MLX4_NO_RR); -} - -static void mlx4_mpt_release(struct mlx4_dev *dev, u32 index) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, index); - if (mlx4_cmd(dev, in_param, RES_MPT, RES_OP_RESERVE, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed to release mr index:%d\n", - index); - return; - } - __mlx4_mpt_release(dev, index); -} - -int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index) -{ - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - - return mlx4_table_get(dev, &mr_table->dmpt_table, index); -} - -static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index) -{ - u64 param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(¶m, index); - return mlx4_cmd_imm(dev, param, ¶m, RES_MPT, RES_OP_MAP_ICM, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - } - return __mlx4_mpt_alloc_icm(dev, index); -} - -void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index) -{ - struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; - - mlx4_table_put(dev, &mr_table->dmpt_table, index); -} - -static void mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, index); - if (mlx4_cmd(dev, in_param, RES_MPT, RES_OP_MAP_ICM, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed to free icm of mr index:%d\n", - index); - return; - } - return __mlx4_mpt_free_icm(dev, index); -} - -int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, - int npages, int page_shift, struct mlx4_mr *mr) -{ - u32 index; - int err; - - index = mlx4_mpt_reserve(dev); - if (index == -1) - return -ENOMEM; - - err = mlx4_mr_alloc_reserved(dev, index, pd, iova, size, - access, npages, page_shift, mr); - if (err) - mlx4_mpt_release(dev, index); - - return err; -} -EXPORT_SYMBOL_GPL(mlx4_mr_alloc); - -static int mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr) -{ - int err; - - if (mr->enabled == MLX4_MPT_EN_HW) { - err = mlx4_HW2SW_MPT(dev, NULL, - key_to_hw_index(mr->key) & - (dev->caps.num_mpts - 1)); - if (err) { - mlx4_warn(dev, "HW2SW_MPT failed (%d).", err); - mlx4_warn(dev, "Most likely the MR has MWs bound to it.\n"); - return err; - } - - mr->enabled = MLX4_MPT_EN_SW; - } - mlx4_mtt_cleanup(dev, &mr->mtt); - - return 0; -} - -int mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr) -{ - int ret; - - ret = mlx4_mr_free_reserved(dev, mr); - if (ret) - return ret; - if (mr->enabled) - mlx4_mpt_free_icm(dev, key_to_hw_index(mr->key)); - mlx4_mpt_release(dev, key_to_hw_index(mr->key)); - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_mr_free); - -int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mpt_entry *mpt_entry; - int err; - - err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mr->key)); - if (err) - return err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_table; - } - mpt_entry = mailbox->buf; - - memset(mpt_entry, 0, sizeof *mpt_entry); - - mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_MIO | - MLX4_MPT_FLAG_REGION | - mr->access); - - mpt_entry->key = cpu_to_be32(key_to_hw_index(mr->key)); - mpt_entry->pd_flags = cpu_to_be32(mr->pd | MLX4_MPT_PD_FLAG_EN_INV); - mpt_entry->start = cpu_to_be64(mr->iova); - mpt_entry->length = cpu_to_be64(mr->size); - mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); - - if (mr->mtt.order < 0) { - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL); - mpt_entry->mtt_addr = 0; - } else { - mpt_entry->mtt_addr = cpu_to_be64(mlx4_mtt_addr(dev, - &mr->mtt)); - } - - if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) { - /* fast register MR in free state */ - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); - mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG | - MLX4_MPT_PD_FLAG_RAE); - mpt_entry->mtt_sz = cpu_to_be32(1 << mr->mtt.order); - } else { - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS); - } - - err = mlx4_SW2HW_MPT(dev, mailbox, - key_to_hw_index(mr->key) & (dev->caps.num_mpts - 1)); - if (err) { - mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); - goto err_cmd; - } - mr->enabled = MLX4_MPT_EN_HW; - - mlx4_free_cmd_mailbox(dev, mailbox); - - return 0; - -err_cmd: - mlx4_free_cmd_mailbox(dev, mailbox); - -err_table: - mlx4_mpt_free_icm(dev, key_to_hw_index(mr->key)); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_mr_enable); - -static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - __be64 *mtts; - dma_addr_t dma_handle; - int i; - - mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->offset + - start_index, &dma_handle); - - if (!mtts) - return -ENOMEM; - - dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, - npages * sizeof (u64), DMA_TO_DEVICE); - - for (i = 0; i < npages; ++i) - mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - - dma_sync_single_for_device(&dev->pdev->dev, dma_handle, - npages * sizeof (u64), DMA_TO_DEVICE); - - return 0; -} - -int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list) -{ - int err = 0; - int chunk; - int mtts_per_page; - int max_mtts_first_page; - - /* compute how may mtts fit in the first page */ - mtts_per_page = PAGE_SIZE / sizeof(u64); - max_mtts_first_page = mtts_per_page - (mtt->offset + start_index) - % mtts_per_page; - - chunk = min_t(int, max_mtts_first_page, npages); - - while (npages > 0) { - err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); - if (err) - return err; - npages -= chunk; - start_index += chunk; - page_list += chunk; - - chunk = min_t(int, mtts_per_page, npages); - } - return err; -} - -int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list) -{ - struct mlx4_cmd_mailbox *mailbox = NULL; - __be64 *inbox = NULL; - int chunk; - int err = 0; - int i; - - if (mtt->order < 0) - return -EINVAL; - - if (mlx4_is_mfunc(dev)) { - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - inbox = mailbox->buf; - - while (npages > 0) { - chunk = min_t(int, MLX4_MAILBOX_SIZE / sizeof(u64) - 2, - npages); - inbox[0] = cpu_to_be64(mtt->offset + start_index); - inbox[1] = 0; - for (i = 0; i < chunk; ++i) - inbox[i + 2] = cpu_to_be64(page_list[i] | - MLX4_MTT_FLAG_PRESENT); - err = mlx4_WRITE_MTT(dev, mailbox, chunk); - if (err) { - mlx4_free_cmd_mailbox(dev, mailbox); - return err; - } - - npages -= chunk; - start_index += chunk; - page_list += chunk; - } - mlx4_free_cmd_mailbox(dev, mailbox); - return err; - } - - return __mlx4_write_mtt(dev, mtt, start_index, npages, page_list); -} -EXPORT_SYMBOL_GPL(mlx4_write_mtt); - -int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - struct mlx4_buf *buf) -{ - u64 *page_list; - int err; - int i; - - page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL); - if (!page_list) - return -ENOMEM; - - for (i = 0; i < buf->npages; ++i) - if (buf->nbufs == 1) - page_list[i] = buf->direct.map + (i << buf->page_shift); - else - page_list[i] = buf->page_list[i].map; - - err = mlx4_write_mtt(dev, mtt, 0, buf->npages, page_list); - - kfree(page_list); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); - -int mlx4_mw_alloc(struct mlx4_dev *dev, u32 pd, enum mlx4_mw_type type, - struct mlx4_mw *mw) -{ - u32 index; - - index = mlx4_mpt_reserve(dev); - if (index == -1) - return -ENOMEM; - - mw->key = hw_index_to_key(index); - mw->pd = pd; - mw->type = type; - mw->enabled = MLX4_MPT_DISABLED; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_mw_alloc); - -int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_mpt_entry *mpt_entry; - int err; - - err = mlx4_mpt_alloc_icm(dev, key_to_hw_index(mw->key)); - if (err) - return err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_table; - } - mpt_entry = mailbox->buf; - - memset(mpt_entry, 0, sizeof(*mpt_entry)); - - /* Note that the MLX4_MPT_FLAG_REGION bit in mpt_entry->flags is turned - * off, thus creating a memory window and not a memory region. - */ - mpt_entry->key = cpu_to_be32(key_to_hw_index(mw->key)); - mpt_entry->pd_flags = cpu_to_be32(mw->pd); - if (mw->type == MLX4_MW_TYPE_2) { - mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); - mpt_entry->qpn = cpu_to_be32(MLX4_MPT_QP_FLAG_BOUND_QP); - mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_EN_INV); - } - - err = mlx4_SW2HW_MPT(dev, mailbox, - key_to_hw_index(mw->key) & - (dev->caps.num_mpts - 1)); - if (err) { - mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); - goto err_cmd; - } - mw->enabled = MLX4_MPT_EN_HW; - - mlx4_free_cmd_mailbox(dev, mailbox); - - return 0; - -err_cmd: - mlx4_free_cmd_mailbox(dev, mailbox); - -err_table: - mlx4_mpt_free_icm(dev, key_to_hw_index(mw->key)); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_mw_enable); - -void mlx4_mw_free(struct mlx4_dev *dev, struct mlx4_mw *mw) -{ - int err; - - if (mw->enabled == MLX4_MPT_EN_HW) { - err = mlx4_HW2SW_MPT(dev, NULL, - key_to_hw_index(mw->key) & - (dev->caps.num_mpts - 1)); - if (err) - mlx4_warn(dev, "xxx HW2SW_MPT failed (%d)\n", err); - - mw->enabled = MLX4_MPT_EN_SW; - } - if (mw->enabled) - mlx4_mpt_free_icm(dev, key_to_hw_index(mw->key)); - mlx4_mpt_release(dev, key_to_hw_index(mw->key)); -} -EXPORT_SYMBOL_GPL(mlx4_mw_free); - -int mlx4_init_mr_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_mr_table *mr_table = &priv->mr_table; - int err; - - /* Nothing to do for slaves - all MR handling is forwarded - * to the master */ - if (mlx4_is_slave(dev)) - return 0; - - if (!is_power_of_2(dev->caps.num_mpts)) - return -EINVAL; - - err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts, - ~0, dev->caps.reserved_mrws, 0); - if (err) - return err; - - err = mlx4_buddy_init(&mr_table->mtt_buddy, - ilog2(div_u64(dev->caps.num_mtts, - (1 << log_mtts_per_seg)))); - if (err) - goto err_buddy; - - if (dev->caps.reserved_mtts) { - priv->reserved_mtts = - mlx4_alloc_mtt_range(dev, - fls(dev->caps.reserved_mtts - 1)); - if (priv->reserved_mtts < 0) { - mlx4_warn(dev, "MTT table of order %u is too small.\n", - mr_table->mtt_buddy.max_order); - err = -ENOMEM; - goto err_reserve_mtts; - } - } - - return 0; - -err_reserve_mtts: - mlx4_buddy_cleanup(&mr_table->mtt_buddy); - -err_buddy: - mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); - - return err; -} - -void mlx4_cleanup_mr_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_mr_table *mr_table = &priv->mr_table; - - if (mlx4_is_slave(dev)) - return; - if (priv->reserved_mtts >= 0) - mlx4_free_mtt_range(dev, priv->reserved_mtts, - fls(dev->caps.reserved_mtts - 1)); - mlx4_buddy_cleanup(&mr_table->mtt_buddy); - mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); -} - -static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list, - int npages, u64 iova) -{ - int i, page_mask; - - if (npages > fmr->max_pages) - return -EINVAL; - - page_mask = (1 << fmr->page_shift) - 1; - - /* We are getting page lists, so va must be page aligned. */ - if (iova & page_mask) - return -EINVAL; - - /* Trust the user not to pass misaligned data in page_list */ - if (0) - for (i = 0; i < npages; ++i) { - if (page_list[i] & ~page_mask) - return -EINVAL; - } - - if (fmr->maps >= fmr->max_maps) - return -EINVAL; - - return 0; -} - -int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, - int npages, u64 iova, u32 *lkey, u32 *rkey) -{ - u32 key; - int i, err; - - err = mlx4_check_fmr(fmr, page_list, npages, iova); - if (err) - return err; - - ++fmr->maps; - - key = key_to_hw_index(fmr->mr.key); - key += dev->caps.num_mpts; - *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); - - *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; - - /* Make sure MPT status is visible before writing MTT entries */ - wmb(); - - dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, - npages * sizeof(u64), DMA_TO_DEVICE); - - for (i = 0; i < npages; ++i) - fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - - dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle, - npages * sizeof(u64), DMA_TO_DEVICE); - - fmr->mpt->key = cpu_to_be32(key); - fmr->mpt->lkey = cpu_to_be32(key); - fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift)); - fmr->mpt->start = cpu_to_be64(iova); - - /* Make MTT entries are visible before setting MPT status */ - wmb(); - - *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW; - - /* Make sure MPT status is visible before consumer can use FMR */ - wmb(); - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr); - -int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, - int max_maps, u8 page_shift, struct mlx4_fmr *fmr) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err = -ENOMEM, ret; - - if (max_maps > dev->caps.max_fmr_maps) - return -EINVAL; - - if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32) - return -EINVAL; - - /* All MTTs must fit in the same page */ - if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) - return -EINVAL; - - fmr->page_shift = page_shift; - fmr->max_pages = max_pages; - fmr->max_maps = max_maps; - fmr->maps = 0; - - err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages, - page_shift, &fmr->mr); - if (err) - return err; - - fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, - fmr->mr.mtt.offset, - &fmr->dma_handle); - - if (!fmr->mtts) { - err = -ENOMEM; - goto err_free; - } - - return 0; - -err_free: - ret = mlx4_mr_free(dev, &fmr->mr); - if (ret) - mlx4_err(dev, "Error deregistering MR. The system may have become unstable."); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); - -int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int err; - - err = mlx4_mr_enable(dev, &fmr->mr); - if (err) - return err; - - fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, - key_to_hw_index(fmr->mr.key), NULL); - if (!fmr->mpt) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_enable); - -void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, - u32 *lkey, u32 *rkey) -{ - u32 key; - - if (!fmr->maps) - return; - - key = key_to_hw_index(fmr->mr.key) & (dev->caps.num_mpts - 1); - - *(u8 *)fmr->mpt = MLX4_MPT_STATUS_SW; - - /* Make sure MPT status is visible before changing MPT fields */ - wmb(); - - fmr->mr.key = hw_index_to_key(key); - - fmr->mpt->key = cpu_to_be32(key); - fmr->mpt->lkey = cpu_to_be32(key); - fmr->mpt->length = 0; - fmr->mpt->start = 0; - - /* Make sure MPT data is visible before changing MPT status */ - wmb(); - - *(u8 *)fmr->mpt = MLX4_MPT_STATUS_HW; - - /* Make sure MPT satus is visible */ - wmb(); - - fmr->maps = 0; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); - -int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) -{ - int ret; - - if (fmr->maps) - return -EBUSY; - - ret = mlx4_mr_free(dev, &fmr->mr); - if (ret) - return ret; - fmr->mr.enabled = MLX4_MPT_DISABLED; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_fmr_free); - -int mlx4_SYNC_TPT(struct mlx4_dev *dev) -{ - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000, - MLX4_CMD_NATIVE); -} -EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/sys/ofed/drivers/net/mlx4/pd.c b/sys/ofed/drivers/net/mlx4/pd.c deleted file mode 100644 index 89a8854699ac..000000000000 --- a/sys/ofed/drivers/net/mlx4/pd.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2005, 2014 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/errno.h> -#include <linux/module.h> -#include <linux/io-mapping.h> - -#include <linux/page.h> - -#include "mlx4.h" -#include "icm.h" - -enum { - MLX4_NUM_RESERVED_UARS = 8 -}; - -int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap); - if (*pdn == -1) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_pd_alloc); - -void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) -{ - mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn, MLX4_USE_RR); -} -EXPORT_SYMBOL_GPL(mlx4_pd_free); - -int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - *xrcdn = mlx4_bitmap_alloc(&priv->xrcd_bitmap); - if (*xrcdn == -1) - return -ENOMEM; - - return 0; -} - -int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) -{ - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, - RES_XRCD, RES_OP_RESERVE, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - return err; - - *xrcdn = get_param_l(&out_param); - return 0; - } - return __mlx4_xrcd_alloc(dev, xrcdn); -} -EXPORT_SYMBOL_GPL(mlx4_xrcd_alloc); - -void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) -{ - mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn, MLX4_USE_RR); -} - -void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, xrcdn); - err = mlx4_cmd(dev, in_param, RES_XRCD, - RES_OP_RESERVE, MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - mlx4_warn(dev, "Failed to release xrcdn %d\n", xrcdn); - } else - __mlx4_xrcd_free(dev, xrcdn); -} -EXPORT_SYMBOL_GPL(mlx4_xrcd_free); - -int mlx4_init_pd_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds, - (1 << NOT_MASKED_PD_BITS) - 1, - dev->caps.reserved_pds, 0); -} - -void mlx4_cleanup_pd_table(struct mlx4_dev *dev) -{ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->pd_bitmap); -} - -int mlx4_init_xrcd_table(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return mlx4_bitmap_init(&priv->xrcd_bitmap, (1 << 16), - (1 << 16) - 1, dev->caps.reserved_xrcds + 1, 0); -} - -void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev) -{ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->xrcd_bitmap); -} - -int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) -{ - int offset; - - uar->index = mlx4_bitmap_alloc(&mlx4_priv(dev)->uar_table.bitmap); - if (uar->index == -1) - return -ENOMEM; - - if (mlx4_is_slave(dev)) - offset = uar->index % ((int) pci_resource_len(dev->pdev, 2) / - dev->caps.uar_page_size); - else - offset = uar->index; - uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + offset; - uar->map = NULL; - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_uar_alloc); - -void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) -{ - mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index, MLX4_USE_RR); -} -EXPORT_SYMBOL_GPL(mlx4_uar_free); - -#ifndef CONFIG_PPC -int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_uar *uar; - int err = 0; - int idx; - - if (!priv->bf_mapping) - return -ENOMEM; - - mutex_lock(&priv->bf_mutex); - if (!list_empty(&priv->bf_list)) - uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); - else { - if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { - err = -ENOMEM; - goto out; - } - uar = kmalloc_node(sizeof *uar, GFP_KERNEL, node); - if (!uar) { - uar = kmalloc(sizeof *uar, GFP_KERNEL); - if (!uar) { - err = -ENOMEM; - goto out; - } - } - err = mlx4_uar_alloc(dev, uar); - if (err) - goto free_kmalloc; - - uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE); - if (!uar->map) { - err = -ENOMEM; - goto free_uar; - } - - uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT); - if (!uar->bf_map) { - err = -ENOMEM; - goto unamp_uar; - } - uar->free_bf_bmap = 0; - list_add(&uar->bf_list, &priv->bf_list); - } - - bf->uar = uar; - idx = ffz(uar->free_bf_bmap); - uar->free_bf_bmap |= 1 << idx; - bf->uar = uar; - bf->offset = 0; - bf->buf_size = dev->caps.bf_reg_size / 2; - bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; - if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) - list_del_init(&uar->bf_list); - - goto out; - -unamp_uar: - bf->uar = NULL; - iounmap(uar->map); - -free_uar: - mlx4_uar_free(dev, uar); - -free_kmalloc: - kfree(uar); - -out: - mutex_unlock(&priv->bf_mutex); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_bf_alloc); - -void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int idx; - - if (!bf->uar || !bf->uar->bf_map) - return; - - mutex_lock(&priv->bf_mutex); - idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; - bf->uar->free_bf_bmap &= ~(1 << idx); - if (!bf->uar->free_bf_bmap) { - if (!list_empty(&bf->uar->bf_list)) - list_del(&bf->uar->bf_list); - - io_mapping_unmap(bf->uar->bf_map); - iounmap(bf->uar->map); - mlx4_uar_free(dev, bf->uar); - kfree(bf->uar); - } else if (list_empty(&bf->uar->bf_list)) - list_add(&bf->uar->bf_list, &priv->bf_list); - - mutex_unlock(&priv->bf_mutex); -} -EXPORT_SYMBOL_GPL(mlx4_bf_free); - -#else -int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) -{ - memset(bf, 0, sizeof *bf); - return -ENOSYS; -} -EXPORT_SYMBOL_GPL(mlx4_bf_alloc); - -void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) -{ - return; -} -EXPORT_SYMBOL_GPL(mlx4_bf_free); -#endif - -int mlx4_init_uar_table(struct mlx4_dev *dev) -{ - if (dev->caps.num_uars <= 128) { - mlx4_err(dev, "Only %d UAR pages (need more than 128)\n", - dev->caps.num_uars); - mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n"); - return -ENODEV; - } - - return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap, - dev->caps.num_uars, dev->caps.num_uars - 1, - dev->caps.reserved_uars, 0); -} - -void mlx4_cleanup_uar_table(struct mlx4_dev *dev) -{ - mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap); -} diff --git a/sys/ofed/drivers/net/mlx4/port.c b/sys/ofed/drivers/net/mlx4/port.c deleted file mode 100644 index aeb38746cbd5..000000000000 --- a/sys/ofed/drivers/net/mlx4/port.c +++ /dev/null @@ -1,1224 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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. - */ - -#define LINUXKPI_PARAM_PREFIX mlx4_ - -#include <linux/errno.h> -#include <linux/if_ether.h> -#include <linux/module.h> -#include <linux/err.h> - -#include <linux/mlx4/cmd.h> -#include <linux/moduleparam.h> -#include "mlx4.h" -#include "mlx4_stats.h" - - -int mlx4_set_4k_mtu = -1; -module_param_named(set_4k_mtu, mlx4_set_4k_mtu, int, 0444); -MODULE_PARM_DESC(set_4k_mtu, - "(Obsolete) attempt to set 4K MTU to all ConnectX ports"); - - -#define MLX4_MAC_VALID (1ull << 63) - -#define MLX4_VLAN_VALID (1u << 31) -#define MLX4_VLAN_MASK 0xfff - -void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) -{ - int i; - - mutex_init(&table->mutex); - for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { - table->entries[i] = 0; - table->refs[i] = 0; - } - table->max = 1 << dev->caps.log_num_macs; - table->total = 0; -} - -void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) -{ - int i; - - mutex_init(&table->mutex); - for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { - table->entries[i] = 0; - table->refs[i] = 0; - } - table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; - table->total = 0; -} - -static int validate_index(struct mlx4_dev *dev, - struct mlx4_mac_table *table, int index) -{ - int err = 0; - - if (index < 0 || index >= table->max || !table->refs[index]) { - mlx4_warn(dev, "No valid Mac entry for the given index\n"); - err = -EINVAL; - } - return err; -} - -static int find_index(struct mlx4_dev *dev, - struct mlx4_mac_table *table, u64 mac) -{ - int i; - - for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { - if ((mac & MLX4_MAC_MASK) == - (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) - return i; - } - /* Mac not found */ - return -EINVAL; -} - -static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, - __be64 *entries) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 in_mod; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); - - in_mod = MLX4_SET_PORT_MAC_TABLE << 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; -} - -int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; - struct mlx4_mac_table *table = &info->mac_table; - int i, err = 0; - int free = -1; - - mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n", - (unsigned long long) mac, port); - - mutex_lock(&table->mutex); - for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { - if (free < 0 && !table->refs[i]) { - free = i; - continue; - } - - if ((mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) && - table->refs[i]) { - /* MAC already registered, Must not have duplicates */ - err = i; - ++table->refs[i]; - goto out; - } - } - - mlx4_dbg(dev, "Free MAC index is %d\n", free); - - if (table->total == table->max) { - /* No free mac entries */ - err = -ENOSPC; - goto out; - } - - /* Register new MAC */ - table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); - - err = mlx4_set_port_mac_table(dev, port, table->entries); - if (unlikely(err)) { - mlx4_err(dev, "Failed adding MAC: 0x%llx\n", - (unsigned long long) mac); - table->entries[free] = 0; - goto out; - } - table->refs[free] = 1; - - err = free; - ++table->total; -out: - mutex_unlock(&table->mutex); - return err; -} -EXPORT_SYMBOL_GPL(__mlx4_register_mac); - -int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - u64 out_param = 0; - int err = -EINVAL; - - if (mlx4_is_mfunc(dev)) { - if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { - err = mlx4_cmd_imm(dev, mac, &out_param, - ((u32) port) << 8 | (u32) RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - } - if (err && err == -EINVAL && mlx4_is_slave(dev)) { - /* retry using old REG_MAC format */ - set_param_l(&out_param, port); - err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) - dev->flags |= MLX4_FLAG_OLD_REG_MAC; - } - if (err) - return err; - - return get_param_l(&out_param); - } - return __mlx4_register_mac(dev, port, mac); -} -EXPORT_SYMBOL_GPL(mlx4_register_mac); - -int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) -{ - return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + - (port - 1) * (1 << dev->caps.log_num_macs); -} -EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); - -void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - struct mlx4_port_info *info; - struct mlx4_mac_table *table; - int index; - - if (port < 1 || port > dev->caps.num_ports) { - mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); - return; - } - info = &mlx4_priv(dev)->port[port]; - table = &info->mac_table; - mutex_lock(&table->mutex); - - index = find_index(dev, table, mac); - - if (validate_index(dev, table, index)) - goto out; - - if (--table->refs[index]) { - mlx4_dbg(dev, "Have more references for index %d," - "no need to modify mac table\n", index); - goto out; - } - - table->entries[index] = 0; - mlx4_set_port_mac_table(dev, port, table->entries); - --table->total; -out: - mutex_unlock(&table->mutex); -} -EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); - -void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) -{ - u64 out_param = 0; - - if (mlx4_is_mfunc(dev)) { - if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { - (void) mlx4_cmd_imm(dev, mac, &out_param, - ((u32) port) << 8 | (u32) RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - } else { - /* use old unregister mac format */ - set_param_l(&out_param, port); - (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - } - return; - } - __mlx4_unregister_mac(dev, port, mac); - return; -} -EXPORT_SYMBOL_GPL(mlx4_unregister_mac); - -int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) -{ - struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; - struct mlx4_mac_table *table = &info->mac_table; - int index = qpn - info->base_qpn; - int err = 0; - - /* CX1 doesn't support multi-functions */ - mutex_lock(&table->mutex); - - err = validate_index(dev, table, index); - if (err) - goto out; - - table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); - - err = mlx4_set_port_mac_table(dev, port, table->entries); - if (unlikely(err)) { - mlx4_err(dev, "Failed adding MAC: 0x%llx\n", - (unsigned long long) new_mac); - table->entries[index] = 0; - } -out: - mutex_unlock(&table->mutex); - return err; -} -EXPORT_SYMBOL_GPL(__mlx4_replace_mac); - -static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, - __be32 *entries) -{ - struct mlx4_cmd_mailbox *mailbox; - u32 in_mod; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); - in_mod = MLX4_SET_PORT_VLAN_TABLE << 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; -} - -int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) -{ - struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; - int i; - - for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { - if (table->refs[i] && - (vid == (MLX4_VLAN_MASK & - be32_to_cpu(table->entries[i])))) { - /* VLAN already registered, increase reference count */ - *idx = i; - return 0; - } - } - - return -ENOENT; -} -EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); - -int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, - int *index) -{ - struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; - int i, err = 0; - int free = -1; - - mutex_lock(&table->mutex); - - if (table->total == table->max) { - /* No free vlan entries */ - err = -ENOSPC; - goto out; - } - - for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { - if (free < 0 && (table->refs[i] == 0)) { - free = i; - continue; - } - - if (table->refs[i] && - (vlan == (MLX4_VLAN_MASK & - be32_to_cpu(table->entries[i])))) { - /* Vlan already registered, increase references count */ - *index = i; - ++table->refs[i]; - goto out; - } - } - - if (free < 0) { - err = -ENOMEM; - goto out; - } - - /* Register new VLAN */ - table->refs[free] = 1; - table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); - - err = mlx4_set_port_vlan_table(dev, port, table->entries); - if (unlikely(err)) { - mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); - table->refs[free] = 0; - table->entries[free] = 0; - goto out; - } - - *index = free; - ++table->total; -out: - mutex_unlock(&table->mutex); - return err; -} - -int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) -{ - u64 out_param = 0; - int err; - - if (vlan > 4095) - return -EINVAL; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, vlan, &out_param, - ((u32) port) << 8 | (u32) RES_VLAN, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) - *index = get_param_l(&out_param); - - return err; - } - return __mlx4_register_vlan(dev, port, vlan, index); -} -EXPORT_SYMBOL_GPL(mlx4_register_vlan); - -void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) -{ - struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; - int index; - - mutex_lock(&table->mutex); - if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { - mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); - goto out; - } - - if (index < MLX4_VLAN_REGULAR) { - mlx4_warn(dev, "Trying to free special vlan index %d\n", index); - goto out; - } - - if (--table->refs[index]) { - mlx4_dbg(dev, "Have %d more references for index %d, " - "no need to modify vlan table\n", table->refs[index], - index); - goto out; - } - table->entries[index] = 0; - mlx4_set_port_vlan_table(dev, port, table->entries); - --table->total; -out: - mutex_unlock(&table->mutex); -} - -void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) -{ - u64 out_param = 0; - - if (mlx4_is_mfunc(dev)) { - (void) mlx4_cmd_imm(dev, vlan, &out_param, - ((u32) port) << 8 | (u32) RES_VLAN, - RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - return; - } - __mlx4_unregister_vlan(dev, port, vlan); -} -EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); - -int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) -{ - struct mlx4_cmd_mailbox *inmailbox, *outmailbox; - u8 *inbuf, *outbuf; - int err; - - inmailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(inmailbox)) - return PTR_ERR(inmailbox); - - outmailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(outmailbox)) { - mlx4_free_cmd_mailbox(dev, inmailbox); - return PTR_ERR(outmailbox); - } - - inbuf = inmailbox->buf; - outbuf = outmailbox->buf; - memset(inbuf, 0, 256); - memset(outbuf, 0, 256); - inbuf[0] = 1; - inbuf[1] = 1; - inbuf[2] = 1; - inbuf[3] = 1; - *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); - *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); - - err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - if (!err) - *caps = *(__be32 *) (outbuf + 84); - mlx4_free_cmd_mailbox(dev, inmailbox); - mlx4_free_cmd_mailbox(dev, outmailbox); - return err; -} -static struct mlx4_roce_gid_entry zgid_entry; - -int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave) -{ - if (slave == 0) - return MLX4_ROCE_PF_GIDS; - if (slave <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % dev->num_vfs)) - return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs) + 1; - return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs; -} - -int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave) -{ - int gids; - int vfs; - - gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; - vfs = dev->num_vfs; - - if (slave == 0) - return 0; - if (slave <= gids % vfs) - return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); - - return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); -} - -static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, - u8 op_mod, struct mlx4_cmd_mailbox *inbox) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_port_info *port_info; - struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; - struct mlx4_slave_state *slave_st = &master->slave_state[slave]; - struct mlx4_set_port_rqp_calc_context *qpn_context; - struct mlx4_set_port_general_context *gen_context; - struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; - int reset_qkey_viols; - int port; - int is_eth; - int num_gids; - int base; - u32 in_modifier; - u32 promisc; - u16 mtu, prev_mtu; - int err; - int i, j; - int offset; - __be32 agg_cap_mask; - __be32 slave_cap_mask; - __be32 new_cap_mask; - - port = in_mod & 0xff; - in_modifier = (in_mod >> 8) & 0xff; - is_eth = op_mod; - port_info = &priv->port[port]; - - if (op_mod > 1) - return -EINVAL; - - /* Slaves cannot perform SET_PORT operations except changing MTU */ - if (is_eth) { - if (slave != dev->caps.function && - in_modifier != MLX4_SET_PORT_GENERAL && - in_modifier != MLX4_SET_PORT_GID_TABLE) { - mlx4_warn(dev, "denying SET_PORT for slave:%d," - "port %d, config_select 0x%x\n", - slave, port, in_modifier); - return -EINVAL; - } - switch (in_modifier) { - case MLX4_SET_PORT_RQP_CALC: - qpn_context = inbox->buf; - qpn_context->base_qpn = - cpu_to_be32(port_info->base_qpn); - qpn_context->n_mac = 0x7; - promisc = be32_to_cpu(qpn_context->promisc) >> - SET_PORT_PROMISC_SHIFT; - qpn_context->promisc = cpu_to_be32( - promisc << SET_PORT_PROMISC_SHIFT | - port_info->base_qpn); - promisc = be32_to_cpu(qpn_context->mcast) >> - SET_PORT_MC_PROMISC_SHIFT; - qpn_context->mcast = cpu_to_be32( - promisc << SET_PORT_MC_PROMISC_SHIFT | - port_info->base_qpn); - break; - case MLX4_SET_PORT_GENERAL: - gen_context = inbox->buf; - /* Mtu is configured as the max MTU among all the - * the functions on the port. */ - mtu = be16_to_cpu(gen_context->mtu); - mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + - ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); - prev_mtu = slave_st->mtu[port]; - slave_st->mtu[port] = mtu; - if (mtu > master->max_mtu[port]) - master->max_mtu[port] = mtu; - if (mtu < prev_mtu && prev_mtu == - master->max_mtu[port]) { - slave_st->mtu[port] = mtu; - master->max_mtu[port] = mtu; - for (i = 0; i < dev->num_slaves; i++) { - master->max_mtu[port] = - max(master->max_mtu[port], - master->slave_state[i].mtu[port]); - } - } - - gen_context->mtu = cpu_to_be16(master->max_mtu[port]); - break; - case MLX4_SET_PORT_GID_TABLE: - /* change to MULTIPLE entries: number of guest's gids - * need a FOR-loop here over number of gids the guest has. - * 1. Check no duplicates in gids passed by slave - */ - num_gids = mlx4_get_slave_num_gids(dev, slave); - base = mlx4_get_base_gid_ix(dev, slave); - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (i = 0; i < num_gids; gid_entry_mbox++, i++) { - if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, - sizeof(zgid_entry))) - continue; - gid_entry_mb1 = gid_entry_mbox + 1; - for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { - if (!memcmp(gid_entry_mb1->raw, - zgid_entry.raw, sizeof(zgid_entry))) - continue; - if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, - sizeof(gid_entry_mbox->raw))) { - /* found duplicate */ - return -EINVAL; - } - } - } - - /* 2. Check that do not have duplicates in OTHER - * entries in the port GID table - */ - for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { - if (i >= base && i < base + num_gids) - continue; /* don't compare to slave's current gids */ - gid_entry_tbl = &priv->roce_gids[port - 1][i]; - if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) - continue; - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (j = 0; j < num_gids; gid_entry_mbox++, j++) { - if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, - sizeof(zgid_entry))) - continue; - if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, - sizeof(gid_entry_tbl->raw))) { - /* found duplicate */ - mlx4_warn(dev, "requested gid entry for slave:%d " - "is a duplicate of gid at index %d\n", - slave, i); - return -EINVAL; - } - } - } - - /* insert slave GIDs with memcpy, starting at slave's base index */ - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) - memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16); - - /* Now, copy roce port gids table to current mailbox for passing to FW */ - gid_entry_mbox = (struct mlx4_roce_gid_entry *) (inbox->buf); - for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) - memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16); - - break; - } - return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, - MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - } - - /* For IB, we only consider: - * - The capability mask, which is set to the aggregate of all - * slave function capabilities - * - The QKey violatin counter - reset according to each request. - */ - - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; - new_cap_mask = ((__be32 *) inbox->buf)[2]; - } else { - reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; - new_cap_mask = ((__be32 *) inbox->buf)[1]; - } - - /* slave may not set the IS_SM capability for the port */ - if (slave != mlx4_master_func_num(dev) && - (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) - return -EINVAL; - - /* No DEV_MGMT in multifunc mode */ - if (mlx4_is_mfunc(dev) && - (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) - return -EINVAL; - - agg_cap_mask = 0; - slave_cap_mask = - priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; - priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; - for (i = 0; i < dev->num_slaves; i++) - agg_cap_mask |= - priv->mfunc.master.slave_state[i].ib_cap_mask[port]; - - /* only clear mailbox for guests. Master may be setting - * MTU or PKEY table size - */ - if (slave != dev->caps.function) - memset(inbox->buf, 0, 256); - if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; - ((__be32 *) inbox->buf)[2] = agg_cap_mask; - } else { - ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; - ((__be32 *) inbox->buf)[1] = agg_cap_mask; - } - - err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - if (err) - priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = - slave_cap_mask; - return err; -} - -int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return mlx4_common_set_port(dev, slave, vhcr->in_modifier, - vhcr->op_modifier, inbox); -} - -/* bit locations for set port command with zero op modifier */ -enum { - MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ - MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ - MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, - MLX4_CHANGE_PORT_VL_CAP = 21, - MLX4_CHANGE_PORT_MTU_CAP = 22, -}; - -int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) -{ - struct mlx4_cmd_mailbox *mailbox; - int err = -EINVAL, vl_cap, pkey_tbl_flag = 0; - u32 in_mod; - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_NONE) - return 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - memset(mailbox->buf, 0, 256); - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { - in_mod = MLX4_SET_PORT_GENERAL << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, - MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - } else { - ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; - - if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { - pkey_tbl_flag = 1; - ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); - } - - /* IB VL CAP enum isn't used by the firmware, just numerical values */ - for (vl_cap = dev->caps.vl_cap[port]; - vl_cap >= 1; vl_cap >>= 1) { - ((__be32 *) mailbox->buf)[0] = cpu_to_be32( - (1 << MLX4_CHANGE_PORT_MTU_CAP) | - (1 << MLX4_CHANGE_PORT_VL_CAP) | - (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | - (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | - (vl_cap << MLX4_SET_PORT_VL_CAP)); - err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - if (err != -ENOMEM) - break; - } - } - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} - -int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, - u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_general_context *context; - int err; - u32 in_mod; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - context->flags = SET_PORT_GEN_ALL_VALID; - context->mtu = cpu_to_be16(mtu); - context->pptx = (pptx * (!pfctx)) << 7; - context->pfctx = pfctx; - context->pprx = (pprx * (!pfcrx)) << 7; - context->pfcrx = pfcrx; - - in_mod = MLX4_SET_PORT_GENERAL << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_general); - -int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, - u8 promisc) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_rqp_calc_context *context; - int err; - u32 in_mod; - u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? - MCAST_DIRECT : MCAST_DEFAULT; - - if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) - return 0; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - context->base_qpn = cpu_to_be32(base_qpn); - context->n_mac = dev->caps.log_num_macs; - context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | - base_qpn); - context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | - base_qpn); - context->intra_no_vlan = 0; - context->no_vlan = MLX4_NO_VLAN_IDX; - context->intra_vlan_miss = 0; - context->vlan_miss = MLX4_VLAN_MISS_IDX; - - in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); - -int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_prio2tc_context *context; - int err; - u32 in_mod; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - 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, u8 port, u8 *tc_tx_bw, - u8 *pg, u16 *ratelimit) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_scheduler_context *context; - int err; - u32 in_mod; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - memset(context, 0, sizeof *context); - - for (i = 0; i < MLX4_NUM_TC; i++) { - struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; - u16 r; - if (ratelimit && ratelimit[i]) { - if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { - r = ratelimit[i]; - tc->max_bw_units = - htons(MLX4_RATELIMIT_100M_UNITS); - } else { - r = ratelimit[i]/10; - tc->max_bw_units = - htons(MLX4_RATELIMIT_1G_UNITS); - } - tc->max_bw_value = htons(r); - } else { - tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); - tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); - } - - tc->pg = htons(pg[i]); - tc->bw_precentage = htons(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_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err = 0; - - return err; -} - -int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, - u64 mac, u64 clear, u8 mode) -{ - return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, - MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); -} -EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); - -int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err = 0; - - return err; -} - -int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - return 0; -} - -void mlx4_set_stats_bitmap(struct mlx4_dev *dev, unsigned long *stats_bitmap) -{ - int last_i = 0; - - bitmap_zero(stats_bitmap, NUM_ALL_STATS); - - if (mlx4_is_slave(dev)) { - last_i = dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN ? - NUM_PKT_STATS + NUM_FLOW_STATS : NUM_PKT_STATS; - } else { - bitmap_set(stats_bitmap, last_i, NUM_PKT_STATS); - last_i = NUM_PKT_STATS; - - if (dev->caps.flags2 & - MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) { - bitmap_set(stats_bitmap, last_i, NUM_FLOW_STATS); - last_i += NUM_FLOW_STATS; - } - } - - if (mlx4_is_slave(dev)) - bitmap_set(stats_bitmap, last_i, NUM_VF_STATS); - last_i += NUM_VF_STATS; - - if (mlx4_is_master(dev)) - bitmap_set(stats_bitmap, last_i, NUM_VPORT_STATS); - last_i += NUM_VPORT_STATS; - - bitmap_set(stats_bitmap, last_i, NUM_PORT_STATS); -} -EXPORT_SYMBOL(mlx4_set_stats_bitmap); - -int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, found_ix = -1; - int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; - - if (!mlx4_is_mfunc(dev)) - return -EINVAL; - - for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { - if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) { - found_ix = i; - break; - } - } - - if (found_ix >= 0) { - if (found_ix < MLX4_ROCE_PF_GIDS) - *slave_id = 0; - else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % dev->num_vfs) * - (vf_gids / dev->num_vfs + 1)) - *slave_id = ((found_ix - MLX4_ROCE_PF_GIDS) / - (vf_gids / dev->num_vfs + 1)) + 1; - else - *slave_id = - ((found_ix - MLX4_ROCE_PF_GIDS - - ((vf_gids % dev->num_vfs) * ((vf_gids / dev->num_vfs + 1)))) / - (vf_gids / dev->num_vfs)) + vf_gids % dev->num_vfs + 1; - } - - return (found_ix >= 0) ? 0 : -EINVAL; -} -EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); - -int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - if (!mlx4_is_master(dev)) - return -EINVAL; - - memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16); - return 0; -} -EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); - -/* Cable Module Info */ -#define MODULE_INFO_MAX_READ 48 - -#define I2C_ADDR_LOW 0x50 -#define I2C_ADDR_HIGH 0x51 -#define I2C_PAGE_SIZE 256 - -/* Module Info Data */ -struct mlx4_cable_info { - u8 i2c_addr; - u8 page_num; - __be16 dev_mem_address; - __be16 reserved1; - __be16 size; - __be32 reserved2[2]; - u8 data[MODULE_INFO_MAX_READ]; -}; - -enum cable_info_err { - CABLE_INF_INV_PORT = 0x1, - CABLE_INF_OP_NOSUP = 0x2, - CABLE_INF_NOT_CONN = 0x3, - CABLE_INF_NO_EEPRM = 0x4, - CABLE_INF_PAGE_ERR = 0x5, - CABLE_INF_INV_ADDR = 0x6, - CABLE_INF_I2C_ADDR = 0x7, - CABLE_INF_QSFP_VIO = 0x8, - CABLE_INF_I2C_BUSY = 0x9, -}; - -#define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) - -#ifdef DEBUG -static inline const char *cable_info_mad_err_str(u16 mad_status) -{ - u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); - - switch (err) { - case CABLE_INF_INV_PORT: - return "invalid port selected"; - case CABLE_INF_OP_NOSUP: - return "operation not supported for this port (the port is of type CX4 or internal)"; - case CABLE_INF_NOT_CONN: - return "cable is not connected"; - case CABLE_INF_NO_EEPRM: - return "the connected cable has no EPROM (passive copper cable)"; - case CABLE_INF_PAGE_ERR: - return "page number is greater than 15"; - case CABLE_INF_INV_ADDR: - return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; - case CABLE_INF_I2C_ADDR: - return "invalid I2C slave address"; - case CABLE_INF_QSFP_VIO: - return "at least one cable violates the QSFP specification and ignores the modsel signal"; - case CABLE_INF_I2C_BUSY: - return "I2C bus is constantly busy"; - } - return "Unknown Error"; -} -#endif /* DEBUG */ - -/** - * mlx4_get_module_info - Read cable module eeprom data - * @dev: mlx4_dev. - * @port: port number. - * @offset: byte offset in eeprom to start reading data from. - * @size: num of bytes to read. - * @data: output buffer to put the requested data into. - * - * Reads cable module eeprom data, puts the outcome data into - * data pointer paramer. - * Returns num of read bytes on success or a negative error - * code. - */ -int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, u16 offset, - u16 size, u8 *data) -{ - struct mlx4_cmd_mailbox *inbox, *outbox; - struct mlx4_mad_ifc *inmad, *outmad; - struct mlx4_cable_info *cable_info; - u16 i2c_addr; - int ret; - - if (size > MODULE_INFO_MAX_READ) - size = MODULE_INFO_MAX_READ; - - inbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(inbox)) { - mlx4_err(dev, - "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(inbox)); - return PTR_ERR(inbox); - } - - outbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(outbox)) { - mlx4_free_cmd_mailbox(dev, inbox); - mlx4_err(dev, - "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(outbox)); - return PTR_ERR(outbox); - } - - inmad = (struct mlx4_mad_ifc *)(inbox->buf); - outmad = (struct mlx4_mad_ifc *)(outbox->buf); - - inmad->method = 0x1; /* Get */ - inmad->class_version = 0x1; - inmad->mgmt_class = 0x1; - inmad->base_version = 0x1; - inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ - - if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) - /* Cross pages reads are not allowed - * read until offset 256 in low page - */ - size -= offset + size - I2C_PAGE_SIZE; - - i2c_addr = I2C_ADDR_LOW; - if (offset >= I2C_PAGE_SIZE) { - /* Reset offset to high page */ - i2c_addr = I2C_ADDR_HIGH; - offset -= I2C_PAGE_SIZE; - } - - cable_info = (struct mlx4_cable_info *)inmad->data; - cable_info->dev_mem_address = cpu_to_be16(offset); - cable_info->page_num = 0; - cable_info->i2c_addr = i2c_addr; - cable_info->size = cpu_to_be16(size); - - ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (ret) - goto out; - - if (be16_to_cpu(outmad->status)) { - /* Mad returned with bad status */ - ret = be16_to_cpu(outmad->status); -#ifdef DEBUG - mlx4_warn(dev, "MLX4_CMD_MAD_IFC Get Module info attr(%x) " - "port(%d) i2c_addr(%x) offset(%d) size(%d): Response " - "Mad Status(%x) - %s\n", 0xFF60, port, i2c_addr, offset, - size, ret, cable_info_mad_err_str(ret)); -#endif - if (i2c_addr == I2C_ADDR_HIGH && - MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) - /* Some SFP cables do not support i2c slave - * address 0x51 (high page), abort silently. - */ - ret = 0; - else - ret = -ret; - goto out; - } - cable_info = (struct mlx4_cable_info *)outmad->data; - memcpy(data, cable_info->data, size); - ret = size; -out: - mlx4_free_cmd_mailbox(dev, inbox); - mlx4_free_cmd_mailbox(dev, outbox); - return ret; -} -EXPORT_SYMBOL(mlx4_get_module_info); diff --git a/sys/ofed/drivers/net/mlx4/profile.c b/sys/ofed/drivers/net/mlx4/profile.c deleted file mode 100644 index aa5f957feccd..000000000000 --- a/sys/ofed/drivers/net/mlx4/profile.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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/slab.h> - -#include "mlx4.h" -#include "fw.h" - -enum { - MLX4_RES_QP, - MLX4_RES_RDMARC, - MLX4_RES_ALTC, - MLX4_RES_AUXC, - MLX4_RES_SRQ, - MLX4_RES_CQ, - MLX4_RES_EQ, - MLX4_RES_DMPT, - MLX4_RES_CMPT, - MLX4_RES_MTT, - MLX4_RES_MCG, - MLX4_RES_NUM -}; - -static const char *res_name[] = { - [MLX4_RES_QP] = "QP", - [MLX4_RES_RDMARC] = "RDMARC", - [MLX4_RES_ALTC] = "ALTC", - [MLX4_RES_AUXC] = "AUXC", - [MLX4_RES_SRQ] = "SRQ", - [MLX4_RES_CQ] = "CQ", - [MLX4_RES_EQ] = "EQ", - [MLX4_RES_DMPT] = "DMPT", - [MLX4_RES_CMPT] = "CMPT", - [MLX4_RES_MTT] = "MTT", - [MLX4_RES_MCG] = "MCG", -}; - -u64 mlx4_make_profile(struct mlx4_dev *dev, - struct mlx4_profile *request, - struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *init_hca) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource { - u64 size; - u64 start; - int type; - u64 num; - int log_num; - }; - - u64 total_size = 0; - struct mlx4_resource *profile; - struct mlx4_resource tmp; - int i, j; - - profile = kcalloc(MLX4_RES_NUM, sizeof(*profile), GFP_KERNEL); - if (!profile) - return -ENOMEM; - - profile[MLX4_RES_QP].size = dev_cap->qpc_entry_sz; - profile[MLX4_RES_RDMARC].size = dev_cap->rdmarc_entry_sz; - profile[MLX4_RES_ALTC].size = dev_cap->altc_entry_sz; - profile[MLX4_RES_AUXC].size = dev_cap->aux_entry_sz; - profile[MLX4_RES_SRQ].size = dev_cap->srq_entry_sz; - profile[MLX4_RES_CQ].size = dev_cap->cqc_entry_sz; - profile[MLX4_RES_EQ].size = dev_cap->eqc_entry_sz; - profile[MLX4_RES_DMPT].size = dev_cap->dmpt_entry_sz; - profile[MLX4_RES_CMPT].size = dev_cap->cmpt_entry_sz; - profile[MLX4_RES_MTT].size = dev_cap->mtt_entry_sz; - profile[MLX4_RES_MCG].size = mlx4_get_mgm_entry_size(dev); - - profile[MLX4_RES_QP].num = request->num_qp; - profile[MLX4_RES_RDMARC].num = request->num_qp * request->rdmarc_per_qp; - profile[MLX4_RES_ALTC].num = request->num_qp; - profile[MLX4_RES_AUXC].num = request->num_qp; - profile[MLX4_RES_SRQ].num = request->num_srq; - profile[MLX4_RES_CQ].num = request->num_cq; - profile[MLX4_RES_EQ].num = mlx4_is_mfunc(dev) ? - dev->phys_caps.num_phys_eqs : - min_t(unsigned, dev_cap->max_eqs, MAX_MSIX); - profile[MLX4_RES_DMPT].num = request->num_mpt; - profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; - profile[MLX4_RES_MTT].num = ((u64)request->num_mtt_segs) * - (1 << log_mtts_per_seg); - profile[MLX4_RES_MCG].num = request->num_mcg; - - for (i = 0; i < MLX4_RES_NUM; ++i) { - profile[i].type = i; - profile[i].num = roundup_pow_of_two(profile[i].num); - profile[i].log_num = ilog2(profile[i].num); - profile[i].size *= profile[i].num; - profile[i].size = max(profile[i].size, (u64) PAGE_SIZE); - } - - /* - * Sort the resources in decreasing order of size. Since they - * all have sizes that are powers of 2, we'll be able to keep - * resources aligned to their size and pack them without gaps - * using the sorted order. - */ - for (i = MLX4_RES_NUM; i > 0; --i) - for (j = 1; j < i; ++j) { - if (profile[j].size > profile[j - 1].size) { - tmp = profile[j]; - profile[j] = profile[j - 1]; - profile[j - 1] = tmp; - } - } - - for (i = 0; i < MLX4_RES_NUM; ++i) { - if (profile[i].size) { - profile[i].start = total_size; - total_size += profile[i].size; - } - - if (total_size > dev_cap->max_icm_sz) { - mlx4_err(dev, "Profile requires 0x%llx bytes; " - "won't fit in 0x%llx bytes of context memory.\n", - (unsigned long long) total_size, - (unsigned long long) dev_cap->max_icm_sz); - kfree(profile); - return -ENOMEM; - } - - if (profile[i].size) - mlx4_dbg(dev, " profile[%2d] (%6s): 2^%02d entries @ 0x%10llx, " - "size 0x%10llx\n", - i, res_name[profile[i].type], profile[i].log_num, - (unsigned long long) profile[i].start, - (unsigned long long) profile[i].size); - } - - mlx4_dbg(dev, "HCA context memory: reserving %d KB\n", - (int) (total_size >> 10)); - - for (i = 0; i < MLX4_RES_NUM; ++i) { - switch (profile[i].type) { - case MLX4_RES_QP: - dev->caps.num_qps = profile[i].num; - init_hca->qpc_base = profile[i].start; - init_hca->log_num_qps = profile[i].log_num; - break; - case MLX4_RES_RDMARC: - for (priv->qp_table.rdmarc_shift = 0; - request->num_qp << priv->qp_table.rdmarc_shift < profile[i].num; - ++priv->qp_table.rdmarc_shift) - ; /* nothing */ - dev->caps.max_qp_dest_rdma = 1 << priv->qp_table.rdmarc_shift; - priv->qp_table.rdmarc_base = (u32) profile[i].start; - init_hca->rdmarc_base = profile[i].start; - init_hca->log_rd_per_qp = priv->qp_table.rdmarc_shift; - break; - case MLX4_RES_ALTC: - init_hca->altc_base = profile[i].start; - break; - case MLX4_RES_AUXC: - init_hca->auxc_base = profile[i].start; - break; - case MLX4_RES_SRQ: - dev->caps.num_srqs = profile[i].num; - init_hca->srqc_base = profile[i].start; - init_hca->log_num_srqs = profile[i].log_num; - break; - case MLX4_RES_CQ: - dev->caps.num_cqs = profile[i].num; - init_hca->cqc_base = profile[i].start; - init_hca->log_num_cqs = profile[i].log_num; - break; - case MLX4_RES_EQ: - dev->caps.num_eqs = roundup_pow_of_two(min_t(unsigned, dev_cap->max_eqs, - MAX_MSIX)); - init_hca->eqc_base = profile[i].start; - init_hca->log_num_eqs = ilog2(dev->caps.num_eqs); - break; - case MLX4_RES_DMPT: - dev->caps.num_mpts = profile[i].num; - priv->mr_table.mpt_base = profile[i].start; - init_hca->dmpt_base = profile[i].start; - init_hca->log_mpt_sz = profile[i].log_num; - break; - case MLX4_RES_CMPT: - init_hca->cmpt_base = profile[i].start; - break; - case MLX4_RES_MTT: - dev->caps.num_mtts = profile[i].num; - priv->mr_table.mtt_base = profile[i].start; - init_hca->mtt_base = profile[i].start; - break; - case MLX4_RES_MCG: - init_hca->mc_base = profile[i].start; - init_hca->log_mc_entry_sz = - ilog2(mlx4_get_mgm_entry_size(dev)); - init_hca->log_mc_table_sz = profile[i].log_num; - if (dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - dev->caps.num_mgms = profile[i].num; - } else { - init_hca->log_mc_hash_sz = - profile[i].log_num - 1; - dev->caps.num_mgms = profile[i].num >> 1; - dev->caps.num_amgms = profile[i].num >> 1; - } - break; - default: - break; - } - } - - /* - * PDs don't take any HCA memory, but we assign them as part - * of the HCA profile anyway. - */ - dev->caps.num_pds = MLX4_NUM_PDS; - - kfree(profile); - return total_size; -} diff --git a/sys/ofed/drivers/net/mlx4/qp.c b/sys/ofed/drivers/net/mlx4/qp.c deleted file mode 100644 index fe8d3c2de07f..000000000000 --- a/sys/ofed/drivers/net/mlx4/qp.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright (c) 2004 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved. - * Copyright (c) 2004 Voltaire, Inc. 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/types.h> -#include <linux/gfp.h> -#include <linux/module.h> - -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/qp.h> - -#include "mlx4.h" -#include "icm.h" - -/* - * QP to support BF should have bits 6,7 cleared - */ -#define MLX4_BF_QP_SKIP_MASK 0xc0 -#define MLX4_MAX_BF_QP_RANGE 0x40 - -void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) -{ - struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; - struct mlx4_qp *qp; - - spin_lock(&qp_table->lock); - - qp = __mlx4_qp_lookup(dev, qpn); - if (qp) - atomic_inc(&qp->refcount); - - spin_unlock(&qp_table->lock); - - if (!qp) { - mlx4_dbg(dev, "Async event for none existent QP %08x\n", qpn); - return; - } - - qp->event(qp, event_type); - - if (atomic_dec_and_test(&qp->refcount)) - complete(&qp->free); -} - -/* used for INIT/CLOSE port logic */ -static int is_master_qp0(struct mlx4_dev *dev, struct mlx4_qp *qp, int *real_qp0, int *proxy_qp0) -{ - /* this procedure is called after we already know we are on the master */ - /* qp0 is either the proxy qp0, or the real qp0 */ - u32 pf_proxy_offset = dev->phys_caps.base_proxy_sqpn + 8 * mlx4_master_func_num(dev); - *proxy_qp0 = qp->qpn >= pf_proxy_offset && qp->qpn <= pf_proxy_offset + 1; - - *real_qp0 = qp->qpn >= dev->phys_caps.base_sqpn && - qp->qpn <= dev->phys_caps.base_sqpn + 1; - - return *real_qp0 || *proxy_qp0; -} - -static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, - struct mlx4_qp_context *context, - enum mlx4_qp_optpar optpar, - int sqd_event, struct mlx4_qp *qp, int native) -{ - static const u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE] = { - [MLX4_QP_STATE_RST] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_INIT] = MLX4_CMD_RST2INIT_QP, - }, - [MLX4_QP_STATE_INIT] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_INIT] = MLX4_CMD_INIT2INIT_QP, - [MLX4_QP_STATE_RTR] = MLX4_CMD_INIT2RTR_QP, - }, - [MLX4_QP_STATE_RTR] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_RTR2RTS_QP, - }, - [MLX4_QP_STATE_RTS] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_RTS2RTS_QP, - [MLX4_QP_STATE_SQD] = MLX4_CMD_RTS2SQD_QP, - }, - [MLX4_QP_STATE_SQD] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_SQD2RTS_QP, - [MLX4_QP_STATE_SQD] = MLX4_CMD_SQD2SQD_QP, - }, - [MLX4_QP_STATE_SQER] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - [MLX4_QP_STATE_RTS] = MLX4_CMD_SQERR2RTS_QP, - }, - [MLX4_QP_STATE_ERR] = { - [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, - [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, - } - }; - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; - int ret = 0; - int real_qp0 = 0; - int proxy_qp0 = 0; - u8 port; - - if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE || - !op[cur_state][new_state]) - return -EINVAL; - - if (op[cur_state][new_state] == MLX4_CMD_2RST_QP) { - ret = mlx4_cmd(dev, 0, qp->qpn, 2, - MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A, native); - if (mlx4_is_master(dev) && cur_state != MLX4_QP_STATE_ERR && - cur_state != MLX4_QP_STATE_RST && - is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) { - port = (qp->qpn & 1) + 1; - if (proxy_qp0) - priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0; - else - priv->mfunc.master.qp0_state[port].qp0_active = 0; - } - return ret; - } - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) { - u64 mtt_addr = mlx4_mtt_addr(dev, mtt); - context->mtt_base_addr_h = mtt_addr >> 32; - context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; - } - - *(__be32 *) mailbox->buf = cpu_to_be32(optpar); - memcpy(mailbox->buf + 8, context, sizeof *context); - - ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn = - cpu_to_be32(qp->qpn); - - ret = mlx4_cmd(dev, mailbox->dma, - qp->qpn | (!!sqd_event << 31), - new_state == MLX4_QP_STATE_RST ? 2 : 0, - op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C, native); - - if (mlx4_is_master(dev) && is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) { - port = (qp->qpn & 1) + 1; - if (cur_state != MLX4_QP_STATE_ERR && - cur_state != MLX4_QP_STATE_RST && - new_state == MLX4_QP_STATE_ERR) { - if (proxy_qp0) - priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0; - else - priv->mfunc.master.qp0_state[port].qp0_active = 0; - } else if (new_state == MLX4_QP_STATE_RTR) { - if (proxy_qp0) - priv->mfunc.master.qp0_state[port].proxy_qp0_active = 1; - else - priv->mfunc.master.qp0_state[port].qp0_active = 1; - } - } - - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; -} - -int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, - struct mlx4_qp_context *context, - enum mlx4_qp_optpar optpar, - int sqd_event, struct mlx4_qp *qp) -{ - return __mlx4_qp_modify(dev, mtt, cur_state, new_state, context, - optpar, sqd_event, qp, 0); -} -EXPORT_SYMBOL_GPL(mlx4_qp_modify); - -int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, - int *base, u8 flags) -{ - int bf_qp = !!(flags & (u8) MLX4_RESERVE_BF_QP); - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - - /* Only IPoIB uses a large cnt. In this case, just allocate - * as usual, ignoring bf skipping, since IPoIB does not run over RoCE - */ - if (cnt > MLX4_MAX_BF_QP_RANGE && bf_qp) - bf_qp = 0; - - *base = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align, - bf_qp ? MLX4_BF_QP_SKIP_MASK : 0); - if (*base == -1) - return -ENOMEM; - - return 0; -} - -int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, - int *base, u8 flags) -{ - u64 in_param = 0; - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, (((u32) flags) << 24) | (u32) cnt); - set_param_h(&in_param, align); - err = mlx4_cmd_imm(dev, in_param, &out_param, - RES_QP, RES_OP_RESERVE, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) - return err; - - *base = get_param_l(&out_param); - return 0; - } - return __mlx4_qp_reserve_range(dev, cnt, align, base, flags); -} -EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range); - -void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - - if (mlx4_is_qp_reserved(dev, (u32) base_qpn)) - return; - mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, MLX4_USE_RR); -} - -void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) -{ - u64 in_param = 0; - int err; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, base_qpn); - set_param_h(&in_param, cnt); - err = mlx4_cmd(dev, in_param, RES_QP, RES_OP_RESERVE, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (err) { - mlx4_warn(dev, "Failed to release qp range" - " base:%d cnt:%d\n", base_qpn, cnt); - } - } else - __mlx4_qp_release_range(dev, base_qpn, cnt); -} -EXPORT_SYMBOL_GPL(mlx4_qp_release_range); - -int __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - int err; - - err = mlx4_table_get(dev, &qp_table->qp_table, qpn); - if (err) - goto err_out; - - err = mlx4_table_get(dev, &qp_table->auxc_table, qpn); - if (err) - goto err_put_qp; - - err = mlx4_table_get(dev, &qp_table->altc_table, qpn); - if (err) - goto err_put_auxc; - - err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn); - if (err) - goto err_put_altc; - - err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn); - if (err) - goto err_put_rdmarc; - - return 0; - -err_put_rdmarc: - mlx4_table_put(dev, &qp_table->rdmarc_table, qpn); - -err_put_altc: - mlx4_table_put(dev, &qp_table->altc_table, qpn); - -err_put_auxc: - mlx4_table_put(dev, &qp_table->auxc_table, qpn); - -err_put_qp: - mlx4_table_put(dev, &qp_table->qp_table, qpn); - -err_out: - return err; -} - -static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) -{ - u64 param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(¶m, qpn); - return mlx4_cmd_imm(dev, param, ¶m, RES_QP, RES_OP_MAP_ICM, - MLX4_CMD_ALLOC_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - } - return __mlx4_qp_alloc_icm(dev, qpn); -} - -void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - - mlx4_table_put(dev, &qp_table->cmpt_table, qpn); - mlx4_table_put(dev, &qp_table->rdmarc_table, qpn); - mlx4_table_put(dev, &qp_table->altc_table, qpn); - mlx4_table_put(dev, &qp_table->auxc_table, qpn); - mlx4_table_put(dev, &qp_table->qp_table, qpn); -} - -static void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, qpn); - if (mlx4_cmd(dev, in_param, RES_QP, RES_OP_MAP_ICM, - MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed to free icm of qp:%d\n", qpn); - } else - __mlx4_qp_free_icm(dev, qpn); -} - -int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_qp_table *qp_table = &priv->qp_table; - int err; - - if (!qpn) - return -EINVAL; - - qp->qpn = qpn; - - err = mlx4_qp_alloc_icm(dev, qpn); - if (err) - return err; - - spin_lock_irq(&qp_table->lock); - err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & - (dev->caps.num_qps - 1), qp); - spin_unlock_irq(&qp_table->lock); - if (err) - goto err_icm; - - atomic_set(&qp->refcount, 1); - init_completion(&qp->free); - - return 0; - -err_icm: - mlx4_qp_free_icm(dev, qpn); - return err; -} - -EXPORT_SYMBOL_GPL(mlx4_qp_alloc); - -void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp) -{ - struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; - unsigned long flags; - - spin_lock_irqsave(&qp_table->lock, flags); - radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1)); - spin_unlock_irqrestore(&qp_table->lock, flags); -} -EXPORT_SYMBOL_GPL(mlx4_qp_remove); - -void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) -{ - if (atomic_dec_and_test(&qp->refcount)) - complete(&qp->free); - wait_for_completion(&qp->free); - - mlx4_qp_free_icm(dev, qp->qpn); -} -EXPORT_SYMBOL_GPL(mlx4_qp_free); - -static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) -{ - return mlx4_cmd(dev, 0, base_qpn, 0, MLX4_CMD_CONF_SPECIAL_QP, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); -} - -int mlx4_init_qp_table(struct mlx4_dev *dev) -{ - struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; - int err; - int reserved_from_top = 0; - int reserved_from_bot; - int k; - - spin_lock_init(&qp_table->lock); - INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC); - if (mlx4_is_slave(dev)) - return 0; - - /* - * We reserve 2 extra QPs per port for the special QPs. The - * block of special QPs must be aligned to a multiple of 8, so - * round up. - * - * We also reserve the MSB of the 24-bit QP number to indicate - * that a QP is an XRC QP. - */ - dev->phys_caps.base_sqpn = - ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8); - - { - int sort[MLX4_NUM_QP_REGION]; - int i, j, tmp; - int last_base = dev->caps.num_qps; - - for (i = 1; i < MLX4_NUM_QP_REGION; ++i) - sort[i] = i; - - for (i = MLX4_NUM_QP_REGION; i > 0; --i) { - for (j = 2; j < i; ++j) { - if (dev->caps.reserved_qps_cnt[sort[j]] > - dev->caps.reserved_qps_cnt[sort[j - 1]]) { - tmp = sort[j]; - sort[j] = sort[j - 1]; - sort[j - 1] = tmp; - } - } - } - - for (i = 1; i < MLX4_NUM_QP_REGION; ++i) { - last_base -= dev->caps.reserved_qps_cnt[sort[i]]; - dev->caps.reserved_qps_base[sort[i]] = last_base; - reserved_from_top += - dev->caps.reserved_qps_cnt[sort[i]]; - } - - } - - /* Reserve 8 real SQPs in both native and SRIOV modes. - * In addition, in SRIOV mode, reserve 8 proxy SQPs per function - * (for all PFs and VFs), and 8 corresponding tunnel QPs. - * Each proxy SQP works opposite its own tunnel QP. - * - * The QPs are arranged as follows: - * a. 8 real SQPs - * b. All the proxy SQPs (8 per function) - * c. All the tunnel QPs (8 per function) - */ - reserved_from_bot = mlx4_num_reserved_sqps(dev); - if (reserved_from_bot + reserved_from_top > dev->caps.num_qps) { - mlx4_err(dev, "Number of reserved QPs is higher than number " - "of QPs, increase the value of log_num_qp\n"); - return -EINVAL; - } - - err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps, - (1 << 23) - 1, reserved_from_bot, - reserved_from_top); - if (err) - return err; - - if (mlx4_is_mfunc(dev)) { - /* for PPF use */ - dev->phys_caps.base_proxy_sqpn = dev->phys_caps.base_sqpn + 8; - dev->phys_caps.base_tunnel_sqpn = dev->phys_caps.base_sqpn + 8 + 8 * MLX4_MFUNC_MAX; - - /* In mfunc, calculate proxy and tunnel qp offsets for the PF here, - * since the PF does not call mlx4_slave_caps */ - dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof (u32), GFP_KERNEL); - - if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy || - !dev->caps.qp1_tunnel || !dev->caps.qp1_proxy) { - err = -ENOMEM; - goto err_mem; - } - - for (k = 0; k < dev->caps.num_ports; k++) { - dev->caps.qp0_proxy[k] = dev->phys_caps.base_proxy_sqpn + - 8 * mlx4_master_func_num(dev) + k; - dev->caps.qp0_tunnel[k] = dev->caps.qp0_proxy[k] + 8 * MLX4_MFUNC_MAX; - dev->caps.qp1_proxy[k] = dev->phys_caps.base_proxy_sqpn + - 8 * mlx4_master_func_num(dev) + MLX4_MAX_PORTS + k; - dev->caps.qp1_tunnel[k] = dev->caps.qp1_proxy[k] + 8 * MLX4_MFUNC_MAX; - } - } - - - err = mlx4_CONF_SPECIAL_QP(dev, dev->phys_caps.base_sqpn); - if (err) - goto err_mem; - return 0; - -err_mem: - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - dev->caps.qp0_tunnel = dev->caps.qp0_proxy = - dev->caps.qp1_tunnel = dev->caps.qp1_proxy = NULL; - return err; -} - -void mlx4_cleanup_qp_table(struct mlx4_dev *dev) -{ - if (mlx4_is_slave(dev)) - return; - - mlx4_CONF_SPECIAL_QP(dev, 0); - mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap); -} - -int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, - struct mlx4_qp_context *context) -{ - struct mlx4_cmd_mailbox *mailbox; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - err = mlx4_cmd_box(dev, 0, mailbox->dma, qp->qpn, 0, - MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); - if (!err) - memcpy(context, mailbox->buf + 8, sizeof *context); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_qp_query); - -int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - struct mlx4_qp_context *context, - struct mlx4_qp *qp, enum mlx4_qp_state *qp_state) -{ - int err; - int i; - enum mlx4_qp_state states[] = { - MLX4_QP_STATE_RST, - MLX4_QP_STATE_INIT, - MLX4_QP_STATE_RTR, - MLX4_QP_STATE_RTS - }; - - for (i = 0; i < ARRAY_SIZE(states) - 1; i++) { - context->flags &= cpu_to_be32(~(0xf << 28)); - context->flags |= cpu_to_be32(states[i + 1] << 28); - err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1], - context, 0, 0, qp); - if (err) { - mlx4_err(dev, "Failed to bring QP to state: " - "%d with error: %d\n", - states[i + 1], err); - return err; - } - - *qp_state = states[i + 1]; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mlx4_qp_to_ready); diff --git a/sys/ofed/drivers/net/mlx4/reset.c b/sys/ofed/drivers/net/mlx4/reset.c deleted file mode 100644 index 44ec1e12b898..000000000000 --- a/sys/ofed/drivers/net/mlx4/reset.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 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/errno.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/jiffies.h> - -#include "mlx4.h" - -int mlx4_reset(struct mlx4_dev *dev) -{ - void __iomem *reset; - u32 *hca_header = NULL; - int pcie_cap; - u16 devctl; - u16 linkctl; - u16 vendor; - unsigned long end; - u32 sem; - int i; - int err = 0; - -#define MLX4_RESET_BASE 0xf0000 -#define MLX4_RESET_SIZE 0x400 -#define MLX4_SEM_OFFSET 0x3fc -#define MLX4_RESET_OFFSET 0x10 -#define MLX4_RESET_VALUE swab32(1) - -#define MLX4_SEM_TIMEOUT_JIFFIES (10 * HZ) -#define MLX4_RESET_TIMEOUT_JIFFIES (2 * HZ) - - /* - * Reset the chip. This is somewhat ugly because we have to - * save off the PCI header before reset and then restore it - * after the chip reboots. We skip config space offsets 22 - * and 23 since those have a special meaning. - */ - - /* Do we need to save off the full 4K PCI Express header?? */ - hca_header = kmalloc(256, GFP_KERNEL); - if (!hca_header) { - err = -ENOMEM; - mlx4_err(dev, "Couldn't allocate memory to save HCA " - "PCI header, aborting.\n"); - goto out; - } - - pcie_cap = pci_pcie_cap(dev->pdev); - - for (i = 0; i < 64; ++i) { - if (i == 22 || i == 23) - continue; - if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) { - err = -ENODEV; - mlx4_err(dev, "Couldn't save HCA " - "PCI header, aborting.\n"); - goto out; - } - } - - reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE, - MLX4_RESET_SIZE); - if (!reset) { - err = -ENOMEM; - mlx4_err(dev, "Couldn't map HCA reset register, aborting.\n"); - goto out; - } - - /* grab HW semaphore to lock out flash updates */ - end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES; - do { - sem = readl(reset + MLX4_SEM_OFFSET); - if (!sem) - break; - - msleep(1); - } while (time_before(jiffies, end)); - - if (sem) { - mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n"); - err = -EAGAIN; - iounmap(reset); - goto out; - } - - /* actually hit reset */ - writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET); - iounmap(reset); - - /* wait half a second before accessing device */ - msleep(500); - - end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES; - do { - if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) && - vendor != 0xffff) - break; - - msleep(1); - } while (time_before(jiffies, end)); - - if (vendor == 0xffff) { - err = -ENODEV; - mlx4_err(dev, "PCI device did not come back after reset, " - "aborting.\n"); - goto out; - } - - /* Now restore the PCI headers */ - if (pcie_cap) { - devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_DEVCTL, - devctl)) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA PCI Express " - "Device Control register, aborting.\n"); - goto out; - } - linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_LNKCTL, - linkctl)) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA PCI Express " - "Link control register, aborting.\n"); - goto out; - } - } - - for (i = 0; i < 16; ++i) { - if (i * 4 == PCI_COMMAND) - continue; - - if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA reg %x, " - "aborting.\n", i); - goto out; - } - } - - if (pci_write_config_dword(dev->pdev, PCI_COMMAND, - hca_header[PCI_COMMAND / 4])) { - err = -ENODEV; - mlx4_err(dev, "Couldn't restore HCA COMMAND, " - "aborting.\n"); - goto out; - } - -out: - kfree(hca_header); - - return err; -} diff --git a/sys/ofed/drivers/net/mlx4/resource_tracker.c b/sys/ofed/drivers/net/mlx4/resource_tracker.c deleted file mode 100644 index 1bdab675ad1e..000000000000 --- a/sys/ofed/drivers/net/mlx4/resource_tracker.c +++ /dev/null @@ -1,4686 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. - * All rights reserved. - * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. 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/sched.h> -#include <linux/pci.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/mlx4/cmd.h> -#include <linux/mlx4/qp.h> -#include <linux/if_ether.h> -#include <linux/etherdevice.h> - -#include "mlx4.h" -#include "fw.h" - -#define MLX4_MAC_VALID (1ull << 63) - -struct mac_res { - struct list_head list; - u64 mac; - int ref_count; - u8 smac_index; - u8 port; -}; - -struct vlan_res { - struct list_head list; - u16 vlan; - int ref_count; - int vlan_index; - u8 port; -}; - -struct res_common { - struct list_head list; - struct rb_node node; - u64 res_id; - int owner; - int state; - int from_state; - int to_state; - int removing; -}; - -enum { - RES_ANY_BUSY = 1 -}; - -struct res_gid { - struct list_head list; - u8 gid[16]; - enum mlx4_protocol prot; - enum mlx4_steer_type steer; - u64 reg_id; -}; - -enum res_qp_states { - RES_QP_BUSY = RES_ANY_BUSY, - - /* QP number was allocated */ - RES_QP_RESERVED, - - /* ICM memory for QP context was mapped */ - RES_QP_MAPPED, - - /* QP is in hw ownership */ - RES_QP_HW -}; - -struct res_qp { - struct res_common com; - struct res_mtt *mtt; - struct res_cq *rcq; - struct res_cq *scq; - struct res_srq *srq; - struct list_head mcg_list; - spinlock_t mcg_spl; - int local_qpn; - atomic_t ref_count; - u32 qpc_flags; - /* saved qp params before VST enforcement in order to restore on VGT */ - u8 sched_queue; - __be32 param3; - u8 vlan_control; - u8 fvl_rx; - u8 pri_path_fl; - u8 vlan_index; - u8 feup; -}; - -enum res_mtt_states { - RES_MTT_BUSY = RES_ANY_BUSY, - RES_MTT_ALLOCATED, -}; - -static inline const char *mtt_states_str(enum res_mtt_states state) -{ - switch (state) { - case RES_MTT_BUSY: return "RES_MTT_BUSY"; - case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED"; - default: return "Unknown"; - } -} - -struct res_mtt { - struct res_common com; - int order; - atomic_t ref_count; -}; - -enum res_mpt_states { - RES_MPT_BUSY = RES_ANY_BUSY, - RES_MPT_RESERVED, - RES_MPT_MAPPED, - RES_MPT_HW, -}; - -struct res_mpt { - struct res_common com; - struct res_mtt *mtt; - int key; -}; - -enum res_eq_states { - RES_EQ_BUSY = RES_ANY_BUSY, - RES_EQ_RESERVED, - RES_EQ_HW, -}; - -struct res_eq { - struct res_common com; - struct res_mtt *mtt; -}; - -enum res_cq_states { - RES_CQ_BUSY = RES_ANY_BUSY, - RES_CQ_ALLOCATED, - RES_CQ_HW, -}; - -struct res_cq { - struct res_common com; - struct res_mtt *mtt; - atomic_t ref_count; -}; - -enum res_srq_states { - RES_SRQ_BUSY = RES_ANY_BUSY, - RES_SRQ_ALLOCATED, - RES_SRQ_HW, -}; - -struct res_srq { - struct res_common com; - struct res_mtt *mtt; - struct res_cq *cq; - atomic_t ref_count; -}; - -enum res_counter_states { - RES_COUNTER_BUSY = RES_ANY_BUSY, - RES_COUNTER_ALLOCATED, -}; - -struct res_counter { - struct res_common com; - int port; -}; - -enum res_xrcdn_states { - RES_XRCD_BUSY = RES_ANY_BUSY, - RES_XRCD_ALLOCATED, -}; - -struct res_xrcdn { - struct res_common com; - int port; -}; - -enum res_fs_rule_states { - RES_FS_RULE_BUSY = RES_ANY_BUSY, - RES_FS_RULE_ALLOCATED, -}; - -struct res_fs_rule { - struct res_common com; - int qpn; -}; - -static int mlx4_is_eth(struct mlx4_dev *dev, int port) -{ - return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1; -} - -static void *res_tracker_lookup(struct rb_root *root, u64 res_id) -{ - struct rb_node *node = root->rb_node; - - while (node) { - struct res_common *res = container_of(node, struct res_common, - node); - - if (res_id < res->res_id) - node = node->rb_left; - else if (res_id > res->res_id) - node = node->rb_right; - else - return res; - } - return NULL; -} - -static int res_tracker_insert(struct rb_root *root, struct res_common *res) -{ - struct rb_node **new = &(root->rb_node), *parent = NULL; - - /* Figure out where to put new node */ - while (*new) { - struct res_common *this = container_of(*new, struct res_common, - node); - - parent = *new; - if (res->res_id < this->res_id) - new = &((*new)->rb_left); - else if (res->res_id > this->res_id) - new = &((*new)->rb_right); - else - return -EEXIST; - } - - /* Add new node and rebalance tree. */ - rb_link_node(&res->node, parent, new); - rb_insert_color(&res->node, root); - - return 0; -} - -enum qp_transition { - QP_TRANS_INIT2RTR, - QP_TRANS_RTR2RTS, - QP_TRANS_RTS2RTS, - QP_TRANS_SQERR2RTS, - QP_TRANS_SQD2SQD, - QP_TRANS_SQD2RTS -}; - -/* For Debug uses */ -static const char *ResourceType(enum mlx4_resource rt) -{ - switch (rt) { - case RES_QP: return "RES_QP"; - case RES_CQ: return "RES_CQ"; - case RES_SRQ: return "RES_SRQ"; - case RES_MPT: return "RES_MPT"; - case RES_MTT: return "RES_MTT"; - case RES_MAC: return "RES_MAC"; - case RES_VLAN: return "RES_VLAN"; - case RES_EQ: return "RES_EQ"; - case RES_COUNTER: return "RES_COUNTER"; - case RES_FS_RULE: return "RES_FS_RULE"; - case RES_XRCD: return "RES_XRCD"; - default: return "Unknown resource type !!!"; - }; -} - -static void rem_slave_vlans(struct mlx4_dev *dev, int slave); -static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, - enum mlx4_resource res_type, int count, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct resource_allocator *res_alloc = - &priv->mfunc.master.res_tracker.res_alloc[res_type]; - int err = -EINVAL; - int allocated, free, reserved, guaranteed, from_free; - - spin_lock(&res_alloc->alloc_lock); - allocated = (port > 0) ? - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : - res_alloc->allocated[slave]; - free = (port > 0) ? res_alloc->res_port_free[port - 1] : - res_alloc->res_free; - reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] : - res_alloc->res_reserved; - guaranteed = res_alloc->guaranteed[slave]; - - if (allocated + count > res_alloc->quota[slave]) - goto out; - - if (allocated + count <= guaranteed) { - err = 0; - } else { - /* portion may need to be obtained from free area */ - if (guaranteed - allocated > 0) - from_free = count - (guaranteed - allocated); - else - from_free = count; - - if (free - from_free > reserved) - err = 0; - } - - if (!err) { - /* grant the request */ - if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count; - res_alloc->res_port_free[port - 1] -= count; - } else { - res_alloc->allocated[slave] += count; - res_alloc->res_free -= count; - } - } - -out: - spin_unlock(&res_alloc->alloc_lock); - return err; - -} - -static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, - enum mlx4_resource res_type, int count, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct resource_allocator *res_alloc = - &priv->mfunc.master.res_tracker.res_alloc[res_type]; - - spin_lock(&res_alloc->alloc_lock); - if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count; - res_alloc->res_port_free[port - 1] += count; - } else { - res_alloc->allocated[slave] -= count; - res_alloc->res_free += count; - } - - spin_unlock(&res_alloc->alloc_lock); - return; -} - -static inline void initialize_res_quotas(struct mlx4_dev *dev, - struct resource_allocator *res_alloc, - enum mlx4_resource res_type, - int vf, int num_instances) -{ - res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1)); - res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; - if (vf == mlx4_master_func_num(dev)) { - res_alloc->res_free = num_instances; - if (res_type == RES_MTT) { - /* reserved mtts will be taken out of the PF allocation */ - res_alloc->res_free += dev->caps.reserved_mtts; - res_alloc->guaranteed[vf] += dev->caps.reserved_mtts; - res_alloc->quota[vf] += dev->caps.reserved_mtts; - } - } -} - -void mlx4_init_quotas(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int pf; - - /* quotas for VFs are initialized in mlx4_slave_cap */ - if (mlx4_is_slave(dev)) - return; - - if (!mlx4_is_mfunc(dev)) { - dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps - - mlx4_num_reserved_sqps(dev); - dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs; - dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs; - dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts; - dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws; - return; - } - - pf = mlx4_master_func_num(dev); - dev->quotas.qp = - priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf]; - dev->quotas.cq = - priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf]; - dev->quotas.srq = - priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf]; - dev->quotas.mtt = - priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf]; - dev->quotas.mpt = - priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf]; -} -int mlx4_init_resource_tracker(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i, j; - int t; - - priv->mfunc.master.res_tracker.slave_list = - kzalloc(dev->num_slaves * sizeof(struct slave_list), - GFP_KERNEL); - if (!priv->mfunc.master.res_tracker.slave_list) - return -ENOMEM; - - for (i = 0 ; i < dev->num_slaves; i++) { - for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t) - INIT_LIST_HEAD(&priv->mfunc.master.res_tracker. - slave_list[i].res_list[t]); - mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex); - } - - mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n", - dev->num_slaves); - for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) - priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT; - - for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { - struct resource_allocator *res_alloc = - &priv->mfunc.master.res_tracker.res_alloc[i]; - res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - if (i == RES_MAC || i == RES_VLAN) - res_alloc->allocated = kzalloc(MLX4_MAX_PORTS * - (dev->num_vfs + 1) * sizeof(int), - GFP_KERNEL); - else - res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - - if (!res_alloc->quota || !res_alloc->guaranteed || - !res_alloc->allocated) - goto no_mem_err; - - spin_lock_init(&res_alloc->alloc_lock); - for (t = 0; t < dev->num_vfs + 1; t++) { - switch (i) { - case RES_QP: - initialize_res_quotas(dev, res_alloc, RES_QP, - t, dev->caps.num_qps - - dev->caps.reserved_qps - - mlx4_num_reserved_sqps(dev)); - break; - case RES_CQ: - initialize_res_quotas(dev, res_alloc, RES_CQ, - t, dev->caps.num_cqs - - dev->caps.reserved_cqs); - break; - case RES_SRQ: - initialize_res_quotas(dev, res_alloc, RES_SRQ, - t, dev->caps.num_srqs - - dev->caps.reserved_srqs); - break; - case RES_MPT: - initialize_res_quotas(dev, res_alloc, RES_MPT, - t, dev->caps.num_mpts - - dev->caps.reserved_mrws); - break; - case RES_MTT: - initialize_res_quotas(dev, res_alloc, RES_MTT, - t, dev->caps.num_mtts - - dev->caps.reserved_mtts); - break; - case RES_MAC: - if (t == mlx4_master_func_num(dev)) { - res_alloc->quota[t] = - MLX4_MAX_MAC_NUM - 2 * dev->num_vfs; - res_alloc->guaranteed[t] = res_alloc->quota[t]; - for (j = 0; j < MLX4_MAX_PORTS; j++) - res_alloc->res_port_free[j] = MLX4_MAX_MAC_NUM; - } else { - res_alloc->quota[t] = 2; - res_alloc->guaranteed[t] = 2; - } - break; - case RES_VLAN: - if (t == mlx4_master_func_num(dev)) { - res_alloc->quota[t] = MLX4_MAX_VLAN_NUM; - res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2; - for (j = 0; j < MLX4_MAX_PORTS; j++) - res_alloc->res_port_free[j] = - res_alloc->quota[t]; - } else { - res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2; - res_alloc->guaranteed[t] = 0; - } - break; - case RES_COUNTER: - res_alloc->quota[t] = dev->caps.max_counters; - res_alloc->guaranteed[t] = 0; - if (t == mlx4_master_func_num(dev)) - res_alloc->res_free = res_alloc->quota[t]; - break; - default: - break; - } - if (i == RES_MAC || i == RES_VLAN) { - for (j = 0; j < MLX4_MAX_PORTS; j++) - res_alloc->res_port_rsvd[j] += - res_alloc->guaranteed[t]; - } else { - res_alloc->res_reserved += res_alloc->guaranteed[t]; - } - } - } - spin_lock_init(&priv->mfunc.master.res_tracker.lock); - return 0; - -no_mem_err: - for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { - kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); - priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); - priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); - priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; - } - return -ENOMEM; -} - -void mlx4_free_resource_tracker(struct mlx4_dev *dev, - enum mlx4_res_tracker_free_type type) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int i; - - if (priv->mfunc.master.res_tracker.slave_list) { - if (type != RES_TR_FREE_STRUCTS_ONLY) { - for (i = 0; i < dev->num_slaves; i++) { - if (type == RES_TR_FREE_ALL || - dev->caps.function != i) - mlx4_delete_all_resources_for_slave(dev, i); - } - /* free master's vlans */ - i = dev->caps.function; - mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); - rem_slave_vlans(dev, i); - mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex); - } - - if (type != RES_TR_FREE_SLAVES_ONLY) { - for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { - kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated); - priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed); - priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL; - kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota); - priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL; - } - kfree(priv->mfunc.master.res_tracker.slave_list); - priv->mfunc.master.res_tracker.slave_list = NULL; - } - } -} - -static void update_pkey_index(struct mlx4_dev *dev, int slave, - struct mlx4_cmd_mailbox *inbox) -{ - u8 sched = *(u8 *)(inbox->buf + 64); - u8 orig_index = *(u8 *)(inbox->buf + 35); - u8 new_index; - struct mlx4_priv *priv = mlx4_priv(dev); - int port; - - port = (sched >> 6 & 1) + 1; - - new_index = priv->virt2phys_pkey[slave][port - 1][orig_index]; - *(u8 *)(inbox->buf + 35) = new_index; -} - -static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, - u8 slave) -{ - struct mlx4_qp_context *qp_ctx = inbox->buf + 8; - enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); - u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; - int port; - - if (MLX4_QP_ST_UD == ts) { - port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port)) - qp_ctx->pri_path.mgid_index = mlx4_get_base_gid_ix(dev, slave) | 0x80; - else - qp_ctx->pri_path.mgid_index = 0x80 | slave; - - } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) { - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { - port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port)) { - qp_ctx->pri_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); - qp_ctx->pri_path.mgid_index &= 0x7f; - } else { - qp_ctx->pri_path.mgid_index = slave & 0x7F; - } - } - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { - port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port)) { - qp_ctx->alt_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); - qp_ctx->alt_path.mgid_index &= 0x7f; - } else { - qp_ctx->alt_path.mgid_index = slave & 0x7F; - } - } - } -} - -static int check_counter_index_validity(struct mlx4_dev *dev, int slave, int port, int idx) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct counter_index *counter, *tmp_counter; - - if (slave == 0) { - list_for_each_entry_safe(counter, tmp_counter, - &priv->counters_table.global_port_list[port - 1], - list) { - if (counter->index == idx) - return 0; - } - return -EINVAL; - } else { - list_for_each_entry_safe(counter, tmp_counter, - &priv->counters_table.vf_list[slave - 1][port - 1], - list) { - if (counter->index == idx) - return 0; - } - return -EINVAL; - } -} - -static int update_vport_qp_param(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *inbox, - u8 slave, u32 qpn) -{ - struct mlx4_qp_context *qpc = inbox->buf + 8; - struct mlx4_vport_oper_state *vp_oper; - struct mlx4_priv *priv; - u32 qp_type; - int port; - - port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; - priv = mlx4_priv(dev); - vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; - qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - - if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && - qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX) { - if (check_counter_index_validity(dev, slave, port, - qpc->pri_path.counter_index)) - return -EINVAL; - } - - mlx4_dbg(dev, "%s: QP counter_index %d for slave %d port %d\n", - __func__, qpc->pri_path.counter_index, slave, port); - - if ((dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK) && - dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH && - !mlx4_is_qp_reserved(dev, qpn) && - qp_type == MLX4_QP_ST_MLX && - qpc->pri_path.counter_index != 0xFF) { - /* disable multicast loopback to qp with same counter */ - qpc->pri_path.fl |= MLX4_FL_ETH_SRC_CHECK_MC_LB; - qpc->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; - } - - if (MLX4_VGT != vp_oper->state.default_vlan) { - /* the reserved QPs (special, proxy, tunnel) - * do not operate over vlans - */ - if (mlx4_is_qp_reserved(dev, qpn)) - return 0; - - /* force strip vlan by clear vsd */ - qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); - /* preserve IF_COUNTER flag */ - qpc->pri_path.vlan_control &= - MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER; - if (MLX4_QP_ST_RC != qp_type) { - if (0 != vp_oper->state.default_vlan) { - qpc->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; - } else { /* priority tagged */ - qpc->pri_path.vlan_control |= - MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; - } - } - qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN; - qpc->pri_path.vlan_index = vp_oper->vlan_idx; - qpc->pri_path.fl |= MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; - qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; - qpc->pri_path.sched_queue &= 0xC7; - qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3; - } - if (vp_oper->state.spoofchk) { - qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC; - qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx; - } - return 0; -} - -static int mpt_mask(struct mlx4_dev *dev) -{ - return dev->caps.num_mpts - 1; -} - -static void *find_res(struct mlx4_dev *dev, u64 res_id, - enum mlx4_resource type) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type], - res_id); -} - -static int get_res(struct mlx4_dev *dev, int slave, u64 res_id, - enum mlx4_resource type, - void *res) -{ - struct res_common *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = find_res(dev, res_id, type); - if (!r) { - err = -ENONET; - goto exit; - } - - if (r->state == RES_ANY_BUSY) { - err = -EBUSY; - goto exit; - } - - if (r->owner != slave) { - err = -EPERM; - goto exit; - } - - r->from_state = r->state; - r->state = RES_ANY_BUSY; - - if (res) - *((struct res_common **)res) = r; - -exit: - spin_unlock_irq(mlx4_tlock(dev)); - return err; -} - -int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, - enum mlx4_resource type, - u64 res_id, int *slave) -{ - - struct res_common *r; - int err = -ENOENT; - int id = res_id; - - if (type == RES_QP) - id &= 0x7fffff; - spin_lock(mlx4_tlock(dev)); - - r = find_res(dev, id, type); - if (r) { - *slave = r->owner; - err = 0; - } - spin_unlock(mlx4_tlock(dev)); - - return err; -} - -static void put_res(struct mlx4_dev *dev, int slave, u64 res_id, - enum mlx4_resource type) -{ - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - r = find_res(dev, res_id, type); - if (r) - r->state = r->from_state; - spin_unlock_irq(mlx4_tlock(dev)); -} - -static struct res_common *alloc_qp_tr(int id) -{ - struct res_qp *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_QP_RESERVED; - ret->local_qpn = id; - INIT_LIST_HEAD(&ret->mcg_list); - spin_lock_init(&ret->mcg_spl); - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_mtt_tr(int id, int order) -{ - struct res_mtt *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->order = order; - ret->com.state = RES_MTT_ALLOCATED; - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_mpt_tr(int id, int key) -{ - struct res_mpt *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_MPT_RESERVED; - ret->key = key; - - return &ret->com; -} - -static struct res_common *alloc_eq_tr(int id) -{ - struct res_eq *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_EQ_RESERVED; - - return &ret->com; -} - -static struct res_common *alloc_cq_tr(int id) -{ - struct res_cq *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_CQ_ALLOCATED; - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_srq_tr(int id) -{ - struct res_srq *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_SRQ_ALLOCATED; - atomic_set(&ret->ref_count, 0); - - return &ret->com; -} - -static struct res_common *alloc_counter_tr(int id) -{ - struct res_counter *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_COUNTER_ALLOCATED; - - return &ret->com; -} - -static struct res_common *alloc_xrcdn_tr(int id) -{ - struct res_xrcdn *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_XRCD_ALLOCATED; - - return &ret->com; -} - -static struct res_common *alloc_fs_rule_tr(u64 id, int qpn) -{ - struct res_fs_rule *ret; - - ret = kzalloc(sizeof *ret, GFP_KERNEL); - if (!ret) - return NULL; - - ret->com.res_id = id; - ret->com.state = RES_FS_RULE_ALLOCATED; - ret->qpn = qpn; - return &ret->com; -} - -static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, - int extra) -{ - struct res_common *ret; - - switch (type) { - case RES_QP: - ret = alloc_qp_tr(id); - break; - case RES_MPT: - ret = alloc_mpt_tr(id, extra); - break; - case RES_MTT: - ret = alloc_mtt_tr(id, extra); - break; - case RES_EQ: - ret = alloc_eq_tr(id); - break; - case RES_CQ: - ret = alloc_cq_tr(id); - break; - case RES_SRQ: - ret = alloc_srq_tr(id); - break; - case RES_MAC: - printk(KERN_ERR "implementation missing\n"); - return NULL; - case RES_COUNTER: - ret = alloc_counter_tr(id); - break; - case RES_XRCD: - ret = alloc_xrcdn_tr(id); - break; - case RES_FS_RULE: - ret = alloc_fs_rule_tr(id, extra); - break; - default: - return NULL; - } - if (ret) - ret->owner = slave; - - return ret; -} - -static int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, - enum mlx4_resource type, int extra) -{ - int i; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - struct res_common **res_arr; - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct rb_root *root = &tracker->res_tree[type]; - - res_arr = kzalloc(count * sizeof *res_arr, GFP_KERNEL); - if (!res_arr) - return -ENOMEM; - - for (i = 0; i < count; ++i) { - res_arr[i] = alloc_tr(base + i, type, slave, extra); - if (!res_arr[i]) { - for (--i; i >= 0; --i) - kfree(res_arr[i]); - - kfree(res_arr); - return -ENOMEM; - } - } - - spin_lock_irq(mlx4_tlock(dev)); - for (i = 0; i < count; ++i) { - if (find_res(dev, base + i, type)) { - err = -EEXIST; - goto undo; - } - err = res_tracker_insert(root, res_arr[i]); - if (err) - goto undo; - list_add_tail(&res_arr[i]->list, - &tracker->slave_list[slave].res_list[type]); - } - spin_unlock_irq(mlx4_tlock(dev)); - kfree(res_arr); - - return 0; - -undo: - for (--i; i >= 0; --i) { - rb_erase(&res_arr[i]->node, root); - list_del_init(&res_arr[i]->list); - } - - spin_unlock_irq(mlx4_tlock(dev)); - - for (i = 0; i < count; ++i) - kfree(res_arr[i]); - - kfree(res_arr); - - return err; -} - -static int remove_qp_ok(struct res_qp *res) -{ - if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || - !list_empty(&res->mcg_list)) { - pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", - res->com.state, atomic_read(&res->ref_count)); - return -EBUSY; - } else if (res->com.state != RES_QP_RESERVED) { - return -EPERM; - } - - return 0; -} - -static int remove_mtt_ok(struct res_mtt *res, int order) -{ - if (res->com.state == RES_MTT_BUSY || - atomic_read(&res->ref_count)) { - printk(KERN_DEBUG "%s-%d: state %s, ref_count %d\n", - __func__, __LINE__, - mtt_states_str(res->com.state), - atomic_read(&res->ref_count)); - return -EBUSY; - } else if (res->com.state != RES_MTT_ALLOCATED) - return -EPERM; - else if (res->order != order) - return -EINVAL; - - return 0; -} - -static int remove_mpt_ok(struct res_mpt *res) -{ - if (res->com.state == RES_MPT_BUSY) - return -EBUSY; - else if (res->com.state != RES_MPT_RESERVED) - return -EPERM; - - return 0; -} - -static int remove_eq_ok(struct res_eq *res) -{ - if (res->com.state == RES_MPT_BUSY) - return -EBUSY; - else if (res->com.state != RES_MPT_RESERVED) - return -EPERM; - - return 0; -} - -static int remove_counter_ok(struct res_counter *res) -{ - if (res->com.state == RES_COUNTER_BUSY) - return -EBUSY; - else if (res->com.state != RES_COUNTER_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_xrcdn_ok(struct res_xrcdn *res) -{ - if (res->com.state == RES_XRCD_BUSY) - return -EBUSY; - else if (res->com.state != RES_XRCD_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_fs_rule_ok(struct res_fs_rule *res) -{ - if (res->com.state == RES_FS_RULE_BUSY) - return -EBUSY; - else if (res->com.state != RES_FS_RULE_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_cq_ok(struct res_cq *res) -{ - if (res->com.state == RES_CQ_BUSY) - return -EBUSY; - else if (res->com.state != RES_CQ_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_srq_ok(struct res_srq *res) -{ - if (res->com.state == RES_SRQ_BUSY) - return -EBUSY; - else if (res->com.state != RES_SRQ_ALLOCATED) - return -EPERM; - - return 0; -} - -static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) -{ - switch (type) { - case RES_QP: - return remove_qp_ok((struct res_qp *)res); - case RES_CQ: - return remove_cq_ok((struct res_cq *)res); - case RES_SRQ: - return remove_srq_ok((struct res_srq *)res); - case RES_MPT: - return remove_mpt_ok((struct res_mpt *)res); - case RES_MTT: - return remove_mtt_ok((struct res_mtt *)res, extra); - case RES_MAC: - return -ENOSYS; - case RES_EQ: - return remove_eq_ok((struct res_eq *)res); - case RES_COUNTER: - return remove_counter_ok((struct res_counter *)res); - case RES_XRCD: - return remove_xrcdn_ok((struct res_xrcdn *)res); - case RES_FS_RULE: - return remove_fs_rule_ok((struct res_fs_rule *)res); - default: - return -EINVAL; - } -} - -static int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count, - enum mlx4_resource type, int extra) -{ - u64 i; - int err; - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - for (i = base; i < base + count; ++i) { - r = res_tracker_lookup(&tracker->res_tree[type], i); - if (!r) { - err = -ENOENT; - goto out; - } - if (r->owner != slave) { - err = -EPERM; - goto out; - } - err = remove_ok(r, type, extra); - if (err) - goto out; - } - - for (i = base; i < base + count; ++i) { - r = res_tracker_lookup(&tracker->res_tree[type], i); - rb_erase(&r->node, &tracker->res_tree[type]); - list_del(&r->list); - kfree(r); - } - err = 0; - -out: - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn, - enum res_qp_states state, struct res_qp **qp, - int alloc) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_qp *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_QP_BUSY: - mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n", - __func__, (unsigned long long)r->com.res_id); - err = -EBUSY; - break; - - case RES_QP_RESERVED: - if (r->com.state == RES_QP_MAPPED && !alloc) - break; - - mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", (unsigned long long)r->com.res_id); - err = -EINVAL; - break; - - case RES_QP_MAPPED: - if ((r->com.state == RES_QP_RESERVED && alloc) || - r->com.state == RES_QP_HW) - break; - else { - mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", - (unsigned long long)r->com.res_id); - err = -EINVAL; - } - - break; - - case RES_QP_HW: - if (r->com.state != RES_QP_MAPPED) - err = -EINVAL; - break; - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_QP_BUSY; - if (qp) - *qp = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index, - enum res_mpt_states state, struct res_mpt **mpt) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_mpt *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_MPT_BUSY: - err = -EINVAL; - break; - - case RES_MPT_RESERVED: - if (r->com.state != RES_MPT_MAPPED) - err = -EINVAL; - break; - - case RES_MPT_MAPPED: - if (r->com.state != RES_MPT_RESERVED && - r->com.state != RES_MPT_HW) - err = -EINVAL; - break; - - case RES_MPT_HW: - if (r->com.state != RES_MPT_MAPPED) - err = -EINVAL; - break; - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_MPT_BUSY; - if (mpt) - *mpt = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, - enum res_eq_states state, struct res_eq **eq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_eq *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_EQ_BUSY: - err = -EINVAL; - break; - - case RES_EQ_RESERVED: - if (r->com.state != RES_EQ_HW) - err = -EINVAL; - break; - - case RES_EQ_HW: - if (r->com.state != RES_EQ_RESERVED) - err = -EINVAL; - break; - - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_EQ_BUSY; - if (eq) - *eq = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn, - enum res_cq_states state, struct res_cq **cq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_cq *r; - int err; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_CQ_BUSY: - err = -EBUSY; - break; - - case RES_CQ_ALLOCATED: - if (r->com.state != RES_CQ_HW) - err = -EINVAL; - else if (atomic_read(&r->ref_count)) - err = -EBUSY; - else - err = 0; - break; - - case RES_CQ_HW: - if (r->com.state != RES_CQ_ALLOCATED) - err = -EINVAL; - else - err = 0; - break; - - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_CQ_BUSY; - if (cq) - *cq = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, - enum res_srq_states state, struct res_srq **srq) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_srq *r; - int err = 0; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index); - if (!r) - err = -ENOENT; - else if (r->com.owner != slave) - err = -EPERM; - else { - switch (state) { - case RES_SRQ_BUSY: - err = -EINVAL; - break; - - case RES_SRQ_ALLOCATED: - if (r->com.state != RES_SRQ_HW) - err = -EINVAL; - else if (atomic_read(&r->ref_count)) - err = -EBUSY; - break; - - case RES_SRQ_HW: - if (r->com.state != RES_SRQ_ALLOCATED) - err = -EINVAL; - break; - - default: - err = -EINVAL; - } - - if (!err) { - r->com.from_state = r->com.state; - r->com.to_state = state; - r->com.state = RES_SRQ_BUSY; - if (srq) - *srq = r; - } - } - - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static void res_abort_move(struct mlx4_dev *dev, int slave, - enum mlx4_resource type, int id) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[type], id); - if (r && (r->owner == slave)) - r->state = r->from_state; - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void res_end_move(struct mlx4_dev *dev, int slave, - enum mlx4_resource type, int id) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_common *r; - - spin_lock_irq(mlx4_tlock(dev)); - r = res_tracker_lookup(&tracker->res_tree[type], id); - if (r && (r->owner == slave)) - r->state = r->to_state; - spin_unlock_irq(mlx4_tlock(dev)); -} - -static int valid_reserved(struct mlx4_dev *dev, int slave, int qpn) -{ - return mlx4_is_qp_reserved(dev, qpn) && - (mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn)); -} - -static int fw_reserved(struct mlx4_dev *dev, int qpn) -{ - return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]; -} - -static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err; - int count; - int align; - int base; - int qpn; - u8 flags; - - switch (op) { - case RES_OP_RESERVE: - count = get_param_l(&in_param) & 0xffffff; - flags = get_param_l(&in_param) >> 24; - align = get_param_h(&in_param); - err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); - if (err) - return err; - - err = __mlx4_qp_reserve_range(dev, count, align, &base, flags); - if (err) { - mlx4_release_resource(dev, slave, RES_QP, count, 0); - return err; - } - - err = add_res_range(dev, slave, base, count, RES_QP, 0); - if (err) { - mlx4_release_resource(dev, slave, RES_QP, count, 0); - __mlx4_qp_release_range(dev, base, count); - return err; - } - set_param_l(out_param, base); - break; - case RES_OP_MAP_ICM: - qpn = get_param_l(&in_param) & 0x7fffff; - if (valid_reserved(dev, slave, qpn)) { - err = add_res_range(dev, slave, qpn, 1, RES_QP, 0); - if (err) - return err; - } - - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, - NULL, 1); - if (err) - return err; - - if (!fw_reserved(dev, qpn)) { - err = __mlx4_qp_alloc_icm(dev, qpn); - if (err) { - res_abort_move(dev, slave, RES_QP, qpn); - return err; - } - } - - res_end_move(dev, slave, RES_QP, qpn); - break; - - default: - err = -EINVAL; - break; - } - return err; -} - -static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err = -EINVAL; - int base; - int order; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - order = get_param_l(&in_param); - - err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0); - if (err) - return err; - - base = __mlx4_alloc_mtt_range(dev, order); - if (base == -1) { - mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); - return -ENOMEM; - } - - err = add_res_range(dev, slave, base, 1, RES_MTT, order); - if (err) { - mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); - __mlx4_free_mtt_range(dev, base, order); - } else - set_param_l(out_param, base); - - return err; -} - -static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err = -EINVAL; - int index; - int id; - struct res_mpt *mpt; - - switch (op) { - case RES_OP_RESERVE: - err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0); - if (err) - break; - - index = __mlx4_mpt_reserve(dev); - if (index == -1) { - mlx4_release_resource(dev, slave, RES_MPT, 1, 0); - break; - } - id = index & mpt_mask(dev); - - err = add_res_range(dev, slave, id, 1, RES_MPT, index); - if (err) { - mlx4_release_resource(dev, slave, RES_MPT, 1, 0); - __mlx4_mpt_release(dev, index); - break; - } - set_param_l(out_param, index); - break; - case RES_OP_MAP_ICM: - index = get_param_l(&in_param); - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, - RES_MPT_MAPPED, &mpt); - if (err) - return err; - - err = __mlx4_mpt_alloc_icm(dev, mpt->key); - if (err) { - res_abort_move(dev, slave, RES_MPT, id); - return err; - } - - res_end_move(dev, slave, RES_MPT, id); - break; - } - return err; -} - -static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int cqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0); - if (err) - break; - - err = __mlx4_cq_alloc_icm(dev, &cqn); - if (err) { - mlx4_release_resource(dev, slave, RES_CQ, 1, 0); - break; - } - - err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0); - if (err) { - mlx4_release_resource(dev, slave, RES_CQ, 1, 0); - __mlx4_cq_free_icm(dev, cqn); - break; - } - - set_param_l(out_param, cqn); - break; - - default: - err = -EINVAL; - } - - return err; -} - -static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int srqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0); - if (err) - break; - - err = __mlx4_srq_alloc_icm(dev, &srqn); - if (err) { - mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); - break; - } - - err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0); - if (err) { - mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); - __mlx4_srq_free_icm(dev, srqn); - break; - } - - set_param_l(out_param, srqn); - break; - - default: - err = -EINVAL; - } - - return err; -} - -static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, - u8 smac_index, u64 *mac) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - if (res->smac_index == smac_index && res->port == (u8) port) { - *mac = res->mac; - return 0; - } - } - return -ENOENT; -} - -static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - if (res->mac == mac && res->port == (u8) port) { - /* mac found. update ref count */ - ++res->ref_count; - return 0; - } - } - - if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) - return -EINVAL; - res = kzalloc(sizeof *res, GFP_KERNEL); - if (!res) { - mlx4_release_resource(dev, slave, RES_MAC, 1, port); - return -ENOMEM; - } - res->mac = mac; - res->port = (u8) port; - res->smac_index = smac_index; - res->ref_count = 1; - list_add_tail(&res->list, - &tracker->slave_list[slave].res_list[RES_MAC]); - return 0; -} - - -static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - if (res->mac == mac && res->port == (u8) port) { - if (!--res->ref_count) { - list_del(&res->list); - mlx4_release_resource(dev, slave, RES_MAC, 1, port); - kfree(res); - } - break; - } - } -} - -static void rem_slave_macs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mac_list = - &tracker->slave_list[slave].res_list[RES_MAC]; - struct mac_res *res, *tmp; - int i; - - list_for_each_entry_safe(res, tmp, mac_list, list) { - list_del(&res->list); - /* dereference the mac the num times the slave referenced it */ - for (i = 0; i < res->ref_count; i++) - __mlx4_unregister_mac(dev, res->port, res->mac); - mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); - kfree(res); - } -} - -static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int in_port) -{ - int err = -EINVAL; - int port; - u64 mac; - u8 smac_index = 0; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - port = !in_port ? get_param_l(out_param) : in_port; - mac = in_param; - - err = __mlx4_register_mac(dev, port, mac); - if (err >= 0) { - smac_index = err; - set_param_l(out_param, err); - err = 0; - } - - if (!err) { - err = mac_add_to_slave(dev, slave, mac, port, smac_index); - if (err) - __mlx4_unregister_mac(dev, port, mac); - } - return err; -} - -static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan, - int port, int vlan_index) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *vlan_list = - &tracker->slave_list[slave].res_list[RES_VLAN]; - struct vlan_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, vlan_list, list) { - if (res->vlan == vlan && res->port == (u8) port) { - /* vlan found. update ref count */ - ++res->ref_count; - return 0; - } - } - - if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port)) - return -EINVAL; - res = kzalloc(sizeof(*res), GFP_KERNEL); - if (!res) { - mlx4_release_resource(dev, slave, RES_VLAN, 1, port); - return -ENOMEM; - } - res->vlan = vlan; - res->port = (u8) port; - res->vlan_index = vlan_index; - res->ref_count = 1; - list_add_tail(&res->list, - &tracker->slave_list[slave].res_list[RES_VLAN]); - return 0; -} - - -static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan, - int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *vlan_list = - &tracker->slave_list[slave].res_list[RES_VLAN]; - struct vlan_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, vlan_list, list) { - if (res->vlan == vlan && res->port == (u8) port) { - if (!--res->ref_count) { - list_del(&res->list); - mlx4_release_resource(dev, slave, RES_VLAN, - 1, port); - kfree(res); - } - break; - } - } -} - -static void rem_slave_vlans(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *vlan_list = - &tracker->slave_list[slave].res_list[RES_VLAN]; - struct vlan_res *res, *tmp; - int i; - - list_for_each_entry_safe(res, tmp, vlan_list, list) { - list_del(&res->list); - /* dereference the vlan the num times the slave referenced it */ - for (i = 0; i < res->ref_count; i++) - __mlx4_unregister_vlan(dev, res->port, res->vlan); - mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port); - kfree(res); - } -} - -static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int in_port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; - int err = -EINVAL; - u16 vlan; - int vlan_index; - int port; - - port = !in_port ? get_param_l(out_param) : in_port; - - if (!port) - return err; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - /* upstream kernels had NOP for reg/unreg vlan. Continue this. */ - if (!in_port && port > 0 && port <= dev->caps.num_ports) { - slave_state[slave].old_vlan_api = true; - return 0; - } - - vlan = (u16) in_param; - - err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); - if (!err) { - set_param_l(out_param, (u32) vlan_index); - err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index); - if (err) - __mlx4_unregister_vlan(dev, port, vlan); - } - return err; -} - -static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int port) -{ - u32 index; - int err; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - err = __mlx4_counter_alloc(dev, slave, port, &index); - if (!err) - set_param_l(out_param, index); - - return err; -} - -static int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - u32 xrcdn; - int err; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - err = __mlx4_xrcd_alloc(dev, &xrcdn); - if (err) - return err; - - err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); - if (err) - __mlx4_xrcd_free(dev, xrcdn); - else - set_param_l(out_param, xrcdn); - - return err; -} - -int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int alop = vhcr->op_modifier; - - switch (vhcr->in_modifier & 0xFF) { - case RES_QP: - err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MTT: - err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MPT: - err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_CQ: - err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_SRQ: - err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MAC: - err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_VLAN: - err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_COUNTER: - err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_XRCD: - err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - default: - err = -EINVAL; - break; - } - - return err; -} - -static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param) -{ - int err; - int count; - int base; - int qpn; - - switch (op) { - case RES_OP_RESERVE: - base = get_param_l(&in_param) & 0x7fffff; - count = get_param_h(&in_param); - err = rem_res_range(dev, slave, base, count, RES_QP, 0); - if (err) - break; - mlx4_release_resource(dev, slave, RES_QP, count, 0); - __mlx4_qp_release_range(dev, base, count); - break; - case RES_OP_MAP_ICM: - qpn = get_param_l(&in_param) & 0x7fffff; - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED, - NULL, 0); - if (err) - return err; - - if (!fw_reserved(dev, qpn)) - __mlx4_qp_free_icm(dev, qpn); - - res_end_move(dev, slave, RES_QP, qpn); - - if (valid_reserved(dev, slave, qpn)) - err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int err = -EINVAL; - int base; - int order; - - if (op != RES_OP_RESERVE_AND_MAP) - return err; - - base = get_param_l(&in_param); - order = get_param_h(&in_param); - err = rem_res_range(dev, slave, base, 1, RES_MTT, order); - if (!err) { - mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0); - __mlx4_free_mtt_range(dev, base, order); - } - return err; -} - -static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param) -{ - int err = -EINVAL; - int index; - int id; - struct res_mpt *mpt; - - switch (op) { - case RES_OP_RESERVE: - index = get_param_l(&in_param); - id = index & mpt_mask(dev); - err = get_res(dev, slave, id, RES_MPT, &mpt); - if (err) - break; - index = mpt->key; - put_res(dev, slave, id, RES_MPT); - - err = rem_res_range(dev, slave, id, 1, RES_MPT, 0); - if (err) - break; - mlx4_release_resource(dev, slave, RES_MPT, 1, 0); - __mlx4_mpt_release(dev, index); - break; - case RES_OP_MAP_ICM: - index = get_param_l(&in_param); - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, - RES_MPT_RESERVED, &mpt); - if (err) - return err; - - __mlx4_mpt_free_icm(dev, mpt->key); - res_end_move(dev, slave, RES_MPT, id); - return err; - break; - default: - err = -EINVAL; - break; - } - return err; -} - -static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int cqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - cqn = get_param_l(&in_param); - err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0); - if (err) - break; - - mlx4_release_resource(dev, slave, RES_CQ, 1, 0); - __mlx4_cq_free_icm(dev, cqn); - break; - - default: - err = -EINVAL; - break; - } - - return err; -} - -static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int srqn; - int err; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - srqn = get_param_l(&in_param); - err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0); - if (err) - break; - - mlx4_release_resource(dev, slave, RES_SRQ, 1, 0); - __mlx4_srq_free_icm(dev, srqn); - break; - - default: - err = -EINVAL; - break; - } - - return err; -} - -static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int in_port) -{ - int port; - int err = 0; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - port = !in_port ? get_param_l(out_param) : in_port; - mac_del_from_slave(dev, slave, in_param, port); - __mlx4_unregister_mac(dev, port, in_param); - break; - default: - err = -EINVAL; - break; - } - - return err; - -} - -static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int port) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; - int err = 0; - - switch (op) { - case RES_OP_RESERVE_AND_MAP: - if (slave_state[slave].old_vlan_api == true) - return 0; - if (!port) - return -EINVAL; - vlan_del_from_slave(dev, slave, in_param, port); - __mlx4_unregister_vlan(dev, port, in_param); - break; - default: - err = -EINVAL; - break; - } - - return err; -} - -static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param, int port) -{ - int index; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - index = get_param_l(&in_param); - - __mlx4_counter_free(dev, slave, port, index); - - return 0; -} - -static int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, - u64 in_param, u64 *out_param) -{ - int xrcdn; - int err; - - if (op != RES_OP_RESERVE) - return -EINVAL; - - xrcdn = get_param_l(&in_param); - err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); - if (err) - return err; - - __mlx4_xrcd_free(dev, xrcdn); - - return err; -} - -int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err = -EINVAL; - int alop = vhcr->op_modifier; - - switch (vhcr->in_modifier & 0xFF) { - case RES_QP: - err = qp_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param); - break; - - case RES_MTT: - err = mtt_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MPT: - err = mpt_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param); - break; - - case RES_CQ: - err = cq_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_SRQ: - err = srq_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - break; - - case RES_MAC: - err = mac_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_VLAN: - err = vlan_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_COUNTER: - err = counter_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param, - (vhcr->in_modifier >> 8) & 0xFF); - break; - - case RES_XRCD: - err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, - vhcr->in_param, &vhcr->out_param); - - default: - break; - } - return err; -} - -/* ugly but other choices are uglier */ -static int mr_phys_mpt(struct mlx4_mpt_entry *mpt) -{ - return (be32_to_cpu(mpt->flags) >> 9) & 1; -} - -static int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt) -{ - return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8; -} - -static int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->mtt_sz); -} - -static u32 mr_get_pd(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->pd_flags) & 0x00ffffff; -} - -static int mr_is_fmr(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG; -} - -static int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE; -} - -static int mr_is_region(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION; -} - -static int qp_get_mtt_addr(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; -} - -static int srq_get_mtt_addr(struct mlx4_srq_context *srqc) -{ - return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8; -} - -static int qp_get_mtt_size(struct mlx4_qp_context *qpc) -{ - int page_shift = (qpc->log_page_size & 0x3f) + 12; - int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf; - int log_sq_sride = qpc->sq_size_stride & 7; - int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf; - int log_rq_stride = qpc->rq_size_stride & 7; - int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1; - int rss = (be32_to_cpu(qpc->flags) >> 13) & 1; - u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0; - int sq_size; - int rq_size; - int total_pages; - int total_mem; - int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f; - - sq_size = 1 << (log_sq_size + log_sq_sride + 4); - rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4)); - total_mem = sq_size + rq_size; - total_pages = - roundup_pow_of_two((total_mem + (page_offset << 6)) >> - page_shift); - - return total_pages; -} - -static int check_mtt_range(struct mlx4_dev *dev, int slave, int start, - int size, struct res_mtt *mtt) -{ - int res_start = mtt->com.res_id; - int res_size = (1 << mtt->order); - - if (start < res_start || start + size > res_start + res_size) - return -EPERM; - return 0; -} - -int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int index = vhcr->in_modifier; - struct res_mtt *mtt; - struct res_mpt *mpt; - int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz; - int phys; - int id; - u32 pd; - int pd_slave; - - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt); - if (err) - return err; - - /* Currently disable memory windows since this feature isn't tested yet - * under virtualization. - */ - if (!mr_is_region(inbox->buf)) { - err = -ENOSYS; - goto ex_abort; - } - - /* Make sure that the PD bits related to the slave id are zeros. */ - pd = mr_get_pd(inbox->buf); - pd_slave = (pd >> 17) & 0x7f; - if (pd_slave != 0 && pd_slave != slave) { - err = -EPERM; - goto ex_abort; - } - - if (mr_is_fmr(inbox->buf)) { - /* FMR and Bind Enable are forbidden in slave devices. */ - if (mr_is_bind_enabled(inbox->buf)) { - err = -EPERM; - goto ex_abort; - } - /* FMR and Memory Windows are also forbidden. */ - if (!mr_is_region(inbox->buf)) { - err = -EPERM; - goto ex_abort; - } - } - - phys = mr_phys_mpt(inbox->buf); - if (!phys) { - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_abort; - - err = check_mtt_range(dev, slave, mtt_base, - mr_get_mtt_size(inbox->buf), mtt); - if (err) - goto ex_put; - - mpt->mtt = mtt; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put; - - if (!phys) { - atomic_inc(&mtt->ref_count); - put_res(dev, slave, mtt->com.res_id, RES_MTT); - } - - res_end_move(dev, slave, RES_MPT, id); - return 0; - -ex_put: - if (!phys) - put_res(dev, slave, mtt->com.res_id, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_MPT, id); - - return err; -} - -int mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int index = vhcr->in_modifier; - struct res_mpt *mpt; - int id; - - id = index & mpt_mask(dev); - err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt); - if (err) - return err; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_abort; - - if (mpt->mtt) - atomic_dec(&mpt->mtt->ref_count); - - res_end_move(dev, slave, RES_MPT, id); - return 0; - -ex_abort: - res_abort_move(dev, slave, RES_MPT, id); - - return err; -} - -int mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int index = vhcr->in_modifier; - struct res_mpt *mpt; - int id; - - id = index & mpt_mask(dev); - err = get_res(dev, slave, id, RES_MPT, &mpt); - if (err) - return err; - - if (mpt->com.from_state != RES_MPT_HW) { - err = -EBUSY; - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - -out: - put_res(dev, slave, id, RES_MPT); - return err; -} - -static int qp_get_rcqn(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->cqn_recv) & 0xffffff; -} - -static int qp_get_scqn(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->cqn_send) & 0xffffff; -} - -static u32 qp_get_srqn(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->srqn) & 0x1ffffff; -} - -static void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr, - struct mlx4_qp_context *context) -{ - u32 qpn = vhcr->in_modifier & 0xffffff; - u32 qkey = 0; - - if (mlx4_get_parav_qkey(dev, qpn, &qkey)) - return; - - /* adjust qkey in qp context */ - context->qkey = cpu_to_be32(qkey); -} - -int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_mtt *mtt; - struct res_qp *qp; - struct mlx4_qp_context *qpc = inbox->buf + 8; - int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz; - int mtt_size = qp_get_mtt_size(qpc); - struct res_cq *rcq; - struct res_cq *scq; - int rcqn = qp_get_rcqn(qpc); - int scqn = qp_get_scqn(qpc); - u32 srqn = qp_get_srqn(qpc) & 0xffffff; - int use_srq = (qp_get_srqn(qpc) >> 24) & 1; - struct res_srq *srq; - int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; - - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); - if (err) - return err; - qp->local_qpn = local_qpn; - qp->sched_queue = 0; - qp->param3 = 0; - qp->vlan_control = 0; - qp->fvl_rx = 0; - qp->pri_path_fl = 0; - qp->vlan_index = 0; - qp->feup = 0; - qp->qpc_flags = be32_to_cpu(qpc->flags); - - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_abort; - - err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); - if (err) - goto ex_put_mtt; - - err = get_res(dev, slave, rcqn, RES_CQ, &rcq); - if (err) - goto ex_put_mtt; - - if (scqn != rcqn) { - err = get_res(dev, slave, scqn, RES_CQ, &scq); - if (err) - goto ex_put_rcq; - } else - scq = rcq; - - if (use_srq) { - err = get_res(dev, slave, srqn, RES_SRQ, &srq); - if (err) - goto ex_put_scq; - } - - adjust_proxy_tun_qkey(dev, vhcr, qpc); - update_pkey_index(dev, slave, inbox); - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put_srq; - atomic_inc(&mtt->ref_count); - qp->mtt = mtt; - atomic_inc(&rcq->ref_count); - qp->rcq = rcq; - atomic_inc(&scq->ref_count); - qp->scq = scq; - - if (scqn != rcqn) - put_res(dev, slave, scqn, RES_CQ); - - if (use_srq) { - atomic_inc(&srq->ref_count); - put_res(dev, slave, srqn, RES_SRQ); - qp->srq = srq; - } - put_res(dev, slave, rcqn, RES_CQ); - put_res(dev, slave, mtt_base, RES_MTT); - res_end_move(dev, slave, RES_QP, qpn); - - return 0; - -ex_put_srq: - if (use_srq) - put_res(dev, slave, srqn, RES_SRQ); -ex_put_scq: - if (scqn != rcqn) - put_res(dev, slave, scqn, RES_CQ); -ex_put_rcq: - put_res(dev, slave, rcqn, RES_CQ); -ex_put_mtt: - put_res(dev, slave, mtt_base, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_QP, qpn); - - return err; -} - -static int eq_get_mtt_addr(struct mlx4_eq_context *eqc) -{ - return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8; -} - -static int eq_get_mtt_size(struct mlx4_eq_context *eqc) -{ - int log_eq_size = eqc->log_eq_size & 0x1f; - int page_shift = (eqc->log_page_size & 0x3f) + 12; - - if (log_eq_size + 5 < page_shift) - return 1; - - return 1 << (log_eq_size + 5 - page_shift); -} - -static int cq_get_mtt_addr(struct mlx4_cq_context *cqc) -{ - return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8; -} - -static int cq_get_mtt_size(struct mlx4_cq_context *cqc) -{ - int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f; - int page_shift = (cqc->log_page_size & 0x3f) + 12; - - if (log_cq_size + 5 < page_shift) - return 1; - - return 1 << (log_cq_size + 5 - page_shift); -} - -int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int eqn = vhcr->in_modifier; - int res_id = (slave << 8) | eqn; - struct mlx4_eq_context *eqc = inbox->buf; - int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; - int mtt_size = eq_get_mtt_size(eqc); - struct res_eq *eq; - struct res_mtt *mtt; - - err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0); - if (err) - return err; - err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq); - if (err) - goto out_add; - - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto out_move; - - err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt); - if (err) - goto out_put; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto out_put; - - atomic_inc(&mtt->ref_count); - eq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_EQ, res_id); - return 0; - -out_put: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -out_move: - res_abort_move(dev, slave, RES_EQ, res_id); -out_add: - rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); - return err; -} - -static int get_containing_mtt(struct mlx4_dev *dev, int slave, int start, - int len, struct res_mtt **res) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct res_mtt *mtt; - int err = -EINVAL; - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT], - com.list) { - if (!check_mtt_range(dev, slave, start, len, mtt)) { - *res = mtt; - mtt->com.from_state = mtt->com.state; - mtt->com.state = RES_MTT_BUSY; - err = 0; - break; - } - } - spin_unlock_irq(mlx4_tlock(dev)); - - return err; -} - -static int verify_qp_parameters(struct mlx4_dev *dev, - struct mlx4_cmd_mailbox *inbox, - enum qp_transition transition, u8 slave) -{ - u32 qp_type; - struct mlx4_qp_context *qp_ctx; - enum mlx4_qp_optpar optpar; - int port; - int num_gids; - - qp_ctx = inbox->buf + 8; - qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; - optpar = be32_to_cpu(*(__be32 *) inbox->buf); - - switch (qp_type) { - case MLX4_QP_ST_RC: - case MLX4_QP_ST_UC: - switch (transition) { - case QP_TRANS_INIT2RTR: - case QP_TRANS_RTR2RTS: - case QP_TRANS_RTS2RTS: - case QP_TRANS_SQD2SQD: - case QP_TRANS_SQD2RTS: - if (slave != mlx4_master_func_num(dev)) - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { - port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) - num_gids = mlx4_get_slave_num_gids(dev, slave); - else - num_gids = 1; - if (qp_ctx->pri_path.mgid_index >= num_gids) - return -EINVAL; - } - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { - port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; - if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) - num_gids = mlx4_get_slave_num_gids(dev, slave); - else - num_gids = 1; - if (qp_ctx->alt_path.mgid_index >= num_gids) - return -EINVAL; - } - break; - default: - break; - } - - break; - default: - break; - } - - return 0; -} - -int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_mtt mtt; - __be64 *page_list = inbox->buf; - u64 *pg_list = (u64 *)page_list; - int i; - struct res_mtt *rmtt = NULL; - int start = be64_to_cpu(page_list[0]); - int npages = vhcr->in_modifier; - int err; - - err = get_containing_mtt(dev, slave, start, npages, &rmtt); - if (err) - return err; - - /* Call the SW implementation of write_mtt: - * - Prepare a dummy mtt struct - * - Translate inbox contents to simple addresses in host endianness */ - mtt.offset = 0; /* TBD this is broken but I don't handle it since - we don't really use it */ - mtt.order = 0; - mtt.page_shift = 0; - for (i = 0; i < npages; ++i) - pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL); - - err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages, - ((u64 *)page_list + 2)); - - if (rmtt) - put_res(dev, slave, rmtt->com.res_id, RES_MTT); - - return err; -} - -int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); - struct res_eq *eq; - int err; - - err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq); - if (err) - return err; - - err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL); - if (err) - goto ex_abort; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put; - - atomic_dec(&eq->mtt->ref_count); - put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_EQ, res_id); - rem_res_range(dev, slave, res_id, 1, RES_EQ, 0); - - return 0; - -ex_put: - put_res(dev, slave, eq->mtt->com.res_id, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_EQ, res_id); - - return err; -} - -int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_event_eq_info *event_eq; - struct mlx4_cmd_mailbox *mailbox; - u32 in_modifier = 0; - int err; - int res_id; - struct res_eq *req; - - if (!priv->mfunc.master.slave_state) - return -EINVAL; - - /* check for slave valid, slave not PF, and slave active */ - if (slave < 0 || slave >= dev->num_slaves || - slave == dev->caps.function || - !priv->mfunc.master.slave_state[slave].active) - return 0; - - event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; - - /* Create the event only if the slave is registered */ - if (event_eq->eqn < 0) - return 0; - - mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); - res_id = (slave << 8) | event_eq->eqn; - err = get_res(dev, slave, res_id, RES_EQ, &req); - if (err) - goto unlock; - - if (req->com.from_state != RES_EQ_HW) { - err = -EINVAL; - goto put; - } - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto put; - } - - if (eqe->type == MLX4_EVENT_TYPE_CMD) { - ++event_eq->token; - eqe->event.cmd.token = cpu_to_be16(event_eq->token); - } - - memcpy(mailbox->buf, (u8 *) eqe, 28); - - in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16); - - err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, - MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); - - put_res(dev, slave, res_id, RES_EQ); - mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); - mlx4_free_cmd_mailbox(dev, mailbox); - return err; - -put: - put_res(dev, slave, res_id, RES_EQ); - -unlock: - mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]); - return err; -} - -int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); - struct res_eq *eq; - int err; - - err = get_res(dev, slave, res_id, RES_EQ, &eq); - if (err) - return err; - - if (eq->com.from_state != RES_EQ_HW) { - err = -EINVAL; - goto ex_put; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - -ex_put: - put_res(dev, slave, res_id, RES_EQ); - return err; -} - -int mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int cqn = vhcr->in_modifier; - struct mlx4_cq_context *cqc = inbox->buf; - int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; - struct res_cq *cq; - struct res_mtt *mtt; - - err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq); - if (err) - return err; - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto out_move; - err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); - if (err) - goto out_put; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto out_put; - atomic_inc(&mtt->ref_count); - cq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_CQ, cqn); - return 0; - -out_put: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -out_move: - res_abort_move(dev, slave, RES_CQ, cqn); - return err; -} - -int mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int cqn = vhcr->in_modifier; - struct res_cq *cq; - - err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq); - if (err) - return err; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto out_move; - atomic_dec(&cq->mtt->ref_count); - res_end_move(dev, slave, RES_CQ, cqn); - return 0; - -out_move: - res_abort_move(dev, slave, RES_CQ, cqn); - return err; -} - -int mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int cqn = vhcr->in_modifier; - struct res_cq *cq; - int err; - - err = get_res(dev, slave, cqn, RES_CQ, &cq); - if (err) - return err; - - if (cq->com.from_state != RES_CQ_HW) - goto ex_put; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -ex_put: - put_res(dev, slave, cqn, RES_CQ); - - return err; -} - -static int handle_resize(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd, - struct res_cq *cq) -{ - int err; - struct res_mtt *orig_mtt; - struct res_mtt *mtt; - struct mlx4_cq_context *cqc = inbox->buf; - int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz; - - err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt); - if (err) - return err; - - if (orig_mtt != cq->mtt) { - err = -EINVAL; - goto ex_put; - } - - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_put; - - err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt); - if (err) - goto ex_put1; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put1; - atomic_dec(&orig_mtt->ref_count); - put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); - atomic_inc(&mtt->ref_count); - cq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - return 0; - -ex_put1: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -ex_put: - put_res(dev, slave, orig_mtt->com.res_id, RES_MTT); - - return err; - -} - -int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int cqn = vhcr->in_modifier; - struct res_cq *cq; - int err; - - err = get_res(dev, slave, cqn, RES_CQ, &cq); - if (err) - return err; - - if (cq->com.from_state != RES_CQ_HW) - goto ex_put; - - if (vhcr->op_modifier == 0) { - err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq); - goto ex_put; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -ex_put: - put_res(dev, slave, cqn, RES_CQ); - - return err; -} - -static int srq_get_mtt_size(struct mlx4_srq_context *srqc) -{ - int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; - int log_rq_stride = srqc->logstride & 7; - int page_shift = (srqc->log_page_size & 0x3f) + 12; - - if (log_srq_size + log_rq_stride + 4 < page_shift) - return 1; - - return 1 << (log_srq_size + log_rq_stride + 4 - page_shift); -} - -int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_mtt *mtt; - struct res_srq *srq; - struct mlx4_srq_context *srqc = inbox->buf; - int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz; - - if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff)) - return -EINVAL; - - err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq); - if (err) - return err; - err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); - if (err) - goto ex_abort; - err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc), - mtt); - if (err) - goto ex_put_mtt; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_put_mtt; - - atomic_inc(&mtt->ref_count); - srq->mtt = mtt; - put_res(dev, slave, mtt->com.res_id, RES_MTT); - res_end_move(dev, slave, RES_SRQ, srqn); - return 0; - -ex_put_mtt: - put_res(dev, slave, mtt->com.res_id, RES_MTT); -ex_abort: - res_abort_move(dev, slave, RES_SRQ, srqn); - - return err; -} - -int mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_srq *srq; - - err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq); - if (err) - return err; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_abort; - atomic_dec(&srq->mtt->ref_count); - if (srq->cq) - atomic_dec(&srq->cq->ref_count); - res_end_move(dev, slave, RES_SRQ, srqn); - - return 0; - -ex_abort: - res_abort_move(dev, slave, RES_SRQ, srqn); - - return err; -} - -int mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_srq *srq; - - err = get_res(dev, slave, srqn, RES_SRQ, &srq); - if (err) - return err; - if (srq->com.from_state != RES_SRQ_HW) { - err = -EBUSY; - goto out; - } - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - put_res(dev, slave, srqn, RES_SRQ); - return err; -} - -int mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int srqn = vhcr->in_modifier; - struct res_srq *srq; - - err = get_res(dev, slave, srqn, RES_SRQ, &srq); - if (err) - return err; - - if (srq->com.from_state != RES_SRQ_HW) { - err = -EBUSY; - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - put_res(dev, slave, srqn, RES_SRQ); - return err; -} - -int mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_qp *qp; - - err = get_res(dev, slave, qpn, RES_QP, &qp); - if (err) - return err; - if (qp->com.from_state != RES_QP_HW) { - err = -EBUSY; - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - put_res(dev, slave, qpn, RES_QP); - return err; -} - -int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_qp_context *context = inbox->buf + 8; - adjust_proxy_tun_qkey(dev, vhcr, context); - update_pkey_index(dev, slave, inbox); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -static int roce_verify_mac(struct mlx4_dev *dev, int slave, - struct mlx4_qp_context *qpc, - struct mlx4_cmd_mailbox *inbox) -{ - u64 mac; - int port; - u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - u8 sched = *(u8 *)(inbox->buf + 64); - u8 smac_ix; - - port = (sched >> 6 & 1) + 1; - if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { - smac_ix = qpc->pri_path.grh_mylmc & 0x7f; - if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) - return -ENOENT; - } - return 0; -} - -int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *qpc = inbox->buf + 8; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_qp *qp; - u8 orig_sched_queue; - __be32 orig_param3 = qpc->param3; - u8 orig_vlan_control = qpc->pri_path.vlan_control; - u8 orig_fvl_rx = qpc->pri_path.fvl_rx; - u8 orig_pri_path_fl = qpc->pri_path.fl; - u8 orig_vlan_index = qpc->pri_path.vlan_index; - u8 orig_feup = qpc->pri_path.feup; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); - if (err) - return err; - - if (roce_verify_mac(dev, slave, qpc, inbox)) - return -EINVAL; - - update_pkey_index(dev, slave, inbox); - update_gid(dev, inbox, (u8)slave); - adjust_proxy_tun_qkey(dev, vhcr, qpc); - orig_sched_queue = qpc->pri_path.sched_queue; - - err = get_res(dev, slave, qpn, RES_QP, &qp); - if (err) - return err; - if (qp->com.from_state != RES_QP_HW) { - err = -EBUSY; - goto out; - } - - /* do not modify vport QP params for RSS QPs */ - if (!(qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET))) { - err = update_vport_qp_param(dev, inbox, slave, qpn); - if (err) - goto out; - } - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -out: - /* if no error, save sched queue value passed in by VF. This is - * essentially the QOS value provided by the VF. This will be useful - * if we allow dynamic changes from VST back to VGT - */ - if (!err) { - qp->sched_queue = orig_sched_queue; - qp->param3 = orig_param3; - qp->vlan_control = orig_vlan_control; - qp->fvl_rx = orig_fvl_rx; - qp->pri_path_fl = orig_pri_path_fl; - qp->vlan_index = orig_vlan_index; - qp->feup = orig_feup; - } - put_res(dev, slave, qpn, RES_QP); - return err; -} - -int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave); - if (err) - return err; - - update_pkey_index(dev, slave, inbox); - update_gid(dev, inbox, (u8)slave); - adjust_proxy_tun_qkey(dev, vhcr, context); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave); - if (err) - return err; - - update_pkey_index(dev, slave, inbox); - update_gid(dev, inbox, (u8)slave); - adjust_proxy_tun_qkey(dev, vhcr, context); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - - -int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_qp_context *context = inbox->buf + 8; - adjust_proxy_tun_qkey(dev, vhcr, context); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave); - if (err) - return err; - - adjust_proxy_tun_qkey(dev, vhcr, context); - update_gid(dev, inbox, (u8)slave); - update_pkey_index(dev, slave, inbox); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct mlx4_qp_context *context = inbox->buf + 8; - - err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave); - if (err) - return err; - - adjust_proxy_tun_qkey(dev, vhcr, context); - update_gid(dev, inbox, (u8)slave); - update_pkey_index(dev, slave, inbox); - return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); -} - -int mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - int qpn = vhcr->in_modifier & 0x7fffff; - struct res_qp *qp; - - err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0); - if (err) - return err; - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - if (err) - goto ex_abort; - - atomic_dec(&qp->mtt->ref_count); - atomic_dec(&qp->rcq->ref_count); - atomic_dec(&qp->scq->ref_count); - if (qp->srq) - atomic_dec(&qp->srq->ref_count); - res_end_move(dev, slave, RES_QP, qpn); - return 0; - -ex_abort: - res_abort_move(dev, slave, RES_QP, qpn); - - return err; -} - -static struct res_gid *find_gid(struct mlx4_dev *dev, int slave, - struct res_qp *rqp, u8 *gid) -{ - struct res_gid *res; - - list_for_each_entry(res, &rqp->mcg_list, list) { - if (!memcmp(res->gid, gid, 16)) - return res; - } - return NULL; -} - -static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, - u8 *gid, enum mlx4_protocol prot, - enum mlx4_steer_type steer, u64 reg_id) -{ - struct res_gid *res; - int err; - - res = kzalloc(sizeof *res, GFP_KERNEL); - if (!res) - return -ENOMEM; - - spin_lock_irq(&rqp->mcg_spl); - if (find_gid(dev, slave, rqp, gid)) { - kfree(res); - err = -EEXIST; - } else { - memcpy(res->gid, gid, 16); - res->prot = prot; - res->steer = steer; - res->reg_id = reg_id; - list_add_tail(&res->list, &rqp->mcg_list); - err = 0; - } - spin_unlock_irq(&rqp->mcg_spl); - - return err; -} - -static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp, - u8 *gid, enum mlx4_protocol prot, - enum mlx4_steer_type steer, u64 *reg_id) -{ - struct res_gid *res; - int err; - - spin_lock_irq(&rqp->mcg_spl); - res = find_gid(dev, slave, rqp, gid); - if (!res || res->prot != prot || res->steer != steer) - err = -EINVAL; - else { - *reg_id = res->reg_id; - list_del(&res->list); - kfree(res); - err = 0; - } - spin_unlock_irq(&rqp->mcg_spl); - - return err; -} - -static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_loopback, enum mlx4_protocol prot, - enum mlx4_steer_type type, u64 *reg_id) -{ - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5], - block_loopback, prot, - reg_id); - case MLX4_STEERING_MODE_B0: - return mlx4_qp_attach_common(dev, qp, gid, - block_loopback, prot, type); - default: - return -EINVAL; - } -} - -static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot, enum mlx4_steer_type type, - u64 reg_id) -{ - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return mlx4_flow_detach(dev, reg_id); - case MLX4_STEERING_MODE_B0: - return mlx4_qp_detach_common(dev, qp, gid, prot, type); - default: - return -EINVAL; - } -} - -int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - struct mlx4_qp qp; /* dummy for calling attach/detach */ - u8 *gid = inbox->buf; - enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; - int err; - int qpn; - struct res_qp *rqp; - u64 reg_id = 0; - int attach = vhcr->op_modifier; - int block_loopback = vhcr->in_modifier >> 31; - u8 steer_type_mask = 2; - enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; - - qpn = vhcr->in_modifier & 0xffffff; - err = get_res(dev, slave, qpn, RES_QP, &rqp); - if (err) - return err; - - qp.qpn = qpn; - if (attach) { - err = qp_attach(dev, &qp, gid, block_loopback, prot, - type, ®_id); - if (err) { - pr_err("Fail to attach rule to qp 0x%x\n", qpn); - goto ex_put; - } - err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id); - if (err) - goto ex_detach; - } else { - err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id); - if (err) - goto ex_put; - - err = qp_detach(dev, &qp, gid, prot, type, reg_id); - if (err) - pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n", - qpn, (unsigned long long)reg_id); - } - put_res(dev, slave, qpn, RES_QP); - return err; - -ex_detach: - qp_detach(dev, &qp, gid, prot, type, reg_id); -ex_put: - put_res(dev, slave, qpn, RES_QP); - return err; -} - -/* - * MAC validation for Flow Steering rules. - * VF can attach rules only with a mac address which is assigned to it. - */ -static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, - struct list_head *rlist) -{ - struct mac_res *res, *tmp; - __be64 be_mac; - - /* make sure it isn't multicast or broadcast mac*/ - if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && - !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { - list_for_each_entry_safe(res, tmp, rlist, list) { - be_mac = cpu_to_be64(res->mac << 16); - if (!memcmp(&be_mac, eth_header->eth.dst_mac, ETH_ALEN)) - return 0; - } - pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", - eth_header->eth.dst_mac, slave); - return -EINVAL; - } - return 0; -} - -/* - * In case of missing eth header, append eth header with a MAC address - * assigned to the VF. - */ -static int add_eth_header(struct mlx4_dev *dev, int slave, - struct mlx4_cmd_mailbox *inbox, - struct list_head *rlist, int header_id) -{ - struct mac_res *res, *tmp; - u8 port; - struct mlx4_net_trans_rule_hw_ctrl *ctrl; - struct mlx4_net_trans_rule_hw_eth *eth_header; - struct mlx4_net_trans_rule_hw_ipv4 *ip_header; - struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; - __be64 be_mac = 0; - __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); - - ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; - port = ctrl->port; - eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); - - /* Clear a space in the inbox for eth header */ - switch (header_id) { - case MLX4_NET_TRANS_RULE_ID_IPV4: - ip_header = - (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); - memmove(ip_header, eth_header, - sizeof(*ip_header) + sizeof(*l4_header)); - break; - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) - (eth_header + 1); - memmove(l4_header, eth_header, sizeof(*l4_header)); - break; - default: - return -EINVAL; - } - list_for_each_entry_safe(res, tmp, rlist, list) { - if (port == res->port) { - be_mac = cpu_to_be64(res->mac << 16); - break; - } - } - if (!be_mac) { - pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d .\n", - port); - return -EINVAL; - } - - memset(eth_header, 0, sizeof(*eth_header)); - eth_header->size = sizeof(*eth_header) >> 2; - eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); - memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); - memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); - - return 0; - -} - -int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; - int err; - int qpn; - struct res_qp *rqp; - struct mlx4_net_trans_rule_hw_ctrl *ctrl; - struct _rule_hw *rule_header; - int header_id; - - if (dev->caps.steering_mode != - MLX4_STEERING_MODE_DEVICE_MANAGED) - return -EOPNOTSUPP; - - ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; - qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; - err = get_res(dev, slave, qpn, RES_QP, &rqp); - if (err) { - pr_err("Steering rule with qpn 0x%x rejected.\n", qpn); - return err; - } - rule_header = (struct _rule_hw *)(ctrl + 1); - header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); - - switch (header_id) { - case MLX4_NET_TRANS_RULE_ID_ETH: - if (validate_eth_header_mac(slave, rule_header, rlist)) { - err = -EINVAL; - goto err_put; - } - break; - case MLX4_NET_TRANS_RULE_ID_IB: - break; - case MLX4_NET_TRANS_RULE_ID_IPV4: - case MLX4_NET_TRANS_RULE_ID_TCP: - case MLX4_NET_TRANS_RULE_ID_UDP: - pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n"); - if (add_eth_header(dev, slave, inbox, rlist, header_id)) { - err = -EINVAL; - goto err_put; - } - vhcr->in_modifier += - sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; - break; - default: - pr_err("Corrupted mailbox.\n"); - err = -EINVAL; - goto err_put; - } - - err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, - vhcr->in_modifier, 0, - MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - goto err_put; - - err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); - if (err) { - mlx4_err(dev, "Fail to add flow steering resources.\n "); - /* detach rule*/ - mlx4_cmd(dev, vhcr->out_param, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - goto err_put; - } - atomic_inc(&rqp->ref_count); -err_put: - put_res(dev, slave, qpn, RES_QP); - return err; -} - -int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - struct res_qp *rqp; - struct res_fs_rule *rrule; - - if (dev->caps.steering_mode != - MLX4_STEERING_MODE_DEVICE_MANAGED) - return -EOPNOTSUPP; - - err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); - if (err) - return err; - /* Release the rule form busy state before removal */ - put_res(dev, slave, vhcr->in_param, RES_FS_RULE); - err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); - if (err) - return err; - - err = mlx4_cmd(dev, vhcr->in_param, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (!err) { - err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, - 0); - atomic_dec(&rqp->ref_count); - - if (err) { - mlx4_err(dev, "Fail to remove flow steering resources.\n "); - goto out; - } - } - -out: - put_res(dev, slave, rrule->qpn, RES_QP); - return err; -} - -enum { - BUSY_MAX_RETRIES = 10 -}; - -int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave, - struct mlx4_vhcr *vhcr, - struct mlx4_cmd_mailbox *inbox, - struct mlx4_cmd_mailbox *outbox, - struct mlx4_cmd_info *cmd) -{ - int err; - - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); - - return err; -} - -static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) -{ - struct res_gid *rgid; - struct res_gid *tmp; - struct mlx4_qp qp; /* dummy for calling attach/detach */ - - list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { - switch (dev->caps.steering_mode) { - case MLX4_STEERING_MODE_DEVICE_MANAGED: - mlx4_flow_detach(dev, rgid->reg_id); - break; - case MLX4_STEERING_MODE_B0: - qp.qpn = rqp->local_qpn; - (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, - rgid->prot, rgid->steer); - break; - } - list_del(&rgid->list); - kfree(rgid); - } -} - -static int _move_all_busy(struct mlx4_dev *dev, int slave, - enum mlx4_resource type, int print) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = - &priv->mfunc.master.res_tracker; - struct list_head *rlist = &tracker->slave_list[slave].res_list[type]; - struct res_common *r; - struct res_common *tmp; - int busy; - - busy = 0; - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(r, tmp, rlist, list) { - if (r->owner == slave) { - if (!r->removing) { - if (r->state == RES_ANY_BUSY) { - if (print) - mlx4_dbg(dev, - "%s id 0x%llx is busy\n", - ResourceType(type), - (unsigned long long)r->res_id); - ++busy; - } else { - r->from_state = r->state; - r->state = RES_ANY_BUSY; - r->removing = 1; - } - } - } - } - spin_unlock_irq(mlx4_tlock(dev)); - - return busy; -} - -static int move_all_busy(struct mlx4_dev *dev, int slave, - enum mlx4_resource type) -{ - unsigned long begin; - int busy; - - begin = jiffies; - do { - busy = _move_all_busy(dev, slave, type, 0); - if (time_after(jiffies, begin + 5 * HZ)) - break; - if (busy) - cond_resched(); - } while (busy); - - if (busy) - busy = _move_all_busy(dev, slave, type, 1); - - return busy; -} -static void rem_slave_qps(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *qp_list = - &tracker->slave_list[slave].res_list[RES_QP]; - struct res_qp *qp; - struct res_qp *tmp; - int state; - u64 in_param; - int qpn; - int err; - - err = move_all_busy(dev, slave, RES_QP); - if (err) - mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy" - "for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(qp, tmp, qp_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (qp->com.owner == slave) { - qpn = qp->com.res_id; - detach_qp(dev, slave, qp); - state = qp->com.from_state; - while (state != 0) { - switch (state) { - case RES_QP_RESERVED: - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&qp->com.node, - &tracker->res_tree[RES_QP]); - list_del(&qp->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - if (!valid_reserved(dev, slave, qpn)) { - __mlx4_qp_release_range(dev, qpn, 1); - mlx4_release_resource(dev, slave, - RES_QP, 1, 0); - } - kfree(qp); - state = 0; - break; - case RES_QP_MAPPED: - if (!valid_reserved(dev, slave, qpn)) - __mlx4_qp_free_icm(dev, qpn); - state = RES_QP_RESERVED; - break; - case RES_QP_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, - qp->local_qpn, 2, - MLX4_CMD_2RST_QP, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_qps: failed" - " to move slave %d qpn %d to" - " reset\n", slave, - qp->local_qpn); - atomic_dec(&qp->rcq->ref_count); - atomic_dec(&qp->scq->ref_count); - atomic_dec(&qp->mtt->ref_count); - if (qp->srq) - atomic_dec(&qp->srq->ref_count); - state = RES_QP_MAPPED; - break; - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_srqs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *srq_list = - &tracker->slave_list[slave].res_list[RES_SRQ]; - struct res_srq *srq; - struct res_srq *tmp; - int state; - u64 in_param; - LIST_HEAD(tlist); - int srqn; - int err; - - err = move_all_busy(dev, slave, RES_SRQ); - if (err) - mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(srq, tmp, srq_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (srq->com.owner == slave) { - srqn = srq->com.res_id; - state = srq->com.from_state; - while (state != 0) { - switch (state) { - case RES_SRQ_ALLOCATED: - __mlx4_srq_free_icm(dev, srqn); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&srq->com.node, - &tracker->res_tree[RES_SRQ]); - list_del(&srq->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, - RES_SRQ, 1, 0); - kfree(srq); - state = 0; - break; - - case RES_SRQ_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, srqn, 1, - MLX4_CMD_HW2SW_SRQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_srqs: failed" - " to move slave %d srq %d to" - " SW ownership\n", - slave, srqn); - - atomic_dec(&srq->mtt->ref_count); - if (srq->cq) - atomic_dec(&srq->cq->ref_count); - state = RES_SRQ_ALLOCATED; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_cqs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *cq_list = - &tracker->slave_list[slave].res_list[RES_CQ]; - struct res_cq *cq; - struct res_cq *tmp; - int state; - u64 in_param; - LIST_HEAD(tlist); - int cqn; - int err; - - err = move_all_busy(dev, slave, RES_CQ); - if (err) - mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(cq, tmp, cq_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) { - cqn = cq->com.res_id; - state = cq->com.from_state; - while (state != 0) { - switch (state) { - case RES_CQ_ALLOCATED: - __mlx4_cq_free_icm(dev, cqn); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&cq->com.node, - &tracker->res_tree[RES_CQ]); - list_del(&cq->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, - RES_CQ, 1, 0); - kfree(cq); - state = 0; - break; - - case RES_CQ_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, cqn, 1, - MLX4_CMD_HW2SW_CQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_cqs: failed" - " to move slave %d cq %d to" - " SW ownership\n", - slave, cqn); - atomic_dec(&cq->mtt->ref_count); - state = RES_CQ_ALLOCATED; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_mrs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *mpt_list = - &tracker->slave_list[slave].res_list[RES_MPT]; - struct res_mpt *mpt; - struct res_mpt *tmp; - int state; - u64 in_param; - LIST_HEAD(tlist); - int mptn; - int err; - - err = move_all_busy(dev, slave, RES_MPT); - if (err) - mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (mpt->com.owner == slave) { - mptn = mpt->com.res_id; - state = mpt->com.from_state; - while (state != 0) { - switch (state) { - case RES_MPT_RESERVED: - __mlx4_mpt_release(dev, mpt->key); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&mpt->com.node, - &tracker->res_tree[RES_MPT]); - list_del(&mpt->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, - RES_MPT, 1, 0); - kfree(mpt); - state = 0; - break; - - case RES_MPT_MAPPED: - __mlx4_mpt_free_icm(dev, mpt->key); - state = RES_MPT_RESERVED; - break; - - case RES_MPT_HW: - in_param = slave; - err = mlx4_cmd(dev, in_param, mptn, 0, - MLX4_CMD_HW2SW_MPT, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_mrs: failed" - " to move slave %d mpt %d to" - " SW ownership\n", - slave, mptn); - if (mpt->mtt) - atomic_dec(&mpt->mtt->ref_count); - state = RES_MPT_MAPPED; - break; - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_mtts(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = - &priv->mfunc.master.res_tracker; - struct list_head *mtt_list = - &tracker->slave_list[slave].res_list[RES_MTT]; - struct res_mtt *mtt; - struct res_mtt *tmp; - int state; - LIST_HEAD(tlist); - int base; - int err; - - err = move_all_busy(dev, slave, RES_MTT); - if (err) - mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (mtt->com.owner == slave) { - base = mtt->com.res_id; - state = mtt->com.from_state; - while (state != 0) { - switch (state) { - case RES_MTT_ALLOCATED: - __mlx4_free_mtt_range(dev, base, - mtt->order); - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&mtt->com.node, - &tracker->res_tree[RES_MTT]); - list_del(&mtt->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_release_resource(dev, slave, RES_MTT, - 1 << mtt->order, 0); - kfree(mtt); - state = 0; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = - &priv->mfunc.master.res_tracker; - struct list_head *fs_rule_list = - &tracker->slave_list[slave].res_list[RES_FS_RULE]; - struct res_fs_rule *fs_rule; - struct res_fs_rule *tmp; - int state; - u64 base; - int err; - - err = move_all_busy(dev, slave, RES_FS_RULE); - if (err) - mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n", - slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (fs_rule->com.owner == slave) { - base = fs_rule->com.res_id; - state = fs_rule->com.from_state; - while (state != 0) { - switch (state) { - case RES_FS_RULE_ALLOCATED: - /* detach rule */ - err = mlx4_cmd(dev, base, 0, 0, - MLX4_QP_FLOW_STEERING_DETACH, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&fs_rule->com.node, - &tracker->res_tree[RES_FS_RULE]); - list_del(&fs_rule->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - kfree(fs_rule); - state = 0; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_eqs(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *eq_list = - &tracker->slave_list[slave].res_list[RES_EQ]; - struct res_eq *eq; - struct res_eq *tmp; - int err; - int state; - LIST_HEAD(tlist); - int eqn; - struct mlx4_cmd_mailbox *mailbox; - - err = move_all_busy(dev, slave, RES_EQ); - if (err) - mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(eq, tmp, eq_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (eq->com.owner == slave) { - eqn = eq->com.res_id; - state = eq->com.from_state; - while (state != 0) { - switch (state) { - case RES_EQ_RESERVED: - spin_lock_irq(mlx4_tlock(dev)); - rb_erase(&eq->com.node, - &tracker->res_tree[RES_EQ]); - list_del(&eq->com.list); - spin_unlock_irq(mlx4_tlock(dev)); - kfree(eq); - state = 0; - break; - - case RES_EQ_HW: - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - cond_resched(); - continue; - } - err = mlx4_cmd_box(dev, slave, 0, - eqn & 0xff, 0, - MLX4_CMD_HW2SW_EQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); - if (err) - mlx4_dbg(dev, "rem_slave_eqs: failed" - " to move slave %d eqs %d to" - " SW ownership\n", slave, eqn); - mlx4_free_cmd_mailbox(dev, mailbox); - atomic_dec(&eq->mtt->ref_count); - state = RES_EQ_RESERVED; - break; - - default: - state = 0; - } - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -static void rem_slave_counters(struct mlx4_dev *dev, int slave) -{ - __mlx4_slave_counters_free(dev, slave); -} - -static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct list_head *xrcdn_list = - &tracker->slave_list[slave].res_list[RES_XRCD]; - struct res_xrcdn *xrcd; - struct res_xrcdn *tmp; - int err; - int xrcdn; - - err = move_all_busy(dev, slave, RES_XRCD); - if (err) - mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns to " - "busy for slave %d\n", slave); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { - if (xrcd->com.owner == slave) { - xrcdn = xrcd->com.res_id; - rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]); - list_del(&xrcd->com.list); - kfree(xrcd); - __mlx4_xrcd_free(dev, xrcdn); - } - } - spin_unlock_irq(mlx4_tlock(dev)); -} - -void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); - rem_slave_macs(dev, slave); - rem_slave_vlans(dev, slave); - rem_slave_fs_rule(dev, slave); - rem_slave_qps(dev, slave); - rem_slave_srqs(dev, slave); - rem_slave_cqs(dev, slave); - rem_slave_mrs(dev, slave); - rem_slave_eqs(dev, slave); - rem_slave_mtts(dev, slave); - rem_slave_counters(dev, slave); - rem_slave_xrcdns(dev, slave); - mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); -} - -void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) -{ - struct mlx4_vf_immed_vlan_work *work = - container_of(_work, struct mlx4_vf_immed_vlan_work, work); - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_update_qp_context *upd_context; - struct mlx4_dev *dev = &work->priv->dev; - struct mlx4_resource_tracker *tracker = - &work->priv->mfunc.master.res_tracker; - struct list_head *qp_list = - &tracker->slave_list[work->slave].res_list[RES_QP]; - struct res_qp *qp; - struct res_qp *tmp; - u64 qp_path_mask_vlan_ctrl = - ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED)); - - u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) | - (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) | - (1ULL << MLX4_UPD_QP_PATH_MASK_CV) | - (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) | - (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) | - (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) | - (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE)); - - int err; - int port, errors = 0; - u8 vlan_control; - - if (mlx4_is_slave(dev)) { - mlx4_warn(dev, "Trying to update-qp in slave %d\n", - work->slave); - goto out; - } - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - goto out; - - if (!work->vlan_id) - vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; - else - vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | - MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; - - upd_context = mailbox->buf; - upd_context->qp_mask = cpu_to_be64(MLX4_UPD_QP_MASK_VSD); - - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(qp, tmp, qp_list, com.list) { - spin_unlock_irq(mlx4_tlock(dev)); - if (qp->com.owner == work->slave) { - if (qp->com.from_state != RES_QP_HW || - !qp->sched_queue || /* no INIT2RTR trans yet */ - mlx4_is_qp_reserved(dev, qp->local_qpn) || - qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) { - spin_lock_irq(mlx4_tlock(dev)); - continue; - } - port = (qp->sched_queue >> 6 & 1) + 1; - if (port != work->port) { - spin_lock_irq(mlx4_tlock(dev)); - continue; - } - if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff)) - upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask); - else - upd_context->primary_addr_path_mask = - cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl); - if (work->vlan_id == MLX4_VGT) { - upd_context->qp_context.param3 = qp->param3; - upd_context->qp_context.pri_path.vlan_control = qp->vlan_control; - upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx; - upd_context->qp_context.pri_path.vlan_index = qp->vlan_index; - upd_context->qp_context.pri_path.fl = qp->pri_path_fl; - upd_context->qp_context.pri_path.feup = qp->feup; - upd_context->qp_context.pri_path.sched_queue = - qp->sched_queue; - } else { - upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN); - upd_context->qp_context.pri_path.vlan_control = vlan_control; - upd_context->qp_context.pri_path.vlan_index = work->vlan_ix; - upd_context->qp_context.pri_path.fvl_rx = - qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN; - upd_context->qp_context.pri_path.fl = - qp->pri_path_fl | MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN; - upd_context->qp_context.pri_path.feup = - qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; - upd_context->qp_context.pri_path.sched_queue = - qp->sched_queue & 0xC7; - upd_context->qp_context.pri_path.sched_queue |= - ((work->qos & 0x7) << 3); - } - - err = mlx4_cmd(dev, mailbox->dma, - qp->local_qpn & 0xffffff, - 0, MLX4_CMD_UPDATE_QP, - MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); - if (err) { - mlx4_info(dev, "UPDATE_QP failed for slave %d, " - "port %d, qpn %d (%d)\n", - work->slave, port, qp->local_qpn, - err); - errors++; - } - } - spin_lock_irq(mlx4_tlock(dev)); - } - spin_unlock_irq(mlx4_tlock(dev)); - mlx4_free_cmd_mailbox(dev, mailbox); - - if (errors) - mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n", - errors, work->slave, work->port); - - /* unregister previous vlan_id if needed and we had no errors - * while updating the QPs - */ - if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors && - NO_INDX != work->orig_vlan_ix) - __mlx4_unregister_vlan(&work->priv->dev, work->port, - work->orig_vlan_id); -out: - kfree(work); - return; -} - diff --git a/sys/ofed/drivers/net/mlx4/sense.c b/sys/ofed/drivers/net/mlx4/sense.c deleted file mode 100644 index 3615e6513e9f..000000000000 --- a/sys/ofed/drivers/net/mlx4/sense.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2007, 2014 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/errno.h> -#include <linux/if_ether.h> - -#include <linux/mlx4/cmd.h> - -#include "mlx4.h" - -int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, - enum mlx4_port_type *type) -{ - u64 out_param; - int err = 0; - - err = mlx4_cmd_imm(dev, 0, &out_param, port, 0, - MLX4_CMD_SENSE_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) { - mlx4_err(dev, "Sense command failed for port: %d\n", port); - return err; - } - - if (out_param > 2) { - mlx4_err(dev, "Sense returned illegal value: 0x%llx\n", (unsigned long long)out_param); - return -EINVAL; - } - - *type = out_param; - return 0; -} - -void mlx4_do_sense_ports(struct mlx4_dev *dev, - enum mlx4_port_type *stype, - enum mlx4_port_type *defaults) -{ - struct mlx4_sense *sense = &mlx4_priv(dev)->sense; - int err; - int i; - - for (i = 1; i <= dev->caps.num_ports; i++) { - stype[i - 1] = 0; - if (sense->do_sense_port[i] && sense->sense_allowed[i] && - dev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { - err = mlx4_SENSE_PORT(dev, i, &stype[i - 1]); - if (err) - stype[i - 1] = defaults[i - 1]; - } else - stype[i - 1] = defaults[i - 1]; - } - - /* - * If sensed nothing, remain in current configuration. - */ - for (i = 0; i < dev->caps.num_ports; i++) - stype[i] = stype[i] ? stype[i] : defaults[i]; - -} - -static void mlx4_sense_port(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mlx4_sense *sense = container_of(delay, struct mlx4_sense, - sense_poll); - struct mlx4_dev *dev = sense->dev; - struct mlx4_priv *priv = mlx4_priv(dev); - enum mlx4_port_type stype[MLX4_MAX_PORTS]; - - mutex_lock(&priv->port_mutex); - mlx4_do_sense_ports(dev, stype, &dev->caps.port_type[1]); - - if (mlx4_check_port_params(dev, stype)) - goto sense_again; - - if (mlx4_change_port_types(dev, stype)) - mlx4_err(dev, "Failed to change port_types\n"); - -sense_again: - mutex_unlock(&priv->port_mutex); - queue_delayed_work(mlx4_wq , &sense->sense_poll, - round_jiffies_relative(MLX4_SENSE_RANGE)); -} - -void mlx4_start_sense(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_sense *sense = &priv->sense; - - if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) - return; - - queue_delayed_work(mlx4_wq , &sense->sense_poll, - round_jiffies_relative(MLX4_SENSE_RANGE)); -} - -void mlx4_stop_sense(struct mlx4_dev *dev) -{ - cancel_delayed_work_sync(&mlx4_priv(dev)->sense.sense_poll); -} - -void mlx4_sense_init(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_sense *sense = &priv->sense; - int port; - - sense->dev = dev; - for (port = 1; port <= dev->caps.num_ports; port++) - sense->do_sense_port[port] = 1; - - INIT_DEFERRABLE_WORK(&sense->sense_poll, mlx4_sense_port); -} diff --git a/sys/ofed/drivers/net/mlx4/srq.c b/sys/ofed/drivers/net/mlx4/srq.c deleted file mode 100644 index fcb6255c7e62..000000000000 --- a/sys/ofed/drivers/net/mlx4/srq.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2007, 2008, 2014 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/mlx4/cmd.h> -#include <linux/mlx4/srq.h> -#include <linux/module.h> -#include <linux/gfp.h> - -#include "mlx4.h" -#include "icm.h" - -void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - struct mlx4_srq *srq; - - spin_lock(&srq_table->lock); - - srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1)); - if (srq) - atomic_inc(&srq->refcount); - - spin_unlock(&srq_table->lock); - - if (!srq) { - mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn); - return; - } - - srq->event(srq, event_type); - - if (atomic_dec_and_test(&srq->refcount)) - complete(&srq->free); -} - -static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int srq_num) -{ - return mlx4_cmd(dev, mailbox->dma, srq_num, 0, - MLX4_CMD_SW2HW_SRQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); -} - -static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int srq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, srq_num, - mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark) -{ - return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); -} - -static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int srq_num) -{ - return mlx4_cmd_box(dev, 0, mailbox->dma, srq_num, 0, MLX4_CMD_QUERY_SRQ, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); -} - -int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - int err; - - - *srqn = mlx4_bitmap_alloc(&srq_table->bitmap); - if (*srqn == -1) - return -ENOMEM; - - err = mlx4_table_get(dev, &srq_table->table, *srqn); - if (err) - goto err_out; - - err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn); - if (err) - goto err_put; - return 0; - -err_put: - mlx4_table_put(dev, &srq_table->table, *srqn); - -err_out: - mlx4_bitmap_free(&srq_table->bitmap, *srqn, MLX4_NO_RR); - return err; -} - -static int mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn) -{ - u64 out_param; - int err; - - if (mlx4_is_mfunc(dev)) { - err = mlx4_cmd_imm(dev, 0, &out_param, RES_SRQ, - RES_OP_RESERVE_AND_MAP, - MLX4_CMD_ALLOC_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); - if (!err) - *srqn = get_param_l(&out_param); - - return err; - } - return __mlx4_srq_alloc_icm(dev, srqn); -} - -void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - - mlx4_table_put(dev, &srq_table->cmpt_table, srqn); - mlx4_table_put(dev, &srq_table->table, srqn); - mlx4_bitmap_free(&srq_table->bitmap, srqn, MLX4_NO_RR); -} - -static void mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn) -{ - u64 in_param = 0; - - if (mlx4_is_mfunc(dev)) { - set_param_l(&in_param, srqn); - if (mlx4_cmd(dev, in_param, RES_SRQ, RES_OP_RESERVE_AND_MAP, - MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) - mlx4_warn(dev, "Failed freeing cq:%d\n", srqn); - return; - } - __mlx4_srq_free_icm(dev, srqn); -} - -int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, - struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_srq_context *srq_context; - u64 mtt_addr; - int err; - - err = mlx4_srq_alloc_icm(dev, &srq->srqn); - if (err) - return err; - - spin_lock_irq(&srq_table->lock); - err = radix_tree_insert(&srq_table->tree, srq->srqn, srq); - spin_unlock_irq(&srq_table->lock); - if (err) - goto err_icm; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - err = PTR_ERR(mailbox); - goto err_radix; - } - - srq_context = mailbox->buf; - memset(srq_context, 0, sizeof *srq_context); - - srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) | - srq->srqn); - srq_context->logstride = srq->wqe_shift - 4; - srq_context->xrcd = cpu_to_be16(xrcd); - srq_context->pg_offset_cqn = cpu_to_be32(cqn & 0xffffff); - srq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; - - mtt_addr = mlx4_mtt_addr(dev, mtt); - srq_context->mtt_base_addr_h = mtt_addr >> 32; - srq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); - srq_context->pd = cpu_to_be32(pdn); - srq_context->db_rec_addr = cpu_to_be64(db_rec); - - err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn); - mlx4_free_cmd_mailbox(dev, mailbox); - if (err) - goto err_radix; - - atomic_set(&srq->refcount, 1); - init_completion(&srq->free); - - return 0; - -err_radix: - spin_lock_irq(&srq_table->lock); - radix_tree_delete(&srq_table->tree, srq->srqn); - spin_unlock_irq(&srq_table->lock); - -err_icm: - mlx4_srq_free_icm(dev, srq->srqn); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_srq_alloc); - -void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - int err; - - err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn); - if (err) - mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn); - - spin_lock_irq(&srq_table->lock); - radix_tree_delete(&srq_table->tree, srq->srqn); - spin_unlock_irq(&srq_table->lock); - - if (atomic_dec_and_test(&srq->refcount)) - complete(&srq->free); - wait_for_completion(&srq->free); - - mlx4_srq_free_icm(dev, srq->srqn); -} -EXPORT_SYMBOL_GPL(mlx4_srq_free); - -int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark) -{ - return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark); -} -EXPORT_SYMBOL_GPL(mlx4_srq_arm); - -int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_srq_context *srq_context; - int err; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - srq_context = mailbox->buf; - - err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn); - if (err) - goto err_out; - *limit_watermark = be16_to_cpu(srq_context->limit_watermark); - -err_out: - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL_GPL(mlx4_srq_query); - -int mlx4_init_srq_table(struct mlx4_dev *dev) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - int err; - - spin_lock_init(&srq_table->lock); - INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC); - if (mlx4_is_slave(dev)) - return 0; - - err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs, - dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0); - if (err) - return err; - - return 0; -} - -void mlx4_cleanup_srq_table(struct mlx4_dev *dev) -{ - if (mlx4_is_slave(dev)) - return; - mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap); -} - -struct mlx4_srq *mlx4_srq_lookup(struct mlx4_dev *dev, u32 srqn) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - struct mlx4_srq *srq; - unsigned long flags; - - spin_lock_irqsave(&srq_table->lock, flags); - srq = radix_tree_lookup(&srq_table->tree, - srqn & (dev->caps.num_srqs - 1)); - spin_unlock_irqrestore(&srq_table->lock, flags); - - return srq; -} -EXPORT_SYMBOL_GPL(mlx4_srq_lookup); diff --git a/sys/ofed/drivers/net/mlx4/sys_tune.c b/sys/ofed/drivers/net/mlx4/sys_tune.c deleted file mode 100644 index 87eb30e6ccfe..000000000000 --- a/sys/ofed/drivers/net/mlx4/sys_tune.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 2010, 2014 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/sched.h> -#include <linux/mutex.h> -#include <asm/atomic.h> - -#include "mlx4.h" - -#if defined(CONFIG_X86) && defined(CONFIG_APM_MODULE) - -/* Each CPU is put into a group. In most cases, the group number is - * equal to the CPU number of one of the CPUs in the group. The - * exception is group NR_CPUS which is the default group. This is - * protected by sys_tune_startup_mutex. */ -DEFINE_PER_CPU(int, idle_cpu_group) = NR_CPUS; - -/* For each group, a count of the number of CPUs in the group which - * are known to be busy. A busy CPU might be running the busy loop - * below or general kernel code. The count is decremented on entry to - * the old pm_idle handler and incremented on exit. The aim is to - * avoid the count going to zero or negative. This situation can - * occur temporarily during module unload or CPU hot-plug but - * normality will be restored when the affected CPUs next exit the - * idle loop. */ -static atomic_t busy_cpu_count[NR_CPUS+1]; - -/* A workqueue item to be executed to cause the CPU to exit from the - * idle loop. */ -DEFINE_PER_CPU(struct work_struct, sys_tune_cpu_work); - -#define sys_tune_set_state(CPU,STATE) \ - do { } while(0) - - -/* A mutex to protect most of the module datastructures. */ -static DEFINE_MUTEX(sys_tune_startup_mutex); - -/* The old pm_idle handler. */ -static void (*old_pm_idle)(void) = NULL; - -static void sys_tune_pm_idle(void) -{ - atomic_t *busy_cpus_ptr; - int busy_cpus; - int cpu = smp_processor_id(); - - busy_cpus_ptr = &(busy_cpu_count[per_cpu(idle_cpu_group, cpu)]); - - sys_tune_set_state(cpu, 2); - - local_irq_enable(); - while (!need_resched()) { - busy_cpus = atomic_read(busy_cpus_ptr); - - /* If other CPUs in this group are busy then let this - * CPU go idle. We mustn't let the number of busy - * CPUs drop below 1. */ - if ( busy_cpus > 1 && - old_pm_idle != NULL && - ( atomic_cmpxchg(busy_cpus_ptr, busy_cpus, - busy_cpus-1) == busy_cpus ) ) { - local_irq_disable(); - sys_tune_set_state(cpu, 3); - /* This check might not be necessary, but it - * seems safest to include it because there - * might be a kernel version which requires - * it. */ - if (need_resched()) - local_irq_enable(); - else - old_pm_idle(); - /* This CPU is busy again. */ - sys_tune_set_state(cpu, 1); - atomic_add(1, busy_cpus_ptr); - return; - } - - cpu_relax(); - } - sys_tune_set_state(cpu, 0); -} - - -void sys_tune_work_func(struct work_struct *work) -{ - /* Do nothing. Since this function is running in process - * context, the idle thread isn't running on this CPU. */ -} - - -#ifdef CONFIG_SMP -static void sys_tune_smp_call(void *info) -{ - schedule_work(&get_cpu_var(sys_tune_cpu_work)); - put_cpu_var(sys_tune_cpu_work); -} -#endif - - -#ifdef CONFIG_SMP -static void sys_tune_refresh(void) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) - on_each_cpu(&sys_tune_smp_call, NULL, 0, 1); -#else - on_each_cpu(&sys_tune_smp_call, NULL, 1); -#endif -} -#else -static void sys_tune_refresh(void) -{ - /* The current thread is executing on the one and only CPU so - * the idle thread isn't running. */ -} -#endif - - - -static int sys_tune_cpu_group(int cpu) -{ -#ifdef CONFIG_SMP - const cpumask_t *mask; - int other_cpu; - int group; - -#if defined(topology_thread_cpumask) && defined(ST_HAVE_EXPORTED_CPU_SIBLING_MAP) - /* Keep one hyperthread busy per core. */ - mask = topology_thread_cpumask(cpu); -#else - return cpu; -#endif - for_each_cpu_mask(cpu, *(mask)) { - group = per_cpu(idle_cpu_group, other_cpu); - if (group != NR_CPUS) - return group; - } -#endif - - return cpu; -} - - -static void sys_tune_add_cpu(int cpu) -{ - int group; - - /* Do nothing if this CPU has already been added. */ - if (per_cpu(idle_cpu_group, cpu) != NR_CPUS) - return; - - group = sys_tune_cpu_group(cpu); - per_cpu(idle_cpu_group, cpu) = group; - atomic_inc(&(busy_cpu_count[group])); - -} - -static void sys_tune_del_cpu(int cpu) -{ - - int group; - - if (per_cpu(idle_cpu_group, cpu) == NR_CPUS) - return; - - group = per_cpu(idle_cpu_group, cpu); - /* If the CPU was busy, this can cause the count to drop to - * zero. To rectify this, we need to cause one of the other - * CPUs in the group to exit the idle loop. If the CPU was - * not busy then this causes the contribution for this CPU to - * go to -1 which can cause the overall count to drop to zero - * or go negative. To rectify this situation we need to cause - * this CPU to exit the idle loop. */ - atomic_dec(&(busy_cpu_count[group])); - per_cpu(idle_cpu_group, cpu) = NR_CPUS; - -} - - -static int sys_tune_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - int cpu = (long)hcpu; - - switch(action) { -#ifdef CPU_ONLINE_FROZEN - case CPU_ONLINE_FROZEN: -#endif - case CPU_ONLINE: - mutex_lock(&sys_tune_startup_mutex); - sys_tune_add_cpu(cpu); - mutex_unlock(&sys_tune_startup_mutex); - /* The CPU might have already entered the idle loop in - * the wrong group. Make sure it exits the idle loop - * so that it picks up the correct group. */ - sys_tune_refresh(); - break; - -#ifdef CPU_DEAD_FROZEN - case CPU_DEAD_FROZEN: -#endif - case CPU_DEAD: - mutex_lock(&sys_tune_startup_mutex); - sys_tune_del_cpu(cpu); - mutex_unlock(&sys_tune_startup_mutex); - /* The deleted CPU may have been the only busy CPU in - * the group. Make sure one of the other CPUs in the - * group exits the idle loop. */ - sys_tune_refresh(); - break; - } - return NOTIFY_OK; -} - - -static struct notifier_block sys_tune_cpu_nb = { - .notifier_call = sys_tune_cpu_notify, -}; - - -static void sys_tune_ensure_init(void) -{ - BUG_ON (old_pm_idle != NULL); - - /* Atomically update pm_idle to &sys_tune_pm_idle. The old value - * is stored in old_pm_idle before installing the new - * handler. */ - do { - old_pm_idle = pm_idle; - } while (cmpxchg(&pm_idle, old_pm_idle, &sys_tune_pm_idle) != - old_pm_idle); -} -#endif - -void sys_tune_fini(void) -{ -#if defined(CONFIG_X86) && defined(CONFIG_APM_MODULE) - void (*old)(void); - int cpu; - - unregister_cpu_notifier(&sys_tune_cpu_nb); - - mutex_lock(&sys_tune_startup_mutex); - - - old = cmpxchg(&pm_idle, &sys_tune_pm_idle, old_pm_idle); - - for_each_online_cpu(cpu) - sys_tune_del_cpu(cpu); - - mutex_unlock(&sys_tune_startup_mutex); - - /* Our handler may still be executing on other CPUs. - * Schedule this thread on all CPUs to make sure all - * idle threads get interrupted. */ - sys_tune_refresh(); - - /* Make sure the work item has finished executing on all CPUs. - * This in turn ensures that all idle threads have been - * interrupted. */ - flush_scheduled_work(); -#endif /* CONFIG_X86 */ -} - -void sys_tune_init(void) -{ -#if defined(CONFIG_X86) && defined(CONFIG_APM_MODULE) - int cpu; - - for_each_possible_cpu(cpu) { - INIT_WORK(&per_cpu(sys_tune_cpu_work, cpu), - sys_tune_work_func); - } - - /* Start by registering the handler to ensure we don't miss - * any updates. */ - register_cpu_notifier(&sys_tune_cpu_nb); - - mutex_lock(&sys_tune_startup_mutex); - - for_each_online_cpu(cpu) - sys_tune_add_cpu(cpu); - - sys_tune_ensure_init(); - - - mutex_unlock(&sys_tune_startup_mutex); - - /* Ensure our idle handler starts to run. */ - sys_tune_refresh(); -#endif -} - diff --git a/sys/ofed/include/linux/mlx4/cmd.h b/sys/ofed/include/linux/mlx4/cmd.h deleted file mode 100644 index e2d41bcf417a..000000000000 --- a/sys/ofed/include/linux/mlx4/cmd.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (c) 2006 Cisco Systems, Inc. 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. - */ - -#ifndef MLX4_CMD_H -#define MLX4_CMD_H - -#include <linux/dma-mapping.h> -#include <linux/types.h> - -enum { - /* initialization and general commands */ - MLX4_CMD_SYS_EN = 0x1, - MLX4_CMD_SYS_DIS = 0x2, - MLX4_CMD_MAP_FA = 0xfff, - MLX4_CMD_UNMAP_FA = 0xffe, - MLX4_CMD_RUN_FW = 0xff6, - MLX4_CMD_MOD_STAT_CFG = 0x34, - MLX4_CMD_QUERY_DEV_CAP = 0x3, - MLX4_CMD_QUERY_FW = 0x4, - MLX4_CMD_ENABLE_LAM = 0xff8, - MLX4_CMD_DISABLE_LAM = 0xff7, - MLX4_CMD_QUERY_DDR = 0x5, - MLX4_CMD_QUERY_ADAPTER = 0x6, - MLX4_CMD_INIT_HCA = 0x7, - MLX4_CMD_CLOSE_HCA = 0x8, - MLX4_CMD_INIT_PORT = 0x9, - MLX4_CMD_CLOSE_PORT = 0xa, - MLX4_CMD_QUERY_HCA = 0xb, - MLX4_CMD_QUERY_PORT = 0x43, - MLX4_CMD_SENSE_PORT = 0x4d, - MLX4_CMD_HW_HEALTH_CHECK = 0x50, - MLX4_CMD_SET_PORT = 0xc, - MLX4_CMD_SET_NODE = 0x5a, - MLX4_CMD_QUERY_FUNC = 0x56, - MLX4_CMD_ACCESS_DDR = 0x2e, - MLX4_CMD_MAP_ICM = 0xffa, - MLX4_CMD_UNMAP_ICM = 0xff9, - MLX4_CMD_MAP_ICM_AUX = 0xffc, - MLX4_CMD_UNMAP_ICM_AUX = 0xffb, - MLX4_CMD_SET_ICM_SIZE = 0xffd, - /*master notify fw on finish for slave's flr*/ - MLX4_CMD_INFORM_FLR_DONE = 0x5b, - MLX4_CMD_GET_OP_REQ = 0x59, - - /* TPT commands */ - MLX4_CMD_SW2HW_MPT = 0xd, - MLX4_CMD_QUERY_MPT = 0xe, - MLX4_CMD_HW2SW_MPT = 0xf, - MLX4_CMD_READ_MTT = 0x10, - MLX4_CMD_WRITE_MTT = 0x11, - MLX4_CMD_SYNC_TPT = 0x2f, - - /* EQ commands */ - MLX4_CMD_MAP_EQ = 0x12, - MLX4_CMD_SW2HW_EQ = 0x13, - MLX4_CMD_HW2SW_EQ = 0x14, - MLX4_CMD_QUERY_EQ = 0x15, - - /* CQ commands */ - MLX4_CMD_SW2HW_CQ = 0x16, - MLX4_CMD_HW2SW_CQ = 0x17, - MLX4_CMD_QUERY_CQ = 0x18, - MLX4_CMD_MODIFY_CQ = 0x2c, - - /* SRQ commands */ - MLX4_CMD_SW2HW_SRQ = 0x35, - MLX4_CMD_HW2SW_SRQ = 0x36, - MLX4_CMD_QUERY_SRQ = 0x37, - MLX4_CMD_ARM_SRQ = 0x40, - - /* QP/EE commands */ - MLX4_CMD_RST2INIT_QP = 0x19, - MLX4_CMD_INIT2RTR_QP = 0x1a, - MLX4_CMD_RTR2RTS_QP = 0x1b, - MLX4_CMD_RTS2RTS_QP = 0x1c, - MLX4_CMD_SQERR2RTS_QP = 0x1d, - MLX4_CMD_2ERR_QP = 0x1e, - MLX4_CMD_RTS2SQD_QP = 0x1f, - MLX4_CMD_SQD2SQD_QP = 0x38, - MLX4_CMD_SQD2RTS_QP = 0x20, - MLX4_CMD_2RST_QP = 0x21, - MLX4_CMD_QUERY_QP = 0x22, - MLX4_CMD_INIT2INIT_QP = 0x2d, - MLX4_CMD_SUSPEND_QP = 0x32, - MLX4_CMD_UNSUSPEND_QP = 0x33, - MLX4_CMD_UPDATE_QP = 0x61, - /* special QP and management commands */ - MLX4_CMD_CONF_SPECIAL_QP = 0x23, - MLX4_CMD_MAD_IFC = 0x24, - - /* multicast commands */ - MLX4_CMD_READ_MCG = 0x25, - MLX4_CMD_WRITE_MCG = 0x26, - MLX4_CMD_MGID_HASH = 0x27, - - /* miscellaneous commands */ - MLX4_CMD_DIAG_RPRT = 0x30, - MLX4_CMD_NOP = 0x31, - MLX4_CMD_ACCESS_MEM = 0x2e, - MLX4_CMD_SET_VEP = 0x52, - - /* Ethernet specific commands */ - MLX4_CMD_SET_VLAN_FLTR = 0x47, - MLX4_CMD_SET_MCAST_FLTR = 0x48, - MLX4_CMD_DUMP_ETH_STATS = 0x49, - - /* Communication channel commands */ - MLX4_CMD_ARM_COMM_CHANNEL = 0x57, - MLX4_CMD_GEN_EQE = 0x58, - - /* virtual commands */ - MLX4_CMD_ALLOC_RES = 0xf00, - MLX4_CMD_FREE_RES = 0xf01, - MLX4_CMD_MCAST_ATTACH = 0xf05, - MLX4_CMD_UCAST_ATTACH = 0xf06, - MLX4_CMD_PROMISC = 0xf08, - MLX4_CMD_QUERY_FUNC_CAP = 0xf0a, - MLX4_CMD_QP_ATTACH = 0xf0b, - - /* debug commands */ - MLX4_CMD_QUERY_DEBUG_MSG = 0x2a, - MLX4_CMD_SET_DEBUG_MSG = 0x2b, - - /* statistics commands */ - MLX4_CMD_QUERY_IF_STAT = 0X54, - MLX4_CMD_SET_IF_STAT = 0X55, - - /* register/delete flow steering network rules */ - MLX4_QP_FLOW_STEERING_ATTACH = 0x65, - MLX4_QP_FLOW_STEERING_DETACH = 0x66, - MLX4_FLOW_STEERING_IB_UC_QP_RANGE = 0x64, -}; - -enum { - MLX4_CMD_TIME_CLASS_A = 60000, - MLX4_CMD_TIME_CLASS_B = 60000, - MLX4_CMD_TIME_CLASS_C = 60000, -}; - -enum { - MLX4_MAILBOX_SIZE = 4096, - MLX4_ACCESS_MEM_ALIGN = 256, -}; - -enum { - /* set port opcode modifiers */ - MLX4_SET_PORT_GENERAL = 0x0, - MLX4_SET_PORT_RQP_CALC = 0x1, - MLX4_SET_PORT_MAC_TABLE = 0x2, - MLX4_SET_PORT_VLAN_TABLE = 0x3, - MLX4_SET_PORT_PRIO_MAP = 0x4, - MLX4_SET_PORT_GID_TABLE = 0x5, - MLX4_SET_PORT_PRIO2TC = 0x8, - MLX4_SET_PORT_SCHEDULER = 0x9 -}; - -enum { - MLX4_CMD_WRAPPED, - MLX4_CMD_NATIVE -}; - -struct mlx4_dev; - -struct mlx4_cmd_mailbox { - void *buf; - dma_addr_t dma; -}; - -int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, - int out_is_imm, u32 in_modifier, u8 op_modifier, - u16 op, unsigned long timeout, int native); - -/* Invoke a command with no output parameter */ -static inline int mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u32 in_modifier, - u8 op_modifier, u16 op, unsigned long timeout, - int native) -{ - return __mlx4_cmd(dev, in_param, NULL, 0, in_modifier, - op_modifier, op, timeout, native); -} - -/* Invoke a command with an output mailbox */ -static inline int mlx4_cmd_box(struct mlx4_dev *dev, u64 in_param, u64 out_param, - u32 in_modifier, u8 op_modifier, u16 op, - unsigned long timeout, int native) -{ - return __mlx4_cmd(dev, in_param, &out_param, 0, in_modifier, - op_modifier, op, timeout, native); -} - -/* - * Invoke a command with an immediate output parameter (and copy the - * output into the caller's out_param pointer after the command - * executes). - */ -static inline int mlx4_cmd_imm(struct mlx4_dev *dev, u64 in_param, u64 *out_param, - u32 in_modifier, u8 op_modifier, u16 op, - unsigned long timeout, int native) -{ - return __mlx4_cmd(dev, in_param, out_param, 1, in_modifier, - op_modifier, op, timeout, native); -} - -struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev); -void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox); - -u32 mlx4_comm_get_version(void); -int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac); -int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos); -int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting); -int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state); -int mlx4_get_vf_link_state(struct mlx4_dev *dev, int port, int vf); -/* - * mlx4_get_slave_default_vlan - - * retrun true if VST ( default vlan) - * if VST will fill vlan & qos (if not NULL) - */ -bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, u16 *vlan, u8 *qos); - -enum { - IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */ - IFLA_VF_LINK_STATE_ENABLE, /* link always up */ - IFLA_VF_LINK_STATE_DISABLE, /* link always down */ - __IFLA_VF_LINK_STATE_MAX, -}; - -#define MLX4_COMM_GET_IF_REV(cmd_chan_ver) (u8)((cmd_chan_ver) >> 8) - -#endif /* MLX4_CMD_H */ diff --git a/sys/ofed/include/linux/mlx4/cq.h b/sys/ofed/include/linux/mlx4/cq.h deleted file mode 100644 index b39910a97a38..000000000000 --- a/sys/ofed/include/linux/mlx4/cq.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. 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. - */ - -#ifndef MLX4_CQ_H -#define MLX4_CQ_H - -#include <linux/types.h> - -#include <linux/mlx4/device.h> -#include <linux/mlx4/doorbell.h> - -struct mlx4_cqe { - __be32 vlan_my_qpn; - __be32 immed_rss_invalid; - __be32 g_mlpath_rqpn; - union { - struct { - union { - struct { - __be16 sl_vid; - __be16 rlid; - }; - __be32 timestamp_16_47; - }; - __be16 status; - u8 ipv6_ext_mask; - u8 badfcs_enc; - }; - struct { - __be16 reserved1; - u8 smac[6]; - }; - }; - __be32 byte_cnt; - __be16 wqe_index; - __be16 checksum; - u8 reserved2[1]; - __be16 timestamp_0_15; - u8 owner_sr_opcode; -} __packed; - -struct mlx4_err_cqe { - __be32 my_qpn; - u32 reserved1[5]; - __be16 wqe_index; - u8 vendor_err_syndrome; - u8 syndrome; - u8 reserved2[3]; - u8 owner_sr_opcode; -}; - -struct mlx4_ts_cqe { - __be32 vlan_my_qpn; - __be32 immed_rss_invalid; - __be32 g_mlpath_rqpn; - __be32 timestamp_hi; - __be16 status; - u8 ipv6_ext_mask; - u8 badfcs_enc; - __be32 byte_cnt; - __be16 wqe_index; - __be16 checksum; - u8 reserved; - __be16 timestamp_lo; - u8 owner_sr_opcode; -} __packed; - -enum { - MLX4_CQE_VLAN_PRESENT_MASK = 1 << 29, - MLX4_CQE_QPN_MASK = 0xffffff, - MLX4_CQE_VID_MASK = 0xfff, -}; - -enum { - MLX4_CQE_OWNER_MASK = 0x80, - MLX4_CQE_IS_SEND_MASK = 0x40, - MLX4_CQE_OPCODE_MASK = 0x1f -}; - -enum { - MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01, - MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02, - MLX4_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04, - MLX4_CQE_SYNDROME_WR_FLUSH_ERR = 0x05, - MLX4_CQE_SYNDROME_MW_BIND_ERR = 0x06, - MLX4_CQE_SYNDROME_BAD_RESP_ERR = 0x10, - MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11, - MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, - MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13, - MLX4_CQE_SYNDROME_REMOTE_OP_ERR = 0x14, - MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15, - MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16, - MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22, -}; - -enum { - MLX4_CQE_STATUS_IPV4 = 1 << 6, - MLX4_CQE_STATUS_IPV4F = 1 << 7, - MLX4_CQE_STATUS_IPV6 = 1 << 8, - MLX4_CQE_STATUS_IPV4OPT = 1 << 9, - MLX4_CQE_STATUS_TCP = 1 << 10, - MLX4_CQE_STATUS_UDP = 1 << 11, - MLX4_CQE_STATUS_IPOK = 1 << 12, -}; - -enum { - MLX4_CQE_LLC = 1, - MLX4_CQE_SNAP = 1 << 1, - MLX4_CQE_BAD_FCS = 1 << 4, -}; - -static inline void mlx4_cq_arm(struct mlx4_cq *cq, u32 cmd, - u8 __iomem *uar_page, - spinlock_t *doorbell_lock) -{ - __be32 doorbell[2]; - u32 sn; - u32 ci; - - sn = cq->arm_sn & 3; - ci = cq->cons_index & 0xffffff; - - *cq->arm_db = cpu_to_be32(sn << 28 | cmd | ci); - - /* - * Make sure that the doorbell record in host memory is - * written before ringing the doorbell via PCI MMIO. - */ - wmb(); - - doorbell[0] = cpu_to_be32(sn << 28 | cmd | cq->cqn); - doorbell[1] = cpu_to_be32(ci); - - mlx4_write64(doorbell, uar_page + MLX4_CQ_DOORBELL, doorbell_lock); -} - -static inline void mlx4_cq_set_ci(struct mlx4_cq *cq) -{ - *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff); -} - -enum { - MLX4_CQ_DB_REQ_NOT_SOL = 1 << 24, - MLX4_CQ_DB_REQ_NOT = 2 << 24 -}; - -int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, - u16 count, u16 period); -int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, - int entries, struct mlx4_mtt *mtt); -int mlx4_cq_ignore_overrun(struct mlx4_dev *dev, struct mlx4_cq *cq); -#endif /* MLX4_CQ_H */ diff --git a/sys/ofed/include/linux/mlx4/device.h b/sys/ofed/include/linux/mlx4/device.h deleted file mode 100644 index 7f545b1b8ba0..000000000000 --- a/sys/ofed/include/linux/mlx4/device.h +++ /dev/null @@ -1,1327 +0,0 @@ -/* - * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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. - */ - -#ifndef MLX4_DEVICE_H -#define MLX4_DEVICE_H - -#include <linux/pci.h> -#include <linux/completion.h> -#include <linux/radix-tree.h> -#include <linux/types.h> -#include <linux/bitops.h> -#include <linux/workqueue.h> -#include <asm/atomic.h> - -#include <linux/clocksource.h> - -#define MAX_MSIX_P_PORT 17 -#define MAX_MSIX 64 -#define MSIX_LEGACY_SZ 4 -#define MIN_MSIX_P_PORT 5 - -#define MLX4_ROCE_MAX_GIDS 128 -#define MLX4_ROCE_PF_GIDS 16 - -#define MLX4_NUM_UP 8 -#define MLX4_NUM_TC 8 -#define MLX4_MAX_100M_UNITS_VAL 255 /* - * work around: can't set values - * greater then this value when - * using 100 Mbps units. - */ -#define MLX4_RATELIMIT_100M_UNITS 3 /* 100 Mbps */ -#define MLX4_RATELIMIT_1G_UNITS 4 /* 1 Gbps */ -#define MLX4_RATELIMIT_DEFAULT 0x00ff - -#define CORE_CLOCK_MASK 0xffffffffffffULL - -enum { - MLX4_FLAG_MSI_X = 1 << 0, - MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, - MLX4_FLAG_MASTER = 1 << 2, - MLX4_FLAG_SLAVE = 1 << 3, - MLX4_FLAG_SRIOV = 1 << 4, - MLX4_FLAG_DEV_NUM_STR = 1 << 5, - MLX4_FLAG_OLD_REG_MAC = 1 << 6, -}; - -enum { - MLX4_PORT_CAP_IS_SM = 1 << 1, - MLX4_PORT_CAP_DEV_MGMT_SUP = 1 << 19, -}; - -enum { - MLX4_MAX_PORTS = 2, - MLX4_MAX_PORT_PKEYS = 128 -}; - -/* base qkey for use in sriov tunnel-qp/proxy-qp communication. - * These qkeys must not be allowed for general use. This is a 64k range, - * and to test for violation, we use the mask (protect against future chg). - */ -#define MLX4_RESERVED_QKEY_BASE (0xFFFF0000) -#define MLX4_RESERVED_QKEY_MASK (0xFFFF0000) - -enum { - MLX4_BOARD_ID_LEN = 64, - MLX4_VSD_LEN = 208 -}; - -enum { - MLX4_MAX_NUM_PF = 16, - MLX4_MAX_NUM_VF = 64, - MLX4_MFUNC_MAX = 80, - MLX4_MAX_EQ_NUM = 1024, - MLX4_MFUNC_EQ_NUM = 4, - MLX4_MFUNC_MAX_EQES = 8, - MLX4_MFUNC_EQE_MASK = (MLX4_MFUNC_MAX_EQES - 1) -}; - -/* Driver supports 3 different device methods to manage traffic steering: - * -device managed - High level API for ib and eth flow steering. FW is - * managing flow steering tables. - * - B0 steering mode - Common low level API for ib and (if supported) eth. - * - A0 steering mode - Limited low level API for eth. In case of IB, - * B0 mode is in use. - */ -enum { - MLX4_STEERING_MODE_A0, - MLX4_STEERING_MODE_B0, - MLX4_STEERING_MODE_DEVICE_MANAGED -}; - -static inline const char *mlx4_steering_mode_str(int steering_mode) -{ - switch (steering_mode) { - case MLX4_STEERING_MODE_A0: - return "A0 steering"; - - case MLX4_STEERING_MODE_B0: - return "B0 steering"; - - case MLX4_STEERING_MODE_DEVICE_MANAGED: - return "Device managed flow steering"; - - default: - return "Unrecognize steering mode"; - } -} - -enum { - MLX4_DEV_CAP_FLAG_RC = 1LL << 0, - MLX4_DEV_CAP_FLAG_UC = 1LL << 1, - MLX4_DEV_CAP_FLAG_UD = 1LL << 2, - MLX4_DEV_CAP_FLAG_XRC = 1LL << 3, - MLX4_DEV_CAP_FLAG_SRQ = 1LL << 6, - MLX4_DEV_CAP_FLAG_IPOIB_CSUM = 1LL << 7, - MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1LL << 8, - MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL << 9, - MLX4_DEV_CAP_FLAG_DPDP = 1LL << 12, - MLX4_DEV_CAP_FLAG_BLH = 1LL << 15, - MLX4_DEV_CAP_FLAG_MEM_WINDOW = 1LL << 16, - MLX4_DEV_CAP_FLAG_APM = 1LL << 17, - MLX4_DEV_CAP_FLAG_ATOMIC = 1LL << 18, - MLX4_DEV_CAP_FLAG_RAW_MCAST = 1LL << 19, - MLX4_DEV_CAP_FLAG_UD_AV_PORT = 1LL << 20, - MLX4_DEV_CAP_FLAG_UD_MCAST = 1LL << 21, - MLX4_DEV_CAP_FLAG_IBOE = 1LL << 30, - MLX4_DEV_CAP_FLAG_UC_LOOPBACK = 1LL << 32, - MLX4_DEV_CAP_FLAG_FCS_KEEP = 1LL << 34, - MLX4_DEV_CAP_FLAG_WOL_PORT1 = 1LL << 37, - MLX4_DEV_CAP_FLAG_WOL_PORT2 = 1LL << 38, - MLX4_DEV_CAP_FLAG_UDP_RSS = 1LL << 40, - MLX4_DEV_CAP_FLAG_VEP_UC_STEER = 1LL << 41, - MLX4_DEV_CAP_FLAG_VEP_MC_STEER = 1LL << 42, - MLX4_DEV_CAP_FLAG_CROSS_CHANNEL = 1LL << 44, - MLX4_DEV_CAP_FLAG_COUNTERS = 1LL << 48, - MLX4_DEV_CAP_FLAG_COUNTERS_EXT = 1LL << 49, - MLX4_DEV_CAP_FLAG_SET_PORT_ETH_SCHED = 1LL << 53, - MLX4_DEV_CAP_FLAG_SENSE_SUPPORT = 1LL << 55, - MLX4_DEV_CAP_FLAG_FAST_DROP = 1LL << 57, - MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV = 1LL << 59, - MLX4_DEV_CAP_FLAG_64B_EQE = 1LL << 61, - MLX4_DEV_CAP_FLAG_64B_CQE = 1LL << 62 -}; - -enum { - MLX4_DEV_CAP_FLAG2_RSS = 1LL << 0, - MLX4_DEV_CAP_FLAG2_RSS_TOP = 1LL << 1, - MLX4_DEV_CAP_FLAG2_RSS_XOR = 1LL << 2, - MLX4_DEV_CAP_FLAG2_FS_EN = 1LL << 3, - MLX4_DEV_CAP_FLAG2_FSM = 1LL << 4, - MLX4_DEV_CAP_FLAG2_VLAN_CONTROL = 1LL << 5, - MLX4_DEV_CAP_FLAG2_UPDATE_QP = 1LL << 6, - MLX4_DEV_CAP_FLAG2_LB_SRC_CHK = 1LL << 7, - MLX4_DEV_CAP_FLAG2_DMFS_IPOIB = 1LL << 8, - MLX4_DEV_CAP_FLAG2_ETS_CFG = 1LL << 9, - MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP = 1LL << 10, - MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN = 1LL << 11, - MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT = 1LL << 12, - MLX4_DEV_CAP_FLAG2_TS = 1LL << 13, - MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW = 1LL << 14, - MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN = 1LL << 15, - MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS = 1LL << 16, - MLX4_DEV_CAP_FLAG2_FS_EN_NCSI = 1LL << 17, - MLX4_DEV_CAP_FLAG2_80_VFS = 1LL << 18, - MLX4_DEV_CAP_FLAG2_DMFS_TAG_MODE = 1LL << 19, - MLX4_DEV_CAP_FLAG2_ROCEV2 = 1LL << 20, - MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL = 1LL << 21, - MLX4_DEV_CAP_FLAG2_CQE_STRIDE = 1LL << 22, - MLX4_DEV_CAP_FLAG2_EQE_STRIDE = 1LL << 23, - MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB = 1LL << 24, - MLX4_DEV_CAP_FLAG2_RX_CSUM_MODE = 1LL << 25, -}; - -/* bit enums for an 8-bit flags field indicating special use - * QPs which require special handling in qp_reserve_range. - * Currently, this only includes QPs used by the ETH interface, - * where we expect to use blueflame. These QPs must not have - * bits 6 and 7 set in their qp number. - * - * This enum may use only bits 0..7. - */ -enum { - MLX4_RESERVE_BF_QP = 1 << 7, -}; - -enum { - MLX4_DEV_CAP_CQ_FLAG_IO = 1 << 0 -}; - -enum { - MLX4_DEV_CAP_64B_EQE_ENABLED = 1LL << 0, - MLX4_DEV_CAP_64B_CQE_ENABLED = 1LL << 1 -}; - -enum { - MLX4_USER_DEV_CAP_64B_CQE = 1L << 0 -}; - -enum { - MLX4_FUNC_CAP_64B_EQE_CQE = 1L << 0 -}; - - -#define MLX4_ATTR_EXTENDED_PORT_INFO cpu_to_be16(0xff90) - -enum { - MLX4_BMME_FLAG_WIN_TYPE_2B = 1 << 1, - MLX4_BMME_FLAG_LOCAL_INV = 1 << 6, - MLX4_BMME_FLAG_REMOTE_INV = 1 << 7, - MLX4_BMME_FLAG_TYPE_2_WIN = 1 << 9, - MLX4_BMME_FLAG_RESERVED_LKEY = 1 << 10, - MLX4_BMME_FLAG_FAST_REG_WR = 1 << 11, -}; - -enum mlx4_event { - MLX4_EVENT_TYPE_COMP = 0x00, - MLX4_EVENT_TYPE_PATH_MIG = 0x01, - MLX4_EVENT_TYPE_COMM_EST = 0x02, - MLX4_EVENT_TYPE_SQ_DRAINED = 0x03, - MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE = 0x13, - MLX4_EVENT_TYPE_SRQ_LIMIT = 0x14, - MLX4_EVENT_TYPE_CQ_ERROR = 0x04, - MLX4_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, - MLX4_EVENT_TYPE_EEC_CATAS_ERROR = 0x06, - MLX4_EVENT_TYPE_PATH_MIG_FAILED = 0x07, - MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10, - MLX4_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11, - MLX4_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12, - MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR = 0x08, - MLX4_EVENT_TYPE_PORT_CHANGE = 0x09, - MLX4_EVENT_TYPE_EQ_OVERFLOW = 0x0f, - MLX4_EVENT_TYPE_ECC_DETECT = 0x0e, - MLX4_EVENT_TYPE_CMD = 0x0a, - MLX4_EVENT_TYPE_VEP_UPDATE = 0x19, - MLX4_EVENT_TYPE_COMM_CHANNEL = 0x18, - MLX4_EVENT_TYPE_OP_REQUIRED = 0x1a, - MLX4_EVENT_TYPE_FATAL_WARNING = 0x1b, - MLX4_EVENT_TYPE_FLR_EVENT = 0x1c, - MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT = 0x1d, - MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT = 0x3e, - MLX4_EVENT_TYPE_NONE = 0xff, -}; - -enum { - MLX4_PORT_CHANGE_SUBTYPE_DOWN = 1, - MLX4_PORT_CHANGE_SUBTYPE_ACTIVE = 4 -}; - -enum { - MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_BAD_CABLE = 1, - MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_UNSUPPORTED_CABLE = 2, -}; - -enum { - MLX4_FATAL_WARNING_SUBTYPE_WARMING = 0, -}; - -enum slave_port_state { - SLAVE_PORT_DOWN = 0, - SLAVE_PENDING_UP, - SLAVE_PORT_UP, -}; - -enum slave_port_gen_event { - SLAVE_PORT_GEN_EVENT_DOWN = 0, - SLAVE_PORT_GEN_EVENT_UP, - SLAVE_PORT_GEN_EVENT_NONE, -}; - -enum slave_port_state_event { - MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN, - MLX4_PORT_STATE_DEV_EVENT_PORT_UP, - MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID, - MLX4_PORT_STATE_IB_EVENT_GID_INVALID, -}; - -enum { - MLX4_PERM_LOCAL_READ = 1 << 10, - MLX4_PERM_LOCAL_WRITE = 1 << 11, - MLX4_PERM_REMOTE_READ = 1 << 12, - MLX4_PERM_REMOTE_WRITE = 1 << 13, - MLX4_PERM_ATOMIC = 1 << 14, - MLX4_PERM_BIND_MW = 1 << 15, -}; - -enum { - MLX4_OPCODE_NOP = 0x00, - MLX4_OPCODE_SEND_INVAL = 0x01, - MLX4_OPCODE_RDMA_WRITE = 0x08, - MLX4_OPCODE_RDMA_WRITE_IMM = 0x09, - MLX4_OPCODE_SEND = 0x0a, - MLX4_OPCODE_SEND_IMM = 0x0b, - MLX4_OPCODE_LSO = 0x0e, - MLX4_OPCODE_RDMA_READ = 0x10, - MLX4_OPCODE_ATOMIC_CS = 0x11, - MLX4_OPCODE_ATOMIC_FA = 0x12, - MLX4_OPCODE_MASKED_ATOMIC_CS = 0x14, - MLX4_OPCODE_MASKED_ATOMIC_FA = 0x15, - MLX4_OPCODE_BIND_MW = 0x18, - MLX4_OPCODE_FMR = 0x19, - MLX4_OPCODE_LOCAL_INVAL = 0x1b, - MLX4_OPCODE_CONFIG_CMD = 0x1f, - - MLX4_RECV_OPCODE_RDMA_WRITE_IMM = 0x00, - MLX4_RECV_OPCODE_SEND = 0x01, - MLX4_RECV_OPCODE_SEND_IMM = 0x02, - MLX4_RECV_OPCODE_SEND_INVAL = 0x03, - - MLX4_CQE_OPCODE_ERROR = 0x1e, - MLX4_CQE_OPCODE_RESIZE = 0x16, -}; - -enum { - MLX4_STAT_RATE_OFFSET = 5 -}; - -enum mlx4_protocol { - MLX4_PROT_IB_IPV6 = 0, - MLX4_PROT_ETH, - MLX4_PROT_IB_IPV4, - MLX4_PROT_FCOE -}; - -enum { - MLX4_MTT_FLAG_PRESENT = 1 -}; - -enum { - MLX4_MAX_MTT_SHIFT = 31 -}; - -enum mlx4_qp_region { - MLX4_QP_REGION_FW = 0, - MLX4_QP_REGION_ETH_ADDR, - MLX4_QP_REGION_FC_ADDR, - MLX4_QP_REGION_FC_EXCH, - MLX4_NUM_QP_REGION -}; - -enum mlx4_port_type { - MLX4_PORT_TYPE_NONE = 0, - MLX4_PORT_TYPE_IB = 1, - MLX4_PORT_TYPE_ETH = 2, - MLX4_PORT_TYPE_AUTO = 3, - MLX4_PORT_TYPE_NA = 4 -}; - -enum mlx4_special_vlan_idx { - MLX4_NO_VLAN_IDX = 0, - MLX4_VLAN_MISS_IDX, - MLX4_VLAN_REGULAR -}; - -enum mlx4_steer_type { - MLX4_MC_STEER = 0, - MLX4_UC_STEER, - MLX4_NUM_STEERS -}; - -enum { - MLX4_NUM_FEXCH = 64 * 1024, -}; - -enum { - MLX4_MAX_FAST_REG_PAGES = 511, -}; - -enum { - MLX4_DEV_PMC_SUBTYPE_GUID_INFO = 0x14, - MLX4_DEV_PMC_SUBTYPE_PORT_INFO = 0x15, - MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE = 0x16, -}; - -/* Port mgmt change event handling */ -enum { - MLX4_EQ_PORT_INFO_MSTR_SM_LID_CHANGE_MASK = 1 << 0, - MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK = 1 << 1, - MLX4_EQ_PORT_INFO_LID_CHANGE_MASK = 1 << 2, - MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK = 1 << 3, - MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK = 1 << 4, -}; - -#define MSTR_SM_CHANGE_MASK (MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK | \ - MLX4_EQ_PORT_INFO_MSTR_SM_LID_CHANGE_MASK) - -enum mlx4_module_id { - MLX4_MODULE_ID_SFP = 0x3, - MLX4_MODULE_ID_QSFP = 0xC, - MLX4_MODULE_ID_QSFP_PLUS = 0xD, - MLX4_MODULE_ID_QSFP28 = 0x11, -}; - -static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor) -{ - return (major << 32) | (minor << 16) | subminor; -} - -struct mlx4_phys_caps { - u32 gid_phys_table_len[MLX4_MAX_PORTS + 1]; - u32 pkey_phys_table_len[MLX4_MAX_PORTS + 1]; - u32 num_phys_eqs; - u32 base_sqpn; - u32 base_proxy_sqpn; - u32 base_tunnel_sqpn; -}; - -struct mlx4_caps { - u64 fw_ver; - u32 function; - int num_ports; - int vl_cap[MLX4_MAX_PORTS + 1]; - int ib_mtu_cap[MLX4_MAX_PORTS + 1]; - __be32 ib_port_def_cap[MLX4_MAX_PORTS + 1]; - u64 def_mac[MLX4_MAX_PORTS + 1]; - int eth_mtu_cap[MLX4_MAX_PORTS + 1]; - int gid_table_len[MLX4_MAX_PORTS + 1]; - int pkey_table_len[MLX4_MAX_PORTS + 1]; - int trans_type[MLX4_MAX_PORTS + 1]; - int vendor_oui[MLX4_MAX_PORTS + 1]; - int wavelength[MLX4_MAX_PORTS + 1]; - u64 trans_code[MLX4_MAX_PORTS + 1]; - int local_ca_ack_delay; - int num_uars; - u32 uar_page_size; - int bf_reg_size; - int bf_regs_per_page; - int max_sq_sg; - int max_rq_sg; - int num_qps; - int max_wqes; - int max_sq_desc_sz; - int max_rq_desc_sz; - int max_qp_init_rdma; - int max_qp_dest_rdma; - u32 *qp0_proxy; - u32 *qp1_proxy; - u32 *qp0_tunnel; - u32 *qp1_tunnel; - int num_srqs; - int max_srq_wqes; - int max_srq_sge; - int reserved_srqs; - int num_cqs; - int max_cqes; - int reserved_cqs; - int num_eqs; - int reserved_eqs; - int num_comp_vectors; - int comp_pool; - int num_mpts; - int max_fmr_maps; - u64 num_mtts; - int fmr_reserved_mtts; - int reserved_mtts; - int reserved_mrws; - int reserved_uars; - int num_mgms; - int num_amgms; - int reserved_mcgs; - int num_qp_per_mgm; - int steering_mode; - int num_pds; - int reserved_pds; - int max_xrcds; - int reserved_xrcds; - int mtt_entry_sz; - u32 max_msg_sz; - u32 page_size_cap; - u64 flags; - u64 flags2; - u32 bmme_flags; - u32 reserved_lkey; - u16 stat_rate_support; - u8 cq_timestamp; - u8 port_width_cap[MLX4_MAX_PORTS + 1]; - int max_gso_sz; - int max_rss_tbl_sz; - int reserved_qps_cnt[MLX4_NUM_QP_REGION]; - int reserved_qps; - int reserved_qps_base[MLX4_NUM_QP_REGION]; - int log_num_macs; - int log_num_vlans; - enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; - u8 supported_type[MLX4_MAX_PORTS + 1]; - u8 suggested_type[MLX4_MAX_PORTS + 1]; - u8 default_sense[MLX4_MAX_PORTS + 1]; - u32 port_mask[MLX4_MAX_PORTS + 1]; - enum mlx4_port_type possible_type[MLX4_MAX_PORTS + 1]; - u32 max_counters; - u8 port_ib_mtu[MLX4_MAX_PORTS + 1]; - u16 sqp_demux; - u32 sync_qp; - u32 cq_flags; - u32 eqe_size; - u32 cqe_size; - u8 eqe_factor; - u32 userspace_caps; /* userspace must be aware to */ - u32 function_caps; /* functions must be aware to */ - u8 fast_drop; - u16 hca_core_clock; - u32 max_basic_counters; - u32 max_extended_counters; - u8 def_counter_index[MLX4_MAX_PORTS + 1]; -}; - -struct mlx4_buf_list { - void *buf; - dma_addr_t map; -}; - -struct mlx4_buf { - struct mlx4_buf_list direct; - struct mlx4_buf_list *page_list; - int nbufs; - int npages; - int page_shift; -}; - -struct mlx4_mtt { - u32 offset; - int order; - int page_shift; -}; - -enum { - MLX4_DB_PER_PAGE = PAGE_SIZE / 4 -}; - -struct mlx4_db_pgdir { - struct list_head list; - DECLARE_BITMAP(order0, MLX4_DB_PER_PAGE); - DECLARE_BITMAP(order1, MLX4_DB_PER_PAGE / 2); - unsigned long *bits[2]; - __be32 *db_page; - dma_addr_t db_dma; -}; - -struct mlx4_ib_user_db_page; - -struct mlx4_db { - __be32 *db; - union { - struct mlx4_db_pgdir *pgdir; - struct mlx4_ib_user_db_page *user_page; - } u; - dma_addr_t dma; - int index; - int order; -}; - -struct mlx4_hwq_resources { - struct mlx4_db db; - struct mlx4_mtt mtt; - struct mlx4_buf buf; -}; - -struct mlx4_mr { - struct mlx4_mtt mtt; - u64 iova; - u64 size; - u32 key; - u32 pd; - u32 access; - int enabled; -}; - -enum mlx4_mw_type { - MLX4_MW_TYPE_1 = 1, - MLX4_MW_TYPE_2 = 2, -}; - -struct mlx4_mw { - u32 key; - u32 pd; - enum mlx4_mw_type type; - int enabled; -}; - -struct mlx4_fmr { - struct mlx4_mr mr; - struct mlx4_mpt_entry *mpt; - __be64 *mtts; - dma_addr_t dma_handle; - int max_pages; - int max_maps; - int maps; - u8 page_shift; -}; - -struct mlx4_uar { - unsigned long pfn; - int index; - struct list_head bf_list; - unsigned free_bf_bmap; - void __iomem *map; - void __iomem *bf_map; -}; - -struct mlx4_bf { - unsigned long offset; - int buf_size; - struct mlx4_uar *uar; - void __iomem *reg; -}; - -struct mlx4_cq { - void (*comp) (struct mlx4_cq *); - void (*event) (struct mlx4_cq *, enum mlx4_event); - - struct mlx4_uar *uar; - - u32 cons_index; - - __be32 *set_ci_db; - __be32 *arm_db; - int arm_sn; - - int cqn; - unsigned vector; - - atomic_t refcount; - struct completion free; - int eqn; - u16 irq; -}; - -struct mlx4_qp { - void (*event) (struct mlx4_qp *, enum mlx4_event); - - int qpn; - - atomic_t refcount; - struct completion free; -}; - -struct mlx4_srq { - void (*event) (struct mlx4_srq *, enum mlx4_event); - - int srqn; - int max; - int max_gs; - int wqe_shift; - - atomic_t refcount; - struct completion free; -}; - -struct mlx4_av { - __be32 port_pd; - u8 reserved1; - u8 g_slid; - __be16 dlid; - u8 reserved2; - u8 gid_index; - u8 stat_rate; - u8 hop_limit; - __be32 sl_tclass_flowlabel; - u8 dgid[16]; -}; - -struct mlx4_eth_av { - __be32 port_pd; - u8 reserved1; - u8 smac_idx; - u16 reserved2; - u8 reserved3; - u8 gid_index; - u8 stat_rate; - u8 hop_limit; - __be32 sl_tclass_flowlabel; - u8 dgid[16]; - u8 s_mac[6]; - u8 reserved4[2]; - __be16 vlan; - u8 mac[6]; -}; - -union mlx4_ext_av { - struct mlx4_av ib; - struct mlx4_eth_av eth; -}; - -struct mlx4_if_stat_control { - u8 reserved1[3]; - /* Extended counters enabled */ - u8 cnt_mode; - /* Number of interfaces */ - __be32 num_of_if; - __be32 reserved[2]; -}; - -struct mlx4_if_stat_basic { - struct mlx4_if_stat_control control; - struct { - __be64 IfRxFrames; - __be64 IfRxOctets; - __be64 IfTxFrames; - __be64 IfTxOctets; - } counters[]; -}; -#define MLX4_IF_STAT_BSC_SZ(ports)(sizeof(struct mlx4_if_stat_extended) +\ - sizeof(((struct mlx4_if_stat_extended *)0)->\ - counters[0]) * ports) - -struct mlx4_if_stat_extended { - struct mlx4_if_stat_control control; - struct { - __be64 IfRxUnicastFrames; - __be64 IfRxUnicastOctets; - __be64 IfRxMulticastFrames; - __be64 IfRxMulticastOctets; - __be64 IfRxBroadcastFrames; - __be64 IfRxBroadcastOctets; - __be64 IfRxNoBufferFrames; - __be64 IfRxNoBufferOctets; - __be64 IfRxErrorFrames; - __be64 IfRxErrorOctets; - __be32 reserved[39]; - __be64 IfTxUnicastFrames; - __be64 IfTxUnicastOctets; - __be64 IfTxMulticastFrames; - __be64 IfTxMulticastOctets; - __be64 IfTxBroadcastFrames; - __be64 IfTxBroadcastOctets; - __be64 IfTxDroppedFrames; - __be64 IfTxDroppedOctets; - __be64 IfTxRequestedFramesSent; - __be64 IfTxGeneratedFramesSent; - __be64 IfTxTsoOctets; - } __packed counters[]; -}; -#define MLX4_IF_STAT_EXT_SZ(ports) (sizeof(struct mlx4_if_stat_extended) +\ - sizeof(((struct mlx4_if_stat_extended *)\ - 0)->counters[0]) * ports) - -union mlx4_counter { - struct mlx4_if_stat_control control; - struct mlx4_if_stat_basic basic; - struct mlx4_if_stat_extended ext; -}; -#define MLX4_IF_STAT_SZ(ports) MLX4_IF_STAT_EXT_SZ(ports) - -struct mlx4_quotas { - int qp; - int cq; - int srq; - int mpt; - int mtt; - int counter; - int xrcd; -}; - -struct mlx4_dev { - struct pci_dev *pdev; - unsigned long flags; - unsigned long num_slaves; - struct mlx4_caps caps; - struct mlx4_phys_caps phys_caps; - struct mlx4_quotas quotas; - struct radix_tree_root qp_table_tree; - u8 rev_id; - char board_id[MLX4_BOARD_ID_LEN]; - u16 vsd_vendor_id; - char vsd[MLX4_VSD_LEN]; - int num_vfs; - int numa_node; - int oper_log_mgm_entry_size; - u64 regid_promisc_array[MLX4_MAX_PORTS + 1]; - u64 regid_allmulti_array[MLX4_MAX_PORTS + 1]; -}; - -struct mlx4_clock_params { - u64 offset; - u8 bar; - u8 size; -}; - -struct mlx4_eqe { - u8 reserved1; - u8 type; - u8 reserved2; - u8 subtype; - union { - u32 raw[6]; - struct { - __be32 cqn; - } __packed comp; - struct { - u16 reserved1; - __be16 token; - u32 reserved2; - u8 reserved3[3]; - u8 status; - __be64 out_param; - } __packed cmd; - struct { - __be32 qpn; - } __packed qp; - struct { - __be32 srqn; - } __packed srq; - struct { - __be32 cqn; - u32 reserved1; - u8 reserved2[3]; - u8 syndrome; - } __packed cq_err; - struct { - u32 reserved1[2]; - __be32 port; - } __packed port_change; - struct { - #define COMM_CHANNEL_BIT_ARRAY_SIZE 4 - u32 reserved; - u32 bit_vec[COMM_CHANNEL_BIT_ARRAY_SIZE]; - } __packed comm_channel_arm; - struct { - u8 port; - u8 reserved[3]; - __be64 mac; - } __packed mac_update; - struct { - __be32 slave_id; - } __packed flr_event; - struct { - __be16 current_temperature; - __be16 warning_threshold; - } __packed warming; - struct { - u8 reserved[3]; - u8 port; - union { - struct { - __be16 mstr_sm_lid; - __be16 port_lid; - __be32 changed_attr; - u8 reserved[3]; - u8 mstr_sm_sl; - __be64 gid_prefix; - } __packed port_info; - struct { - __be32 block_ptr; - __be32 tbl_entries_mask; - } __packed tbl_change_info; - } params; - } __packed port_mgmt_change; - struct { - u8 reserved[3]; - u8 port; - u32 reserved1[5]; - } __packed bad_cable; - } event; - u8 slave_id; - u8 reserved3[2]; - u8 owner; -} __packed; - -struct mlx4_init_port_param { - int set_guid0; - int set_node_guid; - int set_si_guid; - u16 mtu; - int port_width_cap; - u16 vl_cap; - u16 max_gid; - u16 max_pkey; - u64 guid0; - u64 node_guid; - u64 si_guid; -}; - -#define MAD_IFC_DATA_SZ 192 -/* MAD IFC Mailbox */ -struct mlx4_mad_ifc { - u8 base_version; - u8 mgmt_class; - u8 class_version; - u8 method; - __be16 status; - __be16 class_specific; - __be64 tid; - __be16 attr_id; - __be16 resv; - __be32 attr_mod; - __be64 mkey; - __be16 dr_slid; - __be16 dr_dlid; - u8 reserved[28]; - u8 data[MAD_IFC_DATA_SZ]; -} __packed; - -#define mlx4_foreach_port(port, dev, type) \ - for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ - if ((type) == (dev)->caps.port_mask[(port)]) - -#define mlx4_foreach_non_ib_transport_port(port, dev) \ - for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ - if (((dev)->caps.port_mask[port] != MLX4_PORT_TYPE_IB)) - -#define mlx4_foreach_ib_transport_port(port, dev) \ - for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ - if (((dev)->caps.port_mask[port] == MLX4_PORT_TYPE_IB) || \ - ((dev)->caps.flags & MLX4_DEV_CAP_FLAG_IBOE)) - -#define MLX4_INVALID_SLAVE_ID 0xFF - -#define MLX4_SINK_COUNTER_INDEX 0xff - -void handle_port_mgmt_change_event(struct work_struct *work); - -static inline int mlx4_master_func_num(struct mlx4_dev *dev) -{ - return dev->caps.function; -} - -static inline int mlx4_is_master(struct mlx4_dev *dev) -{ - return dev->flags & MLX4_FLAG_MASTER; -} - -static inline int mlx4_num_reserved_sqps(struct mlx4_dev *dev) -{ - return dev->phys_caps.base_sqpn + 8 + - 16 * MLX4_MFUNC_MAX * !!mlx4_is_master(dev); -} - -static inline int mlx4_is_qp_reserved(struct mlx4_dev *dev, u32 qpn) -{ - return (qpn < dev->phys_caps.base_sqpn + 8 + - 16 * MLX4_MFUNC_MAX * !!mlx4_is_master(dev)); -} - -static inline int mlx4_is_guest_proxy(struct mlx4_dev *dev, int slave, u32 qpn) -{ - int guest_proxy_base = dev->phys_caps.base_proxy_sqpn + slave * 8; - - if (qpn >= guest_proxy_base && qpn < guest_proxy_base + 8) - return 1; - - return 0; -} - -static inline int mlx4_is_mfunc(struct mlx4_dev *dev) -{ - return dev->flags & (MLX4_FLAG_SLAVE | MLX4_FLAG_MASTER); -} - -static inline int mlx4_is_slave(struct mlx4_dev *dev) -{ - return dev->flags & MLX4_FLAG_SLAVE; -} - -int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, - struct mlx4_buf *buf); -void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf); -static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset) -{ - if (BITS_PER_LONG == 64 || buf->nbufs == 1) - return (u8 *)buf->direct.buf + offset; - else - return (u8 *)buf->page_list[offset >> PAGE_SHIFT].buf + - (offset & (PAGE_SIZE - 1)); -} - -int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn); -void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn); -int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn); -void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn); - -int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar); -void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar); -int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node); -void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf); - -int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, - struct mlx4_mtt *mtt); -void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt); -u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt); - -int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, - int npages, int page_shift, struct mlx4_mr *mr); -int mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr); -int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr); -int mlx4_mw_alloc(struct mlx4_dev *dev, u32 pd, enum mlx4_mw_type type, - struct mlx4_mw *mw); -void mlx4_mw_free(struct mlx4_dev *dev, struct mlx4_mw *mw); -int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw); -int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - int start_index, int npages, u64 *page_list); -int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - struct mlx4_buf *buf); - -int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order); -void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db); - -int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, - int size, int max_direct); -void mlx4_free_hwq_res(struct mlx4_dev *mdev, struct mlx4_hwq_resources *wqres, - int size); - -int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, - struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, - unsigned vector, int collapsed, int timestamp_en); -void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq); - -int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, - int *base, u8 flags); -void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt); - -int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp); -void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp); - -int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcdn, - struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq); -void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq); -int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark); -int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark); - -int mlx4_INIT_PORT(struct mlx4_dev *dev, int port); -int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port); - -int mlx4_unicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol prot); -int mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol prot); -int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - u8 port, int block_mcast_loopback, - enum mlx4_protocol protocol, u64 *reg_id); -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol protocol, u64 reg_id); - -enum { - MLX4_DOMAIN_UVERBS = 0x1000, - MLX4_DOMAIN_ETHTOOL = 0x2000, - MLX4_DOMAIN_RFS = 0x3000, - MLX4_DOMAIN_NIC = 0x5000, -}; - -enum mlx4_net_trans_rule_id { - MLX4_NET_TRANS_RULE_ID_ETH = 0, - MLX4_NET_TRANS_RULE_ID_IB, - MLX4_NET_TRANS_RULE_ID_IPV6, - MLX4_NET_TRANS_RULE_ID_IPV4, - MLX4_NET_TRANS_RULE_ID_TCP, - MLX4_NET_TRANS_RULE_ID_UDP, - MLX4_NET_TRANS_RULE_NUM, /* should be last */ - MLX4_NET_TRANS_RULE_DUMMY = -1, /* force enum to be signed */ -}; - -extern const u16 __sw_id_hw[]; - -static inline int map_hw_to_sw_id(u16 header_id) -{ - - int i; - for (i = 0; i < MLX4_NET_TRANS_RULE_NUM; i++) { - if (header_id == __sw_id_hw[i]) - return i; - } - return -EINVAL; -} - -enum mlx4_net_trans_promisc_mode { - MLX4_FS_REGULAR = 1, - MLX4_FS_ALL_DEFAULT, - MLX4_FS_MC_DEFAULT, - MLX4_FS_UC_SNIFFER, - MLX4_FS_MC_SNIFFER, - MLX4_FS_MODE_NUM, /* should be last */ - MLX4_FS_MODE_DUMMY = -1, /* force enum to be signed */ -}; - -struct mlx4_spec_eth { - u8 dst_mac[6]; - u8 dst_mac_msk[6]; - u8 src_mac[6]; - u8 src_mac_msk[6]; - u8 ether_type_enable; - __be16 ether_type; - __be16 vlan_id_msk; - __be16 vlan_id; -}; - -struct mlx4_spec_tcp_udp { - __be16 dst_port; - __be16 dst_port_msk; - __be16 src_port; - __be16 src_port_msk; -}; - -struct mlx4_spec_ipv4 { - __be32 dst_ip; - __be32 dst_ip_msk; - __be32 src_ip; - __be32 src_ip_msk; -}; - -struct mlx4_spec_ib { - __be32 l3_qpn; - __be32 qpn_msk; - u8 dst_gid[16]; - u8 dst_gid_msk[16]; -}; - -struct mlx4_spec_list { - struct list_head list; - enum mlx4_net_trans_rule_id id; - union { - struct mlx4_spec_eth eth; - struct mlx4_spec_ib ib; - struct mlx4_spec_ipv4 ipv4; - struct mlx4_spec_tcp_udp tcp_udp; - }; -}; - -enum mlx4_net_trans_hw_rule_queue { - MLX4_NET_TRANS_Q_FIFO, - MLX4_NET_TRANS_Q_LIFO, -}; - -struct mlx4_net_trans_rule { - struct list_head list; - enum mlx4_net_trans_hw_rule_queue queue_mode; - bool exclusive; - bool allow_loopback; - enum mlx4_net_trans_promisc_mode promisc_mode; - u8 port; - u16 priority; - u32 qpn; -}; - -struct mlx4_net_trans_rule_hw_ctrl { - __be16 prio; - u8 type; - u8 flags; - u8 rsvd1; - u8 funcid; - u8 vep; - u8 port; - __be32 qpn; - __be32 rsvd2; -}; - -struct mlx4_net_trans_rule_hw_ib { - u8 size; - u8 rsvd1; - __be16 id; - u32 rsvd2; - __be32 l3_qpn; - __be32 qpn_mask; - u8 dst_gid[16]; - u8 dst_gid_msk[16]; -} __packed; - -struct mlx4_net_trans_rule_hw_eth { - u8 size; - u8 rsvd; - __be16 id; - u8 rsvd1[6]; - u8 dst_mac[6]; - u16 rsvd2; - u8 dst_mac_msk[6]; - u16 rsvd3; - u8 src_mac[6]; - u16 rsvd4; - u8 src_mac_msk[6]; - u8 rsvd5; - u8 ether_type_enable; - __be16 ether_type; - __be16 vlan_tag_msk; - __be16 vlan_tag; -} __packed; - -struct mlx4_net_trans_rule_hw_tcp_udp { - u8 size; - u8 rsvd; - __be16 id; - __be16 rsvd1[3]; - __be16 dst_port; - __be16 rsvd2; - __be16 dst_port_msk; - __be16 rsvd3; - __be16 src_port; - __be16 rsvd4; - __be16 src_port_msk; -} __packed; - -struct mlx4_net_trans_rule_hw_ipv4 { - u8 size; - u8 rsvd; - __be16 id; - __be32 rsvd1; - __be32 dst_ip; - __be32 dst_ip_msk; - __be32 src_ip; - __be32 src_ip_msk; -} __packed; - -struct _rule_hw { - union { - struct { - u8 size; - u8 rsvd; - __be16 id; - }; - struct mlx4_net_trans_rule_hw_eth eth; - struct mlx4_net_trans_rule_hw_ib ib; - struct mlx4_net_trans_rule_hw_ipv4 ipv4; - struct mlx4_net_trans_rule_hw_tcp_udp tcp_udp; - }; -}; - -int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, u32 qpn, - enum mlx4_net_trans_promisc_mode mode); -int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port, - enum mlx4_net_trans_promisc_mode mode); -int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port); -int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port); -int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port); -int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port); - -int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac); -void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac); -int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port); -int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac); -void mlx4_set_stats_bitmap(struct mlx4_dev *dev, unsigned long *stats_bitmap); -int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, - u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx); -int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, - u8 promisc); -int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc); -int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, - u8 *pg, u16 *ratelimit); -int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); -int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); -void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan); - -int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, - int npages, u64 iova, u32 *lkey, u32 *rkey); -int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, - int max_maps, u8 page_shift, struct mlx4_fmr *fmr); -int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr); -void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, - u32 *lkey, u32 *rkey); -int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); -int mlx4_SYNC_TPT(struct mlx4_dev *dev); -int mlx4_query_diag_counters(struct mlx4_dev *mlx4_dev, int array_length, - u8 op_modifier, u32 in_offset[], - u32 counter_out[]); - -int mlx4_test_interrupts(struct mlx4_dev *dev); -int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector); -void mlx4_release_eq(struct mlx4_dev *dev, int vec); - -int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port); -int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port); - -int mlx4_counter_alloc(struct mlx4_dev *dev, u8 port, u32 *idx); -void mlx4_counter_free(struct mlx4_dev *dev, u8 port, u32 idx); - -int mlx4_flow_attach(struct mlx4_dev *dev, - struct mlx4_net_trans_rule *rule, u64 *reg_id); -int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id); -int map_sw_to_hw_steering_mode(struct mlx4_dev *dev, - enum mlx4_net_trans_promisc_mode flow_type); -int map_sw_to_hw_steering_id(struct mlx4_dev *dev, - enum mlx4_net_trans_rule_id id); -int hw_rule_sz(struct mlx4_dev *dev, enum mlx4_net_trans_rule_id id); - -void mlx4_sync_pkey_table(struct mlx4_dev *dev, int slave, int port, - int i, int val); - -int mlx4_get_parav_qkey(struct mlx4_dev *dev, u32 qpn, u32 *qkey); - -int mlx4_is_slave_active(struct mlx4_dev *dev, int slave); -int mlx4_gen_pkey_eqe(struct mlx4_dev *dev, int slave, u8 port); -int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port); -int mlx4_gen_slaves_port_mgt_ev(struct mlx4_dev *dev, u8 port, int attr, u16 lid, u8 sl); -int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port, u8 port_subtype_change); -enum slave_port_state mlx4_get_slave_port_state(struct mlx4_dev *dev, int slave, u8 port); -int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int event, enum slave_port_gen_event *gen_event); - -void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid); -__be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave); -int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, int *slave_id); -int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u8 *gid); - -int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn); - -int mlx4_read_clock(struct mlx4_dev *dev); -int mlx4_get_internal_clock_params(struct mlx4_dev *dev, - struct mlx4_clock_params *params); - -int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, - u16 offset, u16 size, u8 *data); - -#endif /* MLX4_DEVICE_H */ diff --git a/sys/ofed/include/linux/mlx4/doorbell.h b/sys/ofed/include/linux/mlx4/doorbell.h deleted file mode 100644 index 6724e5ea2966..000000000000 --- a/sys/ofed/include/linux/mlx4/doorbell.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2004 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2005 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. - */ - -#ifndef MLX4_DOORBELL_H -#define MLX4_DOORBELL_H - -#include <linux/types.h> -#include <linux/io.h> - -#define MLX4_SEND_DOORBELL 0x14 -#define MLX4_CQ_DOORBELL 0x20 - -#if BITS_PER_LONG == 64 -/* - * Assume that we can just write a 64-bit doorbell atomically. s390 - * actually doesn't have writeq() but S/390 systems don't even have - * PCI so we won't worry about it. - */ - -#define MLX4_DECLARE_DOORBELL_LOCK(name) -#define MLX4_INIT_DOORBELL_LOCK(ptr) do { } while (0) -#define MLX4_GET_DOORBELL_LOCK(ptr) (NULL) - -static inline void mlx4_write64(__be32 val[2], void __iomem *dest, - spinlock_t *doorbell_lock) -{ - __raw_writeq(*(u64 *) val, dest); -} - -#else - -/* - * Just fall back to a spinlock to protect the doorbell if - * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit - * MMIO writes. - */ - -#define MLX4_DECLARE_DOORBELL_LOCK(name) spinlock_t name; -#define MLX4_INIT_DOORBELL_LOCK(ptr) spin_lock_init(ptr) -#define MLX4_GET_DOORBELL_LOCK(ptr) (ptr) - -static inline void mlx4_write64(__be32 val[2], void __iomem *dest, - spinlock_t *doorbell_lock) -{ - unsigned long flags; - - spin_lock_irqsave(doorbell_lock, flags); - __raw_writel((__force u32) val[0], dest); - __raw_writel((__force u32) val[1], (u8 *)dest + 4); - spin_unlock_irqrestore(doorbell_lock, flags); -} - -#endif - -#endif /* MLX4_DOORBELL_H */ diff --git a/sys/ofed/include/linux/mlx4/driver.h b/sys/ofed/include/linux/mlx4/driver.h deleted file mode 100644 index b090c01a48d5..000000000000 --- a/sys/ofed/include/linux/mlx4/driver.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2006 Cisco Systems, Inc. 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. - */ - -#ifndef MLX4_DRIVER_H -#define MLX4_DRIVER_H - -#include <linux/mlx4/device.h> - -struct mlx4_dev; - -#define MLX4_MAC_MASK 0xffffffffffffULL -#define MLX4_BE_SHORT_MASK cpu_to_be16(0xffff) -#define MLX4_BE_WORD_MASK cpu_to_be32(0xffffffff) - -enum mlx4_dev_event { - MLX4_DEV_EVENT_CATASTROPHIC_ERROR, - MLX4_DEV_EVENT_PORT_UP, - MLX4_DEV_EVENT_PORT_DOWN, - MLX4_DEV_EVENT_PORT_REINIT, - MLX4_DEV_EVENT_PORT_MGMT_CHANGE, - MLX4_DEV_EVENT_SLAVE_INIT, - MLX4_DEV_EVENT_SLAVE_SHUTDOWN, -}; - -struct mlx4_interface { - void * (*add) (struct mlx4_dev *dev); - void (*remove)(struct mlx4_dev *dev, void *context); - void (*event) (struct mlx4_dev *dev, void *context, - enum mlx4_dev_event event, unsigned long param); - void * (*get_dev)(struct mlx4_dev *dev, void *context, u8 port); - struct list_head list; - enum mlx4_protocol protocol; -}; - -enum { - MLX4_MAX_DEVICES = 32, - MLX4_DEVS_TBL_SIZE = MLX4_MAX_DEVICES + 1, - MLX4_DBDF2VAL_STR_SIZE = 512, - MLX4_STR_NAME_SIZE = 64, - MLX4_MAX_BDF_VALS = 2, - MLX4_ENDOF_TBL = -1LL -}; - -struct mlx4_dbdf2val { - u64 dbdf; - int val[MLX4_MAX_BDF_VALS]; -}; - -struct mlx4_range { - int min; - int max; -}; - -/* - * mlx4_dbdf2val_lst struct holds all the data needed to convert - * dbdf-to-value-list string into dbdf-to-value table. - * dbdf-to-value-list string is a comma separated list of dbdf-to-value strings. - * the format of dbdf-to-value string is: "[mmmm:]bb:dd.f-v1[;v2]" - * mmmm - Domain number (optional) - * bb - Bus number - * dd - device number - * f - Function number - * v1 - First value related to the domain-bus-device-function. - * v2 - Second value related to the domain-bus-device-function (optional). - * bb, dd - Two hexadecimal digits without preceding 0x. - * mmmm - Four hexadecimal digits without preceding 0x. - * f - One hexadecimal without preceding 0x. - * v1,v2 - Number with normal convention (e.g 100, 0xd3). - * dbdf-to-value-list string format: - * "[mmmm:]bb:dd.f-v1[;v2],[mmmm:]bb:dd.f-v1[;v2],..." - * - */ -struct mlx4_dbdf2val_lst { - char name[MLX4_STR_NAME_SIZE]; /* String name */ - char str[MLX4_DBDF2VAL_STR_SIZE]; /* dbdf2val list str */ - struct mlx4_dbdf2val tbl[MLX4_DEVS_TBL_SIZE];/* dbdf to value table */ - int num_vals; /* # of vals per dbdf */ - int def_val[MLX4_MAX_BDF_VALS]; /* Default values */ - struct mlx4_range range; /* Valid values range */ -}; - -int mlx4_fill_dbdf2val_tbl(struct mlx4_dbdf2val_lst *dbdf2val_lst); -int mlx4_get_val(struct mlx4_dbdf2val *tbl, struct pci_dev *pdev, int idx, - int *val); - -int mlx4_register_interface(struct mlx4_interface *intf); -void mlx4_unregister_interface(struct mlx4_interface *intf); - -void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, - int port); - -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif -static inline u64 mlx4_mac_to_u64(const u8 *addr) -{ - u64 mac = 0; - int i; - - for (i = 0; i < ETH_ALEN; i++) { - mac <<= 8; - mac |= addr[i]; - } - return mac; -} - -#endif /* MLX4_DRIVER_H */ diff --git a/sys/ofed/include/linux/mlx4/qp.h b/sys/ofed/include/linux/mlx4/qp.h deleted file mode 100644 index c8b6cb108b25..000000000000 --- a/sys/ofed/include/linux/mlx4/qp.h +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. 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. - */ - -#ifndef MLX4_QP_H -#define MLX4_QP_H - -#include <linux/types.h> - -#include <linux/mlx4/device.h> - -#define MLX4_INVALID_LKEY 0x100 - -#define DS_SIZE_ALIGNMENT 16 - -#define SET_BYTE_COUNT(byte_count) cpu_to_be32(byte_count) -#define SET_LSO_MSS(mss_hdr_size) cpu_to_be32(mss_hdr_size) -#define DS_BYTE_COUNT_MASK cpu_to_be32(0x7fffffff) - -enum ib_m_qp_attr_mask { - IB_M_EXT_CLASS_1 = 1 << 28, - IB_M_EXT_CLASS_2 = 1 << 29, - IB_M_EXT_CLASS_3 = 1 << 30, - - IB_M_QP_MOD_VEND_MASK = (IB_M_EXT_CLASS_1 | IB_M_EXT_CLASS_2 | - IB_M_EXT_CLASS_3) -}; - -enum mlx4_qp_optpar { - MLX4_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, - MLX4_QP_OPTPAR_RRE = 1 << 1, - MLX4_QP_OPTPAR_RAE = 1 << 2, - MLX4_QP_OPTPAR_RWE = 1 << 3, - MLX4_QP_OPTPAR_PKEY_INDEX = 1 << 4, - MLX4_QP_OPTPAR_Q_KEY = 1 << 5, - MLX4_QP_OPTPAR_RNR_TIMEOUT = 1 << 6, - MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH = 1 << 7, - MLX4_QP_OPTPAR_SRA_MAX = 1 << 8, - MLX4_QP_OPTPAR_RRA_MAX = 1 << 9, - MLX4_QP_OPTPAR_PM_STATE = 1 << 10, - MLX4_QP_OPTPAR_RETRY_COUNT = 1 << 12, - MLX4_QP_OPTPAR_RNR_RETRY = 1 << 13, - MLX4_QP_OPTPAR_ACK_TIMEOUT = 1 << 14, - MLX4_QP_OPTPAR_SCHED_QUEUE = 1 << 16, - MLX4_QP_OPTPAR_COUNTER_INDEX = 1 << 20 -}; - -enum mlx4_qp_state { - MLX4_QP_STATE_RST = 0, - MLX4_QP_STATE_INIT = 1, - MLX4_QP_STATE_RTR = 2, - MLX4_QP_STATE_RTS = 3, - MLX4_QP_STATE_SQER = 4, - MLX4_QP_STATE_SQD = 5, - MLX4_QP_STATE_ERR = 6, - MLX4_QP_STATE_SQ_DRAINING = 7, - MLX4_QP_NUM_STATE -}; - -enum { - MLX4_QP_ST_RC = 0x0, - MLX4_QP_ST_UC = 0x1, - MLX4_QP_ST_RD = 0x2, - MLX4_QP_ST_UD = 0x3, - MLX4_QP_ST_XRC = 0x6, - MLX4_QP_ST_MLX = 0x7 -}; - -enum { - MLX4_QP_PM_MIGRATED = 0x3, - MLX4_QP_PM_ARMED = 0x0, - MLX4_QP_PM_REARM = 0x1 -}; - -enum { - /* params1 */ - MLX4_QP_BIT_SRE = 1 << 15, - MLX4_QP_BIT_SWE = 1 << 14, - MLX4_QP_BIT_SAE = 1 << 13, - /* params2 */ - MLX4_QP_BIT_RRE = 1 << 15, - MLX4_QP_BIT_RWE = 1 << 14, - MLX4_QP_BIT_RAE = 1 << 13, - MLX4_QP_BIT_RIC = 1 << 4, - MLX4_QP_BIT_COLL_SYNC_RQ = 1 << 2, - MLX4_QP_BIT_COLL_SYNC_SQ = 1 << 1, - MLX4_QP_BIT_COLL_MASTER = 1 << 0 -}; - -enum { - MLX4_RSS_HASH_XOR = 0, - MLX4_RSS_HASH_TOP = 1, - - MLX4_RSS_UDP_IPV6 = 1 << 0, - MLX4_RSS_UDP_IPV4 = 1 << 1, - MLX4_RSS_TCP_IPV6 = 1 << 2, - MLX4_RSS_IPV6 = 1 << 3, - MLX4_RSS_TCP_IPV4 = 1 << 4, - MLX4_RSS_IPV4 = 1 << 5, - - /* offset of mlx4_rss_context within mlx4_qp_context.pri_path */ - MLX4_RSS_OFFSET_IN_QPC_PRI_PATH = 0x24, - /* offset of being RSS indirection QP within mlx4_qp_context.flags */ - MLX4_RSS_QPC_FLAG_OFFSET = 13, -}; - -struct mlx4_rss_context { - __be32 base_qpn; - __be32 default_qpn; - u16 reserved; - u8 hash_fn; - u8 flags; - __be32 rss_key[10]; - __be32 base_qpn_udp; -}; - -struct mlx4_qp_path { - u8 fl; - u8 vlan_control; - u8 disable_pkey_check; - u8 pkey_index; - u8 counter_index; - u8 grh_mylmc; - __be16 rlid; - u8 ackto; - u8 mgid_index; - u8 static_rate; - u8 hop_limit; - __be32 tclass_flowlabel; - u8 rgid[16]; - u8 sched_queue; - u8 vlan_index; - u8 feup; - u8 fvl_rx; - u8 reserved4[2]; - u8 dmac[6]; -}; - -enum { /* fl */ - MLX4_FL_CV = 1 << 6, - MLX4_FL_ETH_HIDE_CQE_VLAN = 1 << 2, - MLX4_FL_ETH_SRC_CHECK_MC_LB = 1 << 1, - MLX4_FL_ETH_SRC_CHECK_UC_LB = 1 << 0, -}; -enum { /* vlan_control */ - MLX4_VLAN_CTRL_ETH_SRC_CHECK_IF_COUNTER = 1 << 7, - MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED = 1 << 6, - MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED = 1 << 2, - MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED = 1 << 1,/* 802.1p priorty tag*/ - MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED = 1 << 0 -}; - -enum { /* feup */ - MLX4_FEUP_FORCE_ETH_UP = 1 << 6, /* force Eth UP */ - MLX4_FSM_FORCE_ETH_SRC_MAC = 1 << 5, /* force Source MAC */ - MLX4_FVL_FORCE_ETH_VLAN = 1 << 3 /* force Eth vlan */ -}; - -enum { /* fvl_rx */ - MLX4_FVL_RX_FORCE_ETH_VLAN = 1 << 0 /* enforce Eth rx vlan */ -}; - -struct mlx4_qp_context { - __be32 flags; - __be32 pd; - u8 mtu_msgmax; - u8 rq_size_stride; - u8 sq_size_stride; - u8 rlkey; - __be32 usr_page; - __be32 local_qpn; - __be32 remote_qpn; - struct mlx4_qp_path pri_path; - struct mlx4_qp_path alt_path; - __be32 params1; - u32 reserved1; - __be32 next_send_psn; - __be32 cqn_send; - u32 reserved2[2]; - __be32 last_acked_psn; - __be32 ssn; - __be32 params2; - __be32 rnr_nextrecvpsn; - __be32 xrcd; - __be32 cqn_recv; - __be64 db_rec_addr; - __be32 qkey; - __be32 srqn; - __be32 msn; - __be16 rq_wqe_counter; - __be16 sq_wqe_counter; - u32 reserved3[2]; - __be32 param3; - __be32 nummmcpeers_basemkey; - u8 log_page_size; - u8 reserved4[2]; - u8 mtt_base_addr_h; - __be32 mtt_base_addr_l; - u32 reserved5[10]; -}; - -struct mlx4_update_qp_context { - __be64 qp_mask; - __be64 primary_addr_path_mask; - __be64 secondary_addr_path_mask; - u64 reserved1; - struct mlx4_qp_context qp_context; - u64 reserved2[58]; -}; - -enum { - MLX4_UPD_QP_MASK_PM_STATE = 32, - MLX4_UPD_QP_MASK_VSD = 33, -}; - -enum { - MLX4_UPD_QP_PATH_MASK_PKEY_INDEX = 0 + 32, - MLX4_UPD_QP_PATH_MASK_FSM = 1 + 32, - MLX4_UPD_QP_PATH_MASK_MAC_INDEX = 2 + 32, - MLX4_UPD_QP_PATH_MASK_FVL = 3 + 32, - MLX4_UPD_QP_PATH_MASK_CV = 4 + 32, - MLX4_UPD_QP_PATH_MASK_VLAN_INDEX = 5 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN = 6 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED = 7 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P = 8 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED = 9 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED = 10 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P = 11 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED = 12 + 32, - MLX4_UPD_QP_PATH_MASK_FEUP = 13 + 32, - MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE = 14 + 32, - MLX4_UPD_QP_PATH_MASK_IF_COUNTER_INDEX = 15 + 32, - MLX4_UPD_QP_PATH_MASK_FVL_RX = 16 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_UC_LB = 18 + 32, - MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB = 19 + 32, -}; - -enum { /* param3 */ - MLX4_STRIP_VLAN = 1 << 30 -}; - - -/* Which firmware version adds support for NEC (NoErrorCompletion) bit */ -#define MLX4_FW_VER_WQE_CTRL_NEC mlx4_fw_ver(2, 2, 232) - -enum { - MLX4_WQE_CTRL_OWN = 1 << 31, - MLX4_WQE_CTRL_NEC = 1 << 29, - MLX4_WQE_CTRL_RR = 1 << 6, - MLX4_WQE_CTRL_FENCE = 1 << 6, - MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, - MLX4_WQE_CTRL_SOLICITED = 1 << 1, - MLX4_WQE_CTRL_IP_CSUM = 1 << 4, - MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, - MLX4_WQE_CTRL_INS_VLAN = 1 << 6, - MLX4_WQE_CTRL_STRONG_ORDER = 1 << 7, - MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0, -}; - -struct mlx4_wqe_ctrl_seg { - __be32 owner_opcode; - __be16 vlan_tag; - u8 ins_vlan; - u8 fence_size; - /* - * High 24 bits are SRC remote buffer; low 8 bits are flags: - * [7] SO (strong ordering) - * [5] TCP/UDP checksum - * [4] IP checksum - * [3:2] C (generate completion queue entry) - * [1] SE (solicited event) - * [0] FL (force loopback) - */ - union { - __be32 srcrb_flags; - __be16 srcrb_flags16[2]; - }; - /* - * imm is immediate data for send/RDMA write w/ immediate; - * also invalidation key for send with invalidate; input - * modifier for WQEs on CCQs. - */ - __be32 imm; -}; - -enum { - MLX4_WQE_MLX_VL15 = 1 << 17, - MLX4_WQE_MLX_SLR = 1 << 16 -}; - -struct mlx4_wqe_mlx_seg { - u8 owner; - u8 reserved1[2]; - u8 opcode; - __be16 sched_prio; - u8 reserved2; - u8 size; - /* - * [17] VL15 - * [16] SLR - * [15:12] static rate - * [11:8] SL - * [4] ICRC - * [3:2] C - * [0] FL (force loopback) - */ - __be32 flags; - __be16 rlid; - u16 reserved3; -}; - -struct mlx4_wqe_datagram_seg { - __be32 av[8]; - __be32 dqpn; - __be32 qkey; - __be16 vlan; - u8 mac[6]; -}; - -struct mlx4_wqe_lso_seg { - __be32 mss_hdr_size; - __be32 header[0]; -}; - -enum mlx4_wqe_bind_seg_flags2 { - MLX4_WQE_BIND_TYPE_2 = (1<<31), - MLX4_WQE_BIND_ZERO_BASED = (1<<30), -}; - -struct mlx4_wqe_bind_seg { - __be32 flags1; - __be32 flags2; - __be32 new_rkey; - __be32 lkey; - __be64 addr; - __be64 length; -}; - -enum { - MLX4_WQE_FMR_PERM_LOCAL_READ = 1 << 27, - MLX4_WQE_FMR_PERM_LOCAL_WRITE = 1 << 28, - MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_READ = 1 << 29, - MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_WRITE = 1 << 30, - MLX4_WQE_FMR_AND_BIND_PERM_ATOMIC = 1 << 31 -}; - -struct mlx4_wqe_fmr_seg { - __be32 flags; - __be32 mem_key; - __be64 buf_list; - __be64 start_addr; - __be64 reg_len; - __be32 offset; - __be32 page_size; - u32 reserved[2]; -}; - -struct mlx4_wqe_fmr_ext_seg { - u8 flags; - u8 reserved; - __be16 app_mask; - __be16 wire_app_tag; - __be16 mem_app_tag; - __be32 wire_ref_tag_base; - __be32 mem_ref_tag_base; -}; - -struct mlx4_wqe_local_inval_seg { - u64 reserved1; - __be32 mem_key; - u32 reserved2; - u64 reserved3[2]; -}; - -struct mlx4_wqe_raddr_seg { - __be64 raddr; - __be32 rkey; - u32 reserved; -}; - -struct mlx4_wqe_atomic_seg { - __be64 swap_add; - __be64 compare; -}; - -struct mlx4_wqe_masked_atomic_seg { - __be64 swap_add; - __be64 compare; - __be64 swap_add_mask; - __be64 compare_mask; -}; - -struct mlx4_wqe_data_seg { - __be32 byte_count; - __be32 lkey; - __be64 addr; -}; - -enum { - MLX4_INLINE_ALIGN = 64, - MLX4_INLINE_SEG = 1 << 31, -}; - -struct mlx4_wqe_inline_seg { - __be32 byte_count; -}; - -int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, - struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar, - int sqd_event, struct mlx4_qp *qp); - -int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, - struct mlx4_qp_context *context); - -int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, - struct mlx4_qp_context *context, - struct mlx4_qp *qp, enum mlx4_qp_state *qp_state); - -static inline struct mlx4_qp *__mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) -{ - return radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1)); -} - -void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp); - -#endif /* MLX4_QP_H */ diff --git a/sys/ofed/include/linux/mlx4/srq.h b/sys/ofed/include/linux/mlx4/srq.h deleted file mode 100644 index 192e0f7784f2..000000000000 --- a/sys/ofed/include/linux/mlx4/srq.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2007 Cisco Systems, Inc. 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. - */ - -#ifndef MLX4_SRQ_H -#define MLX4_SRQ_H - -struct mlx4_wqe_srq_next_seg { - u16 reserved1; - __be16 next_wqe_index; - u32 reserved2[3]; -}; - -struct mlx4_srq *mlx4_srq_lookup(struct mlx4_dev *dev, u32 srqn); - -#endif /* MLX4_SRQ_H */ |