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