Wednesday June 14, 2006 | Anish's Weblog Anish's Weblog |
|
Yes, OpenSolaris is a Gemini !! It is probably more famous than these Geminis were when they were a year old. Happy Birthday !! Posted by anish ( Jun 14 2006, 09:11:48 AM PDT ) Permalink ::softint added for x64 servers On SPARC based systems, ::softint MDB macro provided software interrupt information. This macro was not ported over to the x64 side. Now, starting with Solaris 11 Build 42 onwards one can get live software interrupt info on the x64 systems. # echo ::softint | mdb -k Note that with Advanced DDI Interrupt Interfaces, interrupt service routines take two arguments (ARG1, ARG2) and the software interrupt identifier is ADDR. Technorati Tag: OpenSolaris Technorati Tag: Solaris Posted by anish ( Jun 12 2006, 12:11:26 PM PDT ) Permalink Equivalent of 'cat /proc/interrupts' New MDB dcmd ::interruptsSolaris Express now has support for a new MDB dcmd ::interrupts that shows similar output to that of 'cat /proc/interrupts' on Linux. Output of ::interrupts on a x64 running 64-bit Solaris Express: (System is using IOAPIC) # echo ::interrupts | mdb -k IRQ Vector IPL Bus Type CPU Share APIC/INT# ISR(s) 3 0xb1 12 ISA Fixed 1 1 0x0/0x3 asyintr 4 0xb0 12 ISA Fixed 1 1 0x0/0x4 asyintr 6 0x42 5 ISA Fixed 3 1 0x0/0x6 fdc_intr 9 0x80 9 PCI Fixed 1 1 0x0/0x9 acpi_wrapper_isr 15 0x41 5 ISA Fixed 2 1 0x0/0xf ata_intr 16 0x81 9 PCI Fixed 1 3 0x0/0x10 hci1394_isr, uhci_intr, uhci_intr 17 0x82 9 PCI Fixed 2 1 0x0/0x11 audio810_intr 18 0x40 5 PCI Fixed 3 3 0x0/0x12 ata_intr, uhci_intr, ata_intr 19 0x22 1 PCI Fixed 1 1 0x0/0x13 uhci_intr 23 0x20 1 PCI Fixed 0 1 0x0/0x17 ehci_intr 24 0x45 5 PCI Fixed 0 1 0x1/0x0 adpu320_intr 48 0x60 6 PCI Fixed 2 1 0x2/0x0 e1000g_intr 72 0x43 5 MSI 3 1 - mpt_intr 73 0x44 5 MSI 3 1 - mpt_intr 160 0xa0 0 IPI ALL 0 - poke_cpu 192 0xc0 13 IPI ALL 1 - xc_serv 208 0xd0 14 IPI ALL 1 - kcpc_hw_overflow_intr 209 0xd1 14 IPI ALL 1 - cbe_fire 210 0xd3 14 IPI ALL 1 - cbe_fire 224 0xe0 15 IPI ALL 1 - xc_serv 225 0xe1 15 IPI ALL 1 - apic_error_intrWhere IPL is the interrupt priority, APIC is the local APIC, Driver name is represented as <driver_name><instance#> and Type shows where Fixed (legacy) or MSI interrupts are being used. IPI interrupt type indicates xcalls. The Share column shows if the interrupt is being shared and by how many. On a uppc(7d) based system, the sample output is shown here # echo ::interrupts | mdb -k > ::interrupts IRQ Vector IPL(lo/hi) Bus Share ISR(s) 0 0x20 14/14 - 1 cbe_fire 3 0x23 12/12 ISA 1 asyintr 4 0x24 12/12 ISA 1 asyintr 5 0x25 1/1 PCI 1 ehci_intr 6 0x26 5/5 ISA 1 fdc_intr 7 0x27 5/5 ISA 1 ecpp_isr 9 0x29 9/9 - 1 acpi_wrapper_isr 10 0x2a 1/9 PCI 3 e1000g_intr, hci1394_isr, uhci_intr 11 0x2b 1/1 PCI 1 uhci_intr 12 0x2c 1/9 PCI 2 uhci_intr, audiovia823x_intr 14 0x2e 5/5 PCI 1 ata_intr 15 0x2f 5/5 PCI 1 ata_intr # echo ::interrupts -d | mdb -k IRQ Vector IPL(lo/hi) Bus Share Driver Name(s) 0 0x20 14/14 - 1 cbe_fire 3 0x23 12/12 ISA 1 asy#1 4 0x24 12/12 ISA 1 asy#0 5 0x25 1/1 PCI 1 ehci#0 6 0x26 5/5 ISA 1 fdc#0 7 0x27 5/5 ISA 1 ecpp#0 9 0x29 9/9 - 1 acpi_wrapper_isr 10 0x2a 1/9 PCI 3 e1000g#0, hci1394#0, uhci#1 11 0x2b 1/1 PCI 1 uhci#0 12 0x2c 1/9 PCI 2 uhci#2, audiovia823x#0 14 0x2e 5/5 PCI 1 ata#0 15 0x2f 5/5 PCI 1 ata#1 On a Niagara based SunFire T2000, the output looks like this: # echo ::interrupts | mdb -k Device Shared Type MSG # State INO Mondo Pil CPU e1000g#1 no MSI 1 enbl 0x19 0x799 6 26 e1000g#0 no MSI 0 enbl 0x18 0x798 6 18 px#0 no PCIe 27 enbl 0x3b 0x7bb 1 30 px#0 no PCIe 51 enbl 0x3a 0x7ba 14 31 px#0 no PCIe 49 enbl 0x39 0x7b9 14 0 px#0 no PCIe 48 enbl 0x38 0x7b8 9 1 e1000g#3 no MSI 2 enbl 0x1a 0x7da 6 28 e1000g#2 no MSI 1 enbl 0x19 0x7d9 6 27 su#0 no Fixed --- enbl 0x2 0x7c2 12 20 uata#0 no Fixed --- enbl 0x4 0x7c4 4 3 ohci#1 no Fixed --- enbl 0x3 0x7c3 9 22 ohci#0 no Fixed --- enbl 0x1 0x7c1 9 23 mpt#0 no MSI 0 enbl 0x18 0x7d8 4 19 px#1 no PCIe 27 enbl 0x3b 0x7fb 1 24 px#1 no PCIe 51 enbl 0x3a 0x7fa 14 25 px#1 no PCIe 49 enbl 0x39 0x7f9 14 26 px#1 no PCIe 48 enbl 0x38 0x7f8 9 27Here interrupt Type PCIe implies it is using PCI Express INTx. On a SunFire V890, (which does not support MSI interrupts, the ouput looks like this: # echo ::interrupts | mdb -k Device Shared Type MSG # State INO Mondo Pil CPU uata#0 no Fixed --- enbl 0x1c 0x21c 4 19 ge#0 no Fixed --- enbl 0x0 0x200 6 7 qlc#0 no Fixed --- enbl 0x4 0x204 4 18 su#1 no Fixed --- enbl 0x2d 0x26d 12 1 su#0 no Fixed --- enbl 0x2e 0x26e 12 0 pcf8584#2 yes Fixed --- enbl 0x28 0x268 4 2 pcf8584#3 yes Fixed --- enbl 0x28 0x268 4 2 eri#0 no Fixed --- enbl 0x1d 0x25d 6 17 ohci#0 no Fixed --- enbl 0x1f 0x25f 9 20 se#0 no Fixed --- enbl 0x22 0x262 12 21 todds1287#0 no Fixed --- enbl 0x24 0x264 15 22 hpc3130#3 no Fixed --- enbl 0x26 0x266 1 23 hpc3130#0 yes Fixed --- enbl 0x27 0x267 1 7 hpc3130#1 yes Fixed --- enbl 0x27 0x267 1 7 hpc3130#2 yes Fixed --- enbl 0x27 0x267 1 7 pcf8584#1 yes Fixed --- enbl 0x23 0x263 4 0 pcf8584#0 yes Fixed --- enbl 0x23 0x263 4 0 Technorati Tag: OpenSolaris Technorati Tag: Solaris Posted by anish ( Apr 14 2006, 08:29:15 AM PDT ) Permalink New Article on Advanced DDI interrupt interfaces Advanced DDI Interrupt Handlers. Thanks to John Stearns for making it possible. Technorati Tag: OpenSolaris Technorati Tag: Solaris Posted by anish ( Mar 29 2006, 01:54:26 PM PST ) Permalink use MSIs (if the underlying hardware is capable) has increased. List includes:
In addition, the following drivers use the new Advanced DDI Interrupt Framework natively.
Technorati Tag: OpenSolaris Technorati Tag: Solaris Posted by anish ( Dec 28 2005, 06:47:50 PM PST ) Permalink Comments [0] Solaris b26: changes to DDI interrupt interfaces More legacy DDI interrupt interfaces are obsoletedWith Solaris b26 the following DDI Interrupt interfaces and data structures are being obsoleted:
See modified Appendix B of the latest Solaris Express WDD that maps above obsoleted interfaces, data structures to the new DDI Interrupt interfaces and data structures respectively. We strongly urge the device driver developers to start using the new interrupt DDI Interfaces Technorati Tag: OpenSolaris Technorati Tag: Solaris Posted by anish ( Nov 04 2005, 11:47:28 AM PST ) Permalink Comments [1] Solaris Express 6/05 WDD released Technorati Tag: OpenSolaris Technorati Tag: Solaris Posted by anish ( Jul 11 2005, 02:14:43 PM PDT ) Permalink Comments [0] Solaris Express 6/05 announces new DDI interrupt interfaces Check out What's new in Solaris Express 6/05. Posted by anish ( Jul 11 2005, 01:52:50 PM PDT ) Permalink Comments [1] Device Driver Development: How to add interrupts in a driver New DDI interrupt interfacesThis writeup is about the new DDI interrupt interfaces introduced in OpenSolaris.The older DDI interrupt interfaces are being replaced for the following reasons:
IMPORTANT: See Advanced Interrupt Handlers added recently to developer.sun.com that replaced most of this blog. Topics not covered there are still retained here. New DDI Interrupt Data structures
See OpenSolaris source code
that
defines data structures to be used with the new DDI interrupt
framework: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Legacy Interrupt Functions | Replacements (Recommended) |
|---|---|
|
ddi_add_intr(9F) |
Three-step process:
|
| ddi_add_softintr(9F) | ddi_intr_add_softint(9F) |
| ddi_dev_nintrs(9F) | ddi_intr_get_nintrs(9F) |
| ddi_get_iblock_cookie(9F) | Three-step process:
|
| ddi_get_soft_iblock_cookie(9F) | Three-step process:
|
| ddi_intr_hilevel(9F) | ddi_intr_get_hilevel_pri(9F) |
| ddi_remove_intr(9F) | ddi_intr_remove_handler(9F) |
| ddi_remove_softintr(9F) | ddi_intr_remove_softint(9F) |
| ddi_trigger_softintr(9F) | ddi_intr_trigger_softint(9F) |
| ddi_idevice_cookie(9S) | Not applicable |
| ddi_iblock_cookie(9S) for mutex_init(9F) etc. |
(void *)(uintptr_t) |
/* Change the soft interrupt priority to 9 */
if (ddi_intr_set_softint_pri(mydev->mydev_softint_hdl, 9) !=
DDI_SUCCESS) {
cmn_err (CE_WARN, "ddi_intr_set_softint_pri failed");
}
/* Check if an interrupt is pending */
if (ddi_intr_get_pending(mydevp->htable[0], &pending) != DDI_SUCCESS) {
cmn_err(CE_WARN, "ddi_intr_get_pending() failed");
} else if (pending)
cmn_err(CE_NOTE, "ddi_intr_get_pending(): Interrupt pending");
/* Set interrupt masking to prevent device from receiving interrupts */
if ((ddi_intr_set_mask(mydevp->htable[0]) != DDI_SUCCESS))
cmn_err(CE_WARN, "ddi_intr_set_mask() failed");
/* Clear interrupt masking. If successful device will start generating interrupts */
if (ddi_intr_clr_mask(mydevp->htable[0]) != DDI_SUCCESS)
cmn_err(CE_WARN, "ddi_intr_clr_mask() failed");
Hardware interrupts overview for Solaris X86
Welcome to OpenSolaris, and the wonders of Solaris 10.
This paper provides a brief introduction to hardware interrupts on x86 platforms. It is relevant for Intel and AMD based platforms. Interrupt handling is done via interrupt controller hardware in the system which are mostly sideband signals. Inband interrupts, for e.g. Message Signalled Interrupts (MSIs), introduced with PCI v2.2 specification onwards, will be discussed in another blog. MSIs are becoming mainstay with advent of new interrconnects like PCI-Express.
However, there are mainly two kinds of hardware interrupt controllers which are commonly used on x86 platforms:
This is supported by the Solaris uppc(7d) module and its source is located at usr/src/uts/i86pc/io/psm/uppc.c. Each PIC can handle 8 vectored priority interrupting sources and there are two PICs cascaded together to provide 16 interrupts on x86 systems. However, one of the pin - IRQ2 of the 1st PIC is used to cascade the 2nd PIC and so there are only 15 interrupt sources. This can not be used for multiprocessor (MP) systems without any major modifications.
This is supported by the Solaris pcplusmp(7d) module and its source is located at usr/src/uts/i86pc/io/pcplusmp/apic.c. It consists of two components - I/O APIC and Local APIC. The Local APIC is embedded in the CPU while the I/O APIC is used for connecting the interrupting sources. The Local APIC also has the capability to send interprocessor interrupt from one cpu to another and so APIC is widely used on all the x86 MP systems. Each system can have multiple I/O APICs and each I/O APIC can have 4, 16, 20 or 24 interrupt pins. Since the Local APIC is embedded in the CPU and the I/O APIC can handle more than 16 interrupt sources, even the single-CPU systems uses APIC as well instead of some other hardware.
There are many systems, which have I/O APICs with 4 inputs(this is typically done for PCI-X slotted systems, where each slot is given a dedicated I/O APIC, enabling INTA-INTD for each of the slots to have a dedicated input).
Solaris supports multiple I/O APICs.
processor #1 processor #2
+-----------+ +-----------+
| | | |
| CPU | | CPU |
| | | |
+-----------+ +-----------+
| local APIC| | local APIC|
+-----------+ +-----------+
^ ^
| |
| |
| |
v v Processor system bus
<----------------------------------------------------------------->
^
|
|
|
+-----------------------------+
| | |
| v |
| +--------+ |
| | | |
| | Bridge | |
| | | |
| +--------+ |
| ^ |
| | |
| v PCI |
| <------------------> |
| ^ |
| | |
| v |
| +----------+ |
| | | |
| | I/O APIC |<-----|---External
| | |<-----|---Interrupts
| +----------+ |
| |
+-----------------------------+
System Chip set
When a device driver adding the interrupt through ddi_add_intr(9f),
it
eventually gets to uppc_addspl() in uppc(7d) for PIC or apic_addspl() in pcplusmp(7d) if using APIC. The interrupt pin will be identified and then enabled. It is quite simple for the uppc(7d) case, the interrupt pin to enable on the PICs is basically 1-1 mapped to the "IRQ#" or the
"interrupt" property of the device on Solaris. But for APIC (pcplusmp(7d)), it is a lot more complicated as internally it either
uses the MP Spec. 1.4[2] or ACPI specification[3] to locate the right interrupt pin of the right I/O APIC for the device. The system BIOS sets up how the interrupts are routed and saves that information in either the MP Specification table or somewhere that ACPI can easily access. pcplusmp(7d) then access that information to initialize and add the interrupts.
During the ddi_add_intr(9f) call, the device interrupt handler's entry point is stored in the autovect[] and the interrupt pin will be enabled through uppc_addspl (for PCI) or apic_addspl(for APIC). Also, before the interrupt pin is enabled, an interrupt "vector" (refered to as "vector" from now on) will have to be selected for the CPU to trigger when that particular interrupt comes in. For Intel CPUs, there are total 256 vectors and the first 32 vectors are reserved for special functions and so the first available vector for devices is 32 (or hex 0x20).
For uppc(7d), vectors are set up such that the 1st pin or IRQ#0 is mapped to 32, IRQ1 to 33 and
so on. As for pcplusmp(7d), it is not as simple. Solaris handles interrupts based on interrupt priority and each device is assigned a unique priority (can be modified by the device driver). Say, if a device "abc" is assigned priority 5, then all other interrupts at 5 or lower can NOT be triggered when the interrupt handler of "abc" is executing. However, an interrupt of priority 6 or higher is allowed to trigger. Since APIC has mechanism to prioritize interrupts, pcplusmp(7d) needs to select the vectors accordingly.
In order to handle the interrupt priority properly, there are few internal interface calls provided by uppc(7d) and pcplusmp(7d). They are the uppc_intr_enter()/uppc_intr_exit() for the uppc(7d); and apic_intr_enter()/apic_intr_exit() for pcplusmp(7d). After the interrupt is triggered but before the interrupt handler is called, uppc_intr_enter() or apic_intr_enter() will be called to setup the interrupt priority accordingly to block all other interrupts with the same or lower priority. After the interrupt handler is completed, then uppc_intr_exit() or apic_intr_exit() is called to restore the interrupt priority.
On the x86 platform, all the local variables of the interrupt handler are on stack. Also, if the interrupt handler needs to call another
function, the parameters that are passed to the function are on stack too. i.e. all the interrupt handlers should use the stack one way or
the other.
usr/src/uts/common/io/avintr.c
#define MAX_VECT 256
struct av_head autovect[MAX_VECT];
usr/src/uts/common/sys/avintr.h
struct autovec {
/*
* Interrupt handler and argument to pass to it.
*/
struct autovec *av_link; /* pointer to next on in chain */
uint_t (*av_vector)();
caddr_t av_intarg;
uint_t av_prilevel; /* priority level */
/*
* Interrupt handle/id (like intrspec structure pointer) used to
* identify a specific instance of interrupt handler in case we
* have to remove the interrupt handler later.
*
*/
void *av_intr_id;
dev_info_t *av_dip;
};
av_vector is the device interrupt handler.
struct av_head {
struct autovec *avh_link;
ushort_t avh_hi_pri;
ushort_t avh_lo_pri;
};
- All interrupts run at some priority which has a ceiling of LOCK_LEVEL.
Interrupts below LOCK_LEVEL run as threads.
usr/src/uts/intel/sys/machlock.h
#define CLOCK_LEVEL 10
#define LOCK_LEVEL 10
- The following sequence shows what is done for each CPU to allocate
enough interrupt threads to handle the interrupts. Since interrupts
are prioritized, one interrupt thread per priority should be sufficient.
usr/src/uts/i86pc/os/mp_startup.c
void
start_other_cpus(int cprboot)
{
for (who = 0; who < NCPU; who++) {
mp_startup_init(who);
...
}
void
mp_startup_init(void)
{
init_intr_threads(cp);
...
}
usr/src/uts/i86pc/os/intr.c
/*
* Allocate threads and stacks for interrupt handling.
*/
#define NINTR_THREADS (LOCK_LEVEL-1) /* number of interrupt threads */
void
init_intr_threads(struct cpu *cp)
{
int i;
for (i = 0; i < NINTR_THREADS; i++)
(void) thread_create_intr(cp);
...
}
usr/src/uts/common/disp/thread.c
void
thread_create_intr(struct cpu *cp)
{
- Here is the actual code handling the interrupts on x86.
*setlvl is the wrapper for uppc_intr_enter() or apic_intr_enter().
}
NOTE: Calling the interrupt handler is done in low level assembly code
which is not discussed here.
Device Type |
Attachment Type format |
| Port Devices |
ib::PORT_GUID,0,service-name |
| HCA_SVC devices |
ib::HCA_GUID,0,servicename |
| VPPA devices |
ib::PORT_GUID,P_Key,service-name |
| IOC devices |
ib::IOC-GUID |
| Pseudo devices |
ib::driver_name,unit-address |
Static attachment |
Attachment type format |
| IB Fabric |
ib |
| Host Channel Adapter(s) |
hca:HCA-GUID |
# cfgadm -a ib hca:2C90109764440 Ap_Id Type Receptacle Occupant Condition hca:2C90109764440 IB-HCA connected configured ok ib IB-Fabric connected configured ok ib::2C90109764440,0,svch IB-HCA_SVC connected unconfigured unknown ib::2C90109764441,0,psvc IB-PORT connected unconfigured unknown ib::2C90109764441,ffff,ipib IB-VPPA connected unconfigured unknown ib::2C90109764442,0,psvc IB-PORT connected unconfigured unknown ib::2C90109764442,ffff,ipib IB-VPPA connected unconfigured unknown ib::daplt,0 IB-PSEUDO connected configured ok ib::rpcib,0 IB-PSEUDO connected configured ok #
# cfgadm -x list_clients hca:2C90109764440 Ap_Id IB Client Alternate HCA ib::daplt,0 daplt no ib::rpcib,0 nfs/ib no - ibmf no - ibdm no #
# cfgadm -a ib::daplt,0 Ap_Id Type Receptacle Occupant Condition ib::daplt,0 IB-PSEUDO connected unconfigured unknown # cfgadm -yc configure ib::daplt,0 # cfgadm -a ib::daplt,0 Ap_Id Type Receptacle Occupant Condition ib::daplt,0 IB-PSEUDO connected configured ok #Unconfiguring a device:
# cfgadm -a ib::daplt,0 Ap_Id Type Receptacle Occupant Condition ib::daplt,0 IB-PSEUDO connected configured ok # cfgadm -yc unconfigure ib::daplt,0 # cfgadm -a ib::daplt,0 Ap_Id Type Receptacle Occupant Condition ib::daplt,0 IB-PSEUDO connected unconfigured unknownThe example below shows how to unconfigure all kernel clients of a give InfiniBand Host Channel Adapter.
# cfgadm -x unconfig_clients hca:2C90109764440 Unconfigure Clients of HCA /devices/ib:2C90109764440 This operation will unconfigure IB clients of this HCA Continue (yes/no)? yes <<<<<<< #
# cfgadm -x list_services ib
PORT communication services:
psvc
VPPA communication services:
ipib
HCA communication services:
svch
# cfgadm -o comm=port,service=srp -x add_service ib
# cfgadm -x list_services ib
PORT communication services:
srp <<<<<<<<<<<<<<
psvc
VPPA communication services:
ipib
HCA communication services:
svch
#
Delete a communication service:
# cfgadm -x list_services ib
PORT communication services:
srp
psvc
VPPA communication services:
ipib
HCA communication services:
svch
# cfgadm -o comm=port,service=srp -x delete_service ib
# cfgadm -x list_services ib
PORT communication services:
psvc
VPPA communication services:
ipib
HCA communication services:
svch
#
Note that the examples are shown only for Port Devices but are applicable to all three device types.
port-list, port-entries, service-id, and service-name
| Archives | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Language | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Links | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Referrers | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Today's Page Hits: 18 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||