Mercurial > illumos > illumos-gate
changeset 10027:c95796758397
6814751 px_dma_allocmp and hermon_dbr_page_alloc leak
author | agiri <Giri.Adari@Sun.COM> |
---|---|
date | Thu, 02 Jul 2009 14:17:43 -0700 |
parents | 2659dc230676 |
children | 2de34ea54ad5 |
files | usr/src/uts/common/io/ib/adapters/hermon/hermon.c usr/src/uts/common/io/ib/adapters/hermon/hermon_misc.c usr/src/uts/common/sys/ib/adapters/hermon/hermon.h usr/src/uts/common/sys/ib/adapters/hermon/hermon_misc.h |
diffstat | 4 files changed, 55 insertions(+), 106 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon.c Thu Jul 02 14:05:51 2009 -0700 +++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon.c Thu Jul 02 14:17:43 2009 -0700 @@ -3494,7 +3494,6 @@ int status; hermon_dbr_info_t *info; - /* * Allocate the UAR page for kernel use. This UAR page is * the privileged UAR page through which all kernel generated @@ -3519,9 +3518,7 @@ if (status != DDI_SUCCESS) { return (DDI_FAILURE); } - - /* store the page pointer in the private area - the rest s/b done */ - state->hs_kern_dbr = info->dbr_page; + state->hs_kern_dbr = info; return (DDI_SUCCESS); } @@ -3533,10 +3530,8 @@ static void hermon_internal_uarpg_fini(hermon_state_t *state) { - /* Free up Hermon UAR page #1 (kernel driver doorbells) */ hermon_rsrc_free(state, &state->hs_uarkpg_rsrc); - } @@ -3550,7 +3545,6 @@ hermon_rsrc_t *qp0_rsrc, *qp1_rsrc, *qp_resvd; int status; - /* Initialize the lock used for special QP rsrc management */ mutex_init(&state->hs_spec_qplock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->hs_intrmsi_pri));
--- a/usr/src/uts/common/io/ib/adapters/hermon/hermon_misc.c Thu Jul 02 14:05:51 2009 -0700 +++ b/usr/src/uts/common/io/ib/adapters/hermon/hermon_misc.c Thu Jul 02 14:17:43 2009 -0700 @@ -237,7 +237,6 @@ * in this case, we want exactly one page per call, and aligned on a * page - and may need to be mapped to the user for access */ - int hermon_dbr_page_alloc(hermon_state_t *state, hermon_dbr_info_t **dinfo) { @@ -247,10 +246,9 @@ ddi_dma_attr_t dma_attr; ddi_dma_cookie_t cookie; uint_t cookie_cnt; - hermon_dbr_header_t *pagehdr; int i; hermon_dbr_info_t *info; - uint64_t dmaaddr; + caddr_t dmaaddr; uint64_t dmalen; info = kmem_zalloc(sizeof (hermon_dbr_info_t), KM_SLEEP); @@ -274,7 +272,7 @@ status = ddi_dma_mem_alloc(dma_hdl, PAGESIZE, &state->hs_reg_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, - NULL, (caddr_t *)&dmaaddr, (size_t *)&dmalen, &acc_hdl); + NULL, &dmaaddr, (size_t *)&dmalen, &acc_hdl); if (status != DDI_SUCCESS) { ddi_dma_free_handle(&dma_hdl); cmn_err(CE_CONT, "dbr DMA mem alloc failed(status %d)", status); @@ -284,7 +282,7 @@ /* this memory won't be IB registered, so do the bind here */ status = ddi_dma_addr_bind_handle(dma_hdl, NULL, - (caddr_t)(uintptr_t)dmaaddr, (size_t)dmalen, DDI_DMA_RDWR | + dmaaddr, (size_t)dmalen, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &cookie, &cookie_cnt); if (status != DDI_SUCCESS) { ddi_dma_mem_free(&acc_hdl); @@ -299,18 +297,15 @@ /* init the info structure with returned info */ info->dbr_dmahdl = dma_hdl; info->dbr_acchdl = acc_hdl; - info->dbr_page = (caddr_t)(uintptr_t)dmaaddr; + info->dbr_page = (hermon_dbr_t *)(void *)dmaaddr; + info->dbr_link = NULL; /* extract the phys addr from the cookie */ info->dbr_paddr = cookie.dmac_laddress; - /* should have everything now, so do the init of the header */ - pagehdr = (hermon_dbr_header_t *)(void *)info->dbr_page; - pagehdr->next = 0; - pagehdr->firstfree = 0; - pagehdr->nfree = HERMON_NUM_DBR_PER_PAGE; - pagehdr->dbr_info = info; + info->dbr_firstfree = 0; + info->dbr_nfree = HERMON_NUM_DBR_PER_PAGE; /* link all DBrs onto the free list */ for (i = 0; i < HERMON_NUM_DBR_PER_PAGE; i++) { - pagehdr->dbr[i] = i + 1; + info->dbr_page[i] = i + 1; } return (DDI_SUCCESS); @@ -328,9 +323,9 @@ hermon_dbr_alloc(hermon_state_t *state, uint_t index, ddi_acc_handle_t *acchdl, hermon_dbr_t **vdbr, uint64_t *pdbr, uint64_t *mapoffset) { - hermon_dbr_header_t *pagehdr, *lastpage; hermon_dbr_t *record = NULL; - hermon_dbr_info_t *dinfo = NULL; + hermon_dbr_info_t *info = NULL; + uint32_t idx; int status; if (index != state->hs_kernel_uar_index) @@ -338,37 +333,30 @@ mapoffset)); mutex_enter(&state->hs_dbr_lock); - /* 'pagehdr' holds pointer to first page */ - pagehdr = (hermon_dbr_header_t *)(void *)state->hs_kern_dbr; - do { - lastpage = pagehdr; /* save pagehdr for later linking */ - if (pagehdr->nfree == 0) { - pagehdr = (hermon_dbr_header_t *)(void *)pagehdr->next; - continue; /* page is full, go to next if there is one */ - } - dinfo = pagehdr->dbr_info; - break; /* found a page w/ one available */ - } while (pagehdr != 0); - - if (dinfo == NULL) { /* did NOT find a page with one available */ - status = hermon_dbr_page_alloc(state, &dinfo); + for (info = state->hs_kern_dbr; info != NULL; info = info->dbr_link) + if (info->dbr_nfree != 0) + break; /* found a page w/ one available */ + + if (info == NULL) { /* did NOT find a page with one available */ + status = hermon_dbr_page_alloc(state, &info); if (status != DDI_SUCCESS) { /* do error handling */ mutex_exit(&state->hs_dbr_lock); return (DDI_FAILURE); } /* got a new page, so link it in. */ - pagehdr = (hermon_dbr_header_t *)(void *)dinfo->dbr_page; - lastpage->next = pagehdr; + info->dbr_link = state->hs_kern_dbr; + state->hs_kern_dbr = info; } - record = pagehdr->dbr + pagehdr->firstfree; - pagehdr->firstfree = *record; - pagehdr->nfree--; + idx = info->dbr_firstfree; + record = info->dbr_page + idx; + info->dbr_firstfree = *record; + info->dbr_nfree--; *record = 0; - *acchdl = dinfo->dbr_acchdl; + *acchdl = info->dbr_acchdl; *vdbr = record; - *pdbr = ((uintptr_t)record - (uintptr_t)pagehdr + dinfo->dbr_paddr); + *pdbr = info->dbr_paddr + idx * sizeof (hermon_dbr_t); mutex_exit(&state->hs_dbr_lock); return (DDI_SUCCESS); } @@ -380,22 +368,25 @@ * the dbr, but will NEVER free pages of dbrs - small * price to pay, but userland access never will anyway */ - void hermon_dbr_free(hermon_state_t *state, uint_t indx, hermon_dbr_t *record) { - hermon_dbr_header_t *pagehdr; + hermon_dbr_t *page; + hermon_dbr_info_t *info; if (indx != state->hs_kernel_uar_index) { hermon_user_dbr_free(state, indx, record); return; } + page = (hermon_dbr_t *)(uintptr_t)((uintptr_t)record & PAGEMASK); mutex_enter(&state->hs_dbr_lock); - pagehdr = (hermon_dbr_header_t *)((uintptr_t)record & - (uintptr_t)PAGEMASK); - *record = pagehdr->firstfree; - pagehdr->firstfree = record - pagehdr->dbr; - pagehdr->nfree++; /* decr the count for this one */ + for (info = state->hs_kern_dbr; info != NULL; info = info->dbr_link) + if (info->dbr_page == page) + break; + ASSERT(info != NULL); + *record = info->dbr_firstfree; + info->dbr_firstfree = record - info->dbr_page; + info->dbr_nfree++; mutex_exit(&state->hs_dbr_lock); } @@ -411,8 +402,7 @@ void hermon_dbr_kern_free(hermon_state_t *state) { - hermon_dbr_header_t *pagehdr, *lastpage; - hermon_dbr_info_t *dinfo; + hermon_dbr_info_t *info, *link; hermon_user_dbr_t *udbr, *next; hermon_udbr_page_t *pagep, *nextp; hermon_umap_db_entry_t *umapdb; @@ -421,15 +411,12 @@ extern hermon_umap_db_t hermon_userland_rsrc_db; mutex_enter(&state->hs_dbr_lock); - pagehdr = (hermon_dbr_header_t *)(void *)state->hs_kern_dbr; - while (pagehdr != NULL) { - lastpage = (hermon_dbr_header_t *)(void *)pagehdr->next; - dinfo = pagehdr->dbr_info; - (void) ddi_dma_unbind_handle(dinfo->dbr_dmahdl); - ddi_dma_mem_free(&dinfo->dbr_acchdl); /* free page */ - ddi_dma_free_handle(&dinfo->dbr_dmahdl); - kmem_free(dinfo, sizeof (hermon_dbr_info_t)); - pagehdr = lastpage; + for (info = state->hs_kern_dbr; info != NULL; info = link) { + (void) ddi_dma_unbind_handle(info->dbr_dmahdl); + ddi_dma_mem_free(&info->dbr_acchdl); /* free page */ + ddi_dma_free_handle(&info->dbr_dmahdl); + link = info->dbr_link; + kmem_free(info, sizeof (hermon_dbr_info_t)); } udbr = state->hs_user_dbr;
--- a/usr/src/uts/common/sys/ib/adapters/hermon/hermon.h Thu Jul 02 14:05:51 2009 -0700 +++ b/usr/src/uts/common/sys/ib/adapters/hermon/hermon.h Thu Jul 02 14:17:43 2009 -0700 @@ -580,9 +580,11 @@ hermon_qphdl_t *hs_qphdl; hermon_srqhdl_t *hs_srqhdl; kmutex_t hs_dbr_lock; /* lock for dbr mgmt */ - caddr_t hs_kern_dbr; - /* XXX needs work - link list of non-kernel dbr resources */ + /* linked list of kernel dbr resources */ + hermon_dbr_info_t *hs_kern_dbr; + + /* linked list of non-kernel dbr resources */ hermon_user_dbr_t *hs_user_dbr; /*
--- a/usr/src/uts/common/sys/ib/adapters/hermon/hermon_misc.h Thu Jul 02 14:05:51 2009 -0700 +++ b/usr/src/uts/common/sys/ib/adapters/hermon/hermon_misc.h Thu Jul 02 14:17:43 2009 -0700 @@ -179,8 +179,6 @@ * of UAR index, 3 bits of driver instance number). This is especially true * for 32-bit kernels. */ - - #define HERMON_NUM_UAR_SHIFT 0xA /* @@ -199,56 +197,24 @@ * Though it may lead to minor wastage, it also means that reuse is easier since * any DBr can be used for either, and we don't have to play allocation games. * - * The structure of a page of DBrs looks like this: - * - * ------------------------------ - * | | - * | | - * | HEADER structure | - * | | - * |----------------------------| - * | | - * | | - * | | - * | DBrs | ((PAGESIZE >> 3) - 4) DBrs / page - * | | - * | | - * | | - * | | - * | | - * |----------------------------| - * - * - * The state structure will hold the pointer to the start of a list of pages - * containing DBr's. As you allocate each page you also allocate a dbr_into - * structure, that contains the access information about the page, to minimize - * what needs to be in the page itself - what's there is just what's needed - * to step through at alloc time + * The state structure will hold the pointer to the start of a list of struct + * hermon_dbr_info_s, each one containing the necessary information to manage + * a page of DBr's. */ typedef uint64_t hermon_dbr_t; typedef struct hermon_dbr_info_s { - caddr_t dbr_page; /* addr of page */ - uint64_t dbr_paddr; /* paddr of page for HCA */ + struct hermon_dbr_info_s *dbr_link; + hermon_dbr_t *dbr_page; /* virtual addr of page */ + uint64_t dbr_paddr; /* physical addr of page */ ddi_acc_handle_t dbr_acchdl; ddi_dma_handle_t dbr_dmahdl; - ddi_umem_cookie_t dbr_umemcookie; + uint32_t dbr_nfree; /* #free DBrs in this page */ + uint32_t dbr_firstfree; /* idx of first free DBr */ } hermon_dbr_info_t; -typedef struct hermon_dbr_header_s { - struct hermon_dbr_header_s *next; /* next page in chain */ - /* (zero means last) */ - hermon_dbr_info_t *dbr_info; /* info structure for this page */ - uint32_t nfree; /* #free DBrs in this page */ - uint32_t firstfree; /* idx of first free DBr in this page */ - hermon_dbr_t dbr[1]; /* rest ot he page is the DBrs */ -} hermon_dbr_header_t; - -#define HERMON_DBR_HEADER_LEN /* size in QUADWORDS/DBRs */ \ - ((sizeof (hermon_dbr_header_t) / sizeof (hermon_dbr_t)) - 1) - -#define HERMON_NUM_DBR_PER_PAGE ((PAGESIZE >> 3) - HERMON_DBR_HEADER_LEN) +#define HERMON_NUM_DBR_PER_PAGE (PAGESIZE / sizeof (hermon_dbr_t)) /*