On Fri, May 22, 2020 at 01:48:28PM -0400, sven falempin wrote:
>  After a few days ... (free size too small  288 < 1024 /2 )
> 
> Maybe this can help make the driver better.
> 
> printf '%x\n' $((0x350+0xf7)) ; grep -A2 'if_iwx.c:515'  /tmp/iwx.dis
> 447
> /usr/src/sys/dev/pci/if_iwx.c:515
>      447:       41 c7 86 28 2f 05 00    movl   $0x0,0x52f28(%r14)
>      44e:       00 00 00 00
> 
> [0]-[current]-[~]
> # cat -n /usr/src/sys/dev/pci/if_iwx.c | grep -C5 -E '  515'
>    510          /* free paging*/
>    511          for (i = 0; i < dram->paging_cnt; i++)
>    512                  iwx_dma_contig_free(dram->paging);
>    513
>    514          free(dram->paging, M_DEVBUF, dram->paging_cnt *
> sizeof(*dram->paging));
>    515          dram->paging_cnt = 0;
>    516          dram->paging = NULL;
>    517  }
>    518
>    519  int
>    520  iwx_get_num_sections(const struct iwx_fw_sects *fws, int start

This should fix free with a wrong size in the error case, and avoids
re-allocating a chunk of DMA memory (sc->ctxt_info_dma) every time the
firmware gets loaded. Instead, this chunk is now allocated once at
attach time. This seems to be the allocation that failed in your case.

diff 66ecf2e2f524653126dce17a447a43b26ee90abb /usr/src
blob - c3ca08c7a726326e37cda8645596a176051b6cf4
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -230,7 +230,7 @@ int iwx_alloc_fw_monitor_block(struct iwx_softc *, uin
 int    iwx_alloc_fw_monitor(struct iwx_softc *, uint8_t);
 int    iwx_apply_debug_destination(struct iwx_softc *);
 int    iwx_ctxt_info_init(struct iwx_softc *, const struct iwx_fw_sects *);
-void   iwx_ctxt_info_free(struct iwx_softc *);
+void   iwx_ctxt_info_free_fw_img(struct iwx_softc *);
 void   iwx_ctxt_info_free_paging(struct iwx_softc *);
 int    iwx_init_fw_sec(struct iwx_softc *, const struct iwx_fw_sects *,
            struct iwx_context_info_dram *);
@@ -535,52 +535,60 @@ iwx_init_fw_sec(struct iwx_softc *sc, const struct iwx
     struct iwx_context_info_dram *ctxt_dram)
 {
        struct iwx_self_init_dram *dram = &sc->init_dram;
-       int i, ret, lmac_cnt, umac_cnt, paging_cnt;
+       int i, ret, fw_cnt = 0;
 
        KASSERT(dram->paging == NULL);
 
-       lmac_cnt = iwx_get_num_sections(fws, 0);
+       dram->lmac_cnt = iwx_get_num_sections(fws, 0);
        /* add 1 due to separator */
-       umac_cnt = iwx_get_num_sections(fws, lmac_cnt + 1);
+       dram->umac_cnt = iwx_get_num_sections(fws, dram->lmac_cnt + 1);
        /* add 2 due to separators */
-       paging_cnt = iwx_get_num_sections(fws, lmac_cnt + umac_cnt + 2);
+       dram->paging_cnt = iwx_get_num_sections(fws,
+           dram->lmac_cnt + dram->umac_cnt + 2);
 
-       dram->fw = mallocarray(umac_cnt + lmac_cnt, sizeof(*dram->fw),
-           M_DEVBUF,  M_ZERO | M_NOWAIT);
-       if (!dram->fw)
+       dram->fw = mallocarray(dram->umac_cnt + dram->lmac_cnt,
+           sizeof(*dram->fw), M_DEVBUF,  M_ZERO | M_NOWAIT);
+       if (!dram->fw) {
+               printf("%s: could not allocate memory for firmware sections\n",
+                   DEVNAME(sc));
                return ENOMEM;
-       dram->paging = mallocarray(paging_cnt, sizeof(*dram->paging),
+       }
+
+       dram->paging = mallocarray(dram->paging_cnt, sizeof(*dram->paging),
            M_DEVBUF, M_ZERO | M_NOWAIT);
-       if (!dram->paging)
+       if (!dram->paging) {
+               printf("%s: could not allocate memory for firmware paging\n",
+                   DEVNAME(sc));
                return ENOMEM;
+       }
 
        /* initialize lmac sections */
-       for (i = 0; i < lmac_cnt; i++) {
+       for (i = 0; i < dram->lmac_cnt; i++) {
                ret = iwx_ctxt_info_alloc_dma(sc, &fws->fw_sect[i],
-                                                  &dram->fw[dram->fw_cnt]);
+                                                  &dram->fw[fw_cnt]);
                if (ret)
                        return ret;
                ctxt_dram->lmac_img[i] =
-                       htole64(dram->fw[dram->fw_cnt].paddr);
+                       htole64(dram->fw[fw_cnt].paddr);
                DPRINTF(("%s: firmware LMAC section %d at 0x%llx size %lld\n", 
__func__, i,
-                   (unsigned long long)dram->fw[dram->fw_cnt].paddr,
-                   (unsigned long long)dram->fw[dram->fw_cnt].size));
-               dram->fw_cnt++;
+                   (unsigned long long)dram->fw[fw_cnt].paddr,
+                   (unsigned long long)dram->fw[fw_cnt].size));
+               fw_cnt++;
        }
 
        /* initialize umac sections */
-       for (i = 0; i < umac_cnt; i++) {
+       for (i = 0; i < dram->umac_cnt; i++) {
                /* access FW with +1 to make up for lmac separator */
                ret = iwx_ctxt_info_alloc_dma(sc,
-                   &fws->fw_sect[dram->fw_cnt + 1], &dram->fw[dram->fw_cnt]);
+                   &fws->fw_sect[fw_cnt + 1], &dram->fw[fw_cnt]);
                if (ret)
                        return ret;
                ctxt_dram->umac_img[i] =
-                       htole64(dram->fw[dram->fw_cnt].paddr);
+                       htole64(dram->fw[fw_cnt].paddr);
                DPRINTF(("%s: firmware UMAC section %d at 0x%llx size %lld\n", 
__func__, i,
-                       (unsigned long long)dram->fw[dram->fw_cnt].paddr,
-                       (unsigned long long)dram->fw[dram->fw_cnt].size));
-               dram->fw_cnt++;
+                       (unsigned long long)dram->fw[fw_cnt].paddr,
+                       (unsigned long long)dram->fw[fw_cnt].size));
+               fw_cnt++;
        }
 
        /*
@@ -593,9 +601,9 @@ iwx_init_fw_sec(struct iwx_softc *sc, const struct iwx
         * Given that, the logic here in accessing the fw image is a bit
         * different - fw_cnt isn't changing so loop counter is added to it.
         */
