Chameleon

Chameleon Commit Details

Date:2010-07-24 03:58:45 (13 years 9 months ago)
Author:Rekursor
Commit:210
Parents: 209
Message:mem detect optimization, very fast now :)
Changes:
M/trunk/i386/libsaio/platform.c
M/trunk/i386/libsaio/spd.c
M/trunk/i386/libsaio/spd.h

File differences

trunk/i386/libsaio/spd.c
11
22
3
3
4
5
6
47
58
69
......
8588
8689
8790
88
89
90
91
92
93
9194
9295
9396
9497
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
95123
96124
97
125
98126
99127
100128
101129
102
130
103131
104132
105
106
133
134
107135
108136
109137
110138
111139
112
113
140
141
142
143
144
145
114146
115147
116
148
117149
118150
119151
......
181213
182214
183215
184
216
185217
186218
187
188
219
189220
190221
191
222
192223
193224
194
225
195226
196227
197
198
199
200
201
202
203
204
205
206
207
208
228
229
230
231
232
233
234
235
236
237
238
239
240
209241
210242
211243
212244
213245
246
214247
215248
216249
217
250
218251
219252
220253
......
227260
228261
229262
263
264
230265
231266
232267
233
234268
235269
236
237
238270
271
239272
240273
241274
242275
243276
244
245
246277
278
279
280
247281
248282
249283
......
262296
263297
264298
265
266
299
300
267301
268302
269303
270304
271
272
273
305
306
274307
275308
276309
......
279312
280313
281314
282
315
316
283317
284318
285319
......
289323
290324
291325
292
293
294
295
326
296327
297328
298329
......
322353
323354
324355
325
356
326357
327358
328359
......
345376
346377
347378
379
348380
381
349382
/*
* spd.c - serial presence detect memory information
* (restored from pcefi10.5)
*
* Originally restored from pcefi10.5
* Dynamic mem detection original impl. by Rekursor
* System profiler fix and other fixes by Mozodojo.
*/
#include "libsaio.h"
while (!( inb(base + SMBHSTSTS) & 0x02))// wait til command finished
{
rdtsc(l2, h2);
t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / (Platform.CPU.TSCFrequency / 40);
if (t > 10)
break;// break after 10ms
t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / (Platform.CPU.TSCFrequency / 100);
if (t > 5)
break;// break after 5ms
}
return inb(base + SMBHSTDAT);
}
/* SPD i2c read optimization: prefetch only what we need, read non prefetcheable bytes on the fly */
#define READ_SPD(spd, base, slot, x) spd[x] = smb_read_byte_intel(base, 0x50 + slot, x)
int spd_indexes[] = {
SPD_MEMORY_TYPE,
SPD_DDR3_MEMORY_BANK,
SPD_DDR3_MEMORY_CODE,
SPD_NUM_ROWS,
SPD_NUM_COLUMNS,
SPD_NUM_DIMM_BANKS,
SPD_NUM_BANKS_PER_SDRAM,
4,7,8,9,12,64, /* TODO: give names to these values */
95,96,97,98, 122,123,124,125 /* UIS */
};
#define SPD_INDEXES_SIZE (sizeof(spd_indexes) / sizeof(int))
/** Read from spd *used* values only*/
static void init_spd(char * spd, uint32_t base, int slot)
{
int i;
for (i=0; i< SPD_INDEXES_SIZE; i++) {
READ_SPD(spd, base, slot, spd_indexes[i]);
}
}
/** Get Vendor Name from spd, 2 cases handled DDR3 and DDR2,
have different formats, always return a valid ptr.*/
const char * getVendorName(RamSlotInfo_t* slot)
const char * getVendorName(RamSlotInfo_t* slot, uint32_t base, int slot_num)
{
uint8_t bank = 0;
uint8_t code = 0;
int i = 0;
const char * spd = slot->spd;
char * spd = slot->spd;
if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) { // DDR3
bank = spd[0x75];
code = spd[0x76];
bank = spd[SPD_DDR3_MEMORY_BANK];
code = spd[SPD_DDR3_MEMORY_CODE];
for (i=0; i < VEN_MAP_SIZE; i++)
if (bank==vendorMap[i].bank && code==vendorMap[i].code)
return vendorMap[i].name;
}
else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
if(spd[0x40]==0x7f) {
for (i=0x40; i<0x48 && spd[i]==0x7f;i++) bank++;
if(spd[64]==0x7f) {
for (i=64; i<72 && spd[i]==0x7f;i++) {
bank++;
READ_SPD(spd, base, slot_num,i+1); // prefetch next spd byte to read for next loop
}
READ_SPD(spd, base, slot_num,i);
code = spd[i];
} else {
code = spd[0x40];
code = spd[64];
bank = 0;
}
for (i=0; i < VEN_MAP_SIZE; i++)
}
/** Get DDR3 or DDR2 Part Number, always return a valid ptr */
const char * getDDRPartNum(const char* spd)
const char * getDDRPartNum(char* spd, uint32_t base, int slot)
{
static char asciiPartNo[32];
const char * sPart = NULL;
int i, index = 0;
int i, start=0, index = 0;
if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) {
sPart = &spd[128];
start = 128;
}
else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
sPart = &spd[73];
start = 73;
}
if (sPart) { // Check that the spd part name is zero terminated and that it is ascii:
bzero(asciiPartNo, 32);
for (i=0; i<32; i++) {
char c = sPart[i];
if (isalpha(c) || isdigit(c) || ispunct(c)) // It seems that System Profiler likes only letters and digits...
asciiPartNo[index++] = c;
else if (!isascii(c))
break;
}
return strdup(asciiPartNo);
}
// Check that the spd part name is zero terminated and that it is ascii:
bzero(asciiPartNo, 32);
char c;
for (i=start; i<start+32; i++) {
READ_SPD(spd, base, slot, i); // only read once the corresponding model part (ddr3 or ddr2)
c = spd[i];
if (isalpha(c) || isdigit(c) || ispunct(c)) // It seems that System Profiler likes only letters and digits...
asciiPartNo[index++] = c;
else if (!isascii(c))
break;
}
return strdup(asciiPartNo);
return NULL;
}
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)
{
int i, x, speed;
int i, speed;
uint8_t spd_size, spd_type;
uint32_t base;
bool dump = false;
bool fullBanks = // needed at least for laptops
Platform.DMI.MemoryModules == Platform.DMI.MaxMemorySlots;
// Search MAX_RAM_SLOTS slots
char spdbuf[256];
for (i = 0; i < MAX_RAM_SLOTS; i++){
slot = &Platform.RAM.DIMM[i];
spd_size = smb_read_byte_intel(base, 0x50 + i, 0);
// Check spd is present
if (spd_size && (spd_size != 0xff) ) {
slot->spd = malloc(spd_size);
if (slot->spd == NULL) continue;
slot->spd = spdbuf;
slot->InUse = true;
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);
//for (x = 0; x < spd_size; x++) slot->spd[x] = smb_read_byte_intel(base, 0x50 + i, x);
init_spd(slot->spd, base, i);
switch (slot->spd[SPD_MEMORY_TYPE]) {
case SPD_MEMORY_TYPE_SDRAM_DDR2:
spd_type = (slot->spd[SPD_MEMORY_TYPE] < ((char) 12) ? slot->spd[SPD_MEMORY_TYPE] : 0);
slot->Type = spd_mem_to_smbios[spd_type];
slot->PartNo = getDDRPartNum(slot->spd);
slot->Vendor = getVendorName(slot);
slot->PartNo = getDDRPartNum(slot->spd, base, i);
slot->Vendor = getVendorName(slot, base, i);
slot->SerialNo = getDDRSerial(slot->spd);
// 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",
if (slot->Frequency<speed) slot->Frequency = speed; // should test the mem controller to get potential overclocking info ?
printf("Slot: %d Type %d %dMB (%s) %dMHz Vendor=%s\n PartNo=%s SerialNo=%s\n",
i,
(int)slot->Type,
slot->ModuleSize,
slot->Vendor,
slot->PartNo,
slot->SerialNo);
dumpPhysAddr("spd content: ",slot->spd, spd_size);
if(DEBUG_SPD) {
dumpPhysAddr("spd content: ",slot->spd, spd_size);
getc();
}
}
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 (slot->spd) {
free(slot->spd);
slot->spd = NULL;
}
slot->spd = NULL;
} // for
}
int i;
while (current) {
#if DEBUG_SPD
#if 0
printf("%02x:%02x.%x [%04x] [%04x:%04x] :: %s\n",
current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func,
current->class_id, current->vendor_id, current->device_id,
void scan_spd(PlatformInfo_t *p)
{
printf("\n--> Start of mem detect:\n");
find_and_read_smbus_controller(root_pci_dev);
printf("\n<-- End of mem detect.\n");
}
trunk/i386/libsaio/spd.h
9494
9595
9696
97
98
9799
98100
99101
#define SPD_MANUFACTURER_SPECIFIC_DATA 99 /* Manufacturer specific data (bytes 99-125) */
#define SPD_INTEL_SPEC_FOR_FREQUENCY 126 /* Intel specification for frequency */
#define SPD_INTEL_SPEC_100_MHZ 127 /* Intel specification details for 100MHz support */
#define SPD_DDR3_MEMORY_BANK 0x75
#define SPD_DDR3_MEMORY_CODE 0x76
/* DRAM specifications use the following naming conventions for SPD locations */
#define SPD_tRP SPD_MIN_ROW_PRECHARGE_TIME
trunk/i386/libsaio/platform.c
3737
3838
3939
40
40
41
42
43
4144
4245
4346
44
47
4548
4649
50
4751
4852
4953
/** scan mem for memory autodection purpose */
void scan_mem() {
bool useAutodetection = false;
static bool done = false;
if (done) return;
bool useAutodetection = true;
getBoolForKey(kUseMemDetect, &useAutodetection, &bootInfo->bootConfig);
if (useAutodetection) {
scan_memory(&Platform);
scan_memory(&Platform); // useless at least for now, mem freq now only relies on spd.
scan_spd(&Platform);
}
done = true;
}
/**

Archive Download the corresponding diff file

Revision: 210