aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ti/wlcore
diff options
context:
space:
mode:
authorArkady Miasnikov <a-miasnikov@ti.com>2012-06-18 09:21:12 -0400
committerLuciano Coelho <coelho@ti.com>2012-06-22 15:52:01 -0400
commite1262efb9bf9864532c0dfca2b2e222aee7bd0a5 (patch)
tree6d674f6d8e3d0102261d53bc787b3c171fc4e8ec /drivers/net/wireless/ti/wlcore
parentf1a26e638e646d971f77c5a5186ee254b3f4e818 (diff)
wlcore: access the firmware memory via debugfs
Applications running in the user space needs access to the memory of the chip. Examples of such access - read/write global variables - access to firmware log - dump memory after firmware panic event Arbitrary 4-bytes aligned location can be accessed by read/write file wlcore/mem [Check return value of wlcore_raw_read/write and wlcore_set_partition calls as required by the recent IO changes. -- Luca] Signed-off-by: Arkady Miasnikov <a-miasnikov@ti.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/ti/wlcore')
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index 1768f37049bd..80dbc5304fac 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -38,6 +38,8 @@
38/* ms */ 38/* ms */
39#define WL1271_DEBUGFS_STATS_LIFETIME 1000 39#define WL1271_DEBUGFS_STATS_LIFETIME 1000
40 40
41#define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE))
42
41/* debugfs macros idea from mac80211 */ 43/* debugfs macros idea from mac80211 */
42int wl1271_format_buffer(char __user *userbuf, size_t count, 44int wl1271_format_buffer(char __user *userbuf, size_t count,
43 loff_t *ppos, char *fmt, ...) 45 loff_t *ppos, char *fmt, ...)
@@ -1025,6 +1027,195 @@ static const struct file_operations sleep_auth_ops = {
1025 .llseek = default_llseek, 1027 .llseek = default_llseek,
1026}; 1028};
1027 1029
1030static ssize_t dev_mem_read(struct file *file,
1031 char __user *user_buf, size_t count,
1032 loff_t *ppos)
1033{
1034 struct wl1271 *wl = file->private_data;
1035 struct wlcore_partition_set part, old_part;
1036 size_t bytes = count;
1037 int ret;
1038 char *buf;
1039
1040 /* only requests of dword-aligned size and offset are supported */
1041 if (bytes % 4)
1042 return -EINVAL;
1043
1044 if (*ppos % 4)
1045 return -EINVAL;
1046
1047 /* function should return in reasonable time */
1048 bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
1049
1050 if (bytes == 0)
1051 return -EINVAL;
1052
1053 memset(&part, 0, sizeof(part));
1054 part.mem.start = file->f_pos;
1055 part.mem.size = bytes;
1056
1057 buf = kmalloc(bytes, GFP_KERNEL);
1058 if (!buf)
1059 return -ENOMEM;
1060
1061 mutex_lock(&wl->mutex);
1062
1063 if (wl->state == WL1271_STATE_OFF) {
1064 ret = -EFAULT;
1065 goto skip_read;
1066 }
1067
1068 ret = wl1271_ps_elp_wakeup(wl);
1069 if (ret < 0)
1070 goto skip_read;
1071
1072 /* store current partition and switch partition */
1073 memcpy(&old_part, &wl->curr_part, sizeof(old_part));
1074 ret = wlcore_set_partition(wl, &part);
1075 if (ret < 0)
1076 goto part_err;
1077
1078 ret = wlcore_raw_read(wl, 0, buf, bytes, false);
1079 if (ret < 0)
1080 goto read_err;
1081
1082read_err:
1083 /* recover partition */
1084 ret = wlcore_set_partition(wl, &old_part);
1085 if (ret < 0)
1086 goto part_err;
1087
1088part_err:
1089 wl1271_ps_elp_sleep(wl);
1090
1091skip_read:
1092 mutex_unlock(&wl->mutex);
1093
1094 if (ret == 0) {
1095 ret = copy_to_user(user_buf, buf, bytes);
1096 if (ret < bytes) {
1097 bytes -= ret;
1098 *ppos += bytes;
1099 ret = 0;
1100 } else {
1101 ret = -EFAULT;
1102 }
1103 }
1104
1105 kfree(buf);
1106
1107 return ((ret == 0) ? bytes : ret);
1108}
1109
1110static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
1111 size_t count, loff_t *ppos)
1112{
1113 struct wl1271 *wl = file->private_data;
1114 struct wlcore_partition_set part, old_part;
1115 size_t bytes = count;
1116 int ret;
1117 char *buf;
1118
1119 /* only requests of dword-aligned size and offset are supported */
1120 if (bytes % 4)
1121 return -EINVAL;
1122
1123 if (*ppos % 4)
1124 return -EINVAL;
1125
1126 /* function should return in reasonable time */
1127 bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
1128
1129 if (bytes == 0)
1130 return -EINVAL;
1131
1132 memset(&part, 0, sizeof(part));
1133 part.mem.start = file->f_pos;
1134 part.mem.size = bytes;
1135
1136 buf = kmalloc(bytes, GFP_KERNEL);
1137 if (!buf)
1138 return -ENOMEM;
1139
1140 ret = copy_from_user(buf, user_buf, bytes);
1141 if (ret) {
1142 ret = -EFAULT;
1143 goto err_out;
1144 }
1145
1146 mutex_lock(&wl->mutex);
1147
1148 if (wl->state == WL1271_STATE_OFF) {
1149 ret = -EFAULT;
1150 goto skip_write;
1151 }
1152
1153 ret = wl1271_ps_elp_wakeup(wl);
1154 if (ret < 0)
1155 goto skip_write;
1156
1157 /* store current partition and switch partition */
1158 memcpy(&old_part, &wl->curr_part, sizeof(old_part));
1159 ret = wlcore_set_partition(wl, &part);
1160 if (ret < 0)
1161 goto part_err;
1162
1163 ret = wlcore_raw_write(wl, 0, buf, bytes, false);
1164 if (ret < 0)
1165 goto write_err;
1166
1167write_err:
1168 /* recover partition */
1169 ret = wlcore_set_partition(wl, &old_part);
1170 if (ret < 0)
1171 goto part_err;
1172
1173part_err:
1174 wl1271_ps_elp_sleep(wl);
1175
1176skip_write:
1177 mutex_unlock(&wl->mutex);
1178
1179 if (ret == 0)
1180 *ppos += bytes;
1181
1182err_out:
1183 kfree(buf);
1184
1185 return ((ret == 0) ? bytes : ret);
1186}
1187
1188static loff_t dev_mem_seek(struct file *file, loff_t offset, int orig)
1189{
1190 loff_t ret;
1191
1192 /* only requests of dword-aligned size and offset are supported */
1193 if (offset % 4)
1194 return -EINVAL;
1195
1196 switch (orig) {
1197 case SEEK_SET:
1198 file->f_pos = offset;
1199 ret = file->f_pos;
1200 break;
1201 case SEEK_CUR:
1202 file->f_pos += offset;
1203 ret = file->f_pos;
1204 break;
1205 default:
1206 ret = -EINVAL;
1207 }
1208
1209 return ret;
1210}
1211
1212static const struct file_operations dev_mem_ops = {
1213 .open = simple_open,
1214 .read = dev_mem_read,
1215 .write = dev_mem_write,
1216 .llseek = dev_mem_seek,
1217};
1218
1028static int wl1271_debugfs_add_files(struct wl1271 *wl, 1219static int wl1271_debugfs_add_files(struct wl1271 *wl,
1029 struct dentry *rootdir) 1220 struct dentry *rootdir)
1030{ 1221{
@@ -1059,6 +1250,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
1059 DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming); 1250 DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming);
1060 DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming); 1251 DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming);
1061 1252
1253 DEBUGFS_ADD_PREFIX(dev, mem, rootdir);
1062 1254
1063 return 0; 1255 return 0;
1064 1256