diff options
| -rw-r--r-- | drivers/net/qlcnic/qlcnic.h | 31 | ||||
| -rw-r--r-- | drivers/net/qlcnic/qlcnic_ctx.c | 125 | ||||
| -rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 132 |
3 files changed, 287 insertions, 1 deletions
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 970389331bbc..7f4e11bd4cd4 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h | |||
| @@ -555,6 +555,7 @@ struct qlcnic_recv_context { | |||
| 555 | #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026 | 555 | #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026 |
| 556 | #define QLCNIC_CDRP_CMD_SET_PORTMIRRORING 0x00000027 | 556 | #define QLCNIC_CDRP_CMD_SET_PORTMIRRORING 0x00000027 |
| 557 | #define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028 | 557 | #define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028 |
| 558 | #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS 0x0000002a | ||
| 558 | 559 | ||
| 559 | #define QLCNIC_RCODE_SUCCESS 0 | 560 | #define QLCNIC_RCODE_SUCCESS 0 |
| 560 | #define QLCNIC_RCODE_TIMEOUT 17 | 561 | #define QLCNIC_RCODE_TIMEOUT 17 |
| @@ -1126,6 +1127,31 @@ struct qlcnic_esw_func_cfg { | |||
| 1126 | u8 reserved; | 1127 | u8 reserved; |
| 1127 | }; | 1128 | }; |
| 1128 | 1129 | ||
| 1130 | #define QLCNIC_STATS_VERSION 1 | ||
| 1131 | #define QLCNIC_STATS_PORT 1 | ||
| 1132 | #define QLCNIC_STATS_ESWITCH 2 | ||
| 1133 | #define QLCNIC_QUERY_RX_COUNTER 0 | ||
| 1134 | #define QLCNIC_QUERY_TX_COUNTER 1 | ||
| 1135 | struct __qlcnic_esw_statistics { | ||
| 1136 | __le16 context_id; | ||
| 1137 | __le16 version; | ||
| 1138 | __le16 size; | ||
| 1139 | __le16 unused; | ||
| 1140 | __le64 unicast_frames; | ||
| 1141 | __le64 multicast_frames; | ||
| 1142 | __le64 broadcast_frames; | ||
| 1143 | __le64 dropped_frames; | ||
| 1144 | __le64 errors; | ||
| 1145 | __le64 local_frames; | ||
| 1146 | __le64 numbytes; | ||
| 1147 | __le64 rsvd[3]; | ||
| 1148 | }; | ||
| 1149 | |||
| 1150 | struct qlcnic_esw_statistics { | ||
| 1151 | struct __qlcnic_esw_statistics rx; | ||
| 1152 | struct __qlcnic_esw_statistics tx; | ||
| 1153 | }; | ||
| 1154 | |||
| 1129 | int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); | 1155 | int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); |
| 1130 | int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); | 1156 | int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); |
| 1131 | 1157 | ||
| @@ -1252,6 +1278,11 @@ int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8); | |||
| 1252 | int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8, | 1278 | int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8, |
| 1253 | u8, u8, u16); | 1279 | u8, u8, u16); |
| 1254 | int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8); | 1280 | int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8); |
| 1281 | int qlcnic_get_port_stats(struct qlcnic_adapter *, const u8, const u8, | ||
| 1282 | struct __qlcnic_esw_statistics *); | ||
| 1283 | int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8, | ||
| 1284 | struct __qlcnic_esw_statistics *); | ||
| 1285 | int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8); | ||
| 1255 | extern int qlcnic_config_tso; | 1286 | extern int qlcnic_config_tso; |
| 1256 | 1287 | ||
| 1257 | /* | 1288 | /* |
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index cc5d861d9a12..57c9b09bd16a 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c | |||
| @@ -983,3 +983,128 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id, | |||
| 983 | 983 | ||
| 984 | return err; | 984 | return err; |
| 985 | } | 985 | } |
| 986 | |||
| 987 | int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, | ||
| 988 | const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) { | ||
| 989 | |||
| 990 | size_t stats_size = sizeof(struct __qlcnic_esw_statistics); | ||
| 991 | dma_addr_t stats_dma_t; | ||
| 992 | void *stats_addr; | ||
| 993 | u32 arg1; | ||
| 994 | int err; | ||
| 995 | |||
| 996 | if (esw_stats == NULL) | ||
| 997 | return -ENOMEM; | ||
| 998 | |||
| 999 | if (adapter->op_mode != QLCNIC_MGMT_FUNC && | ||
| 1000 | func != adapter->ahw.pci_func) { | ||
| 1001 | dev_err(&adapter->pdev->dev, | ||
| 1002 | "Not privilege to query stats for func=%d", func); | ||
| 1003 | return -EIO; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | stats_addr = pci_alloc_consistent(adapter->pdev, stats_size, | ||
| 1007 | &stats_dma_t); | ||
| 1008 | if (!stats_addr) { | ||
| 1009 | dev_err(&adapter->pdev->dev, "Unable to allocate memory\n"); | ||
| 1010 | return -ENOMEM; | ||
| 1011 | } | ||
| 1012 | memset(stats_addr, 0, stats_size); | ||
| 1013 | |||
| 1014 | arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12; | ||
| 1015 | arg1 |= rx_tx << 15 | stats_size << 16; | ||
| 1016 | |||
| 1017 | err = qlcnic_issue_cmd(adapter, | ||
| 1018 | adapter->ahw.pci_func, | ||
| 1019 | adapter->fw_hal_version, | ||
| 1020 | arg1, | ||
| 1021 | MSD(stats_dma_t), | ||
| 1022 | LSD(stats_dma_t), | ||
| 1023 | QLCNIC_CDRP_CMD_GET_ESWITCH_STATS); | ||
| 1024 | |||
| 1025 | if (!err) | ||
| 1026 | memcpy(esw_stats, stats_addr, stats_size); | ||
| 1027 | |||
| 1028 | pci_free_consistent(adapter->pdev, stats_size, stats_addr, | ||
| 1029 | stats_dma_t); | ||
| 1030 | return err; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, | ||
| 1034 | const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) { | ||
| 1035 | |||
| 1036 | struct __qlcnic_esw_statistics port_stats; | ||
| 1037 | u8 i; | ||
| 1038 | int ret = -EIO; | ||
| 1039 | |||
| 1040 | if (esw_stats == NULL) | ||
| 1041 | return -ENOMEM; | ||
| 1042 | if (adapter->op_mode != QLCNIC_MGMT_FUNC) | ||
| 1043 | return -EIO; | ||
| 1044 | if (adapter->npars == NULL) | ||
| 1045 | return -EIO; | ||
| 1046 | |||
| 1047 | memset(esw_stats, 0, sizeof(struct __qlcnic_esw_statistics)); | ||
| 1048 | esw_stats->context_id = eswitch; | ||
| 1049 | |||
| 1050 | for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { | ||
| 1051 | if (adapter->npars[i].phy_port != eswitch) | ||
| 1052 | continue; | ||
| 1053 | |||
| 1054 | memset(&port_stats, 0, sizeof(struct __qlcnic_esw_statistics)); | ||
| 1055 | if (qlcnic_get_port_stats(adapter, i, rx_tx, &port_stats)) | ||
| 1056 | continue; | ||
| 1057 | |||
| 1058 | esw_stats->size = port_stats.size; | ||
| 1059 | esw_stats->version = port_stats.version; | ||
| 1060 | esw_stats->unicast_frames += port_stats.unicast_frames; | ||
| 1061 | esw_stats->multicast_frames += port_stats.multicast_frames; | ||
| 1062 | esw_stats->broadcast_frames += port_stats.broadcast_frames; | ||
| 1063 | esw_stats->dropped_frames += port_stats.dropped_frames; | ||
| 1064 | esw_stats->errors += port_stats.errors; | ||
| 1065 | esw_stats->local_frames += port_stats.local_frames; | ||
| 1066 | esw_stats->numbytes += port_stats.numbytes; | ||
| 1067 | |||
| 1068 | ret = 0; | ||
| 1069 | } | ||
| 1070 | return ret; | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw, | ||
| 1074 | const u8 port, const u8 rx_tx) | ||
| 1075 | { | ||
| 1076 | |||
| 1077 | u32 arg1; | ||
| 1078 | |||
| 1079 | if (adapter->op_mode != QLCNIC_MGMT_FUNC) | ||
| 1080 | return -EIO; | ||
| 1081 | |||
| 1082 | if (func_esw == QLCNIC_STATS_PORT) { | ||
| 1083 | if (port >= QLCNIC_MAX_PCI_FUNC) | ||
| 1084 | goto err_ret; | ||
| 1085 | } else if (func_esw == QLCNIC_STATS_ESWITCH) { | ||
| 1086 | if (port >= QLCNIC_NIU_MAX_XG_PORTS) | ||
| 1087 | goto err_ret; | ||
| 1088 | } else { | ||
| 1089 | goto err_ret; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | if (rx_tx > QLCNIC_QUERY_TX_COUNTER) | ||
| 1093 | goto err_ret; | ||
| 1094 | |||
| 1095 | arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12; | ||
| 1096 | arg1 |= BIT_14 | rx_tx << 15; | ||
| 1097 | |||
| 1098 | return qlcnic_issue_cmd(adapter, | ||
| 1099 | adapter->ahw.pci_func, | ||
| 1100 | adapter->fw_hal_version, | ||
| 1101 | arg1, | ||
| 1102 | 0, | ||
| 1103 | 0, | ||
| 1104 | QLCNIC_CDRP_CMD_GET_ESWITCH_STATS); | ||
| 1105 | |||
| 1106 | err_ret: | ||
| 1107 | dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d" | ||
| 1108 | "rx_ctx=%d\n", func_esw, port, rx_tx); | ||
| 1109 | return -EIO; | ||
| 1110 | } | ||
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 06ffd7637f87..a30bde52d40b 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c | |||
| @@ -3378,6 +3378,115 @@ qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj, | |||
| 3378 | } | 3378 | } |
| 3379 | 3379 | ||
| 3380 | static ssize_t | 3380 | static ssize_t |
| 3381 | qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj, | ||
| 3382 | struct bin_attribute *attr, char *buf, loff_t offset, size_t size) | ||
| 3383 | { | ||
| 3384 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 3385 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | ||
| 3386 | struct qlcnic_esw_statistics port_stats; | ||
| 3387 | int ret; | ||
| 3388 | |||
| 3389 | if (size != sizeof(struct qlcnic_esw_statistics)) | ||
| 3390 | return QL_STATUS_INVALID_PARAM; | ||
| 3391 | |||
| 3392 | if (offset >= QLCNIC_MAX_PCI_FUNC) | ||
| 3393 | return QL_STATUS_INVALID_PARAM; | ||
| 3394 | |||
| 3395 | memset(&port_stats, 0, size); | ||
| 3396 | ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER, | ||
| 3397 | &port_stats.rx); | ||
| 3398 | if (ret) | ||
| 3399 | return ret; | ||
| 3400 | |||
| 3401 | ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER, | ||
| 3402 | &port_stats.tx); | ||
| 3403 | if (ret) | ||
| 3404 | return ret; | ||
| 3405 | |||
| 3406 | memcpy(buf, &port_stats, size); | ||
| 3407 | return size; | ||
| 3408 | } | ||
| 3409 | |||
| 3410 | static ssize_t | ||
| 3411 | qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj, | ||
| 3412 | struct bin_attribute *attr, char *buf, loff_t offset, size_t size) | ||
| 3413 | { | ||
| 3414 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 3415 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | ||
| 3416 | struct qlcnic_esw_statistics esw_stats; | ||
| 3417 | int ret; | ||
| 3418 | |||
| 3419 | if (size != sizeof(struct qlcnic_esw_statistics)) | ||
| 3420 | return QL_STATUS_INVALID_PARAM; | ||
| 3421 | |||
| 3422 | if (offset >= QLCNIC_NIU_MAX_XG_PORTS) | ||
| 3423 | return QL_STATUS_INVALID_PARAM; | ||
| 3424 | |||
| 3425 | memset(&esw_stats, 0, size); | ||
| 3426 | ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER, | ||
| 3427 | &esw_stats.rx); | ||
| 3428 | if (ret) | ||
| 3429 | return ret; | ||
| 3430 | |||
| 3431 | ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER, | ||
| 3432 | &esw_stats.tx); | ||
| 3433 | if (ret) | ||
| 3434 | return ret; | ||
| 3435 | |||
| 3436 | memcpy(buf, &esw_stats, size); | ||
| 3437 | return size; | ||
| 3438 | } | ||
| 3439 | |||
| 3440 | static ssize_t | ||
| 3441 | qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj, | ||
| 3442 | struct bin_attribute *attr, char *buf, loff_t offset, size_t size) | ||
| 3443 | { | ||
| 3444 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 3445 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | ||
| 3446 | int ret; | ||
| 3447 | |||
| 3448 | if (offset >= QLCNIC_NIU_MAX_XG_PORTS) | ||
| 3449 | return QL_STATUS_INVALID_PARAM; | ||
| 3450 | |||
| 3451 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset, | ||
| 3452 | QLCNIC_QUERY_RX_COUNTER); | ||
| 3453 | if (ret) | ||
| 3454 | return ret; | ||
| 3455 | |||
| 3456 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset, | ||
| 3457 | QLCNIC_QUERY_TX_COUNTER); | ||
| 3458 | if (ret) | ||
| 3459 | return ret; | ||
| 3460 | |||
| 3461 | return size; | ||
| 3462 | } | ||
| 3463 | |||
| 3464 | static ssize_t | ||
| 3465 | qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj, | ||
| 3466 | struct bin_attribute *attr, char *buf, loff_t offset, size_t size) | ||
| 3467 | { | ||
| 3468 | |||
| 3469 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 3470 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | ||
| 3471 | int ret; | ||
| 3472 | |||
| 3473 | if (offset >= QLCNIC_MAX_PCI_FUNC) | ||
| 3474 | return QL_STATUS_INVALID_PARAM; | ||
| 3475 | |||
| 3476 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, | ||
| 3477 | QLCNIC_QUERY_RX_COUNTER); | ||
| 3478 | if (ret) | ||
| 3479 | return ret; | ||
| 3480 | |||
| 3481 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, | ||
| 3482 | QLCNIC_QUERY_TX_COUNTER); | ||
| 3483 | if (ret) | ||
| 3484 | return ret; | ||
| 3485 | |||
| 3486 | return size; | ||
| 3487 | } | ||
| 3488 | |||
| 3489 | static ssize_t | ||
| 3381 | qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj, | 3490 | qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj, |
| 3382 | struct bin_attribute *attr, char *buf, loff_t offset, size_t size) | 3491 | struct bin_attribute *attr, char *buf, loff_t offset, size_t size) |
| 3383 | { | 3492 | { |
| @@ -3426,6 +3535,20 @@ static struct bin_attribute bin_attr_pci_config = { | |||
| 3426 | .write = NULL, | 3535 | .write = NULL, |
| 3427 | }; | 3536 | }; |
| 3428 | 3537 | ||
| 3538 | static struct bin_attribute bin_attr_port_stats = { | ||
| 3539 | .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)}, | ||
| 3540 | .size = 0, | ||
| 3541 | .read = qlcnic_sysfs_get_port_stats, | ||
| 3542 | .write = qlcnic_sysfs_clear_port_stats, | ||
| 3543 | }; | ||
| 3544 | |||
| 3545 | static struct bin_attribute bin_attr_esw_stats = { | ||
| 3546 | .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)}, | ||
| 3547 | .size = 0, | ||
| 3548 | .read = qlcnic_sysfs_get_esw_stats, | ||
| 3549 | .write = qlcnic_sysfs_clear_esw_stats, | ||
| 3550 | }; | ||
| 3551 | |||
| 3429 | static struct bin_attribute bin_attr_esw_config = { | 3552 | static struct bin_attribute bin_attr_esw_config = { |
| 3430 | .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)}, | 3553 | .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)}, |
| 3431 | .size = 0, | 3554 | .size = 0, |
| @@ -3465,6 +3588,9 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) | |||
| 3465 | { | 3588 | { |
| 3466 | struct device *dev = &adapter->pdev->dev; | 3589 | struct device *dev = &adapter->pdev->dev; |
| 3467 | 3590 | ||
| 3591 | if (device_create_bin_file(dev, &bin_attr_port_stats)) | ||
| 3592 | dev_info(dev, "failed to create port stats sysfs entry"); | ||
| 3593 | |||
| 3468 | if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) | 3594 | if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) |
| 3469 | return; | 3595 | return; |
| 3470 | if (device_create_file(dev, &dev_attr_diag_mode)) | 3596 | if (device_create_file(dev, &dev_attr_diag_mode)) |
| @@ -3484,7 +3610,8 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) | |||
| 3484 | dev_info(dev, "failed to create esw config sysfs entry"); | 3610 | dev_info(dev, "failed to create esw config sysfs entry"); |
| 3485 | if (device_create_bin_file(dev, &bin_attr_pm_config)) | 3611 | if (device_create_bin_file(dev, &bin_attr_pm_config)) |
| 3486 | dev_info(dev, "failed to create pm config sysfs entry"); | 3612 | dev_info(dev, "failed to create pm config sysfs entry"); |
| 3487 | 3613 | if (device_create_bin_file(dev, &bin_attr_esw_stats)) | |
| 3614 | dev_info(dev, "failed to create eswitch stats sysfs entry"); | ||
| 3488 | } | 3615 | } |
| 3489 | 3616 | ||
| 3490 | static void | 3617 | static void |
| @@ -3492,6 +3619,8 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) | |||
| 3492 | { | 3619 | { |
| 3493 | struct device *dev = &adapter->pdev->dev; | 3620 | struct device *dev = &adapter->pdev->dev; |
| 3494 | 3621 | ||
| 3622 | device_remove_bin_file(dev, &bin_attr_port_stats); | ||
| 3623 | |||
| 3495 | if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) | 3624 | if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) |
| 3496 | return; | 3625 | return; |
| 3497 | device_remove_file(dev, &dev_attr_diag_mode); | 3626 | device_remove_file(dev, &dev_attr_diag_mode); |
| @@ -3504,6 +3633,7 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) | |||
| 3504 | device_remove_bin_file(dev, &bin_attr_npar_config); | 3633 | device_remove_bin_file(dev, &bin_attr_npar_config); |
| 3505 | device_remove_bin_file(dev, &bin_attr_esw_config); | 3634 | device_remove_bin_file(dev, &bin_attr_esw_config); |
| 3506 | device_remove_bin_file(dev, &bin_attr_pm_config); | 3635 | device_remove_bin_file(dev, &bin_attr_pm_config); |
| 3636 | device_remove_bin_file(dev, &bin_attr_esw_stats); | ||
| 3507 | } | 3637 | } |
| 3508 | 3638 | ||
| 3509 | #ifdef CONFIG_INET | 3639 | #ifdef CONFIG_INET |
