现在的位置: 首页 > 综合 > 正文

Solaris Source Insight: PCI bus driver moduls – npe Part 5

2013年06月10日 ⁄ 综合 ⁄ 共 8871字 ⁄ 字号 评论关闭

    Fri Nov 13
    14:19:32 CST 2009


  • DDI_INTROP_NAVAIL/DDI_INTROP_NINTRS

Return the number of supported interrupt number. If
MSI/X supported, the responding capability registers will tell the
number. Otherwise, the interrupt number was saved in parent private
data of devinfo node.

 

[i86pc/os/ddi_impl.c]

925 int

926 i_ddi_get_intx_nintrs(dev_info_t *dip)

927 {

928 |_______struct ddi_parent_private_data *pdp;

929

930 |_______if ((pdp = ddi_get_parent_data(dip)) ==
NULL)

931 |_______|_______return (0);

932

933 |_______return (pdp->par_nintr);

934 }

 

Let's roll back to check what kind of things passed to
npe_intr_ops().

 

[i86pc/io/pciex/npe.c]

829 /*

830 * npe_intr_ops

831 */

832 static int

833 npe_intr_ops(dev_info_t *pdip, dev_info_t *rdip,
ddi_intr_op_t intr_op,

834 ddi_intr_handle_impl_t *hdlp, void *result)

835 {

836 |_______return (pci_common_intr_ops(pdip, rdip,
intr_op, hdlp, result));

837 }

 

pdip – the bus devinfo node

rdip – the leaf devinfo node which issued the request

intr_op – interrupt ops, following operations
supported

 

[common/sys/ddi_intr_impl.h]

42 /*

43 * Typedef for interrupt ops

44 */

45 typedef enum {

46 |_______DDI_INTROP_SUPPORTED_TYPES = 1,|/* 1 get
supported interrupts types */

47 |_______DDI_INTROP_NINTRS,|_____|_______/* 2 get num
of interrupts supported */

48 |_______DDI_INTROP_ALLOC,|______|_______/* 3
allocate interrupt handle */

49 |_______DDI_INTROP_GETPRI,|_____|_______/* 4 get
priority */

50 |_______DDI_INTROP_SETPRI,|_____|_______/* 5 set
priority */

51 |_______DDI_INTROP_ADDISR,|_____|_______/* 6 add
interrupt handler */

52 |_______DDI_INTROP_DUPVEC,|_____|_______/* 7
duplicate interrupt handler */

53 |_______DDI_INTROP_ENABLE,|_____|_______/* 8 enable
interrupt */

54 |_______DDI_INTROP_BLOCKENABLE,||_______/* 9 block
enable interrupts */

55 |_______DDI_INTROP_BLOCKDISABLE,|_______/* 10 block
disable interrupts */

56 |_______DDI_INTROP_DISABLE,|____|_______/* 11
disable interrupt */

57 |_______DDI_INTROP_REMISR,|_____|_______/* 12 remove
interrupt handler */

58 |_______DDI_INTROP_FREE,|_______|_______/* 13 free
interrupt handle */

59 |_______DDI_INTROP_GETCAP,|_____|_______/* 14 get
capacity */

60 |_______DDI_INTROP_SETCAP,|_____|_______/* 15 set
capacity */

61 |_______DDI_INTROP_SETMASK,|____|_______/* 16 set
mask */

62 |_______DDI_INTROP_CLRMASK,|____|_______/* 17 clear
mask */

63 |_______DDI_INTROP_GETPENDING,|_|_______/* 18 get
pending interrupt */

64 |_______DDI_INTROP_NAVAIL,|_____|_______/* 19 get
num of available interrupts */

65 |_______DDI_INTROP_GETPOOL,|____|_______/* 20 get
resource management pool */

66 |_______DDI_INTROP_GETTARGET,|__|_______/* 21 get
target for a given intr(s) */

67 |_______DDI_INTROP_SETTARGET|___|_______/* 22 set
target for a given intr(s) */

68 } ddi_intr_op_t;

 

hdlp – the implementation structure for DDI interrupt
handling

result – the returned result data

 

[common/sys/ddi_intr_impl.h]

74 /*

75 * One such data structure is allocated per
ddi_intr_handle_t

76 * This is the incore copy of the regular interrupt
info.

77 */

78 typedef struct ddi_intr_handle_impl {

79 |_______dev_info_t|_____|_______*ih_dip;|_______/*
dip associated with handle */

80 |_______uint16_t|_______|_______ih_type;|_______/*
interrupt type being used */

81 |_______ushort_t|_______|_______ih_inum;|_______/*
interrupt number */

82 |_______uint32_t|_______|_______ih_vector;|_____/*
vector number */

83 |_______uint16_t|_______|_______ih_ver;||_______/*
Version */

84 |_______uint_t|_|_______|_______ih_state;|______/*
interrupt handle state */

85 |_______uint_t|_|_______|_______ih_cap;||_______/*
interrupt capabilities */

86 |_______uint_t|_|_______|_______ih_pri;||_______/*
priority - bus dependent */

87 |_______krwlock_t|______|_______ih_rwlock;|_____/*
read/write lock per handle */

… …

125 } ddi_intr_handle_impl_t;

 

This structure will be passed through different
functions for DDI interrupt handling. Type, inum, vector are basic to
understand the implementation. Specific interrupts are always
specified by the combination of interrupt type and inum. For legacy
devices, inum refers to the nth interrupt, typically as defined by
the devices interrupts property. For PCI fixed interrupts, inum
refers to the interrupt number. The inum is the relative interrupt
vector number, from 0 to 31 for MSI, from 0 to 2047 for MSI-X.
The first interrupt vector is 0. The last relative vector is 31
for MSI or 2047 for MSI-X. Three interrupt types are defined in
Solaris DDI.

 

[common/sys/ddi_intr.h]

61 /* Hardware interrupt types */

62 #define|DDI_INTR_TYPE_FIXED|____0x1

63 #define|DDI_INTR_TYPE_MSI|______0x2

64 #define|DDI_INTR_TYPE_MSIX|_____0x4

 

The second piece of interrupt data is stored as ddi
parent private data. It's created for both fixed interrupt and MSI/X
interrupt types.

 

[i86pc/io/pci/pci_common.c]

134 /*

135 * Create the ddi_parent_private_data for a pseudo
child.

136 */

137 void

138 pci_common_set_parent_private_data(dev_info_t *dip)

139 {

140 |_______struct ddi_parent_private_data *pdptr;

141

142 |_______pdptr = (struct ddi_parent_private_data
*)kmem_zalloc(

143 |_______ (sizeof (struct
ddi_parent_private_data) +

144 |_______ sizeof (struct intrspec)), KM_SLEEP);

145 |_______pdptr->par_intr = (struct intrspec
*)(pdptr + 1);

146 |_______pdptr->par_nintr = 1;

147 |_______ddi_set_parent_data(dip, pdptr);

148 }

 

[common/sys/ddi_impldefs.h]

735 /*

736 * parent private data structure contains register,
interrupt, property

737 * and range information.

738 */

739 struct ddi_parent_private_data {

740 |_______int par_nreg;|__|_______|_______/* number
of regs */

741 |_______struct regspec *par_reg;|_______/* array of
regs */

742 |_______int par_nintr;|_|_______|_______/* number
of interrupts */

743 |_______struct intrspec *par_intr;|_____/* array of
possible interrupts */

744 |_______int par_nrng;|__|_______|_______/* number
of ranges */

745 |_______struct rangespec *par_rng;|_____/* array of
ranges */

746 };

747 #define|DEVI_PD(d)|_____/

748 |_______((struct ddi_parent_private_data
*)DEVI((d))->devi_parent_data)

 

[common/sys/ddi_intr_impl.h]

390 /*

391 * This structure represents one interrupt possible
from the given

392 * device. It is used in an array for devices with
multiple interrupts.

393 */

394 struct intrspec {

395 |_______uint_t intrspec_pri;|___|_______/* interrupt
priority */

396 |_______uint_t intrspec_vec;|___|_______/* vector #
(0 if none) */

397 |_______uint_t (*intrspec_func)();|_____/* function
to call for interrupt, */

398 |_______|_______|_______|_______|_______/* If
(uint_t (*)()) 0, none. */

399 |_______|_______|_______|_______|_______/* If
(uint_t (*)()) 1, then */

400 };

 

