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