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 126ee59fa0dSYishai Hadas void mlx4_ib_slave_alias_guid_event(struct mlx4_ib_dev *dev, int slave, 127ee59fa0dSYishai Hadas int port, int slave_init) 128ee59fa0dSYishai Hadas { 129ee59fa0dSYishai Hadas __be64 curr_guid, required_guid; 130ee59fa0dSYishai Hadas int record_num = slave / 8; 131ee59fa0dSYishai Hadas int index = slave % 8; 132ee59fa0dSYishai Hadas int port_index = port - 1; 133ee59fa0dSYishai Hadas unsigned long flags; 134ee59fa0dSYishai Hadas int do_work = 0; 135ee59fa0dSYishai Hadas 136ee59fa0dSYishai Hadas spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 137ee59fa0dSYishai Hadas if (dev->sriov.alias_guid.ports_guid[port_index].state_flags & 138ee59fa0dSYishai Hadas GUID_STATE_NEED_PORT_INIT) 139ee59fa0dSYishai Hadas goto unlock; 140ee59fa0dSYishai Hadas if (!slave_init) { 141ee59fa0dSYishai Hadas curr_guid = *(__be64 *)&dev->sriov. 142ee59fa0dSYishai Hadas alias_guid.ports_guid[port_index]. 143ee59fa0dSYishai Hadas all_rec_per_port[record_num]. 144ee59fa0dSYishai Hadas all_recs[GUID_REC_SIZE * index]; 145ee59fa0dSYishai Hadas if (curr_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL) || 146ee59fa0dSYishai Hadas !curr_guid) 147ee59fa0dSYishai Hadas goto unlock; 148ee59fa0dSYishai Hadas required_guid = cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL); 149ee59fa0dSYishai Hadas } else { 150ee59fa0dSYishai Hadas required_guid = mlx4_get_admin_guid(dev->dev, slave, port); 151ee59fa0dSYishai Hadas if (required_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 152ee59fa0dSYishai Hadas goto unlock; 153ee59fa0dSYishai Hadas } 154ee59fa0dSYishai Hadas *(__be64 *)&dev->sriov.alias_guid.ports_guid[port_index]. 155ee59fa0dSYishai Hadas all_rec_per_port[record_num]. 156ee59fa0dSYishai Hadas all_recs[GUID_REC_SIZE * index] = required_guid; 157ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 158ee59fa0dSYishai Hadas all_rec_per_port[record_num].guid_indexes 159ee59fa0dSYishai Hadas |= mlx4_ib_get_aguid_comp_mask_from_ix(index); 160ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 161ee59fa0dSYishai Hadas all_rec_per_port[record_num].status 162ee59fa0dSYishai Hadas = MLX4_GUID_INFO_STATUS_IDLE; 163ee59fa0dSYishai Hadas /* set to run immediately */ 164ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 165ee59fa0dSYishai Hadas all_rec_per_port[record_num].time_to_run = 0; 166ee59fa0dSYishai Hadas dev->sriov.alias_guid.ports_guid[port_index]. 167ee59fa0dSYishai Hadas all_rec_per_port[record_num]. 168ee59fa0dSYishai Hadas guids_retry_schedule[index] = 0; 169ee59fa0dSYishai Hadas do_work = 1; 170ee59fa0dSYishai Hadas unlock: 171ee59fa0dSYishai Hadas spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 172ee59fa0dSYishai Hadas 173ee59fa0dSYishai Hadas if (do_work) 174ee59fa0dSYishai Hadas mlx4_ib_init_alias_guid_work(dev, port_index); 175ee59fa0dSYishai Hadas } 176ee59fa0dSYishai 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; 19274d4943fSOr Gerlitz int slave_id, slave_port; 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; 22074d4943fSOr Gerlitz 22174d4943fSOr Gerlitz slave_port = mlx4_phys_to_slave_port(dev->dev, slave_id, port_num); 22274d4943fSOr Gerlitz if (slave_port < 0) /* this port isn't available for the VF */ 22374d4943fSOr Gerlitz continue; 22474d4943fSOr Gerlitz 225a0c64a17SJack Morgenstein tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE]; 226a0c64a17SJack Morgenstein form_cache_ag = get_cached_alias_guid(dev, port_num, 227a0c64a17SJack Morgenstein (NUM_ALIAS_GUID_IN_REC * block_num) + i); 228a0c64a17SJack Morgenstein /* 229a0c64a17SJack Morgenstein * Check if guid is not the same as in the cache, 230a0c64a17SJack Morgenstein * If it is different, wait for the snoop_smp or the port mgmt 231a0c64a17SJack Morgenstein * change event to update the slave on its port state change 232a0c64a17SJack Morgenstein */ 233a0c64a17SJack Morgenstein if (tmp_cur_ag != form_cache_ag) 234a0c64a17SJack Morgenstein continue; 235a0c64a17SJack Morgenstein 23699ee4df6SYishai Hadas spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 23799ee4df6SYishai Hadas required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]; 23899ee4df6SYishai Hadas 23999ee4df6SYishai Hadas if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 24099ee4df6SYishai Hadas required_value = 0; 24199ee4df6SYishai Hadas 24299ee4df6SYishai Hadas if (tmp_cur_ag == required_value) { 24399ee4df6SYishai Hadas rec->guid_indexes = rec->guid_indexes & 24499ee4df6SYishai Hadas ~mlx4_ib_get_aguid_comp_mask_from_ix(i); 24599ee4df6SYishai Hadas } else { 24699ee4df6SYishai Hadas /* may notify port down if value is 0 */ 24799ee4df6SYishai Hadas if (tmp_cur_ag != MLX4_NOT_SET_GUID) { 24899ee4df6SYishai Hadas spin_unlock_irqrestore(&dev->sriov. 24999ee4df6SYishai Hadas alias_guid.ag_work_lock, flags); 25099ee4df6SYishai Hadas continue; 25199ee4df6SYishai Hadas } 25299ee4df6SYishai Hadas } 25399ee4df6SYishai Hadas spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, 25499ee4df6SYishai Hadas flags); 25599ee4df6SYishai Hadas mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num); 256a0c64a17SJack Morgenstein /*2 cases: Valid GUID, and Invalid Guid*/ 257a0c64a17SJack Morgenstein 258a0c64a17SJack Morgenstein if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/ 259a0c64a17SJack Morgenstein prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num); 260a0c64a17SJack Morgenstein new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num, 261a0c64a17SJack Morgenstein MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID, 262a0c64a17SJack Morgenstein &gen_event); 263a0c64a17SJack Morgenstein pr_debug("slave: %d, port: %d prev_port_state: %d," 264a0c64a17SJack Morgenstein " new_port_state: %d, gen_event: %d\n", 265a0c64a17SJack Morgenstein slave_id, port_num, prev_state, new_state, gen_event); 266a0c64a17SJack Morgenstein if (gen_event == SLAVE_PORT_GEN_EVENT_UP) { 267a0c64a17SJack Morgenstein pr_debug("sending PORT_UP event to slave: %d, port: %d\n", 268a0c64a17SJack Morgenstein slave_id, port_num); 269a0c64a17SJack Morgenstein mlx4_gen_port_state_change_eqe(dev->dev, slave_id, 270a0c64a17SJack Morgenstein port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE); 271a0c64a17SJack Morgenstein } 272a0c64a17SJack Morgenstein } else { /* request to invalidate GUID */ 273a0c64a17SJack Morgenstein set_and_calc_slave_port_state(dev->dev, slave_id, port_num, 274a0c64a17SJack Morgenstein MLX4_PORT_STATE_IB_EVENT_GID_INVALID, 275a0c64a17SJack Morgenstein &gen_event); 27699ee4df6SYishai Hadas if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) { 277a0c64a17SJack Morgenstein pr_debug("sending PORT DOWN event to slave: %d, port: %d\n", 278a0c64a17SJack Morgenstein slave_id, port_num); 27999ee4df6SYishai Hadas mlx4_gen_port_state_change_eqe(dev->dev, 28099ee4df6SYishai Hadas slave_id, 28199ee4df6SYishai Hadas port_num, 282a0c64a17SJack Morgenstein MLX4_PORT_CHANGE_SUBTYPE_DOWN); 283a0c64a17SJack Morgenstein } 284a0c64a17SJack Morgenstein } 285a0c64a17SJack Morgenstein } 28699ee4df6SYishai Hadas } 287a0c64a17SJack Morgenstein 288a0c64a17SJack Morgenstein static void aliasguid_query_handler(int status, 289a0c64a17SJack Morgenstein struct ib_sa_guidinfo_rec *guid_rec, 290a0c64a17SJack Morgenstein void *context) 291a0c64a17SJack Morgenstein { 292a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev; 293a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context *cb_ctx = context; 294a0c64a17SJack Morgenstein u8 port_index ; 295a0c64a17SJack Morgenstein int i; 296a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_info_rec_det *rec; 297a0c64a17SJack Morgenstein unsigned long flags, flags1; 29899ee4df6SYishai Hadas ib_sa_comp_mask declined_guid_indexes = 0; 29999ee4df6SYishai Hadas ib_sa_comp_mask applied_guid_indexes = 0; 30099ee4df6SYishai Hadas unsigned int resched_delay_sec = 0; 301a0c64a17SJack Morgenstein 302a0c64a17SJack Morgenstein if (!context) 303a0c64a17SJack Morgenstein return; 304a0c64a17SJack Morgenstein 305a0c64a17SJack Morgenstein dev = cb_ctx->dev; 306a0c64a17SJack Morgenstein port_index = cb_ctx->port - 1; 307a0c64a17SJack Morgenstein rec = &dev->sriov.alias_guid.ports_guid[port_index]. 308a0c64a17SJack Morgenstein all_rec_per_port[cb_ctx->block_num]; 309a0c64a17SJack Morgenstein 310a0c64a17SJack Morgenstein if (status) { 311a0c64a17SJack Morgenstein pr_debug("(port: %d) failed: status = %d\n", 312a0c64a17SJack Morgenstein cb_ctx->port, status); 313*9285ec4cSJason A. Donenfeld rec->time_to_run = ktime_get_boottime_ns() + 1 * NSEC_PER_SEC; 314a0c64a17SJack Morgenstein goto out; 315a0c64a17SJack Morgenstein } 316a0c64a17SJack Morgenstein 317a0c64a17SJack Morgenstein if (guid_rec->block_num != cb_ctx->block_num) { 318a0c64a17SJack Morgenstein pr_err("block num mismatch: %d != %d\n", 319a0c64a17SJack Morgenstein cb_ctx->block_num, guid_rec->block_num); 320a0c64a17SJack Morgenstein goto out; 321a0c64a17SJack Morgenstein } 322a0c64a17SJack Morgenstein 323a0c64a17SJack Morgenstein pr_debug("lid/port: %d/%d, block_num: %d\n", 324a0c64a17SJack Morgenstein be16_to_cpu(guid_rec->lid), cb_ctx->port, 325a0c64a17SJack Morgenstein guid_rec->block_num); 326a0c64a17SJack Morgenstein 327a0c64a17SJack Morgenstein rec = &dev->sriov.alias_guid.ports_guid[port_index]. 328a0c64a17SJack Morgenstein all_rec_per_port[guid_rec->block_num]; 329a0c64a17SJack Morgenstein 33099ee4df6SYishai Hadas spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 331a0c64a17SJack Morgenstein for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) { 33299ee4df6SYishai Hadas __be64 sm_response, required_val; 33399ee4df6SYishai Hadas 33499ee4df6SYishai Hadas if (!(cb_ctx->guid_indexes & 33599ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i))) 33699ee4df6SYishai Hadas continue; 33799ee4df6SYishai Hadas sm_response = *(__be64 *)&guid_rec->guid_info_list 33899ee4df6SYishai Hadas [i * GUID_REC_SIZE]; 33999ee4df6SYishai Hadas required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE]; 34099ee4df6SYishai Hadas if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) { 34199ee4df6SYishai Hadas if (required_val == 34299ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 34399ee4df6SYishai Hadas goto next_entry; 34499ee4df6SYishai Hadas 34599ee4df6SYishai Hadas /* A new value was set till we got the response */ 34699ee4df6SYishai Hadas pr_debug("need to set new value %llx, record num %d, block_num:%d\n", 34799ee4df6SYishai Hadas be64_to_cpu(required_val), 34899ee4df6SYishai Hadas i, guid_rec->block_num); 34999ee4df6SYishai Hadas goto entry_declined; 35099ee4df6SYishai Hadas } 35199ee4df6SYishai Hadas 352a0c64a17SJack Morgenstein /* check if the SM didn't assign one of the records. 35399ee4df6SYishai Hadas * if it didn't, re-ask for. 354a0c64a17SJack Morgenstein */ 35599ee4df6SYishai Hadas if (sm_response == MLX4_NOT_SET_GUID) { 35699ee4df6SYishai Hadas if (rec->guids_retry_schedule[i] == 0) 357f5479601SYishai Hadas mlx4_ib_warn(&dev->ib_dev, 358f5479601SYishai Hadas "%s:Record num %d in block_num: %d was declined by SM\n", 359f5479601SYishai Hadas __func__, i, 360f5479601SYishai Hadas guid_rec->block_num); 36199ee4df6SYishai Hadas goto entry_declined; 362a0c64a17SJack Morgenstein } else { 363a0c64a17SJack Morgenstein /* properly assigned record. */ 364a0c64a17SJack Morgenstein /* We save the GUID we just got from the SM in the 365a0c64a17SJack Morgenstein * admin_guid in order to be persistent, and in the 366a0c64a17SJack Morgenstein * request from the sm the process will ask for the same GUID */ 367f5479601SYishai Hadas if (required_val && 36899ee4df6SYishai Hadas sm_response != required_val) { 36999ee4df6SYishai Hadas /* Warn only on first retry */ 37099ee4df6SYishai Hadas if (rec->guids_retry_schedule[i] == 0) 371a0c64a17SJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set" 372a0c64a17SJack Morgenstein " admin guid after SysAdmin " 373a0c64a17SJack Morgenstein "configuration. " 374a0c64a17SJack Morgenstein "Record num %d in block_num:%d " 375a0c64a17SJack Morgenstein "was declined by SM, " 37699ee4df6SYishai Hadas "new val(0x%llx) was kept, SM returned (0x%llx)\n", 377a0c64a17SJack Morgenstein __func__, i, 378a0c64a17SJack Morgenstein guid_rec->block_num, 37999ee4df6SYishai Hadas be64_to_cpu(required_val), 38099ee4df6SYishai Hadas be64_to_cpu(sm_response)); 38199ee4df6SYishai Hadas goto entry_declined; 382a0c64a17SJack Morgenstein } else { 38399ee4df6SYishai Hadas *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] = 38499ee4df6SYishai Hadas sm_response; 3852350f247SYishai Hadas if (required_val == 0) 3862350f247SYishai Hadas mlx4_set_admin_guid(dev->dev, 3872350f247SYishai Hadas sm_response, 3882350f247SYishai Hadas (guid_rec->block_num 3892350f247SYishai Hadas * NUM_ALIAS_GUID_IN_REC) + i, 3902350f247SYishai Hadas cb_ctx->port); 39199ee4df6SYishai Hadas goto next_entry; 392a0c64a17SJack Morgenstein } 393a0c64a17SJack Morgenstein } 39499ee4df6SYishai Hadas entry_declined: 39599ee4df6SYishai Hadas declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i); 39699ee4df6SYishai Hadas rec->guids_retry_schedule[i] = 39799ee4df6SYishai Hadas (rec->guids_retry_schedule[i] == 0) ? 1 : 39899ee4df6SYishai Hadas min((unsigned int)60, 39999ee4df6SYishai Hadas rec->guids_retry_schedule[i] * 2); 40099ee4df6SYishai Hadas /* using the minimum value among all entries in that record */ 40199ee4df6SYishai Hadas resched_delay_sec = (resched_delay_sec == 0) ? 40299ee4df6SYishai Hadas rec->guids_retry_schedule[i] : 40399ee4df6SYishai Hadas min(resched_delay_sec, 40499ee4df6SYishai Hadas rec->guids_retry_schedule[i]); 40599ee4df6SYishai Hadas continue; 40699ee4df6SYishai Hadas 40799ee4df6SYishai Hadas next_entry: 40899ee4df6SYishai Hadas rec->guids_retry_schedule[i] = 0; 409a0c64a17SJack Morgenstein } 41099ee4df6SYishai Hadas 41199ee4df6SYishai Hadas applied_guid_indexes = cb_ctx->guid_indexes & ~declined_guid_indexes; 41299ee4df6SYishai Hadas if (declined_guid_indexes || 41399ee4df6SYishai Hadas rec->guid_indexes & ~(applied_guid_indexes)) { 41499ee4df6SYishai Hadas pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n", 41599ee4df6SYishai Hadas guid_rec->block_num, 41699ee4df6SYishai Hadas be64_to_cpu((__force __be64)rec->guid_indexes), 41799ee4df6SYishai Hadas be64_to_cpu((__force __be64)applied_guid_indexes), 41899ee4df6SYishai Hadas be64_to_cpu((__force __be64)declined_guid_indexes)); 419*9285ec4cSJason A. Donenfeld rec->time_to_run = ktime_get_boottime_ns() + 42099ee4df6SYishai Hadas resched_delay_sec * NSEC_PER_SEC; 42199ee4df6SYishai Hadas } else { 42299ee4df6SYishai Hadas rec->status = MLX4_GUID_INFO_STATUS_SET; 42399ee4df6SYishai Hadas } 42499ee4df6SYishai Hadas spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 425a0c64a17SJack Morgenstein /* 426a0c64a17SJack Morgenstein The func is call here to close the cases when the 427a0c64a17SJack Morgenstein sm doesn't send smp, so in the sa response the driver 428a0c64a17SJack Morgenstein notifies the slave. 429a0c64a17SJack Morgenstein */ 430a0c64a17SJack Morgenstein mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num, 431a0c64a17SJack Morgenstein cb_ctx->port, 432a0c64a17SJack Morgenstein guid_rec->guid_info_list); 433a0c64a17SJack Morgenstein out: 434a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 435a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 43699ee4df6SYishai Hadas if (!dev->sriov.is_going_down) { 43799ee4df6SYishai Hadas get_low_record_time_index(dev, port_index, &resched_delay_sec); 438a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq, 439a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port_index]. 44099ee4df6SYishai Hadas alias_guid_work, 44199ee4df6SYishai Hadas msecs_to_jiffies(resched_delay_sec * 1000)); 44299ee4df6SYishai Hadas } 443a0c64a17SJack Morgenstein if (cb_ctx->sa_query) { 444a0c64a17SJack Morgenstein list_del(&cb_ctx->list); 445a0c64a17SJack Morgenstein kfree(cb_ctx); 446a0c64a17SJack Morgenstein } else 447a0c64a17SJack Morgenstein complete(&cb_ctx->done); 448a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 449a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 450a0c64a17SJack Morgenstein } 451a0c64a17SJack Morgenstein 452a0c64a17SJack Morgenstein static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index) 453a0c64a17SJack Morgenstein { 454a0c64a17SJack Morgenstein int i; 455a0c64a17SJack Morgenstein u64 cur_admin_val; 456a0c64a17SJack Morgenstein ib_sa_comp_mask comp_mask = 0; 457a0c64a17SJack Morgenstein 458a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status 45999ee4df6SYishai Hadas = MLX4_GUID_INFO_STATUS_SET; 460a0c64a17SJack Morgenstein 461a0c64a17SJack Morgenstein /* calculate the comp_mask for that record.*/ 462a0c64a17SJack Morgenstein for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 463a0c64a17SJack Morgenstein cur_admin_val = 464a0c64a17SJack Morgenstein *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. 465a0c64a17SJack Morgenstein all_rec_per_port[index].all_recs[GUID_REC_SIZE * i]; 466a0c64a17SJack Morgenstein /* 467a0c64a17SJack Morgenstein check the admin value: if it's for delete (~00LL) or 468a0c64a17SJack Morgenstein it is the first guid of the first record (hw guid) or 469a0c64a17SJack Morgenstein the records is not in ownership of the sysadmin and the sm doesn't 470a0c64a17SJack Morgenstein need to assign GUIDs, then don't put it up for assignment. 471a0c64a17SJack Morgenstein */ 472a0c64a17SJack Morgenstein if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val || 473f5479601SYishai Hadas (!index && !i)) 474a0c64a17SJack Morgenstein continue; 475c1e7e466SJack Morgenstein comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i); 476a0c64a17SJack Morgenstein } 477a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[port - 1]. 47899ee4df6SYishai Hadas all_rec_per_port[index].guid_indexes |= comp_mask; 47999ee4df6SYishai Hadas if (dev->sriov.alias_guid.ports_guid[port - 1]. 48099ee4df6SYishai Hadas all_rec_per_port[index].guid_indexes) 48199ee4df6SYishai Hadas dev->sriov.alias_guid.ports_guid[port - 1]. 48299ee4df6SYishai Hadas all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE; 48399ee4df6SYishai Hadas 484a0c64a17SJack Morgenstein } 485a0c64a17SJack Morgenstein 486a0c64a17SJack Morgenstein static int set_guid_rec(struct ib_device *ibdev, 48799ee4df6SYishai Hadas struct mlx4_next_alias_guid_work *rec) 488a0c64a17SJack Morgenstein { 489a0c64a17SJack Morgenstein int err; 490a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ibdev); 491a0c64a17SJack Morgenstein struct ib_sa_guidinfo_rec guid_info_rec; 492a0c64a17SJack Morgenstein ib_sa_comp_mask comp_mask; 493a0c64a17SJack Morgenstein struct ib_port_attr attr; 494a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context *callback_context; 495a0c64a17SJack Morgenstein unsigned long resched_delay, flags, flags1; 49699ee4df6SYishai Hadas u8 port = rec->port + 1; 49799ee4df6SYishai Hadas int index = rec->block_num; 49899ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det; 499a0c64a17SJack Morgenstein struct list_head *head = 500a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].cb_list; 501a0c64a17SJack Morgenstein 502c4550c63SOr Gerlitz memset(&attr, 0, sizeof(attr)); 503a0c64a17SJack Morgenstein err = __mlx4_ib_query_port(ibdev, port, &attr, 1); 504a0c64a17SJack Morgenstein if (err) { 505a0c64a17SJack Morgenstein pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n", 506a0c64a17SJack Morgenstein err, port); 507a0c64a17SJack Morgenstein return err; 508a0c64a17SJack Morgenstein } 509a0c64a17SJack Morgenstein /*check the port was configured by the sm, otherwise no need to send */ 510a0c64a17SJack Morgenstein if (attr.state != IB_PORT_ACTIVE) { 511a0c64a17SJack Morgenstein pr_debug("port %d not active...rescheduling\n", port); 512a0c64a17SJack Morgenstein resched_delay = 5 * HZ; 513a0c64a17SJack Morgenstein err = -EAGAIN; 514a0c64a17SJack Morgenstein goto new_schedule; 515a0c64a17SJack Morgenstein } 516a0c64a17SJack Morgenstein 517a0c64a17SJack Morgenstein callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL); 518a0c64a17SJack Morgenstein if (!callback_context) { 519a0c64a17SJack Morgenstein err = -ENOMEM; 520a0c64a17SJack Morgenstein resched_delay = HZ * 5; 521a0c64a17SJack Morgenstein goto new_schedule; 522a0c64a17SJack Morgenstein } 523a0c64a17SJack Morgenstein callback_context->port = port; 524a0c64a17SJack Morgenstein callback_context->dev = dev; 525a0c64a17SJack Morgenstein callback_context->block_num = index; 52699ee4df6SYishai Hadas callback_context->guid_indexes = rec_det->guid_indexes; 52799ee4df6SYishai Hadas callback_context->method = rec->method; 528a0c64a17SJack Morgenstein 529a0c64a17SJack Morgenstein memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec)); 530a0c64a17SJack Morgenstein 53162ede777SHiatt, Don guid_info_rec.lid = ib_lid_be16(attr.lid); 532a0c64a17SJack Morgenstein guid_info_rec.block_num = index; 533a0c64a17SJack Morgenstein 534a0c64a17SJack Morgenstein memcpy(guid_info_rec.guid_info_list, rec_det->all_recs, 535a0c64a17SJack Morgenstein GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC); 536a0c64a17SJack Morgenstein comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM | 537a0c64a17SJack Morgenstein rec_det->guid_indexes; 538a0c64a17SJack Morgenstein 539a0c64a17SJack Morgenstein init_completion(&callback_context->done); 540a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 541a0c64a17SJack Morgenstein list_add_tail(&callback_context->list, head); 542a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 543a0c64a17SJack Morgenstein 544a0c64a17SJack Morgenstein callback_context->query_id = 545a0c64a17SJack Morgenstein ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client, 546a0c64a17SJack Morgenstein ibdev, port, &guid_info_rec, 54799ee4df6SYishai Hadas comp_mask, rec->method, 1000, 548a0c64a17SJack Morgenstein GFP_KERNEL, aliasguid_query_handler, 549a0c64a17SJack Morgenstein callback_context, 550a0c64a17SJack Morgenstein &callback_context->sa_query); 551a0c64a17SJack Morgenstein if (callback_context->query_id < 0) { 552a0c64a17SJack Morgenstein pr_debug("ib_sa_guid_info_rec_query failed, query_id: " 553a0c64a17SJack Morgenstein "%d. will reschedule to the next 1 sec.\n", 554a0c64a17SJack Morgenstein callback_context->query_id); 555a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 556a0c64a17SJack Morgenstein list_del(&callback_context->list); 557a0c64a17SJack Morgenstein kfree(callback_context); 558a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 559a0c64a17SJack Morgenstein resched_delay = 1 * HZ; 560a0c64a17SJack Morgenstein err = -EAGAIN; 561a0c64a17SJack Morgenstein goto new_schedule; 562a0c64a17SJack Morgenstein } 563a0c64a17SJack Morgenstein err = 0; 564a0c64a17SJack Morgenstein goto out; 565a0c64a17SJack Morgenstein 566a0c64a17SJack Morgenstein new_schedule: 567a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 568a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 569a0c64a17SJack Morgenstein invalidate_guid_record(dev, port, index); 570a0c64a17SJack Morgenstein if (!dev->sriov.is_going_down) { 571a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 572a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 573a0c64a17SJack Morgenstein resched_delay); 574a0c64a17SJack Morgenstein } 575a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 576a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 577a0c64a17SJack Morgenstein 578a0c64a17SJack Morgenstein out: 579a0c64a17SJack Morgenstein return err; 580a0c64a17SJack Morgenstein } 581a0c64a17SJack Morgenstein 582f5479601SYishai Hadas static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port) 583f5479601SYishai Hadas { 584f5479601SYishai Hadas int j, k, entry; 585f5479601SYishai Hadas __be64 guid; 586f5479601SYishai Hadas 587f5479601SYishai Hadas /*Check if the SM doesn't need to assign the GUIDs*/ 588f5479601SYishai Hadas for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 589f5479601SYishai Hadas for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) { 590f5479601SYishai Hadas entry = j * NUM_ALIAS_GUID_IN_REC + k; 591f5479601SYishai Hadas /* no request for the 0 entry (hw guid) */ 592f5479601SYishai Hadas if (!entry || entry > dev->dev->persist->num_vfs || 593f5479601SYishai Hadas !mlx4_is_slave_active(dev->dev, entry)) 594f5479601SYishai Hadas continue; 595f5479601SYishai Hadas guid = mlx4_get_admin_guid(dev->dev, entry, port); 596f5479601SYishai Hadas *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. 597f5479601SYishai Hadas all_rec_per_port[j].all_recs 598f5479601SYishai Hadas [GUID_REC_SIZE * k] = guid; 599f5479601SYishai Hadas pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n", 600f5479601SYishai Hadas entry, 601f5479601SYishai Hadas be64_to_cpu(guid), 602f5479601SYishai Hadas port); 603f5479601SYishai Hadas } 604f5479601SYishai Hadas } 605f5479601SYishai Hadas } 606a0c64a17SJack Morgenstein void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port) 607a0c64a17SJack Morgenstein { 608a0c64a17SJack Morgenstein int i; 609a0c64a17SJack Morgenstein unsigned long flags, flags1; 610a0c64a17SJack Morgenstein 611a0c64a17SJack Morgenstein pr_debug("port %d\n", port); 612a0c64a17SJack Morgenstein 613a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 614a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 615f5479601SYishai Hadas 616f5479601SYishai Hadas if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags & 617f5479601SYishai Hadas GUID_STATE_NEED_PORT_INIT) { 618f5479601SYishai Hadas mlx4_ib_guid_port_init(dev, port); 619f5479601SYishai Hadas dev->sriov.alias_guid.ports_guid[port - 1].state_flags &= 620f5479601SYishai Hadas (~GUID_STATE_NEED_PORT_INIT); 621f5479601SYishai Hadas } 622a0c64a17SJack Morgenstein for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++) 623a0c64a17SJack Morgenstein invalidate_guid_record(dev, port, i); 624a0c64a17SJack Morgenstein 625a0c64a17SJack Morgenstein if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) { 626a0c64a17SJack Morgenstein /* 627a0c64a17SJack Morgenstein make sure no work waits in the queue, if the work is already 628a0c64a17SJack Morgenstein queued(not on the timer) the cancel will fail. That is not a problem 629a0c64a17SJack Morgenstein because we just want the work started. 630a0c64a17SJack Morgenstein */ 6317a9a2970SLinus Torvalds cancel_delayed_work(&dev->sriov.alias_guid. 632a0c64a17SJack Morgenstein ports_guid[port - 1].alias_guid_work); 633a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 634a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 635a0c64a17SJack Morgenstein 0); 636a0c64a17SJack Morgenstein } 637a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 638a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 639a0c64a17SJack Morgenstein } 640a0c64a17SJack Morgenstein 64199ee4df6SYishai Hadas static void set_required_record(struct mlx4_ib_dev *dev, u8 port, 64299ee4df6SYishai Hadas struct mlx4_next_alias_guid_work *next_rec, 64399ee4df6SYishai Hadas int record_index) 64499ee4df6SYishai Hadas { 64599ee4df6SYishai Hadas int i; 64699ee4df6SYishai Hadas int lowset_time_entry = -1; 64799ee4df6SYishai Hadas int lowest_time = 0; 64899ee4df6SYishai Hadas ib_sa_comp_mask delete_guid_indexes = 0; 64999ee4df6SYishai Hadas ib_sa_comp_mask set_guid_indexes = 0; 65099ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det *rec = 65199ee4df6SYishai Hadas &dev->sriov.alias_guid.ports_guid[port]. 65299ee4df6SYishai Hadas all_rec_per_port[record_index]; 65399ee4df6SYishai Hadas 65499ee4df6SYishai Hadas for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 65599ee4df6SYishai Hadas if (!(rec->guid_indexes & 65699ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i))) 65799ee4df6SYishai Hadas continue; 65899ee4df6SYishai Hadas 65999ee4df6SYishai Hadas if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] == 66099ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 66199ee4df6SYishai Hadas delete_guid_indexes |= 66299ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i); 66399ee4df6SYishai Hadas else 66499ee4df6SYishai Hadas set_guid_indexes |= 66599ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i); 66699ee4df6SYishai Hadas 66799ee4df6SYishai Hadas if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <= 66899ee4df6SYishai Hadas lowest_time) { 66999ee4df6SYishai Hadas lowset_time_entry = i; 67099ee4df6SYishai Hadas lowest_time = rec->guids_retry_schedule[i]; 67199ee4df6SYishai Hadas } 67299ee4df6SYishai Hadas } 67399ee4df6SYishai Hadas 67499ee4df6SYishai Hadas memcpy(&next_rec->rec_det, rec, sizeof(*rec)); 67599ee4df6SYishai Hadas next_rec->port = port; 67699ee4df6SYishai Hadas next_rec->block_num = record_index; 67799ee4df6SYishai Hadas 67899ee4df6SYishai Hadas if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] == 67999ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) { 68099ee4df6SYishai Hadas next_rec->rec_det.guid_indexes = delete_guid_indexes; 68199ee4df6SYishai Hadas next_rec->method = MLX4_GUID_INFO_RECORD_DELETE; 68299ee4df6SYishai Hadas } else { 68399ee4df6SYishai Hadas next_rec->rec_det.guid_indexes = set_guid_indexes; 68499ee4df6SYishai Hadas next_rec->method = MLX4_GUID_INFO_RECORD_SET; 68599ee4df6SYishai Hadas } 68699ee4df6SYishai Hadas } 68799ee4df6SYishai Hadas 68899ee4df6SYishai Hadas /* return index of record that should be updated based on lowest 68999ee4df6SYishai Hadas * rescheduled time 69099ee4df6SYishai Hadas */ 69199ee4df6SYishai Hadas static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port, 69299ee4df6SYishai Hadas int *resched_delay_sec) 69399ee4df6SYishai Hadas { 69499ee4df6SYishai Hadas int record_index = -1; 69599ee4df6SYishai Hadas u64 low_record_time = 0; 69699ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det rec; 69799ee4df6SYishai Hadas int j; 69899ee4df6SYishai Hadas 69999ee4df6SYishai Hadas for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 70099ee4df6SYishai Hadas rec = dev->sriov.alias_guid.ports_guid[port]. 70199ee4df6SYishai Hadas all_rec_per_port[j]; 70299ee4df6SYishai Hadas if (rec.status == MLX4_GUID_INFO_STATUS_IDLE && 70399ee4df6SYishai Hadas rec.guid_indexes) { 70499ee4df6SYishai Hadas if (record_index == -1 || 70599ee4df6SYishai Hadas rec.time_to_run < low_record_time) { 70699ee4df6SYishai Hadas record_index = j; 70799ee4df6SYishai Hadas low_record_time = rec.time_to_run; 70899ee4df6SYishai Hadas } 70999ee4df6SYishai Hadas } 71099ee4df6SYishai Hadas } 71199ee4df6SYishai Hadas if (resched_delay_sec) { 712*9285ec4cSJason A. Donenfeld u64 curr_time = ktime_get_boottime_ns(); 71399ee4df6SYishai Hadas 71499ee4df6SYishai Hadas *resched_delay_sec = (low_record_time < curr_time) ? 0 : 71599ee4df6SYishai Hadas div_u64((low_record_time - curr_time), NSEC_PER_SEC); 71699ee4df6SYishai Hadas } 71799ee4df6SYishai Hadas 71899ee4df6SYishai Hadas return record_index; 71999ee4df6SYishai Hadas } 72099ee4df6SYishai Hadas 721a0c64a17SJack Morgenstein /* The function returns the next record that was 722a0c64a17SJack Morgenstein * not configured (or failed to be configured) */ 723a0c64a17SJack Morgenstein static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port, 724a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work *rec) 725a0c64a17SJack Morgenstein { 726a0c64a17SJack Morgenstein unsigned long flags; 72799ee4df6SYishai Hadas int record_index; 72899ee4df6SYishai Hadas int ret = 0; 729a0c64a17SJack Morgenstein 730a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 73199ee4df6SYishai Hadas record_index = get_low_record_time_index(dev, port, NULL); 73299ee4df6SYishai Hadas 73399ee4df6SYishai Hadas if (record_index < 0) { 73499ee4df6SYishai Hadas ret = -ENOENT; 73599ee4df6SYishai Hadas goto out; 736a0c64a17SJack Morgenstein } 73799ee4df6SYishai Hadas 73899ee4df6SYishai Hadas set_required_record(dev, port, rec, record_index); 73999ee4df6SYishai Hadas out: 740a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 74199ee4df6SYishai Hadas return ret; 742a0c64a17SJack Morgenstein } 743a0c64a17SJack Morgenstein 744a0c64a17SJack Morgenstein static void alias_guid_work(struct work_struct *work) 745a0c64a17SJack Morgenstein { 746a0c64a17SJack Morgenstein struct delayed_work *delay = to_delayed_work(work); 747a0c64a17SJack Morgenstein int ret = 0; 748a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work *rec; 749a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port = 750a0c64a17SJack Morgenstein container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det, 751a0c64a17SJack Morgenstein alias_guid_work); 752a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent; 753a0c64a17SJack Morgenstein struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid, 754a0c64a17SJack Morgenstein struct mlx4_ib_sriov, 755a0c64a17SJack Morgenstein alias_guid); 756a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov); 757a0c64a17SJack Morgenstein 758a0c64a17SJack Morgenstein rec = kzalloc(sizeof *rec, GFP_KERNEL); 75915d4626eSLeon Romanovsky if (!rec) 760a0c64a17SJack Morgenstein return; 761a0c64a17SJack Morgenstein 762a0c64a17SJack Morgenstein pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1); 763a0c64a17SJack Morgenstein ret = get_next_record_to_update(dev, sriov_alias_port->port, rec); 764a0c64a17SJack Morgenstein if (ret) { 765a0c64a17SJack Morgenstein pr_debug("No more records to update.\n"); 766a0c64a17SJack Morgenstein goto out; 767a0c64a17SJack Morgenstein } 768a0c64a17SJack Morgenstein 76999ee4df6SYishai Hadas set_guid_rec(&dev->ib_dev, rec); 770a0c64a17SJack Morgenstein out: 771a0c64a17SJack Morgenstein kfree(rec); 772a0c64a17SJack Morgenstein } 773a0c64a17SJack Morgenstein 774a0c64a17SJack Morgenstein 775a0c64a17SJack Morgenstein void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port) 776a0c64a17SJack Morgenstein { 777a0c64a17SJack Morgenstein unsigned long flags, flags1; 778a0c64a17SJack Morgenstein 779a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 780a0c64a17SJack Morgenstein return; 781a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 782a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 783a0c64a17SJack Morgenstein if (!dev->sriov.is_going_down) { 784faa9141cSTalat Batheesh /* If there is pending one should cancel then run, otherwise 78599ee4df6SYishai Hadas * won't run till previous one is ended as same work 78699ee4df6SYishai Hadas * struct is used. 78799ee4df6SYishai Hadas */ 78899ee4df6SYishai Hadas cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port]. 78999ee4df6SYishai Hadas alias_guid_work); 790a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq, 791a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0); 792a0c64a17SJack Morgenstein } 793a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 794a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 795a0c64a17SJack Morgenstein } 796a0c64a17SJack Morgenstein 797a0c64a17SJack Morgenstein void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev) 798a0c64a17SJack Morgenstein { 799a0c64a17SJack Morgenstein int i; 800a0c64a17SJack Morgenstein struct mlx4_ib_sriov *sriov = &dev->sriov; 801a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context *cb_ctx; 802a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_port_rec_det *det; 803a0c64a17SJack Morgenstein struct ib_sa_query *sa_query; 804a0c64a17SJack Morgenstein unsigned long flags; 805a0c64a17SJack Morgenstein 806a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 807a0c64a17SJack Morgenstein det = &sriov->alias_guid.ports_guid[i]; 808587443e7SJack Morgenstein cancel_delayed_work_sync(&det->alias_guid_work); 809a0c64a17SJack Morgenstein spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 810a0c64a17SJack Morgenstein while (!list_empty(&det->cb_list)) { 811a0c64a17SJack Morgenstein cb_ctx = list_entry(det->cb_list.next, 812a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context, 813a0c64a17SJack Morgenstein list); 814a0c64a17SJack Morgenstein sa_query = cb_ctx->sa_query; 815a0c64a17SJack Morgenstein cb_ctx->sa_query = NULL; 816a0c64a17SJack Morgenstein list_del(&cb_ctx->list); 817a0c64a17SJack Morgenstein spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 818a0c64a17SJack Morgenstein ib_sa_cancel_query(cb_ctx->query_id, sa_query); 819a0c64a17SJack Morgenstein wait_for_completion(&cb_ctx->done); 820a0c64a17SJack Morgenstein kfree(cb_ctx); 821a0c64a17SJack Morgenstein spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 822a0c64a17SJack Morgenstein } 823a0c64a17SJack Morgenstein spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 824a0c64a17SJack Morgenstein } 825a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 826a0c64a17SJack Morgenstein flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 827a0c64a17SJack Morgenstein destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 828a0c64a17SJack Morgenstein } 829a0c64a17SJack Morgenstein ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 830a0c64a17SJack Morgenstein kfree(dev->sriov.alias_guid.sa_client); 831a0c64a17SJack Morgenstein } 832a0c64a17SJack Morgenstein 833a0c64a17SJack Morgenstein int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev) 834a0c64a17SJack Morgenstein { 835a0c64a17SJack Morgenstein char alias_wq_name[15]; 836a0c64a17SJack Morgenstein int ret = 0; 837f5479601SYishai Hadas int i, j; 838a0c64a17SJack Morgenstein union ib_gid gid; 839a0c64a17SJack Morgenstein 840a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 841a0c64a17SJack Morgenstein return 0; 842a0c64a17SJack Morgenstein dev->sriov.alias_guid.sa_client = 843a0c64a17SJack Morgenstein kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL); 844a0c64a17SJack Morgenstein if (!dev->sriov.alias_guid.sa_client) 845a0c64a17SJack Morgenstein return -ENOMEM; 846a0c64a17SJack Morgenstein 847a0c64a17SJack Morgenstein ib_sa_register_client(dev->sriov.alias_guid.sa_client); 848a0c64a17SJack Morgenstein 849a0c64a17SJack Morgenstein spin_lock_init(&dev->sriov.alias_guid.ag_work_lock); 850a0c64a17SJack Morgenstein 851a0c64a17SJack Morgenstein for (i = 1; i <= dev->num_ports; ++i) { 8523023a1e9SKamal Heib if (dev->ib_dev.ops.query_gid(&dev->ib_dev, i, 0, &gid)) { 853a0c64a17SJack Morgenstein ret = -EFAULT; 854a0c64a17SJack Morgenstein goto err_unregister; 855a0c64a17SJack Morgenstein } 856a0c64a17SJack Morgenstein } 857a0c64a17SJack Morgenstein 858a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 859a0c64a17SJack Morgenstein memset(&dev->sriov.alias_guid.ports_guid[i], 0, 860a0c64a17SJack Morgenstein sizeof (struct mlx4_sriov_alias_guid_port_rec_det)); 861f5479601SYishai Hadas dev->sriov.alias_guid.ports_guid[i].state_flags |= 862f5479601SYishai Hadas GUID_STATE_NEED_PORT_INIT; 863a0c64a17SJack Morgenstein for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 864f5479601SYishai Hadas /* mark each val as it was deleted */ 865f5479601SYishai Hadas memset(dev->sriov.alias_guid.ports_guid[i]. 866f5479601SYishai Hadas all_rec_per_port[j].all_recs, 0xFF, 867f5479601SYishai Hadas sizeof(dev->sriov.alias_guid.ports_guid[i]. 868f5479601SYishai Hadas all_rec_per_port[j].all_recs)); 869a0c64a17SJack Morgenstein } 870a0c64a17SJack Morgenstein INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list); 871a0c64a17SJack Morgenstein /*prepare the records, set them to be allocated by sm*/ 872f5479601SYishai Hadas if (mlx4_ib_sm_guid_assign) 873f5479601SYishai Hadas for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++) 874f5479601SYishai Hadas mlx4_set_admin_guid(dev->dev, 0, j, i + 1); 875a0c64a17SJack Morgenstein for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) 876a0c64a17SJack Morgenstein invalidate_guid_record(dev, i + 1, j); 877a0c64a17SJack Morgenstein 878a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid; 879a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].port = i; 880a0c64a17SJack Morgenstein 881a0c64a17SJack Morgenstein snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i); 882a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].wq = 883fb6375d7SBhaktipriya Shridhar alloc_ordered_workqueue(alias_wq_name, WQ_MEM_RECLAIM); 884a0c64a17SJack Morgenstein if (!dev->sriov.alias_guid.ports_guid[i].wq) { 885a0c64a17SJack Morgenstein ret = -ENOMEM; 886a0c64a17SJack Morgenstein goto err_thread; 887a0c64a17SJack Morgenstein } 888a0c64a17SJack Morgenstein INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work, 889a0c64a17SJack Morgenstein alias_guid_work); 890a0c64a17SJack Morgenstein } 891a0c64a17SJack Morgenstein return 0; 892a0c64a17SJack Morgenstein 893a0c64a17SJack Morgenstein err_thread: 894a0c64a17SJack Morgenstein for (--i; i >= 0; i--) { 895a0c64a17SJack Morgenstein destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 896a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].wq = NULL; 897a0c64a17SJack Morgenstein } 898a0c64a17SJack Morgenstein 899a0c64a17SJack Morgenstein err_unregister: 900a0c64a17SJack Morgenstein ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 901a0c64a17SJack Morgenstein kfree(dev->sriov.alias_guid.sa_client); 902a0c64a17SJack Morgenstein dev->sriov.alias_guid.sa_client = NULL; 903a0c64a17SJack Morgenstein pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret); 904a0c64a17SJack Morgenstein return ret; 905a0c64a17SJack Morgenstein } 906