/** * struct iwl_phy_db - stores phy configuration and calibration data. * * @cfg: phy configuration. * @calib_nch: non channel specific calibration data. * @n_group_papd: number of entries in papd channel group. * @calib_ch_group_papd: calibration data related to papd channel group. * @n_group_txp: number of entries in tx power channel group. * @calib_ch_group_txp: calibration data related to tx power chanel group. * @trans: transport layer
*/ struct iwl_phy_db { struct iwl_phy_db_entry cfg; struct iwl_phy_db_entry calib_nch; int n_group_papd; struct iwl_phy_db_entry *calib_ch_group_papd; int n_group_txp; struct iwl_phy_db_entry *calib_ch_group_txp;
/* for parsing of tx power channel group data that comes from the firmware*/ struct iwl_phy_db_chg_txp {
__le32 space;
__le16 max_channel_idx;
} __packed;
/* TODO: add default values of the phy db. */ return phy_db;
}
IWL_EXPORT_SYMBOL(iwl_phy_db_init);
/* * get phy db section: returns a pointer to a phy db section specified by * type and channel group id.
*/ staticstruct iwl_phy_db_entry *
iwl_phy_db_get_section(struct iwl_phy_db *phy_db, enum iwl_phy_db_section_type type,
u16 chg_id)
{ if (!phy_db || type >= IWL_PHY_DB_MAX) return NULL;
switch (type) { case IWL_PHY_DB_CFG: return &phy_db->cfg; case IWL_PHY_DB_CALIB_NCH: return &phy_db->calib_nch; case IWL_PHY_DB_CALIB_CHG_PAPD: if (chg_id >= phy_db->n_group_papd) return NULL; return &phy_db->calib_ch_group_papd[chg_id]; case IWL_PHY_DB_CALIB_CHG_TXP: if (chg_id >= phy_db->n_group_txp) return NULL; return &phy_db->calib_ch_group_txp[chg_id]; default: return NULL;
} return NULL;
}
if (pkt_len < sizeof(*phy_db_notif)) return -EINVAL;
type = le16_to_cpu(phy_db_notif->type);
size = le16_to_cpu(phy_db_notif->length);
if (pkt_len < sizeof(*phy_db_notif) + size) return -EINVAL;
if (!phy_db) return -EINVAL;
if (type == IWL_PHY_DB_CALIB_CHG_PAPD) {
chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); if (phy_db && !phy_db->calib_ch_group_papd) { /* * Firmware sends the largest index first, so we can use * it to know how much we should allocate.
*/
phy_db->calib_ch_group_papd = kcalloc(chg_id + 1, sizeof(struct iwl_phy_db_entry),
GFP_ATOMIC); if (!phy_db->calib_ch_group_papd) return -ENOMEM;
phy_db->n_group_papd = chg_id + 1;
}
} elseif (type == IWL_PHY_DB_CALIB_CHG_TXP) {
chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); if (phy_db && !phy_db->calib_ch_group_txp) { /* * Firmware sends the largest index first, so we can use * it to know how much we should allocate.
*/
phy_db->calib_ch_group_txp = kcalloc(chg_id + 1, sizeof(struct iwl_phy_db_entry),
GFP_ATOMIC); if (!phy_db->calib_ch_group_txp) return -ENOMEM;
phy_db->n_group_txp = chg_id + 1;
}
}
entry = iwl_phy_db_get_section(phy_db, type, chg_id); if (!entry) return -EINVAL;
for (i = 0; i < phy_db->n_group_txp; i++) {
txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; if (!txp_chg) return 0xff; /* * Looking for the first channel group that its max channel is * higher then wanted channel.
*/ if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) return i;
} return 0xff;
} static int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,
u32 type, u8 **data, u16 *size, u16 ch_id)
{ struct iwl_phy_db_entry *entry;
u16 ch_group_id = 0;
/* Send all the channel specific groups to operational fw */ for (i = 0; i < max_ch_groups; i++) {
entry = iwl_phy_db_get_section(phy_db,
type,
i); if (!entry) return -EINVAL;
if (!entry->size) continue;
/* Send the requested PHY DB section */
err = iwl_send_phy_db_cmd(phy_db,
type,
entry->size,
entry->data); if (err) {
IWL_ERR(phy_db->trans, "Can't SEND phy_db section %d (%d), err %d\n",
type, i, err); return err;
}
IWL_DEBUG_INFO(phy_db->trans, "Sent PHY_DB HCMD, type = %d num = %d\n",
type, i);
}
return 0;
}
int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
{
u8 *data = NULL;
u16 size = 0; int err;
IWL_DEBUG_INFO(phy_db->trans, "Sending phy db data and configuration to runtime image\n");
/* Send PHY DB CFG section */
err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG,
&data, &size, 0); if (err) {
IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n"); return err;
}
err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data); if (err) {
IWL_ERR(phy_db->trans, "Cannot send HCMD of Phy DB cfg section\n"); return err;
}
err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH,
&data, &size, 0); if (err) {
IWL_ERR(phy_db->trans, "Cannot get Phy DB non specific channel section\n"); return err;
}
err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data); if (err) {
IWL_ERR(phy_db->trans, "Cannot send HCMD of Phy DB non specific channel section\n"); return err;
}
/* Send all the TXP channel specific data */
err = iwl_phy_db_send_all_channel_groups(phy_db,
IWL_PHY_DB_CALIB_CHG_PAPD,
phy_db->n_group_papd); if (err) {
IWL_ERR(phy_db->trans, "Cannot send channel specific PAPD groups\n"); return err;
}
/* Send all the TXP channel specific data */
err = iwl_phy_db_send_all_channel_groups(phy_db,
IWL_PHY_DB_CALIB_CHG_TXP,
phy_db->n_group_txp); if (err) {
IWL_ERR(phy_db->trans, "Cannot send channel specific TX power groups\n"); return err;
}
IWL_DEBUG_INFO(phy_db->trans, "Finished sending phy db non channel data\n"); return 0;
}
IWL_EXPORT_SYMBOL(iwl_send_phy_db_data);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.