iwlwifi: Add TLVs and fields for 16.0 uCode
authorDavid Spinadel <david.spinadel@intel.com>
Sat, 10 Mar 2012 21:00:13 +0000 (13:00 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 12 Mar 2012 18:22:08 +0000 (14:22 -0400)
New TLVs for ucode sections that are not known as
instruction or data.

New TLVs for phy-configuration and default calibrations.

Add default calib and phy config fields to iwl_fw.

Signed-off-by: David Spinadel <david.spinadel@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-shared.h

index a21af3df6c8ac3a442a66981a565af5567c4827b..19ccd36a55b3d441a64773ad09b18aab7eedcf87 100644 (file)
@@ -208,6 +208,25 @@ struct fw_img_parsing {
        int sec_counter;
 };
 
+/*
+ * struct fw_sec_parsing: to extract fw section and it's offset from tlv
+ */
+struct fw_sec_parsing {
+       __le32 offset;
+       const u8 data[];
+} __packed;
+
+/**
+ * struct iwl_tlv_calib_data - parse the default calib data from TLV
+ *
+ * @ucode_type: the uCode to which the following default calib relates.
+ * @calib: default calibrations.
+ */
+struct iwl_tlv_calib_data {
+       __le32 ucode_type;
+       __le64 calib;
+} __packed;
+
 struct iwl_firmware_pieces {
        struct fw_img_parsing img[IWL_UCODE_TYPE_MAX];
 
@@ -257,6 +276,47 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
        pieces->img[type].sec[sec].offset = offset;
 }
 
+/*
+ * Gets uCode section from tlv.
+ */
+static int iwl_store_ucode_sec(struct iwl_firmware_pieces *pieces,
+                              const void *data, enum iwl_ucode_type type,
+                              int size)
+{
+       struct fw_img_parsing *img;
+       struct fw_sec *sec;
+       struct fw_sec_parsing *sec_parse;
+
+       if (WARN_ON(!pieces || !data || type >= IWL_UCODE_TYPE_MAX))
+               return -1;
+
+       sec_parse = (struct fw_sec_parsing *)data;
+
+       img = &pieces->img[type];
+       sec = &img->sec[img->sec_counter];
+
+       sec->offset = le32_to_cpu(sec_parse->offset);
+       sec->data = sec_parse->data;
+
+       ++img->sec_counter;
+
+       return 0;
+}
+
+static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data)
+{
+       struct iwl_tlv_calib_data *def_calib =
+                                       (struct iwl_tlv_calib_data *)data;
+       u32 ucode_type = le32_to_cpu(def_calib->ucode_type);
+       if (ucode_type >= IWL_UCODE_TYPE_MAX) {
+               IWL_ERR(drv, "Wrong ucode_type %u for default calibration.\n",
+                       ucode_type);
+               return -EINVAL;
+       }
+       drv->fw.default_calib[ucode_type] = le64_to_cpu(def_calib->calib);
+       return 0;
+}
+
 static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
                                    const struct firmware *ucode_raw,
                                    struct iwl_firmware_pieces *pieces)
@@ -586,6 +646,29 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                        capa->standard_phy_calibration_size =
                                        le32_to_cpup((__le32 *)tlv_data);
                        break;
+                case IWL_UCODE_TLV_SEC_RT:
+                       iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
+                                           tlv_len);
+                       break;
+               case IWL_UCODE_TLV_SEC_INIT:
+                       iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
+                                           tlv_len);
+                       break;
+               case IWL_UCODE_TLV_SEC_WOWLAN:
+                       iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
+                                           tlv_len);
+                       break;
+               case IWL_UCODE_TLV_DEF_CALIB:
+                       if (tlv_len != sizeof(struct iwl_tlv_calib_data))
+                               goto invalid_tlv_len;
+                       if (iwl_set_default_calib(drv, tlv_data))
+                               goto tlv_error;
+                       break;
+               case IWL_UCODE_TLV_PHY_SKU:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
+                       break;
                default:
                        IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
                        break;
@@ -602,6 +685,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
 
  invalid_tlv_len:
        IWL_ERR(drv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
+ tlv_error:
        iwl_print_hex_dump(drv, IWL_DL_FW, tlv_data, tlv_len);
 
        return -EINVAL;
index 7ca6c952635769c846d6d00ff97c508a7cd214e4..c924ccb93c8ca566bd9286e50ec440957eaf40bd 100644 (file)
@@ -124,6 +124,11 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_WOWLAN_INST       = 16,
        IWL_UCODE_TLV_WOWLAN_DATA       = 17,
        IWL_UCODE_TLV_FLAGS             = 18,
+       IWL_UCODE_TLV_SEC_RT            = 19,
+       IWL_UCODE_TLV_SEC_INIT          = 20,
+       IWL_UCODE_TLV_SEC_WOWLAN        = 21,
+       IWL_UCODE_TLV_DEF_CALIB         = 22,
+       IWL_UCODE_TLV_PHY_SKU           = 23,
 };
 
 struct iwl_ucode_tlv {
index 253f7e501d464c072ca63548dcbdf8eaf87b3240..c99a7fd1d29a5069877694b042d226bace612bf7 100644 (file)
@@ -85,6 +85,22 @@ enum iwl_ucode_tlv_flag {
 #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE                19
 #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE                 253
 
+/**
+ * enum iwl_ucode_type
+ *
+ * The type of ucode.
+ *
+ * @IWL_UCODE_REGULAR: Normal runtime ucode
+ * @IWL_UCODE_INIT: Initial ucode
+ * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode
+ */
+enum iwl_ucode_type {
+       IWL_UCODE_REGULAR,
+       IWL_UCODE_INIT,
+       IWL_UCODE_WOWLAN,
+       IWL_UCODE_TYPE_MAX,
+};
+
 struct iwl_ucode_capabilities {
        u32 max_probe_length;
        u32 standard_phy_calibration_size;
@@ -142,6 +158,9 @@ struct iwl_fw {
 
        u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
        u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+
+       u64 default_calib[IWL_UCODE_TYPE_MAX];
+       u32 phy_config;
 };
 
 #endif  /* __iwl_fw_h__ */
index d899c5c40e07e23202da4eef7132fabd06652f9c..b515d657a0ade1a99675af8c92207403819bbf5c 100644 (file)
@@ -192,22 +192,6 @@ struct iwl_hw_params {
        const struct iwl_sensitivity_ranges *sens;
 };
 
-/**
- * enum iwl_ucode_type
- *
- * The type of ucode.
- *
- * @IWL_UCODE_REGULAR: Normal runtime ucode
- * @IWL_UCODE_INIT: Initial ucode
- * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode
- */
-enum iwl_ucode_type {
-       IWL_UCODE_REGULAR,
-       IWL_UCODE_INIT,
-       IWL_UCODE_WOWLAN,
-       IWL_UCODE_TYPE_MAX,
-};
-
 /*
  * LED mode
  *    IWL_LED_DEFAULT:  use device default