Received: by 2002:a25:ad19:0:0:0:0:0 with SMTP id y25csp1269659ybi; Tue, 16 Jul 2019 12:14:24 -0700 (PDT) X-Google-Smtp-Source: APXvYqzSyxDO92tTChiJ1sWbi2vAGAleSxMF8wMStDUUB+ol6x0Kmia33q/+c4mU+Kpod0a6mZ9I X-Received: by 2002:a17:90a:2023:: with SMTP id n32mr37149502pjc.3.1563304464330; Tue, 16 Jul 2019 12:14:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1563304464; cv=none; d=google.com; s=arc-20160816; b=eCi87ZWN8kXoKucyn7HdcAXarcIdcsfDggshZ2l6DW/P5DbnXBwUMR6itxEwc4ulbA K5/6g5xJrEtxtBdRggVc3yZ6W0ktD9zTEq+0T2EqYhmSGjVnocwjM3z11Y9WiXLVok9X OARyhfT79ctwdLlZ2fjAqNh7+2yppvaXnDUUkl275Equ4SAklA1NcKKa3QAo2x6XSo+v DmAeTOV2hgRUPXxkJC1wGG5VPZx+lMnyD4anG7Vjd/qp73qu3ADsvyeySkcQvQUomCzV P5Kpyhh3dXGR41FTAy+pwTwwl8iIjrSvfmKI+ttIPffC6ScIZXaCfsbN63ez06bJ24Ci ogfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-language :content-transfer-encoding:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:dkim-signature; bh=/VY41JW7HWgnKCGFO/1KioyDFZirGbA3kqgL/hekL48=; b=UHejkkXvh1c7aO8NXDw3sCUatEphegwoOU8jT+C6qqm8IQ/+3axLUDPF6RdL9iHgZz LzHKVva1T8JhRjbqJsBXzm6yk6FuoNvCD6F08Rjm+UcmEdilCtNemTsgQhh95oUAiwBI 7sT6Dfo2ItRL/fUvnKJAxtsXhuixlEJ1zMU9uoR6XIw8wj9eFru1ApRSFuurmgROW5ha RnzqM5Myz9zeLWkYDH4owZOiJcfYkQoDJHglEQTgICdJLXjCv9OzruElBsc3Apw3wv+R p/U7gvmyJ41Qr78+LkxqhOhf4/1K/kcEj6j4d/YlBI2YjFaL7LD4Wa3e22+tukxJxwfR /DwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pensando.io header.s=google header.b=io9xV3sD; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c11si1786728pga.118.2019.07.16.12.14.08; Tue, 16 Jul 2019 12:14:24 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pensando.io header.s=google header.b=io9xV3sD; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728190AbfGPTNm (ORCPT + 99 others); Tue, 16 Jul 2019 15:13:42 -0400 Received: from mail-pf1-f193.google.com ([209.85.210.193]:36409 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728137AbfGPTNl (ORCPT ); Tue, 16 Jul 2019 15:13:41 -0400 Received: by mail-pf1-f193.google.com with SMTP id r7so9574294pfl.3 for ; Tue, 16 Jul 2019 12:13:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pensando.io; s=google; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-transfer-encoding:content-language; bh=/VY41JW7HWgnKCGFO/1KioyDFZirGbA3kqgL/hekL48=; b=io9xV3sDFtY8JjZyTsvgRaeLt7waVT+gnVR4xSXY/d329z34QILxU5WV0TIGraTC2/ Wc2L7QeBh3pEfpKIm9gGWShIGt4pOOeTV0/n6P1CgtggepsBDGzWLznHCgo90oXMtiVJ SCibG9GJt+vSSa5eMQSCoTtRmuIgfxA85JuSTqYVcEkTFV9+BVfJCpukfQ+1jubFZqkR /DYzXc1UMOv4XlYevo7iofGBKzIfcWJINC1ALmkRJKpZ9R/TFQ504CYQOcpWalj8SDoE 3osMCd0dPEDNq1hPTfwfWCVCCfmkqR+l9n6Fc4pKNEymHjqfd4+621cM8hC5ezyzz9if JoAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-transfer-encoding :content-language; bh=/VY41JW7HWgnKCGFO/1KioyDFZirGbA3kqgL/hekL48=; b=PQtxHjUkkNRRzKmLJXQqdRnVlUnr//Za5bX/XRQUNOQ+Vlsq6UG5NUlw2LSuaTQawH oD+fc1rM26jtTLSRoPfMsNioouLYS7HY43yUEeGRIbPpJ6e9vBjiOErEtZFwzzXwGRsL uRNcNPMbGamXliwlk7HMI6/WgYWSOLblMmTDh7R3zYnwkl8ZWZiTQERsnlPn4z5xbWbU iQa2L7Xdow020szTJjRZGDj5yrmSbE0o+z0GBKbr9zsHAGxeINZgpqQ3j7kfh+TLedSG ZcNVi/dU8ECNTE8d/9cKbiiKPv6tK011XTpHCHW6JywH1vtI2whJf1Tmob7hD4pPAzwy Fimg== X-Gm-Message-State: APjAAAXLKYODyG9IwYzZz7ninybobA9x8WVFxSy0DfcYHCmAyHxHGxfa c5oN2TRe6/cwt461vbYaV+EEXQ== X-Received: by 2002:a63:724f:: with SMTP id c15mr36881495pgn.257.1563304420815; Tue, 16 Jul 2019 12:13:40 -0700 (PDT) Received: from Shannons-MacBook-Pro.local ([12.1.37.26]) by smtp.gmail.com with ESMTPSA id w2sm16966201pgc.32.2019.07.16.12.13.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 16 Jul 2019 12:13:40 -0700 (PDT) Subject: Re: [RFC PATCH 5/5] PTP: Add support for Intel PMC Timed GPIO Controller To: Felipe Balbi , Richard Cochran Cc: netdev@vger.kernel.org, Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H . Peter Anvin" , x86@kernel.org, linux-kernel@vger.kernel.org, "Christopher S . Hall" References: <20190716072038.8408-1-felipe.balbi@linux.intel.com> <20190716072038.8408-6-felipe.balbi@linux.intel.com> From: Shannon Nelson Message-ID: <33864ede-1ce1-92f2-f049-a975060b2743@pensando.io> Date: Tue, 16 Jul 2019 12:14:44 -0700 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:60.0) Gecko/20100101 Thunderbird/60.7.2 MIME-Version: 1.0 In-Reply-To: <20190716072038.8408-6-felipe.balbi@linux.intel.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-US Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 7/16/19 12:20 AM, Felipe Balbi wrote: > Add a driver supporting Intel Timed GPIO controller available as part > of some Intel PMCs. > > Signed-off-by: Felipe Balbi Hi Felipe, just a couple of quick comments: There are several places where a line is continued on the next line, but should be indented to match the opening parenthesis on a function call or 'if' expression. Shouldn't there be a kthread_stop() in intel_pmc_tgpio_remove(), or did I miss that somewhere? Cheers, sln > --- > drivers/ptp/Kconfig | 8 + > drivers/ptp/Makefile | 1 + > drivers/ptp/ptp-intel-pmc-tgpio.c | 378 ++++++++++++++++++++++++++++++ > 3 files changed, 387 insertions(+) > create mode 100644 drivers/ptp/ptp-intel-pmc-tgpio.c > > diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig > index 9b8fee5178e8..bb0fce70a783 100644 > --- a/drivers/ptp/Kconfig > +++ b/drivers/ptp/Kconfig > @@ -107,6 +107,14 @@ config PTP_1588_CLOCK_PCH > To compile this driver as a module, choose M here: the module > will be called ptp_pch. > > +config PTP_INTEL_PMC_TGPIO > + tristate "Intel PMC Timed GPIO" > + depends on X86 > + depends on ACPI > + imply PTP_1588_CLOCK > + help > + This driver adds support for Intel PMC Timed GPIO Controller > + > config PTP_1588_CLOCK_KVM > tristate "KVM virtual PTP clock" > depends on PTP_1588_CLOCK > diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile > index 677d1d178a3e..ff89c90ace82 100644 > --- a/drivers/ptp/Makefile > +++ b/drivers/ptp/Makefile > @@ -7,6 +7,7 @@ ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o > obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o > obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o > obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o > +obj-$(CONFIG_PTP_INTEL_PMC_TGPIO) += ptp-intel-pmc-tgpio.o > obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o > obj-$(CONFIG_PTP_1588_CLOCK_KVM) += ptp_kvm.o > obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp-qoriq.o > diff --git a/drivers/ptp/ptp-intel-pmc-tgpio.c b/drivers/ptp/ptp-intel-pmc-tgpio.c > new file mode 100644 > index 000000000000..880ece34868a > --- /dev/null > +++ b/drivers/ptp/ptp-intel-pmc-tgpio.c > @@ -0,0 +1,378 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Intel Timed GPIO Controller Driver > + * > + * Copyright (C) 2018 Intel Corporation > + * Author: Felipe Balbi > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define TGPIOCTL 0x00 > +#define TGPIOCOMPV31_0 0x10 > +#define TGPIOCOMPV63_32 0x14 > +#define TGPIOPIV31_0 0x18 > +#define TGPIOPIV63_32 0x1c > +#define TGPIOTCV31_0 0x20 > +#define TGPIOTCV63_32 0x24 > +#define TGPIOECCV31_0 0x28 > +#define TGPIOECCV63_32 0x2c > +#define TGPIOEC31_0 0x30 > +#define TGPIOEC63_32 0x34 > + > +/* Control Register */ > +#define TGPIOCTL_EN BIT(0) > +#define TGPIOCTL_DIR BIT(1) > +#define TGPIOCTL_EP GENMASK(3, 2) > +#define TGPIOCTL_EP_RISING_EDGE (0 << 2) > +#define TGPIOCTL_EP_FALLING_EDGE (1 << 2) > +#define TGPIOCTL_EP_TOGGLE_EDGE (2 << 2) > +#define TGPIOCTL_PM BIT(4) > + > +#define NSECS_PER_SEC 1000000000 > +#define TGPIO_MAX_ADJ_TIME 999999900 > + > +struct intel_pmc_tgpio { > + struct ptp_clock_info info; > + struct ptp_clock *clock; > + > + struct mutex lock; > + struct device *dev; > + void __iomem *base; > + > + struct task_struct *event_thread; > + bool input; > +}; > +#define to_intel_pmc_tgpio(i) (container_of((i), struct intel_pmc_tgpio, info)) > + > +static inline u64 to_intel_pmc_tgpio_time(struct ptp_clock_time *t) > +{ > + return t->sec * NSECS_PER_SEC + t->nsec; > +} > + > +static inline u64 intel_pmc_tgpio_readq(void __iomem *base, u32 offset) > +{ > + return lo_hi_readq(base + offset); > +} > + > +static inline void intel_pmc_tgpio_writeq(void __iomem *base, u32 offset, u64 v) > +{ > + return lo_hi_writeq(v, base + offset); > +} > + > +static inline u32 intel_pmc_tgpio_readl(void __iomem *base, u32 offset) > +{ > + return readl(base + offset); > +} > + > +static inline void intel_pmc_tgpio_writel(void __iomem *base, u32 offset, u32 value) > +{ > + writel(value, base + offset); > +} > + > +static struct ptp_pin_desc intel_pmc_tgpio_pin_config[] = { > + { \ > + .name = "pin0", \ > + .index = 0, \ > + .func = PTP_PF_NONE, \ > + .chan = 0, \ > + } > +}; > + > +static int intel_pmc_tgpio_gettime64(struct ptp_clock_info *info, > + struct timespec64 *ts) > +{ > + struct intel_pmc_tgpio *tgpio = to_intel_pmc_tgpio(info); > + u64 now; > + > + mutex_lock(&tgpio->lock); > + now = get_art_ns_now(); > + *ts = ns_to_timespec64(now); > + mutex_unlock(&tgpio->lock); > + > + return 0; > +} > + > +static int intel_pmc_tgpio_settime64(struct ptp_clock_info *info, > + const struct timespec64 *ts) > +{ > + return -EOPNOTSUPP; > +} > + > +static int intel_pmc_tgpio_event_thread(void *_tgpio) > +{ > + struct intel_pmc_tgpio *tgpio = _tgpio; > + u64 reg; > + > + while (!kthread_should_stop()) { > + bool input; > + int i; > + > + mutex_lock(&tgpio->lock); > + input = tgpio->input; > + mutex_unlock(&tgpio->lock); > + > + if (!input) > + schedule(); > + > + reg = intel_pmc_tgpio_readq(tgpio->base, TGPIOEC31_0); > + > + for (i = 0; i < reg; i++) { > + struct ptp_clock_event event; > + > + event.type = PTP_CLOCK_EXTTS; > + event.index = 0; > + event.timestamp = intel_pmc_tgpio_readq(tgpio->base, > + TGPIOTCV31_0); > + > + ptp_clock_event(tgpio->clock, &event); > + } > + schedule_timeout_interruptible(10); > + } > + > + return 0; > +} > + > +static int intel_pmc_tgpio_config_input(struct intel_pmc_tgpio *tgpio, > + struct ptp_extts_request *extts, int on) > +{ > + u32 ctrl; > + bool input; > + > + ctrl = intel_pmc_tgpio_readl(tgpio->base, TGPIOCTL); > + ctrl &= ~TGPIOCTL_EN; > + intel_pmc_tgpio_writel(tgpio->base, TGPIOCTL, ctrl); > + > + if (on) { > + ctrl |= TGPIOCTL_DIR; > + > + if (extts->flags & PTP_RISING_EDGE && > + extts->flags & PTP_FALLING_EDGE) > + ctrl |= TGPIOCTL_EP_TOGGLE_EDGE; > + else if (extts->flags & PTP_RISING_EDGE) > + ctrl |= TGPIOCTL_EP_RISING_EDGE; > + else if (extts->flags & PTP_FALLING_EDGE) > + ctrl |= TGPIOCTL_EP_FALLING_EDGE; > + > + /* gotta program all other bits before EN bit is set */ > + intel_pmc_tgpio_writel(tgpio->base, TGPIOCTL, ctrl); > + ctrl |= TGPIOCTL_EN; > + input = true; > + } else { > + ctrl &= ~(TGPIOCTL_DIR | TGPIOCTL_EN); > + input = false; > + } > + > + intel_pmc_tgpio_writel(tgpio->base, TGPIOCTL, ctrl); > + tgpio->input = input; > + > + if (input) > + wake_up_process(tgpio->event_thread); > + > + return 0; > +} > + > +static int intel_pmc_tgpio_config_output(struct intel_pmc_tgpio *tgpio, > + struct ptp_perout_request *perout, int on) > +{ > + u32 ctrl; > + > + ctrl = intel_pmc_tgpio_readl(tgpio->base, TGPIOCTL); > + if (on) { > + struct ptp_clock_time *period = &perout->period; > + struct ptp_clock_time *start = &perout->start; > + > + if (ctrl & TGPIOCTL_EN) > + return 0; > + > + intel_pmc_tgpio_writeq(tgpio->base, TGPIOCOMPV31_0, > + to_intel_pmc_tgpio_time(start)); > + > + intel_pmc_tgpio_writeq(tgpio->base, TGPIOPIV31_0, > + to_intel_pmc_tgpio_time(period)); > + > + ctrl &= ~TGPIOCTL_DIR; > + if (perout->flags & PTP_PEROUT_ONE_SHOT) > + ctrl &= ~TGPIOCTL_PM; > + else > + ctrl |= TGPIOCTL_PM; > + > + /* gotta program all other bits before EN bit is set */ > + intel_pmc_tgpio_writel(tgpio->base, TGPIOCTL, ctrl); > + > + ctrl |= TGPIOCTL_EN; > + intel_pmc_tgpio_writel(tgpio->base, TGPIOCTL, ctrl); > + } else { > + if (!(ctrl & ~TGPIOCTL_EN)) > + return 0; > + > + ctrl &= ~(TGPIOCTL_EN | TGPIOCTL_PM); > + intel_pmc_tgpio_writel(tgpio->base, TGPIOCTL, ctrl); > + } > + > + return 0; > +} > + > +static int intel_pmc_tgpio_enable(struct ptp_clock_info *info, > + struct ptp_clock_request *req, int on) > +{ > + struct intel_pmc_tgpio *tgpio = to_intel_pmc_tgpio(info); > + int ret = -EOPNOTSUPP; > + > + mutex_lock(&tgpio->lock); > + switch (req->type) { > + case PTP_CLK_REQ_EXTTS: > + ret = intel_pmc_tgpio_config_input(tgpio, &req->extts, on); > + break; > + case PTP_CLK_REQ_PEROUT: > + ret = intel_pmc_tgpio_config_output(tgpio, &req->perout, on); > + break; > + default: > + break; > + } > + mutex_unlock(&tgpio->lock); > + > + return ret; > +} > + > +static int intel_pmc_tgpio_get_time_fn(ktime_t *device_time, > + struct system_counterval_t *system_counter, void *_tgpio) > +{ > + get_tsc_ns(system_counter, device_time); > + return 0; > +} > + > +static int intel_pmc_tgpio_getcrosststamp(struct ptp_clock_info *info, > + struct system_device_crosststamp *cts) > +{ > + struct intel_pmc_tgpio *tgpio = to_intel_pmc_tgpio(info); > + > + return get_device_system_crosststamp(intel_pmc_tgpio_get_time_fn, tgpio, > + NULL, cts); > +} > + > +static int intel_pmc_tgpio_counttstamp(struct ptp_clock_info *info, > + struct ptp_event_count_tstamp *count) > +{ > + struct intel_pmc_tgpio *tgpio = to_intel_pmc_tgpio(info); > + u32 dt_hi_tmp; > + u32 dt_hi; > + u32 dt_lo; > + > + dt_hi_tmp = intel_pmc_tgpio_readl(tgpio->base, TGPIOTCV63_32); > + dt_lo = intel_pmc_tgpio_readl(tgpio->base, TGPIOTCV31_0); > + > + count->event_count = intel_pmc_tgpio_readl(tgpio->base, TGPIOECCV63_32); > + count->event_count <<= 32; > + count->event_count |= intel_pmc_tgpio_readl(tgpio->base, TGPIOECCV31_0); > + > + dt_hi = intel_pmc_tgpio_readl(tgpio->base, TGPIOTCV63_32); > + > + if (dt_hi_tmp != dt_hi && dt_lo & 0x80000000) > + count->device_time.sec = dt_hi_tmp; > + else > + count->device_time.sec = dt_hi; > + > + count->device_time.nsec = dt_lo; > + > + return 0; > +} > + > +static int intel_pmc_tgpio_verify(struct ptp_clock_info *ptp, unsigned int pin, > + enum ptp_pin_function func, unsigned int chan) > +{ > + return 0; > +} > + > +static const struct ptp_clock_info intel_pmc_tgpio_info = { > + .owner = THIS_MODULE, > + .name = "Intel PMC TGPIO", > + .max_adj = 50000000, > + .n_pins = 1, > + .n_ext_ts = 1, > + .n_per_out = 1, > + .pin_config = intel_pmc_tgpio_pin_config, > + .gettime64 = intel_pmc_tgpio_gettime64, > + .settime64 = intel_pmc_tgpio_settime64, > + .enable = intel_pmc_tgpio_enable, > + .getcrosststamp = intel_pmc_tgpio_getcrosststamp, > + .counttstamp = intel_pmc_tgpio_counttstamp, > + .verify = intel_pmc_tgpio_verify, > +}; > + > +static int intel_pmc_tgpio_probe(struct platform_device *pdev) > +{ > + struct intel_pmc_tgpio *tgpio; > + struct device *dev; > + struct resource *res; > + > + dev = &pdev->dev; > + tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL); > + if (!tgpio) > + return -ENOMEM; > + > + tgpio->dev = dev; > + tgpio->info = intel_pmc_tgpio_info; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + tgpio->base = devm_ioremap_resource(dev, res); > + if (!tgpio->base) > + return -ENOMEM; > + > + mutex_init(&tgpio->lock); > + platform_set_drvdata(pdev, tgpio); > + > + tgpio->event_thread = kthread_create(intel_pmc_tgpio_event_thread, > + tgpio, dev_name(tgpio->dev)); > + if (IS_ERR(tgpio->event_thread)) > + return PTR_ERR(tgpio->event_thread); > + > + tgpio->clock = ptp_clock_register(&tgpio->info, &pdev->dev); > + if (IS_ERR(tgpio->clock)) > + return PTR_ERR(tgpio->clock); > + > + wake_up_process(tgpio->event_thread); > + > + return 0; > +} > + > +static int intel_pmc_tgpio_remove(struct platform_device *pdev) > +{ > + struct intel_pmc_tgpio *tgpio = platform_get_drvdata(pdev); > + > + ptp_clock_unregister(tgpio->clock); > + > + return 0; > +} > + > +static const struct acpi_device_id intel_pmc_acpi_match[] = { > + /* TODO */ > + > + { }, > +}; > + > +/* MODULE_ALIAS("acpi*:TODO:*"); */ > + > +static struct platform_driver intel_pmc_tgpio_driver = { > + .probe = intel_pmc_tgpio_probe, > + .remove = intel_pmc_tgpio_remove, > + .driver = { > + .name = "intel-pmc-tgpio", > + .acpi_match_table = ACPI_PTR(intel_pmc_acpi_match), > + }, > +}; > + > +module_platform_driver(intel_pmc_tgpio_driver); > + > +MODULE_AUTHOR("Felipe Balbi "); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("Intel PMC Timed GPIO Controller Driver");