ptp: ocp: Add firmware capability bits for feature gating
authorJonathan Lemon <jonathan.lemon@gmail.com>
Thu, 10 Mar 2022 20:19:07 +0000 (12:19 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 11 Mar 2022 11:54:45 +0000 (11:54 +0000)
Add the ability to group sysfs nodes behind a firmware feature
check.  This way non-present sysfs attributes are omitted on
older firmware, which does not have newer features.

This will be used in the upcoming patches which adds more
features to the timecard.

Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/ptp/ptp_ocp.c

index 1a4a284749eb55022196ad445a32025e06f45e49..0b43aaaf5286c860ef191e09b1332aa4ca949e5e 100644 (file)
@@ -218,6 +218,13 @@ struct ptp_ocp_sma_connector {
        bool    disabled;
 };
 
+struct ocp_attr_group {
+       u64 cap;
+       const struct attribute_group *group;
+};
+
+#define OCP_CAP_BASIC  BIT(0)
+
 #define OCP_BOARD_ID_LEN               13
 #define OCP_SERIAL_LEN                 6
 
@@ -248,6 +255,7 @@ struct ptp_ocp {
        struct platform_device  *spi_flash;
        struct clk_hw           *i2c_clk;
        struct timer_list       watchdog;
+       const struct ocp_attr_group *attr_tbl;
        const struct ptp_ocp_eeprom_map *eeprom_map;
        struct dentry           *debug_root;
        time64_t                gnss_lost;
@@ -265,6 +273,7 @@ struct ptp_ocp {
        int                     flash_start;
        u32                     utc_tai_offset;
        u32                     ts_window_adjust;
+       u64                     fw_cap;
        struct ptp_ocp_sma_connector sma[4];
 };
 
@@ -290,6 +299,8 @@ static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
 static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
 static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
 
+static const struct ocp_attr_group fb_timecard_groups[];
+
 struct ptp_ocp_eeprom_map {
        u16     off;
        u16     len;
@@ -1526,6 +1537,8 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
        bp->flash_start = 1024 * 4096;
        bp->eeprom_map = fb_eeprom_map;
        bp->fw_version = ioread32(&bp->image->version);
+       bp->attr_tbl = fb_timecard_groups;
+       bp->fw_cap = OCP_CAP_BASIC;
 
        ptp_ocp_tod_init(bp);
        ptp_ocp_nmea_out_init(bp);
@@ -2167,7 +2180,7 @@ tod_correction_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RW(tod_correction);
 
-static struct attribute *timecard_attrs[] = {
+static struct attribute *fb_timecard_attrs[] = {
        &dev_attr_serialnum.attr,
        &dev_attr_gnss_sync.attr,
        &dev_attr_clock_source.attr,
@@ -2186,7 +2199,13 @@ static struct attribute *timecard_attrs[] = {
        &dev_attr_tod_correction.attr,
        NULL,
 };
-ATTRIBUTE_GROUPS(timecard);
+static const struct attribute_group fb_timecard_group = {
+       .attrs = fb_timecard_attrs,
+};
+static const struct ocp_attr_group fb_timecard_groups[] = {
+       { .cap = OCP_CAP_BASIC,     .group = &fb_timecard_group },
+       { },
+};
 
 static void
 gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
@@ -2605,6 +2624,7 @@ ptp_ocp_complete(struct ptp_ocp *bp)
 {
        struct pps_device *pps;
        char buf[32];
+       int i, err;
 
        if (bp->gnss_port != -1) {
                sprintf(buf, "ttyS%d", bp->gnss_port);
@@ -2629,8 +2649,13 @@ ptp_ocp_complete(struct ptp_ocp *bp)
        if (pps)
                ptp_ocp_symlink(bp, pps->dev, "pps");
 
-       if (device_add_groups(&bp->dev, timecard_groups))
-               pr_err("device add groups failed\n");
+       for (i = 0; bp->attr_tbl[i].cap; i++) {
+               if (!(bp->attr_tbl[i].cap & bp->fw_cap))
+                       continue;
+               err = sysfs_create_group(&bp->dev.kobj, bp->attr_tbl[i].group);
+               if (err)
+                       return err;
+       }
 
        ptp_ocp_debugfs_add_device(bp);
 
@@ -2703,12 +2728,15 @@ static void
 ptp_ocp_detach_sysfs(struct ptp_ocp *bp)
 {
        struct device *dev = &bp->dev;
+       int i;
 
        sysfs_remove_link(&dev->kobj, "ttyGNSS");
        sysfs_remove_link(&dev->kobj, "ttyMAC");
        sysfs_remove_link(&dev->kobj, "ptp");
        sysfs_remove_link(&dev->kobj, "pps");
-       device_remove_groups(dev, timecard_groups);
+       if (bp->attr_tbl)
+               for (i = 0; bp->attr_tbl[i].cap; i++)
+                       sysfs_remove_group(&dev->kobj, bp->attr_tbl[i].group);
 }
 
 static void