This diff makes 3168 devices actually work with iwm(4).
These devices have never worked right since the driver just threw
errors when trying to load firmware.

Loosely based on FreeBSD r345002 and Linux commit
44fd09dad5d2b78efbabbbbf623774e561e36cca

Tested with:
iwm0 at pci4 dev 0 function 0 "Intel Dual Band Wireless-AC 3168" rev 0x10, msi
iwm0: hw rev 0x220, fw ver 29.1654887522.0, address xx:xx:xx:xx:xx:xx

Please also test on any other types of iwm devices to ensure that this
won't break anything.

diff refs/heads/master refs/heads/nvmsdp
blob - ea6f2b9561ee5f7634fb0db5a19e466b67e8f473 (mode 644)
blob + 322894c03b5705071d8fd79391b8b138f2b01c34 (mode 600)
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -319,7 +319,7 @@ int iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, u
 int    iwm_nvm_read_section(struct iwm_softc *, uint16_t, uint8_t *,
            uint16_t *, size_t);
 void   iwm_init_channel_map(struct iwm_softc *, const uint16_t * const,
-           const uint8_t *nvm_channels, size_t nchan);
+           const uint8_t *nvm_channels, int nchan);
 void   iwm_setup_ht_rates(struct iwm_softc *);
 void   iwm_htprot_task(void *);
 void   iwm_update_htprot(struct ieee80211com *, struct ieee80211_node *);
@@ -340,7 +340,7 @@ void        iwm_ba_task(void *);
 int    iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *,
            const uint16_t *, const uint16_t *,
            const uint16_t *, const uint16_t *,
-           const uint16_t *);
+           const uint16_t *, int);
 void   iwm_set_hw_address_8000(struct iwm_softc *, struct iwm_nvm_data *,
            const uint16_t *, const uint16_t *);
 int    iwm_parse_nvm_sections(struct iwm_softc *, struct iwm_nvm_section *);
@@ -2374,6 +2374,7 @@ const int iwm_nvm_to_read[] = {
        IWM_NVM_SECTION_TYPE_REGULATORY,
        IWM_NVM_SECTION_TYPE_CALIBRATION,
        IWM_NVM_SECTION_TYPE_PRODUCTION,
+       IWM_NVM_SECTION_TYPE_REGULATORY_SDP,
        IWM_NVM_SECTION_TYPE_HW_8000,
        IWM_NVM_SECTION_TYPE_MAC_OVERRIDE,
        IWM_NVM_SECTION_TYPE_PHY_SKU,
@@ -2511,7 +2512,7 @@ iwm_fw_valid_rx_ant(struct iwm_softc *sc)
 
 void
 iwm_init_channel_map(struct iwm_softc *sc, const uint16_t * const nvm_ch_flags,
-    const uint8_t *nvm_channels, size_t nchan)
+    const uint8_t *nvm_channels, int nchan)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct iwm_nvm_data *data = &sc->sc_nvm;
@@ -2796,7 +2797,7 @@ int
 iwm_parse_nvm_data(struct iwm_softc *sc, const uint16_t *nvm_hw,
     const uint16_t *nvm_sw, const uint16_t *nvm_calib,
     const uint16_t *mac_override, const uint16_t *phy_sku,
-    const uint16_t *regulatory)
+    const uint16_t *regulatory, int n_regulatory)
 {
        struct iwm_nvm_data *data = &sc->sc_nvm;
        uint8_t hw_addr[ETHER_ADDR_LEN];
@@ -2855,12 +2856,19 @@ iwm_parse_nvm_data(struct iwm_softc *sc, const uint16_
        } else
                iwm_set_hw_address_8000(sc, data, mac_override, nvm_hw);
 
-       if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000)
-               iwm_init_channel_map(sc, &nvm_sw[IWM_NVM_CHANNELS],
-                   iwm_nvm_channels, nitems(iwm_nvm_channels));
-       else
+       if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
+               if (sc->nvm_type == IWM_NVM_SDP) {
+                       iwm_init_channel_map(sc, regulatory, iwm_nvm_channels,
+                           MIN(n_regulatory, nitems(iwm_nvm_channels)));
+               } else {
+                       iwm_init_channel_map(sc, &nvm_sw[IWM_NVM_CHANNELS],
+                           iwm_nvm_channels,
+                           MIN(n_regulatory, nitems(iwm_nvm_channels)));
+               }
+       } else
                iwm_init_channel_map(sc, &regulatory[IWM_NVM_CHANNELS_8000],
-                   iwm_nvm_channels_8000, nitems(iwm_nvm_channels_8000));
+                   iwm_nvm_channels_8000,
+                   MIN(n_regulatory, nitems(iwm_nvm_channels_8000)));
 
        data->calib_version = 255;   /* TODO:
                                        this value will prevent some checks from
@@ -2876,6 +2884,7 @@ iwm_parse_nvm_sections(struct iwm_softc *sc, struct iw
 {
        const uint16_t *hw, *sw, *calib, *mac_override = NULL, *phy_sku = NULL;
        const uint16_t *regulatory = NULL;
+       int n_regulatory = 0;
 
        /* Checking for required sections */
        if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
@@ -2885,6 +2894,15 @@ iwm_parse_nvm_sections(struct iwm_softc *sc, struct iw
                }
 
                hw = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_HW].data;
