diff options
author | Himanshu Madhani <himanshu.madhani@qlogic.com> | 2013-03-12 05:02:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-13 05:35:05 -0400 |
commit | a520030e326a1267fba6babe685ad574174bde27 (patch) | |
tree | 3cb388606f065aa7da1bdfc0f47cd33787dd9771 /drivers/net/ethernet/qlogic/qlcnic | |
parent | 99eee14a14ec8bf36c0705a038fa8d00917fb679 (diff) |
qlcnic: Implement flash sysfs callback for 83xx adapter
QLogic applications use these callbacks to perform
o NIC Partitioning (NPAR) configuration and management
o Diagnostic tests
o Flash access and updates
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 253 |
3 files changed, 265 insertions, 8 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index c08fa20dd5f0..56c3676bdbfe 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -2272,7 +2272,7 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter) | |||
2272 | return 0; | 2272 | return 0; |
2273 | } | 2273 | } |
2274 | 2274 | ||
2275 | static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter) | 2275 | int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *adapter) |
2276 | { | 2276 | { |
2277 | int ret; | 2277 | int ret; |
2278 | u32 cmd; | 2278 | u32 cmd; |
@@ -2290,7 +2290,7 @@ static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter) | |||
2290 | return 0; | 2290 | return 0; |
2291 | } | 2291 | } |
2292 | 2292 | ||
2293 | static int qlcnic_83xx_disable_flash_write_op(struct qlcnic_adapter *adapter) | 2293 | int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter) |
2294 | { | 2294 | { |
2295 | int ret; | 2295 | int ret; |
2296 | 2296 | ||
@@ -2364,7 +2364,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter, | |||
2364 | return -EIO; | 2364 | return -EIO; |
2365 | 2365 | ||
2366 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | 2366 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { |
2367 | ret = qlcnic_83xx_enable_flash_write_op(adapter); | 2367 | ret = qlcnic_83xx_enable_flash_write(adapter); |
2368 | if (ret) { | 2368 | if (ret) { |
2369 | qlcnic_83xx_unlock_flash(adapter); | 2369 | qlcnic_83xx_unlock_flash(adapter); |
2370 | dev_err(&adapter->pdev->dev, | 2370 | dev_err(&adapter->pdev->dev, |
@@ -2406,7 +2406,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter, | |||
2406 | } | 2406 | } |
2407 | 2407 | ||
2408 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | 2408 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { |
2409 | ret = qlcnic_83xx_disable_flash_write_op(adapter); | 2409 | ret = qlcnic_83xx_disable_flash_write(adapter); |
2410 | if (ret) { | 2410 | if (ret) { |
2411 | qlcnic_83xx_unlock_flash(adapter); | 2411 | qlcnic_83xx_unlock_flash(adapter); |
2412 | dev_err(&adapter->pdev->dev, | 2412 | dev_err(&adapter->pdev->dev, |
@@ -2446,8 +2446,8 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, | |||
2446 | u32 temp; | 2446 | u32 temp; |
2447 | int ret = -EIO; | 2447 | int ret = -EIO; |
2448 | 2448 | ||
2449 | if ((count < QLC_83XX_FLASH_BULK_WRITE_MIN) || | 2449 | if ((count < QLC_83XX_FLASH_WRITE_MIN) || |
2450 | (count > QLC_83XX_FLASH_BULK_WRITE_MAX)) { | 2450 | (count > QLC_83XX_FLASH_WRITE_MAX)) { |
2451 | dev_err(&adapter->pdev->dev, | 2451 | dev_err(&adapter->pdev->dev, |
2452 | "%s: Invalid word count\n", __func__); | 2452 | "%s: Invalid word count\n", __func__); |
2453 | return -EIO; | 2453 | return -EIO; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 648a73f904ee..fbb3d1d9e55c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/etherdevice.h> | 12 | #include <linux/etherdevice.h> |
13 | #include "qlcnic_hw.h" | 13 | #include "qlcnic_hw.h" |
14 | 14 | ||
15 | #define QLCNIC_83XX_BAR0_LENGTH 0x4000 | ||
16 | |||
15 | /* Directly mapped registers */ | 17 | /* Directly mapped registers */ |
16 | #define QLC_83XX_CRB_WIN_BASE 0x3800 | 18 | #define QLC_83XX_CRB_WIN_BASE 0x3800 |
17 | #define QLC_83XX_CRB_WIN_FUNC(f) (QLC_83XX_CRB_WIN_BASE+((f)*4)) | 19 | #define QLC_83XX_CRB_WIN_FUNC(f) (QLC_83XX_CRB_WIN_BASE+((f)*4)) |
@@ -257,8 +259,8 @@ struct qlc_83xx_idc { | |||
257 | #define QLC_83XX_FLASH_BULK_WRITE_CMD 0xcadcadca | 259 | #define QLC_83XX_FLASH_BULK_WRITE_CMD 0xcadcadca |
258 | #define QLC_83XX_FLASH_READ_RETRY_COUNT 5000 | 260 | #define QLC_83XX_FLASH_READ_RETRY_COUNT 5000 |
259 | #define QLC_83XX_FLASH_STATUS_READY 0x6 | 261 | #define QLC_83XX_FLASH_STATUS_READY 0x6 |
260 | #define QLC_83XX_FLASH_BULK_WRITE_MIN 2 | 262 | #define QLC_83XX_FLASH_WRITE_MIN 2 |
261 | #define QLC_83XX_FLASH_BULK_WRITE_MAX 64 | 263 | #define QLC_83XX_FLASH_WRITE_MAX 64 |
262 | #define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY 1 | 264 | #define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY 1 |
263 | #define QLC_83XX_ERASE_MODE 1 | 265 | #define QLC_83XX_ERASE_MODE 1 |
264 | #define QLC_83XX_WRITE_MODE 2 | 266 | #define QLC_83XX_WRITE_MODE 2 |
@@ -451,4 +453,6 @@ int qlcnic_83xx_loopback_test(struct net_device *, u8); | |||
451 | int qlcnic_83xx_interrupt_test(struct net_device *); | 453 | int qlcnic_83xx_interrupt_test(struct net_device *); |
452 | int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state); | 454 | int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state); |
453 | int qlcnic_83xx_flash_test(struct qlcnic_adapter *); | 455 | int qlcnic_83xx_flash_test(struct qlcnic_adapter *); |
456 | int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *); | ||
457 | int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *); | ||
454 | #endif | 458 | #endif |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 4e464dcfcb3f..c77675da671f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | |||
@@ -884,6 +884,244 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, | |||
884 | return size; | 884 | return size; |
885 | } | 885 | } |
886 | 886 | ||
887 | static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp, | ||
888 | struct kobject *kobj, | ||
889 | struct bin_attribute *attr, | ||
890 | char *buf, loff_t offset, | ||
891 | size_t size) | ||
892 | { | ||
893 | unsigned char *p_read_buf; | ||
894 | int ret, count; | ||
895 | struct device *dev = container_of(kobj, struct device, kobj); | ||
896 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | ||
897 | |||
898 | if (!size) | ||
899 | return QL_STATUS_INVALID_PARAM; | ||
900 | if (!buf) | ||
901 | return QL_STATUS_INVALID_PARAM; | ||
902 | |||
903 | count = size / sizeof(u32); | ||
904 | |||
905 | if (size % sizeof(u32)) | ||
906 | count++; | ||
907 | |||
908 | p_read_buf = kcalloc(size, sizeof(unsigned char), GFP_KERNEL); | ||
909 | if (!p_read_buf) | ||
910 | return -ENOMEM; | ||
911 | if (qlcnic_83xx_lock_flash(adapter) != 0) { | ||
912 | kfree(p_read_buf); | ||
913 | return -EIO; | ||
914 | } | ||
915 | |||
916 | ret = qlcnic_83xx_lockless_flash_read32(adapter, offset, p_read_buf, | ||
917 | count); | ||
918 | |||
919 | if (ret) { | ||
920 | qlcnic_83xx_unlock_flash(adapter); | ||
921 | kfree(p_read_buf); | ||
922 | return ret; | ||
923 | } | ||
924 | |||
925 | qlcnic_83xx_unlock_flash(adapter); | ||
926 | memcpy(buf, p_read_buf, size); | ||
927 | kfree(p_read_buf); | ||
928 | |||
929 | return size; | ||
930 | } | ||
931 | |||
932 | static int qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter, | ||
933 | char *buf, loff_t offset, | ||
934 | size_t size) | ||
935 | { | ||
936 | int i, ret, count; | ||
937 | unsigned char *p_cache, *p_src; | ||
938 | |||
939 | p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL); | ||
940 | if (!p_cache) | ||
941 | return -ENOMEM; | ||
942 | |||
943 | memcpy(p_cache, buf, size); | ||
944 | p_src = p_cache; | ||
945 | count = size / sizeof(u32); | ||
946 | |||
947 | if (qlcnic_83xx_lock_flash(adapter) != 0) { | ||
948 | kfree(p_cache); | ||
949 | return -EIO; | ||
950 | } | ||
951 | |||
952 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | ||
953 | ret = qlcnic_83xx_enable_flash_write(adapter); | ||
954 | if (ret) { | ||
955 | kfree(p_cache); | ||
956 | qlcnic_83xx_unlock_flash(adapter); | ||
957 | return -EIO; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | for (i = 0; i < count / QLC_83XX_FLASH_WRITE_MAX; i++) { | ||
962 | ret = qlcnic_83xx_flash_bulk_write(adapter, offset, | ||
963 | (u32 *)p_src, | ||
964 | QLC_83XX_FLASH_WRITE_MAX); | ||
965 | |||
966 | if (ret) { | ||
967 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | ||
968 | ret = qlcnic_83xx_disable_flash_write(adapter); | ||
969 | if (ret) { | ||
970 | kfree(p_cache); | ||
971 | qlcnic_83xx_unlock_flash(adapter); | ||
972 | return -EIO; | ||
973 | } | ||
974 | } | ||
975 | |||
976 | kfree(p_cache); | ||
977 | qlcnic_83xx_unlock_flash(adapter); | ||
978 | return -EIO; | ||
979 | } | ||
980 | |||
981 | p_src = p_src + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX; | ||
982 | offset = offset + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX; | ||
983 | } | ||
984 | |||
985 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | ||
986 | ret = qlcnic_83xx_disable_flash_write(adapter); | ||
987 | if (ret) { | ||
988 | kfree(p_cache); | ||
989 | qlcnic_83xx_unlock_flash(adapter); | ||
990 | return -EIO; | ||
991 | } | ||
992 | } | ||
993 | |||
994 | kfree(p_cache); | ||
995 | qlcnic_83xx_unlock_flash(adapter); | ||
996 | |||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | static int qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter, | ||
1001 | char *buf, loff_t offset, size_t size) | ||
1002 | { | ||
1003 | int i, ret, count; | ||
1004 | unsigned char *p_cache, *p_src; | ||
1005 | |||
1006 | p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL); | ||
1007 | if (!p_cache) | ||
1008 | return -ENOMEM; | ||
1009 | |||
1010 | memcpy(p_cache, buf, size); | ||
1011 | p_src = p_cache; | ||
1012 | count = size / sizeof(u32); | ||
1013 | |||
1014 | if (qlcnic_83xx_lock_flash(adapter) != 0) { | ||
1015 | kfree(p_cache); | ||
1016 | return -EIO; | ||
1017 | } | ||
1018 | |||
1019 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | ||
1020 | ret = qlcnic_83xx_enable_flash_write(adapter); | ||
1021 | if (ret) { | ||
1022 | kfree(p_cache); | ||
1023 | qlcnic_83xx_unlock_flash(adapter); | ||
1024 | return -EIO; | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | for (i = 0; i < count; i++) { | ||
1029 | ret = qlcnic_83xx_flash_write32(adapter, offset, (u32 *)p_src); | ||
1030 | if (ret) { | ||
1031 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | ||
1032 | ret = qlcnic_83xx_disable_flash_write(adapter); | ||
1033 | if (ret) { | ||
1034 | kfree(p_cache); | ||
1035 | qlcnic_83xx_unlock_flash(adapter); | ||
1036 | return -EIO; | ||
1037 | } | ||
1038 | } | ||
1039 | kfree(p_cache); | ||
1040 | qlcnic_83xx_unlock_flash(adapter); | ||
1041 | return -EIO; | ||
1042 | } | ||
1043 | |||
1044 | p_src = p_src + sizeof(u32); | ||
1045 | offset = offset + sizeof(u32); | ||
1046 | } | ||
1047 | |||
1048 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | ||
1049 | ret = qlcnic_83xx_disable_flash_write(adapter); | ||
1050 | if (ret) { | ||
1051 | kfree(p_cache); | ||
1052 | qlcnic_83xx_unlock_flash(adapter); | ||
1053 | return -EIO; | ||
1054 | } | ||
1055 | } | ||
1056 | |||
1057 | kfree(p_cache); | ||
1058 | qlcnic_83xx_unlock_flash(adapter); | ||
1059 | |||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp, | ||
1064 | struct kobject *kobj, | ||
1065 | struct bin_attribute *attr, | ||
1066 | char *buf, loff_t offset, | ||
1067 | size_t size) | ||
1068 | { | ||
1069 | int ret; | ||
1070 | static int flash_mode; | ||
1071 | unsigned long data; | ||
1072 | struct device *dev = container_of(kobj, struct device, kobj); | ||
1073 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | ||
1074 | |||
1075 | if (!buf) | ||
1076 | return QL_STATUS_INVALID_PARAM; | ||
1077 | |||
1078 | ret = kstrtoul(buf, 16, &data); | ||
1079 | |||
1080 | switch (data) { | ||
1081 | case QLC_83XX_FLASH_SECTOR_ERASE_CMD: | ||
1082 | flash_mode = QLC_83XX_ERASE_MODE; | ||
1083 | ret = qlcnic_83xx_erase_flash_sector(adapter, offset); | ||
1084 | if (ret) { | ||
1085 | dev_err(&adapter->pdev->dev, | ||
1086 | "%s failed at %d\n", __func__, __LINE__); | ||
1087 | return -EIO; | ||
1088 | } | ||
1089 | break; | ||
1090 | |||
1091 | case QLC_83XX_FLASH_BULK_WRITE_CMD: | ||
1092 | flash_mode = QLC_83XX_BULK_WRITE_MODE; | ||
1093 | break; | ||
1094 | |||
1095 | case QLC_83XX_FLASH_WRITE_CMD: | ||
1096 | flash_mode = QLC_83XX_WRITE_MODE; | ||
1097 | break; | ||
1098 | default: | ||
1099 | if (flash_mode == QLC_83XX_BULK_WRITE_MODE) { | ||
1100 | ret = qlcnic_83xx_sysfs_flash_bulk_write(adapter, buf, | ||
1101 | offset, size); | ||
1102 | if (ret) { | ||
1103 | dev_err(&adapter->pdev->dev, | ||
1104 | "%s failed at %d\n", | ||
1105 | __func__, __LINE__); | ||
1106 | return -EIO; | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | if (flash_mode == QLC_83XX_WRITE_MODE) { | ||
1111 | ret = qlcnic_83xx_sysfs_flash_write(adapter, buf, | ||
1112 | offset, size); | ||
1113 | if (ret) { | ||
1114 | dev_err(&adapter->pdev->dev, | ||
1115 | "%s failed at %d\n", __func__, | ||
1116 | __LINE__); | ||
1117 | return -EIO; | ||
1118 | } | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | return size; | ||
1123 | } | ||
1124 | |||
887 | static struct device_attribute dev_attr_bridged_mode = { | 1125 | static struct device_attribute dev_attr_bridged_mode = { |
888 | .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, | 1126 | .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, |
889 | .show = qlcnic_show_bridged_mode, | 1127 | .show = qlcnic_show_bridged_mode, |
@@ -958,6 +1196,13 @@ static struct bin_attribute bin_attr_pm_config = { | |||
958 | .write = qlcnic_sysfs_write_pm_config, | 1196 | .write = qlcnic_sysfs_write_pm_config, |
959 | }; | 1197 | }; |
960 | 1198 | ||
1199 | static struct bin_attribute bin_attr_flash = { | ||
1200 | .attr = {.name = "flash", .mode = (S_IRUGO | S_IWUSR)}, | ||
1201 | .size = 0, | ||
1202 | .read = qlcnic_83xx_sysfs_flash_read_handler, | ||
1203 | .write = qlcnic_83xx_sysfs_flash_write_handler, | ||
1204 | }; | ||
1205 | |||
961 | void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) | 1206 | void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) |
962 | { | 1207 | { |
963 | struct device *dev = &adapter->pdev->dev; | 1208 | struct device *dev = &adapter->pdev->dev; |
@@ -1046,10 +1291,18 @@ void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter) | |||
1046 | 1291 | ||
1047 | void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter) | 1292 | void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter) |
1048 | { | 1293 | { |
1294 | struct device *dev = &adapter->pdev->dev; | ||
1295 | |||
1049 | qlcnic_create_diag_entries(adapter); | 1296 | qlcnic_create_diag_entries(adapter); |
1297 | |||
1298 | if (sysfs_create_bin_file(&dev->kobj, &bin_attr_flash)) | ||
1299 | dev_info(dev, "failed to create flash sysfs entry\n"); | ||
1050 | } | 1300 | } |
1051 | 1301 | ||
1052 | void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter) | 1302 | void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter) |
1053 | { | 1303 | { |
1304 | struct device *dev = &adapter->pdev->dev; | ||
1305 | |||
1054 | qlcnic_remove_diag_entries(adapter); | 1306 | qlcnic_remove_diag_entries(adapter); |
1307 | sysfs_remove_bin_file(&dev->kobj, &bin_attr_flash); | ||
1055 | } | 1308 | } |