qlcnic_sysfs.c 27.3 KB
Newer Older
1 2 3 4 5 6 7
/*
 * QLogic qlcnic NIC Driver
 * Copyright (c) 2009-2013 QLogic Corporation
 *
 * See LICENSE.qlcnic for copyright and licensing details.
 */

8 9 10 11 12
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>

#include "qlcnic.h"
S
Sony Chacko 已提交
13
#include "qlcnic_hw.h"
14 15 16 17 18 19 20 21 22 23

#include <linux/swab.h>
#include <linux/dma-mapping.h>
#include <net/ip.h>
#include <linux/ipv6.h>
#include <linux/inetdevice.h>
#include <linux/sysfs.h>
#include <linux/aer.h>
#include <linux/log2.h>

S
Sony Chacko 已提交
24 25
#define QLC_STATUS_UNSUPPORTED_CMD	-2

26 27 28 29 30 31 32 33 34 35
int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
{
	return -EOPNOTSUPP;
}

int qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
{
	return -EOPNOTSUPP;
}

36 37 38
static ssize_t qlcnic_store_bridged_mode(struct device *dev,
					 struct device_attribute *attr,
					 const char *buf, size_t len)
39 40 41 42 43
{
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	unsigned long new;
	int ret = -EINVAL;

44
	if (!(adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG))
45 46 47 48 49 50 51 52
		goto err_out;

	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
		goto err_out;

	if (strict_strtoul(buf, 2, &new))
		goto err_out;

S
Sony Chacko 已提交
53
	if (!qlcnic_config_bridged_mode(adapter, !!new))
54 55 56 57 58 59
		ret = len;

err_out:
	return ret;
}

60 61 62
static ssize_t qlcnic_show_bridged_mode(struct device *dev,
					struct device_attribute *attr,
					char *buf)
63 64 65 66
{
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	int bridged_mode = 0;

67
	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG)
68 69 70 71 72
		bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);

	return sprintf(buf, "%d\n", bridged_mode);
}

73 74 75
static ssize_t qlcnic_store_diag_mode(struct device *dev,
				      struct device_attribute *attr,
				      const char *buf, size_t len)
76 77 78 79 80 81 82 83 84 85 86 87 88
{
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	unsigned long new;

	if (strict_strtoul(buf, 2, &new))
		return -EINVAL;

	if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
		adapter->flags ^= QLCNIC_DIAG_ENABLED;

	return len;
}

89 90
static ssize_t qlcnic_show_diag_mode(struct device *dev,
				     struct device_attribute *attr, char *buf)
91 92
{
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
S
Sony Chacko 已提交
93
	return sprintf(buf, "%d\n", !!(adapter->flags & QLCNIC_DIAG_ENABLED));
94 95
}

96 97
static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon,
				  u8 *state, u8 *rate)
98 99 100 101 102 103 104 105 106
{
	*rate = LSB(beacon);
	*state = MSB(beacon);

	QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state);

	if (!*state) {
		*rate = __QLCNIC_MAX_LED_RATE;
		return 0;
107
	} else if (*state > __QLCNIC_MAX_LED_STATE) {
108
		return -EINVAL;
109
	}
110 111 112 113 114 115 116

	if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
		return -EINVAL;

	return 0;
}

117 118 119
static ssize_t qlcnic_store_beacon(struct device *dev,
				   struct device_attribute *attr,
				   const char *buf, size_t len)
120 121
{
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
S
Sony Chacko 已提交
122 123
	struct qlcnic_hardware_context *ahw = adapter->ahw;
	int err, max_sds_rings = adapter->max_sds_rings;
124 125
	u16 beacon;
	u8 b_state, b_rate;
S
Sony Chacko 已提交
126
	unsigned long h_beacon;
127

128
	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
129 130
		dev_warn(dev,
			 "LED test not supported in non privileged mode\n");
131 132 133
		return -EOPNOTSUPP;
	}

