aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajesh Borundia <rajesh.borundia@qlogic.com>2013-04-19 03:01:11 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-19 16:02:38 -0400
commit4000e7a78d12d71e37fcd2366c73fcb02e97fffb (patch)
tree8408088ddf4c1586356a4435fa1fb3a1baaf3f8c
parentf036e4f44ef04ffd78ffc2f515ebf60ffa543d21 (diff)
qlcnic: Support MAC address, Tx rate config.
o Add support for MAC address and Tx rate configuration per VF via iproute2 tool. o Tx rate change is allowed while the guest is running and the VF driver is loaded. o MAC address change is allowed only when VF driver is not loaded. Signed-off-by: Manish Chopra <manish.chopra@qlogic.com> Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h8
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c72
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c131
4 files changed, 213 insertions, 3 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 33f154e4c75b..b3ab7a3386e3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -341,6 +341,11 @@ static const struct net_device_ops qlcnic_netdev_ops = {
341#ifdef CONFIG_NET_POLL_CONTROLLER 341#ifdef CONFIG_NET_POLL_CONTROLLER
342 .ndo_poll_controller = qlcnic_poll_controller, 342 .ndo_poll_controller = qlcnic_poll_controller,
343#endif 343#endif
344#ifdef CONFIG_QLCNIC_SRIOV
345 .ndo_set_vf_mac = qlcnic_sriov_set_vf_mac,
346 .ndo_set_vf_tx_rate = qlcnic_sriov_set_vf_tx_rate,
347 .ndo_get_vf_config = qlcnic_sriov_get_vf_config,
348#endif
344}; 349};
345 350
346static const struct net_device_ops qlcnic_netdev_failed_ops = { 351static const struct net_device_ops qlcnic_netdev_failed_ops = {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
index 72db8b135dc7..5f73d42d6689 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
@@ -116,6 +116,8 @@ struct qlcnic_resources {
116 116
117struct qlcnic_vport { 117struct qlcnic_vport {
118 u16 handle; 118 u16 handle;
119 u16 max_tx_bw;
120 u16 min_tx_bw;
119 u8 mac[6]; 121 u8 mac[6];
120}; 122};
121 123
@@ -173,6 +175,8 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *);
173void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *); 175void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *);
174int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *, 176int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *,
175 struct qlcnic_bc_trans *); 177 struct qlcnic_bc_trans *);
178int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *,
179 struct qlcnic_info *, u16);
176 180
177static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) 181static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
178{ 182{
@@ -199,6 +203,10 @@ bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *,
199 struct qlcnic_vf_info *); 203 struct qlcnic_vf_info *);
200void qlcnic_sriov_pf_reset(struct qlcnic_adapter *); 204void qlcnic_sriov_pf_reset(struct qlcnic_adapter *);
201int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *); 205int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *);
206int qlcnic_sriov_set_vf_mac(struct net_device *, int, u8 *);
207int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int);
208int qlcnic_sriov_get_vf_config(struct net_device *, int ,
209 struct ifla_vf_info *);
202#else 210#else
203static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} 211static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {}
204static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} 212static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 305c7cd1e56e..b00cba96a82a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -181,6 +181,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
181 goto qlcnic_destroy_async_wq; 181 goto qlcnic_destroy_async_wq;
182 } 182 }
183 sriov->vf_info[i].vp = vp; 183 sriov->vf_info[i].vp = vp;
184 vp->max_tx_bw = MAX_BW;
184 random_ether_addr(vp->mac); 185 random_ether_addr(vp->mac);
185 dev_info(&adapter->pdev->dev, 186 dev_info(&adapter->pdev->dev,
186 "MAC Address %pM is configured for VF %d\n", 187 "MAC Address %pM is configured for VF %d\n",
@@ -378,12 +379,83 @@ static void qlcnic_sriov_vf_cfg_buff_desc(struct qlcnic_adapter *adapter)
378 adapter->max_rds_rings = MAX_RDS_RINGS; 379 adapter->max_rds_rings = MAX_RDS_RINGS;
379} 380}
380 381
382int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *adapter,
383 struct qlcnic_info *npar_info, u16 vport_id)
384{
385 struct device *dev = &adapter->pdev->dev;
386 struct qlcnic_cmd_args cmd;
387 int err;
388 u32 status;
389
390 err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
391 if (err)
392 return err;
393
394 cmd.req.arg[1] = vport_id << 16 | 0x1;
395 err = qlcnic_issue_cmd(adapter, &cmd);
396 if (err) {
397 dev_err(&adapter->pdev->dev,
398 "Failed to get vport info, err=%d\n", err);
399 qlcnic_free_mbx_args(&cmd);
400 return err;
401 }
402
403 status = cmd.rsp.arg[2] & 0xffff;
404 if (status & BIT_0)
405 npar_info->min_tx_bw = MSW(cmd.rsp.arg[2]);
406 if (status & BIT_1)
407 npar_info->max_tx_bw = LSW(cmd.rsp.arg[3]);
408 if (status & BIT_2)
409 npar_info->max_tx_ques = MSW(cmd.rsp.arg[3]);
410 if (status & BIT_3)
411 npar_info->max_tx_mac_filters = LSW(cmd.rsp.arg[4]);
412 if (status & BIT_4)
413 npar_info->max_rx_mcast_mac_filters = MSW(cmd.rsp.arg[4]);
414 if (status & BIT_5)
415 npar_info->max_rx_ucast_mac_filters = LSW(cmd.rsp.arg[5]);
416 if (status & BIT_6)
417 npar_info->max_rx_ip_addr = MSW(cmd.rsp.arg[5]);
418 if (status & BIT_7)
419 npar_info->max_rx_lro_flow = LSW(cmd.rsp.arg[6]);
420 if (status & BIT_8)
421 npar_info->max_rx_status_rings = MSW(cmd.rsp.arg[6]);
422 if (status & BIT_9)
423 npar_info->max_rx_buf_rings = LSW(cmd.rsp.arg[7]);
424
425 npar_info->max_rx_ques = MSW(cmd.rsp.arg[7]);
426 npar_info->max_tx_vlan_keys = LSW(cmd.rsp.arg[8]);
427 npar_info->max_local_ipv6_addrs = MSW(cmd.rsp.arg[8]);
428 npar_info->max_remote_ipv6_addrs = LSW(cmd.rsp.arg[9]);
429
430 dev_info(dev, "\n\tmin_tx_bw: %d, max_tx_bw: %d max_tx_ques: %d,\n"
431 "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n"
432 "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n"
433 "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n"
434 "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n"
435 "\tlocal_ipv6_addr: %d, remote_ipv6_addr: %d\n",
436 npar_info->min_tx_bw, npar_info->max_tx_bw,
437 npar_info->max_tx_ques, npar_info->max_tx_mac_filters,
438 npar_info->max_rx_mcast_mac_filters,
439 npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr,
440 npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings,
441 npar_info->max_rx_buf_rings, npar_info->max_rx_ques,
442 npar_info->max_tx_vlan_keys, npar_info->max_local_ipv6_addrs,
443 npar_info->max_remote_ipv6_addrs);
444
445 qlcnic_free_mbx_args(&cmd);
446 return err;
447}
448
381static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) 449static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)
382{ 450{
383 struct qlcnic_info nic_info; 451 struct qlcnic_info nic_info;
384 struct qlcnic_hardware_context *ahw = adapter->ahw; 452 struct qlcnic_hardware_context *ahw = adapter->ahw;
385 int err; 453 int err;
386 454
455 err = qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, 0);
456 if (err)
457 return err;
458
387 err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func); 459 err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
388 if (err) 460 if (err)
389 return -EIO; 461 return -EIO;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index a0135297b1c6..59d385b7ccd7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -10,6 +10,8 @@
10#include <linux/types.h> 10#include <linux/types.h>
11 11
12#define QLCNIC_SRIOV_VF_MAX_MAC 1 12#define QLCNIC_SRIOV_VF_MAX_MAC 1
13#define QLC_VF_MIN_TX_RATE 100
14#define QLC_VF_MAX_TX_RATE 9999
13 15
14static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); 16static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
15 17
@@ -62,8 +64,9 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,
62{ 64{
63 struct qlcnic_sriov *sriov = adapter->ahw->sriov; 65 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
64 struct qlcnic_resources *res = &sriov->ff_max; 66 struct qlcnic_resources *res = &sriov->ff_max;
65 int ret = -EIO, vpid;
66 u32 temp, num_vf_macs, num_vfs, max; 67 u32 temp, num_vf_macs, num_vfs, max;
68 int ret = -EIO, vpid, id;
69 struct qlcnic_vport *vp;
67 70
68 vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); 71 vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func);
69 if (vpid < 0) 72 if (vpid < 0)
@@ -72,8 +75,6 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,
72 num_vfs = sriov->num_vfs; 75 num_vfs = sriov->num_vfs;
73 max = num_vfs + 1; 76 max = num_vfs + 1;
74 info->bit_offsets = 0xffff; 77 info->bit_offsets = 0xffff;
75 info->min_tx_bw = 0;
76 info->max_tx_bw = MAX_BW;
77 info->max_tx_ques = res->num_tx_queues / max; 78 info->max_tx_ques = res->num_tx_queues / max;
78 info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters; 79 info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters;
79 num_vf_macs = QLCNIC_SRIOV_VF_MAX_MAC; 80 num_vf_macs = QLCNIC_SRIOV_VF_MAX_MAC;
@@ -83,7 +84,15 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,
83 info->max_rx_ucast_mac_filters = temp; 84 info->max_rx_ucast_mac_filters = temp;
84 temp = res->num_tx_mac_filters - (num_vfs * num_vf_macs); 85 temp = res->num_tx_mac_filters - (num_vfs * num_vf_macs);
85 info->max_tx_mac_filters = temp; 86 info->max_tx_mac_filters = temp;
87 info->min_tx_bw = 0;
88 info->max_tx_bw = MAX_BW;
86 } else { 89 } else {
90 id = qlcnic_sriov_func_to_index(adapter, func);
91 if (id < 0)
92 return id;
93 vp = sriov->vf_info[id].vp;
94 info->min_tx_bw = vp->min_tx_bw;
95 info->max_tx_bw = vp->max_tx_bw;
87 info->max_rx_ucast_mac_filters = num_vf_macs; 96 info->max_rx_ucast_mac_filters = num_vf_macs;
88 info->max_tx_mac_filters = num_vf_macs; 97 info->max_tx_mac_filters = num_vf_macs;
89 } 98 }
@@ -1416,3 +1425,119 @@ int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *adapter)
1416 __func__, ahw->op_mode); 1425 __func__, ahw->op_mode);
1417 return err; 1426 return err;
1418} 1427}
1428
1429int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
1430{
1431 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1432 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
1433 int i, num_vfs = sriov->num_vfs;
1434 struct qlcnic_vf_info *vf_info;
1435 u8 *curr_mac;
1436
1437 if (!qlcnic_sriov_pf_check(adapter))
1438 return -EOPNOTSUPP;
1439
1440 if (!is_valid_ether_addr(mac) || vf >= num_vfs)
1441 return -EINVAL;
1442
1443 if (!compare_ether_addr(adapter->mac_addr, mac)) {
1444 netdev_err(netdev, "MAC address is already in use by the PF\n");
1445 return -EINVAL;
1446 }
1447
1448 for (i = 0; i < num_vfs; i++) {
1449 vf_info = &sriov->vf_info[i];
1450 if (!compare_ether_addr(vf_info->vp->mac, mac)) {
1451 netdev_err(netdev,
1452 "MAC address is already in use by VF %d\n",
1453 i);
1454 return -EINVAL;
1455 }
1456 }
1457
1458 vf_info = &sriov->vf_info[vf];
1459 curr_mac = vf_info->vp->mac;
1460
1461 if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {
1462 netdev_err(netdev,
1463 "MAC address change failed for VF %d, as VF driver is loaded. Please unload VF driver and retry the operation\n",
1464 vf);
1465 return -EOPNOTSUPP;
1466 }
1467
1468 memcpy(curr_mac, mac, netdev->addr_len);
1469 netdev_info(netdev, "MAC Address %pM is configured for VF %d\n",
1470 mac, vf);
1471 return 0;
1472}
1473
1474int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf, int tx_rate)
1475{
1476 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1477 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
1478 struct qlcnic_vf_info *vf_info;
1479 struct qlcnic_info nic_info;
1480 struct qlcnic_vport *vp;
1481 u16 vpid;
1482
1483 if (!qlcnic_sriov_pf_check(adapter))
1484 return -EOPNOTSUPP;
1485
1486 if (vf >= sriov->num_vfs)
1487 return -EINVAL;
1488
1489 if (tx_rate >= 10000 || tx_rate < 100) {
1490 netdev_err(netdev,
1491 "Invalid Tx rate, allowed range is [%d - %d]",
1492 QLC_VF_MIN_TX_RATE, QLC_VF_MAX_TX_RATE);
1493 return -EINVAL;
1494 }
1495
1496 if (tx_rate == 0)
1497 tx_rate = 10000;
1498
1499 vf_info = &sriov->vf_info[vf];
1500 vp = vf_info->vp;
1501 vpid = vp->handle;
1502
1503 if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {
1504 if (qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, vpid))
1505 return -EIO;
1506
1507 nic_info.max_tx_bw = tx_rate / 100;
1508 nic_info.bit_offsets = BIT_0;
1509
1510 if (qlcnic_sriov_pf_set_vport_info(adapter, &nic_info, vpid))
1511 return -EIO;
1512 }
1513
1514 vp->max_tx_bw = tx_rate / 100;
1515 netdev_info(netdev,
1516 "Setting Tx rate %d (Mbps), %d %% of PF bandwidth, for VF %d\n",
1517 tx_rate, vp->max_tx_bw, vf);
1518 return 0;
1519}
1520
1521int qlcnic_sriov_get_vf_config(struct net_device *netdev,
1522 int vf, struct ifla_vf_info *ivi)
1523{
1524 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1525 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
1526 struct qlcnic_vport *vp;
1527
1528 if (!qlcnic_sriov_pf_check(adapter))
1529 return -EOPNOTSUPP;
1530
1531 if (vf >= sriov->num_vfs)
1532 return -EINVAL;
1533
1534 vp = sriov->vf_info[vf].vp;
1535 memcpy(&ivi->mac, vp->mac, ETH_ALEN);
1536 if (vp->max_tx_bw == MAX_BW)
1537 ivi->tx_rate = 0;
1538 else
1539 ivi->tx_rate = vp->max_tx_bw * 100;
1540
1541 ivi->vf = vf;
1542 return 0;
1543}