* [PATCH 11/16] ehca: completion queue
From: Heiko J Schick @ 2006-04-27 10:49 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_cq.c | 445 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 445 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_cq.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_cq.c 2006-04-24 15:12:03.000000000 +0200
@@ -0,0 +1,445 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Completion queue handling
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ *
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_cq.c,v 1.24 2006/04/24 13:12:03 schickhj Exp $
+ */
+
+#define DEB_PREFIX "e_cq"
+
+#include <asm/current.h>
+
+#include "ehca_kernel.h"
+#include "ehca_iverbs.h"
+#include "ehca_classes.h"
+#include "ehca_irq.h"
+#include "hcp_if.h"
+
+int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp)
+{
+ unsigned int qp_num = qp->real_qp_num;
+ unsigned int key = qp_num & (QP_HASHTAB_LEN-1);
+ unsigned long spl_flags = 0;
+
+ spin_lock_irqsave(&cq->spinlock, spl_flags);
+ hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]);
+ spin_unlock_irqrestore(&cq->spinlock, spl_flags);
+
+ EDEB(7, "cq_num=%x real_qp_num=%x", cq->cq_number, qp_num);
+
+ return 0;
+}
+
+int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
+{
+ int ret = -EINVAL;
+ unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
+ struct hlist_node *iter = NULL;
+ struct ehca_qp *qp = NULL;
+ unsigned long spl_flags = 0;
+
+ spin_lock_irqsave(&cq->spinlock, spl_flags);
+ hlist_for_each(iter, &cq->qp_hashtab[key]) {
+ qp = hlist_entry(iter, struct ehca_qp, list_entries);
+ if (qp->real_qp_num == real_qp_num) {
+ hlist_del(iter);
+ EDEB(7, "removed qp from cq .cq_num=%x real_qp_num=%x",
+ cq->cq_number, real_qp_num);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cq->spinlock, spl_flags);
+ if (ret!=0) {
+ EDEB_ERR(4, "qp not found cq_num=%x real_qp_num=%x",
+ cq->cq_number, real_qp_num);
+ }
+
+ return ret;
+}
+
+struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
+{
+ struct ehca_qp *ret = NULL;
+ unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
+ struct hlist_node *iter = NULL;
+ struct ehca_qp *qp = NULL;
+ hlist_for_each(iter, &cq->qp_hashtab[key]) {
+ qp = hlist_entry(iter, struct ehca_qp, list_entries);
+ if (qp->real_qp_num == real_qp_num) {
+ ret = qp;
+ break;
+ }
+ }
+ return ret;
+}
+
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ extern struct ehca_module ehca_module;
+ struct ib_cq *cq = NULL;
+ struct ehca_cq *my_cq = NULL;
+ u32 number_of_entries = cqe;
+ struct ehca_shca *shca = NULL;
+ struct ipz_adapter_handle adapter_handle;
+ struct ipz_eq_handle eq_handle;
+ struct ipz_cq_handle *cq_handle_ref = NULL;
+ u32 act_nr_of_entries = 0;
+ u32 act_pages = 0;
+ u32 counter = 0;
+ void *vpage = NULL;
+ u64 rpage = 0;
+ struct h_galpa gal;
+ u64 cqx_fec = 0;
+ u64 hipz_rc = H_SUCCESS;
+ int ipz_rc = 0;
+ int ret = 0;
+ const u32 additional_cqe=20;
+ int i= 0;
+ unsigned long flags;
+
+ EHCA_CHECK_DEVICE_P(device);
+ EDEB_EN(7, "device=%p cqe=%x context=%p", device, cqe, context);
+
+ /* CQs maximum depth is 4GB-64, but we need additional 20 as buffer
+ * for receiving errors CQEs.
+ */
+ if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
+ return ERR_PTR(-EINVAL);
+ number_of_entries += additional_cqe;
+
+ my_cq = kmem_cache_alloc(ehca_module.cache_cq, SLAB_KERNEL);
+ if (my_cq == NULL) {
+ cq = ERR_PTR(-ENOMEM);
+ EDEB_ERR(4, "Out of memory for ehca_cq struct device=%p",
+ device);
+ goto create_cq_exit0;
+ }
+
+ memset(my_cq, 0, sizeof(struct ehca_cq));
+ spin_lock_init(&my_cq->spinlock);
+ spin_lock_init(&my_cq->cb_lock);
+ spin_lock_init(&my_cq->task_lock);
+ my_cq->ownpid = current->tgid;
+
+ cq = &my_cq->ib_cq;
+
+ shca = container_of(device, struct ehca_shca, ib_device);
+ adapter_handle = shca->ipz_hca_handle;
+ eq_handle = shca->eq.ipz_eq_handle;
+ cq_handle_ref = &my_cq->ipz_cq_handle;
+
+ do {
+ if (!idr_pre_get(&ehca_cq_idr, GFP_KERNEL)) {
+ cq = ERR_PTR(-ENOMEM);
+ EDEB_ERR(4,
+ "Can't reserve idr resources. "
+ "device=%p", device);
+ goto create_cq_exit1;
+ }
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ } while (ret == -EAGAIN);
+
+ if (ret) {
+ cq = ERR_PTR(-ENOMEM);
+ EDEB_ERR(4,
+ "Can't allocate new idr entry. "
+ "device=%p", device);
+ goto create_cq_exit1;
+ }
+
+ hipz_rc = hipz_h_alloc_resource_cq(adapter_handle,
+ &my_cq->pf,
+ eq_handle,
+ my_cq->token,
+ number_of_entries,
+ cq_handle_ref,
+ &act_nr_of_entries,
+ &act_pages,
+ &my_cq->galpas);
+ if (hipz_rc != H_SUCCESS) {
+ EDEB_ERR(4,
+ "hipz_h_alloc_resource_cq() failed "
+ "hipz_rc=%lx device=%p", hipz_rc, device);
+ cq = ERR_PTR(ehca2ib_return_code(hipz_rc));
+ goto create_cq_exit2;
+ }
+
+ ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, act_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
+ if (!ipz_rc) {
+ EDEB_ERR(4,
+ "ipz_queue_ctor() failed "
+ "ipz_rc=%x device=%p", ipz_rc, device);
+ cq = ERR_PTR(-EINVAL);
+ goto create_cq_exit3;
+ }
+
+ for (counter = 0; counter < act_pages; counter++) {
+ vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
+ if (!vpage) {
+ EDEB_ERR(4, "ipz_qpageit_get_inc() "
+ "returns NULL device=%p", device);
+ cq = ERR_PTR(-EAGAIN);
+ goto create_cq_exit4;
+ }
+ rpage = virt_to_abs(vpage);
+
+ hipz_rc = hipz_h_register_rpage_cq(adapter_handle,
+ my_cq->ipz_cq_handle,
+ &my_cq->pf,
+ 0,
+ 0,
+ rpage,
+ 1,
+ my_cq->galpas.
+ kernel);
+
+ if (hipz_rc < H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_register_rpage_cq() failed "
+ "ehca_cq=%p cq_num=%x hipz_rc=%lx "
+ "counter=%i act_pages=%i",
+ my_cq, my_cq->cq_number,
+ hipz_rc, counter, act_pages);
+ cq = ERR_PTR(-EINVAL);
+ goto create_cq_exit4;
+ }
+
+ if (counter == (act_pages - 1)) {
+ vpage = ipz_qpageit_get_inc(
+ &my_cq->ipz_queue);
+ if ((hipz_rc != H_SUCCESS) || (vpage != 0)) {
+ EDEB_ERR(4, "Registration of pages not "
+ "complete ehca_cq=%p cq_num=%x "
+ "hipz_rc=%lx",
+ my_cq, my_cq->cq_number, hipz_rc);
+ cq = ERR_PTR(-EAGAIN);
+ goto create_cq_exit4;
+ }
+ } else {
+ if (hipz_rc != H_PAGE_REGISTERED) {
+ EDEB_ERR(4, "Registration of page failed "
+ "ehca_cq=%p cq_num=%x hipz_rc=%lx"
+ "counter=%i act_pages=%i",
+ my_cq, my_cq->cq_number,
+ hipz_rc, counter, act_pages);
+ cq = ERR_PTR(-ENOMEM);
+ goto create_cq_exit4;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&my_cq->ipz_queue);
+
+ gal = my_cq->galpas.kernel;
+ cqx_fec = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_fec));
+ EDEB(8, "ehca_cq=%p cq_num=%x CQX_FEC=%lx",
+ my_cq, my_cq->cq_number, cqx_fec);
+
+ my_cq->ib_cq.cqe = my_cq->nr_of_entries =
+ act_nr_of_entries-additional_cqe;
+ my_cq->cq_number = (my_cq->ipz_cq_handle.handle) & 0xffff;
+
+ for (i = 0; i < QP_HASHTAB_LEN; i++)
+ INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]);
+
+ if (context) {
+ struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
+ struct ehca_create_cq_resp resp;
+ struct vm_area_struct *vma = NULL;
+ memset(&resp, 0, sizeof(resp));
+ resp.cq_number = my_cq->cq_number;
+ resp.token = my_cq->token;
+ resp.ipz_queue.qe_size = ipz_queue->qe_size;
+ resp.ipz_queue.act_nr_of_sg = ipz_queue->act_nr_of_sg;
+ resp.ipz_queue.queue_length = ipz_queue->queue_length;
+ resp.ipz_queue.pagesize = ipz_queue->pagesize;
+ resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
+ ehca_mmap_nopage(((u64) (my_cq->token) << 32) | 0x12000000,
+ ipz_queue->queue_length,
+ ((void**)&resp.ipz_queue.queue),
+ &vma);
+ my_cq->uspace_queue = resp.ipz_queue.queue;
+ resp.galpas = my_cq->galpas;
+ ehca_mmap_register(my_cq->galpas.user.fw_handle,
+ ((void**)&resp.galpas.kernel.fw_handle),
+ &vma);
+ my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
+ if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
+ EDEB_ERR(4, "Copy to udata failed.");
+ goto create_cq_exit4;
+ }
+ }
+
+ EDEB_EX(7,"retcode=%p ehca_cq=%p cq_num=%x cq_size=%x",
+ cq, my_cq, my_cq->cq_number, act_nr_of_entries);
+ return cq;
+
+create_cq_exit4:
+ ipz_queue_dtor(&my_cq->ipz_queue);
+
+create_cq_exit3:
+ hipz_rc = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
+ EDEB(3, "hipz_h_destroy_cq() failed ehca_cq=%p cq_num=%x hipz_rc=%lx",
+ my_cq, my_cq->cq_number, hipz_rc);
+
+create_cq_exit2:
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ idr_remove(&ehca_cq_idr, my_cq->token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+create_cq_exit1:
+ kmem_cache_free(ehca_module.cache_cq, my_cq);
+
+create_cq_exit0:
+ EDEB_EX(7, "An error has occured retcode=%p ", cq);
+ return cq;
+}
+
+int ehca_destroy_cq(struct ib_cq *cq)
+{
+ extern struct ehca_module ehca_module;
+ u64 hipz_rc = H_SUCCESS;
+ int retcode = 0;
+ struct ehca_cq *my_cq = NULL;
+ int cq_num = 0;
+ struct ib_device *device = NULL;
+ struct ehca_shca *shca = NULL;
+ struct ipz_adapter_handle adapter_handle;
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ EHCA_CHECK_CQ(cq);
+ my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ cq_num = my_cq->cq_number;
+ device = cq->device;
+ EHCA_CHECK_DEVICE(device);
+ shca = container_of(device, struct ehca_shca, ib_device);
+ adapter_handle = shca->ipz_hca_handle;
+ EDEB_EN(7, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ while (my_cq->nr_callbacks != 0)
+ yield();
+
+ idr_remove(&ehca_cq_idr, my_cq->token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (my_cq->uspace_queue!=0 && my_cq->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_cq->ownpid);
+ return -EINVAL;
+ }
+
+ /* un-mmap if vma alloc */
+ if (my_cq->uspace_queue!=0) {
+ retcode = ehca_munmap(my_cq->uspace_queue,
+ my_cq->ipz_queue.queue_length);
+ retcode = ehca_munmap(my_cq->uspace_fwh, 4096);
+ }
+
+ hipz_rc = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
+ if (hipz_rc == H_R_STATE) {
+ /* cq in err: read err data and destroy it forcibly */
+ EDEB(4, "ehca_cq=%p cq_num=%x ressource=%lx in err state. "
+ "Try to delete it forcibly.",
+ my_cq, my_cq->cq_number, my_cq->ipz_cq_handle.handle);
+ ehca_error_data(shca, my_cq, my_cq->ipz_cq_handle.handle);
+ hipz_rc = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
+ if (hipz_rc == H_SUCCESS) {
+ EDEB(4, "ehca_cq=%p cq_num=%x deleted successfully.",
+ my_cq, my_cq->cq_number);
+ }
+ }
+ if (hipz_rc != H_SUCCESS) {
+ EDEB_ERR(4,"hipz_h_destroy_cq() failed "
+ "hipz_rc=%lx ehca_cq=%p cq_num=%x",
+ hipz_rc, my_cq, my_cq->cq_number);
+ retcode = ehca2ib_return_code(hipz_rc);
+ goto destroy_cq_exit0;
+ }
+ ipz_queue_dtor(&my_cq->ipz_queue);
+ kmem_cache_free(ehca_module.cache_cq, my_cq);
+
+destroy_cq_exit0:
+ EDEB_EX(7, "ehca_cq=%p cq_num=%x retcode=%x ",
+ my_cq, cq_num, retcode);
+ return retcode;
+}
+
+int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
+{
+ int retcode = 0;
+ struct ehca_cq *my_cq = NULL;
+ u32 cur_pid = current->tgid;
+
+ if (unlikely(NULL == cq)) {
+ EDEB_ERR(4, "cq is NULL");
+ return -EFAULT;
+ }
+
+ my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ EDEB_EN(7, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+
+ if (my_cq->uspace_queue!=0 && my_cq->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_cq->ownpid);
+ return -EINVAL;
+ }
+
+ /* TODO: proper resize needs to be done */
+ retcode = -EFAULT;
+ EDEB_ERR(4, "not implemented yet");
+
+ EDEB_EX(7, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+ return retcode;
+}
^ permalink raw reply
* [PATCH 08/16] ehca: memory region
From: Heiko J Schick @ 2006-04-27 10:49 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_mrmw.c | 2492 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ehca_mrmw.h | 145 +++
2 files changed, 2637 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_mrmw.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_mrmw.h 2006-02-28 09:49:25.000000000 +0100
@@ -0,0 +1,145 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * MR/MW declarations and inline functions
+ *
+ * Authors: Dietmar Decker <ddecker@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_mrmw.h,v 1.9 2006/02/28 08:49:25 schickhj Exp $
+ */
+
+#ifndef _EHCA_MRMW_H_
+#define _EHCA_MRMW_H_
+
+#undef DEB_PREFIX
+#define DEB_PREFIX "mrmw"
+
+int ehca_reg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_reg_mr_rpages(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo);
+
+int ehca_rereg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int mr_access_flags,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_unmap_one_fmr(struct ehca_shca *shca,
+ struct ehca_mr *e_fmr);
+
+int ehca_reg_smr(struct ehca_shca *shca,
+ struct ehca_mr *e_origmr,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_reg_internal_maxmr(struct ehca_shca *shca,
+ struct ehca_pd *e_pd,
+ struct ehca_mr **maxmr);
+
+int ehca_reg_maxmr(struct ehca_shca *shca,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_dereg_internal_maxmr(struct ehca_shca *shca);
+
+int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ u64 *iova_start,
+ u64 *size);
+
+int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
+ u64 *page_list,
+ int list_len);
+
+int ehca_set_pagebuf(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage);
+
+int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u64 *rpage);
+
+int ehca_mr_is_maxmr(u64 size,
+ u64 *iova_start);
+
+void ehca_mrmw_map_acl(int ib_acl,
+ u32 *hipz_acl);
+
+void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
+
+void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
+ int *ib_acl);
+
+int ehca_mrmw_map_rc_alloc(const u64 rc);
+
+int ehca_mrmw_map_rc_rrpg_last(const u64 rc);
+
+int ehca_mrmw_map_rc_rrpg_notlast(const u64 rc);
+
+int ehca_mrmw_map_rc_query_mr(const u64 rc);
+
+int ehca_mrmw_map_rc_free_mr(const u64 rc);
+
+int ehca_mrmw_map_rc_free_mw(const u64 rc);
+
+int ehca_mrmw_map_rc_reg_smr(const u64 rc);
+
+void ehca_mr_deletenew(struct ehca_mr *mr);
+
+#endif /*_EHCA_MRMW_H_*/
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_mrmw.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_mrmw.c 2006-04-25 16:51:33.000000000 +0200
@@ -0,0 +1,2492 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * MR/MW functions
+ *
+ * Authors: Dietmar Decker <ddecker@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_mrmw.c,v 1.24 2006/04/25 14:51:33 decker Exp $
+ */
+
+#undef DEB_PREFIX
+#define DEB_PREFIX "mrmw"
+
+#include <asm/current.h>
+
+#include "ehca_kernel.h"
+#include "ehca_iverbs.h"
+#include "ehca_mrmw.h"
+#include "hcp_if.h"
+#include "hipz_hw.h"
+
+extern int ehca_use_hp_mr;
+
+static struct ehca_mr *ehca_mr_new(void)
+{
+ extern struct ehca_module ehca_module;
+ struct ehca_mr *me;
+
+ me = kmem_cache_alloc(ehca_module.cache_mr, SLAB_KERNEL);
+ if (me) {
+ memset(me, 0, sizeof(struct ehca_mr));
+ spin_lock_init(&me->mrlock);
+ EDEB_EX(7, "ehca_mr=%p sizeof(ehca_mr_t)=%x", me,
+ (u32) sizeof(struct ehca_mr));
+ } else {
+ EDEB_ERR(3, "alloc failed");
+ }
+
+ return me;
+}
+
+static void ehca_mr_delete(struct ehca_mr *me)
+{
+ extern struct ehca_module ehca_module;
+
+ kmem_cache_free(ehca_module.cache_mr, me);
+}
+
+static struct ehca_mw *ehca_mw_new(void)
+{
+ extern struct ehca_module ehca_module;
+ struct ehca_mw *me;
+
+ me = kmem_cache_alloc(ehca_module.cache_mw, SLAB_KERNEL);
+ if (me) {
+ memset(me, 0, sizeof(struct ehca_mw));
+ spin_lock_init(&me->mwlock);
+ EDEB_EX(7, "ehca_mw=%p sizeof(ehca_mw_t)=%x", me,
+ (u32) sizeof(struct ehca_mw));
+ } else {
+ EDEB_ERR(3, "alloc failed");
+ }
+
+ return me;
+}
+
+static void ehca_mw_delete(struct ehca_mw *me)
+{
+ extern struct ehca_module ehca_module;
+
+ kmem_cache_free(ehca_module.cache_mw, me);
+}
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
+{
+ struct ib_mr *ib_mr = NULL;
+ int retcode = 0;
+ struct ehca_mr *e_maxmr = NULL;
+ struct ehca_pd *e_pd = NULL;
+ struct ehca_shca *shca = NULL;
+
+ EDEB_EN(7, "pd=%p mr_access_flags=%x", pd, mr_access_flags);
+
+ EHCA_CHECK_PD_P(pd);
+ e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ shca = container_of(pd->device, struct ehca_shca, ib_device);
+
+ if (shca->maxmr) {
+ e_maxmr = ehca_mr_new();
+ if (!e_maxmr) {
+ EDEB_ERR(4, "out of memory");
+ ib_mr = ERR_PTR(-ENOMEM);
+ goto get_dma_mr_exit0;
+ }
+
+ retcode = ehca_reg_maxmr(shca, e_maxmr,
+ (u64 *)KERNELBASE,
+ mr_access_flags, e_pd,
+ &e_maxmr->ib.ib_mr.lkey,
+ &e_maxmr->ib.ib_mr.rkey);
+ if (retcode != 0) {
+ ib_mr = ERR_PTR(retcode);
+ goto get_dma_mr_exit0;
+ }
+ ib_mr = &e_maxmr->ib.ib_mr;
+ } else {
+ EDEB_ERR(4, "no internal max-MR exist!");
+ ib_mr = ERR_PTR(-EINVAL);
+ goto get_dma_mr_exit0;
+ }
+
+get_dma_mr_exit0:
+ if (IS_ERR(ib_mr))
+ EDEB_EX(4, "rc=%lx pd=%p mr_access_flags=%x ",
+ PTR_ERR(ib_mr), pd, mr_access_flags);
+ else
+ EDEB_EX(7, "ib_mr=%p lkey=%x rkey=%x",
+ ib_mr, ib_mr->lkey, ib_mr->rkey);
+ return (ib_mr);
+} /* end ehca_get_dma_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ int mr_access_flags,
+ u64 *iova_start)
+{
+ struct ib_mr *ib_mr = NULL;
+ int retcode = 0;
+ struct ehca_mr *e_mr = NULL;
+ struct ehca_shca *shca = NULL;
+ struct ehca_pd *e_pd = NULL;
+ u64 size = 0;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ u32 num_pages_mr = 0;
+ u32 num_pages_4k = 0; /* 4k portion "pages" */
+
+ EDEB_EN(7, "pd=%p phys_buf_array=%p num_phys_buf=%x "
+ "mr_access_flags=%x iova_start=%p", pd, phys_buf_array,
+ num_phys_buf, mr_access_flags, iova_start);
+
+ EHCA_CHECK_PD_P(pd);
+ if ((num_phys_buf <= 0) || ehca_adr_bad(phys_buf_array)) {
+ EDEB_ERR(4, "bad input values: num_phys_buf=%x "
+ "phys_buf_array=%p", num_phys_buf, phys_buf_array);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_phys_mr_exit0;
+ }
+ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
+ /* Remote Write Access requires Local Write Access */
+ /* Remote Atomic Access requires Local Write Access */
+ EDEB_ERR(4, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_phys_mr_exit0;
+ }
+
+ /* check physical buffer list and calculate size */
+ retcode = ehca_mr_chk_buf_and_calc_size(phys_buf_array, num_phys_buf,
+ iova_start, &size);
+ if (retcode != 0) {
+ ib_mr = ERR_PTR(retcode);
+ goto reg_phys_mr_exit0;
+ }
+ if ((size == 0) ||
+ (((u64)iova_start + size) < (u64)iova_start)) {
+ EDEB_ERR(4, "bad input values: size=%lx iova_start=%p",
+ size, iova_start);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_phys_mr_exit0;
+ }
+
+ e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ shca = container_of(pd->device, struct ehca_shca, ib_device);
+
+ e_mr = ehca_mr_new();
+ if (!e_mr) {
+ EDEB_ERR(4, "out of memory");
+ ib_mr = ERR_PTR(-ENOMEM);
+ goto reg_phys_mr_exit0;
+ }
+
+ /* determine number of MR pages */
+ num_pages_mr = ( (((u64)iova_start % PAGE_SIZE) + size +
+ PAGE_SIZE - 1) / PAGE_SIZE );
+ num_pages_4k = ( (((u64)iova_start % EHCA_PAGESIZE) + size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE );
+
+ /* register MR on HCA */
+ if (ehca_mr_is_maxmr(size, iova_start)) {
+ e_mr->flags |= EHCA_MR_FLAG_MAXMR;
+ retcode = ehca_reg_maxmr(shca, e_mr, iova_start,
+ mr_access_flags, e_pd,
+ &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (retcode != 0) {
+ ib_mr = ERR_PTR(retcode);
+ goto reg_phys_mr_exit1;
+ }
+ } else {
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.num_phys_buf = num_phys_buf;
+ pginfo.phys_buf_array = phys_buf_array;
+ pginfo.next_4k = ( ((u64)iova_start & ~PAGE_MASK) /
+ EHCA_PAGESIZE);
+
+ retcode = ehca_reg_mr(shca, e_mr, iova_start, size,
+ mr_access_flags, e_pd, &pginfo,
+ &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (retcode != 0) {
+ ib_mr = ERR_PTR(retcode);
+ goto reg_phys_mr_exit1;
+ }
+ }
+
+ /* successful registration of all pages */
+ ib_mr = &e_mr->ib.ib_mr;
+ goto reg_phys_mr_exit0;
+
+reg_phys_mr_exit1:
+ ehca_mr_delete(e_mr);
+reg_phys_mr_exit0:
+ if (IS_ERR(ib_mr))
+ EDEB_EX(4, "rc=%lx pd=%p phys_buf_array=%p "
+ "num_phys_buf=%x mr_access_flags=%x iova_start=%p",
+ PTR_ERR(ib_mr), pd, phys_buf_array,
+ num_phys_buf, mr_access_flags, iova_start);
+ else
+ EDEB_EX(7, "ib_mr=%p lkey=%x rkey=%x",
+ ib_mr, ib_mr->lkey, ib_mr->rkey);
+ return (ib_mr);
+} /* end ehca_reg_phys_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
+ struct ib_umem *region,
+ int mr_access_flags,
+ struct ib_udata *udata)
+{
+ struct ib_mr *ib_mr = NULL;
+ struct ehca_mr *e_mr = NULL;
+ struct ehca_shca *shca = NULL;
+ struct ehca_pd *e_pd = NULL;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ int retcode = 0;
+ u32 num_pages_mr = 0;
+ u32 num_pages_4k = 0; /* 4k portion "pages" */
+
+ EDEB_EN(7, "pd=%p region=%p mr_access_flags=%x udata=%p",
+ pd, region, mr_access_flags, udata);
+
+ EHCA_CHECK_PD_P(pd);
+ if (ehca_adr_bad(region)) {
+ EDEB_ERR(4, "bad input values: region=%p", region);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
+ /* Remote Write Access requires Local Write Access */
+ /* Remote Atomic Access requires Local Write Access */
+ EDEB_ERR(4, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+ EDEB(7, "user_base=%lx virt_base=%lx length=%lx offset=%x page_size=%x "
+ "chunk_list.next=%p",
+ region->user_base, region->virt_base, region->length,
+ region->offset, region->page_size, region->chunk_list.next);
+ if (region->page_size != PAGE_SIZE) {
+ EDEB_ERR(4, "page size not supported, region->page_size=%x",
+ region->page_size);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+
+ if ((region->length == 0) ||
+ ((region->virt_base + region->length) < region->virt_base)) {
+ EDEB_ERR(4, "bad input values: length=%lx virt_base=%lx",
+ region->length, region->virt_base);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+
+ e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ shca = container_of(pd->device, struct ehca_shca, ib_device);
+
+ e_mr = ehca_mr_new();
+ if (!e_mr) {
+ EDEB_ERR(4, "out of memory");
+ ib_mr = ERR_PTR(-ENOMEM);
+ goto reg_user_mr_exit0;
+ }
+
+ /* determine number of MR pages */
+ num_pages_mr = ( ((region->virt_base % PAGE_SIZE) + region->length +
+ PAGE_SIZE - 1) / PAGE_SIZE );
+ num_pages_4k = ( ((region->virt_base % EHCA_PAGESIZE) + region->length +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE );
+
+ /* register MR on HCA */
+ pginfo.type = EHCA_MR_PGI_USER;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.region = region;
+ pginfo.next_4k = region->offset / EHCA_PAGESIZE;
+ pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
+ (®ion->chunk_list),
+ list);
+
+ retcode = ehca_reg_mr(shca, e_mr, (u64 *)region->virt_base,
+ region->length, mr_access_flags, e_pd, &pginfo,
+ &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+ if (retcode != 0) {
+ ib_mr = ERR_PTR(retcode);
+ goto reg_user_mr_exit1;
+ }
+
+ /* successful registration of all pages */
+ ib_mr = &e_mr->ib.ib_mr;
+ goto reg_user_mr_exit0;
+
+reg_user_mr_exit1:
+ ehca_mr_delete(e_mr);
+reg_user_mr_exit0:
+ if (IS_ERR(ib_mr))
+ EDEB_EX(4, "rc=%lx pd=%p region=%p mr_access_flags=%x "
+ "udata=%p",
+ PTR_ERR(ib_mr), pd, region, mr_access_flags, udata);
+ else
+ EDEB_EX(7, "ib_mr=%p lkey=%x rkey=%x",
+ ib_mr, ib_mr->lkey, ib_mr->rkey);
+ return (ib_mr);
+} /* end ehca_reg_user_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_rereg_phys_mr(struct ib_mr *mr,
+ int mr_rereg_mask,
+ struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ int mr_access_flags,
+ u64 *iova_start)
+{
+ int retcode = 0;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mr *e_mr = NULL;
+ u64 new_size = 0;
+ u64 *new_start = NULL;
+ u32 new_acl = 0;
+ struct ehca_pd *new_pd = NULL;
+ u32 tmp_lkey = 0;
+ u32 tmp_rkey = 0;
+ unsigned long sl_flags;
+ u32 num_pages_mr = 0;
+ u32 num_pages_4k = 0; /* 4k portion "pages" */
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+
+ EDEB_EN(7, "mr=%p mr_rereg_mask=%x pd=%p phys_buf_array=%p "
+ "num_phys_buf=%x mr_access_flags=%x iova_start=%p",
+ mr, mr_rereg_mask, pd, phys_buf_array, num_phys_buf,
+ mr_access_flags, iova_start);
+
+ EHCA_CHECK_MR(mr);
+ my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject!=NULL && my_pd->ib_pd.uobject->context!=NULL &&
+ my_pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ if (!(mr_rereg_mask & IB_MR_REREG_TRANS)) {
+ /* TODO not supported, because PHYP rereg hCall needs pages*/
+ /* TODO: We will follow this with Tom ....*/
+ EDEB_ERR(4, "rereg without IB_MR_REREG_TRANS not supported yet,"
+ " mr_rereg_mask=%x", mr_rereg_mask);
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
+ if (mr_rereg_mask & IB_MR_REREG_PD) {
+ EHCA_CHECK_PD(pd);
+ }
+
+ if ((mr_rereg_mask &
+ ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS)) ||
+ (mr_rereg_mask == 0)) {
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ shca = container_of(mr->device, struct ehca_shca, ib_device);
+
+ /* check other parameters */
+ if (e_mr == shca->maxmr) {
+ /* should be impossible, however reject to be sure */
+ EDEB_ERR(3, "rereg internal max-MR impossible, mr=%p "
+ "shca->maxmr=%p mr->lkey=%x",
+ mr, shca->maxmr, mr->lkey);
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+ if (mr_rereg_mask & IB_MR_REREG_TRANS) { /* transl., i.e. addr/size */
+ if (e_mr->flags & EHCA_MR_FLAG_FMR) {
+ EDEB_ERR(4, "not supported for FMR, mr=%p flags=%x",
+ mr, e_mr->flags);
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+ if (ehca_adr_bad(phys_buf_array) || num_phys_buf <= 0) {
+ EDEB_ERR(4, "bad input values: mr_rereg_mask=%x "
+ "phys_buf_array=%p num_phys_buf=%x",
+ mr_rereg_mask, phys_buf_array, num_phys_buf);
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+ }
+ if ((mr_rereg_mask & IB_MR_REREG_ACCESS) && /* change ACL */
+ (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)))) {
+ /* Remote Write Access requires Local Write Access */
+ /* Remote Atomic Access requires Local Write Access */
+ EDEB_ERR(4, "bad input values: mr_rereg_mask=%x "
+ "mr_access_flags=%x", mr_rereg_mask, mr_access_flags);
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ /* set requested values dependent on rereg request */
+ spin_lock_irqsave(&e_mr->mrlock, sl_flags); /* get lock TODO for MR */
+ new_start = e_mr->start; /* new == old address */
+ new_size = e_mr->size; /* new == old length */
+ new_acl = e_mr->acl; /* new == old access control */
+ new_pd = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
+
+ if (mr_rereg_mask & IB_MR_REREG_TRANS) {
+ new_start = iova_start; /* change address */
+ /* check physical buffer list and calculate size */
+ retcode = ehca_mr_chk_buf_and_calc_size(phys_buf_array,
+ num_phys_buf,
+ iova_start, &new_size);
+ if (retcode != 0)
+ goto rereg_phys_mr_exit1;
+ if ((new_size == 0) ||
+ (((u64)iova_start + new_size) < (u64)iova_start)) {
+ EDEB_ERR(4, "bad input values: new_size=%lx "
+ "iova_start=%p", new_size, iova_start);
+ retcode = -EINVAL;
+ goto rereg_phys_mr_exit1;
+ }
+ num_pages_mr = ( (((u64)new_start % PAGE_SIZE) + new_size +
+ PAGE_SIZE - 1) / PAGE_SIZE );
+ num_pages_4k = ( (((u64)new_start % EHCA_PAGESIZE) + new_size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE );
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.num_phys_buf = num_phys_buf;
+ pginfo.phys_buf_array = phys_buf_array;
+ pginfo.next_4k = ( ((u64)iova_start & ~PAGE_MASK) /
+ EHCA_PAGESIZE);
+ }
+ if (mr_rereg_mask & IB_MR_REREG_ACCESS)
+ new_acl = mr_access_flags;
+ if (mr_rereg_mask & IB_MR_REREG_PD)
+ new_pd = container_of(pd, struct ehca_pd, ib_pd);
+
+ EDEB(7, "mr=%p new_start=%p new_size=%lx new_acl=%x new_pd=%p "
+ "num_pages_mr=%x num_pages_4k=%x", e_mr, new_start, new_size,
+ new_acl, new_pd, num_pages_mr, num_pages_4k);
+
+ retcode = ehca_rereg_mr(shca, e_mr, new_start, new_size, new_acl,
+ new_pd, &pginfo, &tmp_lkey, &tmp_rkey);
+ if (retcode != 0)
+ goto rereg_phys_mr_exit1;
+
+ /* successful reregistration */
+ if (mr_rereg_mask & IB_MR_REREG_PD)
+ mr->pd = pd;
+ mr->lkey = tmp_lkey;
+ mr->rkey = tmp_rkey;
+
+rereg_phys_mr_exit1:
+ spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); /* free spin lock */
+rereg_phys_mr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x mr=%p mr_rereg_mask=%x pd=%p "
+ "phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x "
+ "iova_start=%p",
+ retcode, mr, mr_rereg_mask, pd, phys_buf_array,
+ num_phys_buf, mr_access_flags, iova_start);
+ else
+ EDEB_EX(7, "mr=%p mr_rereg_mask=%x pd=%p phys_buf_array=%p "
+ "num_phys_buf=%x mr_access_flags=%x iova_start=%p",
+ mr, mr_rereg_mask, pd, phys_buf_array, num_phys_buf,
+ mr_access_flags, iova_start);
+
+ return (retcode);
+} /* end ehca_rereg_phys_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mr *e_mr = NULL;
+ struct ipz_pd fwpd; /* Firmware PD */
+ u32 access_ctrl = 0;
+ u64 tmp_remote_size = 0;
+ u64 tmp_remote_len = 0;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+
+ unsigned long sl_flags;
+
+ EDEB_EN(7, "mr=%p mr_attr=%p", mr, mr_attr);
+
+ EHCA_CHECK_MR(mr);
+
+ my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject!=NULL && my_pd->ib_pd.uobject->context!=NULL &&
+ my_pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ retcode = -EINVAL;
+ goto query_mr_exit0;
+ }
+
+ e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
+ if (ehca_adr_bad(mr_attr)) {
+ EDEB_ERR(4, "bad input values: mr_attr=%p", mr_attr);
+ retcode = -EINVAL;
+ goto query_mr_exit0;
+ }
+ if ((e_mr->flags & EHCA_MR_FLAG_FMR)) {
+ EDEB_ERR(4, "not supported for FMR, mr=%p e_mr=%p "
+ "e_mr->flags=%x", mr, e_mr, e_mr->flags);
+ retcode = -EINVAL;
+ goto query_mr_exit0;
+ }
+
+ shca = container_of(mr->device, struct ehca_shca, ib_device);
+ memset(mr_attr, 0, sizeof(struct ib_mr_attr));
+ spin_lock_irqsave(&e_mr->mrlock, sl_flags); /* get spin lock TODO?? */
+
+ rc = hipz_h_query_mr(shca->ipz_hca_handle, &e_mr->pf,
+ &e_mr->ipz_mr_handle, &mr_attr->size,
+ &mr_attr->device_virt_addr, &tmp_remote_size,
+ &tmp_remote_len, &access_ctrl, &fwpd,
+ &mr_attr->lkey, &mr_attr->rkey);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_mr_query failed, rc=%lx mr=%p "
+ "hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ rc, mr, shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle, mr->lkey);
+ retcode = ehca_mrmw_map_rc_query_mr(rc);
+ goto query_mr_exit1;
+ }
+ ehca_mrmw_reverse_map_acl(&access_ctrl, &mr_attr->mr_access_flags);
+ mr_attr->pd = mr->pd;
+
+query_mr_exit1:
+ spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); /* free spin lock */
+query_mr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x mr=%p mr_attr=%p", retcode, mr, mr_attr);
+ else
+ EDEB_EX(7, "pd=%p device_virt_addr=%lx size=%lx "
+ "mr_access_flags=%x lkey=%x rkey=%x",
+ mr_attr->pd, mr_attr->device_virt_addr,
+ mr_attr->size, mr_attr->mr_access_flags,
+ mr_attr->lkey, mr_attr->rkey);
+ return (retcode);
+} /* end ehca_query_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_dereg_mr(struct ib_mr *mr)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mr *e_mr = NULL;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+
+ EDEB_EN(7, "mr=%p", mr);
+
+ EHCA_CHECK_MR(mr);
+ my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject!=NULL && my_pd->ib_pd.uobject->context!=NULL &&
+ my_pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ retcode = -EINVAL;
+ goto dereg_mr_exit0;
+ }
+
+ e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
+ shca = container_of(mr->device, struct ehca_shca, ib_device);
+
+ if ((e_mr->flags & EHCA_MR_FLAG_FMR)) {
+ EDEB_ERR(4, "not supported for FMR, mr=%p e_mr=%p "
+ "e_mr->flags=%x", mr, e_mr, e_mr->flags);
+ retcode = -EINVAL;
+ goto dereg_mr_exit0;
+ } else if (e_mr == shca->maxmr) {
+ /* should be impossible, however reject to be sure */
+ EDEB_ERR(3, "dereg internal max-MR impossible, mr=%p "
+ "shca->maxmr=%p mr->lkey=%x",
+ mr, shca->maxmr, mr->lkey);
+ retcode = -EINVAL;
+ goto dereg_mr_exit0;
+ }
+
+ /* TODO: BUSY: MR still has bound window(s) */
+ rc = hipz_h_free_resource_mr(shca->ipz_hca_handle, &e_mr->pf,
+ &e_mr->ipz_mr_handle);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_free_mr failed, rc=%lx shca=%p e_mr=%p"
+ " hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
+ rc, shca, e_mr, shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle, mr->lkey);
+ retcode = ehca_mrmw_map_rc_free_mr(rc);
+ goto dereg_mr_exit0;
+ }
+
+ /* successful deregistration */
+ ehca_mr_delete(e_mr);
+
+dereg_mr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x mr=%p", retcode, mr);
+ else
+ EDEB_EX(7, "");
+ return (retcode);
+} /* end ehca_dereg_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
+{
+ struct ib_mw *ib_mw = NULL;
+ u64 rc = H_SUCCESS;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mw *e_mw = NULL;
+ struct ehca_pd *e_pd = NULL;
+
+ EDEB_EN(7, "pd=%p", pd);
+
+ EHCA_CHECK_PD_P(pd);
+ e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ shca = container_of(pd->device, struct ehca_shca, ib_device);
+
+ e_mw = ehca_mw_new();
+ if (!e_mw) {
+ ib_mw = ERR_PTR(-ENOMEM);
+ goto alloc_mw_exit0;
+ }
+
+ rc = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, &e_mw->pf,
+ &shca->pf, e_pd->fw_pd,
+ &e_mw->ipz_mw_handle, &e_mw->ib_mw.rkey);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_mw_allocate failed, rc=%lx shca=%p "
+ "hca_hndl=%lx mw=%p", rc, shca,
+ shca->ipz_hca_handle.handle, e_mw);
+ ib_mw = ERR_PTR(ehca_mrmw_map_rc_alloc(rc));
+ goto alloc_mw_exit1;
+ }
+ /* save R_Key in local copy */
+ /* TODO????? mw->rkey = *rkey_p; */
+
+ /* successful MW allocation */
+ ib_mw = &e_mw->ib_mw;
+ goto alloc_mw_exit0;
+
+alloc_mw_exit1:
+ ehca_mw_delete(e_mw);
+alloc_mw_exit0:
+ if (IS_ERR(ib_mw))
+ EDEB_EX(4, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd);
+ else
+ EDEB_EX(7, "ib_mw=%p rkey=%x", ib_mw, ib_mw->rkey);
+ return (ib_mw);
+} /* end ehca_alloc_mw() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_bind_mw(struct ib_qp *qp,
+ struct ib_mw *mw,
+ struct ib_mw_bind *mw_bind)
+{
+ int retcode = 0;
+
+ /* TODO: not supported up to now */
+ EDEB_ERR(4, "bind MW currently not supported by HCAD");
+ retcode = -EPERM;
+ goto bind_mw_exit0;
+
+bind_mw_exit0:
+ if (retcode)
+ EDEB_EX(4, "rc=%x qp=%p mw=%p mw_bind=%p",
+ retcode, qp, mw, mw_bind);
+ else
+ EDEB_EX(7, "qp=%p mw=%p mw_bind=%p", qp, mw, mw_bind);
+ return (retcode);
+} /* end ehca_bind_mw() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_dealloc_mw(struct ib_mw *mw)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mw *e_mw = NULL;
+
+ EDEB_EN(7, "mw=%p", mw);
+
+ EHCA_CHECK_MW(mw);
+ e_mw = container_of(mw, struct ehca_mw, ib_mw);
+ shca = container_of(mw->device, struct ehca_shca, ib_device);
+
+ rc = hipz_h_free_resource_mw(shca->ipz_hca_handle, &e_mw->pf,
+ &e_mw->ipz_mw_handle);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_free_mw failed, rc=%lx shca=%p mw=%p "
+ "rkey=%x hca_hndl=%lx mw_hndl=%lx",
+ rc, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
+ e_mw->ipz_mw_handle.handle);
+ retcode = ehca_mrmw_map_rc_free_mw(rc);
+ goto dealloc_mw_exit0;
+ }
+ /* successful deallocation */
+ ehca_mw_delete(e_mw);
+
+dealloc_mw_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x mw=%p", retcode, mw);
+ else
+ EDEB_EX(7, "");
+ return (retcode);
+} /* end ehca_dealloc_mw() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
+ int mr_access_flags,
+ struct ib_fmr_attr *fmr_attr)
+{
+ struct ib_fmr *ib_fmr = NULL;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mr *e_fmr = NULL;
+ int retcode = 0;
+ struct ehca_pd *e_pd = NULL;
+ u32 tmp_lkey = 0;
+ u32 tmp_rkey = 0;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+
+ EDEB_EN(7, "pd=%p mr_access_flags=%x fmr_attr=%p",
+ pd, mr_access_flags, fmr_attr);
+
+ EHCA_CHECK_PD_P(pd);
+ if (ehca_adr_bad(fmr_attr)) {
+ EDEB_ERR(4, "bad input values: fmr_attr=%p", fmr_attr);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+
+ EDEB(7, "max_pages=%x max_maps=%x page_shift=%x",
+ fmr_attr->max_pages, fmr_attr->max_maps, fmr_attr->page_shift);
+
+ /* check other parameters */
+ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
+ /* Remote Write Access requires Local Write Access */
+ /* Remote Atomic Access requires Local Write Access */
+ EDEB_ERR(4, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+ if (mr_access_flags & IB_ACCESS_MW_BIND) {
+ EDEB_ERR(4, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+ if ((fmr_attr->max_pages == 0) || (fmr_attr->max_maps == 0)) {
+ EDEB_ERR(4, "bad input values: fmr_attr->max_pages=%x "
+ "fmr_attr->max_maps=%x fmr_attr->page_shift=%x",
+ fmr_attr->max_pages, fmr_attr->max_maps,
+ fmr_attr->page_shift);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+ if ( ((1 << fmr_attr->page_shift) != EHCA_PAGESIZE) &&
+ ((1 << fmr_attr->page_shift) != PAGE_SIZE) ) {
+ EDEB_ERR(4, "unsupported fmr_attr->page_shift=%x",
+ fmr_attr->page_shift);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+
+ e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ shca = container_of(pd->device, struct ehca_shca, ib_device);
+
+ e_fmr = ehca_mr_new();
+ if (!e_fmr) {
+ ib_fmr = ERR_PTR(-ENOMEM);
+ goto alloc_fmr_exit0;
+ }
+ e_fmr->flags |= EHCA_MR_FLAG_FMR;
+
+ /* register MR on HCA */
+ retcode = ehca_reg_mr(shca, e_fmr, NULL,
+ fmr_attr->max_pages * (1 << fmr_attr->page_shift),
+ mr_access_flags, e_pd, &pginfo,
+ &tmp_lkey, &tmp_rkey);
+ if (retcode != 0) {
+ ib_fmr = ERR_PTR(retcode);
+ goto alloc_fmr_exit1;
+ }
+
+ /* successful */
+ e_fmr->fmr_page_size = 1 << fmr_attr->page_shift;
+ e_fmr->fmr_max_pages = fmr_attr->max_pages;
+ e_fmr->fmr_max_maps = fmr_attr->max_maps;
+ e_fmr->fmr_map_cnt = 0;
+ ib_fmr = &e_fmr->ib.ib_fmr;
+ goto alloc_fmr_exit0;
+
+alloc_fmr_exit1:
+ ehca_mr_delete(e_fmr);
+alloc_fmr_exit0:
+ if (IS_ERR(ib_fmr))
+ EDEB_EX(4, "rc=%lx pd=%p mr_access_flags=%x "
+ "fmr_attr=%p", PTR_ERR(ib_fmr), pd,
+ mr_access_flags, fmr_attr);
+ else
+ EDEB_EX(7, "ib_fmr=%p tmp_lkey=%x tmp_rkey=%x",
+ ib_fmr, tmp_lkey, tmp_rkey);
+ return (ib_fmr);
+} /* end ehca_alloc_fmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_map_phys_fmr(struct ib_fmr *fmr,
+ u64 *page_list,
+ int list_len,
+ u64 iova)
+{
+ int retcode = 0;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mr *e_fmr = NULL;
+ struct ehca_pd *e_pd = NULL;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ u32 tmp_lkey = 0;
+ u32 tmp_rkey = 0;
+ /* TODO unsigned long sl_flags; */
+
+ EDEB_EN(7, "fmr=%p page_list=%p list_len=%x iova=%lx",
+ fmr, page_list, list_len, iova);
+
+ EHCA_CHECK_FMR(fmr);
+ e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
+ shca = container_of(fmr->device, struct ehca_shca, ib_device);
+ e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
+
+ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
+ EDEB_ERR(4, "not a FMR, e_fmr=%p e_fmr->flags=%x",
+ e_fmr, e_fmr->flags);
+ retcode = -EINVAL;
+ goto map_phys_fmr_exit0;
+ }
+ retcode = ehca_fmr_check_page_list(e_fmr, page_list, list_len);
+ if (retcode != 0)
+ goto map_phys_fmr_exit0;
+ if (iova % e_fmr->fmr_page_size) {
+ /* only whole-numbered pages */
+ EDEB_ERR(4, "bad iova, iova=%lx fmr_page_size=%x",
+ iova, e_fmr->fmr_page_size);
+ retcode = -EINVAL;
+ goto map_phys_fmr_exit0;
+ }
+ if (e_fmr->fmr_map_cnt >= e_fmr->fmr_max_maps) {
+ /* HCAD does not limit the maps, however trace this anyway */
+ EDEB(6, "map limit exceeded, fmr=%p e_fmr->fmr_map_cnt=%x "
+ "e_fmr->fmr_max_maps=%x",
+ fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
+ }
+
+ pginfo.type = EHCA_MR_PGI_FMR;
+ pginfo.num_pages = list_len;
+ pginfo.page_list = page_list;
+ pginfo.next_4k = ( (iova & (e_fmr->fmr_page_size-1)) /
+ EHCA_PAGESIZE);
+
+ /* TODO spin_lock_irqsave(&e_fmr->mrlock, sl_flags); */
+
+ retcode = ehca_rereg_mr(shca, e_fmr, (u64 *)iova,
+ list_len * e_fmr->fmr_page_size,
+ e_fmr->acl, e_pd, &pginfo,
+ &tmp_lkey, &tmp_rkey);
+ if (retcode != 0) {
+ /* TODO spin_unlock_irqrestore(&fmr->mrlock, sl_flags); */
+ goto map_phys_fmr_exit0;
+ }
+ /* successful reregistration */
+ e_fmr->fmr_map_cnt++;
+ /* TODO spin_unlock_irqrestore(&fmr->mrlock, sl_flags); */
+
+ e_fmr->ib.ib_fmr.lkey = tmp_lkey;
+ e_fmr->ib.ib_fmr.rkey = tmp_rkey;
+
+map_phys_fmr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x fmr=%p page_list=%p list_len=%x "
+ "iova=%lx",
+ retcode, fmr, page_list, list_len, iova);
+ else
+ EDEB_EX(7, "lkey=%x rkey=%x",
+ e_fmr->ib.ib_fmr.lkey, e_fmr->ib.ib_fmr.rkey);
+ return (retcode);
+} /* end ehca_map_phys_fmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_unmap_fmr(struct list_head *fmr_list)
+{
+ int retcode = 0;
+ struct ib_fmr *ib_fmr = NULL;
+ struct ehca_shca *shca = NULL;
+ struct ehca_shca *prev_shca = NULL;
+ struct ehca_mr *e_fmr = NULL;
+ u32 num_fmr = 0;
+ u32 unmap_fmr_cnt = 0;
+ /* TODO unsigned long sl_flags; */
+
+ EDEB_EN(7, "fmr_list=%p", fmr_list);
+
+ /* check all FMR belong to same SHCA, and check internal flag */
+ list_for_each_entry(ib_fmr, fmr_list, list) {
+ prev_shca = shca;
+ shca = container_of(ib_fmr->device, struct ehca_shca,
+ ib_device);
+ EHCA_CHECK_FMR(ib_fmr);
+ e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
+ if ((shca != prev_shca) && (prev_shca != 0)) {
+ EDEB_ERR(4, "SHCA mismatch, shca=%p prev_shca=%p "
+ "e_fmr=%p", shca, prev_shca, e_fmr);
+ retcode = -EINVAL;
+ goto unmap_fmr_exit0;
+ }
+ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
+ EDEB_ERR(4, "not a FMR, e_fmr=%p e_fmr->flags=%x",
+ e_fmr, e_fmr->flags);
+ retcode = -EINVAL;
+ goto unmap_fmr_exit0;
+ }
+ num_fmr++;
+ }
+
+ /* loop over all FMRs to unmap */
+ list_for_each_entry(ib_fmr, fmr_list, list) {
+ unmap_fmr_cnt++;
+ e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
+ shca = container_of(ib_fmr->device, struct ehca_shca,
+ ib_device);
+ /* TODO??? spin_lock_irqsave(&fmr->mrlock, sl_flags); */
+ retcode = ehca_unmap_one_fmr(shca, e_fmr);
+ /* TODO???? spin_unlock_irqrestore(&fmr->mrlock, sl_flags); */
+ if (retcode != 0) {
+ /* unmap failed, stop unmapping of rest of FMRs */
+ EDEB_ERR(4, "unmap of one FMR failed, stop rest, "
+ "e_fmr=%p num_fmr=%x unmap_fmr_cnt=%x lkey=%x",
+ e_fmr, num_fmr, unmap_fmr_cnt,
+ e_fmr->ib.ib_fmr.lkey);
+ goto unmap_fmr_exit0;
+ }
+ }
+
+unmap_fmr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
+ retcode, fmr_list, num_fmr, unmap_fmr_cnt);
+ else
+ EDEB_EX(7, "num_fmr=%x", num_fmr);
+ return (retcode);
+} /* end ehca_unmap_fmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_dealloc_fmr(struct ib_fmr *fmr)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_shca *shca = NULL;
+ struct ehca_mr *e_fmr = NULL;
+
+ EDEB_EN(7, "fmr=%p", fmr);
+
+ EHCA_CHECK_FMR(fmr);
+ e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
+ shca = container_of(fmr->device, struct ehca_shca, ib_device);
+
+ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
+ EDEB_ERR(4, "not a FMR, e_fmr=%p e_fmr->flags=%x",
+ e_fmr, e_fmr->flags);
+ retcode = -EINVAL;
+ goto free_fmr_exit0;
+ }
+
+ rc = hipz_h_free_resource_mr(shca->ipz_hca_handle, &e_fmr->pf,
+ &e_fmr->ipz_mr_handle);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_free_mr failed, rc=%lx e_fmr=%p "
+ "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
+ rc, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle, fmr->lkey);
+ ehca_mrmw_map_rc_free_mr(rc);
+ goto free_fmr_exit0;
+ }
+ /* successful deregistration */
+ ehca_mr_delete(e_fmr);
+
+free_fmr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x fmr=%p", retcode, fmr);
+ else
+ EDEB_EX(7, "");
+ return (retcode);
+} /* end ehca_dealloc_fmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey, /*OUT*/
+ u32 *rkey) /*OUT*/
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_pfmr *pfmr = &e_mr->pf;
+ u32 hipz_acl = 0;
+
+ EDEB_EN(7, "shca=%p e_mr=%p iova_start=%p size=%lx acl=%x e_pd=%p "
+ "pginfo=%p num_pages=%lx num_4k=%lx", shca, e_mr, iova_start,
+ size, acl, e_pd, pginfo, pginfo->num_pages, pginfo->num_4k);
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ if (ehca_use_hp_mr == 1)
+ hipz_acl |= 0x00000001;
+
+ rc = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, pfmr, &shca->pf,
+ (u64)iova_start, size, hipz_acl,
+ e_pd->fw_pd, &e_mr->ipz_mr_handle,
+ lkey, rkey);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_alloc_mr failed, rc=%lx hca_hndl=%lx "
+ "mr_hndl=%lx", rc, shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle);
+ retcode = ehca_mrmw_map_rc_alloc(rc);
+ goto ehca_reg_mr_exit0;
+ }
+
+ retcode = ehca_reg_mr_rpages(shca, e_mr, pginfo);
+ if (retcode != 0)
+ goto ehca_reg_mr_exit1;
+
+ /* successful registration */
+ e_mr->num_pages = pginfo->num_pages;
+ e_mr->num_4k = pginfo->num_4k;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
+ goto ehca_reg_mr_exit0;
+
+ehca_reg_mr_exit1:
+ rc = hipz_h_free_resource_mr(shca->ipz_hca_handle, pfmr,
+ &e_mr->ipz_mr_handle);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(1, "rc=%lx shca=%p e_mr=%p iova_start=%p "
+ "size=%lx acl=%x e_pd=%p lkey=%x pginfo=%p "
+ "num_pages=%lx num_4k=%lx retcode=%x", rc, shca, e_mr,
+ iova_start, size, acl, e_pd, *lkey, pginfo,
+ pginfo->num_pages, pginfo->num_4k, retcode);
+ EDEB_ERR(1, "internal error in ehca_reg_mr, not recoverable");
+ }
+ehca_reg_mr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x shca=%p e_mr=%p iova_start=%p "
+ "size=%lx acl=%x e_pd=%p pginfo=%p num_pages=%lx "
+ "num_4k=%lx", retcode, shca, e_mr, iova_start, size,
+ acl, e_pd, pginfo, pginfo->num_pages, pginfo->num_4k);
+ else
+ EDEB_EX(7, "retcode=%x lkey=%x rkey=%x", retcode, *lkey, *rkey);
+ return (retcode);
+} /* end ehca_reg_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_mr_rpages(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_pfmr *pfmr = &e_mr->pf;
+ u32 rnum = 0;
+ u64 rpage = 0;
+ u32 i;
+ u64 *kpage = NULL;
+
+ EDEB_EN(7, "shca=%p e_mr=%p pginfo=%p num_pages=%lx num_4k=%lx",
+ shca, e_mr, pginfo, pginfo->num_pages, pginfo->num_4k);
+
+ kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!kpage) {
+ EDEB_ERR(4, "kpage alloc failed");
+ retcode = -ENOMEM;
+ goto ehca_reg_mr_rpages_exit0;
+ }
+
+ /* max 512 pages per shot */
+ for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
+
+ if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+ rnum = pginfo->num_4k % 512; /* last shot */
+ if (rnum == 0)
+ rnum = 512; /* last shot is full */
+ } else
+ rnum = 512;
+
+ if (rnum > 1) {
+ retcode = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
+ if (retcode) {
+ EDEB_ERR(4, "ehca_set_pagebuf bad rc, "
+ "retcode=%x rnum=%x kpage=%p",
+ retcode, rnum, kpage);
+ retcode = -EFAULT;
+ goto ehca_reg_mr_rpages_exit1;
+ }
+ rpage = virt_to_abs(kpage);
+ if (rpage == 0) {
+ EDEB_ERR(4, "kpage=%p i=%x", kpage, i);
+ retcode = -EFAULT;
+ goto ehca_reg_mr_rpages_exit1;
+ }
+ } else { /* rnum==1 */
+ retcode = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
+ if (retcode) {
+ EDEB_ERR(4, "ehca_set_pagebuf_1 bad rc, "
+ "retcode=%x i=%x", retcode, i);
+ retcode = -EFAULT;
+ goto ehca_reg_mr_rpages_exit1;
+ }
+ }
+
+ EDEB(9, "i=%x rnum=%x rpage=%lx", i, rnum, rpage);
+
+ rc = hipz_h_register_rpage_mr(shca->ipz_hca_handle,
+ &e_mr->ipz_mr_handle, pfmr,
+ &shca->pf,
+ 0, /* pagesize hardcoded to 4k */
+ 0, rpage, rnum);
+
+ if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+ /* check for 'registration complete'==H_SUCCESS */
+ /* and for 'page registered'==H_PAGE_REGISTERED */
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "last hipz_reg_rpage_mr failed, "
+ "rc=%lx e_mr=%p i=%x hca_hndl=%lx "
+ "mr_hndl=%lx lkey=%x", rc, e_mr, i,
+ shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle,
+ e_mr->ib.ib_mr.lkey);
+ retcode = ehca_mrmw_map_rc_rrpg_last(rc);
+ break;
+ } else
+ retcode = 0;
+ } else if (rc != H_PAGE_REGISTERED) {
+ EDEB_ERR(4, "hipz_reg_rpage_mr failed, rc=%lx e_mr=%p "
+ "i=%x lkey=%x hca_hndl=%lx mr_hndl=%lx",
+ rc, e_mr, i, e_mr->ib.ib_mr.lkey,
+ shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle);
+ retcode = ehca_mrmw_map_rc_rrpg_notlast(rc);
+ break;
+ } else
+ retcode = 0;
+ } /* end for(i) */
+
+
+ehca_reg_mr_rpages_exit1:
+ kfree(kpage);
+ehca_reg_mr_rpages_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x shca=%p e_mr=%p pginfo=%p "
+ "num_pages=%lx num_4k=%lx", retcode, shca, e_mr,
+ pginfo, pginfo->num_pages, pginfo->num_4k);
+ else
+ EDEB_EX(7, "retcode=%x", retcode);
+ return (retcode);
+} /* end ehca_reg_mr_rpages() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ u32 acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey, /*OUT*/
+ u32 *rkey) /*OUT*/
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_pfmr *pfmr = &e_mr->pf;
+ u64 iova_start_out = 0;
+ u32 hipz_acl = 0;
+ u64 *kpage = NULL;
+ u64 rpage = 0;
+ struct ehca_mr_pginfo pginfo_save;
+
+ EDEB_EN(7, "shca=%p e_mr=%p iova_start=%p size=%lx acl=%x "
+ "e_pd=%p pginfo=%p num_pages=%lx num_4k=%lx", shca, e_mr,
+ iova_start, size, acl, e_pd, pginfo, pginfo->num_pages,
+ pginfo->num_4k);
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+
+ kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!kpage) {
+ EDEB_ERR(4, "kpage alloc failed");
+ retcode = -ENOMEM;
+ goto ehca_rereg_mr_rereg1_exit0;
+ }
+
+ pginfo_save = *pginfo;
+ retcode = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
+ if (retcode != 0) {
+ EDEB_ERR(4, "set pagebuf failed, e_mr=%p pginfo=%p type=%x "
+ "num_pages=%lx num_4k=%lx kpage=%p", e_mr, pginfo,
+ pginfo->type, pginfo->num_pages, pginfo->num_4k,kpage);
+ goto ehca_rereg_mr_rereg1_exit1;
+ }
+ rpage = virt_to_abs(kpage);
+ if (rpage == 0) {
+ EDEB_ERR(4, "kpage=%p", kpage);
+ retcode = -EFAULT;
+ goto ehca_rereg_mr_rereg1_exit1;
+ }
+ rc = hipz_h_reregister_pmr(shca->ipz_hca_handle, pfmr, &shca->pf,
+ &e_mr->ipz_mr_handle, (u64)iova_start,
+ size, hipz_acl, e_pd->fw_pd, rpage,
+ &iova_start_out, lkey, rkey);
+ if (rc != H_SUCCESS) {
+ /* reregistration unsuccessful, */
+ /* try it again with the 3 hCalls, */
+ /* e.g. this is required in case H_MR_CONDITION */
+ /* (MW bound or MR is shared) */
+ EDEB(6, "hipz_h_reregister_pmr failed (Rereg1), rc=%lx "
+ "e_mr=%p", rc, e_mr);
+ *pginfo = pginfo_save;
+ retcode = -EAGAIN;
+ } else if ((u64 *)iova_start_out != iova_start) {
+ EDEB_ERR(4, "PHYP changed iova_start in rereg_pmr, "
+ "iova_start=%p iova_start_out=%lx e_mr=%p "
+ "mr_handle=%lx lkey=%x", iova_start, iova_start_out,
+ e_mr, e_mr->ipz_mr_handle.handle, e_mr->ib.ib_mr.lkey);
+ retcode = -EFAULT;
+ } else {
+ /* successful reregistration */
+ /* note: start and start_out are identical for eServer HCAs */
+ e_mr->num_pages = pginfo->num_pages;
+ e_mr->num_4k = pginfo->num_4k;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
+ }
+
+ehca_rereg_mr_rereg1_exit1:
+ kfree(kpage);
+ehca_rereg_mr_rereg1_exit0:
+ if ((retcode) && (retcode != -EAGAIN))
+ EDEB_EX(4, "retcode=%x rc=%lx lkey=%x rkey=%x pginfo=%p "
+ "num_pages=%lx num_4k=%lx", retcode, rc, *lkey,
+ *rkey, pginfo, pginfo->num_pages, pginfo->num_4k);
+ else
+ EDEB_EX(7, "retcode=%x rc=%lx lkey=%x rkey=%x pginfo=%p "
+ "num_pages=%lx num_4k=%lx", retcode, rc, *lkey,
+ *rkey, pginfo, pginfo->num_pages, pginfo->num_4k);
+ return (retcode);
+} /* end ehca_rereg_mr_rereg1() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_rereg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey,
+ u32 *rkey)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_pfmr *pfmr = &e_mr->pf;
+ int Rereg1Hcall = 1; /* 1: use hipz_h_reregister_pmr directly */
+ int Rereg3Hcall = 0; /* 1: use 3 hipz calls for reregistration */
+
+ EDEB_EN(7, "shca=%p e_mr=%p iova_start=%p size=%lx acl=%x "
+ "e_pd=%p pginfo=%p num_pages=%lx num_4k=%lx", shca, e_mr,
+ iova_start, size, acl, e_pd, pginfo, pginfo->num_pages,
+ pginfo->num_4k);
+
+ /* first determine reregistration hCall(s) */
+ if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
+ (pginfo->num_4k > e_mr->num_4k)) {
+ EDEB(7, "Rereg3 case, pginfo->num_4k=%lx "
+ "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
+ Rereg1Hcall = 0;
+ Rereg3Hcall = 1;
+ }
+
+ if (e_mr->flags & EHCA_MR_FLAG_MAXMR) { /* check for max-MR */
+ Rereg1Hcall = 0;
+ Rereg3Hcall = 1;
+ e_mr->flags &= ~EHCA_MR_FLAG_MAXMR;
+ EDEB(4, "Rereg MR for max-MR! e_mr=%p", e_mr);
+ }
+
+ if (Rereg1Hcall) {
+ retcode = ehca_rereg_mr_rereg1(shca, e_mr, iova_start, size,
+ acl, e_pd, pginfo, lkey, rkey);
+ if (retcode != 0) {
+ if (retcode == -EAGAIN)
+ Rereg3Hcall = 1;
+ else
+ goto ehca_rereg_mr_exit0;
+ }
+ }
+
+ if (Rereg3Hcall) {
+ struct ehca_mr save_mr;
+
+ /* first deregister old MR */
+ rc = hipz_h_free_resource_mr(shca->ipz_hca_handle, pfmr,
+ &e_mr->ipz_mr_handle);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_free_mr failed, rc=%lx e_mr=%p "
+ "hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
+ rc, e_mr, shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle,
+ e_mr->ib.ib_mr.lkey);
+ retcode = ehca_mrmw_map_rc_free_mr(rc);
+ goto ehca_rereg_mr_exit0;
+ }
+ /* clean ehca_mr_t, without changing struct ib_mr and lock */
+ save_mr = *e_mr;
+ ehca_mr_deletenew(e_mr);
+
+ /* set some MR values */
+ e_mr->flags = save_mr.flags;
+ e_mr->fmr_page_size = save_mr.fmr_page_size;
+ e_mr->fmr_max_pages = save_mr.fmr_max_pages;
+ e_mr->fmr_max_maps = save_mr.fmr_max_maps;
+ e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
+
+ retcode = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
+ e_pd, pginfo, lkey, rkey);
+ if (retcode != 0) {
+ u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
+ memcpy(&e_mr->flags, &(save_mr.flags),
+ sizeof(struct ehca_mr) - offset);
+ goto ehca_rereg_mr_exit0;
+ }
+ }
+
+ehca_rereg_mr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x shca=%p e_mr=%p iova_start=%p size=%lx "
+ "acl=%x e_pd=%p pginfo=%p num_pages=%lx lkey=%x "
+ "rkey=%x Rereg1Hcall=%x Rereg3Hcall=%x",
+ retcode, shca, e_mr, iova_start, size, acl, e_pd,
+ pginfo, pginfo->num_pages, *lkey, *rkey, Rereg1Hcall,
+ Rereg3Hcall);
+ else
+ EDEB_EX(7, "retcode=%x shca=%p e_mr=%p iova_start=%p size=%lx "
+ "acl=%x e_pd=%p pginfo=%p num_pages=%lx lkey=%x "
+ "rkey=%x Rereg1Hcall=%x Rereg3Hcall=%x",
+ retcode, shca, e_mr, iova_start, size, acl, e_pd,
+ pginfo, pginfo->num_pages, *lkey, *rkey, Rereg1Hcall,
+ Rereg3Hcall);
+
+ return (retcode);
+} /* end ehca_rereg_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_unmap_one_fmr(struct ehca_shca *shca,
+ struct ehca_mr *e_fmr)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_pfmr *pfmr = &e_fmr->pf;
+ int Rereg1Hcall = 1; /* 1: use hipz_mr_reregister directly */
+ int Rereg3Hcall = 0; /* 1: use 3 hipz calls for unmapping */
+ struct ehca_pd *e_pd = NULL;
+ struct ehca_mr save_fmr;
+ u32 tmp_lkey = 0;
+ u32 tmp_rkey = 0;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+
+ EDEB_EN(7, "shca=%p e_fmr=%p", shca, e_fmr);
+
+ /* first check if reregistration hCall can be used for unmap */
+ if (e_fmr->fmr_max_pages > 512) {
+ Rereg1Hcall = 0;
+ Rereg3Hcall = 1;
+ }
+
+ e_pd = container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
+
+ if (Rereg1Hcall) {
+ /* note: after using rereg hcall with len=0, */
+ /* rereg hcall must be used again for registering pages */
+ u64 start_out = 0;
+ rc = hipz_h_reregister_pmr(shca->ipz_hca_handle, pfmr,
+ &shca->pf, &e_fmr->ipz_mr_handle, 0,
+ 0, 0, e_pd->fw_pd, 0, &start_out,
+ &tmp_lkey, &tmp_rkey);
+ if (rc != H_SUCCESS) {
+ /* should not happen, because length checked above, */
+ /* FMRs are not shared and no MW bound to FMRs */
+ EDEB_ERR(4, "hipz_reregister_pmr failed (Rereg1), "
+ "rc=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+ "lkey=%x", rc, e_fmr,
+ shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey);
+ Rereg3Hcall = 1;
+ } else {
+ /* successful reregistration */
+ e_fmr->start = NULL;
+ e_fmr->size = 0;
+ }
+ }
+
+ if (Rereg3Hcall) {
+ struct ehca_mr save_mr;
+
+ /* first free old FMR */
+ rc = hipz_h_free_resource_mr(shca->ipz_hca_handle, pfmr,
+ &e_fmr->ipz_mr_handle);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_free_mr failed, rc=%lx e_fmr=%p "
+ "hca_hndl=%lx mr_hndl=%lx lkey=%x", rc, e_fmr,
+ shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey);
+ retcode = ehca_mrmw_map_rc_free_mr(rc);
+ goto ehca_unmap_one_fmr_exit0;
+ }
+ /* clean ehca_mr_t, without changing lock */
+ save_fmr = *e_fmr;
+ ehca_mr_deletenew(e_fmr);
+
+ /* set some MR values */
+ e_fmr->flags = save_fmr.flags;
+ e_fmr->fmr_page_size = save_fmr.fmr_page_size;
+ e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
+ e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
+ e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
+ e_fmr->acl = save_fmr.acl;
+
+ pginfo.type = EHCA_MR_PGI_FMR;
+ pginfo.num_pages = 0;
+ pginfo.num_4k = 0;
+ retcode = ehca_reg_mr(shca, e_fmr, NULL,
+ (e_fmr->fmr_max_pages *
+ e_fmr->fmr_page_size),
+ e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
+ &tmp_rkey);
+ if (retcode != 0) {
+ u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
+ memcpy(&e_fmr->flags, &(save_mr.flags),
+ sizeof(struct ehca_mr) - offset);
+ goto ehca_unmap_one_fmr_exit0;
+ }
+ }
+
+ehca_unmap_one_fmr_exit0:
+ EDEB_EX(7, "retcode=%x tmp_lkey=%x tmp_rkey=%x fmr_max_pages=%x "
+ "Rereg1Hcall=%x Rereg3Hcall=%x", retcode, tmp_lkey, tmp_rkey,
+ e_fmr->fmr_max_pages, Rereg1Hcall, Rereg3Hcall);
+ return (retcode);
+} /* end ehca_unmap_one_fmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_smr(struct ehca_shca *shca,
+ struct ehca_mr *e_origmr,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey, /*OUT*/
+ u32 *rkey) /*OUT*/
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_pfmr *pfmr = &e_newmr->pf;
+ u32 hipz_acl = 0;
+
+ EDEB_EN(7,"shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x e_pd=%p",
+ shca, e_origmr, e_newmr, iova_start, acl, e_pd);
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+
+ rc = hipz_h_register_smr(shca->ipz_hca_handle, pfmr, &e_origmr->pf,
+ &shca->pf, &e_origmr->ipz_mr_handle,
+ (u64)iova_start, hipz_acl, e_pd->fw_pd,
+ &e_newmr->ipz_mr_handle, lkey, rkey);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_reg_smr failed, rc=%lx shca=%p e_origmr=%p "
+ "e_newmr=%p iova_start=%p acl=%x e_pd=%p hca_hndl=%lx "
+ "mr_hndl=%lx lkey=%x", rc, shca, e_origmr, e_newmr,
+ iova_start, acl, e_pd, shca->ipz_hca_handle.handle,
+ e_origmr->ipz_mr_handle.handle,
+ e_origmr->ib.ib_mr.lkey);
+ retcode = ehca_mrmw_map_rc_reg_smr(rc);
+ goto ehca_reg_smr_exit0;
+ }
+ /* successful registration */
+ e_newmr->num_pages = e_origmr->num_pages;
+ e_newmr->num_4k = e_origmr->num_4k;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
+ goto ehca_reg_smr_exit0;
+
+ehca_reg_smr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x shca=%p e_origmr=%p e_newmr=%p "
+ "iova_start=%p acl=%x e_pd=%p", retcode,
+ shca, e_origmr, e_newmr, iova_start, acl, e_pd);
+ else
+ EDEB_EX(7, "retcode=%x lkey=%x rkey=%x",
+ retcode, *lkey, *rkey);
+ return (retcode);
+} /* end ehca_reg_smr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* register internal max-MR to internal SHCA */
+int ehca_reg_internal_maxmr(
+ struct ehca_shca *shca,
+ struct ehca_pd *e_pd,
+ struct ehca_mr **e_maxmr) /*OUT*/
+{
+ int retcode = 0;
+ struct ehca_mr *e_mr = NULL;
+ u64 *iova_start = NULL;
+ u64 size_maxmr = 0;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ib_phys_buf ib_pbuf;
+ u32 num_pages_mr = 0;
+ u32 num_pages_4k = 0; /* 4k portion "pages" */
+
+ EDEB_EN(7, "shca=%p e_pd=%p e_maxmr=%p", shca, e_pd, e_maxmr);
+
+ if (ehca_adr_bad(shca) || ehca_adr_bad(e_pd) || ehca_adr_bad(e_maxmr)) {
+ EDEB_ERR(4, "bad input values: shca=%p e_pd=%p e_maxmr=%p",
+ shca, e_pd, e_maxmr);
+ retcode = -EINVAL;
+ goto ehca_reg_internal_maxmr_exit0;
+ }
+
+ e_mr = ehca_mr_new();
+ if (!e_mr) {
+ EDEB_ERR(4, "out of memory");
+ retcode = -ENOMEM;
+ goto ehca_reg_internal_maxmr_exit0;
+ }
+ e_mr->flags |= EHCA_MR_FLAG_MAXMR;
+
+ /* register internal max-MR on HCA */
+ size_maxmr = (u64)high_memory - PAGE_OFFSET;
+ EDEB(9, "high_memory=%p PAGE_OFFSET=%lx", high_memory, PAGE_OFFSET);
+ iova_start = (u64 *)KERNELBASE;
+ ib_pbuf.addr = 0;
+ ib_pbuf.size = size_maxmr;
+ num_pages_mr = ( (((u64)iova_start % PAGE_SIZE) + size_maxmr +
+ PAGE_SIZE - 1) / PAGE_SIZE);
+ num_pages_4k = ( (((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE );
+
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.num_phys_buf = 1;
+ pginfo.phys_buf_array = &ib_pbuf;
+
+ retcode = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
+ &pginfo, &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (retcode != 0) {
+ EDEB_ERR(4, "reg of internal max MR failed, e_mr=%p "
+ "iova_start=%p size_maxmr=%lx num_pages_mr=%x "
+ "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
+ num_pages_mr, num_pages_4k);
+ goto ehca_reg_internal_maxmr_exit1;
+ }
+
+ /* successful registration of all pages */
+ e_mr->ib.ib_mr.device = e_pd->ib_pd.device;
+ e_mr->ib.ib_mr.pd = &e_pd->ib_pd;
+ e_mr->ib.ib_mr.uobject = NULL;
+ atomic_inc(&(e_pd->ib_pd.usecnt));
+ atomic_set(&(e_mr->ib.ib_mr.usecnt), 0);
+ *e_maxmr = e_mr;
+ goto ehca_reg_internal_maxmr_exit0;
+
+ehca_reg_internal_maxmr_exit1:
+ ehca_mr_delete(e_mr);
+ehca_reg_internal_maxmr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x shca=%p e_pd=%p e_maxmr=%p",
+ retcode, shca, e_pd, e_maxmr);
+ else
+ EDEB_EX(7, "*e_maxmr=%p lkey=%x rkey=%x",
+ *e_maxmr, (*e_maxmr)->ib.ib_mr.lkey,
+ (*e_maxmr)->ib.ib_mr.rkey);
+ return (retcode);
+} /* end ehca_reg_internal_maxmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_maxmr(struct ehca_shca *shca,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey,
+ u32 *rkey)
+{
+ int retcode = 0;
+ u64 rc = H_SUCCESS;
+ struct ehca_pfmr *pfmr = &e_newmr->pf;
+ struct ehca_mr *e_origmr = shca->maxmr;
+ u32 hipz_acl = 0;
+
+ EDEB_EN(7,"shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x e_pd=%p",
+ shca, e_origmr, e_newmr, iova_start, acl, e_pd);
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+
+ rc = hipz_h_register_smr(shca->ipz_hca_handle, pfmr, &e_origmr->pf,
+ &shca->pf, &e_origmr->ipz_mr_handle,
+ (u64)iova_start, hipz_acl, e_pd->fw_pd,
+ &e_newmr->ipz_mr_handle, lkey, rkey);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_reg_smr failed, rc=%lx e_origmr=%p "
+ "hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ rc, e_origmr, shca->ipz_hca_handle.handle,
+ e_origmr->ipz_mr_handle.handle,
+ e_origmr->ib.ib_mr.lkey);
+ retcode = ehca_mrmw_map_rc_reg_smr(rc);
+ goto ehca_reg_maxmr_exit0;
+ }
+ /* successful registration */
+ e_newmr->num_pages = e_origmr->num_pages;
+ e_newmr->num_4k = e_origmr->num_4k;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
+
+ehca_reg_maxmr_exit0:
+ EDEB_EX(7, "retcode=%x lkey=%x rkey=%x", retcode, *lkey, *rkey);
+ return (retcode);
+} /* end ehca_reg_maxmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
+{
+ int retcode = 0;
+ struct ehca_mr *e_maxmr = NULL;
+ struct ib_pd *ib_pd = NULL;
+
+ EDEB_EN(7, "shca=%p shca->maxmr=%p", shca, shca->maxmr);
+
+ if (shca->maxmr == 0) {
+ EDEB_ERR(4, "bad call, shca=%p", shca);
+ retcode = -EINVAL;
+ goto ehca_dereg_internal_maxmr_exit0;
+ }
+
+ e_maxmr = shca->maxmr;
+ ib_pd = e_maxmr->ib.ib_mr.pd;
+ shca->maxmr = NULL; /* remove internal max-MR indication from SHCA */
+
+ retcode = ehca_dereg_mr(&e_maxmr->ib.ib_mr);
+ if (retcode != 0) {
+ EDEB_ERR(3, "dereg internal max-MR failed, "
+ "retcode=%x e_maxmr=%p shca=%p lkey=%x",
+ retcode, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey);
+ shca->maxmr = e_maxmr;
+ goto ehca_dereg_internal_maxmr_exit0;
+ }
+
+ atomic_dec(&ib_pd->usecnt);
+
+ehca_dereg_internal_maxmr_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x shca=%p shca->maxmr=%p",
+ retcode, shca, shca->maxmr);
+ else
+ EDEB_EX(7, "");
+ return (retcode);
+} /* end ehca_dereg_internal_maxmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* check physical buffer array of MR verbs for validness and
+ * calculates MR size
+ */
+int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ u64 *iova_start,
+ u64 *size)
+{
+ struct ib_phys_buf *pbuf = phys_buf_array;
+ u64 size_count = 0;
+ u32 i;
+
+ if (num_phys_buf == 0) {
+ EDEB_ERR(4, "bad phys buf array len, num_phys_buf=0");
+ return (-EINVAL);
+ }
+ /* check first buffer */
+ if (((u64)iova_start & ~PAGE_MASK) != (pbuf->addr & ~PAGE_MASK)) {
+ EDEB_ERR(4, "iova_start/addr mismatch, iova_start=%p "
+ "pbuf->addr=%lx pbuf->size=%lx",
+ iova_start, pbuf->addr, pbuf->size);
+ return (-EINVAL);
+ }
+ if (((pbuf->addr + pbuf->size) % PAGE_SIZE) &&
+ (num_phys_buf > 1)) {
+ EDEB_ERR(4, "addr/size mismatch in 1st buf, pbuf->addr=%lx "
+ "pbuf->size=%lx", pbuf->addr, pbuf->size);
+ return (-EINVAL);
+ }
+
+ for (i = 0; i < num_phys_buf; i++) {
+ if ((i > 0) && (pbuf->addr % PAGE_SIZE)) {
+ EDEB_ERR(4, "bad address, i=%x pbuf->addr=%lx "
+ "pbuf->size=%lx", i, pbuf->addr, pbuf->size);
+ return (-EINVAL);
+ }
+ if (((i > 0) && /* not 1st */
+ (i < (num_phys_buf - 1)) && /* not last */
+ (pbuf->size % PAGE_SIZE)) || (pbuf->size == 0)) {
+ EDEB_ERR(4, "bad size, i=%x pbuf->size=%lx",
+ i, pbuf->size);
+ return (-EINVAL);
+ }
+ size_count += pbuf->size;
+ pbuf++;
+ }
+
+ *size = size_count;
+ return (0);
+} /* end ehca_mr_chk_buf_and_calc_size() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* check page list of map FMR verb for validness */
+int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
+ u64 *page_list,
+ int list_len)
+{
+ u32 i;
+ u64 *page = NULL;
+
+ if (ehca_adr_bad(page_list)) {
+ EDEB_ERR(4, "bad page_list, page_list=%p fmr=%p",
+ page_list, e_fmr);
+ return (-EINVAL);
+ }
+
+ if ((list_len == 0) || (list_len > e_fmr->fmr_max_pages)) {
+ EDEB_ERR(4, "bad list_len, list_len=%x e_fmr->fmr_max_pages=%x "
+ "fmr=%p", list_len, e_fmr->fmr_max_pages, e_fmr);
+ return (-EINVAL);
+ }
+
+ /* each page must be aligned */
+ page = page_list;
+ for (i = 0; i < list_len; i++) {
+ if (*page % e_fmr->fmr_page_size) {
+ EDEB_ERR(4, "bad page, i=%x *page=%lx page=%p "
+ "fmr=%p fmr_page_size=%x",
+ i, *page, page, e_fmr, e_fmr->fmr_page_size);
+ return (-EINVAL);
+ }
+ page++;
+ }
+
+ return (0);
+} /* end ehca_fmr_check_page_list() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* setup page buffer from page info */
+int ehca_set_pagebuf(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int retcode = 0;
+ struct ib_umem_chunk *prev_chunk = NULL;
+ struct ib_umem_chunk *chunk = NULL;
+ struct ib_phys_buf *pbuf = NULL;
+ u64 *fmrlist = NULL;
+ u64 num4k = 0;
+ u64 pgaddr = 0;
+ u64 offs4k = 0;
+ u32 i = 0;
+ u32 j = 0;
+
+ EDEB_EN(7, "pginfo=%p type=%x num_pages=%lx num_4k=%lx next_buf=%lx "
+ "next_4k=%lx number=%x kpage=%p page_cnt=%lx page_4k_cnt=%lx "
+ "next_listelem=%lx region=%p next_chunk=%p next_nmap=%lx",
+ pginfo, pginfo->type, pginfo->num_pages, pginfo->num_4k,
+ pginfo->next_buf, pginfo->next_4k, number, kpage,
+ pginfo->page_cnt, pginfo->page_4k_cnt, pginfo->next_listelem,
+ pginfo->region, pginfo->next_chunk, pginfo->next_nmap);
+
+ if (pginfo->type == EHCA_MR_PGI_PHYS) {
+ /* loop over desired phys_buf_array entries */
+ while (i < number) {
+ pbuf = pginfo->phys_buf_array + pginfo->next_buf;
+ num4k = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
+ offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
+ while (pginfo->next_4k < offs4k + num4k) {
+ /* sanity check */
+ if ((pginfo->page_cnt >= pginfo->num_pages) ||
+ (pginfo->page_4k_cnt >= pginfo->num_4k)) {
+ EDEB_ERR(4, "page_cnt >= num_pages, "
+ "page_cnt=%lx num_pages=%lx "
+ "page_4k_cnt=%lx num_4k=%lx "
+ "i=%x", pginfo->page_cnt,
+ pginfo->num_pages,
+ pginfo->page_4k_cnt,
+ pginfo->num_4k, i);
+ retcode = -EFAULT;
+ }
+ *kpage = phys_to_abs(
+ (pbuf->addr & (EHCA_PAGESIZE-1))
+ + (pginfo->next_4k * EHCA_PAGESIZE));
+ if ((*kpage == 0) && (pbuf->addr != 0)) {
+ EDEB_ERR(4, "pbuf->addr=%lx "
+ "pbuf->size=%lx next_4k=%lx",
+ pbuf->addr, pbuf->size,
+ pginfo->next_4k);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if(pginfo->next_4k >= PAGE_SIZE/EHCA_PAGESIZE)
+ (pginfo->page_cnt)++;
+ kpage++;
+ i++;
+ if (i >= number) break;
+ }
+ if (pginfo->next_4k >= offs4k + num4k) {
+ (pginfo->next_buf)++;
+ pginfo->next_4k = 0;
+ }
+ }
+ } else if (pginfo->type == EHCA_MR_PGI_USER) {
+ /* loop over desired chunk entries */
+ chunk = pginfo->next_chunk;
+ prev_chunk = pginfo->next_chunk;
+ list_for_each_entry_continue(chunk,
+ (&(pginfo->region->chunk_list)),
+ list) {
+ EDEB(9, "chunk->page_list[0]=%lx",
+ (u64)sg_dma_address(&chunk->page_list[0]));
+ for (i = pginfo->next_nmap; i < chunk->nmap; ) {
+ pgaddr = ( page_to_pfn(chunk->page_list[i].page)
+ << PAGE_SHIFT );
+ *kpage = phys_to_abs(pgaddr +
+ (pginfo->next_4k *
+ EHCA_PAGESIZE));
+ EDEB(9,"pgaddr=%lx *kpage=%lx next_4k=%lx",
+ pgaddr, *kpage, pginfo->next_4k);
+ if (*kpage == 0) {
+ EDEB_ERR(4, "pgaddr=%lx "
+ "chunk->page_list[i]=%lx i=%x "
+ "next_4k=%lx mr=%p", pgaddr,
+ (u64)sg_dma_address(
+ &chunk->page_list[i]),
+ i, pginfo->next_4k, e_mr);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ kpage++;
+ if (pginfo->next_4k >= PAGE_SIZE/EHCA_PAGESIZE) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_nmap)++;
+ pginfo->next_4k = 0;
+ i++;
+ }
+ j++;
+ if (j >= number) break;
+ }
+ if ( (pginfo->next_nmap >= chunk->nmap) &&
+ (j >= number) ) {
+ pginfo->next_nmap = 0;
+ prev_chunk = chunk;
+ break;
+ } else if (pginfo->next_nmap >= chunk->nmap) {
+ pginfo->next_nmap = 0;
+ prev_chunk = chunk;
+ } else if (j >= number)
+ break;
+ else
+ prev_chunk = chunk;
+ }
+ pginfo->next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->region->chunk_list)),
+ list);
+ } else if (pginfo->type == EHCA_MR_PGI_FMR) {
+ /* loop over desired page_list entries */
+ fmrlist = pginfo->page_list + pginfo->next_listelem;
+ for (i = 0; i < number; i++) {
+ *kpage = phys_to_abs((*fmrlist & (EHCA_PAGESIZE-1)) +
+ pginfo->next_4k * EHCA_PAGESIZE);
+ if (*kpage == 0) {
+ EDEB_ERR(4, "*fmrlist=%lx fmrlist=%p "
+ "next_listelem=%lx next_4k=%lx",
+ *fmrlist, fmrlist,
+ pginfo->next_listelem,pginfo->next_4k);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ kpage++;
+ if ( pginfo->next_4k >=
+ ((e_mr->fmr_page_size) / EHCA_PAGESIZE) ) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_listelem)++;
+ fmrlist++;
+ pginfo->next_4k = 0;
+ }
+ }
+ } else {
+ EDEB_ERR(4, "bad pginfo->type=%x", pginfo->type);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+
+ehca_set_pagebuf_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
+ "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
+ "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
+ "next_listelem=%lx region=%p next_chunk=%p "
+ "next_nmap=%lx", retcode, e_mr, pginfo, pginfo->type,
+ pginfo->num_pages, pginfo->num_4k, pginfo->next_buf,
+ pginfo->next_4k, number, kpage, pginfo->page_cnt,
+ pginfo->page_4k_cnt, i, pginfo->next_listelem,
+ pginfo->region, pginfo->next_chunk, pginfo->next_nmap);
+ else
+ EDEB_EX(7, "retcode=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
+ "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
+ "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
+ "next_listelem=%lx region=%p next_chunk=%p "
+ "next_nmap=%lx", retcode, e_mr, pginfo, pginfo->type,
+ pginfo->num_pages, pginfo->num_4k, pginfo->next_buf,
+ pginfo->next_4k, number, kpage, pginfo->page_cnt,
+ pginfo->page_4k_cnt, i, pginfo->next_listelem,
+ pginfo->region, pginfo->next_chunk, pginfo->next_nmap);
+ return (retcode);
+} /* end ehca_set_pagebuf() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* setup 1 page from page info page buffer */
+int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u64 *rpage)
+{
+ int retcode = 0;
+ struct ib_phys_buf *tmp_pbuf = NULL;
+ u64 *fmrlist = NULL;
+ struct ib_umem_chunk *chunk = NULL;
+ struct ib_umem_chunk *prev_chunk = NULL;
+ u64 pgaddr = 0;
+ u64 num4k = 0;
+ u64 offs4k = 0;
+
+ EDEB_EN(7, "pginfo=%p type=%x num_pages=%lx num_4k=%lx next_buf=%lx "
+ "next_4k=%lx rpage=%p page_cnt=%lx page_4k_cnt=%lx "
+ "next_listelem=%lx region=%p next_chunk=%p next_nmap=%lx",
+ pginfo, pginfo->type, pginfo->num_pages, pginfo->num_4k,
+ pginfo->next_buf, pginfo->next_4k, rpage, pginfo->page_cnt,
+ pginfo->page_4k_cnt, pginfo->next_listelem, pginfo->region,
+ pginfo->next_chunk, pginfo->next_nmap);
+
+ if (pginfo->type == EHCA_MR_PGI_PHYS) {
+ /* sanity check */
+ if ((pginfo->page_cnt >= pginfo->num_pages) ||
+ (pginfo->page_4k_cnt >= pginfo->num_4k)) {
+ EDEB_ERR(4, "page_cnt >= num_pages, page_cnt=%lx "
+ "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
+ pginfo->page_cnt, pginfo->num_pages,
+ pginfo->page_4k_cnt, pginfo->num_4k);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
+ num4k = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
+ offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
+ *rpage = phys_to_abs((tmp_pbuf->addr & (EHCA_PAGESIZE-1)) +
+ (pginfo->next_4k * EHCA_PAGESIZE));
+ if ((*rpage == 0) && (tmp_pbuf->addr != 0)) {
+ EDEB_ERR(4, "tmp_pbuf->addr=%lx"
+ " tmp_pbuf->size=%lx next_4k=%lx",
+ tmp_pbuf->addr, tmp_pbuf->size,
+ pginfo->next_4k);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if(pginfo->next_4k >= PAGE_SIZE/EHCA_PAGESIZE)
+ (pginfo->page_cnt)++;
+ if (pginfo->next_4k >= offs4k + num4k) {
+ (pginfo->next_buf)++;
+ pginfo->next_4k = 0;
+ }
+ } else if (pginfo->type == EHCA_MR_PGI_USER) {
+ chunk = pginfo->next_chunk;
+ prev_chunk = pginfo->next_chunk;
+ list_for_each_entry_continue(chunk,
+ (&(pginfo->region->chunk_list)),
+ list) {
+ pgaddr = ( page_to_pfn(chunk->page_list[
+ pginfo->next_nmap].page)
+ << PAGE_SHIFT);
+ *rpage = phys_to_abs(pgaddr +
+ (pginfo->next_4k * EHCA_PAGESIZE));
+ EDEB(9,"pgaddr=%lx *rpage=%lx next_4k=%lx", pgaddr,
+ *rpage, pginfo->next_4k);
+ if (*rpage == 0) {
+ EDEB_ERR(4, "pgaddr=%lx chunk->page_list[]=%lx "
+ "next_nmap=%lx next_4k=%lx mr=%p",
+ pgaddr, (u64)sg_dma_address(
+ &chunk->page_list[
+ pginfo->next_nmap]),
+ pginfo->next_nmap, pginfo->next_4k,
+ e_mr);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if (pginfo->next_4k >= PAGE_SIZE/EHCA_PAGESIZE) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_nmap)++;
+ pginfo->next_4k = 0;
+ }
+ if (pginfo->next_nmap >= chunk->nmap) {
+ pginfo->next_nmap = 0;
+ prev_chunk = chunk;
+ }
+ break;
+ }
+ pginfo->next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->region->chunk_list)),
+ list);
+ } else if (pginfo->type == EHCA_MR_PGI_FMR) {
+ fmrlist = pginfo->page_list + pginfo->next_listelem;
+ *rpage = phys_to_abs((*fmrlist & (EHCA_PAGESIZE-1)) +
+ pginfo->next_4k * EHCA_PAGESIZE);
+ if (*rpage == 0) {
+ EDEB_ERR(4, "*fmrlist=%lx fmrlist=%p next_listelem=%lx "
+ "next_4k=%lx", *fmrlist, fmrlist,
+ pginfo->next_listelem, pginfo->next_4k);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if (pginfo->next_4k >= (e_mr->fmr_page_size)/EHCA_PAGESIZE) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_listelem)++;
+ pginfo->next_4k = 0;
+ }
+ } else {
+ EDEB_ERR(4, "bad pginfo->type=%x", pginfo->type);
+ retcode = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+
+ehca_set_pagebuf_1_exit0:
+ if (retcode)
+ EDEB_EX(4, "retcode=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
+ "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
+ "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
+ "region=%p next_chunk=%p next_nmap=%lx", retcode, e_mr,
+ pginfo, pginfo->type, pginfo->num_pages, pginfo->num_4k,
+ pginfo->next_buf, pginfo->next_4k, rpage,
+ pginfo->page_cnt, pginfo->page_4k_cnt,
+ pginfo->next_listelem, pginfo->region,
+ pginfo->next_chunk, pginfo->next_nmap);
+ else
+ EDEB_EX(7, "retcode=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
+ "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
+ "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
+ "region=%p next_chunk=%p next_nmap=%lx", retcode, e_mr,
+ pginfo, pginfo->type, pginfo->num_pages, pginfo->num_4k,
+ pginfo->next_buf, pginfo->next_4k, rpage,
+ pginfo->page_cnt, pginfo->page_4k_cnt,
+ pginfo->next_listelem, pginfo->region,
+ pginfo->next_chunk, pginfo->next_nmap);
+ return (retcode);
+} /* end ehca_set_pagebuf_1() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* check MR if it is a max-MR, i.e. uses whole memory
+ * in case it's a max-MR 1 is returned, else 0
+ */
+int ehca_mr_is_maxmr(u64 size,
+ u64 *iova_start)
+{
+ /* a MR is treated as max-MR only if it fits following: */
+ if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
+ (iova_start == (void*)KERNELBASE)) {
+ EDEB(6, "this is a max-MR");
+ return (1);
+ } else
+ return (0);
+} /* end ehca_mr_is_maxmr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+/* map access control for MR/MW. This routine is used for MR and MW. */
+void ehca_mrmw_map_acl(int ib_acl,
+ u32 *hipz_acl)
+{
+ *hipz_acl = 0;
+ if (ib_acl & IB_ACCESS_REMOTE_READ)
+ *hipz_acl |= HIPZ_ACCESSCTRL_R_READ;
+ if (ib_acl & IB_ACCESS_REMOTE_WRITE)
+ *hipz_acl |= HIPZ_ACCESSCTRL_R_WRITE;
+ if (ib_acl & IB_ACCESS_REMOTE_ATOMIC)
+ *hipz_acl |= HIPZ_ACCESSCTRL_R_ATOMIC;
+ if (ib_acl & IB_ACCESS_LOCAL_WRITE)
+ *hipz_acl |= HIPZ_ACCESSCTRL_L_WRITE;
+ if (ib_acl & IB_ACCESS_MW_BIND)
+ *hipz_acl |= HIPZ_ACCESSCTRL_MW_BIND;
+} /* end ehca_mrmw_map_acl() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* sets page size in hipz access control for MR/MW. */
+void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl) /*INOUT*/
+{
+ return; /* HCA supports only 4k */
+} /* end ehca_mrmw_set_pgsize_hipz_acl() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* reverse map access control for MR/MW.
+ * This routine is used for MR and MW.
+ */
+void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
+ int *ib_acl) /*OUT*/
+{
+ *ib_acl = 0;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_R_READ)
+ *ib_acl |= IB_ACCESS_REMOTE_READ;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_R_WRITE)
+ *ib_acl |= IB_ACCESS_REMOTE_WRITE;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_R_ATOMIC)
+ *ib_acl |= IB_ACCESS_REMOTE_ATOMIC;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_L_WRITE)
+ *ib_acl |= IB_ACCESS_LOCAL_WRITE;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_MW_BIND)
+ *ib_acl |= IB_ACCESS_MW_BIND;
+} /* end ehca_mrmw_reverse_map_acl() */
+
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for MR/MW allocations
+ * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
+ */
+int ehca_mrmw_map_rc_alloc(const u64 rc)
+{
+ switch (rc) {
+ case H_SUCCESS: /* successful completion */
+ return (0);
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RT_PARM: /* invalid resource type */
+ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+ case H_MLENGTH_PARM: /* invalid memory length */
+ case H_MEM_ACCESS_PARM: /* invalid access controls */
+ case H_CONSTRAINED: /* resource constraint */
+ return (-EINVAL);
+ case H_BUSY: /* long busy */
+ return (-EBUSY);
+ default:
+ return (-EINVAL);
+ }
+} /* end ehca_mrmw_map_rc_alloc() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for MR register rpage
+ * Used for hipz_h_register_rpage_mr at registering last page
+ */
+int ehca_mrmw_map_rc_rrpg_last(const u64 rc)
+{
+ switch (rc) {
+ case H_SUCCESS: /* registration complete */
+ return (0);
+ case H_PAGE_REGISTERED: /* page registered */
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+/* case H_QT_PARM: invalid queue type */
+ case H_PARAMETER: /* invalid logical address, */
+ /* or count zero or greater 512 */
+ case H_TABLE_FULL: /* page table full */
+ case H_HARDWARE: /* HCA not operational */
+ return (-EINVAL);
+ case H_BUSY: /* long busy */
+ return (-EBUSY);
+ default:
+ return (-EINVAL);
+ }
+} /* end ehca_mrmw_map_rc_rrpg_last() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for MR register rpage
+ * Used for hipz_h_register_rpage_mr at registering one page, but not last page
+ */
+int ehca_mrmw_map_rc_rrpg_notlast(const u64 rc)
+{
+ switch (rc) {
+ case H_PAGE_REGISTERED: /* page registered */
+ return (0);
+ case H_SUCCESS: /* registration complete */
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+/* case H_QT_PARM: invalid queue type */
+ case H_PARAMETER: /* invalid logical address, */
+ /* or count zero or greater 512 */
+ case H_TABLE_FULL: /* page table full */
+ case H_HARDWARE: /* HCA not operational */
+ return (-EINVAL);
+ case H_BUSY: /* long busy */
+ return (-EBUSY);
+ default:
+ return (-EINVAL);
+ }
+} /* end ehca_mrmw_map_rc_rrpg_notlast() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
+int ehca_mrmw_map_rc_query_mr(const u64 rc)
+{
+ switch (rc) {
+ case H_SUCCESS: /* successful completion */
+ return (0);
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ return (-EINVAL);
+ case H_BUSY: /* long busy */
+ return (-EBUSY);
+ default:
+ return (-EINVAL);
+ }
+} /* end ehca_mrmw_map_rc_query_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for freeing MR resource
+ * Used for hipz_h_free_resource_mr
+ */
+int ehca_mrmw_map_rc_free_mr(const u64 rc)
+{
+ switch (rc) {
+ case H_SUCCESS: /* resource freed */
+ return (0);
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ case H_R_STATE: /* invalid resource state */
+ case H_HARDWARE: /* HCA not operational */
+ return (-EINVAL);
+ case H_RESOURCE: /* Resource in use */
+ case H_BUSY: /* long busy */
+ return (-EBUSY);
+ default:
+ return (-EINVAL);
+ }
+} /* end ehca_mrmw_map_rc_free_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for freeing MW resource
+ * Used for hipz_h_free_resource_mw
+ */
+int ehca_mrmw_map_rc_free_mw(const u64 rc)
+{
+ switch (rc) {
+ case H_SUCCESS: /* resource freed */
+ return (0);
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ case H_R_STATE: /* invalid resource state */
+ case H_HARDWARE: /* HCA not operational */
+ return (-EINVAL);
+ case H_RESOURCE: /* Resource in use */
+ case H_BUSY: /* long busy */
+ return (-EBUSY);
+ default:
+ return (-EINVAL);
+ }
+} /* end ehca_mrmw_map_rc_free_mw() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for SMR registrations
+ * Used for hipz_h_register_smr.
+ */
+int ehca_mrmw_map_rc_reg_smr(const u64 rc)
+{
+ switch (rc) {
+ case H_SUCCESS: /* successful completion */
+ return (0);
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ case H_MEM_PARM: /* invalid MR virtual address */
+ case H_MEM_ACCESS_PARM: /* invalid access controls */
+ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+ return (-EINVAL);
+ case H_BUSY: /* long busy */
+ return (-EBUSY);
+ default:
+ return (-EINVAL);
+ }
+} /* end ehca_mrmw_map_rc_reg_smr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/* MR destructor and constructor
+ * used in Reregister MR verb, memsets ehca_mr_t to 0,
+ * except struct ib_mr and spinlock
+ */
+void ehca_mr_deletenew(struct ehca_mr *mr)
+{
+ u32 offset = (u64)(&mr->flags) - (u64)mr;
+ memset(&mr->flags, 0, sizeof(*mr) - offset);
+} /* end ehca_mr_deletenew() */
^ permalink raw reply
* [PATCH 10/16] ehca: event queue
From: Heiko J Schick @ 2006-04-27 10:49 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_eq.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 225 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_eq.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_eq.c 2006-04-27 08:34:02.000000000 +0200
@@ -0,0 +1,225 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Event queue handling
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ *
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_eq.c,v 1.17 2006/04/27 06:34:02 schickhj Exp $
+ */
+
+#define DEB_PREFIX "e_eq"
+
+#include "ehca_classes.h"
+#include "ehca_irq.h"
+#include "ehca_iverbs.h"
+#include "ehca_kernel.h"
+#include "ehca_qes.h"
+#include "hcp_if.h"
+#include "ipz_pt_fn.h"
+
+int ehca_create_eq(struct ehca_shca *shca,
+ struct ehca_eq *eq,
+ const enum ehca_eq_type type, const u32 length)
+{
+ u64 ret = H_SUCCESS;
+ u32 nr_pages = 0;
+ u32 i;
+ void *vpage = NULL;
+
+ EDEB_EN(7, "shca=%p eq=%p length=%x", shca, eq, length);
+ EHCA_CHECK_ADR(shca);
+ EHCA_CHECK_ADR(eq);
+
+ spin_lock_init(&eq->spinlock);
+ eq->is_initialized = 0;
+
+ if (type!=EHCA_EQ && type!=EHCA_NEQ) {
+ EDEB_ERR(4, "Invalid EQ type %x. eq=%p", type, eq);
+ return -EINVAL;
+ }
+ if (length==0) {
+ EDEB_ERR(4, "EQ length must not be zero. eq=%p", eq);
+ return -EINVAL;
+ }
+
+ ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
+ &eq->pf,
+ type,
+ length,
+ &eq->ipz_eq_handle,
+ &eq->length,
+ &nr_pages, &eq->ist);
+
+ if (ret != H_SUCCESS) {
+ EDEB_ERR(4, "Can't allocate EQ / NEQ. eq=%p", eq);
+ return -EINVAL;
+ }
+
+ ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
+ if (!ret) {
+ EDEB_ERR(4, "Can't allocate EQ pages. eq=%p", eq);
+ goto create_eq_exit1;
+ }
+
+ for (i = 0; i < nr_pages; i++) {
+ u64 rpage;
+
+ if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+ ret = H_RESOURCE;
+ goto create_eq_exit2;
+ }
+
+ rpage = virt_to_abs(vpage);
+ ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
+ eq->ipz_eq_handle,
+ &eq->pf,
+ 0, 0, rpage, 1);
+
+ if (i == (nr_pages - 1)) {
+ /* last page */
+ vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+ if ((ret != H_SUCCESS) || (vpage != 0))
+ goto create_eq_exit2;
+ } else {
+ if ((ret != H_PAGE_REGISTERED) || (vpage == 0))
+ goto create_eq_exit2;
+ }
+ }
+
+ ipz_qeit_reset(&eq->ipz_queue);
+
+ /* register interrupt handlers and initialize work queues */
+ if (type == EHCA_EQ) {
+ ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_eq,
+ SA_INTERRUPT, "ehca_eq",
+ (void *)shca);
+ if (ret < 0)
+ EDEB_ERR(4, "Can't map interrupt handler.");
+
+ tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
+ } else if (type == EHCA_NEQ) {
+ ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_neq,
+ SA_INTERRUPT, "ehca_neq",
+ (void *)shca);
+ if (ret < 0)
+ EDEB_ERR(4, "Can't map interrupt handler.");
+
+ tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca);
+ }
+
+ eq->is_initialized = 1;
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return 0;
+
+create_eq_exit2:
+ ipz_queue_dtor(&eq->ipz_queue);
+
+create_eq_exit1:
+ hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return -EINVAL;
+}
+
+void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq)
+{
+ unsigned long flags = 0;
+ void *eqe = NULL;
+
+ EDEB_EN(7, "shca=%p eq=%p", shca, eq);
+ EHCA_CHECK_ADR_P(shca);
+ EHCA_CHECK_EQ_P(eq);
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+ eqe = ipz_eqit_eq_get_inc_valid(&eq->ipz_queue);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ EDEB_EX(7, "eq=%p eqe=%p", eq, eqe);
+
+ return eqe;
+}
+
+void ehca_poll_eqs(unsigned long data)
+{
+ struct ehca_shca *shca;
+ struct ehca_module *module = (struct ehca_module*)data;
+
+ spin_lock(&module->shca_lock);
+ list_for_each_entry(shca, &module->shca_list, shca_list) {
+ if (shca->eq.is_initialized)
+ ehca_tasklet_eq((unsigned long)(void*)shca);
+ }
+ mod_timer(&module->timer, jiffies + HZ);
+ spin_unlock(&module->shca_lock);
+
+ return;
+}
+
+int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
+{
+ unsigned long flags = 0;
+ u64 retcode = H_SUCCESS;
+
+ EDEB_EN(7, "shca=%p eq=%p", shca, eq);
+ EHCA_CHECK_ADR(shca);
+ EHCA_CHECK_EQ(eq);
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+ ibmebus_free_irq(NULL, eq->ist, (void *)shca);
+
+ retcode = hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
+
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ if (retcode != H_SUCCESS) {
+ EDEB_ERR(4, "Can't free EQ resources.");
+ return -EINVAL;
+ }
+ ipz_queue_dtor(&eq->ipz_queue);
+
+ EDEB_EX(7, "retcode=%lx", retcode);
+
+ return 0;
+}
^ permalink raw reply
* [PATCH 09/16] ehca: protection domain and address vector
From: Heiko J Schick @ 2006-04-27 10:49 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_av.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ehca_pd.c | 122 ++++++++++++++++++++++++
2 files changed, 431 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_av.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_av.c 2006-04-11 15:25:50.000000000 +0200
@@ -0,0 +1,309 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * adress vector functions
+ *
+ * Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Khadija Souissi <souissik@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_av.c,v 1.12 2006/04/11 13:25:50 nguyen Exp $
+ */
+
+
+#define DEB_PREFIX "ehav"
+
+#include <asm/current.h>
+
+#include "ehca_kernel.h"
+#include "ehca_tools.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+
+struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+ extern struct ehca_module ehca_module;
+ extern int ehca_static_rate;
+ int retcode = 0;
+ struct ehca_av *av = NULL;
+ struct ehca_shca *shca = NULL;
+
+ EHCA_CHECK_PD_P(pd);
+ EHCA_CHECK_ADR_P(ah_attr);
+
+ shca = container_of(pd->device, struct ehca_shca, ib_device);
+
+ EDEB_EN(7,"pd=%p ah_attr=%p", pd, ah_attr);
+
+ av = kmem_cache_alloc(ehca_module.cache_av, SLAB_KERNEL);
+ if (av == NULL) {
+ EDEB_ERR(4,"Out of memory pd=%p ah_attr=%p", pd, ah_attr);
+ retcode = -ENOMEM;
+ goto create_ah_exit0;
+ }
+
+ av->av.sl = ah_attr->sl;
+ av->av.dlid = ntohs(ah_attr->dlid);
+ av->av.slid_path_bits = ah_attr->src_path_bits;
+
+ if (ehca_static_rate < 0) {
+ int ah_mult = ib_rate_to_mult(ah_attr->static_rate);
+ int ehca_mult =
+ ib_rate_to_mult(shca->sport[ah_attr->port_num].rate );
+
+ if (ah_mult >= ehca_mult)
+ av->av.ipd = 0;
+ else
+ av->av.ipd = (ah_mult > 0) ?
+ ((ehca_mult - 1) / ah_mult) : 0;
+ } else
+ av->av.ipd = ehca_static_rate;
+
+ EDEB(7,"IPD av->av.ipd set =%x ah_attr->static_rate=%x "
+ "shca_ib_rate=%x ",av->av.ipd, ah_attr->static_rate,
+ shca->sport[ah_attr->port_num].rate);
+
+ av->av.lnh = ah_attr->ah_flags;
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_TCLASS_MASK,
+ ah_attr->grh.traffic_class);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
+ ah_attr->grh.flow_label);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
+ ah_attr->grh.hop_limit);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1B);
+ /* IB transport */
+ av->av.grh.word_0 = be64_to_cpu(av->av.grh.word_0);
+ /* set sgid in grh.word_1 */
+ if (ah_attr->ah_flags & IB_AH_GRH) {
+ int rc = 0;
+ struct ib_port_attr port_attr;
+ union ib_gid gid;
+ memset(&port_attr, 0, sizeof(port_attr));
+ rc = ehca_query_port(pd->device, ah_attr->port_num,
+ &port_attr);
+ if (rc != 0) { /* invalid port number */
+ retcode = -EINVAL;
+ EDEB_ERR(4, "Invalid port number "
+ "ehca_query_port() returned %x "
+ "pd=%p ah_attr=%p", rc, pd, ah_attr);
+ goto create_ah_exit1;
+ }
+ memset(&gid, 0, sizeof(gid));
+ rc = ehca_query_gid(pd->device,
+ ah_attr->port_num,
+ ah_attr->grh.sgid_index, &gid);
+ if (rc != 0) {
+ retcode = -EINVAL;
+ EDEB_ERR(4, "Failed to retrieve sgid "
+ "ehca_query_gid() returned %x "
+ "pd=%p ah_attr=%p", rc, pd, ah_attr);
+ goto create_ah_exit1;
+ }
+ memcpy(&av->av.grh.word_1, &gid, sizeof(gid));
+ }
+ /* for the time being we use a hard coded PMTU of 2048 Bytes */
+ av->av.pmtu = 4;
+
+ /* dgid comes in grh.word_3 */
+ memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid,
+ sizeof(ah_attr->grh.dgid));
+
+ EHCA_REGISTER_AV(device, pd);
+
+ EDEB_EX(7,"pd=%p ah_attr=%p av=%p", pd, ah_attr, av);
+ return (&av->ib_ah);
+
+create_ah_exit1:
+ kmem_cache_free(ehca_module.cache_av, av);
+
+create_ah_exit0:
+ EDEB_EX(7,"retcode=%x pd=%p ah_attr=%p", retcode, pd, ah_attr);
+ return ERR_PTR(retcode);
+}
+
+int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
+{
+ struct ehca_av *av = NULL;
+ struct ehca_ud_av new_ehca_av;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+ int ret = 0;
+
+ EHCA_CHECK_AV(ah);
+ EHCA_CHECK_ADR(ah_attr);
+
+ EDEB_EN(7,"ah=%p ah_attr=%p", ah, ah_attr);
+
+ my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject!=NULL && my_pd->ib_pd.uobject->context!=NULL &&
+ my_pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ memset(&new_ehca_av, 0, sizeof(new_ehca_av));
+ new_ehca_av.sl = ah_attr->sl;
+ new_ehca_av.dlid = ntohs(ah_attr->dlid);
+ new_ehca_av.slid_path_bits = ah_attr->src_path_bits;
+ new_ehca_av.ipd = ah_attr->static_rate;
+ new_ehca_av.lnh = EHCA_BMASK_SET(GRH_FLAG_MASK,
+ ((ah_attr->ah_flags & IB_AH_GRH) > 0));
+ new_ehca_av.grh.word_0 = EHCA_BMASK_SET(GRH_TCLASS_MASK,
+ ah_attr->grh.traffic_class);
+ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
+ ah_attr->grh.flow_label);
+ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
+ ah_attr->grh.hop_limit);
+ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1b);
+ new_ehca_av.grh.word_0 = be64_to_cpu(new_ehca_av.grh.word_0);
+
+ /* set sgid in grh.word_1 */
+ if (ah_attr->ah_flags & IB_AH_GRH) {
+ int rc = 0;
+ struct ib_port_attr port_attr;
+ union ib_gid gid;
+ memset(&port_attr, 0, sizeof(port_attr));
+ rc = ehca_query_port(ah->device, ah_attr->port_num,
+ &port_attr);
+ if (rc != 0) { /* invalid port number */
+ ret = -EINVAL;
+ EDEB_ERR(4, "Invalid port number "
+ "ehca_query_port() returned %x "
+ "ah=%p ah_attr=%p port_num=%x",
+ rc, ah, ah_attr, ah_attr->port_num);
+ goto modify_ah_exit1;
+ }
+ memset(&gid, 0, sizeof(gid));
+ rc = ehca_query_gid(ah->device,
+ ah_attr->port_num,
+ ah_attr->grh.sgid_index, &gid);
+ if (rc != 0) {
+ ret = -EINVAL;
+ EDEB_ERR(4,
+ "Failed to retrieve sgid "
+ "ehca_query_gid() returned %x "
+ "ah=%p ah_attr=%p port_num=%x "
+ "sgid_index=%x",
+ rc, ah, ah_attr, ah_attr->port_num,
+ ah_attr->grh.sgid_index);
+ goto modify_ah_exit1;
+ }
+ memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid));
+ }
+
+ new_ehca_av.pmtu = 4; /* see also comment in create_ah() */
+
+ memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid,
+ sizeof(ah_attr->grh.dgid));
+
+ av = container_of(ah, struct ehca_av, ib_ah);
+ av->av = new_ehca_av;
+
+modify_ah_exit1:
+ EDEB_EX(7,"ret=%x ah=%p ah_attr=%p", ret, ah, ah_attr);
+
+ return ret;
+}
+
+int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
+{
+ int ret = 0;
+ struct ehca_av *av = NULL;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+
+ EHCA_CHECK_AV(ah);
+ EHCA_CHECK_ADR(ah_attr);
+
+ EDEB_EN(7,"ah=%p ah_attr=%p", ah, ah_attr);
+
+ my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject!=NULL && my_pd->ib_pd.uobject->context!=NULL &&
+ my_pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ av = container_of(ah, struct ehca_av, ib_ah);
+ memcpy(&ah_attr->grh.dgid, &av->av.grh.word_3,
+ sizeof(ah_attr->grh.dgid));
+ ah_attr->sl = av->av.sl;
+
+ ah_attr->dlid = av->av.dlid;
+
+ ah_attr->src_path_bits = av->av.slid_path_bits;
+ ah_attr->static_rate = av->av.ipd;
+ ah_attr->ah_flags = EHCA_BMASK_GET(GRH_FLAG_MASK, av->av.lnh);
+ ah_attr->grh.traffic_class = EHCA_BMASK_GET(GRH_TCLASS_MASK,
+ av->av.grh.word_0);
+ ah_attr->grh.hop_limit = EHCA_BMASK_GET(GRH_HOPLIMIT_MASK,
+ av->av.grh.word_0);
+ ah_attr->grh.flow_label = EHCA_BMASK_GET(GRH_FLOWLABEL_MASK,
+ av->av.grh.word_0);
+
+ EDEB_EX(7,"ah=%p ah_attr=%p ret=%x", ah, ah_attr, ret);
+ return ret;
+}
+
+int ehca_destroy_ah(struct ib_ah *ah)
+{
+ extern struct ehca_module ehca_module;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+ int ret = 0;
+
+ EHCA_CHECK_AV(ah);
+ EHCA_DEREGISTER_AV(ah);
+
+ EDEB_EN(7,"ah=%p", ah);
+
+ my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject!=NULL && my_pd->ib_pd.uobject->context!=NULL &&
+ my_pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ kmem_cache_free(ehca_module.cache_av,
+ container_of(ah, struct ehca_av, ib_ah));
+
+ EDEB_EX(7,"ret=%x ah=%p", ret, ah);
+ return ret;
+}
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_pd.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_pd.c 2006-03-27 11:23:18.000000000 +0200
@@ -0,0 +1,122 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * PD functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_pd.c,v 1.5 2006/03/27 09:23:18 schickhj Exp $
+ */
+
+
+#define DEB_PREFIX "vpd "
+
+#include <asm/current.h>
+
+#include "ehca_kernel.h"
+#include "ehca_tools.h"
+#include "ehca_iverbs.h"
+
+struct ib_pd *ehca_alloc_pd(struct ib_device *device,
+ struct ib_ucontext *context, struct ib_udata *udata)
+{
+ extern struct ehca_module ehca_module;
+ struct ib_pd *mypd = NULL;
+ struct ehca_pd *pd = NULL;
+
+ EDEB_EN(7, "device=%p context=%p udata=%p", device, context, udata);
+
+ EHCA_CHECK_DEVICE_P(device);
+
+ pd = kmem_cache_alloc(ehca_module.cache_pd, SLAB_KERNEL);
+ if (pd == NULL) {
+ EDEB_ERR(4, "ERROR device=%p context=%p pd=%p"
+ " out of memory", device, context, mypd);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(pd, 0, sizeof(struct ehca_pd));
+ pd->ownpid = current->tgid;
+
+ /* Kernel PD: when device = -1, 0
+ * User PD: when context != -1
+ */
+ if (context == NULL) {
+ /* Kernel PDs after init reuses always
+ * the one created in ehca_shca_reopen()
+ */
+ struct ehca_shca *shca = container_of(device, struct ehca_shca,
+ ib_device);
+ pd->fw_pd.value = shca->pd->fw_pd.value;
+ } else {
+ pd->fw_pd.value = (u64)pd;
+ }
+
+ mypd = &pd->ib_pd;
+
+ EHCA_REGISTER_PD(device, pd);
+
+ EDEB_EX(7, "device=%p context=%p pd=%p", device, context, mypd);
+
+ return (mypd);
+}
+
+int ehca_dealloc_pd(struct ib_pd *pd)
+{
+ extern struct ehca_module ehca_module;
+ int ret = 0;
+ u32 cur_pid = current->tgid;
+ struct ehca_pd *my_pd = NULL;
+
+ EDEB_EN(7, "pd=%p", pd);
+
+ EHCA_CHECK_PD(pd);
+ my_pd = container_of(pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject!=NULL && my_pd->ib_pd.uobject->context!=NULL &&
+ my_pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ EHCA_DEREGISTER_PD(pd);
+
+ kmem_cache_free(ehca_module.cache_pd,
+ container_of(pd, struct ehca_pd, ib_pd));
+
+ EDEB_EX(7, "pd=%p", pd);
+
+ return ret;
+}
^ permalink raw reply
* [PATCH 07/16] ehca: interrupt handling routines
From: Heiko J Schick @ 2006-04-27 10:48 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_irq.c | 712 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ehca_irq.h | 79 ++++++
2 files changed, 791 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_irq.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_irq.h 2006-04-11 09:29:54.000000000 +0200
@@ -0,0 +1,79 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Function definitions and structs for EQs, NEQs and interrupts
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_irq.h,v 1.10 2006/04/11 07:29:54 schickhj Exp $
+ */
+
+#ifndef __EHCA_IRQ_H
+#define __EHCA_IRQ_H
+
+
+struct ehca_shca;
+
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <asm/types.h>
+
+int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource);
+
+irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs);
+void ehca_tasklet_neq(unsigned long data);
+
+irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs);
+void ehca_tasklet_eq(unsigned long data);
+
+struct ehca_cpu_comp_task {
+ wait_queue_head_t wait_queue;
+ struct list_head cq_list;
+ struct task_struct *task;
+ spinlock_t task_lock;
+};
+
+struct ehca_comp_pool {
+ struct ehca_cpu_comp_task *cpu_comp_tasks;
+ int last_cpu;
+ spinlock_t last_cpu_lock;
+};
+
+struct ehca_comp_pool *ehca_create_comp_pool(void);
+void ehca_destroy_comp_pool(struct ehca_comp_pool *pool);
+void ehca_queue_comp_task(struct ehca_comp_pool *pool, struct ehca_cq *__cq);
+
+#endif
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_irq.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_irq.c 2006-04-24 15:12:03.000000000 +0200
@@ -0,0 +1,712 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Functions for EQs, NEQs and interrupts
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_irq.c,v 1.23 2006/04/24 13:12:03 schickhj Exp $
+ */
+#define DEB_PREFIX "eirq"
+
+#include "ehca_classes.h"
+#include "ehca_irq.h"
+#include "ehca_iverbs.h"
+#include "ehca_kernel.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+#include "hipz_fns.h"
+
+#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
+#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31)
+#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM(2,7)
+#define EQE_CQ_NUMBER EHCA_BMASK_IBM(8,31)
+#define EQE_QP_NUMBER EHCA_BMASK_IBM(8,31)
+#define EQE_QP_TOKEN EHCA_BMASK_IBM(32,63)
+#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32,63)
+
+#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
+#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7)
+#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15)
+#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
+
+#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
+#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
+
+static inline void comp_event_callback(struct ehca_cq *cq)
+{
+ EDEB_EN(7, "cq=%p", cq);
+
+ if (cq->ib_cq.comp_handler == NULL)
+ return;
+
+ spin_lock(&cq->cb_lock);
+ cq->ib_cq.comp_handler(&cq->ib_cq, cq->ib_cq.cq_context);
+ spin_unlock(&cq->cb_lock);
+
+ EDEB_EX(7, "cq=%p", cq);
+
+ return;
+}
+
+static void print_error_data(struct ehca_shca * shca, void* data,
+ u64* rblock, int length)
+{
+ u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
+ u64 resource = rblock[1];
+
+ EDEB_EN(7, "shca=%p data=%p rblock=%p length=%x",
+ shca, data, rblock, length);
+
+ switch (type) {
+ case 0x1: /* Queue Pair */
+ {
+ struct ehca_qp *qp = (struct ehca_qp*)data;
+
+ /* only print error data if AER is set */
+ if (rblock[6] == 0)
+ return;
+
+ EDEB_ERR(4, "QP 0x%x (resource=%lx) has errors.",
+ qp->ib_qp.qp_num, resource);
+ break;
+ }
+ case 0x4: /* Completion Queue */
+ {
+ struct ehca_cq *cq = (struct ehca_cq*)data;
+
+ EDEB_ERR(4, "CQ 0x%x (resource=%lx) has errors.",
+ cq->cq_number, resource);
+ break;
+ }
+ default:
+ EDEB_ERR(4, "Unknown errror type: %lx on %s.",
+ type, shca->ib_device.name);
+ break;
+ }
+
+ EDEB_ERR(4, "Error data is available: %lx.", resource);
+ EDEB_ERR(4, "EHCA ----- error data begin "
+ "---------------------------------------------------");
+ EDEB_DMP(4, rblock, length, "resource=%lx", resource);
+ EDEB_ERR(4, "EHCA ----- error data end "
+ "----------------------------------------------------");
+
+ EDEB_EX(7, "");
+
+ return;
+}
+
+int ehca_error_data(struct ehca_shca *shca, void *data,
+ u64 resource)
+{
+
+ unsigned long ret = 0;
+ u64 *rblock;
+ unsigned long block_count;
+
+ EDEB_EN(7, "shca=%p data=%p resource=%lx", shca, data, resource);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Cannot allocate rblock memory.");
+ ret = -ENOMEM;
+ goto error_data1;
+ }
+
+ ret = hipz_h_error_data(shca->ipz_hca_handle,
+ resource,
+ rblock,
+ &block_count);
+
+ if (ret == H_R_STATE) {
+ EDEB_ERR(4, "No error data is available: %lx.", resource);
+ }
+ else if (ret == H_SUCCESS) {
+ int length;
+
+ length = EHCA_BMASK_GET(ERROR_DATA_LENGTH, rblock[0]);
+
+ if (length > PAGE_SIZE)
+ length = PAGE_SIZE;
+
+ print_error_data(shca, data, rblock, length);
+ }
+ else {
+ EDEB_ERR(4, "Error data could not be fetched: %lx", resource);
+ }
+
+ kfree(rblock);
+
+error_data1:
+ return ret;
+
+}
+
+static void qp_event_callback(struct ehca_shca *shca,
+ u64 eqe,
+ enum ib_event_type event_type)
+{
+ struct ib_event event;
+ struct ehca_qp *qp;
+ unsigned long flags;
+ u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
+
+ EDEB_EN(7, "eqe=%lx", eqe);
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+
+ if (qp == NULL)
+ return;
+
+ ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
+
+ if (qp->ib_qp.event_handler == NULL)
+ return;
+
+ event.device = &shca->ib_device;
+ event.event = event_type;
+ event.element.qp = &qp->ib_qp;
+
+ qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+
+ EDEB_EX(7, "qp=%p", qp);
+
+ return;
+}
+
+static void cq_event_callback(struct ehca_shca *shca,
+ u64 eqe)
+{
+ struct ehca_cq *cq;
+ unsigned long flags;
+ u32 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe);
+
+ EDEB_EN(7, "eqe=%lx", eqe);
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (cq == NULL)
+ return;
+
+ ehca_error_data(shca, cq, cq->ipz_cq_handle.handle);
+
+ EDEB_EX(7, "cq=%p", cq);
+
+ return;
+}
+
+static void parse_identifier(struct ehca_shca *shca, u64 eqe)
+{
+ u8 identifier = EHCA_BMASK_GET(EQE_EE_IDENTIFIER, eqe);
+
+ EDEB_EN(7, "shca=%p eqe=%lx", shca, eqe);
+
+ switch (identifier) {
+ case 0x02: /* path migrated */
+ qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG);
+ break;
+ case 0x03: /* communication established */
+ qp_event_callback(shca, eqe, IB_EVENT_COMM_EST);
+ break;
+ case 0x04: /* send queue drained */
+ qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED);
+ break;
+ case 0x05: /* QP error */
+ case 0x06: /* QP error */
+ qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL);
+ break;
+ case 0x07: /* CQ error */
+ case 0x08: /* CQ error */
+ cq_event_callback(shca, eqe);
+ break;
+ case 0x09: /* MRMWPTE error */
+ EDEB_ERR(4, "MRMWPTE error.");
+ break;
+ case 0x0A: /* port event */
+ EDEB_ERR(4, "Port event.");
+ break;
+ case 0x0B: /* MR access error */
+ EDEB_ERR(4, "MR access error.");
+ break;
+ case 0x0C: /* EQ error */
+ EDEB_ERR(4, "EQ error.");
+ break;
+ case 0x0D: /* P/Q_Key mismatch */
+ EDEB_ERR(4, "P/Q_Key mismatch.");
+ break;
+ case 0x10: /* sampling complete */
+ EDEB_ERR(4, "Sampling complete.");
+ break;
+ case 0x11: /* unaffiliated access error */
+ EDEB_ERR(4, "Unaffiliated access error.");
+ break;
+ case 0x12: /* path migrating error */
+ EDEB_ERR(4, "Path migration error.");
+ break;
+ case 0x13: /* interface trace stopped */
+ EDEB_ERR(4, "Interface trace stopped.");
+ break;
+ case 0x14: /* first error capture info available */
+ default:
+ EDEB_ERR(4, "Unknown identifier: %x on %s.",
+ identifier, shca->ib_device.name);
+ break;
+ }
+
+ EDEB_EX(7, "eqe=%lx identifier=%x", eqe, identifier);
+
+ return;
+}
+
+static void parse_ec(struct ehca_shca *shca, u64 eqe)
+{
+ struct ib_event event;
+ u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
+ u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
+
+ EDEB_EN(7, "shca=%p eqe=%lx", shca, eqe);
+
+ switch (ec) {
+ case 0x30: /* port availability change */
+ if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
+ EDEB(4, "%s: port %x is active.",
+ shca->ib_device.name, port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ACTIVE;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+ ib_dispatch_event(&event);
+ } else {
+ EDEB(4, "%s: port %x is inactive.",
+ shca->ib_device.name, port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ERR;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_DOWN;
+ ib_dispatch_event(&event);
+ }
+ break;
+ case 0x31:
+ /* port configuration change */
+ /* disruptive change is caused by */
+ /* LID, PKEY or SM change */
+ EDEB(4, "EHCA disruptive port %x "
+ "configuration change.", port);
+
+ EDEB(4, "%s: port %x is inactive.",
+ shca->ib_device.name, port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ERR;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_DOWN;
+ ib_dispatch_event(&event);
+
+ EDEB(4, "%s: port %x is active.",
+ shca->ib_device.name, port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ACTIVE;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+ ib_dispatch_event(&event);
+ break;
+ case 0x32: /* adapter malfunction */
+ EDEB_ERR(4, "Adapter malfunction.");
+ break;
+ case 0x33: /* trace stopped */
+ EDEB_ERR(4, "Traced stopped.");
+ break;
+ default:
+ EDEB_ERR(4, "Unknown event code: %x on %s.",
+ ec, shca->ib_device.name);
+ break;
+ }
+
+ EDEB_EN(7, "eqe=%lx ec=%x", eqe, ec);
+
+ return;
+}
+
+static inline void reset_eq_pending(struct ehca_cq *cq)
+{
+ u64 CQx_EP = 0;
+ struct h_galpa gal = cq->galpas.kernel;
+
+ EDEB_EN(7, "cq=%p", cq);
+
+ hipz_galpa_store_cq(gal, cqx_ep, 0x0);
+ CQx_EP = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_ep));
+ EDEB(7, "CQx_EP=%lx", CQx_EP);
+
+ EDEB_EX(7, "cq=%p", cq);
+
+ return;
+}
+
+irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)dev_id;
+
+ EDEB_EN(7, "dev_id=%p", dev_id);
+
+ tasklet_hi_schedule(&shca->neq.interrupt_task);
+
+ EDEB_EX(7, "");
+
+ return IRQ_HANDLED;
+}
+
+void ehca_tasklet_neq(unsigned long data)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)data;
+ struct ehca_eqe *eqe;
+ u64 ret = H_SUCCESS;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
+
+ while (eqe) {
+ if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry))
+ parse_ec(shca, eqe->entry);
+
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
+ }
+
+ ret = hipz_h_reset_event(shca->ipz_hca_handle,
+ shca->neq.ipz_eq_handle, 0xFFFFFFFFFFFFFFFFL);
+
+ if (ret != H_SUCCESS)
+ EDEB_ERR(4, "Can't clear notification events.");
+
+ EDEB_EX(7, "shca=%p", shca);
+
+ return;
+}
+
+irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)dev_id;
+
+ EDEB_EN(7, "dev_id=%p", dev_id);
+
+ tasklet_hi_schedule(&shca->eq.interrupt_task);
+
+ EDEB_EX(7, "");
+
+ return IRQ_HANDLED;
+}
+
+void ehca_tasklet_eq(unsigned long data)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)data;
+ struct ehca_eqe *eqe;
+ int int_state;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ do {
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
+
+ if ((shca->hw_level >= 2) && (eqe != NULL))
+ int_state = 1;
+ else
+ int_state = 0;
+
+ while ((int_state == 1) || (eqe != 0)) {
+ while (eqe) {
+ u64 eqe_value = eqe->entry;
+
+ EDEB(7, "eqe_value=%lx", eqe_value);
+
+ /* TODO: better structure */
+ if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT,
+ eqe_value)) {
+ extern struct ehca_comp_pool* ehca_pool;
+ extern struct idr ehca_cq_idr;
+ unsigned long flags;
+ u32 token;
+ struct ehca_cq *cq;
+
+ EDEB(6, "... completion event");
+ token =
+ EHCA_BMASK_GET(EQE_CQ_TOKEN,
+ eqe_value);
+ spin_lock_irqsave(&ehca_cq_idr_lock,
+ flags);
+ cq = idr_find(&ehca_cq_idr, token);
+
+ if (cq == NULL) {
+ spin_unlock(&ehca_cq_idr_lock);
+ break;
+ }
+
+ reset_eq_pending(cq);
+ ehca_queue_comp_task(ehca_pool, cq);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock,
+ flags);
+ } else {
+ EDEB(6, "... non completion event");
+ parse_identifier(shca, eqe_value);
+ }
+ eqe =
+ (struct ehca_eqe *)ehca_poll_eq(shca,
+ &shca->eq);
+ }
+
+ if (shca->hw_level >= 2)
+ int_state =
+ hipz_h_query_int_state(shca->ipz_hca_handle,
+ shca->eq.ist);
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
+
+ }
+ } while (int_state != 0);
+
+ EDEB_EX(7, "shca=%p", shca);
+
+ return;
+}
+
+static inline int find_next_online_cpu(struct ehca_comp_pool* pool)
+{
+ unsigned long flags_last_cpu;
+
+ spin_lock_irqsave(&pool->last_cpu_lock, flags_last_cpu);
+ pool->last_cpu = next_cpu(pool->last_cpu, cpu_online_map);
+
+ if (pool->last_cpu == NR_CPUS)
+ pool->last_cpu = 0;
+
+ spin_unlock_irqrestore(&pool->last_cpu_lock, flags_last_cpu);
+
+ return pool->last_cpu;
+}
+
+void ehca_queue_comp_task(struct ehca_comp_pool *pool, struct ehca_cq *__cq)
+{
+ int cpu;
+ int cpu_id;
+ struct ehca_cpu_comp_task *cct;
+ unsigned long flags_cct;
+ unsigned long flags_cq;
+
+ cpu = get_cpu();
+ cpu_id = find_next_online_cpu(pool);
+
+ EDEB_EN(7, "pool=%p cq=%p cq_nr=%x CPU=%x:%x:%x:%x",
+ pool, __cq, __cq->cq_number,
+ cpu, cpu_id, num_online_cpus(), num_possible_cpus());
+
+ BUG_ON(!cpu_online(cpu_id));
+
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
+
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+ spin_lock_irqsave(&__cq->task_lock, flags_cq);
+
+ if (__cq->nr_callbacks == 0) {
+ __cq->nr_callbacks++;
+ list_add_tail(&__cq->entry, &cct->cq_list);
+ wake_up(&cct->wait_queue);
+ }
+ else
+ __cq->nr_callbacks++;
+
+ spin_unlock_irqrestore(&__cq->task_lock, flags_cq);
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+
+ put_cpu();
+
+ EDEB_EX(7, "cct=%p", cct);
+
+ return;
+}
+
+static void run_comp_task(struct ehca_cpu_comp_task* cct)
+{
+ struct ehca_cq *cq = NULL;
+ unsigned long flags_cct;
+ unsigned long flags_cq;
+
+
+ EDEB_EN(7, "cct=%p", cct);
+
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+
+ while (!list_empty(&cct->cq_list)) {
+ cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+ comp_event_callback(cq);
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+
+ spin_lock_irqsave(&cq->task_lock, flags_cq);
+ cq->nr_callbacks--;
+ if (cq->nr_callbacks == 0)
+ list_del_init(cct->cq_list.next);
+ spin_unlock_irqrestore(&cq->task_lock, flags_cq);
+
+ }
+
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+
+ EDEB_EX(7, "cct=%p cq=%p", cct, cq);
+
+ return;
+}
+
+static int comp_task(void *__cct)
+{
+ struct ehca_cpu_comp_task* cct = __cct;
+ DECLARE_WAITQUEUE(wait, current);
+
+ EDEB_EN(7, "cct=%p", cct);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ while(!kthread_should_stop()) {
+ add_wait_queue(&cct->wait_queue, &wait);
+
+ if (list_empty(&cct->cq_list))
+ schedule();
+ else
+ __set_current_state(TASK_RUNNING);
+
+ remove_wait_queue(&cct->wait_queue, &wait);
+
+ if (!list_empty(&cct->cq_list))
+ run_comp_task(__cct);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ __set_current_state(TASK_RUNNING);
+
+ EDEB_EX(7, "");
+
+ return 0;
+}
+
+static struct task_struct *create_comp_task(struct ehca_comp_pool *pool,
+ int cpu)
+{
+ struct ehca_cpu_comp_task *cct;
+
+ EDEB_EN(7, "cpu=%d:%d", cpu, NR_CPUS);
+
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+ spin_lock_init(&cct->task_lock);
+ INIT_LIST_HEAD(&cct->cq_list);
+ init_waitqueue_head(&cct->wait_queue);
+ cct->task = kthread_create(comp_task, cct, "ehca_comp/%d", cpu);
+
+ EDEB_EX(7, "cct/%d=%p", cpu, cct);
+
+ return cct->task;
+}
+
+static void destroy_comp_task(struct ehca_comp_pool *pool,
+ int cpu)
+{
+ struct ehca_cpu_comp_task *cct;
+ struct task_struct *task;
+
+ EDEB_EN(7, "pool=%p cpu=%d:%d", pool, cpu, NR_CPUS);
+
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+ cct->task = NULL;
+ task = cct->task;
+
+ if (task)
+ kthread_stop(task);
+
+ EDEB_EX(7, "");
+
+ return;
+}
+
+struct ehca_comp_pool *ehca_create_comp_pool(void)
+{
+ struct ehca_comp_pool *pool;
+ int cpu;
+ struct task_struct *task;
+
+ EDEB_EN(7, "");
+
+ pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL);
+ if (pool == NULL)
+ return NULL;
+
+ spin_lock_init(&pool->last_cpu_lock);
+ pool->last_cpu = any_online_cpu(cpu_online_map);
+
+ pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task);
+ if (pool->cpu_comp_tasks == NULL) {
+ kfree(pool);
+ return NULL;
+ }
+
+ for_each_online_cpu(cpu) {
+ task = create_comp_task(pool, cpu);
+ if (task) {
+ kthread_bind(task, cpu);
+ wake_up_process(task);
+ }
+ }
+
+ EDEB_EX(7, "pool=%p", pool);
+
+ return pool;
+}
+
+void ehca_destroy_comp_pool(struct ehca_comp_pool *pool)
+{
+ int i;
+
+ EDEB_EN(7, "pool=%p", pool);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_online(i))
+ destroy_comp_task(pool, i);
+ }
+
+ EDEB_EN(7, "");
+
+ return;
+}
^ permalink raw reply
* [PATCH 06/16] ehca: common include files
From: Heiko J Schick @ 2006-04-27 10:48 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_iverbs.h | 183 +++++++++++++++++++++++++++
ehca_kernel.h | 162 ++++++++++++++++++++++++
ehca_tools.h | 387 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 732 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_iverbs.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_iverbs.h 2006-04-04 23:51:52.000000000 +0200
@@ -0,0 +1,183 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Function definitions for internal functions
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Dietmar Decker <ddecker@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_iverbs.h,v 1.8 2006/04/04 21:51:52 nguyen Exp $
+ */
+
+#ifndef __EHCA_IVERBS_H__
+#define __EHCA_IVERBS_H__
+
+#include "ehca_classes.h"
+
+int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props);
+
+int ehca_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props);
+
+int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
+
+int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid);
+
+int ehca_modify_port(struct ib_device *ibdev, u8 port, int port_modify_mask,
+ struct ib_port_modify *props);
+
+struct ib_pd *ehca_alloc_pd(struct ib_device *device,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+
+int ehca_dealloc_pd(struct ib_pd *pd);
+
+struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
+
+int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
+
+int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
+
+int ehca_destroy_ah(struct ib_ah *ah);
+
+struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
+
+struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ int mr_access_flags, u64 *iova_start);
+
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
+ struct ib_umem *region,
+ int mr_access_flags, struct ib_udata *udata);
+
+int ehca_rereg_phys_mr(struct ib_mr *mr,
+ int mr_rereg_mask,
+ struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf, int mr_access_flags, u64 *iova_start);
+
+int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr);
+
+int ehca_dereg_mr(struct ib_mr *mr);
+
+struct ib_mw *ehca_alloc_mw(struct ib_pd *pd);
+
+int ehca_bind_mw(struct ib_qp *qp, struct ib_mw *mw,
+ struct ib_mw_bind *mw_bind);
+
+int ehca_dealloc_mw(struct ib_mw *mw);
+
+struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
+ int mr_access_flags,
+ struct ib_fmr_attr *fmr_attr);
+
+int ehca_map_phys_fmr(struct ib_fmr *fmr,
+ u64 *page_list, int list_len, u64 iova);
+
+int ehca_unmap_fmr(struct list_head *fmr_list);
+
+int ehca_dealloc_fmr(struct ib_fmr *fmr);
+
+enum ehca_eq_type {
+ EHCA_EQ = 0, /* Event Queue */
+ EHCA_NEQ /* Notification Event Queue */
+};
+
+int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq,
+ enum ehca_eq_type type, const u32 length);
+
+int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq);
+
+void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
+
+
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+
+int ehca_destroy_cq(struct ib_cq *cq);
+
+int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata);
+
+int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
+
+int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
+
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify);
+
+struct ib_qp *ehca_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int ehca_destroy_qp(struct ib_qp *qp);
+
+int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
+
+int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
+
+int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr,
+ struct ib_send_wr **bad_send_wr);
+
+int ehca_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr);
+
+u64 ehca_define_sqp(struct ehca_shca *shca, struct ehca_qp *ibqp,
+ struct ib_qp_init_attr *qp_init_attr);
+
+int ehca_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
+
+int ehca_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
+
+struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
+ struct ib_udata *udata);
+
+int ehca_dealloc_ucontext(struct ib_ucontext *context);
+
+int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+
+void ehca_poll_eqs(unsigned long data);
+
+int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
+ struct vm_area_struct **vma);
+
+int ehca_mmap_register(u64 physical,void **mapped,
+ struct vm_area_struct **vma);
+
+int ehca_munmap(unsigned long addr, size_t len);
+
+#endif
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_kernel.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_kernel.h 2006-04-03 08:40:54.000000000 +0200
@@ -0,0 +1,162 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Generalized functions for code shared between kernel and userspace
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Khadija Souissi <souissik@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_kernel.h,v 1.13 2006/04/03 06:40:54 schickhj Exp $
+ */
+
+#ifndef _EHCA_KERNEL_H_
+#define _EHCA_KERNEL_H_
+
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/version.h>
+
+#include <asm/abs_addr.h>
+#include <asm/ibmebus.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/**
+ * ehca_adr_bad - Handle to be used for adress translation mechanisms,
+ * currently a placeholder.
+ */
+inline static int ehca_adr_bad(void *adr)
+{
+ return (adr == 0);
+};
+
+/* We will remove this lines in SVN when it is included in the Linux kernel.
+ * We don't want to introducte unnecessary dependencies to a patched kernel.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+#include <asm/hvcall.h>
+#define H_SUCCESS 0
+#define H_BUSY 1
+#define H_CONSTRAINED 4
+#define H_LONG_BUSY_ORDER_1_MSEC 9900
+#define H_LONG_BUSY_ORDER_10_MSEC 9901
+#define H_LONG_BUSY_ORDER_100_MSEC 9902
+#define H_LONG_BUSY_ORDER_1_SEC 9903
+#define H_LONG_BUSY_ORDER_10_SEC 9904
+#define H_LONG_BUSY_ORDER_100_SEC 9905
+
+#define H_IS_LONG_BUSY(x) ((x >= H_LongBusyStartRange) && (x <= H_LongBusyEndRange))
+
+#define H_PARTIAL_STORE 16
+#define H_PAGE_REGISTERED 15
+#define H_IN_PROGRESS 14
+#define H_PARTIAL 5
+#define H_NOT_AVAILABLE 3
+#define H_Closed 2
+
+#define H_HARDWARE -1
+#define H_PARAMETER -4
+#define H_NO_MEM -9
+#define H_RESOURCE -16
+
+#define H_ADAPTER_PARM -17
+#define H_RH_PARM -18
+#define H_RCQ_PARM -19
+#define H_SCQ_PARM -20
+#define H_EQ_PARM -21
+#define H_RT_PARM -22
+#define H_ST_PARM -23
+#define H_SIGT_PARM -24
+#define H_TOKEN_PARM -25
+#define H_MLENGTH_PARM -27
+#define H_MEM_PARM -28
+#define H_MEM_ACCESS_PARM -29
+#define H_ATTR_PARM -30
+#define H_PORT_PARM -31
+#define H_MCG_PARM -32
+#define H_VL_PARM -33
+#define H_TSIZE_PARM -34
+#define H_TRACE_PARM -35
+#define H_MASK_PARM -37
+#define H_MCG_FULL -38
+#define H_ALIAS_EXIST -39
+#define H_P_COUNTER -40
+#define H_TABLE_FULL -41
+#define H_ALT_TABLE -42
+#define H_MR_CONDITION -43
+#define H_NOT_ENOUGH_RESOURCES -44
+#define H_R_STATE -45
+#define H_RESCINDEND -46
+
+/* H call defines to be moved to kernel */
+#define H_RESET_EVENTS 0x15C
+#define H_ALLOC_RESOURCE 0x160
+#define H_FREE_RESOURCE 0x164
+#define H_MODIFY_QP 0x168
+#define H_QUERY_QP 0x16C
+#define H_REREGISTER_PMR 0x170
+#define H_REGISTER_SMR 0x174
+#define H_QUERY_MR 0x178
+#define H_QUERY_MW 0x17C
+#define H_QUERY_HCA 0x180
+#define H_QUERY_PORT 0x184
+#define H_MODIFY_PORT 0x188
+#define H_DEFINE_AQP1 0x18C
+#define H_GET_TRACE_BUFFER 0x190
+#define H_DEFINE_AQP0 0x194
+#define H_RESIZE_MR 0x198
+#define H_ATTACH_MCQP 0x19C
+#define H_DETACH_MCQP 0x1A0
+#define H_CREATE_RPT 0x1A4
+#define H_REMOVE_RPT 0x1A8
+#define H_REGISTER_RPAGES 0x1AC
+#define H_DISABLE_AND_GETC 0x1B0
+#define H_ERROR_DATA 0x1B4
+#define H_GET_HCA_INFO 0x1B8
+#define H_GET_PERF_COUNT 0x1BC
+#define H_MANAGE_TRACE 0x1C0
+#define H_QUERY_INT_STATE 0x1E4
+#define H_CB_ALIGNMENT 4096
+#endif /* LINUX_VERSION_CODE */
+
+#endif /* _EHCA_KERNEL_H_ */
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_tools.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_tools.h 2006-03-30 14:36:54.000000000 +0200
@@ -0,0 +1,387 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * auxiliary functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Khadija Souissi <souissik@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_tools.h,v 1.12 2006/03/30 12:36:54 schickhj Exp $
+ */
+
+
+#ifndef EHCA_TOOLS_H
+#define EHCA_TOOLS_H
+
+#define EHCA_EDEB_TRACE_MASK_SIZE 32
+extern u8 ehca_edeb_mask[EHCA_EDEB_TRACE_MASK_SIZE];
+#define EDEB_ID_TO_U32(str4) (str4[3] | (str4[2] << 8) | (str4[1] << 16) | \
+ (str4[0] << 24))
+
+inline static u64 ehca_edeb_filter(const u32 level,
+ const u32 id, const u32 line)
+{
+ u64 ret = 0;
+ u32 filenr = 0;
+ u32 filter_level = 9;
+ u32 dynamic_level = 0;
+
+ /* This is code written for the gcc -O2 optimizer which should colapse
+ * to two single ints filter_level is the first level kicked out by
+ * compiler means trace everythin below 6. */
+ if (id == EDEB_ID_TO_U32("ehav")) {
+ filenr = 0x01;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("clas")) {
+ filenr = 0x02;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("cqeq")) {
+ filenr = 0x03;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("shca")) {
+ filenr = 0x05;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("eirq")) {
+ filenr = 0x06;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("lMad")) {
+ filenr = 0x07;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("mcas")) {
+ filenr = 0x08;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("mrmw")) {
+ filenr = 0x09;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("vpd ")) {
+ filenr = 0x0a;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("e_qp")) {
+ filenr = 0x0b;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("uqes")) {
+ filenr = 0x0c;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("PHYP")) {
+ filenr = 0x0d;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("hcpi")) {
+ filenr = 0x0e;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("iptz")) {
+ filenr = 0x0f;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("spta")) {
+ filenr = 0x10;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("simp")) {
+ filenr = 0x11;
+ filter_level = 8;
+ }
+ if (id == EDEB_ID_TO_U32("reqs")) {
+ filenr = 0x12;
+ filter_level = 8;
+ }
+
+ if ((filenr - 1) > sizeof(ehca_edeb_mask)) {
+ filenr = 0;
+ }
+
+ if (filenr == 0) {
+ filter_level = 9;
+ } /* default */
+ ret = filenr * 0x10000 + line;
+ if (filter_level <= level) {
+ return (ret | 0x100000000L); /* this is the flag to not trace */
+ }
+ dynamic_level = ehca_edeb_mask[filenr];
+ if (likely(dynamic_level <= level)) {
+ ret = ret | 0x100000000L;
+ };
+ return ret;
+}
+
+#ifdef EHCA_USE_HCALL_KERNEL
+#ifdef CONFIG_PPC_PSERIES
+
+#include <asm/paca.h>
+
+/**
+ * IS_EDEB_ON - Checks if debug is on for the given level.
+ */
+#define IS_EDEB_ON(level) \
+ ((ehca_edeb_filter(level, EDEB_ID_TO_U32(DEB_PREFIX), __LINE__) & 0x100000000L)==0)
+
+#define EDEB_P_GENERIC(level,idstring,format,args...) \
+do { \
+ u64 ehca_edeb_filterresult = \
+ ehca_edeb_filter(level, EDEB_ID_TO_U32(DEB_PREFIX), __LINE__);\
+ if ((ehca_edeb_filterresult & 0x100000000L) == 0) \
+ printk("PU%04x %08x:%s " idstring " "format "\n", \
+ get_paca()->paca_index, (u32)(ehca_edeb_filterresult), \
+ __func__, ##args); \
+} while (1==0)
+
+#elif REAL_HCALL
+
+#define EDEB_P_GENERIC(level,idstring,format,args...) \
+do { \
+ u64 ehca_edeb_filterresult = \
+ ehca_edeb_filter(level, EDEB_ID_TO_U32(DEB_PREFIX), __LINE__); \
+ if ((ehca_edeb_filterresult & 0x100000000L) == 0) \
+ printk("%08x:%s " idstring " "format "\n", \
+ (u32)(ehca_edeb_filterresult), \
+ __func__, ##args); \
+} while (1==0)
+
+#endif
+#else
+
+#define IS_EDEB_ON(level) (1)
+
+#define EDEB_P_GENERIC(level,idstring,format,args...) \
+do { \
+ printk("%s " idstring " "format "\n", \
+ __func__, ##args); \
+} while (1==0)
+
+#endif
+
+/**
+ * EDEB - Trace output macro.
+ * @level tracelevel
+ * @format optional format string, use "" if not desired
+ * @args printf like arguments for trace, use %Lx for u64, %x for u32
+ * %p for pointer
+ */
+#define EDEB(level,format,args...) \
+ EDEB_P_GENERIC(level,"",format,##args)
+#define EDEB_ERR(level,format,args...) \
+ EDEB_P_GENERIC(level,"HCAD_ERROR ",format,##args)
+#define EDEB_EN(level,format,args...) \
+ EDEB_P_GENERIC(level,">>>",format,##args)
+#define EDEB_EX(level,format,args...) \
+ EDEB_P_GENERIC(level,"<<<",format,##args)
+
+/**
+ * EDEB macro to dump a memory block, whose length is n*8 bytes.
+ * Each line has the following layout:
+ * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
+ */
+#define EDEB_DMP(level,adr,len,format,args...) \
+ do { \
+ unsigned int x; \
+ unsigned int l = (unsigned int)(len); \
+ unsigned char *deb = (unsigned char*)(adr); \
+ for (x = 0; x < l; x += 16) { \
+ EDEB(level, format " adr=%p ofs=%04x %016lx %016lx", \
+ ##args, deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
+ deb += 16; \
+ } \
+ } while (0)
+
+/* define a bitmask, little endian version */
+#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+/* define a bitmask, the ibm way... */
+#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+/* internal function, don't use */
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+/* internal function, don't use */
+#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+/* return value shifted and masked by mask\n
+ * variable|=HCA_BMASK_SET(MY_MASK,0x4711) ORs the bits in variable\n
+ * variable&=~HCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
+ * in variable
+ */
+#define EHCA_BMASK_SET(mask,value) \
+ ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+/* extract a parameter from value by mask\n
+ * param=EHCA_BMASK_GET(MY_MASK,value)
+ */
+#define EHCA_BMASK_GET(mask,value) \
+ ( EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
+
+#define PARANOIA_MODE
+#ifdef PARANOIA_MODE
+
+#define EHCA_CHECK_ADR_P(adr) \
+ if (unlikely(adr==0)) { \
+ EDEB_ERR(4, "adr=%p check failed line %i", adr, \
+ __LINE__); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_ADR(adr) \
+ if (unlikely(adr==0)) { \
+ EDEB_ERR(4, "adr=%p check failed line %i", adr, \
+ __LINE__); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_DEVICE_P(device) \
+ if (unlikely(device==0)) { \
+ EDEB_ERR(4, "device=%p check failed", device); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_DEVICE(device) \
+ if (unlikely(device==0)) { \
+ EDEB_ERR(4, "device=%p check failed", device); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_PD(pd) \
+ if (unlikely(pd==0)) { \
+ EDEB_ERR(4, "pd=%p check failed", pd); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_PD_P(pd) \
+ if (unlikely(pd==0)) { \
+ EDEB_ERR(4, "pd=%p check failed", pd); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_AV(av) \
+ if (unlikely(av==0)) { \
+ EDEB_ERR(4, "av=%p check failed", av); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_AV_P(av) \
+ if (unlikely(av==0)) { \
+ EDEB_ERR(4, "av=%p check failed", av); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_CQ(cq) \
+ if (unlikely(cq==0)) { \
+ EDEB_ERR(4, "cq=%p check failed", cq); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_CQ_P(cq) \
+ if (unlikely(cq==0)) { \
+ EDEB_ERR(4, "cq=%p check failed", cq); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_EQ(eq) \
+ if (unlikely(eq==0)) { \
+ EDEB_ERR(4, "eq=%p check failed", eq); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_EQ_P(eq) \
+ if (unlikely(eq==0)) { \
+ EDEB_ERR(4, "eq=%p check failed", eq); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_QP(qp) \
+ if (unlikely(qp==0)) { \
+ EDEB_ERR(4, "qp=%p check failed", qp); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_QP_P(qp) \
+ if (unlikely(qp==0)) { \
+ EDEB_ERR(4, "qp=%p check failed", qp); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_MR(mr) \
+ if (unlikely(mr==0)) { \
+ EDEB_ERR(4, "mr=%p check failed", mr); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_MR_P(mr) \
+ if (unlikely(mr==0)) { \
+ EDEB_ERR(4, "mr=%p check failed", mr); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_MW(mw) \
+ if (unlikely(mw==0)) { \
+ EDEB_ERR(4, "mw=%p check failed", mw); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_MW_P(mw) \
+ if (unlikely(mw==0)) { \
+ EDEB_ERR(4, "mw=%p check failed", mw); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_CHECK_FMR(fmr) \
+ if (unlikely(fmr==0)) { \
+ EDEB_ERR(4, "fmr=%p check failed", fmr); \
+ return -EFAULT; }
+
+#define EHCA_CHECK_FMR_P(fmr) \
+ if (unlikely(fmr==0)) { \
+ EDEB_ERR(4, "fmr=%p check failed", fmr); \
+ return ERR_PTR(-EFAULT); }
+
+#define EHCA_REGISTER_PD(device,pd)
+#define EHCA_REGISTER_AV(pd,av)
+#define EHCA_DEREGISTER_PD(PD)
+#define EHCA_DEREGISTER_AV(av)
+#else
+#define EHCA_CHECK_DEVICE_P(device)
+
+#define EHCA_CHECK_PD(pd)
+#define EHCA_REGISTER_PD(device,pd)
+#define EHCA_DEREGISTER_PD(PD)
+#endif
+
+/**
+ * ehca2ib_return_code - Returns ib return code corresponding to the given
+ * ehca return code.
+ */
+static inline int ehca2ib_return_code(u64 ehca_rc)
+{
+ switch (ehca_rc) {
+ case H_SUCCESS:
+ return 0;
+ case H_BUSY:
+ return -EBUSY;
+ case H_NO_MEM:
+ return -ENOMEM;
+ default:
+ return -EINVAL;
+ }
+}
+
+#endif /* EHCA_TOOLS_H */
^ permalink raw reply
* [PATCH 04/16] ehca: userspace support
From: Heiko J Schick @ 2006-04-27 10:48 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_uverbs.c | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 409 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_uverbs.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_uverbs.c 2006-04-24 15:12:03.000000000 +0200
@@ -0,0 +1,409 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * userspace support verbs
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_uverbs.c,v 1.18 2006/04/24 13:12:03 schickhj Exp $
+ */
+
+#undef DEB_PREFIX
+#define DEB_PREFIX "uver"
+
+#include <asm/current.h>
+
+#include "ehca_classes.h"
+#include "ehca_iverbs.h"
+#include "ehca_kernel.h"
+#include "ehca_mrmw.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
+ struct ib_udata *udata)
+{
+ struct ehca_ucontext *my_context = NULL;
+
+ EHCA_CHECK_ADR_P(device);
+ EDEB_EN(7, "device=%p name=%s", device, device->name);
+
+ my_context = kzalloc(sizeof *my_context, GFP_KERNEL);
+ if (NULL == my_context) {
+ EDEB_ERR(4, "Out of memory device=%p", device);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ EDEB_EX(7, "device=%p ucontext=%p", device, my_context);
+
+ return &my_context->ib_ucontext;
+}
+
+int ehca_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct ehca_ucontext *my_context = NULL;
+ EHCA_CHECK_ADR(context);
+ EDEB_EN(7, "ucontext=%p", context);
+ my_context = container_of(context, struct ehca_ucontext, ib_ucontext);
+ kfree(my_context);
+ EDEB_EN(7, "ucontext=%p", context);
+ return 0;
+}
+
+struct page *ehca_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct page *mypage = NULL;
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ EDEB_EN(7,
+ "vm_start=%lx vm_end=%lx vm_page_prot=%lx vm_fileoff=%lx "
+ "address=%lx",
+ vma->vm_start, vma->vm_end, vma->vm_page_prot, fileoffset,
+ address);
+
+ if (q_type == 1) { /* CQ */
+ struct ehca_cq *cq = NULL;
+ u64 offset;
+ void *vaddr = NULL;
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (cq->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (cq == 0) {
+ EDEB_ERR(4, "cq is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ if (rsrc_type == 2) {
+ EDEB(6, "cq=%p cq queuearea", cq);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ } else if (q_type == 2) { /* QP */
+ struct ehca_qp *qp = NULL;
+ struct ehca_pd *pd = NULL;
+ u64 offset;
+ void *vaddr = NULL;
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (qp == NULL) {
+ EDEB_ERR(4, "qp is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ if (rsrc_type == 2) { /* rqueue */
+ EDEB(6, "qp=%p qp rqueuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ } else if (rsrc_type == 3) { /* squeue */
+ EDEB(6, "qp=%p qp squeuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
+ EDEB(6, "offset=%lx vaddr=%p", offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ }
+
+ if (mypage == NULL) {
+ EDEB_ERR(4, "Invalid page adr==NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ get_page(mypage);
+ EDEB_EX(7, "page adr=%p", mypage);
+ return mypage;
+}
+
+static struct vm_operations_struct ehcau_vm_ops = {
+ .nopage = ehca_nopage,
+};
+
+int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+
+
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 ret = -EFAULT; /* assume the worst */
+ u64 vsize = 0; /* must be calculated/set below */
+ u64 physical = 0; /* must be calculated/set below */
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ EDEB_EN(7, "vm_start=%lx vm_end=%lx vm_page_prot=%lx vm_fileoff=%lx",
+ vma->vm_start, vma->vm_end, vma->vm_page_prot, fileoffset);
+
+ if (q_type == 1) { /* CQ */
+ struct ehca_cq *cq;
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (cq->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return -ENOMEM;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (cq == 0)
+ return -EINVAL;
+ if (cq->ib_cq.uobject == 0)
+ return -EINVAL;
+ if (cq->ib_cq.uobject->context != context)
+ return -EINVAL;
+ if (rsrc_type == 1) { /* galpa fw handle */
+ EDEB(6, "cq=%p cq triggerarea", cq);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != 4096) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+ physical = cq->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize,
+ physical);
+ ret =
+ remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret != 0) {
+ EDEB_ERR(4,
+ "Error: remap_pfn_range() returned %x!",
+ ret);
+ ret = -ENOMEM;
+ }
+ goto mmap_exit0;
+ } else if (rsrc_type == 2) { /* cq queue_addr */
+ EDEB(6, "cq=%p cq q_addr", cq);
+ /* vma->vm_page_prot =
+ * pgprot_noncached(vma->vm_page_prot); */
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else {
+ EDEB_ERR(6, "bad resource type %x", rsrc_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ } else if (q_type == 2) { /* QP */
+ struct ehca_qp *qp = NULL;
+ struct ehca_pd *pd = NULL;
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid!=cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return -ENOMEM;
+ }
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (qp == NULL || qp->ib_qp.uobject == NULL ||
+ qp->ib_qp.uobject->context != context) {
+ EDEB(6, "qp=%p, uobject=%p, context=%p",
+ qp, qp->ib_qp.uobject, qp->ib_qp.uobject->context);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ if (rsrc_type == 1) { /* galpa fw handle */
+ EDEB(6, "qp=%p qp triggerarea", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != 4096) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+ physical = qp->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize,
+ physical);
+ ret =
+ remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret != 0) {
+ EDEB_ERR(4,
+ "Error: remap_pfn_range() returned %x!",
+ ret);
+ ret = -ENOMEM;
+ }
+ goto mmap_exit0;
+ } else if (rsrc_type == 2) { /* qp rqueue_addr */
+ EDEB(6, "qp=%p qp rqueue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else if (rsrc_type == 3) { /* qp squeue_addr */
+ EDEB(6, "qp=%p qp squeue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ ret = 0;
+ goto mmap_exit0;
+ } else {
+ EDEB_ERR(4, "bad resource type %x",
+ rsrc_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+ } else {
+ EDEB_ERR(4, "bad queue type %x", q_type);
+ ret = -EINVAL;
+ goto mmap_exit0;
+ }
+
+mmap_exit0:
+ EDEB_EX(7, "ret=%x", ret);
+ return ret;
+}
+
+int ehca_mmap_nopage(u64 foffset,u64 length,void ** mapped,struct vm_area_struct ** vma)
+{
+ EDEB_EN(7, "foffset=%lx length=%lx", foffset, length);
+ down_write(¤t->mm->mmap_sem);
+ *mapped=(void*)
+ do_mmap(NULL,0,
+ length,
+ PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
+ foffset);
+ up_write(¤t->mm->mmap_sem);
+ if (*mapped) {
+ *vma = find_vma(current->mm,(u64)*mapped);
+ if (*vma) {
+ (*vma)->vm_flags |= VM_RESERVED;
+ (*vma)->vm_ops = &ehcau_vm_ops;
+ } else {
+ EDEB_ERR(4,"couldn't find queue vma queue=%p",
+ *mapped);
+ }
+ } else {
+ EDEB_ERR(4,"couldn't create mmap length=%lx",length);
+ }
+ EDEB_EX(7, "mapped=%p", *mapped);
+ return 0;
+}
+
+int ehca_mmap_register(u64 physical,void ** mapped,struct vm_area_struct ** vma)
+{
+ int ret;
+ unsigned long vsize;
+ ehca_mmap_nopage(0,4096,mapped,vma);
+ (*vma)->vm_flags |= VM_RESERVED;
+ vsize = (*vma)->vm_end - (*vma)->vm_start;
+ if (vsize != 4096) {
+ EDEB_ERR(4, "invalid vsize=%lx",
+ (*vma)->vm_end - (*vma)->vm_start);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
+ (*vma)->vm_flags |= VM_IO | VM_RESERVED;
+
+ EDEB(6, "vsize=%lx physical=%lx", vsize,
+ physical);
+ ret =
+ remap_pfn_range((*vma), (*vma)->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ (*vma)->vm_page_prot);
+ if (ret != 0) {
+ EDEB_ERR(4,
+ "Error: remap_pfn_range() returned %x!",
+ ret);
+ ret = -ENOMEM;
+ }
+ return ret;
+
+}
+
+int ehca_munmap(unsigned long addr, size_t len) {
+ int ret=0;
+ struct mm_struct *mm = current->mm;
+ if (mm!=0) {
+ down_write(&mm->mmap_sem);
+ ret = do_munmap(mm, addr, len);
+ up_write(&mm->mmap_sem);
+ }
+ return ret;
+}
^ permalink raw reply
* [PATCH 05/16] ehca: InfiniBand query and multicast functionality
From: Heiko J Schick @ 2006-04-27 10:48 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_hca.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ehca_mcast.c | 198 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 484 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_hca.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_hca.c 2006-04-25 09:32:54.000000000 +0200
@@ -0,0 +1,286 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * HCA query functions
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_hca.c,v 1.13 2006/04/25 07:32:54 schickhj Exp $
+ */
+
+#undef DEB_PREFIX
+#define DEB_PREFIX "shca"
+
+#include "ehca_kernel.h"
+#include "ehca_tools.h"
+
+#include "hcp_if.h"
+
+#define TO_MAX_INT(dest, src) \
+ if (src >= INT_MAX) \
+ dest = INT_MAX; \
+ else \
+ dest = src
+
+int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_hca *rblock;
+
+ EDEB_EN(7, "");
+
+ memset(props, 0, sizeof(struct ib_device_attr));
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_device0;
+ }
+
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query device properties");
+ ret = -EINVAL;
+ goto query_device1;
+ }
+ props->fw_ver = rblock->hw_ver;
+ props->max_mr_size = rblock->max_mr_size;
+ props->vendor_id = rblock->vendor_id >> 8;
+ props->vendor_part_id = rblock->vendor_part_id >> 16;
+ props->hw_ver = rblock->hw_ver;
+ TO_MAX_INT(props->max_qp, (rblock->max_qp - rblock->cur_qp));
+ TO_MAX_INT(props->max_qp_wr, rblock->max_wqes_wq);
+ props->max_sge = rblock->max_sge;
+ props->max_sge_rd = rblock->max_sge_rd;
+ TO_MAX_INT(props->max_cq, (rblock->max_cq - rblock->cur_cq));
+ props->max_cqe = rblock->max_cqe;
+ TO_MAX_INT(props->max_mr, (rblock->max_cq - rblock->cur_mr));
+ TO_MAX_INT(props->max_pd, rblock->max_pd);
+ props->max_mw = rblock->max_mw;
+ TO_MAX_INT(props->max_mr, (rblock->max_mw - rblock->cur_mw));
+ props->max_raw_ipv6_qp = rblock->max_raw_ipv6_qp;
+ props->max_raw_ethy_qp = rblock->max_raw_ethy_qp;
+ props->max_mcast_grp = rblock->max_mcast_grp;
+ props->max_mcast_qp_attach = rblock->max_qps_attached_mcast_grp;
+ props->max_total_mcast_qp_attach = rblock->max_qps_attached_all_mcast_grp;
+ TO_MAX_INT(props->max_ah, rblock->max_ah);
+ props->max_fmr = rblock->max_mr;
+ props->max_srq = 0;
+ props->max_srq_wr = 0;
+ props->max_srq_sge = 0;
+ props->max_pkeys = 16;
+ props->local_ca_ack_delay = rblock->local_ca_ack_delay;
+
+query_device1:
+ kfree(rblock);
+
+query_device0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_query_port(struct ib_device *ibdev,
+ u8 port, struct ib_port_attr *props)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_port *rblock;
+
+ EDEB_EN(7, "port=%x", port);
+
+ memset(props, 0, sizeof(struct ib_port_attr));
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_port0;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_port1;
+ }
+
+ props->state = rblock->state;
+
+ switch (rblock->max_mtu) {
+ case 0x1:
+ props->active_mtu = props->max_mtu = IB_MTU_256;
+ break;
+ case 0x2:
+ props->active_mtu = props->max_mtu = IB_MTU_512;
+ break;
+ case 0x3:
+ props->active_mtu = props->max_mtu = IB_MTU_1024;
+ break;
+ case 0x4:
+ props->active_mtu = props->max_mtu = IB_MTU_2048;
+ break;
+ case 0x5:
+ props->active_mtu = props->max_mtu = IB_MTU_4096;
+ break;
+ default:
+ EDEB_ERR(4, "Unknown MTU size: %x.", rblock->max_mtu);
+ }
+
+ props->gid_tbl_len = rblock->gid_tbl_len;
+ props->max_msg_sz = rblock->max_msg_sz;
+ props->bad_pkey_cntr = rblock->bad_pkey_cntr;
+ props->qkey_viol_cntr = rblock->qkey_viol_cntr;
+ props->pkey_tbl_len = rblock->pkey_tbl_len;
+ props->lid = rblock->lid;
+ props->sm_lid = rblock->sm_lid;
+ props->lmc = rblock->lmc;
+ props->sm_sl = rblock->sm_sl;
+ props->subnet_timeout = rblock->subnet_timeout;
+ props->init_type_reply = rblock->init_type_reply;
+
+ props->active_width = IB_WIDTH_12X;
+ props->active_speed = 0x1;
+
+query_port1:
+ kfree(rblock);
+
+query_port0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_port *rblock;
+
+ EDEB_EN(7, "port=%x index=%x", port, index);
+
+ if (index > 16) {
+ EDEB_ERR(4, "Invalid index: %x.", index);
+ ret = -EINVAL;
+ goto query_pkey0;
+ }
+
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_pkey0;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_pkey1;
+ }
+
+ memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16));
+
+query_pkey1:
+ kfree(rblock);
+
+query_pkey0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *gid)
+{
+ int ret = 0;
+ struct ehca_shca *shca;
+ struct hipz_query_port *rblock;
+
+ EDEB_EN(7, "port=%x index=%x", port, index);
+
+ if (index > 255) {
+ EDEB_ERR(4, "Invalid index: %x.", index);
+ ret = -EINVAL;
+ goto query_gid0;
+ }
+
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto query_gid0;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_gid1;
+ }
+
+ memcpy(&gid->raw[0], &rblock->gid_prefix, sizeof(u64));
+ memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64));
+
+query_gid1:
+ kfree(rblock);
+
+query_gid0:
+ EDEB_EX(7, "ret=%x GID=%lx%lx", ret,
+ *(u64 *) & gid->raw[0],
+ *(u64 *) & gid->raw[8]);
+
+ return ret;
+}
+
+int ehca_modify_port(struct ib_device *ibdev,
+ u8 port, int port_modify_mask,
+ struct ib_port_modify *props)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "port=%x", port);
+
+ /* Not implemented yet. */
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_mcast.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_mcast.c 2006-04-04 23:52:30.000000000 +0200
@@ -0,0 +1,198 @@
+
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * mcast functions
+ *
+ * Authors: Khadija Souissi <souissik@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_mcast.c,v 1.9 2006/04/04 21:52:30 nguyen Exp $
+ */
+
+#define DEB_PREFIX "mcas"
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include "ehca_kernel.h"
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+
+#include "hcp_if.h"
+
+#define MAX_MC_LID 0xFFFE
+#define MIN_MC_LID 0xC000 /* Multicast limits */
+#define EHCA_VALID_MULTICAST_GID(gid) ((gid)[0] == 0xFF)
+#define EHCA_VALID_MULTICAST_LID(lid) (((lid) >= MIN_MC_LID) && ((lid) <= MAX_MC_LID))
+
+int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_shca *shca = NULL;
+ union ib_gid my_gid;
+ u64 hipz_rc = H_SUCCESS;
+ int retcode = 0;
+
+ EHCA_CHECK_ADR(ibqp);
+ EHCA_CHECK_ADR(gid);
+
+ my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+
+ EHCA_CHECK_QP(my_qp);
+ if (ibqp->qp_type != IB_QPT_UD) {
+ EDEB_ERR(4, "invalid qp_type %x gid, retcode=%x",
+ ibqp->qp_type, EINVAL);
+ return (-EINVAL);
+ }
+
+ shca = container_of(ibqp->pd->device, struct ehca_shca, ib_device);
+ EHCA_CHECK_ADR(shca);
+
+ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
+ EDEB_ERR(4, "gid is not valid mulitcast gid retcode=%x",
+ EINVAL);
+ return (-EINVAL);
+ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
+ EDEB_ERR(4, "lid=%x is not valid mulitcast lid retcode=%x",
+ lid, EINVAL);
+ return (-EINVAL);
+ }
+
+ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+
+ hipz_rc = hipz_h_attach_mcqp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ my_qp->galpas.kernel,
+ lid, my_gid.global.subnet_prefix,
+ my_gid.global.interface_id);
+ if (H_SUCCESS != hipz_rc) {
+ EDEB_ERR(4,
+ "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
+ "hipz_rc=%lx", my_qp, ibqp->qp_num, hipz_rc);
+ }
+ retcode = ehca2ib_return_code(hipz_rc);
+
+ EDEB_EX(7, "mcast attach retcode=%x\n"
+ "ehca_qp=%p qp_num=%x lid=%x\n"
+ "my_gid= %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n",
+ retcode, my_qp, ibqp->qp_num, lid,
+ my_gid.raw[0], my_gid.raw[1],
+ my_gid.raw[2], my_gid.raw[3],
+ my_gid.raw[4], my_gid.raw[5],
+ my_gid.raw[6], my_gid.raw[7],
+ my_gid.raw[8], my_gid.raw[9],
+ my_gid.raw[10], my_gid.raw[11],
+ my_gid.raw[12], my_gid.raw[13],
+ my_gid.raw[14], my_gid.raw[15]);
+
+ return retcode;
+}
+
+int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_shca *shca = NULL;
+ union ib_gid my_gid;
+ u64 hipz_rc = H_SUCCESS;
+ int retcode = 0;
+
+ EHCA_CHECK_ADR(ibqp);
+ EHCA_CHECK_ADR(gid);
+
+ my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+
+ EHCA_CHECK_QP(my_qp);
+ if (ibqp->qp_type != IB_QPT_UD) {
+ EDEB_ERR(4, "invalid qp_type %x gid, retcode=%x",
+ ibqp->qp_type, EINVAL);
+ return (-EINVAL);
+ }
+
+ shca = container_of(ibqp->pd->device, struct ehca_shca, ib_device);
+ EHCA_CHECK_ADR(shca);
+
+ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
+ EDEB_ERR(4, "gid is not valid mulitcast gid retcode=%x",
+ EINVAL);
+ return (-EINVAL);
+ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
+ EDEB_ERR(4, "lid=%x is not valid mulitcast lid retcode=%x",
+ lid, EINVAL);
+ return (-EINVAL);
+ }
+
+ EDEB_EN(7, "dgid=%p qp_numl=%x lid=%x",
+ gid, ibqp->qp_num, lid);
+
+ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+
+ hipz_rc = hipz_h_detach_mcqp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ my_qp->galpas.kernel,
+ lid, my_gid.global.subnet_prefix,
+ my_gid.global.interface_id);
+ if (H_SUCCESS != hipz_rc) {
+ EDEB_ERR(4,
+ "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
+ "hipz_rc=%lx", my_qp, ibqp->qp_num, hipz_rc);
+ }
+ retcode = ehca2ib_return_code(hipz_rc);
+
+ EDEB_EX(7, "mcast detach retcode=%x\n"
+ "ehca_qp=%p qp_num=%x lid=%x\n"
+ "my_gid= %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n"
+ " %x %x %x %x\n",
+ retcode, my_qp, ibqp->qp_num, lid,
+ my_gid.raw[0], my_gid.raw[1],
+ my_gid.raw[2], my_gid.raw[3],
+ my_gid.raw[4], my_gid.raw[5],
+ my_gid.raw[6], my_gid.raw[7],
+ my_gid.raw[8], my_gid.raw[9],
+ my_gid.raw[10], my_gid.raw[11],
+ my_gid.raw[12], my_gid.raw[13],
+ my_gid.raw[14], my_gid.raw[15]);
+
+ return retcode;
+}
^ permalink raw reply
* [PATCH 03/16] ehca: structure definitions
From: Heiko J Schick @ 2006-04-27 10:48 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_classes.h | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
ehca_classes_pSeries.h | 253 +++++++++++++++++++++++++++++++++++++++
2 files changed, 567 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_classes.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_classes.h 2006-04-24 15:12:03.000000000 +0200
@@ -0,0 +1,314 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Struct definition for eHCA internal structures
+ *
+ * Authors:Heiko J Schick <schickhj@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_classes.h,v 1.23 2006/04/24 13:12:03 schickhj Exp $
+ */
+
+#ifndef __EHCA_CLASSES_H__
+#define __EHCA_CLASSES_H__
+
+#include "ehca_kernel.h"
+#include "ipz_pt_fn.h"
+
+struct ehca_module;
+struct ehca_qp;
+struct ehca_cq;
+struct ehca_eq;
+struct ehca_mr;
+struct ehca_mw;
+struct ehca_pd;
+struct ehca_av;
+
+#ifdef CONFIG_PPC64
+#include "ehca_classes_pSeries.h"
+#endif
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "ehca_irq.h"
+
+struct ehca_module {
+ struct list_head shca_list;
+ spinlock_t shca_lock;
+ struct timer_list timer;
+ kmem_cache_t *cache_pd;
+ kmem_cache_t *cache_cq;
+ kmem_cache_t *cache_qp;
+ kmem_cache_t *cache_av;
+ kmem_cache_t *cache_mr;
+ kmem_cache_t *cache_mw;
+ struct ehca_pfmodule pf;
+};
+
+struct ehca_eq {
+ u32 length;
+ struct ipz_queue ipz_queue;
+ struct ipz_eq_handle ipz_eq_handle;
+ struct work_struct work;
+ struct h_galpas galpas;
+ int is_initialized;
+ struct ehca_pfeq pf;
+ spinlock_t spinlock;
+ struct tasklet_struct interrupt_task;
+ u32 ist;
+};
+
+struct ehca_sport {
+ struct ib_cq *ibcq_aqp1;
+ struct ib_qp *ibqp_aqp1;
+ enum ib_rate rate;
+ enum ib_port_state port_state;
+};
+
+struct ehca_shca {
+ struct ib_device ib_device;
+ struct ibmebus_dev *ibmebus_dev;
+ u8 num_ports;
+ int hw_level;
+ struct list_head shca_list;
+ struct ipz_adapter_handle ipz_hca_handle;
+ struct ehca_sport sport[2];
+ struct ehca_eq eq;
+ struct ehca_eq neq;
+ struct ehca_mr *maxmr;
+ struct ehca_pd *pd;
+ struct ehca_pfshca pf;
+ struct h_galpas galpas;
+};
+
+struct ehca_pd {
+ struct ib_pd ib_pd;
+ struct ipz_pd fw_pd;
+ struct ehca_pfpd pf;
+ u32 ownpid;
+};
+
+struct ehca_qp {
+ struct ib_qp ib_qp;
+ u32 qp_type;
+ struct ipz_queue ipz_squeue;
+ struct ipz_queue ipz_rqueue;
+ struct h_galpas galpas;
+ u32 qkey;
+ u32 real_qp_num;
+ u32 token;
+ spinlock_t spinlock_s;
+ spinlock_t spinlock_r;
+ u32 sq_max_inline_data_size;
+ struct ipz_qp_handle ipz_qp_handle;
+ struct ehca_pfqp pf;
+ struct ib_qp_init_attr init_attr;
+ u64 uspace_squeue;
+ u64 uspace_rqueue;
+ u64 uspace_fwh;
+ struct ehca_cq* send_cq;
+ unsigned int sqerr_purgeflag;
+ struct hlist_node list_entries;
+};
+
+/* must be power of 2 */
+#define QP_HASHTAB_LEN 8
+
+struct ehca_cq {
+ struct ib_cq ib_cq;
+ struct ipz_queue ipz_queue;
+ struct h_galpas galpas;
+ spinlock_t spinlock;
+ u32 cq_number;
+ u32 token;
+ u32 nr_of_entries;
+ struct ipz_cq_handle ipz_cq_handle;
+ struct ehca_pfcq pf;
+ spinlock_t cb_lock;
+ u64 uspace_queue;
+ u64 uspace_fwh;
+ struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
+ struct list_head entry;
+ u32 nr_callbacks;
+ spinlock_t task_lock;
+ u32 ownpid;
+};
+
+enum ehca_mr_flag {
+ EHCA_MR_FLAG_FMR = 0x80000000, /* FMR, created with ehca_alloc_fmr */
+ EHCA_MR_FLAG_MAXMR = 0x40000000, /* max-MR */
+};
+
+struct ehca_mr {
+ union {
+ struct ib_mr ib_mr; /* must always be first in ehca_mr */
+ struct ib_fmr ib_fmr; /* must always be first in ehca_mr */
+ } ib;
+
+ spinlock_t mrlock;
+
+ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!! ehca_mr_deletenew() memsets from flags to end of structure
+ * !!! DON'T move flags or insert another field before.
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+ enum ehca_mr_flag flags;
+ u32 num_pages; /* number of MR pages */
+ u32 num_4k; /* number of 4k "page" portions to form MR */
+ int acl; /* ACL (stored here for usage in reregister) */
+ u64 *start; /* virtual start address (stored here for */
+ /* usage in reregister) */
+ u64 size; /* size (stored here for usage in reregister) */
+ u32 fmr_page_size; /* page size for FMR */
+ u32 fmr_max_pages; /* max pages for FMR */
+ u32 fmr_max_maps; /* max outstanding maps for FMR */
+ u32 fmr_map_cnt; /* map counter for FMR */
+ /* fw specific data */
+ struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */
+ struct h_galpas galpas;
+ /* data for userspace bridge */
+ u32 nr_of_pages;
+ void *pagearray;
+
+ struct ehca_pfmr pf; /* platform specific part of MR */
+};
+
+struct ehca_mw {
+ struct ib_mw ib_mw; /* gen2 mw, must always be first in ehca_mw */
+ spinlock_t mwlock;
+
+ u8 never_bound; /* indication MW was never bound */
+ struct ipz_mrmw_handle ipz_mw_handle; /* MW handle for h-calls */
+ struct h_galpas galpas;
+
+ struct ehca_pfmw pf; /* platform specific part of MW */
+};
+
+enum ehca_mr_pgi_type {
+ EHCA_MR_PGI_PHYS = 1, /* type of ehca_reg_phys_mr,
+ * ehca_rereg_phys_mr,
+ * ehca_reg_internal_maxmr */
+ EHCA_MR_PGI_USER = 2, /* type of ehca_reg_user_mr */
+ EHCA_MR_PGI_FMR = 3 /* type of ehca_map_phys_fmr */
+};
+
+struct ehca_mr_pginfo {
+ enum ehca_mr_pgi_type type;
+ u64 num_pages;
+ u64 page_cnt;
+ u64 num_4k; /* number of 4k "page" portions */
+ u64 page_4k_cnt; /* counter for 4k "page" portions */
+ u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */
+
+ /* type EHCA_MR_PGI_PHYS section */
+ int num_phys_buf;
+ struct ib_phys_buf *phys_buf_array;
+ u64 next_buf;
+
+ /* type EHCA_MR_PGI_USER section */
+ struct ib_umem *region;
+ struct ib_umem_chunk *next_chunk;
+ u64 next_nmap;
+
+ /* type EHCA_MR_PGI_FMR section */
+ u64 *page_list;
+ u64 next_listelem;
+ /* next_4k also used within EHCA_MR_PGI_FMR */
+};
+
+struct ehca_av {
+ struct ib_ah ib_ah;
+ struct ehca_ud_av av;
+};
+
+struct ehca_ucontext {
+ struct ib_ucontext ib_ucontext;
+};
+
+struct ehca_module *ehca_module_new(void);
+
+int ehca_module_delete(struct ehca_module *me);
+
+int ehca_eq_ctor(struct ehca_eq *eq);
+
+int ehca_eq_dtor(struct ehca_eq *eq);
+
+struct ehca_shca *ehca_shca_new(void);
+
+int ehca_shca_delete(struct ehca_shca *me);
+
+struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
+
+extern spinlock_t ehca_qp_idr_lock;
+extern spinlock_t ehca_cq_idr_lock;
+extern struct idr ehca_qp_idr;
+extern struct idr ehca_cq_idr;
+
+struct ipzu_queue_resp {
+ u64 queue; /* points to first queue entry */
+ u32 qe_size; /* queue entry size */
+ u32 act_nr_of_sg;
+ u32 queue_length; /* queue length allocated in bytes */
+ u32 pagesize;
+ u32 toggle_state;
+ u32 dummy; /* padding for 8 byte alignment */
+};
+
+struct ehca_create_cq_resp {
+ u32 cq_number;
+ u32 token;
+ struct ipzu_queue_resp ipz_queue;
+ struct h_galpas galpas;
+};
+
+struct ehca_create_qp_resp {
+ u32 qp_num;
+ u32 token;
+ u32 qp_type;
+ u32 qkey;
+ /* qp_num assigned by ehca: sqp0/1 may have got different numbers */
+ u32 real_qp_num;
+ u32 dummy; /* padding for 8 byte alignment */
+ struct ipzu_queue_resp ipz_squeue;
+ struct ipzu_queue_resp ipz_rqueue;
+ struct h_galpas galpas;
+};
+
+int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
+int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
+struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+
+#endif
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h 2006-02-27 18:00:32.000000000 +0100
@@ -0,0 +1,253 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * pSeries interface definitions
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_classes_pSeries.h,v 1.3 2006/02/27 17:00:32 nguyen Exp $
+ */
+
+#ifndef __EHCA_CLASSES_PSERIES_H__
+#define __EHCA_CLASSES_PSERIES_H__
+
+#include "hcp_phyp.h"
+#include "ipz_pt_fn.h"
+
+
+struct ehca_pfmodule {
+};
+
+struct ehca_pfshca {
+};
+
+struct ehca_pfqp {
+ struct ipz_qpt sqpt;
+ struct ipz_qpt rqpt;
+};
+
+struct ehca_pfcq {
+ struct ipz_qpt qpt;
+ u32 cqnr;
+};
+
+struct ehca_pfeq {
+ struct ipz_qpt qpt;
+ struct h_galpa galpa;
+ u32 eqnr;
+};
+
+struct ehca_pfpd {
+};
+
+struct ehca_pfmr {
+};
+
+struct ehca_pfmw {
+};
+
+struct ipz_adapter_handle {
+ u64 handle;
+};
+
+struct ipz_cq_handle {
+ u64 handle;
+};
+
+struct ipz_eq_handle {
+ u64 handle;
+};
+
+struct ipz_qp_handle {
+ u64 handle;
+};
+struct ipz_mrmw_handle {
+ u64 handle;
+};
+
+struct ipz_pd {
+ u32 value;
+};
+
+struct hcp_modify_qp_control_block {
+ u32 qkey; /* 00 */
+ u32 rdd; /* reliable datagram domain */
+ u32 send_psn; /* 02 */
+ u32 receive_psn; /* 03 */
+ u32 prim_phys_port; /* 04 */
+ u32 alt_phys_port; /* 05 */
+ u32 prim_p_key_idx; /* 06 */
+ u32 alt_p_key_idx; /* 07 */
+ u32 rdma_atomic_ctrl; /* 08 */
+ u32 qp_state; /* 09 */
+ u32 reserved_10; /* 10 */
+ u32 rdma_nr_atomic_resp_res; /* 11 */
+ u32 path_migration_state; /* 12 */
+ u32 rdma_atomic_outst_dest_qp; /* 13 */
+ u32 dest_qp_nr; /* 14 */
+ u32 min_rnr_nak_timer_field; /* 15 */
+ u32 service_level; /* 16 */
+ u32 send_grh_flag; /* 17 */
+ u32 retry_count; /* 18 */
+ u32 timeout; /* 19 */
+ u32 path_mtu; /* 20 */
+ u32 max_static_rate; /* 21 */
+ u32 dlid; /* 22 */
+ u32 rnr_retry_count; /* 23 */
+ u32 source_path_bits; /* 24 */
+ u32 traffic_class; /* 25 */
+ u32 hop_limit; /* 26 */
+ u32 source_gid_idx; /* 27 */
+ u32 flow_label; /* 28 */
+ u32 reserved_29; /* 29 */
+ union { /* 30 */
+ u64 dw[2];
+ u8 byte[16];
+ } dest_gid;
+ u32 service_level_al; /* 34 */
+ u32 send_grh_flag_al; /* 35 */
+ u32 retry_count_al; /* 36 */
+ u32 timeout_al; /* 37 */
+ u32 max_static_rate_al; /* 38 */
+ u32 dlid_al; /* 39 */
+ u32 rnr_retry_count_al; /* 40 */
+ u32 source_path_bits_al; /* 41 */
+ u32 traffic_class_al; /* 42 */
+ u32 hop_limit_al; /* 43 */
+ u32 source_gid_idx_al; /* 44 */
+ u32 flow_label_al; /* 45 */
+ u32 reserved_46; /* 46 */
+ u32 reserved_47; /* 47 */
+ union { /* 48 */
+ u64 dw[2];
+ u8 byte[16];
+ } dest_gid_al;
+ u32 max_nr_outst_send_wr; /* 52 */
+ u32 max_nr_outst_recv_wr; /* 53 */
+ u32 disable_ete_credit_check; /* 54 */
+ u32 qp_number; /* 55 */
+ u64 send_queue_handle; /* 56 */
+ u64 recv_queue_handle; /* 58 */
+ u32 actual_nr_sges_in_sq_wqe; /* 60 */
+ u32 actual_nr_sges_in_rq_wqe; /* 61 */
+ u32 qp_enable; /* 62 */
+ u32 curr_srq_limit; /* 63 */
+ u64 qp_aff_asyn_ev_log_reg; /* 64 */
+ u64 shared_rq_hndl; /* 66 */
+ u64 trigg_doorbell_qp_hndl; /* 68 */
+ u32 reserved_70_127[58]; /* 70 */
+};
+
+#define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0)
+#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2)
+#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3)
+#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4)
+#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6)
+#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8)
+#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9)
+#define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13)
+#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15)
+#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16)
+#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17)
+#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18)
+#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19)
+#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20)
+#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21)
+#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22)
+#define MQPCB_DLID EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23)
+#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24)
+#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31)
+#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25)
+#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26)
+#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27)
+#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28)
+#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31)
+#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31)
+#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32)
+#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31)
+#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33)
+#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34)
+#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35)
+#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36)
+#define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37)
+#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38)
+#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39)
+#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40)
+#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41)
+#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42)
+#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31)
+#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31)
+#define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31)
+#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48)
+#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31)
+#define MQPCB_MASK_CURR_SQR_LIMIT EHCA_BMASK_IBM(49,49)
+#define MQPCB_CURR_SQR_LIMIT EHCA_BMASK_IBM(15,31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50)
+#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51)
+
+#endif /* __EHCA_CLASSES_PSERIES_H__ */
^ permalink raw reply
* [PATCH 02/16] ehca: module infrastructure
From: Heiko J Schick @ 2006-04-27 10:48 UTC (permalink / raw)
To: openib-general, Christoph Raisch, Hoang-Nam Nguyen, Marcus Eder,
schihei, linux-kernel, linuxppc-dev
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
ehca_main.c | 973 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 973 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_main.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_main.c 2006-04-27 10:55:45.000000000 +0200
@@ -0,0 +1,973 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * module start stop, hca detection
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ehca_main.c,v 1.35 2006/04/25 08:59:43 schickhj Exp $
+ */
+
+#define DEB_PREFIX "shca"
+
+#include "ehca_classes.h"
+#include "ehca_iverbs.h"
+#include "ehca_kernel.h"
+#include "ehca_mrmw.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
+MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
+MODULE_VERSION("SVNEHCA_0005");
+
+struct ehca_comp_pool* ehca_pool;
+
+int ehca_open_aqp1 = 0;
+int ehca_debug_level = -1;
+int ehca_hw_level = 0;
+int ehca_nr_ports = 2;
+int ehca_use_hp_mr = 0;
+int ehca_port_act_time = 30;
+int ehca_poll_all_eqs = 1;
+int ehca_static_rate = -1;
+
+module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
+module_param_named(debug_level, ehca_debug_level, int, 0);
+module_param_named(hw_level, ehca_hw_level, int, 0);
+module_param_named(nr_ports, ehca_nr_ports, int, 0);
+module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
+module_param_named(port_act_time, ehca_port_act_time, int, 0);
+module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
+module_param_named(static_rate, ehca_static_rate, int, 0);
+
+MODULE_PARM_DESC(open_aqp1,
+ "AQP1 on startup (0: no (default), 1: yes)");
+MODULE_PARM_DESC(debug_level,
+ "debug level"
+ " (0: node, 6: only errors (default), 9: all)");
+MODULE_PARM_DESC(hw_level,
+ "hardware level"
+ " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
+MODULE_PARM_DESC(nr_ports,
+ "number of connected ports (default: 2)");
+MODULE_PARM_DESC(use_hp_mr,
+ "high performance MRs (0: no (default), 1: yes)");
+MODULE_PARM_DESC(port_act_time,
+ "time to wait for port activation (default: 30 sec)");
+MODULE_PARM_DESC(poll_all_eqs,
+ "polls all event queues periodically"
+ " (0: no, 1: yes (default))");
+MODULE_PARM_DESC(static_rate,
+ "set permanent static rate (default: disabled)");
+
+/* This external trace mask controls what will end up in the
+ * kernel ring buffer. Number 6 means, that everything between
+ * 0 and 5 will be stored.
+ */
+u8 ehca_edeb_mask[EHCA_EDEB_TRACE_MASK_SIZE]={6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 6, 6,
+ 6, 6, 0, 0};
+
+spinlock_t ehca_qp_idr_lock;
+spinlock_t ehca_cq_idr_lock;
+DEFINE_IDR(ehca_qp_idr);
+DEFINE_IDR(ehca_cq_idr);
+
+struct ehca_module ehca_module;
+
+void ehca_init_trace(void)
+{
+ EDEB_EN(7, "");
+
+ if (ehca_debug_level != -1) {
+ int i;
+ for (i = 0; i < EHCA_EDEB_TRACE_MASK_SIZE; i++)
+ ehca_edeb_mask[i] = ehca_debug_level;
+ }
+
+ EDEB_EX(7, "");
+}
+
+int ehca_create_slab_caches(struct ehca_module *ehca_module)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "");
+
+ ehca_module->cache_pd =
+ kmem_cache_create("ehca_cache_pd",
+ sizeof(struct ehca_pd),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (ehca_module->cache_pd == NULL) {
+ EDEB_ERR(4, "Cannot create PD SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches1;
+ }
+
+ ehca_module->cache_cq =
+ kmem_cache_create("ehca_cache_cq",
+ sizeof(struct ehca_cq),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (ehca_module->cache_cq == NULL) {
+ EDEB_ERR(4, "Cannot create CQ SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches2;
+ }
+
+ ehca_module->cache_qp =
+ kmem_cache_create("ehca_cache_qp",
+ sizeof(struct ehca_qp),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (ehca_module->cache_qp == NULL) {
+ EDEB_ERR(4, "Cannot create QP SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches3;
+ }
+
+ ehca_module->cache_av =
+ kmem_cache_create("ehca_cache_av",
+ sizeof(struct ehca_av),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (ehca_module->cache_av == NULL) {
+ EDEB_ERR(4, "Cannot create AV SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches4;
+ }
+
+ ehca_module->cache_mw =
+ kmem_cache_create("ehca_cache_mw",
+ sizeof(struct ehca_mw),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (ehca_module->cache_mw == NULL) {
+ EDEB_ERR(4, "Cannot create MW SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches5;
+ }
+
+ ehca_module->cache_mr =
+ kmem_cache_create("ehca_cache_mr",
+ sizeof(struct ehca_mr),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (ehca_module->cache_mr == NULL) {
+ EDEB_ERR(4, "Cannot create MR SLAB cache.");
+ ret = -ENOMEM;
+ goto create_slab_caches6;
+ }
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+
+create_slab_caches6:
+ kmem_cache_destroy(ehca_module->cache_mw);
+
+create_slab_caches5:
+ kmem_cache_destroy(ehca_module->cache_av);
+
+create_slab_caches4:
+ kmem_cache_destroy(ehca_module->cache_qp);
+
+create_slab_caches3:
+ kmem_cache_destroy(ehca_module->cache_cq);
+
+create_slab_caches2:
+ kmem_cache_destroy(ehca_module->cache_pd);
+
+create_slab_caches1:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+int ehca_destroy_slab_caches(struct ehca_module *ehca_module)
+{
+ int ret;
+
+ EDEB_EN(7, "");
+
+ ret = kmem_cache_destroy(ehca_module->cache_pd);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy PD SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_cq);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy CQ SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_qp);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy QP SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_av);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy AV SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_mw);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy MW SLAB cache. ret=%x", ret);
+
+ ret = kmem_cache_destroy(ehca_module->cache_mr);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy MR SLAB cache. ret=%x", ret);
+
+ EDEB_EX(7, "");
+
+ return 0;
+}
+
+#define EHCA_HCAAVER EHCA_BMASK_IBM(32,39)
+#define EHCA_REVID EHCA_BMASK_IBM(40,63)
+
+int ehca_sense_attributes(struct ehca_shca *shca)
+{
+ int ret = -EINVAL;
+ u64 rc = H_SUCCESS;
+ struct hipz_query_hca *rblock;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Cannot allocate rblock memory.");
+ ret = -ENOMEM;
+ goto num_ports0;
+ }
+
+ rc = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
+ if (rc != H_SUCCESS) {
+ EDEB_ERR(4, "Cannot query device properties.rc=%lx", rc);
+ ret = -EPERM;
+ goto num_ports1;
+ }
+
+ if (ehca_nr_ports == 1)
+ shca->num_ports = 1;
+ else
+ shca->num_ports = (u8) rblock->num_ports;
+
+ EDEB(6, " ... found %x ports", rblock->num_ports);
+
+ if (ehca_hw_level == 0) {
+ u32 hcaaver;
+ u32 revid;
+
+ hcaaver = EHCA_BMASK_GET(EHCA_HCAAVER, rblock->hw_ver);
+ revid = EHCA_BMASK_GET(EHCA_REVID, rblock->hw_ver);
+
+ EDEB(6, " ... hardware version=%x:%x",
+ hcaaver, revid);
+
+ if ((hcaaver == 1) && (revid == 0))
+ shca->hw_level = 0;
+ else if ((hcaaver == 1) && (revid == 1))
+ shca->hw_level = 1;
+ else if ((hcaaver == 1) && (revid == 2))
+ shca->hw_level = 2;
+ }
+ EDEB(6, " ... hardware level=%x", shca->hw_level);
+
+ shca->sport[0].rate = IB_RATE_30_GBPS;
+ shca->sport[1].rate = IB_RATE_30_GBPS;
+
+ ret = 0;
+
+num_ports1:
+ kfree(rblock);
+
+num_ports0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static int init_node_guid(struct ehca_shca* shca)
+{
+ int ret = 0;
+ struct hipz_query_hca *rblock;
+
+ EDEB_EN(7, "");
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ EDEB_ERR(4, "Can't allocate rblock memory.");
+ ret = -ENOMEM;
+ goto init_node_guid0;
+ }
+
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
+ EDEB_ERR(4, "Can't query device properties");
+ ret = -EINVAL;
+ goto init_node_guid1;
+ }
+
+ memcpy(&shca->ib_device.node_guid, &rblock->node_guid, (sizeof(u64)));
+
+init_node_guid1:
+ kfree(rblock);
+
+init_node_guid0:
+ EDEB_EX(7, "node_guid=%lx ret=%x", shca->ib_device.node_guid, ret);
+
+ return ret;
+}
+
+int ehca_register_device(struct ehca_shca *shca)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ ret = init_node_guid(shca);
+ if (ret != 0)
+ return ret;
+
+ strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
+ shca->ib_device.owner = THIS_MODULE;
+
+ shca->ib_device.uverbs_abi_ver = 5;
+ shca->ib_device.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
+ (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
+
+ shca->ib_device.node_type = RDMA_NODE_IB_CA;
+ shca->ib_device.phys_port_cnt = shca->num_ports;
+ shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev;
+ shca->ib_device.query_device = ehca_query_device;
+ shca->ib_device.query_port = ehca_query_port;
+ shca->ib_device.query_gid = ehca_query_gid;
+ shca->ib_device.query_pkey = ehca_query_pkey;
+ /* shca->in_device.modify_device = ehca_modify_device */
+ shca->ib_device.modify_port = ehca_modify_port;
+ shca->ib_device.alloc_ucontext = ehca_alloc_ucontext;
+ shca->ib_device.dealloc_ucontext = ehca_dealloc_ucontext;
+ shca->ib_device.alloc_pd = ehca_alloc_pd;
+ shca->ib_device.dealloc_pd = ehca_dealloc_pd;
+ shca->ib_device.create_ah = ehca_create_ah;
+ /* shca->ib_device.modify_ah = ehca_modify_ah; */
+ shca->ib_device.query_ah = ehca_query_ah;
+ shca->ib_device.destroy_ah = ehca_destroy_ah;
+ shca->ib_device.create_qp = ehca_create_qp;
+ shca->ib_device.modify_qp = ehca_modify_qp;
+ shca->ib_device.query_qp = ehca_query_qp;
+ shca->ib_device.destroy_qp = ehca_destroy_qp;
+ shca->ib_device.post_send = ehca_post_send;
+ shca->ib_device.post_recv = ehca_post_recv;
+ shca->ib_device.create_cq = ehca_create_cq;
+ shca->ib_device.destroy_cq = ehca_destroy_cq;
+ shca->ib_device.resize_cq = ehca_resize_cq;
+ shca->ib_device.poll_cq = ehca_poll_cq;
+ /* shca->ib_device.peek_cq = ehca_peek_cq; */
+ shca->ib_device.req_notify_cq = ehca_req_notify_cq;
+ /* shca->ib_device.req_ncomp_notif = ehca_req_ncomp_notif; */
+ shca->ib_device.get_dma_mr = ehca_get_dma_mr;
+ shca->ib_device.reg_phys_mr = ehca_reg_phys_mr;
+ shca->ib_device.reg_user_mr = ehca_reg_user_mr;
+ shca->ib_device.query_mr = ehca_query_mr;
+ shca->ib_device.dereg_mr = ehca_dereg_mr;
+ shca->ib_device.rereg_phys_mr = ehca_rereg_phys_mr;
+ shca->ib_device.alloc_mw = ehca_alloc_mw;
+ shca->ib_device.bind_mw = ehca_bind_mw;
+ shca->ib_device.dealloc_mw = ehca_dealloc_mw;
+ shca->ib_device.alloc_fmr = ehca_alloc_fmr;
+ shca->ib_device.map_phys_fmr = ehca_map_phys_fmr;
+ shca->ib_device.unmap_fmr = ehca_unmap_fmr;
+ shca->ib_device.dealloc_fmr = ehca_dealloc_fmr;
+ shca->ib_device.attach_mcast = ehca_attach_mcast;
+ shca->ib_device.detach_mcast = ehca_detach_mcast;
+ /* shca->ib_device.process_mad = ehca_process_mad; */
+ shca->ib_device.mmap = ehca_mmap;
+
+ ret = ib_register_device(&shca->ib_device);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
+{
+ struct ehca_sport *sport;
+ struct ib_cq *ibcq;
+ struct ib_qp *ibqp;
+ struct ib_qp_init_attr qp_init_attr;
+ int ret = 0;
+
+ EDEB_EN(7, "shca=%p port=%x", shca, port);
+
+ sport = &shca->sport[port - 1];
+
+ if (sport->ibcq_aqp1 != NULL) {
+ EDEB_ERR(4, "AQP1 CQ is already created.");
+ return -EPERM;
+ }
+
+ ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
+ if (IS_ERR(ibcq)) {
+ EDEB_ERR(4, "Cannot create AQP1 CQ.");
+ return PTR_ERR(ibcq);
+ }
+ sport->ibcq_aqp1 = ibcq;
+
+ if (sport->ibqp_aqp1 != NULL) {
+ EDEB_ERR(4, "AQP1 QP is already created.");
+ ret = -EPERM;
+ goto create_aqp1;
+ }
+
+ memset(&qp_init_attr, 0, sizeof(struct ib_qp_init_attr));
+ qp_init_attr.send_cq = ibcq;
+ qp_init_attr.recv_cq = ibcq;
+ qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
+ qp_init_attr.cap.max_send_wr = 100;
+ qp_init_attr.cap.max_recv_wr = 100;
+ qp_init_attr.cap.max_send_sge = 2;
+ qp_init_attr.cap.max_recv_sge = 1;
+ qp_init_attr.qp_type = IB_QPT_GSI;
+ qp_init_attr.port_num = port;
+ qp_init_attr.qp_context = NULL;
+ qp_init_attr.event_handler = NULL;
+ qp_init_attr.srq = NULL;
+
+ ibqp = ib_create_qp(&shca->pd->ib_pd, &qp_init_attr);
+ if (IS_ERR(ibqp)) {
+ EDEB_ERR(4, "Cannot create AQP1 QP.");
+ ret = PTR_ERR(ibqp);
+ goto create_aqp1;
+ }
+ sport->ibqp_aqp1 = ibqp;
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+
+create_aqp1:
+ ib_destroy_cq(sport->ibcq_aqp1);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static int ehca_destroy_aqp1(struct ehca_sport *sport)
+{
+ int ret = 0;
+
+ EDEB_EN(7, "sport=%p", sport);
+
+ ret = ib_destroy_qp(sport->ibqp_aqp1);
+ if (ret != 0) {
+ EDEB_ERR(4, "Cannot destroy AQP1 QP. ret=%x", ret);
+ goto destroy_aqp1;
+ }
+
+ ret = ib_destroy_cq(sport->ibcq_aqp1);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy AQP1 CQ. ret=%x", ret);
+
+destroy_aqp1:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static ssize_t ehca_show_debug_mask(struct device_driver *ddp, char *buf)
+{
+ int i;
+ int total = 0;
+ total += snprintf(buf + total, PAGE_SIZE - total, "%d",
+ ehca_edeb_mask[0]);
+ for (i = 1; i < EHCA_EDEB_TRACE_MASK_SIZE; i++) {
+ total += snprintf(buf + total, PAGE_SIZE - total, "%d",
+ ehca_edeb_mask[i]);
+ }
+
+ total += snprintf(buf + total, PAGE_SIZE - total, "\n");
+
+ return total;
+}
+
+static ssize_t ehca_store_debug_mask(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ int i;
+ for (i = 0; i < EHCA_EDEB_TRACE_MASK_SIZE; i++) {
+ char value = buf[i] - '0';
+ if ((value <= 9) && (count >= i)) {
+ ehca_edeb_mask[i] = value;
+ }
+ }
+ return count;
+}
+DRIVER_ATTR(debug_mask, S_IRUSR | S_IWUSR,
+ ehca_show_debug_mask, ehca_store_debug_mask);
+
+void ehca_create_driver_sysfs(struct ibmebus_driver *drv)
+{
+ driver_create_file(&drv->driver, &driver_attr_debug_mask);
+}
+
+void ehca_remove_driver_sysfs(struct ibmebus_driver *drv)
+{
+ driver_remove_file(&drv->driver, &driver_attr_debug_mask);
+}
+
+#define EHCA_RESOURCE_ATTR(name) \
+static ssize_t ehca_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ehca_shca *shca; \
+ struct hipz_query_hca *rblock; \
+ int data; \
+ \
+ shca = dev->driver_data; \
+ \
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); \
+ if (!rblock) { \
+ EDEB_ERR(4, "Can't allocate rblock memory."); \
+ return 0; \
+ } \
+ \
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \
+ EDEB_ERR(4, "Can't query device properties"); \
+ kfree(rblock); \
+ return 0; \
+ } \
+ \
+ data = rblock->name; \
+ kfree(rblock); \
+ \
+ if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1)) \
+ return snprintf(buf, 256, "1\n"); \
+ else \
+ return snprintf(buf, 256, "%d\n", data); \
+ \
+} \
+static DEVICE_ATTR(name, S_IRUGO, ehca_show_##name, NULL);
+
+EHCA_RESOURCE_ATTR(num_ports);
+EHCA_RESOURCE_ATTR(hw_ver);
+EHCA_RESOURCE_ATTR(max_eq);
+EHCA_RESOURCE_ATTR(cur_eq);
+EHCA_RESOURCE_ATTR(max_cq);
+EHCA_RESOURCE_ATTR(cur_cq);
+EHCA_RESOURCE_ATTR(max_qp);
+EHCA_RESOURCE_ATTR(cur_qp);
+EHCA_RESOURCE_ATTR(max_mr);
+EHCA_RESOURCE_ATTR(cur_mr);
+EHCA_RESOURCE_ATTR(max_mw);
+EHCA_RESOURCE_ATTR(cur_mw);
+EHCA_RESOURCE_ATTR(max_pd);
+EHCA_RESOURCE_ATTR(max_ah);
+
+static ssize_t ehca_show_adapter_handle(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ehca_shca *shca = dev->driver_data;
+
+ return sprintf(buf, "%lx\n", shca->ipz_hca_handle.handle);
+
+}
+static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
+
+
+
+void ehca_create_device_sysfs(struct ibmebus_dev *dev)
+{
+ device_create_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
+ device_create_file(&dev->ofdev.dev, &dev_attr_num_ports);
+ device_create_file(&dev->ofdev.dev, &dev_attr_hw_ver);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_eq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_eq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_cq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_cq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_qp);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_qp);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_mr);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mr);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_mw);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mw);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_pd);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_ah);
+}
+
+void ehca_remove_device_sysfs(struct ibmebus_dev *dev)
+{
+ device_remove_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_num_ports);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_hw_ver);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_eq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_eq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_cq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_cq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_qp);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_qp);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mr);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mr);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mw);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mw);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_pd);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_ah);
+}
+
+static int __devinit ehca_probe(struct ibmebus_dev *dev,
+ const struct of_device_id *id)
+{
+ struct ehca_shca *shca;
+ u64 *handle;
+ struct ib_pd *ibpd;
+ int ret = 0;
+
+ EDEB_EN(7, "name=%s", dev->name);
+
+ handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
+ if (!handle) {
+ EDEB_ERR(4, "Cannot get eHCA handle for adapter: %s.",
+ dev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+
+ if (!(*handle)) {
+ EDEB_ERR(4, "Wrong eHCA handle for adapter: %s.",
+ dev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+
+ shca = (struct ehca_shca *)ib_alloc_device(sizeof(*shca));
+ if (shca == NULL) {
+ EDEB_ERR(4, "Cannot allocate shca memory.");
+ return -ENOMEM;
+ }
+
+ shca->ibmebus_dev = dev;
+ shca->ipz_hca_handle.handle = *handle;
+ dev->ofdev.dev.driver_data = shca;
+
+ ret = ehca_sense_attributes(shca);
+ if (ret < 0) {
+ EDEB_ERR(4, "Cannot sense eHCA attributes.");
+ goto probe1;
+ }
+
+ /* create event queues */
+ ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048);
+ if (ret != 0) {
+ EDEB_ERR(4, "Cannot create EQ.");
+ goto probe1;
+ }
+
+ ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513);
+ if (ret != 0) {
+ EDEB_ERR(4, "Cannot create NEQ.");
+ goto probe2;
+ }
+
+ /* create internal protection domain */
+ ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+ if (IS_ERR(ibpd)) {
+ EDEB_ERR(4, "Cannot create internal PD.");
+ ret = PTR_ERR(ibpd);
+ goto probe3;
+ }
+
+ shca->pd = container_of(ibpd, struct ehca_pd, ib_pd);
+ shca->pd->ib_pd.device = &shca->ib_device;
+
+ /* create internal max MR */
+ if (shca->maxmr == 0) {
+ struct ehca_mr *e_maxmr = NULL;
+ ret = ehca_reg_internal_maxmr(shca, shca->pd, &e_maxmr);
+ if (ret != 0) {
+ EDEB_ERR(4, "Cannot create internal MR. ret=%x", ret);
+ goto probe4;
+ }
+ shca->maxmr = e_maxmr;
+ }
+
+ ret = ehca_register_device(shca);
+ if (ret != 0) {
+ EDEB_ERR(4, "Cannot register Infiniband device.");
+ goto probe5;
+ }
+
+ /* create AQP1 for port 1 */
+ if (ehca_open_aqp1 == 1) {
+ shca->sport[0].port_state = IB_PORT_DOWN;
+ ret = ehca_create_aqp1(shca, 1);
+ if (ret != 0) {
+ EDEB_ERR(4, "Cannot create AQP1 for port 1.");
+ goto probe6;
+ }
+ }
+
+ /* create AQP1 for port 2 */
+ if ((ehca_open_aqp1 == 1) && (shca->num_ports == 2)) {
+ shca->sport[1].port_state = IB_PORT_DOWN;
+ ret = ehca_create_aqp1(shca, 2);
+ if (ret != 0) {
+ EDEB_ERR(4, "Cannot create AQP1 for port 2.");
+ goto probe7;
+ }
+ }
+
+ ehca_create_device_sysfs(dev);
+
+ spin_lock(&ehca_module.shca_lock);
+ list_add(&shca->shca_list, &ehca_module.shca_list);
+ spin_unlock(&ehca_module.shca_lock);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return 0;
+
+probe7:
+ ret = ehca_destroy_aqp1(&shca->sport[0]);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy AQP1 for port 1. ret=%x", ret);
+
+probe6:
+ ib_unregister_device(&shca->ib_device);
+
+probe5:
+ ret = ehca_dereg_internal_maxmr(shca);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy internal MR. ret=%x", ret);
+
+probe4:
+ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy internal PD. ret=%x", ret);
+
+probe3:
+ ret = ehca_destroy_eq(shca, &shca->neq);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy NEQ. ret=%x", ret);
+
+probe2:
+ ret = ehca_destroy_eq(shca, &shca->eq);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy EQ. ret=%x", ret);
+
+probe1:
+ ib_dealloc_device(&shca->ib_device);
+
+ EDEB_EX(4, "ret=%x", ret);
+
+ return -EINVAL;
+}
+
+static int __devexit ehca_remove(struct ibmebus_dev *dev)
+{
+ struct ehca_shca *shca = dev->ofdev.dev.driver_data;
+ int ret;
+
+ EDEB_EN(7, "shca=%p", shca);
+
+ ehca_remove_device_sysfs(dev);
+
+ if (ehca_open_aqp1 == 1) {
+ int i;
+
+ for (i = 0; i < shca->num_ports; i++) {
+ ret = ehca_destroy_aqp1(&shca->sport[i]);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy AQP1 for port %x."
+ " ret=%x", ret, i);
+ }
+ }
+
+ ib_unregister_device(&shca->ib_device);
+
+ ret = ehca_dereg_internal_maxmr(shca);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy internal MR. ret=%x", ret);
+
+ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy internal PD. ret=%x", ret);
+
+ ret = ehca_destroy_eq(shca, &shca->eq);
+ if (ret != 0)
+ EDEB_ERR(4, "Cannot destroy EQ. ret=%x", ret);
+
+ ret = ehca_destroy_eq(shca, &shca->neq);
+ if (ret != 0)
+ EDEB_ERR(4, "Canot destroy NEQ. ret=%x", ret);
+
+ ib_dealloc_device(&shca->ib_device);
+
+ spin_lock(&ehca_module.shca_lock);
+ list_del(&shca->shca_list);
+ spin_unlock(&ehca_module.shca_lock);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+}
+
+static struct of_device_id ehca_device_table[] =
+{
+ {
+ .name = "lhca",
+ .compatible = "IBM,lhca",
+ },
+ {},
+};
+
+static struct ibmebus_driver ehca_driver = {
+ .name = "ehca",
+ .id_table = ehca_device_table,
+ .probe = ehca_probe,
+ .remove = ehca_remove,
+};
+
+int __init ehca_module_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "eHCA Infiniband Device Driver "
+ "(Rel.: SVNEHCA_0005)\n");
+ EDEB_EN(7, "");
+
+ idr_init(&ehca_qp_idr);
+ idr_init(&ehca_cq_idr);
+ spin_lock_init(&ehca_qp_idr_lock);
+ spin_lock_init(&ehca_cq_idr_lock);
+
+ INIT_LIST_HEAD(&ehca_module.shca_list);
+ spin_lock_init(&ehca_module.shca_lock);
+
+ ehca_init_trace();
+
+ ehca_pool = ehca_create_comp_pool();
+ if (ehca_pool == NULL) {
+ EDEB_ERR(4, "Cannot create comp pool.");
+ ret = -EINVAL;
+ goto module_init0;
+ }
+
+ if ((ret = ehca_create_slab_caches(&ehca_module)) != 0) {
+ EDEB_ERR(4, "Cannot create SLAB caches");
+ ret = -ENOMEM;
+ goto module_init1;
+ }
+
+ if ((ret = ibmebus_register_driver(&ehca_driver)) != 0) {
+ EDEB_ERR(4, "Cannot register eHCA device driver");
+ ret = -EINVAL;
+ goto module_init2;
+ }
+
+ ehca_create_driver_sysfs(&ehca_driver);
+
+ if (ehca_poll_all_eqs != 1) {
+ EDEB_ERR(4, "WARNING!!!");
+ EDEB_ERR(4, "It is possible to lose interrupts.");
+
+ return 0;
+ }
+
+ init_timer(&ehca_module.timer);
+ ehca_module.timer.function = ehca_poll_eqs;
+ ehca_module.timer.data = (unsigned long)(void*)&ehca_module;
+ ehca_module.timer.expires = jiffies + HZ;
+ add_timer(&ehca_module.timer);
+
+ EDEB_EX(7, "ret=%x", ret);
+
+ return 0;
+
+module_init2:
+ ehca_destroy_slab_caches(&ehca_module);
+
+module_init1:
+ ehca_destroy_comp_pool(ehca_pool);
+
+module_init0:
+ EDEB_EX(7, "ret=%x", ret);
+
+ return ret;
+};
+
+void __exit ehca_module_exit(void)
+{
+ EDEB_EN(7, "");
+
+ if (ehca_poll_all_eqs == 1)
+ del_timer_sync(&ehca_module.timer);
+
+ ehca_remove_driver_sysfs(&ehca_driver);
+ ibmebus_unregister_driver(&ehca_driver);
+
+ if (ehca_destroy_slab_caches(&ehca_module) != 0)
+ EDEB_ERR(4, "Cannot destroy SLAB caches");
+
+ ehca_destroy_comp_pool(ehca_pool);
+
+ idr_destroy(&ehca_cq_idr);
+ idr_destroy(&ehca_qp_idr);
+
+ EDEB_EX(7, "");
+};
+
+module_init(ehca_module_init);
+module_exit(ehca_module_exit);
^ permalink raw reply
* [PATCH 01/16] ehca: integration in Linux kernel build system
From: Heiko J Schick @ 2006-04-27 12:05 UTC (permalink / raw)
To: linux-kernel, openib-general, linuxppc-dev, Marcus Eder,
Christoph Raisch, Hoang-Nam Nguyen, schickhj
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
Kconfig | 6 ++++++
Makefile | 29 +++++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/Kconfig 2006-01-04 16:29:05.000000000 +0100
@@ -0,0 +1,6 @@
+config INFINIBAND_EHCA
+ tristate "eHCA support"
+ depends on IBMEBUS && INFINIBAND
+ ---help---
+ This is a low level device driver for the IBM
+ GX based Host channel adapters (HCAs)
\ No newline at end of file
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/Makefile 2006-03-06 12:26:36.000000000 +0100
@@ -0,0 +1,29 @@
+# Authors: Heiko J Schick <schickhj@de.ibm.com>
+# Christoph Raisch <raisch@de.ibm.com>
+#
+# Copyright (c) 2005 IBM Corporation
+#
+# All rights reserved.
+#
+# This source code is distributed under a dual license of GPL v2.0 and OpenIB BSD.
+
+obj-$(CONFIG_INFINIBAND_EHCA) += hcad_mod.o
+
+hcad_mod-objs = ehca_main.o \
+ ehca_hca.o \
+ ehca_mcast.o \
+ ehca_pd.o \
+ ehca_av.o \
+ ehca_eq.o \
+ ehca_cq.o \
+ ehca_qp.o \
+ ehca_sqp.o \
+ ehca_mrmw.o \
+ ehca_reqs.o \
+ ehca_irq.o \
+ ehca_uverbs.o \
+ hcp_if.o \
+ hcp_phyp.o \
+ ipz_pt_fn.o
+
+CFLAGS += -DEHCA_USE_HCALL -DEHCA_USE_HCALL_KERNEL
^ permalink raw reply
* [PATCH 00/16] ehca: IBM eHCA InfiniBand Device Driver
From: Heiko J Schick @ 2006-04-27 12:05 UTC (permalink / raw)
To: linux-kernel, openib-general, linuxppc-dev, Marcus Eder,
Christoph Raisch, Hoang-Nam Nguyen, schickhj
Hello,
many thanks for your comments. They are very helpful for us. All
17 patches have to be applied, otherwise the driver won't compile.
We added an initial version to support large pages. At the moment
we verified it only for 4K pages, because we're struggling to get
a Linux kernel with 64K pages running properly on our system.
We would appreciate for any comments and feedbacks.
Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
Changelog-by: Heiko J Schick <schickhj@de.ibm.com>
Changelog:
Differences to PatchSet http://openib.org/pipermail/openib-general/2006-March/018144.html
Differences to PatchSet http://openib.org/pipermail/openib-general/2006-March/017412.html
- Renamed module param tracelevel to debug_level
- Reformated MODULE_PARAM_DESC in ehca_main.c
- Removed EHCA_CACHE_CREATE / EHCA_CACHE_DESTROY macros
- Renamed debug_level sysfs entry to debug_mask
- debug_mask sysfs entry has now only one value
- Added LARGEPAGE support (EXPERIMENTAL)
- Changed locking for internal IDRs (for CQs and QPs)
- ehca_poll_eqs uses now mod_timer instead of add_timer
- Removed compile warnings in libehca because of missing header files
- Added function ibv_read_sysfs_file to be compatible with libibverbs 1.0
- Removed libsysfs usage in libehca
- Rename HCALLs defines from StudlyCaps to SHUTTING_CAPS
- Improve scaling code for completion queue
- Remove use of struct ib_gid in firmware bridge
- Improve coding style in firmware bridge
- Rework static rate encoding
- Removed ehca_kv_to_g()
- Splitted remaining shared kernel/userspace files
- Removed defines in user space to reuse kernel files
- Removed struct ehca_qp_core, ehca_cq_core
- Removed all trailing blanks found
- Fixed sparse warnings
- Improved eq SMP scaling
- Added fork access protection to queue entries
Kconfig | 6
Makefile | 29
ehca_av.c | 309 ++++++
ehca_classes.h | 314 ++++++
ehca_classes_pSeries.h | 253 ++++
ehca_cq.c | 445 ++++++++
ehca_eq.c | 225 ++++
ehca_hca.c | 286 +++++
ehca_irq.c | 712 ++++++++++++++
ehca_irq.h | 79 +
ehca_iverbs.h | 183 +++
ehca_kernel.h | 162 +++
ehca_main.c | 973 +++++++++++++++++++
ehca_mcast.c | 198 +++
ehca_mrmw.c | 2492 +++++++++++++++++++++++++++++++++++++++++++++++++
ehca_mrmw.h | 145 ++
ehca_pd.c | 122 ++
ehca_qes.h | 278 +++++
ehca_qp.c | 1592 +++++++++++++++++++++++++++++++
ehca_reqs.c | 685 +++++++++++++
ehca_sqp.c | 126 ++
ehca_tools.h | 387 +++++++
ehca_uverbs.c | 409 ++++++++
hcp_if.c | 2028 +++++++++++++++++++++++++++++++++++++++
hcp_if.h | 398 +++++++
hcp_phyp.c | 97 +
hcp_phyp.h | 97 +
hipz_fns.h | 73 +
hipz_fns_core.h | 126 ++
hipz_hw.h | 398 +++++++
ipz_pt_fn.c | 184 +++
ipz_pt_fn.h | 258 +++++
32 files changed, 14069 insertions(+)
^ permalink raw reply
* Re: Linux 2.6 sources for MPC852T processor
From: David Jander @ 2006-04-27 10:41 UTC (permalink / raw)
To: Dan Malek; +Cc: chandrasekhar_n, linuxppc-embedded
In-Reply-To: <0606BE3C-7751-4E71-B724-FEFE2FF252C8@embeddededge.com>
On Thursday 27 April 2006 01:32, Dan Malek wrote:
> There is a horrible bug in the 8xx TLB miss handler that is in the
> 2.6.16
> sources. I don't know when it appeared. Enable the CPU6 Errata
> workaround to see if that solves the problem and please report back
> to me. I'm working on a solution.
I received instructions from Marcelo to reverse two patches he sent me this
morning, that did solve the problem. In fact those patches changed some
TLB-related assembly code in head_8xx.S
Greetings,
--
David Jander
^ permalink raw reply
* [PATCH 4/4] powerpc: merge the rest of the vio code
From: Stephen Rothwell @ 2006-04-27 7:23 UTC (permalink / raw)
To: ppc-dev
In-Reply-To: <20060427172146.4660a953.sfr@canb.auug.org.au>
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/kernel/vio.c | 198 ++++++++++++++++++++++++++-----
arch/powerpc/platforms/iseries/Makefile | 1
arch/powerpc/platforms/iseries/iommu.c | 3
arch/powerpc/platforms/iseries/iommu.h | 35 -----
arch/powerpc/platforms/iseries/pci.c | 2
arch/powerpc/platforms/iseries/vio.c | 67 ----------
arch/powerpc/platforms/pseries/Makefile | 1
arch/powerpc/platforms/pseries/vio.c | 133 ---------------------
include/asm-powerpc/iseries/iommu.h | 35 +++++
include/asm-powerpc/vio.h | 8 -
10 files changed, 201 insertions(+), 282 deletions(-)
delete mode 100644 arch/powerpc/platforms/iseries/iommu.h
delete mode 100644 arch/powerpc/platforms/iseries/vio.c
delete mode 100644 arch/powerpc/platforms/pseries/vio.c
create mode 100644 include/asm-powerpc/iseries/iommu.h
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
d79e3d667af2d5babcc931a71aa536ff150ba541
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 1952929..ac5c7bf 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -13,25 +13,102 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/types.h>
+#include <linux/device.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
+#include <linux/kobject.h>
+
#include <asm/iommu.h>
#include <asm/dma.h>
#include <asm/vio.h>
#include <asm/prom.h>
#include <asm/firmware.h>
-
-struct vio_dev vio_bus_device = { /* fake "parent" device */
+#include <asm/tce.h>
+#include <asm/abs_addr.h>
+#include <asm/page.h>
+#include <asm/hvcall.h>
+#include <asm/iseries/vio.h>
+#include <asm/iseries/hv_types.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/iommu.h>
+
+extern struct subsystem devices_subsys; /* needed for vio_find_name() */
+
+static struct vio_dev vio_bus_device = { /* fake "parent" device */
.name = vio_bus_device.dev.bus_id,
.type = "",
.dev.bus_id = "vio",
.dev.bus = &vio_bus_type,
};
-static struct vio_bus_ops vio_bus_ops;
+#ifdef CONFIG_PPC_ISERIES
+struct device *iSeries_vio_dev = &vio_bus_device.dev;
+EXPORT_SYMBOL(iSeries_vio_dev);
+
+static struct iommu_table veth_iommu_table;
+static struct iommu_table vio_iommu_table;
+
+static void __init iommu_vio_init(void)
+{
+ iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
+ veth_iommu_table.it_size /= 2;
+ vio_iommu_table = veth_iommu_table;
+ vio_iommu_table.it_offset += veth_iommu_table.it_size;
+
+ if (!iommu_init_table(&veth_iommu_table))
+ printk("Virtual Bus VETH TCE table failed.\n");
+ if (!iommu_init_table(&vio_iommu_table))
+ printk("Virtual Bus VIO TCE table failed.\n");
+}
+#endif
+
+static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
+{
+#ifdef CONFIG_PPC_ISERIES
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+ if (strcmp(dev->type, "vlan") == 0)
+ return &veth_iommu_table;
+ return &vio_iommu_table;
+ } else
+#endif
+ {
+ unsigned int *dma_window;
+ struct iommu_table *newTceTable;
+ unsigned long offset;
+ int dma_window_property_size;
+
+ dma_window = (unsigned int *)get_property(
+ dev->dev.platform_data, "ibm,my-dma-window",
+ &dma_window_property_size);
+ if (!dma_window)
+ return NULL;
+
+ newTceTable = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
+
+ /*
+ * There should be some code to extract the phys-encoded
+ * offset using prom_n_addr_cells(). However, according to
+ * a comment on earlier versions, it's always zero, so we
+ * don't bother
+ */
+ offset = dma_window[1] >> PAGE_SHIFT;
+
+ /* TCE table size - measured in tce entries */
+ newTceTable->it_size = dma_window[4] >> PAGE_SHIFT;
+ /* offset for VIO should always be 0 */
+ newTceTable->it_offset = offset;
+ newTceTable->it_busno = 0;
+ newTceTable->it_index = (unsigned long)dma_window[0];
+ newTceTable->it_type = TCE_VB;
+
+ return iommu_init_table(newTceTable);
+ }
+}
/**
* vio_match_device: - Tell if a VIO device has a matching
@@ -126,6 +203,16 @@ void vio_unregister_driver(struct vio_dr
}
EXPORT_SYMBOL(vio_unregister_driver);
+/* vio_dev refcount hit 0 */
+static void __devinit vio_dev_release(struct device *dev)
+{
+ if (dev->platform_data) {
+ /* XXX free TCE table */
+ of_node_put(dev->platform_data);
+ }
+ kfree(to_vio_dev(dev));
+}
+
/**
* vio_register_device_node: - Register a new vio device.
* @of_node: The OF node for this device.
@@ -185,10 +272,17 @@ struct vio_dev * __devinit vio_register_
if (unit_address != NULL)
viodev->unit_address = *unit_address;
}
- viodev->iommu_table = vio_bus_ops.build_iommu_table(viodev);
+ viodev->iommu_table = vio_build_iommu_table(viodev);
+
+ /* init generic 'struct device' fields: */
+ viodev->dev.parent = &vio_bus_device.dev;
+ viodev->dev.bus = &vio_bus_type;
+ viodev->dev.release = vio_dev_release;
/* register with generic device framework */
- if (vio_register_device(viodev) == NULL) {
+ if (device_register(&viodev->dev)) {
+ printk(KERN_ERR "%s: failed to register device %s\n",
+ __FUNCTION__, viodev->dev.bus_id);
/* XXX free TCE table */
kfree(viodev);
return NULL;
@@ -201,12 +295,18 @@ EXPORT_SYMBOL(vio_register_device_node);
/**
* vio_bus_init: - Initialize the virtual IO bus
*/
-int __init vio_bus_init(struct vio_bus_ops *ops)
+static int __init vio_bus_init(void)
{
int err;
struct device_node *node_vroot;
- vio_bus_ops = *ops;
+#ifdef CONFIG_PPC_ISERIES
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+ iommu_vio_init();
+ vio_bus_device.iommu_table = &vio_iommu_table;
+ iSeries_vio_dev = &vio_bus_device.dev;
+ }
+#endif
err = bus_register(&vio_bus_type);
if (err) {
@@ -243,16 +343,7 @@ int __init vio_bus_init(struct vio_bus_o
return 0;
}
-
-/* vio_dev refcount hit 0 */
-static void __devinit vio_dev_release(struct device *dev)
-{
- if (dev->platform_data) {
- /* XXX free TCE table */
- of_node_put(dev->platform_data);
- }
- kfree(to_vio_dev(dev));
-}
+__initcall(vio_bus_init);
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -274,23 +365,6 @@ static struct device_attribute vio_dev_a
__ATTR_NULL
};
-struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev)
-{
- /* init generic 'struct device' fields: */
- viodev->dev.parent = &vio_bus_device.dev;
- viodev->dev.bus = &vio_bus_type;
- viodev->dev.release = vio_dev_release;
-
- /* register with generic device framework */
- if (device_register(&viodev->dev)) {
- printk(KERN_ERR "%s: failed to register device %s\n",
- __FUNCTION__, viodev->dev.bus_id);
- return NULL;
- }
-
- return viodev;
-}
-
void __devinit vio_unregister_device(struct vio_dev *viodev)
{
device_unregister(&viodev->dev);
@@ -412,3 +486,59 @@ const void *vio_get_attribute(struct vio
return get_property(vdev->dev.platform_data, which, length);
}
EXPORT_SYMBOL(vio_get_attribute);
+
+#ifdef CONFIG_PPC_PSERIES
+/* vio_find_name() - internal because only vio.c knows how we formatted the
+ * kobject name
+ * XXX once vio_bus_type.devices is actually used as a kset in
+ * drivers/base/bus.c, this function should be removed in favor of
+ * "device_find(kobj_name, &vio_bus_type)"
+ */
+static struct vio_dev *vio_find_name(const char *kobj_name)
+{
+ struct kobject *found;
+
+ found = kset_find_obj(&devices_subsys.kset, kobj_name);
+ if (!found)
+ return NULL;
+
+ return to_vio_dev(container_of(found, struct device, kobj));
+}
+
+/**
+ * vio_find_node - find an already-registered vio_dev
+ * @vnode: device_node of the virtual device we're looking for
+ */
+struct vio_dev *vio_find_node(struct device_node *vnode)
+{
+ uint32_t *unit_address;
+ char kobj_name[BUS_ID_SIZE];
+
+ /* construct the kobject name from the device node */
+ unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
+ if (!unit_address)
+ return NULL;
+ snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
+
+ return vio_find_name(kobj_name);
+}
+EXPORT_SYMBOL(vio_find_node);
+
+int vio_enable_interrupts(struct vio_dev *dev)
+{
+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
+ if (rc != H_SUCCESS)
+ printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
+ return rc;
+}
+EXPORT_SYMBOL(vio_enable_interrupts);
+
+int vio_disable_interrupts(struct vio_dev *dev)
+{
+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
+ if (rc != H_SUCCESS)
+ printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
+ return rc;
+}
+EXPORT_SYMBOL(vio_disable_interrupts);
+#endif /* CONFIG_PPC_PSERIES */
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index ce8c0b9..7e67a20 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -3,7 +3,6 @@ EXTRA_CFLAGS += -mno-minimal-toc
obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \
hvcall.o proc.o htab.o iommu.o misc.o irq.o
obj-$(CONFIG_PCI) += pci.o vpdinfo.o
-obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_VIOPATH) += viopath.o
obj-$(CONFIG_MODULES) += ksyms.o
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index bea0b70..a8d9631 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -33,8 +33,7 @@ #include <asm/machdep.h>
#include <asm/abs_addr.h>
#include <asm/pci-bridge.h>
#include <asm/iseries/hv_call_xm.h>
-
-#include "iommu.h"
+#include <asm/iseries/iommu.h>
extern struct list_head iSeries_Global_Device_List;
diff --git a/arch/powerpc/platforms/iseries/iommu.h b/arch/powerpc/platforms/iseries/iommu.h
deleted file mode 100644
index cb5658f..0000000
--- a/arch/powerpc/platforms/iseries/iommu.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_IOMMU_H
-#define _PLATFORMS_ISERIES_IOMMU_H
-
-/*
- * Copyright (C) 2005 Stephen Rothwell, IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the:
- * Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- */
-
-struct device_node;
-struct iommu_table;
-
-/* Creates table for an individual device node */
-extern void iommu_devnode_init_iSeries(struct device_node *dn);
-
-/* Get table parameters from HV */
-extern void iommu_table_getparms_iSeries(unsigned long busno,
- unsigned char slotno, unsigned char virtbus,
- struct iommu_table *tbl);
-
-#endif /* _PLATFORMS_ISERIES_IOMMU_H */
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 5a61c6f..428ffb5 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -37,13 +37,13 @@ #include <asm/abs_addr.h>
#include <asm/iseries/hv_call_xm.h>
#include <asm/iseries/mf.h>
+#include <asm/iseries/iommu.h>
#include <asm/ppc-pci.h>
#include "irq.h"
#include "pci.h"
#include "call_pci.h"
-#include "iommu.h"
/*
* Forward declares of prototypes.
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
deleted file mode 100644
index bdd2b7d..0000000
--- a/arch/powerpc/platforms/iseries/vio.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * IBM PowerPC iSeries Virtual I/O Infrastructure Support.
- *
- * Copyright (c) 2005 Stephen Rothwell, IBM Corp.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/vio.h>
-#include <asm/iommu.h>
-#include <asm/tce.h>
-#include <asm/abs_addr.h>
-#include <asm/page.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_xm.h>
-
-#include "iommu.h"
-
-struct device *iSeries_vio_dev = &vio_bus_device.dev;
-EXPORT_SYMBOL(iSeries_vio_dev);
-
-static struct iommu_table veth_iommu_table;
-static struct iommu_table vio_iommu_table;
-
-static void __init iommu_vio_init(void)
-{
- iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
- veth_iommu_table.it_size /= 2;
- vio_iommu_table = veth_iommu_table;
- vio_iommu_table.it_offset += veth_iommu_table.it_size;
-
- if (!iommu_init_table(&veth_iommu_table))
- printk("Virtual Bus VETH TCE table failed.\n");
- if (!iommu_init_table(&vio_iommu_table))
- printk("Virtual Bus VIO TCE table failed.\n");
-}
-
-static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
-{
- if (strcmp(dev->type, "vlan") == 0)
- return &veth_iommu_table;
- return &vio_iommu_table;
-}
-
-static struct vio_bus_ops vio_bus_ops_iseries = {
- .build_iommu_table = vio_build_iommu_table,
-};
-
-/**
- * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus
- */
-static int __init vio_bus_init_iseries(void)
-{
- iommu_vio_init();
- vio_bus_device.iommu_table = &vio_iommu_table;
- iSeries_vio_dev = &vio_bus_device.dev;
- return vio_bus_init(&vio_bus_ops_iseries);
-}
-__initcall(vio_bus_init_iseries);
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 9308986..b46ce3b 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -2,7 +2,6 @@ obj-y := pci.o lpar.o hvCall.o nvram.o
setup.o iommu.o ras.o rtasd.o pci_dlpar.o \
firmware.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c
deleted file mode 100644
index d289166..0000000
--- a/arch/powerpc/platforms/pseries/vio.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * IBM PowerPC pSeries Virtual I/O Infrastructure Support.
- *
- * Copyright (c) 2003-2005 IBM Corp.
- * Dave Engebretsen engebret@us.ibm.com
- * Santiago Leon santil@us.ibm.com
- * Hollis Blanchard <hollisb@us.ibm.com>
- * Stephen Rothwell
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kobject.h>
-#include <asm/iommu.h>
-#include <asm/dma.h>
-#include <asm/prom.h>
-#include <asm/vio.h>
-#include <asm/hvcall.h>
-#include <asm/tce.h>
-
-extern struct subsystem devices_subsys; /* needed for vio_find_name() */
-
-/**
- * vio_build_iommu_table: - gets the dma information from OF and
- * builds the TCE tree.
- * @dev: the virtual device.
- *
- * Returns a pointer to the built tce tree, or NULL if it can't
- * find property.
-*/
-static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
-{
- unsigned int *dma_window;
- struct iommu_table *newTceTable;
- unsigned long offset;
- int dma_window_property_size;
-
- dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
- if(!dma_window) {
- return NULL;
- }
-
- newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
-
- /* There should be some code to extract the phys-encoded offset
- using prom_n_addr_cells(). However, according to a comment
- on earlier versions, it's always zero, so we don't bother */
- offset = dma_window[1] >> PAGE_SHIFT;
-
- /* TCE table size - measured in tce entries */
- newTceTable->it_size = dma_window[4] >> PAGE_SHIFT;
- /* offset for VIO should always be 0 */
- newTceTable->it_offset = offset;
- newTceTable->it_busno = 0;
- newTceTable->it_index = (unsigned long)dma_window[0];
- newTceTable->it_type = TCE_VB;
-
- return iommu_init_table(newTceTable);
-}
-
-static struct vio_bus_ops vio_bus_ops_pseries = {
- .build_iommu_table = vio_build_iommu_table,
-};
-
-/**
- * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus
- */
-static int __init vio_bus_init_pseries(void)
-{
- return vio_bus_init(&vio_bus_ops_pseries);
-}
-
-__initcall(vio_bus_init_pseries);
-
-/* vio_find_name() - internal because only vio.c knows how we formatted the
- * kobject name
- * XXX once vio_bus_type.devices is actually used as a kset in
- * drivers/base/bus.c, this function should be removed in favor of
- * "device_find(kobj_name, &vio_bus_type)"
- */
-static struct vio_dev *vio_find_name(const char *kobj_name)
-{
- struct kobject *found;
-
- found = kset_find_obj(&devices_subsys.kset, kobj_name);
- if (!found)
- return NULL;
-
- return to_vio_dev(container_of(found, struct device, kobj));
-}
-
-/**
- * vio_find_node - find an already-registered vio_dev
- * @vnode: device_node of the virtual device we're looking for
- */
-struct vio_dev *vio_find_node(struct device_node *vnode)
-{
- uint32_t *unit_address;
- char kobj_name[BUS_ID_SIZE];
-
- /* construct the kobject name from the device node */
- unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
- if (!unit_address)
- return NULL;
- snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
-
- return vio_find_name(kobj_name);
-}
-EXPORT_SYMBOL(vio_find_node);
-
-int vio_enable_interrupts(struct vio_dev *dev)
-{
- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
- if (rc != H_SUCCESS)
- printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
- return rc;
-}
-EXPORT_SYMBOL(vio_enable_interrupts);
-
-int vio_disable_interrupts(struct vio_dev *dev)
-{
- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
- if (rc != H_SUCCESS)
- printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
- return rc;
-}
-EXPORT_SYMBOL(vio_disable_interrupts);
diff --git a/include/asm-powerpc/iseries/iommu.h b/include/asm-powerpc/iseries/iommu.h
new file mode 100644
index 0000000..0edbfe1
--- /dev/null
+++ b/include/asm-powerpc/iseries/iommu.h
@@ -0,0 +1,35 @@
+#ifndef _ASM_POWERPC_ISERIES_IOMMU_H
+#define _ASM_POWERPC_ISERIES_IOMMU_H
+
+/*
+ * Copyright (C) 2005 Stephen Rothwell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the:
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ */
+
+struct device_node;
+struct iommu_table;
+
+/* Creates table for an individual device node */
+extern void iommu_devnode_init_iSeries(struct device_node *dn);
+
+/* Get table parameters from HV */
+extern void iommu_table_getparms_iSeries(unsigned long busno,
+ unsigned char slotno, unsigned char virtbus,
+ struct iommu_table *tbl);
+
+#endif /* _ASM_POWERPC_ISERIES_IOMMU_H */
diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h
index 9c09a8f..10da7f3 100644
--- a/include/asm-powerpc/vio.h
+++ b/include/asm-powerpc/vio.h
@@ -64,22 +64,14 @@ struct vio_driver {
struct device_driver driver;
};
-struct vio_bus_ops {
- struct iommu_table *(*build_iommu_table)(struct vio_dev *dev);
-};
-
extern struct dma_mapping_ops vio_dma_ops;
extern struct bus_type vio_bus_type;
-extern struct vio_dev vio_bus_device;
extern int vio_register_driver(struct vio_driver *drv);
extern void vio_unregister_driver(struct vio_driver *drv);
-extern struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev);
extern void __devinit vio_unregister_device(struct vio_dev *dev);
-extern int vio_bus_init(struct vio_bus_ops *);
-
struct device_node;
extern struct vio_dev * __devinit vio_register_device_node(
--
1.3.1
^ permalink raw reply related
* [PATCH 3/4] powerpc: use a common vio_match_device routine
From: Stephen Rothwell @ 2006-04-27 7:21 UTC (permalink / raw)
To: ppc-dev
In-Reply-To: <20060427171821.6ebdf3fb.sfr@canb.auug.org.au>
This requires the compatible properties having vaules that are empty
strings instead of just being empty properties.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/kernel/vio.c | 3 ++-
arch/powerpc/platforms/iseries/setup.c | 10 +++++-----
arch/powerpc/platforms/iseries/vio.c | 12 ------------
arch/powerpc/platforms/pseries/vio.c | 12 ------------
include/asm-powerpc/vio.h | 1 -
5 files changed, 7 insertions(+), 31 deletions(-)
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
2c0c46b1d70d543203c547034bc1a78ab0fb10a9
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 9b46eed..1952929 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -47,7 +47,8 @@ static const struct vio_device_id *vio_m
const struct vio_device_id *ids, const struct vio_dev *dev)
{
while (ids->type[0] != '\0') {
- if (vio_bus_ops.match(ids, dev))
+ if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
+ device_is_compatible(dev->dev.platform_data, ids->compat))
return ids;
ids++;
}
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 901acbc..befd36a 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -927,7 +927,7 @@ void dt_vdevices(struct iseries_flat_dt
snprintf(buf, sizeof(buf), "viocons@%08x", reg);
dt_start_node(dt, buf);
dt_prop_str(dt, "device_type", "serial");
- dt_prop_empty(dt, "compatible");
+ dt_prop_str(dt, "compatible", "");
dt_prop_u32(dt, "reg", reg);
dt_end_node(dt);
reg++;
@@ -949,7 +949,7 @@ void dt_vdevices(struct iseries_flat_dt
snprintf(buf, 32, "vlan@%08x", reg + i);
dt_start_node(dt, buf);
dt_prop_str(dt, "device_type", "vlan");
- dt_prop_empty(dt, "compatible");
+ dt_prop_str(dt, "compatible", "");
dt_prop_u32(dt, "reg", reg + i);
dt_prop_u32(dt, "linux,unit_address", i);
@@ -970,7 +970,7 @@ void dt_vdevices(struct iseries_flat_dt
snprintf(buf, 32, "viodasd@%08x", reg + i);
dt_start_node(dt, buf);
dt_prop_str(dt, "device_type", "viodasd");
- dt_prop_empty(dt, "compatible");
+ dt_prop_str(dt, "compatible", "");
dt_prop_u32(dt, "reg", reg + i);
dt_prop_u32(dt, "linux,unit_address", i);
dt_end_node(dt);
@@ -980,7 +980,7 @@ void dt_vdevices(struct iseries_flat_dt
snprintf(buf, 32, "viocd@%08x", reg + i);
dt_start_node(dt, buf);
dt_prop_str(dt, "device_type", "viocd");
- dt_prop_empty(dt, "compatible");
+ dt_prop_str(dt, "compatible", "");
dt_prop_u32(dt, "reg", reg + i);
dt_prop_u32(dt, "linux,unit_address", i);
dt_end_node(dt);
@@ -990,7 +990,7 @@ void dt_vdevices(struct iseries_flat_dt
snprintf(buf, 32, "viotape@%08x", reg + i);
dt_start_node(dt, buf);
dt_prop_str(dt, "device_type", "viotape");
- dt_prop_empty(dt, "compatible");
+ dt_prop_str(dt, "compatible", "");
dt_prop_u32(dt, "reg", reg + i);
dt_prop_u32(dt, "linux,unit_address", i);
dt_end_node(dt);
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
index a689da6..bdd2b7d 100644
--- a/arch/powerpc/platforms/iseries/vio.c
+++ b/arch/powerpc/platforms/iseries/vio.c
@@ -50,18 +50,7 @@ static struct iommu_table *vio_build_iom
return &vio_iommu_table;
}
-/**
- * vio_match_device_iseries: - Tell if a iSeries VIO device matches a
- * vio_device_id
- */
-static int vio_match_device_iseries(const struct vio_device_id *id,
- const struct vio_dev *dev)
-{
- return strncmp(dev->type, id->type, strlen(id->type)) == 0;
-}
-
static struct vio_bus_ops vio_bus_ops_iseries = {
- .match = vio_match_device_iseries,
.build_iommu_table = vio_build_iommu_table,
};
@@ -75,5 +64,4 @@ static int __init vio_bus_init_iseries(v
iSeries_vio_dev = &vio_bus_device.dev;
return vio_bus_init(&vio_bus_ops_iseries);
}
-
__initcall(vio_bus_init_iseries);
diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c
index b3925ae..d289166 100644
--- a/arch/powerpc/platforms/pseries/vio.c
+++ b/arch/powerpc/platforms/pseries/vio.c
@@ -27,17 +27,6 @@ #include <asm/tce.h>
extern struct subsystem devices_subsys; /* needed for vio_find_name() */
/**
- * vio_match_device_pseries: - Tell if a pSeries VIO device matches a
- * vio_device_id
- */
-static int vio_match_device_pseries(const struct vio_device_id *id,
- const struct vio_dev *dev)
-{
- return (strncmp(dev->type, id->type, strlen(id->type)) == 0) &&
- device_is_compatible(dev->dev.platform_data, id->compat);
-}
-
-/**
* vio_build_iommu_table: - gets the dma information from OF and
* builds the TCE tree.
* @dev: the virtual device.
@@ -76,7 +65,6 @@ static struct iommu_table *vio_build_iom
}
static struct vio_bus_ops vio_bus_ops_pseries = {
- .match = vio_match_device_pseries,
.build_iommu_table = vio_build_iommu_table,
};
diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h
index 0055d8e..9c09a8f 100644
--- a/include/asm-powerpc/vio.h
+++ b/include/asm-powerpc/vio.h
@@ -65,7 +65,6 @@ struct vio_driver {
};
struct vio_bus_ops {
- int (*match)(const struct vio_device_id *id, const struct vio_dev *dev);
struct iommu_table *(*build_iommu_table)(struct vio_dev *dev);
};
--
1.3.1
^ permalink raw reply related
* [PATCH 2/4] powerpc: use the device tree for the iSeries vio bus probe
From: Stephen Rothwell @ 2006-04-27 7:18 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20060427170902.51a5a098.sfr@canb.auug.org.au>
As an added bonus, since every vio_dev now has a device_node
associated with it, hotplug now works.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/kernel/vio.c | 171 +++++++++++++++++++++++++++-----
arch/powerpc/platforms/iseries/setup.c | 4 +
arch/powerpc/platforms/iseries/vio.c | 70 ++-----------
arch/powerpc/platforms/pseries/vio.c | 147 ++--------------------------
include/asm-powerpc/vio.h | 9 +-
5 files changed, 169 insertions(+), 232 deletions(-)
Booted on an iSeries 270 and built for pSeries.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
457201dcad29a4a3fdb7230a6260dcee2c223ddb
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 971020c..9b46eed 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -22,9 +22,7 @@ #include <asm/iommu.h>
#include <asm/dma.h>
#include <asm/vio.h>
#include <asm/prom.h>
-
-static const struct vio_device_id *vio_match_device(
- const struct vio_device_id *, const struct vio_dev *);
+#include <asm/firmware.h>
struct vio_dev vio_bus_device = { /* fake "parent" device */
.name = vio_bus_device.dev.bus_id,
@@ -35,6 +33,27 @@ struct vio_dev vio_bus_device = { /* fa
static struct vio_bus_ops vio_bus_ops;
+/**
+ * vio_match_device: - Tell if a VIO device has a matching
+ * VIO device id structure.
+ * @ids: array of VIO device id structures to search in
+ * @dev: the VIO device structure to match against
+ *
+ * Used by a driver to check whether a VIO device present in the
+ * system is in its list of supported devices. Returns the matching
+ * vio_device_id structure or NULL if there is no match.
+ */
+static const struct vio_device_id *vio_match_device(
+ const struct vio_device_id *ids, const struct vio_dev *dev)
+{
+ while (ids->type[0] != '\0') {
+ if (vio_bus_ops.match(ids, dev))
+ return ids;
+ ids++;
+ }
+ return NULL;
+}
+
/*
* Convert from struct device to struct vio_dev and pass to driver.
* dev->driver has already been set by generic code because vio_bus_match
@@ -107,25 +126,76 @@ void vio_unregister_driver(struct vio_dr
EXPORT_SYMBOL(vio_unregister_driver);
/**
- * vio_match_device: - Tell if a VIO device has a matching
- * VIO device id structure.
- * @ids: array of VIO device id structures to search in
- * @dev: the VIO device structure to match against
+ * vio_register_device_node: - Register a new vio device.
+ * @of_node: The OF node for this device.
*
- * Used by a driver to check whether a VIO device present in the
- * system is in its list of supported devices. Returns the matching
- * vio_device_id structure or NULL if there is no match.
+ * Creates and initializes a vio_dev structure from the data in
+ * of_node (dev.platform_data) and adds it to the list of virtual devices.
+ * Returns a pointer to the created vio_dev or NULL if node has
+ * NULL device_type or compatible fields.
*/
-static const struct vio_device_id *vio_match_device(
- const struct vio_device_id *ids, const struct vio_dev *dev)
+struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
{
- while (ids->type[0] != '\0') {
- if (vio_bus_ops.match(ids, dev))
- return ids;
- ids++;
+ struct vio_dev *viodev;
+ unsigned int *unit_address;
+ unsigned int *irq_p;
+
+ /* we need the 'device_type' property, in order to match with drivers */
+ if (of_node->type == NULL) {
+ printk(KERN_WARNING "%s: node %s missing 'device_type'\n",
+ __FUNCTION__,
+ of_node->name ? of_node->name : "<unknown>");
+ return NULL;
}
- return NULL;
+
+ unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
+ if (unit_address == NULL) {
+ printk(KERN_WARNING "%s: node %s missing 'reg'\n",
+ __FUNCTION__,
+ of_node->name ? of_node->name : "<unknown>");
+ return NULL;
+ }
+
+ /* allocate a vio_dev for this node */
+ viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL);
+ if (viodev == NULL)
+ return NULL;
+
+ viodev->dev.platform_data = of_node_get(of_node);
+
+ viodev->irq = NO_IRQ;
+ irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
+ if (irq_p) {
+ int virq = virt_irq_create_mapping(*irq_p);
+ if (virq == NO_IRQ) {
+ printk(KERN_ERR "Unable to allocate interrupt "
+ "number for %s\n", of_node->full_name);
+ } else
+ viodev->irq = irq_offset_up(virq);
+ }
+
+ snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
+ viodev->name = of_node->name;
+ viodev->type = of_node->type;
+ viodev->unit_address = *unit_address;
+ if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+ unit_address = (unsigned int *)get_property(of_node,
+ "linux,unit_address", NULL);
+ if (unit_address != NULL)
+ viodev->unit_address = *unit_address;
+ }
+ viodev->iommu_table = vio_bus_ops.build_iommu_table(viodev);
+
+ /* register with generic device framework */
+ if (vio_register_device(viodev) == NULL) {
+ /* XXX free TCE table */
+ kfree(viodev);
+ return NULL;
+ }
+
+ return viodev;
}
+EXPORT_SYMBOL(vio_register_device_node);
/**
* vio_bus_init: - Initialize the virtual IO bus
@@ -133,6 +203,7 @@ static const struct vio_device_id *vio_m
int __init vio_bus_init(struct vio_bus_ops *ops)
{
int err;
+ struct device_node *node_vroot;
vio_bus_ops = *ops;
@@ -153,23 +224,54 @@ int __init vio_bus_init(struct vio_bus_o
return err;
}
+ node_vroot = find_devices("vdevice");
+ if (node_vroot) {
+ struct device_node *of_node;
+
+ /*
+ * Create struct vio_devices for each virtual device in
+ * the device tree. Drivers will associate with them later.
+ */
+ for (of_node = node_vroot->child; of_node != NULL;
+ of_node = of_node->sibling) {
+ printk(KERN_DEBUG "%s: processing %p\n",
+ __FUNCTION__, of_node);
+ vio_register_device_node(of_node);
+ }
+ }
+
return 0;
}
/* vio_dev refcount hit 0 */
static void __devinit vio_dev_release(struct device *dev)
{
- if (vio_bus_ops.release_device)
- vio_bus_ops.release_device(dev);
+ if (dev->platform_data) {
+ /* XXX free TCE table */
+ of_node_put(dev->platform_data);
+ }
kfree(to_vio_dev(dev));
}
-static ssize_t viodev_show_name(struct device *dev,
+static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", to_vio_dev(dev)->name);
}
-DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL);
+
+static ssize_t devspec_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct device_node *of_node = dev->platform_data;
+
+ return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none");
+}
+
+static struct device_attribute vio_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(devspec),
+ __ATTR_NULL
+};
struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev)
{
@@ -184,16 +286,12 @@ struct vio_dev * __devinit vio_register_
__FUNCTION__, viodev->dev.bus_id);
return NULL;
}
- device_create_file(&viodev->dev, &dev_attr_name);
return viodev;
}
void __devinit vio_unregister_device(struct vio_dev *viodev)
{
- if (vio_bus_ops.unregister_device)
- vio_bus_ops.unregister_device(viodev);
- device_remove_file(&viodev->dev, &dev_attr_name);
device_unregister(&viodev->dev);
}
EXPORT_SYMBOL(vio_unregister_device);
@@ -267,22 +365,23 @@ static int vio_hotplug(struct device *de
char *buffer, int buffer_size)
{
const struct vio_dev *vio_dev = to_vio_dev(dev);
+ struct device_node *dn = dev->platform_data;
char *cp;
int length;
if (!num_envp)
return -ENOMEM;
- if (!vio_dev->dev.platform_data)
+ if (!dn)
return -ENODEV;
- cp = (char *)get_property(vio_dev->dev.platform_data, "compatible", &length);
+ cp = (char *)get_property(dn, "compatible", &length);
if (!cp)
return -ENODEV;
envp[0] = buffer;
length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
vio_dev->type, cp);
- if (buffer_size - length <= 0)
+ if ((buffer_size - length) <= 0)
return -ENOMEM;
envp[1] = NULL;
return 0;
@@ -290,9 +389,25 @@ static int vio_hotplug(struct device *de
struct bus_type vio_bus_type = {
.name = "vio",
+ .dev_attrs = vio_dev_attrs,
.uevent = vio_hotplug,
.match = vio_bus_match,
.probe = vio_bus_probe,
.remove = vio_bus_remove,
.shutdown = vio_bus_shutdown,
};
+
+/**
+ * vio_get_attribute: - get attribute for virtual device
+ * @vdev: The vio device to get property.
+ * @which: The property/attribute to be extracted.
+ * @length: Pointer to length of returned data size (unused if NULL).
+ *
+ * Calls prom.c's get_property() to return the value of the
+ * attribute specified by @which
+*/
+const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
+{
+ return get_property(vdev->dev.platform_data, which, length);
+}
+EXPORT_SYMBOL(vio_get_attribute);
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 4862b8e..901acbc 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -951,6 +951,7 @@ void dt_vdevices(struct iseries_flat_dt
dt_prop_str(dt, "device_type", "vlan");
dt_prop_empty(dt, "compatible");
dt_prop_u32(dt, "reg", reg + i);
+ dt_prop_u32(dt, "linux,unit_address", i);
mac_addr[0] = 0x02;
mac_addr[1] = 0x01;
@@ -971,6 +972,7 @@ void dt_vdevices(struct iseries_flat_dt
dt_prop_str(dt, "device_type", "viodasd");
dt_prop_empty(dt, "compatible");
dt_prop_u32(dt, "reg", reg + i);
+ dt_prop_u32(dt, "linux,unit_address", i);
dt_end_node(dt);
}
reg += HVMAXARCHITECTEDVIRTUALDISKS;
@@ -980,6 +982,7 @@ void dt_vdevices(struct iseries_flat_dt
dt_prop_str(dt, "device_type", "viocd");
dt_prop_empty(dt, "compatible");
dt_prop_u32(dt, "reg", reg + i);
+ dt_prop_u32(dt, "linux,unit_address", i);
dt_end_node(dt);
}
reg += HVMAXARCHITECTEDVIRTUALCDROMS;
@@ -989,6 +992,7 @@ void dt_vdevices(struct iseries_flat_dt
dt_prop_str(dt, "device_type", "viotape");
dt_prop_empty(dt, "compatible");
dt_prop_u32(dt, "reg", reg + i);
+ dt_prop_u32(dt, "linux,unit_address", i);
dt_end_node(dt);
}
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
index 22045a2..a689da6 100644
--- a/arch/powerpc/platforms/iseries/vio.c
+++ b/arch/powerpc/platforms/iseries/vio.c
@@ -43,58 +43,11 @@ static void __init iommu_vio_init(void)
printk("Virtual Bus VIO TCE table failed.\n");
}
-/**
- * vio_register_device_iseries: - Register a new iSeries vio device.
- * @voidev: The device to register.
- */
-static struct vio_dev *__init vio_register_device_iseries(char *type,
- uint32_t unit_num)
+static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
{
- struct vio_dev *viodev;
-
- /* allocate a vio_dev for this device */
- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (!viodev)
- return NULL;
- memset(viodev, 0, sizeof(struct vio_dev));
-
- snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
-
- viodev->name = viodev->dev.bus_id;
- viodev->type = type;
- viodev->unit_address = unit_num;
- viodev->iommu_table = &vio_iommu_table;
- if (vio_register_device(viodev) == NULL) {
- kfree(viodev);
- return NULL;
- }
- return viodev;
-}
-
-static void __init probe_bus_iseries(void)
-{
- HvLpIndexMap vlan_map;
- struct vio_dev *viodev;
- int i;
-
- /* there is only one of each of these */
- vio_register_device_iseries("viocons", 0);
- vio_register_device_iseries("vscsi", 0);
-
- vlan_map = HvLpConfig_getVirtualLanIndexMap();
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
- if ((vlan_map & (0x8000 >> i)) == 0)
- continue;
- viodev = vio_register_device_iseries("vlan", i);
- /* veth is special and has it own iommu_table */
- viodev->iommu_table = &veth_iommu_table;
- }
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
- vio_register_device_iseries("viodasd", i);
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
- vio_register_device_iseries("viocd", i);
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
- vio_register_device_iseries("viotape", i);
+ if (strcmp(dev->type, "vlan") == 0)
+ return &veth_iommu_table;
+ return &vio_iommu_table;
}
/**
@@ -109,6 +62,7 @@ static int vio_match_device_iseries(cons
static struct vio_bus_ops vio_bus_ops_iseries = {
.match = vio_match_device_iseries,
+ .build_iommu_table = vio_build_iommu_table,
};
/**
@@ -116,16 +70,10 @@ static struct vio_bus_ops vio_bus_ops_is
*/
static int __init vio_bus_init_iseries(void)
{
- int err;
-
- err = vio_bus_init(&vio_bus_ops_iseries);
- if (err == 0) {
- iommu_vio_init();
- vio_bus_device.iommu_table = &vio_iommu_table;
- iSeries_vio_dev = &vio_bus_device.dev;
- probe_bus_iseries();
- }
- return err;
+ iommu_vio_init();
+ vio_bus_device.iommu_table = &vio_iommu_table;
+ iSeries_vio_dev = &vio_bus_device.dev;
+ return vio_bus_init(&vio_bus_ops_iseries);
}
__initcall(vio_bus_init_iseries);
diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c
index 8e53e04..b3925ae 100644
--- a/arch/powerpc/platforms/pseries/vio.c
+++ b/arch/powerpc/platforms/pseries/vio.c
@@ -26,26 +26,6 @@ #include <asm/tce.h>
extern struct subsystem devices_subsys; /* needed for vio_find_name() */
-static void probe_bus_pseries(void)
-{
- struct device_node *node_vroot, *of_node;
-
- node_vroot = find_devices("vdevice");
- if ((node_vroot == NULL) || (node_vroot->child == NULL))
- /* this machine doesn't do virtual IO, and that's ok */
- return;
-
- /*
- * Create struct vio_devices for each virtual device in the device tree.
- * Drivers will associate with them later.
- */
- for (of_node = node_vroot->child; of_node != NULL;
- of_node = of_node->sibling) {
- printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
- vio_register_device_node(of_node);
- }
-}
-
/**
* vio_match_device_pseries: - Tell if a pSeries VIO device matches a
* vio_device_id
@@ -57,47 +37,6 @@ static int vio_match_device_pseries(cons
device_is_compatible(dev->dev.platform_data, id->compat);
}
-static void vio_release_device_pseries(struct device *dev)
-{
- /* XXX free TCE table */
- of_node_put(dev->platform_data);
-}
-
-static ssize_t viodev_show_devspec(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct device_node *of_node = dev->platform_data;
-
- return sprintf(buf, "%s\n", of_node->full_name);
-}
-DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
-
-static void vio_unregister_device_pseries(struct vio_dev *viodev)
-{
- device_remove_file(&viodev->dev, &dev_attr_devspec);
-}
-
-static struct vio_bus_ops vio_bus_ops_pseries = {
- .match = vio_match_device_pseries,
- .unregister_device = vio_unregister_device_pseries,
- .release_device = vio_release_device_pseries,
-};
-
-/**
- * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus
- */
-static int __init vio_bus_init_pseries(void)
-{
- int err;
-
- err = vio_bus_init(&vio_bus_ops_pseries);
- if (err == 0)
- probe_bus_pseries();
- return err;
-}
-
-__initcall(vio_bus_init_pseries);
-
/**
* vio_build_iommu_table: - gets the dma information from OF and
* builds the TCE tree.
@@ -136,88 +75,20 @@ static struct iommu_table *vio_build_iom
return iommu_init_table(newTceTable);
}
+static struct vio_bus_ops vio_bus_ops_pseries = {
+ .match = vio_match_device_pseries,
+ .build_iommu_table = vio_build_iommu_table,
+};
+
/**
- * vio_register_device_node: - Register a new vio device.
- * @of_node: The OF node for this device.
- *
- * Creates and initializes a vio_dev structure from the data in
- * of_node (dev.platform_data) and adds it to the list of virtual devices.
- * Returns a pointer to the created vio_dev or NULL if node has
- * NULL device_type or compatible fields.
+ * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus
*/
-struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
+static int __init vio_bus_init_pseries(void)
{
- struct vio_dev *viodev;
- unsigned int *unit_address;
- unsigned int *irq_p;
-
- /* we need the 'device_type' property, in order to match with drivers */
- if ((NULL == of_node->type)) {
- printk(KERN_WARNING
- "%s: node %s missing 'device_type'\n", __FUNCTION__,
- of_node->name ? of_node->name : "<unknown>");
- return NULL;
- }
-
- unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
- if (!unit_address) {
- printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
- of_node->name ? of_node->name : "<unknown>");
- return NULL;
- }
-
- /* allocate a vio_dev for this node */
- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (!viodev) {
- return NULL;
- }
- memset(viodev, 0, sizeof(struct vio_dev));
-
- viodev->dev.platform_data = of_node_get(of_node);
-
- viodev->irq = NO_IRQ;
- irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
- if (irq_p) {
- int virq = virt_irq_create_mapping(*irq_p);
- if (virq == NO_IRQ) {
- printk(KERN_ERR "Unable to allocate interrupt "
- "number for %s\n", of_node->full_name);
- } else
- viodev->irq = irq_offset_up(virq);
- }
-
- snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
- viodev->name = of_node->name;
- viodev->type = of_node->type;
- viodev->unit_address = *unit_address;
- viodev->iommu_table = vio_build_iommu_table(viodev);
-
- /* register with generic device framework */
- if (vio_register_device(viodev) == NULL) {
- /* XXX free TCE table */
- kfree(viodev);
- return NULL;
- }
- device_create_file(&viodev->dev, &dev_attr_devspec);
-
- return viodev;
+ return vio_bus_init(&vio_bus_ops_pseries);
}
-EXPORT_SYMBOL(vio_register_device_node);
-/**
- * vio_get_attribute: - get attribute for virtual device
- * @vdev: The vio device to get property.
- * @which: The property/attribute to be extracted.
- * @length: Pointer to length of returned data size (unused if NULL).
- *
- * Calls prom.c's get_property() to return the value of the
- * attribute specified by the preprocessor constant @which
-*/
-const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
-{
- return get_property(vdev->dev.platform_data, (char*)which, length);
-}
-EXPORT_SYMBOL(vio_get_attribute);
+__initcall(vio_bus_init_pseries);
/* vio_find_name() - internal because only vio.c knows how we formatted the
* kobject name
diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h
index 0544ece..0055d8e 100644
--- a/include/asm-powerpc/vio.h
+++ b/include/asm-powerpc/vio.h
@@ -66,8 +66,7 @@ struct vio_driver {
struct vio_bus_ops {
int (*match)(const struct vio_device_id *id, const struct vio_dev *dev);
- void (*unregister_device)(struct vio_dev *);
- void (*release_device)(struct device *);
+ struct iommu_table *(*build_iommu_table)(struct vio_dev *dev);
};
extern struct dma_mapping_ops vio_dma_ops;
@@ -82,14 +81,14 @@ extern void __devinit vio_unregister_dev
extern int vio_bus_init(struct vio_bus_ops *);
-#ifdef CONFIG_PPC_PSERIES
struct device_node;
extern struct vio_dev * __devinit vio_register_device_node(
struct device_node *node_vdev);
-extern struct vio_dev *vio_find_node(struct device_node *vnode);
-extern const void *vio_get_attribute(struct vio_dev *vdev, void *which,
+extern const void *vio_get_attribute(struct vio_dev *vdev, char *which,
int *length);
+#ifdef CONFIG_PPC_PSERIES
+extern struct vio_dev *vio_find_node(struct device_node *vnode);
extern int vio_enable_interrupts(struct vio_dev *dev);
extern int vio_disable_interrupts(struct vio_dev *dev);
#endif
--
1.3.1
^ permalink raw reply related
* [PATCH 1/4] powerpc: add all the iSeries virtual devices to the device tree
From: Stephen Rothwell @ 2006-04-27 7:09 UTC (permalink / raw)
To: ppc-dev
We do this by putting them in the flattened device tree at setup time.
This required the flattened device tree blob to be made bigger.
Currenly we don't do anything with these.
Also make a function static.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/platforms/iseries/setup.c | 88 ++++++++++++++++++++++++++++++++
arch/powerpc/platforms/iseries/vio.c | 2 -
2 files changed, 88 insertions(+), 2 deletions(-)
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
ea41f9a9099decfb4f7b9c061e7e38defa6b4744
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 3c51448..4862b8e 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -28,6 +28,7 @@ #include <linux/kdev_t.h>
#include <linux/major.h>
#include <linux/root_dev.h>
#include <linux/kernel.h>
+#include <linux/if_ether.h> /* ETH_ALEN */
#include <asm/processor.h>
#include <asm/machdep.h>
@@ -45,6 +46,7 @@ #include <asm/paca.h>
#include <asm/cache.h>
#include <asm/sections.h>
#include <asm/abs_addr.h>
+#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_lp_config.h>
#include <asm/iseries/hv_call_event.h>
#include <asm/iseries/hv_call_xm.h>
@@ -710,7 +712,7 @@ define_machine(iseries) {
};
struct blob {
- unsigned char data[PAGE_SIZE];
+ unsigned char data[PAGE_SIZE * 2];
unsigned long next;
};
@@ -911,6 +913,88 @@ void dt_model(struct iseries_flat_dt *dt
dt_prop_str(dt, "compatible", "IBM,iSeries");
}
+void dt_vdevices(struct iseries_flat_dt *dt)
+{
+ u32 reg = 0;
+ HvLpIndexMap vlan_map;
+ int i;
+ char buf[32];
+
+ dt_start_node(dt, "vdevice");
+ dt_prop_u32(dt, "#address-cells", 1);
+ dt_prop_u32(dt, "#size-cells", 0);
+
+ snprintf(buf, sizeof(buf), "viocons@%08x", reg);
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", "serial");
+ dt_prop_empty(dt, "compatible");
+ dt_prop_u32(dt, "reg", reg);
+ dt_end_node(dt);
+ reg++;
+
+ snprintf(buf, sizeof(buf), "v-scsi@%08x", reg);
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", "vscsi");
+ dt_prop_str(dt, "compatible", "IBM,v-scsi");
+ dt_prop_u32(dt, "reg", reg);
+ dt_end_node(dt);
+ reg++;
+
+ vlan_map = HvLpConfig_getVirtualLanIndexMap();
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+ unsigned char mac_addr[ETH_ALEN];
+
+ if ((vlan_map & (0x8000 >> i)) == 0)
+ continue;
+ snprintf(buf, 32, "vlan@%08x", reg + i);
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", "vlan");
+ dt_prop_empty(dt, "compatible");
+ dt_prop_u32(dt, "reg", reg + i);
+
+ mac_addr[0] = 0x02;
+ mac_addr[1] = 0x01;
+ mac_addr[2] = 0xff;
+ mac_addr[3] = i;
+ mac_addr[4] = 0xff;
+ mac_addr[5] = HvLpConfig_getLpIndex_outline();
+ dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);
+ dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);
+
+ dt_end_node(dt);
+ }
+ reg += HVMAXARCHITECTEDVIRTUALLANS;
+
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) {
+ snprintf(buf, 32, "viodasd@%08x", reg + i);
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", "viodasd");
+ dt_prop_empty(dt, "compatible");
+ dt_prop_u32(dt, "reg", reg + i);
+ dt_end_node(dt);
+ }
+ reg += HVMAXARCHITECTEDVIRTUALDISKS;
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) {
+ snprintf(buf, 32, "viocd@%08x", reg + i);
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", "viocd");
+ dt_prop_empty(dt, "compatible");
+ dt_prop_u32(dt, "reg", reg + i);
+ dt_end_node(dt);
+ }
+ reg += HVMAXARCHITECTEDVIRTUALCDROMS;
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) {
+ snprintf(buf, 32, "viotape@%08x", reg + i);
+ dt_start_node(dt, buf);
+ dt_prop_str(dt, "device_type", "viotape");
+ dt_prop_empty(dt, "compatible");
+ dt_prop_u32(dt, "reg", reg + i);
+ dt_end_node(dt);
+ }
+
+ dt_end_node(dt);
+}
+
void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
{
u64 tmp[2];
@@ -941,6 +1025,8 @@ void build_flat_dt(struct iseries_flat_d
dt_cpus(dt);
+ dt_vdevices(dt);
+
dt_end_node(dt);
dt_push_u32(dt, OF_DT_END);
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
index ad36ab0..22045a2 100644
--- a/arch/powerpc/platforms/iseries/vio.c
+++ b/arch/powerpc/platforms/iseries/vio.c
@@ -71,7 +71,7 @@ static struct vio_dev *__init vio_regist
return viodev;
}
-void __init probe_bus_iseries(void)
+static void __init probe_bus_iseries(void)
{
HvLpIndexMap vlan_map;
struct vio_dev *viodev;
--
1.3.1
^ permalink raw reply related
* Re: PPC Linux support for Tundra TSI148
From: Gerhard Jaeger @ 2006-04-27 7:13 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: Martin, Tim
In-Reply-To: <821B2170E9E7F04FA38DF7EC21DE4871049711CD@VCAEXCH01.hq.corp.viasat.com>
See my comments inline:
On Wednesday 26 April 2006 18:24, Martin, Tim wrote:
> Gerhard,
>
> Thanks for the information. More questions...
>
> What type of transfers were you doing? (e.g. A32/D64? SST320 or SST267?)
A32/D64 and 2eSST @ SST320
> Are these transfer from userspace data, from kernelspace data, or from
> the Tundra's pattern buffer?
They are from userspace.
> What was your PCI bus speed & width?
???
> Were you using inbound/outbound windows or Tundra's DMA controller?
DMA - via /dev/vme_dma0 interface
> What was the Tundra chipset configuration for the 168 MBps?
i.e. Buffersize 64K, 4K alignment, 2K PCI Fifo and 1K VME Fifo.
Using the Tundra driver and its interface structure, I used a
request level of 2, fairmode is set to normal, timeon timeout timer
is set to 7 and timeoff is set to no waiting (0).
>
> Thanks,
> Tim
>
> > -----Original Message-----
> > From: linuxppc-embedded-bounces+tmartin=viasat.com@ozlabs.org
> > [mailto:linuxppc-embedded-bounces+tmartin=viasat.com@ozlabs.org] On
> Behalf
> > Of Gerhard Jaeger
> > Sent: Wednesday, April 26, 2006 12:26 AM
> > To: linuxppc-embedded@ozlabs.org
> > Subject: Re: PPC Linux support for Tundra TSI148
> >
> > On Wednesday 26 April 2006 01:47, Martin, Tim wrote:
> > > Does anyone out there have any real world measured performance of a
> > > Linux PowerPC (kernel module + user space application) doing 2eSST
> VME
> > > transfers with the Tundra TSI148 chipset?
> > >
> > > Tundra has a Linux driver available for the Motorola MVME6100 , but
> told
> > > me they don't have any performance data available. I'm looking for
> > > sustained throughput rates, not the peak burst rates (e.g. 320 MBps,
> 267
> > > MBps).
> > >
> >
> > Hi,
> >
> > I've done here some tests between two MVME6100, while updating the
> 6100
> > BSP
> > for our embedded Linux distro. Depending on the buffersize, alignment,
> VME
> > and
> > PCI FIFO settings we have (without further optimizations) throughput
> rates
> > ranging
> > from 100MBps up to 168MBps. I think some tuning could still be done.
> >
> >HTH
> > Gerhard
--
Gerhard Jaeger <gjaeger@sysgo.com>
SYSGO AG Embedded and Real-Time Software
www.sysgo.com | www.elinos.com | www.pikeos.com | www.osek.de
^ permalink raw reply
* linux 2.4.26 bummer problem
From: Prakash N @ 2006-04-27 6:06 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 7060 bytes --]
Hi,
Iam trying to run linux 2.4.26 from mvista in xilinx XUPV2P board.
During booting I get this error message,
Mounted devfs on /dev
.
Freeing unused kernel memory: 60k init
init started: BusyBox v1.1.2 (2006.04.24-13:20+0000) multi-call binary
Starting pid 11, console /dev/console: '/etc/init.d/rcS'
Bummer, could not run '/etc/init.d/rcS': No such file or directory
Bummer, could not run
ML300 powerpc linux 2.4.21-pre7 E.I.S. edition
(none) login:
.
But I could see in the generated root file system this file is there.
Even its not logging with anything.
My inittab file is
::sysinit:/etc/init.d/rcS
#::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
::respawn:/sbin/getty 9600 tts/0
Without init options specified in busybox configuration I got,
.
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
mount_devfs_fs(): unable to mount devfs, err: -5
Freeing unused kernel memory: 60k init
Warning: unable to open an initial console.
Kernel panic: No init found. Try passing init= option to kernel.
Some replies in usenet, which I answered,
- x bits set for this shell script?
SInce Iam new to this embedded linux, could you tell whats that x bits means, is it exec permission (if so for whom,root?).
- does a shell run?
Iam not clear why does it say /etc/init.d/rcS is not there, while its definitely there.
I feel shell is not running. I want to just put what I get in minicom
----------------------------------------------------------------------------------------------------------------------------------------
loaded at: 00400000 004C11E4
board data at: 004BE13C 004BE154
relocated to: 00405634 0040564C
zimage at: 00405BF9 004BDD33
avail ram: 004C2000 10000000
Linux/PPC load: console=ttyS0,9600 root=/dev/xsysace/disc0/part2 rw
Uncompressing Linux...done.
Now booting the kernel
Linux version 2.4.26 (root@edvl28.cedt.iisc.ernet.in) (gcc version 3.4.1) #16 Sat Apr 22 15:19:6Xilinx Virtex-II Pro port (C) 2002 MontaVista Software, Inc. (source@mvista.com)
On node 0 totalpages: 65536
zone(0): 65536 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: console=ttyS0,9600 root=/dev/xsysace/disc0/part2 rw
Xilinx INTC #0 at 0x41200000 mapped to 0xFDFFE000
Calibrating delay loop... 299.00 BogoMIPS
Memory: 257332k available (1284k kernel code, 380k data, 60k init, 0k highmem)
Dentry cache hash table entries: 32768 (order: 6, 262144 bytes)
Inode cache hash table entries: 16384 (order: 5, 131072 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer cache hash table entries: 16384 (order: 4, 65536 bytes)
Page-cache hash table entries: 65536 (order: 6, 262144 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
Starting kswapd
devfs: v1.12c (20020818) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.
pty: 256 Unix98 ptys configured
Serial driver version 5.05c (2001-07-08) with no serial options enabled
ttyS00 at 0xfdfff003 (irq = 29) is a 16550A
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
loop: loaded (max 8 devices)
Partition check:
xsysacea: p1 p2
System ACE at 0x41800000 mapped to 0xD1070000, irq=30, 250880KB
eth0: using fifo mode.
eth0: No PHY detected. Assuming a PHY at address 0.
eth0: Xilinx EMAC #0 at 0x40C00000 mapped to 0xD1083000, irq=31
eth0: id 2.0h; block id 7, type 1
SCSI subsystem driver Revision: 1.00
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 2048 buckets, 16Kbytes
TCP: Hash tables configured (established 16384 bind 32768)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
Mounted devfs on /dev
Freeing unused kernel memory: 60k init
init started: BusyBox v1.1.2 (2006.04.27-03:52+0000) multi-call binary
Starting pid 11, console /dev/console: '/etc/init.d/rcS'
Bummer, could not run '/etc/init.d/rcS': No such file or directory
Bummer, could not run '/etc/init.d/rcS': No such file
ML300 powerpc linux 2.4.21-pre7 E.I.S. edition
(none) login:
-----------------------------------------------------------------------------------------------------------------------------------
Here If I type su or root or whatever it asks password but always says incorrect login.
- try init=/bin/sh as a kernel parameter. Does it run?
My init tab file is
----------------------------------------------------------------------------------------------------------------------------
::init=/bin/sh
::sysinit:/etc/init.d/rcS
#::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
::respawn:/sbin/getty 9600 tts/0
------------------------------------------------------------------------------------------------------------------------------
The log is
..........
VFS: Mounted root (ext2 filesystem).
mount_devfs_fs(): unable to mount devfs, err: -5
Freeing unused kernel memory: 60k init
Warning: unable to open an initial console.
Kernel panic: No init found. Try passing init= option to kernel.
<0>Rebooting in 180 seconds..
-----------------------------------------------------------------------------------------------------------------
- all needed libraries to run available on your target?
I feel yes, as I could see these in lib folder of my RFS.
ld-2.3.3.so libdl.so.2 libnss_dns.so.2 libpthread.so.0
ld.so.1 libgcc_s_nof.so.1 libnss_files-2.3.3.so libresolv-2.3.3.so
libanl-2.3.3.so libgcc_s.so.1 libnss_files.so.2 libresolv.so.2
libanl.so.1 libm-2.3.3.so libnss_hesiod-2.3.3.so librt-2.3.3.so
libBrokenLocale-2.3.3.so libmemusage.so libnss_hesiod.so.2 librt.so.1
libBrokenLocale.so.1 libm.so.6 libnss_nis-2.3.3.so libSegFault.so
libc-2.3.3.so libnsl-2.3.3.so libnss_nisplus-2.3.3.so libstdc++.so.6
libcrypt-2.3.3.so libnsl.so.1 libnss_nisplus.so.2 libthread_db-1.0.so
libcrypt.so.1 libnss_compat-2.3.3.so libnss_nis.so.2 libthread_db.so.1
libc.so.6 libnss_compat.so.2 libpcprofile.so libutil-2.3.3.so
libdl-2.3.3.so libnss_dns-2.3.3.so libpthread-0.10.so libutil.so.1
guide me where Iam wrong
Prakash
---------------------------------
Jiyo cricket on Yahoo! India cricket
Yahoo! Messenger Mobile Stay in touch with your buddies all the time.
[-- Attachment #2: Type: text/html, Size: 9201 bytes --]
^ permalink raw reply
* Linux 2.4 devel on ML403 board : problem with prompt
From: jean-francois.hasson @ 2006-04-27 6:06 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
I am trying to port linux 2.4 devel to ML403. I have used advices from this
mailing list and some websites and finally got to th epoint where
everything seems find except I cannot get the boot prompt. I have used
busybox 1.0.1 and it seems init runs well, rcS runs well and afterr that I
do not get the prompt. I have activated the askfirst line in inittab and I
am asked to hit enter to go further but all I get is, automatically,
without hitting the keyboard, is character X. I do not seem to have any
echo. I have the console node defined in /dev. Has anyone an idea as to
what I have done wrong ?
Best regards,
JF Hasson
#
This e-mail and any attached documents may contain confidential or proprietary information. If you are not the intended recipient, please advise the sender immediately and delete this e-mail and all attached documents from your computer system. Any unauthorised disclosure, distribution or copying hereof is prohibited.
Ce courriel et les documents qui y sont attaches peuvent contenir des informations confidentielles. Au cas ou vous ne seriez pas le destinataire de ce courriel, vous etes prie d'en informer l'expediteur immediatement et de le detruire ainsi que tous les documents attaches de votre systeme informatique. Toute divulgation, distribution ou copie du present courriel et des documents attaches sans autorisation prealable de son emetteur est interdite.
#
^ permalink raw reply
* Re: Linux 2.6 sources for MPC852T processor
From: Dan Malek @ 2006-04-26 23:32 UTC (permalink / raw)
To: David Jander; +Cc: linuxppc-embedded
In-Reply-To: <200604261350.05295.david.jander@protonic.nl>
On Apr 26, 2006, at 7:50 AM, David Jander wrote:
> Yes, MPC852T is supported, although I might add that I have been
> using 2.6.14
> and 2.6.15 sucessfully with our own MPC852T-based board, but 2.6.16
> did not
> boot and as of today I don't know why, or whether this is an issue
> at all
> with boards other than ours.
There is a horrible bug in the 8xx TLB miss handler that is in the
2.6.16
sources. I don't know when it appeared. Enable the CPU6 Errata
workaround to see if that solves the problem and please report back
to me. I'm working on a solution.
Thanks.
-- Dan
^ permalink raw reply
* Re: PPC 405GPr support in linux 2.4.32
From: Stephen Williams @ 2006-04-26 23:57 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <20060426163540.H16236@cox.net>
Matt Porter wrote:
> On Wed, Apr 26, 2006 at 04:19:23PM -0700, Stephen Williams wrote:
>> ... seems completely missing in the linux-2.3.32 tree from kernel.org.
>> This used to be in the linuxppc-2.4 BK tree that no longer exists, so
>> what happened to the ppc405GPr support?!
>
> There's some stuff that never got submitted upstream to kernel.org
> during 2.4 due partially to 2.5 appearing. All upstream devel
> moved to 2.5/2.6 and no effort was made to merge stuff from the
> linuxppc-2.4 tree to linux-2.4. Oh, and Marcelo didn't want
> to take "new stuff" into linux-2.4 at that time either.
>
> There's still rsync://source.mvista.com/linuxppc-2.4 available with
> the 405gpr/sycamore support.
Well then I guess for 405GPr support and the SystemACE drivers
I'm on my own. Is there a git tree for main line 2.4 maintenance
(against which I could maintain patches) or am I on my own there
too?
It should be easy enough to rescue the gpr support form the bk
working dir that I have (or the mvista repository as you point
out) and make up patches.
--
Steve Williams "The woods are lovely, dark and deep.
steve at icarus.com But I have promises to keep,
http://www.icarus.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep."
^ permalink raw reply
* Re: PPC 405GPr support in linux 2.4.32
From: Matt Porter @ 2006-04-26 23:35 UTC (permalink / raw)
To: Stephen Williams; +Cc: linuxppc-embedded
In-Reply-To: <e2ov5s$1hn$1@sea.gmane.org>
On Wed, Apr 26, 2006 at 04:19:23PM -0700, Stephen Williams wrote:
> ... seems completely missing in the linux-2.3.32 tree from kernel.org.
> This used to be in the linuxppc-2.4 BK tree that no longer exists, so
> what happened to the ppc405GPr support?!
There's some stuff that never got submitted upstream to kernel.org
during 2.4 due partially to 2.5 appearing. All upstream devel
moved to 2.5/2.6 and no effort was made to merge stuff from the
linuxppc-2.4 tree to linux-2.4. Oh, and Marcelo didn't want
to take "new stuff" into linux-2.4 at that time either.
There's still rsync://source.mvista.com/linuxppc-2.4 available with
the 405gpr/sycamore support.
-Matt
^ permalink raw reply
* Re: PPC 405GPr support in linux 2.4.32
From: Tolunay Orkun @ 2006-04-26 23:48 UTC (permalink / raw)
To: Stephen Williams; +Cc: linuxppc-embedded
In-Reply-To: <e2ov5s$1hn$1@sea.gmane.org>
Stephen Williams wrote:
> ... seems completely missing in the linux-2.3.32 tree from kernel.org.
> This used to be in the linuxppc-2.4 BK tree that no longer exists, so
> what happened to the ppc405GPr support?!
I guess nobody sent patches upstream and development shifted to 2.6
kernel. 405Gpr is not alone. 405EP and a number of other CPU support
that was present never got its way up kernel.org sources.
^ permalink raw reply
* Re: [Fastboot] Documentation feedback request.
From: Michael Ellerman @ 2006-04-26 23:44 UTC (permalink / raw)
To: David Wilder; +Cc: linuxppc-dev list, fastboot
In-Reply-To: <444FB2AF.3020802@us.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 11643 bytes --]
Hi David,
Nice work. Few comments below ...
On Wed, 2006-04-26 at 10:49 -0700, David Wilder wrote:
> Attached is a updated Documentation/kdump/kdump.txt. Please provide
> comments. I will incorporate your feedback and send up to Linus.
>
> plain text document attachment (kdump-final-20060425.txt)
> ================================================================
> Documentation for Kdump - The kexec-based Crash Dumping Solution
> ================================================================
>
> This document includes overview, setup and installation, and analysis
> information.
>
> Overview
> ========
>
> Kdump uses kexec to quickly boot to a dump-capture kernel whenever a
> dump of the system kernel's memory needs to be taken (for example, when
> the system panics). The system kernel's memory image is preserved across
> the reboot and is accessible to the dump-capture kernel.
>
> You can use common Linux commands, such as cp and scp, to copy the
> memory image to a dump file on the local disk, or across the network to
> a remote system.
>
> Kdump and kexec are currently supported on the x86, x86_64, and ppc64
> architectures.
s/ppc64/64-bit powerpc/ ?
> When the system kernel boots, it reserves a small section of memory for
> the dump-capture kernel. This ensures that ongoing Direct Memory Access
> (DMA) from the system kernel does not corrupt the dump-capture kernel.
> The kexec -p command loads the dump-capture kernel into this reserved
> memory.
Well hopefully ;)
> On x86 machines, the first 640 KB of physical memory is needed to boot,
> regardless of where the kernel loads. Therefore, kexec backs up this
> region just before rebooting into the dump-capture kernel.
>
> All of the necessary information about the system kernel's core image is
> encoded in the ELF format, and stored in a reserved area of memory
> before a crash. The physical address of the start of the ELF header is
> passed to the dump-capture kernel through the elfcorehdr= boot
> parameter.
>
> With the dump-capture kernel, you can access the memory image, or "old
> memory," in two ways:
>
> - Through a /dev/oldmem device interface. A capture utility can read the
> device file and write out the memory in raw format. This is a raw dump
> of memory. Analysis and capture tools must be intelligent enough to
> determine where to look for the right information.
>
> - Through /proc/vmcore. This exports the dump as an ELF-format file that
> you can write out using file copy commands such as cp or scp. Further,
> you can use analysis tools such as the GNU Debugger (GDB) and the Crash
> tool to debug the dump file. This method ensures that the dump pages are
> correctly ordered.
>
>
> Setup and Installation
> ======================
>
> Install kexec-tools and the Kdump patch
> ---------------------------------------
>
> 1) Login as the root user.
>
> 2) Download the kexec-tools user-space package from the following URL:
>
> http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz
>
> 3) Unpack the tarball with the tar command, as follows:
>
> tar xvpzf kexec-tools-1.101.tar.gz
>
> 4) Download the latest consolidated Kdump patch from the following URL:
>
> http://lse.sourceforge.net/kdump/
>
> (This location is being used until all the user-space Kdump patches
> are integrated with the kexec-tools package.)
>
> 5) Change to the kexec-tools-1.101 directory, as follows:
>
> cd kexec-tools-1.101
>
> 6) Apply the consolidated patch to the kexec-tools-1.101 source tree
> with the patch command, as follows. (Modify the path to the downloaded
> patch as necessary.)
>
> patch -p1 < /path-to-kdump-patch/kexec-tools-1.101-kdump.patch
>
> 7) Configure the package, as follows:
>
> ./configure
>
> 8) Compile the package, as follows:
>
> make
>
> 9) Install the package, as follows:
>
> make install
>
>
> Download and build the system and dump-capture kernels
> ------------------------------------------------------
>
> Download the mainline (vanilla) kernel source code (2.6.13-rc1 or newer)
> from http://www.kernel.org. Two kernels must be built: a system kernel
> and a dump-capture kernel. Use the following steps to configure these
> kernels with the necessary kexec and Kdump features:
>
> System kernel
> -------------
>
> 1) Enable "kexec system call" in "Processor type and features."
>
> CONFIG_KEXEC=y
>
> 2) Enable "sysfs file system support" in "Filesystem" -> "Pseudo
> filesystems." This is usually enabled by default.
>
> CONFIG_SYSFS=y
>
> Note that "sysfs file system support" might not appear in the "Pseudo
> filesystems" menu if "Configure standard kernel features (for small
> systems)" is not enabled in "General Setup." In this case, check the
> .config file itself to ensure that sysfs is turned on, as follows:
>
> grep 'CONFIG_SYSFS' .config
Is there a particular requirement for sysfs?
> 3) Enable "Compile the kernel with debug info" in "Kernel hacking."
>
> CONFIG_DEBUG_INFO=Y
>
> This causes the kernel to be built with debug symbols. The dump
> analysis tools require a vmlinux with debug symbols in order to read
> and analyze a dump file.
>
> 4) Make and install the kernel and its modules. Update the boot loader
> (such as grub, yaboot, or lilo) configuration files as necessary.
>
> 5) Boot the system kernel with the boot parameter "crashkernel=Y@X",
> where Y specifies how much memory to reserve for the dump-capture kernel
> and X specifies the beginning of this reserved memory. For example,
> "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
> starting at physical address 0x01000000 for the dump-capture kernel.
Most of this doesn't apply to powerpc.
> On x86 and x86_64, use "crashkernel=64M@16M".
>
> On ppc64, use "crashkernel=128M@32M".
No just use "crashkernel=128M".
> The dump-capture kernel
> -----------------------
>
> 1) Under "General setup," append "-kdump" to the current string in
> "Local version."
>
> 2) On x86, enable high memory support under "Processor type and
> features":
>
> CONFIG_HIGHMEM=y
>
> 3) On x86 and x86_64, disable symmetric multi-processing support
> under "Processor type and features":
>
> CONFIG_SMP=n
>
> 4) On ppc64, disable NUMA support and enable EMBEDDED support:
>
> CONFIG_NUMA=n
> CONFIG_EMBEDDED=y
> CONFIG_EEH=N for the dump-capture kernel
Why are we disabling NUMA? AFAIK we work on more systems with NUMA than
without?
And why are we turning off EMBEDDED and EEH?
> 5) Enable "kernel crash dumps" support under "Processor type and
> features":
>
> CONFIG_CRASH_DUMP=y
>
> 6) Use a suitable value for "Physical address where the kernel is
> loaded" (under "Processor type and features"). This only appears when
> "kernel crash dumps" is enabled. By default this value is 0x1000000
> (16MB). It should be the same as X in the "crashkernel=Y@X" boot
> parameter discussed above.
>
> On x86 and x86_64, use "CONFIG_PHYSICAL_START=0x1000000".
>
> On ppc64 the value is automatically set at 32MB when
> CONFIG_CRASH_DUMP is set.
This whole step should start "On x86 ..."
> 6) Optionally enable "/proc/vmcore support" under "Filesystems" ->
> "Pseudo filesystems".
6 + 1 = 6 :D
> CONFIG_PROC_VMCORE=y
>
> 7) Make and install the kernel and its modules. DO NOT add this kernel
> to the boot loader configuration files.
>
>
> Load the Dump-capture Kernel
> ============================
>
> After booting to the system kernel, load the dump-capture kernel using
> the following command:
>
> kexec -p <dump-capture-kernel> \
> --initrd=<initrd-for-dump-capture-kernel> --args-linux \
> --append="root=<root-dev> init 1 irqpoll"
I've never tested irqpoll on powerpc, I'm not sure we want to recommend
it, has someone tested it?
> Notes on loading the dump-capture kernel:
>
> * <dump-capture-kernel> must be a vmlinux image (that is, an
> uncompressed ELF image). bzImage does not work at this time.
>
> * By default, the ELF headers are stored in ELF64 format to support
> systems with more than 4GB memory. The --elf32-core-headers option can
> be used to force the generation of ELF32 headers. This is necessary
> because GDB currently cannot open vmcore files with ELF64 headers on
> 32-bit systems. ELF32 headers can be used on non-PAE systems (that is,
> less than 4GB of memory).
>
> * The "irqpoll" boot parameter reduces driver initialization failures
> due to shared interrupts in the dump-capture kernel.
>
> * You must specify <root-dev> in the format corresponding to the root
> device name in the output of mount command.
> * "init 1" boots the dump-capture kernel into single-user mode without
> networking. If you want networking, use "init 3."
>
>
> Kernel Panic
> ============
>
> After successfully loading the dump-capture kernel as previously
> described, the system will reboot into the dump-capture kernel if a
> panic occurs. You can write a module to force the panic, or use
> "ALT-SysRq-c" to initiate a crash dump for testing purposes.
>
>
> Write Out the Dump File
> =======================
>
> After the dump-capture kernel is booted, write out the dump file with
> the following command:
>
> cp /proc/vmcore <dump-file>
>
> You can also access dumped memory as a /dev/oldmem device for a linear
> and raw view. To create the device, use the following command:
>
> mknod /dev/oldmem c 1 12
>
> Use the dd command with suitable options for count, bs, and skip to
> access specific portions of the dump.
>
> To see the entire memory, use the following command:
>
> dd if=/dev/oldmem of=oldmem.001
>
>
> Analysis
> ========
>
> Before analyzing the dump image, you should reboot into a stable kernel.
>
> You can do limited analysis using GDB on the dump file copied out of
> /proc/vmcore. Use the debug vmlinux built with -g and run the following
> command:
>
> gdb vmlinux <dump-file>
>
> Stack trace for the task on processor 0, register display, and memory
> display work fine.
>
> Note: GDB cannot analyze core files generated in ELF64 format for x86.
> On systems with a maximum of 4GB of memory, you can generate
> ELF32-format headers using the --elf32-core-headers kernel option on the
> dump kernel.
>
> You can also use the Crash utility to analyze dump files in Kdump
> format. Crash is available on Dave Anderson's site at the following URL:
>
> http://people.redhat.com/~anderson/
>
>
> To Do
> =====
>
> 1) Provide a kernel pages filtering mechanism, so core file size is not
> extreme on systems with huge memory banks.
>
> 2) Relocatable kernel can help in maintaining multiple kernels for
> crash_dump, and the same kernel as the system kernel can be used to
> capture the dump.
>
>
> Contact
> =======
>
> Vivek Goyal (vgoyal@in.ibm.com)
> Maneesh Soni (maneesh@in.ibm.com)
fastboot@lists.osdl.org
cheers
--
Michael Ellerman
IBM OzLabs
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox