diff options
Diffstat (limited to 'modules/devices/spd-decode.c')
-rw-r--r-- | modules/devices/spd-decode.c | 1509 |
1 files changed, 1509 insertions, 0 deletions
diff --git a/modules/devices/spd-decode.c b/modules/devices/spd-decode.c new file mode 100644 index 00000000..ac1dd52b --- /dev/null +++ b/modules/devices/spd-decode.c @@ -0,0 +1,1509 @@ +/* + * spd-decode.c + * Copyright (c) 2010 Leandro A. F. Pereira + * + * Based on decode-dimms.pl + * Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com> + * modified by Christian Zuckschwerdt <zany@triq.net> + * modified by Burkart Lingner <burkart@bollchen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <ctype.h> +#include <math.h> +#include <stdio.h> +#include <sys/stat.h> + +#include "hardinfo.h" +#include "devices.h" + +typedef enum { + UNKNOWN, + DIRECT_RAMBUS, + RAMBUS, + FPM_DRAM, + EDO, + PIPELINED_NIBBLE, + SDR_SDRAM, + MULTIPLEXED_ROM, + DDR_SGRAM, + DDR_SDRAM, + DDR2_SDRAM, + DDR3_SDRAM +} RamType; + +char *spd_info = NULL; + +static const char *ram_types[] = { + "Unknown", + "Direct Rambus", + "Rambus", + "FPM DRAM", + "EDO", + "Pipelined Nibble", + "SDR SDRAM", + "Multiplexed ROM", + "DDR SGRAM", + "DDR SDRAM", + "DDR2 SDRAM", + "DDR3 SDRAM" +}; + +static const char *vendors1[] = { "AMD", "AMI", "Fairchild", "Fujitsu", + "GTE", "Harris", "Hitachi", "Inmos", + "Intel", "I.T.T.", "Intersil", + "Monolithic Memories", + "Mostek", + "Freescale (former Motorola)", + "National", "NEC", + "RCA", "Raytheon", + "Conexant (Rockwell)", "Seeq", + "NXP (former Signetics, Philips Semi.)", + "Synertek", + "Texas Instruments", "Toshiba", + "Xicor", "Zilog", "Eurotechnique", + "Mitsubishi", + "Lucent (AT&T)", "Exel", "Atmel", + "SGS/Thomson", + "Lattice Semi.", "NCR", + "Wafer Scale Integration", "IBM", + "Tristar", "Visic", + "Intl. CMOS Technology", "SSSI", + "MicrochipTechnology", "Ricoh Ltd.", + "VLSI", "Micron Technology", + "Hyundai Electronics", + "OKI Semiconductor", "ACTEL", + "Sharp", + "Catalyst", "Panasonic", "IDT", + "Cypress", + "DEC", "LSI Logic", + "Zarlink (former Plessey)", "UTMC", + "Thinking Machine", "Thomson CSF", + "Integrated CMOS (Vertex)", + "Honeywell", + "Tektronix", "Sun Microsystems", + "SST", "ProMos/Mosel Vitelic", + "Infineon (former Siemens)", + "Macronix", "Xerox", "Plus Logic", + "SunDisk", "Elan Circuit Tech.", + "European Silicon Str.", + "Apple Computer", + "Xilinx", "Compaq", + "Protocol Engines", "SCI", + "Seiko Instruments", "Samsung", + "I3 Design System", "Klic", + "Crosspoint Solutions", + "Alliance Semiconductor", "Tandem", + "Hewlett-Packard", + "Intg. Silicon Solutions", + "Brooktree", "New Media", + "MHS Electronic", + "Performance Semi.", + "Winbond Electronic", + "Kawasaki Steel", + "Bright Micro", + "TECMAR", "Exar", "PCMCIA", + "LG Semi (former Goldstar)", + "Northern Telecom", "Sanyo", + "Array Microsystems", + "Crystal Semiconductor", + "Analog Devices", "PMC-Sierra", + "Asparix", "Convex Computer", + "Quality Semiconductor", + "Nimbus Technology", "Transwitch", + "Micronas (ITT Intermetall)", + "Cannon", "Altera", "NEXCOM", + "QUALCOMM", + "Sony", "Cray Research", + "AMS(Austria Micro)", "Vitesse", + "Aster Electronics", + "Bay Networks (Synoptic)", + "Zentrum or ZMD", + "TRW", + "Thesys", "Solbourne Computer", + "Allied-Signal", "Dialog", + "Media Vision", + "Level One Communication" +}; + +static const char *vendors2[] = { "Cirrus Logic", + "National Instruments", + "ILC Data Device", + "Alcatel Mietec", + "Micro Linear", + "Univ. of NC", + "JTAG Technologies", + "BAE Systems", + "Nchip", + "Galileo Tech", + "Bestlink Systems", + "Graychip", + "GENNUM", + "VideoLogic", + "Robert Bosch", + "Chip Express", + "DATARAM", + "United Microelec Corp.", + "TCSI", + "Smart Modular", + "Hughes Aircraft", + "Lanstar Semiconductor", + "Qlogic", "Kingston", + "Music Semi", + "Ericsson Components", + "SpaSE", + "Eon Silicon Devices", + "Programmable Micro Corp", + "DoD", + "Integ. Memories Tech.", + "Corollary Inc.", + "Dallas Semiconductor", + "Omnivision", + "EIV(Switzerland)", + "Novatel Wireless", + "Zarlink (former Mitel)", + "Clearpoint", + "Cabletron", + "STEC (former Silicon Technology)", + "Vanguard", + "Hagiwara Sys-Com", + "Vantis", "Celestica", + "Century", + "Hal Computers", + "Rohm Company Ltd.", + "Juniper Networks", + "Libit Signal Processing", + "Mushkin Enhanced Memory", + "Tundra Semiconductor", + "Adaptec Inc.", + "LightSpeed Semi.", + "ZSP Corp.", + "AMIC Technology", + "Adobe Systems", + "Dynachip", + "PNY Electronics", + "Newport Digital", + "MMC Networks", + "T Square", + "Seiko Epson", + "Broadcom", + "Viking Components", + "V3 Semiconductor", + "Flextronics (former Orbit)", + "Suwa Electronics", + "Transmeta", + "Micron CMS", + "American Computer & Digital Components Inc", + "Enhance 3000 Inc", + "Tower Semiconductor", + "CPU Design", + "Price Point", + "Maxim Integrated Product", + "Tellabs", + "Centaur Technology", + "Unigen Corporation", + "Transcend Information", + "Memory Card Technology", + "CKD Corporation Ltd.", + "Capital Instruments, Inc.", + "Aica Kogyo, Ltd.", + "Linvex Technology", + "MSC Vertriebs GmbH", + "AKM Company, Ltd.", + "Dynamem, Inc.", + "NERA ASA", + "GSI Technology", + "Dane-Elec (C Memory)", + "Acorn Computers", + "Lara Technology", + "Oak Technology, Inc.", + "Itec Memory", + "Tanisys Technology", + "Truevision", + "Wintec Industries", + "Super PC Memory", + "MGV Memory", + "Galvantech", + "Gadzoox Nteworks", + "Multi Dimensional Cons.", + "GateField", + "Integrated Memory System", + "Triscend", "XaQti", + "Goldenram", + "Clear Logic", + "Cimaron Communications", + "Nippon Steel Semi. Corp.", + "Advantage Memory", + "AMCC", + "LeCroy", + "Yamaha Corporation", + "Digital Microwave", + "NetLogic Microsystems", + "MIMOS Semiconductor", + "Advanced Fibre", + "BF Goodrich Data.", + "Epigram", + "Acbel Polytech Inc.", + "Apacer Technology", + "Admor Memory", + "FOXCONN", + "Quadratics Superconductor", + "3COM", +}; + +static const char *vendors3[] = { "Camintonn Corporation", "ISOA Incorporated", + "Agate Semiconductor", "ADMtek Incorporated", + "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies", + "Ardent Technologies", + "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies", + "WorkX AG", + "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions", + "Power General", + "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity", + "Delkin Devices", + "Symagery Microsystems", "C-Port Corporation", + "SiberCore Technologies", "Southland Microsystems", + "Malleable Technologies", "Kendin Communications", + "Great Technology Microcomputer", "Sanmina Corporation", + "HADCO Corporation", "Corsair", "Actrans System Inc.", + "ALPHA Technologies", + "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies", + "Align Manufacturing", "Peregrine Semiconductor", + "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies", + "Chrysalis ITS", + "ADTEC Corporation", "Kentron Technologies", "Win Technologies", + "Tachyon Semiconductor (former ASIC Designs Inc.)", + "Extreme Packet Devices", "RF Micro Devices", "Siemens AG", + "Sarnoff Corporation", + "Itautec Philco SA", "Radiata Inc.", "Benchmark Elect. (AVEX)", + "Legend", + "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated", + "SwitchOn Networks", + "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology", + "Virata Corporation", + "Excess Bandwidth", "West Bay Semiconductor", "DSP Group", + "Newport Communications", + "Chip2Chip Incorporated", "Phobos Corporation", + "Intellitech Corporation", "Nordic VLSI ASA", + "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor", + "Agilent Technologies", + "Centillium Communications", "W.L. Gore", "HanBit Electronics", + "GlobeSpan", + "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated", + "MetaLink Technologies", "Feiya Technology", "I & C Technology", + "Shikatronics", + "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions", + "Hyperchip", "Gemstone Communications", "Anadigm (former Anadyne)", + "3ParData", + "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys", + "Skyup Technology", "HiNT Corporation", "Chiaro", + "MDT Technologies GmbH (former MCI Computer GMBH)", + "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory", + "Legerity", + "Jasmine Networks", "Caspian Networks", "nCUBE", + "Silicon Access Networks", + "FDK Corporation", "High Bandwidth Access", "MultiLink Technology", + "BRECIS", + "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic", + "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power", + "eSilicon", "Morphics Technology", "Accelerant Networks", + "Silicon Wave", + "SandCraft", "Elpida" +}; + +static const char *vendors4[] = { "Solectron", "Optosys Technologies", + "Buffalo (former Melco)", + "TriMedia Technologies", + "Cyan Technologies", "Global Locate", + "Optillion", + "Terago Communications", + "Ikanos Communications", + "Princeton Technology", + "Nanya Technology", + "Elite Flash Storage", + "Mysticom", "LightSand Communications", + "ATI Technologies", + "Agere Systems", + "NeoMagic", "AuroraNetics", "Golden Empire", + "Mushkin", + "Tioga Technologies", "Netlist", "TeraLogic", + "Cicada Semiconductor", + "Centon Electronics", "Tyco Electronics", + "Magis Works", "Zettacom", + "Cogency Semiconductor", "Chipcon AS", + "Aspex Technology", + "F5 Networks", + "Programmable Silicon Solutions", + "ChipWrights", + "Acorn Networks", + "Quicklogic", + "Kingmax Semiconductor", "BOPS", "Flasys", + "BitBlitz Communications", + "eMemory Technology", "Procket Networks", + "Purple Ray", + "Trebia Networks", + "Delta Electronics", "Onex Communications", + "Ample Communications", + "Memory Experts Intl", + "Astute Networks", "Azanda Network Devices", + "Dibcom", "Tekmos", + "API NetWorks", "Bay Microsystems", + "Firecron Ltd", + "Resonext Communications", + "Tachys Technologies", "Equator Technology", + "Concept Computer", + "SILCOM", + "3Dlabs", "c't Magazine", "Sanera Systems", + "Silicon Packets", + "Viasystems Group", "Simtek", + "Semicon Devices Singapore", + "Satron Handelsges", + "Improv Systems", "INDUSYS GmbH", "Corrent", + "Infrant Technologies", + "Ritek Corp", "empowerTel Networks", + "Hypertec", + "Cavium Networks", + "PLX Technology", "Massana Design", + "Intrinsity", + "Valence Semiconductor", + "Terawave Communications", + "IceFyre Semiconductor", "Primarion", + "Picochip Designs Ltd", + "Silverback Systems", + "Jade Star Technologies", + "Pijnenburg Securealink", + "TakeMS International AG", + "Cambridge Silicon Radio", + "Swissbit", "Nazomi Communications", + "eWave System", + "Rockwell Collins", "Picocel Co., Ltd.", + "Alphamosaic Ltd", + "Sandburst", + "SiCon Video", "NanoAmp Solutions", + "Ericsson Technology", + "PrairieComm", + "Mitac International", "Layer N Networks", + "MtekVision", + "Allegro Networks", + "Marvell Semiconductors", + "Netergy Microelectronic", "NVIDIA", + "Internet Machines", + "Peak Electronics", + "Litchfield Communication", + "Accton Technology", + "Teradiant Networks", + "Europe Technologies", "Cortina Systems", + "RAM Components", + "Raqia Networks", + "ClearSpeed", "Matsushita Battery", + "Xelerated", + "SimpleTech", + "Utron Technology", "Astec International", + "AVM gmbH", + "Redux Communications", + "Dot Hill Systems", "TeraChip" +}; + +static const char *vendors5[] = { "T-RAM Incorporated", + "Innovics Wireless", "Teknovus", "KeyEye Communications", + "Runcom Technologies", "RedSwitch", "Dotcast", + "Silicon Mountain Memory", + "Signia Technologies", "Pixim", "Galazar Networks", + "White Electronic Designs", + "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology", + "Europe Technologies", + "Potentia Power Systems", "C-guys Incorporated", + "Digital Communications Technology Incorporated", + "Silicon-Based Technology", + "Fulcrum Microsystems", "Positivo Informatica Ltd", + "XIOtech Corporation", "PortalPlayer", + "Zhiying Software", "Direct2Data", "Phonex Broadband", + "Skyworks Solutions", + "Entropic Communications", "Pacific Force Technology", "Zensys A/S", + "Legend Silicon Corp.", + "sci-worx GmbH", "SMSC (former Oasis Silicon Systems)", + "Renesas Technology", "Raza Microelectronics", + "Phyworks", "MediaTek", "Non-cents Productions", "US Modular", + "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies", + "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ", + "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies", + "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology", + "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision", + "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom", + "Bandspeed", + "LeWiz Communications", "CPU Technology", "Ramaxel Technology", + "DSP Group", + "Axis Communications", "Legacy Electronics", "Chrontel", + "Powerchip Semiconductor", + "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology", + "VirtualDigm", + "G Skill Intl", "Quanta Computer", "Yield Microelectronics", + "Afa Technologies", + "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks", + "Advance Modules", + "Microsoft", "Open-Silicon", "Goal Semiconductor", + "ARC International", + "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics", + "Adimos", "SiGe Semiconductor", "Fodus Communications", + "Credence Systems Corp.", + "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies", + "GateChange Technologies", + "High Density Devices AS", "Synopsys", "Gigaram", + "Enigma Semiconductor Inc.", + "Century Micro Inc.", "Icera Semiconductor", + "Mediaworks Integrated Systems", "O'Neil Product Development", + "Supreme Top Technology Ltd.", "MicroDisplay Corporation", + "Team Group Inc.", "Sinett Corporation", + "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.", + "SMaL Camera Technologies", "Thomson SC", "Airgo Networks", + "Wisair Ltd.", + "SigmaTel", "Arkados", "Compete IT gmbH Co. KG", + "Eudar Technology Inc.", + "Focus Enhancements", "Xyratex" +}; + +static const char *vendors6[] = { "Specular Networks", + "Patriot Memory", + "U-Chip Technology Corp.", + "Silicon Optix", + "Greenfield Networks", + "CompuRAM GmbH", "Stargen, Inc.", + "NetCell Corporation", + "Excalibrus Technologies Ltd", + "SCM Microsystems", + "Xsigo Systems, Inc.", + "CHIPS & Systems Inc", + "Tier 1 Multichip Solutions", + "CWRL Labs", "Teradici", + "Gigaram, Inc.", + "g2 Microsystems", + "PowerFlash Semiconductor", + "P.A. Semi, Inc.", + "NovaTech Solutions, S.A.", + "c2 Microsystems, Inc.", + "Level5 Networks", + "COS Memory AG", + "Innovasic Semiconductor", + "02IC Co. Ltd", "Tabula, Inc.", + "Crucial Technology", + "Chelsio Communications", + "Solarflare Communications", + "Xambala Inc.", "EADS Astrium", + "ATO Semicon Co. Ltd.", + "Imaging Works, Inc.", + "Astute Networks, Inc.", "Tzero", + "Emulex", + "Power-One", "Pulse~LINK Inc.", + "Hon Hai Precision Industry", + "White Rock Networks Inc.", + "Telegent Systems USA, Inc.", + "Atrua Technologies, Inc.", + "Acbel Polytech Inc.", + "eRide Inc.", + "ULi Electronics Inc.", + "Magnum Semiconductor Inc.", + "neoOne Technology, Inc.", + "Connex Technology, Inc.", + "Stream Processors, Inc.", + "Focus Enhancements", + "Telecis Wireless, Inc.", + "uNav Microelectronics", + "Tarari, Inc.", "Ambric, Inc.", + "Newport Media, Inc.", "VMTS", + "Enuclia Semiconductor, Inc.", + "Virtium Technology Inc.", + "Solid State System Co., Ltd.", + "Kian Tech LLC", + "Artimi", + "Power Quotient International", + "Avago Technologies", + "ADTechnology", "Sigma Designs", + "SiCortex, Inc.", + "Ventura Technology Group", + "eASIC", "M.H.S. SAS", + "Micro Star International", + "Rapport Inc.", + "Makway International", + "Broad Reach Engineering Co.", + "Semiconductor Mfg Intl Corp", + "SiConnect", "FCI USA Inc.", + "Validity Sensors", + "Coney Technology Co. Ltd.", + "Spans Logic", "Neterion Inc.", + "Qimonda", + "New Japan Radio Co. Ltd.", + "Velogix", "Montalvo Systems", + "iVivity Inc.", + "Walton Chaintech", + "AENEON", + "Lorom Industrial Co. Ltd.", + "Radiospire Networks", + "Sensio Technologies, Inc.", + "Nethra Imaging", + "Hexon Technology Pte Ltd", + "CompuStocx (CSX)", + "Methode Electronics, Inc.", + "Connect One Ltd.", + "Opulan Technologies", + "Septentrio NV", + "Goldenmars Technology Inc.", + "Kreton Corporation", + "Cochlear Ltd.", + "Altair Semiconductor", + "NetEffect, Inc.", + "Spansion, Inc.", + "Taiwan Semiconductor Mfg", + "Emphany Systems Inc.", + "ApaceWave Technologies", + "Mobilygen Corporation", "Tego", + "Cswitch Corporation", + "Haier (Beijing) IC Design Co.", + "MetaRAM", + "Axel Electronics Co. Ltd.", + "Tilera Corporation", + "Aquantia", + "Vivace Semiconductor", + "Redpine Signals", "Octalica", + "InterDigital Communications", + "Avant Technology", + "Asrock, Inc.", "Availink", + "Quartics, Inc.", + "Element CXI", + "Innovaciones Microelectronicas", + "VeriSilicon Microelectronics", + "W5 Networks" +}; + +static const char *vendors7[] = { "MOVEKING", "Mavrix Technology, Inc.", + "CellGuide Ltd.", "Faraday Technology", + "Diablo Technologies, Inc.", "Jennic", "Octasic", + "Molex Incorporated", + "3Leaf Networks", + "Bright Micron Technology", "Netxen", "NextWave Broadband Inc.", + "DisplayLink", "ZMOS Technology", + "Tec-Hill", "Multigig, Inc.", "Amimon", "Euphonic Technologies, Inc.", + "BRN Phoenix", + "InSilica", "Ember Corporation", "Avexir Technologies Corporation", + "Echelon Corporation", + "Edgewater Computer Systems", "XMOS Semiconductor Ltd.", + "GENUSION, Inc.", "Memory Corp NV", + "SiliconBlue Technologies", "Rambus Inc." +}; + +static const char **vendors[7] = { vendors1, vendors2, vendors3, vendors4, vendors5, vendors6, + vendors7 +}; + +/* + * We consider that no data was written to this area of the SPD EEPROM if + * all bytes read 0x00 or all bytes read 0xff + */ +static int spd_written(unsigned char *bytes, int len) +{ + do { + if (*bytes == 0x00 || *bytes == 0xFF) + return 1; + } while (--len && bytes++); + + return 0; +} + +static int parity(int value) +{ + value ^= value >> 16; + value ^= value >> 8; + value ^= value >> 4; + value &= 0xf; + + return (0x6996 >> value) & 1; +} + +static void decode_sdr_module_size(unsigned char *bytes, int *size) +{ + int i, k = 0; + + i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17; + if (bytes[5] <= 8 && bytes[17] <= 8) { + k = bytes[5] * bytes[17]; + } + + if (i > 0 && i <= 12 && k > 0) { + if (size) { + *size = (1 << i) * k; + } + } else { + if (size) { + *size = -1; + } + } +} + +static void decode_sdr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras) +{ + float cas[3], ctime; + int i, j; + + for (i = 0, j = 0; j < 7; j++) { + if (bytes[18] & 1 << j) { + cas[i++] = j + 1; + } + } + + ctime = (bytes[9] >> 4 + bytes[9] & 0xf) * 0.1; + + if (trcd) { + *trcd = ceil(bytes[29] / ctime); + } + if (trp) { + *trp = ceil(bytes[27] / ctime); + } + if (tras) { + *tras = ceil(bytes[30] / ctime); + } + if (tcl) { + *tcl = cas[i]; + } +} + +static void decode_sdr_module_row_address_bits(unsigned char *bytes, char **bits) +{ + char *temp; + + switch (bytes[3]) { + case 0: + temp = "Undefined"; + break; + case 1: + temp = "1/16"; + break; + case 2: + temp = "2/27"; + break; + case 3: + temp = "3/18"; + break; + default: + /* printf("%d\n", bytes[3]); */ + temp = "Unknown"; + } + + if (bits) { + *bits = temp; + } +} + +static void decode_sdr_module_col_address_bits(unsigned char *bytes, char **bits) +{ + char *temp; + + switch (bytes[4]) { + case 0: + temp = "Undefined"; + break; + case 1: + temp = "1/16"; + break; + case 2: + temp = "2/17"; + break; + case 3: + temp = "3/18"; + break; + default: + /*printf("%d\n", bytes[4]); */ + temp = "Unknown"; + } + + if (bits) { + *bits = temp; + } +} + +static void decode_sdr_module_number_of_rows(unsigned char *bytes, int *rows) +{ + if (rows) { + *rows = bytes[5]; + } +} + +static void decode_sdr_module_data_with(unsigned char *bytes, int *width) +{ + if (width) { + if (bytes[7] > 1) { + *width = 0; + } else { + *width = (bytes[7] * 0xff) + bytes[6]; + } + } +} + +static void decode_sdr_module_interface_signal_levels(unsigned char *bytes, char **signal_levels) +{ + char *temp; + + switch (bytes[8]) { + case 0: + temp = "5.0 Volt/TTL"; + break; + case 1: + temp = "LVTTL"; + break; + case 2: + temp = "HSTL 1.5"; + break; + case 3: + temp = "SSTL 3.3"; + break; + case 4: + temp = "SSTL 2.5"; + break; + case 255: + temp = "New Table"; + break; + default: + temp = "Undefined"; + } + + if (signal_levels) { + *signal_levels = temp; + } +} + +static void decode_sdr_module_configuration_type(unsigned char *bytes, char **module_config_type) +{ + char *temp; + + switch (bytes[11]) { + case 0: + temp = "No parity"; + break; + case 1: + temp = "Parity"; + break; + case 2: + temp = "ECC"; + break; + default: + temp = "Undefined"; + } + + if (module_config_type) { + *module_config_type = temp; + } +} + +static void decode_sdr_module_refresh_type(unsigned char *bytes, char **refresh_type) +{ + char *temp; + + if (bytes[12] & 0x80) { + temp = "Self refreshing"; + } else { + temp = "Not self refreshing"; + } + + if (refresh_type) { + *refresh_type = temp; + } +} + +static void decode_sdr_module_refresh_rate(unsigned char *bytes, char **refresh_rate) +{ + char *temp; + + switch (bytes[12] & 0x7f) { + case 0: + temp = "Normal (15.625us)"; + break; + case 1: + temp = "Reduced (3.9us)"; + break; + case 2: + temp = "Reduced (7.8us)"; + break; + case 3: + temp = "Extended (31.3us)"; + break; + case 4: + temp = "Extended (62.5us)"; + break; + case 5: + temp = "Extended (125us)"; + break; + default: + temp = "Undefined"; + } + + if (refresh_rate) { + *refresh_rate = temp; + } +} + +static gchar *decode_sdr_sdram(unsigned char *bytes, int *size) +{ + int rows, data_width; + float tcl, trcd, trp, tras; + char *row_address_bits, *col_address_bits, *signal_level; + char *module_config_type, *refresh_type, *refresh_rate; + + decode_sdr_module_size(bytes, size); + decode_sdr_module_timings(bytes, &tcl, &trcd, &trp, &tras); + decode_sdr_module_row_address_bits(bytes, &row_address_bits); + decode_sdr_module_col_address_bits(bytes, &col_address_bits); + decode_sdr_module_number_of_rows(bytes, &rows); + decode_sdr_module_data_with(bytes, &data_width); + decode_sdr_module_interface_signal_levels(bytes, &signal_level); + decode_sdr_module_configuration_type(bytes, &module_config_type); + decode_sdr_module_refresh_type(bytes, &refresh_type); + decode_sdr_module_refresh_rate(bytes, &refresh_rate); + + /* TODO: + - RAS to CAS delay + - Supported CAS latencies + - Supported CS latencies + - Supported WE latencies + - Cycle Time / Access time + - SDRAM module attributes + - SDRAM device attributes + - Row densities + - Other misc stuff + */ + + return g_strdup_printf("[Module Information]\n" + "Module type=SDR\n" + "SPD revision=%d\n" + "Row address bits=%s\n" + "Column address bits=%s\n" + "Number of rows=%d\n" + "Data width=%d bits\n" + "Interface signal levels=%s\n" + "Configuration type=%s\n" + "Refresh=%s (%s)\n" + "[Timings]\n" + "tCL=%.2f\n" + "tRCD=%.2f\n" + "tRP=%.2f\n" + "tRAS=%.2f\n", + bytes[62], + row_address_bits, col_address_bits, rows, + data_width, signal_level, module_config_type, + refresh_type, refresh_rate, tcl, trcd, trp, tras); +} + +static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pcclk) +{ + float temp, clk; + int tbits, pc; + + temp = (bytes[9] >> 4) + (bytes[9] & 0xf) * 0.1; + clk = 2 * (1000 / temp); + tbits = (bytes[7] * 256) + bytes[6]; + + if (bytes[11] == 2 || bytes[11] == 1) { + tbits -= 8; + } + + pc = clk * tbits / 8; + if (pc % 100 > 50) { + pc += 100; + } + pc -= pc % 100; + + if (ddrclk) + *ddrclk = (int) clk; + + if (pcclk) + *pcclk = pc; +} + +static void decode_ddr_module_size(unsigned char *bytes, int *size) +{ + int i, k; + + i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17; + k = (bytes[5] <= 8 && bytes[17] <= 8) ? bytes[5] * bytes[17] : 0; + + if (i > 0 && i <= 12 && k > 0) { + if (size) { + *size = (1 << i) * k; + } + } else { + if (size) { + *size = -1; + } + } +} + +static void *decode_ddr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras) +{ + float ctime; + float highest_cas = 0; + int i; + + for (i = 0; i < 7; i++) { + if (bytes[18] & (1 << i)) { + highest_cas = 1 + i * 0.5f; + } + } + + ctime = (bytes[9] >> 4) + (bytes[9] & 0xf) * 0.1; + + if (trcd) { + *trcd = (bytes[29] >> 2) + ((bytes[29] & 3) * 0.25); + *trcd = ceil(*trcd / ctime); + } + + if (trp) { + *trp = (bytes[27] >> 2) + ((bytes[27] & 3) * 0.25); + *trp = ceil(*trp / ctime); + } + + if (tras) { + *tras = bytes[30]; + *tras = ceil(*tras / ctime); + } + + if (tcl) { + *tcl = highest_cas; + } +} + +static gchar *decode_ddr_sdram(unsigned char *bytes, int *size) +{ + float ddr_clock; + float tcl, trcd, trp, tras; + int pc_speed; + + decode_ddr_module_speed(bytes, &ddr_clock, &pc_speed); + decode_ddr_module_size(bytes, size); + decode_ddr_module_timings(bytes, &tcl, &trcd, &trp, &tras); + + return g_strdup_printf("[Module Information]\n" + "Module type=DDR %.2fMHz (PC%d)\n" + "SPD revision=%d.%d\n" + "[Timings]\n" + "tCL=%.2f\n" + "tRCD=%.2f\n" + "tRP=%.2f\n" + "tRAS=%.2f\n", ddr_clock, pc_speed, bytes[62] >> 4, bytes[62] & 0xf, tcl, trcd, trp, tras); +} + +static float decode_ddr2_module_ctime(unsigned char byte) +{ + float ctime; + + ctime = (byte >> 4); + byte &= 0xf; + + if (byte <= 9) { + ctime += byte * 0.1; + } else if (byte == 10) { + ctime += 0.25; + } else if (byte == 11) { + ctime += 0.33; + } else if (byte == 12) { + ctime += 0.66; + } else if (byte == 13) { + ctime += 0.75; + } + + return ctime; +} + +static void decode_ddr2_module_speed(unsigned char *bytes, float *ddr_clock, int *pc2_speed) +{ + float ctime; + float ddrclk; + int tbits, pcclk; + + ctime = decode_ddr2_module_ctime(bytes[9]); + ddrclk = 2 * (1000 / ctime); + + tbits = (bytes[7] * 256) + bytes[6]; + if (bytes[11] & 0x03) { + tbits -= 8; + } + + pcclk = ddrclk * tbits / 8; + pcclk -= pcclk % 100; + + if (ddr_clock) { + *ddr_clock = (int) ddrclk; + } + if (pc2_speed) { + *pc2_speed = pcclk; + } +} + +static void decode_ddr2_module_size(unsigned char *bytes, int *size) +{ + int i, k; + + i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17; + k = ((bytes[5] & 0x7) + 1) * bytes[17]; + + if (i > 0 && i <= 12 && k > 0) { + if (*size) { + *size = ((1 << i) * k); + } + } else { + if (*size) { + *size = 0; + } + } +} + +static void decode_ddr2_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras, float *tcl) +{ + float ctime; + float highest_cas = 0; + int i; + + for (i = 0; i < 7; i++) { + if (bytes[18] & (1 << i)) { + highest_cas = i; + } + } + + ctime = decode_ddr2_module_ctime(bytes[9]); + + if (trcd) { + *trcd = ceil(((bytes[29] >> 2) + ((bytes[29] & 3) * 0.25)) / ctime); + } + + if (trp) { + *trp = ceil(((bytes[27] >> 2) + ((bytes[27] & 3) * 0.25)) / ctime); + } + + if (tras) { + *tras = ceil(bytes[30] / ctime); + } + + if (tcl) { + *tcl = highest_cas; + } +} + +static gchar *decode_ddr2_sdram(unsigned char *bytes, int *size) +{ + float ddr_clock; + float trcd, trp, tras, tcl; + int pc2_speed; + + decode_ddr2_module_speed(bytes, &ddr_clock, &pc2_speed); + decode_ddr2_module_size(bytes, size); + decode_ddr2_module_timings(bytes, &trcd, &trp, &tras, &tcl); + + return g_strdup_printf("[Module Information]\n" + "Module type=DDR2 %.2f MHz (PC2-%d)\n" + "SPD revision=%d.%d\n" + "[Timings]\n" + "tCL=%.2f\n" + "tRCD=%.2f\n" + "tRP=%.2f\n" + "tRAS=%.2f\n", ddr_clock, pc2_speed, bytes[62] >> 4, bytes[62] & 0xf, tcl, trcd, trp, tras); +} + +static void decode_ddr3_module_speed(unsigned char *bytes, float *ddr_clock, int *pc3_speed) +{ + float ctime; + float ddrclk; + int tbits, pcclk; + float mtb = 0.125; + + if (bytes[10] == 1 && bytes[11] == 8) + mtb = 0.125; + if (bytes[10] == 1 && bytes[11] == 15) + mtb = 0.0625; + ctime = mtb * bytes[12]; + + ddrclk = 2 * (1000 / ctime); + + tbits = 64; + switch (bytes[8]) { + case 1: + tbits = 16; + break; + case 4: + tbits = 32; + break; + case 3: + case 0xb: + tbits = 64; + break; + } + + pcclk = ddrclk * tbits / 8; + pcclk -= pcclk % 100; + + if (ddr_clock) { + *ddr_clock = (int) ddrclk; + } + if (pc3_speed) { + *pc3_speed = pcclk; + } +} + +static void decode_ddr3_module_size(unsigned char *bytes, int *size) +{ + *size = 512 << bytes[4]; +} + +static void decode_ddr3_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras, float *tcl) +{ + float ctime; + float highest_cas = 0; + int i; + float mtb = 0.125; + + if (bytes[10] == 1 && bytes[11] == 8) + mtb = 0.125; + if (bytes[10] == 1 && bytes[11] == 15) + mtb = 0.0625; + ctime = mtb * bytes[12]; + + switch (bytes[14]) { + case 6: + highest_cas = 5; + break; + case 4: + highest_cas = 6; + break; + case 0xc: + highest_cas = 7; + break; + case 0x1e: + highest_cas = 8; + break; + } + if (trcd) { + *trcd = bytes[18] * mtb; + } + + if (trp) { + *trp = bytes[20] * mtb; + } + + if (tras) { + *tras = (bytes[22] + bytes[21] & 0xf) * mtb; + } + + if (tcl) { + *tcl = highest_cas; + } +} + +static void decode_ddr3_module_type(unsigned char *bytes, const char **type) +{ + switch (bytes[3]) { + case 0x00: + *type = "Undefined"; + break; + case 0x01: + *type = "RDIMM (Registered Long DIMM)"; + break; + case 0x02: + *type = "UDIMM (Unbuffered Long DIMM)"; + break; + case 0x03: + *type = "SODIMM (Small Outline DIMM)"; + break; + default: + *type = "Unknown"; + } +} + +static gchar *decode_ddr3_sdram(unsigned char *bytes, int *size) +{ + float ddr_clock; + float trcd, trp, tras, tcl; + int pc3_speed; + const char *type; + + decode_ddr3_module_speed(bytes, &ddr_clock, &pc3_speed); + decode_ddr3_module_size(bytes, size); + decode_ddr3_module_timings(bytes, &trcd, &trp, &tras, &tcl); + decode_ddr3_module_type(bytes, &type); + + return g_strdup_printf("[Module Information]\n" + "Module type=DDR3 %.2f MHz (PC3-%d)\n" + "SPD revision=%d.%d\n" + "Type=%s\n" + "[Timings]\n" + "tCL=%.2f\n" + "tRCD=%.3fns\n" + "tRP=%.3fns\n" + "tRAS=%.3fns\n", + ddr_clock, pc3_speed, + bytes[1] >> 4, bytes[1] & 0xf, + type, + tcl, + trcd, + trp, + tras); +} + +static void decode_ddr3_part_number(unsigned char *bytes, char *part_number) +{ + int i; + if (part_number) { + for (i = 128; i <= 145; i++) + *part_number++ = bytes[i]; + *part_number = '\0'; + } +} + +static void decode_ddr3_manufacturer(unsigned char *bytes, char **manufacturer) +{ + char *out = "Unknown"; + + end: + if (manufacturer) { + *manufacturer = out; + } +} + +static void decode_module_manufacturer(unsigned char *bytes, char **manufacturer) +{ + char *out = "Unknown"; + unsigned char first; + int ai = 0; + int len = 8; + unsigned char *initial = bytes; + + if (!spd_written(bytes, 8)) { + out = "Undefined"; + goto end; + } + + do { + ai++; + } while ((--len && (*bytes++ == 0x7f))); + first = *--bytes; + + if (ai == 0) { + out = "Invalid"; + goto end; + } + + if (parity(first) != 1) { + out = "Invalid"; + goto end; + } + + out = (char *) vendors[ai - 1][(first & 0x7f) - 1]; + + end: + if (manufacturer) { + *manufacturer = out; + } +} + +static void decode_module_part_number(unsigned char *bytes, char *part_number) +{ + if (part_number) { + bytes += 8 + 64; + + while (*bytes++ && *bytes >= 32 && *bytes < 127) { + *part_number++ = *bytes; + } + *part_number = '\0'; + } +} + +static int decode_ram_type(unsigned char *bytes) +{ + if (bytes[0] < 4) { + switch (bytes[2]) { + case 1: + return DIRECT_RAMBUS; + case 17: + return RAMBUS; + } + } else { + switch (bytes[2]) { + case 1: + return FPM_DRAM; + case 2: + return EDO; + case 3: + return PIPELINED_NIBBLE; + case 4: + return SDR_SDRAM; + case 5: + return MULTIPLEXED_ROM; + case 6: + return DDR_SGRAM; + case 7: + return DDR_SDRAM; + case 8: + return DDR2_SDRAM; + case 11: + return DDR3_SDRAM; + } + } + + return UNKNOWN; +} + +static void read_spd(char *spd_path, int offset, size_t size, int use_sysfs, unsigned char *bytes_out) +{ + if (use_sysfs) { + FILE *spd; + gchar *temp_path; + + temp_path = g_strdup_printf("%s/eeprom", spd_path); + if ((spd = fopen(temp_path, "rb"))) { + fseek(spd, offset, SEEK_SET); + fread(bytes_out, 1, size, spd); + fclose(spd); + } + + g_free(temp_path); + } else { + int i; + + for (i = 0; i <= 3; i++) { + FILE *spd; + char *temp_path; + + temp_path = g_strdup_printf("%s/%02x", spd_path, offset + i * 16); + if ((spd = fopen(temp_path, "rb"))) { + fread(bytes_out + i * 16, 1, 16, spd); + fclose(spd); + } + + g_free(temp_path); + } + } +} + +static gchar *decode_dimms(GSList * dimm_list, gboolean use_sysfs) +{ + GSList *dimm; + GString *output; + gint count = 0; + + output = g_string_new(""); + + for (dimm = dimm_list; dimm; dimm = dimm->next, count++) { + gchar *spd_path = (gchar *) dimm->data; + gchar *manufacturer; + gchar *detailed_info; + gchar *moreinfo_key; + gchar part_number[32]; + unsigned char bytes[256]; + int module_size; + RamType ram_type; + + shell_status_pulse(); + + read_spd(spd_path, 0, 256, use_sysfs, bytes); + ram_type = decode_ram_type(bytes); + + switch (ram_type) { + case DDR2_SDRAM: + detailed_info = decode_ddr2_sdram(bytes, &module_size); + decode_module_part_number(bytes, part_number); + decode_module_manufacturer(bytes + 64, &manufacturer); + break; + case DDR3_SDRAM: + detailed_info = decode_ddr3_sdram(bytes, &module_size); + decode_ddr3_part_number(bytes, part_number); + decode_ddr3_manufacturer(bytes, &manufacturer); + break; + case DDR_SDRAM: + detailed_info = decode_ddr_sdram(bytes, &module_size); + decode_module_part_number(bytes, part_number); + decode_module_manufacturer(bytes + 64, &manufacturer); + break; + case SDR_SDRAM: + detailed_info = decode_sdr_sdram(bytes, &module_size); + decode_module_part_number(bytes, part_number); + decode_module_manufacturer(bytes + 64, &manufacturer); + break; + default: + DEBUG("Unsupported EEPROM type: %s\n", ram_types[ram_type]); + continue; + } + + + + gchar *key = g_strdup_printf("MEM%d", count); + moreinfo_add_with_prefix("DEV", key, g_strdup(detailed_info)); + g_free(key); + g_string_append_printf(output, "$MEM%d$%d=%s|%d MB|%s\n", count, count, part_number, module_size, manufacturer); + + g_free(spd_path); + g_free(detailed_info); + } + + return g_string_free(output, FALSE); +} + +void scan_spd_do(void) +{ + GDir *dir = NULL; + GSList *dimm_list = NULL; + gboolean use_sysfs = FALSE; + gchar *dir_entry; + gchar *list; + + if (g_file_test("/sys/bus/i2c/drivers/eeprom", G_FILE_TEST_EXISTS)) { + dir = g_dir_open("/sys/bus/i2c/drivers/eeprom", 0, NULL); + use_sysfs = TRUE; + } else if (g_file_test("/proc/sys/dev/sensors", G_FILE_TEST_EXISTS)) { + dir = g_dir_open("/proc/sys/dev/sensors", 0, NULL); + } + + if (!dir) { + g_free(spd_info); + if (!g_file_test("/sys/module/eeprom", G_FILE_TEST_EXISTS)) { + spd_info = g_strdup(_("[SPD]\n" + "Please load the eeprom module to obtain information about memory SPD=\n" + "[$ShellParam$]\n" + "ReloadInterval=500\n")); + } else { + spd_info = g_strdup(_("[SPD]\n" "Reading memory SPD not supported on this system=\n")); + } + + return; + } + + while ((dir_entry = (char *) g_dir_read_name(dir))) { + if (use_sysfs && isdigit(dir_entry[0])) { + dimm_list = g_slist_prepend(dimm_list, g_strdup_printf("/sys/bus/i2c/drivers/eeprom/%s", dir_entry)); + } else if (g_str_has_prefix(dir_entry, "eeprom-")) { + dimm_list = g_slist_prepend(dimm_list, g_strdup_printf("/proc/sys/dev/sensors/%s", dir_entry)); + } + } + + g_dir_close(dir); + + list = decode_dimms(dimm_list, use_sysfs); + g_slist_free(dimm_list); + + g_free(spd_info); + spd_info = g_strdup_printf("[SPD]\n" + "%s\n" + "[$ShellParam$]\n" + "ViewType=1\n" + "ColumnTitle$TextValue=Bank\n" + "ColumnTitle$Extra1=Size\n" + "ColumnTitle$Extra2=Manufacturer\n" + "ColumnTitle$Value=Model\n" "ShowColumnHeaders=true\n", list); + g_free(list); +} |