aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/benet/cq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/benet/cq.c')
-rw-r--r--drivers/staging/benet/cq.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/drivers/staging/benet/cq.c b/drivers/staging/benet/cq.c
new file mode 100644
index 000000000000..650458645433
--- /dev/null
+++ b/drivers/staging/benet/cq.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2005 - 2008 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include "hwlib.h"
+#include "bestatus.h"
+
+/*
+ * Completion Queue Objects
+ */
+/*
+ *============================================================================
+ * P U B L I C R O U T I N E S
+ *============================================================================
+ */
+
+/*
+ This routine creates a completion queue based on the client completion
+ queue configuration information.
+
+
+ FunctionObject - Handle to a function object
+ CqBaseVa - Base VA for a the CQ ring
+ NumEntries - CEV_CQ_CNT_* values
+ solEventEnable - 0 = All CQEs can generate Events if CQ is eventable
+ 1 = only CQEs with solicited bit set are eventable
+ eventable - Eventable CQ, generates interrupts.
+ nodelay - 1 = Force interrupt, relevent if CQ eventable.
+ Interrupt is asserted immediately after EQE
+ write is confirmed, regardless of EQ Timer
+ or watermark settings.
+ wme - Enable watermark based coalescing
+ wmThresh - High watermark(CQ fullness at which event
+ or interrupt should be asserted). These are the
+ CEV_WATERMARK encoded values.
+ EqObject - EQ Handle to assign to this CQ
+ ppCqObject - Internal CQ Handle returned.
+
+ Returns BE_SUCCESS if successfull, otherwise a useful error code is
+ returned.
+
+ IRQL < DISPATCH_LEVEL
+
+*/
+int be_cq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 length, bool solicited_eventable,
+ bool no_delay, u32 wm_thresh,
+ struct be_eq_object *eq_object, struct be_cq_object *cq_object)
+{
+ int status = BE_SUCCESS;
+ u32 num_entries_encoding;
+ u32 num_entries = length / sizeof(struct MCC_CQ_ENTRY_AMAP);
+ struct FWCMD_COMMON_CQ_CREATE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ u32 n;
+ unsigned long irql;
+
+ ASSERT(rd);
+ ASSERT(cq_object);
+ ASSERT(length % sizeof(struct MCC_CQ_ENTRY_AMAP) == 0);
+
+ switch (num_entries) {
+ case 256:
+ num_entries_encoding = CEV_CQ_CNT_256;
+ break;
+ case 512:
+ num_entries_encoding = CEV_CQ_CNT_512;
+ break;
+ case 1024:
+ num_entries_encoding = CEV_CQ_CNT_1024;
+ break;
+ default:
+ ASSERT(0);
+ return BE_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * All cq entries all the same size. Use iSCSI version
+ * as a test for the proper rd length.
+ */
+ memset(cq_object, 0, sizeof(*cq_object));
+
+ atomic_set(&cq_object->ref_count, 0);
+ cq_object->parent_function = pfob;
+ cq_object->eq_object = eq_object;
+ cq_object->num_entries = num_entries;
+ /* save for MCC cq processing */
+ cq_object->va = rd->va;
+
+ /* map into UT. */
+ length = num_entries * sizeof(struct MCC_CQ_ENTRY_AMAP);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ ASSERT(wrb);
+ TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_CQ_CREATE);
+
+ fwcmd->params.request.num_pages = PAGES_SPANNED(OFFSET_IN_PAGE(rd->va),
+ length);
+
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, valid, &fwcmd->params.request.context, 1);
+ n = pfob->pci_function_number;
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Func, &fwcmd->params.request.context, n);
+
+ n = (eq_object != NULL);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Eventable,
+ &fwcmd->params.request.context, n);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Armed, &fwcmd->params.request.context, 1);
+
+ n = eq_object ? eq_object->eq_id : 0;
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, EQID, &fwcmd->params.request.context, n);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Count,
+ &fwcmd->params.request.context, num_entries_encoding);
+
+ n = 0; /* Protection Domain is always 0 in Linux driver */
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, PD, &fwcmd->params.request.context, n);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, NoDelay,
+ &fwcmd->params.request.context, no_delay);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, SolEvent,
+ &fwcmd->params.request.context, solicited_eventable);
+
+ n = (wm_thresh != 0xFFFFFFFF);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, WME, &fwcmd->params.request.context, n);
+
+ n = (n ? wm_thresh : 0);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Watermark,
+ &fwcmd->params.request.context, n);
+ /* Create a page list for the FWCMD. */
+ be_rd_to_pa_list(rd, fwcmd->params.request.pages,
+ ARRAY_SIZE(fwcmd->params.request.pages));
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "MCC to create CQ failed.");
+ goto Error;
+ }
+ /* Remember the CQ id. */
+ cq_object->cq_id = fwcmd->params.response.cq_id;
+
+ /* insert this cq into eq_object reference */
+ if (eq_object) {
+ atomic_inc(&eq_object->ref_count);
+ list_add_tail(&cq_object->cqlist_for_eq,
+ &eq_object->cq_list_head);
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+
+ Deferences the given object. Once the object's reference count drops to
+ zero, the object is destroyed and all resources that are held by this object
+ are released. The on-chip context is also destroyed along with the queue
+ ID, and any mappings made into the UT.
+
+ cq_object - CQ handle returned from cq_object_create.
+
+ returns the current reference count on the object
+
+ IRQL: IRQL < DISPATCH_LEVEL
+*/
+int be_cq_destroy(struct be_cq_object *cq_object)
+{
+ int status = 0;
+
+ /* Nothing should reference this CQ at this point. */
+ ASSERT(atomic_read(&cq_object->ref_count) == 0);
+
+ /* Send fwcmd to destroy the CQ. */
+ status = be_function_ring_destroy(cq_object->parent_function,
+ cq_object->cq_id, FWCMD_RING_TYPE_CQ,
+ NULL, NULL, NULL, NULL);
+ ASSERT(status == 0);
+
+ /* Remove reference if this is an eventable CQ. */
+ if (cq_object->eq_object) {
+ atomic_dec(&cq_object->eq_object->ref_count);
+ list_del(&cq_object->cqlist_for_eq);
+ }
+ return BE_SUCCESS;
+}
+