1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <assert.h> 30 #include <sys/types.h> 31 #include <libdevinfo.h> 32 #include <fm/topo_mod.h> 33 #include <pcibus.h> 34 #include <did.h> 35 36 #include "did_impl.h" 37 #include "did_props.h" 38 39 static did_hash_t *did_hash_create(topo_mod_t *); 40 static void did_hash_destroy(did_hash_t *); 41 42 int 43 did_hash_init(topo_mod_t *hdl) 44 { 45 did_hash_t *dh = did_hash_create(hdl); 46 47 if (dh != NULL) { 48 topo_mod_setspecific(hdl, (void *) dh); 49 return (0); 50 } else { 51 return (-1); 52 } 53 } 54 55 void 56 did_hash_fini(topo_mod_t *mod) 57 { 58 did_hash_t *dh = (did_hash_t *)topo_mod_getspecific(mod); 59 60 topo_mod_setspecific(mod, NULL); 61 if (dh == NULL) 62 return; 63 did_hash_destroy(dh); 64 } 65 66 static uint64_t 67 did_dnhash(di_node_t key) 68 { 69 static uint64_t key_divisor = 0; 70 uint64_t keyn; 71 72 /* 73 * A bit naughty here, we're aware that a di_info_t is a 74 * pointer to a struct. For our hashing, we want use the size 75 * of that struct, which we determine here, somewhat 76 * impolitely. 77 */ 78 if (key_divisor == 0) 79 key_divisor = sizeof (*key); 80 81 keyn = (uintptr_t)key; 82 83 return (keyn / key_divisor); 84 } 85 86 static did_hash_t * 87 did_hash_create(topo_mod_t *hdl) 88 { 89 did_hash_t *r = topo_mod_zalloc(hdl, sizeof (did_hash_t)); 90 91 if (r == NULL) { 92 (void) topo_mod_seterrno(hdl, EMOD_NOMEM); 93 return (NULL); 94 } 95 r->dph_mod = hdl; 96 r->dph_hashlen = REC_HASHLEN; 97 r->dph_hash = topo_mod_zalloc(hdl, 98 r->dph_hashlen * sizeof (did_t *)); 99 if (r->dph_hash == NULL) { 100 topo_mod_free(hdl, r, sizeof (did_hash_t)); 101 (void) topo_mod_seterrno(hdl, EMOD_NOMEM); 102 return (NULL); 103 } 104 return (r); 105 } 106 107 static void 108 did_hash_destroy(did_hash_t *ht) 109 { 110 did_t *e, *n; 111 int idx; 112 113 if (ht == NULL) 114 return; 115 for (idx = 0; idx < ht->dph_hashlen; idx++) { 116 for (e = ht->dph_hash[idx]; e != NULL; ) { 117 n = e->dp_next; 118 did_destroy(e); 119 e = n; 120 } 121 } 122 topo_mod_free(ht->dph_mod, 123 ht->dph_hash, ht->dph_hashlen * sizeof (did_t *)); 124 topo_mod_free(ht->dph_mod, ht, sizeof (did_hash_t)); 125 } 126 127 void 128 did_hash_insert(topo_mod_t *mp, di_node_t key, did_t *new) 129 { 130 did_hash_t *tab = (did_hash_t *)topo_mod_getspecific(mp); 131 did_t *assertchk; 132 int idx = did_dnhash(key) % tab->dph_hashlen; 133 134 tab->dph_nelems++; 135 did_hold(new); 136 topo_mod_dprintf(tab->dph_mod, "Insert [key=%p] into %p, bucket %d\n", 137 key, (void *)tab, idx); 138 if (tab->dph_hash[idx] == NULL) { 139 tab->dph_hash[idx] = new; 140 topo_mod_dprintf(tab->dph_mod, "first entry.\n"); 141 } else { 142 /* 143 * We should not be putting in a duplicate entry 144 */ 145 for (assertchk = tab->dph_hash[idx]; 146 assertchk != NULL; 147 assertchk = assertchk->dp_next) 148 assert(assertchk->dp_src != key); 149 new->dp_next = tab->dph_hash[idx]; 150 tab->dph_hash[idx] = new; 151 } 152 } 153 154 did_t * 155 did_hash_lookup(topo_mod_t *mp, di_node_t key) 156 { 157 did_t *e; 158 did_hash_t *tab = (did_hash_t *)topo_mod_getspecific(mp); 159 int idx = did_dnhash(key) % tab->dph_hashlen; 160 161 e = tab->dph_hash[idx]; 162 while (e != NULL) { 163 if (e->dp_src == key) { 164 did_hold(e); 165 return (e); 166 } 167 e = e->dp_next; 168 } 169 return (NULL); 170 } 171