Commit 07c5ba91 authored by Josh Collier's avatar Josh Collier Committed by Jason Gunthorpe

IB/hfi1: Add debugfs to control expansion ROM write protect

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 file handle is closed.  The
current implementation will only allow one handle to be opened at a time
across all hfi1 devices.
Reviewed-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarJosh Collier <josh.d.collier@intel.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent 57425822
...@@ -1080,6 +1080,77 @@ static int qsfp2_debugfs_release(struct inode *in, struct file *fp) ...@@ -1080,6 +1080,77 @@ static int qsfp2_debugfs_release(struct inode *in, struct file *fp)
return __qsfp_debugfs_release(in, fp, 1); return __qsfp_debugfs_release(in, fp, 1);
} }
#define EXPROM_WRITE_ENABLE BIT_ULL(14)
static bool 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 = true;
dd_dev_info(dd, "Disable Expansion ROM Write Protection\n");
} else {
exprom_wp_disabled = false;
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 unsigned long exprom_in_use;
static int exprom_wp_debugfs_open(struct inode *in, struct file *fp)
{
if (test_and_set_bit(0, &exprom_in_use))
return -EBUSY;
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);
clear_bit(0, &exprom_in_use);
return 0;
}
#define DEBUGFS_OPS(nm, readroutine, writeroutine) \ #define DEBUGFS_OPS(nm, readroutine, writeroutine) \
{ \ { \
.name = nm, \ .name = nm, \
...@@ -1119,6 +1190,9 @@ static const struct counter_info port_cntr_ops[] = { ...@@ -1119,6 +1190,9 @@ static const struct counter_info port_cntr_ops[] = {
qsfp1_debugfs_open, qsfp1_debugfs_release), qsfp1_debugfs_open, qsfp1_debugfs_release),
DEBUGFS_XOPS("qsfp2", qsfp2_debugfs_read, qsfp2_debugfs_write, DEBUGFS_XOPS("qsfp2", qsfp2_debugfs_read, qsfp2_debugfs_write,
qsfp2_debugfs_open, qsfp2_debugfs_release), 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("asic_flags", asic_flags_read, asic_flags_write),
DEBUGFS_OPS("dc8051_memory", dc8051_memory_read, NULL), DEBUGFS_OPS("dc8051_memory", dc8051_memory_read, NULL),
DEBUGFS_OPS("lcb", debugfs_lcb_read, debugfs_lcb_write), DEBUGFS_OPS("lcb", debugfs_lcb_read, debugfs_lcb_write),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment