Chameleon

Chameleon Commit Details

Date:2010-02-21 04:39:14 (14 years 2 months ago)
Author:Rekursor
Commit:98
Parents: 97
Message:First attemp to fix laptops bank 0/2 not handled correctly and also Unifosa memory with no vendor id->using part fingerprint instead.
Changes:
M/trunk/i386/libsaio/SMBIOS.h
M/trunk/i386/libsaio/platform.c
M/trunk/i386/libsaio/spd.c
M/trunk/i386/libsaio/platform.h
M/trunk/version
M/trunk/i386/libsaio/mem.c

File differences

trunk/version
1
1
2.0-RC5pre10
2.0-RC5pre11
trunk/i386/libsaio/spd.c
6565
6666
6767
68
68
6969
70
71
72
70
71
72
73
7374
7475
7576
......
9091
9192
9293
93
94
95
96
9497
9598
9699
......
178181
179182
180183
181
184
182185
183186
184187
185188
186189
187
188
189
190
190
191
192
193
191194
192195
193196
194197
195198
196199
197
200
201
198202
199
203
200204
201
202205
203206
204207
205
206
207
208
209
210
211
212
213
208214
209
210
211
215
216
217
218
219
220
212221
213
214
215
222
223
224
216225
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
226
227
228
229
230
231
232
232233
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
258261
259262
260
261263
264
265
266
267
268
262269
263
264
265
266
267270
268271
269272
#define SMBHSTDAT 5
/** Get Vendor Name from spd, 2 cases handled DDR3 and DDR2, have different formats.*/
const char * getVendorName(const char * spd)
const char * getVendorName(RamSlotInfo_t* slot)
{
uint8_t code;
int i;
uint8_t bank=0;
uint8_t bank = 0;
uint8_t code = 0;
int i = 0;
const char * spd = slot->spd;
if (spd[2]==0x0b) { // DDR3
bank = spd[0x75];
if (bank==vendorMap[i].bank && code==vendorMap[i].code)
return vendorMap[i].name;
}
/* OK there is no vendor id here lets try to match the partnum if it exists */
if (strstr(slot->Vendor,"GU332") == slot->Vendor) // Unifosa fingerprint
return "Unifosa";
return "NoName";
}
return inb(base + SMBHSTDAT);
}
int mapping []= {0,1,2,3,4,5}; // RAM_SLOT_ENUMERATOR;
int mapping []= {0,2,1,3,4,6,5,7,8,10,9,11};
/** Read from smbus the SPD content and interpret it for detecting memory attributes */
static void read_smb_intel(pci_dt_t *smbus_dev)
{
static int serialnum=0;
int i, x, ser;
uint8_tspd_size, spd_type;
uint32_tbase;
bool dump = false;
int i, x, ser, speed;
uint8_t spd_size, spd_type;
uint32_t base;
bool dump = false;
RamSlotInfo_t* slot;
base = pci_config_read16(smbus_dev->dev.addr, 0x20) & 0xFFFE;
DBG("Scanning smbus_dev <%04x, %04x> ...\n",smbus_dev->vendor_id, smbus_dev->device_id);
getBoolForKey("DumpSPD", &dump, &bootInfo->bootConfig);
bool fullBanks = // needed at least for laptops
Platform.DMI.MemoryModules == Platform.DMI.MaxMemorySlots;
// Search MAX_RAM_SLOTS slots
for (i = 0; i < MAX_RAM_SLOTS; i++){
for (i = 0; i < Platform.DMI.MaxMemorySlots; i++){
slot = &Platform.RAM.DIMM[i];
Platform.DMI.DIMM[i]=mapping[i]; // for now no special mapping
spd_size = smb_read_byte_intel(base, 0x50 + i, 0);
// Check spd is present
if (spd_size && spd_size != 0xff)
{
slot->InUse = true;
if (spd_size && spd_size != 0xff) {
slot->InUse = true;
slot->spd = malloc(spd_size);
if (slot->spd) {
bzero(slot->spd, spd_size);
slot->spd = malloc(spd_size);
if (slot->spd) {
bzero(slot->spd, spd_size);
// Copy spd data into buffer
for (x = 0; x < spd_size; x++)
slot->spd[x] = smb_read_byte_intel(base, 0x50 + i, x);
switch (slot->spd[SPD_MEMORY_TYPE]) {
case SPD_MEMORY_TYPE_SDRAM_DDR2:
// Copy spd data into buffer
for (x = 0; x < spd_size; x++)
slot->spd[x] = smb_read_byte_intel(base, 0x50 + i, x);
slot->ModuleSize = ((1 << (slot->spd[SPD_NUM_ROWS] & 0x0f) + (slot->spd[SPD_NUM_COLUMNS] & 0x0f) - 17) *
((slot->spd[SPD_NUM_DIMM_BANKS] & 0x7) + 1) * slot->spd[SPD_NUM_BANKS_PER_SDRAM]);
break;
switch (slot->spd[SPD_MEMORY_TYPE]) {
case SPD_MEMORY_TYPE_SDRAM_DDR2:
slot->ModuleSize = ((1 << (slot->spd[SPD_NUM_ROWS] & 0x0f) + (slot->spd[SPD_NUM_COLUMNS] & 0x0f) - 17) *
((slot->spd[SPD_NUM_DIMM_BANKS] & 0x7) + 1) * slot->spd[SPD_NUM_BANKS_PER_SDRAM]);
break;
case SPD_MEMORY_TYPE_SDRAM_DDR3:
slot->ModuleSize = ((slot->spd[4] & 0x0f) + 28 ) + ((slot->spd[8] & 0x7) + 3 );
slot->ModuleSize -= (slot->spd[7] & 0x7) + 25;
slot->ModuleSize = ((1 << slot->ModuleSize) * (((slot->spd[7] >> 3) & 0x1f) + 1));
break;
}
case SPD_MEMORY_TYPE_SDRAM_DDR3:
slot->ModuleSize = ((slot->spd[4] & 0x0f) + 28 ) + ((slot->spd[8] & 0x7) + 3 );
slot->ModuleSize -= (slot->spd[7] & 0x7) + 25;
slot->ModuleSize = ((1 << slot->ModuleSize) * (((slot->spd[7] >> 3) & 0x1f) + 1));
break;
}
spd_type = (slot->spd[SPD_MEMORY_TYPE] < ((char) 12) ? slot->spd[SPD_MEMORY_TYPE] : 0);
slot->Type = spd_mem_to_smbios[spd_type];
strncpy(slot->PartNo, getDDRPartNum(slot->spd), 64);
strncpy(slot->Vendor, getVendorName(slot->spd), 64);
ser = getDDRSerial(slot->spd);
if (ser==0) {
sprintf(slot->SerialNo, "10000000%d", serialnum);
serialnum++;
}
else
sprintf(slot->SerialNo, "%d", ser);
// determine speed
slot->Frequency = getDDRspeedMhz(slot->spd);
if(dump) {
printf("Slot %d Type %d %dMB (%s) %dMHz Vendor=%s, PartNo=%s SerialNo=%s\n",
i,
(int)slot->Type,
slot->ModuleSize,
spd_memory_types[spd_type],
slot->Frequency,
slot->Vendor,
slot->PartNo,
slot->SerialNo);
}
spd_type = (slot->spd[SPD_MEMORY_TYPE] < ((char) 12) ? slot->spd[SPD_MEMORY_TYPE] : 0);
slot->Type = spd_mem_to_smbios[spd_type];
strncpy(slot->PartNo, getDDRPartNum(slot->spd), 64);
strncpy(slot->Vendor, getVendorName(slot), 64);
ser = getDDRSerial(slot->spd);
if (ser==0) {
sprintf(slot->SerialNo, "10000000%d", serialnum);
serialnum++;
}
else
sprintf(slot->SerialNo, "%d", ser);
// determine spd speed
speed = getDDRspeedMhz(slot->spd);
if (speed > slot->Frequency) slot->Frequency = speed; // just in case dmi wins on spd
if(dump) {
printf("Slot %d Type %d %dMB (%s) %dMHz Vendor=%s, PartNo=%s SerialNo=%s\n",
i,
(int)slot->Type,
slot->ModuleSize,
spd_memory_types[spd_type],
slot->Frequency,
slot->Vendor,
slot->PartNo,
slot->SerialNo);
dumpPhysAddr("spd content: ",slot->spd, spd_size);
getc();
}
}
}
// laptops sometimes show slot 0 and 2 with slot 1 empty when only 2 slots are presents so:
Platform.DMI.DIMM[i]=
i>0 && Platform.RAM.DIMM[1].InUse==false && fullBanks && Platform.DMI.MaxMemorySlots==2 ?
mapping[i] : i; // for laptops case, mapping setup would need to be more generic than this
}
#if DEBUG_SPD
printf("Press a key to continue\n");
getc();
#endif
}
static struct smbus_controllers_t smbus_controllers[] = {
trunk/i386/libsaio/SMBIOS.h
112112
113113
114114
115
115116
116117
117118
SMBBytebankLocator;
SMBBytememoryType;
SMBWordtypeDetail;
SMBWord speed;
} __attribute__((packed));
#endif /* !_LIBSAIO_SMBIOS_H */
trunk/i386/libsaio/mem.c
6363
6464
6565
66
6667
6768
6869
......
7172
7273
7374
74
75
7576
7677
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
77103
78104
79105
80
81
82106
83107
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
100129
101130
102131
103132
104
105
106
107
108
109
110
111
112
133
134
113135
114136
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129137
}
printf("%s\n",buffer);
}
void dumpAllTablesOfType(int i)
{
char title[32];
dmihdr;
dmihdr = FindNextDmiTableOfType(i, 4)) {
sprintf(title,"Table (type %d) :" , i);
dumpPhysAddr(title, dmihdr, dmihdr->length);
dumpPhysAddr(title, dmihdr, dmihdr->length+16);
}
}
const char * getDMIString(struct DMIHeader * dmihdr, uint8_t strNum)
{
const char * ret =NULL;
const char * startAddr = (const char *) dmihdr;
const char * limit = NULL;
if (!dmihdr || dmihdr->length<4 || strNum==0) return NULL;
startAddr += dmihdr->length;
limit = startAddr + 256;
for(; strNum; strNum--) {
if ((*startAddr)==0 && *(startAddr+1)==0) break;
if (*startAddr && strNum<=1) {
ret = startAddr; // current str
break;
}
while(*startAddr && startAddr<limit) startAddr++;
if (startAddr==limit) break; // no terminator found
else if((*startAddr==0) && *(startAddr+1)==0) break;
else startAddr++;
}
return ret;
}
void scan_memory(PlatformInfo_t *p)
{
int i=0;
uint8_t bc=0;
struct SMBEntryPoint* smbios = NULL;
struct DMIHeader * dmihdr = NULL;
struct DMIMemoryControllerInfo* ctrlInfo = NULL;
struct DMIMemoryModuleInfo* memInfo[MAX_RAM_SLOTS];
/*
struct DMIPhysicalMemoryArray* physMemArray;
struct DMIMemoryDevice* memDev;
*/
smbios = getSmbios(SMBIOS_ORIGINAL);/* checks for _SM_ anchor and table header checksum */
if (smbios==NULL) return ; // getSmbios() return a non null value if smbios is found
ctrlInfo = (struct DMIMemoryControllerInfo*) FindFirstDmiTableOfType(5, 4);
Platform.DMI.MaxMemorySlots = ctrlInfo ? ctrlInfo->numberOfMemorySlots : 0;
printf("Number of smbios detected Slots: %02d\n", Platform.DMI.MaxMemorySlots);
Platform.DMI.MemoryModules = 0;
struct DMIMemoryModuleInfo* memInfo[MAX_RAM_SLOTS]; // 6
struct DMIPhysicalMemoryArray* physMemArray; // 16
struct DMIMemoryDevice* memDev[MAX_RAM_SLOTS]; //17
/* We mainly don't use obsolete tables 5,6 because most of computers don't handle it anymore */
Platform.DMI.MemoryModules = 0;
/* Now lets peek info rom table 16,17 as for some bios, table 5 & 6 are not used */
physMemArray = (struct DMIPhysicalMemoryArray*) FindFirstDmiTableOfType(16, 4);
Platform.DMI.MaxMemorySlots = physMemArray ? physMemArray->numberOfMemoryDevices : 0;
i = 0;
for(dmihdr = FindFirstDmiTableOfType(17, 4);
dmihdr;
dmihdr = FindNextDmiTableOfType(17, 4) ) {
memDev[i] = (struct DMIMemoryDevice*) dmihdr;
if (memDev[i]->size !=0 ) Platform.DMI.MemoryModules++;
if (memDev[i]->speed>0) Platform.RAM.DIMM[i].Frequency = memDev[i]->speed; // take it here for now but we'll check spd and dmi table 6 as well
i++;
}
// for table 6, we only have a look at the current speed
i = 0;
for(dmihdr = FindFirstDmiTableOfType(6, 4);
dmihdr;
dmihdr = FindNextDmiTableOfType(6, 4) ) {
memInfo[i] = (struct DMIMemoryModuleInfo*) dmihdr;
bc = memInfo[i]->bankConnections;
Platform.RAM.DIMM[i].BankConnCnt = 2;
if ((bc & 0x0F) == 0x0F) Platform.RAM.DIMM[i].BankConnCnt--; // 0xF nibble means no connection (3.3.7)
if ((bc & 0xF0) == 0xF0) Platform.RAM.DIMM[i].BankConnCnt--; // 0xF nibble means no connection (3.3.7)
printf("Bank Connection code for Slot %d is %02x, so %d bank connections per slot deducted.\n",
i+1, bc, Platform.RAM.DIMM[i].BankConnCnt);
if ( memInfo[i]->installedSize < 0x7D) // >= 0x7D means error / not installed
Platform.DMI.MemoryModules++;
if (memInfo[i]->currentSpeed > Platform.RAM.DIMM[i].Frequency)
Platform.RAM.DIMM[i].Frequency = memInfo[i]->currentSpeed; // favor real overclocked speed if any
i++;
}
Platform.DMI.CntMemorySlots = i;
getc();
/*
physMemArray = (struct DMIPhysicalMemoryArray*) getSmbiosTableStructure(smbios, 16, 0x1);
memDev = (struct DMIMemoryDevice*) getSmbiosTableStructure(smbios, 17, 0x1);
*/
/*
dumpAllTablesOfType(5);
dumpAllTablesOfType(6 );
getc();
dumpAllTablesOfType(16);
dumpAllTablesOfType(17);
getc();
*/
}
trunk/i386/libsaio/platform.c
4141
4242
4343
44
4544
scan_cpu(&Platform);
scan_memory(&Platform);
scan_spd(&Platform);
}
trunk/i386/libsaio/platform.h
7777
7878
7979
80
8081
8182
8283
typedef struct _RamSlotInfo_t {
boolInUse;
uint8_tType;
uint8_t BankConnections; // table type 6, see (3.3.7)
uint8_t BankConnCnt;
uint32_t ModuleSize;// Size of Module in MB
uint32_t Frequency; // in Mhz

Archive Download the corresponding diff file

Revision: 98