aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wimax/i2400m/fw.c189
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h4
2 files changed, 134 insertions, 59 deletions
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 1fd2fee4c6c2..897e0be698c6 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -78,11 +78,11 @@
78 * 78 *
79 * We can then upload the firmware file. The file is composed of a BCF 79 * We can then upload the firmware file. The file is composed of a BCF
80 * header (basic data, keys and signatures) and a list of write 80 * header (basic data, keys and signatures) and a list of write
81 * commands and payloads. We first upload the header 81 * commands and payloads. Optionally more BCF headers might follow the
82 * [i2400m_dnload_init()] and then pass the commands and payloads 82 * main payload. We first upload the header [i2400m_dnload_init()] and
83 * verbatim to the i2400m_bm_cmd() function 83 * then pass the commands and payloads verbatim to the i2400m_bm_cmd()
84 * [i2400m_dnload_bcf()]. Then we tell the device to jump to the new 84 * function [i2400m_dnload_bcf()]. Then we tell the device to jump to
85 * firmware [i2400m_dnload_finalize()]. 85 * the new firmware [i2400m_dnload_finalize()].
86 * 86 *
87 * Once firmware is uploaded, we are good to go :) 87 * Once firmware is uploaded, we are good to go :)
88 * 88 *
@@ -115,6 +115,7 @@
115 * i2400m_dev_bootstrap Called by __i2400m_dev_start() 115 * i2400m_dev_bootstrap Called by __i2400m_dev_start()
116 * request_firmware 116 * request_firmware
117 * i2400m_fw_check 117 * i2400m_fw_check
118 * i2400m_fw_hdr_check
118 * i2400m_fw_dnload 119 * i2400m_fw_dnload
119 * release_firmware 120 * release_firmware
120 * 121 *
@@ -1151,75 +1152,142 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
1151 1152
1152 1153
1153/* 1154/*
1154 * Run quick consistency tests on the firmware file 1155 * Run consistency tests on the firmware file and load up headers
1155 * 1156 *
1156 * Check for the firmware being made for the i2400m device, 1157 * Check for the firmware being made for the i2400m device,
1157 * etc...These checks are mostly informative, as the device will make 1158 * etc...These checks are mostly informative, as the device will make
1158 * them too; but the driver's response is more informative on what 1159 * them too; but the driver's response is more informative on what
1159 * went wrong. 1160 * went wrong.
1161 *
1162 * This will also look at all the headers present on the firmware
1163 * file, and update i2400m->fw_bcf_hdr to point to them.
1160 */ 1164 */
1161static 1165static
1162int i2400m_fw_check(struct i2400m *i2400m, 1166int i2400m_fw_hdr_check(struct i2400m *i2400m,
1163 const struct i2400m_bcf_hdr *bcf, 1167 const struct i2400m_bcf_hdr *bcf_hdr,
1164 size_t bcf_size) 1168 size_t index, size_t offset)
1165{ 1169{
1166 int result;
1167 struct device *dev = i2400m_dev(i2400m); 1170 struct device *dev = i2400m_dev(i2400m);
1171
1168 unsigned module_type, header_len, major_version, minor_version, 1172 unsigned module_type, header_len, major_version, minor_version,
1169 module_id, module_vendor, date, size; 1173 module_id, module_vendor, date, size;
1170 1174
1171 /* Check hard errors */ 1175 module_type = bcf_hdr->module_type;
1172 result = -EINVAL; 1176 header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len);
1173 if (bcf_size < sizeof(*bcf)) { /* big enough header? */ 1177 major_version = (le32_to_cpu(bcf_hdr->header_version) & 0xffff0000)
1174 dev_err(dev, "firmware %s too short: " 1178 >> 16;
1175 "%zu B vs %zu (at least) expected\n", 1179 minor_version = le32_to_cpu(bcf_hdr->header_version) & 0x0000ffff;
1176 i2400m->fw_name, bcf_size, sizeof(*bcf)); 1180 module_id = le32_to_cpu(bcf_hdr->module_id);
1177 goto error; 1181 module_vendor = le32_to_cpu(bcf_hdr->module_vendor);
1178 } 1182 date = le32_to_cpu(bcf_hdr->date);
1179 1183 size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
1180 module_type = bcf->module_type; 1184
1181 header_len = sizeof(u32) * le32_to_cpu(bcf->header_len); 1185 d_printf(1, dev, "firmware %s #%d@%08x: BCF header "
1182 major_version = (le32_to_cpu(bcf->header_version) & 0xffff0000) >> 16; 1186 "type:vendor:id 0x%x:%x:%x v%u.%u (%zu/%zu B) built %08x\n",
1183 minor_version = le32_to_cpu(bcf->header_version) & 0x0000ffff; 1187 i2400m->fw_name, index, offset,
1184 module_id = le32_to_cpu(bcf->module_id); 1188 module_type, module_vendor, module_id,
1185 module_vendor = le32_to_cpu(bcf->module_vendor); 1189 major_version, minor_version, header_len, size, date);
1186 date = le32_to_cpu(bcf->date); 1190
1187 size = sizeof(u32) * le32_to_cpu(bcf->size); 1191 /* Hard errors */
1188 1192 if (major_version != 1) {
1189 if (bcf_size != size) { /* annoyingly paranoid */ 1193 dev_err(dev, "firmware %s #%d@%08x: major header version "
1190 dev_err(dev, "firmware %s: bad size, got " 1194 "v%u.%u not supported\n",
1191 "%zu B vs %u expected\n", 1195 i2400m->fw_name, index, offset,
1192 i2400m->fw_name, bcf_size, size); 1196 major_version, minor_version);
1193 goto error; 1197 return -EBADF;
1194 } 1198 }
1195 1199
1196 d_printf(2, dev, "type 0x%x id 0x%x vendor 0x%x; header v%u.%u (%zu B) "
1197 "date %08x (%zu B)\n",
1198 module_type, module_id, module_vendor,
1199 major_version, minor_version, (size_t) header_len,
1200 date, (size_t) size);
1201
1202 if (module_type != 6) { /* built for the right hardware? */ 1200 if (module_type != 6) { /* built for the right hardware? */
1203 dev_err(dev, "bad fw %s: unexpected module type 0x%x; " 1201 dev_err(dev, "firmware %s #%d@%08x: unexpected module "
1204 "aborting\n", i2400m->fw_name, module_type); 1202 "type 0x%x; aborting\n",
1205 goto error; 1203 i2400m->fw_name, index, offset,
1204 module_type);
1205 return -EBADF;
1206 } 1206 }
1207 1207
1208 if (major_version != 1) { 1208 if (module_vendor != 0x8086) {
1209 dev_err(dev, "%s: major header version v%u.%u not supported\n", 1209 dev_err(dev, "firmware %s #%d@%08x: unexpected module "
1210 i2400m->fw_name, major_version, minor_version); 1210 "vendor 0x%x; aborting\n",
1211 goto error; 1211 i2400m->fw_name, index, offset, module_vendor);
1212 return -EBADF;
1212 } 1213 }
1213 1214
1214 /* Check soft-er errors */
1215 result = 0;
1216 if (module_vendor != 0x8086)
1217 dev_err(dev, "bad fw %s? unexpected vendor 0x%04x\n",
1218 i2400m->fw_name, module_vendor);
1219 if (date < 0x20080300) 1215 if (date < 0x20080300)
1220 dev_err(dev, "bad fw %s? build date too old %08x\n", 1216 dev_warn(dev, "firmware %s #%d@%08x: build date %08x "
1221 i2400m->fw_name, date); 1217 "too old; unsupported\n",
1222error: 1218 i2400m->fw_name, index, offset, date);
1219 return 0;
1220}
1221
1222
1223/*
1224 * Run consistency tests on the firmware file and load up headers
1225 *
1226 * Check for the firmware being made for the i2400m device,
1227 * etc...These checks are mostly informative, as the device will make
1228 * them too; but the driver's response is more informative on what
1229 * went wrong.
1230 *
1231 * This will also look at all the headers present on the firmware
1232 * file, and update i2400m->fw_hdrs to point to them.
1233 */
1234static
1235int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size)
1236{
1237 int result;
1238 struct device *dev = i2400m_dev(i2400m);
1239 size_t headers = 0;
1240 const struct i2400m_bcf_hdr *bcf_hdr;
1241 const void *itr, *next, *top;
1242 unsigned slots = 0, used_slots = 0;
1243
1244 for (itr = bcf, top = itr + bcf_size;
1245 itr < top;
1246 headers++, itr = next) {
1247 size_t leftover, offset, header_len, size;
1248
1249 leftover = top - itr;
1250 offset = itr - (const void *) bcf;
1251 if (leftover <= sizeof(*bcf_hdr)) {
1252 dev_err(dev, "firmware %s: %zu B left at @%x, "
1253 "not enough for BCF header\n",
1254 i2400m->fw_name, leftover, offset);
1255 break;
1256 }
1257 bcf_hdr = itr;
1258 /* Only the first header is supposed to be followed by
1259 * payload */
1260 header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len);
1261 size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
1262 if (headers == 0)
1263 next = itr + size;
1264 else
1265 next = itr + header_len;
1266
1267 result = i2400m_fw_hdr_check(i2400m, bcf_hdr, headers, offset);
1268 if (result < 0)
1269 continue;
1270 if (used_slots + 1 >= slots) {
1271 /* +1 -> we need to account for the one we'll
1272 * occupy and at least an extra one for
1273 * always being NULL */
1274 result = i2400m_zrealloc_2x(
1275 (void **) &i2400m->fw_hdrs, &slots,
1276 sizeof(i2400m->fw_hdrs[0]),
1277 GFP_KERNEL);
1278 if (result < 0)
1279 goto error_zrealloc;
1280 }
1281 i2400m->fw_hdrs[used_slots] = bcf_hdr;
1282 used_slots++;
1283 }
1284 if (headers == 0) {
1285 dev_err(dev, "firmware %s: no usable headers found\n",
1286 i2400m->fw_name);
1287 result = -EBADF;
1288 } else
1289 result = 0;
1290error_zrealloc:
1223 return result; 1291 return result;
1224} 1292}
1225 1293
@@ -1359,13 +1427,16 @@ int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags)
1359 bcf = (void *) fw->data; 1427 bcf = (void *) fw->data;
1360 i2400m->fw_name = fw_name; 1428 i2400m->fw_name = fw_name;
1361 ret = i2400m_fw_check(i2400m, bcf, fw->size); 1429 ret = i2400m_fw_check(i2400m, bcf, fw->size);
1362 if (ret >= 0) { 1430 if (ret >= 0)
1363 ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags); 1431 ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags);
1364 if (ret >= 0) 1432 if (ret < 0)
1365 break; 1433 dev_err(dev, "%s: cannot use: %d, skipping\n",
1366 } else 1434 fw_name, ret);
1367 dev_err(dev, "%s: cannot use, skipping\n", fw_name); 1435 kfree(i2400m->fw_hdrs);
1436 i2400m->fw_hdrs = NULL;
1368 release_firmware(fw); 1437 release_firmware(fw);
1438 if (ret >= 0) /* firmware loaded succesfully */
1439 break;
1369 } 1440 }
1370 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); 1441 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
1371 return ret; 1442 return ret;
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index bcb1882ed741..5ac2cce88ba0 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -421,6 +421,9 @@ struct i2400m_barker_db;
421 * @fw_version: version of the firmware interface, Major.minor, 421 * @fw_version: version of the firmware interface, Major.minor,
422 * encoded in the high word and low word (major << 16 | minor). 422 * encoded in the high word and low word (major << 16 | minor).
423 * 423 *
424 * @fw_hdrs: NULL terminated array of pointers to the firmware
425 * headers. This is only available during firmware load time.
426 *
424 * @barker: barker type that the device uses; this is initialized by 427 * @barker: barker type that the device uses; this is initialized by
425 * i2400m_is_boot_barker() the first time it is called. Then it 428 * i2400m_is_boot_barker() the first time it is called. Then it
426 * won't change during the life cycle of the device and everytime 429 * won't change during the life cycle of the device and everytime
@@ -491,6 +494,7 @@ struct i2400m {
491 struct dentry *debugfs_dentry; 494 struct dentry *debugfs_dentry;
492 const char *fw_name; /* name of the current firmware image */ 495 const char *fw_name; /* name of the current firmware image */
493 unsigned long fw_version; /* version of the firmware interface */ 496 unsigned long fw_version; /* version of the firmware interface */
497 const struct i2400m_bcf_hdr **fw_hdrs;
494 struct i2400m_barker_db *barker; 498 struct i2400m_barker_db *barker;
495}; 499};
496 500