Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9c8ea3d authored by Dean Luick's avatar Dean Luick Committed by Doug Ledford
Browse files

IB/hfi1: Add ASIC flag view/clear



Different OSes using parts of the same hardware may leave
cross-device flags set.  Export a debugfs file to view and
clear these flags if needed.

Reviewed-by: default avatarMitko Haralanov <mitko.haralanov@intel.com>
Reviewed-by: default avatarEaswar Hariharan <easwar.hariharan@intel.com>
Signed-off-by: default avatarDean Luick <dean.luick@intel.com>
Signed-off-by: default avatarJubin John <jubin.john@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent ae993e7f
Loading
Loading
Loading
Loading
+125 −0
Original line number Diff line number Diff line
@@ -404,6 +404,130 @@ static ssize_t portcntrs_debugfs_read(struct file *file, char __user *buf,
	return rval;
}

static void check_dyn_flag(u64 scratch0, char *p, int size, int *used,
			   int this_hfi, int hfi, u32 flag, const char *what)
{
	u32 mask;

	mask = flag << (hfi ? CR_DYN_SHIFT : 0);
	if (scratch0 & mask) {
		*used += scnprintf(p + *used, size - *used,
				   "  0x%08x - HFI%d %s in use, %s device\n",
				   mask, hfi, what,
				   this_hfi == hfi ? "this" : "other");
	}
}

static ssize_t asic_flags_read(struct file *file, char __user *buf,
			       size_t count, loff_t *ppos)
{
	struct hfi1_pportdata *ppd;
	struct hfi1_devdata *dd;
	u64 scratch0;
	char *tmp;
	int ret = 0;
	int size;
	int used;
	int i;

	rcu_read_lock();
	ppd = private2ppd(file);
	dd = ppd->dd;
	size = PAGE_SIZE;
	used = 0;
	tmp = kmalloc(size, GFP_KERNEL);
	if (!tmp) {
		rcu_read_unlock();
		return -ENOMEM;
	}

	scratch0 = read_csr(dd, ASIC_CFG_SCRATCH);
	used += scnprintf(tmp + used, size - used,
			  "Resource flags: 0x%016llx\n", scratch0);

	/* check permanent flag */
	if (scratch0 & CR_THERM_INIT) {
		used += scnprintf(tmp + used, size - used,
				  "  0x%08x - thermal monitoring initialized\n",
				  (u32)CR_THERM_INIT);
	}

	/* check each dynamic flag on each HFI */
	for (i = 0; i < 2; i++) {
		check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i,
			       CR_SBUS, "SBus");
		check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i,
			       CR_EPROM, "EPROM");
		check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i,
			       CR_I2C1, "i2c chain 1");
		check_dyn_flag(scratch0, tmp, size, &used, dd->hfi1_id, i,
			       CR_I2C2, "i2c chain 2");
	}
	used += scnprintf(tmp + used, size - used, "Write bits to clear\n");

	ret = simple_read_from_buffer(buf, count, ppos, tmp, used);
	rcu_read_unlock();
	kfree(tmp);
	return ret;
}

static ssize_t asic_flags_write(struct file *file, const char __user *buf,
				size_t count, loff_t *ppos)
{
	struct hfi1_pportdata *ppd;
	struct hfi1_devdata *dd;
	char *buff;
	int ret;
	unsigned long long value;
	u64 scratch0;
	u64 clear;

	rcu_read_lock();
	ppd = private2ppd(file);
	dd = ppd->dd;

	buff = kmalloc(count + 1, GFP_KERNEL);
	if (!buff) {
		ret = -ENOMEM;
		goto do_return;
	}

	ret = copy_from_user(buff, buf, count);
	if (ret > 0) {
		ret = -EFAULT;
		goto do_free;
	}

	/* zero terminate and read the expected integer */
	buff[count] = 0;
	ret = kstrtoull(buff, 0, &value);
	if (ret)
		goto do_free;
	clear = value;

	/* obtain exclusive access */
	mutex_lock(&dd->asic_data->asic_resource_mutex);
	acquire_hw_mutex(dd);

	scratch0 = read_csr(dd, ASIC_CFG_SCRATCH);
	scratch0 &= ~clear;
	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);
	mutex_unlock(&dd->asic_data->asic_resource_mutex);

	/* return the number of bytes written */
	ret = count;

 do_free:
	kfree(buff);
 do_return:
	rcu_read_unlock();
	return ret;
}

/*
 * read the per-port QSFP data for ppd
 */
@@ -821,6 +945,7 @@ static const struct counter_info port_cntr_ops[] = {
		     qsfp1_debugfs_open, qsfp1_debugfs_release),
	DEBUGFS_XOPS("qsfp2", qsfp2_debugfs_read, qsfp2_debugfs_write,
		     qsfp2_debugfs_open, qsfp2_debugfs_release),
	DEBUGFS_OPS("asic_flags", asic_flags_read, asic_flags_write),
};

void hfi1_dbg_ibdev_init(struct hfi1_ibdev *ibd)