]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.drivers/ehca-malloc-speedup
Updated xen patches taken from suse.
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.drivers / ehca-malloc-speedup
1 From: Stefan Roscher <stefan.roscher@de.ibm.com>
2 Subject: Re: [PATCH 1/3] IB/ehca: Replace vmalloc with kmalloc
3 Date Wed, 22 Apr 2009 16:02:28 +0200
4 References: bnc#491430
5 Patch-mainline: 2.6.31
6
7 In case of large queue pairs there is the possibillity of allocation failures
8 due to memory fragmentation with kmalloc(). To ensure the memory is allocated
9 even if kmalloc() can not find chunks which are big enough, we try to allocate
10 the memory with vmalloc().
11
12 Because kmalloc() is faster than vmalloc() causing a huge performance win
13 when someone allocates a large number of queue pairs. We fall back to
14 vmalloc() only if kmalloc() can't deliver the memory chunk.
15
16 Signed-off-by: Stefan Roscher <stefan.roscher@de.ibm.com>
17 Acked-by: <mfrueh@suse.de>
18
19 --- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/ipz_pt_fn.c
20 +++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/ipz_pt_fn.c
21 @@ -220,10 +220,13 @@ int ipz_queue_ctor(struct ehca_pd *pd, s
22 queue->small_page = NULL;
23
24 /* allocate queue page pointers */
25 - queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
26 + queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
27 if (!queue->queue_pages) {
28 - ehca_gen_err("Couldn't allocate queue page list");
29 - return 0;
30 + queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
31 + if (!queue->queue_pages) {
32 + ehca_gen_err("Couldn't allocate queue page list");
33 + return 0;
34 + }
35 }
36 memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
37
38 @@ -240,7 +243,10 @@ int ipz_queue_ctor(struct ehca_pd *pd, s
39 ipz_queue_ctor_exit0:
40 ehca_gen_err("Couldn't alloc pages queue=%p "
41 "nr_of_pages=%x", queue, nr_of_pages);
42 - vfree(queue->queue_pages);
43 + if (is_vmalloc_addr(queue->queue_pages))
44 + vfree(queue->queue_pages);
45 + else
46 + kfree(queue->queue_pages);
47
48 return 0;
49 }
50 @@ -262,7 +268,10 @@ int ipz_queue_dtor(struct ehca_pd *pd, s
51 free_page((unsigned long)queue->queue_pages[i]);
52 }
53
54 - vfree(queue->queue_pages);
55 + if (is_vmalloc_addr(queue->queue_pages))
56 + vfree(queue->queue_pages);
57 + else
58 + kfree(queue->queue_pages);
59
60 return 1;
61 }
62 --- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/ehca_qp.c
63 +++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/ehca_qp.c
64 @@ -457,7 +457,7 @@ static struct ehca_qp *internal_create_q
65 ib_device);
66 struct ib_ucontext *context = NULL;
67 u64 h_ret;
68 - int is_llqp = 0, has_srq = 0;
69 + int is_llqp = 0, has_srq = 0, is_user = 0;
70 int qp_type, max_send_sge, max_recv_sge, ret;
71
72 /* h_call's out parameters */
73 @@ -599,9 +599,6 @@ static struct ehca_qp *internal_create_q
74 }
75 }
76
77 - if (pd->uobject && udata)
78 - context = pd->uobject->context;
79 -
80 my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL);
81 if (!my_qp) {
82 ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd);
83 @@ -609,6 +606,11 @@ static struct ehca_qp *internal_create_q
84 return ERR_PTR(-ENOMEM);
85 }
86
87 + if (pd->uobject && udata) {
88 + is_user = 1;
89 + context = pd->uobject->context;
90 + }
91 +
92 atomic_set(&my_qp->nr_events, 0);
93 init_waitqueue_head(&my_qp->wait_completion);
94 spin_lock_init(&my_qp->spinlock_s);
95 @@ -697,7 +699,7 @@ static struct ehca_qp *internal_create_q
96 (parms.squeue.is_small || parms.rqueue.is_small);
97 }
98
99 - h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
100 + h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms, is_user);
101 if (h_ret != H_SUCCESS) {
102 ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li",
103 h_ret);
104 @@ -759,18 +761,20 @@ static struct ehca_qp *internal_create_q
105 goto create_qp_exit2;
106 }
107
108 - my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length /
109 - my_qp->ipz_squeue.qe_size;
110 - my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
111 - sizeof(struct ehca_qmap_entry));
112 - if (!my_qp->sq_map.map) {
113 - ehca_err(pd->device, "Couldn't allocate squeue "
114 - "map ret=%i", ret);
115 - goto create_qp_exit3;
116 - }
117 - INIT_LIST_HEAD(&my_qp->sq_err_node);
118 - /* to avoid the generation of bogus flush CQEs */
119 - reset_queue_map(&my_qp->sq_map);
120 + if (!is_user) {
121 + my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length /
122 + my_qp->ipz_squeue.qe_size;
123 + my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
124 + sizeof(struct ehca_qmap_entry));
125 + if (!my_qp->sq_map.map) {
126 + ehca_err(pd->device, "Couldn't allocate squeue "
127 + "map ret=%i", ret);
128 + goto create_qp_exit3;
129 + }
130 + INIT_LIST_HEAD(&my_qp->sq_err_node);
131 + /* to avoid the generation of bogus flush CQEs */
132 + reset_queue_map(&my_qp->sq_map);
133 + }
134 }
135
136 if (HAS_RQ(my_qp)) {
137 @@ -782,20 +786,21 @@ static struct ehca_qp *internal_create_q
138 "and pages ret=%i", ret);
139 goto create_qp_exit4;
140 }
141 -
142 - my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
143 - my_qp->ipz_rqueue.qe_size;
144 - my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
145 - sizeof(struct ehca_qmap_entry));
146 - if (!my_qp->rq_map.map) {
147 - ehca_err(pd->device, "Couldn't allocate squeue "
148 - "map ret=%i", ret);
149 - goto create_qp_exit5;
150 + if (!is_user) {
151 + my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
152 + my_qp->ipz_rqueue.qe_size;
153 + my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
154 + sizeof(struct ehca_qmap_entry));
155 + if (!my_qp->rq_map.map) {
156 + ehca_err(pd->device, "Couldn't allocate squeue "
157 + "map ret=%i", ret);
158 + goto create_qp_exit5;
159 + }
160 + INIT_LIST_HEAD(&my_qp->rq_err_node);
161 + /* to avoid the generation of bogus flush CQEs */
162 + reset_queue_map(&my_qp->rq_map);
163 }
164 - INIT_LIST_HEAD(&my_qp->rq_err_node);
165 - /* to avoid the generation of bogus flush CQEs */
166 - reset_queue_map(&my_qp->rq_map);
167 - } else if (init_attr->srq) {
168 + } else if (init_attr->srq && !is_user) {
169 /* this is a base QP, use the queue map of the SRQ */
170 my_qp->rq_map = my_srq->rq_map;
171 INIT_LIST_HEAD(&my_qp->rq_err_node);
172 @@ -908,7 +913,7 @@ create_qp_exit7:
173 kfree(my_qp->mod_qp_parm);
174
175 create_qp_exit6:
176 - if (HAS_RQ(my_qp))
177 + if (HAS_RQ(my_qp) && !is_user)
178 vfree(my_qp->rq_map.map);
179
180 create_qp_exit5:
181 @@ -916,7 +921,7 @@ create_qp_exit5:
182 ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
183
184 create_qp_exit4:
185 - if (HAS_SQ(my_qp))
186 + if (HAS_SQ(my_qp) && !is_user)
187 vfree(my_qp->sq_map.map);
188
189 create_qp_exit3:
190 @@ -1224,6 +1229,7 @@ static int internal_modify_qp(struct ib_
191 u64 update_mask;
192 u64 h_ret;
193 int bad_wqe_cnt = 0;
194 + int is_user = 0;
195 int squeue_locked = 0;
196 unsigned long flags = 0;
197
198 @@ -1246,6 +1252,8 @@ static int internal_modify_qp(struct ib_
199 ret = ehca2ib_return_code(h_ret);
200 goto modify_qp_exit1;
201 }
202 + if (ibqp->uobject)
203 + is_user = 1;
204
205 qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state);
206
207 @@ -1708,7 +1716,8 @@ static int internal_modify_qp(struct ib_
208 goto modify_qp_exit2;
209 }
210 }
211 - if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) {
212 + if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)
213 + && !is_user) {
214 ret = check_for_left_cqes(my_qp, shca);
215 if (ret)
216 goto modify_qp_exit2;
217 @@ -1718,16 +1727,17 @@ static int internal_modify_qp(struct ib_
218 ipz_qeit_reset(&my_qp->ipz_rqueue);
219 ipz_qeit_reset(&my_qp->ipz_squeue);
220
221 - if (qp_cur_state == IB_QPS_ERR) {
222 + if (qp_cur_state == IB_QPS_ERR && !is_user) {
223 del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
224
225 if (HAS_RQ(my_qp))
226 del_from_err_list(my_qp->recv_cq,
227 &my_qp->rq_err_node);
228 }
229 - reset_queue_map(&my_qp->sq_map);
230 + if (!is_user)
231 + reset_queue_map(&my_qp->sq_map);
232
233 - if (HAS_RQ(my_qp))
234 + if (HAS_RQ(my_qp) && !is_user)
235 reset_queue_map(&my_qp->rq_map);
236 }
237
238 @@ -2118,10 +2128,12 @@ static int internal_destroy_qp(struct ib
239 int ret;
240 u64 h_ret;
241 u8 port_num;
242 + int is_user = 0;
243 enum ib_qp_type qp_type;
244 unsigned long flags;
245
246 if (uobject) {
247 + is_user = 1;
248 if (my_qp->mm_count_galpa ||
249 my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
250 ehca_err(dev, "Resources still referenced in "
251 @@ -2148,10 +2160,10 @@ static int internal_destroy_qp(struct ib
252 * SRQs will never get into an error list and do not have a recv_cq,
253 * so we need to skip them here.
254 */
255 - if (HAS_RQ(my_qp) && !IS_SRQ(my_qp))
256 + if (HAS_RQ(my_qp) && !IS_SRQ(my_qp) && !is_user)
257 del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node);
258
259 - if (HAS_SQ(my_qp))
260 + if (HAS_SQ(my_qp) && !is_user)
261 del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
262
263 /* now wait until all pending events have completed */
264 @@ -2189,13 +2201,13 @@ static int internal_destroy_qp(struct ib
265
266 if (HAS_RQ(my_qp)) {
267 ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
268 -
269 - vfree(my_qp->rq_map.map);
270 + if (!is_user)
271 + vfree(my_qp->rq_map.map);
272 }
273 if (HAS_SQ(my_qp)) {
274 ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
275 -
276 - vfree(my_qp->sq_map.map);
277 + if (!is_user)
278 + vfree(my_qp->sq_map.map);
279 }
280 kmem_cache_free(qp_cache, my_qp);
281 atomic_dec(&shca->num_qps);
282 --- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_if.c
283 +++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_if.c
284 @@ -284,7 +284,7 @@ u64 hipz_h_alloc_resource_cq(const struc
285 param->act_pages = (u32)outs[4];
286
287 if (ret == H_SUCCESS)
288 - hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
289 + hcp_galpas_ctor(&cq->galpas, 0, outs[5], outs[6]);
290
291 if (ret == H_NOT_ENOUGH_RESOURCES)
292 ehca_gen_err("Not enough resources. ret=%li", ret);
293 @@ -293,7 +293,7 @@ u64 hipz_h_alloc_resource_cq(const struc
294 }
295
296 u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
297 - struct ehca_alloc_qp_parms *parms)
298 + struct ehca_alloc_qp_parms *parms, int is_user)
299 {
300 u64 ret;
301 u64 allocate_controls, max_r10_reg, r11, r12;
302 @@ -359,7 +359,7 @@ u64 hipz_h_alloc_resource_qp(const struc
303 (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
304
305 if (ret == H_SUCCESS)
306 - hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]);
307 + hcp_galpas_ctor(&parms->galpas, is_user, outs[6], outs[6]);
308
309 if (ret == H_NOT_ENOUGH_RESOURCES)
310 ehca_gen_err("Not enough resources. ret=%li", ret);
311 --- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_if.h
312 +++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_if.h
313 @@ -78,7 +78,7 @@ u64 hipz_h_alloc_resource_cq(const struc
314 * initialize resources, create empty QPPTs (2 rings).
315 */
316 u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
317 - struct ehca_alloc_qp_parms *parms);
318 + struct ehca_alloc_qp_parms *parms, int is_user);
319
320 u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
321 const u8 port_id,
322 --- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_phyp.c
323 +++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_phyp.c
324 @@ -54,12 +54,15 @@ int hcall_unmap_page(u64 mapaddr)
325 return 0;
326 }
327
328 -int hcp_galpas_ctor(struct h_galpas *galpas,
329 +int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
330 u64 paddr_kernel, u64 paddr_user)
331 {
332 - int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
333 - if (ret)
334 - return ret;
335 + if (!is_user) {
336 + int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
337 + if (ret)
338 + return ret;
339 + } else
340 + galpas->kernel.fw_handle = NULL;
341
342 galpas->user.fw_handle = paddr_user;
343
344 --- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_phyp.h
345 +++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_phyp.h
346 @@ -78,7 +78,7 @@ static inline void hipz_galpa_store(stru
347 *(volatile u64 __force *)addr = value;
348 }
349
350 -int hcp_galpas_ctor(struct h_galpas *galpas,
351 +int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
352 u64 paddr_kernel, u64 paddr_user);
353
354 int hcp_galpas_dtor(struct h_galpas *galpas);
355 --- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/ehca_main.c
356 +++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/ehca_main.c
357 @@ -52,7 +52,7 @@
358 #include "ehca_tools.h"
359 #include "hcp_if.h"
360
361 -#define HCAD_VERSION "0026"
362 +#define HCAD_VERSION "0027"
363
364 MODULE_LICENSE("Dual BSD/GPL");
365 MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");