lpfc_mem.c revision 5542134f61157d0bbd4e392919cae811a88a3e81
1/*******************************************************************
2 * This file is part of the Emulex Linux Device Driver for         *
3 * Enterprise Fibre Channel Host Bus Adapters.                     *
4 * Refer to the README file included with this package for         *
5 * driver version and adapter support.                             *
6 * Copyright (C) 2004 Emulex Corporation.                          *
7 * www.emulex.com                                                  *
8 *                                                                 *
9 * This program is free software; you can redistribute it and/or   *
10 * modify it under the terms of the GNU General Public License     *
11 * as published by the Free Software Foundation; either version 2  *
12 * of the License, or (at your option) any later version.          *
13 *                                                                 *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of  *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
17 * GNU General Public License for more details, a copy of which    *
18 * can be found in the file COPYING included with this package.    *
19 *******************************************************************/
20
21#include <linux/mempool.h>
22#include <linux/pci.h>
23#include <linux/interrupt.h>
24
25#include "lpfc_hw.h"
26#include "lpfc_sli.h"
27#include "lpfc_disc.h"
28#include "lpfc_scsi.h"
29#include "lpfc.h"
30#include "lpfc_crtn.h"
31
32#define LPFC_MBUF_POOL_SIZE     64      /* max elements in MBUF safety pool */
33#define LPFC_MEM_POOL_SIZE      64      /* max elem in non-DMA safety pool */
34
35static void *
36lpfc_pool_kmalloc(unsigned int gfp_flags, void *data)
37{
38	return kmalloc((unsigned long)data, gfp_flags);
39}
40
41static void
42lpfc_pool_kfree(void *obj, void *data)
43{
44	kfree(obj);
45}
46
47int
48lpfc_mem_alloc(struct lpfc_hba * phba)
49{
50	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
51	int i;
52
53	phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
54				phba->pcidev, phba->cfg_sg_dma_buf_size, 8, 0);
55	if (!phba->lpfc_scsi_dma_buf_pool)
56		goto fail;
57
58	phba->lpfc_mbuf_pool = pci_pool_create("lpfc_mbuf_pool", phba->pcidev,
59							LPFC_BPL_SIZE, 8,0);
60	if (!phba->lpfc_mbuf_pool)
61		goto fail_free_dma_buf_pool;
62
63	pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) *
64					 LPFC_MBUF_POOL_SIZE, GFP_KERNEL);
65	pool->max_count = 0;
66	pool->current_count = 0;
67	for ( i = 0; i < LPFC_MBUF_POOL_SIZE; i++) {
68		pool->elements[i].virt = pci_pool_alloc(phba->lpfc_mbuf_pool,
69				       GFP_KERNEL, &pool->elements[i].phys);
70		if (!pool->elements[i].virt)
71			goto fail_free_mbuf_pool;
72		pool->max_count++;
73		pool->current_count++;
74	}
75
76	phba->mbox_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
77				lpfc_pool_kmalloc, lpfc_pool_kfree,
78				(void *)(unsigned long)sizeof(LPFC_MBOXQ_t));
79	if (!phba->mbox_mem_pool)
80		goto fail_free_mbuf_pool;
81
82	phba->nlp_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
83			lpfc_pool_kmalloc, lpfc_pool_kfree,
84			(void *)(unsigned long)sizeof(struct lpfc_nodelist));
85	if (!phba->nlp_mem_pool)
86		goto fail_free_mbox_pool;
87
88	return 0;
89
90 fail_free_mbox_pool:
91	mempool_destroy(phba->mbox_mem_pool);
92 fail_free_mbuf_pool:
93	while (--i)
94		pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
95						 pool->elements[i].phys);
96	kfree(pool->elements);
97	pci_pool_destroy(phba->lpfc_mbuf_pool);
98 fail_free_dma_buf_pool:
99	pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
100 fail:
101	return -ENOMEM;
102}
103
104void
105lpfc_mem_free(struct lpfc_hba * phba)
106{
107	struct lpfc_sli *psli = &phba->sli;
108	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
109	LPFC_MBOXQ_t *mbox, *next_mbox;
110	struct lpfc_dmabuf   *mp;
111	int i;
112
113	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
114		mp = (struct lpfc_dmabuf *) (mbox->context1);
115		if (mp) {
116			lpfc_mbuf_free(phba, mp->virt, mp->phys);
117			kfree(mp);
118		}
119		list_del(&mbox->list);
120		mempool_free(mbox, phba->mbox_mem_pool);
121	}
122
123	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
124	if (psli->mbox_active) {
125		mbox = psli->mbox_active;
126		mp = (struct lpfc_dmabuf *) (mbox->context1);
127		if (mp) {
128			lpfc_mbuf_free(phba, mp->virt, mp->phys);
129			kfree(mp);
130		}
131		mempool_free(mbox, phba->mbox_mem_pool);
132		psli->mbox_active = NULL;
133	}
134
135	for (i = 0; i < pool->current_count; i++)
136		pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
137						 pool->elements[i].phys);
138	kfree(pool->elements);
139	mempool_destroy(phba->nlp_mem_pool);
140	mempool_destroy(phba->mbox_mem_pool);
141
142	pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
143	pci_pool_destroy(phba->lpfc_mbuf_pool);
144}
145
146void *
147lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
148{
149	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
150	void *ret;
151
152	ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle);
153
154	if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) {
155		pool->current_count--;
156		ret = pool->elements[pool->current_count].virt;
157		*handle = pool->elements[pool->current_count].phys;
158	}
159	return ret;
160}
161
162void
163lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
164{
165	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
166
167	if (pool->current_count < pool->max_count) {
168		pool->elements[pool->current_count].virt = virt;
169		pool->elements[pool->current_count].phys = dma;
170		pool->current_count++;
171	} else {
172		pci_pool_free(phba->lpfc_mbuf_pool, virt, dma);
173	}
174	return;
175}
176