Skip to content

Commit

Permalink
IB/ehca: Support small QP queues
Browse files Browse the repository at this point in the history
eHCA2 supports QP queues that can be as small as 512 bytes. This
greatly reduces memory overhead for consumers that use lots of QPs
with small queues (e.g. RDMA-only QPs). Apart from dealing with
firmware, this code needs to manage bite-sized chunks of kernel pages,
making sure that no kernel page is shared between different protection
domains.

Signed-off-by: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
  • Loading branch information
Stefan Roscher authored and Roland Dreier committed Jul 21, 2007
1 parent 0c10f7b commit e2f81da
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 159 deletions.
41 changes: 26 additions & 15 deletions drivers/infiniband/hw/ehca/ehca_classes.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#ifndef __EHCA_CLASSES_H__
#define __EHCA_CLASSES_H__


struct ehca_module;
struct ehca_qp;
struct ehca_cq;
Expand Down Expand Up @@ -129,6 +128,10 @@ struct ehca_pd {
struct ib_pd ib_pd;
struct ipz_pd fw_pd;
u32 ownpid;
/* small queue mgmt */
struct mutex lock;
struct list_head free[2];
struct list_head full[2];
};

enum ehca_ext_qp_type {
Expand Down Expand Up @@ -307,6 +310,8 @@ int ehca_init_av_cache(void);
void ehca_cleanup_av_cache(void);
int ehca_init_mrmw_cache(void);
void ehca_cleanup_mrmw_cache(void);
int ehca_init_small_qp_cache(void);
void ehca_cleanup_small_qp_cache(void);

extern rwlock_t ehca_qp_idr_lock;
extern rwlock_t ehca_cq_idr_lock;
Expand All @@ -324,7 +329,7 @@ struct ipzu_queue_resp {
u32 queue_length; /* queue length allocated in bytes */
u32 pagesize;
u32 toggle_state;
u32 dummy; /* padding for 8 byte alignment */
u32 offset; /* save offset within a page for small_qp */
};

struct ehca_create_cq_resp {
Expand Down Expand Up @@ -366,15 +371,29 @@ enum ehca_ll_comp_flags {
LLQP_COMP_MASK = 0x60,
};

struct ehca_alloc_queue_parms {
/* input parameters */
int max_wr;
int max_sge;
int page_size;
int is_small;

/* output parameters */
u16 act_nr_wqes;
u8 act_nr_sges;
u32 queue_size; /* bytes for small queues, pages otherwise */
};

struct ehca_alloc_qp_parms {
/* input parameters */
struct ehca_alloc_queue_parms squeue;
struct ehca_alloc_queue_parms rqueue;

/* input parameters */
enum ehca_service_type servicetype;
int qp_storage;
int sigtype;
enum ehca_ext_qp_type ext_type;
enum ehca_ll_comp_flags ll_comp_flags;

int max_send_wr, max_recv_wr;
int max_send_sge, max_recv_sge;
int ud_av_l_key_ctl;

u32 token;
Expand All @@ -384,18 +403,10 @@ struct ehca_alloc_qp_parms {

u32 srq_qpn, srq_token, srq_limit;

/* output parameters */
/* output parameters */
u32 real_qp_num;
struct ipz_qp_handle qp_handle;
struct h_galpas galpas;

u16 act_nr_send_wqes;
u16 act_nr_recv_wqes;
u8 act_nr_recv_sges;
u8 act_nr_send_sges;

u32 nr_rq_pages;
u32 nr_sq_pages;
};

int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
Expand Down
8 changes: 4 additions & 4 deletions drivers/infiniband/hw/ehca/ehca_cq.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
goto create_cq_exit2;
}

ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages,
EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages,
EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0);
if (!ipz_rc) {
ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
ipz_rc, device);
Expand Down Expand Up @@ -285,7 +285,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
return cq;

create_cq_exit4:
ipz_queue_dtor(&my_cq->ipz_queue);
ipz_queue_dtor(NULL, &my_cq->ipz_queue);

create_cq_exit3:
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
Expand Down Expand Up @@ -359,7 +359,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
"ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
return ehca2ib_return_code(h_ret);
}
ipz_queue_dtor(&my_cq->ipz_queue);
ipz_queue_dtor(NULL, &my_cq->ipz_queue);
kmem_cache_free(cq_cache, my_cq);

