[haiku-commits] r41223 - haiku/vendor/freebsd/current/dev/iwn

  • From: korli@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 11 Apr 2011 20:03:02 +0200 (CEST)

Author: korli
Date: 2011-04-11 20:03:02 +0200 (Mon, 11 Apr 2011)
New Revision: 41223
Changeset: https://dev.haiku-os.org/changeset/41223

Modified:
   haiku/vendor/freebsd/current/dev/iwn/if_iwn.c
   haiku/vendor/freebsd/current/dev/iwn/if_iwnreg.h
   haiku/vendor/freebsd/current/dev/iwn/if_iwnvar.h
Log:
updating to FreeBSD 8.2 release

Modified: haiku/vendor/freebsd/current/dev/iwn/if_iwn.c
===================================================================
--- haiku/vendor/freebsd/current/dev/iwn/if_iwn.c       2011-04-11 18:02:55 UTC 
(rev 41222)
+++ haiku/vendor/freebsd/current/dev/iwn/if_iwn.c       2011-04-11 18:03:02 UTC 
(rev 41223)
@@ -122,7 +122,6 @@
 static void    iwn_read_eeprom_enhinfo(struct iwn_softc *);
 static struct ieee80211_node *iwn_node_alloc(struct ieee80211vap *,
                    const uint8_t mac[IEEE80211_ADDR_LEN]);
-static void    iwn_newassoc(struct ieee80211_node *, int);
 static int     iwn_media_change(struct ifnet *);
 static int     iwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void    iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
@@ -135,8 +134,6 @@
 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 +217,14 @@
                    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 *, uint32_t);
+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 *);
@@ -231,6 +234,10 @@
 static int     iwn5000_load_firmware_section(struct iwn_softc *, uint32_t,
                    const uint8_t *, int);
 static int     iwn5000_load_firmware(struct iwn_softc *);
+static int     iwn_read_firmware_leg(struct iwn_softc *,
+                   struct iwn_fw_info *);
+static int     iwn_read_firmware_tlv(struct iwn_softc *,
+                   struct iwn_fw_info *, uint16_t);
 static int     iwn_read_firmware(struct iwn_softc *);
 static int     iwn_clock_wait(struct iwn_softc *);
 static int     iwn_apm_init(struct iwn_softc *);
@@ -310,7 +317,6 @@
        { 0x8086, 0x423D, "Intel(R) PRO/Wireless 5150" },
        { 0x8086, 0x4235, "Intel(R) PRO/Wireless 5300" },
        { 0x8086, 0x4236, "Intel(R) PRO/Wireless 5300" },
-       { 0x8086, 0x4236, "Intel(R) PRO/Wireless 5350" },
        { 0x8086, 0x423A, "Intel(R) PRO/Wireless 5350" },
        { 0x8086, 0x423B, "Intel(R) PRO/Wireless 5350" },
        { 0x8086, 0x0083, "Intel(R) PRO/Wireless 1000" },
@@ -321,8 +327,17 @@
        { 0x8086, 0x4239, "Intel(R) PRO/Wireless 6000" },
        { 0x8086, 0x422B, "Intel(R) PRO/Wireless 6000" },
        { 0x8086, 0x422C, "Intel(R) PRO/Wireless 6000" },
-       { 0x8086, 0x0086, "Intel(R) PRO/Wireless 6050" },
-       { 0x8086, 0x0087, "Intel(R) PRO/Wireless 6050" },
+       { 0x8086, 0x0087, "Intel(R) PRO/Wireless 6250" },
+       { 0x8086, 0x0089, "Intel(R) PRO/Wireless 6250" },
+       { 0x8086, 0x0082, "Intel(R) PRO/Wireless 6205a" },
+       { 0x8086, 0x0085, "Intel(R) PRO/Wireless 6205a" },
+#ifdef notyet
+       { 0x8086, 0x008a, "Intel(R) PRO/Wireless 6205b" },
+       { 0x8086, 0x008b, "Intel(R) PRO/Wireless 6205b" },
+       { 0x8086, 0x008f, "Intel(R) PRO/Wireless 6205b" },
+       { 0x8086, 0x0090, "Intel(R) PRO/Wireless 6205b" },
+       { 0x8086, 0x0091, "Intel(R) PRO/Wireless 6205b" },
+#endif
        { 0, 0, NULL }
 };
 