S
Sony Chacko 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	if (qlcnic_83xx_check(adapter) &&
	    !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
		if (kstrtoul(buf, 2, &h_beacon))
			return -EINVAL;

		if (ahw->beacon_state == h_beacon)
			return len;

		rtnl_lock();
		if (!ahw->beacon_state) {
			if (test_and_set_bit(__QLCNIC_LED_ENABLE,
					     &adapter->state)) {
				rtnl_unlock();
				return -EBUSY;
			}
		}
		if (h_beacon) {
			err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
			if (err)
				goto beacon_err;
		} else {
			err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
			if (err)
				goto beacon_err;
		}
		/* set the current beacon state */
		ahw->beacon_state = h_beacon;
beacon_err:
		if (!ahw->beacon_state)
			clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);

		rtnl_unlock();
		return len;
	}

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	if (len != sizeof(u16))
		return QL_STATUS_INVALID_PARAM;

	memcpy(&beacon, buf, sizeof(u16));
	err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
	if (err)
		return err;

	if (adapter->ahw->beacon_state == b_state)
		return len;

	rtnl_lock();

	if (!adapter->ahw->beacon_state)
		if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
			rtnl_unlock();
			return -EBUSY;
		}

	if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
		err = -EIO;
		goto out;
	}

	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
		err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
		if (err)
			goto out;
		set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
	}

	err = qlcnic_config_led(adapter, b_state, b_rate);
S
Sony Chacko 已提交
201
	if (!err)
202
		err = len;
S
Sony Chacko 已提交
203 204
	else
		ahw->beacon_state = b_state;
205 206 207 208 209 210 211 212 213 214 215 216

	if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
		qlcnic_diag_free_res(adapter->netdev, max_sds_rings);

 out:
	if (!adapter->ahw->beacon_state)
		clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
	rtnl_unlock();

	return err;
}

217 218
static ssize_t qlcnic_show_beacon(struct device *dev,
				  struct device_attribute *attr, char *buf)
219 220 221 222 223 224
{
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);

	return sprintf(buf, "%d\n", adapter->ahw->beacon_state);
}

225 226
static int qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
				     loff_t offset, size_t size)
227 228 229 230 231 232 233 234
{
	size_t crb_size = 4;

	if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
		return -EIO;

	if (offset < QLCNIC_PCI_CRBSPACE) {
		if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
235
				  QLCNIC_PCI_CAMQM_END))
236 237 238 239 240 241 242 243 244 245 246
			crb_size = 8;
		else
			return -EINVAL;
	}

	if ((size != crb_size) || (offset & (crb_size-1)))
		return  -EINVAL;

	return 0;
}

247 248 249
static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
				     struct bin_attribute *attr, char *buf,
				     loff_t offset, size_t size)
250 251 252 253 254 255 256 257
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	int ret;

	ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
	if (ret != 0)
		return ret;
S
Sony Chacko 已提交
258
	qlcnic_read_crb(adapter, buf, offset, size);
259 260 261 262

	return size;
}

263 264 265
static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
				      struct bin_attribute *attr, char *buf,
				      loff_t offset, size_t size)
266 267 268 269 270 271 272 273 274
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	int ret;

	ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
	if (ret != 0)
		return ret;

S
Sony Chacko 已提交
275
	qlcnic_write_crb(adapter, buf, offset, size);
276 277 278
	return size;
}

279 280
static int qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
				     loff_t offset, size_t size)
281 282 283 284 285 286 287 288 289 290
{
	if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
		return -EIO;

	if ((size != 8) || (offset & 0x7))
		return  -EIO;

	return 0;
}

291 292 293
static ssize_t qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
				     struct bin_attribute *attr, char *buf,
				     loff_t offset, size_t size)
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	u64 data;
	int ret;

	ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
	if (ret != 0)
		return ret;

	if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
		return -EIO;

	memcpy(buf, &data, size);

	return size;
}

