DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
SCO OpenServer

idistributed(D3oddi)


idistributed -- dynamically register an interrupt handler

Syntax

#include <sys/devreg.h>
#include <sys/ci/ciintr.h>

void idistributed(driver_info *dip);

Description

The idistributed( ) function is used by device drivers to dynamically register an interrupt handler with the kernel. This function should be used for all single-threaded and multithreaded device drivers except SCSI host adapter drivers, which should use the Sharegister(D3osdi) function.

Arguments


dip
Pointer to the driver_info(D4oddi) strucure.

Return values

None.

Usage

Context and synchronization

Initialization context

Hardware applicability

All

Version applicability

oddi: 3mp, 4mp, 5mp, 6mp

Differences between versions

Earlier releases used the add_intr_handler(D3oddi) function to register the driver's interrupt handler. Calls to add_intr_handler( ) must be replaced with calls to idistributed( ), to dynamically register interrupt handlers if the driver is multithreaded or controls a PCI device. It is recommended that drivers for SCO OpenServer use idistributed( ) in all cases.

SVR5 DDI compatibility

This function is not supported for DDI drivers. See ``Interrupt handlers, attaching and registering'' in HDK Technical Reference for information about attaching interrupts for DDI drivers.

References

bdistributed(D3oddi), cdistributed(D3oddi), get_intr_arg(D3oddi), init(D2oddi), intr(D2oddi), remap_driver_cpu(D3oddi), sdevice(F), sdistributed(D3oddi), Sharegister(D3osdi)

``Interrupt handlers, attaching and registering'' in HDK Technical Reference, ``Multithreaded drivers'' in HDK Technical Reference, ``Linking and testing SCO OpenServer 5 drivers'' in Developing SCO OpenServer 5 kernel drivers

Examples

Two examples are provided for calling idistributed( ). The first shows how to dynamically register interrupts in a driver that can support devices on either a PCI or non-PCI bus. The second is a code fragment for an MDI driver that illustrates how to provide separate interrupt service routines for several boards.

Example 1

This example shows a driver's open(D2oddi) and init(D2oddi) routines. This driver is written to support boards that are on either a PCI or a non-PCI bus. It is assumed the driver is capable of controlling both PCI and non-PCI devices, which is how most drivers should be coded.
   #include "sys/devreg.h"
   #include "sys/ci/ciintr.h"
   #include "sys/pci.h"
   

#define PCI_DEVICE 1 #define NONPCI_DEVICE 2

extern struct xx_adapter_info xx_adapter_info[]; extern xx_processor, xx_weight, xx_ipl;

xxopen() { static int first_time = 1; struct xx_adapter_info *ptr; int y;

...

if (first_time) {

/* * Determine the (32-bit) argument passed to the interrupt * routine for all PCI devices controlled by this driver. * Note that this can also be done at interrupt time but NOT * at init time. */

for (y = 0; y < NADAPTERS; y++) { ptr = &xx_adapter_info[y];

if (ptr->type != PCI_DEVICE) continue;

ptr->intr_arg = get_intr_arg(ptr->bus, IDIST_PCI_IRQ(ptr->device, ptr->function));

} first_time = 0; }

... }

   xxinit()
   {
           int y, bus, device, function;
           struct pci_businfo businfo;
           struct pci_devinfo devinfo;
           driver_info     di;
           ...
           /*
            * Find all adapters that can be controlled by this driver.
            * Note that we must search the PCI buses first because it is
            * possible that a device on a PCI bus may have an IO base address
            * in the EISA/ISA range.
            */
           if (pci_buspresent(&businfo)) {
   

for (y = 0; y < NADAPTERS, y++) {

/* * Note that any or all of xx_vendorID, xx_deviceID, * xx_baseclass, or xx_subclass may be wildcards. */ if (pci_search(xx_vendorID, xx_deviceID, xx_baseclass, xx_subclass, y, &devinfo)) { xx_adapter_info[y].found = 1; xx_adapter_info[y].type = PCI_DEVICE; xx_adapter_info[y].bus = devinfo.busnum; xx_adapter_info[y].device = devinfo.slotnum; xx_adapter_info[y].function = devinfo.funcnum; } else { xx_adapter_info[y].found = 0; break; } } }
/* * Now search for all non-PCI adapters. * Note that this will be adapter specific code. */

for ( ; y < NADAPTERS; y++) { if (xx_adapter_found()) { xx_adapter_info[y].found = 1; xx_adapter_info[y].type = NONPCI_DEVICE; } else { xx_adapter_info[y].found = 0; break; } }

for (y = 0; y < NADAPTERS; y++){ if (!xx_adapter_info[y].found) continue;

di.name = "xx"; di.weight = xx_weight; di.ipl = xx_ipl; di.route = IROUTE_GLOBAL; di.mode = IMODE_SHARED_CDRIVERIPL;

                   /*
                    * It is assumed that this driver is second level
                    * multithreaded and is able to field interrupts on
                    * all available processors. If this is not true then
                    * processor_mask should be set to 1 (this will restrict
                    * interrupts to the base cpu only).
                    */
   

di.processor_mask = remap_driver_cpu(xx_processor, ICPU_EXANY);

if (xx_adapter_info[y].type == PCI_DEVICE) { di.version = DRV_INFO_VERS_2; di.irq = IDIST_PCI_IRQ(xx_adapter_info[y].device, xx_adapter_info[y].function); di.bus = xx_adapter_info[y].bus; } else { di.version = DRV_INFO_VERS_1; di.irq = xx_adapter_info[y].irq; }

idistributed(&di); /* note - argument can be local */ }

... }

Example 2

This code fragment is from the init(D2oddi) routine of a multithreaded MDI driver that can support up to four network cards. It provides separate interrupt service routines (ISRs) for each board (lines 4-21). Each ISR is simply a wrapper routine that calls a common interrupt handler. Lines 28-41 populate a driver_info structure then call idistributed( ) with that structure as an argument.

Providing separate ISRs for each supported device improves performance and scalability for drivers that run on configurations that support distributed interrupts, since multiple interrupt contexts can run concurrently and independently on separate processors. This practice also provides the flexibility to, for example, allow the processing that is specific to a particular network to be bound to a particular processor.

  1 extern int XX_irq[];
  2 extern void (*XX_intrs[]) ();
  3 extern int XX_processor[];
   

4 extern dev_t XXdevice[]; 5 void XXintr0(int lev) 6 { 7 XX_common_intr(lev, XXdevice); 8 } 9 void XXintr1(int lev) 10 { 11 XX_common_intr(lev, XXdevice + 1); 12 } 13 void XXintr2(int lev) 14 { 15 XX_common_intr(lev, XXdevice + 2); 16 } 17 void XXintr3(int lev) 18 { 19 XX_common_intr(lev, XXdevice + 3); 20 } 21 void (*XX_intrs[])() = {XXintr0, XXintr1, XXintr2, XXintr3 };

22 int XX_Processor[] = { 23 DRIVER_CPU_DEFAULT, 24 DRIVER_CPU_DEFAULT, 25 DRIVER_CPU_DEFAULT, 26 DRIVER_CPU_DEFAULT 27 };

28 for (board_index = 0; board_index < NUMDEVICES; board_index++) { 29 driver_info di;

30 di.version = DRV_INFO_VERS_1; 31 di.name = "XX"; 32 di.irq = XX_irq[board_index]; 33 di.iosaddr = 0; 34 di.ioeaddr = 0; 35 di.weight = SPL5; 36 di.intr = (int (*)())XX_intrs[board_index]; 37 di.ipl = SPL5; 38 di.route = IROUTE_GLOBAL; 39 di.mode = IMODE_SHARED_CDRIVERIPL;

40 di.processor_mask = remap_driver_cpu(XX_Processor[board_index], ICPU_EXANY);

41 idistributed(&di); 42 }


19 June 2005
© 2005 The SCO Group, Inc. All rights reserved.
OpenServer 5 HDK - June 2005