The third piece of data related to ddi interrupt is
stored in devinfo structure.

 

126 struct dev_info {

...

237 |_______/* Owned by DDI interrupt framework */

238 |_______devinfo_intr_t|_*devi_intr_p;

… …

276 };

 

[common/sys/ddi_intr_impl.h]

273 /*

274 * One such data structure is allocated for each
dip.

275 * It has interrupt related information that can be

276 * stored/retrieved for convenience.

277 */

278 typedef struct devinfo_intr {

279 |_______/* These three fields show what the device
is capable of */

280 |_______uint_t|_|_______devi_intr_sup_types;|___/*
Intrs supported by device */

281

282 |_______ddi_intr_msix_t|*devi_msix_p;|__|_______/*
MSI-X info, if supported */

283

284 |_______/* Next three fields show current status for
the device */

285 |_______uint_t|_|_______devi_intr_curr_type;|___/*
Interrupt type being used */

286 |_______uint_t|_|_______devi_intr_sup_nintrs;|__/*
#intr supported */

287 |_______uint_t|_|_______devi_intr_curr_nintrs;|_/*
#intr currently being used */

288 |_______/*

289 |_______ * #intr currently being enabled

290 |_______ * (for MSI block enable, the valuse is
either 1 or 0.)

291 |_______ */

292 |_______uint_t|_|_______devi_intr_curr_nenables;

293

294 |_______ddi_intr_handle_t *devi_intr_handle_p;|_/*
Hdl for legacy intr APIs */

295

296 #if defined(__i386) || defined(__amd64)

297 |_______/* Save the PCI config space handle */

298 |_______ddi_acc_handle_t devi_cfg_handle;

299 |_______int|____|_______ devi_cap_ptr;|_|_______/*
MSI or MSI-X cap pointer */

300 #endif

301

302 |_______ddi_irm_req_t|__*devi_irm_req_p;|_______/*
IRM request information */

303 } devinfo_intr_t;

 

  • DDI_INTROP_ALLOC/DDI_INTROP_FREE

Allocate
and free the interrupt vectors. Allocate interrupts of the
interrupt type beginning at the interrupt number inum.
ddi_intr_alloc(9F) will call this function for purpose. If MSI/X is
supported, the actual operation is accomplished through
psm_intr_ops() which is specified in psm module.


 

[i86pc/io/pci/pci_common.c]


359
|_______|_______|_______/*



360
|_______|_______|_______ * Allocate interrupt vectors



361
|_______|_______|_______ */



362
|_______|_______|_______(void) (*psm_intr_ops)(rdip, hdlp,



363
|_______|_______|_______ PSM_INTR_OP_ALLOC_VECTORS, result);


 

  • DDI_INTROP_GETPRI/DDI_INTROP_SETPRI

Interrupt priority is stored at
DEVI(dip)->devi_parent_data->par_intr->intrspec_pri. To
set/change the interrupt priority, platform level psm_intr_ops() must
be called. Two broad classes of interrupt: High-level and normal
interrupts are defined. Most interrupts on the system are normal
interrupts. Seldom must a device be configured to a high-level
interrupt
.

 

[i86pc/io/pci/pci_common.c]

459 |_______case
DDI_INTROP_SETPRI:

460 |_______|_______/*
Validate the interrupt priority passed */

461 |_______|_______if
(*(int *)result > LOCK_LEVEL)

462
|_______|_______|_______return (DDI_FAILURE);

 

High-level interrupts are handled much
like traditional UNIX interrupts
. A high-level interrupt has no
process or thread context of its own
. A high-level interrupt may not
block for any reason
. A high-level ISR may only call
mutex_enter(9F), the associated
mutex_exit(9F), and
ddi_trigger_softintr(9F)

  • DDI_INTROP_ADDISR/DDI_INTROP_REMISR

    Add and remove ispec.

  • DDI_INTROP_GETCAP/DDI_INTROP_SETCAP

  • DDI_INTROP_ENABLE/DDI_INTROP_DISABLE

  • DDI_INTROP_BLOCKDISABLE/DDI_INTROP_BLOCKENABLE

    Rely on pcplusmp psm_intr_ops().

 

To be continued …

抱歉!评论已关闭.