@@ -627,8 +642,8 @@
        ifp->if_init = iwn_init;
        ifp->if_ioctl = iwn_ioctl;
        ifp->if_start = iwn_start;
-       IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
-       ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+       IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+       ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
        IFQ_SET_READY(&ifp->if_snd);
 
        ieee80211_ifattach(ic, macaddr);
@@ -636,7 +651,6 @@
        ic->ic_vap_delete = iwn_vap_delete;
        ic->ic_raw_xmit = iwn_raw_xmit;
        ic->ic_node_alloc = iwn_node_alloc;
-       ic->ic_newassoc = iwn_newassoc;
        ic->ic_wme.wme_update = iwn_wme_update;
        ic->ic_update_mcast = iwn_update_mcast;
        ic->ic_scan_start = iwn_scan_start;
@@ -692,6 +706,9 @@
                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;
@@ -699,6 +716,8 @@
                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:
@@ -707,6 +726,9 @@
                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;
@@ -714,6 +736,9 @@
                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;
@@ -729,16 +754,32 @@
                default:
                        sc->txchainmask = IWN_ANT_ABC;
                        sc->rxchainmask = IWN_ANT_ABC;
+                       sc->calib_runtime = IWN_CALIB_DC;
                        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;
                sc->limits = &iwn6000_sensitivity_limits;
-               sc->fwname = "iwn6000fw";
+               sc->fwname = "iwn6050fw";
                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;
+               sc->calib_runtime = IWN_CALIB_DC;
                break;
+       case IWN_HW_REV_TYPE_6005:
+               sc->sc_hal = &iwn5000_hal;
+               sc->limits = &iwn6000_sensitivity_limits;
+               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;
+               sc->calib_runtime = IWN_CALIB_DC;
+               break;
        default:
                device_printf(sc->sc_dev, "adapter type %d not supported\n",
                    sc->hw_type);
@@ -822,6 +863,8 @@
                ieee80211_ifdetach(ic);
        }
 
+       iwn5000_free_calib_results(sc);
+
        /* Free DMA resources. */
        iwn_free_rx_ring(sc, &sc->rxq);
        if (sc->sc_hal != NULL)
@@ -1666,7 +1709,7 @@
        DPRINTF(sc, IWN_DEBUG_CALIBRATE,
            "%s: calib version=%u pa type=%u voltage=%u\n",
            __func__, hdr.version, hdr.pa_type, le16toh(hdr.volt));
-           sc->calib_ver = hdr.version;
+       sc->calib_ver = hdr.version;
 
        if (sc->hw_type == IWN_HW_REV_TYPE_5150) {
                /* Compute temperature offset. */
@@ -1677,12 +1720,6 @@
                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));
        }
 }
 
@@ -1890,13 +1927,6 @@
        return malloc(sizeof (struct iwn_node), M_80211_NODE,M_NOWAIT | M_ZERO);
 }
 
