+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
+ ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
+ if (ret)
+ goto out;
+
+ priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
+
+ /* The firmware release is in an interesting format: the patch
+ * level is in the most significant nibble ... so fix that: */
+ priv->fwrelease = le32_to_cpu(cmd.fwrelease);
+ priv->fwrelease = (priv->fwrelease << 8) |
+ (priv->fwrelease >> 24 & 0xff);
+
+ /* Some firmware capabilities:
+ * CF card firmware 5.0.16p0: cap 0x00000303
+ * USB dongle firmware 5.110.17p2: cap 0x00000303
+ */
+ lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ cmd.permanentaddr,
+ priv->fwrelease >> 24 & 0xff,
+ priv->fwrelease >> 16 & 0xff,
+ priv->fwrelease >> 8 & 0xff,
+ priv->fwrelease & 0xff,
+ priv->fwcapinfo);
+ lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
+ cmd.hwifversion, cmd.version);
+
+ /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+ /* 5.110.22 have mesh command with 0xa3 command id */
+ /* 10.0.0.p0 FW brings in mesh config command with different id */
+ /* Check FW version MSB and initialize mesh_fw_ver */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
+ priv->mesh_fw_ver = MESH_FW_OLD;
+ else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+ (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
+ priv->mesh_fw_ver = MESH_FW_NEW;
+ else
+ priv->mesh_fw_ver = MESH_NONE;
+
+ /* Clamp region code to 8-bit since FW spec indicates that it should
+ * only ever be 8-bit, even though the field size is 16-bit. Some firmware
+ * returns non-zero high 8 bits here.
+ *
+ * Firmware version 4.0.102 used in CF8381 has region code shifted. We
+ * need to check for this problem and handle it properly.
+ */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
+ priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
+ else
+ priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* use the region code to search for the index */
+ if (priv->regioncode == lbs_region_code_to_index[i])
+ break;
+ }
+
+ /* if it's unidentified region code, use the default (USA) */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ priv->regioncode = 0x10;
+ lbs_pr_info("unidentified region code; using the default (USA)\n");
+ }
+
+ if (priv->current_addr[0] == 0xff)
+ memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);