* [PATCH] tpm: add support for partial reads
From: Jason Gunthorpe @ 2018-07-23 21:48 UTC (permalink / raw)
To: linux-security-module
In-Reply-To: <153201555276.20155.1352499992826895966.stgit@tstruk-mobl1.jf.intel.com>
On Thu, Jul 19, 2018 at 08:52:32AM -0700, Tadeusz Struk wrote:
> Currently to read a response from the TPM device an application needs
> provide "big enough" buffer for the whole response and read it in one go.
> The application doesn't know how big the response it beforehand so it
> always needs to maintain a 4K buffer and read the max (4K).
> In case if the user of the TSS library doesn't provide big enough buffer
> the TCTI spec says that the library should set the required size and return
> TSS2_TCTI_RC_INSUFFICIENT_BUFFER error code so that the application could
> allocate a bigger buffer and call receive again.
> To make it possible in the TSS library this requires being able to do
> partial reads from the driver.
> The library would read the header first to get the actual size of the
> response from the header and then read the rest of the response.
> This patch adds support for partial reads.
You should solve this in user space, the kernel API requires a full
sized buffer here, the tss library should always provide such an
internal buffer and then implement whatever scheme TSS wants by
memcpying from that buffer..
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] drm/dp: add extended receiver capability field present bit
From: Patchwork @ 2018-07-23 21:48 UTC (permalink / raw)
To: matthew.s.atwood; +Cc: intel-gfx
In-Reply-To: <20180723212735.23893-1-matthew.s.atwood@intel.com>
== Series Details ==
Series: series starting with [1/2] drm/dp: add extended receiver capability field present bit
URL : https://patchwork.freedesktop.org/series/47087/
State : warning
== Summary ==
$ dim checkpatch origin/drm-tip
6492b69821b5 drm/dp: add extended receiver capability field present bit
23a1b7942026 drm/i915: implement EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT
-:93: CHECK:LINE_SPACING: Please don't use multiple blank lines
#93: FILE: drivers/gpu/drm/i915/intel_dp.c:3748:
+
+
total: 0 errors, 0 warnings, 1 checks, 66 lines checked
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH v7 00/12] PECI device driver introduction
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David S . Miller,
Mauro Carvalho Chehab, Andrew Morton, Randy Dunlap,
Philippe Ombredanne, Vinod Koul, Stephen Boyd, David Kershner,
Uwe Kleine-Konig, Sagar Dharia, Johan Hovold, Thomas Gleixner,
Juergen Gross, Cyrille Pitchen
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo
Introduction of the Platform Environment Control Interface (PECI) bus
device driver. PECI is a one-wire bus interface that provides a
communication channel from Intel processors and chipset components to
external monitoring or control devices. PECI is designed to support the
following sideband functions:
* Processor and DRAM thermal management
- Processor fan speed control is managed by comparing Digital Thermal
Sensor (DTS) thermal readings acquired via PECI against the
processor-specific fan speed control reference point, or TCONTROL. Both
TCONTROL and DTS thermal readings are accessible via the processor PECI
client. These variables are referenced to a common temperature, the TCC
activation point, and are both defined as negative offsets from that
reference.
- PECI based access to the processor package configuration space provides
a means for Baseboard Management Controllers (BMC) or other platform
management devices to actively manage the processor and memory power
and thermal features.
* Platform Manageability
- Platform manageability functions including thermal, power, and error
monitoring. Note that platform 'power' management includes monitoring
and control for both the processor and DRAM subsystem to assist with
data center power limiting.
- PECI allows read access to certain error registers in the processor MSR
space and status monitoring registers in the PCI configuration space
within the processor and downstream devices.
- PECI permits writes to certain registers in the processor PCI
configuration space.
* Processor Interface Tuning and Diagnostics
- Processor interface tuning and diagnostics capabilities
(Intel Interconnect BIST). The processors Intel Interconnect Built In
Self Test (Intel IBIST) allows for infield diagnostic capabilities in
the Intel UPI and memory controller interfaces. PECI provides a port to
execute these diagnostics via its PCI Configuration read and write
capabilities.
* Failure Analysis
- Output the state of the processor after a failure for analysis via
Crashdump.
PECI uses a single wire for self-clocking and data transfer. The bus
requires no additional control lines. The physical layer is a self-clocked
one-wire bus that begins each bit with a driven, rising edge from an idle
level near zero volts. The duration of the signal driven high depends on
whether the bit value is a logic '0' or logic '1'. PECI also includes
variable data transfer rate established with every message. In this way, it
is highly flexible even though underlying logic is simple.
The interface design was optimized for interfacing between an Intel
processor and chipset components in both single processor and multiple
processor environments. The single wire interface provides low board
routing overhead for the multiple load connections in the congested routing
area near the processor and chipset components. Bus speed, error checking,
and low protocol overhead provides adequate link bandwidth and reliability
to transfer critical device operating conditions and configuration
information.
This implementation provides the basic framework to add PECI extensions to
the Linux bus and device models. A hardware specific 'Adapter' driver can
be attached to the PECI bus to provide sideband functions described above.
It is also possible to access all devices on an adapter from userspace
through the /dev interface. A device specific 'Client' driver also can be
attached to the PECI bus so each processor client's features can be
supported by the 'Client' driver through an adapter connection in the bus.
This patch set includes Aspeed 24xx/25xx PECI driver and PECI
cputemp/dimmtemp drivers as the first implementation for both adapter and
client drivers on the PECI bus framework.
Please review.
Thanks,
-Jae
Changes since v6:
* Dropped off unnecessary examples from dt-bindings document.
* Fixed a bug in DIMM index mask building logic.
* Modified DIMM temp label strings to match with the way in BIOS.
* Changed PECI ioctl base number from B6 to B7 to avoid conflict with
fpga-dfl.
* Seperated the PECI section in MAINTAINERS into two parts - PECI subsystem
and ASPEED PECI driver.
Changes since v5:
* Added more detailed descriptions for PECI client MFD documents.
* Changed PECI client MFD souce file names.
* Fixed DT example of PECI client MFD.
* Removed unnecessary debug printings.
* Moved the asm/intel-family.h inclusion place.
Changes since v4:
* Fixed an incorrect endianness handling in peci-aspeed.
* Added a comment to explain about the asm/intel-family.h inclusion.
* Added an MFD module to support multi-function PECI client devices.
Changes since v3:
* Made code more simple and compact.
* Removed unused header file inclusion.
* Fixed incorrect error return values and messages.
* Removed DTS margin temperature from the peci-cputemp.
* Made some magic numbers use defines.
* Moved peci_get_cpu_id() into peci-core as a common function.
* Replaced the cancel_delayed_work() call with a cancel_delayed_work_sync().
* Replaced AST and Aspeed uses with ASPEED.
* Simplified peci command timeout checking logic using
regmap_read_poll_timeout().
* Simplified endian swap codes using endian handling macros.
* Dropped regmap read/write error checking except for the first access.
* Added a PECI reset setting in the device tree node.
* Removed unnecessary sleep from the probe context.
* Removed IRQF_SHARED flag from irq request code in the ASPEED PECI driver.
* Fixed typos in documents.
* Combined peci-bus.txt, peci-adapter.txt and peci-client.txt into peci.txt.
* Fixed and swept documents to drop some incorrect or unnecessary
descriptions.
* Fixed device tree to make unit-address format use reg contents.
* Simplified bit manipulations using <linux/bitfield.h>.
* Made client CPU model checking use <asm/intel-family.h> if available.
* Modified adapter heap allocation method to use kobject reference count
based.
* Added the low-level PECI xfer IOCTL again to support the Redfish
requirement.
* Added PM domain attach/detach code.
* Added logic for device instantiation through sysfs.
* Fix a bug of interrupt status checking code in peci-aspeed driver.
Changes since v2:
* Divided peci-hwmon driver into two drivers, peci-cputemp and
peci-dimmtemp.
* Added generic dt binding documents for PECI bus, adapter and client.
* Removed in_atomic() call from the PECI core driver.
* Improved PECI commands masking logic.
* Added permission check logic for PECI ioctls.
* Removed unnecessary type casts.
* Fixed some invalid error return codes.
* Added the mark_updated() function to improve update interval checking
logic.
* Fixed a bug in populated DIMM checking function.
* Fixed some typo, grammar and style issues in documents.
* Rewrote hwmon drivers to use devm_hwmon_device_register_with_info API.
* Made peci_match_id() function as a static.
* Replaced a deprecated create_singlethread_workqueue() call with an
alloc_ordered_workqueue() call.
* Reordered local variable definitions in reversed xmas tree notation.
* Listed up client CPUs that can be supported by peci-cputemp and
peci-dimmtemp hwmon drivers.
* Added CPU generation detection logic which checks CPUID signature through
PECI connection.
* Improved interrupt handling logic in the Aspeed PECI adapter driver.
* Fixed SPDX license identifier style in header files.
* Changed some macros in peci.h to static inline functions.
* Dropped sleepable context checking code in peci-core.
* Adjusted rt_mutex protection scope in peci-core.
* Moved adapter->xfer() checking code into peci_register_adapter().
* Improved PECI command retry checking logic.
* Changed ioctl base from 'P' to 0xb6 to avoid confiliction and updated
ioctl-number.txt to reflect the ioctl number of PECI subsystem.
* Added a comment to describe PECI retry action.
* Simplified return code handling of peci_ioctl_ping().
* Changed type of peci_ioctl_fn[] to static const.
* Fixed range checking code for valid PECI commands.
* Fixed the error return code on invalid PECI commands.
* Fixed incorrect definitions of PECI ioctl and its handling logic.
Changes since v1:
* Additionally implemented a core driver to support PECI linux bus driver
model.
* Modified Aspeed PECI driver to make that to be an adapter driver in PECI
bus.
* Modified PECI hwmon driver to make that to be a client driver in PECI
bus.
* Simplified hwmon driver attribute labels and removed redundant strings.
* Removed core_nums from device tree setting of hwmon driver and modified
core number detection logic to check the resolved_core register in client
CPU's local PCI configuration area.
* Removed dimm_nums from device tree setting of hwmon driver and added
populated DIMM detection logic to support dynamic creation.
* Removed indexing gap on core temperature and DIMM temperature attributes.
* Improved hwmon registration and dynamic attribute creation logic.
* Fixed structure definitions in PECI uapi header to make that use __u8,
__u16 and etc.
* Modified wait_for_completion_interruptible_timeout error handling logic
in Aspeed PECI driver to deliver errors correctly.
* Removed low-level xfer command from ioctl and kept only high-level PECI
command suite as ioctls.
* Fixed I/O timeout logic in Aspeed PECI driver using ktime.
* Added a function into hwmon driver to simplify update delay checking.
* Added a function into hwmon driver to convert 10.6 to millidegree.
* Dropped non-standard attributes in hwmon driver.
* Fixed OF table for hwmon to make it indicate as a PECI client of Intel
CPU target.
* Added a maintainer of PECI subsystem into MAINTAINERS document.
Jae Hyun Yoo (13):
dt-bindings: Add a document of PECI subsystem
Documentation: ioctl: Add ioctl numbers for PECI subsystem
peci: Add support for PECI bus driver core
dt-bindings: Add a document of PECI adapter driver for ASPEED
AST24xx/25xx SoCs
ARM: dts: aspeed: peci: Add PECI node
peci: Add a PECI adapter driver for Aspeed AST24xx/AST25xx
dt-bindings: mfd: Add a document for PECI client MFD
mfd: intel-peci-client: Add PECI client MFD driver
Documentation: hwmon: Add documents for PECI hwmon client drivers
hwmon: Add PECI cputemp driver
hwmon: Add PECI dimmtemp driver
Add maintainers for the PECI subsystem
.../bindings/mfd/intel-peci-client.txt | 34 +
.../devicetree/bindings/peci/peci-aspeed.txt | 55 +
.../devicetree/bindings/peci/peci.txt | 43 +
Documentation/hwmon/peci-cputemp | 78 +
Documentation/hwmon/peci-dimmtemp | 50 +
Documentation/ioctl/ioctl-number.txt | 2 +
MAINTAINERS | 21 +
arch/arm/boot/dts/aspeed-g4.dtsi | 26 +
arch/arm/boot/dts/aspeed-g5.dtsi | 26 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/hwmon/Kconfig | 28 +
drivers/hwmon/Makefile | 2 +
drivers/hwmon/peci-cputemp.c | 401 +++++
drivers/hwmon/peci-dimmtemp.c | 295 ++++
drivers/mfd/Kconfig | 14 +
drivers/mfd/Makefile | 1 +
drivers/mfd/intel-peci-client.c | 182 +++
drivers/peci/Kconfig | 39 +
drivers/peci/Makefile | 9 +
drivers/peci/peci-aspeed.c | 498 ++++++
drivers/peci/peci-core.c | 1438 +++++++++++++++++
include/linux/mfd/intel-peci-client.h | 81 +
include/linux/peci.h | 104 ++
include/uapi/linux/peci-ioctl.h | 265 +++
25 files changed, 3695 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/intel-peci-client.txt
create mode 100644 Documentation/devicetree/bindings/peci/peci-aspeed.txt
create mode 100644 Documentation/devicetree/bindings/peci/peci.txt
create mode 100644 Documentation/hwmon/peci-cputemp
create mode 100644 Documentation/hwmon/peci-dimmtemp
create mode 100644 drivers/hwmon/peci-cputemp.c
create mode 100644 drivers/hwmon/peci-dimmtemp.c
create mode 100644 drivers/mfd/intel-peci-client.c
create mode 100644 drivers/peci/Kconfig
create mode 100644 drivers/peci/Makefile
create mode 100644 drivers/peci/peci-aspeed.c
create mode 100644 drivers/peci/peci-core.c
create mode 100644 include/linux/mfd/intel-peci-client.h
create mode 100644 include/linux/peci.h
create mode 100644 include/uapi/linux/peci-ioctl.h
--
2.18.0
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] Drivers: Xen: xlate_mmu.c: Fixed comment layout
From: Mark Railton @ 2018-07-23 21:48 UTC (permalink / raw)
To: Randy Dunlap; +Cc: jgross, xen-devel, boris.ostrovsky, linux-kernel
In-Reply-To: <01b221f3-d923-1abb-0168-bfeba80b9a9a@infradead.org>
On Mon, Jul 23, 2018 at 02:44:28PM -0700, Randy Dunlap wrote:
> On 07/23/2018 02:40 PM, Mark Railton wrote:
> > On Mon, Jul 23, 2018 at 02:38:20PM -0700, Randy Dunlap wrote:
> >> On 07/23/2018 02:34 PM, Mark Railton wrote:
> >>> Fixed issue with multi line comment
> >>
> >> Fix [not Fixed]
> >>
> >>>
> >>> Signed-off-by: Mark Railton <mark@markrailton.com>
> >>> ---
> >>> drivers/xen/xlate_mmu.c | 5 +++--
> >>> 1 file changed, 3 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c
> >>> index 23f1387b3ef7..3b03bc1641ed 100644
> >>> --- a/drivers/xen/xlate_mmu.c
> >>> +++ b/drivers/xen/xlate_mmu.c
> >>> @@ -151,8 +151,9 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
> >>> struct remap_data data;
> >>> unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
> >>>
> >>> - /* Kept here for the purpose of making sure code doesn't break
> >>> - x86 PVOPS */
> >>> + /* Kept here for the purpose of making sure code doesn't
> >>> + * break x86 PVOPS
> >>> + */
> >>
> >> That is still not the preferred kernel multi-line comment style.
> >> Documentation/process/coding-style.rst says:
> >>
> >> /*
> >> * This is the preferred style for multi-line
> >> * comments in the Linux kernel source code.
> >> * Please use it consistently.
> >> *
> >> * Description: A column of asterisks on the left side,
> >> * with beginning and ending almost-blank lines.
> >> */
> >>
> >> although Networking code has a slightly different preferred style (as in
> >> your patch).
> >>
> >>> BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
> >>>
> >>> data.fgfn = gfn;
> >>>
> >>
> >>
> >> --
> >> ~Randy
> >
> > Thank's for the feedback, I'll get that updated now.
> >
> > I'm still kinda new to this, I assume I need to send the new patch via
> > git send-email?
>
> That is one option. Use whatever works for you.
>
> There are several email clients that also work well.
> See Documentation/process/email-clients.rst.
>
>
> --
> ~Randy
From 57c8104d2a30020005be16df2ca69ed66f6c4ae9 Mon Sep 17 00:00:00 2001
From: Mark Railton <mark@markrailton.com>
Date: Mon, 23 Jul 2018 22:28:53 +0100
Subject: [PATCH] Drivers: Xen: xlate_mmu.c: Fixed comment layout
Fixed issue with multi line comment
Signed-off-by: Mark Railton <mark@markrailton.com>
---
drivers/xen/xlate_mmu.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c
index 23f1387b3ef7..2b77c79f8ce7 100644
--- a/drivers/xen/xlate_mmu.c
+++ b/drivers/xen/xlate_mmu.c
@@ -151,8 +151,10 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
struct remap_data data;
unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
- /* Kept here for the purpose of making sure code doesn't break
- x86 PVOPS */
+ /*
+ * Kept here for the purpose of making sure code doesn't
+ * break x86 PVOPS
+ */
BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
data.fgfn = gfn;
--
2.17.1
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel
^ permalink raw reply related
* Re: [PATCH] Drivers: Xen: xlate_mmu.c: Fixed comment layout
From: Mark Railton @ 2018-07-23 21:48 UTC (permalink / raw)
To: Randy Dunlap; +Cc: boris.ostrovsky, jgross, xen-devel, linux-kernel
In-Reply-To: <01b221f3-d923-1abb-0168-bfeba80b9a9a@infradead.org>
On Mon, Jul 23, 2018 at 02:44:28PM -0700, Randy Dunlap wrote:
> On 07/23/2018 02:40 PM, Mark Railton wrote:
> > On Mon, Jul 23, 2018 at 02:38:20PM -0700, Randy Dunlap wrote:
> >> On 07/23/2018 02:34 PM, Mark Railton wrote:
> >>> Fixed issue with multi line comment
> >>
> >> Fix [not Fixed]
> >>
> >>>
> >>> Signed-off-by: Mark Railton <mark@markrailton.com>
> >>> ---
> >>> drivers/xen/xlate_mmu.c | 5 +++--
> >>> 1 file changed, 3 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c
> >>> index 23f1387b3ef7..3b03bc1641ed 100644
> >>> --- a/drivers/xen/xlate_mmu.c
> >>> +++ b/drivers/xen/xlate_mmu.c
> >>> @@ -151,8 +151,9 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
> >>> struct remap_data data;
> >>> unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
> >>>
> >>> - /* Kept here for the purpose of making sure code doesn't break
> >>> - x86 PVOPS */
> >>> + /* Kept here for the purpose of making sure code doesn't
> >>> + * break x86 PVOPS
> >>> + */
> >>
> >> That is still not the preferred kernel multi-line comment style.
> >> Documentation/process/coding-style.rst says:
> >>
> >> /*
> >> * This is the preferred style for multi-line
> >> * comments in the Linux kernel source code.
> >> * Please use it consistently.
> >> *
> >> * Description: A column of asterisks on the left side,
> >> * with beginning and ending almost-blank lines.
> >> */
> >>
> >> although Networking code has a slightly different preferred style (as in
> >> your patch).
> >>
> >>> BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
> >>>
> >>> data.fgfn = gfn;
> >>>
> >>
> >>
> >> --
> >> ~Randy
> >
> > Thank's for the feedback, I'll get that updated now.
> >
> > I'm still kinda new to this, I assume I need to send the new patch via
> > git send-email?
>
> That is one option. Use whatever works for you.
>
> There are several email clients that also work well.
> See Documentation/process/email-clients.rst.
>
>
> --
> ~Randy
From 57c8104d2a30020005be16df2ca69ed66f6c4ae9 Mon Sep 17 00:00:00 2001
From: Mark Railton <mark@markrailton.com>
Date: Mon, 23 Jul 2018 22:28:53 +0100
Subject: [PATCH] Drivers: Xen: xlate_mmu.c: Fixed comment layout
Fixed issue with multi line comment
Signed-off-by: Mark Railton <mark@markrailton.com>
---
drivers/xen/xlate_mmu.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c
index 23f1387b3ef7..2b77c79f8ce7 100644
--- a/drivers/xen/xlate_mmu.c
+++ b/drivers/xen/xlate_mmu.c
@@ -151,8 +151,10 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
struct remap_data data;
unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
- /* Kept here for the purpose of making sure code doesn't break
- x86 PVOPS */
+ /*
+ * Kept here for the purpose of making sure code doesn't
+ * break x86 PVOPS
+ */
BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
data.fgfn = gfn;
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v2 04/15] xfs: make deferred processing safe for embedded dfops
From: Bill O'Donnell @ 2018-07-23 20:45 UTC (permalink / raw)
To: Brian Foster; +Cc: linux-xfs
In-Reply-To: <20180723130414.47980-5-bfoster@redhat.com>
On Mon, Jul 23, 2018 at 09:04:03AM -0400, Brian Foster wrote:
> xfs_defer_finish() has a couple quirks that are not safe with
> respect to the upcoming internal dfops functionality. First,
> xfs_defer_finish() attaches the passed in dfops structure to
> ->t_dfops and caches and restores the original value. Second, it
> continues to use the initial dfops reference before and after the
> transaction roll.
>
> These behaviors assume that dop is an independent memory allocation
> from the transaction itself, which may not always be true once
> transactions begin to use an embedded dfops structure. In the latter
> model, dfops processing creates a new xfs_defer_ops structure with
> each transaction and the associated state is migrated across to the
> new transaction.
>
> Fix up xfs_defer_finish() to handle the possibility of the current
> dfops changing after a transaction roll. Since ->t_dfops is used
> unconditionally in this path, it is no longer necessary to
> attach/restore ->t_dfops and pass it explicitly down to
> xfs_defer_trans_roll(). Update dop in the latter function and the
> caller to ensure that it always refers to the current dfops
> structure.
>
> Signed-off-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
Looks good.
Reviewed-by: Bill O'Donnell <billodo@redhat.com>
> ---
> fs/xfs/libxfs/xfs_defer.c | 32 ++++++++++++++------------------
> 1 file changed, 14 insertions(+), 18 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
> index c4b0eaeb5190..ee734a8b3fa9 100644
> --- a/fs/xfs/libxfs/xfs_defer.c
> +++ b/fs/xfs/libxfs/xfs_defer.c
> @@ -225,9 +225,9 @@ xfs_defer_trans_abort(
> /* Roll a transaction so we can do some deferred op processing. */
> STATIC int
> xfs_defer_trans_roll(
> - struct xfs_trans **tp,
> - struct xfs_defer_ops *dop)
> + struct xfs_trans **tp)
> {
> + struct xfs_defer_ops *dop = (*tp)->t_dfops;
> int i;
> int error;
>
> @@ -243,6 +243,7 @@ xfs_defer_trans_roll(
>
> /* Roll the transaction. */
> error = xfs_trans_roll(tp);
> + dop = (*tp)->t_dfops;
> if (error) {
> trace_xfs_defer_trans_roll_error((*tp)->t_mountp, dop, error);
> xfs_defer_trans_abort(*tp, dop, error);
> @@ -338,31 +339,25 @@ xfs_defer_finish(
> void *state;
> int error = 0;
> void (*cleanup_fn)(struct xfs_trans *, void *, int);
> - struct xfs_defer_ops *orig_dop;
>
> ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
> + ASSERT((*tp)->t_dfops == dop);
>
> trace_xfs_defer_finish((*tp)->t_mountp, dop, _RET_IP_);
>
> - /*
> - * Attach dfops to the transaction during deferred ops processing. This
> - * explicitly causes calls into the allocator to defer AGFL block frees.
> - * Note that this code can go away once all dfops users attach to the
> - * associated tp.
> - */
> - ASSERT(!(*tp)->t_dfops || ((*tp)->t_dfops == dop));
> - orig_dop = (*tp)->t_dfops;
> - (*tp)->t_dfops = dop;
> -
> /* Until we run out of pending work to finish... */
> while (xfs_defer_has_unfinished_work(dop)) {
> /* Log intents for work items sitting in the intake. */
> xfs_defer_intake_work(*tp, dop);
>
> - /* Roll the transaction. */
> - error = xfs_defer_trans_roll(tp, dop);
> + /*
> + * Roll the transaction and update dop in case dfops was
> + * embedded in the transaction.
> + */
> + error = xfs_defer_trans_roll(tp);
> if (error)
> goto out;
> + dop = (*tp)->t_dfops;
>
> /* Log an intent-done item for the first pending item. */
> dfp = list_first_entry(&dop->dop_pending,
> @@ -428,10 +423,11 @@ xfs_defer_finish(
> * Roll the transaction once more to avoid returning to the caller
> * with a dirty transaction.
> */
> - if ((*tp)->t_flags & XFS_TRANS_DIRTY)
> - error = xfs_defer_trans_roll(tp, dop);
> + if ((*tp)->t_flags & XFS_TRANS_DIRTY) {
> + error = xfs_defer_trans_roll(tp);
> + dop = (*tp)->t_dfops;
> + }
> out:
> - (*tp)->t_dfops = orig_dop;
> if (error)
> trace_xfs_defer_finish_error((*tp)->t_mountp, dop, error);
> else
> --
> 2.17.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v7 12/12] Add maintainers for the PECI subsystem
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, Linus Walleij,
Jason M Biils
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds maintainer information for the PECI subsystem.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
---
MAINTAINERS | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7afb9ad5a85c..28a87cb77723 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1266,6 +1266,14 @@ F: arch/arm/mach-aspeed/
F: arch/arm/boot/dts/aspeed-*
N: aspeed
+ARM/ASPEED PECI DRIVER
+M: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+M: Jason M Biils <jason.m.bills@linux.intel.com>
+L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/peci/peci-aspeed.txt
+F: drivers/peci/peci-aspeed.c
+
ARM/CALXEDA HIGHBANK ARCHITECTURE
M: Rob Herring <robh@kernel.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -11254,6 +11262,19 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/peaq-wmi.c
+PECI SUBSYSTEM
+M: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+M: Jason M Biils <jason.m.bills@linux.intel.com>
+L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/peci/
+F: drivers/mfd/intel-peci-client.c
+F: drivers/peci/
+F: drivers/hwmon/peci-*.c
+F: include/linux/mfd/intel-peci-client.h
+F: include/linux/peci.h
+F: include/uapi/linux/peci-ioctl.h
+
PER-CPU MEMORY ALLOCATOR
M: Tejun Heo <tj@kernel.org>
M: Christoph Lameter <cl@linux.com>
--
2.18.0
^ permalink raw reply related
* [PATCH v7 12/12] Add maintainers for the PECI subsystem
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds maintainer information for the PECI subsystem.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
---
MAINTAINERS | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7afb9ad5a85c..28a87cb77723 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1266,6 +1266,14 @@ F: arch/arm/mach-aspeed/
F: arch/arm/boot/dts/aspeed-*
N: aspeed
+ARM/ASPEED PECI DRIVER
+M: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+M: Jason M Biils <jason.m.bills@linux.intel.com>
+L: linux-aspeed at lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/peci/peci-aspeed.txt
+F: drivers/peci/peci-aspeed.c
+
ARM/CALXEDA HIGHBANK ARCHITECTURE
M: Rob Herring <robh@kernel.org>
L: linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
@@ -11254,6 +11262,19 @@ L: platform-driver-x86 at vger.kernel.org
S: Maintained
F: drivers/platform/x86/peaq-wmi.c
+PECI SUBSYSTEM
+M: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+M: Jason M Biils <jason.m.bills@linux.intel.com>
+L: openbmc at lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/peci/
+F: drivers/mfd/intel-peci-client.c
+F: drivers/peci/
+F: drivers/hwmon/peci-*.c
+F: include/linux/mfd/intel-peci-client.h
+F: include/linux/peci.h
+F: include/uapi/linux/peci-ioctl.h
+
PER-CPU MEMORY ALLOCATOR
M: Tejun Heo <tj@kernel.org>
M: Christoph Lameter <cl@linux.com>
--
2.18.0
^ permalink raw reply related
* [PATCH v7 12/12] Add maintainers for the PECI subsystem
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds maintainer information for the PECI subsystem.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
---
MAINTAINERS | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7afb9ad5a85c..28a87cb77723 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1266,6 +1266,14 @@ F: arch/arm/mach-aspeed/
F: arch/arm/boot/dts/aspeed-*
N: aspeed
+ARM/ASPEED PECI DRIVER
+M: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+M: Jason M Biils <jason.m.bills@linux.intel.com>
+L: linux-aspeed at lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/peci/peci-aspeed.txt
+F: drivers/peci/peci-aspeed.c
+
ARM/CALXEDA HIGHBANK ARCHITECTURE
M: Rob Herring <robh@kernel.org>
L: linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
@@ -11254,6 +11262,19 @@ L: platform-driver-x86 at vger.kernel.org
S: Maintained
F: drivers/platform/x86/peaq-wmi.c
+PECI SUBSYSTEM
+M: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+M: Jason M Biils <jason.m.bills@linux.intel.com>
+L: openbmc at lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/peci/
+F: drivers/mfd/intel-peci-client.c
+F: drivers/peci/
+F: drivers/hwmon/peci-*.c
+F: include/linux/mfd/intel-peci-client.h
+F: include/linux/peci.h
+F: include/uapi/linux/peci-ioctl.h
+
PER-CPU MEMORY ALLOCATOR
M: Tejun Heo <tj@kernel.org>
M: Christoph Lameter <cl@linux.com>
--
2.18.0
^ permalink raw reply related
* [PATCH v7 11/12] hwmon: Add PECI dimmtemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, Alan Cox,
Andy Shevchenko, Jason M Biils, Miguel Ojeda, Andrew Lunn,
Stef van Os
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI dimmtemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-dimmtemp.c | 295 ++++++++++++++++++++++++++++++++++
3 files changed, 310 insertions(+)
create mode 100644 drivers/hwmon/peci-dimmtemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index f08b4a670ac5..d2299d850508 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1320,6 +1320,20 @@ config SENSORS_PECI_CPUTEMP
This driver can also be built as a module. If so, the module
will be called peci-cputemp.
+config SENSORS_PECI_DIMMTEMP
+ tristate "PECI DIMM temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI hwmon
+ driver which provides Digital Thermal Sensor (DTS) thermal readings of
+ DIMM components that are accessible using the PECI Client Command
+ Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-dimmtemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-dimmtemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 13ebde089ad5..b7cf35bcfbaf 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
+obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
new file mode 100644
index 000000000000..b098cb483b21
--- /dev/null
+++ b/drivers/hwmon/peci-dimmtemp.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define DIMM_MASK_CHECK_DELAY_JIFFIES msecs_to_jiffies(5000)
+#define DIMM_MASK_CHECK_RETRY_MAX 60 /* 60 x 5 secs = 5 minutes */
+
+struct peci_dimmtemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct workqueue_struct *work_queue;
+ struct delayed_work work_handler;
+ struct temp_data temp[DIMM_NUMS_MAX];
+ u32 dimm_mask;
+ int retry_count;
+ u32 temp_config[DIMM_NUMS_MAX + 1];
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+static const char *dimmtemp_label[CHAN_RANK_MAX][DIMM_IDX_MAX] = {
+ { "DIMM A1", "DIMM A2", "DIMM A3" },
+ { "DIMM B1", "DIMM B2", "DIMM B3" },
+ { "DIMM C1", "DIMM C2", "DIMM C3" },
+ { "DIMM D1", "DIMM D2", "DIMM D3" },
+ { "DIMM E1", "DIMM E2", "DIMM E3" },
+ { "DIMM F1", "DIMM F2", "DIMM F3" },
+ { "DIMM G1", "DIMM G2", "DIMM G3" },
+ { "DIMM H1", "DIMM H2", "DIMM H3" },
+};
+
+static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+{
+ int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+ int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+ u8 cfg_data[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp[dimm_no]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc)
+ return rc;
+
+ priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000;
+
+ peci_temp_mark_updated(&priv->temp[dimm_no]);
+
+ return 0;
+}
+
+static int dimmtemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx;
+
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ chan_rank = channel / dimm_idx_max;
+ dimm_idx = channel % dimm_idx_max;
+ *str = dimmtemp_label[chan_rank][dimm_idx];
+ return 0;
+}
+
+static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ int rc;
+
+ if (attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+ rc = get_dimm_temp(priv, channel);
+ if (rc)
+ return rc;
+
+ *val = priv->temp[channel].value;
+ return 0;
+}
+
+static umode_t dimmtemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_dimmtemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr) &&
+ priv->dimm_mask & BIT(channel))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops dimmtemp_ops = {
+ .is_visible = dimmtemp_is_visible,
+ .read_string = dimmtemp_read_string,
+ .read = dimmtemp_read,
+};
+
+static int check_populated_dimms(struct peci_dimmtemp *priv)
+{
+ u32 chan_rank_max = priv->gen_info->chan_rank_max;
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx, rc;
+ u8 cfg_data[4];
+
+ for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd,
+ MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc) {
+ priv->dimm_mask = 0;
+ return rc;
+ }
+
+ for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
+ if (cfg_data[dimm_idx])
+ priv->dimm_mask |= BIT(chan_rank *
+ dimm_idx_max +
+ dimm_idx);
+ }
+
+ if (!priv->dimm_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask);
+ return 0;
+}
+
+static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+{
+ int rc, i, config_idx, channels;
+ struct device *hwmon_dev;
+
+ rc = check_populated_dimms(priv);
+ if (rc) {
+ if (rc == -EAGAIN) {
+ if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) {
+ queue_delayed_work(priv->work_queue,
+ &priv->work_handler,
+ DIMM_MASK_CHECK_DELAY_JIFFIES);
+ priv->retry_count++;
+ dev_dbg(priv->dev,
+ "Deferred DIMM temp info creation\n");
+ } else {
+ dev_err(priv->dev,
+ "Timeout DIMM temp info creation\n");
+ rc = -ETIMEDOUT;
+ }
+ }
+
+ return rc;
+ }
+
+ channels = priv->gen_info->chan_rank_max *
+ priv->gen_info->dimm_idx_max;
+ for (i = 0, config_idx = 0; i < channels; i++)
+ if (priv->dimm_mask & BIT(i))
+ while (i >= config_idx)
+ priv->temp_config[config_idx++] =
+ HWMON_T_LABEL | HWMON_T_INPUT;
+
+ priv->chip.ops = &dimmtemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+ rc = PTR_ERR_OR_ZERO(hwmon_dev);
+ if (!rc)
+ dev_dbg(priv->dev, "%s: sensor '%s'\n",
+ dev_name(hwmon_dev), priv->name);
+
+ return rc;
+}
+
+static void create_dimm_temp_info_delayed(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp,
+ work_handler);
+ int rc;
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN)
+ dev_dbg(priv->dev, "Failed to create DIMM temp info\n");
+}
+
+static int peci_dimmtemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_dimmtemp *priv;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_dimmtemp.cpu%d",
+ priv->mfd->cpu_no);
+
+ priv->work_queue = alloc_ordered_workqueue(priv->name, 0);
+ if (!priv->work_queue)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed);
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN) {
+ dev_err(dev, "Failed to create DIMM temp info\n");
+ goto err_free_wq;
+ }
+
+ return 0;
+
+err_free_wq:
+ destroy_workqueue(priv->work_queue);
+ return rc;
+}
+
+static int peci_dimmtemp_remove(struct platform_device *pdev)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(&pdev->dev);
+
+ cancel_delayed_work_sync(&priv->work_handler);
+ destroy_workqueue(priv->work_queue);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_dimmtemp_of_table[] = {
+ { .compatible = "intel,peci-dimmtemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_dimmtemp_of_table);
+#endif
+
+static const struct platform_device_id peci_dimmtemp_ids[] = {
+ { .name = "peci-dimmtemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_dimmtemp_ids);
+
+static struct platform_driver peci_dimmtemp_driver = {
+ .probe = peci_dimmtemp_probe,
+ .remove = peci_dimmtemp_remove,
+ .id_table = peci_dimmtemp_ids,
+ .driver = {
+ .name = "peci-dimmtemp",
+ .of_match_table = of_match_ptr(peci_dimmtemp_of_table),
+ },
+};
+module_platform_driver(peci_dimmtemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI dimmtemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 11/12] hwmon: Add PECI dimmtemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI dimmtemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-dimmtemp.c | 295 ++++++++++++++++++++++++++++++++++
3 files changed, 310 insertions(+)
create mode 100644 drivers/hwmon/peci-dimmtemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index f08b4a670ac5..d2299d850508 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1320,6 +1320,20 @@ config SENSORS_PECI_CPUTEMP
This driver can also be built as a module. If so, the module
will be called peci-cputemp.
+config SENSORS_PECI_DIMMTEMP
+ tristate "PECI DIMM temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI hwmon
+ driver which provides Digital Thermal Sensor (DTS) thermal readings of
+ DIMM components that are accessible using the PECI Client Command
+ Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-dimmtemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-dimmtemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 13ebde089ad5..b7cf35bcfbaf 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
+obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
new file mode 100644
index 000000000000..b098cb483b21
--- /dev/null
+++ b/drivers/hwmon/peci-dimmtemp.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define DIMM_MASK_CHECK_DELAY_JIFFIES msecs_to_jiffies(5000)
+#define DIMM_MASK_CHECK_RETRY_MAX 60 /* 60 x 5 secs = 5 minutes */
+
+struct peci_dimmtemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct workqueue_struct *work_queue;
+ struct delayed_work work_handler;
+ struct temp_data temp[DIMM_NUMS_MAX];
+ u32 dimm_mask;
+ int retry_count;
+ u32 temp_config[DIMM_NUMS_MAX + 1];
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+static const char *dimmtemp_label[CHAN_RANK_MAX][DIMM_IDX_MAX] = {
+ { "DIMM A1", "DIMM A2", "DIMM A3" },
+ { "DIMM B1", "DIMM B2", "DIMM B3" },
+ { "DIMM C1", "DIMM C2", "DIMM C3" },
+ { "DIMM D1", "DIMM D2", "DIMM D3" },
+ { "DIMM E1", "DIMM E2", "DIMM E3" },
+ { "DIMM F1", "DIMM F2", "DIMM F3" },
+ { "DIMM G1", "DIMM G2", "DIMM G3" },
+ { "DIMM H1", "DIMM H2", "DIMM H3" },
+};
+
+static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+{
+ int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+ int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+ u8 cfg_data[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp[dimm_no]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc)
+ return rc;
+
+ priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000;
+
+ peci_temp_mark_updated(&priv->temp[dimm_no]);
+
+ return 0;
+}
+
+static int dimmtemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx;
+
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ chan_rank = channel / dimm_idx_max;
+ dimm_idx = channel % dimm_idx_max;
+ *str = dimmtemp_label[chan_rank][dimm_idx];
+ return 0;
+}
+
+static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ int rc;
+
+ if (attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+ rc = get_dimm_temp(priv, channel);
+ if (rc)
+ return rc;
+
+ *val = priv->temp[channel].value;
+ return 0;
+}
+
+static umode_t dimmtemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_dimmtemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr) &&
+ priv->dimm_mask & BIT(channel))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops dimmtemp_ops = {
+ .is_visible = dimmtemp_is_visible,
+ .read_string = dimmtemp_read_string,
+ .read = dimmtemp_read,
+};
+
+static int check_populated_dimms(struct peci_dimmtemp *priv)
+{
+ u32 chan_rank_max = priv->gen_info->chan_rank_max;
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx, rc;
+ u8 cfg_data[4];
+
+ for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd,
+ MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc) {
+ priv->dimm_mask = 0;
+ return rc;
+ }
+
+ for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
+ if (cfg_data[dimm_idx])
+ priv->dimm_mask |= BIT(chan_rank *
+ dimm_idx_max +
+ dimm_idx);
+ }
+
+ if (!priv->dimm_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask);
+ return 0;
+}
+
+static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+{
+ int rc, i, config_idx, channels;
+ struct device *hwmon_dev;
+
+ rc = check_populated_dimms(priv);
+ if (rc) {
+ if (rc == -EAGAIN) {
+ if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) {
+ queue_delayed_work(priv->work_queue,
+ &priv->work_handler,
+ DIMM_MASK_CHECK_DELAY_JIFFIES);
+ priv->retry_count++;
+ dev_dbg(priv->dev,
+ "Deferred DIMM temp info creation\n");
+ } else {
+ dev_err(priv->dev,
+ "Timeout DIMM temp info creation\n");
+ rc = -ETIMEDOUT;
+ }
+ }
+
+ return rc;
+ }
+
+ channels = priv->gen_info->chan_rank_max *
+ priv->gen_info->dimm_idx_max;
+ for (i = 0, config_idx = 0; i < channels; i++)
+ if (priv->dimm_mask & BIT(i))
+ while (i >= config_idx)
+ priv->temp_config[config_idx++] =
+ HWMON_T_LABEL | HWMON_T_INPUT;
+
+ priv->chip.ops = &dimmtemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+ rc = PTR_ERR_OR_ZERO(hwmon_dev);
+ if (!rc)
+ dev_dbg(priv->dev, "%s: sensor '%s'\n",
+ dev_name(hwmon_dev), priv->name);
+
+ return rc;
+}
+
+static void create_dimm_temp_info_delayed(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp,
+ work_handler);
+ int rc;
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN)
+ dev_dbg(priv->dev, "Failed to create DIMM temp info\n");
+}
+
+static int peci_dimmtemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_dimmtemp *priv;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_dimmtemp.cpu%d",
+ priv->mfd->cpu_no);
+
+ priv->work_queue = alloc_ordered_workqueue(priv->name, 0);
+ if (!priv->work_queue)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed);
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN) {
+ dev_err(dev, "Failed to create DIMM temp info\n");
+ goto err_free_wq;
+ }
+
+ return 0;
+
+err_free_wq:
+ destroy_workqueue(priv->work_queue);
+ return rc;
+}
+
+static int peci_dimmtemp_remove(struct platform_device *pdev)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(&pdev->dev);
+
+ cancel_delayed_work_sync(&priv->work_handler);
+ destroy_workqueue(priv->work_queue);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_dimmtemp_of_table[] = {
+ { .compatible = "intel,peci-dimmtemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_dimmtemp_of_table);
+#endif
+
+static const struct platform_device_id peci_dimmtemp_ids[] = {
+ { .name = "peci-dimmtemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_dimmtemp_ids);
+
+static struct platform_driver peci_dimmtemp_driver = {
+ .probe = peci_dimmtemp_probe,
+ .remove = peci_dimmtemp_remove,
+ .id_table = peci_dimmtemp_ids,
+ .driver = {
+ .name = "peci-dimmtemp",
+ .of_match_table = of_match_ptr(peci_dimmtemp_of_table),
+ },
+};
+module_platform_driver(peci_dimmtemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI dimmtemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 11/12] hwmon: Add PECI dimmtemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David S . Miller,
Mauro Carvalho Chehab, Andrew Morton, Randy Dunlap,
Philippe Ombredanne, Vinod Koul, Stephen Boyd, David Kershner,
Uwe Kleine-Konig, Sagar Dharia, Johan Hovold, Thomas Gleixner,
Juergen Gross, Cyrille Pitchen
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, Alan Cox,
Andy Shevchenko, Jason M Biils, Miguel Ojeda, Andrew Lunn,
Stef van Os
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI dimmtemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-dimmtemp.c | 295 ++++++++++++++++++++++++++++++++++
3 files changed, 310 insertions(+)
create mode 100644 drivers/hwmon/peci-dimmtemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index f08b4a670ac5..d2299d850508 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1320,6 +1320,20 @@ config SENSORS_PECI_CPUTEMP
This driver can also be built as a module. If so, the module
will be called peci-cputemp.
+config SENSORS_PECI_DIMMTEMP
+ tristate "PECI DIMM temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI hwmon
+ driver which provides Digital Thermal Sensor (DTS) thermal readings of
+ DIMM components that are accessible using the PECI Client Command
+ Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-dimmtemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-dimmtemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 13ebde089ad5..b7cf35bcfbaf 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
+obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
new file mode 100644
index 000000000000..b098cb483b21
--- /dev/null
+++ b/drivers/hwmon/peci-dimmtemp.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define DIMM_MASK_CHECK_DELAY_JIFFIES msecs_to_jiffies(5000)
+#define DIMM_MASK_CHECK_RETRY_MAX 60 /* 60 x 5 secs = 5 minutes */
+
+struct peci_dimmtemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct workqueue_struct *work_queue;
+ struct delayed_work work_handler;
+ struct temp_data temp[DIMM_NUMS_MAX];
+ u32 dimm_mask;
+ int retry_count;
+ u32 temp_config[DIMM_NUMS_MAX + 1];
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+static const char *dimmtemp_label[CHAN_RANK_MAX][DIMM_IDX_MAX] = {
+ { "DIMM A1", "DIMM A2", "DIMM A3" },
+ { "DIMM B1", "DIMM B2", "DIMM B3" },
+ { "DIMM C1", "DIMM C2", "DIMM C3" },
+ { "DIMM D1", "DIMM D2", "DIMM D3" },
+ { "DIMM E1", "DIMM E2", "DIMM E3" },
+ { "DIMM F1", "DIMM F2", "DIMM F3" },
+ { "DIMM G1", "DIMM G2", "DIMM G3" },
+ { "DIMM H1", "DIMM H2", "DIMM H3" },
+};
+
+static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+{
+ int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+ int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+ u8 cfg_data[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp[dimm_no]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc)
+ return rc;
+
+ priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000;
+
+ peci_temp_mark_updated(&priv->temp[dimm_no]);
+
+ return 0;
+}
+
+static int dimmtemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx;
+
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ chan_rank = channel / dimm_idx_max;
+ dimm_idx = channel % dimm_idx_max;
+ *str = dimmtemp_label[chan_rank][dimm_idx];
+ return 0;
+}
+
+static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ int rc;
+
+ if (attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+ rc = get_dimm_temp(priv, channel);
+ if (rc)
+ return rc;
+
+ *val = priv->temp[channel].value;
+ return 0;
+}
+
+static umode_t dimmtemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_dimmtemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr) &&
+ priv->dimm_mask & BIT(channel))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops dimmtemp_ops = {
+ .is_visible = dimmtemp_is_visible,
+ .read_string = dimmtemp_read_string,
+ .read = dimmtemp_read,
+};
+
+static int check_populated_dimms(struct peci_dimmtemp *priv)
+{
+ u32 chan_rank_max = priv->gen_info->chan_rank_max;
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx, rc;
+ u8 cfg_data[4];
+
+ for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd,
+ MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc) {
+ priv->dimm_mask = 0;
+ return rc;
+ }
+
+ for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
+ if (cfg_data[dimm_idx])
+ priv->dimm_mask |= BIT(chan_rank *
+ dimm_idx_max +
+ dimm_idx);
+ }
+
+ if (!priv->dimm_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask);
+ return 0;
+}
+
+static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+{
+ int rc, i, config_idx, channels;
+ struct device *hwmon_dev;
+
+ rc = check_populated_dimms(priv);
+ if (rc) {
+ if (rc == -EAGAIN) {
+ if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) {
+ queue_delayed_work(priv->work_queue,
+ &priv->work_handler,
+ DIMM_MASK_CHECK_DELAY_JIFFIES);
+ priv->retry_count++;
+ dev_dbg(priv->dev,
+ "Deferred DIMM temp info creation\n");
+ } else {
+ dev_err(priv->dev,
+ "Timeout DIMM temp info creation\n");
+ rc = -ETIMEDOUT;
+ }
+ }
+
+ return rc;
+ }
+
+ channels = priv->gen_info->chan_rank_max *
+ priv->gen_info->dimm_idx_max;
+ for (i = 0, config_idx = 0; i < channels; i++)
+ if (priv->dimm_mask & BIT(i))
+ while (i >= config_idx)
+ priv->temp_config[config_idx++] =
+ HWMON_T_LABEL | HWMON_T_INPUT;
+
+ priv->chip.ops = &dimmtemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+ rc = PTR_ERR_OR_ZERO(hwmon_dev);
+ if (!rc)
+ dev_dbg(priv->dev, "%s: sensor '%s'\n",
+ dev_name(hwmon_dev), priv->name);
+
+ return rc;
+}
+
+static void create_dimm_temp_info_delayed(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp,
+ work_handler);
+ int rc;
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN)
+ dev_dbg(priv->dev, "Failed to create DIMM temp info\n");
+}
+
+static int peci_dimmtemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_dimmtemp *priv;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_dimmtemp.cpu%d",
+ priv->mfd->cpu_no);
+
+ priv->work_queue = alloc_ordered_workqueue(priv->name, 0);
+ if (!priv->work_queue)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed);
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN) {
+ dev_err(dev, "Failed to create DIMM temp info\n");
+ goto err_free_wq;
+ }
+
+ return 0;
+
+err_free_wq:
+ destroy_workqueue(priv->work_queue);
+ return rc;
+}
+
+static int peci_dimmtemp_remove(struct platform_device *pdev)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(&pdev->dev);
+
+ cancel_delayed_work_sync(&priv->work_handler);
+ destroy_workqueue(priv->work_queue);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_dimmtemp_of_table[] = {
+ { .compatible = "intel,peci-dimmtemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_dimmtemp_of_table);
+#endif
+
+static const struct platform_device_id peci_dimmtemp_ids[] = {
+ { .name = "peci-dimmtemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_dimmtemp_ids);
+
+static struct platform_driver peci_dimmtemp_driver = {
+ .probe = peci_dimmtemp_probe,
+ .remove = peci_dimmtemp_remove,
+ .id_table = peci_dimmtemp_ids,
+ .driver = {
+ .name = "peci-dimmtemp",
+ .of_match_table = of_match_ptr(peci_dimmtemp_of_table),
+ },
+};
+module_platform_driver(peci_dimmtemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI dimmtemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 11/12] hwmon: Add PECI dimmtemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI dimmtemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-dimmtemp.c | 295 ++++++++++++++++++++++++++++++++++
3 files changed, 310 insertions(+)
create mode 100644 drivers/hwmon/peci-dimmtemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index f08b4a670ac5..d2299d850508 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1320,6 +1320,20 @@ config SENSORS_PECI_CPUTEMP
This driver can also be built as a module. If so, the module
will be called peci-cputemp.
+config SENSORS_PECI_DIMMTEMP
+ tristate "PECI DIMM temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI hwmon
+ driver which provides Digital Thermal Sensor (DTS) thermal readings of
+ DIMM components that are accessible using the PECI Client Command
+ Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-dimmtemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-dimmtemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 13ebde089ad5..b7cf35bcfbaf 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
+obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
new file mode 100644
index 000000000000..b098cb483b21
--- /dev/null
+++ b/drivers/hwmon/peci-dimmtemp.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define DIMM_MASK_CHECK_DELAY_JIFFIES msecs_to_jiffies(5000)
+#define DIMM_MASK_CHECK_RETRY_MAX 60 /* 60 x 5 secs = 5 minutes */
+
+struct peci_dimmtemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct workqueue_struct *work_queue;
+ struct delayed_work work_handler;
+ struct temp_data temp[DIMM_NUMS_MAX];
+ u32 dimm_mask;
+ int retry_count;
+ u32 temp_config[DIMM_NUMS_MAX + 1];
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+static const char *dimmtemp_label[CHAN_RANK_MAX][DIMM_IDX_MAX] = {
+ { "DIMM A1", "DIMM A2", "DIMM A3" },
+ { "DIMM B1", "DIMM B2", "DIMM B3" },
+ { "DIMM C1", "DIMM C2", "DIMM C3" },
+ { "DIMM D1", "DIMM D2", "DIMM D3" },
+ { "DIMM E1", "DIMM E2", "DIMM E3" },
+ { "DIMM F1", "DIMM F2", "DIMM F3" },
+ { "DIMM G1", "DIMM G2", "DIMM G3" },
+ { "DIMM H1", "DIMM H2", "DIMM H3" },
+};
+
+static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+{
+ int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+ int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+ u8 cfg_data[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp[dimm_no]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc)
+ return rc;
+
+ priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000;
+
+ peci_temp_mark_updated(&priv->temp[dimm_no]);
+
+ return 0;
+}
+
+static int dimmtemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx;
+
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ chan_rank = channel / dimm_idx_max;
+ dimm_idx = channel % dimm_idx_max;
+ *str = dimmtemp_label[chan_rank][dimm_idx];
+ return 0;
+}
+
+static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ int rc;
+
+ if (attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+ rc = get_dimm_temp(priv, channel);
+ if (rc)
+ return rc;
+
+ *val = priv->temp[channel].value;
+ return 0;
+}
+
+static umode_t dimmtemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_dimmtemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr) &&
+ priv->dimm_mask & BIT(channel))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops dimmtemp_ops = {
+ .is_visible = dimmtemp_is_visible,
+ .read_string = dimmtemp_read_string,
+ .read = dimmtemp_read,
+};
+
+static int check_populated_dimms(struct peci_dimmtemp *priv)
+{
+ u32 chan_rank_max = priv->gen_info->chan_rank_max;
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx, rc;
+ u8 cfg_data[4];
+
+ for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd,
+ MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+ if (rc) {
+ priv->dimm_mask = 0;
+ return rc;
+ }
+
+ for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
+ if (cfg_data[dimm_idx])
+ priv->dimm_mask |= BIT(chan_rank *
+ dimm_idx_max +
+ dimm_idx);
+ }
+
+ if (!priv->dimm_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask);
+ return 0;
+}
+
+static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+{
+ int rc, i, config_idx, channels;
+ struct device *hwmon_dev;
+
+ rc = check_populated_dimms(priv);
+ if (rc) {
+ if (rc == -EAGAIN) {
+ if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) {
+ queue_delayed_work(priv->work_queue,
+ &priv->work_handler,
+ DIMM_MASK_CHECK_DELAY_JIFFIES);
+ priv->retry_count++;
+ dev_dbg(priv->dev,
+ "Deferred DIMM temp info creation\n");
+ } else {
+ dev_err(priv->dev,
+ "Timeout DIMM temp info creation\n");
+ rc = -ETIMEDOUT;
+ }
+ }
+
+ return rc;
+ }
+
+ channels = priv->gen_info->chan_rank_max *
+ priv->gen_info->dimm_idx_max;
+ for (i = 0, config_idx = 0; i < channels; i++)
+ if (priv->dimm_mask & BIT(i))
+ while (i >= config_idx)
+ priv->temp_config[config_idx++] =
+ HWMON_T_LABEL | HWMON_T_INPUT;
+
+ priv->chip.ops = &dimmtemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+ rc = PTR_ERR_OR_ZERO(hwmon_dev);
+ if (!rc)
+ dev_dbg(priv->dev, "%s: sensor '%s'\n",
+ dev_name(hwmon_dev), priv->name);
+
+ return rc;
+}
+
+static void create_dimm_temp_info_delayed(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp,
+ work_handler);
+ int rc;
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN)
+ dev_dbg(priv->dev, "Failed to create DIMM temp info\n");
+}
+
+static int peci_dimmtemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_dimmtemp *priv;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_dimmtemp.cpu%d",
+ priv->mfd->cpu_no);
+
+ priv->work_queue = alloc_ordered_workqueue(priv->name, 0);
+ if (!priv->work_queue)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed);
+
+ rc = create_dimm_temp_info(priv);
+ if (rc && rc != -EAGAIN) {
+ dev_err(dev, "Failed to create DIMM temp info\n");
+ goto err_free_wq;
+ }
+
+ return 0;
+
+err_free_wq:
+ destroy_workqueue(priv->work_queue);
+ return rc;
+}
+
+static int peci_dimmtemp_remove(struct platform_device *pdev)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(&pdev->dev);
+
+ cancel_delayed_work_sync(&priv->work_handler);
+ destroy_workqueue(priv->work_queue);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_dimmtemp_of_table[] = {
+ { .compatible = "intel,peci-dimmtemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_dimmtemp_of_table);
+#endif
+
+static const struct platform_device_id peci_dimmtemp_ids[] = {
+ { .name = "peci-dimmtemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_dimmtemp_ids);
+
+static struct platform_driver peci_dimmtemp_driver = {
+ .probe = peci_dimmtemp_probe,
+ .remove = peci_dimmtemp_remove,
+ .id_table = peci_dimmtemp_ids,
+ .driver = {
+ .name = "peci-dimmtemp",
+ .of_match_table = of_match_ptr(peci_dimmtemp_of_table),
+ },
+};
+module_platform_driver(peci_dimmtemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI dimmtemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 10/12] hwmon: Add PECI cputemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, Alan Cox,
Andy Shevchenko, Jason M Biils, Miguel Ojeda, Andrew Lunn,
Stef van Os
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI cputemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-cputemp.c | 401 +++++++++++++++++++++++++++++++++++
3 files changed, 416 insertions(+)
create mode 100644 drivers/hwmon/peci-cputemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 81da17a42dc9..f08b4a670ac5 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1306,6 +1306,20 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+config SENSORS_PECI_CPUTEMP
+ tristate "PECI CPU temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI
+ cputemp driver which provides Digital Thermal Sensor (DTS) thermal
+ readings of the CPU package and CPU cores that are accessible using
+ the PECI Client Command Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-cputemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-cputemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 93f7f41ea4ad..13ebde089ad5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
new file mode 100644
index 000000000000..d92b31678876
--- /dev/null
+++ b/drivers/hwmon/peci-cputemp.c
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_CHANNEL_NUMS 4
+#define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX
+#define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS)
+
+/* The RESOLVED_CORES register in PCU of a client CPU */
+#define REG_RESOLVED_CORES_BUS 1
+#define REG_RESOLVED_CORES_DEVICE 30
+#define REG_RESOLVED_CORES_FUNCTION 3
+#define REG_RESOLVED_CORES_OFFSET 0xB4
+
+struct temp_group {
+ struct temp_data die;
+ struct temp_data tcontrol;
+ struct temp_data tthrottle;
+ struct temp_data tjmax;
+ struct temp_data core[CORETEMP_CHANNEL_NUMS];
+};
+
+struct peci_cputemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct temp_group temp;
+ u32 core_mask;
+ u32 temp_config[CPUTEMP_CHANNEL_NUMS + 1];
+ uint config_idx;
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+enum cputemp_channels {
+ channel_die,
+ channel_tcontrol,
+ channel_tthrottle,
+ channel_tjmax,
+ channel_core,
+};
+
+static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+ /* Die temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+
+ /* Tcontrol temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+
+ /* Tthrottle temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Tjmax temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Core temperature - for all core channels */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+};
+
+static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = {
+ "Die",
+ "Tcontrol",
+ "Tthrottle",
+ "Tjmax",
+ "Core 0", "Core 1", "Core 2", "Core 3",
+ "Core 4", "Core 5", "Core 6", "Core 7",
+ "Core 8", "Core 9", "Core 10", "Core 11",
+ "Core 12", "Core 13", "Core 14", "Core 15",
+ "Core 16", "Core 17", "Core 18", "Core 19",
+ "Core 20", "Core 21", "Core 22", "Core 23",
+};
+
+static s32 ten_dot_six_to_millidegree(s32 val)
+{
+ return ((val ^ 0x8000) - 0x8000) * 1000 / 64;
+}
+
+static int get_temp_targets(struct peci_cputemp *priv)
+{
+ s32 tthrottle_offset;
+ s32 tcontrol_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ /**
+ * Just use only the tcontrol marker to determine if target values need
+ * update.
+ */
+ if (!peci_temp_need_update(&priv->temp.tcontrol))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_TEMP_TARGET,
+ 0, pkg_cfg);
+ if (rc)
+ return rc;
+
+ priv->temp.tjmax.value = pkg_cfg[2] * 1000;
+
+ tcontrol_margin = pkg_cfg[1];
+ tcontrol_margin = ((tcontrol_margin ^ 0x80) - 0x80) * 1000;
+ priv->temp.tcontrol.value = priv->temp.tjmax.value - tcontrol_margin;
+
+ tthrottle_offset = (pkg_cfg[3] & 0x2f) * 1000;
+ priv->temp.tthrottle.value = priv->temp.tjmax.value - tthrottle_offset;
+
+ peci_temp_mark_updated(&priv->temp.tcontrol);
+
+ return 0;
+}
+
+static int get_die_temp(struct peci_cputemp *priv)
+{
+ struct peci_get_temp_msg msg;
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.die))
+ return 0;
+
+ msg.addr = priv->addr;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_GET_TEMP, &msg);
+ if (rc)
+ return rc;
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.die.value = priv->temp.tjmax.value +
+ (msg.temp_raw * 1000 / 64);
+
+ peci_temp_mark_updated(&priv->temp.die);
+
+ return 0;
+}
+
+static int get_core_temp(struct peci_cputemp *priv, int core_index)
+{
+ s32 core_dts_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.core[core_index]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_PER_CORE_DTS_TEMP,
+ core_index, pkg_cfg);
+ if (rc)
+ return rc;
+
+ core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg);
+
+ /**
+ * Processors return a value of the core DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ * Error codes:
+ * 0x8000: General sensor error
+ * 0x8001: Reserved
+ * 0x8002: Underflow on reading value
+ * 0x8003-0x81ff: Reserved
+ */
+ if (core_dts_margin >= 0x8000 && core_dts_margin <= 0x81ff)
+ return -EIO;
+
+ core_dts_margin = ten_dot_six_to_millidegree(core_dts_margin);
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.core[core_index].value = priv->temp.tjmax.value +
+ core_dts_margin;
+
+ peci_temp_mark_updated(&priv->temp.core[core_index]);
+
+ return 0;
+}
+
+static int cputemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = cputemp_label[channel];
+ return 0;
+}
+
+static int cputemp_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+ int rc, core_index;
+
+ if (channel >= CPUTEMP_CHANNEL_NUMS ||
+ !(priv->temp_config[channel] & BIT(attr)))
+ return -EOPNOTSUPP;
+
+ rc = get_temp_targets(priv);
+ if (rc)
+ return rc;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ switch (channel) {
+ case channel_die:
+ rc = get_die_temp(priv);
+ if (rc)
+ break;
+
+ *val = priv->temp.die.value;
+ break;
+ case channel_tcontrol:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case channel_tthrottle:
+ *val = priv->temp.tthrottle.value;
+ break;
+ case channel_tjmax:
+ *val = priv->temp.tjmax.value;
+ break;
+ default:
+ core_index = channel - DEFAULT_CHANNEL_NUMS;
+ rc = get_core_temp(priv, core_index);
+ if (rc)
+ break;
+
+ *val = priv->temp.core[core_index].value;
+ break;
+ }
+ break;
+ case hwmon_temp_max:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case hwmon_temp_crit:
+ *val = priv->temp.tjmax.value;
+ break;
+ case hwmon_temp_crit_hyst:
+ *val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
+ break;
+ default:
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ return rc;
+}
+
+static umode_t cputemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_cputemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr))
+ if (channel < DEFAULT_CHANNEL_NUMS ||
+ (channel >= DEFAULT_CHANNEL_NUMS &&
+ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops cputemp_ops = {
+ .is_visible = cputemp_is_visible,
+ .read_string = cputemp_read_string,
+ .read = cputemp_read,
+};
+
+static int check_resolved_cores(struct peci_cputemp *priv)
+{
+ struct peci_rd_pci_cfg_local_msg msg;
+ int rc;
+
+ /* Get the RESOLVED_CORES register value */
+ msg.addr = priv->addr;
+ msg.bus = REG_RESOLVED_CORES_BUS;
+ msg.device = REG_RESOLVED_CORES_DEVICE;
+ msg.function = REG_RESOLVED_CORES_FUNCTION;
+ msg.reg = REG_RESOLVED_CORES_OFFSET;
+ msg.rx_len = 4;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
+ if (rc)
+ return rc;
+
+ priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
+ if (!priv->core_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask);
+ return 0;
+}
+
+static int create_core_temp_info(struct peci_cputemp *priv)
+{
+ int rc, i;
+
+ rc = check_resolved_cores(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < priv->gen_info->core_max; i++)
+ if (priv->core_mask & BIT(i))
+ while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx)
+ priv->temp_config[priv->config_idx++] =
+ config_table[channel_core];
+
+ return 0;
+}
+
+static int peci_cputemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_cputemp *priv;
+ struct device *hwmon_dev;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_cputemp.cpu%d", mfd->cpu_no);
+
+ priv->temp_config[priv->config_idx++] = config_table[channel_die];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tjmax];
+
+ rc = create_core_temp_info(priv);
+ if (rc)
+ dev_dbg(dev, "Skipped creating core temp info\n");
+
+ priv->chip.ops = &cputemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_cputemp_of_table[] = {
+ { .compatible = "intel,peci-cputemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_cputemp_of_table);
+#endif
+
+static const struct platform_device_id peci_cputemp_ids[] = {
+ { .name = "peci-cputemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_cputemp_ids);
+
+static struct platform_driver peci_cputemp_driver = {
+ .probe = peci_cputemp_probe,
+ .id_table = peci_cputemp_ids,
+ .driver = {
+ .name = "peci-cputemp",
+ .of_match_table = of_match_ptr(peci_cputemp_of_table),
+ },
+};
+module_platform_driver(peci_cputemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI cputemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 10/12] hwmon: Add PECI cputemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI cputemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-cputemp.c | 401 +++++++++++++++++++++++++++++++++++
3 files changed, 416 insertions(+)
create mode 100644 drivers/hwmon/peci-cputemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 81da17a42dc9..f08b4a670ac5 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1306,6 +1306,20 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+config SENSORS_PECI_CPUTEMP
+ tristate "PECI CPU temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI
+ cputemp driver which provides Digital Thermal Sensor (DTS) thermal
+ readings of the CPU package and CPU cores that are accessible using
+ the PECI Client Command Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-cputemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-cputemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 93f7f41ea4ad..13ebde089ad5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
new file mode 100644
index 000000000000..d92b31678876
--- /dev/null
+++ b/drivers/hwmon/peci-cputemp.c
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_CHANNEL_NUMS 4
+#define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX
+#define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS)
+
+/* The RESOLVED_CORES register in PCU of a client CPU */
+#define REG_RESOLVED_CORES_BUS 1
+#define REG_RESOLVED_CORES_DEVICE 30
+#define REG_RESOLVED_CORES_FUNCTION 3
+#define REG_RESOLVED_CORES_OFFSET 0xB4
+
+struct temp_group {
+ struct temp_data die;
+ struct temp_data tcontrol;
+ struct temp_data tthrottle;
+ struct temp_data tjmax;
+ struct temp_data core[CORETEMP_CHANNEL_NUMS];
+};
+
+struct peci_cputemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct temp_group temp;
+ u32 core_mask;
+ u32 temp_config[CPUTEMP_CHANNEL_NUMS + 1];
+ uint config_idx;
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+enum cputemp_channels {
+ channel_die,
+ channel_tcontrol,
+ channel_tthrottle,
+ channel_tjmax,
+ channel_core,
+};
+
+static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+ /* Die temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+
+ /* Tcontrol temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+
+ /* Tthrottle temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Tjmax temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Core temperature - for all core channels */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+};
+
+static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = {
+ "Die",
+ "Tcontrol",
+ "Tthrottle",
+ "Tjmax",
+ "Core 0", "Core 1", "Core 2", "Core 3",
+ "Core 4", "Core 5", "Core 6", "Core 7",
+ "Core 8", "Core 9", "Core 10", "Core 11",
+ "Core 12", "Core 13", "Core 14", "Core 15",
+ "Core 16", "Core 17", "Core 18", "Core 19",
+ "Core 20", "Core 21", "Core 22", "Core 23",
+};
+
+static s32 ten_dot_six_to_millidegree(s32 val)
+{
+ return ((val ^ 0x8000) - 0x8000) * 1000 / 64;
+}
+
+static int get_temp_targets(struct peci_cputemp *priv)
+{
+ s32 tthrottle_offset;
+ s32 tcontrol_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ /**
+ * Just use only the tcontrol marker to determine if target values need
+ * update.
+ */
+ if (!peci_temp_need_update(&priv->temp.tcontrol))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_TEMP_TARGET,
+ 0, pkg_cfg);
+ if (rc)
+ return rc;
+
+ priv->temp.tjmax.value = pkg_cfg[2] * 1000;
+
+ tcontrol_margin = pkg_cfg[1];
+ tcontrol_margin = ((tcontrol_margin ^ 0x80) - 0x80) * 1000;
+ priv->temp.tcontrol.value = priv->temp.tjmax.value - tcontrol_margin;
+
+ tthrottle_offset = (pkg_cfg[3] & 0x2f) * 1000;
+ priv->temp.tthrottle.value = priv->temp.tjmax.value - tthrottle_offset;
+
+ peci_temp_mark_updated(&priv->temp.tcontrol);
+
+ return 0;
+}
+
+static int get_die_temp(struct peci_cputemp *priv)
+{
+ struct peci_get_temp_msg msg;
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.die))
+ return 0;
+
+ msg.addr = priv->addr;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_GET_TEMP, &msg);
+ if (rc)
+ return rc;
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.die.value = priv->temp.tjmax.value +
+ (msg.temp_raw * 1000 / 64);
+
+ peci_temp_mark_updated(&priv->temp.die);
+
+ return 0;
+}
+
+static int get_core_temp(struct peci_cputemp *priv, int core_index)
+{
+ s32 core_dts_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.core[core_index]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_PER_CORE_DTS_TEMP,
+ core_index, pkg_cfg);
+ if (rc)
+ return rc;
+
+ core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg);
+
+ /**
+ * Processors return a value of the core DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ * Error codes:
+ * 0x8000: General sensor error
+ * 0x8001: Reserved
+ * 0x8002: Underflow on reading value
+ * 0x8003-0x81ff: Reserved
+ */
+ if (core_dts_margin >= 0x8000 && core_dts_margin <= 0x81ff)
+ return -EIO;
+
+ core_dts_margin = ten_dot_six_to_millidegree(core_dts_margin);
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.core[core_index].value = priv->temp.tjmax.value +
+ core_dts_margin;
+
+ peci_temp_mark_updated(&priv->temp.core[core_index]);
+
+ return 0;
+}
+
+static int cputemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = cputemp_label[channel];
+ return 0;
+}
+
+static int cputemp_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+ int rc, core_index;
+
+ if (channel >= CPUTEMP_CHANNEL_NUMS ||
+ !(priv->temp_config[channel] & BIT(attr)))
+ return -EOPNOTSUPP;
+
+ rc = get_temp_targets(priv);
+ if (rc)
+ return rc;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ switch (channel) {
+ case channel_die:
+ rc = get_die_temp(priv);
+ if (rc)
+ break;
+
+ *val = priv->temp.die.value;
+ break;
+ case channel_tcontrol:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case channel_tthrottle:
+ *val = priv->temp.tthrottle.value;
+ break;
+ case channel_tjmax:
+ *val = priv->temp.tjmax.value;
+ break;
+ default:
+ core_index = channel - DEFAULT_CHANNEL_NUMS;
+ rc = get_core_temp(priv, core_index);
+ if (rc)
+ break;
+
+ *val = priv->temp.core[core_index].value;
+ break;
+ }
+ break;
+ case hwmon_temp_max:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case hwmon_temp_crit:
+ *val = priv->temp.tjmax.value;
+ break;
+ case hwmon_temp_crit_hyst:
+ *val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
+ break;
+ default:
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ return rc;
+}
+
+static umode_t cputemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_cputemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr))
+ if (channel < DEFAULT_CHANNEL_NUMS ||
+ (channel >= DEFAULT_CHANNEL_NUMS &&
+ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops cputemp_ops = {
+ .is_visible = cputemp_is_visible,
+ .read_string = cputemp_read_string,
+ .read = cputemp_read,
+};
+
+static int check_resolved_cores(struct peci_cputemp *priv)
+{
+ struct peci_rd_pci_cfg_local_msg msg;
+ int rc;
+
+ /* Get the RESOLVED_CORES register value */
+ msg.addr = priv->addr;
+ msg.bus = REG_RESOLVED_CORES_BUS;
+ msg.device = REG_RESOLVED_CORES_DEVICE;
+ msg.function = REG_RESOLVED_CORES_FUNCTION;
+ msg.reg = REG_RESOLVED_CORES_OFFSET;
+ msg.rx_len = 4;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
+ if (rc)
+ return rc;
+
+ priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
+ if (!priv->core_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask);
+ return 0;
+}
+
+static int create_core_temp_info(struct peci_cputemp *priv)
+{
+ int rc, i;
+
+ rc = check_resolved_cores(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < priv->gen_info->core_max; i++)
+ if (priv->core_mask & BIT(i))
+ while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx)
+ priv->temp_config[priv->config_idx++] =
+ config_table[channel_core];
+
+ return 0;
+}
+
+static int peci_cputemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_cputemp *priv;
+ struct device *hwmon_dev;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_cputemp.cpu%d", mfd->cpu_no);
+
+ priv->temp_config[priv->config_idx++] = config_table[channel_die];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tjmax];
+
+ rc = create_core_temp_info(priv);
+ if (rc)
+ dev_dbg(dev, "Skipped creating core temp info\n");
+
+ priv->chip.ops = &cputemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_cputemp_of_table[] = {
+ { .compatible = "intel,peci-cputemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_cputemp_of_table);
+#endif
+
+static const struct platform_device_id peci_cputemp_ids[] = {
+ { .name = "peci-cputemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_cputemp_ids);
+
+static struct platform_driver peci_cputemp_driver = {
+ .probe = peci_cputemp_probe,
+ .id_table = peci_cputemp_ids,
+ .driver = {
+ .name = "peci-cputemp",
+ .of_match_table = of_match_ptr(peci_cputemp_of_table),
+ },
+};
+module_platform_driver(peci_cputemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI cputemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 10/12] hwmon: Add PECI cputemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David S . Miller,
Mauro Carvalho Chehab, Andrew Morton, Randy Dunlap,
Philippe Ombredanne, Vinod Koul, Stephen Boyd, David Kershner,
Uwe Kleine-Konig, Sagar Dharia, Johan Hovold, Thomas Gleixner,
Juergen Gross, Cyrille Pitchen
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, Alan Cox,
Andy Shevchenko, Jason M Biils, Miguel Ojeda, Andrew Lunn,
Stef van Os
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI cputemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-cputemp.c | 401 +++++++++++++++++++++++++++++++++++
3 files changed, 416 insertions(+)
create mode 100644 drivers/hwmon/peci-cputemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 81da17a42dc9..f08b4a670ac5 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1306,6 +1306,20 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+config SENSORS_PECI_CPUTEMP
+ tristate "PECI CPU temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI
+ cputemp driver which provides Digital Thermal Sensor (DTS) thermal
+ readings of the CPU package and CPU cores that are accessible using
+ the PECI Client Command Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-cputemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-cputemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 93f7f41ea4ad..13ebde089ad5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
new file mode 100644
index 000000000000..d92b31678876
--- /dev/null
+++ b/drivers/hwmon/peci-cputemp.c
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_CHANNEL_NUMS 4
+#define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX
+#define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS)
+
+/* The RESOLVED_CORES register in PCU of a client CPU */
+#define REG_RESOLVED_CORES_BUS 1
+#define REG_RESOLVED_CORES_DEVICE 30
+#define REG_RESOLVED_CORES_FUNCTION 3
+#define REG_RESOLVED_CORES_OFFSET 0xB4
+
+struct temp_group {
+ struct temp_data die;
+ struct temp_data tcontrol;
+ struct temp_data tthrottle;
+ struct temp_data tjmax;
+ struct temp_data core[CORETEMP_CHANNEL_NUMS];
+};
+
+struct peci_cputemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct temp_group temp;
+ u32 core_mask;
+ u32 temp_config[CPUTEMP_CHANNEL_NUMS + 1];
+ uint config_idx;
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+enum cputemp_channels {
+ channel_die,
+ channel_tcontrol,
+ channel_tthrottle,
+ channel_tjmax,
+ channel_core,
+};
+
+static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+ /* Die temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+
+ /* Tcontrol temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+
+ /* Tthrottle temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Tjmax temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Core temperature - for all core channels */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+};
+
+static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = {
+ "Die",
+ "Tcontrol",
+ "Tthrottle",
+ "Tjmax",
+ "Core 0", "Core 1", "Core 2", "Core 3",
+ "Core 4", "Core 5", "Core 6", "Core 7",
+ "Core 8", "Core 9", "Core 10", "Core 11",
+ "Core 12", "Core 13", "Core 14", "Core 15",
+ "Core 16", "Core 17", "Core 18", "Core 19",
+ "Core 20", "Core 21", "Core 22", "Core 23",
+};
+
+static s32 ten_dot_six_to_millidegree(s32 val)
+{
+ return ((val ^ 0x8000) - 0x8000) * 1000 / 64;
+}
+
+static int get_temp_targets(struct peci_cputemp *priv)
+{
+ s32 tthrottle_offset;
+ s32 tcontrol_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ /**
+ * Just use only the tcontrol marker to determine if target values need
+ * update.
+ */
+ if (!peci_temp_need_update(&priv->temp.tcontrol))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_TEMP_TARGET,
+ 0, pkg_cfg);
+ if (rc)
+ return rc;
+
+ priv->temp.tjmax.value = pkg_cfg[2] * 1000;
+
+ tcontrol_margin = pkg_cfg[1];
+ tcontrol_margin = ((tcontrol_margin ^ 0x80) - 0x80) * 1000;
+ priv->temp.tcontrol.value = priv->temp.tjmax.value - tcontrol_margin;
+
+ tthrottle_offset = (pkg_cfg[3] & 0x2f) * 1000;
+ priv->temp.tthrottle.value = priv->temp.tjmax.value - tthrottle_offset;
+
+ peci_temp_mark_updated(&priv->temp.tcontrol);
+
+ return 0;
+}
+
+static int get_die_temp(struct peci_cputemp *priv)
+{
+ struct peci_get_temp_msg msg;
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.die))
+ return 0;
+
+ msg.addr = priv->addr;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_GET_TEMP, &msg);
+ if (rc)
+ return rc;
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.die.value = priv->temp.tjmax.value +
+ (msg.temp_raw * 1000 / 64);
+
+ peci_temp_mark_updated(&priv->temp.die);
+
+ return 0;
+}
+
+static int get_core_temp(struct peci_cputemp *priv, int core_index)
+{
+ s32 core_dts_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.core[core_index]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_PER_CORE_DTS_TEMP,
+ core_index, pkg_cfg);
+ if (rc)
+ return rc;
+
+ core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg);
+
+ /**
+ * Processors return a value of the core DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ * Error codes:
+ * 0x8000: General sensor error
+ * 0x8001: Reserved
+ * 0x8002: Underflow on reading value
+ * 0x8003-0x81ff: Reserved
+ */
+ if (core_dts_margin >= 0x8000 && core_dts_margin <= 0x81ff)
+ return -EIO;
+
+ core_dts_margin = ten_dot_six_to_millidegree(core_dts_margin);
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.core[core_index].value = priv->temp.tjmax.value +
+ core_dts_margin;
+
+ peci_temp_mark_updated(&priv->temp.core[core_index]);
+
+ return 0;
+}
+
+static int cputemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = cputemp_label[channel];
+ return 0;
+}
+
+static int cputemp_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+ int rc, core_index;
+
+ if (channel >= CPUTEMP_CHANNEL_NUMS ||
+ !(priv->temp_config[channel] & BIT(attr)))
+ return -EOPNOTSUPP;
+
+ rc = get_temp_targets(priv);
+ if (rc)
+ return rc;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ switch (channel) {
+ case channel_die:
+ rc = get_die_temp(priv);
+ if (rc)
+ break;
+
+ *val = priv->temp.die.value;
+ break;
+ case channel_tcontrol:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case channel_tthrottle:
+ *val = priv->temp.tthrottle.value;
+ break;
+ case channel_tjmax:
+ *val = priv->temp.tjmax.value;
+ break;
+ default:
+ core_index = channel - DEFAULT_CHANNEL_NUMS;
+ rc = get_core_temp(priv, core_index);
+ if (rc)
+ break;
+
+ *val = priv->temp.core[core_index].value;
+ break;
+ }
+ break;
+ case hwmon_temp_max:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case hwmon_temp_crit:
+ *val = priv->temp.tjmax.value;
+ break;
+ case hwmon_temp_crit_hyst:
+ *val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
+ break;
+ default:
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ return rc;
+}
+
+static umode_t cputemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_cputemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr))
+ if (channel < DEFAULT_CHANNEL_NUMS ||
+ (channel >= DEFAULT_CHANNEL_NUMS &&
+ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops cputemp_ops = {
+ .is_visible = cputemp_is_visible,
+ .read_string = cputemp_read_string,
+ .read = cputemp_read,
+};
+
+static int check_resolved_cores(struct peci_cputemp *priv)
+{
+ struct peci_rd_pci_cfg_local_msg msg;
+ int rc;
+
+ /* Get the RESOLVED_CORES register value */
+ msg.addr = priv->addr;
+ msg.bus = REG_RESOLVED_CORES_BUS;
+ msg.device = REG_RESOLVED_CORES_DEVICE;
+ msg.function = REG_RESOLVED_CORES_FUNCTION;
+ msg.reg = REG_RESOLVED_CORES_OFFSET;
+ msg.rx_len = 4;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
+ if (rc)
+ return rc;
+
+ priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
+ if (!priv->core_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask);
+ return 0;
+}
+
+static int create_core_temp_info(struct peci_cputemp *priv)
+{
+ int rc, i;
+
+ rc = check_resolved_cores(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < priv->gen_info->core_max; i++)
+ if (priv->core_mask & BIT(i))
+ while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx)
+ priv->temp_config[priv->config_idx++] =
+ config_table[channel_core];
+
+ return 0;
+}
+
+static int peci_cputemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_cputemp *priv;
+ struct device *hwmon_dev;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_cputemp.cpu%d", mfd->cpu_no);
+
+ priv->temp_config[priv->config_idx++] = config_table[channel_die];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tjmax];
+
+ rc = create_core_temp_info(priv);
+ if (rc)
+ dev_dbg(dev, "Skipped creating core temp info\n");
+
+ priv->chip.ops = &cputemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_cputemp_of_table[] = {
+ { .compatible = "intel,peci-cputemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_cputemp_of_table);
+#endif
+
+static const struct platform_device_id peci_cputemp_ids[] = {
+ { .name = "peci-cputemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_cputemp_ids);
+
+static struct platform_driver peci_cputemp_driver = {
+ .probe = peci_cputemp_probe,
+ .id_table = peci_cputemp_ids,
+ .driver = {
+ .name = "peci-cputemp",
+ .of_match_table = of_match_ptr(peci_cputemp_of_table),
+ },
+};
+module_platform_driver(peci_cputemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI cputemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 10/12] hwmon: Add PECI cputemp driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI cputemp hwmon driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Stef van Os <stef.van.os@prodrive-technologies.com>
---
drivers/hwmon/Kconfig | 14 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci-cputemp.c | 401 +++++++++++++++++++++++++++++++++++
3 files changed, 416 insertions(+)
create mode 100644 drivers/hwmon/peci-cputemp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 81da17a42dc9..f08b4a670ac5 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1306,6 +1306,20 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+config SENSORS_PECI_CPUTEMP
+ tristate "PECI CPU temperature monitoring support"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI
+ cputemp driver which provides Digital Thermal Sensor (DTS) thermal
+ readings of the CPU package and CPU cores that are accessible using
+ the PECI Client Command Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-cputemp for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-cputemp.
+
source drivers/hwmon/pmbus/Kconfig
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 93f7f41ea4ad..13ebde089ad5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
new file mode 100644
index 000000000000..d92b31678876
--- /dev/null
+++ b/drivers/hwmon/peci-cputemp.c
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_CHANNEL_NUMS 4
+#define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX
+#define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS)
+
+/* The RESOLVED_CORES register in PCU of a client CPU */
+#define REG_RESOLVED_CORES_BUS 1
+#define REG_RESOLVED_CORES_DEVICE 30
+#define REG_RESOLVED_CORES_FUNCTION 3
+#define REG_RESOLVED_CORES_OFFSET 0xB4
+
+struct temp_group {
+ struct temp_data die;
+ struct temp_data tcontrol;
+ struct temp_data tthrottle;
+ struct temp_data tjmax;
+ struct temp_data core[CORETEMP_CHANNEL_NUMS];
+};
+
+struct peci_cputemp {
+ struct peci_mfd *mfd;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ const struct cpu_gen_info *gen_info;
+ struct temp_group temp;
+ u32 core_mask;
+ u32 temp_config[CPUTEMP_CHANNEL_NUMS + 1];
+ uint config_idx;
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+};
+
+enum cputemp_channels {
+ channel_die,
+ channel_tcontrol,
+ channel_tthrottle,
+ channel_tjmax,
+ channel_core,
+};
+
+static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+ /* Die temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+
+ /* Tcontrol temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+
+ /* Tthrottle temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Tjmax temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Core temperature - for all core channels */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+};
+
+static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = {
+ "Die",
+ "Tcontrol",
+ "Tthrottle",
+ "Tjmax",
+ "Core 0", "Core 1", "Core 2", "Core 3",
+ "Core 4", "Core 5", "Core 6", "Core 7",
+ "Core 8", "Core 9", "Core 10", "Core 11",
+ "Core 12", "Core 13", "Core 14", "Core 15",
+ "Core 16", "Core 17", "Core 18", "Core 19",
+ "Core 20", "Core 21", "Core 22", "Core 23",
+};
+
+static s32 ten_dot_six_to_millidegree(s32 val)
+{
+ return ((val ^ 0x8000) - 0x8000) * 1000 / 64;
+}
+
+static int get_temp_targets(struct peci_cputemp *priv)
+{
+ s32 tthrottle_offset;
+ s32 tcontrol_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ /**
+ * Just use only the tcontrol marker to determine if target values need
+ * update.
+ */
+ if (!peci_temp_need_update(&priv->temp.tcontrol))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_TEMP_TARGET,
+ 0, pkg_cfg);
+ if (rc)
+ return rc;
+
+ priv->temp.tjmax.value = pkg_cfg[2] * 1000;
+
+ tcontrol_margin = pkg_cfg[1];
+ tcontrol_margin = ((tcontrol_margin ^ 0x80) - 0x80) * 1000;
+ priv->temp.tcontrol.value = priv->temp.tjmax.value - tcontrol_margin;
+
+ tthrottle_offset = (pkg_cfg[3] & 0x2f) * 1000;
+ priv->temp.tthrottle.value = priv->temp.tjmax.value - tthrottle_offset;
+
+ peci_temp_mark_updated(&priv->temp.tcontrol);
+
+ return 0;
+}
+
+static int get_die_temp(struct peci_cputemp *priv)
+{
+ struct peci_get_temp_msg msg;
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.die))
+ return 0;
+
+ msg.addr = priv->addr;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_GET_TEMP, &msg);
+ if (rc)
+ return rc;
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.die.value = priv->temp.tjmax.value +
+ (msg.temp_raw * 1000 / 64);
+
+ peci_temp_mark_updated(&priv->temp.die);
+
+ return 0;
+}
+
+static int get_core_temp(struct peci_cputemp *priv, int core_index)
+{
+ s32 core_dts_margin;
+ u8 pkg_cfg[4];
+ int rc;
+
+ if (!peci_temp_need_update(&priv->temp.core[core_index]))
+ return 0;
+
+ rc = peci_client_rd_pkg_cfg_cmd(priv->mfd, MBX_INDEX_PER_CORE_DTS_TEMP,
+ core_index, pkg_cfg);
+ if (rc)
+ return rc;
+
+ core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg);
+
+ /**
+ * Processors return a value of the core DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ * Error codes:
+ * 0x8000: General sensor error
+ * 0x8001: Reserved
+ * 0x8002: Underflow on reading value
+ * 0x8003-0x81ff: Reserved
+ */
+ if (core_dts_margin >= 0x8000 && core_dts_margin <= 0x81ff)
+ return -EIO;
+
+ core_dts_margin = ten_dot_six_to_millidegree(core_dts_margin);
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.core[core_index].value = priv->temp.tjmax.value +
+ core_dts_margin;
+
+ peci_temp_mark_updated(&priv->temp.core[core_index]);
+
+ return 0;
+}
+
+static int cputemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = cputemp_label[channel];
+ return 0;
+}
+
+static int cputemp_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+ int rc, core_index;
+
+ if (channel >= CPUTEMP_CHANNEL_NUMS ||
+ !(priv->temp_config[channel] & BIT(attr)))
+ return -EOPNOTSUPP;
+
+ rc = get_temp_targets(priv);
+ if (rc)
+ return rc;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ switch (channel) {
+ case channel_die:
+ rc = get_die_temp(priv);
+ if (rc)
+ break;
+
+ *val = priv->temp.die.value;
+ break;
+ case channel_tcontrol:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case channel_tthrottle:
+ *val = priv->temp.tthrottle.value;
+ break;
+ case channel_tjmax:
+ *val = priv->temp.tjmax.value;
+ break;
+ default:
+ core_index = channel - DEFAULT_CHANNEL_NUMS;
+ rc = get_core_temp(priv, core_index);
+ if (rc)
+ break;
+
+ *val = priv->temp.core[core_index].value;
+ break;
+ }
+ break;
+ case hwmon_temp_max:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case hwmon_temp_crit:
+ *val = priv->temp.tjmax.value;
+ break;
+ case hwmon_temp_crit_hyst:
+ *val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
+ break;
+ default:
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ return rc;
+}
+
+static umode_t cputemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_cputemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr))
+ if (channel < DEFAULT_CHANNEL_NUMS ||
+ (channel >= DEFAULT_CHANNEL_NUMS &&
+ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops cputemp_ops = {
+ .is_visible = cputemp_is_visible,
+ .read_string = cputemp_read_string,
+ .read = cputemp_read,
+};
+
+static int check_resolved_cores(struct peci_cputemp *priv)
+{
+ struct peci_rd_pci_cfg_local_msg msg;
+ int rc;
+
+ /* Get the RESOLVED_CORES register value */
+ msg.addr = priv->addr;
+ msg.bus = REG_RESOLVED_CORES_BUS;
+ msg.device = REG_RESOLVED_CORES_DEVICE;
+ msg.function = REG_RESOLVED_CORES_FUNCTION;
+ msg.reg = REG_RESOLVED_CORES_OFFSET;
+ msg.rx_len = 4;
+
+ rc = peci_client_command(priv->mfd, PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
+ if (rc)
+ return rc;
+
+ priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
+ if (!priv->core_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask);
+ return 0;
+}
+
+static int create_core_temp_info(struct peci_cputemp *priv)
+{
+ int rc, i;
+
+ rc = check_resolved_cores(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < priv->gen_info->core_max; i++)
+ if (priv->core_mask & BIT(i))
+ while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx)
+ priv->temp_config[priv->config_idx++] =
+ config_table[channel_core];
+
+ return 0;
+}
+
+static int peci_cputemp_probe(struct platform_device *pdev)
+{
+ struct peci_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_cputemp *priv;
+ struct device *hwmon_dev;
+ int rc;
+
+ if ((mfd->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mfd = mfd;
+ priv->dev = dev;
+ priv->addr = mfd->addr;
+ priv->gen_info = mfd->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_cputemp.cpu%d", mfd->cpu_no);
+
+ priv->temp_config[priv->config_idx++] = config_table[channel_die];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tjmax];
+
+ rc = create_core_temp_info(priv);
+ if (rc)
+ dev_dbg(dev, "Skipped creating core temp info\n");
+
+ priv->chip.ops = &cputemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id peci_cputemp_of_table[] = {
+ { .compatible = "intel,peci-cputemp" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_cputemp_of_table);
+#endif
+
+static const struct platform_device_id peci_cputemp_ids[] = {
+ { .name = "peci-cputemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_cputemp_ids);
+
+static struct platform_driver peci_cputemp_driver = {
+ .probe = peci_cputemp_probe,
+ .id_table = peci_cputemp_ids,
+ .driver = {
+ .name = "peci-cputemp",
+ .of_match_table = of_match_ptr(peci_cputemp_of_table),
+ },
+};
+module_platform_driver(peci_cputemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI cputemp driver");
+MODULE_LICENSE("GPL v2");
--
2.18.0
^ permalink raw reply related
* [PATCH v7 09/12] Documentation: hwmon: Add documents for PECI hwmon client drivers
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, Jason M Biils
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds hwmon documents for PECI cputemp and dimmtemp drivers.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
---
Documentation/hwmon/peci-cputemp | 78 +++++++++++++++++++++++++++++++
Documentation/hwmon/peci-dimmtemp | 50 ++++++++++++++++++++
2 files changed, 128 insertions(+)
create mode 100644 Documentation/hwmon/peci-cputemp
create mode 100644 Documentation/hwmon/peci-dimmtemp
diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp
new file mode 100644
index 000000000000..821a9258f2e6
--- /dev/null
+++ b/Documentation/hwmon/peci-cputemp
@@ -0,0 +1,78 @@
+Kernel driver peci-cputemp
+==========================
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of the CPU package and CPU cores that are
+accessible using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+sysfs attributes
+----------------
+
+temp1_label "Die"
+temp1_input Provides current die temperature of the CPU package.
+temp1_max Provides thermal control temperature of the CPU package
+ which is also known as Tcontrol.
+temp1_crit Provides shutdown temperature of the CPU package which
+ is also known as the maximum processor junction
+ temperature, Tjmax or Tprochot.
+temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the CPU package.
+
+temp2_label "Tcontrol"
+temp2_input Provides current Tcontrol temperature of the CPU
+ package which is also known as Fan Temperature target.
+ Indicates the relative value from thermal monitor trip
+ temperature at which fans should be engaged.
+temp2_crit Provides Tcontrol critical value of the CPU package
+ which is same to Tjmax.
+
+temp3_label "Tthrottle"
+temp3_input Provides current Tthrottle temperature of the CPU
+ package. Used for throttling temperature. If this value
+ is allowed and lower than Tjmax - the throttle will
+ occur and reported at lower than Tjmax.
+
+temp4_label "Tjmax"
+temp4_input Provides the maximum junction temperature, Tjmax of the
+ CPU package.
+
+temp[5-*]_label Provides string "Core X", where X is resolved core
+ number.
+temp[5-*]_input Provides current temperature of each core.
+temp[5-*]_max Provides thermal control temperature of the core.
+temp[5-*]_crit Provides shutdown temperature of the core.
+temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the core.
diff --git a/Documentation/hwmon/peci-dimmtemp b/Documentation/hwmon/peci-dimmtemp
new file mode 100644
index 000000000000..c54f2526188c
--- /dev/null
+++ b/Documentation/hwmon/peci-dimmtemp
@@ -0,0 +1,50 @@
+Kernel driver peci-dimmtemp
+===========================
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of DIMM components that are accessible
+using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+sysfs attributes
+----------------
+
+temp[N]_label Provides string "DIMM CI", where C is DIMM channel and
+ I is DIMM index of the populated DIMM.
+temp[N]_input Provides current temperature of the populated DIMM.
+
+Note:
+ DIMM temperature attributes will appear when the client CPU's BIOS
+ completes memory training and testing.
--
2.18.0
^ permalink raw reply related
* [PATCH v7 09/12] Documentation: hwmon: Add documents for PECI hwmon client drivers
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds hwmon documents for PECI cputemp and dimmtemp drivers.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
---
Documentation/hwmon/peci-cputemp | 78 +++++++++++++++++++++++++++++++
Documentation/hwmon/peci-dimmtemp | 50 ++++++++++++++++++++
2 files changed, 128 insertions(+)
create mode 100644 Documentation/hwmon/peci-cputemp
create mode 100644 Documentation/hwmon/peci-dimmtemp
diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp
new file mode 100644
index 000000000000..821a9258f2e6
--- /dev/null
+++ b/Documentation/hwmon/peci-cputemp
@@ -0,0 +1,78 @@
+Kernel driver peci-cputemp
+==========================
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of the CPU package and CPU cores that are
+accessible using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+sysfs attributes
+----------------
+
+temp1_label "Die"
+temp1_input Provides current die temperature of the CPU package.
+temp1_max Provides thermal control temperature of the CPU package
+ which is also known as Tcontrol.
+temp1_crit Provides shutdown temperature of the CPU package which
+ is also known as the maximum processor junction
+ temperature, Tjmax or Tprochot.
+temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the CPU package.
+
+temp2_label "Tcontrol"
+temp2_input Provides current Tcontrol temperature of the CPU
+ package which is also known as Fan Temperature target.
+ Indicates the relative value from thermal monitor trip
+ temperature at which fans should be engaged.
+temp2_crit Provides Tcontrol critical value of the CPU package
+ which is same to Tjmax.
+
+temp3_label "Tthrottle"
+temp3_input Provides current Tthrottle temperature of the CPU
+ package. Used for throttling temperature. If this value
+ is allowed and lower than Tjmax - the throttle will
+ occur and reported at lower than Tjmax.
+
+temp4_label "Tjmax"
+temp4_input Provides the maximum junction temperature, Tjmax of the
+ CPU package.
+
+temp[5-*]_label Provides string "Core X", where X is resolved core
+ number.
+temp[5-*]_input Provides current temperature of each core.
+temp[5-*]_max Provides thermal control temperature of the core.
+temp[5-*]_crit Provides shutdown temperature of the core.
+temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the core.
diff --git a/Documentation/hwmon/peci-dimmtemp b/Documentation/hwmon/peci-dimmtemp
new file mode 100644
index 000000000000..c54f2526188c
--- /dev/null
+++ b/Documentation/hwmon/peci-dimmtemp
@@ -0,0 +1,50 @@
+Kernel driver peci-dimmtemp
+===========================
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of DIMM components that are accessible
+using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+sysfs attributes
+----------------
+
+temp[N]_label Provides string "DIMM CI", where C is DIMM channel and
+ I is DIMM index of the populated DIMM.
+temp[N]_input Provides current temperature of the populated DIMM.
+
+Note:
+ DIMM temperature attributes will appear when the client CPU's BIOS
+ completes memory training and testing.
--
2.18.0
^ permalink raw reply related
* [PATCH v7 09/12] Documentation: hwmon: Add documents for PECI hwmon client drivers
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds hwmon documents for PECI cputemp and dimmtemp drivers.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Reviewed-by: Haiyue Wang <haiyue.wang@linux.intel.com>
Reviewed-by: James Feist <james.feist@linux.intel.com>
Reviewed-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: Jean Delvare <jdelvare@suse.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
---
Documentation/hwmon/peci-cputemp | 78 +++++++++++++++++++++++++++++++
Documentation/hwmon/peci-dimmtemp | 50 ++++++++++++++++++++
2 files changed, 128 insertions(+)
create mode 100644 Documentation/hwmon/peci-cputemp
create mode 100644 Documentation/hwmon/peci-dimmtemp
diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp
new file mode 100644
index 000000000000..821a9258f2e6
--- /dev/null
+++ b/Documentation/hwmon/peci-cputemp
@@ -0,0 +1,78 @@
+Kernel driver peci-cputemp
+==========================
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of the CPU package and CPU cores that are
+accessible using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+sysfs attributes
+----------------
+
+temp1_label "Die"
+temp1_input Provides current die temperature of the CPU package.
+temp1_max Provides thermal control temperature of the CPU package
+ which is also known as Tcontrol.
+temp1_crit Provides shutdown temperature of the CPU package which
+ is also known as the maximum processor junction
+ temperature, Tjmax or Tprochot.
+temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the CPU package.
+
+temp2_label "Tcontrol"
+temp2_input Provides current Tcontrol temperature of the CPU
+ package which is also known as Fan Temperature target.
+ Indicates the relative value from thermal monitor trip
+ temperature at which fans should be engaged.
+temp2_crit Provides Tcontrol critical value of the CPU package
+ which is same to Tjmax.
+
+temp3_label "Tthrottle"
+temp3_input Provides current Tthrottle temperature of the CPU
+ package. Used for throttling temperature. If this value
+ is allowed and lower than Tjmax - the throttle will
+ occur and reported at lower than Tjmax.
+
+temp4_label "Tjmax"
+temp4_input Provides the maximum junction temperature, Tjmax of the
+ CPU package.
+
+temp[5-*]_label Provides string "Core X", where X is resolved core
+ number.
+temp[5-*]_input Provides current temperature of each core.
+temp[5-*]_max Provides thermal control temperature of the core.
+temp[5-*]_crit Provides shutdown temperature of the core.
+temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the core.
diff --git a/Documentation/hwmon/peci-dimmtemp b/Documentation/hwmon/peci-dimmtemp
new file mode 100644
index 000000000000..c54f2526188c
--- /dev/null
+++ b/Documentation/hwmon/peci-dimmtemp
@@ -0,0 +1,50 @@
+Kernel driver peci-dimmtemp
+===========================
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of DIMM components that are accessible
+using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+sysfs attributes
+----------------
+
+temp[N]_label Provides string "DIMM CI", where C is DIMM channel and
+ I is DIMM index of the populated DIMM.
+temp[N]_input Provides current temperature of the populated DIMM.
+
+Note:
+ DIMM temperature attributes will appear when the client CPU's BIOS
+ completes memory training and testing.
--
2.18.0
^ permalink raw reply related
* [PATCH v7 08/12] mfd: intel-peci-client: Add PECI client MFD driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, James Feist,
Jason M Biils, Vernon Mauery
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI client MFD driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: James Feist <james.feist@linux.intel.com>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Vernon Mauery <vernon.mauery@linux.intel.com>
---
drivers/mfd/Kconfig | 14 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/intel-peci-client.c | 182 ++++++++++++++++++++++++++
include/linux/mfd/intel-peci-client.h | 81 ++++++++++++
4 files changed, 278 insertions(+)
create mode 100644 drivers/mfd/intel-peci-client.c
create mode 100644 include/linux/mfd/intel-peci-client.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f3fa516011ec..e38b591479d4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -595,6 +595,20 @@ config MFD_INTEL_MSIC
Passage) chip. This chip embeds audio, battery, GPIO, etc.
devices used in Intel Medfield platforms.
+config MFD_INTEL_PECI_CLIENT
+ bool "Intel PECI client"
+ depends on (PECI || COMPILE_TEST)
+ select MFD_CORE
+ help
+ If you say yes to this option, support will be included for the
+ multi-funtional Intel PECI (Platform Environment Control Interface)
+ client. PECI is a one-wire bus interface that provides a communication
+ channel from PECI clients in Intel processors and chipset components
+ to external monitoring or control devices.
+
+ Additional drivers must be enabled in order to use the functionality
+ of the device.
+
config MFD_IPAQ_MICRO
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2852a6042ecf..29e2cacc58bd 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -203,6 +203,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o
obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_INTEL_PECI_CLIENT) += intel-peci-client.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
new file mode 100644
index 000000000000..d7702cf1ea50
--- /dev/null
+++ b/drivers/mfd/intel-peci-client.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/of_device.h>
+
+enum cpu_gens {
+ CPU_GEN_HSX = 0, /* Haswell Xeon */
+ CPU_GEN_BRX, /* Broadwell Xeon */
+ CPU_GEN_SKX, /* Skylake Xeon */
+};
+
+static struct mfd_cell peci_functions[] = {
+ {
+ .name = "peci-cputemp",
+ .of_compatible = "intel,peci-cputemp",
+ },
+ {
+ .name = "peci-dimmtemp",
+ .of_compatible = "intel,peci-dimmtemp",
+ },
+};
+
+static const struct cpu_gen_info cpu_gen_info_table[] = {
+ [CPU_GEN_HSX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_HASWELL_X,
+ .core_max = CORE_MAX_ON_HSX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_HSX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_HSX },
+ [CPU_GEN_BRX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_BROADWELL_X,
+ .core_max = CORE_MAX_ON_BDX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_BDX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
+ [CPU_GEN_SKX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_SKYLAKE_X,
+ .core_max = CORE_MAX_ON_SKX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_SKX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKX },
+};
+
+static int peci_client_get_cpu_gen_info(struct peci_mfd *priv)
+{
+ u32 cpu_id;
+ int i, rc;
+
+ rc = peci_get_cpu_id(priv->adapter, priv->addr, &cpu_id);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_gen_info_table); i++) {
+ if (FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id) +
+ FIELD_GET(CPU_ID_EXT_FAMILY_MASK, cpu_id) ==
+ cpu_gen_info_table[i].family &&
+ FIELD_GET(CPU_ID_MODEL_MASK, cpu_id) ==
+ FIELD_GET(LOWER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model) &&
+ FIELD_GET(CPU_ID_EXT_MODEL_MASK, cpu_id) ==
+ FIELD_GET(UPPER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model)) {
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(cpu_gen_info_table))
+ return -ENODEV;
+
+ priv->gen_info = &cpu_gen_info_table[i];
+
+ return 0;
+}
+
+bool peci_temp_need_update(struct temp_data *temp)
+{
+ if (temp->valid &&
+ time_before(jiffies, temp->last_updated + UPDATE_INTERVAL))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(peci_temp_need_update);
+
+void peci_temp_mark_updated(struct temp_data *temp)
+{
+ temp->valid = 1;
+ temp->last_updated = jiffies;
+}
+EXPORT_SYMBOL_GPL(peci_temp_mark_updated);
+
+int peci_client_command(struct peci_mfd *priv, enum peci_cmd cmd, void *vmsg)
+{
+ return peci_command(priv->adapter, cmd, vmsg);
+}
+EXPORT_SYMBOL_GPL(peci_client_command);
+
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *priv, u8 mbx_idx,
+ u16 param, u8 *data)
+{
+ struct peci_rd_pkg_cfg_msg msg;
+ int rc;
+
+ msg.addr = priv->addr;
+ msg.index = mbx_idx;
+ msg.param = param;
+ msg.rx_len = 4;
+
+ rc = peci_command(priv->adapter, PECI_CMD_RD_PKG_CFG, &msg);
+ if (!rc)
+ memcpy(data, msg.pkg_config, 4);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(peci_client_rd_pkg_cfg_cmd);
+
+static int peci_client_probe(struct peci_client *client)
+{
+ struct device *dev = &client->dev;
+ struct peci_mfd *priv;
+ int rc;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->client = client;
+ priv->dev = dev;
+ priv->adapter = client->adapter;
+ priv->addr = client->addr;
+ priv->cpu_no = client->addr - PECI_BASE_ADDR;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_client.cpu%d", priv->cpu_no);
+
+ rc = peci_client_get_cpu_gen_info(priv);
+ if (rc)
+ return rc;
+
+ rc = devm_mfd_add_devices(priv->dev, priv->cpu_no, peci_functions,
+ ARRAY_SIZE(peci_functions), NULL, 0, NULL);
+ if (rc < 0) {
+ dev_err(priv->dev, "devm_mfd_add_devices failed: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id peci_client_of_table[] = {
+ { .compatible = "intel,peci-client" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_client_of_table);
+#endif
+
+static const struct peci_device_id peci_client_ids[] = {
+ { .name = "peci-client", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(peci, peci_client_ids);
+
+static struct peci_driver peci_client_driver = {
+ .probe = peci_client_probe,
+ .id_table = peci_client_ids,
+ .driver = {
+ .name = "peci-client",
+ .of_match_table =
+ of_match_ptr(peci_client_of_table),
+ },
+};
+module_peci_driver(peci_client_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI client MFD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
new file mode 100644
index 000000000000..7ec272cddceb
--- /dev/null
+++ b/include/linux/mfd/intel-peci-client.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef __LINUX_MFD_PECI_CLIENT_H
+#define __LINUX_MFD_PECI_CLIENT_H
+
+#include <linux/peci.h>
+
+#if IS_ENABLED(CONFIG_X86)
+#include <asm/intel-family.h>
+#else
+/**
+ * Architectures other than x86 cannot include the header file so define these
+ * at here. These are needed for detecting type of client x86 CPUs behind a PECI
+ * connection.
+ */
+#define INTEL_FAM6_HASWELL_X 0x3F
+#define INTEL_FAM6_BROADWELL_X 0x4F
+#define INTEL_FAM6_SKYLAKE_X 0x55
+#endif
+
+#define LOWER_NIBBLE_MASK GENMASK(3, 0)
+#define UPPER_NIBBLE_MASK GENMASK(7, 4)
+
+#define CPU_ID_MODEL_MASK GENMASK(7, 4)
+#define CPU_ID_FAMILY_MASK GENMASK(11, 8)
+#define CPU_ID_EXT_MODEL_MASK GENMASK(19, 16)
+#define CPU_ID_EXT_FAMILY_MASK GENMASK(27, 20)
+
+#define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */
+#define CHAN_RANK_MAX_ON_HSX 8 /* Max number of channel ranks on Haswell */
+#define DIMM_IDX_MAX_ON_HSX 3 /* Max DIMM index per channel on Haswell */
+
+#define CORE_MAX_ON_BDX 24 /* Max number of cores on Broadwell */
+#define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */
+#define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */
+
+#define CORE_MAX_ON_SKX 28 /* Max number of cores on Skylake */
+#define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */
+#define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */
+
+#define CORE_NUMS_MAX CORE_MAX_ON_SKX
+#define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX
+#define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX
+#define DIMM_NUMS_MAX (CHAN_RANK_MAX * DIMM_IDX_MAX)
+
+#define TEMP_TYPE_PECI 6 /* Sensor type 6: Intel PECI */
+
+#define UPDATE_INTERVAL HZ
+
+struct temp_data {
+ uint valid;
+ s32 value;
+ ulong last_updated;
+};
+
+struct cpu_gen_info {
+ u16 family;
+ u8 model;
+ uint core_max;
+ uint chan_rank_max;
+ uint dimm_idx_max;
+};
+
+struct peci_mfd {
+ struct peci_client *client;
+ struct device *dev;
+ struct peci_adapter *adapter;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ uint cpu_no;
+ const struct cpu_gen_info *gen_info;
+};
+
+bool peci_temp_need_update(struct temp_data *temp);
+void peci_temp_mark_updated(struct temp_data *temp);
+int peci_client_command(struct peci_mfd *mfd, enum peci_cmd cmd, void *vmsg);
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *mfd, u8 mbx_idx,
+ u16 param, u8 *data);
+
+#endif /* __LINUX_MFD_PECI_CLIENT_H */
--
2.18.0
^ permalink raw reply related
* [PATCH v7 08/12] mfd: intel-peci-client: Add PECI client MFD driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI client MFD driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: James Feist <james.feist@linux.intel.com>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Vernon Mauery <vernon.mauery@linux.intel.com>
---
drivers/mfd/Kconfig | 14 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/intel-peci-client.c | 182 ++++++++++++++++++++++++++
include/linux/mfd/intel-peci-client.h | 81 ++++++++++++
4 files changed, 278 insertions(+)
create mode 100644 drivers/mfd/intel-peci-client.c
create mode 100644 include/linux/mfd/intel-peci-client.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f3fa516011ec..e38b591479d4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -595,6 +595,20 @@ config MFD_INTEL_MSIC
Passage) chip. This chip embeds audio, battery, GPIO, etc.
devices used in Intel Medfield platforms.
+config MFD_INTEL_PECI_CLIENT
+ bool "Intel PECI client"
+ depends on (PECI || COMPILE_TEST)
+ select MFD_CORE
+ help
+ If you say yes to this option, support will be included for the
+ multi-funtional Intel PECI (Platform Environment Control Interface)
+ client. PECI is a one-wire bus interface that provides a communication
+ channel from PECI clients in Intel processors and chipset components
+ to external monitoring or control devices.
+
+ Additional drivers must be enabled in order to use the functionality
+ of the device.
+
config MFD_IPAQ_MICRO
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2852a6042ecf..29e2cacc58bd 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -203,6 +203,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o
obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_INTEL_PECI_CLIENT) += intel-peci-client.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
new file mode 100644
index 000000000000..d7702cf1ea50
--- /dev/null
+++ b/drivers/mfd/intel-peci-client.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/of_device.h>
+
+enum cpu_gens {
+ CPU_GEN_HSX = 0, /* Haswell Xeon */
+ CPU_GEN_BRX, /* Broadwell Xeon */
+ CPU_GEN_SKX, /* Skylake Xeon */
+};
+
+static struct mfd_cell peci_functions[] = {
+ {
+ .name = "peci-cputemp",
+ .of_compatible = "intel,peci-cputemp",
+ },
+ {
+ .name = "peci-dimmtemp",
+ .of_compatible = "intel,peci-dimmtemp",
+ },
+};
+
+static const struct cpu_gen_info cpu_gen_info_table[] = {
+ [CPU_GEN_HSX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_HASWELL_X,
+ .core_max = CORE_MAX_ON_HSX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_HSX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_HSX },
+ [CPU_GEN_BRX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_BROADWELL_X,
+ .core_max = CORE_MAX_ON_BDX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_BDX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
+ [CPU_GEN_SKX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_SKYLAKE_X,
+ .core_max = CORE_MAX_ON_SKX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_SKX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKX },
+};
+
+static int peci_client_get_cpu_gen_info(struct peci_mfd *priv)
+{
+ u32 cpu_id;
+ int i, rc;
+
+ rc = peci_get_cpu_id(priv->adapter, priv->addr, &cpu_id);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_gen_info_table); i++) {
+ if (FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id) +
+ FIELD_GET(CPU_ID_EXT_FAMILY_MASK, cpu_id) ==
+ cpu_gen_info_table[i].family &&
+ FIELD_GET(CPU_ID_MODEL_MASK, cpu_id) ==
+ FIELD_GET(LOWER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model) &&
+ FIELD_GET(CPU_ID_EXT_MODEL_MASK, cpu_id) ==
+ FIELD_GET(UPPER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model)) {
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(cpu_gen_info_table))
+ return -ENODEV;
+
+ priv->gen_info = &cpu_gen_info_table[i];
+
+ return 0;
+}
+
+bool peci_temp_need_update(struct temp_data *temp)
+{
+ if (temp->valid &&
+ time_before(jiffies, temp->last_updated + UPDATE_INTERVAL))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(peci_temp_need_update);
+
+void peci_temp_mark_updated(struct temp_data *temp)
+{
+ temp->valid = 1;
+ temp->last_updated = jiffies;
+}
+EXPORT_SYMBOL_GPL(peci_temp_mark_updated);
+
+int peci_client_command(struct peci_mfd *priv, enum peci_cmd cmd, void *vmsg)
+{
+ return peci_command(priv->adapter, cmd, vmsg);
+}
+EXPORT_SYMBOL_GPL(peci_client_command);
+
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *priv, u8 mbx_idx,
+ u16 param, u8 *data)
+{
+ struct peci_rd_pkg_cfg_msg msg;
+ int rc;
+
+ msg.addr = priv->addr;
+ msg.index = mbx_idx;
+ msg.param = param;
+ msg.rx_len = 4;
+
+ rc = peci_command(priv->adapter, PECI_CMD_RD_PKG_CFG, &msg);
+ if (!rc)
+ memcpy(data, msg.pkg_config, 4);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(peci_client_rd_pkg_cfg_cmd);
+
+static int peci_client_probe(struct peci_client *client)
+{
+ struct device *dev = &client->dev;
+ struct peci_mfd *priv;
+ int rc;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->client = client;
+ priv->dev = dev;
+ priv->adapter = client->adapter;
+ priv->addr = client->addr;
+ priv->cpu_no = client->addr - PECI_BASE_ADDR;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_client.cpu%d", priv->cpu_no);
+
+ rc = peci_client_get_cpu_gen_info(priv);
+ if (rc)
+ return rc;
+
+ rc = devm_mfd_add_devices(priv->dev, priv->cpu_no, peci_functions,
+ ARRAY_SIZE(peci_functions), NULL, 0, NULL);
+ if (rc < 0) {
+ dev_err(priv->dev, "devm_mfd_add_devices failed: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id peci_client_of_table[] = {
+ { .compatible = "intel,peci-client" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_client_of_table);
+#endif
+
+static const struct peci_device_id peci_client_ids[] = {
+ { .name = "peci-client", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(peci, peci_client_ids);
+
+static struct peci_driver peci_client_driver = {
+ .probe = peci_client_probe,
+ .id_table = peci_client_ids,
+ .driver = {
+ .name = "peci-client",
+ .of_match_table =
+ of_match_ptr(peci_client_of_table),
+ },
+};
+module_peci_driver(peci_client_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI client MFD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
new file mode 100644
index 000000000000..7ec272cddceb
--- /dev/null
+++ b/include/linux/mfd/intel-peci-client.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef __LINUX_MFD_PECI_CLIENT_H
+#define __LINUX_MFD_PECI_CLIENT_H
+
+#include <linux/peci.h>
+
+#if IS_ENABLED(CONFIG_X86)
+#include <asm/intel-family.h>
+#else
+/**
+ * Architectures other than x86 cannot include the header file so define these
+ * at here. These are needed for detecting type of client x86 CPUs behind a PECI
+ * connection.
+ */
+#define INTEL_FAM6_HASWELL_X 0x3F
+#define INTEL_FAM6_BROADWELL_X 0x4F
+#define INTEL_FAM6_SKYLAKE_X 0x55
+#endif
+
+#define LOWER_NIBBLE_MASK GENMASK(3, 0)
+#define UPPER_NIBBLE_MASK GENMASK(7, 4)
+
+#define CPU_ID_MODEL_MASK GENMASK(7, 4)
+#define CPU_ID_FAMILY_MASK GENMASK(11, 8)
+#define CPU_ID_EXT_MODEL_MASK GENMASK(19, 16)
+#define CPU_ID_EXT_FAMILY_MASK GENMASK(27, 20)
+
+#define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */
+#define CHAN_RANK_MAX_ON_HSX 8 /* Max number of channel ranks on Haswell */
+#define DIMM_IDX_MAX_ON_HSX 3 /* Max DIMM index per channel on Haswell */
+
+#define CORE_MAX_ON_BDX 24 /* Max number of cores on Broadwell */
+#define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */
+#define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */
+
+#define CORE_MAX_ON_SKX 28 /* Max number of cores on Skylake */
+#define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */
+#define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */
+
+#define CORE_NUMS_MAX CORE_MAX_ON_SKX
+#define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX
+#define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX
+#define DIMM_NUMS_MAX (CHAN_RANK_MAX * DIMM_IDX_MAX)
+
+#define TEMP_TYPE_PECI 6 /* Sensor type 6: Intel PECI */
+
+#define UPDATE_INTERVAL HZ
+
+struct temp_data {
+ uint valid;
+ s32 value;
+ ulong last_updated;
+};
+
+struct cpu_gen_info {
+ u16 family;
+ u8 model;
+ uint core_max;
+ uint chan_rank_max;
+ uint dimm_idx_max;
+};
+
+struct peci_mfd {
+ struct peci_client *client;
+ struct device *dev;
+ struct peci_adapter *adapter;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ uint cpu_no;
+ const struct cpu_gen_info *gen_info;
+};
+
+bool peci_temp_need_update(struct temp_data *temp);
+void peci_temp_mark_updated(struct temp_data *temp);
+int peci_client_command(struct peci_mfd *mfd, enum peci_cmd cmd, void *vmsg);
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *mfd, u8 mbx_idx,
+ u16 param, u8 *data);
+
+#endif /* __LINUX_MFD_PECI_CLIENT_H */
--
2.18.0
^ permalink raw reply related
* [PATCH v7 08/12] mfd: intel-peci-client: Add PECI client MFD driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David S . Miller,
Mauro Carvalho Chehab, Andrew Morton, Randy Dunlap,
Philippe Ombredanne, Vinod Koul, Stephen Boyd, David Kershner,
Uwe Kleine-Konig, Sagar Dharia, Johan Hovold, Thomas Gleixner,
Juergen Gross, Cyrille Pitchen
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, James Feist,
Jason M Biils, Vernon Mauery
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI client MFD driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: James Feist <james.feist@linux.intel.com>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Vernon Mauery <vernon.mauery@linux.intel.com>
---
drivers/mfd/Kconfig | 14 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/intel-peci-client.c | 182 ++++++++++++++++++++++++++
include/linux/mfd/intel-peci-client.h | 81 ++++++++++++
4 files changed, 278 insertions(+)
create mode 100644 drivers/mfd/intel-peci-client.c
create mode 100644 include/linux/mfd/intel-peci-client.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f3fa516011ec..e38b591479d4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -595,6 +595,20 @@ config MFD_INTEL_MSIC
Passage) chip. This chip embeds audio, battery, GPIO, etc.
devices used in Intel Medfield platforms.
+config MFD_INTEL_PECI_CLIENT
+ bool "Intel PECI client"
+ depends on (PECI || COMPILE_TEST)
+ select MFD_CORE
+ help
+ If you say yes to this option, support will be included for the
+ multi-funtional Intel PECI (Platform Environment Control Interface)
+ client. PECI is a one-wire bus interface that provides a communication
+ channel from PECI clients in Intel processors and chipset components
+ to external monitoring or control devices.
+
+ Additional drivers must be enabled in order to use the functionality
+ of the device.
+
config MFD_IPAQ_MICRO
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2852a6042ecf..29e2cacc58bd 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -203,6 +203,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o
obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_INTEL_PECI_CLIENT) += intel-peci-client.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
new file mode 100644
index 000000000000..d7702cf1ea50
--- /dev/null
+++ b/drivers/mfd/intel-peci-client.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/of_device.h>
+
+enum cpu_gens {
+ CPU_GEN_HSX = 0, /* Haswell Xeon */
+ CPU_GEN_BRX, /* Broadwell Xeon */
+ CPU_GEN_SKX, /* Skylake Xeon */
+};
+
+static struct mfd_cell peci_functions[] = {
+ {
+ .name = "peci-cputemp",
+ .of_compatible = "intel,peci-cputemp",
+ },
+ {
+ .name = "peci-dimmtemp",
+ .of_compatible = "intel,peci-dimmtemp",
+ },
+};
+
+static const struct cpu_gen_info cpu_gen_info_table[] = {
+ [CPU_GEN_HSX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_HASWELL_X,
+ .core_max = CORE_MAX_ON_HSX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_HSX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_HSX },
+ [CPU_GEN_BRX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_BROADWELL_X,
+ .core_max = CORE_MAX_ON_BDX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_BDX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
+ [CPU_GEN_SKX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_SKYLAKE_X,
+ .core_max = CORE_MAX_ON_SKX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_SKX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKX },
+};
+
+static int peci_client_get_cpu_gen_info(struct peci_mfd *priv)
+{
+ u32 cpu_id;
+ int i, rc;
+
+ rc = peci_get_cpu_id(priv->adapter, priv->addr, &cpu_id);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_gen_info_table); i++) {
+ if (FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id) +
+ FIELD_GET(CPU_ID_EXT_FAMILY_MASK, cpu_id) ==
+ cpu_gen_info_table[i].family &&
+ FIELD_GET(CPU_ID_MODEL_MASK, cpu_id) ==
+ FIELD_GET(LOWER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model) &&
+ FIELD_GET(CPU_ID_EXT_MODEL_MASK, cpu_id) ==
+ FIELD_GET(UPPER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model)) {
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(cpu_gen_info_table))
+ return -ENODEV;
+
+ priv->gen_info = &cpu_gen_info_table[i];
+
+ return 0;
+}
+
+bool peci_temp_need_update(struct temp_data *temp)
+{
+ if (temp->valid &&
+ time_before(jiffies, temp->last_updated + UPDATE_INTERVAL))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(peci_temp_need_update);
+
+void peci_temp_mark_updated(struct temp_data *temp)
+{
+ temp->valid = 1;
+ temp->last_updated = jiffies;
+}
+EXPORT_SYMBOL_GPL(peci_temp_mark_updated);
+
+int peci_client_command(struct peci_mfd *priv, enum peci_cmd cmd, void *vmsg)
+{
+ return peci_command(priv->adapter, cmd, vmsg);
+}
+EXPORT_SYMBOL_GPL(peci_client_command);
+
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *priv, u8 mbx_idx,
+ u16 param, u8 *data)
+{
+ struct peci_rd_pkg_cfg_msg msg;
+ int rc;
+
+ msg.addr = priv->addr;
+ msg.index = mbx_idx;
+ msg.param = param;
+ msg.rx_len = 4;
+
+ rc = peci_command(priv->adapter, PECI_CMD_RD_PKG_CFG, &msg);
+ if (!rc)
+ memcpy(data, msg.pkg_config, 4);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(peci_client_rd_pkg_cfg_cmd);
+
+static int peci_client_probe(struct peci_client *client)
+{
+ struct device *dev = &client->dev;
+ struct peci_mfd *priv;
+ int rc;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->client = client;
+ priv->dev = dev;
+ priv->adapter = client->adapter;
+ priv->addr = client->addr;
+ priv->cpu_no = client->addr - PECI_BASE_ADDR;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_client.cpu%d", priv->cpu_no);
+
+ rc = peci_client_get_cpu_gen_info(priv);
+ if (rc)
+ return rc;
+
+ rc = devm_mfd_add_devices(priv->dev, priv->cpu_no, peci_functions,
+ ARRAY_SIZE(peci_functions), NULL, 0, NULL);
+ if (rc < 0) {
+ dev_err(priv->dev, "devm_mfd_add_devices failed: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id peci_client_of_table[] = {
+ { .compatible = "intel,peci-client" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_client_of_table);
+#endif
+
+static const struct peci_device_id peci_client_ids[] = {
+ { .name = "peci-client", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(peci, peci_client_ids);
+
+static struct peci_driver peci_client_driver = {
+ .probe = peci_client_probe,
+ .id_table = peci_client_ids,
+ .driver = {
+ .name = "peci-client",
+ .of_match_table =
+ of_match_ptr(peci_client_of_table),
+ },
+};
+module_peci_driver(peci_client_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI client MFD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
new file mode 100644
index 000000000000..7ec272cddceb
--- /dev/null
+++ b/include/linux/mfd/intel-peci-client.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef __LINUX_MFD_PECI_CLIENT_H
+#define __LINUX_MFD_PECI_CLIENT_H
+
+#include <linux/peci.h>
+
+#if IS_ENABLED(CONFIG_X86)
+#include <asm/intel-family.h>
+#else
+/**
+ * Architectures other than x86 cannot include the header file so define these
+ * at here. These are needed for detecting type of client x86 CPUs behind a PECI
+ * connection.
+ */
+#define INTEL_FAM6_HASWELL_X 0x3F
+#define INTEL_FAM6_BROADWELL_X 0x4F
+#define INTEL_FAM6_SKYLAKE_X 0x55
+#endif
+
+#define LOWER_NIBBLE_MASK GENMASK(3, 0)
+#define UPPER_NIBBLE_MASK GENMASK(7, 4)
+
+#define CPU_ID_MODEL_MASK GENMASK(7, 4)
+#define CPU_ID_FAMILY_MASK GENMASK(11, 8)
+#define CPU_ID_EXT_MODEL_MASK GENMASK(19, 16)
+#define CPU_ID_EXT_FAMILY_MASK GENMASK(27, 20)
+
+#define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */
+#define CHAN_RANK_MAX_ON_HSX 8 /* Max number of channel ranks on Haswell */
+#define DIMM_IDX_MAX_ON_HSX 3 /* Max DIMM index per channel on Haswell */
+
+#define CORE_MAX_ON_BDX 24 /* Max number of cores on Broadwell */
+#define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */
+#define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */
+
+#define CORE_MAX_ON_SKX 28 /* Max number of cores on Skylake */
+#define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */
+#define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */
+
+#define CORE_NUMS_MAX CORE_MAX_ON_SKX
+#define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX
+#define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX
+#define DIMM_NUMS_MAX (CHAN_RANK_MAX * DIMM_IDX_MAX)
+
+#define TEMP_TYPE_PECI 6 /* Sensor type 6: Intel PECI */
+
+#define UPDATE_INTERVAL HZ
+
+struct temp_data {
+ uint valid;
+ s32 value;
+ ulong last_updated;
+};
+
+struct cpu_gen_info {
+ u16 family;
+ u8 model;
+ uint core_max;
+ uint chan_rank_max;
+ uint dimm_idx_max;
+};
+
+struct peci_mfd {
+ struct peci_client *client;
+ struct device *dev;
+ struct peci_adapter *adapter;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ uint cpu_no;
+ const struct cpu_gen_info *gen_info;
+};
+
+bool peci_temp_need_update(struct temp_data *temp);
+void peci_temp_mark_updated(struct temp_data *temp);
+int peci_client_command(struct peci_mfd *mfd, enum peci_cmd cmd, void *vmsg);
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *mfd, u8 mbx_idx,
+ u16 param, u8 *data);
+
+#endif /* __LINUX_MFD_PECI_CLIENT_H */
--
2.18.0
^ permalink raw reply related
* [PATCH v7 08/12] mfd: intel-peci-client: Add PECI client MFD driver
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds PECI client MFD driver.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: James Feist <james.feist@linux.intel.com>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Vernon Mauery <vernon.mauery@linux.intel.com>
---
drivers/mfd/Kconfig | 14 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/intel-peci-client.c | 182 ++++++++++++++++++++++++++
include/linux/mfd/intel-peci-client.h | 81 ++++++++++++
4 files changed, 278 insertions(+)
create mode 100644 drivers/mfd/intel-peci-client.c
create mode 100644 include/linux/mfd/intel-peci-client.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f3fa516011ec..e38b591479d4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -595,6 +595,20 @@ config MFD_INTEL_MSIC
Passage) chip. This chip embeds audio, battery, GPIO, etc.
devices used in Intel Medfield platforms.
+config MFD_INTEL_PECI_CLIENT
+ bool "Intel PECI client"
+ depends on (PECI || COMPILE_TEST)
+ select MFD_CORE
+ help
+ If you say yes to this option, support will be included for the
+ multi-funtional Intel PECI (Platform Environment Control Interface)
+ client. PECI is a one-wire bus interface that provides a communication
+ channel from PECI clients in Intel processors and chipset components
+ to external monitoring or control devices.
+
+ Additional drivers must be enabled in order to use the functionality
+ of the device.
+
config MFD_IPAQ_MICRO
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2852a6042ecf..29e2cacc58bd 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -203,6 +203,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o
obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_INTEL_PECI_CLIENT) += intel-peci-client.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
new file mode 100644
index 000000000000..d7702cf1ea50
--- /dev/null
+++ b/drivers/mfd/intel-peci-client.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/of_device.h>
+
+enum cpu_gens {
+ CPU_GEN_HSX = 0, /* Haswell Xeon */
+ CPU_GEN_BRX, /* Broadwell Xeon */
+ CPU_GEN_SKX, /* Skylake Xeon */
+};
+
+static struct mfd_cell peci_functions[] = {
+ {
+ .name = "peci-cputemp",
+ .of_compatible = "intel,peci-cputemp",
+ },
+ {
+ .name = "peci-dimmtemp",
+ .of_compatible = "intel,peci-dimmtemp",
+ },
+};
+
+static const struct cpu_gen_info cpu_gen_info_table[] = {
+ [CPU_GEN_HSX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_HASWELL_X,
+ .core_max = CORE_MAX_ON_HSX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_HSX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_HSX },
+ [CPU_GEN_BRX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_BROADWELL_X,
+ .core_max = CORE_MAX_ON_BDX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_BDX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
+ [CPU_GEN_SKX] = {
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_SKYLAKE_X,
+ .core_max = CORE_MAX_ON_SKX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_SKX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKX },
+};
+
+static int peci_client_get_cpu_gen_info(struct peci_mfd *priv)
+{
+ u32 cpu_id;
+ int i, rc;
+
+ rc = peci_get_cpu_id(priv->adapter, priv->addr, &cpu_id);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_gen_info_table); i++) {
+ if (FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id) +
+ FIELD_GET(CPU_ID_EXT_FAMILY_MASK, cpu_id) ==
+ cpu_gen_info_table[i].family &&
+ FIELD_GET(CPU_ID_MODEL_MASK, cpu_id) ==
+ FIELD_GET(LOWER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model) &&
+ FIELD_GET(CPU_ID_EXT_MODEL_MASK, cpu_id) ==
+ FIELD_GET(UPPER_NIBBLE_MASK,
+ cpu_gen_info_table[i].model)) {
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(cpu_gen_info_table))
+ return -ENODEV;
+
+ priv->gen_info = &cpu_gen_info_table[i];
+
+ return 0;
+}
+
+bool peci_temp_need_update(struct temp_data *temp)
+{
+ if (temp->valid &&
+ time_before(jiffies, temp->last_updated + UPDATE_INTERVAL))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(peci_temp_need_update);
+
+void peci_temp_mark_updated(struct temp_data *temp)
+{
+ temp->valid = 1;
+ temp->last_updated = jiffies;
+}
+EXPORT_SYMBOL_GPL(peci_temp_mark_updated);
+
+int peci_client_command(struct peci_mfd *priv, enum peci_cmd cmd, void *vmsg)
+{
+ return peci_command(priv->adapter, cmd, vmsg);
+}
+EXPORT_SYMBOL_GPL(peci_client_command);
+
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *priv, u8 mbx_idx,
+ u16 param, u8 *data)
+{
+ struct peci_rd_pkg_cfg_msg msg;
+ int rc;
+
+ msg.addr = priv->addr;
+ msg.index = mbx_idx;
+ msg.param = param;
+ msg.rx_len = 4;
+
+ rc = peci_command(priv->adapter, PECI_CMD_RD_PKG_CFG, &msg);
+ if (!rc)
+ memcpy(data, msg.pkg_config, 4);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(peci_client_rd_pkg_cfg_cmd);
+
+static int peci_client_probe(struct peci_client *client)
+{
+ struct device *dev = &client->dev;
+ struct peci_mfd *priv;
+ int rc;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->client = client;
+ priv->dev = dev;
+ priv->adapter = client->adapter;
+ priv->addr = client->addr;
+ priv->cpu_no = client->addr - PECI_BASE_ADDR;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_client.cpu%d", priv->cpu_no);
+
+ rc = peci_client_get_cpu_gen_info(priv);
+ if (rc)
+ return rc;
+
+ rc = devm_mfd_add_devices(priv->dev, priv->cpu_no, peci_functions,
+ ARRAY_SIZE(peci_functions), NULL, 0, NULL);
+ if (rc < 0) {
+ dev_err(priv->dev, "devm_mfd_add_devices failed: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id peci_client_of_table[] = {
+ { .compatible = "intel,peci-client" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_client_of_table);
+#endif
+
+static const struct peci_device_id peci_client_ids[] = {
+ { .name = "peci-client", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(peci, peci_client_ids);
+
+static struct peci_driver peci_client_driver = {
+ .probe = peci_client_probe,
+ .id_table = peci_client_ids,
+ .driver = {
+ .name = "peci-client",
+ .of_match_table =
+ of_match_ptr(peci_client_of_table),
+ },
+};
+module_peci_driver(peci_client_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI client MFD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
new file mode 100644
index 000000000000..7ec272cddceb
--- /dev/null
+++ b/include/linux/mfd/intel-peci-client.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef __LINUX_MFD_PECI_CLIENT_H
+#define __LINUX_MFD_PECI_CLIENT_H
+
+#include <linux/peci.h>
+
+#if IS_ENABLED(CONFIG_X86)
+#include <asm/intel-family.h>
+#else
+/**
+ * Architectures other than x86 cannot include the header file so define these
+ * at here. These are needed for detecting type of client x86 CPUs behind a PECI
+ * connection.
+ */
+#define INTEL_FAM6_HASWELL_X 0x3F
+#define INTEL_FAM6_BROADWELL_X 0x4F
+#define INTEL_FAM6_SKYLAKE_X 0x55
+#endif
+
+#define LOWER_NIBBLE_MASK GENMASK(3, 0)
+#define UPPER_NIBBLE_MASK GENMASK(7, 4)
+
+#define CPU_ID_MODEL_MASK GENMASK(7, 4)
+#define CPU_ID_FAMILY_MASK GENMASK(11, 8)
+#define CPU_ID_EXT_MODEL_MASK GENMASK(19, 16)
+#define CPU_ID_EXT_FAMILY_MASK GENMASK(27, 20)
+
+#define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */
+#define CHAN_RANK_MAX_ON_HSX 8 /* Max number of channel ranks on Haswell */
+#define DIMM_IDX_MAX_ON_HSX 3 /* Max DIMM index per channel on Haswell */
+
+#define CORE_MAX_ON_BDX 24 /* Max number of cores on Broadwell */
+#define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */
+#define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */
+
+#define CORE_MAX_ON_SKX 28 /* Max number of cores on Skylake */
+#define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */
+#define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */
+
+#define CORE_NUMS_MAX CORE_MAX_ON_SKX
+#define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX
+#define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX
+#define DIMM_NUMS_MAX (CHAN_RANK_MAX * DIMM_IDX_MAX)
+
+#define TEMP_TYPE_PECI 6 /* Sensor type 6: Intel PECI */
+
+#define UPDATE_INTERVAL HZ
+
+struct temp_data {
+ uint valid;
+ s32 value;
+ ulong last_updated;
+};
+
+struct cpu_gen_info {
+ u16 family;
+ u8 model;
+ uint core_max;
+ uint chan_rank_max;
+ uint dimm_idx_max;
+};
+
+struct peci_mfd {
+ struct peci_client *client;
+ struct device *dev;
+ struct peci_adapter *adapter;
+ char name[PECI_NAME_SIZE];
+ u8 addr;
+ uint cpu_no;
+ const struct cpu_gen_info *gen_info;
+};
+
+bool peci_temp_need_update(struct temp_data *temp);
+void peci_temp_mark_updated(struct temp_data *temp);
+int peci_client_command(struct peci_mfd *mfd, enum peci_cmd cmd, void *vmsg);
+int peci_client_rd_pkg_cfg_cmd(struct peci_mfd *mfd, u8 mbx_idx,
+ u16 param, u8 *data);
+
+#endif /* __LINUX_MFD_PECI_CLIENT_H */
--
2.18.0
^ permalink raw reply related
* [PATCH v7 07/12] dt-bindings: mfd: Add a document for PECI client MFD
From: Jae Hyun Yoo @ 2018-07-23 21:47 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck, Rob Herring, Mark Rutland, Lee Jones,
Joel Stanley, Andrew Jeffery, Jonathan Corbet, Greg Kroah-Hartman,
Gustavo Pimentel, Kishon Vijay Abraham I, Lorenzo Pieralisi,
Darrick J . Wong, Eric Sandeen, Arnd Bergmann, Wu Hao,
Tomohiro Kusumi, Bryant G . Ly, Frederic Barrat, David
Cc: linux-hwmon, devicetree, linux-kernel, linux-arm-kernel,
linux-aspeed, linux-doc, openbmc, Jae Hyun Yoo, James Feist,
Jason M Biils, Vernon Mauery
In-Reply-To: <20180723214751.1733-1-jae.hyun.yoo@linux.intel.com>
This commit adds a dt-bindings document for PECI client MFD.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Andrew Jeffery <andrew@aj.id.au>
Cc: James Feist <james.feist@linux.intel.com>
Cc: Jason M Biils <jason.m.bills@linux.intel.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Vernon Mauery <vernon.mauery@linux.intel.com>
---
.../bindings/mfd/intel-peci-client.txt | 34 +++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/intel-peci-client.txt
diff --git a/Documentation/devicetree/bindings/mfd/intel-peci-client.txt b/Documentation/devicetree/bindings/mfd/intel-peci-client.txt
new file mode 100644
index 000000000000..cb341e363add
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/intel-peci-client.txt
@@ -0,0 +1,34 @@
+* Intel PECI client bindings
+
+PECI (Platform Environment Control Interface) is a one-wire bus interface that
+provides a communication channel from PECI clients in Intel processors and
+chipset components to external monitoring or control devices. PECI is designed
+to support the following sideband functions:
+
+- Processor and DRAM thermal management
+- Platform Manageability
+- Processor Interface Tuning and Diagnostics
+- Failure Analysis
+
+Required properties:
+- compatible : Should be "intel,peci-client".
+- reg : Should contain address of a client CPU. Address range of CPU
+ clients starts from 0x30 based on PECI specification.
+
+Example:
+ peci-bus@0 {
+ compatible = "vendor,soc-peci";
+ reg = <0x0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ peci-client@30 {
+ compatible = "intel,peci-client";
+ reg = <0x30>;
+ };
+
+ peci-client@31 {
+ compatible = "intel,peci-client";
+ reg = <0x31>;
+ };
+ };
--
2.18.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.