2 * Copyright (C) 2005 - 2008 ServerEngines
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation. The full GNU General
8 * Public License is included in this distribution in the file called COPYING.
10 * Contact Information:
11 * linux-drivers@serverengines.com
14 * 209 N. Fair Oaks Ave
20 This routine creates an event queue based on the client completion
21 queue configuration information.
23 FunctionObject - Handle to a function object
24 EqBaseVa - Base VA for a the EQ ring
25 SizeEncoding - The encoded size for the EQ entries. This value is
26 either CEV_EQ_SIZE_4 or CEV_EQ_SIZE_16
27 NumEntries - CEV_CQ_CNT_* values.
28 Watermark - Enables watermark based coalescing. This parameter
29 must be of the type CEV_WMARK_* if watermarks
30 are enabled. If watermarks to to be disabled
31 this value should be-1.
32 TimerDelay - If a timer delay is enabled this value should be the
33 time of the delay in 8 microsecond units. If
34 delays are not used this parameter should be
36 ppEqObject - Internal EQ Handle returned.
38 Returns BE_SUCCESS if successfull,, otherwise a useful error code
44 be_eq_create(struct be_function_object *pfob,
45 struct ring_desc *rd, u32 eqe_size, u32 num_entries,
46 u32 watermark, /* CEV_WMARK_* or -1 */
47 u32 timer_delay, /* in 8us units, or -1 */
48 struct be_eq_object *eq_object)
50 int status = BE_SUCCESS;
51 u32 num_entries_encoding, eqe_size_encoding, length;
52 struct FWCMD_COMMON_EQ_CREATE *fwcmd = NULL;
53 struct MCC_WRB_AMAP *wrb = NULL;
60 switch (num_entries) {
62 num_entries_encoding = CEV_EQ_CNT_256;
65 num_entries_encoding = CEV_EQ_CNT_512;
68 num_entries_encoding = CEV_EQ_CNT_1024;
71 num_entries_encoding = CEV_EQ_CNT_2048;
74 num_entries_encoding = CEV_EQ_CNT_4096;
78 return BE_STATUS_INVALID_PARAMETER;
83 eqe_size_encoding = CEV_EQ_SIZE_4;
86 eqe_size_encoding = CEV_EQ_SIZE_16;
90 return BE_STATUS_INVALID_PARAMETER;
93 if ((eqe_size == 4 && num_entries < 1024) ||
94 (eqe_size == 16 && num_entries == 4096)) {
95 TRACE(DL_ERR, "Bad EQ size. eqe_size:%d num_entries:%d",
96 eqe_size, num_entries);
98 return BE_STATUS_INVALID_PARAMETER;
101 memset(eq_object, 0, sizeof(*eq_object));
103 atomic_set(&eq_object->ref_count, 0);
104 eq_object->parent_function = pfob;
105 eq_object->eq_id = 0xFFFFFFFF;
107 INIT_LIST_HEAD(&eq_object->cq_list_head);
109 length = num_entries * eqe_size;
111 spin_lock_irqsave(&pfob->post_lock, irql);
113 wrb = be_function_peek_mcc_wrb(pfob);
116 TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
117 status = BE_STATUS_NO_MCC_WRB;
120 /* Prepares an embedded fwcmd, including request/response sizes. */
121 fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_EQ_CREATE);
123 fwcmd->params.request.num_pages = PAGES_SPANNED(OFFSET_IN_PAGE(rd->va),
125 n = pfob->pci_function_number;
126 AMAP_SET_BITS_PTR(EQ_CONTEXT, Func, &fwcmd->params.request.context, n);
128 AMAP_SET_BITS_PTR(EQ_CONTEXT, valid, &fwcmd->params.request.context, 1);
130 AMAP_SET_BITS_PTR(EQ_CONTEXT, Size,
131 &fwcmd->params.request.context, eqe_size_encoding);
133 n = 0; /* Protection Domain is always 0 in Linux driver */
134 AMAP_SET_BITS_PTR(EQ_CONTEXT, PD, &fwcmd->params.request.context, n);
136 /* Let the caller ARM the EQ with the doorbell. */
137 AMAP_SET_BITS_PTR(EQ_CONTEXT, Armed, &fwcmd->params.request.context, 0);
139 AMAP_SET_BITS_PTR(EQ_CONTEXT, Count, &fwcmd->params.request.context,
140 num_entries_encoding);
142 n = pfob->pci_function_number * 32;
143 AMAP_SET_BITS_PTR(EQ_CONTEXT, EventVect,
144 &fwcmd->params.request.context, n);
145 if (watermark != -1) {
146 AMAP_SET_BITS_PTR(EQ_CONTEXT, WME,
147 &fwcmd->params.request.context, 1);
148 AMAP_SET_BITS_PTR(EQ_CONTEXT, Watermark,
149 &fwcmd->params.request.context, watermark);
150 ASSERT(watermark <= CEV_WMARK_240);
152 AMAP_SET_BITS_PTR(EQ_CONTEXT, WME,
153 &fwcmd->params.request.context, 0);
154 if (timer_delay != -1) {
155 AMAP_SET_BITS_PTR(EQ_CONTEXT, TMR,
156 &fwcmd->params.request.context, 1);
158 ASSERT(timer_delay <= 250); /* max value according to EAS */
159 timer_delay = min(timer_delay, (u32)250);
161 AMAP_SET_BITS_PTR(EQ_CONTEXT, Delay,
162 &fwcmd->params.request.context, timer_delay);
164 AMAP_SET_BITS_PTR(EQ_CONTEXT, TMR,
165 &fwcmd->params.request.context, 0);
167 /* Create a page list for the FWCMD. */
168 be_rd_to_pa_list(rd, fwcmd->params.request.pages,
169 ARRAY_SIZE(fwcmd->params.request.pages));
171 status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
172 NULL, NULL, fwcmd, NULL);
173 if (status != BE_SUCCESS) {
174 TRACE(DL_ERR, "MCC to create EQ failed.");
177 /* Get the EQ id. The MPU allocates the IDs. */
178 eq_object->eq_id = fwcmd->params.response.eq_id;
181 spin_unlock_irqrestore(&pfob->post_lock, irql);
183 if (pfob->pend_queue_driving && pfob->mcc) {
184 pfob->pend_queue_driving = 0;
185 be_drive_mcc_wrb_queue(pfob->mcc);
191 Deferences the given object. Once the object's reference count drops to
192 zero, the object is destroyed and all resources that are held by this
193 object are released. The on-chip context is also destroyed along with
194 the queue ID, and any mappings made into the UT.
196 eq_object - EQ handle returned from eq_object_create.
198 Returns BE_SUCCESS if successfull, otherwise a useful error code
201 IRQL: IRQL < DISPATCH_LEVEL
203 int be_eq_destroy(struct be_eq_object *eq_object)
207 ASSERT(atomic_read(&eq_object->ref_count) == 0);
208 /* no CQs should reference this EQ now */
209 ASSERT(list_empty(&eq_object->cq_list_head));
211 /* Send fwcmd to destroy the EQ. */
212 status = be_function_ring_destroy(eq_object->parent_function,
213 eq_object->eq_id, FWCMD_RING_TYPE_EQ,
214 NULL, NULL, NULL, NULL);
220 *---------------------------------------------------------------------------
221 * Function: be_eq_modify_delay
222 * Changes the EQ delay for a group of EQs.
223 * num_eq - The number of EQs in the eq_array to adjust.
224 * This also is the number of delay values in
225 * the eq_delay_array.
226 * eq_array - Array of struct be_eq_object pointers to adjust.
227 * eq_delay_array - Array of "num_eq" timer delays in units
228 * of microseconds. The be_eq_query_delay_range
229 * fwcmd returns the resolution and range of
233 * q_ctxt - Optional. Pointer to a previously allocated
234 * struct. If the MCC WRB ring is full, this
235 * structure is used to queue the operation. It
236 * will be posted to the MCC ring when space
237 * becomes available. All queued commands will
238 * be posted to the ring in the order they are
239 * received. It is always valid to pass a pointer to
240 * a generic be_generic_q_cntxt. However,
241 * the specific context structs
242 * are generally smaller than the generic struct.
243 * return pend_status - BE_SUCCESS (0) on success.
244 * BE_PENDING (postive value) if the FWCMD
245 * completion is pending. Negative error code on failure.
246 *-------------------------------------------------------------------------
249 be_eq_modify_delay(struct be_function_object *pfob,
250 u32 num_eq, struct be_eq_object **eq_array,
251 u32 *eq_delay_array, mcc_wrb_cqe_callback cb,
252 void *cb_context, struct be_eq_modify_delay_q_ctxt *q_ctxt)
254 struct FWCMD_COMMON_MODIFY_EQ_DELAY *fwcmd = NULL;
255 struct MCC_WRB_AMAP *wrb = NULL;
257 struct be_generic_q_ctxt *gen_ctxt = NULL;
261 spin_lock_irqsave(&pfob->post_lock, irql);
263 wrb = be_function_peek_mcc_wrb(pfob);
266 wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
267 gen_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
268 gen_ctxt->context.bytes = sizeof(*q_ctxt);
270 status = BE_STATUS_NO_MCC_WRB;
274 /* Prepares an embedded fwcmd, including request/response sizes. */
275 fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_MODIFY_EQ_DELAY);
278 ASSERT(num_eq <= ARRAY_SIZE(fwcmd->params.request.delay));
279 fwcmd->params.request.num_eq = num_eq;
280 for (i = 0; i < num_eq; i++) {
281 fwcmd->params.request.delay[i].eq_id = eq_array[i]->eq_id;
282 fwcmd->params.request.delay[i].delay_in_microseconds =
286 /* Post the f/w command */
287 status = be_function_post_mcc_wrb(pfob, wrb, gen_ctxt,
288 cb, cb_context, NULL, NULL, fwcmd, NULL);
291 spin_unlock_irqrestore(&pfob->post_lock, irql);
293 if (pfob->pend_queue_driving && pfob->mcc) {
294 pfob->pend_queue_driving = 0;
295 be_drive_mcc_wrb_queue(pfob->mcc);