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

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

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
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -2272,7 +2272,7 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
	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;
	u32 cmd;
@@ -2290,7 +2290,7 @@ static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
	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;

@@ -2364,7 +2364,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
		return -EIO;

	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) {
			qlcnic_83xx_unlock_flash(adapter);
			dev_err(&adapter->pdev->dev,
@@ -2406,7 +2406,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
	}

	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) {
			qlcnic_83xx_unlock_flash(adapter);
			dev_err(&adapter->pdev->dev,
@@ -2446,8 +2446,8 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
	u32 temp;
	int ret = -EIO;

	if ((count < QLC_83XX_FLASH_BULK_WRITE_MIN) ||
	    (count > QLC_83XX_FLASH_BULK_WRITE_MAX)) {
	if ((count < QLC_83XX_FLASH_WRITE_MIN) ||
	    (count > QLC_83XX_FLASH_WRITE_MAX)) {
		dev_err(&adapter->pdev->dev,
			"%s: Invalid word count\n", __func__);
		return -EIO;
+6 −2
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@
#include <linux/etherdevice.h>
#include "qlcnic_hw.h"

#define QLCNIC_83XX_BAR0_LENGTH 0x4000

/* Directly mapped registers */
#define QLC_83XX_CRB_WIN_BASE		0x3800
#define QLC_83XX_CRB_WIN_FUNC(f)	(QLC_83XX_CRB_WIN_BASE+((f)*4))
@@ -257,8 +259,8 @@ struct qlc_83xx_idc {
#define QLC_83XX_FLASH_BULK_WRITE_CMD		0xcadcadca
#define QLC_83XX_FLASH_READ_RETRY_COUNT	5000
#define QLC_83XX_FLASH_STATUS_READY		0x6
#define QLC_83XX_FLASH_BULK_WRITE_MIN		2
#define QLC_83XX_FLASH_BULK_WRITE_MAX		64
#define QLC_83XX_FLASH_WRITE_MIN		2
#define QLC_83XX_FLASH_WRITE_MAX		64
#define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY	1
#define QLC_83XX_ERASE_MODE			1
#define QLC_83XX_WRITE_MODE			2
@@ -451,4 +453,6 @@ int qlcnic_83xx_loopback_test(struct net_device *, u8);
int qlcnic_83xx_interrupt_test(struct net_device *);
int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state);
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
+253 −0
Original line number Diff line number Diff line
@@ -884,6 +884,244 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
	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 = {
       .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
       .show = qlcnic_show_bridged_mode,
@@ -958,6 +1196,13 @@ static struct bin_attribute bin_attr_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)
{
	struct device *dev = &adapter->pdev->dev;
@@ -1046,10 +1291,18 @@ void qlcnic_82xx_remove_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);

	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)
{
	struct device *dev = &adapter->pdev->dev;

	qlcnic_remove_diag_entries(adapter);
	sysfs_remove_bin_file(&dev->kobj, &bin_attr_flash);
}