4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
31 #include <sys/types.h>
39 #include <sys/mdesc.h>
40 #include <sys/mdesc_impl.h>
41 #include <libdevinfo.h>
43 #include "mdesc_mutable.h"
46 static int get_devinfo(uint8_t **mdpp
, size_t *size
);
47 static boolean_t
is_root_complex(di_prom_handle_t ph
, di_node_t di
);
48 static md_node_t
*link_device_node(mmd_t
*mdp
,
49 di_prom_handle_t ph
, di_node_t di
, md_node_t
*node
, char *path
);
50 static int create_children(mmd_t
*mdp
,
51 di_prom_handle_t ph
, md_node_t
*node
, di_node_t parent
);
52 static int create_peers(mmd_t
*mdp
,
53 di_prom_handle_t ph
, md_node_t
*node
, di_node_t dev
);
54 static int device_tree_to_md(mmd_t
*mdp
, md_node_t
*top
);
58 #define LDMA_MODULE LDMA_NAME_DIO
61 /* System Info version supported (only version 1.0) */
62 static ds_ver_t ldma_dio_vers
[] = { {1, 0} };
64 #define LDMA_DIO_NVERS (sizeof (ldma_dio_vers) / sizeof (ds_ver_t))
65 #define LDMA_DIO_NHANDLERS (sizeof (ldma_dio_handlers) / \
66 sizeof (ldma_msg_handler_t))
68 static ldm_msg_func_t ldma_dio_pcidev_info_handler
;
70 static ldma_msg_handler_t ldma_dio_handlers
[] = {
71 {MSGDIO_PCIDEV_INFO
, LDMA_MSGFLG_ACCESS_CONTROL
,
72 ldma_dio_pcidev_info_handler
},
75 ldma_agent_info_t ldma_dio_info
= {
77 ldma_dio_vers
, LDMA_DIO_NVERS
,
78 ldma_dio_handlers
, LDMA_DIO_NHANDLERS
82 static ldma_request_status_t
83 ldma_dio_pcidev_info_handler(ds_ver_t
*ver
, ldma_message_header_t
*request
,
84 size_t request_dlen
, ldma_message_header_t
**replyp
, size_t *reply_dlenp
)
86 ldma_message_header_t
*reply
;
88 uint8_t *md_bufp
= NULL
;
92 LDMA_DBG("%s: PCI device info request", __func__
);
93 rv
= get_devinfo(&md_bufp
, &md_size
);
95 LDMA_ERR("Failed to generate devinfo MD");
96 return (LDMA_REQ_FAILED
);
98 reply
= ldma_alloc_result_msg(request
, md_size
);
100 LDMA_ERR("Memory allocation failure");
102 return (LDMA_REQ_FAILED
);
105 reply
->msg_info
= md_size
;
106 data
= LDMA_HDR2DATA(reply
);
107 (void) memcpy(data
, md_bufp
, md_size
);
109 *reply_dlenp
= md_size
;
111 LDMA_DBG("%s: sending PCI device info", __func__
);
112 return (LDMA_REQ_COMPLETED
);
116 is_root_complex(di_prom_handle_t ph
, di_node_t di
)
121 len
= di_prom_prop_lookup_strings(ph
, di
, "device_type", &type
);
122 if ((len
== 0) || (type
== NULL
))
125 if (strcmp(type
, PCIEX
) != 0)
129 * A root complex node is directly under the root node. So, if
130 * 'di' is not the root node, and its parent has no parent,
131 * then 'di' represents a root complex node.
133 return ((di_parent_node(di
) != DI_NODE_NIL
) &&
134 (di_parent_node(di_parent_node(di
)) == DI_NODE_NIL
));
138 * String properties in the prom can contain multiple null-terminated
139 * strings which are concatenated together. We must represent them in
140 * an MD as a data property. This function retrieves such a property
141 * and adds it to the MD. If the 'alt_name' PROM property exists then
142 * the MD property is created with the value of the PROM 'alt_name'
143 * property, otherwise it is created with the value of the PROM 'name'
147 add_prom_string_prop(di_prom_handle_t ph
,
148 mmd_t
*mdp
, md_node_t
*np
, di_node_t di
, char *name
, char *alt_name
)
151 char *pp_data
= NULL
;
155 if (alt_name
!= NULL
) {
156 count
= di_prom_prop_lookup_strings(ph
, di
, alt_name
, &pp_data
);
158 if (pp_data
== NULL
) {
159 count
= di_prom_prop_lookup_strings(ph
, di
, name
, &pp_data
);
162 if (count
> 0 && pp_data
!= NULL
) {
163 for (str
= pp_data
; count
> 0; str
+= strlen(str
) + 1)
165 rv
= md_add_data_property(mdp
,
166 np
, name
, str
- pp_data
, (uint8_t *)pp_data
);
172 * Add an int property 'name' to an MD from an existing PROM property. If
173 * the 'alt_name' PROM property exists then the MD property is created with
174 * the value of the PROM 'alt_name' property, otherwise it is created with
175 * the value of the PROM 'name' property.
178 add_prom_int_prop(di_prom_handle_t ph
,
179 mmd_t
*mdp
, md_node_t
*np
, di_node_t di
, char *name
, char *alt_name
)
185 if (alt_name
!= NULL
) {
186 count
= di_prom_prop_lookup_ints(ph
, di
, alt_name
, &pp_data
);
188 if (pp_data
== NULL
) {
189 count
= di_prom_prop_lookup_ints(ph
, di
, name
, &pp_data
);
193 * Note: We know that the properties of interest contain a
196 if (count
> 0 && pp_data
!= NULL
) {
198 rv
= md_add_value_property(mdp
, np
, name
, *pp_data
);
204 link_device_node(mmd_t
*mdp
,
205 di_prom_handle_t ph
, di_node_t di
, md_node_t
*node
, char *path
)
209 np
= md_link_new_node(mdp
, "iodevice", node
, "fwd", "back");
213 /* Add the properties from the devinfo node. */
214 if (md_add_string_property(mdp
, np
, "dev_path", path
) != 0)
217 /* Add the required properties for this node. */
218 if (add_prom_string_prop(ph
, mdp
, np
, di
, "device_type", NULL
) != 0)
221 if (add_prom_string_prop(ph
, mdp
, np
, di
, "compatible", NULL
) != 0)
224 if (add_prom_int_prop(ph
,
225 mdp
, np
, di
, "device-id", "real-device-id") != 0)
228 if (add_prom_int_prop(ph
,
229 mdp
, np
, di
, "vendor-id", "real-vendor-id") != 0)
232 if (add_prom_int_prop(ph
,
233 mdp
, np
, di
, "class-code", "real-class-code") != 0)
239 md_free_node(mdp
, np
);
244 create_children(mmd_t
*mdp
,
245 di_prom_handle_t ph
, md_node_t
*md_parent
, di_node_t di_parent
)
253 path
= di_devfs_path(di_parent
);
257 md_node
= link_device_node(mdp
, ph
, di_parent
, md_parent
, path
);
258 di_devfs_path_free(path
);
259 if (md_node
== NULL
) {
263 while ((di_child
= di_child_node(di_parent
)) != DI_NODE_NIL
) {
264 path
= di_devfs_path(di_child
);
266 md_child
= link_device_node(mdp
,
267 ph
, di_child
, md_node
, path
);
268 di_devfs_path_free(path
);
269 if (md_child
== NULL
) {
274 rv
= create_peers(mdp
, ph
, md_node
, di_child
);
279 di_parent
= di_child
;
285 create_peers(mmd_t
*mdp
, di_prom_handle_t ph
, md_node_t
*node
, di_node_t dev
)
290 while ((di_peer
= di_sibling_node(dev
)) != DI_NODE_NIL
) {
291 rv
= create_children(mdp
, ph
, node
, di_peer
);
300 device_tree_to_md(mmd_t
*mdp
, md_node_t
*top
)
307 root
= di_init("/", DINFOSUBTREE
| DINFOPROP
);
309 if (root
== DI_NODE_NIL
) {
310 LDMA_ERR("di_init cannot find device tree root node.");
315 if (ph
== DI_PROM_HANDLE_NIL
) {
316 LDMA_ERR("di_prom_init failed.");
321 node
= di_child_node(root
);
322 while (node
!= NULL
) {
323 if (is_root_complex(ph
, node
)) {
324 rv
= create_children(mdp
, ph
, top
, node
);
328 node
= di_sibling_node(node
);
337 get_devinfo(uint8_t **mdpp
, size_t *size
)
348 rootp
= md_new_node(mdp
, "root");
354 if (device_tree_to_md(mdp
, rootp
) != 0) {
358 md_size
= (int)md_gen_bin(mdp
, &md_bufp
);