+
+               if (sc->nvm_type == IWM_NVM_SDP) {
+                       if (!sections[IWM_NVM_SECTION_TYPE_REGULATORY_SDP].data)
+                               return ENOENT;
+                       regulatory = (const uint16_t *)
+                           sections[IWM_NVM_SECTION_TYPE_REGULATORY_SDP].data;
+                       n_regulatory =
+                           
sections[IWM_NVM_SECTION_TYPE_REGULATORY_SDP].length;
+               }
        } else if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) {
                /* SW and REGULATORY sections are mandatory */
                if (!sections[IWM_NVM_SECTION_TYPE_SW].data ||
@@ -2904,6 +2922,7 @@ iwm_parse_nvm_sections(struct iwm_softc *sc, struct iw
 
                regulatory = (const uint16_t *)
                    sections[IWM_NVM_SECTION_TYPE_REGULATORY].data;
+               n_regulatory = sections[IWM_NVM_SECTION_TYPE_REGULATORY].length;
                hw = (const uint16_t *)
                    sections[IWM_NVM_SECTION_TYPE_HW_8000].data;
                mac_override =
@@ -2919,8 +2938,9 @@ iwm_parse_nvm_sections(struct iwm_softc *sc, struct iw
        calib = (const uint16_t *)
            sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data;
 
+       /* XXX should pass in the length of every section */
        return iwm_parse_nvm_data(sc, hw, sw, calib, mac_override,
-           phy_sku, regulatory);
+           phy_sku, regulatory, n_regulatory);
 }
 
 int
@@ -8138,6 +8158,7 @@ iwm_attach(struct device *parent, struct device *self,
                sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
                sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
                sc->sc_nvm_max_section_size = 16384;
+               sc->nvm_type = IWM_NVM;
                break;
        case PCI_PRODUCT_INTEL_WL_3165_1:
        case PCI_PRODUCT_INTEL_WL_3165_2:
@@ -8146,13 +8167,15 @@ iwm_attach(struct device *parent, struct device *self,
                sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
                sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
                sc->sc_nvm_max_section_size = 16384;
+               sc->nvm_type = IWM_NVM;
                break;
        case PCI_PRODUCT_INTEL_WL_3168_1:
-               sc->sc_fwname = "iwm-3168-22";
+               sc->sc_fwname = "iwm-3168-29";
                sc->host_interrupt_operation_mode = 0;
                sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
                sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
                sc->sc_nvm_max_section_size = 16384;
+               sc->nvm_type = IWM_NVM_SDP;
                break;
        case PCI_PRODUCT_INTEL_WL_7260_1:
        case PCI_PRODUCT_INTEL_WL_7260_2:
@@ -8161,6 +8184,7 @@ iwm_attach(struct device *parent, struct device *self,
                sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
                sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
                sc->sc_nvm_max_section_size = 16384;
+               sc->nvm_type = IWM_NVM;
                break;
        case PCI_PRODUCT_INTEL_WL_7265_1:
        case PCI_PRODUCT_INTEL_WL_7265_2:
@@ -8169,6 +8193,7 @@ iwm_attach(struct device *parent, struct device *self,
                sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
                sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
                sc->sc_nvm_max_section_size = 16384;
+               sc->nvm_type = IWM_NVM;
                break;
        case PCI_PRODUCT_INTEL_WL_8260_1:
        case PCI_PRODUCT_INTEL_WL_8260_2:
@@ -8177,6 +8202,7 @@ iwm_attach(struct device *parent, struct device *self,
                sc->sc_device_family = IWM_DEVICE_FAMILY_8000;
                sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000;
                sc->sc_nvm_max_section_size = 32768;
+               sc->nvm_type = IWM_NVM_EXT;
                break;
        case PCI_PRODUCT_INTEL_WL_8265_1:
                sc->sc_fwname = "iwm-8265-34";
@@ -8184,6 +8210,7 @@ iwm_attach(struct device *parent, struct device *self,
                sc->sc_device_family = IWM_DEVICE_FAMILY_8000;
                sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000;
                sc->sc_nvm_max_section_size = 32768;
+               sc->nvm_type = IWM_NVM_EXT;
                break;
        default:
                printf("%s: unknown adapter type\n", DEVNAME(sc));
blob - ebdbb2114cadf32ee444d148f5d85fd99096e525
blob + c16860241d1d2e5cf974e89e3a138822c1c7314c
--- sys/dev/pci/if_iwmreg.h
+++ sys/dev/pci/if_iwmreg.h
@@ -2096,11 +2096,25 @@ struct iwm_calib_res_notif_phy_db {
 #define IWM_NVM_SECTION_TYPE_CALIBRATION       4
 #define IWM_NVM_SECTION_TYPE_PRODUCTION                5
 #define IWM_NVM_SECTION_TYPE_POST_FCS_CALIB    6
-/* 7, 8, 9 unknown */
+/* 7 unknown */
+#define IWM_NVM_SECTION_TYPE_REGULATORY_SDP    8
+/* 9 unknown */
 #define IWM_NVM_SECTION_TYPE_HW_8000           10
 #define IWM_NVM_SECTION_TYPE_MAC_OVERRIDE      11
 #define IWM_NVM_SECTION_TYPE_PHY_SKU           12
 #define IWM_NVM_NUM_OF_SECTIONS                        13
+
+/**
+ * enum iwm_nvm_type - nvm formats
+ * @IWM_NVM: the regular format
+ * @IWM_NVM_EXT: extended NVM format
+ * @IWM_NVM_SDP: NVM format used by 3168 series
+ */
+enum iwm_nvm_type {
+       IWM_NVM,
+       IWM_NVM_EXT,
+       IWM_NVM_SDP,
+};
 
 /**
  * struct iwm_nvm_access_cmd_ver2 - Request the device to send an NVM section
blob - 9a5da32ea7dd6d59623ddab32125620fca36f644
blob + c69c7fbe7e558939b5f9398cbfb421d9e115b725
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -498,6 +498,7 @@ struct iwm_softc {
 
        int host_interrupt_operation_mode;
        int sc_ltr_enabled;
+       enum iwm_nvm_type nvm_type;
 
        /*
         * Paging parameters - All of the parameters should be set by the

Reply via email to