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 /* 23 * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved. 24 */ 25 26 #include "common.h" 27 #include "regs.h" 28 #include "ulp.h" 29 30 struct peulp { 31 adapter_t *adapter; 32 struct ulp_intr_counts intr_counts; 33 }; 34 35 #define ULP_INTR_MASK (F_HREG_PAR_ERR | F_EGRS_DATA_PAR_ERR | \ 36 F_INGRS_DATA_PAR_ERR | F_PM_INTR | F_PM_E2C_SYNC_ERR | \ 37 F_PM_C2E_SYNC_ERR | F_PM_E2C_EMPTY_ERR | \ 38 F_PM_C2E_EMPTY_ERR | V_PM_PAR_ERR(M_PM_PAR_ERR) | \ 39 F_PM_E2C_WRT_FULL | F_PM_C2E_WRT_FULL) 40 41 void t1_ulp_intr_enable(struct peulp *ulp) 42 { 43 /* Only ASIC boards support PL_ULP block. */ 44 if (t1_is_asic(ulp->adapter)) { 45 u32 pl_intr = t1_read_reg_4(ulp->adapter, A_PL_ENABLE); 46 47 t1_write_reg_4(ulp->adapter, A_ULP_INT_ENABLE, ULP_INTR_MASK); 48 t1_write_reg_4(ulp->adapter, A_PL_ENABLE, 49 pl_intr | F_PL_INTR_ULP); 50 } 51 } 52 53 void t1_ulp_intr_clear(struct peulp *ulp) 54 { 55 if (t1_is_asic(ulp->adapter)) { 56 t1_write_reg_4(ulp->adapter, A_PL_CAUSE, F_PL_INTR_ULP); 57 t1_write_reg_4(ulp->adapter, A_ULP_INT_CAUSE, 0xffffffff); 58 } 59 } 60 61 void t1_ulp_intr_disable(struct peulp *ulp) 62 { 63 if (t1_is_asic(ulp->adapter)) { 64 u32 pl_intr = t1_read_reg_4(ulp->adapter, A_PL_ENABLE); 65 66 t1_write_reg_4(ulp->adapter, A_PL_ENABLE, 67 pl_intr & ~F_PL_INTR_ULP); 68 t1_write_reg_4(ulp->adapter, A_ULP_INT_ENABLE, 0); 69 } 70 } 71 72 int t1_ulp_intr_handler(struct peulp *ulp) 73 { 74 u32 cause = t1_read_reg_4(ulp->adapter, A_ULP_INT_CAUSE); 75 76 if (cause & F_HREG_PAR_ERR) 77 ulp->intr_counts.region_table_parity_err++; 78 79 if (cause & F_EGRS_DATA_PAR_ERR) 80 ulp->intr_counts.egress_tp2ulp_data_parity_err++; 81 82 if (cause & F_INGRS_DATA_PAR_ERR) 83 ulp->intr_counts.ingress_tp2ulp_data_parity_err++; 84 85 if (cause & F_PM_INTR) 86 ulp->intr_counts.pm_intr++; 87 88 if (cause & F_PM_E2C_SYNC_ERR) 89 ulp->intr_counts.pm_e2c_cmd_payload_sync_err++; 90 91 if (cause & F_PM_C2E_SYNC_ERR) 92 ulp->intr_counts.pm_c2e_cmd_payload_sync_err++; 93 94 if (cause & F_PM_E2C_EMPTY_ERR) 95 ulp->intr_counts.pm_e2c_fifo_read_empty_err++; 96 97 if (cause & F_PM_C2E_EMPTY_ERR) 98 ulp->intr_counts.pm_c2e_fifo_read_empty_err++; 99 100 if (G_PM_PAR_ERR(cause)) 101 ulp->intr_counts.pm_parity_err++; 102 103 if (cause & F_PM_E2C_WRT_FULL) 104 ulp->intr_counts.pm_e2c_fifo_write_full_err++; 105 106 if (cause & F_PM_C2E_WRT_FULL) 107 ulp->intr_counts.pm_c2e_fifo_write_full_err++; 108 109 if (cause & ULP_INTR_MASK) 110 t1_fatal_err(ulp->adapter); 111 112 /* Clear status */ 113 t1_write_reg_4(ulp->adapter, A_ULP_INT_CAUSE, cause); 114 return 0; 115 } 116 117 int t1_ulp_init(struct peulp *ulp, unsigned int pm_tx_base) 118 { 119 int i; 120 adapter_t *adapter = ulp->adapter; 121 122 /* 123 * Initialize ULP Region Table. 124 * 125 * The region table memory has read enable tied to one, so data is 126 * read out every cycle. The address to this memory is not defined 127 * at reset and gets set first time when first ulp pdu is handled. 128 * So after reset an undefined location is accessed, and since it is 129 * read before any meaningful data is written to it there can be a 130 * parity error. 131 */ 132 for (i = 0; i < 256; i++) { 133 t1_write_reg_4(adapter, A_ULP_HREG_INDEX, i); 134 t1_write_reg_4(adapter, A_ULP_HREG_DATA, 0); 135 } 136 137 t1_write_reg_4(adapter, A_ULP_ULIMIT, pm_tx_base); 138 t1_write_reg_4(adapter, A_ULP_TAGMASK, (pm_tx_base << 1) - 1); 139 140 if (!t1_is_T1B(adapter)) { 141 /* region table is not used */ 142 t1_write_reg_4(adapter, A_ULP_HREG_INDEX, 0); 143 /* enable page size in pagepod */ 144 t1_write_reg_4(adapter, A_ULP_PIO_CTRL, 1); 145 } 146 return 0; 147 } 148 149 struct peulp *t1_ulp_create(adapter_t *adapter) 150 { 151 struct peulp *ulp = t1_os_malloc_wait_zero(sizeof(*ulp)); 152 153 if (ulp) 154 ulp->adapter = adapter; 155 return ulp; 156 } 157 158 void t1_ulp_destroy(struct peulp * ulp) 159 { 160 t1_os_free((void *)ulp, sizeof(*ulp)); 161 } 162 163 const struct ulp_intr_counts *t1_ulp_get_intr_counts(struct peulp *ulp) 164 { 165 return &ulp->intr_counts; 166 } 167