-static void
-iwn_newassoc(struct ieee80211_node *ni, int isnew)
-{
-       /* XXX move */
-       ieee80211_ratectl_node_init(ni);
-}
-
 static int
 iwn_media_change(struct ifnet *ifp)
 {
@@ -1921,28 +1951,46 @@
        IWN_LOCK(sc);
        callout_stop(&sc->sc_timer_to);
 
-       if (nstate == IEEE80211_S_AUTH && vap->iv_state != IEEE80211_S_AUTH) {
-               /* !AUTH -> AUTH requires adapter config */
-               /* Reset state to handle reassociations correctly. */
+       switch (nstate) {
+       case IEEE80211_S_ASSOC:
+               if (vap->iv_state != IEEE80211_S_RUN)
+                       break;
+               /* FALLTHROUGH */
+       case IEEE80211_S_AUTH:
+               if (vap->iv_state == IEEE80211_S_AUTH)
+                       break;
+
+               /*
+                * !AUTH -> AUTH transition requires state reset to handle
+                * reassociations correctly.
+                */
                sc->rxon.associd = 0;
                sc->rxon.filter &= ~htole32(IWN_FILTER_BSS);
                iwn_calib_reset(sc);
                error = iwn_auth(sc, vap);
-       }
-       if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) {
+               break;
+
+       case IEEE80211_S_RUN:
                /*
+                * RUN -> RUN transition; Just restart the timers.
+                */
+               if (vap->iv_state == IEEE80211_S_RUN &&
+                   vap->iv_opmode != IEEE80211_M_MONITOR) {
+                       iwn_calib_reset(sc);
+                       break;
+               }
+
+               /*
                 * !RUN -> RUN requires setting the association id
                 * which is done with a firmware cmd.  We also defer
                 * starting the timers until that work is done.
                 */
                error = iwn_run(sc, vap);
+               break;
+
+       default:
+               break;
        }
-       if (nstate == IEEE80211_S_RUN) {
-               /*
-                * RUN -> RUN transition; just restart the timers.
-                */
-               iwn_calib_reset(sc);
-       }
        IWN_UNLOCK(sc);
        IEEE80211_LOCK(ic);
        return ivp->iv_newstate(vap, nstate, arg);
@@ -2159,64 +2207,6 @@
 #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.
  */
@@ -2571,7 +2561,7 @@
                        break;
                }
                case IWN5000_CALIBRATION_RESULT:
-                       iwn5000_rx_calib_results(sc, desc, data);
+                       iwn5000_rx_calib_result(sc, desc, data);
                        break;
 
                case IWN5000_CALIBRATION_DONE:
@@ -3007,7 +2997,7 @@
                txant = IWN_LSB(sc->txchainmask);
                tx->rflags |= IWN_RFLAG_ANT(txant);
        } else {
-               tx->linkq = 0;
+               tx->linkq = IWN_RIDX_OFDM54 - ridx;
                flags |= IWN_TX_LINKQ;  /* enable MRR */
        }
 
@@ -4119,10 +4109,14 @@
        val = MAX(calib->rssi[2], val);
 
        /* Determine which antennas are connected. */
-       sc->chainmask = 0;
+       sc->chainmask = sc->rxchainmask;
        for (i = 0; i < 3; i++)
-               if (val - calib->rssi[i] <= 15 * 20)
-                       sc->chainmask |= 1 << i;
+               if (val - calib->rssi[i] > 15 * 20)
+                       sc->chainmask &= ~(1 << i);
+       DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+           "%s: RX chains mask: theoretical=0x%x, actual=0x%x\n",
+           __func__, sc->rxchainmask, sc->chainmask);
+
        /* If none of the TX antennas are connected, keep at least one. */
        if ((sc->chainmask & sc->txchainmask) == 0)
                sc->chainmask |= IWN_LSB(sc->txchainmask);
@@ -4849,11 +4843,9 @@
        struct iwn_node_info node;
        int error;
 
-       sc->calib.state = IWN_CALIB_STATE_INIT;
-
        if (ic->ic_opmode == IEEE80211_M_MONITOR) {
                /* Link LED blinks while monitoring. */
-               iwn_set_led(sc, IWN_LED_LINK, 5, 5);
+               iwn_set_led(sc, IWN_LED_LINK, 20, 20);
                return 0;
        }
        error = iwn_set_timing(sc, ni);
@@ -5198,22 +5190,143 @@
 #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, uint32_t cfg)
+{
+#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",
-           __func__);
+       cmd.ucode.once.enable = CALIB_INIT_CFG;
+       if (cfg == 0) {
+               cmd.ucode.once.start  = CALIB_INIT_CFG;
+               cmd.ucode.once.send   = CALIB_INIT_CFG;
+               cmd.ucode.flags       = CALIB_INIT_CFG;
+       } else
+               cmd.ucode.once.start  = cfg;
+
+       DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+           "%s: query calibration results, cfg %x\n", __func__, cfg);
+
        error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0);
        if (error != 0)
                return error;
