/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #define RXDMA_RESET_TRY_COUNT 5 #define RXDMA_RESET_DELAY 5 #define RXDMA_OP_DISABLE 0 #define RXDMA_OP_ENABLE 1 #define RXDMA_OP_RESET 2 #define RCR_TIMEOUT_ENABLE 1 #define RCR_TIMEOUT_DISABLE 2 #define RCR_THRESHOLD 4 hpi_status_t hpi_rxdma_cfg_logical_page_handle(hpi_handle_t handle, uint8_t rdc, uint64_t page_handle) { rdc_page_handle_t page_hdl; if (!RXDMA_CHANNEL_VALID(rdc)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "rxdma_cfg_logical_page_handle" " Illegal RDC number %d \n", rdc)); return (HPI_RXDMA_RDC_INVALID); } page_hdl.value = 0; page_hdl.bits.handle = (uint32_t)page_handle; RXDMA_REG_WRITE64(handle, RDC_PAGE_HANDLE, rdc, page_hdl.value); return (HPI_SUCCESS); } /* RX DMA functions */ static hpi_status_t hpi_rxdma_cfg_rdc_ctl(hpi_handle_t handle, uint8_t rdc, uint8_t op) { rdc_rx_cfg1_t cfg; uint32_t count = RXDMA_RESET_TRY_COUNT; uint32_t delay_time = RXDMA_RESET_DELAY; uint32_t error = HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RESET_ERR, rdc); if (!RXDMA_CHANNEL_VALID(rdc)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "hpi_rxdma_cfg_rdc_ctl Illegal RDC number %d \n", rdc)); return (HPI_RXDMA_RDC_INVALID); } switch (op) { case RXDMA_OP_ENABLE: RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value); cfg.bits.enable = 1; RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value); HXGE_DELAY(delay_time); break; case RXDMA_OP_DISABLE: RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value); cfg.bits.enable = 0; RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value); HXGE_DELAY(delay_time); RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value); while ((count--) && (cfg.bits.qst == 0)) { HXGE_DELAY(delay_time); RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value); } if (cfg.bits.qst == 0) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " hpi_rxdma_cfg_rdc_ctl" " RXDMA_OP_DISABLE Failed for RDC %d \n", rdc)); return (error); } break; case RXDMA_OP_RESET: cfg.value = 0; cfg.bits.reset = 1; RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value); HXGE_DELAY(delay_time); RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value); while ((count--) && (cfg.bits.qst == 0)) { HXGE_DELAY(delay_time); RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value); } if (count == 0) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " hpi_rxdma_cfg_rdc_ctl" " Reset Failed for RDC %d \n", rdc)); return (error); } break; default: return (HPI_RXDMA_SW_PARAM_ERROR); } return (HPI_SUCCESS); } hpi_status_t hpi_rxdma_cfg_rdc_enable(hpi_handle_t handle, uint8_t rdc) { return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_ENABLE)); } hpi_status_t hpi_rxdma_cfg_rdc_disable(hpi_handle_t handle, uint8_t rdc) { return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_DISABLE)); } hpi_status_t hpi_rxdma_cfg_rdc_reset(hpi_handle_t handle, uint8_t rdc) { return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_RESET)); } static hpi_status_t hpi_rxdma_cfg_rdc_rcr_ctl(hpi_handle_t handle, uint8_t rdc, uint8_t op, uint16_t param) { rdc_rcr_cfg_b_t rcr_cfgb; if (!RXDMA_CHANNEL_VALID(rdc)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "rxdma_cfg_rdc_rcr_ctl Illegal RDC number %d \n", rdc)); return (HPI_RXDMA_RDC_INVALID); } RXDMA_REG_READ64(handle, RDC_RCR_CFG_B, rdc, &rcr_cfgb.value); switch (op) { case RCR_TIMEOUT_ENABLE: rcr_cfgb.bits.timeout = (uint8_t)param; rcr_cfgb.bits.entout = 1; break; case RCR_THRESHOLD: rcr_cfgb.bits.pthres = param; break; case RCR_TIMEOUT_DISABLE: rcr_cfgb.bits.entout = 0; break; default: HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "rxdma_cfg_rdc_rcr_ctl Illegal opcode %x \n", op)); return (HPI_RXDMA_OPCODE_INVALID(rdc)); } RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_B, rdc, rcr_cfgb.value); return (HPI_SUCCESS); } hpi_status_t hpi_rxdma_cfg_rdc_rcr_threshold(hpi_handle_t handle, uint8_t rdc, uint16_t rcr_threshold) { return (hpi_rxdma_cfg_rdc_rcr_ctl(handle, rdc, RCR_THRESHOLD, rcr_threshold)); } hpi_status_t hpi_rxdma_cfg_rdc_rcr_timeout(hpi_handle_t handle, uint8_t rdc, uint8_t rcr_timeout) { return (hpi_rxdma_cfg_rdc_rcr_ctl(handle, rdc, RCR_TIMEOUT_ENABLE, rcr_timeout)); } /* * Configure The RDC channel Rcv Buffer Ring */ hpi_status_t hpi_rxdma_cfg_rdc_ring(hpi_handle_t handle, uint8_t rdc, rdc_desc_cfg_t *rdc_desc_cfg) { rdc_rbr_cfg_a_t cfga; rdc_rbr_cfg_b_t cfgb; rdc_rx_cfg1_t cfg1; rdc_rx_cfg2_t cfg2; rdc_rcr_cfg_a_t rcr_cfga; rdc_rcr_cfg_b_t rcr_cfgb; rdc_page_handle_t page_handle; if (!RXDMA_CHANNEL_VALID(rdc)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "rxdma_cfg_rdc_ring Illegal RDC number %d \n", rdc)); return (HPI_RXDMA_RDC_INVALID); } cfga.value = 0; cfgb.value = 0; cfg1.value = 0; cfg2.value = 0; page_handle.value = 0; if (rdc_desc_cfg->mbox_enable == 1) { cfg1.bits.mbaddr_h = (rdc_desc_cfg->mbox_addr >> 32) & 0xfff; cfg2.bits.mbaddr_l = ((rdc_desc_cfg->mbox_addr & RXDMA_CFIG2_MBADDR_L_MASK) >> RXDMA_CFIG2_MBADDR_L_SHIFT); /* * Only after all the configurations are set, then * enable the RDC or else configuration fatal error * will be returned (especially if the Hypervisor * set up the logical pages with non-zero values. * This HPI function only sets up the configuration. * Call the enable function to enable the RDMC! */ } if (rdc_desc_cfg->full_hdr == 1) cfg2.bits.full_hdr = 1; if (RXDMA_BUFF_OFFSET_VALID(rdc_desc_cfg->offset)) { cfg2.bits.offset = rdc_desc_cfg->offset; } else { cfg2.bits.offset = SW_OFFSET_NO_OFFSET; } /* rbr config */ cfga.value = (rdc_desc_cfg->rbr_addr & (RBR_CFIG_A_STDADDR_MASK | RBR_CFIG_A_STDADDR_BASE_MASK)); /* The remaining 20 bits in the DMA address form the handle */ page_handle.bits.handle = (rdc_desc_cfg->rbr_addr >> 44) && 0xfffff; /* * The RBR ring size must be multiple of 64. */ if ((rdc_desc_cfg->rbr_len < RBR_DEFAULT_MIN_LEN) || (rdc_desc_cfg->rbr_len > RBR_DEFAULT_MAX_LEN) || (rdc_desc_cfg->rbr_len % 64)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "hpi_rxdma_cfg_rdc_ring Illegal RBR Queue Length %d \n", rdc_desc_cfg->rbr_len)); return (HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RBRSZIE_INVALID, rdc)); } /* * The lower 6 bits are hardcoded to 0 and the higher 10 bits are * stored in len. */ cfga.bits.len = rdc_desc_cfg->rbr_len >> 6; HPI_DEBUG_MSG((handle.function, HPI_RDC_CTL, "hpi_rxdma_cfg_rdc_ring CFGA 0x%llx len %d (RBR LEN %d)\n", cfga.value, cfga.bits.len, rdc_desc_cfg->rbr_len)); /* * bksize is 1 bit * Buffer Block Size. b0 - 4K; b1 - 8K. */ if (rdc_desc_cfg->page_size == SIZE_4KB) cfgb.bits.bksize = RBR_BKSIZE_4K; else if (rdc_desc_cfg->page_size == SIZE_8KB) cfgb.bits.bksize = RBR_BKSIZE_8K; else { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "rxdma_cfg_rdc_ring blksize: Illegal buffer size %d \n", rdc_desc_cfg->page_size)); return (HPI_RXDMA_BUFSZIE_INVALID); } /* * Size 0 of packet buffer. b00 - 256; b01 - 512; b10 - 1K; b11 - resvd. */ if (rdc_desc_cfg->valid0) { if (rdc_desc_cfg->size0 == SIZE_256B) cfgb.bits.bufsz0 = RBR_BUFSZ0_256B; else if (rdc_desc_cfg->size0 == SIZE_512B) cfgb.bits.bufsz0 = RBR_BUFSZ0_512B; else if (rdc_desc_cfg->size0 == SIZE_1KB) cfgb.bits.bufsz0 = RBR_BUFSZ0_1K; else { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_cfg_rdc_ring" " blksize0: Illegal buffer size %x \n", rdc_desc_cfg->size0)); return (HPI_RXDMA_BUFSZIE_INVALID); } cfgb.bits.vld0 = 1; } else { cfgb.bits.vld0 = 0; } /* * Size 1 of packet buffer. b0 - 1K; b1 - 2K. */ if (rdc_desc_cfg->valid1) { if (rdc_desc_cfg->size1 == SIZE_1KB) cfgb.bits.bufsz1 = RBR_BUFSZ1_1K; else if (rdc_desc_cfg->size1 == SIZE_2KB) cfgb.bits.bufsz1 = RBR_BUFSZ1_2K; else { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_cfg_rdc_ring" " blksize1: Illegal buffer size %x \n", rdc_desc_cfg->size1)); return (HPI_RXDMA_BUFSZIE_INVALID); } cfgb.bits.vld1 = 1; } else { cfgb.bits.vld1 = 0; } /* * Size 2 of packet buffer. b0 - 2K; b1 - 4K. */ if (rdc_desc_cfg->valid2) { if (rdc_desc_cfg->size2 == SIZE_2KB) cfgb.bits.bufsz2 = RBR_BUFSZ2_2K; else if (rdc_desc_cfg->size2 == SIZE_4KB) cfgb.bits.bufsz2 = RBR_BUFSZ2_4K; else { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_cfg_rdc_ring" " blksize2: Illegal buffer size %x \n", rdc_desc_cfg->size2)); return (HPI_RXDMA_BUFSZIE_INVALID); } cfgb.bits.vld2 = 1; } else { cfgb.bits.vld2 = 0; } rcr_cfga.value = (rdc_desc_cfg->rcr_addr & (RCRCFIG_A_STADDR_MASK | RCRCFIG_A_STADDR_BASE_MASK)); /* * The rcr len must be multiple of 32. */ if ((rdc_desc_cfg->rcr_len < RCR_DEFAULT_MIN_LEN) || (rdc_desc_cfg->rcr_len > HXGE_RCR_MAX) || (rdc_desc_cfg->rcr_len % 32)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_cfg_rdc_ring Illegal RCR Queue Length %d \n", rdc_desc_cfg->rcr_len)); return (HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RCRSZIE_INVALID, rdc)); } /* * Bits 15:5 of the maximum number of 8B entries in RCR. Bits 4:0 are * hard-coded to zero. The maximum size is 2^16 - 32. */ rcr_cfga.bits.len = rdc_desc_cfg->rcr_len >> 5; rcr_cfgb.value = 0; if (rdc_desc_cfg->rcr_timeout_enable == 1) { /* check if the rcr timeout value is valid */ if (RXDMA_RCR_TO_VALID(rdc_desc_cfg->rcr_timeout)) { rcr_cfgb.bits.timeout = rdc_desc_cfg->rcr_timeout; rcr_cfgb.bits.entout = 1; } else { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_cfg_rdc_ring" " Illegal RCR Timeout value %d \n", rdc_desc_cfg->rcr_timeout)); rcr_cfgb.bits.entout = 0; } } else { rcr_cfgb.bits.entout = 0; } /* check if the rcr threshold value is valid */ if (RXDMA_RCR_THRESH_VALID(rdc_desc_cfg->rcr_threshold)) { rcr_cfgb.bits.pthres = rdc_desc_cfg->rcr_threshold; } else { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_cfg_rdc_ring Illegal RCR Threshold value %d \n", rdc_desc_cfg->rcr_threshold)); rcr_cfgb.bits.pthres = 1; } /* now do the actual HW configuration */ RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg1.value); RXDMA_REG_WRITE64(handle, RDC_RX_CFG2, rdc, cfg2.value); RXDMA_REG_WRITE64(handle, RDC_RBR_CFG_A, rdc, cfga.value); RXDMA_REG_WRITE64(handle, RDC_RBR_CFG_B, rdc, cfgb.value); RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_A, rdc, rcr_cfga.value); RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_B, rdc, rcr_cfgb.value); RXDMA_REG_WRITE64(handle, RDC_PAGE_HANDLE, rdc, page_handle.value); return (HPI_SUCCESS); } hpi_status_t hpi_rxdma_ring_perr_stat_get(hpi_handle_t handle, rdc_pref_par_log_t *pre_log, rdc_pref_par_log_t *sha_log) { /* * Hydra doesn't have details about these errors. * It only provides the addresses of the errors. */ HXGE_REG_RD64(handle, RDC_PREF_PAR_LOG, &pre_log->value); HXGE_REG_RD64(handle, RDC_SHADOW_PAR_LOG, &sha_log->value); return (HPI_SUCCESS); } /* system wide conf functions */ hpi_status_t hpi_rxdma_cfg_clock_div_set(hpi_handle_t handle, uint16_t count) { uint64_t offset; rdc_clock_div_t clk_div; offset = RDC_CLOCK_DIV; clk_div.value = 0; clk_div.bits.count = count; HPI_DEBUG_MSG((handle.function, HPI_RDC_CTL, " hpi_rxdma_cfg_clock_div_set: add 0x%llx " "handle 0x%llx value 0x%llx", handle.regp, handle.regh, clk_div.value)); HXGE_REG_WR64(handle, offset, clk_div.value); return (HPI_SUCCESS); } hpi_status_t hpi_rxdma_rdc_rbr_stat_get(hpi_handle_t handle, uint8_t rdc, rdc_rbr_qlen_t *rbr_stat) { if (!RXDMA_CHANNEL_VALID(rdc)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_rdc_rbr_stat_get Illegal RDC Number %d \n", rdc)); return (HPI_RXDMA_RDC_INVALID); } RXDMA_REG_READ64(handle, RDC_RBR_QLEN, rdc, &rbr_stat->value); return (HPI_SUCCESS); } hpi_status_t hpi_rxdma_rdc_rcr_qlen_get(hpi_handle_t handle, uint8_t rdc, uint16_t *rcr_qlen) { rdc_rcr_qlen_t stats; if (!RXDMA_CHANNEL_VALID(rdc)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " rxdma_rdc_rcr_qlen_get Illegal RDC Number %d \n", rdc)); return (HPI_RXDMA_RDC_INVALID); } RXDMA_REG_READ64(handle, RDC_RCR_QLEN, rdc, &stats.value); *rcr_qlen = stats.bits.qlen; HPI_DEBUG_MSG((handle.function, HPI_RDC_CTL, " rxdma_rdc_rcr_qlen_get RDC %d qlen %x qlen %x\n", rdc, *rcr_qlen, stats.bits.qlen)); return (HPI_SUCCESS); } hpi_status_t hpi_rxdma_channel_rbr_empty_clear(hpi_handle_t handle, uint8_t channel) { rdc_stat_t cs; if (!RXDMA_CHANNEL_VALID(channel)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, " hpi_rxdma_channel_rbr_empty_clear", " channel", channel)); return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel)); } RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value); cs.bits.rbr_empty = 1; RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value); return (HPI_SUCCESS); } /* * This function is called to operate on the control and status register. */ hpi_status_t hpi_rxdma_control_status(hpi_handle_t handle, io_op_t op_mode, uint8_t channel, rdc_stat_t *cs_p) { int status = HPI_SUCCESS; rdc_stat_t cs; if (!RXDMA_CHANNEL_VALID(channel)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "hpi_rxdma_control_status", "channel", channel)); return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel)); } switch (op_mode) { case OP_GET: RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs_p->value); break; case OP_SET: RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs_p->value); break; case OP_UPDATE: RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value); RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs_p->value | cs.value); break; default: HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "hpi_rxdma_control_status", "control", op_mode)); return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(channel)); } return (status); } /* * This function is called to operate on the event mask * register which is used for generating interrupts. */ hpi_status_t hpi_rxdma_event_mask(hpi_handle_t handle, io_op_t op_mode, uint8_t channel, rdc_int_mask_t *mask_p) { int status = HPI_SUCCESS; rdc_int_mask_t mask; if (!RXDMA_CHANNEL_VALID(channel)) { HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "hpi_rxdma_event_mask", "channel", channel)); return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel)); } switch (op_mode) { case OP_GET: RXDMA_REG_READ64(handle, RDC_INT_MASK, channel, &mask_p->value); break; case OP_SET: RXDMA_REG_WRITE64(handle, RDC_INT_MASK, channel, mask_p->value); break; case OP_UPDATE: RXDMA_REG_READ64(handle, RDC_INT_MASK, channel, &mask.value); RXDMA_REG_WRITE64(handle, RDC_INT_MASK, channel, mask_p->value | mask.value); break; default: HPI_ERROR_MSG((handle.function, HPI_ERR_CTL, "hpi_rxdma_event_mask", "eventmask", op_mode)); return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(channel)); } return (status); }