/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * PCI nexus driver interface */ #include #include /* nulldev */ #include /* devctl */ #include #include /* ecc_flt for pci_ecc.h */ #include #include #include #include #include #include #include #include #include #include /*LINTLIBRARY*/ static uint8_t pci_axq_hack_get8(ddi_acc_impl_t *handle, uint8_t *addr); static uint16_t pci_axq_hack_get16(ddi_acc_impl_t *handle, uint16_t *addr); static uint32_t pci_axq_hack_get32(ddi_acc_impl_t *handle, uint32_t *addr); static uint64_t pci_axq_hack_get64(ddi_acc_impl_t *handle, uint64_t *addr); static void pci_axq_hack_put8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t data); static void pci_axq_hack_put16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t data); static void pci_axq_hack_put32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t data); static void pci_axq_hack_put64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t data); static void pci_axq_hack_rep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, size_t repcount, uint_t flags); static void pci_axq_hack_rep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, uint16_t *dev_addr, size_t repcount, uint_t flags); static void pci_axq_hack_rep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, uint32_t *dev_addr, size_t repcount, uint_t flags); static void pci_axq_hack_rep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, uint64_t *dev_addr, size_t repcount, uint_t flags); static void pci_axq_hack_rep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, size_t repcount, uint_t flags); static void pci_axq_hack_rep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, uint16_t *dev_addr, size_t repcount, uint_t flags); static void pci_axq_hack_rep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, uint32_t *dev_addr, size_t repcount, uint_t flags); static void pci_axq_hack_rep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, uint64_t *dev_addr, size_t repcount, uint_t flags); /* * On Sunfire 15k systems with AXQs less than 6.1 * we have to use special PIO routines that limit * the number of outstanding PIOs. We setup the * handle with pointers to our special functions * after it has been succesfully mapped by our * parent. */ void pci_axq_pio_limit(pbm_t *pbm_p) { pci_t *pci_p = pbm_p->pbm_pci_p; dev_info_t *dip = pci_p->pci_dip; int (*axq_pio_workaround)(dev_info_t *) = NULL; axq_pio_workaround = (int (*)(dev_info_t *)) modgetsymvalue( "starcat_axq_pio_workaround", 0); if (axq_pio_workaround) { pbm_p->pbm_pio_limit = (axq_pio_workaround)(dip); pbm_p->pbm_pio_counter = pbm_p->pbm_pio_limit; } else pbm_p->pbm_pio_limit = 0; } void pci_axq_setup(ddi_map_req_t *mp, pbm_t *pbm_p) { ddi_acc_hdl_t *hp; ddi_acc_impl_t *ap; if (mp->map_op != DDI_MO_MAP_LOCKED) return; if (!pbm_p->pbm_pio_limit) return; hp = (ddi_acc_hdl_t *)mp->map_handlep; ap = (ddi_acc_impl_t *)hp->ah_platform_private; ap->ahi_get8 = pci_axq_hack_get8; ap->ahi_get16 = pci_axq_hack_get16; ap->ahi_get32 = pci_axq_hack_get32; ap->ahi_get64 = pci_axq_hack_get64; ap->ahi_put8 = pci_axq_hack_put8; ap->ahi_put16 = pci_axq_hack_put16; ap->ahi_put32 = pci_axq_hack_put32; ap->ahi_put64 = pci_axq_hack_put64; ap->ahi_rep_get8 = pci_axq_hack_rep_get8; ap->ahi_rep_get16 = pci_axq_hack_rep_get16; ap->ahi_rep_get32 = pci_axq_hack_rep_get32; ap->ahi_rep_get64 = pci_axq_hack_rep_get64; ap->ahi_rep_put8 = pci_axq_hack_rep_put8; ap->ahi_rep_put16 = pci_axq_hack_rep_put16; ap->ahi_rep_put32 = pci_axq_hack_rep_put32; ap->ahi_rep_put64 = pci_axq_hack_rep_put64; hp->ah_bus_private = (void *)pbm_p; } /* * get/put routines for SunFire 15K systems that have AXQ versions * less than 6.1. These routines limit the number of outsanding * PIOs issues across a PCI Bus. */ static uint8_t pci_axq_hack_get8(ddi_acc_impl_t *handle, uint8_t *addr) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint8_t data; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); data = i_ddi_get8(handle, addr); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); return (data); } static uint16_t pci_axq_hack_get16(ddi_acc_impl_t *handle, uint16_t *addr) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint16_t data; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); data = i_ddi_swap_get16(handle, addr); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); return (data); } static uint32_t pci_axq_hack_get32(ddi_acc_impl_t *handle, uint32_t *addr) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t data; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); data = i_ddi_swap_get32(handle, addr); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); return (data); } static uint64_t pci_axq_hack_get64(ddi_acc_impl_t *handle, uint64_t *addr) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint64_t data; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); data = i_ddi_swap_get64(handle, addr); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); return (data); } static void pci_axq_hack_put8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t data) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_put8(handle, addr, data); membar_sync(); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_put16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t data) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_swap_put16(handle, addr, data); membar_sync(); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_put32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t data) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_swap_put32(handle, addr, data); membar_sync(); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_put64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t data) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_swap_put64(handle, addr, data); membar_sync(); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_rep_get8(handle, host_addr, dev_addr, repcount, flags); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, uint16_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_swap_rep_get16(handle, host_addr, dev_addr, repcount, flags); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, uint32_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_swap_rep_get32(handle, host_addr, dev_addr, repcount, flags); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, uint64_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); i_ddi_swap_rep_get64(handle, host_addr, dev_addr, repcount, flags); PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); while (repcount--) { i_ddi_put8(handle, dev_addr, *host_addr); membar_sync(); if (flags == DDI_DEV_AUTOINCR) dev_addr++; host_addr++; } PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, uint16_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); while (repcount--) { i_ddi_put16(handle, dev_addr, *host_addr); membar_sync(); if (flags == DDI_DEV_AUTOINCR) dev_addr++; host_addr++; } PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, uint32_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); while (repcount--) { i_ddi_put32(handle, dev_addr, *host_addr); membar_sync(); if (flags == DDI_DEV_AUTOINCR) dev_addr++; host_addr++; } PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); } static void pci_axq_hack_rep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, uint64_t *dev_addr, size_t repcount, uint_t flags) { pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private; uint32_t spl; spl = ddi_enter_critical(); PIO_LIMIT_ENTER(pbm_p); while (repcount--) { i_ddi_put64(handle, dev_addr, *host_addr); membar_sync(); if (flags == DDI_DEV_AUTOINCR) dev_addr++; host_addr++; } PIO_LIMIT_EXIT(pbm_p); ddi_exit_critical(spl); }