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

Commit 346fe763 authored by Rajesh K Borundia's avatar Rajesh K Borundia Committed by David S. Miller
Browse files

qlcnic: Add support for configuring eswitch and npars



Following changes are made:
1.Obtain capabilities of Nic partition.
2.Configure tx bandwidth of particular Nic partition.
3.Configure the eswitch for setting port mirroring, enable mac
learning, promiscous mode.

Signed-off-by: default avatarRajesh K Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: default avatarAnirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 45918e2f
Loading
Loading
Loading
Loading
+72 −5
Original line number Diff line number Diff line
@@ -959,8 +959,6 @@ struct qlcnic_adapter {
	u16 switch_mode;
	u16 max_tx_ques;
	u16 max_rx_ques;
	u16 min_tx_bw;
	u16 max_tx_bw;
	u16 max_mtu;

	u32 fw_hal_version;
@@ -984,7 +982,7 @@ struct qlcnic_adapter {

	u64 dev_rst_time;

	struct qlcnic_pci_info *npars;
	struct qlcnic_npar_info *npars;
	struct qlcnic_eswitch *eswitch;
	struct qlcnic_nic_template *nic_ops;

@@ -1042,6 +1040,18 @@ struct qlcnic_pci_info {
	u8	reserved2[106];
};

struct qlcnic_npar_info {
	u16	vlan_id;
	u8	phy_port;
	u8	type;
	u8	active;
	u8	enable_pm;
	u8	dest_npar;
	u8	host_vlan_tag;
	u8	promisc_mode;
	u8	discard_tagged;
	u8	mac_learning;
};
struct qlcnic_eswitch {
	u8	port;
	u8	active_vports;
@@ -1057,6 +1067,63 @@ struct qlcnic_eswitch {
#define QLCNIC_SWITCH_PORT_MIRRORING	BIT_4
};


/* Return codes for Error handling */
#define QL_STATUS_INVALID_PARAM	-1

#define MAX_BW			10000
#define MIN_BW			100
#define MAX_VLAN_ID		4095
#define MIN_VLAN_ID		2
#define MAX_TX_QUEUES		1
#define MAX_RX_QUEUES		4
#define DEFAULT_MAC_LEARN	1

#define IS_VALID_VLAN(vlan)	(vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID)
#define IS_VALID_BW(bw)		(bw >= MIN_BW && bw <= MAX_BW \
							&& (bw % 100) == 0)
#define IS_VALID_TX_QUEUES(que)	(que > 0 && que <= MAX_TX_QUEUES)
#define IS_VALID_RX_QUEUES(que)	(que > 0 && que <= MAX_RX_QUEUES)
#define IS_VALID_MODE(mode)	(mode == 0 || mode == 1)

struct qlcnic_pci_func_cfg {
	u16	func_type;
	u16	min_bw;
	u16	max_bw;
	u16	port_num;
	u8	pci_func;
	u8	func_state;
	u8	def_mac_addr[6];
};

struct qlcnic_npar_func_cfg {
	u32	fw_capab;
	u16	port_num;
	u16	min_bw;
	u16	max_bw;
	u16	max_tx_queues;
	u16	max_rx_queues;
	u8	pci_func;
	u8	op_mode;
};

struct qlcnic_pm_func_cfg {
	u8	pci_func;
	u8	action;
	u8	dest_npar;
	u8	reserved[5];
};

struct qlcnic_esw_func_cfg {
	u16	vlan_id;
	u8	pci_func;
	u8	host_vlan_tag;
	u8	promisc_mode;
	u8	discard_tagged;
	u8	mac_learning;
	u8	reserved;
};

int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);

@@ -1169,9 +1236,9 @@ void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
/* Management functions */
int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
int qlcnic_get_nic_info(struct qlcnic_adapter *, u8);
int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
int qlcnic_get_pci_info(struct qlcnic_adapter *);
int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
int qlcnic_reset_partition(struct qlcnic_adapter *, u8);

/*  eSwitch management functions */
+25 −65
Original line number Diff line number Diff line
@@ -611,7 +611,8 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
}

