Solaris Source Insight: PCI bus driver moduls
<!-- @page { margin: 0.79in }P { margin-bottom: 0.08in }-->Fri Nov 1314:19:32 CST 2009
[*]DDI_INTROP_NAVAIL/DDI_INTROP_NINTRS
Return the number of supported interrupt number. IfMSI/X supported, the responding capability registers will tell thenumber. Otherwise, the interrupt number was saved in parent privatedata of devinfo node.
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 tonpe_intr_ops().
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 operationssupported
42 /*
43* Typedef for interrupt ops
44*/
45 typedef enum {
46 |_______DDI_INTROP_SUPPORTED_TYPES = 1,|/* 1 getsupported interrupts types */
47 |_______DDI_INTROP_NINTRS,|_____|_______/* 2 get numof interrupts supported */
48 |_______DDI_INTROP_ALLOC,|______|_______/* 3allocate interrupt handle */
49 |_______DDI_INTROP_GETPRI,|_____|_______/* 4 getpriority */
50 |_______DDI_INTROP_SETPRI,|_____|_______/* 5 setpriority */
51 |_______DDI_INTROP_ADDISR,|_____|_______/* 6 addinterrupt handler */
52 |_______DDI_INTROP_DUPVEC,|_____|_______/* 7duplicate interrupt handler */
53 |_______DDI_INTROP_ENABLE,|_____|_______/* 8 enableinterrupt */
54 |_______DDI_INTROP_BLOCKENABLE,||_______/* 9 blockenable interrupts */
55 |_______DDI_INTROP_BLOCKDISABLE,|_______/* 10 blockdisable interrupts */
56 |_______DDI_INTROP_DISABLE,|____|_______/* 11disable interrupt */
57 |_______DDI_INTROP_REMISR,|_____|_______/* 12 removeinterrupt handler */
58 |_______DDI_INTROP_FREE,|_______|_______/* 13 freeinterrupt handle */
59 |_______DDI_INTROP_GETCAP,|_____|_______/* 14 getcapacity */
60 |_______DDI_INTROP_SETCAP,|_____|_______/* 15 setcapacity */
61 |_______DDI_INTROP_SETMASK,|____|_______/* 16 setmask */
62 |_______DDI_INTROP_CLRMASK,|____|_______/* 17 clearmask */
63 |_______DDI_INTROP_GETPENDING,|_|_______/* 18 getpending interrupt */
64 |_______DDI_INTROP_NAVAIL,|_____|_______/* 19 getnum of available interrupts */
65 |_______DDI_INTROP_GETPOOL,|____|_______/* 20 getresource management pool */
66 |_______DDI_INTROP_GETTARGET,|__|_______/* 21 gettarget for a given intr(s) */
67 |_______DDI_INTROP_SETTARGET|___|_______/* 22 settarget for a given intr(s) */
68 } ddi_intr_op_t;
hdlp – the implementation structure for DDI interrupthandling
result – the returned result data
74 /*
75* One such data structure is allocated perddi_intr_handle_t
76* This is the incore copy of the regular interruptinfo.
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 differentfunctions for DDI interrupt handling. Type, inum, vector are basic tounderstand the implementation.Specific interrupts are alwaysspecified by thecombination ofinterrupt type and inum. For legacydevices, inum refers to the nth interrupt, typically as definedby thedevices interruptsproperty.For PCI fixed interrupts, inumrefers to the interrupt number. The inum is the relativeinterruptvectornumber,from0to31 for MSI, from 0 to 2047 for MSI-X.The first interrupt vector is 0.Thelastrelative vector is 31for MSI or 2047 for MSI-X. Three interrupt types are defined inSolaris DDI.
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 ddiparent private data. It's created for both fixed interrupt and MSI/Xinterrupt types.
134 /*
135* Create the ddi_parent_private_data for a pseudochild.
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 (structddi_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 }
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;|__|_______|_______/* numberof regs */
741 |_______struct regspec *par_reg;|_______/* array ofregs */
742 |_______int par_nintr;|_|_______|_______/* numberof interrupts */
743 |_______struct intrspec *par_intr;|_____/* array ofpossible interrupts */
744 |_______int par_nrng;|__|_______|_______/* numberof ranges */
745 |_______struct rangespec *par_rng;|_____/* array ofranges */
746 };
747 #define|DEVI_PD(d)|_____\
748 |_______((struct ddi_parent_private_data*)DEVI((d))->devi_parent_data)
390 /*
391* This structure represents one interrupt possiblefrom the given
392* device. It is used in an array for devices withmultiple interrupts.
393*/
394 struct intrspec {
395 |_______uint_t intrspec_pri;|___|_______/* interruptpriority */
396 |_______uint_t intrspec_vec;|___|_______/* vector #(0 if none) */
397 |_______uint_t (*intrspec_func)();|_____/* functionto 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 isstored in devinfo structure.
126 struct dev_info{
… ...
237 |_______/* Owned by DDI interrupt framework */
238 |_______devinfo_intr_t|_*devi_intr_p;
… …
276 };
273 /*
274* One such data structure is allocated for eachdip.
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 deviceis 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 forthe 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 iseither 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
Allocateand free the interrupt vectors. Allocate interruptsoftheinterrupttype beginning at the interrupt number inum.ddi_intr_alloc(9F) will call this function for purpose. If MSI/X issupported, the actual operation is accomplished throughpsm_intr_ops() which is specified in psm module.
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 atDEVI(dip)->devi_parent_data->par_intr->intrspec_pri. Toset/change the interrupt priority, platform level psm_intr_ops() mustbe called. Two broad classes of interrupt: High-level and normalinterrupts are defined. Most interrupts on the system are normalinterrupts. Seldom must a device be configured to a high-levelinterrupt.
459 |_______caseDDI_INTROP_SETPRI:
460 |_______|_______/*Validate the interrupt priority passed */
461 |_______|_______if(*(int *)result > LOCK_LEVEL)
462|_______|_______|_______return (DDI_FAILURE);
High-level interrupts are handled muchlike traditional UNIX interrupts. A high-level interrupt has noprocess or thread context of its own. A high-level interrupt may notblock for any reason. A high-level ISR may only callmutex_enter(9F), the associated mutex_exit(9F), andddi_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 …
页:
[1]