[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 1/1] dmioem: Decode HPE OEM Record 197
From: |
Jerry Hoemann |
Subject: |
Re: [PATCH 1/1] dmioem: Decode HPE OEM Record 197 |
Date: |
Thu, 27 Apr 2023 16:40:48 -0600 |
User-agent: |
Mutt/1.10.1 (2018-07-13) |
On Thu, Apr 27, 2023 at 04:03:21PM +0200, Jean Delvare wrote:
> Hi Jerry,
>
> On Thu, 20 Apr 2023 11:34:11 -0600, Jerry Hoemann wrote:
> > Decode HPE OEM Record 197: Processor Information
> >
> > Signed-off-by: Jerry Hoemann <jerry.hoemann@hpe.com>
> > ---
> > dmioem.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 68 insertions(+)
> >
> > diff --git a/dmioem.c b/dmioem.c
> > index 1ce26b9..636831d 100644
> > --- a/dmioem.c
> > +++ b/dmioem.c
> > @@ -789,6 +789,74 @@ static int dmi_decode_hp(const struct dmi_header *h)
> > pr_attr("Virtual Serial Port", "%s", feat & (1 << 4) ?
> > "Enabled" : "Disabled");
> > break;
> >
> > + case 197:
> > + /*
> > + * Vendor Specific: HPE Processor Specific Information
> > + *
> > + * Processor Information structure (Type 197) for each
> > possibly installed
> > + * physical processor to go along with each standard
> > Processor Info
> > + * Record (Type 4). The Type 197 record will be
> > ignored for Processor
> > + * slots that are empty (specified in the Type 4
> > records).
> > + *
> > + * Processor Wattage value will be filled in with
> > information gotten from
> > + * the CPUID instruction or possibly estimated based on
> > CPU Family/Type.
> > + *
> > + * Designator bytes will be 0FFh if the location of the
> > processor does not
> > + * use it. If a system has processor slots, but no
> > sockets, then the value
> > + * in the Socket Designator will be 0FFh. A system
> > would have one or the
> > + * other, or both.
> > + *
> > + * Offset | Name | Width | Description
> > + * -------+------------+-------+-------------
> > + * 0x00 | Type | BYTE | 0xC5, Processor
> > location information
>
> This record contains a lot more than "location" information.
from doc. will change.
>
> > + * 0x01 | Length | BYTE | Length of structure
> > + * 0x02 | Handle | WORD | Unique handle
> > + * 0x04 | Assoc Dev | WORD | Handle of Associated
> > Type 4 Record
> > + * 0x06 | APIC ID | BYTE | Processor local APIC
> > ID.
>
> No trailing dot, for consistency.
done.
>
> > + * 0x07 | OEM Status | BYTE | Bits: 0: BSP, 1:
> > x2APIC, 2: Therm Margining
> > + * 0x08 | Phys Slot | BYTE | Matches silk screen.
> > FF -> not used
> > + * 0x09 | Phys Socket| BYTE | Matches silk screen.
> > FF -> not used
>
> "FF -> not used" can be omitted, this special case is already explained
> above and clearly visible in the code itself.
done
>
> > + * 0x0A | Max Wattage| WORD | Rated max wattage of
> > the processor if !0
>
> "if !0" can be omitted as well, it's an implementation detail.
done
>
> > + * 0x0C | x2APIC ID | DWORD | Processor x2APIC (if
> > OEM Status -> x2APIC)
> > + * 0x10 | Proc UUID | QWORD | Processor Unique
> > Identifier
> > + * 0x18 | Conn Speed | WORD | Interconnect speed in
> > MT/s if !0
>
> Ditto.
done
>
> > + * 0x1A | QDF/S-SPEC |6-BYTES| Processor QDF/S-SPEC
> > Numbers (Intel only)
>
> 6 BYTES (no dash).
done
>
> > + * 0x20 | Reserved | QWORD | Gen11 Reserved
> > + */
> > + pr_handle_name("%s Processor Specific Information",
> > company);
> > + if (h->length < 0x0A) break;
> > + if (!(opt.flags & FLAG_QUIET))
> > + pr_attr("Associated Handle", "0x%04X",
> > WORD(data + 0x04));
> > + pr_attr("APIC ID", "0x%02x", data[0x06]);
>
> The kernel exposes "apicid" as a decimal number in /proc/cpuinfo, so
> maybe we should do the same for consistency?
changed to %u.
>
> > + feat = data[0x07];
> > + pr_attr("OEM Status", "0x%02x", feat);
> > + pr_subattr("BSP", "%s", feat & 0x01 ? "Yes" : "No");
> > + pr_subattr("x2APIC", "%s", feat & 0x02 ? "Yes" : "No");
> > + pr_subattr("Advanced Thermal Margining", "%s", feat &
> > 0x04 ? "Yes" : "No");
>
> The raw feat value isn't particularly valuable, as everything is
> printed in a more human-friendly way afterward. The fact that all 3
> values are held in the same byte is an implementation detail, the
> meaning of these bits is unrelated. So I suggest simplifying the
> display by removing the "OEM Status" line and using pr_attr for the
> flags themselves.
done.
>
> > + if (data[0x08] != 0xFF)
> > + pr_attr("Physical Slot", "%d", data[0x08]);
> > + if (data[0x09] != 0xFF)
> > + pr_attr("Physical Socket", "%d", data[0x09]);
> > + if (h->length < 0x0C) break;
> > + if (data[0x0A])
> > + pr_attr("Maximum Power", "%d Watts",
> > data[0x0A]);
>
> Your documentation indicates this field is a WORD, not a BYTE.
fixed.
>
> > + if (h->length < 0x10) break;
> > + if (feat & 0x02)
> > + pr_attr("x2APIC ID", "0x%08x", DWORD(data +
> > 0x0C));
> > + if (h->length < 0x18) break;
> > + if (DWORD(data + 0x10) || DWORD(data + 0x14))
> > + pr_attr("UUID", "0x%08x", QWORD(data + 0x10));
>
> The format length doesn't match the parameter. QWORD is 8 bytes, so 16
> nibbles must be displayed. Also I'm not entirely sure it is safe to
> pass a QWORD to printf directly, after all it is implemented as a
> struct. It would be more portable to do something like:
>
> pr_attr("UUID", "0x%08x%08x", DWORD(data +
> 0x14), DWORD(data + 0x10));
fixed.
>
> as done in functions dmi_64bit_memory_error_address() and
> dmi_ipmi_base_address() for example.
>
> > + if (h->length < 0x1A) break;
> > + if (WORD(data + 0x18))
> > + pr_attr("Interconnect Speed", "%d MT/s",
> > WORD(data + 0x18));
> > + if (h->length < 0x20) break;
> > + if (WORD(data + 0x1A) && WORD(data + 0x1C) && WORD(data
> > + 0x1E))
>
> This test looks odd. If you want to ensure that at least one byte is
> non-zero, you should use || instead of &&. If you want to ensure that
> all bytes are set, then you can't test with WORD(), you need to test
> each byte individually.
>
> But do you actually need to test all bytes? As far as I can see, what
> we have here is either all zeroes or a 6-char string. If data[0x1F] is
> not 0 then the string is set?
>
> > + pr_attr("QDF/S-SPEC", "%c%c%c%c%c%c",
> > data[0x1A], data[0x1B],
> > + data[0x1C], data[0x1D], data[0x1E],
> > data[0x1F]);
>
> This needs some care. The code assumes all bytes are printable ASCII
> characters. You should call helper function is_printable() to ensure
> this is actually the case.
>
> Also, as far as I can see from my samples, the string is padded with
> spaces on the left hand side (1 for production samples, 2 for
> engineering samples). These spaces do not look good in the output, so
> it would be better to not include them.
>
> I think I would introduce a 7-char buffer to store an actual
> NUL-terminated string value generated from the 6 bytes in this field.
> Before adding a character to the string, I would ensure it is valid
> (ASCII printable), and skip it if it is a space. Then I would pass the
> string to pr_attr/printf, using "%s" as the format. What do you think?
I added a helper function to address the above concerns.
>
> > + if (h->length < 0x24) break;
> > + pr_attr("Reserved", "0x%08x", QWORD(data + 0x20));
>
> Same issue as above about non-matching length and passing a struct to
> printf(). Additionally, I can't see the point of printing a value when
> nobody knows what it represents. So I'd rather just ignore it for the
> time being, and decode that field later if/when we finally know what it
> is and how to decode it.
This should have been a DWORD, not a QWORD. I'll remove.
>
> > + break;
> > +
> > case 199:
> > /*
> > * Vendor Specific: CPU Microcode Patch
>
> Thanks,
> --
> Jean Delvare
> SUSE L3 Support
--
-----------------------------------------------------------------------------
Jerry Hoemann Software Engineer Hewlett Packard Enterprise
-----------------------------------------------------------------------------