312 313 314
static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
				      struct bin_attribute *attr, char *buf,
				      loff_t offset, size_t size)
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	u64 data;
	int ret;

	ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
	if (ret != 0)
		return ret;

	memcpy(&data, buf, size);

	if (qlcnic_pci_mem_write_2M(adapter, offset, data))
		return -EIO;

	return size;
}

S
Sony Chacko 已提交
333 334 335 336 337 338 339 340 341 342 343
static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
{
	int i;
	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
		if (adapter->npars[i].pci_func == pci_func)
			return i;
	}

	return -1;
}

344 345
static int validate_pm_config(struct qlcnic_adapter *adapter,
			      struct qlcnic_pm_func_cfg *pm_cfg, int count)
346
{
S
Sony Chacko 已提交
347 348 349
	u8 src_pci_func, s_esw_id, d_esw_id;
	u8 dest_pci_func;
	int i, src_index, dest_index;
350 351 352 353

	for (i = 0; i < count; i++) {
		src_pci_func = pm_cfg[i].pci_func;
		dest_pci_func = pm_cfg[i].dest_npar;
S
Sony Chacko 已提交
354
		src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func);
355

S
Sony Chacko 已提交
356
		if (src_index < 0)
357 358
			return QL_STATUS_INVALID_PARAM;

S
Sony Chacko 已提交
359 360
		dest_index = qlcnic_is_valid_nic_func(adapter, dest_pci_func);
		if (dest_index < 0)
361 362
			return QL_STATUS_INVALID_PARAM;

S
Sony Chacko 已提交
363 364
		s_esw_id = adapter->npars[src_index].phy_port;
		d_esw_id = adapter->npars[dest_index].phy_port;
365 366 367 368 369

		if (s_esw_id != d_esw_id)
			return QL_STATUS_INVALID_PARAM;
	}

S
Sony Chacko 已提交
370
	return 0;
371 372
}

373 374 375 376 377
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)
378 379 380 381 382
{
	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;
S
Sony Chacko 已提交
383
	int count, rem, i, ret, index;
384 385 386 387 388 389

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

390
	pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
391
	ret = validate_pm_config(adapter, pm_cfg, count);
S
Sony Chacko 已提交
392

393 394 395 396 397
	if (ret)
		return ret;
	for (i = 0; i < count; i++) {
		pci_func = pm_cfg[i].pci_func;
		action = !!pm_cfg[i].action;
S
Sony Chacko 已提交
398 399 400 401 402 403 404
		index = qlcnic_is_valid_nic_func(adapter, pci_func);
		if (index < 0)
			return QL_STATUS_INVALID_PARAM;

		id = adapter->npars[index].phy_port;
		ret = qlcnic_config_port_mirroring(adapter, id,
						   action, pci_func);
405 406 407 408 409 410
		if (ret)
			return ret;
	}

	for (i = 0; i < count; i++) {
		pci_func = pm_cfg[i].pci_func;
S
Sony Chacko 已提交
411 412 413 414
		index = qlcnic_is_valid_nic_func(adapter, pci_func);
		id = adapter->npars[index].phy_port;
		adapter->npars[index].enable_pm = !!pm_cfg[i].action;
		adapter->npars[index].dest_npar = id;
415
	}
S
Sony Chacko 已提交
416

417 418 419
	return size;
}

420 421 422 423 424
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)
425 426 427 428 429
{
	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;
S
Sony Chacko 已提交
430
	u8 pci_func;
431 432 433 434

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

S
Sony Chacko 已提交
435 436 437 438 439 440 441 442
	memset(&pm_cfg, 0,
	       sizeof(struct qlcnic_pm_func_cfg) * QLCNIC_MAX_PCI_FUNC);

	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
		pci_func = adapter->npars[i].pci_func;
		pm_cfg[pci_func].action = adapter->npars[i].enable_pm;
		pm_cfg[pci_func].dest_npar = 0;
		pm_cfg[pci_func].pci_func = i;
443 444 445 446 447 448
	}
	memcpy(buf, &pm_cfg, size);

	return size;
}

