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