From: Jiri Pirko <jiri@resnulli.us>
To: Vadim Fedorenko <vadfed@meta.com>
Cc: Jakub Kicinski <kuba@kernel.org>,
Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
Jonathan Lemon <jonathan.lemon@gmail.com>,
Paolo Abeni <pabeni@redhat.com>,
Vadim Fedorenko <vadim.fedorenko@linux.dev>,
poros@redhat.com, mschmidt@redhat.com, netdev@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org
Subject: Re: [PATCH RFC v6 6/6] ptp_ocp: implement DPLL ops
Date: Tue, 14 Mar 2023 11:05:15 +0100 [thread overview]
Message-ID: <ZBBG2xRhLOIPMD0+@nanopsycho> (raw)
In-Reply-To: <20230312022807.278528-7-vadfed@meta.com>
Sun, Mar 12, 2023 at 03:28:07AM CET, vadfed@meta.com wrote:
>Implement basic DPLL operations in ptp_ocp driver as the
>simplest example of using new subsystem.
>
>Signed-off-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
>---
> drivers/ptp/Kconfig | 1 +
> drivers/ptp/ptp_ocp.c | 209 ++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 200 insertions(+), 10 deletions(-)
>
>diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
>index fe4971b65c64..8c4cfabc1bfa 100644
>--- a/drivers/ptp/Kconfig
>+++ b/drivers/ptp/Kconfig
>@@ -177,6 +177,7 @@ config PTP_1588_CLOCK_OCP
> depends on COMMON_CLK
> select NET_DEVLINK
> select CRC16
>+ select DPLL
> help
> This driver adds support for an OpenCompute time card.
>
>diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
>index 4bbaccd543ad..02c95e724ec8 100644
>--- a/drivers/ptp/ptp_ocp.c
>+++ b/drivers/ptp/ptp_ocp.c
>@@ -23,6 +23,8 @@
> #include <linux/mtd/mtd.h>
> #include <linux/nvmem-consumer.h>
> #include <linux/crc16.h>
>+#include <linux/dpll.h>
>+#include <uapi/linux/dpll.h>
Don't include UAPI directly. I'm pretty sure I had this comment earlier.
>
> #define PCI_VENDOR_ID_FACEBOOK 0x1d9b
> #define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400
>@@ -267,6 +269,7 @@ struct ptp_ocp_sma_connector {
> bool fixed_dir;
> bool disabled;
> u8 default_fcn;
>+ struct dpll_pin *dpll_pin;
> };
>
> struct ocp_attr_group {
>@@ -353,6 +356,7 @@ struct ptp_ocp {
> struct ptp_ocp_signal signal[4];
> struct ptp_ocp_sma_connector sma[4];
It is quite customary to use defines for const numbers like this. Why
don't you do that in ptp_ocp?
> const struct ocp_sma_op *sma_op;
>+ struct dpll_device *dpll;
> };
>
> #define OCP_REQ_TIMESTAMP BIT(0)
>@@ -2689,16 +2693,9 @@ sma4_show(struct device *dev, struct device_attribute *attr, char *buf)
> }
>
> static int
>-ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
>+ptp_ocp_sma_store_val(struct ptp_ocp *bp, int val, enum ptp_ocp_sma_mode mode, int sma_nr)
> {
> struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
>- enum ptp_ocp_sma_mode mode;
>- int val;
>-
>- mode = sma->mode;
>- val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode);
>- if (val < 0)
>- return val;
>
> if (sma->fixed_dir && (mode != sma->mode || val & SMA_DISABLE))
> return -EOPNOTSUPP;
>@@ -2733,6 +2730,21 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
> return val;
> }
>
>+static int
>+ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
>+{
>+ struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
>+ enum ptp_ocp_sma_mode mode;
>+ int val;
>+
>+ mode = sma->mode;
>+ val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode);
>+ if (val < 0)
>+ return val;
>+
>+ return ptp_ocp_sma_store_val(bp, val, mode, sma_nr);
>+}
>+
> static ssize_t
> sma1_store(struct device *dev, struct device_attribute *attr,
> const char *buf, size_t count)
>@@ -4171,12 +4183,151 @@ ptp_ocp_detach(struct ptp_ocp *bp)
> device_unregister(&bp->dev);
> }
>
>+static int ptp_ocp_dpll_pin_to_sma(const struct ptp_ocp *bp, const struct dpll_pin *pin)
>+{
>+ int i;
>+
>+ for (i = 0; i < 4; i++) {
>+ if (bp->sma[i].dpll_pin == pin)
>+ return i;
Just pass &bp->sma[i] as a priv to dpll_pin_register().
and get that pointer directly in pin ops. No need for lookup and use of
sma_nr at all.
>+ }
>+ return -1;
>+}
>+
>+static int ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll,
>+ enum dpll_lock_status *status,
>+ struct netlink_ext_ack *extack)
>+{
>+ struct ptp_ocp *bp = (struct ptp_ocp *)dpll_priv(dpll);
No need to cast (void *), remove it.
>+ int sync;
>+
>+ sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
>+ *status = sync ? DPLL_LOCK_STATUS_LOCKED : DPLL_LOCK_STATUS_UNLOCKED;
>+
>+ return 0;
>+}
>+
>+static int ptp_ocp_dpll_source_idx_get(const struct dpll_device *dpll,
>+ u32 *idx, struct netlink_ext_ack *extack)
>+{
>+ struct ptp_ocp *bp = (struct ptp_ocp *)dpll_priv(dpll);
>+
>+ if (bp->pps_select) {
>+ *idx = ioread32(&bp->pps_select->gpio1);
>+ return 0;
>+ }
>+ return -EINVAL;
>+}
>+
>+static int ptp_ocp_dpll_mode_get(const struct dpll_device *dpll,
>+ u32 *mode, struct netlink_ext_ack *extack)
>+{
>+ *mode = DPLL_MODE_AUTOMATIC;
>+
No need for empty line, I believe.
>+ return 0;
>+}
>+
>+static bool ptp_ocp_dpll_mode_supported(const struct dpll_device *dpll,
>+ const enum dpll_mode mode,
>+ struct netlink_ext_ack *extack)
>+{
>+ if (mode == DPLL_MODE_AUTOMATIC)
>+ return true;
>+
>+ return false;
Just:
return mode == DPLL_MODE_AUTOMATIC;
>+}
>+
>+static int ptp_ocp_dpll_direction_get(const struct dpll_pin *pin,
>+ const struct dpll_device *dpll,
>+ enum dpll_pin_direction *direction,
>+ struct netlink_ext_ack *extack)
>+{
>+ struct ptp_ocp *bp = (struct ptp_ocp *)dpll_priv(dpll);
>+ int sma_nr = ptp_ocp_dpll_pin_to_sma(bp, pin);
>+
>+ if (sma_nr < 0)
>+ return -EINVAL;
>+
>+ *direction = bp->sma[sma_nr].mode == SMA_MODE_IN ? DPLL_PIN_DIRECTION_SOURCE :
>+ DPLL_PIN_DIRECTION_OUTPUT;
>+ return 0;
>+}
>+
>+static int ptp_ocp_dpll_direction_set(const struct dpll_pin *pin,
>+ const struct dpll_device *dpll,
>+ enum dpll_pin_direction direction,
>+ struct netlink_ext_ack *extack)
>+{
>+ struct ptp_ocp *bp = (struct ptp_ocp *)dpll_priv(dpll);
>+ int sma_nr = ptp_ocp_dpll_pin_to_sma(bp, pin);
>+ enum ptp_ocp_sma_mode mode;
>+
>+ if (sma_nr < 0)
>+ return -EINVAL;
>+
>+ mode = direction == DPLL_PIN_DIRECTION_SOURCE ? SMA_MODE_IN : SMA_MODE_OUT;
>+ return ptp_ocp_sma_store_val(bp, 0, mode, sma_nr);
>+}
>+
>+static int ptp_ocp_dpll_frequency_set(const struct dpll_pin *pin,
>+ const struct dpll_device *dpll,
>+ const u32 frequency,
Why you need const for u32?
>+ struct netlink_ext_ack *extack)
>+{
>+ struct ptp_ocp *bp = (struct ptp_ocp *)dpll_priv(dpll);
>+ int sma_nr = ptp_ocp_dpll_pin_to_sma(bp, pin);
>+ int val = frequency == 10000000 ? 0 : 1;
This is weird. I believe you should handle unsupported frequencies
gracefully.
>+
>+ if (sma_nr < 0)
>+ return -EINVAL;
>+
>+
Avoid double empty lines.
>+ return ptp_ocp_sma_store_val(bp, val, bp->sma[sma_nr].mode, sma_nr);
>+}
>+
>+static int ptp_ocp_dpll_frequency_get(const struct dpll_pin *pin,
>+ const struct dpll_device *dpll,
>+ u32 *frequency,
>+ struct netlink_ext_ack *extack)
>+{
>+ struct ptp_ocp *bp = (struct ptp_ocp *)dpll_priv(dpll);
>+ int sma_nr = ptp_ocp_dpll_pin_to_sma(bp, pin);
>+ u32 val;
>+
>+ if (sma_nr < 0)
>+ return -EINVAL;
>+
>+ val = bp->sma_op->get(bp, sma_nr);
>+ if (!val)
>+ *frequency = 1000000;
>+ else
>+ *frequency = 0;
I don't follow. How the frequency could be 0? Does that mean that the
pin is disabled? If yes, you should rather implement
.state_on_dpll_get
.state_on_dpll_set
and leave the frequency constant.
>+ return 0;
>+}
>+
>+static struct dpll_device_ops dpll_ops = {
const
>+ .lock_status_get = ptp_ocp_dpll_lock_status_get,
>+ .source_pin_idx_get = ptp_ocp_dpll_source_idx_get,
Should be called "source_pin_get" and return (struct dpll_pin *)
On the driver api level, no reason to pass indexes. Work with objects.
>+ .mode_get = ptp_ocp_dpll_mode_get,
>+ .mode_supported = ptp_ocp_dpll_mode_supported,
>+};
>+
>+static struct dpll_pin_ops dpll_pins_ops = {
const
>+ .frequency_get = ptp_ocp_dpll_frequency_get,
>+ .frequency_set = ptp_ocp_dpll_frequency_set,
>+ .direction_get = ptp_ocp_dpll_direction_get,
>+ .direction_set = ptp_ocp_dpll_direction_set,
>+};
>+
> static int
> ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> {
>+ struct dpll_pin_properties prop;
> struct devlink *devlink;
>+ char sma[4] = "SMA0";
Won't fit. Just use:
char *sma = "SMA0"
to be safe
> struct ptp_ocp *bp;
>- int err;
>+ int err, i;
>+ u64 clkid;
>
> devlink = devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev);
> if (!devlink) {
>@@ -4226,8 +4377,44 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>
> ptp_ocp_info(bp);
> devlink_register(devlink);
>- return 0;
>
>+ clkid = pci_get_dsn(pdev);
>+ bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE);
>+ if (!bp->dpll) {
>+ dev_err(&pdev->dev, "dpll_device_alloc failed\n");
>+ goto out;
>+ }
>+
>+ err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp, &pdev->dev);
>+ if (err)
>+ goto out;
>+
>+ prop.description = &sma[0];
>+ prop.freq_supported = DPLL_PIN_FREQ_SUPP_MAX;
>+ prop.type = DPLL_PIN_TYPE_EXT;
>+ prop.any_freq_max = 10000000;
>+ prop.any_freq_min = 0;
>+ prop.capabilities = DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE;
>+
>+ for (i = 0; i < 4; i++) {
>+ sma[3] = 0x31 + i;
Ugh. Just use the static const array as I suggested in the dpll patch
reply. Helps you avoid this sort of "magic".
>+ bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &prop);
>+ if (IS_ERR_OR_NULL(bp->sma[i].dpll_pin)) {
How it could be NULL?
>+ bp->sma[i].dpll_pin = NULL;
This would not be needed if the error path iterates over
indexes which were successul.
>+ goto out_dpll;
>+ }
>+ err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, bp, NULL);
>+ if (err)
>+ goto out_dpll;
>+ }
>+
>+ return 0;
>+out_dpll:
>+ for (i = 0; i < 4; i++) {
>+ if (bp->sma[i].dpll_pin)
You don't do unregister of pin here.
>+ dpll_pin_put(bp->sma[i].dpll_pin);
>+ }
>+ dpll_device_put(bp->dpll);
> out:
> ptp_ocp_detach(bp);
> out_disable:
>@@ -4243,6 +4430,8 @@ ptp_ocp_remove(struct pci_dev *pdev)
> struct ptp_ocp *bp = pci_get_drvdata(pdev);
> struct devlink *devlink = priv_to_devlink(bp);
>
>+ dpll_device_unregister(bp->dpll);
>+ dpll_device_put(bp->dpll);
> devlink_unregister(devlink);
> ptp_ocp_detach(bp);
> pci_disable_device(pdev);
>--
>2.34.1
>
next prev parent reply other threads:[~2023-03-14 10:05 UTC|newest]
Thread overview: 103+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-12 2:28 [PATCH RFC v6 0/6] Create common DPLL/clock configuration API Vadim Fedorenko
2023-03-12 2:28 ` [PATCH RFC v6 1/6] dpll: spec: Add Netlink spec in YAML Vadim Fedorenko
2023-03-14 14:44 ` Jiri Pirko
2023-03-16 13:15 ` Kubalewski, Arkadiusz
2023-03-16 13:45 ` Jiri Pirko
2023-03-16 15:19 ` Jiri Pirko
2023-03-17 0:53 ` Kubalewski, Arkadiusz
2023-03-17 10:07 ` Jiri Pirko
2023-03-17 0:52 ` Kubalewski, Arkadiusz
2023-03-17 10:05 ` Jiri Pirko
2023-03-17 14:29 ` Jiri Pirko
2023-03-17 15:14 ` Kubalewski, Arkadiusz
2023-03-17 16:20 ` Jiri Pirko
2023-03-17 18:22 ` Kubalewski, Arkadiusz
2023-03-20 8:10 ` Jiri Pirko
2023-03-21 4:05 ` Jakub Kicinski
2023-03-21 4:13 ` Jakub Kicinski
2023-03-21 4:20 ` Jakub Kicinski
2023-03-17 16:23 ` Jiri Pirko
2023-03-21 4:00 ` Jakub Kicinski
2023-03-17 16:53 ` Jiri Pirko
2023-03-17 18:50 ` Kubalewski, Arkadiusz
2023-03-12 2:28 ` [PATCH RFC v6 2/6] dpll: Add DPLL framework base functions Vadim Fedorenko
2023-03-13 16:21 ` Jiri Pirko
2023-03-13 22:59 ` Vadim Fedorenko
2023-03-14 9:21 ` Jiri Pirko
2023-03-14 17:50 ` Kubalewski, Arkadiusz
2023-03-15 9:22 ` Jiri Pirko
2023-03-16 12:31 ` Jiri Pirko
2023-03-28 15:22 ` Vadim Fedorenko
2023-04-01 12:49 ` Jiri Pirko
2023-04-03 18:18 ` Jakub Kicinski
2023-04-09 7:51 ` Jiri Pirko
[not found] ` <20230410153149.602c6bad@kernel.org>
2023-04-16 16:23 ` Jiri Pirko
2023-04-17 15:53 ` Vadim Fedorenko
[not found] ` <20230417124942.4305abfa@kernel.org>
[not found] ` <ZFDPaXlJainSOqmV@nanopsycho>
[not found] ` <20230502083244.19543d26@kernel.org>
2023-05-03 7:56 ` Jiri Pirko
2023-05-04 2:16 ` Jakub Kicinski
2023-05-04 11:00 ` Jiri Pirko
2023-05-04 11:14 ` Jiri Pirko
2023-05-04 16:04 ` Jakub Kicinski
2023-05-04 17:51 ` Jiri Pirko
2023-05-04 18:44 ` Jakub Kicinski
2023-05-05 10:41 ` Jiri Pirko
2023-05-05 15:35 ` Jakub Kicinski
2023-05-07 7:58 ` Jiri Pirko
2023-05-08 6:50 ` Paolo Abeni
2023-05-08 12:17 ` Jiri Pirko
2023-05-08 19:42 ` Jakub Kicinski
2023-05-09 7:53 ` Jiri Pirko
2023-05-09 14:52 ` Jakub Kicinski
2023-05-09 15:21 ` Jiri Pirko
2023-05-09 17:53 ` Jakub Kicinski
2023-05-10 6:17 ` Jiri Pirko
2023-03-14 16:43 ` Kubalewski, Arkadiusz
2023-03-15 12:14 ` Jiri Pirko
2023-03-14 9:30 ` Jiri Pirko
2023-03-14 15:45 ` Jiri Pirko
2023-03-14 18:35 ` Kubalewski, Arkadiusz
2023-03-15 14:43 ` Jiri Pirko
2023-03-15 15:29 ` Jiri Pirko
2023-03-16 12:20 ` Jiri Pirko
2023-03-16 12:37 ` Jiri Pirko
2023-03-16 13:53 ` Jiri Pirko
2023-03-16 16:16 ` Jiri Pirko
2023-03-17 16:21 ` Jiri Pirko
2023-03-20 10:24 ` Jiri Pirko
2023-03-21 13:34 ` Jiri Pirko
2023-03-23 11:18 ` Jiri Pirko
2023-03-24 9:29 ` Jiri Pirko
2023-03-12 2:28 ` [PATCH RFC v6 3/6] dpll: documentation on DPLL subsystem interface Vadim Fedorenko
2023-03-14 16:14 ` Jiri Pirko
2023-04-03 10:21 ` Kubalewski, Arkadiusz
2023-03-16 13:46 ` Jiri Pirko
2023-04-03 10:23 ` Kubalewski, Arkadiusz
2023-03-12 2:28 ` [PATCH RFC v6 4/6] ice: add admin commands to access cgu configuration Vadim Fedorenko
2023-03-12 2:28 ` [PATCH RFC v6 5/6] ice: implement dpll interface to control cgu Vadim Fedorenko
2023-03-12 2:28 ` [PATCH RFC v6 6/6] ptp_ocp: implement DPLL ops Vadim Fedorenko
2023-03-14 10:05 ` Jiri Pirko [this message]
2023-03-15 0:10 ` Vadim Fedorenko
2023-03-15 12:24 ` Jiri Pirko
2023-03-31 23:28 ` Vadim Fedorenko
2023-04-01 12:53 ` Jiri Pirko
2023-03-15 15:34 ` Jiri Pirko
2023-03-15 15:52 ` Vadim Fedorenko
2023-03-16 12:12 ` Jiri Pirko
2023-03-13 12:20 ` [PATCH RFC v6 0/6] Create common DPLL/clock configuration API Jiri Pirko
2023-03-13 15:33 ` Vadim Fedorenko
2023-03-13 16:22 ` Jiri Pirko
2023-03-13 16:31 ` Vadim Fedorenko
2023-03-17 16:10 ` Jiri Pirko
2023-03-18 5:01 ` Jakub Kicinski
2023-03-23 11:21 ` Jiri Pirko
2023-03-23 18:00 ` Vadim Fedorenko
2023-03-26 17:00 ` [patch dpll-rfc 0/7] dpll: initial patchset extension by mlx5 implementation Jiri Pirko
2023-03-26 17:00 ` [patch dpll-rfc 1/7] dpll: make ops function args const Jiri Pirko
2023-03-26 17:00 ` [patch dpll-rfc 2/7] dpll: allow to call device register multiple times Jiri Pirko
2023-03-26 17:00 ` [patch dpll-rfc 3/7] dpll: introduce a helper to get first dpll ref and use it Jiri Pirko
2023-03-26 17:00 ` [patch dpll-rfc 4/7] dpll: allow to call pin register multiple times Jiri Pirko
2023-03-26 17:00 ` [patch dpll-rfc 5/7] dpll: export dpll_pin_notify() Jiri Pirko
2023-03-26 17:00 ` [patch dpll-rfc 6/7] netdev: expose DPLL pin handle for netdevice Jiri Pirko
2023-03-26 17:00 ` [patch dpll-rfc 7/7] mlx5: Implement SyncE support using DPLL infrastructure Jiri Pirko
2023-03-28 16:36 ` [patch dpll-rfc 0/7] dpll: initial patchset extension by mlx5 implementation Vadim Fedorenko
2023-04-01 12:54 ` Jiri Pirko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZBBG2xRhLOIPMD0+@nanopsycho \
--to=jiri@resnulli.us \
--cc=arkadiusz.kubalewski@intel.com \
--cc=jonathan.lemon@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=mschmidt@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=poros@redhat.com \
--cc=vadfed@meta.com \
--cc=vadim.fedorenko@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).