diff options
| -rw-r--r-- | drivers/infiniband/hw/ehca/ehca_classes.h | 41 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ehca_cq.c | 8 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ehca_eq.c | 8 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ehca_main.c | 14 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ehca_pd.c | 25 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ehca_qp.c | 161 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ehca_uverbs.c | 2 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/hcp_if.c | 30 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ipz_pt_fn.c | 222 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ehca/ipz_pt_fn.h | 26 |
10 files changed, 378 insertions, 159 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 63b8b9f7c4fc..3725aa8664d9 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h | |||
| @@ -43,7 +43,6 @@ | |||
| 43 | #ifndef __EHCA_CLASSES_H__ | 43 | #ifndef __EHCA_CLASSES_H__ |
| 44 | #define __EHCA_CLASSES_H__ | 44 | #define __EHCA_CLASSES_H__ |
| 45 | 45 | ||
| 46 | |||
| 47 | struct ehca_module; | 46 | struct ehca_module; |
| 48 | struct ehca_qp; | 47 | struct ehca_qp; |
| 49 | struct ehca_cq; | 48 | struct ehca_cq; |
| @@ -129,6 +128,10 @@ struct ehca_pd { | |||
| 129 | struct ib_pd ib_pd; | 128 | struct ib_pd ib_pd; |
| 130 | struct ipz_pd fw_pd; | 129 | struct ipz_pd fw_pd; |
| 131 | u32 ownpid; | 130 | u32 ownpid; |
| 131 | /* small queue mgmt */ | ||
| 132 | struct mutex lock; | ||
| 133 | struct list_head free[2]; | ||
| 134 | struct list_head full[2]; | ||
| 132 | }; | 135 | }; |
| 133 | 136 | ||
| 134 | enum ehca_ext_qp_type { | 137 | enum ehca_ext_qp_type { |
| @@ -307,6 +310,8 @@ int ehca_init_av_cache(void); | |||
| 307 | void ehca_cleanup_av_cache(void); | 310 | void ehca_cleanup_av_cache(void); |
| 308 | int ehca_init_mrmw_cache(void); | 311 | int ehca_init_mrmw_cache(void); |
| 309 | void ehca_cleanup_mrmw_cache(void); | 312 | void ehca_cleanup_mrmw_cache(void); |
| 313 | int ehca_init_small_qp_cache(void); | ||
| 314 | void ehca_cleanup_small_qp_cache(void); | ||
| 310 | 315 | ||
| 311 | extern rwlock_t ehca_qp_idr_lock; | 316 | extern rwlock_t ehca_qp_idr_lock; |
| 312 | extern rwlock_t ehca_cq_idr_lock; | 317 | extern rwlock_t ehca_cq_idr_lock; |
| @@ -324,7 +329,7 @@ struct ipzu_queue_resp { | |||
| 324 | u32 queue_length; /* queue length allocated in bytes */ | 329 | u32 queue_length; /* queue length allocated in bytes */ |
| 325 | u32 pagesize; | 330 | u32 pagesize; |
| 326 | u32 toggle_state; | 331 | u32 toggle_state; |
| 327 | u32 dummy; /* padding for 8 byte alignment */ | 332 | u32 offset; /* save offset within a page for small_qp */ |
| 328 | }; | 333 | }; |
| 329 | 334 | ||
| 330 | struct ehca_create_cq_resp { | 335 | struct ehca_create_cq_resp { |
| @@ -366,15 +371,29 @@ enum ehca_ll_comp_flags { | |||
| 366 | LLQP_COMP_MASK = 0x60, | 371 | LLQP_COMP_MASK = 0x60, |
| 367 | }; | 372 | }; |
| 368 | 373 | ||
| 374 | struct ehca_alloc_queue_parms { | ||
| 375 | /* input parameters */ | ||
| 376 | int max_wr; | ||
| 377 | int max_sge; | ||
| 378 | int page_size; | ||
| 379 | int is_small; | ||
| 380 | |||
| 381 | /* output parameters */ | ||
| 382 | u16 act_nr_wqes; | ||
| 383 | u8 act_nr_sges; | ||
| 384 | u32 queue_size; /* bytes for small queues, pages otherwise */ | ||
| 385 | }; | ||
| 386 | |||
| 369 | struct ehca_alloc_qp_parms { | 387 | struct ehca_alloc_qp_parms { |
| 370 | /* input parameters */ | 388 | struct ehca_alloc_queue_parms squeue; |
| 389 | struct ehca_alloc_queue_parms rqueue; | ||
| 390 | |||
| 391 | /* input parameters */ | ||
| 371 | enum ehca_service_type servicetype; | 392 | enum ehca_service_type servicetype; |
| 393 | int qp_storage; | ||
| 372 | int sigtype; | 394 | int sigtype; |
| 373 | enum ehca_ext_qp_type ext_type; | 395 | enum ehca_ext_qp_type ext_type; |
| 374 | enum ehca_ll_comp_flags ll_comp_flags; | 396 | enum ehca_ll_comp_flags ll_comp_flags; |
| 375 | |||
| 376 | int max_send_wr, max_recv_wr; | ||
| 377 | int max_send_sge, max_recv_sge; | ||
| 378 | int ud_av_l_key_ctl; | 397 | int ud_av_l_key_ctl; |
| 379 | 398 | ||
| 380 | u32 token; | 399 | u32 token; |
| @@ -384,18 +403,10 @@ struct ehca_alloc_qp_parms { | |||
| 384 | 403 | ||
| 385 | u32 srq_qpn, srq_token, srq_limit; | 404 | u32 srq_qpn, srq_token, srq_limit; |
| 386 | 405 | ||
| 387 | /* output parameters */ | 406 | /* output parameters */ |
| 388 | u32 real_qp_num; | 407 | u32 real_qp_num; |
| 389 | struct ipz_qp_handle qp_handle; | 408 | struct ipz_qp_handle qp_handle; |
| 390 | struct h_galpas galpas; | 409 | struct h_galpas galpas; |
| 391 | |||
| 392 | u16 act_nr_send_wqes; | ||
| 393 | u16 act_nr_recv_wqes; | ||
| 394 | u8 act_nr_recv_sges; | ||
| 395 | u8 act_nr_send_sges; | ||
| 396 | |||
| 397 | u32 nr_rq_pages; | ||
| 398 | u32 nr_sq_pages; | ||
| 399 | }; | 410 | }; |
| 400 | 411 | ||
| 401 | int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp); | 412 | int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp); |
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 1e8ca3fca4aa..81aff36101ba 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c | |||
| @@ -190,8 +190,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, | |||
| 190 | goto create_cq_exit2; | 190 | goto create_cq_exit2; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages, | 193 | ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages, |
| 194 | EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0); | 194 | EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0); |
| 195 | if (!ipz_rc) { | 195 | if (!ipz_rc) { |
| 196 | ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p", | 196 | ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p", |
| 197 | ipz_rc, device); | 197 | ipz_rc, device); |
| @@ -285,7 +285,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, | |||
| 285 | return cq; | 285 | return cq; |
| 286 | 286 | ||
| 287 | create_cq_exit4: | 287 | create_cq_exit4: |
| 288 | ipz_queue_dtor(&my_cq->ipz_queue); | 288 | ipz_queue_dtor(NULL, &my_cq->ipz_queue); |
| 289 | 289 | ||
| 290 | create_cq_exit3: | 290 | create_cq_exit3: |
| 291 | h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1); | 291 | h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1); |
| @@ -359,7 +359,7 @@ int ehca_destroy_cq(struct ib_cq *cq) | |||
| 359 | "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num); | 359 | "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num); |
| 360 | return ehca2ib_return_code(h_ret); | 360 | return ehca2ib_return_code(h_ret); |
| 361 | } | 361 | } |
| 362 | ipz_queue_dtor(&my_cq->ipz_queue); | 362 | ipz_queue_dtor(NULL, &my_cq->ipz_queue); |
| 363 | kmem_cache_free(cq_cache, my_cq); | 363 | kmem_cache_free(cq_cache, my_cq); |
| 364 | 364 | ||
| 365 | return 0; | 365 | return 0; |
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index 4825975f88cf..1d41faa7a337 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c | |||
| @@ -86,8 +86,8 @@ int ehca_create_eq(struct ehca_shca *shca, | |||
| 86 | return -EINVAL; | 86 | return -EINVAL; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages, | 89 | ret = ipz_queue_ctor(NULL, &eq->ipz_queue, nr_pages, |
| 90 | EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0); | 90 | EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0, 0); |
| 91 | if (!ret) { | 91 | if (!ret) { |
| 92 | ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq); | 92 | ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq); |
| 93 | goto create_eq_exit1; | 93 | goto create_eq_exit1; |
| @@ -145,7 +145,7 @@ int ehca_create_eq(struct ehca_shca *shca, | |||
| 145 | return 0; | 145 | return 0; |
| 146 | 146 | ||
| 147 | create_eq_exit2: | 147 | create_eq_exit2: |
| 148 | ipz_queue_dtor(&eq->ipz_queue); | 148 | ipz_queue_dtor(NULL, &eq->ipz_queue); |
| 149 | 149 | ||
| 150 | create_eq_exit1: | 150 | create_eq_exit1: |
| 151 | hipz_h_destroy_eq(shca->ipz_hca_handle, eq); | 151 | hipz_h_destroy_eq(shca->ipz_hca_handle, eq); |
| @@ -181,7 +181,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq) | |||
| 181 | ehca_err(&shca->ib_device, "Can't free EQ resources."); | 181 | ehca_err(&shca->ib_device, "Can't free EQ resources."); |
| 182 | return -EINVAL; | 182 | return -EINVAL; |
| 183 | } | 183 | } |
| 184 | ipz_queue_dtor(&eq->ipz_queue); | 184 | ipz_queue_dtor(NULL, &eq->ipz_queue); |
| 185 | 185 | ||
| 186 | return 0; | 186 | return 0; |
| 187 | } | 187 | } |
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index bb104b7f73e3..99036b65bb84 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c | |||
| @@ -181,6 +181,12 @@ static int ehca_create_slab_caches(void) | |||
| 181 | goto create_slab_caches5; | 181 | goto create_slab_caches5; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | ret = ehca_init_small_qp_cache(); | ||
| 185 | if (ret) { | ||
| 186 | ehca_gen_err("Cannot create small queue SLAB cache."); | ||
| 187 | goto create_slab_caches6; | ||
| 188 | } | ||
| 189 | |||
| 184 | #ifdef CONFIG_PPC_64K_PAGES | 190 | #ifdef CONFIG_PPC_64K_PAGES |
| 185 | ctblk_cache = kmem_cache_create("ehca_cache_ctblk", | 191 | ctblk_cache = kmem_cache_create("ehca_cache_ctblk", |
| 186 | EHCA_PAGESIZE, H_CB_ALIGNMENT, | 192 | EHCA_PAGESIZE, H_CB_ALIGNMENT, |
| @@ -188,12 +194,15 @@ static int ehca_create_slab_caches(void) | |||
| 188 | NULL); | 194 | NULL); |
| 189 | if (!ctblk_cache) { | 195 | if (!ctblk_cache) { |
| 190 | ehca_gen_err("Cannot create ctblk SLAB cache."); | 196 | ehca_gen_err("Cannot create ctblk SLAB cache."); |
| 191 | ehca_cleanup_mrmw_cache(); | 197 | ehca_cleanup_small_qp_cache(); |
| 192 | goto create_slab_caches5; | 198 | goto create_slab_caches6; |
| 193 | } | 199 | } |
| 194 | #endif | 200 | #endif |
| 195 | return 0; | 201 | return 0; |
| 196 | 202 | ||
| 203 | create_slab_caches6: | ||
| 204 | ehca_cleanup_mrmw_cache(); | ||
| 205 | |||
| 197 | create_slab_caches5: | 206 | create_slab_caches5: |
| 198 | ehca_cleanup_av_cache(); | 207 | ehca_cleanup_av_cache(); |
| 199 | 208 | ||
| @@ -211,6 +220,7 @@ create_slab_caches2: | |||
| 211 | 220 | ||
| 212 | static void ehca_destroy_slab_caches(void) | 221 | static void ehca_destroy_slab_caches(void) |
| 213 | { | 222 | { |
| 223 | ehca_cleanup_small_qp_cache(); | ||
| 214 | ehca_cleanup_mrmw_cache(); | 224 | ehca_cleanup_mrmw_cache(); |
| 215 | ehca_cleanup_av_cache(); | 225 | ehca_cleanup_av_cache(); |
| 216 | ehca_cleanup_qp_cache(); | 226 | ehca_cleanup_qp_cache(); |
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c index c85312ad292b..3dafd7ff36cd 100644 --- a/drivers/infiniband/hw/ehca/ehca_pd.c +++ b/drivers/infiniband/hw/ehca/ehca_pd.c | |||
| @@ -49,6 +49,7 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device, | |||
| 49 | struct ib_ucontext *context, struct ib_udata *udata) | 49 | struct ib_ucontext *context, struct ib_udata *udata) |
| 50 | { | 50 | { |
| 51 | struct ehca_pd *pd; | 51 | struct ehca_pd *pd; |
| 52 | int i; | ||
| 52 | 53 | ||
| 53 | pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL); | 54 | pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL); |
| 54 | if (!pd) { | 55 | if (!pd) { |
| @@ -58,6 +59,11 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device, | |||
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | pd->ownpid = current->tgid; | 61 | pd->ownpid = current->tgid; |
| 62 | for (i = 0; i < 2; i++) { | ||
| 63 | INIT_LIST_HEAD(&pd->free[i]); | ||
| 64 | INIT_LIST_HEAD(&pd->full[i]); | ||
| 65 | } | ||
| 66 | mutex_init(&pd->lock); | ||
| 61 | 67 | ||
| 62 | /* | 68 | /* |
| 63 | * Kernel PD: when device = -1, 0 | 69 | * Kernel PD: when device = -1, 0 |
| @@ -81,6 +87,9 @@ int ehca_dealloc_pd(struct ib_pd *pd) | |||
| 81 | { | 87 | { |
| 82 | u32 cur_pid = current->tgid; | 88 | u32 cur_pid = current->tgid; |
| 83 | struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd); | 89 | struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd); |
| 90 | int i, leftovers = 0; | ||
| 91 | extern struct kmem_cache *small_qp_cache; | ||
| 92 | struct ipz_small_queue_page *page, *tmp; | ||
| 84 | 93 | ||
| 85 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | 94 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && |
| 86 | my_pd->ownpid != cur_pid) { | 95 | my_pd->ownpid != cur_pid) { |
| @@ -89,8 +98,20 @@ int ehca_dealloc_pd(struct ib_pd *pd) | |||
| 89 | return -EINVAL; | 98 | return -EINVAL; |
| 90 | } | 99 | } |
| 91 | 100 | ||
| 92 | kmem_cache_free(pd_cache, | 101 | for (i = 0; i < 2; i++) { |
| 93 | container_of(pd, struct ehca_pd, ib_pd)); | 102 | list_splice(&my_pd->full[i], &my_pd->free[i]); |
| 103 | list_for_each_entry_safe(page, tmp, &my_pd->free[i], list) { | ||
| 104 | leftovers = 1; | ||
| 105 | free_page(page->page); | ||
| 106 | kmem_cache_free(small_qp_cache, page); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | if (leftovers) | ||
| 111 | ehca_warn(pd->device, | ||
| 112 | "Some small queue pages were not freed"); | ||
| 113 | |||
| 114 | kmem_cache_free(pd_cache, my_pd); | ||
| 94 | 115 | ||
| 95 | return 0; | 116 | return 0; |
| 96 | } | 117 | } |
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 483f0ca1acc4..b178cba96345 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c | |||
| @@ -275,34 +275,39 @@ static inline void queue2resp(struct ipzu_queue_resp *resp, | |||
| 275 | resp->toggle_state = queue->toggle_state; | 275 | resp->toggle_state = queue->toggle_state; |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | static inline int ll_qp_msg_size(int nr_sge) | ||
| 279 | { | ||
| 280 | return 128 << nr_sge; | ||
| 281 | } | ||
| 282 | |||
| 283 | /* | 278 | /* |
| 284 | * init_qp_queue initializes/constructs r/squeue and registers queue pages. | 279 | * init_qp_queue initializes/constructs r/squeue and registers queue pages. |
| 285 | */ | 280 | */ |
| 286 | static inline int init_qp_queue(struct ehca_shca *shca, | 281 | static inline int init_qp_queue(struct ehca_shca *shca, |
| 282 | struct ehca_pd *pd, | ||
| 287 | struct ehca_qp *my_qp, | 283 | struct ehca_qp *my_qp, |
| 288 | struct ipz_queue *queue, | 284 | struct ipz_queue *queue, |
| 289 | int q_type, | 285 | int q_type, |
| 290 | u64 expected_hret, | 286 | u64 expected_hret, |
| 291 | int nr_q_pages, | 287 | struct ehca_alloc_queue_parms *parms, |
| 292 | int wqe_size, | 288 | int wqe_size) |
| 293 | int nr_sges) | ||
| 294 | { | 289 | { |
| 295 | int ret, cnt, ipz_rc; | 290 | int ret, cnt, ipz_rc, nr_q_pages; |
| 296 | void *vpage; | 291 | void *vpage; |
| 297 | u64 rpage, h_ret; | 292 | u64 rpage, h_ret; |
| 298 | struct ib_device *ib_dev = &shca->ib_device; | 293 | struct ib_device *ib_dev = &shca->ib_device; |
| 299 | struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle; | 294 | struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle; |
| 300 | 295 | ||
| 301 | if (!nr_q_pages) | 296 | if (!parms->queue_size) |
| 302 | return 0; | 297 | return 0; |
| 303 | 298 | ||
| 304 | ipz_rc = ipz_queue_ctor(queue, nr_q_pages, EHCA_PAGESIZE, | 299 | if (parms->is_small) { |
| 305 | wqe_size, nr_sges); | 300 | nr_q_pages = 1; |
| 301 | ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages, | ||
| 302 | 128 << parms->page_size, | ||
| 303 | wqe_size, parms->act_nr_sges, 1); | ||
| 304 | } else { | ||
| 305 | nr_q_pages = parms->queue_size; | ||
| 306 | ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages, | ||
| 307 | EHCA_PAGESIZE, wqe_size, | ||
| 308 | parms->act_nr_sges, 0); | ||
| 309 | } | ||
| 310 | |||
| 306 | if (!ipz_rc) { | 311 | if (!ipz_rc) { |
| 307 | ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x", | 312 | ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x", |
| 308 | ipz_rc); | 313 | ipz_rc); |
| @@ -323,7 +328,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, | |||
| 323 | h_ret = hipz_h_register_rpage_qp(ipz_hca_handle, | 328 | h_ret = hipz_h_register_rpage_qp(ipz_hca_handle, |
| 324 | my_qp->ipz_qp_handle, | 329 | my_qp->ipz_qp_handle, |
| 325 | NULL, 0, q_type, | 330 | NULL, 0, q_type, |
| 326 | rpage, 1, | 331 | rpage, parms->is_small ? 0 : 1, |
| 327 | my_qp->galpas.kernel); | 332 | my_qp->galpas.kernel); |
| 328 | if (cnt == (nr_q_pages - 1)) { /* last page! */ | 333 | if (cnt == (nr_q_pages - 1)) { /* last page! */ |
| 329 | if (h_ret != expected_hret) { | 334 | if (h_ret != expected_hret) { |
| @@ -354,10 +359,45 @@ static inline int init_qp_queue(struct ehca_shca *shca, | |||
| 354 | return 0; | 359 | return 0; |
| 355 | 360 | ||
| 356 | init_qp_queue1: | 361 | init_qp_queue1: |
| 357 | ipz_queue_dtor(queue); | 362 | ipz_queue_dtor(pd, queue); |
| 358 | return ret; | 363 | return ret; |
| 359 | } | 364 | } |
| 360 | 365 | ||
| 366 | static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp) | ||
| 367 | { | ||
| 368 | if (is_llqp) | ||
| 369 | return 128 << act_nr_sge; | ||
| 370 | else | ||
| 371 | return offsetof(struct ehca_wqe, | ||
| 372 | u.nud.sg_list[act_nr_sge]); | ||
| 373 | } | ||
| 374 | |||
| 375 | static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue, | ||
| 376 | int req_nr_sge, int is_llqp) | ||
| 377 | { | ||
| 378 | u32 wqe_size, q_size; | ||
| 379 | int act_nr_sge = req_nr_sge; | ||
| 380 | |||
| 381 | if (!is_llqp) | ||
| 382 | /* round up #SGEs so WQE size is a power of 2 */ | ||
| 383 | for (act_nr_sge = 4; act_nr_sge <= 252; | ||
| 384 | act_nr_sge = 4 + 2 * act_nr_sge) | ||
| 385 | if (act_nr_sge >= req_nr_sge) | ||
| 386 | break; | ||
| 387 | |||
| 388 | wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp); | ||
| 389 | q_size = wqe_size * (queue->max_wr + 1); | ||
| 390 | |||
| 391 | if (q_size <= 512) | ||
| 392 | queue->page_size = 2; | ||
| 393 | else if (q_size <= 1024) | ||
| 394 | queue->page_size = 3; | ||
| 395 | else | ||
| 396 | queue->page_size = 0; | ||
| 397 | |||
| 398 | queue->is_small = (queue->page_size != 0); | ||
| 399 | } | ||
| 400 | |||
| 361 | /* | 401 | /* |
| 362 | * Create an ib_qp struct that is either a QP or an SRQ, depending on | 402 | * Create an ib_qp struct that is either a QP or an SRQ, depending on |
| 363 | * the value of the is_srq parameter. If init_attr and srq_init_attr share | 403 | * the value of the is_srq parameter. If init_attr and srq_init_attr share |
| @@ -553,10 +593,20 @@ static struct ehca_qp *internal_create_qp( | |||
| 553 | if (my_qp->recv_cq) | 593 | if (my_qp->recv_cq) |
| 554 | parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle; | 594 | parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle; |
| 555 | 595 | ||
| 556 | parms.max_send_wr = init_attr->cap.max_send_wr; | 596 | parms.squeue.max_wr = init_attr->cap.max_send_wr; |
| 557 | parms.max_recv_wr = init_attr->cap.max_recv_wr; | 597 | parms.rqueue.max_wr = init_attr->cap.max_recv_wr; |
| 558 | parms.max_send_sge = max_send_sge; | 598 | parms.squeue.max_sge = max_send_sge; |
| 559 | parms.max_recv_sge = max_recv_sge; | 599 | parms.rqueue.max_sge = max_recv_sge; |
| 600 | |||
| 601 | if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap) | ||
| 602 | && !(context && udata)) { /* no small QP support in userspace ATM */ | ||
| 603 | ehca_determine_small_queue( | ||
| 604 | &parms.squeue, max_send_sge, is_llqp); | ||
| 605 | ehca_determine_small_queue( | ||
| 606 | &parms.rqueue, max_recv_sge, is_llqp); | ||
| 607 | parms.qp_storage = | ||
| 608 | (parms.squeue.is_small || parms.rqueue.is_small); | ||
| 609 | } | ||
| 560 | 610 | ||
| 561 | h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms); | 611 | h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms); |
| 562 | if (h_ret != H_SUCCESS) { | 612 | if (h_ret != H_SUCCESS) { |
| @@ -570,50 +620,33 @@ static struct ehca_qp *internal_create_qp( | |||
| 570 | my_qp->ipz_qp_handle = parms.qp_handle; | 620 | my_qp->ipz_qp_handle = parms.qp_handle; |
| 571 | my_qp->galpas = parms.galpas; | 621 | my_qp->galpas = parms.galpas; |
| 572 | 622 | ||
| 623 | swqe_size = ehca_calc_wqe_size(parms.squeue.act_nr_sges, is_llqp); | ||
| 624 | rwqe_size = ehca_calc_wqe_size(parms.rqueue.act_nr_sges, is_llqp); | ||
| 625 | |||
| 573 | switch (qp_type) { | 626 | switch (qp_type) { |
| 574 | case IB_QPT_RC: | 627 | case IB_QPT_RC: |
| 575 | if (!is_llqp) { | 628 | if (is_llqp) { |
| 576 | swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[ | 629 | parms.squeue.act_nr_sges = 1; |
| 577 | (parms.act_nr_send_sges)]); | 630 | parms.rqueue.act_nr_sges = 1; |
| 578 | rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[ | ||
| 579 | (parms.act_nr_recv_sges)]); | ||
| 580 | } else { /* for LLQP we need to use msg size, not wqe size */ | ||
| 581 | swqe_size = ll_qp_msg_size(max_send_sge); | ||
| 582 | rwqe_size = ll_qp_msg_size(max_recv_sge); | ||
| 583 | parms.act_nr_send_sges = 1; | ||
| 584 | parms.act_nr_recv_sges = 1; | ||
| 585 | } | 631 | } |
| 586 | break; | 632 | break; |
| 587 | case IB_QPT_UC: | ||
| 588 | swqe_size = offsetof(struct ehca_wqe, | ||
| 589 | u.nud.sg_list[parms.act_nr_send_sges]); | ||
| 590 | rwqe_size = offsetof(struct ehca_wqe, | ||
| 591 | u.nud.sg_list[parms.act_nr_recv_sges]); | ||
| 592 | break; | ||
| 593 | |||
| 594 | case IB_QPT_UD: | 633 | case IB_QPT_UD: |
| 595 | case IB_QPT_GSI: | 634 | case IB_QPT_GSI: |
| 596 | case IB_QPT_SMI: | 635 | case IB_QPT_SMI: |
| 636 | /* UD circumvention */ | ||
| 597 | if (is_llqp) { | 637 | if (is_llqp) { |
| 598 | swqe_size = ll_qp_msg_size(parms.act_nr_send_sges); | 638 | parms.squeue.act_nr_sges = 1; |
| 599 | rwqe_size = ll_qp_msg_size(parms.act_nr_recv_sges); | 639 | parms.rqueue.act_nr_sges = 1; |
| 600 | parms.act_nr_send_sges = 1; | ||
| 601 | parms.act_nr_recv_sges = 1; | ||
| 602 | } else { | 640 | } else { |
| 603 | /* UD circumvention */ | 641 | parms.squeue.act_nr_sges -= 2; |
| 604 | parms.act_nr_send_sges -= 2; | 642 | parms.rqueue.act_nr_sges -= 2; |
| 605 | parms.act_nr_recv_sges -= 2; | ||
| 606 | swqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[ | ||
| 607 | parms.act_nr_send_sges]); | ||
| 608 | rwqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[ | ||
| 609 | parms.act_nr_recv_sges]); | ||
| 610 | } | 643 | } |
| 611 | 644 | ||
| 612 | if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) { | 645 | if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) { |
| 613 | parms.act_nr_send_wqes = init_attr->cap.max_send_wr; | 646 | parms.squeue.act_nr_wqes = init_attr->cap.max_send_wr; |
| 614 | parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr; | 647 | parms.rqueue.act_nr_wqes = init_attr->cap.max_recv_wr; |
| 615 | parms.act_nr_send_sges = init_attr->cap.max_send_sge; | 648 | parms.squeue.act_nr_sges = init_attr->cap.max_send_sge; |
| 616 | parms.act_nr_recv_sges = init_attr->cap.max_recv_sge; | 649 | parms.rqueue.act_nr_sges = init_attr->cap.max_recv_sge; |
| 617 | ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1; | 650 | ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1; |
| 618 | } | 651 | } |
| 619 | 652 | ||
| @@ -626,10 +659,9 @@ static struct ehca_qp *internal_create_qp( | |||
| 626 | /* initialize r/squeue and register queue pages */ | 659 | /* initialize r/squeue and register queue pages */ |
| 627 | if (HAS_SQ(my_qp)) { | 660 | if (HAS_SQ(my_qp)) { |
| 628 | ret = init_qp_queue( | 661 | ret = init_qp_queue( |
| 629 | shca, my_qp, &my_qp->ipz_squeue, 0, | 662 | shca, my_pd, my_qp, &my_qp->ipz_squeue, 0, |
| 630 | HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS, | 663 | HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS, |
| 631 | parms.nr_sq_pages, swqe_size, | 664 | &parms.squeue, swqe_size); |
| 632 | parms.act_nr_send_sges); | ||
| 633 | if (ret) { | 665 | if (ret) { |
| 634 | ehca_err(pd->device, "Couldn't initialize squeue " | 666 | ehca_err(pd->device, "Couldn't initialize squeue " |
| 635 | "and pages ret=%x", ret); | 667 | "and pages ret=%x", ret); |
| @@ -639,9 +671,8 @@ static struct ehca_qp *internal_create_qp( | |||
| 639 | 671 | ||
| 640 | if (HAS_RQ(my_qp)) { | 672 | if (HAS_RQ(my_qp)) { |
| 641 | ret = init_qp_queue( | 673 | ret = init_qp_queue( |
| 642 | shca, my_qp, &my_qp->ipz_rqueue, 1, | 674 | shca, my_pd, my_qp, &my_qp->ipz_rqueue, 1, |
| 643 | H_SUCCESS, parms.nr_rq_pages, rwqe_size, | 675 | H_SUCCESS, &parms.rqueue, rwqe_size); |
| 644 | parms.act_nr_recv_sges); | ||
| 645 | if (ret) { | 676 | if (ret) { |
| 646 | ehca_err(pd->device, "Couldn't initialize rqueue " | 677 | ehca_err(pd->device, "Couldn't initialize rqueue " |
| 647 | "and pages ret=%x", ret); | 678 | "and pages ret=%x", ret); |
| @@ -671,10 +702,10 @@ static struct ehca_qp *internal_create_qp( | |||
| 671 | } | 702 | } |
| 672 | 703 | ||
| 673 | init_attr->cap.max_inline_data = 0; /* not supported yet */ | 704 | init_attr->cap.max_inline_data = 0; /* not supported yet */ |
| 674 | init_attr->cap.max_recv_sge = parms.act_nr_recv_sges; | 705 | init_attr->cap.max_recv_sge = parms.rqueue.act_nr_sges; |
| 675 | init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes; | 706 | init_attr->cap.max_recv_wr = parms.rqueue.act_nr_wqes; |
| 676 | init_attr->cap.max_send_sge = parms.act_nr_send_sges; | 707 | init_attr->cap.max_send_sge = parms.squeue.act_nr_sges; |
| 677 | init_attr->cap.max_send_wr = parms.act_nr_send_wqes; | 708 | init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes; |
| 678 | my_qp->init_attr = *init_attr; | 709 | my_qp->init_attr = *init_attr; |
| 679 | 710 | ||
| 680 | /* NOTE: define_apq0() not supported yet */ | 711 | /* NOTE: define_apq0() not supported yet */ |
| @@ -708,6 +739,8 @@ static struct ehca_qp *internal_create_qp( | |||
| 708 | resp.ext_type = my_qp->ext_type; | 739 | resp.ext_type = my_qp->ext_type; |
| 709 | resp.qkey = my_qp->qkey; | 740 | resp.qkey = my_qp->qkey; |
| 710 | resp.real_qp_num = my_qp->real_qp_num; | 741 | resp.real_qp_num = my_qp->real_qp_num; |
| 742 | resp.ipz_rqueue.offset = my_qp->ipz_rqueue.offset; | ||
| 743 | resp.ipz_squeue.offset = my_qp->ipz_squeue.offset; | ||
| 711 | if (HAS_SQ(my_qp)) | 744 | if (HAS_SQ(my_qp)) |
| 712 | queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue); | 745 | queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue); |
| 713 | if (HAS_RQ(my_qp)) | 746 | if (HAS_RQ(my_qp)) |
| @@ -724,11 +757,11 @@ static struct ehca_qp *internal_create_qp( | |||
| 724 | 757 | ||
| 725 | create_qp_exit4: | 758 | create_qp_exit4: |
| 726 | if (HAS_RQ(my_qp)) | 759 | if (HAS_RQ(my_qp)) |
| 727 | ipz_queue_dtor(&my_qp->ipz_rqueue); | 760 | ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); |
| 728 | 761 | ||
| 729 | create_qp_exit3: | 762 | create_qp_exit3: |
| 730 | if (HAS_SQ(my_qp)) | 763 | if (HAS_SQ(my_qp)) |
| 731 | ipz_queue_dtor(&my_qp->ipz_squeue); | 764 | ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); |
| 732 | 765 | ||
| 733 | create_qp_exit2: | 766 | create_qp_exit2: |
| 734 | hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); | 767 | hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); |
| @@ -1735,9 +1768,9 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, | |||
| 1735 | } | 1768 | } |
| 1736 | 1769 | ||
| 1737 | if (HAS_RQ(my_qp)) | 1770 | if (HAS_RQ(my_qp)) |
| 1738 | ipz_queue_dtor(&my_qp->ipz_rqueue); | 1771 | ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); |
| 1739 | if (HAS_SQ(my_qp)) | 1772 | if (HAS_SQ(my_qp)) |
| 1740 | ipz_queue_dtor(&my_qp->ipz_squeue); | 1773 | ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); |
| 1741 | kmem_cache_free(qp_cache, my_qp); | 1774 | kmem_cache_free(qp_cache, my_qp); |
| 1742 | return 0; | 1775 | return 0; |
| 1743 | } | 1776 | } |
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 05c415744e3b..4bc687fdf531 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c | |||
| @@ -149,7 +149,7 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue, | |||
| 149 | ehca_gen_err("vm_insert_page() failed rc=%x", ret); | 149 | ehca_gen_err("vm_insert_page() failed rc=%x", ret); |
| 150 | return ret; | 150 | return ret; |
| 151 | } | 151 | } |
| 152 | start += PAGE_SIZE; | 152 | start += PAGE_SIZE; |
| 153 | } | 153 | } |
| 154 | vma->vm_private_data = mm_count; | 154 | vma->vm_private_data = mm_count; |
| 155 | (*mm_count)++; | 155 | (*mm_count)++; |
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 358796ccf008..fdbfebea7d11 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c | |||
| @@ -52,10 +52,13 @@ | |||
| 52 | #define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11) | 52 | #define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11) |
| 53 | #define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12) | 53 | #define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12) |
| 54 | #define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15) | 54 | #define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15) |
| 55 | #define H_ALL_RES_QP_STORAGE EHCA_BMASK_IBM(16, 17) | ||
| 55 | #define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18) | 56 | #define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18) |
| 56 | #define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21) | 57 | #define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21) |
| 57 | #define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23) | 58 | #define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23) |
| 58 | #define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31) | 59 | #define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31) |
| 60 | #define H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE EHCA_BMASK_IBM(32, 35) | ||
| 61 | #define H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE EHCA_BMASK_IBM(36, 39) | ||
| 59 | #define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63) | 62 | #define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63) |
| 60 | 63 | ||
| 61 | #define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15) | 64 | #define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15) |
| @@ -299,6 +302,11 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, | |||
| 299 | | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0) | 302 | | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0) |
| 300 | | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype) | 303 | | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype) |
| 301 | | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype) | 304 | | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype) |
| 305 | | EHCA_BMASK_SET(H_ALL_RES_QP_STORAGE, parms->qp_storage) | ||
| 306 | | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE, | ||
| 307 | parms->squeue.page_size) | ||
| 308 | | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE, | ||
| 309 | parms->rqueue.page_size) | ||
| 302 | | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING, | 310 | | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING, |
| 303 | !!(parms->ll_comp_flags & LLQP_RECV_COMP)) | 311 | !!(parms->ll_comp_flags & LLQP_RECV_COMP)) |
| 304 | | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING, | 312 | | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING, |
| @@ -309,13 +317,13 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, | |||
| 309 | 317 | ||
| 310 | max_r10_reg = | 318 | max_r10_reg = |
| 311 | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR, | 319 | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR, |
| 312 | parms->max_send_wr + 1) | 320 | parms->squeue.max_wr + 1) |
| 313 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR, | 321 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR, |
| 314 | parms->max_recv_wr + 1) | 322 | parms->rqueue.max_wr + 1) |
| 315 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE, | 323 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE, |
| 316 | parms->max_send_sge) | 324 | parms->squeue.max_sge) |
| 317 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE, | 325 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE, |
| 318 | parms->max_recv_sge); | 326 | parms->rqueue.max_sge); |
| 319 | 327 | ||
| 320 | r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token); | 328 | r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token); |
| 321 | 329 | ||
| @@ -335,17 +343,17 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, | |||
| 335 | 343 | ||
| 336 | parms->qp_handle.handle = outs[0]; | 344 | parms->qp_handle.handle = outs[0]; |
| 337 | parms->real_qp_num = (u32)outs[1]; | 345 | parms->real_qp_num = (u32)outs[1]; |
| 338 | parms->act_nr_send_wqes = | 346 | parms->squeue.act_nr_wqes = |
| 339 | (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]); | 347 | (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]); |
| 340 | parms->act_nr_recv_wqes = | 348 | parms->rqueue.act_nr_wqes = |
| 341 | (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]); | 349 | (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]); |
| 342 | parms->act_nr_send_sges = | 350 | parms->squeue.act_nr_sges = |
| 343 | (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]); | 351 | (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]); |
| 344 | parms->act_nr_recv_sges = | 352 | parms->rqueue.act_nr_sges = |
| 345 | (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]); | 353 | (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]); |
| 346 | parms->nr_sq_pages = | 354 | parms->squeue.queue_size = |
| 347 | (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]); | 355 | (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]); |
| 348 | parms->nr_rq_pages = | 356 | parms->rqueue.queue_size = |
| 349 | (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]); | 357 | (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]); |
| 350 | 358 | ||
| 351 | if (ret == H_SUCCESS) | 359 | if (ret == H_SUCCESS) |
| @@ -497,7 +505,7 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle, | |||
| 497 | const u64 count, | 505 | const u64 count, |
| 498 | const struct h_galpa galpa) | 506 | const struct h_galpa galpa) |
| 499 | { | 507 | { |
| 500 | if (count != 1) { | 508 | if (count > 1) { |
| 501 | ehca_gen_err("Page counter=%lx", count); | 509 | ehca_gen_err("Page counter=%lx", count); |
| 502 | return H_PARAMETER; | 510 | return H_PARAMETER; |
| 503 | } | 511 | } |
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c index 9606f13ed092..a090c679c397 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c | |||
| @@ -40,6 +40,11 @@ | |||
| 40 | 40 | ||
| 41 | #include "ehca_tools.h" | 41 | #include "ehca_tools.h" |
| 42 | #include "ipz_pt_fn.h" | 42 | #include "ipz_pt_fn.h" |
| 43 | #include "ehca_classes.h" | ||
| 44 | |||
| 45 | #define PAGES_PER_KPAGE (PAGE_SIZE >> EHCA_PAGESHIFT) | ||
| 46 | |||
| 47 | struct kmem_cache *small_qp_cache; | ||
| 43 | 48 | ||
| 44 | void *ipz_qpageit_get_inc(struct ipz_queue *queue) | 49 | void *ipz_qpageit_get_inc(struct ipz_queue *queue) |
| 45 | { | 50 | { |
| @@ -49,7 +54,7 @@ void *ipz_qpageit_get_inc(struct ipz_queue *queue) | |||
| 49 | queue->current_q_offset -= queue->pagesize; | 54 | queue->current_q_offset -= queue->pagesize; |
| 50 | ret = NULL; | 55 | ret = NULL; |
| 51 | } | 56 | } |
| 52 | if (((u64)ret) % EHCA_PAGESIZE) { | 57 | if (((u64)ret) % queue->pagesize) { |
| 53 | ehca_gen_err("ERROR!! not at PAGE-Boundary"); | 58 | ehca_gen_err("ERROR!! not at PAGE-Boundary"); |
| 54 | return NULL; | 59 | return NULL; |
| 55 | } | 60 | } |
| @@ -83,80 +88,195 @@ int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset) | |||
| 83 | return -EINVAL; | 88 | return -EINVAL; |
| 84 | } | 89 | } |
| 85 | 90 | ||
| 86 | int ipz_queue_ctor(struct ipz_queue *queue, | 91 | #if PAGE_SHIFT < EHCA_PAGESHIFT |
| 87 | const u32 nr_of_pages, | 92 | #error Kernel pages must be at least as large than eHCA pages (4K) ! |
| 88 | const u32 pagesize, const u32 qe_size, const u32 nr_of_sg) | 93 | #endif |
| 94 | |||
| 95 | /* | ||
| 96 | * allocate pages for queue: | ||
| 97 | * outer loop allocates whole kernel pages (page aligned) and | ||
| 98 | * inner loop divides a kernel page into smaller hca queue pages | ||
| 99 | */ | ||
| 100 | static int alloc_queue_pages(struct ipz_queue *queue, const u32 nr_of_pages) | ||
| 89 | { | 101 | { |
| 90 | int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT; | 102 | int k, f = 0; |
| 91 | int f; | 103 | u8 *kpage; |
| 92 | 104 | ||
| 93 | if (pagesize > PAGE_SIZE) { | ||
| 94 | ehca_gen_err("FATAL ERROR: pagesize=%x is greater " | ||
| 95 | "than kernel page size", pagesize); | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | if (!pages_per_kpage) { | ||
| 99 | ehca_gen_err("FATAL ERROR: invalid kernel page size. " | ||
| 100 | "pages_per_kpage=%x", pages_per_kpage); | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | queue->queue_length = nr_of_pages * pagesize; | ||
| 104 | queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); | ||
| 105 | if (!queue->queue_pages) { | ||
| 106 | ehca_gen_err("ERROR!! didn't get the memory"); | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *)); | ||
| 110 | /* | ||
| 111 | * allocate pages for queue: | ||
| 112 | * outer loop allocates whole kernel pages (page aligned) and | ||
| 113 | * inner loop divides a kernel page into smaller hca queue pages | ||
| 114 | */ | ||
| 115 | f = 0; | ||
| 116 | while (f < nr_of_pages) { | 105 | while (f < nr_of_pages) { |
| 117 | u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL); | 106 | kpage = (u8 *)get_zeroed_page(GFP_KERNEL); |
| 118 | int k; | ||
| 119 | if (!kpage) | 107 | if (!kpage) |
| 120 | goto ipz_queue_ctor_exit0; /*NOMEM*/ | 108 | goto out; |
| 121 | for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) { | 109 | |
| 122 | (queue->queue_pages)[f] = (struct ipz_page *)kpage; | 110 | for (k = 0; k < PAGES_PER_KPAGE && f < nr_of_pages; k++) { |
| 111 | queue->queue_pages[f] = (struct ipz_page *)kpage; | ||
| 123 | kpage += EHCA_PAGESIZE; | 112 | kpage += EHCA_PAGESIZE; |
| 124 | f++; | 113 | f++; |
| 125 | } | 114 | } |
| 126 | } | 115 | } |
| 116 | return 1; | ||
| 127 | 117 | ||
| 128 | queue->current_q_offset = 0; | 118 | out: |
| 119 | for (f = 0; f < nr_of_pages && queue->queue_pages[f]; | ||
| 120 | f += PAGES_PER_KPAGE) | ||
| 121 | free_page((unsigned long)(queue->queue_pages)[f]); | ||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd) | ||
| 126 | { | ||
| 127 | int order = ilog2(queue->pagesize) - 9; | ||
| 128 | struct ipz_small_queue_page *page; | ||
| 129 | unsigned long bit; | ||
| 130 | |||
| 131 | mutex_lock(&pd->lock); | ||
| 132 | |||
| 133 | if (!list_empty(&pd->free[order])) | ||
| 134 | page = list_entry(pd->free[order].next, | ||
| 135 | struct ipz_small_queue_page, list); | ||
| 136 | else { | ||
| 137 | page = kmem_cache_zalloc(small_qp_cache, GFP_KERNEL); | ||
| 138 | if (!page) | ||
| 139 | goto out; | ||
| 140 | |||
| 141 | page->page = get_zeroed_page(GFP_KERNEL); | ||
| 142 | if (!page->page) { | ||
| 143 | kmem_cache_free(small_qp_cache, page); | ||
| 144 | goto out; | ||
| 145 | } | ||
| 146 | |||
| 147 | list_add(&page->list, &pd->free[order]); | ||
| 148 | } | ||
| 149 | |||
| 150 | bit = find_first_zero_bit(page->bitmap, IPZ_SPAGE_PER_KPAGE >> order); | ||
| 151 | __set_bit(bit, page->bitmap); | ||
| 152 | page->fill++; | ||
| 153 | |||
| 154 | if (page->fill == IPZ_SPAGE_PER_KPAGE >> order) | ||
| 155 | list_move(&page->list, &pd->full[order]); | ||
| 156 | |||
| 157 | mutex_unlock(&pd->lock); | ||
| 158 | |||
| 159 | queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9))); | ||
| 160 | queue->small_page = page; | ||
| 161 | return 1; | ||
| 162 | |||
| 163 | out: | ||
| 164 | ehca_err(pd->ib_pd.device, "failed to allocate small queue page"); | ||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 168 | static void free_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd) | ||
| 169 | { | ||
| 170 | int order = ilog2(queue->pagesize) - 9; | ||
| 171 | struct ipz_small_queue_page *page = queue->small_page; | ||
| 172 | unsigned long bit; | ||
| 173 | int free_page = 0; | ||
| 174 | |||
| 175 | bit = ((unsigned long)queue->queue_pages[0] & PAGE_MASK) | ||
| 176 | >> (order + 9); | ||
| 177 | |||
| 178 | mutex_lock(&pd->lock); | ||
| 179 | |||
| 180 | __clear_bit(bit, page->bitmap); | ||
| 181 | page->fill--; | ||
| 182 | |||
| 183 | if (page->fill == 0) { | ||
| 184 | list_del(&page->list); | ||
| 185 | free_page = 1; | ||
| 186 | } | ||
| 187 | |||
| 188 | if (page->fill == (IPZ_SPAGE_PER_KPAGE >> order) - 1) | ||
| 189 | /* the page was full until we freed the chunk */ | ||
| 190 | list_move_tail(&page->list, &pd->free[order]); | ||
| 191 | |||
| 192 | mutex_unlock(&pd->lock); | ||
| 193 | |||
| 194 | if (free_page) { | ||
| 195 | free_page(page->page); | ||
| 196 | kmem_cache_free(small_qp_cache, page); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue, | ||
| 201 | const u32 nr_of_pages, const u32 pagesize, | ||
| 202 | const u32 qe_size, const u32 nr_of_sg, | ||
| 203 | int is_small) | ||
| 204 | { | ||
| 205 | if (pagesize > PAGE_SIZE) { | ||
| 206 | ehca_gen_err("FATAL ERROR: pagesize=%x " | ||
| 207 | "is greater than kernel page size", pagesize); | ||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* init queue fields */ | ||
| 212 | queue->queue_length = nr_of_pages * pagesize; | ||
| 213 | queue->pagesize = pagesize; | ||
| 129 | queue->qe_size = qe_size; | 214 | queue->qe_size = qe_size; |
| 130 | queue->act_nr_of_sg = nr_of_sg; | 215 | queue->act_nr_of_sg = nr_of_sg; |
| 131 | queue->pagesize = pagesize; | 216 | queue->current_q_offset = 0; |
| 132 | queue->toggle_state = 1; | 217 | queue->toggle_state = 1; |
| 133 | return 1; | 218 | queue->small_page = NULL; |
| 134 | 219 | ||
| 135 | ipz_queue_ctor_exit0: | 220 | /* allocate queue page pointers */ |
| 136 | ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x", | 221 | queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); |
| 137 | queue, f, nr_of_pages); | 222 | if (!queue->queue_pages) { |
| 138 | for (f = 0; f < nr_of_pages; f += pages_per_kpage) { | 223 | ehca_gen_err("Couldn't allocate queue page list"); |
| 139 | if (!(queue->queue_pages)[f]) | 224 | return 0; |
| 140 | break; | ||
| 141 | free_page((unsigned long)(queue->queue_pages)[f]); | ||
| 142 | } | 225 | } |
| 226 | memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *)); | ||
| 227 | |||
| 228 | /* allocate actual queue pages */ | ||
| 229 | if (is_small) { | ||
| 230 | if (!alloc_small_queue_page(queue, pd)) | ||
| 231 | goto ipz_queue_ctor_exit0; | ||
| 232 | } else | ||
| 233 | if (!alloc_queue_pages(queue, nr_of_pages)) | ||
| 234 | goto ipz_queue_ctor_exit0; | ||
| 235 | |||
| 236 | return 1; | ||
| 237 | |||
| 238 | ipz_queue_ctor_exit0: | ||
| 239 | ehca_gen_err("Couldn't alloc pages queue=%p " | ||
| 240 | "nr_of_pages=%x", queue, nr_of_pages); | ||
| 241 | vfree(queue->queue_pages); | ||
| 242 | |||
| 143 | return 0; | 243 | return 0; |
| 144 | } | 244 | } |
| 145 | 245 | ||
| 146 | int ipz_queue_dtor(struct ipz_queue *queue) | 246 | int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue) |
| 147 | { | 247 | { |
| 148 | int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT; | 248 | int i, nr_pages; |
| 149 | int g; | ||
| 150 | int nr_pages; | ||
| 151 | 249 | ||
| 152 | if (!queue || !queue->queue_pages) { | 250 | if (!queue || !queue->queue_pages) { |
| 153 | ehca_gen_dbg("queue or queue_pages is NULL"); | 251 | ehca_gen_dbg("queue or queue_pages is NULL"); |
| 154 | return 0; | 252 | return 0; |
| 155 | } | 253 | } |
| 156 | nr_pages = queue->queue_length / queue->pagesize; | 254 | |
| 157 | for (g = 0; g < nr_pages; g += pages_per_kpage) | 255 | if (queue->small_page) |
| 158 | free_page((unsigned long)(queue->queue_pages)[g]); | 256 | free_small_queue_page(queue, pd); |
| 257 | else { | ||
| 258 | nr_pages = queue->queue_length / queue->pagesize; | ||
| 259 | for (i = 0; i < nr_pages; i += PAGES_PER_KPAGE) | ||
| 260 | free_page((unsigned long)queue->queue_pages[i]); | ||
| 261 | } | ||
| 262 | |||
| 159 | vfree(queue->queue_pages); | 263 | vfree(queue->queue_pages); |
| 160 | 264 | ||
| 161 | return 1; | 265 | return 1; |
| 162 | } | 266 | } |
| 267 | |||
| 268 | int ehca_init_small_qp_cache(void) | ||
| 269 | { | ||
| 270 | small_qp_cache = kmem_cache_create("ehca_cache_small_qp", | ||
| 271 | sizeof(struct ipz_small_queue_page), | ||
| 272 | 0, SLAB_HWCACHE_ALIGN, NULL); | ||
| 273 | if (!small_qp_cache) | ||
| 274 | return -ENOMEM; | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | void ehca_cleanup_small_qp_cache(void) | ||
| 280 | { | ||
| 281 | kmem_cache_destroy(small_qp_cache); | ||
| 282 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h index 39a4f64aff41..c6937a044e8a 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h | |||
| @@ -51,11 +51,25 @@ | |||
| 51 | #include "ehca_tools.h" | 51 | #include "ehca_tools.h" |
| 52 | #include "ehca_qes.h" | 52 | #include "ehca_qes.h" |
| 53 | 53 | ||
| 54 | struct ehca_pd; | ||
| 55 | struct ipz_small_queue_page; | ||
| 56 | |||
| 54 | /* struct generic ehca page */ | 57 | /* struct generic ehca page */ |
| 55 | struct ipz_page { | 58 | struct ipz_page { |
| 56 | u8 entries[EHCA_PAGESIZE]; | 59 | u8 entries[EHCA_PAGESIZE]; |
| 57 | }; | 60 | }; |
| 58 | 61 | ||
| 62 | #define IPZ_SPAGE_PER_KPAGE (PAGE_SIZE / 512) | ||
| 63 | |||
| 64 | struct ipz_small_queue_page { | ||
| 65 | unsigned long page; | ||
| 66 | unsigned long bitmap[IPZ_SPAGE_PER_KPAGE / BITS_PER_LONG]; | ||
| 67 | int fill; | ||
| 68 | void *mapped_addr; | ||
| 69 | u32 mmap_count; | ||
| 70 | struct list_head list; | ||
| 71 | }; | ||
| 72 | |||
| 59 | /* struct generic queue in linux kernel virtual memory (kv) */ | 73 | /* struct generic queue in linux kernel virtual memory (kv) */ |
| 60 | struct ipz_queue { | 74 | struct ipz_queue { |
| 61 | u64 current_q_offset; /* current queue entry */ | 75 | u64 current_q_offset; /* current queue entry */ |
| @@ -66,7 +80,8 @@ struct ipz_queue { | |||
| 66 | u32 queue_length; /* queue length allocated in bytes */ | 80 | u32 queue_length; /* queue length allocated in bytes */ |
| 67 | u32 pagesize; | 81 | u32 pagesize; |
| 68 | u32 toggle_state; /* toggle flag - per page */ | 82 | u32 toggle_state; /* toggle flag - per page */ |
| 69 | u32 dummy3; /* 64 bit alignment */ | 83 | u32 offset; /* save offset within page for small_qp */ |
| 84 | struct ipz_small_queue_page *small_page; | ||
| 70 | }; | 85 | }; |
| 71 | 86 | ||
| 72 | /* | 87 | /* |
| @@ -188,9 +203,10 @@ struct ipz_qpt { | |||
| 188 | * see ipz_qpt_ctor() | 203 | * see ipz_qpt_ctor() |
| 189 | * returns true if ok, false if out of memory | 204 | * returns true if ok, false if out of memory |
| 190 | */ | 205 | */ |
| 191 | int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages, | 206 | int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue, |
| 192 | const u32 pagesize, const u32 qe_size, | 207 | const u32 nr_of_pages, const u32 pagesize, |
| 193 | const u32 nr_of_sg); | 208 | const u32 qe_size, const u32 nr_of_sg, |
| 209 | int is_small); | ||
| 194 | 210 | ||
| 195 | /* | 211 | /* |
| 196 | * destructor for a ipz_queue_t | 212 | * destructor for a ipz_queue_t |
| @@ -198,7 +214,7 @@ int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages, | |||
| 198 | * see ipz_queue_ctor() | 214 | * see ipz_queue_ctor() |
| 199 | * returns true if ok, false if queue was NULL-ptr of free failed | 215 | * returns true if ok, false if queue was NULL-ptr of free failed |
| 200 | */ | 216 | */ |
| 201 | int ipz_queue_dtor(struct ipz_queue *queue); | 217 | int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue); |
| 202 | 218 | ||
| 203 | /* | 219 | /* |
| 204 | * constructor for a ipz_qpt_t, | 220 | * constructor for a ipz_qpt_t, |
