diff options
author | Kamal Heib <kamalh@mellanox.com> | 2016-01-06 10:03:59 -0800 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2016-03-10 20:37:13 -0500 |
commit | 119a8e708d16d38eedfa3d920b89b709dda41a8f (patch) | |
tree | 3749c9296e1a084904a8ed30b6d98fa3f9e57107 /drivers/infiniband/sw | |
parent | f2f342115ef2b0755abd73573831351e371f6242 (diff) |
IB/rdmavt: Add AH to rdmavt
Original patch is from Kamal Heib <kamalh@mellanox.com>. It has
been split into three separate patches. This one for rdmavt,
a follow on for qib, and one for hfi1.
Create datastructure for address handle and implement the
create/destroy/modify/query of address handle for rdmavt.
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Kamal Heib <kamalh@mellanox.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
Diffstat (limited to 'drivers/infiniband/sw')
-rw-r--r-- | drivers/infiniband/sw/rdmavt/ah.c | 98 | ||||
-rw-r--r-- | drivers/infiniband/sw/rdmavt/vt.c | 5 |
2 files changed, 98 insertions, 5 deletions
diff --git a/drivers/infiniband/sw/rdmavt/ah.c b/drivers/infiniband/sw/rdmavt/ah.c index d36895597304..2519db98be6c 100644 --- a/drivers/infiniband/sw/rdmavt/ah.c +++ b/drivers/infiniband/sw/rdmavt/ah.c @@ -45,7 +45,49 @@ * */ +#include <linux/slab.h> #include "ah.h" +#include "vt.h" /* for prints */ + +/** + * rvt_check_ah - validate the attributes of AH + * @ibdev: the ib device + * @ah_attr: the attributes of the AH + */ +int rvt_check_ah(struct ib_device *ibdev, + struct ib_ah_attr *ah_attr) +{ + int err; + struct ib_port_attr port_attr; + struct rvt_dev_info *rdi = ib_to_rvt(ibdev); + enum rdma_link_layer link = rdma_port_get_link_layer(ibdev, + ah_attr->port_num); + + err = ib_query_port(ibdev, ah_attr->port_num, &port_attr); + if (err) + return -EINVAL; + if (ah_attr->port_num < 1 || + ah_attr->port_num > ibdev->phys_port_cnt) + return -EINVAL; + if (ah_attr->static_rate != IB_RATE_PORT_CURRENT && + ib_rate_to_mbps(ah_attr->static_rate) < 0) + return -EINVAL; + if ((ah_attr->ah_flags & IB_AH_GRH) && + ah_attr->grh.sgid_index >= port_attr.gid_tbl_len) + return -EINVAL; + if (link != IB_LINK_LAYER_ETHERNET) { + if (ah_attr->dlid == 0) + return -EINVAL; + if (ah_attr->dlid >= RVT_MULTICAST_LID_BASE && + ah_attr->dlid != RVT_PERMISSIVE_LID && + !(ah_attr->ah_flags & IB_AH_GRH)) + return -EINVAL; + } + if (rdi->driver_f.check_ah(ibdev, ah_attr)) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(rvt_check_ah); /** * rvt_create_ah - create an address handle @@ -57,20 +99,68 @@ struct ib_ah *rvt_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) { - return ERR_PTR(-EOPNOTSUPP); + struct rvt_ah *ah; + struct rvt_dev_info *dev = ib_to_rvt(pd->device); + unsigned long flags; + + if (rvt_check_ah(pd->device, ah_attr)) + return ERR_PTR(-EINVAL); + + ah = kmalloc(sizeof(*ah), GFP_ATOMIC); + if (!ah) + return ERR_PTR(-ENOMEM); + + spin_lock_irqsave(&dev->n_ahs_lock, flags); + if (dev->n_ahs_allocated == dev->dparms.props.max_ah) { + spin_unlock(&dev->n_ahs_lock); + kfree(ah); + return ERR_PTR(-ENOMEM); + } + + dev->n_ahs_allocated++; + spin_unlock_irqrestore(&dev->n_ahs_lock, flags); + + ah->attr = *ah_attr; + atomic_set(&ah->refcount, 0); + + return &ah->ibah; } int rvt_destroy_ah(struct ib_ah *ibah) { - return -EOPNOTSUPP; + struct rvt_dev_info *dev = ib_to_rvt(ibah->device); + struct rvt_ah *ah = ibah_to_rvtah(ibah); + unsigned long flags; + + if (atomic_read(&ah->refcount) != 0) + return -EBUSY; + + spin_lock_irqsave(&dev->n_ahs_lock, flags); + dev->n_ahs_allocated--; + spin_unlock_irqrestore(&dev->n_ahs_lock, flags); + + kfree(ah); + + return 0; } int rvt_modify_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) { - return -EOPNOTSUPP; + struct rvt_ah *ah = ibah_to_rvtah(ibah); + + if (rvt_check_ah(ibah->device, ah_attr)) + return -EINVAL; + + ah->attr = *ah_attr; + + return 0; } int rvt_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) { - return -EOPNOTSUPP; + struct rvt_ah *ah = ibah_to_rvtah(ibah); + + *ah_attr = ah->attr; + + return 0; } diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c index e92af9c6521e..7dab0cac5937 100644 --- a/drivers/infiniband/sw/rdmavt/vt.c +++ b/drivers/infiniband/sw/rdmavt/vt.c @@ -221,7 +221,8 @@ int rvt_register_device(struct rvt_dev_info *rdi) if ((!rdi->driver_f.port_callback) || (!rdi->driver_f.get_card_name) || - (!rdi->driver_f.get_pci_dev)) { + (!rdi->driver_f.get_pci_dev) || + (!rdi->driver_f.check_ah)) { return -EINVAL; } @@ -252,6 +253,8 @@ int rvt_register_device(struct rvt_dev_info *rdi) CHECK_DRIVER_OVERRIDE(rdi, destroy_ah); CHECK_DRIVER_OVERRIDE(rdi, modify_ah); CHECK_DRIVER_OVERRIDE(rdi, query_ah); + spin_lock_init(&rdi->n_ahs_lock); + rdi->n_ahs_allocated = 0; /* Shared Receive Queue */ CHECK_DRIVER_OVERRIDE(rdi, create_srq); |