diff mbox series

[for-next] IB/hfi1: Add debugfs to control expansion ROM write protect

Message ID 20190318170137.28516.24695.stgit@scvm10.sc.intel.com (mailing list archive)
State Superseded
Headers show
Series [for-next] IB/hfi1: Add debugfs to control expansion ROM write protect | expand

Commit Message

Dennis Dalessandro March 18, 2019, 5:01 p.m. UTC
From: Josh Collier <josh.d.collier@intel.com>

Some kernels now enable CONFIG_IO_STRICT_DEVMEM
which prevents multiple handles to PCI resource0. In order
to continue to support expansion ROM updates while the
driver is loaded, the driver must now provide an interface
to control the expansion ROM write protection.

This patch adds an exprom_wp debugfs interface that
allows the hfi1_eprom user tool to disable the expansion ROM
write protection by opening the file and writing a '1'.
The write protection is released when writing a '0' or
automatically re-enabled when the handle is closed.
The current implementation will only allow one handle
to be opened at a time across all hfi1 devices.

Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Josh Collier <josh.d.collier@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
---
 drivers/infiniband/hw/hfi1/debugfs.c |   79 ++++++++++++++++++++++++++++++++++
 1 files changed, 79 insertions(+), 0 deletions(-)

Comments

Jason Gunthorpe March 27, 2019, 6:05 p.m. UTC | #1
On Mon, Mar 18, 2019 at 10:01:43AM -0700, Dennis Dalessandro wrote:
> From: Josh Collier <josh.d.collier@intel.com>
> 
> Some kernels now enable CONFIG_IO_STRICT_DEVMEM
> which prevents multiple handles to PCI resource0. In order
> to continue to support expansion ROM updates while the
> driver is loaded, the driver must now provide an interface
> to control the expansion ROM write protection.
> 
> This patch adds an exprom_wp debugfs interface that
> allows the hfi1_eprom user tool to disable the expansion ROM
> write protection by opening the file and writing a '1'.
> The write protection is released when writing a '0' or
> automatically re-enabled when the handle is closed.
> The current implementation will only allow one handle
> to be opened at a time across all hfi1 devices.
> 
> Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
> Signed-off-by: Josh Collier <josh.d.collier@intel.com>
> Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
>  drivers/infiniband/hw/hfi1/debugfs.c |   79 ++++++++++++++++++++++++++++++++++
>  1 files changed, 79 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c
> index 427ba0c..6246707 100644
> +++ b/drivers/infiniband/hw/hfi1/debugfs.c
> @@ -1080,6 +1080,82 @@ static int qsfp2_debugfs_release(struct inode *in, struct file *fp)
>  	return __qsfp_debugfs_release(in, fp, 1);
>  }
>  
> +#define EXPROM_WRITE_ENABLE BIT_ULL(14)
> +
> +static int exprom_wp_disabled;

should be bool

