| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: spdmem.c,v 1.24.6.2 2019/01/03 11:23:54 martin Exp $ */ | | 1 | /* $NetBSD: spdmem.c,v 1.24.6.3 2020/04/14 17:39:28 martin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2007 Nicolas Joly | | 4 | * Copyright (c) 2007 Nicolas Joly |
5 | * Copyright (c) 2007 Paul Goyette | | 5 | * Copyright (c) 2007 Paul Goyette |
6 | * Copyright (c) 2007 Tobias Nygren | | 6 | * Copyright (c) 2007 Tobias Nygren |
7 | * All rights reserved. | | 7 | * All rights reserved. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -25,27 +25,27 @@ | | | @@ -25,27 +25,27 @@ |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * Serial Presence Detect (SPD) memory identification | | 34 | * Serial Presence Detect (SPD) memory identification |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.24.6.2 2019/01/03 11:23:54 martin Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.24.6.3 2020/04/14 17:39:28 martin Exp $"); |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/device.h> | | 41 | #include <sys/device.h> |
42 | #include <sys/endian.h> | | 42 | #include <sys/endian.h> |
43 | #include <sys/sysctl.h> | | 43 | #include <sys/sysctl.h> |
44 | #include <machine/bswap.h> | | 44 | #include <machine/bswap.h> |
45 | | | 45 | |
46 | #include <dev/i2c/i2cvar.h> | | 46 | #include <dev/i2c/i2cvar.h> |
47 | #include <dev/ic/spdmemreg.h> | | 47 | #include <dev/ic/spdmemreg.h> |
48 | #include <dev/ic/spdmemvar.h> | | 48 | #include <dev/ic/spdmemvar.h> |
49 | | | 49 | |
50 | /* Routines for decoding spd data */ | | 50 | /* Routines for decoding spd data */ |
51 | static void decode_edofpm(const struct sysctlnode *, device_t, struct spdmem *); | | 51 | static void decode_edofpm(const struct sysctlnode *, device_t, struct spdmem *); |
| @@ -330,32 +330,32 @@ spdmem_common_attach(struct spdmem_softc | | | @@ -330,32 +330,32 @@ spdmem_common_attach(struct spdmem_softc |
330 | spd_len = sizeof(struct spdmem); | | 330 | spd_len = sizeof(struct spdmem); |
331 | for (i = 3; i < spd_len; i++) | | 331 | for (i = 3; i < spd_len; i++) |
332 | (sc->sc_read)(sc, i, &((uint8_t *)s)[i]); | | 332 | (sc->sc_read)(sc, i, &((uint8_t *)s)[i]); |
333 | | | 333 | |
334 | /* | | 334 | /* |
335 | * Setup our sysctl subtree, hw.spdmemN | | 335 | * Setup our sysctl subtree, hw.spdmemN |
336 | */ | | 336 | */ |
337 | sc->sc_sysctl_log = NULL; | | 337 | sc->sc_sysctl_log = NULL; |
338 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, &node, | | 338 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, &node, |
339 | 0, CTLTYPE_NODE, | | 339 | 0, CTLTYPE_NODE, |
340 | device_xname(self), NULL, NULL, 0, NULL, 0, | | 340 | device_xname(self), NULL, NULL, 0, NULL, 0, |
341 | CTL_HW, CTL_CREATE, CTL_EOL); | | 341 | CTL_HW, CTL_CREATE, CTL_EOL); |
342 | if (node != NULL && spd_len != 0) | | 342 | if (node != NULL && spd_len != 0) |
343 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, | | 343 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, |
344 | 0, | | 344 | 0, |
345 | CTLTYPE_STRUCT, "spd_data", | | 345 | CTLTYPE_STRUCT, "spd_data", |
346 | SYSCTL_DESCR("raw spd data"), NULL, | | 346 | SYSCTL_DESCR("raw spd data"), NULL, |
347 | 0, s, spd_len, | | 347 | 0, s, spd_len, |
348 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 348 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
349 | | | 349 | |
350 | /* | | 350 | /* |
351 | * Decode and print key SPD contents | | 351 | * Decode and print key SPD contents |
352 | */ | | 352 | */ |
353 | if (IS_RAMBUS_TYPE) { | | 353 | if (IS_RAMBUS_TYPE) { |
354 | if (s->sm_type == SPDMEM_MEMTYPE_RAMBUS) | | 354 | if (s->sm_type == SPDMEM_MEMTYPE_RAMBUS) |
355 | type = "Rambus"; | | 355 | type = "Rambus"; |
356 | else if (s->sm_type == SPDMEM_MEMTYPE_DIRECTRAMBUS) | | 356 | else if (s->sm_type == SPDMEM_MEMTYPE_DIRECTRAMBUS) |
357 | type = "Direct Rambus"; | | 357 | type = "Direct Rambus"; |
358 | else | | 358 | else |
359 | type = "Rambus (unknown)"; | | 359 | type = "Rambus (unknown)"; |
360 | | | 360 | |
361 | switch (s->sm_len) { | | 361 | switch (s->sm_len) { |
| @@ -401,27 +401,27 @@ spdmem_common_attach(struct spdmem_softc | | | @@ -401,27 +401,27 @@ spdmem_common_attach(struct spdmem_softc |
401 | | | 401 | |
402 | strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN); | | 402 | strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN); |
403 | | | 403 | |
404 | if (s->sm_type == SPDMEM_MEMTYPE_DDR4SDRAM) { | | 404 | if (s->sm_type == SPDMEM_MEMTYPE_DDR4SDRAM) { |
405 | /* | | 405 | /* |
406 | * The latest spec (DDR4 SPD Document Release 3) defines | | 406 | * The latest spec (DDR4 SPD Document Release 3) defines |
407 | * NVDIMM Hybrid only. | | 407 | * NVDIMM Hybrid only. |
408 | */ | | 408 | */ |
409 | if ((s->sm_ddr4.ddr4_hybrid) | | 409 | if ((s->sm_ddr4.ddr4_hybrid) |
410 | && (s->sm_ddr4.ddr4_hybrid_media == 1)) | | 410 | && (s->sm_ddr4.ddr4_hybrid_media == 1)) |
411 | strlcat(sc->sc_type, " NVDIMM hybrid", | | 411 | strlcat(sc->sc_type, " NVDIMM hybrid", |
412 | SPDMEM_TYPE_MAXLEN); | | 412 | SPDMEM_TYPE_MAXLEN); |
413 | } | | 413 | } |
414 | | | 414 | |
415 | if (node != NULL) | | 415 | if (node != NULL) |
416 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, | | 416 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, |
417 | 0, | | 417 | 0, |
418 | CTLTYPE_STRING, "mem_type", | | 418 | CTLTYPE_STRING, "mem_type", |
419 | SYSCTL_DESCR("memory module type"), NULL, | | 419 | SYSCTL_DESCR("memory module type"), NULL, |
420 | 0, sc->sc_type, 0, | | 420 | 0, sc->sc_type, 0, |
421 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 421 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
422 | | | 422 | |
423 | if (IS_RAMBUS_TYPE) { | | 423 | if (IS_RAMBUS_TYPE) { |
424 | aprint_naive("\n"); | | 424 | aprint_naive("\n"); |
425 | aprint_normal("\n"); | | 425 | aprint_normal("\n"); |
426 | aprint_normal_dev(self, "%s, SPD Revision %s", type, rambus_rev); | | 426 | aprint_normal_dev(self, "%s, SPD Revision %s", type, rambus_rev); |
427 | dimm_size = 1 << (s->sm_rdr.rdr_rows + s->sm_rdr.rdr_cols - 13); | | 427 | dimm_size = 1 << (s->sm_rdr.rdr_rows + s->sm_rdr.rdr_cols - 13); |
| @@ -605,27 +605,27 @@ decode_sdram(const struct sysctlnode *no | | | @@ -605,27 +605,27 @@ decode_sdram(const struct sysctlnode *no |
605 | cycle_time = s->sm_sdr.sdr_cycle_whole * 1000 + | | 605 | cycle_time = s->sm_sdr.sdr_cycle_whole * 1000 + |
606 | s->sm_sdr.sdr_cycle_tenths * 100; | | 606 | s->sm_sdr.sdr_cycle_tenths * 100; |
607 | bits = le16toh(s->sm_sdr.sdr_datawidth); | | 607 | bits = le16toh(s->sm_sdr.sdr_datawidth); |
608 | if (s->sm_config == 1 || s->sm_config == 2) | | 608 | if (s->sm_config == 1 || s->sm_config == 2) |
609 | bits -= 8; | | 609 | bits -= 8; |
610 | | | 610 | |
611 | /* Calculate speed here - from OpenBSD */ | | 611 | /* Calculate speed here - from OpenBSD */ |
612 | if (spd_len >= 128) | | 612 | if (spd_len >= 128) |
613 | freq = ((uint8_t *)s)[126]; | | 613 | freq = ((uint8_t *)s)[126]; |
614 | else | | 614 | else |
615 | freq = 0; | | 615 | freq = 0; |
616 | switch (freq) { | | 616 | switch (freq) { |
617 | /* | | 617 | /* |
618 | * Must check cycle time since some PC-133 DIMMs | | 618 | * Must check cycle time since some PC-133 DIMMs |
619 | * actually report PC-100 | | 619 | * actually report PC-100 |
620 | */ | | 620 | */ |
621 | case 100: | | 621 | case 100: |
622 | case 133: | | 622 | case 133: |
623 | if (cycle_time < 8000) | | 623 | if (cycle_time < 8000) |
624 | speed = 133; | | 624 | speed = 133; |
625 | else | | 625 | else |
626 | speed = 100; | | 626 | speed = 100; |
627 | break; | | 627 | break; |
628 | case 0x66: /* Legacy DIMMs use _hex_ 66! */ | | 628 | case 0x66: /* Legacy DIMMs use _hex_ 66! */ |
629 | default: | | 629 | default: |
630 | speed = 66; | | 630 | speed = 66; |
631 | } | | 631 | } |
| @@ -746,26 +746,50 @@ decode_ddr2(const struct sysctlnode *nod | | | @@ -746,26 +746,50 @@ decode_ddr2(const struct sysctlnode *nod |
746 | | | 746 | |
747 | decode_voltage_refresh(self, s); | | 747 | decode_voltage_refresh(self, s); |
748 | } | | 748 | } |
749 | | | 749 | |
750 | static void | | 750 | static void |
751 | print_part(const char *part, size_t pnsize) | | 751 | print_part(const char *part, size_t pnsize) |
752 | { | | 752 | { |
753 | const char *p = memchr(part, ' ', pnsize); | | 753 | const char *p = memchr(part, ' ', pnsize); |
754 | if (p == NULL) | | 754 | if (p == NULL) |
755 | p = part + pnsize; | | 755 | p = part + pnsize; |
756 | aprint_normal(": %.*s\n", (int)(p - part), part); | | 756 | aprint_normal(": %.*s\n", (int)(p - part), part); |
757 | } | | 757 | } |
758 | | | 758 | |
| | | 759 | static u_int |
| | | 760 | ddr3_value_pico(struct spdmem *s, uint8_t txx_mtb, uint8_t txx_ftb) |
| | | 761 | { |
| | | 762 | u_int mtb, ftb; /* in picoseconds */ |
| | | 763 | intmax_t signed_txx_ftb; |
| | | 764 | u_int val; |
| | | 765 | |
| | | 766 | mtb = (u_int)s->sm_ddr3.ddr3_mtb_dividend * 1000 / |
| | | 767 | s->sm_ddr3.ddr3_mtb_divisor; |
| | | 768 | ftb = (u_int)s->sm_ddr3.ddr3_ftb_dividend * 1000 / |
| | | 769 | s->sm_ddr3.ddr3_ftb_divisor; |
| | | 770 | |
| | | 771 | /* tXX_ftb is signed value */ |
| | | 772 | signed_txx_ftb = (int8_t)txx_ftb; |
| | | 773 | val = txx_mtb * mtb + |
| | | 774 | ((txx_ftb > 127) ? signed_txx_ftb : txx_ftb) * ftb / 1000; |
| | | 775 | |
| | | 776 | return val; |
| | | 777 | } |
| | | 778 | |
| | | 779 | #define __DDR3_VALUE_PICO(s, field) \ |
| | | 780 | ddr3_value_pico(s, s->sm_ddr3.ddr3_##field##_mtb, \ |
| | | 781 | s->sm_ddr3.ddr3_##field##_ftb) |
| | | 782 | |
759 | static void | | 783 | static void |
760 | decode_ddr3(const struct sysctlnode *node, device_t self, struct spdmem *s) | | 784 | decode_ddr3(const struct sysctlnode *node, device_t self, struct spdmem *s) |
761 | { | | 785 | { |
762 | int dimm_size, cycle_time, bits; | | 786 | int dimm_size, cycle_time, bits; |
763 | | | 787 | |
764 | aprint_naive("\n"); | | 788 | aprint_naive("\n"); |
765 | print_part(s->sm_ddr3.ddr3_part, sizeof(s->sm_ddr3.ddr3_part)); | | 789 | print_part(s->sm_ddr3.ddr3_part, sizeof(s->sm_ddr3.ddr3_part)); |
766 | aprint_normal_dev(self, "%s", spdmem_basic_types[s->sm_type]); | | 790 | aprint_normal_dev(self, "%s", spdmem_basic_types[s->sm_type]); |
767 | | | 791 | |
768 | if (s->sm_ddr3.ddr3_mod_type == | | 792 | if (s->sm_ddr3.ddr3_mod_type == |
769 | SPDMEM_DDR3_TYPE_MINI_RDIMM || | | 793 | SPDMEM_DDR3_TYPE_MINI_RDIMM || |
770 | s->sm_ddr3.ddr3_mod_type == SPDMEM_DDR3_TYPE_RDIMM) | | 794 | s->sm_ddr3.ddr3_mod_type == SPDMEM_DDR3_TYPE_RDIMM) |
771 | aprint_normal(" (registered)"); | | 795 | aprint_normal(" (registered)"); |
| @@ -776,48 +800,49 @@ decode_ddr3(const struct sysctlnode *nod | | | @@ -776,48 +800,49 @@ decode_ddr3(const struct sysctlnode *nod |
776 | /* | | 800 | /* |
777 | * DDR3 size specification is quite different from others | | 801 | * DDR3 size specification is quite different from others |
778 | * | | 802 | * |
779 | * Module capacity is defined as | | 803 | * Module capacity is defined as |
780 | * Chip_Capacity_in_bits / 8bits-per-byte * | | 804 | * Chip_Capacity_in_bits / 8bits-per-byte * |
781 | * external_bus_width / internal_bus_width | | 805 | * external_bus_width / internal_bus_width |
782 | * We further divide by 2**20 to get our answer in MB | | 806 | * We further divide by 2**20 to get our answer in MB |
783 | */ | | 807 | */ |
784 | dimm_size = (s->sm_ddr3.ddr3_chipsize + 28 - 20) - 3 + | | 808 | dimm_size = (s->sm_ddr3.ddr3_chipsize + 28 - 20) - 3 + |
785 | (s->sm_ddr3.ddr3_datawidth + 3) - | | 809 | (s->sm_ddr3.ddr3_datawidth + 3) - |
786 | (s->sm_ddr3.ddr3_chipwidth + 2); | | 810 | (s->sm_ddr3.ddr3_chipwidth + 2); |
787 | dimm_size = (1 << dimm_size) * (s->sm_ddr3.ddr3_physbanks + 1); | | 811 | dimm_size = (1 << dimm_size) * (s->sm_ddr3.ddr3_physbanks + 1); |
788 | | | 812 | |
789 | cycle_time = (1000 * s->sm_ddr3.ddr3_mtb_dividend + | | 813 | cycle_time = __DDR3_VALUE_PICO(s, tCKmin); |
790 | (s->sm_ddr3.ddr3_mtb_divisor / 2)) / | | | |
791 | s->sm_ddr3.ddr3_mtb_divisor; | | | |
792 | cycle_time *= s->sm_ddr3.ddr3_tCKmin; | | | |
793 | bits = 1 << (s->sm_ddr3.ddr3_datawidth + 3); | | 814 | bits = 1 << (s->sm_ddr3.ddr3_datawidth + 3); |
794 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, FALSE, | | 815 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, FALSE, |
795 | "PC3", 0); | | 816 | "PC3", 0); |
796 | | | 817 | |
797 | aprint_verbose_dev(self, | | 818 | aprint_verbose_dev(self, |
798 | "%d rows, %d cols, %d log. banks, %d phys. banks, " | | 819 | "%d rows, %d cols, %d log. banks, %d phys. banks, " |
799 | "%d.%03dns cycle time\n", | | 820 | "%d.%03dns cycle time\n", |
800 | s->sm_ddr3.ddr3_rows + 9, s->sm_ddr3.ddr3_cols + 12, | | 821 | s->sm_ddr3.ddr3_rows + 12, s->sm_ddr3.ddr3_cols + 9, |
801 | 1 << (s->sm_ddr3.ddr3_logbanks + 3), | | 822 | 1 << (s->sm_ddr3.ddr3_logbanks + 3), |
802 | s->sm_ddr3.ddr3_physbanks + 1, | | 823 | s->sm_ddr3.ddr3_physbanks + 1, |
803 | cycle_time/1000, cycle_time % 1000); | | 824 | cycle_time/1000, cycle_time % 1000); |
804 | | | 825 | |
805 | #define __DDR3_CYCLES(field) (s->sm_ddr3.field / s->sm_ddr3.ddr3_tCKmin) | | 826 | #define __DDR3_CYCLES(val) \ |
| | | 827 | ((val / cycle_time) + ((val % cycle_time) ? 1 : 0)) |
806 | | | 828 | |
807 | aprint_verbose_dev(self, LATENCY, __DDR3_CYCLES(ddr3_tAAmin), | | 829 | aprint_verbose_dev(self, LATENCY, |
808 | __DDR3_CYCLES(ddr3_tRCDmin), __DDR3_CYCLES(ddr3_tRPmin), | | 830 | __DDR3_CYCLES(__DDR3_VALUE_PICO(s, tAAmin)), |
809 | (s->sm_ddr3.ddr3_tRAS_msb * 256 + s->sm_ddr3.ddr3_tRAS_lsb) / | | 831 | __DDR3_CYCLES(__DDR3_VALUE_PICO(s, tRCDmin)), |
810 | s->sm_ddr3.ddr3_tCKmin); | | 832 | __DDR3_CYCLES(__DDR3_VALUE_PICO(s, tRPmin)), |
| | | 833 | __DDR3_CYCLES((s->sm_ddr3.ddr3_tRAS_msb * 256 |
| | | 834 | + s->sm_ddr3.ddr3_tRAS_lsb) * s->sm_ddr3.ddr3_mtb_dividend |
| | | 835 | / s->sm_ddr3.ddr3_mtb_divisor * 1000)); |
811 | | | 836 | |
812 | #undef __DDR3_CYCLES | | 837 | #undef __DDR3_CYCLES |
813 | | | 838 | |
814 | /* For DDR3, Voltage is written in another area */ | | 839 | /* For DDR3, Voltage is written in another area */ |
815 | if (!s->sm_ddr3.ddr3_NOT15V || s->sm_ddr3.ddr3_135V | | 840 | if (!s->sm_ddr3.ddr3_NOT15V || s->sm_ddr3.ddr3_135V |
816 | || s->sm_ddr3.ddr3_125V) { | | 841 | || s->sm_ddr3.ddr3_125V) { |
817 | aprint_verbose("%s:", device_xname(self)); | | 842 | aprint_verbose("%s:", device_xname(self)); |
818 | if (!s->sm_ddr3.ddr3_NOT15V) | | 843 | if (!s->sm_ddr3.ddr3_NOT15V) |
819 | aprint_verbose(" 1.5V"); | | 844 | aprint_verbose(" 1.5V"); |
820 | if (s->sm_ddr3.ddr3_135V) | | 845 | if (s->sm_ddr3.ddr3_135V) |
821 | aprint_verbose(" 1.35V"); | | 846 | aprint_verbose(" 1.35V"); |
822 | if (s->sm_ddr3.ddr3_125V) | | 847 | if (s->sm_ddr3.ddr3_125V) |
823 | aprint_verbose(" 1.25V"); | | 848 | aprint_verbose(" 1.25V"); |
| @@ -847,47 +872,47 @@ decode_fbdimm(const struct sysctlnode *n | | | @@ -847,47 +872,47 @@ decode_fbdimm(const struct sysctlnode *n |
847 | bits = 1 << (s->sm_fbd.fbdimm_dev_width + 2); | | 872 | bits = 1 << (s->sm_fbd.fbdimm_dev_width + 2); |
848 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, TRUE, | | 873 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, TRUE, |
849 | "PC2", 0); | | 874 | "PC2", 0); |
850 | | | 875 | |
851 | aprint_verbose_dev(self, | | 876 | aprint_verbose_dev(self, |
852 | "%d rows, %d cols, %d banks, %d.%02dns cycle time\n", | | 877 | "%d rows, %d cols, %d banks, %d.%02dns cycle time\n", |
853 | s->sm_fbd.fbdimm_rows, s->sm_fbd.fbdimm_cols, | | 878 | s->sm_fbd.fbdimm_rows, s->sm_fbd.fbdimm_cols, |
854 | 1 << (s->sm_fbd.fbdimm_banks + 2), | | 879 | 1 << (s->sm_fbd.fbdimm_banks + 2), |
855 | cycle_time / 1000, (cycle_time % 1000 + 5) /10 ); | | 880 | cycle_time / 1000, (cycle_time % 1000 + 5) /10 ); |
856 | | | 881 | |
857 | #define __FBDIMM_CYCLES(field) (s->sm_fbd.field / s->sm_fbd.fbdimm_tCKmin) | | 882 | #define __FBDIMM_CYCLES(field) (s->sm_fbd.field / s->sm_fbd.fbdimm_tCKmin) |
858 | | | 883 | |
859 | aprint_verbose_dev(self, LATENCY, __FBDIMM_CYCLES(fbdimm_tAAmin), | | 884 | aprint_verbose_dev(self, LATENCY, __FBDIMM_CYCLES(fbdimm_tAAmin), |
860 | __FBDIMM_CYCLES(fbdimm_tRCDmin), __FBDIMM_CYCLES(fbdimm_tRPmin), | | 885 | __FBDIMM_CYCLES(fbdimm_tRCDmin), __FBDIMM_CYCLES(fbdimm_tRPmin), |
861 | (s->sm_fbd.fbdimm_tRAS_msb * 256 + s->sm_fbd.fbdimm_tRAS_lsb) / | | 886 | (s->sm_fbd.fbdimm_tRAS_msb * 256 + s->sm_fbd.fbdimm_tRAS_lsb) / |
862 | s->sm_fbd.fbdimm_tCKmin); | | 887 | s->sm_fbd.fbdimm_tCKmin); |
863 | | | 888 | |
864 | #undef __FBDIMM_CYCLES | | 889 | #undef __FBDIMM_CYCLES |
865 | | | 890 | |
866 | decode_voltage_refresh(self, s); | | 891 | decode_voltage_refresh(self, s); |
867 | } | | 892 | } |
868 | | | 893 | |
869 | static void | | 894 | static void |
870 | decode_ddr4(const struct sysctlnode *node, device_t self, struct spdmem *s) | | 895 | decode_ddr4(const struct sysctlnode *node, device_t self, struct spdmem *s) |
871 | { | | 896 | { |
872 | int dimm_size, cycle_time, ranks; | | 897 | int dimm_size, cycle_time, ranks; |
873 | int tAA_clocks, tRCD_clocks,tRP_clocks, tRAS_clocks; | | 898 | int tAA_clocks, tRCD_clocks, tRP_clocks, tRAS_clocks; |
874 | | | 899 | |
875 | aprint_naive("\n"); | | 900 | aprint_naive("\n"); |
876 | print_part(s->sm_ddr4.ddr4_part_number, | | 901 | print_part(s->sm_ddr4.ddr4_part_number, |
877 | sizeof(s->sm_ddr4.ddr4_part_number)); | | 902 | sizeof(s->sm_ddr4.ddr4_part_number)); |
878 | aprint_normal_dev(self, "%s", spdmem_basic_types[s->sm_type]); | | 903 | aprint_normal_dev(self, "%s", spdmem_basic_types[s->sm_type]); |
879 | if (s->sm_ddr4.ddr4_mod_type < __arraycount(spdmem_ddr4_module_types)) | | 904 | if (s->sm_ddr4.ddr4_mod_type < __arraycount(spdmem_ddr4_module_types)) |
880 | aprint_normal(" (%s)", | | 905 | aprint_normal(" (%s)", |
881 | spdmem_ddr4_module_types[s->sm_ddr4.ddr4_mod_type]); | | 906 | spdmem_ddr4_module_types[s->sm_ddr4.ddr4_mod_type]); |
882 | aprint_normal(", %sECC, %stemp-sensor, ", | | 907 | aprint_normal(", %sECC, %stemp-sensor, ", |
883 | (s->sm_ddr4.ddr4_bus_width_extension) ? "" : "no ", | | 908 | (s->sm_ddr4.ddr4_bus_width_extension) ? "" : "no ", |
884 | (s->sm_ddr4.ddr4_has_therm_sensor) ? "" : "no "); | | 909 | (s->sm_ddr4.ddr4_has_therm_sensor) ? "" : "no "); |
885 | | | 910 | |
886 | /* | | 911 | /* |
887 | * DDR4 size calculation from JEDEC spec | | 912 | * DDR4 size calculation from JEDEC spec |
888 | * | | 913 | * |
889 | * Module capacity in bytes is defined as | | 914 | * Module capacity in bytes is defined as |
890 | * Chip_Capacity_in_bits / 8bits-per-byte * | | 915 | * Chip_Capacity_in_bits / 8bits-per-byte * |
891 | * primary_bus_width / DRAM_width * | | 916 | * primary_bus_width / DRAM_width * |
892 | * logical_ranks_per_DIMM | | 917 | * logical_ranks_per_DIMM |
893 | * | | 918 | * |
| @@ -902,57 +927,57 @@ decode_ddr4(const struct sysctlnode *nod | | | @@ -902,57 +927,57 @@ decode_ddr4(const struct sysctlnode *nod |
902 | + (s->sm_ddr4.ddr4_primary_bus_width + 3); /* bus width */ | | 927 | + (s->sm_ddr4.ddr4_primary_bus_width + 3); /* bus width */ |
903 | switch (s->sm_ddr4.ddr4_device_width) { /* DRAM width */ | | 928 | switch (s->sm_ddr4.ddr4_device_width) { /* DRAM width */ |
904 | case 0: dimm_size -= 2; | | 929 | case 0: dimm_size -= 2; |
905 | break; | | 930 | break; |
906 | case 1: dimm_size -= 3; | | 931 | case 1: dimm_size -= 3; |
907 | break; | | 932 | break; |
908 | case 2: dimm_size -= 4; | | 933 | case 2: dimm_size -= 4; |
909 | break; | | 934 | break; |
910 | case 4: dimm_size -= 5; | | 935 | case 4: dimm_size -= 5; |
911 | break; | | 936 | break; |
912 | default: | | 937 | default: |
913 | dimm_size = -1; /* flag invalid value */ | | 938 | dimm_size = -1; /* flag invalid value */ |
914 | } | | 939 | } |
915 | if (dimm_size >= 0) { | | 940 | if (dimm_size >= 0) { |
916 | dimm_size = (1 << dimm_size) * | | 941 | dimm_size = (1 << dimm_size) * |
917 | (s->sm_ddr4.ddr4_package_ranks + 1); /* log.ranks/DIMM */ | | 942 | (s->sm_ddr4.ddr4_package_ranks + 1); /* log.ranks/DIMM */ |
918 | if (s->sm_ddr4.ddr4_signal_loading == 2) { | | 943 | if (s->sm_ddr4.ddr4_signal_loading == 2) { |
919 | dimm_size *= (s->sm_ddr4.ddr4_diecount + 1); | | 944 | dimm_size *= (s->sm_ddr4.ddr4_diecount + 1); |
920 | } | | 945 | } |
921 | } | | 946 | } |
922 | | | 947 | |
923 | /* | | 948 | /* |
924 | * Note that the ddr4_xxx_ftb fields are actually signed offsets from | | 949 | * Note that the ddr4_xxx_ftb fields are actually signed offsets from |
925 | * the corresponding mtb value, so we might have to subtract 256! | | 950 | * the corresponding mtb value, so we might have to subtract 256! |
926 | */ | | 951 | */ |
927 | #define __DDR4_VALUE(field) ((s->sm_ddr4.ddr4_##field##_mtb * 125 + \ | | 952 | #define __DDR4_VALUE(field) ((s->sm_ddr4.ddr4_##field##_mtb * 125 + \ |
928 | s->sm_ddr4.ddr4_##field##_ftb) - \ | | 953 | s->sm_ddr4.ddr4_##field##_ftb) - \ |
929 | ((s->sm_ddr4.ddr4_##field##_ftb > 127)?256:0)) | | 954 | ((s->sm_ddr4.ddr4_##field##_ftb > 127)?256:0)) |
930 | /* | | 955 | /* |
931 | * For now, the only value for mtb is 0 = 125ps, and ftb = 1ps | | 956 | * For now, the only value for mtb is 0 = 125ps, and ftb = 1ps |
932 | * so we don't need to figure out the time-base units - just | | 957 | * so we don't need to figure out the time-base units - just |
933 | * hard-code them for now. | | 958 | * hard-code them for now. |
934 | */ | | 959 | */ |
935 | cycle_time = __DDR4_VALUE(tCKAVGmin); | | 960 | cycle_time = __DDR4_VALUE(tCKAVGmin); |
936 | decode_size_speed(self, node, dimm_size, cycle_time, 2, | | 961 | decode_size_speed(self, node, dimm_size, cycle_time, 2, |
937 | 1 << (s->sm_ddr4.ddr4_primary_bus_width + 3), | | 962 | 1 << (s->sm_ddr4.ddr4_primary_bus_width + 3), |
938 | TRUE, "PC4", 0); | | 963 | TRUE, "PC4", 0); |
939 | | | 964 | |
940 | ranks = s->sm_ddr4.ddr4_package_ranks + 1; | | 965 | ranks = s->sm_ddr4.ddr4_package_ranks + 1; |
941 | aprint_verbose_dev(self, | | 966 | aprint_verbose_dev(self, |
942 | "%d rows, %d cols, %d ranks%s, %d banks/group, %d bank groups\n", | | 967 | "%d rows, %d cols, %d ranks%s, %d banks/group, %d bank groups\n", |
943 | s->sm_ddr4.ddr4_rows + 12, s->sm_ddr4.ddr4_cols + 9, | | 968 | s->sm_ddr4.ddr4_rows + 12, s->sm_ddr4.ddr4_cols + 9, |
944 | ranks, (ranks > 1) ? ((s->sm_ddr4.ddr4_rank_mix == 1) | | 969 | ranks, (ranks > 1) ? ((s->sm_ddr4.ddr4_rank_mix == 1) |
945 | ? " (asymmetric)" : " (symmetiric)") : "", | | 970 | ? " (asymmetric)" : " (symmetric)") : "", |
946 | 1 << (2 + s->sm_ddr4.ddr4_logbanks), | | 971 | 1 << (2 + s->sm_ddr4.ddr4_logbanks), |
947 | 1 << s->sm_ddr4.ddr4_bankgroups); | | 972 | 1 << s->sm_ddr4.ddr4_bankgroups); |
948 | | | 973 | |
949 | aprint_verbose_dev(self, "%d.%03dns cycle time\n", | | 974 | aprint_verbose_dev(self, "%d.%03dns cycle time\n", |
950 | cycle_time / 1000, cycle_time % 1000); | | 975 | cycle_time / 1000, cycle_time % 1000); |
951 | | | 976 | |
952 | tAA_clocks = __DDR4_VALUE(tAAmin) * 1000 / cycle_time; | | 977 | tAA_clocks = __DDR4_VALUE(tAAmin) * 1000 / cycle_time; |
953 | tRCD_clocks = __DDR4_VALUE(tRCDmin) * 1000 / cycle_time; | | 978 | tRCD_clocks = __DDR4_VALUE(tRCDmin) * 1000 / cycle_time; |
954 | tRP_clocks = __DDR4_VALUE(tRPmin) * 1000 / cycle_time; | | 979 | tRP_clocks = __DDR4_VALUE(tRPmin) * 1000 / cycle_time; |
955 | tRAS_clocks = (s->sm_ddr4.ddr4_tRASmin_msb * 256 + | | 980 | tRAS_clocks = (s->sm_ddr4.ddr4_tRASmin_msb * 256 + |
956 | s->sm_ddr4.ddr4_tRASmin_lsb) * 125 * 1000 / cycle_time; | | 981 | s->sm_ddr4.ddr4_tRASmin_lsb) * 125 * 1000 / cycle_time; |
957 | | | 982 | |
958 | /* | | 983 | /* |