xref: /illumos-gate/usr/src/uts/common/io/hxge/hpi_txdma.c (revision f3041bfa)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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