162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2012 Mellanox Technologies. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci /***********************************************************/ 3362306a36Sopenharmony_ci/*This file support the handling of the Alias GUID feature. */ 3462306a36Sopenharmony_ci/***********************************************************/ 3562306a36Sopenharmony_ci#include <rdma/ib_mad.h> 3662306a36Sopenharmony_ci#include <rdma/ib_smi.h> 3762306a36Sopenharmony_ci#include <rdma/ib_cache.h> 3862306a36Sopenharmony_ci#include <rdma/ib_sa.h> 3962306a36Sopenharmony_ci#include <rdma/ib_pack.h> 4062306a36Sopenharmony_ci#include <linux/mlx4/cmd.h> 4162306a36Sopenharmony_ci#include <linux/init.h> 4262306a36Sopenharmony_ci#include <linux/errno.h> 4362306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 4462306a36Sopenharmony_ci#include <linux/delay.h> 4562306a36Sopenharmony_ci#include "mlx4_ib.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ciThe driver keeps the current state of all guids, as they are in the HW. 4962306a36Sopenharmony_ciWhenever we receive an smp mad GUIDInfo record, the data will be cached. 5062306a36Sopenharmony_ci*/ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct mlx4_alias_guid_work_context { 5362306a36Sopenharmony_ci u8 port; 5462306a36Sopenharmony_ci struct mlx4_ib_dev *dev ; 5562306a36Sopenharmony_ci struct ib_sa_query *sa_query; 5662306a36Sopenharmony_ci struct completion done; 5762306a36Sopenharmony_ci int query_id; 5862306a36Sopenharmony_ci struct list_head list; 5962306a36Sopenharmony_ci int block_num; 6062306a36Sopenharmony_ci ib_sa_comp_mask guid_indexes; 6162306a36Sopenharmony_ci u8 method; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct mlx4_next_alias_guid_work { 6562306a36Sopenharmony_ci u8 port; 6662306a36Sopenharmony_ci u8 block_num; 6762306a36Sopenharmony_ci u8 method; 6862306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_info_rec_det rec_det; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port, 7262306a36Sopenharmony_ci int *resched_delay_sec); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_civoid mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num, 7562306a36Sopenharmony_ci u32 port_num, u8 *p_data) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci int i; 7862306a36Sopenharmony_ci u64 guid_indexes; 7962306a36Sopenharmony_ci int slave_id; 8062306a36Sopenharmony_ci u32 port_index = port_num - 1; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 8362306a36Sopenharmony_ci return; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid. 8662306a36Sopenharmony_ci ports_guid[port_num - 1]. 8762306a36Sopenharmony_ci all_rec_per_port[block_num].guid_indexes); 8862306a36Sopenharmony_ci pr_debug("port: %u, guid_indexes: 0x%llx\n", port_num, guid_indexes); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 9162306a36Sopenharmony_ci /* The location of the specific index starts from bit number 4 9262306a36Sopenharmony_ci * until bit num 11 */ 9362306a36Sopenharmony_ci if (test_bit(i + 4, (unsigned long *)&guid_indexes)) { 9462306a36Sopenharmony_ci slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ; 9562306a36Sopenharmony_ci if (slave_id >= dev->dev->num_slaves) { 9662306a36Sopenharmony_ci pr_debug("The last slave: %d\n", slave_id); 9762306a36Sopenharmony_ci return; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* cache the guid: */ 10162306a36Sopenharmony_ci memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id], 10262306a36Sopenharmony_ci &p_data[i * GUID_REC_SIZE], 10362306a36Sopenharmony_ci GUID_REC_SIZE); 10462306a36Sopenharmony_ci } else 10562306a36Sopenharmony_ci pr_debug("Guid number: %d in block: %d" 10662306a36Sopenharmony_ci " was not updated\n", i, block_num); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci if (index >= NUM_ALIAS_GUID_PER_PORT) { 11362306a36Sopenharmony_ci pr_err("%s: ERROR: asked for index:%d\n", __func__, index); 11462306a36Sopenharmony_ci return (__force __be64) -1; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index]; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return IB_SA_COMP_MASK(4 + index); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_civoid mlx4_ib_slave_alias_guid_event(struct mlx4_ib_dev *dev, int slave, 12662306a36Sopenharmony_ci int port, int slave_init) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci __be64 curr_guid, required_guid; 12962306a36Sopenharmony_ci int record_num = slave / 8; 13062306a36Sopenharmony_ci int index = slave % 8; 13162306a36Sopenharmony_ci int port_index = port - 1; 13262306a36Sopenharmony_ci unsigned long flags; 13362306a36Sopenharmony_ci int do_work = 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 13662306a36Sopenharmony_ci if (dev->sriov.alias_guid.ports_guid[port_index].state_flags & 13762306a36Sopenharmony_ci GUID_STATE_NEED_PORT_INIT) 13862306a36Sopenharmony_ci goto unlock; 13962306a36Sopenharmony_ci if (!slave_init) { 14062306a36Sopenharmony_ci curr_guid = *(__be64 *)&dev->sriov. 14162306a36Sopenharmony_ci alias_guid.ports_guid[port_index]. 14262306a36Sopenharmony_ci all_rec_per_port[record_num]. 14362306a36Sopenharmony_ci all_recs[GUID_REC_SIZE * index]; 14462306a36Sopenharmony_ci if (curr_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL) || 14562306a36Sopenharmony_ci !curr_guid) 14662306a36Sopenharmony_ci goto unlock; 14762306a36Sopenharmony_ci required_guid = cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL); 14862306a36Sopenharmony_ci } else { 14962306a36Sopenharmony_ci required_guid = mlx4_get_admin_guid(dev->dev, slave, port); 15062306a36Sopenharmony_ci if (required_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 15162306a36Sopenharmony_ci goto unlock; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci *(__be64 *)&dev->sriov.alias_guid.ports_guid[port_index]. 15462306a36Sopenharmony_ci all_rec_per_port[record_num]. 15562306a36Sopenharmony_ci all_recs[GUID_REC_SIZE * index] = required_guid; 15662306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port_index]. 15762306a36Sopenharmony_ci all_rec_per_port[record_num].guid_indexes 15862306a36Sopenharmony_ci |= mlx4_ib_get_aguid_comp_mask_from_ix(index); 15962306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port_index]. 16062306a36Sopenharmony_ci all_rec_per_port[record_num].status 16162306a36Sopenharmony_ci = MLX4_GUID_INFO_STATUS_IDLE; 16262306a36Sopenharmony_ci /* set to run immediately */ 16362306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port_index]. 16462306a36Sopenharmony_ci all_rec_per_port[record_num].time_to_run = 0; 16562306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port_index]. 16662306a36Sopenharmony_ci all_rec_per_port[record_num]. 16762306a36Sopenharmony_ci guids_retry_schedule[index] = 0; 16862306a36Sopenharmony_ci do_work = 1; 16962306a36Sopenharmony_ciunlock: 17062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (do_work) 17362306a36Sopenharmony_ci mlx4_ib_init_alias_guid_work(dev, port_index); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * Whenever new GUID is set/unset (guid table change) create event and 17862306a36Sopenharmony_ci * notify the relevant slave (master also should be notified). 17962306a36Sopenharmony_ci * If the GUID value is not as we have in the cache the slave will not be 18062306a36Sopenharmony_ci * updated; in this case it waits for the smp_snoop or the port management 18162306a36Sopenharmony_ci * event to call the function and to update the slave. 18262306a36Sopenharmony_ci * block_number - the index of the block (16 blocks available) 18362306a36Sopenharmony_ci * port_number - 1 or 2 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_civoid mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev, 18662306a36Sopenharmony_ci int block_num, u32 port_num, 18762306a36Sopenharmony_ci u8 *p_data) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci int i; 19062306a36Sopenharmony_ci u64 guid_indexes; 19162306a36Sopenharmony_ci int slave_id, slave_port; 19262306a36Sopenharmony_ci enum slave_port_state new_state; 19362306a36Sopenharmony_ci enum slave_port_state prev_state; 19462306a36Sopenharmony_ci __be64 tmp_cur_ag, form_cache_ag; 19562306a36Sopenharmony_ci enum slave_port_gen_event gen_event; 19662306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_info_rec_det *rec; 19762306a36Sopenharmony_ci unsigned long flags; 19862306a36Sopenharmony_ci __be64 required_value; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 20162306a36Sopenharmony_ci return; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci rec = &dev->sriov.alias_guid.ports_guid[port_num - 1]. 20462306a36Sopenharmony_ci all_rec_per_port[block_num]; 20562306a36Sopenharmony_ci guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid. 20662306a36Sopenharmony_ci ports_guid[port_num - 1]. 20762306a36Sopenharmony_ci all_rec_per_port[block_num].guid_indexes); 20862306a36Sopenharmony_ci pr_debug("port: %u, guid_indexes: 0x%llx\n", port_num, guid_indexes); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /*calculate the slaves and notify them*/ 21162306a36Sopenharmony_ci for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 21262306a36Sopenharmony_ci /* the location of the specific index runs from bits 4..11 */ 21362306a36Sopenharmony_ci if (!(test_bit(i + 4, (unsigned long *)&guid_indexes))) 21462306a36Sopenharmony_ci continue; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ; 21762306a36Sopenharmony_ci if (slave_id >= dev->dev->persist->num_vfs + 1) 21862306a36Sopenharmony_ci return; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci slave_port = mlx4_phys_to_slave_port(dev->dev, slave_id, port_num); 22162306a36Sopenharmony_ci if (slave_port < 0) /* this port isn't available for the VF */ 22262306a36Sopenharmony_ci continue; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE]; 22562306a36Sopenharmony_ci form_cache_ag = get_cached_alias_guid(dev, port_num, 22662306a36Sopenharmony_ci (NUM_ALIAS_GUID_IN_REC * block_num) + i); 22762306a36Sopenharmony_ci /* 22862306a36Sopenharmony_ci * Check if guid is not the same as in the cache, 22962306a36Sopenharmony_ci * If it is different, wait for the snoop_smp or the port mgmt 23062306a36Sopenharmony_ci * change event to update the slave on its port state change 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci if (tmp_cur_ag != form_cache_ag) 23362306a36Sopenharmony_ci continue; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 23662306a36Sopenharmony_ci required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 23962306a36Sopenharmony_ci required_value = 0; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (tmp_cur_ag == required_value) { 24262306a36Sopenharmony_ci rec->guid_indexes = rec->guid_indexes & 24362306a36Sopenharmony_ci ~mlx4_ib_get_aguid_comp_mask_from_ix(i); 24462306a36Sopenharmony_ci } else { 24562306a36Sopenharmony_ci /* may notify port down if value is 0 */ 24662306a36Sopenharmony_ci if (tmp_cur_ag != MLX4_NOT_SET_GUID) { 24762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov. 24862306a36Sopenharmony_ci alias_guid.ag_work_lock, flags); 24962306a36Sopenharmony_ci continue; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, 25362306a36Sopenharmony_ci flags); 25462306a36Sopenharmony_ci mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num); 25562306a36Sopenharmony_ci /*2 cases: Valid GUID, and Invalid Guid*/ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/ 25862306a36Sopenharmony_ci prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num); 25962306a36Sopenharmony_ci new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num, 26062306a36Sopenharmony_ci MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID, 26162306a36Sopenharmony_ci &gen_event); 26262306a36Sopenharmony_ci pr_debug("slave: %d, port: %u prev_port_state: %d," 26362306a36Sopenharmony_ci " new_port_state: %d, gen_event: %d\n", 26462306a36Sopenharmony_ci slave_id, port_num, prev_state, new_state, gen_event); 26562306a36Sopenharmony_ci if (gen_event == SLAVE_PORT_GEN_EVENT_UP) { 26662306a36Sopenharmony_ci pr_debug("sending PORT_UP event to slave: %d, port: %u\n", 26762306a36Sopenharmony_ci slave_id, port_num); 26862306a36Sopenharmony_ci mlx4_gen_port_state_change_eqe(dev->dev, slave_id, 26962306a36Sopenharmony_ci port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci } else { /* request to invalidate GUID */ 27262306a36Sopenharmony_ci set_and_calc_slave_port_state(dev->dev, slave_id, port_num, 27362306a36Sopenharmony_ci MLX4_PORT_STATE_IB_EVENT_GID_INVALID, 27462306a36Sopenharmony_ci &gen_event); 27562306a36Sopenharmony_ci if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) { 27662306a36Sopenharmony_ci pr_debug("sending PORT DOWN event to slave: %d, port: %u\n", 27762306a36Sopenharmony_ci slave_id, port_num); 27862306a36Sopenharmony_ci mlx4_gen_port_state_change_eqe(dev->dev, 27962306a36Sopenharmony_ci slave_id, 28062306a36Sopenharmony_ci port_num, 28162306a36Sopenharmony_ci MLX4_PORT_CHANGE_SUBTYPE_DOWN); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void aliasguid_query_handler(int status, 28862306a36Sopenharmony_ci struct ib_sa_guidinfo_rec *guid_rec, 28962306a36Sopenharmony_ci void *context) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct mlx4_ib_dev *dev; 29262306a36Sopenharmony_ci struct mlx4_alias_guid_work_context *cb_ctx = context; 29362306a36Sopenharmony_ci u8 port_index ; 29462306a36Sopenharmony_ci int i; 29562306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_info_rec_det *rec; 29662306a36Sopenharmony_ci unsigned long flags, flags1; 29762306a36Sopenharmony_ci ib_sa_comp_mask declined_guid_indexes = 0; 29862306a36Sopenharmony_ci ib_sa_comp_mask applied_guid_indexes = 0; 29962306a36Sopenharmony_ci unsigned int resched_delay_sec = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!context) 30262306a36Sopenharmony_ci return; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci dev = cb_ctx->dev; 30562306a36Sopenharmony_ci port_index = cb_ctx->port - 1; 30662306a36Sopenharmony_ci rec = &dev->sriov.alias_guid.ports_guid[port_index]. 30762306a36Sopenharmony_ci all_rec_per_port[cb_ctx->block_num]; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (status) { 31062306a36Sopenharmony_ci pr_debug("(port: %d) failed: status = %d\n", 31162306a36Sopenharmony_ci cb_ctx->port, status); 31262306a36Sopenharmony_ci rec->time_to_run = ktime_get_boottime_ns() + 1 * NSEC_PER_SEC; 31362306a36Sopenharmony_ci goto out; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (guid_rec->block_num != cb_ctx->block_num) { 31762306a36Sopenharmony_ci pr_err("block num mismatch: %d != %d\n", 31862306a36Sopenharmony_ci cb_ctx->block_num, guid_rec->block_num); 31962306a36Sopenharmony_ci goto out; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci pr_debug("lid/port: %d/%d, block_num: %d\n", 32362306a36Sopenharmony_ci be16_to_cpu(guid_rec->lid), cb_ctx->port, 32462306a36Sopenharmony_ci guid_rec->block_num); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci rec = &dev->sriov.alias_guid.ports_guid[port_index]. 32762306a36Sopenharmony_ci all_rec_per_port[guid_rec->block_num]; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 33062306a36Sopenharmony_ci for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) { 33162306a36Sopenharmony_ci __be64 sm_response, required_val; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (!(cb_ctx->guid_indexes & 33462306a36Sopenharmony_ci mlx4_ib_get_aguid_comp_mask_from_ix(i))) 33562306a36Sopenharmony_ci continue; 33662306a36Sopenharmony_ci sm_response = *(__be64 *)&guid_rec->guid_info_list 33762306a36Sopenharmony_ci [i * GUID_REC_SIZE]; 33862306a36Sopenharmony_ci required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]; 33962306a36Sopenharmony_ci if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) { 34062306a36Sopenharmony_ci if (required_val == 34162306a36Sopenharmony_ci cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 34262306a36Sopenharmony_ci goto next_entry; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* A new value was set till we got the response */ 34562306a36Sopenharmony_ci pr_debug("need to set new value %llx, record num %d, block_num:%d\n", 34662306a36Sopenharmony_ci be64_to_cpu(required_val), 34762306a36Sopenharmony_ci i, guid_rec->block_num); 34862306a36Sopenharmony_ci goto entry_declined; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* check if the SM didn't assign one of the records. 35262306a36Sopenharmony_ci * if it didn't, re-ask for. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci if (sm_response == MLX4_NOT_SET_GUID) { 35562306a36Sopenharmony_ci if (rec->guids_retry_schedule[i] == 0) 35662306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, 35762306a36Sopenharmony_ci "%s:Record num %d in block_num: %d was declined by SM\n", 35862306a36Sopenharmony_ci __func__, i, 35962306a36Sopenharmony_ci guid_rec->block_num); 36062306a36Sopenharmony_ci goto entry_declined; 36162306a36Sopenharmony_ci } else { 36262306a36Sopenharmony_ci /* properly assigned record. */ 36362306a36Sopenharmony_ci /* We save the GUID we just got from the SM in the 36462306a36Sopenharmony_ci * admin_guid in order to be persistent, and in the 36562306a36Sopenharmony_ci * request from the sm the process will ask for the same GUID */ 36662306a36Sopenharmony_ci if (required_val && 36762306a36Sopenharmony_ci sm_response != required_val) { 36862306a36Sopenharmony_ci /* Warn only on first retry */ 36962306a36Sopenharmony_ci if (rec->guids_retry_schedule[i] == 0) 37062306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set" 37162306a36Sopenharmony_ci " admin guid after SysAdmin " 37262306a36Sopenharmony_ci "configuration. " 37362306a36Sopenharmony_ci "Record num %d in block_num:%d " 37462306a36Sopenharmony_ci "was declined by SM, " 37562306a36Sopenharmony_ci "new val(0x%llx) was kept, SM returned (0x%llx)\n", 37662306a36Sopenharmony_ci __func__, i, 37762306a36Sopenharmony_ci guid_rec->block_num, 37862306a36Sopenharmony_ci be64_to_cpu(required_val), 37962306a36Sopenharmony_ci be64_to_cpu(sm_response)); 38062306a36Sopenharmony_ci goto entry_declined; 38162306a36Sopenharmony_ci } else { 38262306a36Sopenharmony_ci *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] = 38362306a36Sopenharmony_ci sm_response; 38462306a36Sopenharmony_ci if (required_val == 0) 38562306a36Sopenharmony_ci mlx4_set_admin_guid(dev->dev, 38662306a36Sopenharmony_ci sm_response, 38762306a36Sopenharmony_ci (guid_rec->block_num 38862306a36Sopenharmony_ci * NUM_ALIAS_GUID_IN_REC) + i, 38962306a36Sopenharmony_ci cb_ctx->port); 39062306a36Sopenharmony_ci goto next_entry; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_cientry_declined: 39462306a36Sopenharmony_ci declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i); 39562306a36Sopenharmony_ci rec->guids_retry_schedule[i] = 39662306a36Sopenharmony_ci (rec->guids_retry_schedule[i] == 0) ? 1 : 39762306a36Sopenharmony_ci min((unsigned int)60, 39862306a36Sopenharmony_ci rec->guids_retry_schedule[i] * 2); 39962306a36Sopenharmony_ci /* using the minimum value among all entries in that record */ 40062306a36Sopenharmony_ci resched_delay_sec = (resched_delay_sec == 0) ? 40162306a36Sopenharmony_ci rec->guids_retry_schedule[i] : 40262306a36Sopenharmony_ci min(resched_delay_sec, 40362306a36Sopenharmony_ci rec->guids_retry_schedule[i]); 40462306a36Sopenharmony_ci continue; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cinext_entry: 40762306a36Sopenharmony_ci rec->guids_retry_schedule[i] = 0; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci applied_guid_indexes = cb_ctx->guid_indexes & ~declined_guid_indexes; 41162306a36Sopenharmony_ci if (declined_guid_indexes || 41262306a36Sopenharmony_ci rec->guid_indexes & ~(applied_guid_indexes)) { 41362306a36Sopenharmony_ci pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n", 41462306a36Sopenharmony_ci guid_rec->block_num, 41562306a36Sopenharmony_ci be64_to_cpu((__force __be64)rec->guid_indexes), 41662306a36Sopenharmony_ci be64_to_cpu((__force __be64)applied_guid_indexes), 41762306a36Sopenharmony_ci be64_to_cpu((__force __be64)declined_guid_indexes)); 41862306a36Sopenharmony_ci rec->time_to_run = ktime_get_boottime_ns() + 41962306a36Sopenharmony_ci resched_delay_sec * NSEC_PER_SEC; 42062306a36Sopenharmony_ci } else { 42162306a36Sopenharmony_ci rec->status = MLX4_GUID_INFO_STATUS_SET; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci The func is call here to close the cases when the 42662306a36Sopenharmony_ci sm doesn't send smp, so in the sa response the driver 42762306a36Sopenharmony_ci notifies the slave. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num, 43062306a36Sopenharmony_ci cb_ctx->port, 43162306a36Sopenharmony_ci guid_rec->guid_info_list); 43262306a36Sopenharmony_ciout: 43362306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 43462306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 43562306a36Sopenharmony_ci if (!dev->sriov.is_going_down) { 43662306a36Sopenharmony_ci get_low_record_time_index(dev, port_index, &resched_delay_sec); 43762306a36Sopenharmony_ci queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq, 43862306a36Sopenharmony_ci &dev->sriov.alias_guid.ports_guid[port_index]. 43962306a36Sopenharmony_ci alias_guid_work, 44062306a36Sopenharmony_ci msecs_to_jiffies(resched_delay_sec * 1000)); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci if (cb_ctx->sa_query) { 44362306a36Sopenharmony_ci list_del(&cb_ctx->list); 44462306a36Sopenharmony_ci kfree(cb_ctx); 44562306a36Sopenharmony_ci } else 44662306a36Sopenharmony_ci complete(&cb_ctx->done); 44762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 44862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci int i; 45462306a36Sopenharmony_ci u64 cur_admin_val; 45562306a36Sopenharmony_ci ib_sa_comp_mask comp_mask = 0; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status 45862306a36Sopenharmony_ci = MLX4_GUID_INFO_STATUS_SET; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* calculate the comp_mask for that record.*/ 46162306a36Sopenharmony_ci for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 46262306a36Sopenharmony_ci cur_admin_val = 46362306a36Sopenharmony_ci *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. 46462306a36Sopenharmony_ci all_rec_per_port[index].all_recs[GUID_REC_SIZE * i]; 46562306a36Sopenharmony_ci /* 46662306a36Sopenharmony_ci check the admin value: if it's for delete (~00LL) or 46762306a36Sopenharmony_ci it is the first guid of the first record (hw guid) or 46862306a36Sopenharmony_ci the records is not in ownership of the sysadmin and the sm doesn't 46962306a36Sopenharmony_ci need to assign GUIDs, then don't put it up for assignment. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val || 47262306a36Sopenharmony_ci (!index && !i)) 47362306a36Sopenharmony_ci continue; 47462306a36Sopenharmony_ci comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port - 1]. 47762306a36Sopenharmony_ci all_rec_per_port[index].guid_indexes |= comp_mask; 47862306a36Sopenharmony_ci if (dev->sriov.alias_guid.ports_guid[port - 1]. 47962306a36Sopenharmony_ci all_rec_per_port[index].guid_indexes) 48062306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port - 1]. 48162306a36Sopenharmony_ci all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int set_guid_rec(struct ib_device *ibdev, 48662306a36Sopenharmony_ci struct mlx4_next_alias_guid_work *rec) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci int err; 48962306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 49062306a36Sopenharmony_ci struct ib_sa_guidinfo_rec guid_info_rec; 49162306a36Sopenharmony_ci ib_sa_comp_mask comp_mask; 49262306a36Sopenharmony_ci struct ib_port_attr attr; 49362306a36Sopenharmony_ci struct mlx4_alias_guid_work_context *callback_context; 49462306a36Sopenharmony_ci unsigned long resched_delay, flags, flags1; 49562306a36Sopenharmony_ci u8 port = rec->port + 1; 49662306a36Sopenharmony_ci int index = rec->block_num; 49762306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det; 49862306a36Sopenharmony_ci struct list_head *head = 49962306a36Sopenharmony_ci &dev->sriov.alias_guid.ports_guid[port - 1].cb_list; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 50262306a36Sopenharmony_ci err = __mlx4_ib_query_port(ibdev, port, &attr, 1); 50362306a36Sopenharmony_ci if (err) { 50462306a36Sopenharmony_ci pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n", 50562306a36Sopenharmony_ci err, port); 50662306a36Sopenharmony_ci return err; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci /*check the port was configured by the sm, otherwise no need to send */ 50962306a36Sopenharmony_ci if (attr.state != IB_PORT_ACTIVE) { 51062306a36Sopenharmony_ci pr_debug("port %d not active...rescheduling\n", port); 51162306a36Sopenharmony_ci resched_delay = 5 * HZ; 51262306a36Sopenharmony_ci err = -EAGAIN; 51362306a36Sopenharmony_ci goto new_schedule; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL); 51762306a36Sopenharmony_ci if (!callback_context) { 51862306a36Sopenharmony_ci err = -ENOMEM; 51962306a36Sopenharmony_ci resched_delay = HZ * 5; 52062306a36Sopenharmony_ci goto new_schedule; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci callback_context->port = port; 52362306a36Sopenharmony_ci callback_context->dev = dev; 52462306a36Sopenharmony_ci callback_context->block_num = index; 52562306a36Sopenharmony_ci callback_context->guid_indexes = rec_det->guid_indexes; 52662306a36Sopenharmony_ci callback_context->method = rec->method; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec)); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci guid_info_rec.lid = ib_lid_be16(attr.lid); 53162306a36Sopenharmony_ci guid_info_rec.block_num = index; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci memcpy(guid_info_rec.guid_info_list, rec_det->all_recs, 53462306a36Sopenharmony_ci GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC); 53562306a36Sopenharmony_ci comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM | 53662306a36Sopenharmony_ci rec_det->guid_indexes; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci init_completion(&callback_context->done); 53962306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 54062306a36Sopenharmony_ci list_add_tail(&callback_context->list, head); 54162306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci callback_context->query_id = 54462306a36Sopenharmony_ci ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client, 54562306a36Sopenharmony_ci ibdev, port, &guid_info_rec, 54662306a36Sopenharmony_ci comp_mask, rec->method, 1000, 54762306a36Sopenharmony_ci GFP_KERNEL, aliasguid_query_handler, 54862306a36Sopenharmony_ci callback_context, 54962306a36Sopenharmony_ci &callback_context->sa_query); 55062306a36Sopenharmony_ci if (callback_context->query_id < 0) { 55162306a36Sopenharmony_ci pr_debug("ib_sa_guid_info_rec_query failed, query_id: " 55262306a36Sopenharmony_ci "%d. will reschedule to the next 1 sec.\n", 55362306a36Sopenharmony_ci callback_context->query_id); 55462306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 55562306a36Sopenharmony_ci list_del(&callback_context->list); 55662306a36Sopenharmony_ci kfree(callback_context); 55762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 55862306a36Sopenharmony_ci resched_delay = 1 * HZ; 55962306a36Sopenharmony_ci err = -EAGAIN; 56062306a36Sopenharmony_ci goto new_schedule; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci err = 0; 56362306a36Sopenharmony_ci goto out; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cinew_schedule: 56662306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 56762306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 56862306a36Sopenharmony_ci invalidate_guid_record(dev, port, index); 56962306a36Sopenharmony_ci if (!dev->sriov.is_going_down) { 57062306a36Sopenharmony_ci queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 57162306a36Sopenharmony_ci &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 57262306a36Sopenharmony_ci resched_delay); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 57562306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ciout: 57862306a36Sopenharmony_ci return err; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci int j, k, entry; 58462306a36Sopenharmony_ci __be64 guid; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /*Check if the SM doesn't need to assign the GUIDs*/ 58762306a36Sopenharmony_ci for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 58862306a36Sopenharmony_ci for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) { 58962306a36Sopenharmony_ci entry = j * NUM_ALIAS_GUID_IN_REC + k; 59062306a36Sopenharmony_ci /* no request for the 0 entry (hw guid) */ 59162306a36Sopenharmony_ci if (!entry || entry > dev->dev->persist->num_vfs || 59262306a36Sopenharmony_ci !mlx4_is_slave_active(dev->dev, entry)) 59362306a36Sopenharmony_ci continue; 59462306a36Sopenharmony_ci guid = mlx4_get_admin_guid(dev->dev, entry, port); 59562306a36Sopenharmony_ci *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. 59662306a36Sopenharmony_ci all_rec_per_port[j].all_recs 59762306a36Sopenharmony_ci [GUID_REC_SIZE * k] = guid; 59862306a36Sopenharmony_ci pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n", 59962306a36Sopenharmony_ci entry, 60062306a36Sopenharmony_ci be64_to_cpu(guid), 60162306a36Sopenharmony_ci port); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_civoid mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci int i; 60862306a36Sopenharmony_ci unsigned long flags, flags1; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci pr_debug("port %d\n", port); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 61362306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags & 61662306a36Sopenharmony_ci GUID_STATE_NEED_PORT_INIT) { 61762306a36Sopenharmony_ci mlx4_ib_guid_port_init(dev, port); 61862306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[port - 1].state_flags &= 61962306a36Sopenharmony_ci (~GUID_STATE_NEED_PORT_INIT); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++) 62262306a36Sopenharmony_ci invalidate_guid_record(dev, port, i); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) { 62562306a36Sopenharmony_ci /* 62662306a36Sopenharmony_ci make sure no work waits in the queue, if the work is already 62762306a36Sopenharmony_ci queued(not on the timer) the cancel will fail. That is not a problem 62862306a36Sopenharmony_ci because we just want the work started. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ci cancel_delayed_work(&dev->sriov.alias_guid. 63162306a36Sopenharmony_ci ports_guid[port - 1].alias_guid_work); 63262306a36Sopenharmony_ci queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 63362306a36Sopenharmony_ci &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 63462306a36Sopenharmony_ci 0); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 63762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic void set_required_record(struct mlx4_ib_dev *dev, u8 port, 64162306a36Sopenharmony_ci struct mlx4_next_alias_guid_work *next_rec, 64262306a36Sopenharmony_ci int record_index) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci int i; 64562306a36Sopenharmony_ci int lowset_time_entry = -1; 64662306a36Sopenharmony_ci int lowest_time = 0; 64762306a36Sopenharmony_ci ib_sa_comp_mask delete_guid_indexes = 0; 64862306a36Sopenharmony_ci ib_sa_comp_mask set_guid_indexes = 0; 64962306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_info_rec_det *rec = 65062306a36Sopenharmony_ci &dev->sriov.alias_guid.ports_guid[port]. 65162306a36Sopenharmony_ci all_rec_per_port[record_index]; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 65462306a36Sopenharmony_ci if (!(rec->guid_indexes & 65562306a36Sopenharmony_ci mlx4_ib_get_aguid_comp_mask_from_ix(i))) 65662306a36Sopenharmony_ci continue; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] == 65962306a36Sopenharmony_ci cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 66062306a36Sopenharmony_ci delete_guid_indexes |= 66162306a36Sopenharmony_ci mlx4_ib_get_aguid_comp_mask_from_ix(i); 66262306a36Sopenharmony_ci else 66362306a36Sopenharmony_ci set_guid_indexes |= 66462306a36Sopenharmony_ci mlx4_ib_get_aguid_comp_mask_from_ix(i); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <= 66762306a36Sopenharmony_ci lowest_time) { 66862306a36Sopenharmony_ci lowset_time_entry = i; 66962306a36Sopenharmony_ci lowest_time = rec->guids_retry_schedule[i]; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci memcpy(&next_rec->rec_det, rec, sizeof(*rec)); 67462306a36Sopenharmony_ci next_rec->port = port; 67562306a36Sopenharmony_ci next_rec->block_num = record_index; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] == 67862306a36Sopenharmony_ci cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) { 67962306a36Sopenharmony_ci next_rec->rec_det.guid_indexes = delete_guid_indexes; 68062306a36Sopenharmony_ci next_rec->method = MLX4_GUID_INFO_RECORD_DELETE; 68162306a36Sopenharmony_ci } else { 68262306a36Sopenharmony_ci next_rec->rec_det.guid_indexes = set_guid_indexes; 68362306a36Sopenharmony_ci next_rec->method = MLX4_GUID_INFO_RECORD_SET; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci/* return index of record that should be updated based on lowest 68862306a36Sopenharmony_ci * rescheduled time 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_cistatic int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port, 69162306a36Sopenharmony_ci int *resched_delay_sec) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci int record_index = -1; 69462306a36Sopenharmony_ci u64 low_record_time = 0; 69562306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_info_rec_det rec; 69662306a36Sopenharmony_ci int j; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 69962306a36Sopenharmony_ci rec = dev->sriov.alias_guid.ports_guid[port]. 70062306a36Sopenharmony_ci all_rec_per_port[j]; 70162306a36Sopenharmony_ci if (rec.status == MLX4_GUID_INFO_STATUS_IDLE && 70262306a36Sopenharmony_ci rec.guid_indexes) { 70362306a36Sopenharmony_ci if (record_index == -1 || 70462306a36Sopenharmony_ci rec.time_to_run < low_record_time) { 70562306a36Sopenharmony_ci record_index = j; 70662306a36Sopenharmony_ci low_record_time = rec.time_to_run; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci if (resched_delay_sec) { 71162306a36Sopenharmony_ci u64 curr_time = ktime_get_boottime_ns(); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci *resched_delay_sec = (low_record_time < curr_time) ? 0 : 71462306a36Sopenharmony_ci div_u64((low_record_time - curr_time), NSEC_PER_SEC); 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return record_index; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci/* The function returns the next record that was 72162306a36Sopenharmony_ci * not configured (or failed to be configured) */ 72262306a36Sopenharmony_cistatic int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port, 72362306a36Sopenharmony_ci struct mlx4_next_alias_guid_work *rec) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci unsigned long flags; 72662306a36Sopenharmony_ci int record_index; 72762306a36Sopenharmony_ci int ret = 0; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 73062306a36Sopenharmony_ci record_index = get_low_record_time_index(dev, port, NULL); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (record_index < 0) { 73362306a36Sopenharmony_ci ret = -ENOENT; 73462306a36Sopenharmony_ci goto out; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci set_required_record(dev, port, rec, record_index); 73862306a36Sopenharmony_ciout: 73962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 74062306a36Sopenharmony_ci return ret; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic void alias_guid_work(struct work_struct *work) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct delayed_work *delay = to_delayed_work(work); 74662306a36Sopenharmony_ci int ret = 0; 74762306a36Sopenharmony_ci struct mlx4_next_alias_guid_work *rec; 74862306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port = 74962306a36Sopenharmony_ci container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det, 75062306a36Sopenharmony_ci alias_guid_work); 75162306a36Sopenharmony_ci struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent; 75262306a36Sopenharmony_ci struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid, 75362306a36Sopenharmony_ci struct mlx4_ib_sriov, 75462306a36Sopenharmony_ci alias_guid); 75562306a36Sopenharmony_ci struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci rec = kzalloc(sizeof *rec, GFP_KERNEL); 75862306a36Sopenharmony_ci if (!rec) 75962306a36Sopenharmony_ci return; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1); 76262306a36Sopenharmony_ci ret = get_next_record_to_update(dev, sriov_alias_port->port, rec); 76362306a36Sopenharmony_ci if (ret) { 76462306a36Sopenharmony_ci pr_debug("No more records to update.\n"); 76562306a36Sopenharmony_ci goto out; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci set_guid_rec(&dev->ib_dev, rec); 76962306a36Sopenharmony_ciout: 77062306a36Sopenharmony_ci kfree(rec); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_civoid mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci unsigned long flags, flags1; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 77962306a36Sopenharmony_ci return; 78062306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 78162306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 78262306a36Sopenharmony_ci if (!dev->sriov.is_going_down) { 78362306a36Sopenharmony_ci /* If there is pending one should cancel then run, otherwise 78462306a36Sopenharmony_ci * won't run till previous one is ended as same work 78562306a36Sopenharmony_ci * struct is used. 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ci cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port]. 78862306a36Sopenharmony_ci alias_guid_work); 78962306a36Sopenharmony_ci queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq, 79062306a36Sopenharmony_ci &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0); 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 79362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_civoid mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci int i; 79962306a36Sopenharmony_ci struct mlx4_ib_sriov *sriov = &dev->sriov; 80062306a36Sopenharmony_ci struct mlx4_alias_guid_work_context *cb_ctx; 80162306a36Sopenharmony_ci struct mlx4_sriov_alias_guid_port_rec_det *det; 80262306a36Sopenharmony_ci struct ib_sa_query *sa_query; 80362306a36Sopenharmony_ci unsigned long flags; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci for (i = 0 ; i < dev->num_ports; i++) { 80662306a36Sopenharmony_ci det = &sriov->alias_guid.ports_guid[i]; 80762306a36Sopenharmony_ci cancel_delayed_work_sync(&det->alias_guid_work); 80862306a36Sopenharmony_ci spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 80962306a36Sopenharmony_ci while (!list_empty(&det->cb_list)) { 81062306a36Sopenharmony_ci cb_ctx = list_entry(det->cb_list.next, 81162306a36Sopenharmony_ci struct mlx4_alias_guid_work_context, 81262306a36Sopenharmony_ci list); 81362306a36Sopenharmony_ci sa_query = cb_ctx->sa_query; 81462306a36Sopenharmony_ci cb_ctx->sa_query = NULL; 81562306a36Sopenharmony_ci list_del(&cb_ctx->list); 81662306a36Sopenharmony_ci spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 81762306a36Sopenharmony_ci ib_sa_cancel_query(cb_ctx->query_id, sa_query); 81862306a36Sopenharmony_ci wait_for_completion(&cb_ctx->done); 81962306a36Sopenharmony_ci kfree(cb_ctx); 82062306a36Sopenharmony_ci spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci for (i = 0 ; i < dev->num_ports; i++) 82562306a36Sopenharmony_ci destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 82662306a36Sopenharmony_ci ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 82762306a36Sopenharmony_ci kfree(dev->sriov.alias_guid.sa_client); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ciint mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci char alias_wq_name[15]; 83362306a36Sopenharmony_ci int ret = 0; 83462306a36Sopenharmony_ci int i, j; 83562306a36Sopenharmony_ci union ib_gid gid; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 83862306a36Sopenharmony_ci return 0; 83962306a36Sopenharmony_ci dev->sriov.alias_guid.sa_client = 84062306a36Sopenharmony_ci kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL); 84162306a36Sopenharmony_ci if (!dev->sriov.alias_guid.sa_client) 84262306a36Sopenharmony_ci return -ENOMEM; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci ib_sa_register_client(dev->sriov.alias_guid.sa_client); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci spin_lock_init(&dev->sriov.alias_guid.ag_work_lock); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci for (i = 1; i <= dev->num_ports; ++i) { 84962306a36Sopenharmony_ci if (dev->ib_dev.ops.query_gid(&dev->ib_dev, i, 0, &gid)) { 85062306a36Sopenharmony_ci ret = -EFAULT; 85162306a36Sopenharmony_ci goto err_unregister; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci for (i = 0 ; i < dev->num_ports; i++) { 85662306a36Sopenharmony_ci memset(&dev->sriov.alias_guid.ports_guid[i], 0, 85762306a36Sopenharmony_ci sizeof (struct mlx4_sriov_alias_guid_port_rec_det)); 85862306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[i].state_flags |= 85962306a36Sopenharmony_ci GUID_STATE_NEED_PORT_INIT; 86062306a36Sopenharmony_ci for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 86162306a36Sopenharmony_ci /* mark each val as it was deleted */ 86262306a36Sopenharmony_ci memset(dev->sriov.alias_guid.ports_guid[i]. 86362306a36Sopenharmony_ci all_rec_per_port[j].all_recs, 0xFF, 86462306a36Sopenharmony_ci sizeof(dev->sriov.alias_guid.ports_guid[i]. 86562306a36Sopenharmony_ci all_rec_per_port[j].all_recs)); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list); 86862306a36Sopenharmony_ci /*prepare the records, set them to be allocated by sm*/ 86962306a36Sopenharmony_ci if (mlx4_ib_sm_guid_assign) 87062306a36Sopenharmony_ci for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++) 87162306a36Sopenharmony_ci mlx4_set_admin_guid(dev->dev, 0, j, i + 1); 87262306a36Sopenharmony_ci for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) 87362306a36Sopenharmony_ci invalidate_guid_record(dev, i + 1, j); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid; 87662306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[i].port = i; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i); 87962306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[i].wq = 88062306a36Sopenharmony_ci alloc_ordered_workqueue(alias_wq_name, WQ_MEM_RECLAIM); 88162306a36Sopenharmony_ci if (!dev->sriov.alias_guid.ports_guid[i].wq) { 88262306a36Sopenharmony_ci ret = -ENOMEM; 88362306a36Sopenharmony_ci goto err_thread; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work, 88662306a36Sopenharmony_ci alias_guid_work); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci return 0; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cierr_thread: 89162306a36Sopenharmony_ci for (--i; i >= 0; i--) { 89262306a36Sopenharmony_ci destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 89362306a36Sopenharmony_ci dev->sriov.alias_guid.ports_guid[i].wq = NULL; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cierr_unregister: 89762306a36Sopenharmony_ci ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 89862306a36Sopenharmony_ci kfree(dev->sriov.alias_guid.sa_client); 89962306a36Sopenharmony_ci dev->sriov.alias_guid.sa_client = NULL; 90062306a36Sopenharmony_ci pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret); 90162306a36Sopenharmony_ci return ret; 90262306a36Sopenharmony_ci} 903