1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <hpi_txdma.h>
29 #include <hxge_impl.h>
30
31 #define TXDMA_WAIT_LOOP 10000
32 #define TXDMA_WAIT_MSEC 5
33
34 static hpi_status_t hpi_txdma_control_reset_wait(hpi_handle_t handle,
35 uint8_t channel);
36
37 hpi_status_t
hpi_txdma_log_page_handle_set(hpi_handle_t handle,uint8_t channel,tdc_page_handle_t * hdl_p)38 hpi_txdma_log_page_handle_set(hpi_handle_t handle, uint8_t channel,
39 tdc_page_handle_t *hdl_p)
40 {
41 int status = HPI_SUCCESS;
42
43 if (!TXDMA_CHANNEL_VALID(channel)) {
44 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
45 " hpi_txdma_log_page_handle_set"
46 " Invalid Input: channel <0x%x>", channel));
47 return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
48 }
49
50 TXDMA_REG_WRITE64(handle, TDC_PAGE_HANDLE, channel, hdl_p->value);
51
52 return (status);
53 }
54
55 hpi_status_t
hpi_txdma_channel_reset(hpi_handle_t handle,uint8_t channel)56 hpi_txdma_channel_reset(hpi_handle_t handle, uint8_t channel)
57 {
58 HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
59 " hpi_txdma_channel_reset" " RESETTING", channel));
60 return (hpi_txdma_channel_control(handle, TXDMA_RESET, channel));
61 }
62
63 hpi_status_t
hpi_txdma_channel_init_enable(hpi_handle_t handle,uint8_t channel)64 hpi_txdma_channel_init_enable(hpi_handle_t handle, uint8_t channel)
65 {
66 return (hpi_txdma_channel_control(handle, TXDMA_INIT_START, channel));
67 }
68
69 hpi_status_t
hpi_txdma_channel_enable(hpi_handle_t handle,uint8_t channel)70 hpi_txdma_channel_enable(hpi_handle_t handle, uint8_t channel)
71 {
72 return (hpi_txdma_channel_control(handle, TXDMA_START, channel));
73 }
74
75 hpi_status_t
hpi_txdma_channel_disable(hpi_handle_t handle,uint8_t channel)76 hpi_txdma_channel_disable(hpi_handle_t handle, uint8_t channel)
77 {
78 return (hpi_txdma_channel_control(handle, TXDMA_STOP, channel));
79 }
80
81 hpi_status_t
hpi_txdma_channel_mbox_enable(hpi_handle_t handle,uint8_t channel)82 hpi_txdma_channel_mbox_enable(hpi_handle_t handle, uint8_t channel)
83 {
84 return (hpi_txdma_channel_control(handle, TXDMA_MBOX_ENABLE, channel));
85 }
86
87 hpi_status_t
hpi_txdma_channel_control(hpi_handle_t handle,txdma_cs_cntl_t control,uint8_t channel)88 hpi_txdma_channel_control(hpi_handle_t handle, txdma_cs_cntl_t control,
89 uint8_t channel)
90 {
91 int status = HPI_SUCCESS;
92 tdc_stat_t cs;
93 tdc_tdr_cfg_t cfg;
94
95 if (!TXDMA_CHANNEL_VALID(channel)) {
96 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
97 " hpi_txdma_channel_control"
98 " Invalid Input: channel <0x%x>", channel));
99 return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
100 }
101
102 switch (control) {
103 case TXDMA_INIT_RESET:
104 cfg.value = 0;
105 TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
106 cfg.bits.reset = 1;
107 TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
108 return (hpi_txdma_control_reset_wait(handle, channel));
109
110 case TXDMA_INIT_START:
111 cfg.value = 0;
112 TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
113 cfg.bits.enable = 1;
114 TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
115 break;
116
117 case TXDMA_RESET:
118 /*
119 * Sets reset bit only (Hardware will reset all the RW bits but
120 * leave the RO bits alone.
121 */
122 cfg.value = 0;
123 cfg.bits.reset = 1;
124 TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
125 return (hpi_txdma_control_reset_wait(handle, channel));
126
127 case TXDMA_START:
128 /* Enable the DMA channel */
129 TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
130 cfg.bits.enable = 1;
131 TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
132 break;
133
134 case TXDMA_STOP:
135 /* Disable the DMA channel */
136 TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
137 cfg.bits.enable = 0;
138 TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
139 status = hpi_txdma_control_stop_wait(handle, channel);
140 if (status) {
141 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
142 "Cannot stop channel %d (TXC hung!)", channel));
143 }
144 break;
145
146 case TXDMA_MBOX_ENABLE:
147 /*
148 * Write 1 to MB bit to enable mailbox update (cleared to 0 by
149 * hardware after update).
150 */
151 TXDMA_REG_READ64(handle, TDC_STAT, channel, &cs.value);
152 cs.bits.mb = 1;
153 TXDMA_REG_WRITE64(handle, TDC_STAT, channel, cs.value);
154 break;
155
156 default:
157 status = (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
158 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
159 " hpi_txdma_channel_control"
160 " Invalid Input: control <0x%x>", control));
161 }
162
163 return (status);
164 }
165
166 hpi_status_t
hpi_txdma_control_status(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,tdc_stat_t * cs_p)167 hpi_txdma_control_status(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
168 tdc_stat_t *cs_p)
169 {
170 int status = HPI_SUCCESS;
171 tdc_stat_t txcs;
172
173 if (!TXDMA_CHANNEL_VALID(channel)) {
174 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
175 " hpi_txdma_control_status"
176 " Invalid Input: channel <0x%x>", channel));
177 return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
178 }
179 switch (op_mode) {
180 case OP_GET:
181 TXDMA_REG_READ64(handle, TDC_STAT, channel, &cs_p->value);
182 break;
183
184 case OP_SET:
185 TXDMA_REG_WRITE64(handle, TDC_STAT, channel, cs_p->value);
186 break;
187
188 case OP_UPDATE:
189 TXDMA_REG_READ64(handle, TDC_STAT, channel, &txcs.value);
190 TXDMA_REG_WRITE64(handle, TDC_STAT, channel,
191 cs_p->value | txcs.value);
192 break;
193
194 default:
195 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
196 " hpi_txdma_control_status"
197 " Invalid Input: control <0x%x>", op_mode));
198 return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
199 }
200
201 return (status);
202 }
203
204 hpi_status_t
hpi_txdma_event_mask(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,tdc_int_mask_t * mask_p)205 hpi_txdma_event_mask(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
206 tdc_int_mask_t *mask_p)
207 {
208 int status = HPI_SUCCESS;
209 tdc_int_mask_t mask;
210
211 if (!TXDMA_CHANNEL_VALID(channel)) {
212 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
213 " hpi_txdma_event_mask Invalid Input: channel <0x%x>",
214 channel));
215 return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
216 }
217 switch (op_mode) {
218 case OP_GET:
219 TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &mask_p->value);
220 break;
221
222 case OP_SET:
223 TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel, mask_p->value);
224 break;
225
226 case OP_UPDATE:
227 TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &mask.value);
228 TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel,
229 mask_p->value | mask.value);
230 break;
231
232 default:
233 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
234 " hpi_txdma_event_mask Invalid Input: eventmask <0x%x>",
235 op_mode));
236 return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
237 }
238
239 return (status);
240 }
241
242 hpi_status_t
hpi_txdma_ring_config(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,uint64_t * reg_data)243 hpi_txdma_ring_config(hpi_handle_t handle, io_op_t op_mode,
244 uint8_t channel, uint64_t *reg_data)
245 {
246 int status = HPI_SUCCESS;
247
248 if (!TXDMA_CHANNEL_VALID(channel)) {
249 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
250 " hpi_txdma_ring_config"
251 " Invalid Input: channel <0x%x>", channel));
252 return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
253 }
254 switch (op_mode) {
255 case OP_GET:
256 TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, reg_data);
257 break;
258
259 case OP_SET:
260 TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, *reg_data);
261 break;
262
263 default:
264 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
265 " hpi_txdma_ring_config"
266 " Invalid Input: ring_config <0x%x>", op_mode));
267 return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
268 }
269
270 return (status);
271 }
272
273 hpi_status_t
hpi_txdma_mbox_config(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,uint64_t * mbox_addr)274 hpi_txdma_mbox_config(hpi_handle_t handle, io_op_t op_mode,
275 uint8_t channel, uint64_t *mbox_addr)
276 {
277 int status = HPI_SUCCESS;
278 tdc_mbh_t mh;
279 tdc_mbl_t ml;
280
281 if (!TXDMA_CHANNEL_VALID(channel)) {
282 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
283 " hpi_txdma_mbox_config Invalid Input: channel <0x%x>",
284 channel));
285 return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
286 }
287
288 mh.value = ml.value = 0;
289
290 switch (op_mode) {
291 case OP_GET:
292 TXDMA_REG_READ64(handle, TDC_MBH, channel, &mh.value);
293 TXDMA_REG_READ64(handle, TDC_MBL, channel, &ml.value);
294 *mbox_addr = ml.value;
295 *mbox_addr |= (mh.value << TDC_MBH_ADDR_SHIFT);
296
297 break;
298
299 case OP_SET:
300 ml.bits.mbaddr = ((*mbox_addr & TDC_MBL_MASK) >> TDC_MBL_SHIFT);
301 TXDMA_REG_WRITE64(handle, TDC_MBL, channel, ml.value);
302 mh.bits.mbaddr = ((*mbox_addr >> TDC_MBH_ADDR_SHIFT) &
303 TDC_MBH_MASK);
304 TXDMA_REG_WRITE64(handle, TDC_MBH, channel, mh.value);
305 break;
306
307 default:
308 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
309 " hpi_txdma_mbox_config Invalid Input: mbox <0x%x>",
310 op_mode));
311 return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
312 }
313
314 return (status);
315 }
316
317 /*
318 * This function is called to set up a transmit descriptor entry.
319 */
320 hpi_status_t
hpi_txdma_desc_gather_set(hpi_handle_t handle,p_tx_desc_t desc_p,uint8_t gather_index,boolean_t mark,uint8_t ngathers,uint64_t dma_ioaddr,uint32_t transfer_len)321 hpi_txdma_desc_gather_set(hpi_handle_t handle, p_tx_desc_t desc_p,
322 uint8_t gather_index, boolean_t mark, uint8_t ngathers,
323 uint64_t dma_ioaddr, uint32_t transfer_len)
324 {
325 int status;
326
327 status = HPI_TXDMA_GATHER_INDEX(gather_index);
328 if (status) {
329 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
330 " hpi_txdma_desc_gather_set"
331 " Invalid Input: gather_index <0x%x>", gather_index));
332 return (status);
333 }
334 if (transfer_len > TX_MAX_TRANSFER_LENGTH) {
335 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
336 " hpi_txdma_desc_gather_set"
337 " Invalid Input: tr_len <0x%x>", transfer_len));
338 return (HPI_FAILURE | HPI_TXDMA_XFER_LEN_INVALID);
339 }
340 if (gather_index == 0) {
341 desc_p->bits.sop = 1;
342 desc_p->bits.mark = mark;
343 desc_p->bits.num_ptr = ngathers;
344 HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
345 "hpi_txdma_gather_set: SOP len %d (%d)",
346 desc_p->bits.tr_len, transfer_len));
347 }
348 desc_p->bits.tr_len = transfer_len;
349 desc_p->bits.sad = dma_ioaddr >> 32;
350 desc_p->bits.sad_l = dma_ioaddr & 0xffffffff;
351
352 HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
353 "hpi_txdma_gather_set: xfer len %d to set (%d)",
354 desc_p->bits.tr_len, transfer_len));
355
356 HXGE_MEM_PIO_WRITE64(handle, desc_p->value);
357
358 return (status);
359 }
360
361 hpi_status_t
hpi_txdma_desc_set_zero(hpi_handle_t handle,uint16_t entries)362 hpi_txdma_desc_set_zero(hpi_handle_t handle, uint16_t entries)
363 {
364 uint32_t offset;
365 int i;
366
367 /*
368 * Assume no wrapped around.
369 */
370 offset = 0;
371 for (i = 0; i < entries; i++) {
372 HXGE_REG_WR64(handle, offset, 0);
373 offset += (i * (sizeof (tx_desc_t)));
374 }
375
376 return (HPI_SUCCESS);
377 }
378
379 /*
380 * This function is called to get the transmit ring head index.
381 */
382 hpi_status_t
hpi_txdma_ring_head_get(hpi_handle_t handle,uint8_t channel,tdc_tdr_head_t * hdl_p)383 hpi_txdma_ring_head_get(hpi_handle_t handle, uint8_t channel,
384 tdc_tdr_head_t *hdl_p)
385 {
386 int status = HPI_SUCCESS;
387
388 if (!TXDMA_CHANNEL_VALID(channel)) {
389 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
390 " hpi_txdma_ring_head_get"
391 " Invalid Input: channel <0x%x>", channel));
392 return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
393 }
394 TXDMA_REG_READ64(handle, TDC_TDR_HEAD, channel, &hdl_p->value);
395
396 return (status);
397 }
398
399 /*
400 * Dumps the contents of transmit descriptors.
401 */
402 /*ARGSUSED*/
403 void
hpi_txdma_dump_desc_one(hpi_handle_t handle,p_tx_desc_t desc_p,int desc_index)404 hpi_txdma_dump_desc_one(hpi_handle_t handle, p_tx_desc_t desc_p, int desc_index)
405 {
406 tx_desc_t desc, *desp;
407
408 #ifdef HXGE_DEBUG
409 uint64_t sad;
410 int xfer_len;
411 #endif
412
413 HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
414 "\n==> hpi_txdma_dump_desc_one: dump "
415 " desc_p $%p descriptor entry %d\n", desc_p, desc_index));
416 desc.value = 0;
417 desp = ((desc_p != NULL) ? desc_p : (p_tx_desc_t)&desc);
418 HXGE_MEM_PIO_READ64(handle, &desp->value);
419 #ifdef HXGE_DEBUG
420 sad = desp->bits.sad;
421 sad = (sad << 32) | desp->bits.sad_l;
422 xfer_len = desp->bits.tr_len;
423 #endif
424 HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL, "\n\t: value 0x%llx\n"
425 "\t\tsad $%p\ttr_len %d len %d\tnptrs %d\tmark %d sop %d\n",
426 desp->value, sad, desp->bits.tr_len, xfer_len,
427 desp->bits.num_ptr, desp->bits.mark, desp->bits.sop));
428
429 HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
430 "\n<== hpi_txdma_dump_desc_one: Done \n"));
431 }
432
433 /*
434 * Static functions start here.
435 */
436 static hpi_status_t
hpi_txdma_control_reset_wait(hpi_handle_t handle,uint8_t channel)437 hpi_txdma_control_reset_wait(hpi_handle_t handle, uint8_t channel)
438 {
439 tdc_tdr_cfg_t txcs;
440 int loop = 0;
441
442 txcs.value = 0;
443 do {
444 HXGE_DELAY(TXDMA_WAIT_MSEC);
445 TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &txcs.value);
446
447 /*
448 * Reset completes when this bit is set to 1 by hw
449 */
450 if (txcs.bits.qst) {
451 return (HPI_SUCCESS);
452 }
453 loop++;
454 } while (loop < TXDMA_WAIT_LOOP);
455
456 if (loop == TXDMA_WAIT_LOOP) {
457 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
458 "hpi_txdma_control_reset_wait: RST bit not "
459 "cleared to 0 txcs.bits 0x%llx", txcs.value));
460 return (HPI_FAILURE | HPI_TXDMA_RESET_FAILED);
461 }
462 return (HPI_SUCCESS);
463 }
464
465 hpi_status_t
hpi_txdma_control_stop_wait(hpi_handle_t handle,uint8_t channel)466 hpi_txdma_control_stop_wait(hpi_handle_t handle, uint8_t channel)
467 {
468 tdc_tdr_cfg_t txcs;
469 int loop = 0;
470
471 do {
472 txcs.value = 0;
473 HXGE_DELAY(TXDMA_WAIT_MSEC);
474 TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &txcs.value);
475 if (txcs.bits.qst) {
476 return (HPI_SUCCESS);
477 }
478 loop++;
479 } while (loop < TXDMA_WAIT_LOOP);
480
481 if (loop == TXDMA_WAIT_LOOP) {
482 HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
483 "hpi_txdma_control_stop_wait: SNG_STATE not "
484 "set to 1 txcs.bits 0x%llx", txcs.value));
485 return (HPI_FAILURE | HPI_TXDMA_STOP_FAILED);
486 }
487 return (HPI_SUCCESS);
488 }
489