/* Get info of a NIC partition */
int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
				struct qlcnic_info *npar_info, u8 func_id)
{
	int	err;
	dma_addr_t nic_dma_t;
@@ -635,29 +636,23 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
			QLCNIC_CDRP_CMD_GET_NIC_INFO);

	if (err == QLCNIC_RCODE_SUCCESS) {
		adapter->physical_port = le16_to_cpu(nic_info->phys_port);
		adapter->switch_mode = le16_to_cpu(nic_info->switch_mode);
		adapter->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
		adapter->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
		adapter->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
		adapter->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
		adapter->max_mtu = le16_to_cpu(nic_info->max_mtu);
		adapter->capabilities = le32_to_cpu(nic_info->capabilities);
		adapter->max_mac_filters = nic_info->max_mac_filters;

		if (adapter->capabilities & BIT_6)
			adapter->flags |= QLCNIC_ESWITCH_ENABLED;
		else
			adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
		npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
		npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
		npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
		npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
		npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
		npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
		npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
		npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);

		dev_info(&adapter->pdev->dev,
			"phy port: %d switch_mode: %d,\n"
			"\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
			"\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
			adapter->physical_port, adapter->switch_mode,
			adapter->max_tx_ques, adapter->max_rx_ques,
			adapter->min_tx_bw, adapter->max_tx_bw,
			adapter->max_mtu, adapter->capabilities);
			npar_info->phys_port, npar_info->switch_mode,
			npar_info->max_tx_ques, npar_info->max_rx_ques,
			npar_info->min_tx_bw, npar_info->max_tx_bw,
			npar_info->max_mtu, npar_info->capabilities);
	} else {
		dev_err(&adapter->pdev->dev,
			"Failed to get nic info%d\n", err);
@@ -672,7 +667,6 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
{
	int err = -EIO;
	u32 func_state;
	dma_addr_t nic_dma_t;
	void *nic_info_addr;
	struct qlcnic_info *nic_info;
@@ -681,17 +675,6 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
	if (adapter->op_mode != QLCNIC_MGMT_FUNC)
		return err;

	if (qlcnic_api_lock(adapter))
		return err;

	func_state = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
	if (QLC_DEV_CHECK_ACTIVE(func_state, nic->pci_func)) {
		qlcnic_api_unlock(adapter);
		return err;
	}

	qlcnic_api_unlock(adapter);

	nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
			&nic_dma_t);
	if (!nic_info_addr)
@@ -716,7 +699,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
			adapter->fw_hal_version,
			MSD(nic_dma_t),
			LSD(nic_dma_t),
			nic_size,
			((nic->pci_func << 16) | nic_size),
			QLCNIC_CDRP_CMD_SET_NIC_INFO);

	if (err != QLCNIC_RCODE_SUCCESS) {
@@ -730,7 +713,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
}

/* Get PCI Info of a partition */
int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
				struct qlcnic_pci_info *pci_info)
{
	int err = 0, i;
	dma_addr_t pci_info_dma_t;
@@ -745,21 +729,6 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
		return -ENOMEM;
	memset(pci_info_addr, 0, pci_size);

	if (!adapter->npars)
		adapter->npars = kzalloc(pci_size, GFP_KERNEL);
	if (!adapter->npars) {
		err = -ENOMEM;
		goto err_npar;
	}

	if (!adapter->eswitch)
		adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
	if (!adapter->eswitch) {
		err = -ENOMEM;
		goto err_eswitch;
	}

	npar = (struct qlcnic_pci_info *) pci_info_addr;
	err = qlcnic_issue_cmd(adapter,
			adapter->ahw.pci_func,
@@ -770,31 +739,24 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
			QLCNIC_CDRP_CMD_GET_PCI_INFO);