@@ -5221,34 +5334,56 @@
        /* 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
@@ -5394,36 +5529,40 @@
                    __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 query calibration, error %d\n",
+                           "%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, 0);
+               if (error != 0) {
+                       device_printf(sc->sc_dev,
+                           "%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!)
@@ -5431,8 +5570,24 @@
                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);
+
+               /*
+                * Tell the runtime firmware to do certain calibration types.
+                */
+               if (sc->calib_runtime != 0) {
+                       error = iwn5000_send_calib_query(sc, sc->calib_runtime);
+                       if (error != 0) {
+                               device_printf(sc->sc_dev,
+                                   "%s: could not send query calibration, "
+                                   "error=%d, cfg=%x\n", __func__, error,
+                                   sc->calib_runtime);
+                       }
+               }
        }
        return error;
 }
@@ -5625,39 +5780,19 @@
        return 0;
 }
 
+/*
+ * Extract text and data sections from a legacy firmware image.
+ */
 static int
-iwn_read_firmware(struct iwn_softc *sc)
+iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw)
 {
-       const struct iwn_hal *hal = sc->sc_hal;
-       struct iwn_fw_info *fw = &sc->fw;
        const uint32_t *ptr;
+       size_t hdrlen = 24;
        uint32_t rev;
-       size_t size;
 
-       IWN_UNLOCK(sc);
-
-       /* Read firmware image from filesystem. */
-       sc->fw_fp = firmware_get(sc->fwname);
-       if (sc->fw_fp == NULL) {
-               device_printf(sc->sc_dev,
-                   "%s: could not load firmare image \"%s\"\n", __func__,
-                   sc->fwname);
-               IWN_LOCK(sc);
-               return EINVAL;
-       }
-       IWN_LOCK(sc);
-
-       size = sc->fw_fp->datasize;
-       if (size < 28) {
-               device_printf(sc->sc_dev,
-                   "%s: truncated firmware header: %zu bytes\n",
-                   __func__, size);
-               return EINVAL;
-       }
-
-       /* Process firmware header. */
        ptr = (const uint32_t *)sc->fw_fp->data;
        rev = le32toh(*ptr++);
+
        /* Check firmware API version. */
        if (IWN_FW_API(rev) <= 1) {
                device_printf(sc->sc_dev,
@@ -5666,34 +5801,27 @@
        }
        if (IWN_FW_API(rev) >= 3) {
                /* Skip build number (version 2 header). */
-               size -= 4;
+               hdrlen += 4;
                ptr++;
        }
+       if (fw->size < hdrlen) {
+               device_printf(sc->sc_dev,
+                   "%s: firmware file too short: %zu bytes\n",
+                   __func__, fw->size);
+               return EINVAL;
+       }
        fw->main.textsz = le32toh(*ptr++);
        fw->main.datasz = le32toh(*ptr++);
        fw->init.textsz = le32toh(*ptr++);
        fw->init.datasz = le32toh(*ptr++);
        fw->boot.textsz = le32toh(*ptr++);
-       size -= 24;
 
-       /* Sanity-check firmware header. */
-       if (fw->main.textsz > hal->fw_text_maxsz ||
-           fw->main.datasz > hal->fw_data_maxsz ||
-           fw->init.textsz > hal->fw_text_maxsz ||
-           fw->init.datasz > hal->fw_data_maxsz ||
-           fw->boot.textsz > IWN_FW_BOOT_TEXT_MAXSZ ||
-           (fw->boot.textsz & 3) != 0) {
-               device_printf(sc->sc_dev, "%s: invalid firmware header\n",
-                   __func__);
-               return EINVAL;
-       }
-
        /* Check that all firmware sections fit. */
-       if (fw->main.textsz + fw->main.datasz + fw->init.textsz +
-           fw->init.datasz + fw->boot.textsz > size) {
+       if (fw->size < hdrlen + fw->main.textsz + fw->main.datasz +
+           fw->init.textsz + fw->init.datasz + fw->boot.textsz) {
                device_printf(sc->sc_dev,
                    "%s: firmware file too short: %zu bytes\n",
-                   __func__, size);
+                   __func__, fw->size);
                return EINVAL;
        }
 
@@ -5707,7 +5835,152 @@
        return 0;
 }
 
+/*
+ * Extract text and data sections from a TLV firmware image.
+ */
+int
+iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw,
+    uint16_t alt)
+{
+       const struct iwn_fw_tlv_hdr *hdr;
+       const struct iwn_fw_tlv *tlv;
+       const uint8_t *ptr, *end;
+       uint64_t altmask;
+       uint32_t len;
+
+       if (fw->size < sizeof (*hdr)) {
+               device_printf(sc->sc_dev,
+                   "%s: firmware file too short: %zu bytes\n",
+                   __func__, fw->size);
+               return EINVAL;
+       }
+       hdr = (const struct iwn_fw_tlv_hdr *)fw->data;
+       if (hdr->signature != htole32(IWN_FW_SIGNATURE)) {
+               device_printf(sc->sc_dev,
+                   "%s: bad firmware file signature 0x%08x\n",
+                   __func__, le32toh(hdr->signature));
+               return EINVAL;
+       }
+
+       /*
+        * Select the closest supported alternative that is less than
+        * or equal to the specified one.
+        */
+       altmask = le64toh(hdr->altmask);
+       while (alt > 0 && !(altmask & (1ULL << alt)))
+               alt--;  /* Downgrade. */
+
+       ptr = (const uint8_t *)(hdr + 1);
+       end = (const uint8_t *)(fw->data + fw->size);
+
+       /* Parse type-length-value fields. */
+       while (ptr + sizeof (*tlv) <= end) {
+               tlv = (const struct iwn_fw_tlv *)ptr;
+               len = le32toh(tlv->len);
+
+               ptr += sizeof (*tlv);
+               if (ptr + len > end) {
+                       device_printf(sc->sc_dev,
+                           "%s: firmware file too short: %zu bytes\n",
+                           __func__, fw->size);
+                       return EINVAL;
+               }
+               /* Skip other alternatives. */
+               if (tlv->alt != 0 && tlv->alt != htole16(alt))
+                       goto next;
+
+               switch (le16toh(tlv->type)) {
+               case IWN_FW_TLV_MAIN_TEXT:
+                       fw->main.text = ptr;
+                       fw->main.textsz = len;
+                       break;
+               case IWN_FW_TLV_MAIN_DATA:
+                       fw->main.data = ptr;
+                       fw->main.datasz = len;
+                       break;
+               case IWN_FW_TLV_INIT_TEXT:
+                       fw->init.text = ptr;
+                       fw->init.textsz = len;
+                       break;
+               case IWN_FW_TLV_INIT_DATA:
+                       fw->init.data = ptr;
+                       fw->init.datasz = len;
+                       break;
+               case IWN_FW_TLV_BOOT_TEXT:
+                       fw->boot.text = ptr;
+                       fw->boot.textsz = len;
+                       break;
+               default:
+                       DPRINTF(sc, IWN_DEBUG_RESET,
+                           "%s: TLV type %d not handled\n",
+                           __func__, le16toh(tlv->type));
+                       break;
+               }
+next:          /* TLV fields are 32-bit aligned. */
+               ptr += (len + 3) & ~3;
+       }
+       return 0;
+}
+
 static int
