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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * PCI Express PEC implementation: 31 * initialization 32 * Bus error interrupt handler 33 */ 34 35 #include <sys/types.h> 36 #include <sys/kmem.h> 37 #include <sys/spl.h> 38 #include <sys/sysmacros.h> 39 #include <sys/sunddi.h> 40 #include <sys/machsystm.h> /* ldphysio() */ 41 #include <sys/async.h> 42 #include <sys/ddi_impldefs.h> 43 #include <sys/ontrap.h> 44 #include <sys/membar.h> 45 #include "px_obj.h" 46 47 /*LINTLIBRARY*/ 48 49 extern uint_t px_ranges_phi_mask; 50 51 static uint_t px_pec_error_intr(caddr_t a); 52 static int px_pec_msg_add_intr(px_t *px_p); 53 static void px_pec_msg_rem_intr(px_t *px_p); 54 55 int 56 px_pec_attach(px_t *px_p) 57 { 58 px_pec_t *pec_p; 59 int i, len; 60 int nrange = px_p->px_ranges_length / sizeof (px_ranges_t); 61 dev_info_t *dip = px_p->px_dip; 62 px_ranges_t *rangep = px_p->px_ranges_p; 63 int ret; 64 65 /* 66 * Allocate a state structure for the PEC and cross-link it 67 * to its per px node state structure. 68 */ 69 pec_p = kmem_zalloc(sizeof (px_pec_t), KM_SLEEP); 70 px_p->px_pec_p = pec_p; 71 pec_p->pec_px_p = px_p; 72 73 len = snprintf(pec_p->pec_nameinst_str, 74 sizeof (pec_p->pec_nameinst_str), 75 "%s%d", NAMEINST(dip)); 76 pec_p->pec_nameaddr_str = pec_p->pec_nameinst_str + ++len; 77 (void) snprintf(pec_p->pec_nameaddr_str, 78 sizeof (pec_p->pec_nameinst_str) - len, 79 "%s@%s", NAMEADDR(dip)); 80 81 /* 82 * Add interrupt handlers to process correctable/fatal/non fatal 83 * PCIE messages. 84 */ 85 if ((ret = px_pec_msg_add_intr(px_p)) != DDI_SUCCESS) { 86 px_pec_msg_rem_intr(px_p); 87 return (ret); 88 } 89 90 /* 91 * Get this pec's mem32 and mem64 segments to determine whether 92 * a dma object originates from ths pec. i.e. dev to dev dma 93 */ 94 for (i = 0; i < nrange; i++, rangep++) { 95 uint64_t rng_addr, rng_size, *pfnbp, *pfnlp; 96 uint32_t rng_type = rangep->child_high & PCI_ADDR_MASK; 97 98 switch (rng_type) { 99 case PCI_ADDR_MEM32: 100 pfnbp = &pec_p->pec_base32_pfn; 101 pfnlp = &pec_p->pec_last32_pfn; 102 break; 103 104 case PCI_ADDR_MEM64: 105 pfnbp = &pec_p->pec_base64_pfn; 106 pfnlp = &pec_p->pec_last64_pfn; 107 break; 108 109 case PCI_ADDR_CONFIG: 110 case PCI_ADDR_IO: 111 default: 112 continue; 113 } 114 rng_addr = (uint64_t)(rangep->parent_high & 115 px_ranges_phi_mask) << 32; 116 rng_addr |= (uint64_t)rangep->parent_low; 117 rng_size = (uint64_t)rangep->size_high << 32; 118 rng_size |= (uint64_t)rangep->size_low; 119 120 *pfnbp = mmu_btop(rng_addr); 121 *pfnlp = mmu_btop(rng_addr + rng_size); 122 } 123 124 mutex_init(&pec_p->pec_pokefault_mutex, NULL, MUTEX_DRIVER, 125 (void *)px_p->px_fm_ibc); 126 127 return (DDI_SUCCESS); 128 } 129 130 void 131 px_pec_detach(px_t *px_p) 132 { 133 dev_info_t *dip = px_p->px_dip; 134 px_pec_t *pec_p = px_p->px_pec_p; 135 136 /* 137 * Free the pokefault mutex. 138 */ 139 DBG(DBG_DETACH, dip, "px_pec_detach:\n"); 140 mutex_destroy(&pec_p->pec_pokefault_mutex); 141 142 /* 143 * Remove interrupt handlers to process correctable/fatal/non fatal 144 * PCIE messages. 145 */ 146 px_pec_msg_rem_intr(px_p); 147 148 /* 149 * Free the pec state structure. 150 */ 151 kmem_free(pec_p, sizeof (px_pec_t)); 152 px_p->px_pec_p = NULL; 153 } 154 155 /* 156 * pec_msg_add_intr: 157 * 158 * Add interrupt handlers to process correctable/fatal/non fatal 159 * PCIE messages. 160 */ 161 static int 162 px_pec_msg_add_intr(px_t *px_p) 163 { 164 dev_info_t *dip = px_p->px_dip; 165 px_pec_t *pec_p = px_p->px_pec_p; 166 ddi_intr_handle_impl_t hdl; 167 int ret = DDI_SUCCESS; 168 169 DBG(DBG_MSG, px_p->px_dip, "px_pec_msg_add_intr\n"); 170 171 /* Initilize handle */ 172 hdl.ih_cb_func = (ddi_intr_handler_t *)px_err_fabric_intr; 173 hdl.ih_cb_arg1 = NULL; 174 hdl.ih_cb_arg2 = NULL; 175 hdl.ih_ver = DDI_INTR_VERSION; 176 hdl.ih_state = DDI_IHDL_STATE_ALLOC; 177 hdl.ih_dip = dip; 178 hdl.ih_inum = 0; 179 180 /* Add correctable error message handler */ 181 hdl.ih_pri = PX_ERR_LOW_PIL; 182 183 if ((ret = px_add_msiq_intr(dip, dip, &hdl, 184 MSG_REC, (msgcode_t)PCIE_CORR_MSG, 185 &pec_p->pec_corr_msg_msiq_id)) != DDI_SUCCESS) { 186 DBG(DBG_MSG, px_p->px_dip, 187 "PCIE_CORR_MSG registration failed\n"); 188 return (DDI_FAILURE); 189 } 190 191 px_lib_msg_setmsiq(dip, PCIE_CORR_MSG, pec_p->pec_corr_msg_msiq_id); 192 px_lib_msg_setvalid(dip, PCIE_CORR_MSG, PCIE_MSG_VALID); 193 194 if ((ret = px_ib_update_intr_state(px_p, px_p->px_dip, 195 hdl.ih_inum, px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id), 196 PX_INTR_STATE_ENABLE, MSG_REC, PCIE_CORR_MSG)) != DDI_SUCCESS) { 197 DBG(DBG_MSG, px_p->px_dip, 198 "PCIE_CORR_MSG update interrupt state failed\n"); 199 return (DDI_FAILURE); 200 } 201 202 /* Add non-fatal error message handler */ 203 hdl.ih_pri = PX_ERR_PIL; 204 205 if ((ret = px_add_msiq_intr(dip, dip, &hdl, 206 MSG_REC, (msgcode_t)PCIE_NONFATAL_MSG, 207 &pec_p->pec_non_fatal_msg_msiq_id)) != DDI_SUCCESS) { 208 DBG(DBG_MSG, px_p->px_dip, 209 "PCIE_NONFATAL_MSG registration failed\n"); 210 return (DDI_FAILURE); 211 } 212 213 px_lib_msg_setmsiq(dip, PCIE_NONFATAL_MSG, 214 pec_p->pec_non_fatal_msg_msiq_id); 215 px_lib_msg_setvalid(dip, PCIE_NONFATAL_MSG, PCIE_MSG_VALID); 216 217 if ((ret = px_ib_update_intr_state(px_p, px_p->px_dip, 218 hdl.ih_inum, px_msiqid_to_devino(px_p, 219 pec_p->pec_non_fatal_msg_msiq_id), PX_INTR_STATE_ENABLE, MSG_REC, 220 PCIE_NONFATAL_MSG)) != DDI_SUCCESS) { 221 DBG(DBG_MSG, px_p->px_dip, 222 "PCIE_NONFATAL_MSG update interrupt state failed\n"); 223 return (DDI_FAILURE); 224 } 225 226 /* Add fatal error message handler */ 227 hdl.ih_pri = PX_ERR_PIL; 228 229 if ((ret = px_add_msiq_intr(dip, dip, &hdl, 230 MSG_REC, (msgcode_t)PCIE_FATAL_MSG, 231 &pec_p->pec_fatal_msg_msiq_id)) != DDI_SUCCESS) { 232 DBG(DBG_MSG, px_p->px_dip, 233 "PCIE_FATAL_MSG registration failed\n"); 234 return (DDI_FAILURE); 235 } 236 237 px_lib_msg_setmsiq(dip, PCIE_FATAL_MSG, pec_p->pec_fatal_msg_msiq_id); 238 px_lib_msg_setvalid(dip, PCIE_FATAL_MSG, PCIE_MSG_VALID); 239 240 if ((ret = px_ib_update_intr_state(px_p, px_p->px_dip, 241 hdl.ih_inum, px_msiqid_to_devino(px_p, 242 pec_p->pec_fatal_msg_msiq_id), PX_INTR_STATE_ENABLE, MSG_REC, 243 PCIE_FATAL_MSG)) != DDI_SUCCESS) { 244 DBG(DBG_MSG, px_p->px_dip, 245 "PCIE_FATAL_MSG update interrupt state failed\n"); 246 return (DDI_FAILURE); 247 } 248 249 return (ret); 250 } 251 252 /* 253 * px_pec_msg_rem_intr: 254 * 255 * Remove interrupt handlers to process correctable/fatal/non fatal 256 * PCIE messages. For now, all these PCIe messages are mapped to 257 * same MSIQ. 258 */ 259 static void 260 px_pec_msg_rem_intr(px_t *px_p) 261 { 262 dev_info_t *dip = px_p->px_dip; 263 px_pec_t *pec_p = px_p->px_pec_p; 264 ddi_intr_handle_impl_t hdl; 265 266 DBG(DBG_MSG, px_p->px_dip, "px_pec_msg_rem_intr: dip 0x%p\n", dip); 267 268 /* Initilize handle */ 269 hdl.ih_ver = DDI_INTR_VERSION; 270 hdl.ih_state = DDI_IHDL_STATE_ALLOC; 271 hdl.ih_dip = dip; 272 hdl.ih_inum = 0; 273 274 if (pec_p->pec_corr_msg_msiq_id >= 0) { 275 px_lib_msg_setvalid(dip, PCIE_CORR_MSG, PCIE_MSG_INVALID); 276 277 (void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, 278 PCIE_CORR_MSG, pec_p->pec_corr_msg_msiq_id); 279 280 (void) px_ib_update_intr_state(px_p, px_p->px_dip, 281 hdl.ih_inum, px_msiqid_to_devino(px_p, 282 pec_p->pec_corr_msg_msiq_id), 283 PX_INTR_STATE_DISABLE, MSG_REC, PCIE_CORR_MSG); 284 285 pec_p->pec_corr_msg_msiq_id = -1; 286 } 287 288 if (pec_p->pec_non_fatal_msg_msiq_id >= 0) { 289 px_lib_msg_setvalid(dip, PCIE_NONFATAL_MSG, 290 PCIE_MSG_INVALID); 291 292 (void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, 293 PCIE_NONFATAL_MSG, pec_p->pec_non_fatal_msg_msiq_id); 294 295 (void) px_ib_update_intr_state(px_p, px_p->px_dip, 296 hdl.ih_inum, px_msiqid_to_devino(px_p, 297 pec_p->pec_non_fatal_msg_msiq_id), 298 PX_INTR_STATE_DISABLE, MSG_REC, PCIE_NONFATAL_MSG); 299 300 pec_p->pec_non_fatal_msg_msiq_id = -1; 301 } 302 303 if (pec_p->pec_fatal_msg_msiq_id >= 0) { 304 px_lib_msg_setvalid(dip, PCIE_FATAL_MSG, PCIE_MSG_INVALID); 305 306 (void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, 307 PCIE_FATAL_MSG, pec_p->pec_fatal_msg_msiq_id); 308 309 (void) px_ib_update_intr_state(px_p, px_p->px_dip, 310 hdl.ih_inum, px_msiqid_to_devino(px_p, 311 pec_p->pec_fatal_msg_msiq_id), 312 PX_INTR_STATE_DISABLE, MSG_REC, PCIE_FATAL_MSG); 313 314 pec_p->pec_fatal_msg_msiq_id = -1; 315 } 316 } 317