summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4u/io/pci/pcix.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/sun4u/io/pci/pcix.c')
-rw-r--r--usr/src/uts/sun4u/io/pci/pcix.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/usr/src/uts/sun4u/io/pci/pcix.c b/usr/src/uts/sun4u/io/pci/pcix.c
new file mode 100644
index 0000000000..47ad7fa236
--- /dev/null
+++ b/usr/src/uts/sun4u/io/pci/pcix.c
@@ -0,0 +1,111 @@
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/async.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/ddi_implfuncs.h>
+#include <sys/pci/pci_obj.h>
+#include <sys/pci.h>
+
+/*LINTLIBRARY*/
+
+static uint16_t
+pcix_get_pcix_cap(ddi_acc_handle_t handle)
+{
+ ushort_t caps_ptr, cap;
+
+ /*
+ * Walk the Capabilities List and locate
+ * the PCI-X Capability.
+ */
+ if (pci_config_get16(handle, PCI_CONF_STAT) & PCI_STAT_CAP)
+ caps_ptr = pci_config_get8(handle, PCI_CONF_CAP_PTR);
+ else
+ caps_ptr = PCI_CAP_NEXT_PTR_NULL;
+
+ while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
+ cap = pci_config_get8(handle, caps_ptr);
+ if (cap == PCI_CAP_ID_PCIX)
+ return (caps_ptr);
+
+ caps_ptr = pci_config_get8(handle, caps_ptr + PCI_CAP_NEXT_PTR);
+ }
+
+ return (0);
+}
+
+void
+pcix_set_cmd_reg(dev_info_t *child, uint16_t value)
+{
+ uint16_t pcix_cap_offset, pcix_cmd;
+ ddi_acc_handle_t handle;
+
+ if (pci_config_setup(child, &handle) != DDI_SUCCESS)
+ return;
+
+ /*
+ * Only modify the Command Register of non-bridge functions.
+ */
+ if ((pci_config_get8(handle, PCI_CONF_HEADER) &
+ PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+ pci_config_teardown(&handle);
+ return;
+ }
+
+ pcix_cap_offset = pcix_get_pcix_cap(handle);
+
+ DEBUG1(DBG_INIT_CLD, child,
+ "pcix_set_cmd_reg: pcix_cap_offset = %x\n", pcix_cap_offset);
+
+ if (pcix_cap_offset) {
+ /*
+ * Read the PCI-X Command Register.
+ */
+ pcix_cmd = pci_config_get16(handle, (pcix_cap_offset + 2));
+
+ DEBUG1(DBG_INIT_CLD, child,
+ "pcix_set_cmd_reg: PCI-X CMD "
+ "Register (Before) %x\n", pcix_cmd);
+
+ pcix_cmd &= ~(0x1f << 2); /* clear bits 6-2 */
+ pcix_cmd |= value;
+
+ DEBUG1(DBG_INIT_CLD, child,
+ "pcix_set_cmd_reg: PCI-X CMD "
+ "Register (After) %x\n", pcix_cmd);
+
+ pci_config_put16(handle, (pcix_cap_offset + 2), pcix_cmd);
+ }
+
+ pci_config_teardown(&handle);
+}