Home | History | Annotate | Download | only in hxge
      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