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