-       for (i = 0; i < paging_cnt; i++) {
+       for (i = 0; i < dram->paging_cnt; i++) {
                /* access FW with +2 to make up for lmac & umac separators */
-               int fw_idx = dram->fw_cnt + i + 2;
+               int fw_idx = fw_cnt + i + 2;
 
                ret = iwx_ctxt_info_alloc_dma(sc,
                    &fws->fw_sect[fw_idx], &dram->paging[i]);
@@ -606,7 +614,6 @@ iwx_init_fw_sec(struct iwx_softc *sc, const struct iwx
                DPRINTF(("%s: firmware paging section %d at 0x%llx size 
%lld\n", __func__, i,
                    (unsigned long long)dram->paging[i].paddr,
                    (unsigned long long)dram->paging[i].size));
-               dram->paging_cnt++;
        }
 
        return 0;
@@ -758,13 +765,6 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct 
        uint32_t control_flags = 0, rb_size;
        int err;
 
-       err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->ctxt_info_dma,
-           sizeof(*ctxt_info), 0);
-       if (err) {
-               printf("%s: could not allocate context info DMA memory\n",
-                   DEVNAME(sc));
-               return err;
-       }
        ctxt_info = sc->ctxt_info_dma.vaddr;
 
        ctxt_info->version.version = 0;
@@ -800,15 +800,17 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct 
        /* allocate ucode sections in dram and set addresses */
        err = iwx_init_fw_sec(sc, fws, &ctxt_info->dram);
        if (err) {
-               iwx_ctxt_info_free(sc);
+               iwx_ctxt_info_free_fw_img(sc);
                return err;
        }
 
        /* Configure debug, if exists */
        if (sc->sc_fw.dbg_dest_tlv_v1) {
                err = iwx_apply_debug_destination(sc);
-               if (err)
+               if (err) {
+                       iwx_ctxt_info_free_fw_img(sc);
                        return err;
+               }
        }
 
        /* kick FW self load */
@@ -829,26 +831,19 @@ iwx_ctxt_info_free_fw_img(struct iwx_softc *sc)
        struct iwx_self_init_dram *dram = &sc->init_dram;
        int i;
 
-       if (!dram->fw) {
-               KASSERT(dram->fw_cnt == 0);
+       if (!dram->fw)
                return;
-       }
 
-       for (i = 0; i < dram->fw_cnt; i++)
+       for (i = 0; i < dram->lmac_cnt + dram->umac_cnt; i++)
                iwx_dma_contig_free(&dram->fw[i]);
 
-       free(dram->fw, M_DEVBUF, dram->fw_cnt * sizeof(dram->fw[0]));
-       dram->fw_cnt = 0;
+       free(dram->fw, M_DEVBUF,
+           (dram->lmac_cnt + dram->umac_cnt) * sizeof(*dram->fw));
+       dram->lmac_cnt = 0;
+       dram->umac_cnt = 0;
        dram->fw = NULL;
 }
 
