* [PATCH 09/16] ehca: event queue
From: Heiko J Schick @ 2006-05-15 17:42 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>
drivers/infiniband/hw/ehca/ehca_eq.c | 222 +++++++++++++++++++++++++++++++++++
1 file changed, 222 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-05-15 13:29:49.000000000 +0200
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+#define DEB_PREFIX "e_eq"
+
+#include "ehca_classes.h"
+#include "ehca_irq.h"
+#include "ehca_iverbs.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)
+ goto create_eq_exit2;
+ } else {
+ if (ret != H_PAGE_REGISTERED || !vpage)
+ 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 h_ret = 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);
+
+ h_ret = hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
+
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4, "Can't free EQ resources.");
+ return -EINVAL;
+ }
+ ipz_queue_dtor(&eq->ipz_queue);
+
+ EDEB_EX(7, "h_ret=%lx", h_ret);
+
+ return h_ret;
+}
^ permalink raw reply
* [PATCH 10/16] ehca: completion queue
From: Heiko J Schick @ 2006-05-15 17:42 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>
drivers/infiniband/hw/ehca/ehca_cq.c | 431 +++++++++++++++++++++++++++++++++++
1 file changed, 431 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-05-15 14:56:34.000000000 +0200
@@ -0,0 +1,431 @@
+/*
+ * 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.
+ */
+
+#define DEB_PREFIX "e_cq"
+
+#include <asm/current.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) {
+ 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;
+ struct ehca_shca *shca = NULL;
+ struct ipz_adapter_handle adapter_handle;
+ /* h_call's out parameters */
+ struct ehca_alloc_cq_parms param;
+ u32 counter = 0;
+ void *vpage = NULL;
+ u64 rpage = 0;
+ struct h_galpa gal;
+ u64 cqx_fec = 0;
+ u64 h_ret = 0;
+ 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);
+
+ if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
+ return ERR_PTR(-EINVAL);
+
+ my_cq = kmem_cache_alloc(ehca_module.cache_cq, SLAB_KERNEL);
+ if (!my_cq) {
+ 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));
+ memset(¶m, 0, sizeof(struct ehca_alloc_cq_parms));
+
+ 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;
+ param.eq_handle = shca->eq.ipz_eq_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;
+ }
+
+ /* CQs maximum depth is 4GB-64, but we need additional 20 as buffer
+ * for receiving errors CQEs.
+ */
+ param.nr_cqe = cqe + additional_cqe;
+ h_ret = hipz_h_alloc_resource_cq(adapter_handle, my_cq, ¶m);
+
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4,"hipz_h_alloc_resource_cq() failed "
+ "h_ret=%lx device=%p", h_ret, device);
+ cq = ERR_PTR(ehca2ib_return_code(h_ret));
+ goto create_cq_exit2;
+ }
+
+ ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.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 < param.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);
+
+ h_ret = hipz_h_register_rpage_cq(adapter_handle,
+ my_cq->ipz_cq_handle,
+ &my_cq->pf,
+ 0,
+ 0,
+ rpage,
+ 1,
+ my_cq->galpas.
+ kernel);
+
+ if (h_ret < H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_register_rpage_cq() failed "
+ "ehca_cq=%p cq_num=%x h_ret=%lx "
+ "counter=%i act_pages=%i",
+ my_cq, my_cq->cq_number,
+ h_ret, counter, param.act_pages);
+ cq = ERR_PTR(-EINVAL);
+ goto create_cq_exit4;
+ }
+
+ if (counter == (param.act_pages - 1)) {
+ vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
+ if ((h_ret != H_SUCCESS) || vpage) {
+ EDEB_ERR(4, "Registration of pages not "
+ "complete ehca_cq=%p cq_num=%x "
+ "h_ret=%lx",
+ my_cq, my_cq->cq_number, h_ret);
+ cq = ERR_PTR(-EAGAIN);
+ goto create_cq_exit4;
+ }
+ } else {
+ if (h_ret != H_PAGE_REGISTERED) {
+ EDEB_ERR(4, "Registration of page failed "
+ "ehca_cq=%p cq_num=%x h_ret=%lx"
+ "counter=%i act_pages=%i",
+ my_cq, my_cq->cq_number,
+ h_ret, counter, param.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 =
+ param.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, param.act_nr_of_entries);
+ return cq;
+
+create_cq_exit4:
+ ipz_queue_dtor(&my_cq->ipz_queue);
+
+create_cq_exit3:
+ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
+ EDEB(3, "hipz_h_destroy_cq() failed ehca_cq=%p cq_num=%x h_ret=%lx",
+ my_cq, my_cq->cq_number, h_ret);
+
+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 h_ret = 0;
+ int ret = 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)
+ yield();
+
+ idr_remove(&ehca_cq_idr, my_cq->token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (my_cq->uspace_queue && 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 ) {
+ ret = ehca_munmap(my_cq->uspace_queue,
+ my_cq->ipz_queue.queue_length);
+ ret = ehca_munmap(my_cq->uspace_fwh, 4096);
+ }
+
+ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
+ if (h_ret == 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);
+ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
+ if (h_ret == H_SUCCESS)
+ EDEB(4, "ehca_cq=%p cq_num=%x deleted successfully.",
+ my_cq, my_cq->cq_number);
+ }
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4,"hipz_h_destroy_cq() failed "
+ "h_ret=%lx ehca_cq=%p cq_num=%x",
+ h_ret, my_cq, my_cq->cq_number);
+ ret = ehca2ib_return_code(h_ret);
+ 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 ret=%x ",
+ my_cq, cq_num, ret);
+ return ret;
+}
+
+int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct ehca_cq *my_cq = NULL;
+ u32 cur_pid = current->tgid;
+
+ if (unlikely(!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 && 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 */
+ ret = -EFAULT;
+ EDEB_ERR(4, "not implemented yet");
+
+ EDEB_EX(7, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+ return ret;
+}
^ permalink raw reply
* [PATCH 11/16] ehca: queue pair
From: Heiko J Schick @ 2006-05-15 17:42 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>
drivers/infiniband/hw/ehca/ehca_qes.h | 274 +++++
drivers/infiniband/hw/ehca/ehca_qp.c | 1565 +++++++++++++++++++++++++++++++++
drivers/infiniband/hw/ehca/ehca_reqs.c | 683 ++++++++++++++
drivers/infiniband/hw/ehca/ehca_sqp.c | 123 ++
4 files changed, 2645 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_qes.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_qes.h 2006-05-02 10:55:26.000000000 +0200
@@ -0,0 +1,274 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Hardware request structures
+ *
+ * Authors: Waleri Fomin <fomin@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.
+ */
+
+
+#ifndef _EHCA_QES_H_
+#define _EHCA_QES_H_
+
+#include "ehca_tools.h"
+
+/**
+ * virtual scatter gather entry to specify remote adresses with length
+ */
+struct ehca_vsgentry {
+ u64 vaddr;
+ u32 lkey;
+ u32 length;
+};
+
+#define GRH_FLAG_MASK EHCA_BMASK_IBM(7,7)
+#define GRH_IPVERSION_MASK EHCA_BMASK_IBM(0,3)
+#define GRH_TCLASS_MASK EHCA_BMASK_IBM(4,12)
+#define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13,31)
+#define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32,47)
+#define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48,55)
+#define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56,63)
+
+/**
+ * Unreliable Datagram Address Vector Format
+ * see IBTA Vol1 chapter 8.3 Global Routing Header
+ */
+struct ehca_ud_av {
+ u8 sl;
+ u8 lnh;
+ u16 dlid;
+ u8 reserved1;
+ u8 reserved2;
+ u8 reserved3;
+ u8 slid_path_bits;
+ u8 reserved4;
+ u8 ipd;
+ u8 reserved5;
+ u8 pmtu;
+ u32 reserved6;
+ u64 reserved7;
+ union {
+ struct {
+ u64 word_0; /* always set to 6 */
+ /*should be 0x1B for IB transport */
+ u64 word_1;
+ u64 word_2;
+ u64 word_3;
+ u64 word_4;
+ } grh;
+ struct {
+ u32 wd_0;
+ u32 wd_1;
+ /* DWord_1 --> SGID */
+
+ u32 sgid_wd3;
+ /* bits 127 - 96 */
+
+ u32 sgid_wd2;
+ /* bits 95 - 64 */
+ /* DWord_2 */
+
+ u32 sgid_wd1;
+ /* bits 63 - 32 */
+
+ u32 sgid_wd0;
+ /* bits 31 - 0 */
+ /* DWord_3 --> DGID */
+
+ u32 dgid_wd3;
+ /* bits 127 - 96
+ **/
+ u32 dgid_wd2;
+ /* bits 95 - 64
+ DWord_4 */
+ u32 dgid_wd1;
+ /* bits 63 - 32 */
+
+ u32 dgid_wd0;
+ /* bits 31 - 0 */
+ } grh_l;
+ };
+};
+
+/* maximum number of sg entries allowed in a WQE */
+#define MAX_WQE_SG_ENTRIES 252
+
+#define WQE_OPTYPE_SEND 0x80
+#define WQE_OPTYPE_RDMAREAD 0x40
+#define WQE_OPTYPE_RDMAWRITE 0x20
+#define WQE_OPTYPE_CMPSWAP 0x10
+#define WQE_OPTYPE_FETCHADD 0x08
+#define WQE_OPTYPE_BIND 0x04
+
+#define WQE_WRFLAG_REQ_SIGNAL_COM 0x80
+#define WQE_WRFLAG_FENCE 0x40
+#define WQE_WRFLAG_IMM_DATA_PRESENT 0x20
+#define WQE_WRFLAG_SOLIC_EVENT 0x10
+
+#define WQEF_CACHE_HINT 0x80
+#define WQEF_CACHE_HINT_RD_WR 0x40
+#define WQEF_TIMED_WQE 0x20
+#define WQEF_PURGE 0x08
+#define WQEF_HIGH_NIBBLE 0xF0
+
+#define MW_BIND_ACCESSCTRL_R_WRITE 0x40
+#define MW_BIND_ACCESSCTRL_R_READ 0x20
+#define MW_BIND_ACCESSCTRL_R_ATOMIC 0x10
+
+struct ehca_wqe {
+ u64 work_request_id;
+ u8 optype;
+ u8 wr_flag;
+ u16 pkeyi;
+ u8 wqef;
+ u8 nr_of_data_seg;
+ u16 wqe_provided_slid;
+ u32 destination_qp_number;
+ u32 resync_psn_sqp;
+ u32 local_ee_context_qkey;
+ u32 immediate_data;
+ union {
+ struct {
+ u64 remote_virtual_adress;
+ u32 rkey;
+ u32 reserved;
+ u64 atomic_1st_op_dma_len;
+ u64 atomic_2nd_op;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
+
+ } nud;
+ struct {
+ u64 ehca_ud_av_ptr;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
+ } ud_avp;
+ struct {
+ struct ehca_ud_av ud_av;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES -
+ 2];
+ } ud_av;
+ struct {
+ u64 reserved0;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
+ } all_rcv;
+
+ struct {
+ u64 reserved;
+ u32 rkey;
+ u32 old_rkey;
+ u64 reserved1;
+ u64 reserved2;
+ u64 virtual_address;
+ u32 reserved3;
+ u32 length;
+ u32 reserved4;
+ u16 reserved5;
+ u8 reserved6;
+ u8 lr_ctl;
+ u32 lkey;
+ u32 reserved7;
+ u64 reserved8;
+ u64 reserved9;
+ u64 reserved10;
+ u64 reserved11;
+ } bind;
+ struct {
+ u64 reserved12;
+ u64 reserved13;
+ u32 size;
+ u32 start;
+ } inline_data;
+ } u;
+
+};
+
+#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
+#define WC_IMM_DATA EHCA_BMASK_IBM(1,1)
+#define WC_GRH_PRESENT EHCA_BMASK_IBM(2,2)
+#define WC_SE_BIT EHCA_BMASK_IBM(3,3)
+#define WC_STATUS_ERROR_BIT 0x80000000
+#define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
+#define WC_STATUS_PURGE_BIT 0x10
+
+struct ehca_cqe {
+ u64 work_request_id;
+ u8 optype;
+ u8 w_completion_flags;
+ u16 reserved1;
+ u32 nr_bytes_transferred;
+ u32 immediate_data;
+ u32 local_qp_number;
+ u8 freed_resource_count;
+ u8 service_level;
+ u16 wqe_count;
+ u32 qp_token;
+ u32 qkey_ee_token;
+ u32 remote_qp_number;
+ u16 dlid;
+ u16 rlid;
+ u16 reserved2;
+ u16 pkey_index;
+ u32 cqe_timestamp;
+ u32 wqe_timestamp;
+ u8 wqe_timestamp_valid;
+ u8 reserved3;
+ u8 reserved4;
+ u8 cqe_flags;
+ u32 status;
+};
+
+struct ehca_eqe {
+ u64 entry;
+};
+
+struct ehca_mrte {
+ u64 starting_va;
+ u64 length; /* length of memory region in bytes*/
+ u32 pd;
+ u8 key_instance;
+ u8 pagesize;
+ u8 mr_control;
+ u8 local_remote_access_ctrl;
+ u8 reserved[0x20 - 0x18];
+ u64 at_pointer[4];
+};
+#endif /*_EHCA_QES_H_*/
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_qp.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_qp.c 2006-05-15 15:43:31.000000000 +0200
@@ -0,0 +1,1565 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * QP functions
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Reinhard Ernst <rernst@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.
+ */
+
+
+#define DEB_PREFIX "e_qp"
+
+#include <asm/current.h>
+
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+#include "hipz_fns.h"
+
+/**
+ * attributes not supported by query qp
+ */
+#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \
+ IB_QP_MAX_QP_RD_ATOMIC | \
+ IB_QP_ACCESS_FLAGS | \
+ IB_QP_EN_SQD_ASYNC_NOTIFY)
+
+/**
+ * ehca (internal) qp state values
+ */
+enum ehca_qp_state {
+ EHCA_QPS_RESET = 1,
+ EHCA_QPS_INIT = 2,
+ EHCA_QPS_RTR = 3,
+ EHCA_QPS_RTS = 5,
+ EHCA_QPS_SQD = 6,
+ EHCA_QPS_SQE = 8,
+ EHCA_QPS_ERR = 128
+};
+
+/**
+ * qp state transitions as defined by IB Arch Rel 1.1 page 431
+ */
+enum ib_qp_statetrans {
+ IB_QPST_ANY2RESET,
+ IB_QPST_ANY2ERR,
+ IB_QPST_RESET2INIT,
+ IB_QPST_INIT2RTR,
+ IB_QPST_INIT2INIT,
+ IB_QPST_RTR2RTS,
+ IB_QPST_RTS2SQD,
+ IB_QPST_RTS2RTS,
+ IB_QPST_SQD2RTS,
+ IB_QPST_SQE2RTS,
+ IB_QPST_SQD2SQD,
+ IB_QPST_MAX /* nr of transitions, this must be last!!! */
+};
+
+/**
+ * ib2ehca_qp_state - maps IB to ehca qp_state
+ * returns ehca qp state corresponding to given ib qp state
+ */
+static inline enum ehca_qp_state ib2ehca_qp_state(enum ib_qp_state ib_qp_state)
+{
+ switch (ib_qp_state) {
+ case IB_QPS_RESET:
+ return EHCA_QPS_RESET;
+ case IB_QPS_INIT:
+ return EHCA_QPS_INIT;
+ case IB_QPS_RTR:
+ return EHCA_QPS_RTR;
+ case IB_QPS_RTS:
+ return EHCA_QPS_RTS;
+ case IB_QPS_SQD:
+ return EHCA_QPS_SQD;
+ case IB_QPS_SQE:
+ return EHCA_QPS_SQE;
+ case IB_QPS_ERR:
+ return EHCA_QPS_ERR;
+ default:
+ EDEB_ERR(4, "invalid ib_qp_state=%x", ib_qp_state);
+ return -EINVAL;
+ }
+}
+
+/**
+ * ehca2ib_qp_state - maps ehca to IB qp_state
+ * returns ib qp state corresponding to given ehca qp state
+ */
+static inline enum ib_qp_state ehca2ib_qp_state(enum ehca_qp_state
+ ehca_qp_state)
+{
+ switch (ehca_qp_state) {
+ case EHCA_QPS_RESET:
+ return IB_QPS_RESET;
+ case EHCA_QPS_INIT:
+ return IB_QPS_INIT;
+ case EHCA_QPS_RTR:
+ return IB_QPS_RTR;
+ case EHCA_QPS_RTS:
+ return IB_QPS_RTS;
+ case EHCA_QPS_SQD:
+ return IB_QPS_SQD;
+ case EHCA_QPS_SQE:
+ return IB_QPS_SQE;
+ case EHCA_QPS_ERR:
+ return IB_QPS_ERR;
+ default:
+ EDEB_ERR(4,"invalid ehca_qp_state=%x",ehca_qp_state);
+ return -EINVAL;
+ }
+}
+
+/**
+ * ehca_qp_type - used as index for req_attr and opt_attr of
+ * struct ehca_modqp_statetrans
+ */
+enum ehca_qp_type {
+ QPT_RC = 0,
+ QPT_UC = 1,
+ QPT_UD = 2,
+ QPT_SQP = 3,
+ QPT_MAX
+};
+
+/**
+ * ib2ehcaqptype - maps Ib to ehca qp_type
+ * returns ehca qp type corresponding to ib qp type
+ */
+static inline enum ehca_qp_type ib2ehcaqptype(enum ib_qp_type ibqptype)
+{
+ switch (ibqptype) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ return QPT_SQP;
+ case IB_QPT_RC:
+ return QPT_RC;
+ case IB_QPT_UC:
+ return QPT_UC;
+ case IB_QPT_UD:
+ return QPT_UD;
+ default:
+ EDEB_ERR(4,"Invalid ibqptype=%x", ibqptype);
+ return -EINVAL;
+ }
+}
+
+static inline enum ib_qp_statetrans get_modqp_statetrans(int ib_fromstate,
+ int ib_tostate)
+{
+ int index = -EINVAL;
+ switch (ib_tostate) {
+ case IB_QPS_RESET:
+ index = IB_QPST_ANY2RESET;
+ break;
+ case IB_QPS_INIT:
+ if (ib_fromstate == IB_QPS_RESET)
+ index = IB_QPST_RESET2INIT;
+ else if (ib_fromstate == IB_QPS_INIT)
+ index = IB_QPST_INIT2INIT;
+ break;
+ case IB_QPS_RTR:
+ if (ib_fromstate == IB_QPS_INIT)
+ index = IB_QPST_INIT2RTR;
+ break;
+ case IB_QPS_RTS:
+ if (ib_fromstate == IB_QPS_RTR)
+ index = IB_QPST_RTR2RTS;
+ else if (ib_fromstate == IB_QPS_RTS)
+ index = IB_QPST_RTS2RTS;
+ else if (ib_fromstate == IB_QPS_SQD)
+ index = IB_QPST_SQD2RTS;
+ else if (ib_fromstate == IB_QPS_SQE)
+ index = IB_QPST_SQE2RTS;
+ break;
+ case IB_QPS_SQD:
+ if (ib_fromstate == IB_QPS_RTS)
+ index = IB_QPST_RTS2SQD;
+ break;
+ case IB_QPS_SQE:
+ break;
+ case IB_QPS_ERR:
+ index = IB_QPST_ANY2ERR;
+ break;
+ default:
+ break;
+ }
+ return index;
+}
+
+enum ehca_service_type {
+ ST_RC = 0,
+ ST_UC = 1,
+ ST_RD = 2,
+ ST_UD = 3
+};
+
+/**
+ * ibqptype2servicetype - returns hcp service type corresponding to given
+ * ib qp type used by create_qp()
+ */
+static inline int ibqptype2servicetype(enum ib_qp_type ibqptype)
+{
+ switch (ibqptype) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ return ST_UD;
+ case IB_QPT_RC:
+ return ST_RC;
+ case IB_QPT_UC:
+ return ST_UC;
+ case IB_QPT_UD:
+ return ST_UD;
+ case IB_QPT_RAW_IPV6:
+ return -EINVAL;
+ case IB_QPT_RAW_ETY:
+ return -EINVAL;
+ default:
+ EDEB_ERR(4, "Invalid ibqptype=%x", ibqptype);
+ return -EINVAL;
+ }
+}
+
+/**
+ * init_qp_queues - Initializes/constructs r/squeue and registers queue pages.
+ */
+static inline int init_qp_queues(struct ipz_adapter_handle ipz_hca_handle,
+ struct ehca_qp *my_qp,
+ int nr_sq_pages,
+ int nr_rq_pages,
+ int swqe_size,
+ int rwqe_size,
+ int nr_send_sges, int nr_receive_sges)
+{
+ int ret = -EINVAL;
+ int cnt = 0;
+ void *vpage = NULL;
+ u64 rpage = 0;
+ int ipz_rc = -1;
+ u64 h_ret = H_PARAMETER;
+
+ ipz_rc = ipz_queue_ctor(&my_qp->ipz_squeue,
+ nr_sq_pages,
+ EHCA_PAGESIZE, swqe_size, nr_send_sges);
+ if (!ipz_rc) {
+ EDEB_ERR(4, "Cannot allocate page for squeue. ipz_rc=%x",
+ ipz_rc);
+ ret = -EBUSY;
+ return ret;
+ }
+
+ ipz_rc = ipz_queue_ctor(&my_qp->ipz_rqueue,
+ nr_rq_pages,
+ EHCA_PAGESIZE, rwqe_size, nr_receive_sges);
+ if (!ipz_rc) {
+ EDEB_ERR(4, "Cannot allocate page for rqueue. ipz_rc=%x",
+ ipz_rc);
+ ret = -EBUSY;
+ goto init_qp_queues0;
+ }
+ /* register SQ pages */
+ for (cnt = 0; cnt < nr_sq_pages; cnt++) {
+ vpage = ipz_qpageit_get_inc(&my_qp->ipz_squeue);
+ if (!vpage) {
+ EDEB_ERR(4, "SQ ipz_qpageit_get_inc() "
+ "failed p_vpage= %p", vpage);
+ ret = -EINVAL;
+ goto init_qp_queues1;
+ }
+ rpage = virt_to_abs(vpage);
+
+ h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf, 0, 0,
+ rpage, 1,
+ my_qp->galpas.kernel);
+ if (h_ret < H_SUCCESS) {
+ EDEB_ERR(4,"SQ hipz_qp_register_rpage() faield "
+ "rc=%lx", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ }
+
+ ipz_qeit_reset(&my_qp->ipz_squeue);
+
+ /* register RQ pages */
+ for (cnt = 0; cnt < nr_rq_pages; cnt++) {
+ vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
+ if (!vpage) {
+ EDEB_ERR(4,"RQ ipz_qpageit_get_inc() "
+ "failed p_vpage = %p", vpage);
+ h_ret = H_RESOURCE;
+ ret = -EINVAL;
+ goto init_qp_queues1;
+ }
+
+ rpage = virt_to_abs(vpage);
+
+ h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf, 0, 1,
+ rpage, 1,my_qp->galpas.kernel);
+ if (h_ret < H_SUCCESS) {
+ EDEB_ERR(4, "RQ hipz_qp_register_rpage() failed "
+ "rc=%lx", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ if (cnt == (nr_rq_pages - 1)) { /* last page! */
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4,"RQ hipz_qp_register_rpage() "
+ "h_ret= %lx ", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
+ if (vpage) {
+ EDEB_ERR(4,"ipz_qpageit_get_inc() "
+ "should not succeed vpage=%p",
+ vpage);
+ ret = -EINVAL;
+ goto init_qp_queues1;
+ }
+ } else {
+ if (h_ret != H_PAGE_REGISTERED) {
+ EDEB_ERR(4,"RQ hipz_qp_register_rpage() "
+ "h_ret= %lx ", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&my_qp->ipz_rqueue);
+
+ return 0;
+
+init_qp_queues1:
+ ipz_queue_dtor(&my_qp->ipz_rqueue);
+init_qp_queues0:
+ ipz_queue_dtor(&my_qp->ipz_squeue);
+ return ret;
+}
+
+
+struct ib_qp *ehca_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ extern struct ehca_module ehca_module;
+ static int da_msg_size[]={ 128, 256, 512, 1024, 2048, 4096 };
+ int ret = -EINVAL;
+
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_pd *my_pd = NULL;
+ struct ehca_shca *shca = NULL;
+ struct ib_ucontext *context = NULL;
+ u64 h_ret = H_PARAMETER;
+ int max_send_sge;
+ int max_recv_sge;
+
+ /* h_call's out parameters */
+ struct ehca_alloc_qp_parms parms;
+ u32 qp_nr = 0, swqe_size = 0, rwqe_size = 0;
+ u8 daqp_completion, isdaqp;
+ unsigned long flags;
+
+ EDEB_EN(7,"pd=%p init_attr=%p", pd, init_attr);
+ EHCA_CHECK_PD_P(pd);
+ EHCA_CHECK_ADR_P(init_attr);
+
+ if (init_attr->sq_sig_type != IB_SIGNAL_REQ_WR &&
+ init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {
+ EDEB_ERR(4, "init_attr->sg_sig_type=%x not allowed",
+ init_attr->sq_sig_type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* save daqp completion bits */
+ daqp_completion = init_attr->qp_type & 0x60;
+ /* save daqp bit */
+ isdaqp = (init_attr->qp_type & 0x80) ? 1 : 0;
+ init_attr->qp_type = init_attr->qp_type & 0x1F;
+
+ if (init_attr->qp_type != IB_QPT_UD &&
+ init_attr->qp_type != IB_QPT_SMI &&
+ init_attr->qp_type != IB_QPT_GSI &&
+ init_attr->qp_type != IB_QPT_UC &&
+ init_attr->qp_type != IB_QPT_RC) {
+ EDEB_ERR(4,"wrong QP Type=%x",init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ }
+ if (init_attr->qp_type != IB_QPT_RC && isdaqp != 0) {
+ EDEB_ERR(4,"unsupported LL QP Type=%x",init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (pd->uobject && udata)
+ context = pd->uobject->context;
+
+ my_qp = kmem_cache_alloc(ehca_module.cache_qp, SLAB_KERNEL);
+ if (!my_qp) {
+ EDEB_ERR(4, "pd=%p not enough memory to alloc qp", pd);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(my_qp, 0, sizeof(struct ehca_qp));
+ memset (&parms, 0, sizeof(struct ehca_alloc_qp_parms));
+ spin_lock_init(&my_qp->spinlock_s);
+ spin_lock_init(&my_qp->spinlock_r);
+
+ my_pd = container_of(pd, struct ehca_pd, ib_pd);
+
+ shca = container_of(pd->device, struct ehca_shca, ib_device);
+ my_qp->recv_cq =
+ container_of(init_attr->recv_cq, struct ehca_cq, ib_cq);
+ my_qp->send_cq =
+ container_of(init_attr->send_cq, struct ehca_cq, ib_cq);
+
+ my_qp->init_attr = *init_attr;
+
+ do {
+ if (!idr_pre_get(&ehca_qp_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ EDEB_ERR(4, "Can't reserve idr resources.");
+ goto create_qp_exit0;
+ }
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ } while (ret == -EAGAIN);
+
+ if (ret) {
+ ret = -ENOMEM;
+ EDEB_ERR(4, "Can't allocate new idr entry.");
+ goto create_qp_exit0;
+ }
+
+ parms.servicetype = ibqptype2servicetype(init_attr->qp_type);
+ if (parms.servicetype < 0) {
+ ret = -EINVAL;
+ EDEB_ERR(4, "Invalid qp_type=%x", init_attr->qp_type);
+ goto create_qp_exit0;
+ }
+
+ if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+ parms.sigtype = HCALL_SIGT_EVERY;
+ else
+ parms.sigtype = HCALL_SIGT_BY_WQE;
+
+ /* UD_AV CIRCUMVENTION */
+ max_send_sge = init_attr->cap.max_send_sge;
+ max_recv_sge = init_attr->cap.max_recv_sge;
+ if (IB_QPT_UD == init_attr->qp_type ||
+ IB_QPT_GSI == init_attr->qp_type ||
+ IB_QPT_SMI == init_attr->qp_type) {
+ max_send_sge += 2;
+ max_recv_sge += 2;
+ }
+
+ EDEB(7, "isdaqp=%x daqp_completion=%x", isdaqp, daqp_completion);
+
+ parms.ipz_eq_handle = shca->eq.ipz_eq_handle;
+ parms.daqp_ctrl = isdaqp | daqp_completion;
+ parms.pd = my_pd->fw_pd;
+ parms.max_recv_sge = max_recv_sge;
+ parms.max_send_sge = max_send_sge;
+
+ h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, my_qp, &parms);
+
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4, "h_alloc_resource_qp() failed h_ret=%lx", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto create_qp_exit1;
+ }
+
+ switch (init_attr->qp_type) {
+ case IB_QPT_RC:
+ if (isdaqp == 0) {
+ swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
+ (parms.act_nr_send_sges)]);
+ rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
+ (parms.act_nr_recv_sges)]);
+ } else { /* for daqp we need to use msg size, not wqe size */
+ swqe_size = da_msg_size[max_send_sge];
+ rwqe_size = da_msg_size[max_recv_sge];
+ parms.act_nr_send_sges = 1;
+ parms.act_nr_recv_sges = 1;
+ }
+ break;
+ case IB_QPT_UC:
+ swqe_size = offsetof(struct ehca_wqe,
+ u.nud.sg_list[parms.act_nr_send_sges]);
+ rwqe_size = offsetof(struct ehca_wqe,
+ u.nud.sg_list[parms.act_nr_recv_sges]);
+ break;
+
+ case IB_QPT_UD:
+ case IB_QPT_GSI:
+ case IB_QPT_SMI:
+ /* UD circumvention */
+ parms.act_nr_recv_sges -= 2;
+ parms.act_nr_send_sges -= 2;
+ swqe_size = offsetof(struct ehca_wqe,
+ u.ud_av.sg_list[parms.act_nr_send_sges]);
+ rwqe_size = offsetof(struct ehca_wqe,
+ u.ud_av.sg_list[parms.act_nr_recv_sges]);
+
+ if (IB_QPT_GSI == init_attr->qp_type ||
+ IB_QPT_SMI == init_attr->qp_type) {
+ parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
+ parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
+ parms.act_nr_send_sges = init_attr->cap.max_send_sge;
+ parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
+ my_qp->real_qp_num =
+ (init_attr->qp_type == IB_QPT_SMI) ? 0 : 1;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ /* initializes r/squeue and registers queue pages */
+ ret = init_qp_queues(shca->ipz_hca_handle, my_qp,
+ parms.nr_sq_pages, parms.nr_rq_pages,
+ swqe_size, rwqe_size,
+ parms.act_nr_send_sges, parms.act_nr_recv_sges);
+ if (ret) {
+ EDEB_ERR(4,"Couldn't initialize r/squeue and pages ret=%x",
+ ret);
+ goto create_qp_exit2;
+ }
+
+ my_qp->ib_qp.pd = &my_pd->ib_pd;
+ my_qp->ib_qp.device = my_pd->ib_pd.device;
+
+ my_qp->ib_qp.recv_cq = init_attr->recv_cq;
+ my_qp->ib_qp.send_cq = init_attr->send_cq;
+
+ my_qp->ib_qp.qp_num = my_qp->real_qp_num;
+ my_qp->ib_qp.qp_type = init_attr->qp_type;
+
+ my_qp->qp_type = init_attr->qp_type;
+ my_qp->ib_qp.srq = init_attr->srq;
+
+ my_qp->ib_qp.qp_context = init_attr->qp_context;
+ my_qp->ib_qp.event_handler = init_attr->event_handler;
+
+ init_attr->cap.max_inline_data = 0; /* not supported yet */
+ init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
+ init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
+ init_attr->cap.max_send_sge = parms.act_nr_send_sges;
+ init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
+
+ /* NOTE: define_apq0() not supported yet */
+ if (init_attr->qp_type == IB_QPT_GSI) {
+ h_ret = ehca_define_sqp(shca, my_qp, init_attr);
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4, "ehca_define_sqp() failed rc=%lx",h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto create_qp_exit3;
+ }
+ }
+ if (init_attr->send_cq) {
+ struct ehca_cq *cq = container_of(init_attr->send_cq,
+ struct ehca_cq, ib_cq);
+ ret = ehca_cq_assign_qp(cq, my_qp);
+ if (ret) {
+ EDEB_ERR(4, "Couldn't assign qp to send_cq ret=%x",
+ ret);
+ goto create_qp_exit3;
+ }
+ my_qp->send_cq = cq;
+ }
+ /* copy queues, galpa data to user space */
+ if (context && udata) {
+ struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
+ struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
+ struct ehca_create_qp_resp resp;
+ struct vm_area_struct * vma;
+ memset(&resp, 0, sizeof(resp));
+
+ resp.qp_num = my_qp->real_qp_num;
+ resp.token = my_qp->token;
+ resp.qp_type = my_qp->qp_type;
+ resp.qkey = my_qp->qkey;
+ resp.real_qp_num = my_qp->real_qp_num;
+ /* rqueue properties */
+ resp.ipz_rqueue.qe_size = ipz_rqueue->qe_size;
+ resp.ipz_rqueue.act_nr_of_sg = ipz_rqueue->act_nr_of_sg;
+ resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
+ resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
+ resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
+ ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
+ ipz_rqueue->queue_length,
+ ((void**)&resp.ipz_rqueue.queue),
+ &vma);
+ my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
+ /* squeue properties */
+ resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
+ resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
+ resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
+ resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
+ resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
+ ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
+ ipz_squeue->queue_length,
+ ((void**)&resp.ipz_squeue.queue),
+ &vma);
+ my_qp->uspace_squeue = resp.ipz_squeue.queue;
+ /* fw_handle */
+ resp.galpas = my_qp->galpas;
+ ehca_mmap_register(my_qp->galpas.user.fw_handle,
+ ((void**)&resp.galpas.kernel.fw_handle),
+ &vma);
+ my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
+
+ if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+ EDEB_ERR(4, "Copy to udata failed");
+ ret = -EINVAL;
+ goto create_qp_exit3;
+ }
+ }
+
+ EDEB_EX(7, "ehca_qp=%p qp_num=%x, token=%x",
+ my_qp, qp_nr, my_qp->token);
+ return &my_qp->ib_qp;
+
+create_qp_exit3:
+ ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(&my_qp->ipz_squeue);
+
+create_qp_exit2:
+ hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
+
+create_qp_exit1:
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ idr_remove(&ehca_qp_idr, my_qp->token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+create_qp_exit0:
+ kmem_cache_free(ehca_module.cache_qp, my_qp);
+ EDEB_EX(4, "failed ret=%x", ret);
+ return ERR_PTR(ret);
+
+}
+
+/**
+ * prepare_sqe_rts - called by internal_modify_qp() at trans sqe -> rts
+ * set purge bit of bad wqe and subsequent wqes to avoid reentering sqe
+ * returns total number of bad wqes in bad_wqe_cnt
+ */
+static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
+ int *bad_wqe_cnt)
+{
+ int ret = 0;
+ u64 h_ret = H_SUCCESS;
+ struct ipz_queue *squeue = NULL;
+ void *bad_send_wqe_p = NULL;
+ void *bad_send_wqe_v = NULL;
+ void *squeue_start_p = NULL;
+ void *squeue_end_p = NULL;
+ void *squeue_start_v = NULL;
+ void *squeue_end_v = NULL;
+ struct ehca_wqe *wqe = NULL;
+ int qp_num = my_qp->ib_qp.qp_num;
+
+ EDEB_EN(7, "ehca_qp=%p qp_num=%x ", my_qp, qp_num);
+
+ /* get send wqe pointer */
+ h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle, &my_qp->pf,
+ &bad_send_wqe_p, NULL, 2);
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_disable_and_get_wqe() failed "
+ "ehca_qp=%p qp_num=%x h_ret=%lx",my_qp, qp_num, h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto prepare_sqe_rts_exit1;
+ }
+ bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
+ EDEB(7, "qp_num=%x bad_send_wqe_p=%p", qp_num, bad_send_wqe_p);
+ /* convert wqe pointer to vadr */
+ bad_send_wqe_v = abs_to_virt((u64)bad_send_wqe_p);
+ EDEB_DMP(6, bad_send_wqe_v, 32, "qp_num=%x bad_wqe", qp_num);
+ squeue = &my_qp->ipz_squeue;
+ squeue_start_p = (void*)virt_to_abs(ipz_qeit_calc(squeue, 0L));
+ squeue_end_p = squeue_start_p+squeue->queue_length;
+ squeue_start_v = abs_to_virt((u64)squeue_start_p);
+ squeue_end_v = abs_to_virt((u64)squeue_end_p);
+ EDEB(6, "qp_num=%x squeue_start_v=%p squeue_end_v=%p",
+ qp_num, squeue_start_v, squeue_end_v);
+
+ /* loop sets wqe's purge bit */
+ wqe = (struct ehca_wqe*)bad_send_wqe_v;
+ *bad_wqe_cnt = 0;
+ while (wqe->optype != 0xff && wqe->wqef != 0xff) {
+ EDEB_DMP(6, wqe, 32, "qp_num=%x wqe", qp_num);
+ wqe->nr_of_data_seg = 0; /* suppress data access */
+ wqe->wqef = WQEF_PURGE; /* WQE to be purged */
+ wqe = (struct ehca_wqe*)((u8*)wqe+squeue->qe_size);
+ *bad_wqe_cnt = (*bad_wqe_cnt)+1;
+ if ((void*)wqe >= squeue_end_v) {
+ wqe = squeue_start_v;
+ }
+ }
+ /* bad wqe will be reprocessed and ignored when pol_cq() is called,
+ * i.e. nr of wqes with flush error status is one less
+ */
+ EDEB(6, "qp_num=%x flusherr_wqe_cnt=%x", qp_num, (*bad_wqe_cnt)-1);
+ wqe->wqef = 0;
+
+prepare_sqe_rts_exit1:
+
+ EDEB_EX(7, "ehca_qp=%p qp_num=%x ret=%x", my_qp, qp_num, ret);
+ return ret;
+}
+
+/**
+ * internal_modify_qp - with circumvention to handle aqp0 properly
+ * smi_reset2init indicates if this is an internal reset-to-init-call for
+ * smi. This flag must always be zero if called from ehca_modify_qp()!
+ * This internal func was intorduced to avoid recursion of ehca_modify_qp()!
+ */
+static int internal_modify_qp(struct ib_qp *ibqp,
+ struct ib_qp_attr *attr,
+ int attr_mask, int smi_reset2init)
+{
+ enum ib_qp_state qp_cur_state = 0, qp_new_state = 0;
+ int cnt = 0, qp_attr_idx = 0, ret = 0;
+
+ enum ib_qp_statetrans statetrans;
+ struct hcp_modify_qp_control_block *mqpcb = NULL;
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_shca *shca = NULL;
+ u64 update_mask = 0;
+ u64 h_ret = H_SUCCESS;
+ int bad_wqe_cnt = 0;
+ int squeue_locked = 0;
+ unsigned long spl_flags = 0;
+
+ my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ shca = container_of(ibqp->pd->device, struct ehca_shca, ib_device);
+
+ EDEB_EN(7, "ehca_qp=%p qp_num=%x ibqp_type=%x "
+ "new qp_state=%x attribute_mask=%x",
+ my_qp, ibqp->qp_num, ibqp->qp_type,
+ attr->qp_state, attr_mask);
+
+ /* do query_qp to obtain current attr values */
+ mqpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (mqpcb == NULL) {
+ ret = -ENOMEM;
+ EDEB_ERR(4, "Could not get zeroed page for mqpcb "
+ "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
+ goto modify_qp_exit0;
+ }
+
+ h_ret = hipz_h_query_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ mqpcb, my_qp->galpas.kernel);
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_query_qp() failed "
+ "ehca_qp=%p qp_num=%x h_ret=%lx",
+ my_qp, ibqp->qp_num, h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto modify_qp_exit1;
+ }
+ EDEB(7, "ehca_qp=%p qp_num=%x ehca_qp_state=%x",
+ my_qp, ibqp->qp_num, mqpcb->qp_state);
+
+ qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state);
+
+ if (qp_cur_state == -EINVAL) { /* invalid qp state */
+ ret = -EINVAL;
+ EDEB_ERR(4, "Invalid current ehca_qp_state=%x "
+ "ehca_qp=%p qp_num=%x",
+ mqpcb->qp_state, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+ /* circumvention to set aqp0 initial state to init
+ as expected by IB spec */
+ if (smi_reset2init == 0 &&
+ ibqp->qp_type == IB_QPT_SMI &&
+ qp_cur_state == IB_QPS_RESET &&
+ (attr_mask & IB_QP_STATE) &&
+ attr->qp_state == IB_QPS_INIT) { /* RESET -> INIT */
+ struct ib_qp_attr smiqp_attr = {
+ .qp_state = IB_QPS_INIT,
+ .port_num = my_qp->init_attr.port_num,
+ .pkey_index = 0,
+ .qkey = 0
+ };
+ int smiqp_attr_mask = IB_QP_STATE | IB_QP_PORT |
+ IB_QP_PKEY_INDEX | IB_QP_QKEY;
+ int smirc = internal_modify_qp(
+ ibqp, &smiqp_attr, smiqp_attr_mask, 1);
+ if (smirc) {
+ EDEB_ERR(4, "SMI RESET -> INIT failed. "
+ "ehca_modify_qp() rc=%x", smirc);
+ ret = H_PARAMETER;
+ goto modify_qp_exit1;
+ }
+ qp_cur_state = IB_QPS_INIT;
+ EDEB(7, "SMI RESET -> INIT succeeded");
+ }
+ /* is transmitted current state equal to "real" current state */
+ if ((attr_mask & IB_QP_CUR_STATE) &&
+ qp_cur_state != attr->cur_qp_state) {
+ ret = -EINVAL;
+ EDEB_ERR(4, "Invalid IB_QP_CUR_STATE attr->curr_qp_state=%x <>"
+ " actual cur_qp_state=%x. ehca_qp=%p qp_num=%x",
+ attr->cur_qp_state, qp_cur_state, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ EDEB(7, "ehca_qp=%p qp_num=%x current qp_state=%x "
+ "new qp_state=%x attribute_mask=%x",
+ my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
+
+ qp_new_state = attr_mask & IB_QP_STATE ? attr->qp_state : qp_cur_state;
+ if (!smi_reset2init &&
+ !ib_modify_qp_is_ok(qp_cur_state, qp_new_state, ibqp->qp_type,
+ attr_mask)) {
+ ret = -EINVAL;
+ EDEB_ERR(4, "Invalid qp transition new_state=%x cur_state=%x "
+ "ehca_qp=%p qp_num=%x attr_mask=%x",
+ qp_new_state, qp_cur_state, my_qp, ibqp->qp_num,
+ attr_mask);
+ goto modify_qp_exit1;
+ }
+
+ if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
+ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
+ else {
+ ret = -EINVAL;
+ EDEB_ERR(4, "Invalid new qp state=%x "
+ "ehca_qp=%p qp_num=%x",
+ qp_new_state, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ /* retrieve state transition struct to get req and opt attrs */
+ statetrans = get_modqp_statetrans(qp_cur_state, qp_new_state);
+ if (statetrans < 0) {
+ ret = -EINVAL;
+ EDEB_ERR(4, "<INVALID STATE CHANGE> qp_cur_state=%x "
+ "new_qp_state=%x State_xsition=%x "
+ "ehca_qp=%p qp_num=%x",
+ qp_cur_state, qp_new_state,
+ statetrans, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ qp_attr_idx = ib2ehcaqptype(ibqp->qp_type);
+
+ if (qp_attr_idx < 0) {
+ ret = qp_attr_idx;
+ EDEB_ERR(4, "Invalid QP type=%x ehca_qp=%p qp_num=%x",
+ ibqp->qp_type, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ EDEB(7, "ehca_qp=%p qp_num=%x <VALID STATE CHANGE> qp_state_xsit=%x",
+ my_qp, ibqp->qp_num, statetrans);
+
+ /* sqe -> rts: set purge bit of bad wqe before actual trans */
+ if ((my_qp->qp_type == IB_QPT_UD ||
+ my_qp->qp_type == IB_QPT_GSI ||
+ my_qp->qp_type == IB_QPT_SMI) &&
+ statetrans == IB_QPST_SQE2RTS) {
+ /* mark next free wqe if kernel */
+ if (my_qp->uspace_squeue == 0) {
+ struct ehca_wqe *wqe = NULL;
+ /* lock send queue */
+ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
+ squeue_locked = 1;
+ /* mark next free wqe */
+ wqe = (struct ehca_wqe*)
+ ipz_qeit_get(&my_qp->ipz_squeue);
+ wqe->optype = wqe->wqef = 0xff;
+ EDEB(7, "qp_num=%x next_free_wqe=%p",
+ ibqp->qp_num, wqe);
+ }
+ ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt);
+ if (ret) {
+ EDEB_ERR(4, "prepare_sqe_rts() failed "
+ "ehca_qp=%p qp_num=%x ret=%x",
+ my_qp, ibqp->qp_num, ret);
+ goto modify_qp_exit2;
+ }
+ }
+
+ /* enable RDMA_Atomic_Control if reset->init und reliable con
+ this is necessary since gen2 does not provide that flag,
+ but pHyp requires it */
+ if (statetrans == IB_QPST_RESET2INIT &&
+ (ibqp->qp_type == IB_QPT_RC || ibqp->qp_type == IB_QPT_UC)) {
+ mqpcb->rdma_atomic_ctrl = 3;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RDMA_ATOMIC_CTRL, 1);
+ }
+ /* circ. pHyp requires #RDMA/Atomic Resp Res for UC INIT -> RTR */
+ if (statetrans == IB_QPST_INIT2RTR &&
+ (ibqp->qp_type == IB_QPT_UC) &&
+ !(attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)) {
+ mqpcb->rdma_nr_atomic_resp_res = 1; /* default to 1 */
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
+ }
+
+ if (attr_mask & IB_QP_PKEY_INDEX) {
+ mqpcb->prim_p_key_idx = attr->pkey_index;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x "
+ "IB_QP_PKEY_INDEX update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_PORT) {
+ if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
+ ret = -EINVAL;
+ EDEB_ERR(4, "Invalid port=%x. "
+ "ehca_qp=%p qp_num=%x num_ports=%x",
+ attr->port_num, my_qp, ibqp->qp_num,
+ shca->num_ports);
+ goto modify_qp_exit2;
+ }
+ mqpcb->prim_phys_port = attr->port_num;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_PORT update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_QKEY) {
+ mqpcb->qkey = attr->qkey;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_QKEY, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_QKEY update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_AV) {
+ int ah_mult = ib_rate_to_mult(attr->ah_attr.static_rate);
+ int ehca_mult = ib_rate_to_mult(shca->sport[my_qp->
+ init_attr.port_num].rate);
+
+ mqpcb->dlid = attr->ah_attr.dlid;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID, 1);
+ mqpcb->source_path_bits = attr->ah_attr.src_path_bits;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS, 1);
+ mqpcb->service_level = attr->ah_attr.sl;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL, 1);
+
+ if (ah_mult < ehca_mult)
+ mqpcb->max_static_rate = (ah_mult > 0) ?
+ ((ehca_mult - 1) / ah_mult) : 0;
+ else
+ mqpcb->max_static_rate = 0;
+
+ EDEB(7, " ipd=mqpcb->max_static_rate set %x "
+ " ah_mult=%x ehca_mult=%x "
+ " attr->ah_attr.static_rate=%x",
+ mqpcb->max_static_rate,ah_mult,ehca_mult,
+ attr->ah_attr.static_rate);
+
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE, 1);
+
+ /* only if GRH is TRUE we might consider SOURCE_GID_IDX
+ * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
+ */
+ if (attr->ah_attr.ah_flags == IB_AH_GRH) {
+ mqpcb->send_grh_flag = 1 << 31;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG, 1);
+ mqpcb->source_gid_idx = attr->ah_attr.grh.sgid_index;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX, 1);
+
+ for (cnt = 0; cnt < 16; cnt++)
+ mqpcb->dest_gid.byte[cnt] =
+ attr->ah_attr.grh.dgid.raw[cnt];
+
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_GID, 1);
+ mqpcb->flow_label = attr->ah_attr.grh.flow_label;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL, 1);
+ mqpcb->hop_limit = attr->ah_attr.grh.hop_limit;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT, 1);
+ mqpcb->traffic_class = attr->ah_attr.grh.traffic_class;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS, 1);
+ }
+
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_AV update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+
+ if (attr_mask & IB_QP_PATH_MTU) {
+ mqpcb->path_mtu = attr->path_mtu;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_PATH_MTU update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_TIMEOUT) {
+ mqpcb->timeout = attr->timeout;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_TIMEOUT update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_RETRY_CNT) {
+ mqpcb->retry_count = attr->retry_cnt;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_RETRY_CNT update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_RNR_RETRY) {
+ mqpcb->rnr_retry_count = attr->rnr_retry;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_RNR_RETRY update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_RQ_PSN) {
+ mqpcb->receive_psn = attr->rq_psn;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RECEIVE_PSN, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_RQ_PSN update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+ mqpcb->rdma_nr_atomic_resp_res = attr->max_dest_rd_atomic < 3 ?
+ attr->max_dest_rd_atomic : 2; /* max is 2 */
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_MAX_DEST_RD_ATOMIC "
+ "update_mask=%lx", my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ mqpcb->rdma_atomic_outst_dest_qp = attr->max_rd_atomic;
+ update_mask |=
+ EHCA_BMASK_SET
+ (MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_MAX_QP_RD_ATOMIC "
+ "update_mask=%lx", my_qp, ibqp->qp_num, update_mask);
+ }
+ if (attr_mask & IB_QP_ALT_PATH) {
+ int ah_mult = ib_rate_to_mult(attr->alt_ah_attr.static_rate);
+ int ehca_mult = ib_rate_to_mult(
+ shca->sport[my_qp->init_attr.port_num].rate);
+
+ mqpcb->dlid_al = attr->alt_ah_attr.dlid;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1);
+ mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1);
+ mqpcb->service_level_al = attr->alt_ah_attr.sl;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1);
+
+ if (ah_mult < ehca_mult)
+ mqpcb->max_static_rate = (ah_mult > 0) ?
+ ((ehca_mult - 1) / ah_mult) : 0;
+ else
+ mqpcb->max_static_rate_al = 0;
+
+ EDEB(7, " ipd=mqpcb->max_static_rate set %x,"
+ " ah_mult=%x ehca_mult=%x",
+ mqpcb->max_static_rate,ah_mult,ehca_mult);
+
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1);
+
+ /* only if GRH is TRUE we might consider SOURCE_GID_IDX
+ * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
+ */
+ if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) {
+ mqpcb->send_grh_flag_al = 1 << 31;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
+ mqpcb->source_gid_idx_al =
+ attr->alt_ah_attr.grh.sgid_index;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1);
+
+ for (cnt = 0; cnt < 16; cnt++)
+ mqpcb->dest_gid_al.byte[cnt] =
+ attr->alt_ah_attr.grh.dgid.raw[cnt];
+
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1);
+ mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1);
+ mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1);
+ mqpcb->traffic_class_al =
+ attr->alt_ah_attr.grh.traffic_class;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1);
+ }
+
+ EDEB(7, "ehca_qp=%p qp_num=%x IB_QP_ALT_PATH update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+
+ if (attr_mask & IB_QP_MIN_RNR_TIMER) {
+ mqpcb->min_rnr_nak_timer_field = attr->min_rnr_timer;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x "
+ "IB_QP_MIN_RNR_TIMER update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+
+ if (attr_mask & IB_QP_SQ_PSN) {
+ mqpcb->send_psn = attr->sq_psn;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_PSN, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x "
+ "IB_QP_SQ_PSN update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+
+ if (attr_mask & IB_QP_DEST_QPN) {
+ mqpcb->dest_qp_nr = attr->dest_qp_num;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_QP_NR, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x "
+ "IB_QP_DEST_QPN update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ }
+
+ if (attr_mask & IB_QP_PATH_MIG_STATE) {
+ mqpcb->path_migration_state = attr->path_mig_state;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x "
+ "IB_QP_PATH_MIG_STATE update_mask=%lx", my_qp,
+ ibqp->qp_num, update_mask);
+ }
+
+ if (attr_mask & IB_QP_CAP) {
+ mqpcb->max_nr_outst_send_wr = attr->cap.max_send_wr+1;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_SEND_WR, 1);
+ mqpcb->max_nr_outst_recv_wr = attr->cap.max_recv_wr+1;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_RECV_WR, 1);
+ EDEB(7, "ehca_qp=%p qp_num=%x "
+ "IB_QP_CAP update_mask=%lx",
+ my_qp, ibqp->qp_num, update_mask);
+ /* no support for max_send/recv_sge yet */
+ }
+
+ EDEB_DMP(7, mqpcb, 4*70, "ehca_qp=%p qp_num=%x", my_qp, ibqp->qp_num);
+
+ h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ update_mask,
+ mqpcb, my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ EDEB_ERR(4, "hipz_h_modify_qp() failed rc=%lx "
+ "ehca_qp=%p qp_num=%x",
+ h_ret, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
+
+ if ((my_qp->qp_type == IB_QPT_UD ||
+ my_qp->qp_type == IB_QPT_GSI ||
+ my_qp->qp_type == IB_QPT_SMI) &&
+ statetrans == IB_QPST_SQE2RTS) {
+ /* doorbell to reprocessing wqes */
+ iosync(); /* serialize GAL register access */
+ hipz_update_sqa(my_qp, bad_wqe_cnt-1);
+ EDEB(6, "doorbell for %x wqes", bad_wqe_cnt);
+ }
+
+ if (statetrans == IB_QPST_RESET2INIT ||
+ statetrans == IB_QPST_INIT2INIT) {
+ mqpcb->qp_enable = 1;
+ mqpcb->qp_state = EHCA_QPS_INIT;
+ update_mask = 0;
+ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_ENABLE, 1);
+
+ EDEB(7, "ehca_qp=%p qp_num=%x "
+ "RESET_2_INIT needs an additional enable "
+ "-> update_mask=%lx", my_qp, ibqp->qp_num, update_mask);
+
+ h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ update_mask,
+ mqpcb,
+ my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ EDEB_ERR(4, "ENABLE in context of "
+ "RESET_2_INIT failed! "
+ "Maybe you didn't get a LID"
+ "h_ret=%lx ehca_qp=%p qp_num=%x",
+ h_ret, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
+ }
+
+ if (statetrans == IB_QPST_ANY2RESET) {
+ ipz_qeit_reset(&my_qp->ipz_rqueue);
+ ipz_qeit_reset(&my_qp->ipz_squeue);
+ }
+
+ if (attr_mask & IB_QP_QKEY)
+ my_qp->qkey = attr->qkey;
+
+modify_qp_exit2:
+ if (squeue_locked) { /* this means: sqe -> rts */
+ spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
+ my_qp->sqerr_purgeflag = 1;
+ }
+
+modify_qp_exit1:
+ kfree(mqpcb);
+
+modify_qp_exit0:
+ EDEB_EX(7, "ehca_qp=%p qp_num=%x ibqp_type=%x ret=%x",
+ my_qp, ibqp->qp_num, ibqp->qp_type, ret);
+ return ret;
+}
+
+int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
+{
+ int ret = 0;
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+
+ EHCA_CHECK_ADR(ibqp);
+ EHCA_CHECK_ADR(attr);
+ EHCA_CHECK_ADR(ibqp->device);
+
+ my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+
+ EDEB_EN(7, "ehca_qp=%p qp_num=%x ibqp_type=%x attr_mask=%x",
+ my_qp, ibqp->qp_num, ibqp->qp_type, attr_mask);
+
+ my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ ret = -EINVAL;
+ } else
+ ret = internal_modify_qp(ibqp, attr, attr_mask, 0);
+
+ EDEB_EX(7, "ehca_qp=%p qp_num=%x ibqp_type=%x ret=%x",
+ my_qp, ibqp->qp_num, ibqp->qp_type, ret);
+ return ret;
+}
+
+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)
+{
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_shca *shca = NULL;
+ struct hcp_modify_qp_control_block *qpcb = NULL;
+ struct ipz_adapter_handle adapter_handle;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+ int cnt = 0, ret = 0;
+ u64 h_ret = H_SUCCESS;
+
+ EHCA_CHECK_ADR(qp);
+ EHCA_CHECK_ADR(qp_attr);
+ EHCA_CHECK_DEVICE(qp->device);
+
+ my_qp = container_of(qp, struct ehca_qp, ib_qp);
+
+ EDEB_EN(7, "ehca_qp=%p qp_num=%x "
+ "qp_attr=%p qp_attr_mask=%x qp_init_attr=%p",
+ my_qp, qp->qp_num, qp_attr, qp_attr_mask, qp_init_attr);
+
+ my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ ret = -EINVAL;
+ goto query_qp_exit0;
+ }
+
+ shca = container_of(qp->device, struct ehca_shca, ib_device);
+ adapter_handle = shca->ipz_hca_handle;
+
+ if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
+ ret = -EINVAL;
+ EDEB_ERR(4,"Invalid attribute mask "
+ "ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
+ my_qp, qp->qp_num, qp_attr_mask);
+ goto query_qp_exit0;
+ }
+
+ qpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL );
+ if (!qpcb) {
+ ret = -ENOMEM;
+ EDEB_ERR(4,"Out of memory for qpcb "
+ "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
+ goto query_qp_exit0;
+ }
+
+ h_ret = hipz_h_query_qp(adapter_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ qpcb, my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ EDEB_ERR(4,"hipz_h_query_qp() failed "
+ "ehca_qp=%p qp_num=%x h_ret=%lx",
+ my_qp, qp->qp_num, h_ret);
+ goto query_qp_exit1;
+ }
+
+ qp_attr->cur_qp_state = ehca2ib_qp_state(qpcb->qp_state);
+ qp_attr->qp_state = qp_attr->cur_qp_state;
+ if (qp_attr->cur_qp_state == -EINVAL) {
+ ret = -EINVAL;
+ EDEB_ERR(4,"Got invalid ehca_qp_state=%x "
+ "ehca_qp=%p qp_num=%x",
+ qpcb->qp_state, my_qp, qp->qp_num);
+ goto query_qp_exit1;
+ }
+
+ if (qp_attr->qp_state == IB_QPS_SQD)
+ qp_attr->sq_draining = 1;
+
+ qp_attr->qkey = qpcb->qkey;
+ qp_attr->path_mtu = qpcb->path_mtu;
+ qp_attr->path_mig_state = qpcb->path_migration_state;
+ qp_attr->rq_psn = qpcb->receive_psn;
+ qp_attr->sq_psn = qpcb->send_psn;
+ qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field;
+ qp_attr->cap.max_send_wr = qpcb->max_nr_outst_send_wr-1;
+ qp_attr->cap.max_recv_wr = qpcb->max_nr_outst_recv_wr-1;
+ /* UD_AV CIRCUMVENTION */
+ if (my_qp->qp_type == IB_QPT_UD) {
+ qp_attr->cap.max_send_sge =
+ qpcb->actual_nr_sges_in_sq_wqe - 2;
+ qp_attr->cap.max_recv_sge =
+ qpcb->actual_nr_sges_in_rq_wqe - 2;
+ } else {
+ qp_attr->cap.max_send_sge =
+ qpcb->actual_nr_sges_in_sq_wqe;
+ qp_attr->cap.max_recv_sge =
+ qpcb->actual_nr_sges_in_rq_wqe;
+ }
+
+ qp_attr->cap.max_inline_data = my_qp->sq_max_inline_data_size;
+ qp_attr->dest_qp_num = qpcb->dest_qp_nr;
+
+ qp_attr->pkey_index =
+ EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->prim_p_key_idx);
+
+ qp_attr->port_num =
+ EHCA_BMASK_GET(MQPCB_PRIM_PHYS_PORT, qpcb->prim_phys_port);
+
+ qp_attr->timeout = qpcb->timeout;
+ qp_attr->retry_cnt = qpcb->retry_count;
+ qp_attr->rnr_retry = qpcb->rnr_retry_count;
+
+ qp_attr->alt_pkey_index =
+ EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->alt_p_key_idx);
+
+ qp_attr->alt_port_num = qpcb->alt_phys_port;
+ qp_attr->alt_timeout = qpcb->timeout_al;
+
+ /* primary av */
+ qp_attr->ah_attr.sl = qpcb->service_level;
+
+ if (qpcb->send_grh_flag) {
+ qp_attr->ah_attr.ah_flags = IB_AH_GRH;
+ }
+
+ qp_attr->ah_attr.static_rate = qpcb->max_static_rate;
+ qp_attr->ah_attr.dlid = qpcb->dlid;
+ qp_attr->ah_attr.src_path_bits = qpcb->source_path_bits;
+ qp_attr->ah_attr.port_num = qp_attr->port_num;
+
+ /* primary GRH */
+ qp_attr->ah_attr.grh.traffic_class = qpcb->traffic_class;
+ qp_attr->ah_attr.grh.hop_limit = qpcb->hop_limit;
+ qp_attr->ah_attr.grh.sgid_index = qpcb->source_gid_idx;
+ qp_attr->ah_attr.grh.flow_label = qpcb->flow_label;
+
+ for (cnt = 0; cnt < 16; cnt++)
+ qp_attr->ah_attr.grh.dgid.raw[cnt] =
+ qpcb->dest_gid.byte[cnt];
+
+ /* alternate AV */
+ qp_attr->alt_ah_attr.sl = qpcb->service_level_al;
+ if (qpcb->send_grh_flag_al) {
+ qp_attr->alt_ah_attr.ah_flags = IB_AH_GRH;
+ }
+
+ qp_attr->alt_ah_attr.static_rate = qpcb->max_static_rate_al;
+ qp_attr->alt_ah_attr.dlid = qpcb->dlid_al;
+ qp_attr->alt_ah_attr.src_path_bits = qpcb->source_path_bits_al;
+
+ /* alternate GRH */
+ qp_attr->alt_ah_attr.grh.traffic_class = qpcb->traffic_class_al;
+ qp_attr->alt_ah_attr.grh.hop_limit = qpcb->hop_limit_al;
+ qp_attr->alt_ah_attr.grh.sgid_index = qpcb->source_gid_idx_al;
+ qp_attr->alt_ah_attr.grh.flow_label = qpcb->flow_label_al;
+
+ for (cnt = 0; cnt < 16; cnt++)
+ qp_attr->alt_ah_attr.grh.dgid.raw[cnt] =
+ qpcb->dest_gid_al.byte[cnt];
+
+ /* return init attributes given in ehca_create_qp */
+ if (qp_init_attr)
+ *qp_init_attr = my_qp->init_attr;
+
+ EDEB(7, "ehca_qp=%p qp_number=%x dest_qp_number=%x "
+ "dlid=%x path_mtu=%x dest_gid=%lx_%lx "
+ "service_level=%x qp_state=%x",
+ my_qp, qpcb->qp_number, qpcb->dest_qp_nr,
+ qpcb->dlid, qpcb->path_mtu,
+ qpcb->dest_gid.dw[0], qpcb->dest_gid.dw[1],
+ qpcb->service_level, qpcb->qp_state);
+
+ EDEB_DMP(7, qpcb, 4*70, "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
+
+query_qp_exit1:
+ kfree(qpcb);
+
+query_qp_exit0:
+ EDEB_EX(7, "ehca_qp=%p qp_num=%x ret=%x",
+ my_qp, qp->qp_num, ret);
+ return ret;
+}
+
+int ehca_destroy_qp(struct ib_qp *ibqp)
+{
+ extern struct ehca_module ehca_module;
+ struct ehca_qp *my_qp = NULL;
+ struct ehca_shca *shca = NULL;
+ struct ehca_pfqp *qp_pf = NULL;
+ struct ehca_pd *my_pd = NULL;
+ u32 cur_pid = current->tgid;
+ u32 qp_num = 0;
+ int ret = 0;
+ u64 h_ret = H_SUCCESS;
+ u8 port_num = 0;
+ enum ib_qp_type qp_type;
+ unsigned long flags;
+
+ EHCA_CHECK_ADR(ibqp);
+
+ my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ qp_num = ibqp->qp_num;
+ qp_pf = &my_qp->pf;
+
+ shca = container_of(ibqp->device, struct ehca_shca, ib_device);
+
+ EDEB_EN(7, "ehca_qp=%p qp_num=%x", my_qp, ibqp->qp_num);
+
+ my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ EDEB_ERR(4, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ if (my_qp->send_cq) {
+ ret = ehca_cq_unassign_qp(my_qp->send_cq,
+ my_qp->real_qp_num);
+ if (ret) {
+ EDEB_ERR(4, "Couldn't unassign qp from send_cq "
+ "ret=%x qp_num=%x cq_num=%x",
+ ret, my_qp->ib_qp.qp_num,
+ my_qp->send_cq->cq_number);
+ goto destroy_qp_exit0;
+ }
+ }
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ idr_remove(&ehca_qp_idr, my_qp->token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ /* un-mmap if vma alloc */
+ if (my_qp->uspace_rqueue) {
+ ret = ehca_munmap(my_qp->uspace_rqueue,
+ my_qp->ipz_rqueue.queue_length);
+ ret = ehca_munmap(my_qp->uspace_squeue,
+ my_qp->ipz_squeue.queue_length);
+ ret = ehca_munmap(my_qp->uspace_fwh, 4096);
+ }
+
+ h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
+ if (h_ret != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_destroy_qp() failed "
+ "rc=%lx ehca_qp=%p qp_num=%x",
+ h_ret, qp_pf, qp_num);
+ goto destroy_qp_exit0;
+ }
+
+ port_num = my_qp->init_attr.port_num;
+ qp_type = my_qp->init_attr.qp_type;
+
+ /* no support for IB_QPT_SMI yet */
+ if (qp_type == IB_QPT_GSI) {
+ struct ib_event event;
+
+ EDEB(4, "device %s: port %x is inactive.",
+ shca->ib_device.name, port_num);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ERR;
+ event.element.port_num = port_num;
+ shca->sport[port_num - 1].port_state = IB_PORT_DOWN;
+ ib_dispatch_event(&event);
+ }
+
+ ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(&my_qp->ipz_squeue);
+ kmem_cache_free(ehca_module.cache_qp, my_qp);
+
+destroy_qp_exit0:
+ ret = ehca2ib_return_code(h_ret);
+ EDEB_EX(7,"ret=%x", ret);
+ return ret;
+}
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_reqs.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_reqs.c 2006-05-15 08:09:49.000000000 +0200
@@ -0,0 +1,683 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * post_send/recv, poll_cq, req_notify
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Reinhard Ernst <rernst@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.
+ */
+
+
+#define DEB_PREFIX "reqs"
+
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+#include "hipz_fns.h"
+
+static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
+ struct ehca_wqe *wqe_p,
+ struct ib_recv_wr *recv_wr)
+{
+ u8 cnt_ds;
+ if (unlikely((recv_wr->num_sge < 0) ||
+ (recv_wr->num_sge > ipz_rqueue->act_nr_of_sg))) {
+ EDEB_ERR(4, "Invalid number of WQE SGE. "
+ "num_sqe=%x max_nr_of_sg=%x",
+ recv_wr->num_sge, ipz_rqueue->act_nr_of_sg);
+ return -EINVAL; /* invalid SG list length */
+ }
+
+ /* clear wqe header until sglist */
+ memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
+
+ wqe_p->work_request_id = be64_to_cpu(recv_wr->wr_id);
+ wqe_p->nr_of_data_seg = recv_wr->num_sge;
+
+ for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) {
+ wqe_p->u.all_rcv.sg_list[cnt_ds].vaddr =
+ be64_to_cpu(recv_wr->sg_list[cnt_ds].addr);
+ wqe_p->u.all_rcv.sg_list[cnt_ds].lkey =
+ ntohl(recv_wr->sg_list[cnt_ds].lkey);
+ wqe_p->u.all_rcv.sg_list[cnt_ds].length =
+ ntohl(recv_wr->sg_list[cnt_ds].length);
+ }
+
+ if (IS_EDEB_ON(7)) {
+ EDEB(7, "RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
+ EDEB_DMP(7, wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
+ }
+
+ return 0;
+}
+
+#if defined(DEBUG_GSI_SEND_WR)
+
+/* need ib_mad struct */
+#include <rdma/ib_mad.h>
+
+static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
+{
+ int idx = 0;
+ int j = 0;
+ while (send_wr) {
+ struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
+ struct ib_sge *sge = send_wr->sg_list;
+ EDEB(4, "send_wr#%x wr_id=%lx num_sge=%x "
+ "send_flags=%x opcode=%x",idx, send_wr->wr_id,
+ send_wr->num_sge, send_wr->send_flags, send_wr->opcode);
+ if (mad_hdr) {
+ EDEB(4, "send_wr#%x mad_hdr base_version=%x "
+ "mgmt_class=%x class_version=%x method=%x "
+ "status=%x class_specific=%x tid=%lx attr_id=%x "
+ "resv=%x attr_mod=%x",
+ idx, mad_hdr->base_version, mad_hdr->mgmt_class,
+ mad_hdr->class_version, mad_hdr->method,
+ mad_hdr->status, mad_hdr->class_specific,
+ mad_hdr->tid, mad_hdr->attr_id, mad_hdr->resv,
+ mad_hdr->attr_mod);
+ }
+ for (j = 0; j < send_wr->num_sge; j++) {
+ u8 *data = (u8 *) abs_to_virt(sge->addr);
+ EDEB(4, "send_wr#%x sge#%x addr=%p length=%x lkey=%x",
+ idx, j, data, sge->length, sge->lkey);
+ /* assume length is n*16 */
+ EDEB_DMP(4, data, sge->length, "send_wr#%x sge#%x",
+ idx, j);
+ sge++;
+ } /* eof for j */
+ idx++;
+ send_wr = send_wr->next;
+ } /* eof while send_wr */
+}
+
+#endif /* DEBUG_GSI_SEND_WR */
+
+static inline int ehca_write_swqe(struct ehca_qp *qp,
+ struct ehca_wqe *wqe_p,
+ const struct ib_send_wr *send_wr)
+{
+ u32 idx;
+ u64 dma_length;
+ struct ehca_av *my_av;
+ u32 remote_qkey = send_wr->wr.ud.remote_qkey;
+
+ if (unlikely((send_wr->num_sge < 0) ||
+ (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) {
+ EDEB_ERR(4, "Invalid number of WQE SGE. "
+ "num_sqe=%x max_nr_of_sg=%x",
+ send_wr->num_sge, qp->ipz_squeue.act_nr_of_sg);
+ return -EINVAL; /* invalid SG list length */
+ }
+
+ /* clear wqe header until sglist */
+ memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
+
+ wqe_p->work_request_id = be64_to_cpu(send_wr->wr_id);
+
+ switch (send_wr->opcode) {
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_IMM:
+ wqe_p->optype = WQE_OPTYPE_SEND;
+ break;
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ wqe_p->optype = WQE_OPTYPE_RDMAWRITE;
+ break;
+ case IB_WR_RDMA_READ:
+ wqe_p->optype = WQE_OPTYPE_RDMAREAD;
+ break;
+ default:
+ EDEB_ERR(4, "Invalid opcode=%x", send_wr->opcode);
+ return -EINVAL; /* invalid opcode */
+ }
+
+ wqe_p->wqef = (send_wr->opcode) & WQEF_HIGH_NIBBLE;
+
+ wqe_p->wr_flag = 0;
+
+ if (send_wr->send_flags & IB_SEND_SIGNALED)
+ wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
+
+ if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
+ send_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
+ /* this might not work as long as HW does not support it */
+ wqe_p->immediate_data = send_wr->imm_data;
+ wqe_p->wr_flag |= WQE_WRFLAG_IMM_DATA_PRESENT;
+ }
+
+ wqe_p->nr_of_data_seg = send_wr->num_sge;
+
+ switch (qp->qp_type) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ /* no break is intential here */
+ case IB_QPT_UD:
+ /* IB 1.2 spec C10-15 compliance */
+ if (send_wr->wr.ud.remote_qkey & 0x80000000)
+ remote_qkey = qp->qkey;
+
+ wqe_p->destination_qp_number =
+ ntohl(send_wr->wr.ud.remote_qpn << 8);
+ wqe_p->local_ee_context_qkey = ntohl(remote_qkey);
+ if (!send_wr->wr.ud.ah) {
+ EDEB_ERR(4, "wr.ud.ah is NULL. qp=%p", qp);
+ return -EINVAL;
+ }
+ my_av = container_of(send_wr->wr.ud.ah, struct ehca_av, ib_ah);
+ wqe_p->u.ud_av.ud_av = my_av->av;
+
+ /* omitted check of IB_SEND_INLINE
+ since HW does not support it */
+ for (idx = 0; idx < send_wr->num_sge; idx++) {
+ wqe_p->u.ud_av.sg_list[idx].vaddr =
+ be64_to_cpu(send_wr->sg_list[idx].addr);
+ wqe_p->u.ud_av.sg_list[idx].lkey =
+ ntohl(send_wr->sg_list[idx].lkey);
+ wqe_p->u.ud_av.sg_list[idx].length =
+ ntohl(send_wr->sg_list[idx].length);
+ } /* eof for idx */
+ if (qp->qp_type == IB_QPT_SMI ||
+ qp->qp_type == IB_QPT_GSI)
+ wqe_p->u.ud_av.ud_av.pmtu = 1;
+ if (qp->qp_type == IB_QPT_GSI) {
+ wqe_p->pkeyi =
+ ntohs(send_wr->wr.ud.pkey_index);
+#ifdef DEBUG_GSI_SEND_WR
+ trace_send_wr_ud(send_wr);
+#endif /* DEBUG_GSI_SEND_WR */
+ }
+ break;
+
+ case IB_QPT_UC:
+ if (send_wr->send_flags & IB_SEND_FENCE)
+ wqe_p->wr_flag |= WQE_WRFLAG_FENCE;
+ /* no break is intentional here */
+ case IB_QPT_RC:
+ /* TODO: atomic not implemented */
+ wqe_p->u.nud.remote_virtual_adress =
+ be64_to_cpu(send_wr->wr.rdma.remote_addr);
+ wqe_p->u.nud.rkey = ntohl(send_wr->wr.rdma.rkey);
+
+ /* omitted checking of IB_SEND_INLINE
+ since HW does not support it */
+ dma_length = 0;
+ for (idx = 0; idx < send_wr->num_sge; idx++) {
+ wqe_p->u.nud.sg_list[idx].vaddr =
+ be64_to_cpu(send_wr->sg_list[idx].addr);
+ wqe_p->u.nud.sg_list[idx].lkey =
+ ntohl(send_wr->sg_list[idx].lkey);
+ wqe_p->u.nud.sg_list[idx].length =
+ ntohl(send_wr->sg_list[idx].length);
+ dma_length += send_wr->sg_list[idx].length;
+ } /* eof idx */
+ wqe_p->u.nud.atomic_1st_op_dma_len = be64_to_cpu(dma_length);
+
+ break;
+
+ default:
+ EDEB_ERR(4, "Invalid qptype=%x", qp->qp_type);
+ return -EINVAL;
+ }
+
+ if (IS_EDEB_ON(7)) {
+ EDEB(7, "SEND WQE written into queue qp=%p ", qp);
+ EDEB_DMP(7, wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "send wqe");
+ }
+ return 0;
+}
+
+/** map_ib_wc_status - convert raw cqe_status to ib_wc_status
+ */
+static inline void map_ib_wc_status(u32 cqe_status,
+ enum ib_wc_status *wc_status)
+{
+ if (unlikely(cqe_status & WC_STATUS_ERROR_BIT)) {
+ switch (cqe_status & 0x3F) {
+ case 0x01:
+ case 0x21:
+ *wc_status = IB_WC_LOC_LEN_ERR;
+ break;
+ case 0x02:
+ case 0x22:
+ *wc_status = IB_WC_LOC_QP_OP_ERR;
+ break;
+ case 0x03:
+ case 0x23:
+ *wc_status = IB_WC_LOC_EEC_OP_ERR;
+ break;
+ case 0x04:
+ case 0x24:
+ *wc_status = IB_WC_LOC_PROT_ERR;
+ break;
+ case 0x05:
+ case 0x25:
+ *wc_status = IB_WC_WR_FLUSH_ERR;
+ break;
+ case 0x06:
+ *wc_status = IB_WC_MW_BIND_ERR;
+ break;
+ case 0x07: /* remote error - look into bits 20:24 */
+ switch ((cqe_status
+ & WC_STATUS_REMOTE_ERROR_FLAGS) >> 11) {
+ case 0x0:
+ /* PSN Sequence Error!
+ couldn't find a matching status! */
+ *wc_status = IB_WC_GENERAL_ERR;
+ break;
+ case 0x1:
+ *wc_status = IB_WC_REM_INV_REQ_ERR;
+ break;
+ case 0x2:
+ *wc_status = IB_WC_REM_ACCESS_ERR;
+ break;
+ case 0x3:
+ *wc_status = IB_WC_REM_OP_ERR;
+ break;
+ case 0x4:
+ *wc_status = IB_WC_REM_INV_RD_REQ_ERR;
+ break;
+ }
+ break;
+ case 0x08:
+ *wc_status = IB_WC_RETRY_EXC_ERR;
+ break;
+ case 0x09:
+ *wc_status = IB_WC_RNR_RETRY_EXC_ERR;
+ break;
+ case 0x0A:
+ case 0x2D:
+ *wc_status = IB_WC_REM_ABORT_ERR;
+ break;
+ case 0x0B:
+ case 0x2E:
+ *wc_status = IB_WC_INV_EECN_ERR;
+ break;
+ case 0x0C:
+ case 0x2F:
+ *wc_status = IB_WC_INV_EEC_STATE_ERR;
+ break;
+ case 0x0D:
+ *wc_status = IB_WC_BAD_RESP_ERR;
+ break;
+ case 0x10:
+ /* WQE purged */
+ *wc_status = IB_WC_WR_FLUSH_ERR;
+ break;
+ default:
+ *wc_status = IB_WC_FATAL_ERR;
+
+ }
+ } else
+ *wc_status = IB_WC_SUCCESS;
+}
+
+int ehca_post_send(struct ib_qp *qp,
+ struct ib_send_wr *send_wr,
+ struct ib_send_wr **bad_send_wr)
+{
+ struct ehca_qp *my_qp = NULL;
+ struct ib_send_wr *cur_send_wr = NULL;
+ struct ehca_wqe *wqe_p = NULL;
+ int wqe_cnt = 0;
+ int ret = 0;
+ unsigned long spl_flags = 0;
+
+ EHCA_CHECK_ADR(qp);
+ my_qp = container_of(qp, struct ehca_qp, ib_qp);
+ EHCA_CHECK_QP(my_qp);
+ EHCA_CHECK_ADR(send_wr);
+ EDEB_EN(7, "ehca_qp=%p qp_num=%x send_wr=%p bad_send_wr=%p",
+ my_qp, qp->qp_num, send_wr, bad_send_wr);
+
+ /* LOCK the QUEUE */
+ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
+
+ /* loop processes list of send reqs */
+ for (cur_send_wr = send_wr; cur_send_wr != NULL;
+ cur_send_wr = cur_send_wr->next) {
+ u64 start_offset = my_qp->ipz_squeue.current_q_offset;
+ /* get pointer next to free WQE */
+ wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
+ if (unlikely(!wqe_p)) {
+ /* too many posted work requests: queue overflow */
+ if (bad_send_wr)
+ *bad_send_wr = cur_send_wr;
+ if (wqe_cnt == 0) {
+ ret = -ENOMEM;
+ EDEB_ERR(4, "Too many posted WQEs qp_num=%x",
+ qp->qp_num);
+ }
+ goto post_send_exit0;
+ }
+ /* write a SEND WQE into the QUEUE */
+ ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
+ /* if something failed,
+ reset the free entry pointer to the start value
+ */
+ if (unlikely(ret)) {
+ my_qp->ipz_squeue.current_q_offset = start_offset;
+ *bad_send_wr = cur_send_wr;
+ if (wqe_cnt == 0) {
+ ret = -EINVAL;
+ EDEB_ERR(4, "Could not write WQE qp_num=%x",
+ qp->qp_num);
+ }
+ goto post_send_exit0;
+ }
+ wqe_cnt++;
+ EDEB(7, "ehca_qp=%p qp_num=%x wqe_cnt=%d",
+ my_qp, qp->qp_num, wqe_cnt);
+ } /* eof for cur_send_wr */
+
+post_send_exit0:
+ /* UNLOCK the QUEUE */
+ spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
+ iosync(); /* serialize GAL register access */
+ hipz_update_sqa(my_qp, wqe_cnt);
+ EDEB_EX(7, "ehca_qp=%p qp_num=%x ret=%x wqe_cnt=%d",
+ my_qp, qp->qp_num, ret, wqe_cnt);
+ return ret;
+}
+
+int ehca_post_recv(struct ib_qp *qp,
+ struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr)
+{
+ struct ehca_qp *my_qp = NULL;
+ struct ib_recv_wr *cur_recv_wr = NULL;
+ struct ehca_wqe *wqe_p = NULL;
+ int wqe_cnt = 0;
+ int ret = 0;
+ unsigned long spl_flags = 0;
+
+ EHCA_CHECK_ADR(qp);
+ my_qp = container_of(qp, struct ehca_qp, ib_qp);
+ EHCA_CHECK_QP(my_qp);
+ EHCA_CHECK_ADR(recv_wr);
+ EDEB_EN(7, "ehca_qp=%p qp_num=%x recv_wr=%p bad_recv_wr=%p",
+ my_qp, qp->qp_num, recv_wr, bad_recv_wr);
+
+ /* LOCK the QUEUE */
+ spin_lock_irqsave(&my_qp->spinlock_r, spl_flags);
+
+ /* loop processes list of send reqs */
+ for (cur_recv_wr = recv_wr; cur_recv_wr != NULL;
+ cur_recv_wr = cur_recv_wr->next) {
+ u64 start_offset = my_qp->ipz_rqueue.current_q_offset;
+ /* get pointer next to free WQE */
+ wqe_p = ipz_qeit_get_inc(&my_qp->ipz_rqueue);
+ if (unlikely(!wqe_p)) {
+ /* too many posted work requests: queue overflow */
+ if (bad_recv_wr)
+ *bad_recv_wr = cur_recv_wr;
+ if (wqe_cnt == 0) {
+ ret = -ENOMEM;
+ EDEB_ERR(4, "Too many posted WQEs qp_num=%x",
+ qp->qp_num);
+ }
+ goto post_recv_exit0;
+ }
+ /* write a RECV WQE into the QUEUE */
+ ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p,
+ cur_recv_wr);
+ /* if something failed,
+ reset the free entry pointer to the start value
+ */
+ if (unlikely(ret)) {
+ my_qp->ipz_rqueue.current_q_offset = start_offset;
+ *bad_recv_wr = cur_recv_wr;
+ if (wqe_cnt == 0) {
+ ret = -EINVAL;
+ EDEB_ERR(4, "Could not write WQE qp_num=%x",
+ qp->qp_num);
+ }
+ goto post_recv_exit0;
+ }
+ wqe_cnt++;
+ EDEB(7, "ehca_qp=%p qp_num=%x wqe_cnt=%d",
+ my_qp, qp->qp_num, wqe_cnt);
+ } /* eof for cur_recv_wr */
+
+post_recv_exit0:
+ spin_unlock_irqrestore(&my_qp->spinlock_r, spl_flags);
+ iosync(); /* serialize GAL register access */
+ hipz_update_rqa(my_qp, wqe_cnt);
+ EDEB_EX(7, "ehca_qp=%p qp_num=%x ret=%x wqe_cnt=%d",
+ my_qp, qp->qp_num, ret, wqe_cnt);
+ return ret;
+}
+
+/**
+ * ib_wc_opcode - Table converts ehca wc opcode to ib
+ * Since we use zero to indicate invalid opcode, the actual ib opcode must
+ * be decremented!!!
+ */
+static const u8 ib_wc_opcode[255] = {
+ [0x01] = IB_WC_RECV+1,
+ [0x02] = IB_WC_RECV_RDMA_WITH_IMM+1,
+ [0x04] = IB_WC_BIND_MW+1,
+ [0x08] = IB_WC_FETCH_ADD+1,
+ [0x10] = IB_WC_COMP_SWAP+1,
+ [0x20] = IB_WC_RDMA_WRITE+1,
+ [0x40] = IB_WC_RDMA_READ+1,
+ [0x80] = IB_WC_SEND+1
+};
+
+/**
+ * internal function to poll one entry of cq
+ */
+static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
+{
+ int ret = 0;
+ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ struct ehca_cqe *cqe = NULL;
+ int cqe_count = 0;
+
+ EDEB_EN(7, "ehca_cq=%p cq_num=%x wc=%p", my_cq, my_cq->cq_number, wc);
+
+poll_cq_one_read_cqe:
+ cqe = (struct ehca_cqe *)
+ ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
+ if (!cqe) {
+ ret = -EAGAIN;
+ EDEB(7, "Completion queue is empty ehca_cq=%p cq_num=%x "
+ "ret=%x", my_cq, my_cq->cq_number, ret);
+ goto poll_cq_one_exit0;
+ }
+ cqe_count++;
+ if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
+ struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
+ int purgeflag = 0;
+ unsigned long spl_flags = 0;
+ if (!qp) {
+ EDEB_ERR(4, "cq_num=%x qp_num=%x "
+ "could not find qp -> ignore cqe",
+ my_cq->cq_number, cqe->local_qp_number);
+ EDEB_DMP(4, cqe, 64, "cq_num=%x qp_num=%x",
+ my_cq->cq_number, cqe->local_qp_number);
+ /* ignore this purged cqe */
+ goto poll_cq_one_read_cqe;
+ }
+ spin_lock_irqsave(&qp->spinlock_s, spl_flags);
+ purgeflag = qp->sqerr_purgeflag;
+ spin_unlock_irqrestore(&qp->spinlock_s, spl_flags);
+
+ if (purgeflag) {
+ EDEB(6, "Got CQE with purged bit qp_num=%x src_qp=%x",
+ cqe->local_qp_number, cqe->remote_qp_number);
+ EDEB_DMP(6, cqe, 64, "qp_num=%x src_qp=%x",
+ cqe->local_qp_number, cqe->remote_qp_number);
+ /* ignore this to avoid double cqes of bad wqe
+ that caused sqe and turn off purge flag */
+ qp->sqerr_purgeflag = 0;
+ goto poll_cq_one_read_cqe;
+ }
+ }
+
+ /* tracing cqe */
+ if (IS_EDEB_ON(7)) {
+ EDEB(7, "Received COMPLETION ehca_cq=%p cq_num=%x -----",
+ my_cq, my_cq->cq_number);
+ EDEB_DMP(7, cqe, 64, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+ EDEB(7, "ehca_cq=%p cq_num=%x -------------------------",
+ my_cq, my_cq->cq_number);
+ }
+
+ /* we got a completion! */
+ wc->wr_id = cqe->work_request_id;
+
+ /* eval ib_wc_opcode */
+ wc->opcode = ib_wc_opcode[cqe->optype]-1;
+ if (unlikely(wc->opcode == -1)) {
+ EDEB_ERR(4, "Invalid cqe->OPType=%x cqe->status=%x "
+ "ehca_cq=%p cq_num=%x",
+ cqe->optype, cqe->status, my_cq, my_cq->cq_number);
+ /* dump cqe for other infos */
+ EDEB_DMP(4, cqe, 64, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+ /* update also queue adder to throw away this entry!!! */
+ goto poll_cq_one_exit0;
+ }
+ /* eval ib_wc_status */
+ if (unlikely(cqe->status & WC_STATUS_ERROR_BIT)) { /* complete with errors */
+ map_ib_wc_status(cqe->status, &wc->status);
+ wc->vendor_err = wc->status;
+ } else
+ wc->status = IB_WC_SUCCESS;
+
+ wc->qp_num = cqe->local_qp_number;
+ wc->byte_len = ntohl(cqe->nr_bytes_transferred);
+ wc->pkey_index = cqe->pkey_index;
+ wc->slid = cqe->rlid;
+ wc->dlid_path_bits = cqe->dlid;
+ wc->src_qp = cqe->remote_qp_number;
+ wc->wc_flags = cqe->w_completion_flags;
+ wc->imm_data = cqe->immediate_data;
+ wc->sl = cqe->service_level;
+
+ if (wc->status != IB_WC_SUCCESS)
+ EDEB(6, "ehca_cq=%p cq_num=%x WARNING unsuccessful cqe "
+ "OPType=%x status=%x qp_num=%x src_qp=%x wr_id=%lx cqe=%p",
+ my_cq, my_cq->cq_number, cqe->optype, cqe->status,
+ cqe->local_qp_number, cqe->remote_qp_number,
+ cqe->work_request_id, cqe);
+
+poll_cq_one_exit0:
+ if (cqe_count > 0)
+ hipz_update_feca(my_cq, cqe_count);
+
+ EDEB_EX(7, "ret=%x ehca_cq=%p cq_number=%x wc=%p "
+ "status=%x opcode=%x qp_num=%x byte_len=%x",
+ ret, my_cq, my_cq->cq_number, wc, wc->status,
+ wc->opcode, wc->qp_num, wc->byte_len);
+
+ return ret;
+}
+
+int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
+{
+ struct ehca_cq *my_cq = NULL;
+ int nr = 0;
+ struct ib_wc *current_wc = NULL;
+ int ret = 0;
+ unsigned long spl_flags = 0;
+
+ EHCA_CHECK_CQ(cq);
+ EHCA_CHECK_ADR(wc);
+
+ my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ EHCA_CHECK_CQ(my_cq);
+
+ EDEB_EN(7, "ehca_cq=%p cq_num=%x num_entries=%d wc=%p",
+ my_cq, my_cq->cq_number, num_entries, wc);
+
+ if (num_entries < 1) {
+ EDEB_ERR(4, "Invalid num_entries=%d ehca_cq=%p cq_num=%x",
+ num_entries, my_cq, my_cq->cq_number);
+ ret = -EINVAL;
+ goto poll_cq_exit0;
+ }
+
+ current_wc = wc;
+ spin_lock_irqsave(&my_cq->spinlock, spl_flags);
+ for (nr = 0; nr < num_entries; nr++) {
+ ret = ehca_poll_cq_one(cq, current_wc);
+ if (ret)
+ break;
+ current_wc++;
+ } /* eof for nr */
+ spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
+ if (ret == -EAGAIN || !ret)
+ ret = nr;
+
+poll_cq_exit0:
+ EDEB_EX(7, "ehca_cq=%p cq_num=%x ret=%x wc=%p nr_entries=%d",
+ my_cq, my_cq->cq_number, ret, wc, nr);
+
+ return ret;
+}
+
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
+{
+ struct ehca_cq *my_cq = NULL;
+ int ret = 0;
+
+ EHCA_CHECK_CQ(cq);
+ my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ EHCA_CHECK_CQ(my_cq);
+ EDEB_EN(7, "ehca_cq=%p cq_num=%x cq_notif=%x",
+ my_cq, my_cq->cq_number, cq_notify);
+
+ switch (cq_notify) {
+ case IB_CQ_SOLICITED:
+ hipz_set_cqx_n0(my_cq, 1);
+ break;
+ case IB_CQ_NEXT_COMP:
+ hipz_set_cqx_n1(my_cq, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ EDEB_EX(7, "ehca_cq=%p cq_num=%x ret=%x",
+ my_cq, my_cq->cq_number, ret);
+
+ return ret;
+}
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ehca_sqp.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ehca_sqp.c 2006-05-15 13:35:24.000000000 +0200
@@ -0,0 +1,123 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * SQP functions
+ *
+ * Authors: Khadija Souissi <souissi@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.
+ */
+
+
+#define DEB_PREFIX "e_qp"
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+
+
+extern int ehca_create_aqp1(struct ehca_shca *shca, struct ehca_sport *sport);
+extern int ehca_destroy_aqp1(struct ehca_sport *sport);
+
+extern int ehca_port_act_time;
+
+/**
+ * ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue
+ * pair is created successfully, the corresponding port gets active.
+ *
+ * Define Special Queue pair 0 (SMI QP) is still not supported.
+ *
+ * @qp_init_attr: Queue pair init attributes with port and queue pair type
+ */
+
+u64 ehca_define_sqp(struct ehca_shca *shca,
+ struct ehca_qp *ehca_qp,
+ struct ib_qp_init_attr *qp_init_attr)
+{
+
+ u32 pma_qp_nr = 0;
+ u32 bma_qp_nr = 0;
+ u64 ret = H_SUCCESS;
+ u8 port = qp_init_attr->port_num;
+ int counter = 0;
+
+ EDEB_EN(7, "port=%x qp_type=%x",
+ port, qp_init_attr->qp_type);
+
+ shca->sport[port - 1].port_state = IB_PORT_DOWN;
+
+ switch (qp_init_attr->qp_type) {
+ case IB_QPT_SMI:
+ /* function not supported yet */
+ break;
+ case IB_QPT_GSI:
+ ret = hipz_h_define_aqp1(shca->ipz_hca_handle,
+ ehca_qp->ipz_qp_handle,
+ ehca_qp->galpas.kernel,
+ (u32) qp_init_attr->port_num,
+ &pma_qp_nr, &bma_qp_nr);
+
+ if (ret != H_SUCCESS) {
+ EDEB_ERR(4, "Can't define AQP1 for port %x. rc=%lx",
+ port, ret);
+ goto ehca_define_aqp1;
+ }
+ break;
+ default:
+ ret = H_PARAMETER;
+ goto ehca_define_aqp1;
+ }
+
+ while ((shca->sport[port - 1].port_state != IB_PORT_ACTIVE) &&
+ (counter < ehca_port_act_time)) {
+ EDEB(6, "... wait until port %x is active",
+ port);
+ msleep_interruptible(1000);
+ counter++;
+ }
+
+ if (counter == ehca_port_act_time) {
+ EDEB_ERR(4, "Port %x is not active.", port);
+ ret = H_HARDWARE;
+ }
+
+ehca_define_aqp1:
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
^ permalink raw reply
* [PATCH 12/16] ehca: firmware InfiniBand interface
From: Heiko J Schick @ 2006-05-15 17:42 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>
drivers/infiniband/hw/ehca/hcp_if.c | 1476 ++++++++++++++++++++++++++++++++++++
drivers/infiniband/hw/ehca/hcp_if.h | 330 ++++++++
2 files changed, 1806 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hcp_if.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hcp_if.h 2006-05-12 12:48:21.000000000 +0200
@@ -0,0 +1,330 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Firmware Infiniband Interface code for POWER
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Gerd Bayer <gerd.bayer@de.ibm.com>
+ * Waleri Fomin <fomin@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.
+ */
+
+#ifndef __HCP_IF_H__
+#define __HCP_IF_H__
+
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "hipz_hw.h"
+
+/**
+ * hipz_h_alloc_resource_eq - Allocate EQ resources in HW and FW, initalize
+ * resources, create the empty EQPT (ring).
+ *
+ * @eq_handle: eq handle for this queue
+ * @act_nr_of_entries: actual number of queue entries
+ * @act_pages: actual number of queue pages
+ * @eq_ist: used by hcp_H_XIRR() call
+ */
+u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_pfeq *pfeq,
+ const u32 neq_control,
+ const u32 number_of_entries,
+ struct ipz_eq_handle *eq_handle,
+ u32 * act_nr_of_entries,
+ u32 * act_pages,
+ u32 * eq_ist);
+
+u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
+ struct ipz_eq_handle eq_handle,
+ const u64 event_mask);
+/**
+ * hipz_h_allocate_resource_cq - Allocate CQ resources in HW and FW, initialize
+ * resources, create the empty CQPT (ring).
+ *
+ * @eq_handle: eq handle to use for this cq
+ * @cq_handle: cq handle for this queue
+ * @act_nr_of_entries: actual number of queue entries
+ * @act_pages: actual number of queue pages
+ * @galpas: contain logical adress of priv. storage and
+ * log_user_storage
+ */
+u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ struct ehca_alloc_cq_parms *param);
+
+
+/**
+ * hipz_h_alloc_resource_qp - Allocate QP resources in HW and FW,
+ * initialize resources, create empty QPPTs (2 rings).
+ *
+ * @h_galpas to access HCA resident QP attributes
+ */
+u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp,
+ struct ehca_alloc_qp_parms *parms);
+
+u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
+ const u8 port_id,
+ struct hipz_query_port *query_port_response_block);
+
+u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
+ struct hipz_query_hca *query_hca_rblock);
+
+/**
+ * hipz_h_register_rpage - hcp_if.h internal function for all
+ * hcp_H_REGISTER_RPAGE calls.
+ *
+ * @logical_address_of_page: kv transformation to GX address in this routine
+ */
+u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 logical_address_of_page,
+ u64 count);
+
+u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_eq_handle eq_handle,
+ struct ehca_pfeq *pfeq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count);
+
+u32 hipz_h_query_int_state(const struct ipz_adapter_handle
+ hcp_adapter_handle,
+ u32 ist);
+
+u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_cq_handle cq_handle,
+ struct ehca_pfcq *pfcq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa gal);
+
+u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa galpa);
+
+u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ void **log_addr_next_sq_wqe_tb_processed,
+ void **log_addr_next_rq_wqe_tb_processed,
+ int dis_and_get_function_code);
+enum hcall_sigt {
+ HCALL_SIGT_NO_CQE = 0,
+ HCALL_SIGT_BY_WQE = 1,
+ HCALL_SIGT_EVERY = 2
+};
+
+u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u64 update_mask,
+ struct hcp_modify_qp_control_block *mqpcb,
+ struct h_galpa gal);
+
+u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ struct hcp_modify_qp_control_block *qqpcb,
+ struct h_galpa gal);
+
+u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp);
+
+u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port);
+
+u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port, u32 * pma_qp_nr,
+ u32 * bma_qp_nr);
+
+u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id);
+
+u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id);
+
+u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ u8 force_flag);
+
+u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_eq *eq);
+
+/**
+ * hipz_h_alloc_resource_mr - Allocate MR resources in HW and FW, initialize
+ * resources.
+ *
+ * @mr: ehca MR
+ * @vaddr: Memory Region I/O Virtual Address
+ * @length: Memory Region Length
+ * @access_ctrl: Memory Region Access Controls
+ * @pd: Protection Domain
+ * @outparms: output parameters
+ */
+u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/**
+ * hipz_h_register_rpage_mr - Register MR resource page in HW and FW .
+ *
+ * @mr: ehca MR
+ * @queue_type: must be zero for MR
+ */
+u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count);
+
+/**
+ * hipz_h_query_mr - Query MR in HW and FW.
+ *
+ * @mr: ehca MR
+ * @outparms: output parameters
+ */
+u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/**
+ * hipz_h_free_resource_mr - Free MR resources in HW and FW.
+ *
+ * @mr: ehca MR
+ */
+u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr);
+
+/**
+ * hipz_h_reregister_pmr - Reregister MR in HW and FW.
+ *
+ * @mr: ehca MR
+ * @vaddr_in: Memory Region I/O Virtual Address
+ * @length: Memory Region Length
+ * @access_ctrl: Memory Region Access Controls
+ * @pd: Protection Domain
+ * @mr_addr_cb: Logical Address of MR Control Block
+ * @outparms: output parameters
+ */
+u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr_in,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ const u64 mr_addr_cb,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/**
+ * hipz_h_register_smr - Register shared MR in HW and FW.
+ *
+ * @mr: ehca MR
+ * @orig_mr: original ehca MR
+ * @vaddr_in: Memory Region I/O Virtual Address of new shared MR
+ * @access_ctrl: Memory Region Access Controls of new shared MR
+ * @pd: Protection Domain of new shared MR
+ * @outparms: output parameters
+ */
+u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const struct ehca_mr *orig_mr,
+ const u64 vaddr_in,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/**
+ * hipz_h_alloc_resource_mw - Allocate MR resources in HW and FW, initialize
+ * resources.
+ *
+ * @mw: ehca MW
+ * @pd: Protection Domain
+ * @outparms: output parameters
+ */
+u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ const struct ipz_pd pd,
+ struct ehca_mw_hipzout_parms *outparms);
+
+/**
+ * hipz_h_query_mw - Query MW in HW and FW.
+ *
+ * @mw: ehca MW
+ * @outparms: output parameters
+ */
+u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ struct ehca_mw_hipzout_parms *outparms);
+
+/**
+ * hipz_h_free_resource_mw - Free MW resources in HW and FW.
+ *
+ * @mw: ehca MW
+ */
+u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw);
+
+u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
+ const u64 ressource_handle,
+ void *rblock,
+ unsigned long *byte_count);
+
+#endif /* __HCP_IF_H__ */
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hcp_if.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hcp_if.c 2006-05-15 15:43:31.000000000 +0200
@@ -0,0 +1,1476 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Firmware Infiniband Interface code for POWER
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Gerd Bayer <gerd.bayer@de.ibm.com>
+ * Waleri Fomin <fomin@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.
+ */
+
+#define DEB_PREFIX "hcpi"
+
+#include <asm/hvcall.h>
+#include "ehca_tools.h"
+#include "hcp_if.h"
+#include "hcp_phyp.h"
+#include "hipz_fns.h"
+
+#define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9,11)
+#define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12,12)
+#define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13,15)
+#define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18,18)
+#define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19,21)
+#define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22,23)
+#define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31,31)
+#define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56,63)
+
+#define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0,15)
+#define H_ALL_RES_QP_MAX_OUTST_RECV_WR EHCA_BMASK_IBM(16,31)
+#define H_ALL_RES_QP_MAX_SEND_SGE EHCA_BMASK_IBM(32,39)
+#define H_ALL_RES_QP_MAX_RECV_SGE EHCA_BMASK_IBM(40,47)
+
+#define H_ALL_RES_QP_ACT_OUTST_SEND_WR EHCA_BMASK_IBM(16,31)
+#define H_ALL_RES_QP_ACT_OUTST_RECV_WR EHCA_BMASK_IBM(48,63)
+#define H_ALL_RES_QP_ACT_SEND_SGE EHCA_BMASK_IBM(8,15)
+#define H_ALL_RES_QP_ACT_RECV_SGE EHCA_BMASK_IBM(24,31)
+
+#define H_ALL_RES_QP_SQUEUE_SIZE_PAGES EHCA_BMASK_IBM(0,31)
+#define H_ALL_RES_QP_RQUEUE_SIZE_PAGES EHCA_BMASK_IBM(32,63)
+
+/* direct access qp controls */
+#define DAQP_CTRL_ENABLE 0x01
+#define DAQP_CTRL_SEND_COMP 0x20
+#define DAQP_CTRL_RECV_COMP 0x40
+
+static u32 get_longbusy_msecs(int longbusy_rc)
+{
+ switch (longbusy_rc) {
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ return 1;
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ return 10;
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ return 100;
+ case H_LONG_BUSY_ORDER_1_SEC:
+ return 1000;
+ case H_LONG_BUSY_ORDER_10_SEC:
+ return 10000;
+ case H_LONG_BUSY_ORDER_100_SEC:
+ return 100000;
+ default:
+ return 1;
+ }
+}
+
+static long ehca_hcall_7arg_7ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7)
+{
+ long ret = H_SUCCESS;
+ int i, sleep_msecs;
+
+ EDEB_EN(7, "opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx arg5=%lx"
+ " arg6=%lx arg7=%lx", opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7);
+
+ for (i = 0; i < 5; i++) {
+ ret = plpar_hcall_7arg_7ret(opcode,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7,
+ out1, out2, out3, out4,
+ out5, out6,out7);
+
+ if (H_IS_LONG_BUSY(ret)) {
+ sleep_msecs = get_longbusy_msecs(ret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (ret < H_SUCCESS)
+ EDEB_ERR(4, "opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx",
+ opcode, ret,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7,
+ *out1, *out2, *out3, *out4,
+ *out5, *out6, *out7);
+
+ EDEB_EX(7, "opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
+ "out4=%lx out5=%lx out6=%lx out7=%lx",
+ opcode, ret, *out1, *out2, *out3, *out4, *out5,
+ *out6, *out7);
+ return ret;
+ }
+
+ EDEB_EX(7, "opcode=%lx ret=H_BUSY", opcode);
+
+ return H_BUSY;
+}
+
+static long ehca_hcall_9arg_9ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long arg9,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7,
+ unsigned long *out8,
+ unsigned long *out9)
+{
+ long ret = H_SUCCESS;
+ int i, sleep_msecs;
+
+ EDEB_EN(7, "opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
+ "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
+ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+ arg8, arg9);
+
+
+ for (i = 0; i < 5; i++) {
+ ret = plpar_hcall_9arg_9ret(opcode,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8,
+ arg9,
+ out1, out2, out3, out4,
+ out5, out6, out7, out8,
+ out9);
+
+ if (H_IS_LONG_BUSY(ret)) {
+ sleep_msecs = get_longbusy_msecs(ret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (ret < H_SUCCESS)
+ EDEB_ERR(4, "opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
+ " arg9=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx out8=%lx"
+ " out9=%lx",
+ opcode, ret,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8,
+ arg9,
+ *out1, *out2, *out3, *out4,
+ *out5, *out6, *out7, *out8,
+ *out9);
+
+ EDEB_EX(7, "opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
+ "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx out9=%lx",
+ opcode, ret,*out1, *out2, *out3, *out4, *out5, *out6,
+ *out7, *out8, *out9);
+ return ret;
+
+ }
+
+ EDEB_EX(7, "opcode=%lx ret=H_BUSY", opcode);
+ return H_BUSY;
+}
+
+u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_pfeq *pfeq,
+ const u32 neq_control,
+ const u32 number_of_entries,
+ struct ipz_eq_handle *eq_handle,
+ u32 * act_nr_of_entries,
+ u32 * act_pages,
+ u32 * eq_ist)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 act_nr_of_entries_out = 0;
+ u64 act_pages_out = 0;
+ u64 eq_ist_out = 0;
+ u64 allocate_controls = 0;
+ u32 x = (u64)(&x);
+
+ EDEB_EN(7, "pfeq=%p adapter_handle=%lx new_control=%x"
+ " number_of_entries=%x",
+ pfeq, adapter_handle.handle, neq_control,
+ number_of_entries);
+
+ /* resource type */
+ allocate_controls = 3ULL;
+
+ /* ISN is associated */
+ if (neq_control != 1)
+ allocate_controls = (1ULL << (63 - 7)) | allocate_controls;
+ else /* notification event queue */
+ allocate_controls = (1ULL << 63) | allocate_controls;
+
+ ret = ehca_hcall_7arg_7ret(H_ALLOC_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ allocate_controls, /* r5 */
+ number_of_entries, /* r6 */
+ 0, 0, 0, 0,
+ &eq_handle->handle, /* r4 */
+ &dummy, /* r5 */
+ &dummy, /* r6 */
+ &act_nr_of_entries_out, /* r7 */
+ &act_pages_out, /* r8 */
+ &eq_ist_out, /* r8 */
+ &dummy);
+
+ *act_nr_of_entries = (u32)act_nr_of_entries_out;
+ *act_pages = (u32)act_pages_out;
+ *eq_ist = (u32)eq_ist_out;
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ EDEB_ERR(4, "Not enough resource - ret=%lx ", ret);
+
+ EDEB_EX(7, "act_nr_of_entries=%x act_pages=%x eq_ist=%x",
+ *act_nr_of_entries, *act_pages, *eq_ist);
+
+ return ret;
+}
+
+u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
+ struct ipz_eq_handle eq_handle,
+ const u64 event_mask)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+
+ EDEB_EN(7, "eq_handle=%lx, adapter_handle=%lx event_mask=%lx",
+ eq_handle.handle, adapter_handle.handle, event_mask);
+
+ ret = ehca_hcall_7arg_7ret(H_RESET_EVENTS,
+ adapter_handle.handle, /* r4 */
+ eq_handle.handle, /* r5 */
+ event_mask, /* r6 */
+ 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ struct ehca_alloc_cq_parms *param)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 act_nr_of_entries_out;
+ u64 act_pages_out;
+ u64 g_la_privileged_out;
+ u64 g_la_user_out;
+
+ EDEB_EN(7, "Adapter_handle=%lx eq_handle=%lx cq_token=%x"
+ " cq_number_of_entries=%x",
+ adapter_handle.handle, param->eq_handle.handle,
+ cq->token, param->nr_cqe);
+
+ ret = ehca_hcall_7arg_7ret(H_ALLOC_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ 2, /* r5 */
+ param->eq_handle.handle, /* r6 */
+ cq->token, /* r7 */
+ param->nr_cqe, /* r8 */
+ 0, 0,
+ &cq->ipz_cq_handle.handle, /* r4 */
+ &dummy, /* r5 */
+ &dummy, /* r6 */
+ &act_nr_of_entries_out, /* r7 */
+ &act_pages_out, /* r8 */
+ &g_la_privileged_out, /* r9 */
+ &g_la_user_out); /* r10 */
+
+ param->act_nr_of_entries = (u32)act_nr_of_entries_out;
+ param->act_pages = (u32)act_pages_out;
+
+ if (ret == H_SUCCESS)
+ hcp_galpas_ctor(&cq->galpas, g_la_privileged_out, g_la_user_out);
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ EDEB_ERR(4, "Not enough resources. ret=%lx", ret);
+
+ EDEB_EX(7, "cq_handle=%lx act_nr_of_entries=%x act_pages=%x",
+ cq->ipz_cq_handle.handle, param->act_nr_of_entries, param->act_pages);
+
+ return ret;
+}
+
+u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp,
+ struct ehca_alloc_qp_parms *parms)
+{
+ u64 ret = H_SUCCESS;
+ u64 allocate_controls;
+ u64 max_r10_reg;
+ u64 dummy = 0;
+ u64 qp_nr_out = 0;
+ u64 r6_out = 0;
+ u64 r7_out = 0;
+ u64 r8_out = 0;
+ u64 g_la_user_out = 0;
+ u64 r11_out = 0;
+ u16 max_nr_receive_wqes = qp->init_attr.cap.max_recv_wr + 1;
+ u16 max_nr_send_wqes = qp->init_attr.cap.max_send_wr + 1;
+ int daqp_ctrl = parms->daqp_ctrl;
+
+ EDEB_EN(7, "Adapter_handle=%lx servicetype=%x signalingtype=%x"
+ " ud_av_l_key=%x send_cq_handle=%lx receive_cq_handle=%lx"
+ " async_eq_handle=%lx qp_token=%x pd=%x max_nr_send_wqes=%x"
+ " max_nr_receive_wqes=%x max_nr_send_sges=%x"
+ " max_nr_receive_sges=%x ud_av_l_key=%x galpa.pid=%x",
+ adapter_handle.handle, parms->servicetype, parms->sigtype,
+ parms->ud_av_l_key_ctl, qp->send_cq->ipz_cq_handle.handle,
+ qp->recv_cq->ipz_cq_handle.handle, parms->ipz_eq_handle.handle,
+ qp->token, parms->pd.value, max_nr_send_wqes,
+ max_nr_receive_wqes, parms->max_send_sge, parms->max_recv_sge,
+ parms->ud_av_l_key_ctl, qp->galpas.pid);
+
+ allocate_controls =
+ EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS,
+ (daqp_ctrl & DAQP_CTRL_ENABLE) ? 1 : 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
+ (daqp_ctrl & DAQP_CTRL_RECV_COMP) ? 1 : 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
+ (daqp_ctrl & DAQP_CTRL_SEND_COMP) ? 1 : 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL,
+ parms->ud_av_l_key_ctl)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1);
+
+ max_r10_reg =
+ EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
+ max_nr_send_wqes)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
+ max_nr_receive_wqes)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
+ parms->max_send_sge)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
+ parms->max_recv_sge);
+
+
+ ret = ehca_hcall_9arg_9ret(H_ALLOC_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ allocate_controls, /* r5 */
+ qp->send_cq->ipz_cq_handle.handle,
+ qp->recv_cq->ipz_cq_handle.handle,
+ parms->ipz_eq_handle.handle,
+ ((u64)qp->token << 32) | parms->pd.value,
+ max_r10_reg, /* r10 */
+ parms->ud_av_l_key_ctl, /* r11 */
+ 0,
+ &qp->ipz_qp_handle.handle,
+ &qp_nr_out, /* r5 */
+ &r6_out, /* r6 */
+ &r7_out, /* r7 */
+ &r8_out, /* r8 */
+ &dummy, /* r9 */
+ &g_la_user_out, /* r10 */
+ &r11_out,
+ &dummy);
+
+ /* extract outputs */
+ qp->real_qp_num = (u32)qp_nr_out;
+
+ parms->act_nr_send_sges =
+ (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, r6_out);
+ parms->act_nr_recv_wqes =
+ (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, r6_out);
+ parms->act_nr_send_sges =
+ (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, r7_out);
+ parms->act_nr_recv_sges =
+ (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, r7_out);
+ parms->nr_sq_pages =
+ (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, r8_out);
+ parms->nr_rq_pages =
+ (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, r8_out);
+
+ if (ret == H_SUCCESS)
+ hcp_galpas_ctor(&qp->galpas, g_la_user_out, g_la_user_out);
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ EDEB_ERR(4, "Not enough resources. ret=%lx",ret);
+
+ EDEB_EX(7, "qp_nr=%x act_nr_send_wqes=%x"
+ " act_nr_receive_wqes=%x act_nr_send_sges=%x"
+ " act_nr_receive_sges=%x nr_sq_pages=%x"
+ " nr_rq_pages=%x galpa.user=%lx galpa.kernel=%lx",
+ qp->real_qp_num, parms->act_nr_send_wqes,
+ parms->act_nr_recv_wqes, parms->act_nr_send_sges,
+ parms->act_nr_recv_sges, parms->nr_sq_pages,
+ parms->nr_rq_pages, qp->galpas.user.fw_handle,
+ qp->galpas.kernel.fw_handle);
+
+ return ret;
+}
+
+u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
+ const u8 port_id,
+ struct hipz_query_port *query_port_response_block)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 r_cb;
+
+ EDEB_EN(7, "adapter_handle=%lx port_id %x",
+ adapter_handle.handle, port_id);
+
+ if (((u64)query_port_response_block) & 0xfff) {
+ EDEB_ERR(4, "response block not page aligned");
+ ret = H_PARAMETER;
+ return ret;
+ }
+
+ r_cb = virt_to_abs(query_port_response_block);
+
+ ret = ehca_hcall_7arg_7ret(H_QUERY_PORT,
+ adapter_handle.handle, /* r4 */
+ port_id, /* r5 */
+ r_cb, /* r6 */
+ 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB_DMP(7, query_port_response_block, 64, "query_port_response_block");
+ EDEB(7, "offset31=%x offset35=%x offset36=%x",
+ ((u32*)query_port_response_block)[32],
+ ((u32*)query_port_response_block)[36],
+ ((u32*)query_port_response_block)[37]);
+ EDEB(7, "offset200=%x offset201=%x offset202=%x "
+ "offset203=%x",
+ ((u32*)query_port_response_block)[0x200],
+ ((u32*)query_port_response_block)[0x201],
+ ((u32*)query_port_response_block)[0x202],
+ ((u32*)query_port_response_block)[0x203]);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
+ struct hipz_query_hca *query_hca_rblock)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 r_cb;
+ EDEB_EN(7, "adapter_handle=%lx", adapter_handle.handle);
+
+ if (((u64)query_hca_rblock) & 0xfff) {
+ EDEB_ERR(4, "response block not page aligned");
+ ret = H_PARAMETER;
+ return ret;
+ }
+
+ r_cb = virt_to_abs(query_hca_rblock);
+
+ ret = ehca_hcall_7arg_7ret(H_QUERY_HCA,
+ adapter_handle.handle, /* r4 */
+ r_cb, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB(7, "offset0=%x offset1=%x offset2=%x offset3=%x",
+ ((u32*)query_hca_rblock)[0],
+ ((u32*)query_hca_rblock)[1],
+ ((u32*)query_hca_rblock)[2], ((u32*)query_hca_rblock)[3]);
+ EDEB(7, "offset4=%x offset5=%x offset6=%x offset7=%x",
+ ((u32*)query_hca_rblock)[4],
+ ((u32*)query_hca_rblock)[5],
+ ((u32*)query_hca_rblock)[6], ((u32*)query_hca_rblock)[7]);
+ EDEB(7, "offset8=%x offset9=%x offseta=%x offsetb=%x",
+ ((u32*)query_hca_rblock)[8],
+ ((u32*)query_hca_rblock)[9],
+ ((u32*)query_hca_rblock)[10], ((u32*)query_hca_rblock)[11]);
+ EDEB(7, "offsetc=%x offsetd=%x offsete=%x offsetf=%x",
+ ((u32*)query_hca_rblock)[12],
+ ((u32*)query_hca_rblock)[13],
+ ((u32*)query_hca_rblock)[14], ((u32*)query_hca_rblock)[15]);
+ EDEB(7, "offset136=%x offset192=%x offset204=%x",
+ ((u32*)query_hca_rblock)[32],
+ ((u32*)query_hca_rblock)[48], ((u32*)query_hca_rblock)[51]);
+ EDEB(7, "offset231=%x offset235=%x",
+ ((u32*)query_hca_rblock)[57], ((u32*)query_hca_rblock)[58]);
+ EDEB(7, "offset200=%x offset201=%x offset202=%x offset203=%x",
+ ((u32*)query_hca_rblock)[0x201],
+ ((u32*)query_hca_rblock)[0x202],
+ ((u32*)query_hca_rblock)[0x203],
+ ((u32*)query_hca_rblock)[0x204]);
+
+ EDEB_EX(7, "ret=%lx adapter_handle=%lx",
+ ret, adapter_handle.handle);
+
+ return ret;
+}
+
+u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 logical_address_of_page,
+ u64 count)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+
+ EDEB_EN(7, "adapter_handle=%lx pagesize=%x queue_type=%x"
+ " resource_handle=%lx logical_address_of_page=%lx count=%lx",
+ adapter_handle.handle, pagesize, queue_type,
+ resource_handle, logical_address_of_page, count);
+
+ ret = ehca_hcall_7arg_7ret(H_REGISTER_RPAGES,
+ adapter_handle.handle, /* r4 */
+ queue_type | pagesize << 8, /* r5 */
+ resource_handle, /* r6 */
+ logical_address_of_page, /* r7 */
+ count, /* r8 */
+ 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_eq_handle eq_handle,
+ struct ehca_pfeq *pfeq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count)
+{
+ u64 ret = H_SUCCESS;
+
+ EDEB_EN(7, "pfeq=%p adapter_handle=%lx eq_handle=%lx pagesize=%x"
+ " queue_type=%x logical_address_of_page=%lx count=%lx",
+ pfeq, adapter_handle.handle, eq_handle.handle, pagesize,
+ queue_type,logical_address_of_page, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "Ppage counter=%lx", count);
+ return H_PARAMETER;
+ }
+ ret = hipz_h_register_rpage(adapter_handle,
+ pagesize,
+ queue_type,
+ eq_handle.handle,
+ logical_address_of_page, count);
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u32 hipz_h_query_int_state(const struct ipz_adapter_handle adapter_handle,
+ u32 ist)
+{
+ u32 ret = H_SUCCESS;
+ u64 dummy = 0;
+
+ EDEB_EN(7, "ist=%x", ist);
+
+ ret = ehca_hcall_7arg_7ret(H_QUERY_INT_STATE,
+ adapter_handle.handle, /* r4 */
+ ist, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ if (ret != H_SUCCESS && ret != H_BUSY)
+ EDEB_ERR(4, "Could not query interrupt state.");
+
+ EDEB_EX(7, "interrupt state: %x", ret);
+
+ return ret;
+}
+
+u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_cq_handle cq_handle,
+ struct ehca_pfcq *pfcq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa gal)
+{
+ u64 ret = H_SUCCESS;
+
+ EDEB_EN(7, "pfcq=%p adapter_handle=%lx cq_handle=%lx pagesize=%x"
+ " queue_type=%x logical_address_of_page=%lx count=%lx",
+ pfcq, adapter_handle.handle, cq_handle.handle, pagesize,
+ queue_type, logical_address_of_page, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "Page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ ret = hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
+ cq_handle.handle, logical_address_of_page,
+ count);
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa galpa)
+{
+ u64 ret = H_SUCCESS;
+
+ EDEB_EN(7, "pfqp=%p adapter_handle=%lx qp_handle=%lx pagesize=%x"
+ " queue_type=%x logical_address_of_page=%lx count=%lx",
+ pfqp, adapter_handle.handle, qp_handle.handle, pagesize,
+ queue_type, logical_address_of_page, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "Page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ ret = hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
+ qp_handle.handle,logical_address_of_page,
+ count);
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ void **log_addr_next_sq_wqe2processed,
+ void **log_addr_next_rq_wqe2processed,
+ int dis_and_get_function_code)
+{
+ u64 ret = H_SUCCESS;
+ u8 function_code = 1;
+ u64 dummy, dummy1, dummy2;
+
+ EDEB_EN(7, "pfqp=%p adapter_handle=%lx function=%x qp_handle=%lx",
+ pfqp, adapter_handle.handle, function_code, qp_handle.handle);
+
+ if (!log_addr_next_sq_wqe2processed)
+ log_addr_next_sq_wqe2processed = (void**)&dummy1;
+ if (!log_addr_next_rq_wqe2processed)
+ log_addr_next_rq_wqe2processed = (void**)&dummy2;
+
+ ret = ehca_hcall_7arg_7ret(H_DISABLE_AND_GETC,
+ adapter_handle.handle, /* r4 */
+ dis_and_get_function_code, /* r5 */
+ qp_handle.handle, /* r6 */
+ 0, 0, 0, 0,
+ (void*)log_addr_next_sq_wqe2processed,
+ (void*)log_addr_next_rq_wqe2processed,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+ EDEB_EX(7, "ret=%lx ladr_next_rq_wqe_out=%p"
+ " ladr_next_sq_wqe_out=%p", ret,
+ *log_addr_next_sq_wqe2processed,
+ *log_addr_next_rq_wqe2processed);
+
+ return ret;
+}
+
+u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u64 update_mask,
+ struct hcp_modify_qp_control_block *mqpcb,
+ struct h_galpa gal)
+{
+ u64 ret = H_SUCCESS;
+ u64 invalid_attribute_identifier = 0;
+ u64 rc_attrib_mask = 0;
+ u64 dummy;
+ u64 r_cb;
+ EDEB_EN(7, "pfqp=%p adapter_handle=%lx qp_handle=%lx"
+ " update_mask=%lx qp_state=%x mqpcb=%p",
+ pfqp, adapter_handle.handle, qp_handle.handle,
+ update_mask, mqpcb->qp_state, mqpcb);
+
+ r_cb = virt_to_abs(mqpcb);
+ ret = ehca_hcall_7arg_7ret(H_MODIFY_QP,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ update_mask, /* r6 */
+ r_cb, /* r7 */
+ 0, 0, 0,
+ &invalid_attribute_identifier, /* r4 */
+ &dummy, /* r5 */
+ &dummy, /* r6 */
+ &dummy, /* r7 */
+ &dummy, /* r8 */
+ &rc_attrib_mask, /* r9 */
+ &dummy);
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ EDEB_ERR(4, "Insufficient resources ret=%lx", ret);
+
+ EDEB_EX(7, "ret=%lx invalid_attribute_identifier=%lx"
+ " invalid_attribute_MASK=%lx", ret,
+ invalid_attribute_identifier, rc_attrib_mask);
+
+ return ret;
+}
+
+u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ struct hcp_modify_qp_control_block *qqpcb,
+ struct h_galpa gal)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 r_cb;
+ EDEB_EN(7, "adapter_handle=%lx qp_handle=%lx",
+ adapter_handle.handle, qp_handle.handle);
+
+ r_cb = virt_to_abs(qqpcb);
+ EDEB(7, "r_cb=%lx", r_cb);
+
+ ret = ehca_hcall_7arg_7ret(H_QUERY_QP,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ r_cb, /* r6 */
+ 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 ladr_next_sq_wqe_out;
+ u64 ladr_next_rq_wqe_out;
+
+ EDEB_EN(7, "qp=%p ipz_qp_handle=%lx adapter_handle=%lx",
+ qp, qp->ipz_qp_handle.handle, adapter_handle.handle);
+
+ ret = hcp_galpas_dtor(&qp->galpas);
+ if (ret) {
+ EDEB_ERR(4, "Could not destruct qp->galpas");
+ return H_RESOURCE;
+ }
+ ret = ehca_hcall_7arg_7ret(H_DISABLE_AND_GETC,
+ adapter_handle.handle, /* r4 */
+ /* function code */
+ 1, /* r5 */
+ qp->ipz_qp_handle.handle, /* r6 */
+ 0, 0, 0, 0,
+ &ladr_next_sq_wqe_out, /* r4 */
+ &ladr_next_rq_wqe_out, /* r5 */
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+ if (ret == H_HARDWARE)
+ EDEB_ERR(4, "HCA not operational. ret=%lx", ret);
+
+ ret = ehca_hcall_7arg_7ret(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ qp->ipz_qp_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ if (ret == H_RESOURCE)
+ EDEB_ERR(4, "Resource still in use. ret=%lx", ret);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+
+ EDEB_EN(7, "port=%x ipz_qp_handle=%lx adapter_handle=%lx",
+ port, qp_handle.handle, adapter_handle.handle);
+
+ ret = ehca_hcall_7arg_7ret(H_DEFINE_AQP0,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ port, /* r6 */
+ 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port, u32 * pma_qp_nr,
+ u32 * bma_qp_nr)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 pma_qp_nr_out;
+ u64 bma_qp_nr_out;
+
+ EDEB_EN(7, "port=%x qp_handle=%lx adapter_handle=%lx",
+ port, qp_handle.handle, adapter_handle.handle);
+
+ ret = ehca_hcall_7arg_7ret(H_DEFINE_AQP1,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ port, /* r6 */
+ 0, 0, 0, 0,
+ &pma_qp_nr_out, /* r4 */
+ &bma_qp_nr_out, /* r5 */
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ *pma_qp_nr = (u32)pma_qp_nr_out;
+ *bma_qp_nr = (u32)bma_qp_nr_out;
+
+ if (ret == H_ALIAS_EXIST)
+ EDEB_ERR(4, "AQP1 already exists. ret=%lx", ret);
+
+ EDEB_EX(7, "ret=%lx pma_qp_nr=%i bma_qp_nr=%i",
+ ret, (int)*pma_qp_nr, (int)*bma_qp_nr);
+
+ return ret;
+}
+
+u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u8 *dgid_sp = (u8*)&subnet_prefix;
+ u8 *dgid_ii = (u8*)&interface_id;
+
+ EDEB_EN(7, "qp_handle=%lx adapter_handle=%lx\nMCG_DGID ="
+ " %d.%d.%d.%d.%d.%d.%d.%d."
+ " %d.%d.%d.%d.%d.%d.%d.%d",
+ qp_handle.handle, adapter_handle.handle,
+ dgid_sp[0], dgid_sp[1],
+ dgid_sp[2], dgid_sp[3],
+ dgid_sp[4], dgid_sp[5],
+ dgid_sp[6], dgid_sp[7],
+ dgid_ii[0], dgid_ii[1],
+ dgid_ii[2], dgid_ii[3],
+ dgid_ii[4], dgid_ii[5],
+ dgid_ii[6], dgid_ii[7]);
+
+ ret = ehca_hcall_7arg_7ret(H_ATTACH_MCQP,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ mcg_dlid, /* r6 */
+ interface_id, /* r7 */
+ subnet_prefix, /* r8 */
+ 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ EDEB_ERR(4, "Not enough resources. ret=%lx", ret);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u8 *dgid_sp = (u8*)&subnet_prefix;
+ u8 *dgid_ii = (u8*)&interface_id;
+
+ EDEB_EN(7, "qp_handle=%lx adapter_handle=%lx\nMCG_DGID ="
+ " %d.%d.%d.%d.%d.%d.%d.%d."
+ " %d.%d.%d.%d.%d.%d.%d.%d",
+ qp_handle.handle, adapter_handle.handle,
+ dgid_sp[0], dgid_sp[1],
+ dgid_sp[2], dgid_sp[3],
+ dgid_sp[4], dgid_sp[5],
+ dgid_sp[6], dgid_sp[7],
+ dgid_ii[0], dgid_ii[1],
+ dgid_ii[2], dgid_ii[3],
+ dgid_ii[4], dgid_ii[5],
+ dgid_ii[6], dgid_ii[7]);
+ ret = ehca_hcall_7arg_7ret(H_DETACH_MCQP,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ mcg_dlid, /* r6 */
+ interface_id, /* r7 */
+ subnet_prefix, /* r8 */
+ 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ u8 force_flag)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+
+ EDEB_EN(7, "cq->pf=%p cq=.%p ipz_cq_handle=%lx adapter_handle=%lx",
+ &cq->pf, cq, cq->ipz_cq_handle.handle, adapter_handle.handle);
+
+ ret = hcp_galpas_dtor(&cq->galpas);
+ if (ret) {
+ EDEB_ERR(4, "Could not destruct cp->galpas");
+ return H_RESOURCE;
+ }
+
+ ret = ehca_hcall_7arg_7ret(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ cq->ipz_cq_handle.handle, /* r5 */
+ force_flag != 0 ? 1L : 0L, /* r6 */
+ 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ if (ret == H_RESOURCE)
+ EDEB(4, "ret=%lx ", ret);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_eq *eq)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+
+ EDEB_EN(7, "eq->pf=%p eq=%p ipz_eq_handle=%lx adapter_handle=%lx",
+ &eq->pf, eq, eq->ipz_eq_handle.handle,
+ adapter_handle.handle);
+
+ ret = hcp_galpas_dtor(&eq->galpas);
+ if (ret) {
+ EDEB_ERR(4, "Could not destruct eq->galpas");
+ return H_RESOURCE;
+ }
+
+ ret = ehca_hcall_7arg_7ret(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ eq->ipz_eq_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+
+ if (ret == H_RESOURCE)
+ EDEB_ERR(4, "Resource in use. ret=%lx ", ret);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 lkey_out;
+ u64 rkey_out;
+
+ EDEB_EN(7, "adapter_handle=%lx mr=%p vaddr=%lx length=%lx"
+ " access_ctrl=%x pd=%x",
+ adapter_handle.handle, mr, vaddr, length, access_ctrl,
+ pd.value);
+
+ ret = ehca_hcall_7arg_7ret(H_ALLOC_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ 5, /* r5 */
+ vaddr, /* r6 */
+ length, /* r7 */
+ (((u64)access_ctrl) << 32ULL), /* r8 */
+ pd.value, /* r9 */
+ 0,
+ &(outparms->handle.handle), /* r4 */
+ &dummy, /* r5 */
+ &lkey_out, /* r6 */
+ &rkey_out, /* r7 */
+ &dummy,
+ &dummy,
+ &dummy);
+ outparms->lkey = (u32)lkey_out;
+ outparms->rkey = (u32)rkey_out;
+
+ EDEB_EX(7, "ret=%lx mr_handle=%lx lkey=%x rkey=%x",
+ ret, outparms->handle.handle, outparms->lkey, outparms->rkey);
+
+ return ret;
+}
+
+u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count)
+{
+ u64 ret = H_SUCCESS;
+
+ EDEB_EN(7, "adapter_handle=%lx mr=%p mr_handle=%lx pagesize=%x"
+ " queue_type=%x logical_address_of_page=%lx count=%lx",
+ adapter_handle.handle, mr, mr->ipz_mr_handle.handle, pagesize,
+ queue_type, logical_address_of_page, count);
+
+ if ((count > 1) && (logical_address_of_page & 0xfff)) {
+ EDEB_ERR(4, "logical_address_of_page not on a 4k boundary "
+ "adapter_handle=%lx mr=%p mr_handle=%lx "
+ "pagesize=%x queue_type=%x logical_address_of_page=%lx"
+ " count=%lx",
+ adapter_handle.handle, mr, mr->ipz_mr_handle.handle,
+ pagesize, queue_type, logical_address_of_page, count);
+ ret = H_PARAMETER;
+ } else
+ ret = hipz_h_register_rpage(adapter_handle, pagesize,
+ queue_type,
+ mr->ipz_mr_handle.handle,
+ logical_address_of_page, count);
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 remote_len_out;
+ u64 remote_vaddr_out;
+ u64 acc_ctrl_pd_out;
+ u64 r9_out;
+
+ EDEB_EN(7, "adapter_handle=%lx mr=%p mr_handle=%lx",
+ adapter_handle.handle, mr, mr->ipz_mr_handle.handle);
+
+ ret = ehca_hcall_7arg_7ret(H_QUERY_MR,
+ adapter_handle.handle, /* r4 */
+ mr->ipz_mr_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &outparms->len, /* r4 */
+ &outparms->vaddr, /* r5 */
+ &remote_len_out, /* r6 */
+ &remote_vaddr_out, /* r7 */
+ &acc_ctrl_pd_out, /* r8 */
+ &r9_out,
+ &dummy);
+
+ outparms->acl = acc_ctrl_pd_out >> 32;
+ outparms->lkey = (u32)(r9_out >> 32);
+ outparms->rkey = (u32)(r9_out & (0xffffffff));
+
+ EDEB_EX(7, "ret=%lx mr_local_length=%lx mr_local_vaddr=%lx "
+ "mr_remote_length=%lx mr_remote_vaddr=%lx access_ctrl=%x "
+ "pd=%x lkey=%x rkey=%x", ret, outparms->len,
+ outparms->vaddr, remote_len_out, remote_vaddr_out,
+ outparms->acl, outparms->acl, outparms->lkey, outparms->rkey);
+
+ return ret;
+}
+
+u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+
+ EDEB_EN(7, "adapter_handle=%lx mr=%p mr_handle=%lx",
+ adapter_handle.handle, mr, mr->ipz_mr_handle.handle);
+
+ ret = ehca_hcall_7arg_7ret(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ mr->ipz_mr_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr_in,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ const u64 mr_addr_cb,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 lkey_out;
+ u64 rkey_out;
+
+ EDEB_EN(7, "adapter_handle=%lx mr=%p mr_handle=%lx vaddr_in=%lx "
+ "length=%lx access_ctrl=%x pd=%x mr_addr_cb=%lx",
+ adapter_handle.handle, mr, mr->ipz_mr_handle.handle, vaddr_in,
+ length, access_ctrl, pd.value, mr_addr_cb);
+
+ ret = ehca_hcall_7arg_7ret(H_REREGISTER_PMR,
+ adapter_handle.handle, /* r4 */
+ mr->ipz_mr_handle.handle, /* r5 */
+ vaddr_in, /* r6 */
+ length, /* r7 */
+ /* r8 */
+ ((((u64)access_ctrl) << 32ULL) | pd.value),
+ mr_addr_cb, /* r9 */
+ 0,
+ &dummy, /* r4 */
+ &outparms->vaddr, /* r5 */
+ &lkey_out, /* r6 */
+ &rkey_out, /* r7 */
+ &dummy,
+ &dummy,
+ &dummy);
+
+ outparms->lkey = (u32)lkey_out;
+ outparms->rkey = (u32)rkey_out;
+
+ EDEB_EX(7, "ret=%lx vaddr=%lx lkey=%x rkey=%x",
+ ret, outparms->vaddr, outparms->lkey, outparms->rkey);
+ return ret;
+}
+
+u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const struct ehca_mr *orig_mr,
+ const u64 vaddr_in,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 lkey_out;
+ u64 rkey_out;
+
+ EDEB_EN(7, "adapter_handle=%lx orig_mr=%p orig_mr_handle=%lx "
+ "vaddr_in=%lx access_ctrl=%x pd=%x", adapter_handle.handle,
+ orig_mr, orig_mr->ipz_mr_handle.handle, vaddr_in, access_ctrl,
+ pd.value);
+
+
+ ret = ehca_hcall_7arg_7ret(H_REGISTER_SMR,
+ adapter_handle.handle, /* r4 */
+ orig_mr->ipz_mr_handle.handle, /* r5 */
+ vaddr_in, /* r6 */
+ (((u64)access_ctrl) << 32ULL), /* r7 */
+ pd.value, /* r8 */
+ 0, 0,
+ &(outparms->handle.handle), /* r4 */
+ &dummy, /* r5 */
+ &lkey_out, /* r6 */
+ &rkey_out, /* r7 */
+ &dummy,
+ &dummy,
+ &dummy);
+ outparms->lkey = (u32)lkey_out;
+ outparms->rkey = (u32)rkey_out;
+
+ EDEB_EX(7, "ret=%lx mr_handle=%lx lkey=%x rkey=%x",
+ ret, outparms->handle.handle, outparms->lkey, outparms->rkey);
+
+ return ret;
+}
+
+u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ const struct ipz_pd pd,
+ struct ehca_mw_hipzout_parms *outparms)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 rkey_out;
+
+ EDEB_EN(7, "adapter_handle=%lx mw=%p pd=%x",
+ adapter_handle.handle, mw, pd.value);
+
+ ret = ehca_hcall_7arg_7ret(H_ALLOC_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ 6, /* r5 */
+ pd.value, /* r6 */
+ 0, 0, 0, 0,
+ &(outparms->handle.handle), /* r4 */
+ &dummy, /* r5 */
+ &dummy, /* r6 */
+ &rkey_out, /* r7 */
+ &dummy,
+ &dummy,
+ &dummy);
+
+ outparms->rkey = (u32)rkey_out;
+
+ EDEB_EX(7, "ret=%lx mw_handle=%lx rkey=%x",
+ ret, outparms->handle.handle, outparms->rkey);
+ return ret;
+}
+
+u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ struct ehca_mw_hipzout_parms *outparms)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 pd_out;
+ u64 rkey_out;
+
+ EDEB_EN(7, "adapter_handle=%lx mw=%p mw_handle=%lx",
+ adapter_handle.handle, mw, mw->ipz_mw_handle.handle);
+
+ ret = ehca_hcall_7arg_7ret(H_QUERY_MW,
+ adapter_handle.handle, /* r4 */
+ mw->ipz_mw_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy, /* r4 */
+ &dummy, /* r5 */
+ &dummy, /* r6 */
+ &rkey_out, /* r7 */
+ &pd_out, /* r8 */
+ &dummy,
+ &dummy);
+ outparms->rkey = (u32)rkey_out;
+
+ EDEB_EX(7, "ret=%lx rkey=%x pd=%lx", ret, outparms->rkey, pd_out);
+
+ return ret;
+}
+
+u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+
+ EDEB_EN(7, "adapter_handle=%lx mw=%p mw_handle=%lx",
+ adapter_handle.handle, mw, mw->ipz_mw_handle.handle);
+
+ ret = ehca_hcall_7arg_7ret(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ mw->ipz_mw_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
+ const u64 ressource_handle,
+ void *rblock,
+ unsigned long *byte_count)
+{
+ u64 ret = H_SUCCESS;
+ u64 dummy;
+ u64 r_cb;
+
+ EDEB_EN(7, "adapter_handle=%lx ressource_handle=%lx rblock=%p",
+ adapter_handle.handle, ressource_handle, rblock);
+
+ if (((u64)rblock) & 0xfff) {
+ EDEB_ERR(4, "rblock not page aligned.");
+ ret = H_PARAMETER;
+ return ret;
+ }
+
+ r_cb = virt_to_abs(rblock);
+
+ ret = ehca_hcall_7arg_7ret(H_ERROR_DATA,
+ adapter_handle.handle,
+ ressource_handle,
+ r_cb,
+ 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB_EX(7, "ret=%lx", ret);
+
+ return ret;
+}
^ permalink raw reply
* [PATCH 13/16] ehca: hardware interface
From: Heiko J Schick @ 2006-05-15 17:43 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>
drivers/infiniband/hw/ehca/hipz_fns.h | 68 ++++
drivers/infiniband/hw/ehca/hipz_fns_core.h | 122 ++++++++
drivers/infiniband/hw/ehca/hipz_hw.h | 395 +++++++++++++++++++++++++++++
3 files changed, 585 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hipz_fns.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hipz_fns.h 2006-05-02 12:48:48.000000000 +0200
@@ -0,0 +1,68 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * HW abstraction register functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Reinhard Ernst <rernst@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.
+ */
+
+#ifndef __HIPZ_FNS_H__
+#define __HIPZ_FNS_H__
+
+#include "ehca_classes.h"
+#include "hipz_hw.h"
+
+#include "hipz_fns_core.h"
+
+#define hipz_galpa_store_eq(gal, offset, value) \
+ hipz_galpa_store(gal, EQTEMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_eq(gal, offset) \
+ hipz_galpa_load(gal, EQTEMM_OFFSET(offset))
+
+#define hipz_galpa_store_qped(gal, offset, value) \
+ hipz_galpa_store(gal, QPEDMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_qped(gal, offset) \
+ hipz_galpa_load(gal, QPEDMM_OFFSET(offset))
+
+#define hipz_galpa_store_mrmw(gal, offset, value) \
+ hipz_galpa_store(gal, MRMWMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_mrmw(gal, offset) \
+ hipz_galpa_load(gal, MRMWMM_OFFSET(offset))
+
+#endif
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hipz_fns_core.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hipz_fns_core.h 2006-05-02 12:48:48.000000000 +0200
@@ -0,0 +1,122 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * HW abstraction register functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Reinhard Ernst <rernst@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.
+ */
+
+#ifndef __HIPZ_FNS_CORE_H__
+#define __HIPZ_FNS_CORE_H__
+
+#include "hcp_phyp.h"
+#include "hipz_hw.h"
+
+#define hipz_galpa_store_cq(gal, offset, value) \
+ hipz_galpa_store(gal, CQTEMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_cq(gal, offset) \
+ hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
+
+#define hipz_galpa_store_qp(gal,offset, value) \
+ hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
+#define hipz_galpa_load_qp(gal, offset) \
+ hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
+
+static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
+{
+ struct h_galpa gal;
+
+ EDEB_EN(7, "qp=%p", qp);
+ gal = qp->galpas.kernel;
+ /* ringing doorbell :-) */
+ hipz_galpa_store_qp(gal, qpx_sqa, EHCA_BMASK_SET(QPX_SQADDER, nr_wqes));
+ EDEB_EX(7, "qp=%p QPx_SQA = %i", qp, nr_wqes);
+}
+
+static inline void hipz_update_rqa(struct ehca_qp *qp, u16 nr_wqes)
+{
+ struct h_galpa gal;
+
+ EDEB_EN(7, "qp=%p", qp);
+ gal = qp->galpas.kernel;
+ /* ringing doorbell :-) */
+ hipz_galpa_store_qp(gal, qpx_rqa, EHCA_BMASK_SET(QPX_RQADDER, nr_wqes));
+ EDEB_EX(7, "qp=%p QPx_RQA = %i", qp, nr_wqes);
+}
+
+static inline void hipz_update_feca(struct ehca_cq *cq, u32 nr_cqes)
+{
+ struct h_galpa gal;
+
+ EDEB_EN(7, "cq=%p", cq);
+ gal = cq->galpas.kernel;
+ hipz_galpa_store_cq(gal, cqx_feca,
+ EHCA_BMASK_SET(CQX_FECADDER, nr_cqes));
+ EDEB_EX(7, "cq=%p CQx_FECA = %i", cq, nr_cqes);
+}
+
+static inline void hipz_set_cqx_n0(struct ehca_cq *cq, u32 value)
+{
+ struct h_galpa gal;
+ u64 CQx_N0_reg = 0;
+
+ EDEB_EN(7, "cq=%p event on solicited completion -- write CQx_N0", cq);
+ gal = cq->galpas.kernel;
+ hipz_galpa_store_cq(gal, cqx_n0,
+ EHCA_BMASK_SET(CQX_N0_GENERATE_SOLICITED_COMP_EVENT,
+ value));
+ CQx_N0_reg = hipz_galpa_load_cq(gal, cqx_n0);
+ EDEB_EX(7, "cq=%p loaded CQx_N0=%lx", cq, (unsigned long)CQx_N0_reg);
+}
+
+static inline void hipz_set_cqx_n1(struct ehca_cq *cq, u32 value)
+{
+ struct h_galpa gal;
+ u64 CQx_N1_reg = 0;
+
+ EDEB_EN(7, "cq=%p event on completion -- write CQx_N1",
+ cq);
+ gal = cq->galpas.kernel;
+ hipz_galpa_store_cq(gal, cqx_n1,
+ EHCA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, value));
+ CQx_N1_reg = hipz_galpa_load_cq(gal, cqx_n1);
+ EDEB_EX(7, "cq=%p loaded CQx_N1=%lx", cq, (unsigned long)CQx_N1_reg);
+}
+
+#endif /* __HIPZ_FNC_CORE_H__ */
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hipz_hw.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hipz_hw.h 2006-05-02 10:55:26.000000000 +0200
@@ -0,0 +1,395 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * eHCA register definitions
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Reinhard Ernst <rernst@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.
+ */
+
+#ifndef __HIPZ_HW_H__
+#define __HIPZ_HW_H__
+
+#include "ehca_tools.h"
+
+/** QP Table Entry Memory Map
+ */
+struct hipz_qptemm {
+ u64 qpx_hcr;
+ u64 qpx_c;
+ u64 qpx_herr;
+ u64 qpx_aer;
+/* 0x20*/
+ u64 qpx_sqa;
+ u64 qpx_sqc;
+ u64 qpx_rqa;
+ u64 qpx_rqc;
+/* 0x40*/
+ u64 qpx_st;
+ u64 qpx_pmstate;
+ u64 qpx_pmfa;
+ u64 qpx_pkey;
+/* 0x60*/
+ u64 qpx_pkeya;
+ u64 qpx_pkeyb;
+ u64 qpx_pkeyc;
+ u64 qpx_pkeyd;
+/* 0x80*/
+ u64 qpx_qkey;
+ u64 qpx_dqp;
+ u64 qpx_dlidp;
+ u64 qpx_portp;
+/* 0xa0*/
+ u64 qpx_slidp;
+ u64 qpx_slidpp;
+ u64 qpx_dlida;
+ u64 qpx_porta;
+/* 0xc0*/
+ u64 qpx_slida;
+ u64 qpx_slidpa;
+ u64 qpx_slvl;
+ u64 qpx_ipd;
+/* 0xe0*/
+ u64 qpx_mtu;
+ u64 qpx_lato;
+ u64 qpx_rlimit;
+ u64 qpx_rnrlimit;
+/* 0x100*/
+ u64 qpx_t;
+ u64 qpx_sqhp;
+ u64 qpx_sqptp;
+ u64 qpx_nspsn;
+/* 0x120*/
+ u64 qpx_nspsnhwm;
+ u64 reserved1;
+ u64 qpx_sdsi;
+ u64 qpx_sdsbc;
+/* 0x140*/
+ u64 qpx_sqwsize;
+ u64 qpx_sqwts;
+ u64 qpx_lsn;
+ u64 qpx_nssn;
+/* 0x160 */
+ u64 qpx_mor;
+ u64 qpx_cor;
+ u64 qpx_sqsize;
+ u64 qpx_erc;
+/* 0x180*/
+ u64 qpx_rnrrc;
+ u64 qpx_ernrwt;
+ u64 qpx_rnrresp;
+ u64 qpx_lmsna;
+/* 0x1a0 */
+ u64 qpx_sqhpc;
+ u64 qpx_sqcptp;
+ u64 qpx_sigt;
+ u64 qpx_wqecnt;
+/* 0x1c0*/
+
+ u64 qpx_rqhp;
+ u64 qpx_rqptp;
+ u64 qpx_rqsize;
+ u64 qpx_nrr;
+/* 0x1e0*/
+ u64 qpx_rdmac;
+ u64 qpx_nrpsn;
+ u64 qpx_lapsn;
+ u64 qpx_lcr;
+/* 0x200*/
+ u64 qpx_rwc;
+ u64 qpx_rwva;
+ u64 qpx_rdsi;
+ u64 qpx_rdsbc;
+/* 0x220*/
+ u64 qpx_rqwsize;
+ u64 qpx_crmsn;
+ u64 qpx_rdd;
+ u64 qpx_larpsn;
+/* 0x240*/
+ u64 qpx_pd;
+ u64 qpx_scqn;
+ u64 qpx_rcqn;
+ u64 qpx_aeqn;
+/* 0x260*/
+ u64 qpx_aaelog;
+ u64 qpx_ram;
+ u64 qpx_rdmaqe0;
+ u64 qpx_rdmaqe1;
+/* 0x280*/
+ u64 qpx_rdmaqe2;
+ u64 qpx_rdmaqe3;
+ u64 qpx_nrpsnhwm;
+/* 0x298*/
+ u64 reserved[(0x400 - 0x298) / 8];
+/* 0x400 extended data */
+ u64 reserved_ext[(0x500 - 0x400) / 8];
+/* 0x500 */
+ u64 reserved2[(0x1000 - 0x500) / 8];
+/* 0x1000 */
+};
+
+#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
+#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
+
+#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
+
+/** MRMWPT Entry Memory Map
+ */
+struct hipz_mrmwmm {
+ /* 0x00 */
+ u64 mrx_hcr;
+
+ u64 mrx_c;
+ u64 mrx_herr;
+ u64 mrx_aer;
+ /* 0x20 */
+ u64 mrx_pp;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ /* 0x40 */
+ u64 reserved4[(0x200 - 0x40) / 8];
+ /* 0x200 */
+ u64 mrx_ctl[64];
+
+};
+
+#define MRX_HCR_LPARID_VALID EHCA_BMASK_IBM(0,0)
+
+#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
+
+struct hipz_qpedmm {
+ /* 0x00 */
+ u64 reserved0[(0x400) / 8];
+ /* 0x400 */
+ u64 qpedx_phh;
+ u64 qpedx_ppsgp;
+ /* 0x410 */
+ u64 qpedx_ppsgu;
+ u64 qpedx_ppdgp;
+ /* 0x420 */
+ u64 qpedx_ppdgu;
+ u64 qpedx_aph;
+ /* 0x430 */
+ u64 qpedx_apsgp;
+ u64 qpedx_apsgu;
+ /* 0x440 */
+ u64 qpedx_apdgp;
+ u64 qpedx_apdgu;
+ /* 0x450 */
+ u64 qpedx_apav;
+ u64 qpedx_apsav;
+ /* 0x460 */
+ u64 qpedx_hcr;
+ u64 reserved1[4];
+ /* 0x488 */
+ u64 qpedx_rrl0;
+ /* 0x490 */
+ u64 qpedx_rrrkey0;
+ u64 qpedx_rrva0;
+ /* 0x4a0 */
+ u64 reserved2;
+ u64 qpedx_rrl1;
+ /* 0x4b0 */
+ u64 qpedx_rrrkey1;
+ u64 qpedx_rrva1;
+ /* 0x4c0 */
+ u64 reserved3;
+ u64 qpedx_rrl2;
+ /* 0x4d0 */
+ u64 qpedx_rrrkey2;
+ u64 qpedx_rrva2;
+ /* 0x4e0 */
+ u64 reserved4;
+ u64 qpedx_rrl3;
+ /* 0x4f0 */
+ u64 qpedx_rrrkey3;
+ u64 qpedx_rrva3;
+};
+
+#define QPEDMM_OFFSET(x) offsetof(struct hipz_QPEDMM,x)
+
+/** CQ Table Entry Memory Map
+ */
+struct hipz_cqtemm {
+ u64 cqx_hcr;
+ u64 cqx_c;
+ u64 cqx_herr;
+ u64 cqx_aer;
+/* 0x20 */
+ u64 cqx_ptp;
+ u64 cqx_tp;
+ u64 cqx_fec;
+ u64 cqx_feca;
+/* 0x40 */
+ u64 cqx_ep;
+ u64 cqx_eq;
+/* 0x50 */
+ u64 reserved1;
+ u64 cqx_n0;
+/* 0x60 */
+ u64 cqx_n1;
+ u64 reserved2[(0x1000 - 0x60) / 8];
+/* 0x1000 */
+};
+
+#define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32,63)
+#define CQX_FECADDER EHCA_BMASK_IBM(32,63)
+#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
+#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
+
+#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
+
+/** EQ Table Entry Memory Map
+ */
+struct hipz_eqtemm {
+ u64 eqx_hcr;
+ u64 eqx_c;
+
+ u64 eqx_herr;
+ u64 eqx_aer;
+/* 0x20 */
+ u64 eqx_ptp;
+ u64 eqx_tp;
+ u64 eqx_ssba;
+ u64 eqx_psba;
+
+/* 0x40 */
+ u64 eqx_cec;
+ u64 eqx_meql;
+ u64 eqx_xisbi;
+ u64 eqx_xisc;
+/* 0x60 */
+ u64 eqx_it;
+
+};
+
+#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
+
+/* access control defines for MR/MW */
+#define HIPZ_ACCESSCTRL_L_WRITE 0x00800000
+#define HIPZ_ACCESSCTRL_R_WRITE 0x00400000
+#define HIPZ_ACCESSCTRL_R_READ 0x00200000
+#define HIPZ_ACCESSCTRL_R_ATOMIC 0x00100000
+#define HIPZ_ACCESSCTRL_MW_BIND 0x00080000
+
+/* query hca response block */
+struct hipz_query_hca {
+ u32 cur_reliable_dg;
+ u32 cur_qp;
+ u32 cur_cq;
+ u32 cur_eq;
+ u32 cur_mr;
+ u32 cur_mw;
+ u32 cur_ee_context;
+ u32 cur_mcast_grp;
+ u32 cur_qp_attached_mcast_grp;
+ u32 reserved1;
+ u32 cur_ipv6_qp;
+ u32 cur_eth_qp;
+ u32 cur_hp_mr;
+ u32 reserved2[3];
+ u32 max_rd_domain;
+ u32 max_qp;
+ u32 max_cq;
+ u32 max_eq;
+ u32 max_mr;
+ u32 max_hp_mr;
+ u32 max_mw;
+ u32 max_mrwpte;
+ u32 max_special_mrwpte;
+ u32 max_rd_ee_context;
+ u32 max_mcast_grp;
+ u32 max_total_mcast_qp_attach;
+ u32 max_mcast_qp_attach;
+ u32 max_raw_ipv6_qp;
+ u32 max_raw_ethy_qp;
+ u32 internal_clock_frequency;
+ u32 max_pd;
+ u32 max_ah;
+ u32 max_cqe;
+ u32 max_wqes_wq;
+ u32 max_partitions;
+ u32 max_rr_ee_context;
+ u32 max_rr_qp;
+ u32 max_rr_hca;
+ u32 max_act_wqs_ee_context;
+ u32 max_act_wqs_qp;
+ u32 max_sge;
+ u32 max_sge_rd;
+ u32 memory_page_size_supported;
+ u64 max_mr_size;
+ u32 local_ca_ack_delay;
+ u32 num_ports;
+ u32 vendor_id;
+ u32 vendor_part_id;
+ u32 hw_ver;
+ u64 node_guid;
+ u64 hca_cap_indicators;
+ u32 data_counter_register_size;
+ u32 max_shared_rq;
+ u32 max_isns_eq;
+ u32 max_neq;
+} __attribute__ ((packed));
+
+/* query port response block */
+struct hipz_query_port {
+ u32 state;
+ u32 bad_pkey_cntr;
+ u32 lmc;
+ u32 lid;
+ u32 subnet_timeout;
+ u32 qkey_viol_cntr;
+ u32 sm_sl;
+ u32 sm_lid;
+ u32 capability_mask;
+ u32 init_type_reply;
+ u32 pkey_tbl_len;
+ u32 gid_tbl_len;
+ u64 gid_prefix;
+ u32 port_nr;
+ u16 pkey_entries[16];
+ u8 reserved1[32];
+ u32 trent_size;
+ u32 trbuf_size;
+ u64 max_msg_sz;
+ u32 max_mtu;
+ u32 vl_cap;
+ u8 reserved2[1900];
+ u64 guid_entries[255];
+} __attribute__ ((packed));
+
+#endif
^ permalink raw reply
* [PATCH 14/16] ehca: queue page table handling
From: Heiko J Schick @ 2006-05-15 17:43 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>
drivers/infiniband/hw/ehca/ipz_pt_fn.c | 177 ++++++++++++++++++++++
drivers/infiniband/hw/ehca/ipz_pt_fn.h | 254 +++++++++++++++++++++++++++++++++
2 files changed, 431 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ipz_pt_fn.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ipz_pt_fn.h 2006-05-12 12:25:43.000000000 +0200
@@ -0,0 +1,254 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * internal queue handling
+ *
+ * Authors: Waleri Fomin <fomin@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.
+ */
+
+#ifndef __IPZ_PT_FN_H__
+#define __IPZ_PT_FN_H__
+
+#include "ehca_qes.h"
+#define EHCA_PAGESHIFT 12
+#define EHCA_PAGESIZE 4096UL
+#define EHCA_PT_ENTRIES 512UL
+
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+
+/* struct generic ehca page
+ */
+struct ipz_page {
+ u8 entries[EHCA_PAGESIZE];
+};
+
+/* struct generic queue in linux kernel virtual memory (kv)
+ */
+struct ipz_queue {
+ u64 current_q_offset; /* current queue entry */
+
+ struct ipz_page **queue_pages; /* array of pages belonging to queue */
+ u32 qe_size; /* queue entry size */
+ u32 act_nr_of_sg;
+ u32 queue_length; /* queue length allocated in bytes */
+ u32 pagesize;
+ u32 toggle_state; /* toggle flag - per page */
+ u32 dummy3; /* 64 bit alignment */
+};
+
+/* return current Queue Entry for a certain q_offset
+ * returns address (kv) of Queue Entry
+ */
+static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)
+{
+ struct ipz_page *current_page = NULL;
+ if (q_offset >= queue->queue_length)
+ return NULL;
+ current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT];
+ return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)];
+}
+
+/* return current Queue Entry
+ * returns address (kv) of Queue Entry
+ */
+static inline void *ipz_qeit_get(struct ipz_queue *queue)
+{
+ return ipz_qeit_calc(queue, queue->current_q_offset);
+}
+
+/* return current Queue Page , increment Queue Page iterator from
+ * page to page in struct ipz_queue, last increment will return 0! and
+ * NOT wrap
+ * returns address (kv) of Queue Page
+ * warning don't use in parallel with ipz_QE_get_inc()
+ */
+void *ipz_qpageit_get_inc(struct ipz_queue *queue);
+
+/* return current Queue Entry, increment Queue Entry iterator by one
+ * step in struct ipz_queue, will wrap in ringbuffer
+ * @returns address (kv) of Queue Entry BEFORE increment
+ * warning don't use in parallel with ipz_qpageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ */
+static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
+{
+ void *ret = NULL;
+
+ ret = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset >= queue->queue_length) {
+ queue->current_q_offset = 0;
+ /* toggle the valid flag */
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+
+ EDEB(7, "queue=%p ret=%p new current_q_addr=%lx qe_size=%x",
+ queue, ret, queue->current_q_offset, queue->qe_size);
+
+ return ret;
+}
+
+/* return current Queue Entry, increment Queue Entry iterator by one
+ * step in struct ipz_queue, will wrap in ringbuffer
+ * returns address (kv) of Queue Entry BEFORE increment
+ * returns 0 and does not increment, if wrong valid state
+ * warning don't use in parallel with ipz_qpageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ */
+static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
+{
+ struct ehca_cqe *cqe = ipz_qeit_get(queue);
+ u32 cqe_flags = cqe->cqe_flags;
+
+ if ((cqe_flags >> 7) != (queue->toggle_state & 1))
+ return NULL;
+
+ ipz_qeit_get_inc(queue);
+ return cqe;
+}
+
+/* returns and resets Queue Entry iterator
+ * returns address (kv) of first Queue Entry
+ */
+static inline void *ipz_qeit_reset(struct ipz_queue *queue)
+{
+ queue->current_q_offset = 0;
+ return ipz_qeit_get(queue);
+}
+
+/** struct generic page table
+ */
+struct ipz_pt {
+ u64 entries[EHCA_PT_ENTRIES];
+};
+
+/* struct page table for a queue, only to be used in pf
+ */
+struct ipz_qpt {
+ /* queue page tables (kv), use u64 because we know the element length */
+ u64 *qpts;
+ u32 allocated_qpts_entries;
+ u32 nr_of_PTEs; /* number of page table entries PTE iterators */
+ u64 *current_pte_addr;
+};
+
+/* constructor for a ipz_queue_t, placement new for ipz_queue_t,
+ * new for all dependent datastructors
+ *
+ * all QP Tables are the same
+ * flow:
+ * allocate+pin queue
+ * see ipz_qpt_ctor()
+ * returns true if ok, false if out of memory
+ */
+int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
+ const u32 pagesize, const u32 qe_size,
+ const u32 nr_of_sg);
+
+/* destructor for a ipz_queue_t
+ * -# free queue
+ * see ipz_queue_ctor()
+ * returns true if ok, false if queue was NULL-ptr of free failed
+ */
+int ipz_queue_dtor(struct ipz_queue *queue);
+
+/* constructor for a ipz_qpt_t,
+ * placement new for struct ipz_queue, new for all dependent datastructors
+ *
+ * all QP Tables are the same,
+ * flow:
+ * -# allocate+pin queue
+ * -# initialise ptcb
+ * -# allocate+pin PTs
+ * -# link PTs to a ring, according to HCA Arch, set bit62 id needed
+ * -# the ring must have room for exactly nr_of_PTEs
+ * see ipz_qpt_ctor()
+ */
+void ipz_qpt_ctor(struct ipz_qpt *qpt,
+ const u32 nr_of_QEs,
+ const u32 pagesize,
+ const u32 qe_size,
+ const u8 lowbyte, const u8 toggle,
+ u32 * act_nr_of_QEs, u32 * act_nr_of_pages);
+
+/* return current Queue Entry, increment Queue Entry iterator by one
+ * step in struct ipz_queue, will wrap in ringbuffer
+ * returns address (kv) of Queue Entry BEFORE increment
+ * warning don't use in parallel with ipz_qpageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ *
+ * fix EQ page problems
+ */
+void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
+
+/* return current Event Queue Entry, increment Queue Entry iterator
+ * by one step in struct ipz_queue if valid, will wrap in ringbuffer
+ * returns address (kv) of Queue Entry BEFORE increment
+ * returns 0 and does not increment, if wrong valid state
+ * warning don't use in parallel with ipz_queue_QPageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ */
+static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ u32 qe = *(u8 *) ret;
+ EDEB(7, "ipz_QEit_EQ_get_inc_valid qe=%x", qe);
+ if ((qe >> 7) == (queue->toggle_state & 1))
+ ipz_qeit_eq_get_inc(queue); /* this is a good one */
+ else
+ ret = NULL;
+ return ret;
+}
+
+/*
+ * returns address (GX) of first queue entry
+ */
+static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt)
+{
+ return be64_to_cpu(qpt->qpts[0]);
+}
+
+/*
+ * returns address (kv) of first page of queue page table
+ */
+static inline void *ipz_qpt_get_qpt(struct ipz_qpt *qpt)
+{
+ return qpt->qpts;
+}
+
+#endif /* __IPZ_PT_FN_H__ */
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ipz_pt_fn.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ipz_pt_fn.c 2006-05-15 15:43:31.000000000 +0200
@@ -0,0 +1,177 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * internal queue handling
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Christoph Raisch <raisch@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.
+ */
+
+#define DEB_PREFIX "iptz"
+
+#include "ehca_tools.h"
+#include "ipz_pt_fn.h"
+
+extern int ehca_hwlevel;
+
+void *ipz_qpageit_get_inc(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->pagesize;
+ if (queue->current_q_offset > queue->queue_length) {
+ queue->current_q_offset -= queue->pagesize;
+ ret = NULL;
+ }
+ if (((u64)ret) % EHCA_PAGESIZE) {
+ EDEB(4, "ERROR!! not at PAGE-Boundary");
+ return NULL;
+ }
+ EDEB(7, "queue=%p ret=%p", queue, ret);
+ return ret;
+}
+
+void *ipz_qeit_eq_get_inc(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ u64 last_entry_in_q = queue->queue_length - queue->qe_size;
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset > last_entry_in_q) {
+ queue->current_q_offset = 0;
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+
+ EDEB(7, "queue=%p ret=%p new current_q_offset=%lx qe_size=%x",
+ queue, ret, queue->current_q_offset, queue->qe_size);
+
+ return ret;
+}
+
+int ipz_queue_ctor(struct ipz_queue *queue,
+ const u32 nr_of_pages,
+ const u32 pagesize, const u32 qe_size, const u32 nr_of_sg)
+{
+ int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
+ int f;
+
+ EDEB_EN(7, "nr_of_pages=%x pagesize=%x qe_size=%x",
+ nr_of_pages, pagesize, qe_size);
+ if (pagesize > PAGE_SIZE) {
+ EDEB_ERR(4, "FATAL ERROR: pagesize=%x is greater than "
+ "kernel page size", pagesize);
+ return 0;
+ }
+ if (!pages_per_kpage) {
+ EDEB_ERR(4, "FATAL ERROR: invalid kernel page size. "
+ "pages_per_kpage=%x", pages_per_kpage);
+ return 0;
+ }
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ if (!queue->queue_pages) {
+ EDEB(4, "ERROR!! didn't get the memory");
+ return 0;
+ }
+ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+ /* allocate pages for queue:
+ while loop allocates whole kernel pages
+ if cond allocates so much mem needed for the rest of queue pages,
+ which is nr_of_pages % pages_per_kpage
+ */
+ f = 0;
+ while (f + pages_per_kpage <= nr_of_pages) {
+ u8 *kpage = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int k;
+ if (!kpage)
+ goto ipz_queue_ctor_exit0; /*NOMEM*/
+ for (k = 0; k < pages_per_kpage; k++) {
+ (queue->queue_pages)[f] = (struct ipz_page *)kpage;
+ kpage += EHCA_PAGESIZE;
+ f++;
+ }
+ }
+ if (f < nr_of_pages) {
+ u8 *kpage = kzalloc((nr_of_pages - f) * EHCA_PAGESIZE,
+ GFP_KERNEL);
+ if (!kpage)
+ goto ipz_queue_ctor_exit0; /*NOMEM*/
+ while (f < nr_of_pages) {
+ (queue->queue_pages)[f] = (struct ipz_page *)kpage;
+ kpage += EHCA_PAGESIZE;
+ f++;
+ }
+ }
+
+ queue->current_q_offset = 0;
+ queue->qe_size = qe_size;
+ queue->act_nr_of_sg = nr_of_sg;
+ queue->pagesize = pagesize;
+ queue->toggle_state = 1;
+ EDEB_EX(7, "queue_length=%x queue_pages=%p qe_size=%x"
+ " act_nr_of_sg=%x", queue->queue_length, queue->queue_pages,
+ queue->qe_size, queue->act_nr_of_sg);
+ return 1;
+
+ ipz_queue_ctor_exit0:
+ EDEB_ERR(4, "Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x",
+ queue, f, nr_of_pages);
+ for (f = 0; f < nr_of_pages; f += pages_per_kpage) {
+ if (!(queue->queue_pages)[f])
+ break;
+ kfree((queue->queue_pages)[f]);
+ }
+ return 0;
+}
+
+int ipz_queue_dtor(struct ipz_queue *queue)
+{
+ int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
+ int g;
+ int nr_pages;
+
+ EDEB_EN(7, "ipz_queue pointer=%p", queue);
+ if (!queue || !queue->queue_pages) {
+ EDEB_ERR(4, "queue or queue_pages is NULL");
+ return 0;
+ }
+ EDEB(7, "destructing a queue with the following "
+ "properties:\n nr_of_pages=%x pagesize=%x qe_size=%x",
+ queue->act_nr_of_sg, queue->pagesize, queue->qe_size);
+ nr_pages = queue->queue_length / queue->pagesize;
+ for (g = 0; g < nr_pages; g += pages_per_kpage)
+ kfree((queue->queue_pages)[g]);
+ vfree(queue->queue_pages);
+
+ EDEB_EX(7, "queue freed!");
+ return 1;
+}
^ permalink raw reply
* [PATCH 15/16] ehca: PHYP abstraction layer
From: Heiko J Schick @ 2006-05-15 17:43 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>
drivers/infiniband/hw/ehca/hcp_phyp.c | 92 ++++++++++++++++++++++++++++++++
drivers/infiniband/hw/ehca/hcp_phyp.h | 95 ++++++++++++++++++++++++++++++++++
2 files changed, 187 insertions(+)
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hcp_phyp.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hcp_phyp.h 2006-05-02 12:48:48.000000000 +0200
@@ -0,0 +1,95 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Firmware calls
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ * Gerd Bayer <gerd.bayer@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.
+ */
+
+#ifndef __HCP_PHYP_H__
+#define __HCP_PHYP_H__
+
+
+/* eHCA page (mapped into memory)
+ resource to access eHCA register pages in CPU address space
+*/
+struct h_galpa {
+ u64 fw_handle;
+ /* for pSeries this is a 64bit memory address where
+ I/O memory is mapped into CPU address space (kv) */
+};
+
+/*
+ resource to access eHCA address space registers, all types
+*/
+struct h_galpas {
+ u32 pid; /*PID of userspace galpa checking */
+ struct h_galpa user; /* user space accessible resource,
+ set to 0 if unused */
+ struct h_galpa kernel; /* kernel space accessible resource,
+ set to 0 if unused */
+};
+
+static inline u64 hipz_galpa_load(struct h_galpa galpa, u32 offset)
+{
+ u64 addr = galpa.fw_handle + offset;
+ u64 out;
+ EDEB_EN(7, "addr=%lx offset=%x ", addr, offset);
+ out = *(u64 *) addr;
+ EDEB_EX(7, "addr=%lx value=%lx", addr, out);
+ return out;
+}
+
+static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value)
+{
+ u64 addr = galpa.fw_handle + offset;
+ EDEB(7, "addr=%lx offset=%x value=%lx", addr,
+ offset, value);
+ *(u64 *) addr = value;
+}
+
+int hcp_galpas_ctor(struct h_galpas *galpas,
+ u64 paddr_kernel, u64 paddr_user);
+
+int hcp_galpas_dtor(struct h_galpas *galpas);
+
+int hcall_map_page(u64 physaddr, u64 * mapaddr);
+
+int hcall_unmap_page(u64 mapaddr);
+
+#endif
--- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hcp_phyp.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hcp_phyp.c 2006-05-03 13:44:00.000000000 +0200
@@ -0,0 +1,92 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * load store abstraction for ehca register access with tracing
+ *
+ * Authors: Christoph Raisch <raisch@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.
+ */
+
+#define DEB_PREFIX "PHYP"
+
+#include "ehca_classes.h"
+#include "hipz_hw.h"
+
+int hcall_map_page(u64 physaddr, u64 *mapaddr)
+{
+ *mapaddr = (u64)(ioremap(physaddr, EHCA_PAGESIZE));
+
+ EDEB(7, "ioremap physaddr=%lx mapaddr=%lx", physaddr, *mapaddr);
+ return 0;
+}
+
+int hcall_unmap_page(u64 mapaddr)
+{
+ EDEB(7, "mapaddr=%lx", mapaddr);
+ iounmap((volatile void __iomem*)mapaddr);
+ return 0;
+}
+
+int hcp_galpas_ctor(struct h_galpas *galpas,
+ u64 paddr_kernel, u64 paddr_user)
+{
+ int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
+ if (ret)
+ return ret;
+
+ galpas->user.fw_handle = paddr_user;
+
+ EDEB(7, "paddr_kernel=%lx paddr_user=%lx galpas->kernel=%lx"
+ " galpas->user=%lx",
+ paddr_kernel, paddr_user, galpas->kernel.fw_handle,
+ galpas->user.fw_handle);
+
+ return ret;
+}
+
+int hcp_galpas_dtor(struct h_galpas *galpas)
+{
+ int ret = 0;
+
+ if (galpas->kernel.fw_handle)
+ ret = hcall_unmap_page(galpas->kernel.fw_handle);
+
+ if (ret)
+ return ret;
+
+ galpas->user.fw_handle = galpas->kernel.fw_handle = 0;
+
+ return ret;
+}
^ permalink raw reply
* [PATCH 16/16] ehca: integration in Linux kernel build system
From: Heiko J Schick @ 2006-05-15 17:43 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>
drivers/infiniband/hw/ehca/Kconfig | 6 ++++++
drivers/infiniband/hw/ehca/Makefile | 16 ++++++++++++++++
2 files changed, 22 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-04-28 13:32:08.000000000 +0200
@@ -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)
--- 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-04-28 13:31:25.000000000 +0200
@@ -0,0 +1,16 @@
+# 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] remove powerpc bitops infavor of existing generic bitops
From: Jon Mason @ 2006-05-15 18:01 UTC (permalink / raw)
To: linuxppc-dev
There already exists a big endian safe bitops implementation in
lib/find_next_bit.c. The code in it is 90%+ common with the powerpc
specific version, so the powerpc version is redundant. This patch
makes the necessary changes to use the generic bitops in powerpc, and
removes the powerpc specific version.
Thanks,
Jon
Signed-off-by: Jon Mason <jdmason@us.ibm.com>
diff -r bfccde0f7221 arch/powerpc/Kconfig
--- a/arch/powerpc/Kconfig Sat May 13 08:42:09 2006 +0700
+++ b/arch/powerpc/Kconfig Mon May 15 17:30:46 2006 +0000
@@ -42,6 +42,10 @@ config GENERIC_HWEIGHT
default y
config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+
+config GENERIC_FIND_NEXT_BIT
bool
default y
diff -r bfccde0f7221 arch/powerpc/lib/Makefile
--- a/arch/powerpc/lib/Makefile Sat May 13 08:42:09 2006 +0700
+++ b/arch/powerpc/lib/Makefile Mon May 15 17:30:46 2006 +0000
@@ -7,7 +7,6 @@ obj-$(CONFIG_PPC32) += div64.o copy_32.o
obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o
endif
-obj-y += bitops.o
obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
memcpy_64.o usercopy_64.o mem_64.o string.o \
strcase.o
diff -r bfccde0f7221 include/asm-powerpc/bitops.h
--- a/include/asm-powerpc/bitops.h Sat May 13 08:42:09 2006 +0700
+++ b/include/asm-powerpc/bitops.h Mon May 15 17:30:46 2006 +0000
@@ -288,8 +288,8 @@ static __inline__ int test_le_bit(unsign
#define __test_and_clear_le_bit(nr, addr) \
__test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define find_first_zero_le_bit(addr, size) find_next_zero_le_bit((addr), (size), 0)
-unsigned long find_next_zero_le_bit(const unsigned long *addr,
+#define find_first_zero_le_bit(addr, size) generic_find_next_zero_le_bit((addr), (size), 0)
+unsigned long generic_find_next_zero_le_bit(const unsigned long *addr,
unsigned long size, unsigned long offset);
/* Bitmap functions for the ext2 filesystem */
@@ -309,7 +309,7 @@ unsigned long find_next_zero_le_bit(cons
#define ext2_find_first_zero_bit(addr, size) \
find_first_zero_le_bit((unsigned long*)addr, size)
#define ext2_find_next_zero_bit(addr, size, off) \
- find_next_zero_le_bit((unsigned long*)addr, size, off)
+ generic_find_next_zero_le_bit((unsigned long*)addr, size, off)
/* Bitmap functions for the minix filesystem. */
diff -r bfccde0f7221 arch/powerpc/lib/bitops.c
--- a/arch/powerpc/lib/bitops.c Sat May 13 08:42:09 2006 +0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-#include <linux/types.h>
-#include <linux/module.h>
-#include <asm/byteorder.h>
-#include <asm/bitops.h>
-
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
-{
- const unsigned long *p = addr + BITOP_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG-1);
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset %= BITS_PER_LONG;
- if (offset) {
- tmp = *(p++);
- tmp &= (~0UL << offset);
- if (size < BITS_PER_LONG)
- goto found_first;
- if (tmp)
- goto found_middle;
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- }
- while (size & ~(BITS_PER_LONG-1)) {
- if ((tmp = *(p++)))
- goto found_middle;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
- tmp = *p;
-
-found_first:
- tmp &= (~0UL >> (BITS_PER_LONG - size));
- if (tmp == 0UL) /* Are any bits set? */
- return result + size; /* Nope. */
-found_middle:
- return result + __ffs(tmp);
-}
-EXPORT_SYMBOL(find_next_bit);
-
-/*
- * This implementation of find_{first,next}_zero_bit was stolen from
- * Linus' asm-alpha/bitops.h.
- */
-unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
-{
- const unsigned long *p = addr + BITOP_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG-1);
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset %= BITS_PER_LONG;
- if (offset) {
- tmp = *(p++);
- tmp |= ~0UL >> (BITS_PER_LONG - offset);
- if (size < BITS_PER_LONG)
- goto found_first;
- if (~tmp)
- goto found_middle;
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- }
- while (size & ~(BITS_PER_LONG-1)) {
- if (~(tmp = *(p++)))
- goto found_middle;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
- tmp = *p;
-
-found_first:
- tmp |= ~0UL << size;
- if (tmp == ~0UL) /* Are any bits zero? */
- return result + size; /* Nope. */
-found_middle:
- return result + ffz(tmp);
-}
-EXPORT_SYMBOL(find_next_zero_bit);
-
-static inline unsigned int ext2_ilog2(unsigned int x)
-{
- int lz;
-
- asm("cntlzw %0,%1": "=r"(lz):"r"(x));
- return 31 - lz;
-}
-
-static inline unsigned int ext2_ffz(unsigned int x)
-{
- u32 rc;
- if ((x = ~x) == 0)
- return 32;
- rc = ext2_ilog2(x & -x);
- return rc;
-}
-
-unsigned long find_next_zero_le_bit(const unsigned long *addr,
- unsigned long size, unsigned long offset)
-{
- const unsigned int *p = ((const unsigned int *)addr) + (offset >> 5);
- unsigned int result = offset & ~31;
- unsigned int tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset &= 31;
- if (offset) {
- tmp = cpu_to_le32p(p++);
- tmp |= ~0U >> (32 - offset); /* bug or feature ? */
- if (size < 32)
- goto found_first;
- if (tmp != ~0)
- goto found_middle;
- size -= 32;
- result += 32;
- }
- while (size >= 32) {
- if ((tmp = cpu_to_le32p(p++)) != ~0)
- goto found_middle;
- result += 32;
- size -= 32;
- }
- if (!size)
- return result;
- tmp = cpu_to_le32p(p);
-found_first:
- tmp |= ~0 << size;
- if (tmp == ~0) /* Are any bits zero? */
- return result + size; /* Nope. */
-found_middle:
- return result + ext2_ffz(tmp);
-}
-EXPORT_SYMBOL(find_next_zero_le_bit);
^ permalink raw reply
* Re: [PATCH] Export PowerPC atomic operations to userspace
From: Brent Cook @ 2006-05-15 18:18 UTC (permalink / raw)
To: Tom Rini; +Cc: linuxppc-embedded
In-Reply-To: <20060515171629.GC22868@smtp.west.cox.net>
On Monday 15 May 2006 12:16, Tom Rini wrote:
> On Mon, May 15, 2006 at 11:54:52AM -0500, Brent Cook wrote:
> > The atomic operations in asm/atomic.h are really useful from userspace
> > too. Other architectures (i386, x86_64, mips) export these to userspace,
> > but the powerpc versions are guarded by __KERNEL__ for some reason. Can
> > we remove these if there is no good reason to guard them?
> >
> > Signed-off-by: Brent Cook <bcook@bpointsys.com>
>
> NAK. i386, x86_64 and mips are broken in this regard. Please google up
> the previous threads that explain why you can't always get atomic
> operations on all architectures and why exporting this is bad.
OK, I see that possibly the only reason atomic_t is even exported is so that
sem.h works. Hopefully sem.h will get fixed and people like me will not be
even tempted by atomic.h.
What I really want is just a standard way to do atomic inc/dec in userspace;
I'm sure that people are going to continue wanting to have atomic_t
workalikes for their code.
After reading this thread:
http://www.developerweb.net/forum/archive/index.php/t-3294.html
it appears that just wrapping an integer in a pthreads mutex on an NPTL
machine wouldn't be much more overhead than using an atomic_t directly.
Looking at glibc's sources for powerpc nptl:
nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
confirms that a futex lock is really similar to an atomic_t.
Thanks!
- Brent
^ permalink raw reply
* Re: [PATCH] Export PowerPC atomic operations to userspace
From: Tom Rini @ 2006-05-15 17:16 UTC (permalink / raw)
To: Brent Cook; +Cc: linuxppc-embedded
In-Reply-To: <200605151154.52599.bcook@bpointsys.com>
On Mon, May 15, 2006 at 11:54:52AM -0500, Brent Cook wrote:
> The atomic operations in asm/atomic.h are really useful from userspace too.
> Other architectures (i386, x86_64, mips) export these to userspace, but the
> powerpc versions are guarded by __KERNEL__ for some reason. Can we remove
> these if there is no good reason to guard them?
>
> Signed-off-by: Brent Cook <bcook@bpointsys.com>
NAK. i386, x86_64 and mips are broken in this regard. Please google up
the previous threads that explain why you can't always get atomic
operations on all architectures and why exporting this is bad.
--
Tom Rini
^ permalink raw reply
* Re: Setting I&D cache enable in the same mtspr instruction
From: Mark A. Greer @ 2006-05-15 18:59 UTC (permalink / raw)
To: Assaf Hoffman; +Cc: Ronen Shitrit, Rita Shtern, linuxppc-embedded
In-Reply-To: <B9FFC3F97441D04093A504CEA31B7C419E2438@msilexch01.marvell.com>
On Mon, May 08, 2006 at 01:39:13PM +0300, Assaf Hoffman wrote:
> Hi,
> I think the implementation of setup_common_caches() in file
> cpu_setup_6xx.S; not according to the spec as far as MPC74xx concerns.
> Looking in the spec (MPC7450 RISC Microprocessor Family Reference
> Manual, MPC7450UM Rev. 5 1/2005) section 3.4.1.5 L1 Instruction and Data
> Cache Flash Invalidation it says:
> "Note that HID0[ICFI] and HID0[DCFI] must not both be set with the same
> mtspr instruction, due to the synchronization requirements described in
> Section 2.4.2.4.1, "Context Synchronization."
> But in the code those two do set together.
> Also, the same section says:
> "An isync must precede the setting of the HID0[ICFI] in order for the
> setting to take effect."
> But in the code, only 'sync' can be found.
>
> /* Enable caches for 603's, 604, 750 & 7400 */
> setup_common_caches:
> mfspr r11,SPRN_HID0
> andi. r0,r11,HID0_DCE
> ori r11,r11,HID0_ICE|HID0_DCE
> ori r8,r11,HID0_ICFI
> bne 1f /* don't invalidate the D-cache
> */
> ori r8,r8,HID0_DCI /* unless it wasn't enabled */
> 1: sync
> mtspr SPRN_HID0,r8 /* enable and invalidate caches
> */
> ^^^^^^^^^^^^^^^^^^^ Here we set both ICFI and DCFI in the same
> mtspr instruction. Also, no isync before setting ICFI.
> sync
> mtspr SPRN_HID0,r11 /* enable caches */
> sync
> isync
> blr
>
> Please advice.
> Thanks.
Yep, looks like a bug. How about a patch? :)
Mark
^ permalink raw reply
* Re: Routing problem
From: Antonio Di Bacco @ 2006-05-15 19:39 UTC (permalink / raw)
To: Yang, Steve; +Cc: linuxppc-embedded
In-Reply-To: <D9055C0A0A86BD4E89AD96A89EA767DB09C061@ALA-MAIL03.corp.ad.wrs.com>
No effect!
I don't understand what is missing in my system.
Thank you for your attention.
Bye,
Antonio.
On Monday 15 May 2006 18:08, Yang, Steve wrote:
> Antonio,
>
> Try this:
>
> sysctl net.ipv4.ip_forward=1
>
> Regards,
> Steve Yang
> 510-749-4535 Alameda
> AIM: steveyang4535
>
> -----Original Message-----
> From: linuxppc-embedded-bounces+syang=windriver.com@ozlabs.org
> [mailto:linuxppc-embedded-bounces+syang=windriver.com@ozlabs.org] On
> Behalf Of Antonio Di Bacco
> Sent: Friday, May 12, 2006 1:53 PM
> To: linuxppc-embedded@ozlabs.org
> Subject: Routing problem
>
> Hi all,
>
> I have a board with an MPC880 using the tow FECs as two ethernet
> interfaces. I tried to enable the ip forwarding with no success. I have
> issued "echo 1
>
> > /proc/sys/net/ipv4/ip_forward", is it sufficient to make Linux work as
> >
> > a
>
> router?
>
> Bye,
> Antonio.
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* Re: [PATCH] remove powerpc bitops infavor of existing generic bitops
From: jschopp @ 2006-05-15 19:56 UTC (permalink / raw)
To: Jon Mason; +Cc: linuxppc-dev
In-Reply-To: <20060515180108.GB17646@us.ibm.com>
> There already exists a big endian safe bitops implementation in
> lib/find_next_bit.c. The code in it is 90%+ common with the powerpc
> specific version, so the powerpc version is redundant. This patch
> makes the necessary changes to use the generic bitops in powerpc, and
> removes the powerpc specific version.
I like generic as much as the next guy, but I'm also a big fan of fast bitops. And the
function below is fast. You'll have to explain to me how the generic code is going to
find the first zero as fast without explicit calls to ppc assembly.
> -static inline unsigned int ext2_ilog2(unsigned int x)
> -{
> - int lz;
> -
> - asm("cntlzw %0,%1": "=r"(lz):"r"(x));
> - return 31 - lz;
> -}
^ permalink raw reply
* route problem and simple sniffer
From: Antonio Di Bacco @ 2006-05-15 20:09 UTC (permalink / raw)
To: linuxppc-embedded
Anyone knows a lightweight sniffer for linux embedded?
I'm going to debug a system that doesn't want to route anything!
Bye,
Antonio.
^ permalink raw reply
* Re: [PATCH] remove powerpc bitops infavor of existing generic bitops
From: Jon Mason @ 2006-05-15 20:38 UTC (permalink / raw)
To: jschopp; +Cc: linuxppc-dev
In-Reply-To: <4468DCDD.5090609@austin.ibm.com>
On Mon, May 15, 2006 at 02:56:13PM -0500, jschopp wrote:
> >There already exists a big endian safe bitops implementation in
> >lib/find_next_bit.c. The code in it is 90%+ common with the powerpc
> >specific version, so the powerpc version is redundant. This patch
> >makes the necessary changes to use the generic bitops in powerpc, and
> >removes the powerpc specific version.
>
> I like generic as much as the next guy, but I'm also a big fan of fast
> bitops. And the function below is fast. You'll have to explain to me how
> the generic code is going to find the first zero as fast without explicit
> calls to ppc assembly.
>
> >-static inline unsigned int ext2_ilog2(unsigned int x)
> >-{
> >- int lz;
> >-
> >- asm("cntlzw %0,%1": "=r"(lz):"r"(x));
> >- return 31 - lz;
> >-}
Ah but here's the trick, there is the same explicit call to ppc
assembly. The only function in the file removed is this one you pointed
out, and the only caller of this function is ext2_ffz. And the only
user of ext2_ffz is find_next_zero_le_bit.
Now the generic code is very similar to the file removed (`diff -Narup
arch/powerpc/lib/bitops.c lib/find_next_bit.c` to see for yourself). In
the same place where ext2_ffz is called, ffz is called in the generic
code. Now if we look at the definition of ffz in
include/asm-powerpc/bitops.h, we see it calls __ilog2 of that same file.
__ilog2 is defined as:
static __inline__ int __ilog2(unsigned long x)
{
int lz;
asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (x));
return BITS_PER_LONG - 1 - lz;
}
So, its really the same code :)
Thanks,
Jon
^ permalink raw reply
* Re: [PATCH 14/16] ehca: queue page table handling
From: Randy.Dunlap @ 2006-05-15 20:54 UTC (permalink / raw)
To: Heiko J Schick
Cc: linux-kernel, openib-general, linuxppc-dev, RAISCH, HNGUYEN,
MEDER
In-Reply-To: <4468BDAD.3020701@de.ibm.com>
On Mon, 15 May 2006 19:43:09 +0200 Heiko J Schick wrote:
> Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
>
>
> drivers/infiniband/hw/ehca/ipz_pt_fn.c | 177 ++++++++++++++++++++++
> drivers/infiniband/hw/ehca/ipz_pt_fn.h | 254 +++++++++++++++++++++++++++++++++
> 2 files changed, 431 insertions(+)
>
>
>
> --- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/ipz_pt_fn.h 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/ipz_pt_fn.h 2006-05-12 12:25:43.000000000 +0200
> @@ -0,0 +1,254 @@
> +/* return current Queue Page , increment Queue Page iterator from
> + * page to page in struct ipz_queue, last increment will return 0! and
> + * NOT wrap
> + * returns address (kv) of Queue Page
> + * warning don't use in parallel with ipz_QE_get_inc()
> + */
When not using kernel-doc format... the preferred multi-line
comment format is:
/*
* foo foo foo ........
* bar bar bar .......
* blahz ..........
*/
repeat below.
> +void *ipz_qpageit_get_inc(struct ipz_queue *queue);
> +
> +/* return current Queue Entry, increment Queue Entry iterator by one
> + * step in struct ipz_queue, will wrap in ringbuffer
> + * @returns address (kv) of Queue Entry BEFORE increment
> + * warning don't use in parallel with ipz_qpageit_get_inc()
> + * warning unpredictable results may occur if steps>act_nr_of_queue_entries
> + */
> +static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
> +{
> + void *ret = NULL;
> +
> + ret = ipz_qeit_get(queue);
> + queue->current_q_offset += queue->qe_size;
> + if (queue->current_q_offset >= queue->queue_length) {
> + queue->current_q_offset = 0;
> + /* toggle the valid flag */
> + queue->toggle_state = (~queue->toggle_state) & 1;
> + }
> +
> + EDEB(7, "queue=%p ret=%p new current_q_addr=%lx qe_size=%x",
> + queue, ret, queue->current_q_offset, queue->qe_size);
> +
> + return ret;
> +}
> +
> +/* return current Queue Entry, increment Queue Entry iterator by one
> + * step in struct ipz_queue, will wrap in ringbuffer
> + * returns address (kv) of Queue Entry BEFORE increment
> + * returns 0 and does not increment, if wrong valid state
> + * warning don't use in parallel with ipz_qpageit_get_inc()
> + * warning unpredictable results may occur if steps>act_nr_of_queue_entries
> + */
> +static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
> +{
> + struct ehca_cqe *cqe = ipz_qeit_get(queue);
> + u32 cqe_flags = cqe->cqe_flags;
> +
> + if ((cqe_flags >> 7) != (queue->toggle_state & 1))
> + return NULL;
> +
> + ipz_qeit_get_inc(queue);
> + return cqe;
> +}
> +
> +/* destructor for a ipz_queue_t
> + * -# free queue
> + * see ipz_queue_ctor()
> + * returns true if ok, false if queue was NULL-ptr of free failed
> + */
> +int ipz_queue_dtor(struct ipz_queue *queue);
> +
> +/* constructor for a ipz_qpt_t,
> + * placement new for struct ipz_queue, new for all dependent datastructors
> + *
> + * all QP Tables are the same,
> + * flow:
> + * -# allocate+pin queue
> + * -# initialise ptcb
> + * -# allocate+pin PTs
> + * -# link PTs to a ring, according to HCA Arch, set bit62 id needed
> + * -# the ring must have room for exactly nr_of_PTEs
> + * see ipz_qpt_ctor()
> + */
> +void ipz_qpt_ctor(struct ipz_qpt *qpt,
> + const u32 nr_of_QEs,
> + const u32 pagesize,
> + const u32 qe_size,
> + const u8 lowbyte, const u8 toggle,
> + u32 * act_nr_of_QEs, u32 * act_nr_of_pages);
> +
> +/* return current Queue Entry, increment Queue Entry iterator by one
> + * step in struct ipz_queue, will wrap in ringbuffer
> + * returns address (kv) of Queue Entry BEFORE increment
> + * warning don't use in parallel with ipz_qpageit_get_inc()
> + * warning unpredictable results may occur if steps>act_nr_of_queue_entries
> + *
> + * fix EQ page problems
> + */
> +void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
> +
> +/* return current Event Queue Entry, increment Queue Entry iterator
> + * by one step in struct ipz_queue if valid, will wrap in ringbuffer
> + * returns address (kv) of Queue Entry BEFORE increment
> + * returns 0 and does not increment, if wrong valid state
> + * warning don't use in parallel with ipz_queue_QPageit_get_inc()
> + * warning unpredictable results may occur if steps>act_nr_of_queue_entries
> + */
> +static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
> +{
> + void *ret = ipz_qeit_get(queue);
> + u32 qe = *(u8 *) ret;
> + EDEB(7, "ipz_QEit_EQ_get_inc_valid qe=%x", qe);
> + if ((qe >> 7) == (queue->toggle_state & 1))
> + ipz_qeit_eq_get_inc(queue); /* this is a good one */
> + else
> + ret = NULL;
> + return ret;
> +}
---
~Randy
^ permalink raw reply
* Re: [PATCH 12/16] ehca: firmware InfiniBand interface
From: Randy.Dunlap @ 2006-05-15 20:47 UTC (permalink / raw)
To: Heiko J Schick
Cc: linux-kernel, openib-general, linuxppc-dev, RAISCH, HNGUYEN,
MEDER
In-Reply-To: <4468BD99.5050505@de.ibm.com>
On Mon, 15 May 2006 19:42:49 +0200 Heiko J Schick wrote:
> Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
>
>
> drivers/infiniband/hw/ehca/hcp_if.c | 1476 ++++++++++++++++++++++++++++++++++++
> drivers/infiniband/hw/ehca/hcp_if.h | 330 ++++++++
> 2 files changed, 1806 insertions(+)
>
>
>
> --- linux-2.6.17-rc2-orig/drivers/infiniband/hw/ehca/hcp_if.h 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.17-rc2/drivers/infiniband/hw/ehca/hcp_if.h 2006-05-12 12:48:21.000000000 +0200
> @@ -0,0 +1,330 @@
> +/**
> + * hipz_h_alloc_resource_eq - Allocate EQ resources in HW and FW, initalize
> + * resources, create the empty EQPT (ring).
> + *
> + * @eq_handle: eq handle for this queue
> + * @act_nr_of_entries: actual number of queue entries
> + * @act_pages: actual number of queue pages
> + * @eq_ist: used by hcp_H_XIRR() call
> + */
kernel-doc format needs:
1. a short function name + description on one line
2. no blank line between function and parameters
3. blank line (optional) before more detailed function description
See Documentation/kernel-doc-nano-HOWTO.txt or other kernel source
files for more info.
And please test it with "make htmldocs" or "make mandocs".
---
~Randy
^ permalink raw reply
* Re: [PATCH 05/16] ehca: common include files
From: Randy.Dunlap @ 2006-05-15 21:03 UTC (permalink / raw)
To: Heiko J Schick
Cc: linux-kernel, openib-general, linuxppc-dev, RAISCH, HNGUYEN,
MEDER
In-Reply-To: <4468BD5B.1060406@de.ibm.com>
On Mon, 15 May 2006 19:41:47 +0200 Heiko J Schick wrote:
> Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
>
>
> drivers/infiniband/hw/ehca/ehca_iverbs.h | 181 +++++++++++++
> drivers/infiniband/hw/ehca/ehca_tools.h | 411 +++++++++++++++++++++++++++++++
> 2 files changed, 592 insertions(+)
>
>
>
> --- 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-05-03 13:44:15.000000000 +0200
> @@ -0,0 +1,411 @@
> +static inline 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
collapse
> + * to two single ints filter_level is the first level kicked out by
> + * compiler means trace everythin below 6. */
everything
plus make a real sentence of that, please.
> +}
> +
> +#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)
> +
> +#elif REAL_HCALL
> +
> +
> +#endif
> +#else
> +
> +#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
> + */
Use real kernel-doc format here, please.
Parameters at least need a colon (':') after their names, like:
* @format: optonal format string, use "" if not desired
and test them...
> +#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.
EDEB_DMP
> + * 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
What are all of those "\n"s up there? and below?
> +#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)))
> +
> +
> +/**
> + * ehca_adr_bad - Handle to be used for adress translation mechanisms,
> + * currently a placeholder.
> + */
Use proper kernel-doc format.
> +static inline int ehca_adr_bad(void *adr)
> +{
> + return !adr;
> +}
> +
> +/**
> + * ehca2ib_return_code - Returns ib return code corresponding to the given
> + * ehca return code.
> + */
Ditto.
---
~Randy
^ permalink raw reply
* Re: [PATCH] Fix pSeries identification in prom_init.c
From: Benjamin Herrenschmidt @ 2006-05-15 21:08 UTC (permalink / raw)
To: Michael Neuling; +Cc: linuxppc-dev list, Paul Mackerras, segher
In-Reply-To: <20060515161810.E633C679EB@ozlabs.org>
> To be safe if we are returned a non terminated string. I'd not realised
> the case you've mentioned.
>
> How much we should trust firmware? With strcpy, should we explicitly
> terminate the string first (I removed one of these originally)? Patch
> below, compiled not run.
I wouldn't bother. If it returns a non-terminated string there, a lot of
stuff will break anyway including the kernel probe code
Ben.
> The OF trampoline code prom_init.c still needs to identify IBM pSeries
> (PAPR) machines in order to run some platform specific code on them like
> instantiating the TCE tables. The code doing that detection was changed
> recently in 2.6.17 early stages but was done slightly incorrectly. It
> should be testing for an exact match of "chrp" and it currently tests
> for anything that begins with "chrp". That means it will incorrectly
> match with platforms using Maple-like device-trees and have open
> firmware. This fixes it by using strcmp instead of strncmp to match what
> the actual platform detection code does.
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
> ---
>
> arch/powerpc/kernel/prom_init.c | 3 ++-
> 1 files changed, 2 insertions(+), 1 deletion(-)
>
> Index: linux-2.6-powerpc/arch/powerpc/kernel/prom_init.c
> ===================================================================
> --- linux-2.6-powerpc.orig/arch/powerpc/kernel/prom_init.c
> +++ linux-2.6-powerpc/arch/powerpc/kernel/prom_init.c
> @@ -1636,7 +1636,8 @@ static int __init prom_find_machine_type
> compat, sizeof(compat)-1);
> if (len <= 0)
> return PLATFORM_GENERIC;
> - if (strncmp(compat, RELOC("chrp"), 4))
> + compat[len] = 0;
> + if (strcmp(compat, RELOC("chrp")))
> return PLATFORM_GENERIC;
>
> /* Default to pSeries. We need to know if we are running LPAR */
>
^ permalink raw reply
* Re: [PATCH 01/16] ehca: module infrastructure
From: Randy.Dunlap @ 2006-05-15 21:14 UTC (permalink / raw)
To: Heiko J Schick
Cc: linux-kernel, openib-general, linuxppc-dev, RAISCH, HNGUYEN,
MEDER
In-Reply-To: <4468BD39.3010008@de.ibm.com>
On Mon, 15 May 2006 19:41:13 +0200 Heiko J Schick wrote:
> Signed-off-by: Heiko J Schick <schickhj@de.ibm.com>
>
>
> drivers/infiniband/hw/ehca/ehca_main.c | 966 +++++++++++++++++++++++++++++++++
> 1 file changed, 966 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-05-15 19:17:26.000000000 +0200
> @@ -0,0 +1,966 @@
> +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;
Don't need to init globals to 0.
---
~Randy
^ permalink raw reply
* Re: [PATCH] remove powerpc bitops infavor of existing generic bitops
From: jschopp @ 2006-05-15 20:42 UTC (permalink / raw)
To: Jon Mason; +Cc: linuxppc-dev
In-Reply-To: <20060515203815.GC17646@us.ibm.com>
> Ah but here's the trick, there is the same explicit call to ppc
> assembly. The only function in the file removed is this one you pointed
> out, and the only caller of this function is ext2_ffz. And the only
> user of ext2_ffz is find_next_zero_le_bit.
>
> Now the generic code is very similar to the file removed (`diff -Narup
> arch/powerpc/lib/bitops.c lib/find_next_bit.c` to see for yourself). In
> the same place where ext2_ffz is called, ffz is called in the generic
> code. Now if we look at the definition of ffz in
> include/asm-powerpc/bitops.h, we see it calls __ilog2 of that same file.
> __ilog2 is defined as:
>
> static __inline__ int __ilog2(unsigned long x)
> {
> int lz;
>
> asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (x));
> return BITS_PER_LONG - 1 - lz;
> }
>
> So, its really the same code :)
Good explination. I'm convinced, so for what it's worth:
Acked-by: Joel Schopp <jschopp@austin.ibm.com>
^ permalink raw reply
* NOT_COHERENT_CACHE: 1. kernel oops in page_add_file_rmap() and 2. crash with HIGHMEM support
From: Gerhard Pircher @ 2006-05-15 22:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <3746.1147538916@www086.gmx.net>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 3647 bytes --]
Hi,
I applied the CONFIG_NOT_COHERENT_CACHE option for the AmigaOne, which has a
northbridge with cache coherence problems. Unfortunately the kernel now
crashes when viewing DVD (for example with totem) and when support for
HIGHMEM is compiled in. Kernel version is 2.6.8-16 (debian).
First some infos:
To get NOT_COHERENT_CACHE working on the AmigaOne, I had to limit the PCI
memory and ISA IO/MEM space of the northbridge first and then changed the
CONFIG_CONSISTENT_BASE parameter from 0xFF100000 to 0xF8100000
(CONSISTENT_SIZE is still set to 0x00200000 = 2MB).
The IO/MEM space was previously mapped like this in the platform setup:
io_block_mapping(0xF0000000, 0xF0000000, 0x10000000, _PAGE_IO)
I changed this line to:
io_block_mapping(0xFD000000, 0xFD000000, 0x01000000, _PAGE_IO) -> ISA MEM
and
io_block_mapping(0xFE000000, 0xFE000000, 0x02000000, _PAGE_IO) -> ISA IO/PCI
config space.
These address ranges are mapped by BATs.
The PCI memory normally goes from 0x80000000 to 0xFCFFFFFF, but is limited
to 0xEFFFFFFF in the PCI host controller resource initialization:
amigaone_init_resource(&hose->mem_resources[0], 0x80000000, 0x0xEFFFFFFF,
IORESOURCE_MEM);
With this setup DMA (and UDMA for IDE devices) works without any data
corruption. I tested this with around 500 MD5 checksum tests of three
different files with a file size of at least 100 MB. But when I view a DVD
for example (without HIGHMEM support), the system crashes with the following
kernel oops:
May 12 00:04:17 localhost kernel: kernel BUG in page_add_file_rmap at
mm/rmap.c:387!
May 12 00:04:17 localhost kernel: Oops: Exception in kernel mode, sig: 5
[#1]
May 12 00:04:17 localhost kernel: NIP: C004968C LR: C0044CB8 SP: D2C77E20
REGS: d2c77d70 TRAP: 0700 Not tainted
May 12 00:04:17 localhost kernel: MSR: 00029032 EE: 1 PR: 0 FP: 0 ME: 1
IR/DR: 11
May 12 00:04:17 localhost kernel: TASK = d4918000[2900] 'totem' THREAD:
d2c76000Last syscall: 246
May 12 00:04:17 localhost kernel: GPR00: 00000001 D2C77E20 D4918000 C0D02720
00000000 D27B02A0 02000000 D4FE4400
May 12 00:04:17 localhost kernel: GPR08: C03D0000 38139785 00000000 38139785
24048444 10054698 00000000 10171158
May 12 00:04:17 localhost kernel: GPR16: 00000000 00000000 0EADDD7C 00015F90
000001F6 315B1970 33CA8000 D4D6BBA0
May 12 00:04:17 localhost kernel: GPR24: 00000000 00000000 02000000 D4B7D33C
33CA8000 C0D02720 38139785 D2888220
May 12 00:04:17 localhost kernel: NIP [c004968c] page_add_file_rmap+0x8/0x78
May 12 00:04:17 localhost kernel: LR [c0044cb8] do_no_page+0x1cc/0x37c
May 12 00:04:17 localhost kernel: Call trace:
May 12 00:04:17 localhost kernel: [c004503c] handle_mm_fault+0xf4/0x174
May 12 00:04:17 localhost kernel: [c0012100] do_page_fault+0x140/0x398
May 12 00:04:17 localhost kernel: [c0008178] handle_page_fault+0xc/0x80
Does anybody know how I can debug this crash, or what's happening here? I
don't think that the PCI memory is the cause for this crash, because the
CONSISTENT_BASE address is a virtual address, which is not mapped phyiscally
to the same address (phys = virt)!?
The second problem is HIGHMEM support in combination with
NOT_COHERENT_CACHE. When both options are enabled, the kernel crashes within
kmap_atomic() early in the boot process. kmap_atomic() is called by
__dma_sync_page_highmem(). I guess it should work even, if I have only 512MB
RAM. I moved the PKMAP_BASE to 0xF0000000, because the default address is
again within the ISA MEM space.
Did anyone else experience this problem?
Thanks in advance!
regards,
Gerhard
--
Mobile Internet - E-Mail und Internet immer und überall!
GMX zum Mitnehmen: http://www.gmx.net/de/go/pocketweb
^ permalink raw reply
* Re: [PATCH 5/6] Have ia64 use add_active_range() and free_area_init_nodes
From: Mel Gorman @ 2006-05-15 22:44 UTC (permalink / raw)
To: Andrew Morton
Cc: davej, tony.luck, linuxppc-dev, ak, bob.picco, linux-kernel,
linux-mm
In-Reply-To: <20060515122728.GA29253@skynet.ie>
> diff -rup -X /usr/src/patchset-0.5/bin//dontdiff linux-2.6.17-rc4-mm4-clean/mm/page_alloc.c linux-2.6.17-rc4-mm4-ia64_force_alignment/mm/page_alloc.c
> --- linux-2.6.17-rc4-mm4-clean/mm/page_alloc.c 2006-05-15 10:37:55.000000000 +0100
> +++ linux-2.6.17-rc4-mm4-ia64_force_alignment/mm/page_alloc.c 2006-05-15 13:10:42.000000000 +0100
> @@ -2640,14 +2640,20 @@ void __init free_area_init_nodes(unsigne
> {
> unsigned long nid;
> int zone_index;
> + unsigned long lowest_pfn = find_min_pfn_with_active_regions();
> +
> + lowest_pfn = zone_boundary_align_pfn(lowest_pfn);
> + arch_max_dma_pfn = zone_boundary_align_pfn(arch_max_dma_pfn);
> + arch_max_dma32_pfn = zone_boundary_align_pfn(arch_max_dma32_pfn);
> + arch_max_low_pfn = zone_boundary_align_pfn(arch_max_low_pfn);
> + arch_max_high_pfn = zone_boundary_align_pfn(arch_max_high_pfn);
>
> /* Record where the zone boundaries are */
> memset(arch_zone_lowest_possible_pfn, 0,
> sizeof(arch_zone_lowest_possible_pfn));
> memset(arch_zone_highest_possible_pfn, 0,
> sizeof(arch_zone_highest_possible_pfn));
> - arch_zone_lowest_possible_pfn[ZONE_DMA] =
> - find_min_pfn_with_active_regions();
> + arch_zone_lowest_possible_pfn[ZONE_DMA] = lowest_pfn;
> arch_zone_highest_possible_pfn[ZONE_DMA] = arch_max_dma_pfn;
> arch_zone_highest_possible_pfn[ZONE_DMA32] = arch_max_dma32_pfn;
> arch_zone_highest_possible_pfn[ZONE_NORMAL] = arch_max_low_pfn;
>
Ok, this patch is broken in a number of ways. It doesn't help the IA64
problem at all and two other machine configurations failed with the patch
applied during regression testing. Please drop and I'll figure out what
the correct solution is to your IA64 machine not booting.
--
Mel Gorman
Part-time Phd Student Linux Technology Center
University of Limerick IBM Dublin Software Lab
^ permalink raw reply
* RE: Routing problem
From: Yang, Steve @ 2006-05-15 16:08 UTC (permalink / raw)
To: Antonio Di Bacco, linuxppc-embedded
Antonio,
Try this:
sysctl net.ipv4.ip_forward=3D1=20
Regards,=20
Steve Yang
510-749-4535 Alameda
AIM: steveyang4535
-----Original Message-----
From: linuxppc-embedded-bounces+syang=3Dwindriver.com@ozlabs.org
[mailto:linuxppc-embedded-bounces+syang=3Dwindriver.com@ozlabs.org] On
Behalf Of Antonio Di Bacco
Sent: Friday, May 12, 2006 1:53 PM
To: linuxppc-embedded@ozlabs.org
Subject: Routing problem
Hi all,
I have a board with an MPC880 using the tow FECs as two ethernet
interfaces. I tried to enable the ip forwarding with no success. I have
issued "echo 1=20
> /proc/sys/net/ipv4/ip_forward", is it sufficient to make Linux work as
> a
router?
Bye,
Antonio.=20
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ 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