1a0c64a17SJack Morgenstein /* 2a0c64a17SJack Morgenstein * Copyright (c) 2012 Mellanox Technologies. All rights reserved. 3a0c64a17SJack Morgenstein * 4a0c64a17SJack Morgenstein * This software is available to you under a choice of one of two 5a0c64a17SJack Morgenstein * licenses. You may choose to be licensed under the terms of the GNU 6a0c64a17SJack Morgenstein * General Public License (GPL) Version 2, available from the file 7a0c64a17SJack Morgenstein * COPYING in the main directory of this source tree, or the 8a0c64a17SJack Morgenstein * OpenIB.org BSD license below: 9a0c64a17SJack Morgenstein * 10a0c64a17SJack Morgenstein * Redistribution and use in source and binary forms, with or 11a0c64a17SJack Morgenstein * without modification, are permitted provided that the following 12a0c64a17SJack Morgenstein * conditions are met: 13a0c64a17SJack Morgenstein * 14a0c64a17SJack Morgenstein * - Redistributions of source code must retain the above 15a0c64a17SJack Morgenstein * copyright notice, this list of conditions and the following 16a0c64a17SJack Morgenstein * disclaimer. 17a0c64a17SJack Morgenstein * 18a0c64a17SJack Morgenstein * - Redistributions in binary form must reproduce the above 19a0c64a17SJack Morgenstein * copyright notice, this list of conditions and the following 20a0c64a17SJack Morgenstein * disclaimer in the documentation and/or other materials 21a0c64a17SJack Morgenstein * provided with the distribution. 22a0c64a17SJack Morgenstein * 23a0c64a17SJack Morgenstein * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24a0c64a17SJack Morgenstein * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25a0c64a17SJack Morgenstein * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26a0c64a17SJack Morgenstein * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27a0c64a17SJack Morgenstein * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28a0c64a17SJack Morgenstein * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29a0c64a17SJack Morgenstein * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30a0c64a17SJack Morgenstein * SOFTWARE. 31a0c64a17SJack Morgenstein */ 32a0c64a17SJack Morgenstein /***********************************************************/ 33a0c64a17SJack Morgenstein /*This file support the handling of the Alias GUID feature. */ 34a0c64a17SJack Morgenstein /***********************************************************/ 35a0c64a17SJack Morgenstein #include <rdma/ib_mad.h> 36a0c64a17SJack Morgenstein #include <rdma/ib_smi.h> 37a0c64a17SJack Morgenstein #include <rdma/ib_cache.h> 38a0c64a17SJack Morgenstein #include <rdma/ib_sa.h> 39a0c64a17SJack Morgenstein #include <rdma/ib_pack.h> 40a0c64a17SJack Morgenstein #include <linux/mlx4/cmd.h> 41a0c64a17SJack Morgenstein #include <linux/module.h> 42a0c64a17SJack Morgenstein #include <linux/init.h> 43a0c64a17SJack Morgenstein #include <linux/errno.h> 44a0c64a17SJack Morgenstein #include <rdma/ib_user_verbs.h> 45a0c64a17SJack Morgenstein #include <linux/delay.h> 46a0c64a17SJack Morgenstein #include "mlx4_ib.h" 47a0c64a17SJack Morgenstein 48a0c64a17SJack Morgenstein /* 49a0c64a17SJack Morgenstein The driver keeps the current state of all guids, as they are in the HW. 50a0c64a17SJack Morgenstein Whenever we receive an smp mad GUIDInfo record, the data will be cached. 51a0c64a17SJack Morgenstein */ 52a0c64a17SJack Morgenstein 53a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context { 54a0c64a17SJack Morgenstein u8 port; 55a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev ; 56a0c64a17SJack Morgenstein struct ib_sa_query *sa_query; 57a0c64a17SJack Morgenstein struct completion done; 58a0c64a17SJack Morgenstein int query_id; 59a0c64a17SJack Morgenstein struct list_head list; 60a0c64a17SJack Morgenstein int block_num; 6199ee4df6SYishai Hadas ib_sa_comp_mask guid_indexes; 6299ee4df6SYishai Hadas u8 method; 63a0c64a17SJack Morgenstein }; 64a0c64a17SJack Morgenstein 65a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work { 66a0c64a17SJack Morgenstein u8 port; 67a0c64a17SJack Morgenstein u8 block_num; 6899ee4df6SYishai Hadas u8 method; 69a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_info_rec_det rec_det; 70a0c64a17SJack Morgenstein }; 71a0c64a17SJack Morgenstein 7299ee4df6SYishai Hadas static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port, 7399ee4df6SYishai Hadas int *resched_delay_sec); 74a0c64a17SJack Morgenstein 75a0c64a17SJack Morgenstein void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num, 76a0c64a17SJack Morgenstein u8 port_num, u8 *p_data) 77a0c64a17SJack Morgenstein { 78a0c64a17SJack Morgenstein int i; 79a0c64a17SJack Morgenstein u64 guid_indexes; 80a0c64a17SJack Morgenstein int slave_id; 81a0c64a17SJack Morgenstein int port_index = port_num - 1; 82a0c64a17SJack Morgenstein 83a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 84a0c64a17SJack Morgenstein return; 85a0c64a17SJack Morgenstein 86a0c64a17SJack Morgenstein guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid. 87a0c64a17SJack Morgenstein ports_guid[port_num - 1]. 88a0c64a17SJack Morgenstein all_rec_per_port[block_num].guid_indexes); 89a0c64a17SJack Morgenstein pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes); 90a0c64a17SJack Morgenstein 91a0c64a17SJack Morgenstein for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 92a0c64a17SJack Morgenstein /* The location of the specific index starts from bit number 4 93a0c64a17SJack Morgenstein * until bit num 11 */ 94a0c64a17SJack Morgenstein if (test_bit(i + 4, (unsigned long *)&guid_indexes)) { 95a0c64a17SJack Morgenstein slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ; 96a0c64a17SJack Morgenstein if (slave_id >= dev->dev->num_slaves) { 97a0c64a17SJack Morgenstein pr_debug("The last slave: %d\n", slave_id); 98a0c64a17SJack Morgenstein return; 99a0c64a17SJack Morgenstein } 100a0c64a17SJack Morgenstein 101a0c64a17SJack Morgenstein /* cache the guid: */ 102a0c64a17SJack Morgenstein memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id], 103a0c64a17SJack Morgenstein &p_data[i * GUID_REC_SIZE], 104a0c64a17SJack Morgenstein GUID_REC_SIZE); 105a0c64a17SJack Morgenstein } else 106a0c64a17SJack Morgenstein pr_debug("Guid number: %d in block: %d" 107a0c64a17SJack Morgenstein " was not updated\n", i, block_num); 108a0c64a17SJack Morgenstein } 109a0c64a17SJack Morgenstein } 110a0c64a17SJack Morgenstein 111a0c64a17SJack Morgenstein static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index) 112a0c64a17SJack Morgenstein { 113a0c64a17SJack Morgenstein if (index >= NUM_ALIAS_GUID_PER_PORT) { 114a0c64a17SJack Morgenstein pr_err("%s: ERROR: asked for index:%d\n", __func__, index); 1158a095030SDoug Ledford return (__force __be64) -1; 116a0c64a17SJack Morgenstein } 117a0c64a17SJack Morgenstein return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index]; 118a0c64a17SJack Morgenstein } 119a0c64a17SJack Morgenstein 120a0c64a17SJack Morgenstein 121c1e7e466SJack Morgenstein ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index) 122a0c64a17SJack Morgenstein { 123a0c64a17SJack Morgenstein return IB_SA_COMP_MASK(4 + index); 124a0c64a17SJack Morgenstein } 125a0c64a17SJack Morgenstein 126*ee59fa0dSYishai Hadas void mlx4_ib_slave_alias_guid_event(struct mlx4_ib_dev *dev, int slave, 127*ee59fa0dSYishai Hadas int port, int slave_init) 128*ee59fa0dSYishai Hadas { 129*ee59fa0dSYishai Hadas __be64 curr_guid, required_guid; 130*ee59fa0dSYishai Hadas int record_num = slave / 8; 131*ee59fa0dSYishai Hadas int index = slave % 8; 132*ee59fa0dSYishai Hadas int port_index = port - 1; 133*ee59fa0dSYishai Hadas unsigned long flags; 134*ee59fa0dSYishai Hadas int do_work = 0; 135*ee59fa0dSYishai Hadas 136*ee59fa0dSYishai Hadas spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 137*ee59fa0dSYishai Hadas if (dev->sriov.alias_guid.ports_guid[port_index].state_flags & 138*ee59fa0dSYishai Hadas GUID_STATE_NEED_PORT_INIT) 139*ee59fa0dSYishai Hadas goto unlock; 140*ee59fa0dSYishai Hadas if (!slave_init) { 141*ee59fa0dSYishai Hadas curr_guid = *(__be64 *)&dev->sriov. 142*ee59fa0dSYishai Hadas alias_guid.ports_guid[port_index]. 143*ee59fa0dSYishai Hadas all_rec_per_port[record_num]. 144*ee59fa0dSYishai Hadas all_recs[GUID_REC_SIZE * index]; 145*ee59fa0dSYishai Hadas if (curr_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL) || 146*ee59fa0dSYishai Hadas !curr_guid) 147*ee59fa0dSYishai Hadas goto unlock; 148*ee59fa0dSYishai Hadas required_guid = cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL); 149*ee59fa0dSYishai Hadas } else { 150*ee59fa0dSYishai Hadas required_guid = mlx4_get_admin_guid(dev->dev, slave, port); 151*ee59fa0dSYishai Hadas if (required_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 152*ee59fa0dSYishai Hadas goto unlock; 153*ee59fa0dSYishai Hadas } 154*ee59fa0dSYishai Hadas *(__be64 *)&dev->sriov.alias_guid.ports_guid[port_index]. 155*ee59fa0dSYishai Hadas all_rec_per_port[record_num]. 156*ee59fa0dSYishai Hadas all_recs[GUID_REC_SIZE * index] = required_guid; 157*ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 158*ee59fa0dSYishai Hadas all_rec_per_port[record_num].guid_indexes 159*ee59fa0dSYishai Hadas |= mlx4_ib_get_aguid_comp_mask_from_ix(index); 160*ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 161*ee59fa0dSYishai Hadas all_rec_per_port[record_num].status 162*ee59fa0dSYishai Hadas = MLX4_GUID_INFO_STATUS_IDLE; 163*ee59fa0dSYishai Hadas /* set to run immediately */ 164*ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 165*ee59fa0dSYishai Hadas all_rec_per_port[record_num].time_to_run = 0; 166*ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 167*ee59fa0dSYishai Hadas all_rec_per_port[record_num]. 168*ee59fa0dSYishai Hadas guids_retry_schedule[index] = 0; 169*ee59fa0dSYishai Hadas do_work = 1; 170*ee59fa0dSYishai Hadas unlock: 171*ee59fa0dSYishai Hadas spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 172*ee59fa0dSYishai Hadas 173*ee59fa0dSYishai Hadas if (do_work) 174*ee59fa0dSYishai Hadas mlx4_ib_init_alias_guid_work(dev, port_index); 175*ee59fa0dSYishai Hadas } 176*ee59fa0dSYishai Hadas 177a0c64a17SJack Morgenstein /* 178a0c64a17SJack Morgenstein * Whenever new GUID is set/unset (guid table change) create event and 179a0c64a17SJack Morgenstein * notify the relevant slave (master also should be notified). 180a0c64a17SJack Morgenstein * If the GUID value is not as we have in the cache the slave will not be 181a0c64a17SJack Morgenstein * updated; in this case it waits for the smp_snoop or the port management 182a0c64a17SJack Morgenstein * event to call the function and to update the slave. 183a0c64a17SJack Morgenstein * block_number - the index of the block (16 blocks available) 184a0c64a17SJack Morgenstein * port_number - 1 or 2 185a0c64a17SJack Morgenstein */ 186a0c64a17SJack Morgenstein void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev, 187a0c64a17SJack Morgenstein int block_num, u8 port_num, 188a0c64a17SJack Morgenstein u8 *p_data) 189a0c64a17SJack Morgenstein { 190a0c64a17SJack Morgenstein int i; 191a0c64a17SJack Morgenstein u64 guid_indexes; 192a0c64a17SJack Morgenstein int slave_id; 193a0c64a17SJack Morgenstein enum slave_port_state new_state; 194a0c64a17SJack Morgenstein enum slave_port_state prev_state; 195a0c64a17SJack Morgenstein __be64 tmp_cur_ag, form_cache_ag; 196a0c64a17SJack Morgenstein enum slave_port_gen_event gen_event; 19799ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det *rec; 19899ee4df6SYishai Hadas unsigned long flags; 19999ee4df6SYishai Hadas __be64 required_value; 200a0c64a17SJack Morgenstein 201a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 202a0c64a17SJack Morgenstein return; 203a0c64a17SJack Morgenstein 20499ee4df6SYishai Hadas rec = &dev->sriov.alias_guid.ports_guid[port_num - 1]. 20599ee4df6SYishai Hadas all_rec_per_port[block_num]; 206a0c64a17SJack Morgenstein guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid. 207a0c64a17SJack Morgenstein ports_guid[port_num - 1]. 208a0c64a17SJack Morgenstein all_rec_per_port[block_num].guid_indexes); 209a0c64a17SJack Morgenstein pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes); 210a0c64a17SJack Morgenstein 211a0c64a17SJack Morgenstein /*calculate the slaves and notify them*/ 212a0c64a17SJack Morgenstein for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 213a0c64a17SJack Morgenstein /* the location of the specific index runs from bits 4..11 */ 214a0c64a17SJack Morgenstein if (!(test_bit(i + 4, (unsigned long *)&guid_indexes))) 215a0c64a17SJack Morgenstein continue; 216a0c64a17SJack Morgenstein 217a0c64a17SJack Morgenstein slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ; 218872bf2fbSYishai Hadas if (slave_id >= dev->dev->persist->num_vfs + 1) 219a0c64a17SJack Morgenstein return; 220a0c64a17SJack Morgenstein tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE]; 221a0c64a17SJack Morgenstein form_cache_ag = get_cached_alias_guid(dev, port_num, 222a0c64a17SJack Morgenstein (NUM_ALIAS_GUID_IN_REC * block_num) + i); 223a0c64a17SJack Morgenstein /* 224a0c64a17SJack Morgenstein * Check if guid is not the same as in the cache, 225a0c64a17SJack Morgenstein * If it is different, wait for the snoop_smp or the port mgmt 226a0c64a17SJack Morgenstein * change event to update the slave on its port state change 227a0c64a17SJack Morgenstein */ 228a0c64a17SJack Morgenstein if (tmp_cur_ag != form_cache_ag) 229a0c64a17SJack Morgenstein continue; 230a0c64a17SJack Morgenstein 23199ee4df6SYishai Hadas spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 23299ee4df6SYishai Hadas required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]; 23399ee4df6SYishai Hadas 23499ee4df6SYishai Hadas if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 23599ee4df6SYishai Hadas required_value = 0; 23699ee4df6SYishai Hadas 23799ee4df6SYishai Hadas if (tmp_cur_ag == required_value) { 23899ee4df6SYishai Hadas rec->guid_indexes = rec->guid_indexes & 23999ee4df6SYishai Hadas ~mlx4_ib_get_aguid_comp_mask_from_ix(i); 24099ee4df6SYishai Hadas } else { 24199ee4df6SYishai Hadas /* may notify port down if value is 0 */ 24299ee4df6SYishai Hadas if (tmp_cur_ag != MLX4_NOT_SET_GUID) { 24399ee4df6SYishai Hadas spin_unlock_irqrestore(&dev->sriov. 24499ee4df6SYishai Hadas alias_guid.ag_work_lock, flags); 24599ee4df6SYishai Hadas continue; 24699ee4df6SYishai Hadas } 24799ee4df6SYishai Hadas } 24899ee4df6SYishai Hadas spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, 24999ee4df6SYishai Hadas flags); 25099ee4df6SYishai Hadas mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num); 251a0c64a17SJack Morgenstein /*2 cases: Valid GUID, and Invalid Guid*/ 252a0c64a17SJack Morgenstein 253a0c64a17SJack Morgenstein if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/ 254a0c64a17SJack Morgenstein prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num); 255a0c64a17SJack Morgenstein new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num, 256a0c64a17SJack Morgenstein MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID, 257a0c64a17SJack Morgenstein &gen_event); 258a0c64a17SJack Morgenstein pr_debug("slave: %d, port: %d prev_port_state: %d," 259a0c64a17SJack Morgenstein " new_port_state: %d, gen_event: %d\n", 260a0c64a17SJack Morgenstein slave_id, port_num, prev_state, new_state, gen_event); 261a0c64a17SJack Morgenstein if (gen_event == SLAVE_PORT_GEN_EVENT_UP) { 262a0c64a17SJack Morgenstein pr_debug("sending PORT_UP event to slave: %d, port: %d\n", 263a0c64a17SJack Morgenstein slave_id, port_num); 264a0c64a17SJack Morgenstein mlx4_gen_port_state_change_eqe(dev->dev, slave_id, 265a0c64a17SJack Morgenstein port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE); 266a0c64a17SJack Morgenstein } 267a0c64a17SJack Morgenstein } else { /* request to invalidate GUID */ 268a0c64a17SJack Morgenstein set_and_calc_slave_port_state(dev->dev, slave_id, port_num, 269a0c64a17SJack Morgenstein MLX4_PORT_STATE_IB_EVENT_GID_INVALID, 270a0c64a17SJack Morgenstein &gen_event); 27199ee4df6SYishai Hadas if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) { 272a0c64a17SJack Morgenstein pr_debug("sending PORT DOWN event to slave: %d, port: %d\n", 273a0c64a17SJack Morgenstein slave_id, port_num); 27499ee4df6SYishai Hadas mlx4_gen_port_state_change_eqe(dev->dev, 27599ee4df6SYishai Hadas slave_id, 27699ee4df6SYishai Hadas port_num, 277a0c64a17SJack Morgenstein MLX4_PORT_CHANGE_SUBTYPE_DOWN); 278a0c64a17SJack Morgenstein } 279a0c64a17SJack Morgenstein } 280a0c64a17SJack Morgenstein } 28199ee4df6SYishai Hadas } 282a0c64a17SJack Morgenstein 283a0c64a17SJack Morgenstein static void aliasguid_query_handler(int status, 284a0c64a17SJack Morgenstein struct ib_sa_guidinfo_rec *guid_rec, 285a0c64a17SJack Morgenstein void *context) 286a0c64a17SJack Morgenstein { 287a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev; 288a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context *cb_ctx = context; 289a0c64a17SJack Morgenstein u8 port_index ; 290a0c64a17SJack Morgenstein int i; 291a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_info_rec_det *rec; 292a0c64a17SJack Morgenstein unsigned long flags, flags1; 29399ee4df6SYishai Hadas ib_sa_comp_mask declined_guid_indexes = 0; 29499ee4df6SYishai Hadas ib_sa_comp_mask applied_guid_indexes = 0; 29599ee4df6SYishai Hadas unsigned int resched_delay_sec = 0; 296a0c64a17SJack Morgenstein 297a0c64a17SJack Morgenstein if (!context) 298a0c64a17SJack Morgenstein return; 299a0c64a17SJack Morgenstein 300a0c64a17SJack Morgenstein dev = cb_ctx->dev; 301a0c64a17SJack Morgenstein port_index = cb_ctx->port - 1; 302a0c64a17SJack Morgenstein rec = &dev->sriov.alias_guid.ports_guid[port_index]. 303a0c64a17SJack Morgenstein all_rec_per_port[cb_ctx->block_num]; 304a0c64a17SJack Morgenstein 305a0c64a17SJack Morgenstein if (status) { 306a0c64a17SJack Morgenstein pr_debug("(port: %d) failed: status = %d\n", 307a0c64a17SJack Morgenstein cb_ctx->port, status); 30899ee4df6SYishai Hadas rec->time_to_run = ktime_get_real_ns() + 1 * NSEC_PER_SEC; 309a0c64a17SJack Morgenstein goto out; 310a0c64a17SJack Morgenstein } 311a0c64a17SJack Morgenstein 312a0c64a17SJack Morgenstein if (guid_rec->block_num != cb_ctx->block_num) { 313a0c64a17SJack Morgenstein pr_err("block num mismatch: %d != %d\n", 314a0c64a17SJack Morgenstein cb_ctx->block_num, guid_rec->block_num); 315a0c64a17SJack Morgenstein goto out; 316a0c64a17SJack Morgenstein } 317a0c64a17SJack Morgenstein 318a0c64a17SJack Morgenstein pr_debug("lid/port: %d/%d, block_num: %d\n", 319a0c64a17SJack Morgenstein be16_to_cpu(guid_rec->lid), cb_ctx->port, 320a0c64a17SJack Morgenstein guid_rec->block_num); 321a0c64a17SJack Morgenstein 322a0c64a17SJack Morgenstein rec = &dev->sriov.alias_guid.ports_guid[port_index]. 323a0c64a17SJack Morgenstein all_rec_per_port[guid_rec->block_num]; 324a0c64a17SJack Morgenstein 32599ee4df6SYishai Hadas spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 326a0c64a17SJack Morgenstein for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) { 32799ee4df6SYishai Hadas __be64 sm_response, required_val; 32899ee4df6SYishai Hadas 32999ee4df6SYishai Hadas if (!(cb_ctx->guid_indexes & 33099ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i))) 33199ee4df6SYishai Hadas continue; 33299ee4df6SYishai Hadas sm_response = *(__be64 *)&guid_rec->guid_info_list 33399ee4df6SYishai Hadas [i * GUID_REC_SIZE]; 33499ee4df6SYishai Hadas required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]; 33599ee4df6SYishai Hadas if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) { 33699ee4df6SYishai Hadas if (required_val == 33799ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 33899ee4df6SYishai Hadas goto next_entry; 33999ee4df6SYishai Hadas 34099ee4df6SYishai Hadas /* A new value was set till we got the response */ 34199ee4df6SYishai Hadas pr_debug("need to set new value %llx, record num %d, block_num:%d\n", 34299ee4df6SYishai Hadas be64_to_cpu(required_val), 34399ee4df6SYishai Hadas i, guid_rec->block_num); 34499ee4df6SYishai Hadas goto entry_declined; 34599ee4df6SYishai Hadas } 34699ee4df6SYishai Hadas 347a0c64a17SJack Morgenstein /* check if the SM didn't assign one of the records. 34899ee4df6SYishai Hadas * if it didn't, re-ask for. 349a0c64a17SJack Morgenstein */ 35099ee4df6SYishai Hadas if (sm_response == MLX4_NOT_SET_GUID) { 35199ee4df6SYishai Hadas if (rec->guids_retry_schedule[i] == 0) 352f5479601SYishai Hadas mlx4_ib_warn(&dev->ib_dev, 353f5479601SYishai Hadas "%s:Record num %d in block_num: %d was declined by SM\n", 354f5479601SYishai Hadas __func__, i, 355f5479601SYishai Hadas guid_rec->block_num); 35699ee4df6SYishai Hadas goto entry_declined; 357a0c64a17SJack Morgenstein } else { 358a0c64a17SJack Morgenstein /* properly assigned record. */ 359a0c64a17SJack Morgenstein /* We save the GUID we just got from the SM in the 360a0c64a17SJack Morgenstein * admin_guid in order to be persistent, and in the 361a0c64a17SJack Morgenstein * request from the sm the process will ask for the same GUID */ 362f5479601SYishai Hadas if (required_val && 36399ee4df6SYishai Hadas sm_response != required_val) { 36499ee4df6SYishai Hadas /* Warn only on first retry */ 36599ee4df6SYishai Hadas if (rec->guids_retry_schedule[i] == 0) 366a0c64a17SJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set" 367a0c64a17SJack Morgenstein " admin guid after SysAdmin " 368a0c64a17SJack Morgenstein "configuration. " 369a0c64a17SJack Morgenstein "Record num %d in block_num:%d " 370a0c64a17SJack Morgenstein "was declined by SM, " 37199ee4df6SYishai Hadas "new val(0x%llx) was kept, SM returned (0x%llx)\n", 372a0c64a17SJack Morgenstein __func__, i, 373a0c64a17SJack Morgenstein guid_rec->block_num, 37499ee4df6SYishai Hadas be64_to_cpu(required_val), 37599ee4df6SYishai Hadas be64_to_cpu(sm_response)); 37699ee4df6SYishai Hadas goto entry_declined; 377a0c64a17SJack Morgenstein } else { 37899ee4df6SYishai Hadas *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] = 37999ee4df6SYishai Hadas sm_response; 3802350f247SYishai Hadas if (required_val == 0) 3812350f247SYishai Hadas mlx4_set_admin_guid(dev->dev, 3822350f247SYishai Hadas sm_response, 3832350f247SYishai Hadas (guid_rec->block_num 3842350f247SYishai Hadas * NUM_ALIAS_GUID_IN_REC) + i, 3852350f247SYishai Hadas cb_ctx->port); 38699ee4df6SYishai Hadas goto next_entry; 387a0c64a17SJack Morgenstein } 388a0c64a17SJack Morgenstein } 38999ee4df6SYishai Hadas entry_declined: 39099ee4df6SYishai Hadas declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i); 39199ee4df6SYishai Hadas rec->guids_retry_schedule[i] = 39299ee4df6SYishai Hadas (rec->guids_retry_schedule[i] == 0) ? 1 : 39399ee4df6SYishai Hadas min((unsigned int)60, 39499ee4df6SYishai Hadas rec->guids_retry_schedule[i] * 2); 39599ee4df6SYishai Hadas /* using the minimum value among all entries in that record */ 39699ee4df6SYishai Hadas resched_delay_sec = (resched_delay_sec == 0) ? 39799ee4df6SYishai Hadas rec->guids_retry_schedule[i] : 39899ee4df6SYishai Hadas min(resched_delay_sec, 39999ee4df6SYishai Hadas rec->guids_retry_schedule[i]); 40099ee4df6SYishai Hadas continue; 40199ee4df6SYishai Hadas 40299ee4df6SYishai Hadas next_entry: 40399ee4df6SYishai Hadas rec->guids_retry_schedule[i] = 0; 404a0c64a17SJack Morgenstein } 40599ee4df6SYishai Hadas 40699ee4df6SYishai Hadas applied_guid_indexes = cb_ctx->guid_indexes & ~declined_guid_indexes; 40799ee4df6SYishai Hadas if (declined_guid_indexes || 40899ee4df6SYishai Hadas rec->guid_indexes & ~(applied_guid_indexes)) { 40999ee4df6SYishai Hadas pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n", 41099ee4df6SYishai Hadas guid_rec->block_num, 41199ee4df6SYishai Hadas be64_to_cpu((__force __be64)rec->guid_indexes), 41299ee4df6SYishai Hadas be64_to_cpu((__force __be64)applied_guid_indexes), 41399ee4df6SYishai Hadas be64_to_cpu((__force __be64)declined_guid_indexes)); 41499ee4df6SYishai Hadas rec->time_to_run = ktime_get_real_ns() + 41599ee4df6SYishai Hadas resched_delay_sec * NSEC_PER_SEC; 41699ee4df6SYishai Hadas } else { 41799ee4df6SYishai Hadas rec->status = MLX4_GUID_INFO_STATUS_SET; 41899ee4df6SYishai Hadas } 41999ee4df6SYishai Hadas spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 420a0c64a17SJack Morgenstein /* 421a0c64a17SJack Morgenstein The func is call here to close the cases when the 422a0c64a17SJack Morgenstein sm doesn't send smp, so in the sa response the driver 423a0c64a17SJack Morgenstein notifies the slave. 424a0c64a17SJack Morgenstein */ 425a0c64a17SJack Morgenstein mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num, 426a0c64a17SJack Morgenstein cb_ctx->port, 427a0c64a17SJack Morgenstein guid_rec->guid_info_list); 428a0c64a17SJack Morgenstein out: 429a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 430a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 43199ee4df6SYishai Hadas if (!dev->sriov.is_going_down) { 43299ee4df6SYishai Hadas get_low_record_time_index(dev, port_index, &resched_delay_sec); 433a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq, 434a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port_index]. 43599ee4df6SYishai Hadas alias_guid_work, 43699ee4df6SYishai Hadas msecs_to_jiffies(resched_delay_sec * 1000)); 43799ee4df6SYishai Hadas } 438a0c64a17SJack Morgenstein if (cb_ctx->sa_query) { 439a0c64a17SJack Morgenstein list_del(&cb_ctx->list); 440a0c64a17SJack Morgenstein kfree(cb_ctx); 441a0c64a17SJack Morgenstein } else 442a0c64a17SJack Morgenstein complete(&cb_ctx->done); 443a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 444a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 445a0c64a17SJack Morgenstein } 446a0c64a17SJack Morgenstein 447a0c64a17SJack Morgenstein static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index) 448a0c64a17SJack Morgenstein { 449a0c64a17SJack Morgenstein int i; 450a0c64a17SJack Morgenstein u64 cur_admin_val; 451a0c64a17SJack Morgenstein ib_sa_comp_mask comp_mask = 0; 452a0c64a17SJack Morgenstein 453a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status 45499ee4df6SYishai Hadas = MLX4_GUID_INFO_STATUS_SET; 455a0c64a17SJack Morgenstein 456a0c64a17SJack Morgenstein /* calculate the comp_mask for that record.*/ 457a0c64a17SJack Morgenstein for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 458a0c64a17SJack Morgenstein cur_admin_val = 459a0c64a17SJack Morgenstein *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. 460a0c64a17SJack Morgenstein all_rec_per_port[index].all_recs[GUID_REC_SIZE * i]; 461a0c64a17SJack Morgenstein /* 462a0c64a17SJack Morgenstein check the admin value: if it's for delete (~00LL) or 463a0c64a17SJack Morgenstein it is the first guid of the first record (hw guid) or 464a0c64a17SJack Morgenstein the records is not in ownership of the sysadmin and the sm doesn't 465a0c64a17SJack Morgenstein need to assign GUIDs, then don't put it up for assignment. 466a0c64a17SJack Morgenstein */ 467a0c64a17SJack Morgenstein if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val || 468f5479601SYishai Hadas (!index && !i)) 469a0c64a17SJack Morgenstein continue; 470c1e7e466SJack Morgenstein comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i); 471a0c64a17SJack Morgenstein } 472a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[port - 1]. 47399ee4df6SYishai Hadas all_rec_per_port[index].guid_indexes |= comp_mask; 47499ee4df6SYishai Hadas if (dev->sriov.alias_guid.ports_guid[port - 1]. 47599ee4df6SYishai Hadas all_rec_per_port[index].guid_indexes) 47699ee4df6SYishai Hadas dev->sriov.alias_guid.ports_guid[port - 1]. 47799ee4df6SYishai Hadas all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE; 47899ee4df6SYishai Hadas 479a0c64a17SJack Morgenstein } 480a0c64a17SJack Morgenstein 481a0c64a17SJack Morgenstein static int set_guid_rec(struct ib_device *ibdev, 48299ee4df6SYishai Hadas struct mlx4_next_alias_guid_work *rec) 483a0c64a17SJack Morgenstein { 484a0c64a17SJack Morgenstein int err; 485a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ibdev); 486a0c64a17SJack Morgenstein struct ib_sa_guidinfo_rec guid_info_rec; 487a0c64a17SJack Morgenstein ib_sa_comp_mask comp_mask; 488a0c64a17SJack Morgenstein struct ib_port_attr attr; 489a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context *callback_context; 490a0c64a17SJack Morgenstein unsigned long resched_delay, flags, flags1; 49199ee4df6SYishai Hadas u8 port = rec->port + 1; 49299ee4df6SYishai Hadas int index = rec->block_num; 49399ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det; 494a0c64a17SJack Morgenstein struct list_head *head = 495a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].cb_list; 496a0c64a17SJack Morgenstein 497a0c64a17SJack Morgenstein err = __mlx4_ib_query_port(ibdev, port, &attr, 1); 498a0c64a17SJack Morgenstein if (err) { 499a0c64a17SJack Morgenstein pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n", 500a0c64a17SJack Morgenstein err, port); 501a0c64a17SJack Morgenstein return err; 502a0c64a17SJack Morgenstein } 503a0c64a17SJack Morgenstein /*check the port was configured by the sm, otherwise no need to send */ 504a0c64a17SJack Morgenstein if (attr.state != IB_PORT_ACTIVE) { 505a0c64a17SJack Morgenstein pr_debug("port %d not active...rescheduling\n", port); 506a0c64a17SJack Morgenstein resched_delay = 5 * HZ; 507a0c64a17SJack Morgenstein err = -EAGAIN; 508a0c64a17SJack Morgenstein goto new_schedule; 509a0c64a17SJack Morgenstein } 510a0c64a17SJack Morgenstein 511a0c64a17SJack Morgenstein callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL); 512a0c64a17SJack Morgenstein if (!callback_context) { 513a0c64a17SJack Morgenstein err = -ENOMEM; 514a0c64a17SJack Morgenstein resched_delay = HZ * 5; 515a0c64a17SJack Morgenstein goto new_schedule; 516a0c64a17SJack Morgenstein } 517a0c64a17SJack Morgenstein callback_context->port = port; 518a0c64a17SJack Morgenstein callback_context->dev = dev; 519a0c64a17SJack Morgenstein callback_context->block_num = index; 52099ee4df6SYishai Hadas callback_context->guid_indexes = rec_det->guid_indexes; 52199ee4df6SYishai Hadas callback_context->method = rec->method; 522a0c64a17SJack Morgenstein 523a0c64a17SJack Morgenstein memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec)); 524a0c64a17SJack Morgenstein 525a0c64a17SJack Morgenstein guid_info_rec.lid = cpu_to_be16(attr.lid); 526a0c64a17SJack Morgenstein guid_info_rec.block_num = index; 527a0c64a17SJack Morgenstein 528a0c64a17SJack Morgenstein memcpy(guid_info_rec.guid_info_list, rec_det->all_recs, 529a0c64a17SJack Morgenstein GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC); 530a0c64a17SJack Morgenstein comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM | 531a0c64a17SJack Morgenstein rec_det->guid_indexes; 532a0c64a17SJack Morgenstein 533a0c64a17SJack Morgenstein init_completion(&callback_context->done); 534a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 535a0c64a17SJack Morgenstein list_add_tail(&callback_context->list, head); 536a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 537a0c64a17SJack Morgenstein 538a0c64a17SJack Morgenstein callback_context->query_id = 539a0c64a17SJack Morgenstein ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client, 540a0c64a17SJack Morgenstein ibdev, port, &guid_info_rec, 54199ee4df6SYishai Hadas comp_mask, rec->method, 1000, 542a0c64a17SJack Morgenstein GFP_KERNEL, aliasguid_query_handler, 543a0c64a17SJack Morgenstein callback_context, 544a0c64a17SJack Morgenstein &callback_context->sa_query); 545a0c64a17SJack Morgenstein if (callback_context->query_id < 0) { 546a0c64a17SJack Morgenstein pr_debug("ib_sa_guid_info_rec_query failed, query_id: " 547a0c64a17SJack Morgenstein "%d. will reschedule to the next 1 sec.\n", 548a0c64a17SJack Morgenstein callback_context->query_id); 549a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 550a0c64a17SJack Morgenstein list_del(&callback_context->list); 551a0c64a17SJack Morgenstein kfree(callback_context); 552a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 553a0c64a17SJack Morgenstein resched_delay = 1 * HZ; 554a0c64a17SJack Morgenstein err = -EAGAIN; 555a0c64a17SJack Morgenstein goto new_schedule; 556a0c64a17SJack Morgenstein } 557a0c64a17SJack Morgenstein err = 0; 558a0c64a17SJack Morgenstein goto out; 559a0c64a17SJack Morgenstein 560a0c64a17SJack Morgenstein new_schedule: 561a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 562a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 563a0c64a17SJack Morgenstein invalidate_guid_record(dev, port, index); 564a0c64a17SJack Morgenstein if (!dev->sriov.is_going_down) { 565a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 566a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 567a0c64a17SJack Morgenstein resched_delay); 568a0c64a17SJack Morgenstein } 569a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 570a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 571a0c64a17SJack Morgenstein 572a0c64a17SJack Morgenstein out: 573a0c64a17SJack Morgenstein return err; 574a0c64a17SJack Morgenstein } 575a0c64a17SJack Morgenstein 576f5479601SYishai Hadas static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port) 577f5479601SYishai Hadas { 578f5479601SYishai Hadas int j, k, entry; 579f5479601SYishai Hadas __be64 guid; 580f5479601SYishai Hadas 581f5479601SYishai Hadas /*Check if the SM doesn't need to assign the GUIDs*/ 582f5479601SYishai Hadas for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 583f5479601SYishai Hadas for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) { 584f5479601SYishai Hadas entry = j * NUM_ALIAS_GUID_IN_REC + k; 585f5479601SYishai Hadas /* no request for the 0 entry (hw guid) */ 586f5479601SYishai Hadas if (!entry || entry > dev->dev->persist->num_vfs || 587f5479601SYishai Hadas !mlx4_is_slave_active(dev->dev, entry)) 588f5479601SYishai Hadas continue; 589f5479601SYishai Hadas guid = mlx4_get_admin_guid(dev->dev, entry, port); 590f5479601SYishai Hadas *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. 591f5479601SYishai Hadas all_rec_per_port[j].all_recs 592f5479601SYishai Hadas [GUID_REC_SIZE * k] = guid; 593f5479601SYishai Hadas pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n", 594f5479601SYishai Hadas entry, 595f5479601SYishai Hadas be64_to_cpu(guid), 596f5479601SYishai Hadas port); 597f5479601SYishai Hadas } 598f5479601SYishai Hadas } 599f5479601SYishai Hadas } 600a0c64a17SJack Morgenstein void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port) 601a0c64a17SJack Morgenstein { 602a0c64a17SJack Morgenstein int i; 603a0c64a17SJack Morgenstein unsigned long flags, flags1; 604a0c64a17SJack Morgenstein 605a0c64a17SJack Morgenstein pr_debug("port %d\n", port); 606a0c64a17SJack Morgenstein 607a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 608a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 609f5479601SYishai Hadas 610f5479601SYishai Hadas if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags & 611f5479601SYishai Hadas GUID_STATE_NEED_PORT_INIT) { 612f5479601SYishai Hadas mlx4_ib_guid_port_init(dev, port); 613f5479601SYishai Hadas dev->sriov.alias_guid.ports_guid[port - 1].state_flags &= 614f5479601SYishai Hadas (~GUID_STATE_NEED_PORT_INIT); 615f5479601SYishai Hadas } 616a0c64a17SJack Morgenstein for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++) 617a0c64a17SJack Morgenstein invalidate_guid_record(dev, port, i); 618a0c64a17SJack Morgenstein 619a0c64a17SJack Morgenstein if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) { 620a0c64a17SJack Morgenstein /* 621a0c64a17SJack Morgenstein make sure no work waits in the queue, if the work is already 622a0c64a17SJack Morgenstein queued(not on the timer) the cancel will fail. That is not a problem 623a0c64a17SJack Morgenstein because we just want the work started. 624a0c64a17SJack Morgenstein */ 6257a9a2970SLinus Torvalds cancel_delayed_work(&dev->sriov.alias_guid. 626a0c64a17SJack Morgenstein ports_guid[port - 1].alias_guid_work); 627a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 628a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 629a0c64a17SJack Morgenstein 0); 630a0c64a17SJack Morgenstein } 631a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 632a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 633a0c64a17SJack Morgenstein } 634a0c64a17SJack Morgenstein 63599ee4df6SYishai Hadas static void set_required_record(struct mlx4_ib_dev *dev, u8 port, 63699ee4df6SYishai Hadas struct mlx4_next_alias_guid_work *next_rec, 63799ee4df6SYishai Hadas int record_index) 63899ee4df6SYishai Hadas { 63999ee4df6SYishai Hadas int i; 64099ee4df6SYishai Hadas int lowset_time_entry = -1; 64199ee4df6SYishai Hadas int lowest_time = 0; 64299ee4df6SYishai Hadas ib_sa_comp_mask delete_guid_indexes = 0; 64399ee4df6SYishai Hadas ib_sa_comp_mask set_guid_indexes = 0; 64499ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det *rec = 64599ee4df6SYishai Hadas &dev->sriov.alias_guid.ports_guid[port]. 64699ee4df6SYishai Hadas all_rec_per_port[record_index]; 64799ee4df6SYishai Hadas 64899ee4df6SYishai Hadas for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 64999ee4df6SYishai Hadas if (!(rec->guid_indexes & 65099ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i))) 65199ee4df6SYishai Hadas continue; 65299ee4df6SYishai Hadas 65399ee4df6SYishai Hadas if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] == 65499ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 65599ee4df6SYishai Hadas delete_guid_indexes |= 65699ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i); 65799ee4df6SYishai Hadas else 65899ee4df6SYishai Hadas set_guid_indexes |= 65999ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i); 66099ee4df6SYishai Hadas 66199ee4df6SYishai Hadas if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <= 66299ee4df6SYishai Hadas lowest_time) { 66399ee4df6SYishai Hadas lowset_time_entry = i; 66499ee4df6SYishai Hadas lowest_time = rec->guids_retry_schedule[i]; 66599ee4df6SYishai Hadas } 66699ee4df6SYishai Hadas } 66799ee4df6SYishai Hadas 66899ee4df6SYishai Hadas memcpy(&next_rec->rec_det, rec, sizeof(*rec)); 66999ee4df6SYishai Hadas next_rec->port = port; 67099ee4df6SYishai Hadas next_rec->block_num = record_index; 67199ee4df6SYishai Hadas 67299ee4df6SYishai Hadas if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] == 67399ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) { 67499ee4df6SYishai Hadas next_rec->rec_det.guid_indexes = delete_guid_indexes; 67599ee4df6SYishai Hadas next_rec->method = MLX4_GUID_INFO_RECORD_DELETE; 67699ee4df6SYishai Hadas } else { 67799ee4df6SYishai Hadas next_rec->rec_det.guid_indexes = set_guid_indexes; 67899ee4df6SYishai Hadas next_rec->method = MLX4_GUID_INFO_RECORD_SET; 67999ee4df6SYishai Hadas } 68099ee4df6SYishai Hadas } 68199ee4df6SYishai Hadas 68299ee4df6SYishai Hadas /* return index of record that should be updated based on lowest 68399ee4df6SYishai Hadas * rescheduled time 68499ee4df6SYishai Hadas */ 68599ee4df6SYishai Hadas static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port, 68699ee4df6SYishai Hadas int *resched_delay_sec) 68799ee4df6SYishai Hadas { 68899ee4df6SYishai Hadas int record_index = -1; 68999ee4df6SYishai Hadas u64 low_record_time = 0; 69099ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det rec; 69199ee4df6SYishai Hadas int j; 69299ee4df6SYishai Hadas 69399ee4df6SYishai Hadas for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 69499ee4df6SYishai Hadas rec = dev->sriov.alias_guid.ports_guid[port]. 69599ee4df6SYishai Hadas all_rec_per_port[j]; 69699ee4df6SYishai Hadas if (rec.status == MLX4_GUID_INFO_STATUS_IDLE && 69799ee4df6SYishai Hadas rec.guid_indexes) { 69899ee4df6SYishai Hadas if (record_index == -1 || 69999ee4df6SYishai Hadas rec.time_to_run < low_record_time) { 70099ee4df6SYishai Hadas record_index = j; 70199ee4df6SYishai Hadas low_record_time = rec.time_to_run; 70299ee4df6SYishai Hadas } 70399ee4df6SYishai Hadas } 70499ee4df6SYishai Hadas } 70599ee4df6SYishai Hadas if (resched_delay_sec) { 70699ee4df6SYishai Hadas u64 curr_time = ktime_get_real_ns(); 70799ee4df6SYishai Hadas 70899ee4df6SYishai Hadas *resched_delay_sec = (low_record_time < curr_time) ? 0 : 70999ee4df6SYishai Hadas div_u64((low_record_time - curr_time), NSEC_PER_SEC); 71099ee4df6SYishai Hadas } 71199ee4df6SYishai Hadas 71299ee4df6SYishai Hadas return record_index; 71399ee4df6SYishai Hadas } 71499ee4df6SYishai Hadas 715a0c64a17SJack Morgenstein /* The function returns the next record that was 716a0c64a17SJack Morgenstein * not configured (or failed to be configured) */ 717a0c64a17SJack Morgenstein static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port, 718a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work *rec) 719a0c64a17SJack Morgenstein { 720a0c64a17SJack Morgenstein unsigned long flags; 72199ee4df6SYishai Hadas int record_index; 72299ee4df6SYishai Hadas int ret = 0; 723a0c64a17SJack Morgenstein 724a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 72599ee4df6SYishai Hadas record_index = get_low_record_time_index(dev, port, NULL); 72699ee4df6SYishai Hadas 72799ee4df6SYishai Hadas if (record_index < 0) { 72899ee4df6SYishai Hadas ret = -ENOENT; 72999ee4df6SYishai Hadas goto out; 730a0c64a17SJack Morgenstein } 73199ee4df6SYishai Hadas 73299ee4df6SYishai Hadas set_required_record(dev, port, rec, record_index); 73399ee4df6SYishai Hadas out: 734a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 73599ee4df6SYishai Hadas return ret; 736a0c64a17SJack Morgenstein } 737a0c64a17SJack Morgenstein 738a0c64a17SJack Morgenstein static void alias_guid_work(struct work_struct *work) 739a0c64a17SJack Morgenstein { 740a0c64a17SJack Morgenstein struct delayed_work *delay = to_delayed_work(work); 741a0c64a17SJack Morgenstein int ret = 0; 742a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work *rec; 743a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port = 744a0c64a17SJack Morgenstein container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det, 745a0c64a17SJack Morgenstein alias_guid_work); 746a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent; 747a0c64a17SJack Morgenstein struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid, 748a0c64a17SJack Morgenstein struct mlx4_ib_sriov, 749a0c64a17SJack Morgenstein alias_guid); 750a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov); 751a0c64a17SJack Morgenstein 752a0c64a17SJack Morgenstein rec = kzalloc(sizeof *rec, GFP_KERNEL); 753a0c64a17SJack Morgenstein if (!rec) { 754a0c64a17SJack Morgenstein pr_err("alias_guid_work: No Memory\n"); 755a0c64a17SJack Morgenstein return; 756a0c64a17SJack Morgenstein } 757a0c64a17SJack Morgenstein 758a0c64a17SJack Morgenstein pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1); 759a0c64a17SJack Morgenstein ret = get_next_record_to_update(dev, sriov_alias_port->port, rec); 760a0c64a17SJack Morgenstein if (ret) { 761a0c64a17SJack Morgenstein pr_debug("No more records to update.\n"); 762a0c64a17SJack Morgenstein goto out; 763a0c64a17SJack Morgenstein } 764a0c64a17SJack Morgenstein 76599ee4df6SYishai Hadas set_guid_rec(&dev->ib_dev, rec); 766a0c64a17SJack Morgenstein out: 767a0c64a17SJack Morgenstein kfree(rec); 768a0c64a17SJack Morgenstein } 769a0c64a17SJack Morgenstein 770a0c64a17SJack Morgenstein 771a0c64a17SJack Morgenstein void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port) 772a0c64a17SJack Morgenstein { 773a0c64a17SJack Morgenstein unsigned long flags, flags1; 774a0c64a17SJack Morgenstein 775a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 776a0c64a17SJack Morgenstein return; 777a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 778a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 779a0c64a17SJack Morgenstein if (!dev->sriov.is_going_down) { 78099ee4df6SYishai Hadas /* If there is pending one should cancell then run, otherwise 78199ee4df6SYishai Hadas * won't run till previous one is ended as same work 78299ee4df6SYishai Hadas * struct is used. 78399ee4df6SYishai Hadas */ 78499ee4df6SYishai Hadas cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port]. 78599ee4df6SYishai Hadas alias_guid_work); 786a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq, 787a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0); 788a0c64a17SJack Morgenstein } 789a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 790a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 791a0c64a17SJack Morgenstein } 792a0c64a17SJack Morgenstein 793a0c64a17SJack Morgenstein void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev) 794a0c64a17SJack Morgenstein { 795a0c64a17SJack Morgenstein int i; 796a0c64a17SJack Morgenstein struct mlx4_ib_sriov *sriov = &dev->sriov; 797a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context *cb_ctx; 798a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_port_rec_det *det; 799a0c64a17SJack Morgenstein struct ib_sa_query *sa_query; 800a0c64a17SJack Morgenstein unsigned long flags; 801a0c64a17SJack Morgenstein 802a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 803a0c64a17SJack Morgenstein cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work); 804a0c64a17SJack Morgenstein det = &sriov->alias_guid.ports_guid[i]; 805a0c64a17SJack Morgenstein spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 806a0c64a17SJack Morgenstein while (!list_empty(&det->cb_list)) { 807a0c64a17SJack Morgenstein cb_ctx = list_entry(det->cb_list.next, 808a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context, 809a0c64a17SJack Morgenstein list); 810a0c64a17SJack Morgenstein sa_query = cb_ctx->sa_query; 811a0c64a17SJack Morgenstein cb_ctx->sa_query = NULL; 812a0c64a17SJack Morgenstein list_del(&cb_ctx->list); 813a0c64a17SJack Morgenstein spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 814a0c64a17SJack Morgenstein ib_sa_cancel_query(cb_ctx->query_id, sa_query); 815a0c64a17SJack Morgenstein wait_for_completion(&cb_ctx->done); 816a0c64a17SJack Morgenstein kfree(cb_ctx); 817a0c64a17SJack Morgenstein spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 818a0c64a17SJack Morgenstein } 819a0c64a17SJack Morgenstein spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 820a0c64a17SJack Morgenstein } 821a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 822a0c64a17SJack Morgenstein flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 823a0c64a17SJack Morgenstein destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 824a0c64a17SJack Morgenstein } 825a0c64a17SJack Morgenstein ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 826a0c64a17SJack Morgenstein kfree(dev->sriov.alias_guid.sa_client); 827a0c64a17SJack Morgenstein } 828a0c64a17SJack Morgenstein 829a0c64a17SJack Morgenstein int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev) 830a0c64a17SJack Morgenstein { 831a0c64a17SJack Morgenstein char alias_wq_name[15]; 832a0c64a17SJack Morgenstein int ret = 0; 833f5479601SYishai Hadas int i, j; 834a0c64a17SJack Morgenstein union ib_gid gid; 835a0c64a17SJack Morgenstein 836a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 837a0c64a17SJack Morgenstein return 0; 838a0c64a17SJack Morgenstein dev->sriov.alias_guid.sa_client = 839a0c64a17SJack Morgenstein kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL); 840a0c64a17SJack Morgenstein if (!dev->sriov.alias_guid.sa_client) 841a0c64a17SJack Morgenstein return -ENOMEM; 842a0c64a17SJack Morgenstein 843a0c64a17SJack Morgenstein ib_sa_register_client(dev->sriov.alias_guid.sa_client); 844a0c64a17SJack Morgenstein 845a0c64a17SJack Morgenstein spin_lock_init(&dev->sriov.alias_guid.ag_work_lock); 846a0c64a17SJack Morgenstein 847a0c64a17SJack Morgenstein for (i = 1; i <= dev->num_ports; ++i) { 848a0c64a17SJack Morgenstein if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) { 849a0c64a17SJack Morgenstein ret = -EFAULT; 850a0c64a17SJack Morgenstein goto err_unregister; 851a0c64a17SJack Morgenstein } 852a0c64a17SJack Morgenstein } 853a0c64a17SJack Morgenstein 854a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 855a0c64a17SJack Morgenstein memset(&dev->sriov.alias_guid.ports_guid[i], 0, 856a0c64a17SJack Morgenstein sizeof (struct mlx4_sriov_alias_guid_port_rec_det)); 857f5479601SYishai Hadas dev->sriov.alias_guid.ports_guid[i].state_flags |= 858f5479601SYishai Hadas GUID_STATE_NEED_PORT_INIT; 859a0c64a17SJack Morgenstein for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 860f5479601SYishai Hadas /* mark each val as it was deleted */ 861f5479601SYishai Hadas memset(dev->sriov.alias_guid.ports_guid[i]. 862f5479601SYishai Hadas all_rec_per_port[j].all_recs, 0xFF, 863f5479601SYishai Hadas sizeof(dev->sriov.alias_guid.ports_guid[i]. 864f5479601SYishai Hadas all_rec_per_port[j].all_recs)); 865a0c64a17SJack Morgenstein } 866a0c64a17SJack Morgenstein INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list); 867a0c64a17SJack Morgenstein /*prepare the records, set them to be allocated by sm*/ 868f5479601SYishai Hadas if (mlx4_ib_sm_guid_assign) 869f5479601SYishai Hadas for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++) 870f5479601SYishai Hadas mlx4_set_admin_guid(dev->dev, 0, j, i + 1); 871a0c64a17SJack Morgenstein for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) 872a0c64a17SJack Morgenstein invalidate_guid_record(dev, i + 1, j); 873a0c64a17SJack Morgenstein 874a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid; 875a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].port = i; 876a0c64a17SJack Morgenstein 877a0c64a17SJack Morgenstein snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i); 878a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].wq = 879a0c64a17SJack Morgenstein create_singlethread_workqueue(alias_wq_name); 880a0c64a17SJack Morgenstein if (!dev->sriov.alias_guid.ports_guid[i].wq) { 881a0c64a17SJack Morgenstein ret = -ENOMEM; 882a0c64a17SJack Morgenstein goto err_thread; 883a0c64a17SJack Morgenstein } 884a0c64a17SJack Morgenstein INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work, 885a0c64a17SJack Morgenstein alias_guid_work); 886a0c64a17SJack Morgenstein } 887a0c64a17SJack Morgenstein return 0; 888a0c64a17SJack Morgenstein 889a0c64a17SJack Morgenstein err_thread: 890a0c64a17SJack Morgenstein for (--i; i >= 0; i--) { 891a0c64a17SJack Morgenstein destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 892a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].wq = NULL; 893a0c64a17SJack Morgenstein } 894a0c64a17SJack Morgenstein 895a0c64a17SJack Morgenstein err_unregister: 896a0c64a17SJack Morgenstein ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 897a0c64a17SJack Morgenstein kfree(dev->sriov.alias_guid.sa_client); 898a0c64a17SJack Morgenstein dev->sriov.alias_guid.sa_client = NULL; 899a0c64a17SJack Morgenstein pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret); 900a0c64a17SJack Morgenstein return ret; 901a0c64a17SJack Morgenstein } 902