-void
-iwx_ctxt_info_free(struct iwx_softc *sc)
-{
-       iwx_dma_contig_free(&sc->ctxt_info_dma);
-       iwx_ctxt_info_free_fw_img(sc);
-}
-
 int
 iwx_firmware_store_section(struct iwx_softc *sc, enum iwx_ucode_type type,
     uint8_t *data, size_t dlen)
@@ -2410,7 +2405,6 @@ void
 iwx_post_alive(struct iwx_softc *sc)
 {
        iwx_ict_reset(sc);
-       iwx_ctxt_info_free(sc);
 }
 
 /*
@@ -3113,6 +3107,9 @@ iwx_load_firmware(struct iwx_softc *sc)
        }
        if (err || !sc->sc_uc.uc_ok)
                printf("%s: could not load firmware\n", DEVNAME(sc));
+
+       iwx_ctxt_info_free_fw_img(sc);
+
        if (!sc->sc_uc.uc_ok)
                return EINVAL;
 
@@ -7774,6 +7771,15 @@ iwx_attach(struct device *parent, struct device *self,
                return;
        }
 
+       /* Allocate DMA memory for loading firmware. */
+       err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->ctxt_info_dma,
+           sizeof(struct iwx_context_info), 0);
+       if (err) {
+               printf("%s: could not allocate memory for loading firmware\n",
+                   DEVNAME(sc));
+               return;
+       }
+
        /* 
         * Allocate DMA memory for firmware transfers.
         * Must be aligned on a 16-byte boundary.
@@ -7781,9 +7787,9 @@ iwx_attach(struct device *parent, struct device *self,
        err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma,
            sc->sc_fwdmasegsz, 16);
        if (err) {
-               printf("%s: could not allocate memory for firmware\n",
+               printf("%s: could not allocate memory for firmware transfers\n",
                    DEVNAME(sc));
-               return;
+               goto fail0;
        }
 
        /* Allocate interrupt cause table (ICT).*/
@@ -7915,6 +7921,7 @@ fail3:    if (sc->ict_dma.vaddr != NULL)
                iwx_dma_contig_free(&sc->ict_dma);
        
 fail1: iwx_dma_contig_free(&sc->fw_dma);
+fail0: iwx_dma_contig_free(&sc->ctxt_info_dma);
        return;
 }
 
blob - 7a0d1c61f771b3691baa72ea835940bcffb48c64
file + sys/dev/pci/if_iwxvar.h
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -346,13 +346,15 @@ struct iwx_bf_data {
 /**
  * struct iwx_self_init_dram - dram data used by self init process
  * @fw: lmac and umac dram data
- * @fw_cnt: total number of items in array
+ * @lmac_cnt: number of lmac sections in fw image
+ * @umac_cnt: number of umac sections in fw image
  * @paging: paging dram data
- * @paging_cnt: total number of items in array
+ * @paging_cnt: number of paging sections needed by fw image
  */
 struct iwx_self_init_dram {
        struct iwx_dma_info *fw;
-       int fw_cnt;
+       int lmac_cnt;
+       int umac_cnt;
        struct iwx_dma_info *paging;
        int paging_cnt;
 };

Reply via email to