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; 192*74d4943fSOr 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; 220*74d4943fSOr Gerlitz 221*74d4943fSOr Gerlitz slave_port = mlx4_phys_to_slave_port(dev->dev, slave_id, port_num); 222*74d4943fSOr Gerlitz if (slave_port < 0) /* this port isn't available for the VF */ 223*74d4943fSOr Gerlitz continue; 224*74d4943fSOr 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); 31399ee4df6SYishai Hadas rec->time_to_run = ktime_get_real_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)); 41999ee4df6SYishai Hadas rec->time_to_run = ktime_get_real_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 502a0c64a17SJack Morgenstein err = __mlx4_ib_query_port(ibdev, port, &attr, 1); 503a0c64a17SJack Morgenstein if (err) { 504a0c64a17SJack Morgenstein pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n", 505a0c64a17SJack Morgenstein err, port); 506a0c64a17SJack Morgenstein return err; 507a0c64a17SJack Morgenstein } 508a0c64a17SJack Morgenstein /*check the port was configured by the sm, otherwise no need to send */ 509a0c64a17SJack Morgenstein if (attr.state != IB_PORT_ACTIVE) { 510a0c64a17SJack Morgenstein pr_debug("port %d not active...rescheduling\n", port); 511a0c64a17SJack Morgenstein resched_delay = 5 * HZ; 512a0c64a17SJack Morgenstein err = -EAGAIN; 513a0c64a17SJack Morgenstein goto new_schedule; 514a0c64a17SJack Morgenstein } 515a0c64a17SJack Morgenstein 516a0c64a17SJack Morgenstein callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL); 517a0c64a17SJack Morgenstein if (!callback_context) { 518a0c64a17SJack Morgenstein err = -ENOMEM; 519a0c64a17SJack Morgenstein resched_delay = HZ * 5; 520a0c64a17SJack Morgenstein goto new_schedule; 521a0c64a17SJack Morgenstein } 522a0c64a17SJack Morgenstein callback_context->port = port; 523a0c64a17SJack Morgenstein callback_context->dev = dev; 524a0c64a17SJack Morgenstein callback_context->block_num = index; 52599ee4df6SYishai Hadas callback_context->guid_indexes = rec_det->guid_indexes; 52699ee4df6SYishai Hadas callback_context->method = rec->method; 527a0c64a17SJack Morgenstein 528a0c64a17SJack Morgenstein memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec)); 529a0c64a17SJack Morgenstein 530a0c64a17SJack Morgenstein guid_info_rec.lid = cpu_to_be16(attr.lid); 531a0c64a17SJack Morgenstein guid_info_rec.block_num = index; 532a0c64a17SJack Morgenstein 533a0c64a17SJack Morgenstein memcpy(guid_info_rec.guid_info_list, rec_det->all_recs, 534a0c64a17SJack Morgenstein GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC); 535a0c64a17SJack Morgenstein comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM | 536a0c64a17SJack Morgenstein rec_det->guid_indexes; 537a0c64a17SJack Morgenstein 538a0c64a17SJack Morgenstein init_completion(&callback_context->done); 539a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 540a0c64a17SJack Morgenstein list_add_tail(&callback_context->list, head); 541a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 542a0c64a17SJack Morgenstein 543a0c64a17SJack Morgenstein callback_context->query_id = 544a0c64a17SJack Morgenstein ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client, 545a0c64a17SJack Morgenstein ibdev, port, &guid_info_rec, 54699ee4df6SYishai Hadas comp_mask, rec->method, 1000, 547a0c64a17SJack Morgenstein GFP_KERNEL, aliasguid_query_handler, 548a0c64a17SJack Morgenstein callback_context, 549a0c64a17SJack Morgenstein &callback_context->sa_query); 550a0c64a17SJack Morgenstein if (callback_context->query_id < 0) { 551a0c64a17SJack Morgenstein pr_debug("ib_sa_guid_info_rec_query failed, query_id: " 552a0c64a17SJack Morgenstein "%d. will reschedule to the next 1 sec.\n", 553a0c64a17SJack Morgenstein callback_context->query_id); 554a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 555a0c64a17SJack Morgenstein list_del(&callback_context->list); 556a0c64a17SJack Morgenstein kfree(callback_context); 557a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 558a0c64a17SJack Morgenstein resched_delay = 1 * HZ; 559a0c64a17SJack Morgenstein err = -EAGAIN; 560a0c64a17SJack Morgenstein goto new_schedule; 561a0c64a17SJack Morgenstein } 562a0c64a17SJack Morgenstein err = 0; 563a0c64a17SJack Morgenstein goto out; 564a0c64a17SJack Morgenstein 565a0c64a17SJack Morgenstein new_schedule: 566a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 567a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 568a0c64a17SJack Morgenstein invalidate_guid_record(dev, port, index); 569a0c64a17SJack Morgenstein if (!dev->sriov.is_going_down) { 570a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 571a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 572a0c64a17SJack Morgenstein resched_delay); 573a0c64a17SJack Morgenstein } 574a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 575a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 576a0c64a17SJack Morgenstein 577a0c64a17SJack Morgenstein out: 578a0c64a17SJack Morgenstein return err; 579a0c64a17SJack Morgenstein } 580a0c64a17SJack Morgenstein 581f5479601SYishai Hadas static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port) 582f5479601SYishai Hadas { 583f5479601SYishai Hadas int j, k, entry; 584f5479601SYishai Hadas __be64 guid; 585f5479601SYishai Hadas 586f5479601SYishai Hadas /*Check if the SM doesn't need to assign the GUIDs*/ 587f5479601SYishai Hadas for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 588f5479601SYishai Hadas for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) { 589f5479601SYishai Hadas entry = j * NUM_ALIAS_GUID_IN_REC + k; 590f5479601SYishai Hadas /* no request for the 0 entry (hw guid) */ 591f5479601SYishai Hadas if (!entry || entry > dev->dev->persist->num_vfs || 592f5479601SYishai Hadas !mlx4_is_slave_active(dev->dev, entry)) 593f5479601SYishai Hadas continue; 594f5479601SYishai Hadas guid = mlx4_get_admin_guid(dev->dev, entry, port); 595f5479601SYishai Hadas *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1]. 596f5479601SYishai Hadas all_rec_per_port[j].all_recs 597f5479601SYishai Hadas [GUID_REC_SIZE * k] = guid; 598f5479601SYishai Hadas pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n", 599f5479601SYishai Hadas entry, 600f5479601SYishai Hadas be64_to_cpu(guid), 601f5479601SYishai Hadas port); 602f5479601SYishai Hadas } 603f5479601SYishai Hadas } 604f5479601SYishai Hadas } 605a0c64a17SJack Morgenstein void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port) 606a0c64a17SJack Morgenstein { 607a0c64a17SJack Morgenstein int i; 608a0c64a17SJack Morgenstein unsigned long flags, flags1; 609a0c64a17SJack Morgenstein 610a0c64a17SJack Morgenstein pr_debug("port %d\n", port); 611a0c64a17SJack Morgenstein 612a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 613a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 614f5479601SYishai Hadas 615f5479601SYishai Hadas if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags & 616f5479601SYishai Hadas GUID_STATE_NEED_PORT_INIT) { 617f5479601SYishai Hadas mlx4_ib_guid_port_init(dev, port); 618f5479601SYishai Hadas dev->sriov.alias_guid.ports_guid[port - 1].state_flags &= 619f5479601SYishai Hadas (~GUID_STATE_NEED_PORT_INIT); 620f5479601SYishai Hadas } 621a0c64a17SJack Morgenstein for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++) 622a0c64a17SJack Morgenstein invalidate_guid_record(dev, port, i); 623a0c64a17SJack Morgenstein 624a0c64a17SJack Morgenstein if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) { 625a0c64a17SJack Morgenstein /* 626a0c64a17SJack Morgenstein make sure no work waits in the queue, if the work is already 627a0c64a17SJack Morgenstein queued(not on the timer) the cancel will fail. That is not a problem 628a0c64a17SJack Morgenstein because we just want the work started. 629a0c64a17SJack Morgenstein */ 6307a9a2970SLinus Torvalds cancel_delayed_work(&dev->sriov.alias_guid. 631a0c64a17SJack Morgenstein ports_guid[port - 1].alias_guid_work); 632a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq, 633a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work, 634a0c64a17SJack Morgenstein 0); 635a0c64a17SJack Morgenstein } 636a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 637a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 638a0c64a17SJack Morgenstein } 639a0c64a17SJack Morgenstein 64099ee4df6SYishai Hadas static void set_required_record(struct mlx4_ib_dev *dev, u8 port, 64199ee4df6SYishai Hadas struct mlx4_next_alias_guid_work *next_rec, 64299ee4df6SYishai Hadas int record_index) 64399ee4df6SYishai Hadas { 64499ee4df6SYishai Hadas int i; 64599ee4df6SYishai Hadas int lowset_time_entry = -1; 64699ee4df6SYishai Hadas int lowest_time = 0; 64799ee4df6SYishai Hadas ib_sa_comp_mask delete_guid_indexes = 0; 64899ee4df6SYishai Hadas ib_sa_comp_mask set_guid_indexes = 0; 64999ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det *rec = 65099ee4df6SYishai Hadas &dev->sriov.alias_guid.ports_guid[port]. 65199ee4df6SYishai Hadas all_rec_per_port[record_index]; 65299ee4df6SYishai Hadas 65399ee4df6SYishai Hadas for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) { 65499ee4df6SYishai Hadas if (!(rec->guid_indexes & 65599ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i))) 65699ee4df6SYishai Hadas continue; 65799ee4df6SYishai Hadas 65899ee4df6SYishai Hadas if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] == 65999ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) 66099ee4df6SYishai Hadas delete_guid_indexes |= 66199ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i); 66299ee4df6SYishai Hadas else 66399ee4df6SYishai Hadas set_guid_indexes |= 66499ee4df6SYishai Hadas mlx4_ib_get_aguid_comp_mask_from_ix(i); 66599ee4df6SYishai Hadas 66699ee4df6SYishai Hadas if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <= 66799ee4df6SYishai Hadas lowest_time) { 66899ee4df6SYishai Hadas lowset_time_entry = i; 66999ee4df6SYishai Hadas lowest_time = rec->guids_retry_schedule[i]; 67099ee4df6SYishai Hadas } 67199ee4df6SYishai Hadas } 67299ee4df6SYishai Hadas 67399ee4df6SYishai Hadas memcpy(&next_rec->rec_det, rec, sizeof(*rec)); 67499ee4df6SYishai Hadas next_rec->port = port; 67599ee4df6SYishai Hadas next_rec->block_num = record_index; 67699ee4df6SYishai Hadas 67799ee4df6SYishai Hadas if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] == 67899ee4df6SYishai Hadas cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) { 67999ee4df6SYishai Hadas next_rec->rec_det.guid_indexes = delete_guid_indexes; 68099ee4df6SYishai Hadas next_rec->method = MLX4_GUID_INFO_RECORD_DELETE; 68199ee4df6SYishai Hadas } else { 68299ee4df6SYishai Hadas next_rec->rec_det.guid_indexes = set_guid_indexes; 68399ee4df6SYishai Hadas next_rec->method = MLX4_GUID_INFO_RECORD_SET; 68499ee4df6SYishai Hadas } 68599ee4df6SYishai Hadas } 68699ee4df6SYishai Hadas 68799ee4df6SYishai Hadas /* return index of record that should be updated based on lowest 68899ee4df6SYishai Hadas * rescheduled time 68999ee4df6SYishai Hadas */ 69099ee4df6SYishai Hadas static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port, 69199ee4df6SYishai Hadas int *resched_delay_sec) 69299ee4df6SYishai Hadas { 69399ee4df6SYishai Hadas int record_index = -1; 69499ee4df6SYishai Hadas u64 low_record_time = 0; 69599ee4df6SYishai Hadas struct mlx4_sriov_alias_guid_info_rec_det rec; 69699ee4df6SYishai Hadas int j; 69799ee4df6SYishai Hadas 69899ee4df6SYishai Hadas for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 69999ee4df6SYishai Hadas rec = dev->sriov.alias_guid.ports_guid[port]. 70099ee4df6SYishai Hadas all_rec_per_port[j]; 70199ee4df6SYishai Hadas if (rec.status == MLX4_GUID_INFO_STATUS_IDLE && 70299ee4df6SYishai Hadas rec.guid_indexes) { 70399ee4df6SYishai Hadas if (record_index == -1 || 70499ee4df6SYishai Hadas rec.time_to_run < low_record_time) { 70599ee4df6SYishai Hadas record_index = j; 70699ee4df6SYishai Hadas low_record_time = rec.time_to_run; 70799ee4df6SYishai Hadas } 70899ee4df6SYishai Hadas } 70999ee4df6SYishai Hadas } 71099ee4df6SYishai Hadas if (resched_delay_sec) { 71199ee4df6SYishai Hadas u64 curr_time = ktime_get_real_ns(); 71299ee4df6SYishai Hadas 71399ee4df6SYishai Hadas *resched_delay_sec = (low_record_time < curr_time) ? 0 : 71499ee4df6SYishai Hadas div_u64((low_record_time - curr_time), NSEC_PER_SEC); 71599ee4df6SYishai Hadas } 71699ee4df6SYishai Hadas 71799ee4df6SYishai Hadas return record_index; 71899ee4df6SYishai Hadas } 71999ee4df6SYishai Hadas 720a0c64a17SJack Morgenstein /* The function returns the next record that was 721a0c64a17SJack Morgenstein * not configured (or failed to be configured) */ 722a0c64a17SJack Morgenstein static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port, 723a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work *rec) 724a0c64a17SJack Morgenstein { 725a0c64a17SJack Morgenstein unsigned long flags; 72699ee4df6SYishai Hadas int record_index; 72799ee4df6SYishai Hadas int ret = 0; 728a0c64a17SJack Morgenstein 729a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags); 73099ee4df6SYishai Hadas record_index = get_low_record_time_index(dev, port, NULL); 73199ee4df6SYishai Hadas 73299ee4df6SYishai Hadas if (record_index < 0) { 73399ee4df6SYishai Hadas ret = -ENOENT; 73499ee4df6SYishai Hadas goto out; 735a0c64a17SJack Morgenstein } 73699ee4df6SYishai Hadas 73799ee4df6SYishai Hadas set_required_record(dev, port, rec, record_index); 73899ee4df6SYishai Hadas out: 739a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags); 74099ee4df6SYishai Hadas return ret; 741a0c64a17SJack Morgenstein } 742a0c64a17SJack Morgenstein 743a0c64a17SJack Morgenstein static void alias_guid_work(struct work_struct *work) 744a0c64a17SJack Morgenstein { 745a0c64a17SJack Morgenstein struct delayed_work *delay = to_delayed_work(work); 746a0c64a17SJack Morgenstein int ret = 0; 747a0c64a17SJack Morgenstein struct mlx4_next_alias_guid_work *rec; 748a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port = 749a0c64a17SJack Morgenstein container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det, 750a0c64a17SJack Morgenstein alias_guid_work); 751a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent; 752a0c64a17SJack Morgenstein struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid, 753a0c64a17SJack Morgenstein struct mlx4_ib_sriov, 754a0c64a17SJack Morgenstein alias_guid); 755a0c64a17SJack Morgenstein struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov); 756a0c64a17SJack Morgenstein 757a0c64a17SJack Morgenstein rec = kzalloc(sizeof *rec, GFP_KERNEL); 758a0c64a17SJack Morgenstein if (!rec) { 759a0c64a17SJack Morgenstein pr_err("alias_guid_work: No Memory\n"); 760a0c64a17SJack Morgenstein return; 761a0c64a17SJack Morgenstein } 762a0c64a17SJack Morgenstein 763a0c64a17SJack Morgenstein pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1); 764a0c64a17SJack Morgenstein ret = get_next_record_to_update(dev, sriov_alias_port->port, rec); 765a0c64a17SJack Morgenstein if (ret) { 766a0c64a17SJack Morgenstein pr_debug("No more records to update.\n"); 767a0c64a17SJack Morgenstein goto out; 768a0c64a17SJack Morgenstein } 769a0c64a17SJack Morgenstein 77099ee4df6SYishai Hadas set_guid_rec(&dev->ib_dev, rec); 771a0c64a17SJack Morgenstein out: 772a0c64a17SJack Morgenstein kfree(rec); 773a0c64a17SJack Morgenstein } 774a0c64a17SJack Morgenstein 775a0c64a17SJack Morgenstein 776a0c64a17SJack Morgenstein void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port) 777a0c64a17SJack Morgenstein { 778a0c64a17SJack Morgenstein unsigned long flags, flags1; 779a0c64a17SJack Morgenstein 780a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 781a0c64a17SJack Morgenstein return; 782a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 783a0c64a17SJack Morgenstein spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1); 784a0c64a17SJack Morgenstein if (!dev->sriov.is_going_down) { 78599ee4df6SYishai Hadas /* If there is pending one should cancell then run, otherwise 78699ee4df6SYishai Hadas * won't run till previous one is ended as same work 78799ee4df6SYishai Hadas * struct is used. 78899ee4df6SYishai Hadas */ 78999ee4df6SYishai Hadas cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port]. 79099ee4df6SYishai Hadas alias_guid_work); 791a0c64a17SJack Morgenstein queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq, 792a0c64a17SJack Morgenstein &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0); 793a0c64a17SJack Morgenstein } 794a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1); 795a0c64a17SJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 796a0c64a17SJack Morgenstein } 797a0c64a17SJack Morgenstein 798a0c64a17SJack Morgenstein void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev) 799a0c64a17SJack Morgenstein { 800a0c64a17SJack Morgenstein int i; 801a0c64a17SJack Morgenstein struct mlx4_ib_sriov *sriov = &dev->sriov; 802a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context *cb_ctx; 803a0c64a17SJack Morgenstein struct mlx4_sriov_alias_guid_port_rec_det *det; 804a0c64a17SJack Morgenstein struct ib_sa_query *sa_query; 805a0c64a17SJack Morgenstein unsigned long flags; 806a0c64a17SJack Morgenstein 807a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 808a0c64a17SJack Morgenstein cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work); 809a0c64a17SJack Morgenstein det = &sriov->alias_guid.ports_guid[i]; 810a0c64a17SJack Morgenstein spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 811a0c64a17SJack Morgenstein while (!list_empty(&det->cb_list)) { 812a0c64a17SJack Morgenstein cb_ctx = list_entry(det->cb_list.next, 813a0c64a17SJack Morgenstein struct mlx4_alias_guid_work_context, 814a0c64a17SJack Morgenstein list); 815a0c64a17SJack Morgenstein sa_query = cb_ctx->sa_query; 816a0c64a17SJack Morgenstein cb_ctx->sa_query = NULL; 817a0c64a17SJack Morgenstein list_del(&cb_ctx->list); 818a0c64a17SJack Morgenstein spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 819a0c64a17SJack Morgenstein ib_sa_cancel_query(cb_ctx->query_id, sa_query); 820a0c64a17SJack Morgenstein wait_for_completion(&cb_ctx->done); 821a0c64a17SJack Morgenstein kfree(cb_ctx); 822a0c64a17SJack Morgenstein spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags); 823a0c64a17SJack Morgenstein } 824a0c64a17SJack Morgenstein spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags); 825a0c64a17SJack Morgenstein } 826a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 827a0c64a17SJack Morgenstein flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 828a0c64a17SJack Morgenstein destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 829a0c64a17SJack Morgenstein } 830a0c64a17SJack Morgenstein ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 831a0c64a17SJack Morgenstein kfree(dev->sriov.alias_guid.sa_client); 832a0c64a17SJack Morgenstein } 833a0c64a17SJack Morgenstein 834a0c64a17SJack Morgenstein int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev) 835a0c64a17SJack Morgenstein { 836a0c64a17SJack Morgenstein char alias_wq_name[15]; 837a0c64a17SJack Morgenstein int ret = 0; 838f5479601SYishai Hadas int i, j; 839a0c64a17SJack Morgenstein union ib_gid gid; 840a0c64a17SJack Morgenstein 841a0c64a17SJack Morgenstein if (!mlx4_is_master(dev->dev)) 842a0c64a17SJack Morgenstein return 0; 843a0c64a17SJack Morgenstein dev->sriov.alias_guid.sa_client = 844a0c64a17SJack Morgenstein kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL); 845a0c64a17SJack Morgenstein if (!dev->sriov.alias_guid.sa_client) 846a0c64a17SJack Morgenstein return -ENOMEM; 847a0c64a17SJack Morgenstein 848a0c64a17SJack Morgenstein ib_sa_register_client(dev->sriov.alias_guid.sa_client); 849a0c64a17SJack Morgenstein 850a0c64a17SJack Morgenstein spin_lock_init(&dev->sriov.alias_guid.ag_work_lock); 851a0c64a17SJack Morgenstein 852a0c64a17SJack Morgenstein for (i = 1; i <= dev->num_ports; ++i) { 853a0c64a17SJack Morgenstein if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) { 854a0c64a17SJack Morgenstein ret = -EFAULT; 855a0c64a17SJack Morgenstein goto err_unregister; 856a0c64a17SJack Morgenstein } 857a0c64a17SJack Morgenstein } 858a0c64a17SJack Morgenstein 859a0c64a17SJack Morgenstein for (i = 0 ; i < dev->num_ports; i++) { 860a0c64a17SJack Morgenstein memset(&dev->sriov.alias_guid.ports_guid[i], 0, 861a0c64a17SJack Morgenstein sizeof (struct mlx4_sriov_alias_guid_port_rec_det)); 862f5479601SYishai Hadas dev->sriov.alias_guid.ports_guid[i].state_flags |= 863f5479601SYishai Hadas GUID_STATE_NEED_PORT_INIT; 864a0c64a17SJack Morgenstein for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) { 865f5479601SYishai Hadas /* mark each val as it was deleted */ 866f5479601SYishai Hadas memset(dev->sriov.alias_guid.ports_guid[i]. 867f5479601SYishai Hadas all_rec_per_port[j].all_recs, 0xFF, 868f5479601SYishai Hadas sizeof(dev->sriov.alias_guid.ports_guid[i]. 869f5479601SYishai Hadas all_rec_per_port[j].all_recs)); 870a0c64a17SJack Morgenstein } 871a0c64a17SJack Morgenstein INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list); 872a0c64a17SJack Morgenstein /*prepare the records, set them to be allocated by sm*/ 873f5479601SYishai Hadas if (mlx4_ib_sm_guid_assign) 874f5479601SYishai Hadas for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++) 875f5479601SYishai Hadas mlx4_set_admin_guid(dev->dev, 0, j, i + 1); 876a0c64a17SJack Morgenstein for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) 877a0c64a17SJack Morgenstein invalidate_guid_record(dev, i + 1, j); 878a0c64a17SJack Morgenstein 879a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid; 880a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].port = i; 881a0c64a17SJack Morgenstein 882a0c64a17SJack Morgenstein snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i); 883a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].wq = 884a0c64a17SJack Morgenstein create_singlethread_workqueue(alias_wq_name); 885a0c64a17SJack Morgenstein if (!dev->sriov.alias_guid.ports_guid[i].wq) { 886a0c64a17SJack Morgenstein ret = -ENOMEM; 887a0c64a17SJack Morgenstein goto err_thread; 888a0c64a17SJack Morgenstein } 889a0c64a17SJack Morgenstein INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work, 890a0c64a17SJack Morgenstein alias_guid_work); 891a0c64a17SJack Morgenstein } 892a0c64a17SJack Morgenstein return 0; 893a0c64a17SJack Morgenstein 894a0c64a17SJack Morgenstein err_thread: 895a0c64a17SJack Morgenstein for (--i; i >= 0; i--) { 896a0c64a17SJack Morgenstein destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq); 897a0c64a17SJack Morgenstein dev->sriov.alias_guid.ports_guid[i].wq = NULL; 898a0c64a17SJack Morgenstein } 899a0c64a17SJack Morgenstein 900a0c64a17SJack Morgenstein err_unregister: 901a0c64a17SJack Morgenstein ib_sa_unregister_client(dev->sriov.alias_guid.sa_client); 902a0c64a17SJack Morgenstein kfree(dev->sriov.alias_guid.sa_client); 903a0c64a17SJack Morgenstein dev->sriov.alias_guid.sa_client = NULL; 904a0c64a17SJack Morgenstein pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret); 905a0c64a17SJack Morgenstein return ret; 906a0c64a17SJack Morgenstein } 907