449 450
static int validate_esw_config(struct qlcnic_adapter *adapter,
			       struct qlcnic_esw_func_cfg *esw_cfg, int count)
451 452 453
{
	u32 op_mode;
	u8 pci_func;
S
Sony Chacko 已提交
454
	int i, ret;
455

S
Sony Chacko 已提交
456 457 458 459
	if (qlcnic_82xx_check(adapter))
		op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
	else
		op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
460 461 462 463 464 465

	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;

S
Sony Chacko 已提交
466 467
		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
			if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
468 469 470 471
				return QL_STATUS_INVALID_PARAM;

		switch (esw_cfg[i].op_mode) {
		case QLCNIC_PORT_DEFAULTS:
S
Sony Chacko 已提交
472 473 474 475 476 477 478 479 480
			if (qlcnic_82xx_check(adapter)) {
				ret = QLC_DEV_GET_DRV(op_mode, pci_func);
			} else {
				ret = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
								  pci_func);
				esw_cfg[i].offload_flags = 0;
			}

			if (ret != QLCNIC_NON_PRIV_FUNC) {
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
				if (esw_cfg[i].mac_anti_spoof != 0)
					return QL_STATUS_INVALID_PARAM;
				if (esw_cfg[i].mac_override != 1)
					return QL_STATUS_INVALID_PARAM;
				if (esw_cfg[i].promisc_mode != 1)
					return QL_STATUS_INVALID_PARAM;
			}
			break;
		case QLCNIC_ADD_VLAN:
			if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
				return QL_STATUS_INVALID_PARAM;
			if (!esw_cfg[i].op_type)
				return QL_STATUS_INVALID_PARAM;
			break;
		case QLCNIC_DEL_VLAN:
			if (!esw_cfg[i].op_type)
				return QL_STATUS_INVALID_PARAM;
			break;
		default:
			return QL_STATUS_INVALID_PARAM;
		}
	}
S
Sony Chacko 已提交
503

504 505 506
	return 0;
}

507 508 509 510 511
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)
512 513 514 515 516 517
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_esw_func_cfg *esw_cfg;
	struct qlcnic_npar_info *npar;
	int count, rem, i, ret;
S
Sony Chacko 已提交
518 519
	int index;
	u8 op_mode = 0, pci_func;
520 521 522 523 524 525

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

526
	esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
527 528 529 530 531
	ret = validate_esw_config(adapter, esw_cfg, count);
	if (ret)
		return ret;

	for (i = 0; i < count; i++) {
S
Sony Chacko 已提交
532
		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
			if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
				return QL_STATUS_INVALID_PARAM;

		if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
			continue;

		op_mode = esw_cfg[i].op_mode;
		qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
		esw_cfg[i].op_mode = op_mode;
		esw_cfg[i].pci_func = adapter->ahw->pci_func;

		switch (esw_cfg[i].op_mode) {
		case QLCNIC_PORT_DEFAULTS:
			qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
			break;
		case QLCNIC_ADD_VLAN:
			qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
			break;
		case QLCNIC_DEL_VLAN:
			esw_cfg[i].vlan_id = 0;
			qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
			break;
		}
	}

558
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
559 560 561 562
		goto out;

	for (i = 0; i < count; i++) {
		pci_func = esw_cfg[i].pci_func;
S
Sony Chacko 已提交
563 564
		index = qlcnic_is_valid_nic_func(adapter, pci_func);
		npar = &adapter->npars[index];
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
		switch (esw_cfg[i].op_mode) {
		case QLCNIC_PORT_DEFAULTS:
			npar->promisc_mode = esw_cfg[i].promisc_mode;
			npar->mac_override = esw_cfg[i].mac_override;
			npar->offload_flags = esw_cfg[i].offload_flags;
			npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
			npar->discard_tagged = esw_cfg[i].discard_tagged;
			break;
		case QLCNIC_ADD_VLAN:
			npar->pvid = esw_cfg[i].vlan_id;
			break;
		case QLCNIC_DEL_VLAN:
			npar->pvid = 0;
			break;
		}
	}