return 0;
Expand Down
8 changes: 4 additions & 4 deletions drivers/infiniband/hw/ehca/ehca_eq.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ int ehca_create_eq(struct ehca_shca *shca,
return -EINVAL;
}

ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
ret = ipz_queue_ctor(NULL, &eq->ipz_queue, nr_pages,
EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0, 0);
if (!ret) {
ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
goto create_eq_exit1;
Expand Down Expand Up @@ -145,7 +145,7 @@ int ehca_create_eq(struct ehca_shca *shca,
return 0;

create_eq_exit2:
ipz_queue_dtor(&eq->ipz_queue);
ipz_queue_dtor(NULL, &eq->ipz_queue);

create_eq_exit1:
hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
Expand Down Expand Up @@ -181,7 +181,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
ehca_err(&shca->ib_device, "Can't free EQ resources.");
return -EINVAL;
}
ipz_queue_dtor(&eq->ipz_queue);
ipz_queue_dtor(NULL, &eq->ipz_queue);

return 0;
}
14 changes: 12 additions & 2 deletions drivers/infiniband/hw/ehca/ehca_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,19 +181,28 @@ static int ehca_create_slab_caches(void)
goto create_slab_caches5;
}

ret = ehca_init_small_qp_cache();
if (ret) {
ehca_gen_err("Cannot create small queue SLAB cache.");
goto create_slab_caches6;
}

#ifdef CONFIG_PPC_64K_PAGES
ctblk_cache = kmem_cache_create("ehca_cache_ctblk",
EHCA_PAGESIZE, H_CB_ALIGNMENT,
SLAB_HWCACHE_ALIGN,
NULL);
if (!ctblk_cache) {
ehca_gen_err("Cannot create ctblk SLAB cache.");
ehca_cleanup_mrmw_cache();
goto create_slab_caches5;
ehca_cleanup_small_qp_cache();
goto create_slab_caches6;
}
#endif
return 0;

create_slab_caches6:
ehca_cleanup_mrmw_cache();

create_slab_caches5:
ehca_cleanup_av_cache();

Expand All @@ -211,6 +220,7 @@ static int ehca_create_slab_caches(void)

static void ehca_destroy_slab_caches(void)
{
ehca_cleanup_small_qp_cache();
ehca_cleanup_mrmw_cache();
ehca_cleanup_av_cache();
ehca_cleanup_qp_cache();
Expand Down
25 changes: 23 additions & 2 deletions drivers/infiniband/hw/ehca/ehca_pd.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
struct ib_ucontext *context, struct ib_udata *udata)
{
struct ehca_pd *pd;
int i;

pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL);
if (!pd) {
Expand All @@ -58,6 +59,11 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
}

pd->ownpid = current->tgid;
for (i = 0; i < 2; i++) {
INIT_LIST_HEAD(&pd->free[i]);
INIT_LIST_HEAD(&pd->full[i]);
}
mutex_init(&pd->lock);

/*
* Kernel PD: when device = -1, 0
Expand All @@ -81,6 +87,9 @@ int ehca_dealloc_pd(struct ib_pd *pd)
{
u32 cur_pid = current->tgid;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
int i, leftovers = 0;
extern struct kmem_cache *small_qp_cache;
struct ipz_small_queue_page *page, *tmp;

if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
my_pd->ownpid != cur_pid) {
Expand All @@ -89,8 +98,20 @@ int ehca_dealloc_pd(struct ib_pd *pd)
return -EINVAL;
}

kmem_cache_free(pd_cache,
container_of(pd, struct ehca_pd, ib_pd));
for (i = 0; i < 2; i++) {
list_splice(&my_pd->full[i], &my_pd->free[i]);
list_for_each_entry_safe(page, tmp, &my_pd->free[i], list) {
leftovers = 1;
free_page(page->page);
kmem_cache_free(small_qp_cache, page);
}
}

if (leftovers)
ehca_warn(pd->device,
"Some small queue pages were not freed");

kmem_cache_free(pd_cache, my_pd);

return 0;
}
Expand Down
Loading

0 comments on commit e2f81da

Please sign in to comment.