	if (err == QLCNIC_RCODE_SUCCESS) {
		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++) {
			adapter->npars[i].id = le32_to_cpu(npar->id);
			adapter->npars[i].active = le32_to_cpu(npar->active);
			adapter->npars[i].type = le32_to_cpu(npar->type);
			adapter->npars[i].default_port =
		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
			pci_info->id = le32_to_cpu(npar->id);
			pci_info->active = le32_to_cpu(npar->active);
			pci_info->type = le32_to_cpu(npar->type);
			pci_info->default_port =
				le32_to_cpu(npar->default_port);
			adapter->npars[i].tx_min_bw =
			pci_info->tx_min_bw =
				le32_to_cpu(npar->tx_min_bw);
			adapter->npars[i].tx_max_bw =
			pci_info->tx_max_bw =
				le32_to_cpu(npar->tx_max_bw);
			memcpy(adapter->npars[i].mac, npar->mac, ETH_ALEN);
			memcpy(pci_info->mac, npar->mac, ETH_ALEN);
		}
	} else {
		dev_err(&adapter->pdev->dev,
			"Failed to get PCI Info%d\n", err);
		kfree(adapter->npars);
		err = -EIO;
	}
	goto err_npar;

err_eswitch:
	kfree(adapter->npars);
	adapter->npars = NULL;

err_npar:
	pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
		pci_info_dma_t);
	return err;
@@ -1012,9 +974,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
	if (err != QLCNIC_RCODE_SUCCESS) {
		dev_err(&adapter->pdev->dev,
			"Failed to configure eswitch port%d\n", eswitch->port);
		eswitch->flags |= QLCNIC_SWITCH_ENABLE;
	} else {
		eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
		dev_info(&adapter->pdev->dev,
			"Configured eSwitch for port %d\n", eswitch->port);
	}
+445 −5
Original line number Diff line number Diff line
@@ -475,6 +475,53 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
		iounmap(adapter->ahw.pci_base0);
}

static int
qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
{
	struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
	int i, ret = 0, err;
	u8 pfn;

	if (!adapter->npars)
		adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
				QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
	if (!adapter->npars)
		return -ENOMEM;

	if (!adapter->eswitch)
		adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
	if (!adapter->eswitch) {
		err = -ENOMEM;
		goto err_eswitch;
	}

	ret = qlcnic_get_pci_info(adapter, pci_info);
	if (!ret) {
		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
			pfn = pci_info[i].id;
			if (pfn > QLCNIC_MAX_PCI_FUNC)
				return QL_STATUS_INVALID_PARAM;
			adapter->npars[pfn].active = pci_info[i].active;
			adapter->npars[pfn].type = pci_info[i].type;
			adapter->npars[pfn].phy_port = pci_info[i].default_port;
			adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
		}

		for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
			adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;

		return ret;
	}

	kfree(adapter->eswitch);
	adapter->eswitch = NULL;
err_eswitch:
	kfree(adapter->npars);

	return ret;
}

static int
qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
{
@@ -494,7 +541,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)

	if (qlcnic_config_npars) {
		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
			id = adapter->npars[i].id;
			id = i;
			if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
				id == adapter->ahw.pci_func)
				continue;
