162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2016 - 2019 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci#include "ah.h" 862306a36Sopenharmony_ci#include "vt.h" /* for prints */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/** 1162306a36Sopenharmony_ci * rvt_check_ah - validate the attributes of AH 1262306a36Sopenharmony_ci * @ibdev: the ib device 1362306a36Sopenharmony_ci * @ah_attr: the attributes of the AH 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * If driver supports a more detailed check_ah function call back to it 1662306a36Sopenharmony_ci * otherwise just check the basics. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Return: 0 on success 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ciint rvt_check_ah(struct ib_device *ibdev, 2162306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci int err; 2462306a36Sopenharmony_ci int port_num = rdma_ah_get_port_num(ah_attr); 2562306a36Sopenharmony_ci struct ib_port_attr port_attr; 2662306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibdev); 2762306a36Sopenharmony_ci u8 ah_flags = rdma_ah_get_ah_flags(ah_attr); 2862306a36Sopenharmony_ci u8 static_rate = rdma_ah_get_static_rate(ah_attr); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci err = ib_query_port(ibdev, port_num, &port_attr); 3162306a36Sopenharmony_ci if (err) 3262306a36Sopenharmony_ci return -EINVAL; 3362306a36Sopenharmony_ci if (port_num < 1 || 3462306a36Sopenharmony_ci port_num > ibdev->phys_port_cnt) 3562306a36Sopenharmony_ci return -EINVAL; 3662306a36Sopenharmony_ci if (static_rate != IB_RATE_PORT_CURRENT && 3762306a36Sopenharmony_ci ib_rate_to_mbps(static_rate) < 0) 3862306a36Sopenharmony_ci return -EINVAL; 3962306a36Sopenharmony_ci if ((ah_flags & IB_AH_GRH) && 4062306a36Sopenharmony_ci rdma_ah_read_grh(ah_attr)->sgid_index >= port_attr.gid_tbl_len) 4162306a36Sopenharmony_ci return -EINVAL; 4262306a36Sopenharmony_ci if (rdi->driver_f.check_ah) 4362306a36Sopenharmony_ci return rdi->driver_f.check_ah(ibdev, ah_attr); 4462306a36Sopenharmony_ci return 0; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_check_ah); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/** 4962306a36Sopenharmony_ci * rvt_create_ah - create an address handle 5062306a36Sopenharmony_ci * @ibah: the IB address handle 5162306a36Sopenharmony_ci * @init_attr: the attributes of the AH 5262306a36Sopenharmony_ci * @udata: pointer to user's input output buffer information. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * This may be called from interrupt context. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * Return: 0 on success 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ciint rvt_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, 5962306a36Sopenharmony_ci struct ib_udata *udata) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct rvt_ah *ah = ibah_to_rvtah(ibah); 6262306a36Sopenharmony_ci struct rvt_dev_info *dev = ib_to_rvt(ibah->device); 6362306a36Sopenharmony_ci unsigned long flags; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (rvt_check_ah(ibah->device, init_attr->ah_attr)) 6662306a36Sopenharmony_ci return -EINVAL; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci spin_lock_irqsave(&dev->n_ahs_lock, flags); 6962306a36Sopenharmony_ci if (dev->n_ahs_allocated == dev->dparms.props.max_ah) { 7062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->n_ahs_lock, flags); 7162306a36Sopenharmony_ci return -ENOMEM; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci dev->n_ahs_allocated++; 7562306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->n_ahs_lock, flags); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci rdma_copy_ah_attr(&ah->attr, init_attr->ah_attr); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (dev->driver_f.notify_new_ah) 8062306a36Sopenharmony_ci dev->driver_f.notify_new_ah(ibah->device, 8162306a36Sopenharmony_ci init_attr->ah_attr, ah); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/** 8762306a36Sopenharmony_ci * rvt_destroy_ah - Destroy an address handle 8862306a36Sopenharmony_ci * @ibah: address handle 8962306a36Sopenharmony_ci * @destroy_flags: destroy address handle flags (see enum rdma_destroy_ah_flags) 9062306a36Sopenharmony_ci * Return: 0 on success 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ciint rvt_destroy_ah(struct ib_ah *ibah, u32 destroy_flags) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct rvt_dev_info *dev = ib_to_rvt(ibah->device); 9562306a36Sopenharmony_ci struct rvt_ah *ah = ibah_to_rvtah(ibah); 9662306a36Sopenharmony_ci unsigned long flags; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci spin_lock_irqsave(&dev->n_ahs_lock, flags); 9962306a36Sopenharmony_ci dev->n_ahs_allocated--; 10062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->n_ahs_lock, flags); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci rdma_destroy_ah_attr(&ah->attr); 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/** 10762306a36Sopenharmony_ci * rvt_modify_ah - modify an ah with given attrs 10862306a36Sopenharmony_ci * @ibah: address handle to modify 10962306a36Sopenharmony_ci * @ah_attr: attrs to apply 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * Return: 0 on success 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ciint rvt_modify_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct rvt_ah *ah = ibah_to_rvtah(ibah); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (rvt_check_ah(ibah->device, ah_attr)) 11862306a36Sopenharmony_ci return -EINVAL; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci ah->attr = *ah_attr; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/** 12662306a36Sopenharmony_ci * rvt_query_ah - return attrs for ah 12762306a36Sopenharmony_ci * @ibah: address handle to query 12862306a36Sopenharmony_ci * @ah_attr: return info in this 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * Return: always 0 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ciint rvt_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct rvt_ah *ah = ibah_to_rvtah(ibah); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci *ah_attr = ah->attr; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 140