+iwn_read_firmware(struct iwn_softc *sc)
+{
+       const struct iwn_hal *hal = sc->sc_hal;
+       struct iwn_fw_info *fw = &sc->fw;
+       int error;
+
+       IWN_UNLOCK(sc);
+
+       memset(fw, 0, sizeof (*fw));
+
+       /* Read firmware image from filesystem. */
+       sc->fw_fp = firmware_get(sc->fwname);
+       if (sc->fw_fp == NULL) {
+               device_printf(sc->sc_dev,
+                   "%s: could not load firmare image \"%s\"\n", __func__,
+                   sc->fwname);
+               IWN_LOCK(sc);
+               return EINVAL;
+       }
+       IWN_LOCK(sc);
+
+       fw->size = sc->fw_fp->datasize;
+       fw->data = (const uint8_t *)sc->fw_fp->data;
+       if (fw->size < sizeof (uint32_t)) {
+               device_printf(sc->sc_dev,
+                   "%s: firmware file too short: %zu bytes\n",
+                   __func__, fw->size);
+               return EINVAL;
+       }
+
+       /* Retrieve text and data sections. */
+       if (*(const uint32_t *)fw->data != 0)   /* Legacy image. */
+               error = iwn_read_firmware_leg(sc, fw);
+       else
+               error = iwn_read_firmware_tlv(sc, fw, 1);
+       if (error != 0) {
+               device_printf(sc->sc_dev,
+                   "%s: could not read firmware sections\n", __func__);
+               return error;
+       }
+
+       /* Make sure text and data sections fit in hardware memory. */
+       if (fw->main.textsz > hal->fw_text_maxsz ||
+           fw->main.datasz > hal->fw_data_maxsz ||
+           fw->init.textsz > hal->fw_text_maxsz ||
+           fw->init.datasz > hal->fw_data_maxsz ||
+           fw->boot.textsz > IWN_FW_BOOT_TEXT_MAXSZ ||
+           (fw->boot.textsz & 3) != 0) {
+               device_printf(sc->sc_dev,
+                   "%s: firmware sections too large\n", __func__);
+               return EINVAL;
+       }
+
+       /* We can proceed with loading the firmware. */
+       return 0;
+}
+
+static int
 iwn_clock_wait(struct iwn_softc *sc)
 {
        int ntries;
@@ -5752,8 +6025,7 @@
                IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA);
 
        if (sc->hw_type != IWN_HW_REV_TYPE_4965 &&
-           sc->hw_type != IWN_HW_REV_TYPE_6000 &&
-           sc->hw_type != IWN_HW_REV_TYPE_6050)
+           sc->hw_type <= IWN_HW_REV_TYPE_1000)
                IWN_SETBITS(sc, IWN_ANA_PLL, IWN_ANA_PLL_INIT);
 
        /* Wait for clock stabilization before accessing prph. */