> +
> +static int exprom_wp_set(struct hfi1_devdata *dd, bool disable)
> +{
> +	u64 gpio_val = 0;
> +
> +	if (disable) {
> +		gpio_val = EXPROM_WRITE_ENABLE;
> +		exprom_wp_disabled = 1;
> +		dd_dev_info(dd, "Disable Expansion ROM Write Protection\n");
> +	} else {
> +		exprom_wp_disabled = 0;
> +		dd_dev_info(dd, "Enable Expansion ROM Write Protection\n");
> +	}
> +
> +	write_csr(dd, ASIC_GPIO_OUT, gpio_val);
> +	write_csr(dd, ASIC_GPIO_OE, gpio_val);
> +
> +	return 0;
> +}
> +
> +static ssize_t exprom_wp_debugfs_read(struct file *file, char __user *buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	return 0;
> +}
> +
> +static ssize_t exprom_wp_debugfs_write(struct file *file,
> +				       const char __user *buf, size_t count,
> +				       loff_t *ppos)
> +{
> +	struct hfi1_pportdata *ppd = private2ppd(file);
> +	char cdata;
> +
> +	if (count != 1)
> +		return -EINVAL;
> +	if (get_user(cdata, buf))
> +		return -EFAULT;
> +	if (cdata == '0')
> +		exprom_wp_set(ppd->dd, false);
> +	else if (cdata == '1')
> +		exprom_wp_set(ppd->dd, true);
> +	else
> +		return -EINVAL;
> +
> +	return 1;
> +}
> +
> +static atomic_t exprom_refcnt = ATOMIC_INIT(0);
> +
> +static int exprom_wp_debugfs_open(struct inode *in, struct file *fp)
> +{
> +	int ret;
> +
> +	ret = atomic_fetch_inc(&exprom_refcnt);
> +	if (ret) {
> +		atomic_dec(&exprom_refcnt);
> +		return -EBUSY;
> +	}
> +	exprom_wp_disabled = 0;

seems weird to set this here

Jason
Jason Gunthorpe March 27, 2019, 6:07 p.m. UTC | #2
On Mon, Mar 18, 2019 at 10:01:43AM -0700, Dennis Dalessandro wrote:
> From: Josh Collier <josh.d.collier@intel.com>
> 
> Some kernels now enable CONFIG_IO_STRICT_DEVMEM
> which prevents multiple handles to PCI resource0. In order
> to continue to support expansion ROM updates while the
> driver is loaded, the driver must now provide an interface
> to control the expansion ROM write protection.
> 
> This patch adds an exprom_wp debugfs interface that
> allows the hfi1_eprom user tool to disable the expansion ROM
> write protection by opening the file and writing a '1'.
> The write protection is released when writing a '0' or
> automatically re-enabled when the handle is closed.
> The current implementation will only allow one handle
> to be opened at a time across all hfi1 devices.
> 
> Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
> Signed-off-by: Josh Collier <josh.d.collier@intel.com>
> Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
>  drivers/infiniband/hw/hfi1/debugfs.c |   79 ++++++++++++++++++++++++++++++++++
>  1 files changed, 79 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c
> index 427ba0c..6246707 100644
> +++ b/drivers/infiniband/hw/hfi1/debugfs.c
> @@ -1080,6 +1080,82 @@ static int qsfp2_debugfs_release(struct inode *in, struct file *fp)
>  	return __qsfp_debugfs_release(in, fp, 1);
>  }
>  
> +#define EXPROM_WRITE_ENABLE BIT_ULL(14)
> +
> +static int exprom_wp_disabled;
> +
> +static int exprom_wp_set(struct hfi1_devdata *dd, bool disable)
> +{
> +	u64 gpio_val = 0;
> +
> +	if (disable) {
> +		gpio_val = EXPROM_WRITE_ENABLE;
> +		exprom_wp_disabled = 1;
> +		dd_dev_info(dd, "Disable Expansion ROM Write Protection\n");
> +	} else {
> +		exprom_wp_disabled = 0;
> +		dd_dev_info(dd, "Enable Expansion ROM Write Protection\n");
> +	}
> +
> +	write_csr(dd, ASIC_GPIO_OUT, gpio_val);
> +	write_csr(dd, ASIC_GPIO_OE, gpio_val);
> +
> +	return 0;
> +}
> +
> +static ssize_t exprom_wp_debugfs_read(struct file *file, char __user *buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	return 0;
> +}
> +
> +static ssize_t exprom_wp_debugfs_write(struct file *file,
> +				       const char __user *buf, size_t count,
> +				       loff_t *ppos)
> +{
> +	struct hfi1_pportdata *ppd = private2ppd(file);
> +	char cdata;
> +
> +	if (count != 1)
> +		return -EINVAL;
> +	if (get_user(cdata, buf))
> +		return -EFAULT;
> +	if (cdata == '0')
> +		exprom_wp_set(ppd->dd, false);
> +	else if (cdata == '1')
> +		exprom_wp_set(ppd->dd, true);
> +	else
> +		return -EINVAL;
> +
> +	return 1;
> +}
> +
> +static atomic_t exprom_refcnt = ATOMIC_INIT(0);
> +
> +static int exprom_wp_debugfs_open(struct inode *in, struct file *fp)
> +{
> +	int ret;
> +
> +	ret = atomic_fetch_inc(&exprom_refcnt);
> +	if (ret) {
> +		atomic_dec(&exprom_refcnt);

And this algorithm is just test and set, no need for a confusing
atomic_inc/dec

Jason
diff mbox series

Patch

diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c
index 427ba0c..6246707 100644
--- a/drivers/infiniband/hw/hfi1/debugfs.c
+++ b/drivers/infiniband/hw/hfi1/debugfs.c
@@ -1080,6 +1080,82 @@  static int qsfp2_debugfs_release(struct inode *in, struct file *fp)
 	return __qsfp_debugfs_release(in, fp, 1);
 }
 
+#define EXPROM_WRITE_ENABLE BIT_ULL(14)
+
+static int exprom_wp_disabled;
+
+static int exprom_wp_set(struct hfi1_devdata *dd, bool disable)
+{
+	u64 gpio_val = 0;
+
+	if (disable) {
+		gpio_val = EXPROM_WRITE_ENABLE;
+		exprom_wp_disabled = 1;
+		dd_dev_info(dd, "Disable Expansion ROM Write Protection\n");
+	} else {
+		exprom_wp_disabled = 0;
+		dd_dev_info(dd, "Enable Expansion ROM Write Protection\n");
+	}
+
+	write_csr(dd, ASIC_GPIO_OUT, gpio_val);
+	write_csr(dd, ASIC_GPIO_OE, gpio_val);
+
+	return 0;
+}
+
+static ssize_t exprom_wp_debugfs_read(struct file *file, char __user *buf,
+				      size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t exprom_wp_debugfs_write(struct file *file,
+				       const char __user *buf, size_t count,
+				       loff_t *ppos)
+{
+	struct hfi1_pportdata *ppd = private2ppd(file);
+	char cdata;
+
+	if (count != 1)
+		return -EINVAL;
+	if (get_user(cdata, buf))
+		return -EFAULT;
+	if (cdata == '0')
+		exprom_wp_set(ppd->dd, false);
+	else if (cdata == '1')
+		exprom_wp_set(ppd->dd, true);
+	else
+		return -EINVAL;
+
+	return 1;
+}
+
+static atomic_t exprom_refcnt = ATOMIC_INIT(0);
+
+static int exprom_wp_debugfs_open(struct inode *in, struct file *fp)
+{
+	int ret;
+
+	ret = atomic_fetch_inc(&exprom_refcnt);
+	if (ret) {
+		atomic_dec(&exprom_refcnt);
+		return -EBUSY;
+	}
+	exprom_wp_disabled = 0;
+	return 0;
+}
+
+static int exprom_wp_debugfs_release(struct inode *in, struct file *fp)
+{
+	struct hfi1_pportdata *ppd = private2ppd(fp);
+
+	if (exprom_wp_disabled)
+		exprom_wp_set(ppd->dd, false);
+	atomic_dec(&exprom_refcnt);
+
+	return 0;
+}
+
 #define DEBUGFS_OPS(nm, readroutine, writeroutine)	\
 { \
 	.name = nm, \
@@ -1119,6 +1195,9 @@  static int qsfp2_debugfs_release(struct inode *in, struct file *fp)
 		     qsfp1_debugfs_open, qsfp1_debugfs_release),
 	DEBUGFS_XOPS("qsfp2", qsfp2_debugfs_read, qsfp2_debugfs_write,
 		     qsfp2_debugfs_open, qsfp2_debugfs_release),
+	DEBUGFS_XOPS("exprom_wp", exprom_wp_debugfs_read,
+		     exprom_wp_debugfs_write, exprom_wp_debugfs_open,
+		     exprom_wp_debugfs_release),
 	DEBUGFS_OPS("asic_flags", asic_flags_read, asic_flags_write),
 	DEBUGFS_OPS("dc8051_memory", dc8051_memory_read, NULL),
 	DEBUGFS_OPS("lcb", debugfs_lcb_read, debugfs_lcb_write),