out:
	return size;
}

585 586 587 588 589
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)
590 591 592 593
{
	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];
S
Sony Chacko 已提交
594
	u8 i, pci_func;
595 596 597 598

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

S
Sony Chacko 已提交
599 600 601 602 603 604 605
	memset(&esw_cfg, 0,
	       sizeof(struct qlcnic_esw_func_cfg) * QLCNIC_MAX_PCI_FUNC);

	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
		pci_func = adapter->npars[i].pci_func;
		esw_cfg[pci_func].pci_func = pci_func;
		if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
606 607
			return QL_STATUS_INVALID_PARAM;
	}
S
Sony Chacko 已提交
608

609 610 611 612 613
	memcpy(buf, &esw_cfg, size);

	return size;
}

614 615 616
static int validate_npar_config(struct qlcnic_adapter *adapter,
				struct qlcnic_npar_func_cfg *np_cfg,
				int count)
617 618 619 620 621
{
	u8 pci_func, i;

	for (i = 0; i < count; i++) {
		pci_func = np_cfg[i].pci_func;
S
Sony Chacko 已提交
622
		if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
623 624 625 626 627 628 629 630 631
			return QL_STATUS_INVALID_PARAM;

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

632 633 634 635 636
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)
637 638 639 640 641
{
	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;
S
Sony Chacko 已提交
642
	int i, count, rem, ret, index;
643 644 645 646 647 648 649
	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;

650
	np_cfg = (struct qlcnic_npar_func_cfg *)buf;
651 652 653 654
	ret = validate_npar_config(adapter, np_cfg, count);
	if (ret)
		return ret;

S
Sony Chacko 已提交
655
	for (i = 0; i < count; i++) {
656
		pci_func = np_cfg[i].pci_func;
S
Sony Chacko 已提交
657 658

		memset(&nic_info, 0, sizeof(struct qlcnic_info));
659 660 661 662 663 664 665 666 667
		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;
S
Sony Chacko 已提交
668 669 670
		index = qlcnic_is_valid_nic_func(adapter, pci_func);
		adapter->npars[index].min_bw = nic_info.min_tx_bw;
		adapter->npars[index].max_bw = nic_info.max_tx_bw;
671 672 673 674
	}

	return size;
}
675 676 677 678 679 680

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)
681 682 683 684 685 686 687 688 689 690
{
	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;

S
Sony Chacko 已提交
691 692 693 694
	memset(&nic_info, 0, sizeof(struct qlcnic_info));
	memset(&np_cfg, 0,
	       sizeof(struct qlcnic_npar_func_cfg) * QLCNIC_MAX_PCI_FUNC);

695
	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
S
Sony Chacko 已提交
696
		if (qlcnic_is_valid_nic_func(adapter, i) < 0)
697 698 699 700 701 702 703 704 705
			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 = (u8)nic_info.op_mode;
		np_cfg[i].port_num = nic_info.phys_port;
		np_cfg[i].fw_capab = nic_info.capabilities;
706
		np_cfg[i].min_bw = nic_info.min_tx_bw;
707 708 709 710
		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;
	}
S
Sony Chacko 已提交
711

712 713 714 715
	memcpy(buf, &np_cfg, size);
	return size;
}

716 717 718 719 720
static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
					   struct kobject *kobj,
					   struct bin_attribute *attr,
					   char *buf, loff_t offset,
					   size_t size)
721 722 723 724 725 726
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_esw_statistics port_stats;
	int ret;

S
Sony Chacko 已提交
727 728 729
	if (qlcnic_83xx_check(adapter))
		return QLC_STATUS_UNSUPPORTED_CMD;

