diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-08-16 20:34:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-08-17 06:59:47 -0400 |
commit | b6021212291d1eb1e7d1245bbd8c53bcbe2355d7 (patch) | |
tree | bc10d1a36a46aaa8e1646a644e77ecafa88a0f14 /drivers/net/qlcnic | |
parent | ecd7d31038e2e0e95b4596eec021e02ba67a0a37 (diff) |
qlcnic: add eswitch statistics support
Adding eswitch statistics support. User can get
whole eswitch stats or stats of func belong to that eswitch.
Added:
o command to get statistics of eswitch and function.
o sysfs support to export eswitch and func statatistics.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic')
-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 |