@@ -519,6 +566,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
{
	void __iomem *msix_base_addr;
	void __iomem *priv_op;
	struct qlcnic_info nic_info;
	u32 func;
	u32 msix_base;
	u32 op_mode, priv_level;
@@ -533,7 +581,14 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
	func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
	adapter->ahw.pci_func = func;

	qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
	if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
		adapter->capabilities = nic_info.capabilities;

		if (adapter->capabilities & BIT_6)
			adapter->flags |= QLCNIC_ESWITCH_ENABLED;
		else
			adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
	}

	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))	{
		adapter->nic_ops = &qlcnic_ops;
@@ -552,7 +607,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
	case QLCNIC_MGMT_FUNC:
		adapter->op_mode = QLCNIC_MGMT_FUNC;
		adapter->nic_ops = &qlcnic_ops;
		qlcnic_get_pci_info(adapter);
		qlcnic_init_pci_info(adapter);
		/* Set privilege level for other functions */
		qlcnic_set_function_modes(adapter);
		dev_info(&adapter->pdev->dev,
@@ -654,7 +709,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
	int i, offset, val;
	int *ptr32;
	struct pci_dev *pdev = adapter->pdev;

	struct qlcnic_info nic_info;
	adapter->driver_mismatch = 0;

	ptr32 = (int *)&serial_num;
@@ -696,7 +751,15 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
	}

	qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
	if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
		adapter->physical_port = nic_info.phys_port;
		adapter->switch_mode = nic_info.switch_mode;
		adapter->max_tx_ques = nic_info.max_tx_ques;
		adapter->max_rx_ques = nic_info.max_rx_ques;
		adapter->capabilities = nic_info.capabilities;
		adapter->max_mac_filters = nic_info.max_mac_filters;
		adapter->max_mtu = nic_info.max_mtu;
	}

	adapter->msix_supported = !!use_msi_x;
	adapter->rss_supported = !!use_msi_x;
@@ -2822,6 +2885,364 @@ static struct bin_attribute bin_attr_mem = {
	.write = qlcnic_sysfs_write_mem,
};

int
validate_pm_config(struct qlcnic_adapter *adapter,
			struct qlcnic_pm_func_cfg *pm_cfg, int count)
{

	u8 src_pci_func, s_esw_id, d_esw_id;
	u8 dest_pci_func;
	int i;

	for (i = 0; i < count; i++) {
		src_pci_func = pm_cfg[i].pci_func;
		dest_pci_func = pm_cfg[i].dest_npar;
		if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
				|| dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
			return QL_STATUS_INVALID_PARAM;

		if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
			return QL_STATUS_INVALID_PARAM;

		if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
			return QL_STATUS_INVALID_PARAM;

		if (!IS_VALID_MODE(pm_cfg[i].action))
			return QL_STATUS_INVALID_PARAM;

		s_esw_id = adapter->npars[src_pci_func].phy_port;
		d_esw_id = adapter->npars[dest_pci_func].phy_port;

		if (s_esw_id != d_esw_id)
			return QL_STATUS_INVALID_PARAM;

	}
	return 0;

}

static ssize_t
qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_pm_func_cfg *pm_cfg;
	u32 id, action, pci_func;
	int count, rem, i, ret;

	count	= size / sizeof(struct qlcnic_pm_func_cfg);
	rem	= size % sizeof(struct qlcnic_pm_func_cfg);
	if (rem)
		return QL_STATUS_INVALID_PARAM;

	pm_cfg = (struct qlcnic_pm_func_cfg *) buf;

	ret = validate_pm_config(adapter, pm_cfg, count);
	if (ret)
		return ret;
	for (i = 0; i < count; i++) {
		pci_func = pm_cfg[i].pci_func;
		action = pm_cfg[i].action;
		id = adapter->npars[pci_func].phy_port;
		ret = qlcnic_config_port_mirroring(adapter, id,
						action, pci_func);
		if (ret)
			return ret;
	}

	for (i = 0; i < count; i++) {
		pci_func = pm_cfg[i].pci_func;
		id = adapter->npars[pci_func].phy_port;
		adapter->npars[pci_func].enable_pm = pm_cfg[i].action;
		adapter->npars[pci_func].dest_npar = id;
	}
	return size;
}

static ssize_t
qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
	int i;

	if (size != sizeof(pm_cfg))
		return QL_STATUS_INVALID_PARAM;

	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
			continue;
		pm_cfg[i].action = adapter->npars[i].enable_pm;
		pm_cfg[i].dest_npar = 0;
		pm_cfg[i].pci_func = i;
	}
	memcpy(buf, &pm_cfg, size);

	return size;
}