730 731 732 733 734 735 736 737
	if (size != sizeof(struct qlcnic_esw_statistics))
		return QL_STATUS_INVALID_PARAM;

	if (offset >= QLCNIC_MAX_PCI_FUNC)
		return QL_STATUS_INVALID_PARAM;

	memset(&port_stats, 0, size);
	ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
738
				    &port_stats.rx);
739 740 741 742
	if (ret)
		return ret;

	ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
743
				    &port_stats.tx);
744 745 746 747 748 749 750
	if (ret)
		return ret;

	memcpy(buf, &port_stats, size);
	return size;
}

751 752 753 754 755
static ssize_t qlcnic_sysfs_get_esw_stats(struct file *file,
					  struct kobject *kobj,
					  struct bin_attribute *attr,
					  char *buf, loff_t offset,
					  size_t size)
756 757 758 759 760 761
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	struct qlcnic_esw_statistics esw_stats;
	int ret;

S
Sony Chacko 已提交
762 763 764
	if (qlcnic_83xx_check(adapter))
		return QLC_STATUS_UNSUPPORTED_CMD;

765 766 767 768 769 770 771 772
	if (size != sizeof(struct qlcnic_esw_statistics))
		return QL_STATUS_INVALID_PARAM;

	if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
		return QL_STATUS_INVALID_PARAM;

	memset(&esw_stats, 0, size);
	ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
773
				       &esw_stats.rx);
774 775 776 777
	if (ret)
		return ret;

	ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
778
				       &esw_stats.tx);
779 780 781 782 783 784 785
	if (ret)
		return ret;

	memcpy(buf, &esw_stats, size);
	return size;
}

786 787 788 789 790
static ssize_t qlcnic_sysfs_clear_esw_stats(struct file *file,
					    struct kobject *kobj,
					    struct bin_attribute *attr,
					    char *buf, loff_t offset,
					    size_t size)
791 792 793 794 795
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	int ret;

S
Sony Chacko 已提交
796 797 798
	if (qlcnic_83xx_check(adapter))
		return QLC_STATUS_UNSUPPORTED_CMD;

799 800 801 802
	if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
		return QL_STATUS_INVALID_PARAM;

	ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
803
				     QLCNIC_QUERY_RX_COUNTER);
804 805 806 807
	if (ret)
		return ret;

	ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
808
				     QLCNIC_QUERY_TX_COUNTER);
809 810 811 812 813 814
	if (ret)
		return ret;

	return size;
}

815 816 817 818 819
static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
					     struct kobject *kobj,
					     struct bin_attribute *attr,
					     char *buf, loff_t offset,
					     size_t size)
820
{
S
Sony Chacko 已提交
821

822 823 824 825
	struct device *dev = container_of(kobj, struct device, kobj);
	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
	int ret;

S
Sony Chacko 已提交
826 827 828
	if (qlcnic_83xx_check(adapter))
		return QLC_STATUS_UNSUPPORTED_CMD;

829 830 831 832
	if (offset >= QLCNIC_MAX_PCI_FUNC)
		return QL_STATUS_INVALID_PARAM;

	ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
833
				     QLCNIC_QUERY_RX_COUNTER);
834 835 836 837
	if (ret)
		return ret;

	ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
838
				     QLCNIC_QUERY_TX_COUNTER);
839 840 841 842 843 844
	if (ret)
		return ret;

	return size;
}

845 846 847 848 849
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)
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
{
	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;
	int i, ret;

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

	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
	if (!pci_info)
		return -ENOMEM;

	ret = qlcnic_get_pci_info(adapter, pci_info);
	if (ret) {
		kfree(pci_info);
		return ret;
	}

S
Sony Chacko 已提交
870 871 872 873
	memset(&pci_cfg, 0,
	       sizeof(struct qlcnic_pci_func_cfg) * QLCNIC_MAX_PCI_FUNC);

	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
874 875 876 877 878 879 880
		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);
	}
