spd.cc
1 #include "version.h" 2 #include "spd.h" 3 #include "osutils.h" 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 #include <unistd.h> 8 #include <string.h> 9 #include <string> 10 #include <dirent.h> 11 #include <stdio.h> 12 #include <cstring> 13 14 __ID("@(#) $Id$"); 15 16 /* SPD is 2048-bit long */ 17 #define SPD_MAXSIZE (2048/8) 18 #define SPD_BLKSIZE 0x10 19 20 #define TYPE_EDO 0x02 21 #define TYPE_SDRAM 0x04 22 23 #define PROCSENSORS "/proc/sys/dev/sensors" 24 #define EEPROMPREFIX "eeprom-" 25 26 static unsigned char spd[SPD_MAXSIZE]; 27 static bool spd_page_loaded[SPD_MAXSIZE / SPD_BLKSIZE]; 28 static string current_eeprom = ""; 29 static unsigned int current_bank = 0; 30 31 static unsigned char get_spd_byte(unsigned int offset) 32 { 33 if ((offset < 0) || (offset >= SPD_MAXSIZE)) 34 return 0; 35 36 if (!spd_page_loaded[offset / SPD_BLKSIZE]) 37 { 38 char chunkname[10]; 39 string name = ""; 40 FILE *in = NULL; 41 42 snprintf(chunkname, sizeof(chunkname), "%02x", 43 (offset / SPD_BLKSIZE) * SPD_BLKSIZE); 44 45 name = current_eeprom + "/" + string(chunkname); 46 47 in = fopen(name.c_str(), "r"); 48 if (in) 49 { 50 for (int i = 0; i < SPD_BLKSIZE; i++) 51 if(fscanf(in, "%d", 52 (int *) &spd[i + (offset / SPD_BLKSIZE) * SPD_BLKSIZE]) < 1) 53 break; 54 fclose(in); 55 spd_page_loaded[offset / SPD_BLKSIZE] = true; 56 } 57 else 58 spd_page_loaded[offset / SPD_BLKSIZE] = false; 59 } 60 61 return spd[offset]; 62 } 63 64 65 static int selecteeprom(const struct dirent *d) 66 { 67 struct stat buf; 68 69 if (d->d_name[0] == '.') 70 return 0; 71 72 if (lstat(d->d_name, &buf) != 0) 73 return 0; 74 75 if (!S_ISDIR(buf.st_mode)) 76 return 0; 77 78 return (strncmp(d->d_name, EEPROMPREFIX, strlen(EEPROMPREFIX)) == 0); 79 } 80 81 82 static hwNode *get_current_bank(hwNode & memory) 83 { 84 char id[20]; 85 hwNode *result = NULL; 86 87 if ((current_bank == 0) && (result = memory.getChild("bank"))) 88 return result; 89 90 snprintf(id, sizeof(id), "bank:%d", current_bank); 91 result = memory.getChild(id); 92 93 if (!result) 94 return memory.addChild(hwNode(id, hw::memory)); 95 else 96 return result; 97 } 98 99 100 static bool scan_eeprom(hwNode & memory, 101 string name) 102 { 103 int memory_type = -1; 104 char buff[20]; 105 unsigned char checksum = 0; 106 unsigned char rows = 0; 107 unsigned char density = 0; 108 unsigned long long size = 0; 109 110 current_eeprom = string(PROCSENSORS) + "/" + name; 111 memset(spd, 0, sizeof(spd)); 112 memset(spd_page_loaded, 0, sizeof(spd_page_loaded)); 113 114 for (int i = 0; i < 63; i++) 115 checksum += get_spd_byte(i); 116 117 if (checksum != get_spd_byte(63)) 118 return false; 119 120 memory_type = get_spd_byte(0x02); 121 122 hwNode *bank = get_current_bank(memory); 123 124 if (!bank) 125 return false; 126 127 switch (memory_type) 128 { 129 case TYPE_SDRAM: 130 bank->setDescription("SDRAM"); 131 break; 132 case TYPE_EDO: 133 bank->setDescription("EDO"); 134 break; 135 } 136 137 rows = get_spd_byte(5); 138 snprintf(buff, sizeof(buff), "%d", rows); 139 bank->setConfig("rows", buff); 140 141 if (bank->getSize() == 0) 142 { 143 density = get_spd_byte(31); 144 for (int j = 0; (j < 8) && (rows > 0); j++) 145 if (density & (1 << j)) 146 { 147 rows--; 148 size += (4 << j) * 1024 * 1024; // MB 149 density ^= (1 << j); 150 if (density == 0) 151 size += rows * (4 << j) * 1024 * 1024; 152 } 153 bank->setSize(size); 154 } 155 156 switch (get_spd_byte(11)) // error detection and correction scheme 157 { 158 case 0x00: 159 bank->setConfig("errordetection", "none"); 160 break; 161 case 0x01: 162 bank->addCapability("parity"); 163 bank->setConfig("errordetection", "parity"); 164 break; 165 case 0x02: 166 bank->addCapability("ecc"); 167 bank->setConfig("errordetection", "ecc"); 168 break; 169 } 170 171 int version = get_spd_byte(62); 172 173 snprintf(buff, sizeof(buff), "spd-%d.%d", (version & 0xF0) >> 4, 174 version & 0x0F); 175 bank->addCapability(buff); 176 177 return true; 178 } 179 180 181 static bool scan_eeproms(hwNode & memory) 182 { 183 struct dirent **namelist; 184 int n; 185 186 current_bank = 0; 187 188 pushd(PROCSENSORS); 189 n = scandir(".", &namelist, selecteeprom, alphasort); 190 popd(); 191 192 if (n < 0) 193 return false; 194 195 for (int i = 0; i < n; i++) 196 { 197 if (scan_eeprom(memory, namelist[i]->d_name)) 198 current_bank++; 199 free(namelist[i]); 200 } 201 free(namelist); 202 203 return true; 204 } 205 206 207 bool scan_spd(hwNode & n) 208 { 209 hwNode *memory = n.getChild("core/memory"); 210 211 current_bank = 0; 212 213 if (!memory) 214 { 215 hwNode *core = n.getChild("core"); 216 217 if (!core) 218 { 219 n.addChild(hwNode("core", hw::bus)); 220 core = n.getChild("core"); 221 } 222 223 if (core) 224 { 225 core->addChild(hwNode("memory", hw::memory)); 226 memory = core->getChild("memory"); 227 } 228 } 229 230 if (memory) 231 { 232 memory->claim(); 233 234 return scan_eeproms(*memory); 235 } 236 237 return false; 238 }