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 nexus driver interface 31 */ 32 #include <sys/types.h> 33 #include <sys/conf.h> /* nulldev */ 34 #include <sys/stat.h> /* devctl */ 35 #include <sys/kmem.h> 36 #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 37 #include <sys/sunddi.h> 38 #include <sys/sunndi.h> 39 #include <sys/ontrap.h> 40 #include <sys/ddi_impldefs.h> 41 #include <sys/ddi_subrdefs.h> 42 #include <sys/epm.h> 43 #include <sys/membar.h> 44 #include <sys/modctl.h> 45 #include <sys/hotplug/pci/pcihp.h> 46 #include <sys/pci/pci_obj.h> 47 48 /*LINTLIBRARY*/ 49 50 static uint8_t pci_axq_hack_get8(ddi_acc_impl_t *handle, uint8_t *addr); 51 static uint16_t pci_axq_hack_get16(ddi_acc_impl_t *handle, uint16_t *addr); 52 static uint32_t pci_axq_hack_get32(ddi_acc_impl_t *handle, uint32_t *addr); 53 static uint64_t pci_axq_hack_get64(ddi_acc_impl_t *handle, uint64_t *addr); 54 static void pci_axq_hack_put8(ddi_acc_impl_t *handle, uint8_t *addr, 55 uint8_t data); 56 static void pci_axq_hack_put16(ddi_acc_impl_t *handle, uint16_t *addr, 57 uint16_t data); 58 static void pci_axq_hack_put32(ddi_acc_impl_t *handle, uint32_t *addr, 59 uint32_t data); 60 static void pci_axq_hack_put64(ddi_acc_impl_t *handle, uint64_t *addr, 61 uint64_t data); 62 static void pci_axq_hack_rep_get8(ddi_acc_impl_t *handle, 63 uint8_t *host_addr, uint8_t *dev_addr, 64 size_t repcount, uint_t flags); 65 static void pci_axq_hack_rep_get16(ddi_acc_impl_t *handle, 66 uint16_t *host_addr, uint16_t *dev_addr, 67 size_t repcount, uint_t flags); 68 static void pci_axq_hack_rep_get32(ddi_acc_impl_t *handle, 69 uint32_t *host_addr, uint32_t *dev_addr, 70 size_t repcount, uint_t flags); 71 static void pci_axq_hack_rep_get64(ddi_acc_impl_t *handle, 72 uint64_t *host_addr, uint64_t *dev_addr, 73 size_t repcount, uint_t flags); 74 static void pci_axq_hack_rep_put8(ddi_acc_impl_t *handle, 75 uint8_t *host_addr, uint8_t *dev_addr, 76 size_t repcount, uint_t flags); 77 static void pci_axq_hack_rep_put16(ddi_acc_impl_t *handle, 78 uint16_t *host_addr, uint16_t *dev_addr, 79 size_t repcount, uint_t flags); 80 static void pci_axq_hack_rep_put32(ddi_acc_impl_t *handle, 81 uint32_t *host_addr, uint32_t *dev_addr, 82 size_t repcount, uint_t flags); 83 static void pci_axq_hack_rep_put64(ddi_acc_impl_t *handle, 84 uint64_t *host_addr, uint64_t *dev_addr, 85 size_t repcount, uint_t flags); 86 87 /* 88 * On Sunfire 15k systems with AXQs less than 6.1 89 * we have to use special PIO routines that limit 90 * the number of outstanding PIOs. We setup the 91 * handle with pointers to our special functions 92 * after it has been succesfully mapped by our 93 * parent. 94 */ 95 96 void 97 pci_axq_pio_limit(pbm_t *pbm_p) 98 { 99 pci_t *pci_p = pbm_p->pbm_pci_p; 100 dev_info_t *dip = pci_p->pci_dip; 101 int (*axq_pio_workaround)(dev_info_t *) = NULL; 102 103 axq_pio_workaround = 104 (int (*)(dev_info_t *)) modgetsymvalue( 105 "starcat_axq_pio_workaround", 0); 106 107 if (axq_pio_workaround) { 108 pbm_p->pbm_pio_limit = (axq_pio_workaround)(dip); 109 pbm_p->pbm_pio_counter = pbm_p->pbm_pio_limit; 110 } else 111 pbm_p->pbm_pio_limit = 0; 112 } 113 114 void 115 pci_axq_setup(ddi_map_req_t *mp, pbm_t *pbm_p) 116 { 117 ddi_acc_hdl_t *hp; 118 ddi_acc_impl_t *ap; 119 120 if (mp->map_op != DDI_MO_MAP_LOCKED) 121 return; 122 if (!pbm_p->pbm_pio_limit) 123 return; 124 125 hp = (ddi_acc_hdl_t *)mp->map_handlep; 126 ap = (ddi_acc_impl_t *)hp->ah_platform_private; 127 128 ap->ahi_get8 = pci_axq_hack_get8; 129 ap->ahi_get16 = pci_axq_hack_get16; 130 ap->ahi_get32 = pci_axq_hack_get32; 131 ap->ahi_get64 = pci_axq_hack_get64; 132 ap->ahi_put8 = pci_axq_hack_put8; 133 ap->ahi_put16 = pci_axq_hack_put16; 134 ap->ahi_put32 = pci_axq_hack_put32; 135 ap->ahi_put64 = pci_axq_hack_put64; 136 ap->ahi_rep_get8 = pci_axq_hack_rep_get8; 137 ap->ahi_rep_get16 = pci_axq_hack_rep_get16; 138 ap->ahi_rep_get32 = pci_axq_hack_rep_get32; 139 ap->ahi_rep_get64 = pci_axq_hack_rep_get64; 140 ap->ahi_rep_put8 = pci_axq_hack_rep_put8; 141 ap->ahi_rep_put16 = pci_axq_hack_rep_put16; 142 ap->ahi_rep_put32 = pci_axq_hack_rep_put32; 143 ap->ahi_rep_put64 = pci_axq_hack_rep_put64; 144 145 hp->ah_bus_private = (void *)pbm_p; 146 } 147 148 /* 149 * get/put routines for SunFire 15K systems that have AXQ versions 150 * less than 6.1. These routines limit the number of outsanding 151 * PIOs issues across a PCI Bus. 152 */ 153 static uint8_t 154 pci_axq_hack_get8(ddi_acc_impl_t *handle, uint8_t *addr) 155 { 156 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 157 uint8_t data; 158 uint32_t spl; 159 160 spl = ddi_enter_critical(); 161 PIO_LIMIT_ENTER(pbm_p); 162 data = i_ddi_get8(handle, addr); 163 PIO_LIMIT_EXIT(pbm_p); 164 ddi_exit_critical(spl); 165 166 return (data); 167 } 168 169 static uint16_t 170 pci_axq_hack_get16(ddi_acc_impl_t *handle, uint16_t *addr) 171 { 172 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 173 uint16_t data; 174 uint32_t spl; 175 176 spl = ddi_enter_critical(); 177 PIO_LIMIT_ENTER(pbm_p); 178 data = i_ddi_swap_get16(handle, addr); 179 PIO_LIMIT_EXIT(pbm_p); 180 ddi_exit_critical(spl); 181 182 return (data); 183 } 184 185 static uint32_t 186 pci_axq_hack_get32(ddi_acc_impl_t *handle, uint32_t *addr) 187 { 188 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 189 uint32_t data; 190 uint32_t spl; 191 192 spl = ddi_enter_critical(); 193 PIO_LIMIT_ENTER(pbm_p); 194 data = i_ddi_swap_get32(handle, addr); 195 PIO_LIMIT_EXIT(pbm_p); 196 ddi_exit_critical(spl); 197 198 return (data); 199 } 200 201 static uint64_t 202 pci_axq_hack_get64(ddi_acc_impl_t *handle, uint64_t *addr) 203 { 204 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 205 uint64_t data; 206 uint32_t spl; 207 208 spl = ddi_enter_critical(); 209 PIO_LIMIT_ENTER(pbm_p); 210 data = i_ddi_swap_get64(handle, addr); 211 PIO_LIMIT_EXIT(pbm_p); 212 ddi_exit_critical(spl); 213 214 return (data); 215 } 216 217 static void 218 pci_axq_hack_put8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t data) 219 { 220 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 221 uint32_t spl; 222 223 spl = ddi_enter_critical(); 224 PIO_LIMIT_ENTER(pbm_p); 225 i_ddi_put8(handle, addr, data); 226 membar_sync(); 227 PIO_LIMIT_EXIT(pbm_p); 228 ddi_exit_critical(spl); 229 } 230 231 static void 232 pci_axq_hack_put16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t data) 233 { 234 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 235 uint32_t spl; 236 237 spl = ddi_enter_critical(); 238 PIO_LIMIT_ENTER(pbm_p); 239 i_ddi_swap_put16(handle, addr, data); 240 membar_sync(); 241 PIO_LIMIT_EXIT(pbm_p); 242 ddi_exit_critical(spl); 243 } 244 245 static void 246 pci_axq_hack_put32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t data) 247 { 248 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 249 uint32_t spl; 250 251 spl = ddi_enter_critical(); 252 PIO_LIMIT_ENTER(pbm_p); 253 i_ddi_swap_put32(handle, addr, data); 254 membar_sync(); 255 PIO_LIMIT_EXIT(pbm_p); 256 ddi_exit_critical(spl); 257 } 258 259 static void 260 pci_axq_hack_put64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t data) 261 { 262 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 263 uint32_t spl; 264 265 spl = ddi_enter_critical(); 266 PIO_LIMIT_ENTER(pbm_p); 267 i_ddi_swap_put64(handle, addr, data); 268 membar_sync(); 269 PIO_LIMIT_EXIT(pbm_p); 270 ddi_exit_critical(spl); 271 } 272 273 static void 274 pci_axq_hack_rep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, 275 uint8_t *dev_addr, size_t repcount, uint_t flags) 276 { 277 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 278 uint32_t spl; 279 280 spl = ddi_enter_critical(); 281 PIO_LIMIT_ENTER(pbm_p); 282 i_ddi_rep_get8(handle, host_addr, dev_addr, repcount, flags); 283 PIO_LIMIT_EXIT(pbm_p); 284 ddi_exit_critical(spl); 285 } 286 287 static void 288 pci_axq_hack_rep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, 289 uint16_t *dev_addr, size_t repcount, uint_t flags) 290 { 291 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 292 uint32_t spl; 293 294 spl = ddi_enter_critical(); 295 PIO_LIMIT_ENTER(pbm_p); 296 i_ddi_swap_rep_get16(handle, host_addr, dev_addr, repcount, flags); 297 PIO_LIMIT_EXIT(pbm_p); 298 ddi_exit_critical(spl); 299 } 300 301 static void 302 pci_axq_hack_rep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, 303 uint32_t *dev_addr, size_t repcount, uint_t flags) 304 { 305 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 306 uint32_t spl; 307 308 spl = ddi_enter_critical(); 309 PIO_LIMIT_ENTER(pbm_p); 310 i_ddi_swap_rep_get32(handle, host_addr, dev_addr, repcount, flags); 311 PIO_LIMIT_EXIT(pbm_p); 312 ddi_exit_critical(spl); 313 } 314 315 static void 316 pci_axq_hack_rep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, 317 uint64_t *dev_addr, size_t repcount, uint_t flags) 318 { 319 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 320 uint32_t spl; 321 322 spl = ddi_enter_critical(); 323 PIO_LIMIT_ENTER(pbm_p); 324 i_ddi_swap_rep_get64(handle, host_addr, dev_addr, repcount, flags); 325 PIO_LIMIT_EXIT(pbm_p); 326 ddi_exit_critical(spl); 327 } 328 329 static void 330 pci_axq_hack_rep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, 331 uint8_t *dev_addr, size_t repcount, uint_t flags) 332 { 333 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 334 uint32_t spl; 335 336 spl = ddi_enter_critical(); 337 PIO_LIMIT_ENTER(pbm_p); 338 while (repcount--) { 339 i_ddi_put8(handle, dev_addr, *host_addr); 340 membar_sync(); 341 if (flags == DDI_DEV_AUTOINCR) 342 dev_addr++; 343 host_addr++; 344 } 345 PIO_LIMIT_EXIT(pbm_p); 346 ddi_exit_critical(spl); 347 } 348 349 static void 350 pci_axq_hack_rep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, 351 uint16_t *dev_addr, size_t repcount, uint_t flags) 352 { 353 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 354 uint32_t spl; 355 356 spl = ddi_enter_critical(); 357 PIO_LIMIT_ENTER(pbm_p); 358 while (repcount--) { 359 i_ddi_put16(handle, dev_addr, *host_addr); 360 membar_sync(); 361 if (flags == DDI_DEV_AUTOINCR) 362 dev_addr++; 363 host_addr++; 364 } 365 PIO_LIMIT_EXIT(pbm_p); 366 ddi_exit_critical(spl); 367 } 368 369 static void 370 pci_axq_hack_rep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, 371 uint32_t *dev_addr, size_t repcount, uint_t flags) 372 { 373 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 374 uint32_t spl; 375 376 spl = ddi_enter_critical(); 377 PIO_LIMIT_ENTER(pbm_p); 378 while (repcount--) { 379 i_ddi_put32(handle, dev_addr, *host_addr); 380 membar_sync(); 381 if (flags == DDI_DEV_AUTOINCR) 382 dev_addr++; 383 host_addr++; 384 } 385 PIO_LIMIT_EXIT(pbm_p); 386 ddi_exit_critical(spl); 387 } 388 static void 389 pci_axq_hack_rep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, 390 uint64_t *dev_addr, size_t repcount, uint_t flags) 391 { 392 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; 393 uint32_t spl; 394 395 spl = ddi_enter_critical(); 396 PIO_LIMIT_ENTER(pbm_p); 397 while (repcount--) { 398 i_ddi_put64(handle, dev_addr, *host_addr); 399 membar_sync(); 400 if (flags == DDI_DEV_AUTOINCR) 401 dev_addr++; 402 host_addr++; 403 } 404 PIO_LIMIT_EXIT(pbm_p); 405 ddi_exit_critical(spl); 406 } 407