Pull ia64-clocksource into release branch
[pandora-kernel.git] / drivers / infiniband / hw / ehca / ehca_hca.c
index b7be950..fc19ef9 100644 (file)
 
 int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
 {
-       int ret = 0;
+       int i, ret = 0;
        struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
                                              ib_device);
        struct hipz_query_hca *rblock;
 
+       static const u32 cap_mapping[] = {
+               IB_DEVICE_RESIZE_MAX_WR,      HCA_CAP_WQE_RESIZE,
+               IB_DEVICE_BAD_PKEY_CNTR,      HCA_CAP_BAD_P_KEY_CTR,
+               IB_DEVICE_BAD_QKEY_CNTR,      HCA_CAP_Q_KEY_VIOL_CTR,
+               IB_DEVICE_RAW_MULTI,          HCA_CAP_RAW_PACKET_MCAST,
+               IB_DEVICE_AUTO_PATH_MIG,      HCA_CAP_AUTO_PATH_MIG,
+               IB_DEVICE_CHANGE_PHY_PORT,    HCA_CAP_SQD_RTS_PORT_CHANGE,
+               IB_DEVICE_UD_AV_PORT_ENFORCE, HCA_CAP_AH_PORT_NR_CHECK,
+               IB_DEVICE_CURR_QP_STATE_MOD,  HCA_CAP_CUR_QP_STATE_MOD,
+               IB_DEVICE_SHUTDOWN_PORT,      HCA_CAP_SHUTDOWN_PORT,
+               IB_DEVICE_INIT_TYPE,          HCA_CAP_INIT_TYPE,
+               IB_DEVICE_PORT_ACTIVE_EVENT,  HCA_CAP_PORT_ACTIVE_EVENT,
+       };
+
        rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
        if (!rblock) {
                ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
@@ -96,6 +110,13 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
        props->max_total_mcast_qp_attach
                = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
 
+       /* translate device capabilities */
+       props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID |
+               IB_DEVICE_RC_RNR_NAK_GEN | IB_DEVICE_N_NOTIFY_CQ;
+       for (i = 0; i < ARRAY_SIZE(cap_mapping); i += 2)
+               if (rblock->hca_cap_indicators & cap_mapping[i + 1])
+                       props->device_cap_flags |= cap_mapping[i];
+
 query_device1:
        ehca_free_fw_ctrlblock(rblock);
 
@@ -106,6 +127,7 @@ int ehca_query_port(struct ib_device *ibdev,
                    u8 port, struct ib_port_attr *props)
 {
        int ret = 0;
+       u64 h_ret;
        struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
                                              ib_device);
        struct hipz_query_port *rblock;
@@ -116,7 +138,8 @@ int ehca_query_port(struct ib_device *ibdev,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_port1;
@@ -147,6 +170,7 @@ int ehca_query_port(struct ib_device *ibdev,
                break;
        }
 
+       props->port_cap_flags  = rblock->capability_mask;
        props->gid_tbl_len     = rblock->gid_tbl_len;
        props->max_msg_sz      = rblock->max_msg_sz;
        props->bad_pkey_cntr   = rblock->bad_pkey_cntr;
@@ -162,18 +186,59 @@ int ehca_query_port(struct ib_device *ibdev,
        props->active_width    = IB_WIDTH_12X;
        props->active_speed    = 0x1;
 
+       /* at the moment (logical) link state is always LINK_UP */
+       props->phys_state      = 0x5;
+
 query_port1:
        ehca_free_fw_ctrlblock(rblock);
 
        return ret;
 }
 
+int ehca_query_sma_attr(struct ehca_shca *shca,
+                       u8 port, struct ehca_sma_attr *attr)
+{
+       int ret = 0;
+       u64 h_ret;
+       struct hipz_query_port *rblock;
+
+       rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
+       if (!rblock) {
+               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+               return -ENOMEM;
+       }
+
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "Can't query port properties");
+               ret = -EINVAL;
+               goto query_sma_attr1;
+       }
+
+       memset(attr, 0, sizeof(struct ehca_sma_attr));
+
+       attr->lid    = rblock->lid;
+       attr->lmc    = rblock->lmc;
+       attr->sm_sl  = rblock->sm_sl;
+       attr->sm_lid = rblock->sm_lid;
+
+       attr->pkey_tbl_len = rblock->pkey_tbl_len;
+       memcpy(attr->pkeys, rblock->pkey_entries, sizeof(attr->pkeys));
+
+query_sma_attr1:
+       ehca_free_fw_ctrlblock(rblock);
+
+       return ret;
+}
+
 int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
 {
        int ret = 0;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+       u64 h_ret;
+       struct ehca_shca *shca;
        struct hipz_query_port *rblock;
 
+       shca = container_of(ibdev, struct ehca_shca, ib_device);
        if (index > 16) {
                ehca_err(&shca->ib_device, "Invalid index: %x.", index);
                return -EINVAL;
@@ -185,7 +250,8 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_pkey1;
@@ -203,6 +269,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
                   int index, union ib_gid *gid)
 {
        int ret = 0;
+       u64 h_ret;
        struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
                                              ib_device);
        struct hipz_query_port *rblock;
@@ -218,7 +285,8 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
                return -ENOMEM;
        }
 
-       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (h_ret != H_SUCCESS) {
                ehca_err(&shca->ib_device, "Can't query port properties");
                ret = -EINVAL;
                goto query_gid1;
@@ -233,10 +301,63 @@ query_gid1:
        return ret;
 }
 
+const u32 allowed_port_caps = (
+       IB_PORT_SM | IB_PORT_LED_INFO_SUP | IB_PORT_CM_SUP |
+       IB_PORT_SNMP_TUNNEL_SUP | IB_PORT_DEVICE_MGMT_SUP |
+       IB_PORT_VENDOR_CLASS_SUP);
+
 int ehca_modify_port(struct ib_device *ibdev,
                     u8 port, int port_modify_mask,
                     struct ib_port_modify *props)
 {
-       /* Not implemented yet */
-       return -EFAULT;
+       int ret = 0;
+       struct ehca_shca *shca;
+       struct hipz_query_port *rblock;
+       u32 cap;
+       u64 hret;
+
+       shca = container_of(ibdev, struct ehca_shca, ib_device);
+       if ((props->set_port_cap_mask | props->clr_port_cap_mask)
+           & ~allowed_port_caps) {
+               ehca_err(&shca->ib_device, "Non-changeable bits set in masks  "
+                        "set=%x  clr=%x  allowed=%x", props->set_port_cap_mask,
+                        props->clr_port_cap_mask, allowed_port_caps);
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&shca->modify_mutex))
+               return -ERESTARTSYS;
+
+       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+       if (!rblock) {
+               ehca_err(&shca->ib_device,  "Can't allocate rblock memory.");
+               ret = -ENOMEM;
+               goto modify_port1;
+       }
+
+       hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+       if (hret != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "Can't query port properties");
+               ret = -EINVAL;
+               goto modify_port2;
+       }
+
+       cap = (rblock->capability_mask | props->set_port_cap_mask)
+               & ~props->clr_port_cap_mask;
+
+       hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
+                                 cap, props->init_type, port_modify_mask);
+       if (hret != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "Modify port failed  hret=%lx",
+                        hret);
+               ret = -EINVAL;
+       }
+
+modify_port2:
+       ehca_free_fw_ctrlblock(rblock);
+
+modify_port1:
+       mutex_unlock(&shca->modify_mutex);
+
+       return ret;
 }