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