@@ -5868,9 +6140,9 @@
                /* Use internal power amplifier only. */
                IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA);
        }
-        if (sc->hw_type == IWN_HW_REV_TYPE_6050 && sc->calib_ver >= 6) {
-                /* Indicate that ROM calibration version is >=6. */
-                IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6);
+       if (sc->hw_type == IWN_HW_REV_TYPE_6050 && sc->calib_ver >= 6) {
+               /* Indicate that ROM calibration version is >=6. */
+               IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6);
        }
        return 0;
 }

Modified: haiku/vendor/freebsd/current/dev/iwn/if_iwnreg.h
===================================================================
--- haiku/vendor/freebsd/current/dev/iwn/if_iwnreg.h    2011-04-11 18:02:55 UTC 
(rev 41222)
+++ haiku/vendor/freebsd/current/dev/iwn/if_iwnreg.h    2011-04-11 18:03:02 UTC 
(rev 41223)
@@ -1,5 +1,5 @@
 /*     $FreeBSD$       */
-/*     $OpenBSD: if_iwnreg.h,v 1.37 2010/02/17 18:23:00 damien Exp $   */
+/*     $OpenBSD: if_iwnreg.h,v 1.40 2010/05/05 19:41:57 damien Exp $   */
 
 /*-
  * Copyright (c) 2007, 2008
@@ -204,6 +204,7 @@
 #define IWN_HW_REV_TYPE_1000   6
 #define IWN_HW_REV_TYPE_6000   7
 #define IWN_HW_REV_TYPE_6050   8
+#define IWN_HW_REV_TYPE_6005   11
 
 /* Possible flags for register IWN_GIO_CHICKEN. */
 #define IWN_GIO_CHICKEN_L1A_NO_L0S_RX  (1 << 23)
@@ -1259,6 +1260,34 @@
        uint32_t        time[2];
 } __packed;
 
+/* TLV firmware header. */
+struct iwn_fw_tlv_hdr {
+       uint32_t        zero;   /* Always 0, to differentiate from legacy. */
+       uint32_t        signature;
+#define IWN_FW_SIGNATURE       0x0a4c5749      /* "IWL\n" */
+
+       uint8_t         descr[64];

[... truncated: 99 lines follow ...]

Other related posts:

  • » [haiku-commits] r41223 - haiku/vendor/freebsd/current/dev/iwn - korli