int
validate_esw_config(struct qlcnic_adapter *adapter,
			struct qlcnic_esw_func_cfg *esw_cfg, int count)
{
	u8 pci_func;
	int i;

	for (i = 0; i < count; i++) {
		pci_func = esw_cfg[i].pci_func;
		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
			return QL_STATUS_INVALID_PARAM;

		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
			return QL_STATUS_INVALID_PARAM;

		if (esw_cfg->host_vlan_tag == 1)
			if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
				return QL_STATUS_INVALID_PARAM;

		if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
				|| !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
				|| !IS_VALID_MODE(esw_cfg[i].mac_learning)
				|| !IS_VALID_MODE(esw_cfg[i].discard_tagged))
			return QL_STATUS_INVALID_PARAM;
	}

	return 0;
}

static ssize_t
qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_esw_func_cfg *esw_cfg;
	u8 id, discard_tagged, promsc_mode, mac_learn;
	u8 vlan_tagging, pci_func, vlan_id;
	int count, rem, i, ret;

	count	= size / sizeof(struct qlcnic_esw_func_cfg);
	rem	= size % sizeof(struct qlcnic_esw_func_cfg);
	if (rem)
		return QL_STATUS_INVALID_PARAM;

	esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
	ret = validate_esw_config(adapter, esw_cfg, count);
	if (ret)
		return ret;

	for (i = 0; i < count; i++) {
		pci_func = esw_cfg[i].pci_func;
		id = adapter->npars[pci_func].phy_port;
		vlan_tagging = esw_cfg[i].host_vlan_tag;
		promsc_mode = esw_cfg[i].promisc_mode;
		mac_learn = esw_cfg[i].mac_learning;
		vlan_id	= esw_cfg[i].vlan_id;
		discard_tagged = esw_cfg[i].discard_tagged;
		ret = qlcnic_config_switch_port(adapter, id, vlan_tagging,
						discard_tagged,
						promsc_mode,
						mac_learn,
						pci_func,
						vlan_id);
		if (ret)
			return ret;
	}

	for (i = 0; i < count; i++) {
		pci_func = esw_cfg[i].pci_func;
		adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
		adapter->npars[pci_func].mac_learning =	esw_cfg[i].mac_learning;
		adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
		adapter->npars[pci_func].discard_tagged	=
						esw_cfg[i].discard_tagged;
		adapter->npars[pci_func].host_vlan_tag =
						esw_cfg[i].host_vlan_tag;
	}

	return size;
}

static ssize_t
qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
	int i;

	if (size != sizeof(esw_cfg))
		return QL_STATUS_INVALID_PARAM;

	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
			continue;

		esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
		esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
		esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
		esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
		esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
	}
	memcpy(buf, &esw_cfg, size);

	return size;
}

int
validate_npar_config(struct qlcnic_adapter *adapter,
				struct qlcnic_npar_func_cfg *np_cfg, int count)
{
	u8 pci_func, i;

	for (i = 0; i < count; i++) {
		pci_func = np_cfg[i].pci_func;
		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
			return QL_STATUS_INVALID_PARAM;

		if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
			return QL_STATUS_INVALID_PARAM;

		if (!IS_VALID_BW(np_cfg[i].min_bw)
				|| !IS_VALID_BW(np_cfg[i].max_bw)
				|| !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
				|| !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
			return QL_STATUS_INVALID_PARAM;
	}
	return 0;
}

static ssize_t
qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_info nic_info;
	struct qlcnic_npar_func_cfg *np_cfg;
	int i, count, rem, ret;
	u8 pci_func;

	count	= size / sizeof(struct qlcnic_npar_func_cfg);
	rem	= size % sizeof(struct qlcnic_npar_func_cfg);
	if (rem)
		return QL_STATUS_INVALID_PARAM;

	np_cfg = (struct qlcnic_npar_func_cfg *) buf;
	ret = validate_npar_config(adapter, np_cfg, count);
	if (ret)
		return ret;

