summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorschwartz <none@none>2007-06-06 13:05:49 -0700
committerschwartz <none@none>2007-06-06 13:05:49 -0700
commit2917a9c9c3eee6fcaedb239f5f68da01f4ed0da9 (patch)
tree3f14bba948390bf71a80d57812d56948c29c8bd6 /usr/src
parentc4e3866948e749beb3671a51c589da2ba299dc03 (diff)
downloadillumos-gate-2917a9c9c3eee6fcaedb239f5f68da01f4ed0da9.tar.gz
PSARC/2007/301 PCItool extensions for handling groups of interrupt vectors
PSARC/2007/302 PSM_INTR_OPS extensions for handling groups of interrupt vectors 6458838 Once intrd performs reassignment, MSI interrupts stop coming 6564773 Cleanup pcitool versioning 6565502 apic_rebind could write IOAPIC for fixed interrupts
Diffstat (limited to 'usr/src')
-rwxr-xr-xusr/src/cmd/intrd/intrd.pl106
-rw-r--r--usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.pm11
-rw-r--r--usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.xs63
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c144
-rw-r--r--usr/src/uts/common/sys/pci_tools.h55
-rw-r--r--usr/src/uts/i86pc/io/mp_platform_common.c73
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_common.c17
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_kstats.c32
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_tools.c117
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic.c10
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic_introp.c432
-rw-r--r--usr/src/uts/i86pc/sys/apic.h6
-rw-r--r--usr/src/uts/i86pc/sys/apic_ctlr.h46
-rw-r--r--usr/src/uts/i86pc/sys/psm_types.h4
-rw-r--r--usr/src/uts/sun4/io/px/px_devctl.c4
-rw-r--r--usr/src/uts/sun4/io/px/px_intr.c20
-rw-r--r--usr/src/uts/sun4/io/px/px_tools.c71
-rw-r--r--usr/src/uts/sun4u/chicago/io/fpc/fpc-impl-4u.c10
-rw-r--r--usr/src/uts/sun4u/io/pci/pci_devctl.c9
-rw-r--r--usr/src/uts/sun4u/io/pci/pci_tools.c79
-rw-r--r--usr/src/uts/sun4u/io/px/px_tools_4u.c1
-rw-r--r--usr/src/uts/sun4v/io/px/px_tools_4v.c3
22 files changed, 931 insertions, 382 deletions
diff --git a/usr/src/cmd/intrd/intrd.pl b/usr/src/cmd/intrd/intrd.pl
index 0c47a647bd..89692891e5 100755
--- a/usr/src/cmd/intrd/intrd.pl
+++ b/usr/src/cmd/intrd/intrd.pl
@@ -21,7 +21,7 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -68,7 +68,7 @@ while ($_ = shift @ARGV) {
if ($using_scengen == 0) {
require Sun::Solaris::Kstat;
require Sun::Solaris::Intrs;
- import Sun::Solaris::Intrs(qw(intrmove));
+ import Sun::Solaris::Intrs(qw(intrmove is_pcplusmp));
require Sys::Syslog;
import Sys::Syslog;
openlog($cmdname, 'pid', 'daemon');
@@ -76,7 +76,6 @@ if ($using_scengen == 0) {
&Sys::Syslog::LOG_INFO));
}
-
my $asserted = 0;
my $assert_level = 'debug'; # syslog level for assertion failures
sub VERIFY($@)
@@ -93,7 +92,7 @@ sub VERIFY($@)
-sub getstat($);
+sub getstat($$);
sub generate_delta($$);
sub compress_deltas($);
sub dumpdelta($);
@@ -142,19 +141,25 @@ sub do_reconfig_cpu($$$); # private function
# ->{"pil"} == pci_intrs:<ivec#>:<nexus>:pil
# ->{"crtime"} == pci_intrs:<ivec#>:<nexus>:crtime
# ->{"ino"} == pci_intrs:<ivec#>:<nexus>:ino
+# ->{"num_ino"} == num inos of single device instance sharing this entry
+# Will be > 1 on pcplusmp X86 systems for devices
+# with multiple MSI interrupts.
# ->{"buspath"} == pci_intrs:<ivec#>:<nexus>:buspath
# ->{"name"} == pci_intrs:<ivec#>:<nexus>:name
# ->{"ihs"} == pci_intrs:<ivec#>:<nexus>:ihs
#
-sub getstat($)
+sub getstat($$)
{
- my ($ks) = @_;
+ my ($ks, $pcplusmp_sys) = @_;
my $cpucnt = 0;
my %stat = ();
my ($minsnap, $maxsnap);
+ # Hash of hash which matches (MSI device, ino) combos to kstats.
+ my %msidevs = ();
+
# kstats are not generated atomically. Each kstat hierarchy will
# have been generated within the kernel at a different time. On a
# thrashing system, we may not run quickly enough in order to get
@@ -177,6 +182,8 @@ sub getstat($)
while (my ($cpu, $cpst) = each %{$ks->{cpu}}) {
next if !exists($ks->{cpu_info}{$cpu}{"cpu_info$cpu"}{state});
+ #"state" fld of kstat w/
+ # modname inst name-"cpuinfo0"
my $state = $ks->{cpu_info}{$cpu}{"cpu_info$cpu"}{state};
next if ($state !~ /^on-line\0/);
my $cpu_sys = $cpst->{sys};
@@ -214,6 +221,10 @@ sub getstat($)
next unless exists $stat{$cpu};
next if ($intrcfg->{type} =~ /^disabled\0/);
+ # Perl looks beyond NULL chars in pattern matching.
+ # Truncate name field at the first NULL
+ $intrcfg->{name} =~ s/\0.*$//;
+
if ($intrcfg->{snaptime} < $minsnap) {
$minsnap = $intrcfg->{snaptime};
} elsif ($intrcfg->{snaptime} > $maxsnap) {
@@ -242,9 +253,62 @@ sub getstat($)
$stat{$cpu}{ivecs}{$cookie}{crtime} = $intrcfg->{crtime};
$stat{$cpu}{ivecs}{$cookie}{pil} = $intrcfg->{pil};
$stat{$cpu}{ivecs}{$cookie}{ino} = $intrcfg->{ino};
+ $stat{$cpu}{ivecs}{$cookie}{num_ino} = 1;
$stat{$cpu}{ivecs}{$cookie}{buspath} = $intrcfg->{buspath};
$stat{$cpu}{ivecs}{$cookie}{name} = $intrcfg->{name};
$stat{$cpu}{ivecs}{$cookie}{ihs} = 1;
+
+ if ($pcplusmp_sys && ($intrcfg->{type} =~ /^msi\0/)) {
+ if (!(exists($msidevs{$intrcfg->{name}}))) {
+ $msidevs{$intrcfg->{name}} = {};
+ }
+ $msidevs{$intrcfg->{name}}{$intrcfg->{ino}} =
+ \$stat{$cpu}{ivecs}{$cookie};
+ }
+ }
+
+ # All MSI interrupts of a device instance share a single MSI address.
+ # On X86 systems with an APIC, this MSI address is interpreted as CPU
+ # routing info by the APIC. For this reason, on these platforms, all
+ # interrupts for MSI devices must be moved to the same CPU at the same
+ # time.
+ #
+ # Since all interrupts will be on the same CPU on these platforms, all
+ # interrupts can be consolidated into one ivec entry. For such devices,
+ # num_ino will be > 1 to denote that a group move is needed.
+
+ # Loop thru all MSI devices on X86 pcplusmp systems.
+ # Nop on other systems.
+ foreach my $msidevkey (sort keys %msidevs) {
+
+ # Loop thru inos of the device, sorted by lowest value first
+ # For each cookie found for a device, incr num_ino for the
+ # lowest cookie and remove other cookies.
+
+ # Assumes PIL is the same for first and current cookies
+
+ my $first_ino = -1;
+ my $first_cookiep;
+ my $curr_cookiep;
+ foreach my $inokey (sort keys %{$msidevs{$msidevkey}}) {
+ $curr_cookiep = $msidevs{$msidevkey}{$inokey};
+ if ($first_ino == -1) {
+ $first_ino = $inokey;
+ $first_cookiep = $curr_cookiep;
+ } else {
+ $$first_cookiep->{num_ino}++;
+ $$first_cookiep->{time} +=
+ $$curr_cookiep->{time};
+ if ($$curr_cookiep->{crtime} >
+ $$first_cookiep->{crtime}) {
+ $$first_cookiep->{crtime} =
+ $$curr_cookiep->{crtime};
+ }
+ # Invalidate this cookie, less complicated and
+ # more efficient than deleting it.
+ $$curr_cookiep->{num_ino} = 0;
+ }
+ }
}
# We define the timerange as the amount of time spent gathering the
@@ -287,10 +351,11 @@ sub getstat($)
# ->{<ivec#>} iterates over ivecs for this cpu
# ->{"time"} time used by this interrupt (in nsec)
# ->{"pil"} pil level of this interrupt
-# ->{"ino"} interrupt number
+# ->{"ino"} interrupt number (or base vector if MSI group)
# ->{"buspath"} filename of the directory of the device's bus
# ->{"name"} device name
# ->{"ihs"} number of different handlers sharing this ino
+# ->{"num_ino"} number of interrupt vectors in MSI group
#
# It prints out the delta structure in a nice, human readable display.
#
@@ -403,9 +468,14 @@ sub generate_delta($$)
}
while (my ($inum, $newivec) = each %{$newcpst->{ivecs}}) {
+
+ # Unused cookie, corresponding to an MSI vector which
+ # is part of a group. The whole group is accounted for
+ # by a different cookie.
+ next if ($newivec->{num_ino} == 0);
+
# If this ivec doesn't exist in $stat, or if $stat
# shows a different crtime, set missing.
-
if (VERIFY(exists $cpst->{ivecs}{$inum} &&
$cpst->{ivecs}{$inum}{crtime} ==
$newivec->{crtime},
@@ -446,6 +516,7 @@ sub generate_delta($$)
$dltivec{buspath} = $newivec->{buspath};
$dltivec{name} = $newivec->{name};
$dltivec{ihs} = $newivec->{ihs};
+ $dltivec{num_ino} = $newivec->{num_ino};
}
if ($delta{$cpu}{tot} < $delta{$cpu}{intrs}) {
# Ewww! Hopefully just a rounding error.
@@ -517,6 +588,7 @@ sub compress_deltas ($)
$newivecs->{$inum}{buspath} = $ivec->{buspath};
$newivecs->{$inum}{name} = $ivec->{name};
$newivecs->{$inum}{ihs} = $ivec->{ihs};
+ $newivecs->{$inum}{num_ino} = $ivec->{num_ino};
}
}
}
@@ -868,7 +940,7 @@ sub do_reconfig($)
next if ($ivec->{origcpu} == $cpuid);
if (!intrmove($ivec->{buspath}, $ivec->{ino},
- $cpuid)) {
+ $cpuid, $ivec->{num_ino})) {
syslog('warning', "Unable to move interrupts")
if $warned++ == 0;
syslog('debug', "Unable to move buspath ".
@@ -1195,9 +1267,20 @@ if (!exists($ks->{pci_intrs})) {
exit 0;
}
-my $stat = getstat($ks);
+# See if this is a system with a pcplusmp APIC.
+# Such systems will get special handling.
+# Assume that if one bus has a pcplusmp APIC that they all do.
+# Get a list of pci_intrs kstats.
+my @elem = values(%{$ks->{pci_intrs}});
+my $elem0 = $elem[0];
+my $elemval = (values(%$elem0))[0];
+# Use its buspath to query the system. It is assumed that either all or none
+# of the busses on a system are hosted by the pcplusmp APIC.
+my $pcplusmp_sys = is_pcplusmp($elemval->{buspath});
+
+my $stat = getstat($ks, $pcplusmp_sys);
for (;;) {
sub clear_deltas {
@@ -1216,7 +1299,7 @@ for (;;) {
} else {
$ks = myks_update();
}
- $newstat = getstat($ks);
+ $newstat = getstat($ks, $pcplusmp_sys);
# $stat or $newstat could be zero if they're uninitialized, or if
# getstat() failed. If $stat is zero, move $newstat to $stat, sleep
@@ -1229,7 +1312,6 @@ for (;;) {
next;
}
-
# 2. Compare $newstat with the prior set of values, result in %$delta.
$delta = generate_delta($stat, $newstat);
diff --git a/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.pm b/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.pm
index 15dc274dd4..98cd3353b1 100644
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.pm
+++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.pm
@@ -1,9 +1,8 @@
# 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.
+# Common Development and Distribution License (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.
@@ -19,7 +18,7 @@
# CDDL HEADER END
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -36,8 +35,8 @@ use DynaLoader;
use vars qw($VERSION @ISA @EXPORT_OK);
our @ISA = qw(Exporter DynaLoader);
-our @EXPORT_OK = qw(intrmove);
-our $VERSION = '0.01';
+our @EXPORT_OK = qw(intrmove is_pcplusmp);
+our $VERSION = '0.02';
bootstrap Sun::Solaris::Intrs $VERSION;
1;
diff --git a/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.xs b/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.xs
index 0c2da8c480..0d563b7d5e 100644
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.xs
+++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Intrs/Intrs.xs
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,39 +42,70 @@
#include "perl.h"
#include "XSUB.h"
+static int
+open_dev(char *path)
+{
+ char intrpath[MAXPATHLEN];
+
+ (void) strcpy(intrpath, "/devices");
+ (void) strcat(intrpath, path);
+ (void) strcat(intrpath, ":intr");
+ return (open(intrpath, O_RDWR));
+}
+
MODULE = Sun::Solaris::Intrs PACKAGE = Sun::Solaris::Intrs
PROTOTYPES: ENABLE
int
-intrmove(path, ino, cpu)
+intrmove(path, ino, cpu, num_ino)
char *path
int ino
int cpu
+ int num_ino
INIT:
- int i, ret;
+ int fd, ret;
pcitool_intr_set_t iset;
- static int fd = -1;
- static char intrpath[MAXPATHLEN];
CODE:
- if (fd == -1 || strcmp(path, intrpath)) {
- (void) strcpy(intrpath, "/devices");
- (void) strcat(intrpath, path);
- (void) strcat(intrpath, ":intr");
- if (fd != -1)
- (void) close(fd);
- fd = open(intrpath, O_RDONLY);
- if (fd == -1) {
- XSRETURN_UNDEF;
- }
+ if ((fd = open_dev(path)) == -1) {
+ XSRETURN_UNDEF;
}
iset.ino = ino;
iset.cpu_id = cpu;
- iset.user_version = PCITOOL_USER_VERSION;
+ iset.flags = (num_ino > 1) ? PCITOOL_INTR_SET_FLAG_GROUP : 0;
+ iset.user_version = PCITOOL_VERSION;
ret = ioctl(fd, PCITOOL_DEVICE_SET_INTR, &iset);
if (ret == -1) {
XSRETURN_UNDEF;
}
+ (void) close(fd);
XSRETURN_YES;
+
+int
+is_pcplusmp(path)
+ char *path
+
+ INIT:
+ int fd, ret;
+ pcitool_intr_info_t iinfo;
+
+ CODE:
+ if ((fd = open_dev(path)) == -1) {
+ XSRETURN_UNDEF;
+ }
+ iinfo.user_version = PCITOOL_VERSION;
+
+ ret = ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &iinfo);
+ (void) close(fd);
+
+ if (ret == -1) {
+ XSRETURN_UNDEF;
+ }
+
+ if (iinfo.ctlr_type == PCITOOL_CTLR_TYPE_PCPLUSMP) {
+ XSRETURN_YES;
+ }
+
+ XSRETURN_NO;
diff --git a/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c
index 25845dd53e..34f406b109 100644
--- a/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c
+++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c
@@ -117,7 +117,7 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
(void) memset(&pci_card, 0, sizeof (pci_card));
err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME,
- piclclass, sizeof (piclclass));
+ piclclass, sizeof (piclclass));
if (err != PICL_SUCCESS)
/* Do not proceed to parse this branch */
@@ -133,7 +133,7 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
/* Do not proceed to parse this branch */
return (err);
err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board,
- sizeof (board));
+ sizeof (board));
if (err == PICL_NORESPONSE)
/* Do not proceed to parse this branch */
@@ -148,7 +148,7 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
}
err = picl_get_propval_by_name
- (pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
+ (pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
if (err != PICL_PROPNOTFOUND)
saved_portid = portid;
@@ -169,7 +169,7 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
if (IS_EBUS(piclclass)) {
err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
- &nodeh, sizeof (picl_nodehdl_t));
+ &nodeh, sizeof (picl_nodehdl_t));
continue;
}
@@ -193,7 +193,7 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
*/
err = picl_get_propinfo_by_name
- (nodeh, OBP_PROP_REG, &pinfo, &proph);
+ (nodeh, OBP_PROP_REG, &pinfo, &proph);
if (err == PICL_SUCCESS) {
/* All of the array of bytes of "reg" have to be read */
reg_val = malloc(pinfo.size);
@@ -212,27 +212,26 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
if (reg_val[0] != 0) {
pci_card.dev_no =
- (((reg_val[0]) & PCI_DEV_MASK) >> 11);
+ (((reg_val[0]) & PCI_DEV_MASK) >> 11);
pci_card.func_no =
- (((reg_val[0]) & PCI_FUNC_MASK) >> 8);
+ (((reg_val[0]) & PCI_FUNC_MASK) >> 8);
pci_card.slot =
- (((reg_val[0]) & PCI_BUS_MASK) >> 16);
+ (((reg_val[0]) & PCI_BUS_MASK) >> 16);
} else
free(reg_val);
}
- err = get_lane_width
- (root_path, pci_card.slot, pci_card.dev_no,
- pci_card.func_no, &actual, &maximum, &freq_max,
- &freq_at, &bus_type);
+ err = get_lane_width(root_path, pci_card.slot, pci_card.dev_no,
+ pci_card.func_no, &actual, &maximum, &freq_max, &freq_at,
+ &bus_type);
if (err != PICL_SUCCESS) {
/* Move on to next node */
log_printf("Getting lane width failed for path %s\n",
- pci_card.notes);
+ pci_card.notes);
err = picl_get_propval_by_name
- (nodeh, PICL_PROP_PEER, &nodeh,
- sizeof (picl_nodehdl_t));
+ (nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
continue;
}
@@ -292,29 +291,29 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
(void) strlcpy(pci_card.model, model, prop_size);
if (bus_type == PCI)
- (void) strlcpy
- (pci_card.bus_type, "PCI", sizeof (pci_card.bus_type));
+ (void) strlcpy(pci_card.bus_type,
+ "PCI", sizeof (pci_card.bus_type));
else if (bus_type == PCIX)
- (void) strlcpy
- (pci_card.bus_type, "PCIx", sizeof (pci_card.bus_type));
+ (void) strlcpy(pci_card.bus_type,
+ "PCIx", sizeof (pci_card.bus_type));
else if (bus_type == PCIE)
- (void) strlcpy
- (pci_card.bus_type, "PCIe", sizeof (pci_card.bus_type));
+ (void) strlcpy(pci_card.bus_type,
+ "PCIe", sizeof (pci_card.bus_type));
else
- (void) strlcpy
- (pci_card.bus_type, "UNKN", sizeof (pci_card.bus_type));
+ (void) strlcpy(pci_card.bus_type,
+ "UNKN", sizeof (pci_card.bus_type));
/* Get revision id */
err = picl_get_propval_by_name
- (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
+ (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
/* Get device id */
err = picl_get_propval_by_name
- (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
+ (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
/* Get vendor id */
err = picl_get_propval_by_name
- (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
+ (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
/*
* prtdiag -v prints all devices
@@ -328,9 +327,8 @@ opl_pci_callback(picl_nodehdl_t pcih, void *args)
log_printf("%-3d ", pci_card.schizo_portid);
log_printf("%4x, %4x, %4x ", rev_id, dev_id, ven_id);
- log_printf
- ("%3d, %2d, %2d",
- pci_card.slot, pci_card.dev_no, pci_card.func_no);
+ log_printf("%3d, %2d, %2d",
+ pci_card.slot, pci_card.dev_no, pci_card.func_no);
/* Print status */
log_printf(" %-5.5s ", status);
@@ -387,19 +385,19 @@ opl_display_pci(int syserrlog, picl_nodehdl_t plafh)
log_printf("\n", 0);
log_printf("\n", 0);
log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
- "", "", 0);
+ "", "", 0);
log_printf("\n", 0);
log_printf(fmt, "LSB", "Type", "LPID", " RvID,DvID,VnID",
- " BDF", "State", "Act, Max", "Name", "Model", 0);
+ " BDF", "State", "Act, Max", "Name", "Model", 0);
log_printf("\n");
- log_printf
- (fmt, "---", "-----", "----", " ------------------",
- " ---------", "-----", "-----------",
- "------------------------------",
- "--------------------", 0);
+ log_printf(fmt,
+ "---", "-----", "----", " ------------------",
+ " ---------", "-----", "-----------",
+ "------------------------------",
+ "--------------------", 0);
log_printf("\n");
log_printf(fmt2, " Logical Path");
log_printf("\n");
@@ -429,7 +427,7 @@ opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
&pinfo, &proph);
if (err != PICL_SUCCESS)
- return (err);
+ return (err);
if (pinfo.type == PICL_PTYPE_CHARSTRING) {
pval = malloc(pinfo.size);
@@ -458,7 +456,7 @@ opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
err = picl_get_propinfo(rowproph, &pinfo);
if (err != PICL_SUCCESS)
- return (err);
+ return (err);
pval = malloc(pinfo.size);
if (pval == NULL)
@@ -485,7 +483,7 @@ do_piclinfo(int syserrlog)
err = picl_initialize();
if (err != PICL_SUCCESS) {
(void) log_printf("picl_initialize failed: %s\n",
- picl_strerror(err));
+ picl_strerror(err));
return (err);
}
@@ -493,7 +491,7 @@ do_piclinfo(int syserrlog)
err = picl_get_root(&rooth);
if (err != PICL_SUCCESS) {
(void) log_printf("Getting root node failed: %s\n",
- picl_strerror(err));
+ picl_strerror(err));
return (err);
}
@@ -501,7 +499,7 @@ do_piclinfo(int syserrlog)
if (err != PICL_SUCCESS) {
(void) log_printf("Getting nodes by name failed: %s\n",
- picl_strerror(err));
+ picl_strerror(err));
return (err);
}
@@ -528,14 +526,14 @@ opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
return (PICL_FAILURE);
err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
- sizeof (picl_nodehdl_t));
+ sizeof (picl_nodehdl_t));
while (err == PICL_SUCCESS) {
err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
- nodename, (strlen(name) + 1));
+ nodename, (strlen(name) + 1));
if (err != PICL_SUCCESS) {
err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
- &childh, sizeof (picl_nodehdl_t));
+ &childh, sizeof (picl_nodehdl_t));
continue;
}
@@ -545,7 +543,7 @@ opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
}
err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
- &childh, sizeof (picl_nodehdl_t));
+ &childh, sizeof (picl_nodehdl_t));
}
return (err);
@@ -579,7 +577,7 @@ read_long(int fd, int bus, int dev, int func, int offset, int *ret)
int rval;
pcitool_reg_t prg;
- prg.user_version = PCITOOL_USER_VERSION;
+ prg.user_version = PCITOOL_VERSION;
prg.barnum = 0;
prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
PCITOOL_ACC_ATTR_ENDN_LTL;
@@ -589,10 +587,8 @@ read_long(int fd, int bus, int dev, int func, int offset, int *ret)
prg.offset = offset;
rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
if (rval != 0) {
- log_printf
- ("DEV_GET failed %d %s\n", rval, strerror(errno));
- log_printf
- ("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
+ log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
+ log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
}
*ret = rval;
return ((uint32_t)prg.data);
@@ -604,7 +600,7 @@ read_word(int fd, int bus, int dev, int func, int offset, int *ret)
int rval;
pcitool_reg_t prg;
- prg.user_version = PCITOOL_USER_VERSION;
+ prg.user_version = PCITOOL_VERSION;
prg.barnum = 0;
prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
PCITOOL_ACC_ATTR_ENDN_LTL;
@@ -614,10 +610,8 @@ read_word(int fd, int bus, int dev, int func, int offset, int *ret)
prg.offset = offset;
rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
if (rval != 0) {
- log_printf
- ("DEV_GET failed %d %s\n", rval, strerror(errno));
- log_printf
- ("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
+ log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
+ log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
}
*ret = rval;
return ((uint16_t)prg.data);
@@ -629,7 +623,7 @@ read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
int rval;
pcitool_reg_t prg;
- prg.user_version = PCITOOL_USER_VERSION;
+ prg.user_version = PCITOOL_VERSION;
prg.barnum = 0;
prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
PCITOOL_ACC_ATTR_ENDN_LTL;
@@ -639,10 +633,8 @@ read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
prg.offset = offset;
rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
if (rval != 0) {
- log_printf
- ("DEV_GET failed %d %s\n", rval, strerror(errno));
- log_printf
- ("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
+ log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
+ log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
}
*ret = rval;
return ((uint8_t)prg.data);
@@ -700,15 +692,15 @@ get_lane_width
if (ret != 0) {
return (PICL_FAILURE);
}
- link_status = read_word(fd, bus, dev, func, cap_ptr +
- PCIE_LINKSTS, &ret);
+ link_status = read_word(fd, bus, dev, func,
+ cap_ptr + PCIE_LINKSTS, &ret);
if (ret != 0) {
return (PICL_FAILURE);
}
*actual = ((link_status >> PCI_LINK_SHIFT) &
- PCI_LINK_MASK);
+ PCI_LINK_MASK);
*maximum = ((link_cap >> PCI_LINK_SHIFT) &
- PCI_LINK_MASK);
+ PCI_LINK_MASK);
*type = PCIE;
}
if (capid == PCI_CAP_ID_PCIX) {
@@ -717,7 +709,7 @@ get_lane_width
int max_speed = PCI_FREQ_66;
hdr_type = read_byte
- (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
+ (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
if (ret != 0) {
/* ioctl failure */
return (PICL_FAILURE);
@@ -726,7 +718,7 @@ get_lane_width
/* This is a PCI-X bridge */
uint16_t sec_status, mode;
sec_status = read_word(fd, bus, dev, func,
- cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
+ cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
if (ret != 0) {
/* ioctl failure */
return (PICL_FAILURE);
@@ -739,8 +731,8 @@ get_lane_width
max_speed = PCI_FREQ_533;
*speed_max = max_speed;
*type = PCIX;
- mode = (sec_status >> PCI_CLASS_BRIDGE)
- & PCI_BRIDGE_MC;
+ mode = (sec_status >> PCI_CLASS_BRIDGE) &
+ PCI_BRIDGE_MC;
if (mode) {
int speed;
if (mode == PCI_MODE_66)
@@ -760,13 +752,13 @@ get_lane_width
return (PICL_FAILURE);
}
if (pcix_status &
- (PCI_LEAF_ULONG << PCI_SHIFT_133))
+ (PCI_LEAF_ULONG << PCI_SHIFT_133))
max_speed = PCI_FREQ_133;
if (pcix_status &
- (PCI_LEAF_ULONG << PCI_SHIFT_266))
+ (PCI_LEAF_ULONG << PCI_SHIFT_266))
max_speed = PCI_FREQ_266;
if (pcix_status &
- (PCI_LEAF_ULONG << PCI_SHIFT_533))
+ (PCI_LEAF_ULONG << PCI_SHIFT_533))
max_speed = PCI_FREQ_533;
*speed_max = max_speed;
*type = PCI;
@@ -823,7 +815,7 @@ picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
* If it is not an int or uint prop, return failure
*/
if ((pinfo.type != PICL_PTYPE_INT) &&
- (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
*ret = PICL_FAILURE;
return (0);
}
@@ -866,21 +858,21 @@ do_walk(picl_nodehdl_t rooth, const char *classname,
char classval[PICL_CLASSNAMELEN_MAX];
err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
- sizeof (chdh));
+ sizeof (chdh));
while (err == PICL_SUCCESS) {
err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
- classval, sizeof (classval));
+ classval, sizeof (classval));
if (err != PICL_SUCCESS)
return (err);
err = callback_fn(chdh, c_args);
if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
- PICL_WALK_CONTINUE)
+ PICL_WALK_CONTINUE)
return (err);
err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
- sizeof (chdh));
+ sizeof (chdh));
}
if (err == PICL_PROPNOTFOUND) /* end of a branch */
return (PICL_WALK_CONTINUE);
diff --git a/usr/src/uts/common/sys/pci_tools.h b/usr/src/uts/common/sys/pci_tools.h
index 5e581074ef..2e9a95aa71 100644
--- a/usr/src/uts/common/sys/pci_tools.h
+++ b/usr/src/uts/common/sys/pci_tools.h
@@ -2,9 +2,8 @@
* 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.
+ * Common Development and Distribution License (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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,11 +35,11 @@ extern "C" {
#endif
/*
- * Versioning. Have different versions for userland program and drivers, so
- * they can all stay in sync with each other.
+ * Versioning.
*/
-#define PCITOOL_USER_VERSION 1
-#define PCITOOL_DRVR_VERSION 1
+#define PCITOOL_V1 1
+#define PCITOOL_V2 2
+#define PCITOOL_VERSION PCITOOL_V2
/* File suffixes for nexus pcitool nodes. */
#define PCI_MINOR_REG "reg"
@@ -52,20 +51,19 @@ extern "C" {
#define PCITOOL_IOC (('P' << 24) | ('C' << 16) | ('T' << 8))
/* Read/write a device on a PCI bus, in physical space. */
-#define PCITOOL_DEVICE_GET_REG (PCITOOL_IOC | 1)
-#define PCITOOL_DEVICE_SET_REG (PCITOOL_IOC | 2)
+#define PCITOOL_DEVICE_GET_REG (PCITOOL_IOC | 1)
+#define PCITOOL_DEVICE_SET_REG (PCITOOL_IOC | 2)
/* Read/write the PCI nexus bridge, in physical space. */
-#define PCITOOL_NEXUS_GET_REG (PCITOOL_IOC | 3)
-#define PCITOOL_NEXUS_SET_REG (PCITOOL_IOC | 4)
+#define PCITOOL_NEXUS_GET_REG (PCITOOL_IOC | 3)
+#define PCITOOL_NEXUS_SET_REG (PCITOOL_IOC | 4)
/* Get/set interrupt-CPU mapping for PCI devices. */
-#define PCITOOL_DEVICE_GET_INTR (PCITOOL_IOC | 5)
-#define PCITOOL_DEVICE_SET_INTR (PCITOOL_IOC | 6)
-
-/* Return the number of supported interrupts on a PCI bus. */
-#define PCITOOL_DEVICE_NUM_INTR (PCITOOL_IOC | 7)
+#define PCITOOL_DEVICE_GET_INTR (PCITOOL_IOC | 5)
+#define PCITOOL_DEVICE_SET_INTR (PCITOOL_IOC | 6)
+/* Get system interrupt information */
+#define PCITOOL_SYSTEM_INTR_INFO (PCITOOL_IOC | 8)
/*
* This file contains data structures for the pci tool.
@@ -131,8 +129,14 @@ typedef struct pcitool_intr_set {
uint32_t ino; /* interrupt to set - to kernel */
uint32_t cpu_id; /* to: cpu to set / from: old cpu returned */
pcitool_errno_t status; /* from kernel */
+ uint32_t flags; /* to kernel */
} pcitool_intr_set_t;
+/*
+ * flags for pcitool_intr_set_t
+ */
+#define PCITOOL_INTR_SET_FLAG_GROUP 0x1
+
/*
* PCITOOL_DEVICE_GET_INTR ioctl data structure to dump out the
@@ -145,7 +149,6 @@ typedef struct pcitool_intr_dev {
char path[MAXPATHLEN]; /* device path - from kernel */
} pcitool_intr_dev_t;
-
typedef struct pcitool_intr_get {
uint16_t user_version; /* Userland program version - to krnl */
uint16_t drvr_version; /* Driver version - from kernel */
@@ -171,6 +174,22 @@ typedef struct pcitool_intr_get {
sizeof (pcitool_intr_dev_t) + \
(num_devs * sizeof (pcitool_intr_dev_t)))
+typedef struct pcitool_intr_info {
+ uint16_t user_version; /* Userland program version - to krnl */
+ uint16_t drvr_version; /* Driver version - from kernel */
+ uint32_t num_intr; /* Number of intrs suppt by nexus */
+ uint32_t ctlr_version; /* Intr ctlr HW version - from kernel */
+ uchar_t ctlr_type; /* A PCITOOL_CTLR_TYPE - from kernel */
+} pcitool_intr_info_t;
+
+/*
+ * Interrupt controller types
+ */
+#define PCITOOL_CTLR_TYPE_UNKNOWN 0
+#define PCITOOL_CTLR_TYPE_RISC 1
+#define PCITOOL_CTLR_TYPE_UPPC 2
+#define PCITOOL_CTLR_TYPE_PCPLUSMP 3
+
/*
* Size and endian fields for acc_attr bitmask.
*/
diff --git a/usr/src/uts/i86pc/io/mp_platform_common.c b/usr/src/uts/i86pc/io/mp_platform_common.c
index acb2d0071d..1a131b619f 100644
--- a/usr/src/uts/i86pc/io/mp_platform_common.c
+++ b/usr/src/uts/i86pc/io/mp_platform_common.c
@@ -1101,6 +1101,35 @@ apic_cpu_in_range(int cpu)
return ((cpu & ~IRQ_USER_BOUND) < apic_nproc);
}
+uint16_t
+apic_get_apic_version()
+{
+ int i;
+ uchar_t min_io_apic_ver = 0;
+ static uint16_t version; /* Cache as value is constant */
+ static boolean_t found = B_FALSE; /* Accomodate zero version */
+
+ if (found == B_FALSE) {
+ found = B_TRUE;
+
+ /*
+ * Don't assume all IO APICs in the system are the same.
+ *
+ * Set to the minimum version.
+ */
+ for (i = 0; i < apic_io_max; i++) {
+ if ((apic_io_ver[i] != 0) &&
+ ((min_io_apic_ver == 0) ||
+ (min_io_apic_ver >= apic_io_ver[i])))
+ min_io_apic_ver = apic_io_ver[i];
+ }
+
+ /* Assume all local APICs are of the same version. */
+ version = (min_io_apic_ver << 8) | apic_cpus[0].aci_local_ver;
+ }
+ return (version);
+}
+
static struct apic_mpfps_hdr *
apic_find_fps_sig(caddr_t cptr, int len)
{
@@ -2766,32 +2795,36 @@ apic_rebind(apic_irq_t *irq_ptr, int bind_cpu,
return (0);
}
- }
- /*
- * NOTE: We do not unmask the RDT here, as an interrupt MAY still
- * come in before we have a chance to reprogram it below. The
- * reprogramming below will simultaneously change and unmask the
- * RDT entry.
- */
+ /*
+ * NOTE: We do not unmask the RDT here, as an interrupt MAY
+ * still come in before we have a chance to reprogram it below.
+ * The reprogramming below will simultaneously change and
+ * unmask the RDT entry.
+ */
- if ((uchar_t)bind_cpu == IRQ_UNBOUND) {
+ if ((uchar_t)bind_cpu == IRQ_UNBOUND) {
+ rdt_entry = AV_LDEST | AV_LOPRI |
+ irq_ptr->airq_rdt_entry;
- rdt_entry = AV_LDEST | AV_LOPRI | irq_ptr->airq_rdt_entry;
+ /* Write the RDT entry -- no specific CPU binding */
+ WRITE_IOAPIC_RDT_ENTRY_HIGH_DWORD(ioapicindex, intin_no,
+ AV_TOALL);
- /* Write the RDT entry -- no specific CPU binding */
- WRITE_IOAPIC_RDT_ENTRY_HIGH_DWORD(ioapicindex, intin_no,
- AV_TOALL);
+ if (airq_temp_cpu != IRQ_UNINIT && airq_temp_cpu !=
+ IRQ_UNBOUND)
+ apic_cpus[airq_temp_cpu].aci_temp_bound--;
- if (airq_temp_cpu != IRQ_UNINIT && airq_temp_cpu != IRQ_UNBOUND)
- apic_cpus[airq_temp_cpu].aci_temp_bound--;
-
- /* Write the vector, trigger, and polarity portion of the RDT */
- WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapicindex, intin_no,
- rdt_entry);
+ /*
+ * Write the vector, trigger, and polarity portion of
+ * the RDT
+ */
+ WRITE_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapicindex, intin_no,
+ rdt_entry);
- irq_ptr->airq_temp_cpu = IRQ_UNBOUND;
- return (0);
+ irq_ptr->airq_temp_cpu = IRQ_UNBOUND;
+ return (0);
+ }
}
if (bind_cpu & IRQ_USER_BOUND) {
diff --git a/usr/src/uts/i86pc/io/pci/pci_common.c b/usr/src/uts/i86pc/io/pci/pci_common.c
index cacc0ae123..a5bdc5afa5 100644
--- a/usr/src/uts/i86pc/io/pci/pci_common.c
+++ b/usr/src/uts/i86pc/io/pci/pci_common.c
@@ -145,7 +145,7 @@ pci_common_set_parent_private_data(dev_info_t *dip)
pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
(sizeof (struct ddi_parent_private_data) +
- sizeof (struct intrspec)), KM_SLEEP);
+ sizeof (struct intrspec)), KM_SLEEP);
pdptr->par_intr = (struct intrspec *)(pdptr + 1);
pdptr->par_nintr = 1;
ddi_set_parent_data(dip, pdptr);
@@ -400,7 +400,7 @@ SUPPORTED_TYPES_OUT:
if (pciepci) {
/* update priority in ispec */
isp = pci_intx_get_ispec(pdip, rdip,
- (int)hdlp->ih_inum);
+ (int)hdlp->ih_inum);
ispec = (struct intrspec *)isp;
if (ispec)
ispec->intrspec_pri = hdlp->ih_pri;
@@ -437,7 +437,7 @@ SUPPORTED_TYPES_OUT:
msix_p = i_ddi_get_msix(hdlp->ih_dip);
if (msix_p &&
(i_ddi_intr_get_current_nintrs(
- hdlp->ih_dip) - 1) == 0) {
+ hdlp->ih_dip) - 1) == 0) {
pci_msix_fini(msix_p);
i_ddi_set_msix(hdlp->ih_dip, NULL);
}
@@ -581,8 +581,9 @@ SUPPORTED_TYPES_OUT:
DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
"pci_enable_intr failed for %d\n", i));
for (j = 0; j < i; j++) {
- hdlp = (ddi_intr_handle_impl_t *)h_array[j];
- pci_disable_intr(pdip, rdip, hdlp,
+ hdlp = (ddi_intr_handle_impl_t *)
+ h_array[j];
+ pci_disable_intr(pdip, rdip, hdlp,
hdlp->ih_inum);
}
return (DDI_FAILURE);
@@ -899,7 +900,7 @@ pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
/*FALLTHRU*/
/* These require no special privileges. */
case PCITOOL_DEVICE_GET_INTR:
- case PCITOOL_DEVICE_NUM_INTR:
+ case PCITOOL_SYSTEM_INTR_INFO:
rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
break;
}
@@ -1599,9 +1600,9 @@ is_amd_northbridge(dev_info_t *dip)
int vendor_id, device_id;
vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "vendor-id", -1);
+ "vendor-id", -1);
device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "device-id", -1);
+ "device-id", -1);
if (IS_AMD_NTBRIDGE(vendor_id, device_id))
return (0);
diff --git a/usr/src/uts/i86pc/io/pci/pci_kstats.c b/usr/src/uts/i86pc/io/pci/pci_kstats.c
index c8032f1286..a387ba1ff8 100644
--- a/usr/src/uts/i86pc/io/pci/pci_kstats.c
+++ b/usr/src/uts/i86pc/io/pci/pci_kstats.c
@@ -72,13 +72,12 @@ static kmutex_t pci_ks_template_lock;
static int
pci_ih_ks_update(kstat_t *ksp, int rw)
{
- pci_kstat_private_t *private_data =
- (pci_kstat_private_t *)ksp->ks_private;
- dev_info_t *rootnex_dip = private_data->rootnex_dip;
- ddi_intr_handle_impl_t *ih_p = private_data->hdlp;
- dev_info_t *dip = ih_p->ih_dip;
- int maxlen =
- sizeof (pci_ks_template.ihks_name.value.c);
+ pci_kstat_private_t *private_data =
+ (pci_kstat_private_t *)ksp->ks_private;
+ dev_info_t *rootnex_dip = private_data->rootnex_dip;
+ ddi_intr_handle_impl_t *ih_p = private_data->hdlp;
+ dev_info_t *dip = ih_p->ih_dip;
+ int maxlen = sizeof (pci_ks_template.ihks_name.value.c);
apic_get_intr_t intrinfo;
(void) snprintf(pci_ks_template.ihks_name.value.c, maxlen, "%s%d",
@@ -112,7 +111,7 @@ pci_ih_ks_update(kstat_t *ksp, int rw)
intrinfo.avgi_req_flags = PSMGI_REQ_CPUID | PSMGI_REQ_VECTOR;
if ((ih_p->ih_state != DDI_IHDL_STATE_ENABLE) ||
(pci_get_intr_from_vecirq(&intrinfo, ih_p->ih_vector, IS_IRQ) !=
- DDI_SUCCESS) ||
+ DDI_SUCCESS) ||
(intrinfo.avgi_cpu_id & PSMGI_CPU_FLAGS)) {
(void) strcpy(pci_ks_template.ihks_type.value.c, "disabled");
@@ -134,8 +133,17 @@ pci_ih_ks_update(kstat_t *ksp, int rw)
* Interrupt is valid (not a dummy), not user-bound to a specific cpu,
* and enabled. Update kstat fields.
*/
- (void) strcpy(pci_ks_template.ihks_type.value.c,
- DDI_INTR_IS_MSI_OR_MSIX(ih_p->ih_type) ? "msi" : "fixed");
+ switch (ih_p->ih_type) {
+ case DDI_INTR_TYPE_MSI:
+ (void) strcpy(pci_ks_template.ihks_type.value.c, "msi");
+ break;
+ case DDI_INTR_TYPE_MSIX:
+ (void) strcpy(pci_ks_template.ihks_type.value.c, "msix");
+ break;
+ default:
+ (void) strcpy(pci_ks_template.ihks_type.value.c, "fixed");
+ break;
+ }
pci_ks_template.ihks_pil.value.ui64 = ih_p->ih_pri;
pci_ks_template.ihks_time.value.ui64 =
((ihdl_plat_t *)ih_p->ih_private)->ip_ticks;
@@ -184,8 +192,8 @@ void pci_kstat_create(kstat_t **kspp, dev_info_t *rootnex_dip,
void
pci_kstat_delete(kstat_t *ksp)
{
- pci_kstat_private_t *kstat_private;
- ddi_intr_handle_impl_t *hdlp;
+ pci_kstat_private_t *kstat_private;
+ ddi_intr_handle_impl_t *hdlp;
if (ksp) {
kstat_private = ksp->ks_private;
diff --git a/usr/src/uts/i86pc/io/pci/pci_tools.c b/usr/src/uts/i86pc/io/pci/pci_tools.c
index 7e4c90c432..7d35c9724b 100644
--- a/usr/src/uts/i86pc/io/pci/pci_tools.c
+++ b/usr/src/uts/i86pc/io/pci/pci_tools.c
@@ -84,7 +84,7 @@ static int pcitool_mem_access(dev_info_t *dip, pcitool_reg_t *prg,
static uint64_t pcitool_map(uint64_t phys_addr, size_t size, size_t *num_pages);
static void pcitool_unmap(uint64_t virt_addr, size_t num_pages);
-/* Extern decalrations */
+/* Extern declarations */
extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
psm_intr_op_t, int *);
@@ -121,21 +121,6 @@ pcitool_uninit(dev_info_t *dip)
ddi_remove_minor_node(dip, PCI_MINOR_REG);
}
-
-/* Return the number of interrupts on a pci bus. */
-static int
-pcitool_intr_get_max_ino(uint32_t *arg, int mode)
-{
- uint32_t num_intr = APIC_MAX_VECTOR;
-
- if (ddi_copyout(&num_intr, arg, sizeof (uint32_t), mode) !=
- DDI_SUCCESS)
- return (EFAULT);
- else
- return (SUCCESS);
-}
-
-
/*ARGSUSED*/
static int
pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
@@ -144,12 +129,31 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
pcitool_intr_set_t iset;
uint32_t old_cpu;
int ret, result;
+ size_t copyinout_size;
int rval = SUCCESS;
- if (ddi_copyin(arg, &iset, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ /* Version 1 of pcitool_intr_set_t doesn't have flags. */
+ copyinout_size = (size_t)&iset.flags - (size_t)&iset;
+
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
return (EFAULT);
+ switch (iset.user_version) {
+ case PCITOOL_V1:
+ break;
+
+ case PCITOOL_V2:
+ copyinout_size = sizeof (pcitool_intr_set_t);
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
+ return (EFAULT);
+ break;
+
+ default:
+ iset.status = PCITOOL_OUT_OF_RANGE;
+ rval = ENOTSUP;
+ goto done_set_intr;
+ }
+
if (iset.ino > APIC_MAX_VECTOR) {
rval = EINVAL;
iset.status = PCITOOL_INVALID_INO;
@@ -164,6 +168,7 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
goto done_set_intr;
}
+
old_cpu &= ~PSMGI_CPU_USER_BOUND;
/*
@@ -172,9 +177,20 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
*/
info_hdl.ih_vector = iset.ino;
info_hdl.ih_private = (void *)(uintptr_t)iset.cpu_id;
- ret = (*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_SET_CPU, &result);
+ if (pcitool_debug)
+ prom_printf("user version:%d, flags:0x%x\n",
+ iset.user_version, iset.flags);
+
+ result = ENOTSUP;
+ if ((iset.user_version >= PCITOOL_V2) &&
+ (iset.flags & PCITOOL_INTR_SET_FLAG_GROUP)) {
+ ret = (*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_GRP_SET_CPU,
+ &result);
+ } else {
+ ret = (*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_SET_CPU,
+ &result);
+ }
- iset.drvr_version = PCITOOL_DRVR_VERSION;
if (ret != PSM_SUCCESS) {
switch (result) {
case EIO: /* Error making the change */
@@ -189,6 +205,10 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
rval = EINVAL;
iset.status = PCITOOL_INVALID_CPUID;
break;
+ case ENOTSUP: /* Requested PSM intr ops missing */
+ rval = ENOTSUP;
+ iset.status = PCITOOL_IO_ERROR;
+ break;
}
}
@@ -196,8 +216,8 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
iset.cpu_id = old_cpu;
done_set_intr:
- if (ddi_copyout(&iset, arg, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ iset.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&iset, arg, copyinout_size, mode) != DDI_SUCCESS)
rval = EFAULT;
return (rval);
}
@@ -337,7 +357,7 @@ done_get_intr:
ndi_devi_exit(dip, circ);
}
- iget->drvr_version = PCITOOL_DRVR_VERSION;
+ iget->drvr_version = PCITOOL_VERSION;
copyout_rval = ddi_copyout(iget, arg,
PCITOOL_IGET_SIZE(num_devs_ret), mode);
@@ -350,6 +370,50 @@ done_get_intr:
return (rval);
}
+/*ARGSUSED*/
+static int
+pcitool_intr_info(dev_info_t *dip, void *arg, int mode)
+{
+ pcitool_intr_info_t intr_info;
+ ddi_intr_handle_impl_t info_hdl;
+ int rval = SUCCESS;
+
+ /* If we need user_version, and to ret same user version as passed in */
+ if (ddi_copyin(arg, &intr_info, sizeof (pcitool_intr_info_t), mode) !=
+ DDI_SUCCESS) {
+ if (pcitool_debug)
+ prom_printf("Error reading arguments\n");
+ return (EFAULT);
+ }
+
+ /* For UPPC systems, psm_intr_ops has no entry for APIC_TYPE. */
+ if ((rval = (*psm_intr_ops)(NULL, &info_hdl,
+ PSM_INTR_OP_APIC_TYPE, NULL)) != PSM_SUCCESS) {
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_UPPC;
+ intr_info.ctlr_version = 0;
+
+ } else {
+ intr_info.ctlr_version = (uint32_t)info_hdl.ih_ver;
+ if (strcmp((char *)info_hdl.ih_private,
+ APIC_PCPLUSMP_NAME) == 0)
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_PCPLUSMP;
+ else
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_UNKNOWN;
+ }
+
+ intr_info.num_intr = APIC_MAX_VECTOR;
+ intr_info.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&intr_info, arg, sizeof (pcitool_intr_info_t), mode) !=
+ DDI_SUCCESS) {
+ if (pcitool_debug)
+ prom_printf("Error returning arguments.\n");
+ rval = EFAULT;
+ }
+
+ return (rval);
+}
+
+
/*
* Main function for handling interrupt CPU binding requests and queries.
@@ -372,8 +436,8 @@ pcitool_intr_admn(dev_info_t *dip, void *arg, int cmd, int mode)
rval = pcitool_get_intr(dip, arg, mode);
break;
- case PCITOOL_DEVICE_NUM_INTR:
- rval = pcitool_intr_get_max_ino(arg, mode);
+ case PCITOOL_SYSTEM_INTR_INFO:
+ rval = pcitool_intr_info(dip, arg, mode);
break;
default:
@@ -571,7 +635,7 @@ pcitool_io_access(dev_info_t *dip, pcitool_reg_t *prg, boolean_t write_flag)
no_trap();
if (pcitool_debug)
prom_printf(
- "pcitool_mem_access: on_trap caught an error...\n");
+ "pcitool_io_access: on_trap caught an error...\n");
prg->status = PCITOOL_INVALID_ADDRESS;
return (EFAULT);
}
@@ -1075,6 +1139,7 @@ pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
pcitool_unmap(virt_addr, num_virt_pages);
}
done_reg:
+ prg.drvr_version = PCITOOL_VERSION;
if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), mode) !=
DDI_SUCCESS) {
if (pcitool_debug)
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.c b/usr/src/uts/i86pc/io/pcplusmp/apic.c
index f51d4adcfd..55f168a4ac 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c
@@ -246,7 +246,7 @@ static struct psm_info apic_psm_info = {
PSM_INFO_VER01_5, /* version */
PSM_OWN_EXCLUSIVE, /* ownership */
(struct psm_ops *)&apic_ops, /* operation */
- "pcplusmp", /* machine name */
+ APIC_PCPLUSMP_NAME, /* machine name */
"pcplusmp v1.4 compatible %I%",
};
@@ -2013,7 +2013,7 @@ apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri, int type,
irqptr->airq_major = major;
if (i == 0) /* they all bound to the same cpu */
cpu = irqptr->airq_cpu = apic_bind_intr(dip, irqno,
- 0xff, 0xff);
+ 0xff, 0xff);
else
irqptr->airq_cpu = cpu;
DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_vectors: irq=0x%x "
@@ -2155,3 +2155,9 @@ apic_modify_vector(uchar_t vector, int irq)
apic_vector_to_irq[vector] = (uchar_t)irq;
return (vector);
}
+
+char *
+apic_get_apic_type()
+{
+ return (apic_psm_info.p_mach_idstring);
+}
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c b/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c
index 324c8cb54d..81325f4930 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c
@@ -95,7 +95,7 @@ apic_pci_msi_enable_vector(dev_info_t *dip, int type, int inum, int vector,
/* MSI Address */
msi_addr = (MSI_ADDR_HDR | (target_apic_id << MSI_ADDR_DEST_SHIFT));
msi_addr |= ((MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) |
- (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT));
+ (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT));
/* MSI Data: MSI is edge triggered according to spec */
msi_data = ((MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) | vector);
@@ -163,7 +163,7 @@ apic_navail_vector(dev_info_t *dip, int pri)
for (i = lowest; i < highest; i++) {
count = 0;
while ((apic_vector_to_irq[i] == APIC_RESV_IRQ) &&
- (i < highest)) {
+ (i < highest)) {
if (APIC_CHECK_RESERVE_VECTORS(i))
break;
count++;
@@ -212,7 +212,7 @@ apic_find_multi_vectors(int pri, int count)
i = (i + msibits) & ~msibits;
start = i;
while ((apic_vector_to_irq[i] == APIC_RESV_IRQ) &&
- (i < highest)) {
+ (i < highest)) {
if (APIC_CHECK_RESERVE_VECTORS(i))
break;
navail++;
@@ -433,107 +433,6 @@ apic_check_msi_support()
return (PSM_FAILURE);
}
-int
-apic_get_vector_intr_info(int vecirq, apic_get_intr_t *intr_params_p)
-{
- struct autovec *av_dev;
- uchar_t irqno;
- int i;
- apic_irq_t *irq_p;
-
- /* Sanity check the vector/irq argument. */
- ASSERT((vecirq >= 0) || (vecirq <= APIC_MAX_VECTOR));
-
- mutex_enter(&airq_mutex);
-
- /*
- * Convert the vecirq arg to an irq using vector_to_irq table
- * if the arg is a vector. Pass thru if already an irq.
- */
- if ((intr_params_p->avgi_req_flags & PSMGI_INTRBY_FLAGS) ==
- PSMGI_INTRBY_VEC)
- irqno = apic_vector_to_irq[vecirq];
- else
- irqno = vecirq;
-
- irq_p = apic_irq_table[irqno];
-
- if ((irq_p == NULL) ||
- (irq_p->airq_temp_cpu == IRQ_UNBOUND) ||
- (irq_p->airq_temp_cpu == IRQ_UNINIT)) {
- mutex_exit(&airq_mutex);
- return (PSM_FAILURE);
- }
-
- if (intr_params_p->avgi_req_flags & PSMGI_REQ_CPUID) {
-
- /* Get the (temp) cpu from apic_irq table, indexed by irq. */
- intr_params_p->avgi_cpu_id = irq_p->airq_temp_cpu;
-
- /* Return user bound info for intrd. */
- if (intr_params_p->avgi_cpu_id & IRQ_USER_BOUND) {
- intr_params_p->avgi_cpu_id &= ~IRQ_USER_BOUND;
- intr_params_p->avgi_cpu_id |= PSMGI_CPU_USER_BOUND;
- }
- }
-
- if (intr_params_p->avgi_req_flags & PSMGI_REQ_VECTOR) {
- intr_params_p->avgi_vector = irq_p->airq_vector;
- }
-
- if (intr_params_p->avgi_req_flags &
- (PSMGI_REQ_NUM_DEVS | PSMGI_REQ_GET_DEVS)) {
- /* Get number of devices from apic_irq table shared field. */
- intr_params_p->avgi_num_devs = irq_p->airq_share;
- }
-
- if (intr_params_p->avgi_req_flags & PSMGI_REQ_GET_DEVS) {
-
- intr_params_p->avgi_req_flags |= PSMGI_REQ_NUM_DEVS;
-
- /* Some devices have NULL dip. Don't count these. */
- if (intr_params_p->avgi_num_devs > 0) {
- for (i = 0, av_dev = autovect[irqno].avh_link;
- av_dev; av_dev = av_dev->av_link)
- if (av_dev->av_vector && av_dev->av_dip)
- i++;
- intr_params_p->avgi_num_devs =
- MIN(intr_params_p->avgi_num_devs, i);
- }
-
- /* There are no viable dips to return. */
- if (intr_params_p->avgi_num_devs == 0)
- intr_params_p->avgi_dip_list = NULL;
-
- else { /* Return list of dips */
-
- /* Allocate space in array for that number of devs. */
- intr_params_p->avgi_dip_list = kmem_zalloc(
- intr_params_p->avgi_num_devs *
- sizeof (dev_info_t *),
- KM_SLEEP);
-
- /*
- * Loop through the device list of the autovec table
- * filling in the dip array.
- *
- * Note that the autovect table may have some special
- * entries which contain NULL dips. These will be
- * ignored.
- */
- for (i = 0, av_dev = autovect[irqno].avh_link;
- av_dev; av_dev = av_dev->av_link)
- if (av_dev->av_vector && av_dev->av_dip)
- intr_params_p->avgi_dip_list[i++] =
- av_dev->av_dip;
- }
- }
-
- mutex_exit(&airq_mutex);
-
- return (PSM_SUCCESS);
-}
-
/*
* apic_pci_msi_unconfigure:
*
@@ -676,6 +575,282 @@ apic_pci_msi_disable_mode(dev_info_t *rdip, int type, int inum)
}
+static int
+apic_set_cpu(uint32_t vector, int cpu, int *result)
+{
+ apic_irq_t *irqp;
+ int iflag;
+ int ret;
+
+ DDI_INTR_IMPLDBG((CE_CONT, "APIC_SET_CPU\n"));
+
+ /* Convert the vector to the irq using vector_to_irq table. */
+ mutex_enter(&airq_mutex);
+ irqp = apic_irq_table[apic_vector_to_irq[vector]];
+ mutex_exit(&airq_mutex);
+
+ if (irqp == NULL) {
+ *result = ENXIO;
+ return (PSM_FAILURE);
+ }
+
+ /* Fail if this is an MSI intr and is part of a group. */
+ if ((irqp->airq_mps_intr_index == MSI_INDEX) &&
+ (irqp->airq_intin_no > 1)) {
+ *result = ENXIO;
+ return (PSM_FAILURE);
+ }
+
+ iflag = intr_clear();
+ lock_set(&apic_ioapic_lock);
+
+ ret = apic_rebind_all(irqp, cpu);
+
+ lock_clear(&apic_ioapic_lock);
+ intr_restore(iflag);
+
+ if (ret) {
+ *result = EIO;
+ return (PSM_FAILURE);
+ }
+ *result = 0;
+ return (PSM_SUCCESS);
+}
+
+static int
+apic_grp_set_cpu(uint32_t vector, int new_cpu, int *result)
+{
+ dev_info_t *orig_dip;
+ uchar_t orig_cpu;
+ int iflag;
+ apic_irq_t *irqps[PCI_MSI_MAX_INTRS];
+ int i;
+ int cap_ptr;
+ int msi_mask_off;
+ ushort_t msi_ctrl;
+ uint32_t msi_pvm;
+ ddi_acc_handle_t handle;
+ int num_vectors = 0;
+
+ DDI_INTR_IMPLDBG((CE_CONT, "APIC_GRP_SET_CPU\n"));
+
+ /*
+ * Take mutex to insure that table doesn't change out from underneath
+ * us while we're playing with it.
+ */
+ mutex_enter(&airq_mutex);
+ irqps[0] = apic_irq_table[apic_vector_to_irq[vector]];
+ orig_cpu = irqps[0]->airq_temp_cpu;
+ orig_dip = irqps[0]->airq_dip;
+ num_vectors = irqps[0]->airq_intin_no;
+
+ /* A "group" of 1 */
+ if (num_vectors == 1) {
+ mutex_exit(&airq_mutex);
+ return (apic_set_cpu(vector, new_cpu, result));
+ }
+
+ *result = ENXIO;
+
+ if (irqps[0]->airq_mps_intr_index != MSI_INDEX) {
+ mutex_exit(&airq_mutex);
+ DDI_INTR_IMPLDBG((CE_CONT, "set_grp: intr not MSI\n"));
+ goto set_grp_intr_done;
+ }
+ if ((num_vectors < 1) || ((num_vectors - 1) & vector)) {
+ mutex_exit(&airq_mutex);
+ DDI_INTR_IMPLDBG((CE_CONT,
+ "set_grp: base vec not part of a grp or not aligned: "
+ "vec:0x%x, num_vec:0x%x\n", vector, num_vectors));
+ goto set_grp_intr_done;
+ }
+ DDI_INTR_IMPLDBG((CE_CONT, "set_grp: num intrs in grp: %d\n",
+ num_vectors));
+
+ ASSERT((num_vectors + vector) < APIC_MAX_VECTOR);
+
+ *result = EIO;
+
+ /*
+ * All IRQ entries in the table for the given device will be not
+ * shared. Since they are not shared, the dip in the table will
+ * be true to the device of interest.
+ */
+ for (i = 1; i < num_vectors; i++) {
+ irqps[i] = apic_irq_table[apic_vector_to_irq[vector + i]];
+ if (irqps[i] == NULL) {
+ mutex_exit(&airq_mutex);
+ goto set_grp_intr_done;
+ }
+#ifdef DEBUG
+ /* Sanity check: CPU and dip is the same for all entries. */
+ if ((irqps[i]->airq_dip != orig_dip) ||
+ (irqps[i]->airq_temp_cpu != orig_cpu)) {
+ mutex_exit(&airq_mutex);
+ DDI_INTR_IMPLDBG((CE_CONT,
+ "set_grp: cpu or dip for vec 0x%x difft than for "
+ "vec 0x%x\n", vector, vector + i));
+ DDI_INTR_IMPLDBG((CE_CONT,
+ " cpu: %d vs %d, dip: 0x%p vs 0x%p\n", orig_cpu,
+ irqps[i]->airq_temp_cpu, (void *)orig_dip,
+ (void *)irqps[i]->airq_dip));
+ goto set_grp_intr_done;
+ }
+#endif /* DEBUG */
+ }
+ mutex_exit(&airq_mutex);
+
+ cap_ptr = i_ddi_get_msi_msix_cap_ptr(orig_dip);
+ handle = i_ddi_get_pci_config_handle(orig_dip);
+ msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
+
+ /* MSI Per vector masking is supported. */
+ if (msi_ctrl & PCI_MSI_PVM_MASK) {
+ if (msi_ctrl & PCI_MSI_64BIT_MASK)
+ msi_mask_off = cap_ptr + PCI_MSI_64BIT_MASKBITS;
+ else
+ msi_mask_off = cap_ptr + PCI_MSI_32BIT_MASK;
+ msi_pvm = pci_config_get32(handle, msi_mask_off);
+ pci_config_put32(handle, msi_mask_off, (uint32_t)-1);
+ DDI_INTR_IMPLDBG((CE_CONT,
+ "set_grp: pvm supported. Mask set to 0x%x\n",
+ pci_config_get32(handle, msi_mask_off)));
+ }
+
+ iflag = intr_clear();
+ lock_set(&apic_ioapic_lock);
+
+ /*
+ * Do the first rebind and check for errors. Apic_rebind_all returns
+ * an error if the CPU is not accepting interrupts. If the first one
+ * succeeds they all will.
+ */
+ if (apic_rebind_all(irqps[0], new_cpu))
+ (void) apic_rebind_all(irqps[0], orig_cpu);
+ else {
+ for (i = 1; i < num_vectors; i++)
+ (void) apic_rebind_all(irqps[i], new_cpu);
+ *result = 0; /* SUCCESS */
+ }
+
+ lock_clear(&apic_ioapic_lock);
+ intr_restore(iflag);
+
+ /* Reenable vectors if per vector masking is supported. */
+ if (msi_ctrl & PCI_MSI_PVM_MASK) {
+ pci_config_put32(handle, msi_mask_off, msi_pvm);
+ DDI_INTR_IMPLDBG((CE_CONT,
+ "set_grp: pvm supported. Mask restored to 0x%x\n",
+ pci_config_get32(handle, msi_mask_off)));
+ }
+
+set_grp_intr_done:
+ if (*result != 0)
+ return (PSM_FAILURE);
+
+ return (PSM_SUCCESS);
+}
+
+static int
+apic_get_vector_intr_info(int vecirq, apic_get_intr_t *intr_params_p)
+{
+ struct autovec *av_dev;
+ uchar_t irqno;
+ int i;
+ apic_irq_t *irq_p;
+
+ /* Sanity check the vector/irq argument. */
+ ASSERT((vecirq >= 0) || (vecirq <= APIC_MAX_VECTOR));
+
+ mutex_enter(&airq_mutex);
+
+ /*
+ * Convert the vecirq arg to an irq using vector_to_irq table
+ * if the arg is a vector. Pass thru if already an irq.
+ */
+ if ((intr_params_p->avgi_req_flags & PSMGI_INTRBY_FLAGS) ==
+ PSMGI_INTRBY_VEC)
+ irqno = apic_vector_to_irq[vecirq];
+ else
+ irqno = vecirq;
+
+ irq_p = apic_irq_table[irqno];
+
+ if ((irq_p == NULL) ||
+ (irq_p->airq_temp_cpu == IRQ_UNBOUND) ||
+ (irq_p->airq_temp_cpu == IRQ_UNINIT)) {
+ mutex_exit(&airq_mutex);
+ return (PSM_FAILURE);
+ }
+
+ if (intr_params_p->avgi_req_flags & PSMGI_REQ_CPUID) {
+
+ /* Get the (temp) cpu from apic_irq table, indexed by irq. */
+ intr_params_p->avgi_cpu_id = irq_p->airq_temp_cpu;
+
+ /* Return user bound info for intrd. */
+ if (intr_params_p->avgi_cpu_id & IRQ_USER_BOUND) {
+ intr_params_p->avgi_cpu_id &= ~IRQ_USER_BOUND;
+ intr_params_p->avgi_cpu_id |= PSMGI_CPU_USER_BOUND;
+ }
+ }
+
+ if (intr_params_p->avgi_req_flags & PSMGI_REQ_VECTOR)
+ intr_params_p->avgi_vector = irq_p->airq_vector;
+
+ if (intr_params_p->avgi_req_flags &
+ (PSMGI_REQ_NUM_DEVS | PSMGI_REQ_GET_DEVS))
+ /* Get number of devices from apic_irq table shared field. */
+ intr_params_p->avgi_num_devs = irq_p->airq_share;
+
+ if (intr_params_p->avgi_req_flags & PSMGI_REQ_GET_DEVS) {
+
+ intr_params_p->avgi_req_flags |= PSMGI_REQ_NUM_DEVS;
+
+ /* Some devices have NULL dip. Don't count these. */
+ if (intr_params_p->avgi_num_devs > 0) {
+ for (i = 0, av_dev = autovect[irqno].avh_link;
+ av_dev; av_dev = av_dev->av_link)
+ if (av_dev->av_vector && av_dev->av_dip)
+ i++;
+ intr_params_p->avgi_num_devs =
+ MIN(intr_params_p->avgi_num_devs, i);
+ }
+
+ /* There are no viable dips to return. */
+ if (intr_params_p->avgi_num_devs == 0)
+ intr_params_p->avgi_dip_list = NULL;
+
+ else { /* Return list of dips */
+
+ /* Allocate space in array for that number of devs. */
+ intr_params_p->avgi_dip_list = kmem_zalloc(
+ intr_params_p->avgi_num_devs *
+ sizeof (dev_info_t *),
+ KM_SLEEP);
+
+ /*
+ * Loop through the device list of the autovec table
+ * filling in the dip array.
+ *
+ * Note that the autovect table may have some special
+ * entries which contain NULL dips. These will be
+ * ignored.
+ */
+ for (i = 0, av_dev = autovect[irqno].avh_link;
+ av_dev; av_dev = av_dev->av_link)
+ if (av_dev->av_vector && av_dev->av_dip)
+ intr_params_p->avgi_dip_list[i++] =
+ av_dev->av_dip;
+ }
+ }
+
+ mutex_exit(&airq_mutex);
+
+ return (PSM_SUCCESS);
+}
+
+
/*
* This function provides external interface to the nexus for all
* functionalities related to the new DDI interrupt framework.
@@ -695,12 +870,11 @@ int
apic_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp,
psm_intr_op_t intr_op, int *result)
{
- int cap, ret;
+ int cap;
int count_vec;
- int cpu;
int old_priority;
int new_priority;
- int iflag;
+ int new_cpu;
apic_irq_t *irqp;
struct intrspec *ispec, intr_spec;
@@ -812,42 +986,28 @@ apic_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp,
hdlp->ih_pri = new_priority; /* set the new value */
break;
case PSM_INTR_OP_SET_CPU:
+ case PSM_INTR_OP_GRP_SET_CPU:
/*
* The interrupt handle given here has been allocated
* specifically for this command, and ih_private carries
* a CPU value.
*/
- cpu = (int)(intptr_t)hdlp->ih_private;
-
- if (!apic_cpu_in_range(cpu)) {
+ new_cpu = (int)(intptr_t)hdlp->ih_private;
+ if (!apic_cpu_in_range(new_cpu)) {
+ DDI_INTR_IMPLDBG((CE_CONT,
+ "[grp_]set_cpu: cpu out of range: %d\n", new_cpu));
*result = EINVAL;
return (PSM_FAILURE);
}
-
-
- /* Convert the vector to the irq using vector_to_irq table. */
- mutex_enter(&airq_mutex);
- irqp = apic_irq_table[apic_vector_to_irq[hdlp->ih_vector]];
- mutex_exit(&airq_mutex);
-
- if (irqp == NULL) {
- *result = ENXIO;
- return (PSM_FAILURE);
- }
-
- iflag = intr_clear();
- lock_set(&apic_ioapic_lock);
-
- ret = apic_rebind_all(irqp, cpu);
-
- lock_clear(&apic_ioapic_lock);
- intr_restore(iflag);
-
- if (ret) {
- *result = EIO;
- return (PSM_FAILURE);
+ if (intr_op == PSM_INTR_OP_SET_CPU) {
+ if (apic_set_cpu(hdlp->ih_vector, new_cpu, result) !=
+ PSM_SUCCESS)
+ return (PSM_FAILURE);
+ } else {
+ if (apic_grp_set_cpu(hdlp->ih_vector, new_cpu,
+ result) != PSM_SUCCESS)
+ return (PSM_FAILURE);
}
- *result = 0;
break;
case PSM_INTR_OP_GET_INTR:
/*
@@ -859,6 +1019,10 @@ apic_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp,
hdlp->ih_vector, hdlp->ih_private) != PSM_SUCCESS)
return (PSM_FAILURE);
break;
+ case PSM_INTR_OP_APIC_TYPE:
+ hdlp->ih_private = apic_get_apic_type();
+ hdlp->ih_ver = apic_get_apic_version();
+ break;
case PSM_INTR_OP_SET_CAP:
default:
return (PSM_FAILURE);
diff --git a/usr/src/uts/i86pc/sys/apic.h b/usr/src/uts/i86pc/sys/apic.h
index 853be5d7c6..d2022e1347 100644
--- a/usr/src/uts/i86pc/sys/apic.h
+++ b/usr/src/uts/i86pc/sys/apic.h
@@ -38,6 +38,8 @@ extern "C" {
#include <sys/psm_common.h>
+#define APIC_PCPLUSMP_NAME "pcplusmp"
+
#define APIC_IO_ADDR 0xfec00000
#define APIC_LOCAL_ADDR 0xfee00000
#define APIC_IO_MEMLEN 0xf
@@ -706,8 +708,6 @@ extern int apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri,
int type, int behavior);
extern void apic_free_vectors(dev_info_t *dip, int inum, int count, int pri,
int type);
-extern int apic_get_vector_intr_info(int vecirq,
- apic_get_intr_t *intr_params_p);
extern uchar_t apic_find_multi_vectors(int pri, int count);
extern int apic_setup_io_intr(void *p, int irq, boolean_t deferred);
extern uint32_t *mapin_apic(uint32_t addr, size_t len, int flags);
@@ -718,6 +718,8 @@ extern uchar_t apic_modify_vector(uchar_t vector, int irq);
extern int apic_pci_msi_unconfigure(dev_info_t *rdip, int type, int inum);
extern int apic_pci_msi_disable_mode(dev_info_t *rdip, int type, int inum);
extern int apic_pci_msi_enable_mode(dev_info_t *rdip, int type, int inum);
+extern char *apic_get_apic_type();
+extern uint16_t apic_get_apic_version();
extern volatile uint32_t *apicadr; /* virtual addr of local APIC */
extern int apic_forceload;
diff --git a/usr/src/uts/i86pc/sys/apic_ctlr.h b/usr/src/uts/i86pc/sys/apic_ctlr.h
new file mode 100644
index 0000000000..78ecba70b7
--- /dev/null
+++ b/usr/src/uts/i86pc/sys/apic_ctlr.h
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_APIC_CTLR_H
+#define _SYS_APIC_CTLR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Macros dealing with controller version field returned as part of
+ * PSM_INTR_OP_APIC_TYPE.
+ */
+#define PSMAT_LOCAL_APIC_VER(ctlr_ver) ((ctlr_ver) & 0xff)
+#define PSMAT_IO_APIC_VER(ctlr_ver) ((ctlr_ver) >> 8)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_APIC_CTLR_H */
diff --git a/usr/src/uts/i86pc/sys/psm_types.h b/usr/src/uts/i86pc/sys/psm_types.h
index 435d2da112..70b49ed3dc 100644
--- a/usr/src/uts/i86pc/sys/psm_types.h
+++ b/usr/src/uts/i86pc/sys/psm_types.h
@@ -58,7 +58,9 @@ typedef enum psm_intr_op_e {
PSM_INTR_OP_GET_SHARED, /* 10. Get the shared intr info */
PSM_INTR_OP_CHECK_MSI, /* 11. Chk if device supports MSI */
PSM_INTR_OP_SET_CPU, /* 12. Set vector's CPU */
- PSM_INTR_OP_GET_INTR /* 13. Get vector's info */
+ PSM_INTR_OP_GET_INTR, /* 13. Get vector's info */
+ PSM_INTR_OP_GRP_SET_CPU, /* 14. Set all device's vectors' CPU */
+ PSM_INTR_OP_APIC_TYPE /* 15. Returns APIC type */
} psm_intr_op_t;
struct psm_ops {
diff --git a/usr/src/uts/sun4/io/px/px_devctl.c b/usr/src/uts/sun4/io/px/px_devctl.c
index 731d419b6b..463ab15c3a 100644
--- a/usr/src/uts/sun4/io/px/px_devctl.c
+++ b/usr/src/uts/sun4/io/px/px_devctl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -240,7 +240,7 @@ px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
/*FALLTHRU*/
/* These require no special privileges. */
case PCITOOL_DEVICE_GET_INTR:
- case PCITOOL_DEVICE_NUM_INTR:
+ case PCITOOL_SYSTEM_INTR_INFO:
rv = pxtool_intr(dip, (void *)arg, cmd, mode);
break;
diff --git a/usr/src/uts/sun4/io/px/px_intr.c b/usr/src/uts/sun4/io/px/px_intr.c
index e9ad60378c..cb29b53996 100644
--- a/usr/src/uts/sun4/io/px/px_intr.c
+++ b/usr/src/uts/sun4/io/px/px_intr.c
@@ -346,7 +346,8 @@ px_msiq_intr(caddr_t arg)
ih_p && (j < ipil_p->ipil_ih_size) &&
((ih_p->ih_msg_code != msg_code) ||
(ih_p->ih_rec_type != msiq_rec_p->msiq_rec_type));
- ih_p = ih_p->ih_next, j++);
+ ih_p = ih_p->ih_next, j++)
+ ;
if ((ih_p->ih_msg_code == msg_code) &&
(ih_p->ih_rec_type == msiq_rec_p->msiq_rec_type)) {
@@ -996,8 +997,21 @@ px_ks_update(kstat_t *ksp, int rw)
if (ih_p->ih_intr_state == PX_INTR_STATE_ENABLE) {
- (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
- (ih_p->ih_rec_type == 0) ? "fixed" : "msi");
+ switch (i_ddi_intr_get_current_type(ih_p->ih_dip)) {
+ case DDI_INTR_TYPE_MSI:
+ (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
+ "msi");
+ break;
+ case DDI_INTR_TYPE_MSIX:
+ (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
+ "msix");
+ break;
+ default:
+ (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
+ "fixed");
+ break;
+ }
+
pxintr_ks_template.pxintr_ks_cpu.value.ui64 = ino_p->ino_cpuid;
pxintr_ks_template.pxintr_ks_pil.value.ui64 = ipil_p->ipil_pil;
pxintr_ks_template.pxintr_ks_time.value.ui64 = ih_p->ih_nsec +
diff --git a/usr/src/uts/sun4/io/px/px_tools.c b/usr/src/uts/sun4/io/px/px_tools.c
index 5bce819abf..bafc8b8f79 100644
--- a/usr/src/uts/sun4/io/px/px_tools.c
+++ b/usr/src/uts/sun4/io/px/px_tools.c
@@ -84,15 +84,33 @@ pxtool_validate_cpuid(uint32_t cpuid)
}
+/*ARGSUSED*/
static int
-pxtool_intr_get_max_ino(uint32_t *arg, int mode)
+pxtool_intr_info(dev_info_t *dip, void *arg, int mode)
{
- if (ddi_copyout(&pxtool_num_inos, arg, sizeof (uint32_t), mode) !=
- DDI_SUCCESS)
+ pcitool_intr_info_t intr_info;
+ int rval = SUCCESS;
+
+ /* If we need user_version, and to ret same user version as passed in */
+ if (ddi_copyin(arg, &intr_info, sizeof (pcitool_intr_info_t), mode) !=
+ DDI_SUCCESS) {
return (EFAULT);
- else
- return (SUCCESS);
+ }
+
+ intr_info.ctlr_version = 0; /* XXX how to get real version? */
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_RISC;
+ intr_info.num_intr = pxtool_num_inos;
+
+ intr_info.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&intr_info, arg, sizeof (pcitool_intr_info_t), mode) !=
+ DDI_SUCCESS) {
+ rval = EFAULT;
+ }
+
+ return (rval);
}
+
+
/*
* Get interrupt information for a given ino.
* Returns info only for inos mapped to devices.
@@ -203,6 +221,7 @@ pxtool_get_intr(dev_info_t *dip, void *arg, int mode)
rval = SUCCESS;
done_get_intr:
+ iget->drvr_version = PCITOOL_VERSION;
copyout_rval =
ddi_copyout(iget, arg, PCITOOL_IGET_SIZE(num_devs_ret), mode);
@@ -231,11 +250,38 @@ pxtool_set_intr(dev_info_t *dip, void *arg, int mode)
px_ib_t *ib_p = px_p->px_ib_p;
uint8_t zero = 0;
int rval = SUCCESS;
+ size_t copyinout_size;
- if (ddi_copyin(arg, &iset, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ bzero(&iset, sizeof (pcitool_intr_set_t));
+
+ /* Version 1 of pcitool_intr_set_t doesn't have flags. */
+ copyinout_size = (size_t)&iset.flags - (size_t)&iset;
+
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
return (EFAULT);
+ switch (iset.user_version) {
+ case PCITOOL_V1:
+ break;
+
+ case PCITOOL_V2:
+ copyinout_size = sizeof (pcitool_intr_set_t);
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
+ return (EFAULT);
+ break;
+
+ default:
+ iset.status = PCITOOL_OUT_OF_RANGE;
+ rval = ENOTSUP;
+ goto done_set_intr;
+ }
+
+ if (iset.flags & PCITOOL_INTR_SET_FLAG_GROUP) {
+ iset.status = PCITOOL_IO_ERROR;
+ rval = ENOTSUP;
+ goto done_set_intr;
+ }
+
iset.status = PCITOOL_INVALID_INO;
rval = EINVAL;
@@ -283,8 +329,8 @@ pxtool_set_intr(dev_info_t *dip, void *arg, int mode)
mutex_exit(&cpu_lock);
done_set_intr:
- if (ddi_copyout(&iset, arg, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ iset.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&iset, arg, copyinout_size, mode) != DDI_SUCCESS)
rval = EFAULT;
return (rval);
@@ -299,9 +345,9 @@ pxtool_intr(dev_info_t *dip, void *arg, int cmd, int mode)
switch (cmd) {
- /* Return the number of interrupts supported by a PCI bus. */
- case PCITOOL_DEVICE_NUM_INTR:
- rval = pxtool_intr_get_max_ino(arg, mode);
+ /* Get system interrupt information. */
+ case PCITOOL_SYSTEM_INTR_INFO:
+ rval = pxtool_intr_info(dip, arg, mode);
break;
/* Get interrupt information for a given ino. */
@@ -655,6 +701,7 @@ pxtool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
rval = pxtool_pciiomem_access(px_p, &prg, &prg.data, write_flag);
done_reg:
+ prg.drvr_version = PCITOOL_VERSION;
if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t),
mode) != DDI_SUCCESS) {
DBG(DBG_TOOLS, dip, "Error returning arguments.\n");
diff --git a/usr/src/uts/sun4u/chicago/io/fpc/fpc-impl-4u.c b/usr/src/uts/sun4u/chicago/io/fpc/fpc-impl-4u.c
index 4899c83369..850501397a 100644
--- a/usr/src/uts/sun4u/chicago/io/fpc/fpc-impl-4u.c
+++ b/usr/src/uts/sun4u/chicago/io/fpc/fpc-impl-4u.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -154,7 +154,7 @@ fpc_platform_node_init(dev_info_t *dip, int *avail)
nodename = kmem_zalloc(nodename_size, KM_SLEEP);
platform_specific_data =
- kmem_zalloc(sizeof (fire4u_specific_t), KM_SLEEP);
+ kmem_zalloc(sizeof (fire4u_specific_t), KM_SLEEP);
(void) strcpy(nodename, name);
(void) strcat(nodename, ":");
@@ -163,7 +163,7 @@ fpc_platform_node_init(dev_info_t *dip, int *avail)
/* Get register banks. */
if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "reg", (caddr_t)&regs_p, &regs_length) != DDI_SUCCESS) {
+ "reg", (caddr_t)&regs_p, &regs_length) != DDI_SUCCESS) {
goto bad_regs_p;
}
@@ -262,7 +262,7 @@ fpc_event_io(fire_perfreg_handle_t handle, fire_perfcnt_t group,
(fire_counter_handle_impl_t *)handle;
int cmd = is_write ? PCITOOL_NEXUS_SET_REG : PCITOOL_NEXUS_GET_REG;
- prg.user_version = PCITOOL_USER_VERSION;
+ prg.user_version = PCITOOL_VERSION;
if (group == jbc) {
prg.barnum = JBUS_BANK;
@@ -303,7 +303,7 @@ fpc_counter_io(fire_perfreg_handle_t handle, fire_perfcnt_t group,
int command =
(is_write) ? PCITOOL_NEXUS_SET_REG : PCITOOL_NEXUS_GET_REG;
- prg.user_version = PCITOOL_USER_VERSION;
+ prg.user_version = PCITOOL_VERSION;
/*
* Note that stated PCIE offsets are relative to the beginning of their
* register bank, while JBUS offsets are absolute.
diff --git a/usr/src/uts/sun4u/io/pci/pci_devctl.c b/usr/src/uts/sun4u/io/pci/pci_devctl.c
index e317de98db..4bd413f06f 100644
--- a/usr/src/uts/sun4u/io/pci/pci_devctl.c
+++ b/usr/src/uts/sun4u/io/pci/pci_devctl.c
@@ -2,9 +2,8 @@
* 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.
+ * Common Development and Distribution License (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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -301,7 +300,7 @@ pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
/*FALLTHRU*/
/* These require no special privileges. */
case PCITOOL_DEVICE_GET_INTR:
- case PCITOOL_DEVICE_NUM_INTR:
+ case PCITOOL_SYSTEM_INTR_INFO:
rv = pcitool_intr_admn(dev, (void *)arg, cmd, mode);
break;
}
diff --git a/usr/src/uts/sun4u/io/pci/pci_tools.c b/usr/src/uts/sun4u/io/pci/pci_tools.c
index 2260447087..0e376c9dcd 100644
--- a/usr/src/uts/sun4u/io/pci/pci_tools.c
+++ b/usr/src/uts/sun4u/io/pci/pci_tools.c
@@ -2,9 +2,8 @@
* 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.
+ * Common Development and Distribution License (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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -268,18 +267,30 @@ pcitool_validate_cpuid(uint32_t cpuid)
}
-/* Return the number of interrupts on a pci bus. */
+/*ARGSUSED*/
static int
-pcitool_intr_get_max_ino(uint32_t *arg, int mode)
+pcitool_intr_info(dev_info_t *dip, void *arg, int mode)
{
- uint32_t num_intr = PCI_MAX_INO;
+ pcitool_intr_info_t intr_info;
+ int rval = SUCCESS;
- if (ddi_copyout(&num_intr, arg, sizeof (uint32_t), mode) !=
+ /* If we need user_version, and to ret same user version as passed in */
+ if (ddi_copyin(arg, &intr_info, sizeof (pcitool_intr_info_t), mode) !=
DDI_SUCCESS) {
return (EFAULT);
- } else {
- return (SUCCESS);
}
+
+ intr_info.ctlr_version = 0; /* XXX how to get real version? */
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_RISC;
+ intr_info.num_intr = PCI_MAX_INO;
+
+ intr_info.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&intr_info, arg, sizeof (pcitool_intr_info_t), mode) !=
+ DDI_SUCCESS) {
+ rval = EFAULT;
+ }
+
+ return (rval);
}
@@ -381,7 +392,7 @@ pcitool_get_intr(dev_info_t *dip, void *arg, int mode, pci_t *pci_p)
}
}
done_get_intr:
- iget->drvr_version = PCITOOL_DRVR_VERSION;
+ iget->drvr_version = PCITOOL_VERSION;
copyout_rval = ddi_copyout(iget, arg,
PCITOOL_IGET_SIZE(num_devs_ret), mode);
@@ -415,11 +426,38 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode, pci_t *pci_p)
uint64_t new_imregval;
volatile uint64_t *imregp;
volatile uint64_t *idregp;
+ size_t copyinout_size;
+
+ bzero(&iset, sizeof (pcitool_intr_set_t));
+
+ /* Version 1 of pcitool_intr_set_t doesn't have flags. */
+ copyinout_size = (size_t)&iset.flags - (size_t)&iset;
- if (ddi_copyin(arg, &iset, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
return (EFAULT);
+ switch (iset.user_version) {
+ case PCITOOL_V1:
+ break;
+
+ case PCITOOL_V2:
+ copyinout_size = sizeof (pcitool_intr_set_t);
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
+ return (EFAULT);
+ break;
+
+ default:
+ iset.status = PCITOOL_OUT_OF_RANGE;
+ rval = ENOTSUP;
+ goto done_set_intr;
+ }
+
+ if (iset.flags & PCITOOL_INTR_SET_FLAG_GROUP) {
+ iset.status = PCITOOL_IO_ERROR;
+ rval = ENOTSUP;
+ goto done_set_intr;
+ }
+
/* Validate input argument and that ino given belongs to a device. */
if ((iset.ino > PCI_MAX_INO) ||
(ib_get_ino_devs(ib_p, iset.ino, &zero, NULL) == 0)) {
@@ -514,9 +552,8 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode, pci_t *pci_p)
rval = EINVAL;
}
done_set_intr:
- iset.drvr_version = PCITOOL_DRVR_VERSION;
- if (ddi_copyout(&iset, arg, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ iset.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&iset, arg, copyinout_size, mode) != DDI_SUCCESS)
rval = EFAULT;
return (rval);
@@ -533,9 +570,9 @@ pcitool_intr_admn(dev_t dev, void *arg, int cmd, int mode)
switch (cmd) {
- /* Return the number of interrupts supported by a PCI bus. */
- case PCITOOL_DEVICE_NUM_INTR:
- rval = pcitool_intr_get_max_ino(arg, mode);
+ /* Get system interrupt information. */
+ case PCITOOL_SYSTEM_INTR_INFO:
+ rval = pcitool_intr_info(dip, arg, mode);
break;
/* Get interrupt information for a given ino. */
@@ -701,7 +738,7 @@ done:
if (pci_rp != NULL)
ddi_prop_free(pci_rp);
- prg.drvr_version = PCITOOL_DRVR_VERSION;
+ prg.drvr_version = PCITOOL_VERSION;
if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), mode) !=
DDI_SUCCESS) {
DEBUG0(DBG_TOOLS, dip, "Copyout failed.\n");
@@ -989,7 +1026,7 @@ pcitool_dev_reg_ops(dev_t dev, void *arg, int cmd, int mode)
}
done_reg:
- prg.drvr_version = PCITOOL_DRVR_VERSION;
+ prg.drvr_version = PCITOOL_VERSION;
if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), mode) !=
DDI_SUCCESS) {
DEBUG0(DBG_TOOLS, dip, "Error returning arguments.\n");
diff --git a/usr/src/uts/sun4u/io/px/px_tools_4u.c b/usr/src/uts/sun4u/io/px/px_tools_4u.c
index 7b9c459bd3..f1d0cb1b2e 100644
--- a/usr/src/uts/sun4u/io/px/px_tools_4u.c
+++ b/usr/src/uts/sun4u/io/px/px_tools_4u.c
@@ -403,6 +403,7 @@ done:
if (px_rp != NULL)
ddi_prop_free(px_rp);
+ prg.drvr_version = PCITOOL_VERSION;
if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t),
mode) != DDI_SUCCESS) {
DBG(DBG_TOOLS, dip, "Copyout failed.\n");
diff --git a/usr/src/uts/sun4v/io/px/px_tools_4v.c b/usr/src/uts/sun4v/io/px/px_tools_4v.c
index a13027ad57..cf0c31c044 100644
--- a/usr/src/uts/sun4v/io/px/px_tools_4v.c
+++ b/usr/src/uts/sun4v/io/px/px_tools_4v.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -516,6 +516,7 @@ pxtool_bus_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
rval = pxtool_phys_access(px_p, prg.phys_addr, &prg.data,
PCITOOL_ACC_IS_BIG_ENDIAN(prg.acc_attr), is_write);
done:
+ prg.drvr_version = PCITOOL_VERSION;
if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t),
mode) != DDI_SUCCESS) {
DBG(DBG_TOOLS, dip, "Copyout failed.\n");