svn commit: r215562 - stable/8/sys/dev/iwn
Bernhard Schmidt
bschmidt at FreeBSD.org
Sat Nov 20 13:13:00 UTC 2010
Author: bschmidt
Date: Sat Nov 20 13:12:59 2010
New Revision: 215562
URL: http://svn.freebsd.org/changeset/base/215562
Log:
MFC r212853-212855:
Rewrite parts of the calibration code which is run while bringing up
the device:
- Group functions used for initial calibration.
- Unobscure some of the code by moving it into its own functions.
- Get rid of some magic numbers.
- Create similar structure as the reference driver has, this should
make further syncs easier.
Modified:
stable/8/sys/dev/iwn/if_iwn.c
stable/8/sys/dev/iwn/if_iwnvar.h
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
stable/8/sys/dev/xen/xenpci/ (props changed)
Modified: stable/8/sys/dev/iwn/if_iwn.c
==============================================================================
--- stable/8/sys/dev/iwn/if_iwn.c Sat Nov 20 12:59:01 2010 (r215561)
+++ stable/8/sys/dev/iwn/if_iwn.c Sat Nov 20 13:12:59 2010 (r215562)
@@ -135,8 +135,6 @@ static void iwn_rx_done(struct iwn_softc
static void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
#endif
-static void iwn5000_rx_calib_results(struct iwn_softc *,
- struct iwn_rx_desc *, struct iwn_rx_data *);
static void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
static void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
@@ -220,8 +218,14 @@ static void iwn5000_ampdu_tx_start(struc
struct ieee80211_node *, uint8_t, uint16_t);
static void iwn5000_ampdu_tx_stop(struct iwn_softc *, uint8_t, uint16_t);
#endif
-static int iwn5000_query_calibration(struct iwn_softc *);
-static int iwn5000_send_calibration(struct iwn_softc *);
+static int iwn5000_send_calib_results(struct iwn_softc *);
+static int iwn5000_save_calib_result(struct iwn_softc *,
+ struct iwn_phy_calib *, int, int);
+static void iwn5000_free_calib_results(struct iwn_softc *);
+static int iwn5000_chrystal_calib(struct iwn_softc *);
+static int iwn5000_send_calib_query(struct iwn_softc *);
+static int iwn5000_rx_calib_result(struct iwn_softc *,
+ struct iwn_rx_desc *, struct iwn_rx_data *);
static int iwn5000_send_wimax_coex(struct iwn_softc *);
static int iwn4965_post_alive(struct iwn_softc *);
static int iwn5000_post_alive(struct iwn_softc *);
@@ -704,6 +708,9 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn5000fw";
sc->txchainmask = IWN_ANT_B;
sc->rxchainmask = IWN_ANT_AB;
+ sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
+ IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC |
+ IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_5150:
sc->sc_hal = &iwn5000_hal;
@@ -711,6 +718,8 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn5150fw";
sc->txchainmask = IWN_ANT_A;
sc->rxchainmask = IWN_ANT_AB;
+ sc->calib_init = IWN_CALIB_DC | IWN_CALIB_LO |
+ IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_5300:
case IWN_HW_REV_TYPE_5350:
@@ -719,6 +728,9 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn5000fw";
sc->txchainmask = IWN_ANT_ABC;
sc->rxchainmask = IWN_ANT_ABC;
+ sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
+ IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC |
+ IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_1000:
sc->sc_hal = &iwn5000_hal;
@@ -726,6 +738,9 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn1000fw";
sc->txchainmask = IWN_ANT_A;
sc->rxchainmask = IWN_ANT_AB;
+ sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
+ IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC |
+ IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_6000:
sc->sc_hal = &iwn5000_hal;
@@ -743,6 +758,8 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->rxchainmask = IWN_ANT_ABC;
break;
}
+ sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
+ IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_6050:
sc->sc_hal = &iwn5000_hal;
@@ -750,6 +767,8 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn6050fw";
sc->txchainmask = IWN_ANT_AB;
sc->rxchainmask = IWN_ANT_AB;
+ sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_DC | IWN_CALIB_LO |
+ IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
break;
case IWN_HW_REV_TYPE_6005:
sc->sc_hal = &iwn5000_hal;
@@ -757,6 +776,8 @@ iwn_hal_attach(struct iwn_softc *sc)
sc->fwname = "iwn6005fw";
sc->txchainmask = IWN_ANT_AB;
sc->rxchainmask = IWN_ANT_AB;
+ sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO |
+ IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND;
break;
default:
device_printf(sc->sc_dev, "adapter type %d not supported\n",
@@ -841,6 +862,8 @@ iwn_cleanup(device_t dev)
ieee80211_ifdetach(ic);
}
+ iwn5000_free_calib_results(sc);
+
/* Free DMA resources. */
iwn_free_rx_ring(sc, &sc->rxq);
if (sc->sc_hal != NULL)
@@ -1696,12 +1719,6 @@ iwn5000_read_eeprom(struct iwn_softc *sc
sc->temp_off = temp - (volt / -5);
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "temp=%d volt=%d offset=%dK\n",
temp, volt, sc->temp_off);
- } else {
- /* Read crystal calibration. */
- iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL,
- &sc->eeprom_crystal, sizeof (uint32_t));
- DPRINTF(sc, IWN_DEBUG_CALIBRATE, "crystal calibration 0x%08x\n",
- le32toh(sc->eeprom_crystal));
}
}
@@ -2195,64 +2212,6 @@ iwn_rx_compressed_ba(struct iwn_softc *s
#endif
/*
- * Process a CALIBRATION_RESULT notification sent by the initialization
- * firmware on response to a CMD_CALIB_CONFIG command (5000 only.)
- */
-static void
-iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc,
- struct iwn_rx_data *data)
-{
- struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1);
- int len, idx = -1;
-
- /* Runtime firmware should not send such a notification. */
- if (sc->sc_flags & IWN_FLAG_CALIB_DONE)
- return;
-
- bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
- len = (le32toh(desc->len) & 0x3fff) - 4;
-
- switch (calib->code) {
- case IWN5000_PHY_CALIB_DC:
- if (sc->hw_type == IWN_HW_REV_TYPE_5150 ||
- sc->hw_type == IWN_HW_REV_TYPE_6050)
- idx = 0;
- break;
- case IWN5000_PHY_CALIB_LO:
- idx = 1;
- break;
- case IWN5000_PHY_CALIB_TX_IQ:
- idx = 2;
- break;
- case IWN5000_PHY_CALIB_TX_IQ_PERIODIC:
- if (sc->hw_type < IWN_HW_REV_TYPE_6000 &&
- sc->hw_type != IWN_HW_REV_TYPE_5150)
- idx = 3;
- break;
- case IWN5000_PHY_CALIB_BASE_BAND:
- idx = 4;
- break;
- }
- if (idx == -1) /* Ignore other results. */
- return;
-
- /* Save calibration result. */
- if (sc->calibcmd[idx].buf != NULL)
- free(sc->calibcmd[idx].buf, M_DEVBUF);
- sc->calibcmd[idx].buf = malloc(len, M_DEVBUF, M_NOWAIT);
- if (sc->calibcmd[idx].buf == NULL) {
- DPRINTF(sc, IWN_DEBUG_CALIBRATE,
- "not enough memory for calibration result %d\n",
- calib->code);
- return;
- }
- DPRINTF(sc, IWN_DEBUG_CALIBRATE,
- "saving calibration result code=%d len=%d\n", calib->code, len);
- sc->calibcmd[idx].len = len;
- memcpy(sc->calibcmd[idx].buf, calib, len);
-}
-
-/*
* Process an RX_STATISTICS or BEACON_STATISTICS firmware notification.
* The latter is sent by the firmware after each received beacon.
*/
@@ -2607,7 +2566,7 @@ iwn_notif_intr(struct iwn_softc *sc)
break;
}
case IWN5000_CALIBRATION_RESULT:
- iwn5000_rx_calib_results(sc, desc, data);
+ iwn5000_rx_calib_result(sc, desc, data);
break;
case IWN5000_CALIBRATION_DONE:
@@ -5238,22 +5197,140 @@ iwn5000_ampdu_tx_stop(struct iwn_softc *
#endif
/*
- * Query calibration tables from the initialization firmware. We do this
- * only once at first boot. Called from a process context.
+ * Send calibration results to the runtime firmware. These results were
+ * obtained on first boot from the initialization firmware, or by reading
+ * the EEPROM for crystal calibration.
*/
static int
-iwn5000_query_calibration(struct iwn_softc *sc)
+iwn5000_send_calib_results(struct iwn_softc *sc)
{
+ struct iwn_calib_info *calib_result;
+ int idx, error;
+
+ for (idx = 0; idx < IWN_CALIB_NUM; idx++) {
+ calib_result = &sc->calib_results[idx];
+
+ /* No support for this type of calibration. */
+ if ((sc->calib_init & (1 << idx)) == 0)
+ continue;
+
+ /* No calibration result available. */
+ if (calib_result->buf == NULL)
+ continue;
+
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+ "%s: send calibration result idx=%d, len=%d\n",
+ __func__, idx, calib_result->len);
+
+ error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, calib_result->buf,
+ calib_result->len, 0);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not send calibration result "
+ "idx=%d, error=%d\n",
+ __func__, idx, error);
+ return error;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Save calibration result at the given index. The index determines
+ * in which order the results are sent to the runtime firmware.
+ */
+static int
+iwn5000_save_calib_result(struct iwn_softc *sc, struct iwn_phy_calib *calib,
+ int len, int idx)
+{
+ struct iwn_calib_info *calib_result = &sc->calib_results[idx];
+
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+ "%s: saving calibration result code=%d, idx=%d, len=%d\n",
+ __func__, calib->code, idx, len);
+
+ if (calib_result->buf != NULL)
+ free(calib_result->buf, M_DEVBUF);
+
+ calib_result->buf = malloc(len, M_DEVBUF, M_NOWAIT);
+ if (calib_result->buf == NULL) {
+ device_printf(sc->sc_dev,
+ "%s: not enough memory for calibration result "
+ "code=%d, len=%d\n", __func__, calib->code, len);
+ return ENOMEM;
+ }
+
+ calib_result->len = len;
+ memcpy(calib_result->buf, calib, len);
+ return 0;
+}
+
+static void
+iwn5000_free_calib_results(struct iwn_softc *sc)
+{
+ struct iwn_calib_info *calib_result;
+ int idx;
+
+ for (idx = 0; idx < IWN_CALIB_NUM; idx++) {
+ calib_result = &sc->calib_results[idx];
+
+ if (calib_result->buf != NULL)
+ free(calib_result->buf, M_DEVBUF);
+
+ calib_result->buf = NULL;
+ calib_result->len = 0;
+ }
+}
+
+/*
+ * Obtain the crystal calibration result from the EEPROM.
+ */
+static int
+iwn5000_chrystal_calib(struct iwn_softc *sc)
+{
+ struct iwn5000_phy_calib_crystal cmd;
+ uint32_t base, crystal;
+ uint16_t val;
+
+ /* Read crystal calibration. */
+ iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2);
+ base = le16toh(val);
+ iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, &crystal,
+ sizeof(uint32_t));
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: crystal calibration=0x%08x\n",
+ __func__, le32toh(crystal));
+
+ memset(&cmd, 0, sizeof cmd);
+ cmd.code = IWN5000_PHY_CALIB_CRYSTAL;
+ cmd.ngroups = 1;
+ cmd.isvalid = 1;
+ cmd.cap_pin[0] = le32toh(crystal) & 0xff;
+ cmd.cap_pin[1] = (le32toh(crystal) >> 16) & 0xff;
+
+ return iwn5000_save_calib_result(sc, (struct iwn_phy_calib *)&cmd,
+ sizeof cmd, IWN_CALIB_IDX_XTAL);
+}
+
+/*
+ * Query calibration results from the initialization firmware. We do this
+ * only once at first boot.
+ */
+static int
+iwn5000_send_calib_query(struct iwn_softc *sc)
+{
+#define CALIB_INIT_CFG 0xffffffff;
struct iwn5000_calib_config cmd;
int error;
memset(&cmd, 0, sizeof cmd);
- cmd.ucode.once.enable = 0xffffffff;
- cmd.ucode.once.start = 0xffffffff;
- cmd.ucode.once.send = 0xffffffff;
- cmd.ucode.flags = 0xffffffff;
- DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n",
+ cmd.ucode.once.enable = CALIB_INIT_CFG;
+ cmd.ucode.once.start = CALIB_INIT_CFG;
+ cmd.ucode.once.send = CALIB_INIT_CFG;
+ cmd.ucode.flags = CALIB_INIT_CFG;
+
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: query calibration results\n",
__func__);
+
error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0);
if (error != 0)
return error;
@@ -5261,34 +5338,56 @@ iwn5000_query_calibration(struct iwn_sof
/* Wait at most two seconds for calibration to complete. */
if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE))
error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", 2 * hz);
+
return error;
+#undef CALIB_INIT_CFG
}
/*
- * Send calibration results to the runtime firmware. These results were
- * obtained on first boot from the initialization firmware.
+ * Process a CALIBRATION_RESULT notification sent by the initialization
+ * firmware on response to a CMD_CALIB_CONFIG command.
*/
static int
-iwn5000_send_calibration(struct iwn_softc *sc)
+iwn5000_rx_calib_result(struct iwn_softc *sc, struct iwn_rx_desc *desc,
+ struct iwn_rx_data *data)
{
- int idx, error;
+#define FRAME_SIZE_MASK 0x3fff
+ struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1);
+ int len, idx;
- for (idx = 0; idx < 5; idx++) {
- if (sc->calibcmd[idx].buf == NULL)
- continue; /* No results available. */
+ bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
+ len = (le32toh(desc->len) & FRAME_SIZE_MASK);
+
+ /* Remove length field itself. */
+ len -= 4;
+
+ /*
+ * Determine the order in which the results will be send to the
+ * runtime firmware.
+ */
+ switch (calib->code) {
+ case IWN5000_PHY_CALIB_DC:
+ idx = IWN_CALIB_IDX_DC;
+ break;
+ case IWN5000_PHY_CALIB_LO:
+ idx = IWN_CALIB_IDX_LO;
+ break;
+ case IWN5000_PHY_CALIB_TX_IQ:
+ idx = IWN_CALIB_IDX_TX_IQ;
+ break;
+ case IWN5000_PHY_CALIB_TX_IQ_PERIODIC:
+ idx = IWN_CALIB_IDX_TX_IQ_PERIODIC;
+ break;
+ case IWN5000_PHY_CALIB_BASE_BAND:
+ idx = IWN_CALIB_IDX_BASE_BAND;
+ break;
+ default:
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
- "send calibration result idx=%d len=%d\n",
- idx, sc->calibcmd[idx].len);
- error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf,
- sc->calibcmd[idx].len, 0);
- if (error != 0) {
- device_printf(sc->sc_dev,
- "%s: could not send calibration result, error %d\n",
- __func__, error);
- return error;
- }
+ "%s: unknown calibration code=%d\n", __func__, calib->code);
+ return EINVAL;
}
- return 0;
+ return iwn5000_save_calib_result(sc, calib, len, idx);
+#undef FRAME_SIZE_MASK
}
static int
@@ -5434,36 +5533,40 @@ iwn5000_post_alive(struct iwn_softc *sc)
__func__, error);
return error;
}
- if (sc->hw_type != IWN_HW_REV_TYPE_5150) {
- struct iwn5000_phy_calib_crystal cmd;
- /* Perform crystal calibration. */
- memset(&cmd, 0, sizeof cmd);
- cmd.code = IWN5000_PHY_CALIB_CRYSTAL;
- cmd.ngroups = 1;
- cmd.isvalid = 1;
- cmd.cap_pin[0] = le32toh(sc->eeprom_crystal) & 0xff;
- cmd.cap_pin[1] = (le32toh(sc->eeprom_crystal) >> 16) & 0xff;
- DPRINTF(sc, IWN_DEBUG_CALIBRATE,
- "sending crystal calibration %d, %d\n",
- cmd.cap_pin[0], cmd.cap_pin[1]);
- error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
+ if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) {
+ /*
+ * Start calibration by setting and sending the chrystal
+ * calibration first, this must be done before we are able
+ * to query the other calibration results.
+ */
+ error = iwn5000_chrystal_calib(sc);
if (error != 0) {
device_printf(sc->sc_dev,
- "%s: crystal calibration failed, error %d\n",
- __func__, error);
+ "%s: could not set chrystal calibration, "
+ "error=%d\n", __func__, error);
return error;
}
- }
- if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) {
- /* Query calibration from the initialization firmware. */
- error = iwn5000_query_calibration(sc);
+ error = iwn5000_send_calib_results(sc);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not send chrystal calibration, "
+ "error=%d\n", __func__, error);
+ return error;
+ }
+
+ /*
+ * Query other calibration results from the initialization
+ * firmware.
+ */
+ error = iwn5000_send_calib_query(sc);
if (error != 0) {
device_printf(sc->sc_dev,
- "%s: could not query calibration, error %d\n",
+ "%s: could not query calibration, error=%d\n",
__func__, error);
return error;
}
+
/*
* We have the calibration results now, reboot with the
* runtime firmware (call ourselves recursively!)
@@ -5471,8 +5574,11 @@ iwn5000_post_alive(struct iwn_softc *sc)
iwn_hw_stop(sc);
error = iwn_hw_init(sc);
} else {
- /* Send calibration results to runtime firmware. */
- error = iwn5000_send_calibration(sc);
+ /*
+ * Send calibration results obtained from the initialization
+ * firmware to the runtime firmware.
+ */
+ error = iwn5000_send_calib_results(sc);
}
return error;
}
Modified: stable/8/sys/dev/iwn/if_iwnvar.h
==============================================================================
--- stable/8/sys/dev/iwn/if_iwnvar.h Sat Nov 20 12:59:01 2010 (r215561)
+++ stable/8/sys/dev/iwn/if_iwnvar.h Sat Nov 20 13:12:59 2010 (r215562)
@@ -263,9 +263,23 @@ struct iwn_softc {
int calib_cnt;
struct iwn_calib_state calib;
+ u_int calib_init;
+#define IWN_CALIB_XTAL (1 << IWN_CALIB_IDX_XTAL)
+#define IWN_CALIB_DC (1 << IWN_CALIB_IDX_DC)
+#define IWN_CALIB_LO (1 << IWN_CALIB_IDX_LO)
+#define IWN_CALIB_TX_IQ (1 << IWN_CALIB_IDX_TX_IQ)
+#define IWN_CALIB_TX_IQ_PERIODIC (1 << IWN_CALIB_IDX_TX_IQ_PERIODIC)
+#define IWN_CALIB_BASE_BAND (1 << IWN_CALIB_IDX_BASE_BAND)
+#define IWN_CALIB_NUM 6
+ struct iwn_calib_info calib_results[IWN_CALIB_NUM];
+#define IWN_CALIB_IDX_XTAL 0
+#define IWN_CALIB_IDX_DC 1
+#define IWN_CALIB_IDX_LO 2
+#define IWN_CALIB_IDX_TX_IQ 3
+#define IWN_CALIB_IDX_TX_IQ_PERIODIC 4
+#define IWN_CALIB_IDX_BASE_BAND 5
struct iwn_fw_info fw;
- struct iwn_calib_info calibcmd[5];
uint32_t errptr;
struct iwn_rx_stat last_rx_stat;
@@ -284,7 +298,6 @@ struct iwn_softc {
uint16_t rfcfg;
uint8_t calib_ver;
char eeprom_domain[4];
- uint32_t eeprom_crystal;
int16_t eeprom_voltage;
int8_t maxpwr2GHz;
int8_t maxpwr5GHz;
More information about the svn-src-all
mailing list