	for (i = 0; i < count ; i++) {
		pci_func = np_cfg[i].pci_func;
		ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
		if (ret)
			return ret;
		nic_info.pci_func = pci_func;
		nic_info.min_tx_bw = np_cfg[i].min_bw;
		nic_info.max_tx_bw = np_cfg[i].max_bw;
		ret = qlcnic_set_nic_info(adapter, &nic_info);
		if (ret)
			return ret;
	}

	return size;

}
static ssize_t
qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_info nic_info;
	struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
	int i, ret;

	if (size != sizeof(np_cfg))
		return QL_STATUS_INVALID_PARAM;

	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
			continue;
		ret = qlcnic_get_nic_info(adapter, &nic_info, i);
		if (ret)
			return ret;

		np_cfg[i].pci_func = i;
		np_cfg[i].op_mode = nic_info.op_mode;
		np_cfg[i].port_num = nic_info.phys_port;
		np_cfg[i].fw_capab = nic_info.capabilities;
		np_cfg[i].min_bw = nic_info.min_tx_bw ;
		np_cfg[i].max_bw = nic_info.max_tx_bw;
		np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
		np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
	}
	memcpy(buf, &np_cfg, size);
	return size;
}

static ssize_t
qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
	struct qlcnic_pci_info	pci_info[QLCNIC_MAX_PCI_FUNC];
	int i, ret;

	if (size != sizeof(pci_cfg))
		return QL_STATUS_INVALID_PARAM;

	ret = qlcnic_get_pci_info(adapter, pci_info);
	if (ret)
		return ret;

	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
		pci_cfg[i].pci_func = pci_info[i].id;
		pci_cfg[i].func_type = pci_info[i].type;
		pci_cfg[i].port_num = pci_info[i].default_port;
		pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
		pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
	}
	memcpy(buf, &pci_cfg, size);
	return size;

}
static struct bin_attribute bin_attr_npar_config = {
	.attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_read_npar_config,
	.write = qlcnic_sysfs_write_npar_config,
};

static struct bin_attribute bin_attr_pci_config = {
	.attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_read_pci_config,
	.write = NULL,
};

static struct bin_attribute bin_attr_esw_config = {
	.attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_read_esw_config,
	.write = qlcnic_sysfs_write_esw_config,
};

static struct bin_attribute bin_attr_pm_config = {
	.attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_read_pm_config,
	.write = qlcnic_sysfs_write_pm_config,
};

static void
qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
{
@@ -2853,6 +3274,18 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
		dev_info(dev, "failed to create crb sysfs entry\n");
	if (device_create_bin_file(dev, &bin_attr_mem))
		dev_info(dev, "failed to create mem sysfs entry\n");
	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
			adapter->op_mode != QLCNIC_MGMT_FUNC)
		return;
	if (device_create_bin_file(dev, &bin_attr_pci_config))
		dev_info(dev, "failed to create pci config sysfs entry");
	if (device_create_bin_file(dev, &bin_attr_npar_config))
		dev_info(dev, "failed to create npar config sysfs entry");
	if (device_create_bin_file(dev, &bin_attr_esw_config))
		dev_info(dev, "failed to create esw config sysfs entry");
	if (device_create_bin_file(dev, &bin_attr_pm_config))
		dev_info(dev, "failed to create pm config sysfs entry");

}


@@ -2864,6 +3297,13 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
	device_remove_file(dev, &dev_attr_diag_mode);
	device_remove_bin_file(dev, &bin_attr_crb);
	device_remove_bin_file(dev, &bin_attr_mem);
	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
			adapter->op_mode != QLCNIC_MGMT_FUNC)
		return;
	device_remove_bin_file(dev, &bin_attr_pci_config);
	device_remove_bin_file(dev, &bin_attr_npar_config);
	device_remove_bin_file(dev, &bin_attr_esw_config);
	device_remove_bin_file(dev, &bin_attr_pm_config);
}

#ifdef CONFIG_INET