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) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * PCI Express PEC implementation: 28 * initialization 29 * Bus error interrupt handler 30 */ 31 32 #include <sys/types.h> 33 #include <sys/kmem.h> 34 #include <sys/spl.h> 35 #include <sys/sysmacros.h> 36 #include <sys/sunddi.h> 37 #include <sys/machsystm.h> /* ldphysio() */ 38 #include <sys/async.h> 39 #include <sys/ddi_impldefs.h> 40 #include <sys/ontrap.h> 41 #include <sys/membar.h> 42 #include "px_obj.h" 43 44 /*LINTLIBRARY*/ 45 46 extern uint_t px_ranges_phi_mask; 47 48 static uint_t px_pec_error_intr(caddr_t a); 49 50 int 51 px_pec_attach(px_t *px_p) 52 { 53 px_pec_t *pec_p; 54 int i, len; 55 int nrange = px_p->px_ranges_length / sizeof (pci_ranges_t); 56 dev_info_t *dip = px_p->px_dip; 57 pci_ranges_t *rangep = px_p->px_ranges_p; 58 59 /* 60 * Allocate a state structure for the PEC and cross-link it 61 * to its per px node state structure. 62 */ 63 pec_p = kmem_zalloc(sizeof (px_pec_t), KM_SLEEP); 64 px_p->px_pec_p = pec_p; 65 pec_p->pec_px_p = px_p; 66 67 len = snprintf(pec_p->pec_nameinst_str, 68 sizeof (pec_p->pec_nameinst_str), 69 "%s%d", NAMEINST(dip)); 70 pec_p->pec_nameaddr_str = pec_p->pec_nameinst_str + ++len; 71 (void) snprintf(pec_p->pec_nameaddr_str, 72 sizeof (pec_p->pec_nameinst_str) - len, 73 "%s@%s", NAMEADDR(dip)); 74 75 /* 76 * Get this pec's mem32 and mem64 segments to determine whether 77 * a dma object originates from ths pec. i.e. dev to dev dma 78 */ 79 for (i = 0; i < nrange; i++, rangep++) { 80 uint64_t rng_addr, rng_size, *pfnbp, *pfnlp; 81 uint32_t rng_type = rangep->child_high & PCI_ADDR_MASK; 82 83 switch (rng_type) { 84 case PCI_ADDR_MEM32: 85 pfnbp = &pec_p->pec_base32_pfn; 86 pfnlp = &pec_p->pec_last32_pfn; 87 break; 88 89 case PCI_ADDR_MEM64: 90 pfnbp = &pec_p->pec_base64_pfn; 91 pfnlp = &pec_p->pec_last64_pfn; 92 break; 93 94 case PCI_ADDR_CONFIG: 95 case PCI_ADDR_IO: 96 default: 97 continue; 98 } 99 rng_addr = (uint64_t)(rangep->parent_high & 100 px_ranges_phi_mask) << 32; 101 rng_addr |= (uint64_t)rangep->parent_low; 102 rng_size = (uint64_t)rangep->size_high << 32; 103 rng_size |= (uint64_t)rangep->size_low; 104 105 *pfnbp = mmu_btop(rng_addr); 106 *pfnlp = mmu_btop(rng_addr + rng_size); 107 } 108 109 /* 110 * This lock is for serializing safe acc calls. It is not associated 111 * with an iblock cookie. 112 */ 113 mutex_init(&pec_p->pec_pokefault_mutex, NULL, MUTEX_DRIVER, NULL); 114 115 return (DDI_SUCCESS); 116 } 117 118 void 119 px_pec_detach(px_t *px_p) 120 { 121 dev_info_t *dip = px_p->px_dip; 122 px_pec_t *pec_p = px_p->px_pec_p; 123 124 /* 125 * Free the pokefault mutex. 126 */ 127 DBG(DBG_DETACH, dip, "px_pec_detach:\n"); 128 mutex_destroy(&pec_p->pec_pokefault_mutex); 129 130 /* 131 * Free the pec state structure. 132 */ 133 kmem_free(pec_p, sizeof (px_pec_t)); 134 px_p->px_pec_p = NULL; 135 } 136 137 /* 138 * pec_msg_add_intr: 139 * 140 * Add interrupt handlers to process correctable/fatal/non fatal 141 * PCIE messages. 142 */ 143 int 144 px_pec_msg_add_intr(px_t *px_p) 145 { 146 dev_info_t *dip = px_p->px_dip; 147 px_pec_t *pec_p = px_p->px_pec_p; 148 ddi_intr_handle_impl_t hdl; 149 int ret = DDI_SUCCESS; 150 151 DBG(DBG_MSG, px_p->px_dip, "px_pec_msg_add_intr\n"); 152 153 /* Initialize handle */ 154 bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 155 hdl.ih_cb_func = (ddi_intr_handler_t *)px_err_fabric_intr; 156 hdl.ih_ver = DDI_INTR_VERSION; 157 hdl.ih_state = DDI_IHDL_STATE_ALLOC; 158 hdl.ih_dip = dip; 159 160 /* Add correctable error message handler */ 161 hdl.ih_pri = PX_ERR_LOW_PIL; 162 163 if ((ret = px_add_msiq_intr(dip, dip, &hdl, 164 MSG_REC, (msgcode_t)PCIE_CORR_MSG, -1, 165 &pec_p->pec_corr_msg_msiq_id)) != DDI_SUCCESS) { 166 DBG(DBG_MSG, px_p->px_dip, 167 "PCIE_CORR_MSG registration failed\n"); 168 return (DDI_FAILURE); 169 } 170 171 px_lib_msg_setmsiq(dip, PCIE_CORR_MSG, pec_p->pec_corr_msg_msiq_id); 172 px_lib_msg_setvalid(dip, PCIE_CORR_MSG, PCIE_MSG_VALID); 173 174 if ((ret = px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum, 175 px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id), 176 PX_ERR_LOW_PIL, PX_INTR_STATE_ENABLE, MSG_REC, 177 PCIE_CORR_MSG)) != DDI_SUCCESS) { 178 DBG(DBG_MSG, px_p->px_dip, 179 "PCIE_CORR_MSG update interrupt state failed\n"); 180 return (DDI_FAILURE); 181 } 182 183 /* Add non-fatal error message handler */ 184 hdl.ih_pri = PX_ERR_PIL; 185 186 if ((ret = px_add_msiq_intr(dip, dip, &hdl, 187 MSG_REC, (msgcode_t)PCIE_NONFATAL_MSG, -1, 188 &pec_p->pec_non_fatal_msg_msiq_id)) != DDI_SUCCESS) { 189 DBG(DBG_MSG, px_p->px_dip, 190 "PCIE_NONFATAL_MSG registration failed\n"); 191 return (DDI_FAILURE); 192 } 193 194 px_lib_msg_setmsiq(dip, PCIE_NONFATAL_MSG, 195 pec_p->pec_non_fatal_msg_msiq_id); 196 px_lib_msg_setvalid(dip, PCIE_NONFATAL_MSG, PCIE_MSG_VALID); 197 198 if ((ret = px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum, 199 px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id), 200 PX_ERR_PIL, PX_INTR_STATE_ENABLE, MSG_REC, 201 PCIE_NONFATAL_MSG)) != DDI_SUCCESS) { 202 DBG(DBG_MSG, px_p->px_dip, 203 "PCIE_NONFATAL_MSG update interrupt state failed\n"); 204 return (DDI_FAILURE); 205 } 206 207 /* Add fatal error message handler */ 208 hdl.ih_pri = PX_ERR_PIL; 209 210 if ((ret = px_add_msiq_intr(dip, dip, &hdl, 211 MSG_REC, (msgcode_t)PCIE_FATAL_MSG, -1, 212 &pec_p->pec_fatal_msg_msiq_id)) != DDI_SUCCESS) { 213 DBG(DBG_MSG, px_p->px_dip, 214 "PCIE_FATAL_MSG registration failed\n"); 215 return (DDI_FAILURE); 216 } 217 218 px_lib_msg_setmsiq(dip, PCIE_FATAL_MSG, pec_p->pec_fatal_msg_msiq_id); 219 px_lib_msg_setvalid(dip, PCIE_FATAL_MSG, PCIE_MSG_VALID); 220 221 if ((ret = px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum, 222 px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id), PX_ERR_PIL, 223 PX_INTR_STATE_ENABLE, MSG_REC, PCIE_FATAL_MSG)) != DDI_SUCCESS) { 224 DBG(DBG_MSG, px_p->px_dip, 225 "PCIE_FATAL_MSG update interrupt state failed\n"); 226 return (DDI_FAILURE); 227 } 228 229 return (ret); 230 } 231 232 /* 233 * px_pec_msg_rem_intr: 234 * 235 * Remove interrupt handlers to process correctable/fatal/non fatal 236 * PCIE messages. For now, all these PCIe messages are mapped to 237 * same MSIQ. 238 */ 239 void 240 px_pec_msg_rem_intr(px_t *px_p) 241 { 242 dev_info_t *dip = px_p->px_dip; 243 px_pec_t *pec_p = px_p->px_pec_p; 244 ddi_intr_handle_impl_t hdl; 245 246 DBG(DBG_MSG, px_p->px_dip, "px_pec_msg_rem_intr: dip 0x%p\n", dip); 247 248 /* Initialize handle */ 249 bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 250 hdl.ih_ver = DDI_INTR_VERSION; 251 hdl.ih_state = DDI_IHDL_STATE_ALLOC; 252 hdl.ih_dip = dip; 253 254 /* Remove correctable error message handler */ 255 if (pec_p->pec_corr_msg_msiq_id >= 0) { 256 px_lib_msg_setvalid(dip, PCIE_CORR_MSG, PCIE_MSG_INVALID); 257 258 hdl.ih_pri = PX_ERR_LOW_PIL; 259 (void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, 260 PCIE_CORR_MSG, pec_p->pec_corr_msg_msiq_id); 261 262 (void) px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum, 263 px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id), 264 PX_ERR_LOW_PIL, PX_INTR_STATE_DISABLE, MSG_REC, 265 PCIE_CORR_MSG); 266 267 pec_p->pec_corr_msg_msiq_id = (msiqid_t)-1; 268 } 269 270 /* Remove non-fatal error message handler */ 271 if (pec_p->pec_non_fatal_msg_msiq_id >= 0) { 272 px_lib_msg_setvalid(dip, PCIE_NONFATAL_MSG, 273 PCIE_MSG_INVALID); 274 275 hdl.ih_pri = PX_ERR_PIL; 276 (void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, 277 PCIE_NONFATAL_MSG, pec_p->pec_non_fatal_msg_msiq_id); 278 279 (void) px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum, 280 px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id), 281 PX_ERR_PIL, PX_INTR_STATE_DISABLE, MSG_REC, 282 PCIE_NONFATAL_MSG); 283 284 pec_p->pec_non_fatal_msg_msiq_id = (msiqid_t)-1; 285 } 286 287 /* Remove fatal error message handler */ 288 if (pec_p->pec_fatal_msg_msiq_id >= 0) { 289 px_lib_msg_setvalid(dip, PCIE_FATAL_MSG, PCIE_MSG_INVALID); 290 291 hdl.ih_pri = PX_ERR_PIL; 292 (void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, 293 PCIE_FATAL_MSG, pec_p->pec_fatal_msg_msiq_id); 294 295 (void) px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum, 296 px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id), 297 PX_ERR_PIL, PX_INTR_STATE_DISABLE, MSG_REC, PCIE_FATAL_MSG); 298 299 pec_p->pec_fatal_msg_msiq_id = (msiqid_t)-1; 300 } 301 } 302