Commit a520030e authored by Himanshu Madhani's avatar Himanshu Madhani Committed by David S. Miller

qlcnic: Implement flash sysfs callback for 83xx adapter

QLogic applications use these callbacks to perform

o  NIC Partitioning (NPAR) configuration and management
o  Diagnostic tests
o  Flash access and updates
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: default avatarShahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 99eee14a
...@@ -2272,7 +2272,7 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter) ...@@ -2272,7 +2272,7 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
return 0; return 0;
} }
static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter) int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *adapter)
{ {
int ret; int ret;
u32 cmd; u32 cmd;
...@@ -2290,7 +2290,7 @@ static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter) ...@@ -2290,7 +2290,7 @@ static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
return 0; return 0;
} }
static int qlcnic_83xx_disable_flash_write_op(struct qlcnic_adapter *adapter) int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter)
{ {
int ret; int ret;
...@@ -2364,7 +2364,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter, ...@@ -2364,7 +2364,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
return -EIO; return -EIO;
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_enable_flash_write_op(adapter); ret = qlcnic_83xx_enable_flash_write(adapter);
if (ret) { if (ret) {
qlcnic_83xx_unlock_flash(adapter); qlcnic_83xx_unlock_flash(adapter);
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
...@@ -2406,7 +2406,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter, ...@@ -2406,7 +2406,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
} }
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_disable_flash_write_op(adapter); ret = qlcnic_83xx_disable_flash_write(adapter);
if (ret) { if (ret) {
qlcnic_83xx_unlock_flash(adapter); qlcnic_83xx_unlock_flash(adapter);
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
...@@ -2446,8 +2446,8 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, ...@@ -2446,8 +2446,8 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
u32 temp; u32 temp;
int ret = -EIO; int ret = -EIO;
if ((count < QLC_83XX_FLASH_BULK_WRITE_MIN) || if ((count < QLC_83XX_FLASH_WRITE_MIN) ||
(count > QLC_83XX_FLASH_BULK_WRITE_MAX)) { (count > QLC_83XX_FLASH_WRITE_MAX)) {
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
"%s: Invalid word count\n", __func__); "%s: Invalid word count\n", __func__);
return -EIO; return -EIO;
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "qlcnic_hw.h" #include "qlcnic_hw.h"
#define QLCNIC_83XX_BAR0_LENGTH 0x4000
/* Directly mapped registers */ /* Directly mapped registers */
#define QLC_83XX_CRB_WIN_BASE 0x3800 #define QLC_83XX_CRB_WIN_BASE 0x3800
#define QLC_83XX_CRB_WIN_FUNC(f) (QLC_83XX_CRB_WIN_BASE+((f)*4)) #define QLC_83XX_CRB_WIN_FUNC(f) (QLC_83XX_CRB_WIN_BASE+((f)*4))
...@@ -257,8 +259,8 @@ struct qlc_83xx_idc { ...@@ -257,8 +259,8 @@ struct qlc_83xx_idc {
#define QLC_83XX_FLASH_BULK_WRITE_CMD 0xcadcadca #define QLC_83XX_FLASH_BULK_WRITE_CMD 0xcadcadca
#define QLC_83XX_FLASH_READ_RETRY_COUNT 5000 #define QLC_83XX_FLASH_READ_RETRY_COUNT 5000
#define QLC_83XX_FLASH_STATUS_READY 0x6 #define QLC_83XX_FLASH_STATUS_READY 0x6
#define QLC_83XX_FLASH_BULK_WRITE_MIN 2 #define QLC_83XX_FLASH_WRITE_MIN 2
#define QLC_83XX_FLASH_BULK_WRITE_MAX 64 #define QLC_83XX_FLASH_WRITE_MAX 64
#define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY 1 #define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY 1
#define QLC_83XX_ERASE_MODE 1 #define QLC_83XX_ERASE_MODE 1
#define QLC_83XX_WRITE_MODE 2 #define QLC_83XX_WRITE_MODE 2
...@@ -451,4 +453,6 @@ int qlcnic_83xx_loopback_test(struct net_device *, u8); ...@@ -451,4 +453,6 @@ int qlcnic_83xx_loopback_test(struct net_device *, u8);
int qlcnic_83xx_interrupt_test(struct net_device *); int qlcnic_83xx_interrupt_test(struct net_device *);
int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state); int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state);
int qlcnic_83xx_flash_test(struct qlcnic_adapter *); int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *);
int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *);
#endif #endif
...@@ -884,6 +884,244 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, ...@@ -884,6 +884,244 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
return size; return size;
} }
static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t offset,
size_t size)
{
unsigned char *p_read_buf;
int ret, count;
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
if (!size)
return QL_STATUS_INVALID_PARAM;
if (!buf)
return QL_STATUS_INVALID_PARAM;
count = size / sizeof(u32);
if (size % sizeof(u32))
count++;
p_read_buf = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
if (!p_read_buf)
return -ENOMEM;
if (qlcnic_83xx_lock_flash(adapter) != 0) {
kfree(p_read_buf);
return -EIO;
}
ret = qlcnic_83xx_lockless_flash_read32(adapter, offset, p_read_buf,
count);
if (ret) {
qlcnic_83xx_unlock_flash(adapter);
kfree(p_read_buf);
return ret;
}
qlcnic_83xx_unlock_flash(adapter);
memcpy(buf, p_read_buf, size);
kfree(p_read_buf);
return size;
}
static int qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter,
char *buf, loff_t offset,
size_t size)
{
int i, ret, count;
unsigned char *p_cache, *p_src;
p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
if (!p_cache)
return -ENOMEM;
memcpy(p_cache, buf, size);
p_src = p_cache;
count = size / sizeof(u32);
if (qlcnic_83xx_lock_flash(adapter) != 0) {
kfree(p_cache);
return -EIO;
}
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_enable_flash_write(adapter);
if (ret) {
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
}
for (i = 0; i < count / QLC_83XX_FLASH_WRITE_MAX; i++) {
ret = qlcnic_83xx_flash_bulk_write(adapter, offset,
(u32 *)p_src,
QLC_83XX_FLASH_WRITE_MAX);
if (ret) {
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_disable_flash_write(adapter);
if (ret) {
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
}
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
p_src = p_src + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX;
offset = offset + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX;
}
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_disable_flash_write(adapter);
if (ret) {
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
}
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return 0;
}
static int qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter,
char *buf, loff_t offset, size_t size)
{
int i, ret, count;
unsigned char *p_cache, *p_src;
p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
if (!p_cache)
return -ENOMEM;
memcpy(p_cache, buf, size);
p_src = p_cache;
count = size / sizeof(u32);
if (qlcnic_83xx_lock_flash(adapter) != 0) {
kfree(p_cache);
return -EIO;
}
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_enable_flash_write(adapter);
if (ret) {
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
}
for (i = 0; i < count; i++) {
ret = qlcnic_83xx_flash_write32(adapter, offset, (u32 *)p_src);
if (ret) {
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_disable_flash_write(adapter);
if (ret) {
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
}
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
p_src = p_src + sizeof(u32);
offset = offset + sizeof(u32);
}
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
ret = qlcnic_83xx_disable_flash_write(adapter);
if (ret) {
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return -EIO;
}
}
kfree(p_cache);
qlcnic_83xx_unlock_flash(adapter);
return 0;
}
static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t offset,
size_t size)
{
int ret;
static int flash_mode;
unsigned long data;
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
if (!buf)
return QL_STATUS_INVALID_PARAM;
ret = kstrtoul(buf, 16, &data);
switch (data) {
case QLC_83XX_FLASH_SECTOR_ERASE_CMD:
flash_mode = QLC_83XX_ERASE_MODE;
ret = qlcnic_83xx_erase_flash_sector(adapter, offset);
if (ret) {
dev_err(&adapter->pdev->dev,
"%s failed at %d\n", __func__, __LINE__);
return -EIO;
}
break;
case QLC_83XX_FLASH_BULK_WRITE_CMD:
flash_mode = QLC_83XX_BULK_WRITE_MODE;
break;
case QLC_83XX_FLASH_WRITE_CMD:
flash_mode = QLC_83XX_WRITE_MODE;
break;
default:
if (flash_mode == QLC_83XX_BULK_WRITE_MODE) {
ret = qlcnic_83xx_sysfs_flash_bulk_write(adapter, buf,
offset, size);
if (ret) {
dev_err(&adapter->pdev->dev,
"%s failed at %d\n",
__func__, __LINE__);
return -EIO;
}
}
if (flash_mode == QLC_83XX_WRITE_MODE) {
ret = qlcnic_83xx_sysfs_flash_write(adapter, buf,
offset, size);
if (ret) {
dev_err(&adapter->pdev->dev,
"%s failed at %d\n", __func__,
__LINE__);
return -EIO;
}
}
}
return size;
}
static struct device_attribute dev_attr_bridged_mode = { static struct device_attribute dev_attr_bridged_mode = {
.attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
.show = qlcnic_show_bridged_mode, .show = qlcnic_show_bridged_mode,
...@@ -958,6 +1196,13 @@ static struct bin_attribute bin_attr_pm_config = { ...@@ -958,6 +1196,13 @@ static struct bin_attribute bin_attr_pm_config = {
.write = qlcnic_sysfs_write_pm_config, .write = qlcnic_sysfs_write_pm_config,
}; };
static struct bin_attribute bin_attr_flash = {
.attr = {.name = "flash", .mode = (S_IRUGO | S_IWUSR)},
.size = 0,
.read = qlcnic_83xx_sysfs_flash_read_handler,
.write = qlcnic_83xx_sysfs_flash_write_handler,
};
void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev; struct device *dev = &adapter->pdev->dev;
...@@ -1046,10 +1291,18 @@ void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter) ...@@ -1046,10 +1291,18 @@ void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter)
void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter) void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev;
qlcnic_create_diag_entries(adapter); qlcnic_create_diag_entries(adapter);
if (sysfs_create_bin_file(&dev->kobj, &bin_attr_flash))
dev_info(dev, "failed to create flash sysfs entry\n");
} }
void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter) void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev;
qlcnic_remove_diag_entries(adapter); qlcnic_remove_diag_entries(adapter);
sysfs_remove_bin_file(&dev->kobj, &bin_attr_flash);
} }
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