S
Sony Chacko 已提交
881

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
	memcpy(buf, &pci_cfg, size);
	kfree(pci_info);
	return size;
}

static struct device_attribute dev_attr_bridged_mode = {
       .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
       .show = qlcnic_show_bridged_mode,
       .store = qlcnic_store_bridged_mode,
};

static struct device_attribute dev_attr_diag_mode = {
	.attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
	.show = qlcnic_show_diag_mode,
	.store = qlcnic_store_diag_mode,
};

static struct device_attribute dev_attr_beacon = {
	.attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)},
	.show = qlcnic_show_beacon,
	.store = qlcnic_store_beacon,
};

static struct bin_attribute bin_attr_crb = {
	.attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_read_crb,
	.write = qlcnic_sysfs_write_crb,
};

static struct bin_attribute bin_attr_mem = {
	.attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_read_mem,
	.write = qlcnic_sysfs_write_mem,
};

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_port_stats = {
	.attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_get_port_stats,
	.write = qlcnic_sysfs_clear_port_stats,
};

static struct bin_attribute bin_attr_esw_stats = {
	.attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
	.size = 0,
	.read = qlcnic_sysfs_get_esw_stats,
	.write = qlcnic_sysfs_clear_esw_stats,
};

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,
};

void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;

965
	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG)
966 967
		if (device_create_file(dev, &dev_attr_bridged_mode))
			dev_warn(dev,
968
				 "failed to create bridged_mode sysfs entry\n");
969 970 971 972 973 974
}

void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;

975
	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG)
976 977 978 979 980 981 982 983 984 985
		device_remove_file(dev, &dev_attr_bridged_mode);
}

void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;

	if (device_create_bin_file(dev, &bin_attr_port_stats))
		dev_info(dev, "failed to create port stats sysfs entry");

986
	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC)
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
		return;
	if (device_create_file(dev, &dev_attr_diag_mode))
		dev_info(dev, "failed to create diag_mode sysfs entry\n");
	if (device_create_bin_file(dev, &bin_attr_crb))
		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 (device_create_bin_file(dev, &bin_attr_pci_config))
		dev_info(dev, "failed to create pci config sysfs entry");
	if (device_create_file(dev, &dev_attr_beacon))
		dev_info(dev, "failed to create beacon sysfs entry");

	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
		return;
	if (device_create_bin_file(dev, &bin_attr_esw_config))
		dev_info(dev, "failed to create esw config sysfs entry");
1004
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
		return;
	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_pm_config))
		dev_info(dev, "failed to create pm config sysfs entry");
	if (device_create_bin_file(dev, &bin_attr_esw_stats))
		dev_info(dev, "failed to create eswitch stats sysfs entry");
}

void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;

	device_remove_bin_file(dev, &bin_attr_port_stats);

1020
	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC)
1021 1022 1023 1024 1025 1026 1027 1028 1029
		return;
	device_remove_file(dev, &dev_attr_diag_mode);
	device_remove_bin_file(dev, &bin_attr_crb);
	device_remove_bin_file(dev, &bin_attr_mem);
	device_remove_bin_file(dev, &bin_attr_pci_config);
	device_remove_file(dev, &dev_attr_beacon);
	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
		return;
	device_remove_bin_file(dev, &bin_attr_esw_config);
1030
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
1031 1032 1033 1034 1035
		return;
	device_remove_bin_file(dev, &bin_attr_npar_config);
	device_remove_bin_file(dev, &bin_attr_pm_config);
	device_remove_bin_file(dev, &bin_attr_esw_stats);
}
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045

void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter)
{
	qlcnic_create_diag_entries(adapter);
}

void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter)
{
	qlcnic_remove_diag_entries(adapter);
}
S
Sony Chacko 已提交
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055

void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter)
{
	qlcnic_create_diag_entries(adapter);
}

void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter)
{
	qlcnic_remove_diag_entries(adapter);
}