IB/hfi1: Add shared ASIC structure
authorDean Luick <dean.luick@intel.com>
Sat, 5 Mar 2016 16:49:45 +0000 (08:49 -0800)
committerDoug Ledford <dledford@redhat.com>
Thu, 17 Mar 2016 19:55:13 +0000 (15:55 -0400)
Create a shared structure to exist between devices that share the
same ASIC.

Reviewed-by: Mitko Haralanov <mitko.haralanov@intel.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@intel.com>
Signed-off-by: Dean Luick <dean.luick@intel.com>
Signed-off-by: Jubin John <jubin.john@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/staging/rdma/hfi1/chip.c
drivers/staging/rdma/hfi1/hfi.h
drivers/staging/rdma/hfi1/init.c

index 0874287dcc045a8179bf56fd6e6d588f3a6f6a6e..686cadf449b95d15f12ce50798fd869b19c74147 100644 (file)
@@ -13800,15 +13800,20 @@ void hfi1_start_cleanup(struct hfi1_devdata *dd)
        ((dev)->base_guid & ~(1ULL << GUID_HFI_INDEX_SHIFT))
 
 /*
+ * Information can be shared between the two HFIs on the same ASIC
+ * in the same OS.  This function finds the peer device and sets
+ * up a shared structure.
+ *
  * Certain chip functions need to be initialized only once per asic
  * instead of per-device. This function finds the peer device and
  * checks whether that chip initialization needs to be done by this
  * device.
  */
-static void asic_should_init(struct hfi1_devdata *dd)
+static int init_asic_data(struct hfi1_devdata *dd)
 {
        unsigned long flags;
        struct hfi1_devdata *tmp, *peer = NULL;
+       int ret = 0;
 
        spin_lock_irqsave(&hfi1_devs_lock, flags);
        /* Find our peer device */
@@ -13826,7 +13831,22 @@ static void asic_should_init(struct hfi1_devdata *dd)
         */
        if (!peer || !(peer->flags & HFI1_DO_INIT_ASIC))
                dd->flags |= HFI1_DO_INIT_ASIC;
+
+       if (peer) {
+               dd->asic_data = peer->asic_data;
+       } else {
+               dd->asic_data = kzalloc(sizeof(*dd->asic_data), GFP_KERNEL);
+               if (!dd->asic_data) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+               mutex_init(&dd->asic_data->asic_resource_mutex);
+       }
+       dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */
+
+done:
        spin_unlock_irqrestore(&hfi1_devs_lock, flags);
+       return ret;
 }
 
 /*
@@ -14076,8 +14096,10 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
        /* needs to be done before we look for the peer device */
        read_guid(dd);
 
-       /* should this device init the ASIC block? */
-       asic_should_init(dd);
+       /* set up shared ASIC data with peer device */
+       ret = init_asic_data(dd);
+       if (ret)
+               goto bail_cleanup;
 
        /* obtain chip sizes, reset chip CSRs */
        init_chip(dd);
index 92154822de5aec7270a329c802ecd1efddc46ced..e71a1c2fbfaca1ea0860b358c33dc9aaf3c7ca96 100644 (file)
@@ -805,6 +805,12 @@ struct hfi1_temp {
        u8 triggers;      /* temperature triggers */
 };
 
+/* common data between shared ASIC HFIs */
+struct hfi1_asic_data {
+       struct hfi1_devdata *dds[2];    /* back pointers */
+       struct mutex asic_resource_mutex;
+};
+
 /* device data struct now contains only "general per-device" info.
  * fields related to a physical IB port are in a hfi1_pportdata struct.
  */
@@ -880,6 +886,9 @@ struct hfi1_devdata {
        wait_queue_head_t                 sdma_unfreeze_wq;
        atomic_t                          sdma_unfreeze_count;
 
+       /* common data between shared ASIC HFIs in this OS */
+       struct hfi1_asic_data *asic_data;
+
        /* hfi1_pportdata, points to array of (physical) port-specific
         * data structs, indexed by pidx (0..n-1)
         */
index 37b3ce8377b6bd768a26db3283d38337e11230ef..260a8e19beb79f979e4b5b583cffd1202420deca 100644 (file)
@@ -974,6 +974,25 @@ void hfi1_free_ctxtdata(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
        kfree(rcd);
 }
 
+/*
+ * Release our hold on the shared asic data.  If we are the last one,
+ * free the structure.  Must be holding hfi1_devs_lock.
+ */
+static void release_asic_data(struct hfi1_devdata *dd)
+{
+       int other;
+
+       if (!dd->asic_data)
+               return;
+       dd->asic_data->dds[dd->hfi1_id] = NULL;
+       other = dd->hfi1_id ? 0 : 1;
+       if (!dd->asic_data->dds[other]) {
+               /* we are the last holder, free it */
+               kfree(dd->asic_data);
+       }
+       dd->asic_data = NULL;
+}
+
 void hfi1_free_devdata(struct hfi1_devdata *dd)
 {
        unsigned long flags;
@@ -981,6 +1000,7 @@ void hfi1_free_devdata(struct hfi1_devdata *dd)
        spin_lock_irqsave(&hfi1_devs_lock, flags);
        idr_remove(&hfi1_unit_table, dd->unit);
        list_del(&dd->list);
+       release_asic_data(dd);
        spin_unlock_irqrestore(&hfi1_devs_lock, flags);
        free_platform_config(dd);
        rcu_barrier(); /* wait for rcu callbacks to complete */