|
@@ -1385,6 +1385,193 @@ void release_hw_mutex(struct hfi1_devdata *dd)
|
|
write_csr(dd, ASIC_CFG_MUTEX, 0);
|
|
write_csr(dd, ASIC_CFG_MUTEX, 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* return the given resource bit(s) as a mask for the given HFI */
|
|
|
|
+static inline u64 resource_mask(u32 hfi1_id, u32 resource)
|
|
|
|
+{
|
|
|
|
+ return ((u64)resource) << (hfi1_id ? CR_DYN_SHIFT : 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void fail_mutex_acquire_message(struct hfi1_devdata *dd,
|
|
|
|
+ const char *func)
|
|
|
|
+{
|
|
|
|
+ dd_dev_err(dd,
|
|
|
|
+ "%s: hardware mutex stuck - suggest rebooting the machine\n",
|
|
|
|
+ func);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Acquire access to a chip resource.
|
|
|
|
+ *
|
|
|
|
+ * Return 0 on success, -EBUSY if resource busy, -EIO if mutex acquire failed.
|
|
|
|
+ */
|
|
|
|
+static int __acquire_chip_resource(struct hfi1_devdata *dd, u32 resource)
|
|
|
|
+{
|
|
|
|
+ u64 scratch0, all_bits, my_bit;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (resource & CR_DYN_MASK) {
|
|
|
|
+ /* a dynamic resource is in use if either HFI has set the bit */
|
|
|
|
+ all_bits = resource_mask(0, resource) |
|
|
|
|
+ resource_mask(1, resource);
|
|
|
|
+ my_bit = resource_mask(dd->hfi1_id, resource);
|
|
|
|
+ } else {
|
|
|
|
+ /* non-dynamic resources are not split between HFIs */
|
|
|
|
+ all_bits = resource;
|
|
|
|
+ my_bit = resource;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* lock against other callers within the driver wanting a resource */
|
|
|
|
+ mutex_lock(&dd->asic_data->asic_resource_mutex);
|
|
|
|
+
|
|
|
|
+ ret = acquire_hw_mutex(dd);
|
|
|
|
+ if (ret) {
|
|
|
|
+ fail_mutex_acquire_message(dd, __func__);
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ scratch0 = read_csr(dd, ASIC_CFG_SCRATCH);
|
|
|
|
+ if (scratch0 & all_bits) {
|
|
|
|
+ ret = -EBUSY;
|
|
|
|
+ } else {
|
|
|
|
+ write_csr(dd, ASIC_CFG_SCRATCH, scratch0 | my_bit);
|
|
|
|
+ /* force write to be visible to other HFI on another OS */
|
|
|
|
+ (void)read_csr(dd, ASIC_CFG_SCRATCH);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ release_hw_mutex(dd);
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ mutex_unlock(&dd->asic_data->asic_resource_mutex);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Acquire access to a chip resource, wait up to mswait milliseconds for
|
|
|
|
+ * the resource to become available.
|
|
|
|
+ *
|
|
|
|
+ * Return 0 on success, -EBUSY if busy (even after wait), -EIO if mutex
|
|
|
|
+ * acquire failed.
|
|
|
|
+ */
|
|
|
|
+int acquire_chip_resource(struct hfi1_devdata *dd, u32 resource, u32 mswait)
|
|
|
|
+{
|
|
|
|
+ unsigned long timeout;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ timeout = jiffies + msecs_to_jiffies(mswait);
|
|
|
|
+ while (1) {
|
|
|
|
+ ret = __acquire_chip_resource(dd, resource);
|
|
|
|
+ if (ret != -EBUSY)
|
|
|
|
+ return ret;
|
|
|
|
+ /* resource is busy, check our timeout */
|
|
|
|
+ if (time_after_eq(jiffies, timeout))
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ usleep_range(80, 120); /* arbitrary delay */
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Release access to a chip resource
|
|
|
|
+ */
|
|
|
|
+void release_chip_resource(struct hfi1_devdata *dd, u32 resource)
|
|
|
|
+{
|
|
|
|
+ u64 scratch0, bit;
|
|
|
|
+
|
|
|
|
+ /* only dynamic resources should ever be cleared */
|
|
|
|
+ if (!(resource & CR_DYN_MASK)) {
|
|
|
|
+ dd_dev_err(dd, "%s: invalid resource 0x%x\n", __func__,
|
|
|
|
+ resource);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ bit = resource_mask(dd->hfi1_id, resource);
|
|
|
|
+
|
|
|
|
+ /* lock against other callers within the driver wanting a resource */
|
|
|
|
+ mutex_lock(&dd->asic_data->asic_resource_mutex);
|
|
|
|
+
|
|
|
|
+ if (acquire_hw_mutex(dd)) {
|
|
|
|
+ fail_mutex_acquire_message(dd, __func__);
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ scratch0 = read_csr(dd, ASIC_CFG_SCRATCH);
|
|
|
|
+ if ((scratch0 & bit) != 0) {
|
|
|
|
+ scratch0 &= ~bit;
|
|
|
|
+ write_csr(dd, ASIC_CFG_SCRATCH, scratch0);
|
|
|
|
+ /* force write to be visible to other HFI on another OS */
|
|
|
|
+ (void)read_csr(dd, ASIC_CFG_SCRATCH);
|
|
|
|
+ } else {
|
|
|
|
+ dd_dev_warn(dd, "%s: id %d, resource 0x%x: bit not set\n",
|
|
|
|
+ __func__, dd->hfi1_id, resource);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ release_hw_mutex(dd);
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ mutex_unlock(&dd->asic_data->asic_resource_mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Return true if resource is set, false otherwise. Print a warning
|
|
|
|
+ * if not set and a function is supplied.
|
|
|
|
+ */
|
|
|
|
+bool check_chip_resource(struct hfi1_devdata *dd, u32 resource,
|
|
|
|
+ const char *func)
|
|
|
|
+{
|
|
|
|
+ u64 scratch0, bit;
|
|
|
|
+
|
|
|
|
+ if (resource & CR_DYN_MASK)
|
|
|
|
+ bit = resource_mask(dd->hfi1_id, resource);
|
|
|
|
+ else
|
|
|
|
+ bit = resource;
|
|
|
|
+
|
|
|
|
+ scratch0 = read_csr(dd, ASIC_CFG_SCRATCH);
|
|
|
|
+ if ((scratch0 & bit) == 0) {
|
|
|
|
+ if (func)
|
|
|
|
+ dd_dev_warn(dd,
|
|
|
|
+ "%s: id %d, resource 0x%x, not acquired!\n",
|
|
|
|
+ func, dd->hfi1_id, resource);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void clear_chip_resources(struct hfi1_devdata *dd, const char *func)
|
|
|
|
+{
|
|
|
|
+ u64 scratch0;
|
|
|
|
+
|
|
|
|
+ /* lock against other callers within the driver wanting a resource */
|
|
|
|
+ mutex_lock(&dd->asic_data->asic_resource_mutex);
|
|
|
|
+
|
|
|
|
+ if (acquire_hw_mutex(dd)) {
|
|
|
|
+ fail_mutex_acquire_message(dd, func);
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* clear all dynamic access bits for this HFI */
|
|
|
|
+ scratch0 = read_csr(dd, ASIC_CFG_SCRATCH);
|
|
|
|
+ scratch0 &= ~resource_mask(dd->hfi1_id, CR_DYN_MASK);
|
|
|
|
+ write_csr(dd, ASIC_CFG_SCRATCH, scratch0);
|
|
|
|
+ /* force write to be visible to other HFI on another OS */
|
|
|
|
+ (void)read_csr(dd, ASIC_CFG_SCRATCH);
|
|
|
|
+
|
|
|
|
+ release_hw_mutex(dd);
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ mutex_unlock(&dd->asic_data->asic_resource_mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void init_chip_resources(struct hfi1_devdata *dd)
|
|
|
|
+{
|
|
|
|
+ /* clear any holds left by us */
|
|
|
|
+ clear_chip_resources(dd, __func__);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void finish_chip_resources(struct hfi1_devdata *dd)
|
|
|
|
+{
|
|
|
|
+ /* clear any holds left by us */
|
|
|
|
+ clear_chip_resources(dd, __func__);
|
|
|
|
+}
|
|
|
|
+
|
|
void set_sbus_fast_mode(struct hfi1_devdata *dd)
|
|
void set_sbus_fast_mode(struct hfi1_devdata *dd)
|
|
{
|
|
{
|
|
write_csr(dd, ASIC_CFG_SBUS_EXECUTE,
|
|
write_csr(dd, ASIC_CFG_SBUS_EXECUTE,
|