Wed Nov 11 13:41:56 CST 2009
driver operation
Driver operation is defined for leaf device drivers or bus nexus drivers supporting direct user process access (open/close/etc). Driver operation for npe module is very simple.
[i86pc/io/pciex/npe.c]
120 struct cb_ops npe_cb_ops = {
121 |_______npe_open,|______|_______|_______/* open */
122 |_______npe_close,|_____|_______|_______/* close */
123 |_______nodev,|_|_______|_______|_______/* strategy */
124 |_______nodev,|_|_______|_______|_______/* print */
125 |_______nodev,|_|_______|_______|_______/* dump */
126 |_______nodev,|_|_______|_______|_______/* read */
127 |_______nodev,|_|_______|_______|_______/* write */
128 |_______npe_ioctl,|_____|_______|_______/* ioctl */
129 |_______nodev,|_|_______|_______|_______/* devmap */
130 |_______nodev,|_|_______|_______|_______/* mmap */
131 |_______nodev,|_|_______|_______|_______/* segmap */
132 |_______nochpoll,|______|_______|_______/* poll */
133 |_______pcie_prop_op,|__|_______|_______/* cb_prop_op */
134 |_______NULL,|__|_______|_______|_______/* streamtab */
135 |_______D_NEW | D_MP | D_HOTPLUG,|______/* Driver compatibility flag */
136 |_______CB_REV,||_______|_______|_______/* rev */
137 |_______nodev,|_|_______|_______|_______/* int (*cb_aread)() */
138 |_______nodev|__|_______|_______|_______/* int (*cb_awrite)() */
139 };
It defines a character driver interface. User level applications can open/close the corresponding device file and issue some ioctl command again it. In npe's open() and close() functions, locks and state machine are used to serialize the controls. Two types of ioctl controls are supported by now, one is for pci tool, which is a common interface for user level applications to read/write pci configure spaces, bind the interrupt and so on (we will come back to the implementation later); another is for common device control, which is routed to pcie_ioclt() for further action.
Bus operations
Npe is a nexus bus driver module, so the its sole is the bus operations.
[i86pc/io/pciex/npe.c]
83 struct bus_ops npe_bus_ops = {
84 |_______BUSO_REV,
85 |_______npe_bus_map,
86 |_______NULL,
87 |_______NULL,
88 |_______NULL,
89 |_______i_ddi_map_fault,
90 |_______ddi_dma_map,
91 |_______ddi_dma_allochdl,
92 |_______ddi_dma_freehdl,
93 |_______ddi_dma_bindhdl,
94 |_______ddi_dma_unbindhdl,
95 |_______ddi_dma_flush,
96 |_______ddi_dma_win,
97 |_______ddi_dma_mctl,
98 |_______npe_ctlops,
99 |_______ddi_bus_prop_op,
100 |_______0,|_____|_______|_______/* (*bus_get_eventcookie)();|___*/
101 |_______0,|_____|_______|_______/* (*bus_add_eventcall)();|_____*/
102 |_______0,|_____|_______|_______/* (*bus_remove_eventcall)();|__*/
103 |_______0,|_____|_______|_______/* (*bus_post_event)();||_______*/
104 |_______0,|_____|_______|_______/* (*bus_intr_ctl)(); */
105 |_______0,|_____|_______|_______/* (*bus_config)(); */
106 |_______0,|_____|_______|_______/* (*bus_unconfig)(); */
107 |_______npe_fm_init,|___|_______/* (*bus_fm_init)(); */
108 |_______NULL,|__|_______|_______/* (*bus_fm_fini)(); */
109 |_______NULL,|__|_______|_______/* (*bus_fm_access_enter)(); */
110 |_______NULL,|__|_______|_______/* (*bus_fm_access_exit)(); */
111 |_______NULL,|__|_______|_______/* (*bus_power)(); */
112 |_______npe_intr_ops,|__|_______/* (*bus_intr_op)(); */
113 |_______pcie_hp_common_ops|_____/* (*bus_hp_op)(); */
114 };
The definition of “struct bus_ops” is in common/sys/devops.h. Not all entries are valid for a specific bus operation version. The comments along with the structure definition is enough for understanding.
[common/sys/devops.h]
118 /*
119 * bus_ops:|____bus nexus drivers only.
120 *
121 * These functions are used to implement the Sun DDI functions
122 * described elsewhere.
123 *
124 * Only nexus drivers support these entry points.
125 *
126 * The following bus nexus functions are provided in the bus nexus
127 * driver operations structure. Note that all functions take both
128 * their dip and the requesters dip except for the child functions since
129 * they will be called from outside the ddi.
130 *
131 *|_____bus_map||_______|_______- Map/unmap/control IU -> device mappings.
132 *|_____bus_get_intrspec|_______- get interrupt specification by number
133 *|_____bus_add_intrspec|_______- add interrupt specification, return cookie
134 *|_____bus_remove_intrspec|____- remove interrupt specification
135 *|_____bus_map_fault|__|_______- bus fault handler
136 *|_____bus_dma_map|____|_______- setup dma mapping
137 *|_____bus_dma_mapctl|_|_______- control (and free) dma mapping
138 *|_____bus_ctl||_______|_______- generic control operations
139 *|_____bus_prop_op|____|________ request for property
140 */
-
bus_map()
We have looked at npe_bus_map() when we tried to find the answer for how PCI leaf drviers access the configure space. The address spaces for a device were encoded in “reg” and “assigned-addresses” properties. Below comments describe the decoding logic.
[common/sys/pci.h]
1100 /*
1101 * This structure represents one entry of the 1275 "reg" property and
1102 * "assigned-addresses" property for a PCI node. For the "reg" property, it
1103 * may be one of an arbitrary length array for devices with multiple address
1104 * windows. For the "assigned-addresses" property, it denotes an assigned
1105 * physical address on the PCI bus. It may be one entry of the six entries
1106 * for devices with multiple base registers.
1107 *
1108 * The physical address format is:
1109 *
1110 * Bit#: 33222222 22221111 11111100 00000000
1111 * 10987654 32109876 54321098 76543210
1112 *
1113 * pci_phys_hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr
1114 * pci_phys_mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
1115 * pci_phys_low cell: llllllll llllllll llllllll llllllll
1116 *
1117 * n is 0 if the address is relocatable, 1 otherwise
1118 * p is 1 if the addressable region is "prefetchable", 0 otherwise
1119 * t is 1 if the address is aliased (for non-relocatable I/O), below
1120 *|_____ 1MB (for mem), or below 64 KB (for relocatable I/O).
1121 * ss is the type code, denoting which address space
1122 * bbbbbbbb is the 8-bit bus number
1123 * ddddd is the 5-bit device number
1124 * fff is the 3-bit function number
1125 * rrrrrrrr is the 8-bit register number
1126 *|_____ should be zero for non-relocatable, when ss is 01, or 10
1127 * hh...hhh is the 32-bit unsigned number
1128 * ll...lll is the 32-bit unsigned number
1129 *
1130 * The physical size format is:
1131 *
1132 * pci_size_hi cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
1133 * pci_size_low cell: llllllll llllllll llllllll llllllll
1134 *
1135 * hh...hhh is the 32-bit unsigned number
1136 * ll...lll is the 32-bit unsigned number
1137 */
1138 struct pci_phys_spec {
1139 |_______uint_t pci_phys_hi;|____|_______/* child's address, hi word */
1140 |_______uint_t pci_phys_mid;|___|_______/* child's address, middle word */
1141 |_______uint_t pci_phys_low;|___|_______/* child's address, low word */
1142 |_______uint_t pci_size_hi;|____|_______/* high word of size field */
1143 |_______uint_t pci_size_low;|___|_______/* low word of size field */
1144 };
1145
1146 typedef struct pci_phys_spec pci_regspec_t;
The actual map operation is passed to npe's parent (rootnex). However, pci system has different “reg” and “assigned-addresses” encoding logic. Hence, in this bus map function, most part is to convert the data from “pci_regspec_t” to “struct regspec” according to the map type and the encoding logic.
-
bus_ctl()
To be continued …