diff options
Diffstat (limited to 'drivers/ptp')
-rw-r--r-- | drivers/ptp/ptp_clock.c | 11 | ||||
-rw-r--r-- | drivers/ptp/ptp_ocp.c | 232 | ||||
-rw-r--r-- | drivers/ptp/ptp_pch.c | 195 | ||||
-rw-r--r-- | drivers/ptp/ptp_sysfs.c | 4 | ||||
-rw-r--r-- | drivers/ptp/ptp_vclock.c | 56 |
5 files changed, 273 insertions, 225 deletions
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 0e4bc8b9329d..b6f2cfd15dd2 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -317,11 +317,18 @@ no_memory: } EXPORT_SYMBOL(ptp_clock_register); +static int unregister_vclock(struct device *dev, void *data) +{ + struct ptp_clock *ptp = dev_get_drvdata(dev); + + ptp_vclock_unregister(info_to_vclock(ptp->info)); + return 0; +} + int ptp_clock_unregister(struct ptp_clock *ptp) { if (ptp_vclock_in_use(ptp)) { - pr_err("ptp: virtual clock in use\n"); - return -EBUSY; + device_for_each_child(&ptp->dev, NULL, unregister_vclock); } ptp->defunct = 1; diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 17ad5f0d13b2..608d1a0eb141 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -52,6 +52,8 @@ struct ocp_reg { u32 servo_offset_i; u32 servo_drift_p; u32 servo_drift_i; + u32 status_offset; + u32 status_drift; }; #define OCP_CTRL_ENABLE BIT(0) @@ -88,9 +90,10 @@ struct tod_reg { #define TOD_CTRL_GNSS_MASK ((1U << 4) - 1) #define TOD_CTRL_GNSS_SHIFT 24 -#define TOD_STATUS_UTC_MASK 0xff -#define TOD_STATUS_UTC_VALID BIT(8) -#define TOD_STATUS_LEAP_VALID BIT(16) +#define TOD_STATUS_UTC_MASK 0xff +#define TOD_STATUS_UTC_VALID BIT(8) +#define TOD_STATUS_LEAP_ANNOUNCE BIT(12) +#define TOD_STATUS_LEAP_VALID BIT(16) struct ts_reg { u32 enable; @@ -760,11 +763,30 @@ __ptp_ocp_clear_drift_locked(struct ptp_ocp *bp) } static void +ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&bp->lock, flags); + + bp->utc_tai_offset = val; + + if (bp->irig_out) + iowrite32(val, &bp->irig_out->adj_sec); + if (bp->dcf_out) + iowrite32(val, &bp->dcf_out->adj_sec); + if (bp->nmea_out) + iowrite32(val, &bp->nmea_out->adj_sec); + + spin_unlock_irqrestore(&bp->lock, flags); +} + +static void ptp_ocp_watchdog(struct timer_list *t) { struct ptp_ocp *bp = from_timer(bp, t, watchdog); unsigned long flags; - u32 status; + u32 status, utc_offset; status = ioread32(&bp->pps_to_clk->status); @@ -781,6 +803,17 @@ ptp_ocp_watchdog(struct timer_list *t) bp->gnss_lost = 0; } + /* if GNSS provides correct data we can rely on + * it to get leap second information + */ + if (bp->tod) { + status = ioread32(&bp->tod->utc_status); + utc_offset = status & TOD_STATUS_UTC_MASK; + if (status & TOD_STATUS_UTC_VALID && + utc_offset != bp->utc_tai_offset) + ptp_ocp_utc_distribute(bp, utc_offset); + } + mod_timer(&bp->watchdog, jiffies + HZ); } @@ -850,25 +883,6 @@ ptp_ocp_init_clock(struct ptp_ocp *bp) } static void -ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val) -{ - unsigned long flags; - - spin_lock_irqsave(&bp->lock, flags); - - bp->utc_tai_offset = val; - - if (bp->irig_out) - iowrite32(val, &bp->irig_out->adj_sec); - if (bp->dcf_out) - iowrite32(val, &bp->dcf_out->adj_sec); - if (bp->nmea_out) - iowrite32(val, &bp->nmea_out->adj_sec); - - spin_unlock_irqrestore(&bp->lock, flags); -} - -static void ptp_ocp_tod_init(struct ptp_ocp *bp) { u32 ctrl, reg; @@ -883,45 +897,26 @@ ptp_ocp_tod_init(struct ptp_ocp *bp) ptp_ocp_utc_distribute(bp, reg & TOD_STATUS_UTC_MASK); } -static void -ptp_ocp_tod_info(struct ptp_ocp *bp) +static const char * +ptp_ocp_tod_proto_name(const int idx) { static const char * const proto_name[] = { "NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none", "UBX", "UBX_UTC", "UBX_LS", "UBX_none" }; + return proto_name[idx]; +} + +static const char * +ptp_ocp_tod_gnss_name(int idx) +{ static const char * const gnss_name[] = { "ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU", + "Unknown" }; - u32 version, ctrl, reg; - int idx; - - version = ioread32(&bp->tod->version); - dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n", - version >> 24, (version >> 16) & 0xff, version & 0xffff); - - ctrl = ioread32(&bp->tod->ctrl); - idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0; - idx += (ctrl >> 16) & 3; - dev_info(&bp->pdev->dev, "control: %x\n", ctrl); - dev_info(&bp->pdev->dev, "TOD Protocol %s %s\n", proto_name[idx], - ctrl & TOD_CTRL_ENABLE ? "enabled" : ""); - - idx = (ctrl >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK; - if (idx < ARRAY_SIZE(gnss_name)) - dev_info(&bp->pdev->dev, "GNSS %s\n", gnss_name[idx]); - - reg = ioread32(&bp->tod->status); - dev_info(&bp->pdev->dev, "status: %x\n", reg); - - reg = ioread32(&bp->tod->adj_sec); - dev_info(&bp->pdev->dev, "correction: %d\n", reg); - - reg = ioread32(&bp->tod->utc_status); - dev_info(&bp->pdev->dev, "utc_status: %x\n", reg); - dev_info(&bp->pdev->dev, "utc_offset: %d valid:%d leap_valid:%d\n", - reg & TOD_STATUS_UTC_MASK, reg & TOD_STATUS_UTC_VALID ? 1 : 0, - reg & TOD_STATUS_LEAP_VALID ? 1 : 0); + if (idx > ARRAY_SIZE(gnss_name)) + idx = ARRAY_SIZE(gnss_name) - 1; + return gnss_name[idx]; } static int @@ -1974,6 +1969,76 @@ available_clock_sources_show(struct device *dev, } static DEVICE_ATTR_RO(available_clock_sources); +static ssize_t +clock_status_drift_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ptp_ocp *bp = dev_get_drvdata(dev); + u32 val; + int res; + + val = ioread32(&bp->reg->status_drift); + res = (val & ~INT_MAX) ? -1 : 1; + res *= (val & INT_MAX); + return sysfs_emit(buf, "%d\n", res); +} +static DEVICE_ATTR_RO(clock_status_drift); + +static ssize_t +clock_status_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ptp_ocp *bp = dev_get_drvdata(dev); + u32 val; + int res; + + val = ioread32(&bp->reg->status_offset); + res = (val & ~INT_MAX) ? -1 : 1; + res *= (val & INT_MAX); + return sysfs_emit(buf, "%d\n", res); +} +static DEVICE_ATTR_RO(clock_status_offset); + +static ssize_t +tod_correction_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ptp_ocp *bp = dev_get_drvdata(dev); + u32 val; + int res; + + val = ioread32(&bp->tod->adj_sec); + res = (val & ~INT_MAX) ? -1 : 1; + res *= (val & INT_MAX); + return sysfs_emit(buf, "%d\n", res); +} + +static ssize_t +tod_correction_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ptp_ocp *bp = dev_get_drvdata(dev); + unsigned long flags; + int err, res; + u32 val = 0; + + err = kstrtos32(buf, 0, &res); + if (err) + return err; + if (res < 0) { + res *= -1; + val |= BIT(31); + } + val |= res; + + spin_lock_irqsave(&bp->lock, flags); + iowrite32(val, &bp->tod->adj_sec); + spin_unlock_irqrestore(&bp->lock, flags); + + return count; +} +static DEVICE_ATTR_RW(tod_correction); + static struct attribute *timecard_attrs[] = { &dev_attr_serialnum.attr, &dev_attr_gnss_sync.attr, @@ -1985,9 +2050,12 @@ static struct attribute *timecard_attrs[] = { &dev_attr_sma4.attr, &dev_attr_available_sma_inputs.attr, &dev_attr_available_sma_outputs.attr, + &dev_attr_clock_status_drift.attr, + &dev_attr_clock_status_offset.attr, &dev_attr_irig_b_mode.attr, &dev_attr_utc_tai_offset.attr, &dev_attr_ts_window_adjust.attr, + &dev_attr_tod_correction.attr, NULL, }; ATTRIBUTE_GROUPS(timecard); @@ -2200,6 +2268,57 @@ ptp_ocp_summary_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary); +static int +ptp_ocp_tod_status_show(struct seq_file *s, void *data) +{ + struct device *dev = s->private; + struct ptp_ocp *bp; + u32 val; + int idx; + + bp = dev_get_drvdata(dev); + + val = ioread32(&bp->tod->ctrl); + if (!(val & TOD_CTRL_ENABLE)) { + seq_printf(s, "TOD Slave disabled\n"); + return 0; + } + seq_printf(s, "TOD Slave enabled, Control Register 0x%08X\n", val); + + idx = val & TOD_CTRL_PROTOCOL ? 4 : 0; + idx += (val >> 16) & 3; + seq_printf(s, "Protocol %s\n", ptp_ocp_tod_proto_name(idx)); + + idx = (val >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK; + seq_printf(s, "GNSS %s\n", ptp_ocp_tod_gnss_name(idx)); + + val = ioread32(&bp->tod->version); + seq_printf(s, "TOD Version %d.%d.%d\n", + val >> 24, (val >> 16) & 0xff, val & 0xffff); + + val = ioread32(&bp->tod->status); + seq_printf(s, "Status register: 0x%08X\n", val); + + val = ioread32(&bp->tod->adj_sec); + idx = (val & ~INT_MAX) ? -1 : 1; + idx *= (val & INT_MAX); + seq_printf(s, "Correction seconds: %d\n", idx); + + val = ioread32(&bp->tod->utc_status); + seq_printf(s, "UTC status register: 0x%08X\n", val); + seq_printf(s, "UTC offset: %d valid:%d\n", + val & TOD_STATUS_UTC_MASK, val & TOD_STATUS_UTC_VALID ? 1 : 0); + seq_printf(s, "Leap second info valid:%d, Leap second announce %d\n", + val & TOD_STATUS_LEAP_VALID ? 1 : 0, + val & TOD_STATUS_LEAP_ANNOUNCE ? 1 : 0); + + val = ioread32(&bp->tod->leap); + seq_printf(s, "Time to next leap second (in sec): %d\n", (s32) val); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ptp_ocp_tod_status); + static struct dentry *ptp_ocp_debugfs_root; static void @@ -2211,6 +2330,9 @@ ptp_ocp_debugfs_add_device(struct ptp_ocp *bp) bp->debug_root = d; debugfs_create_file("summary", 0444, bp->debug_root, &bp->dev, &ptp_ocp_summary_fops); + if (bp->tod) + debugfs_create_file("tod_status", 0444, bp->debug_root, + &bp->dev, &ptp_ocp_tod_status_fops); } static void @@ -2389,8 +2511,6 @@ ptp_ocp_info(struct ptp_ocp *bp) u32 reg; ptp_ocp_phc_info(bp); - if (bp->tod) - ptp_ocp_tod_info(bp); if (bp->image) { u32 ver = ioread32(&bp->image->version); diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c index 8070f3fd98f0..7d4da9e605ef 100644 --- a/drivers/ptp/ptp_pch.c +++ b/drivers/ptp/ptp_pch.c @@ -10,9 +10,10 @@ #include <linux/device.h> #include <linux/err.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/io-64-nonatomic-hi-lo.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> @@ -100,7 +101,6 @@ struct pch_ts_regs { #define PCH_ECS_ETH (1 << 0) #define PCH_ECS_CAN (1 << 1) -#define PCH_STATION_BYTES 6 #define PCH_IEEE1588_ETH (1 << 0) #define PCH_IEEE1588_CAN (1 << 1) @@ -115,8 +115,6 @@ struct pch_dev { int exts0_enabled; int exts1_enabled; - u32 mem_base; - u32 mem_size; u32 irq; struct pci_dev *pdev; spinlock_t register_lock; @@ -148,28 +146,15 @@ static inline void pch_eth_enable_set(struct pch_dev *chip) static u64 pch_systime_read(struct pch_ts_regs __iomem *regs) { u64 ns; - u32 lo, hi; - lo = ioread32(®s->systime_lo); - hi = ioread32(®s->systime_hi); + ns = ioread64_lo_hi(®s->systime_lo); - ns = ((u64) hi) << 32; - ns |= lo; - ns <<= TICKS_NS_SHIFT; - - return ns; + return ns << TICKS_NS_SHIFT; } static void pch_systime_write(struct pch_ts_regs __iomem *regs, u64 ns) { - u32 hi, lo; - - ns >>= TICKS_NS_SHIFT; - hi = ns >> 32; - lo = ns & 0xffffffff; - - iowrite32(lo, ®s->systime_lo); - iowrite32(hi, ®s->systime_hi); + iowrite64_lo_hi(ns >> TICKS_NS_SHIFT, ®s->systime_lo); } static inline void pch_block_reset(struct pch_dev *chip) @@ -235,16 +220,10 @@ u64 pch_rx_snap_read(struct pci_dev *pdev) { struct pch_dev *chip = pci_get_drvdata(pdev); u64 ns; - u32 lo, hi; - lo = ioread32(&chip->regs->rx_snap_lo); - hi = ioread32(&chip->regs->rx_snap_hi); + ns = ioread64_lo_hi(&chip->regs->rx_snap_lo); - ns = ((u64) hi) << 32; - ns |= lo; - ns <<= TICKS_NS_SHIFT; - - return ns; + return ns << TICKS_NS_SHIFT; } EXPORT_SYMBOL(pch_rx_snap_read); @@ -252,16 +231,10 @@ u64 pch_tx_snap_read(struct pci_dev *pdev) { struct pch_dev *chip = pci_get_drvdata(pdev); u64 ns; - u32 lo, hi; - - lo = ioread32(&chip->regs->tx_snap_lo); - hi = ioread32(&chip->regs->tx_snap_hi); - ns = ((u64) hi) << 32; - ns |= lo; - ns <<= TICKS_NS_SHIFT; + ns = ioread64_lo_hi(&chip->regs->tx_snap_lo); - return ns; + return ns << TICKS_NS_SHIFT; } EXPORT_SYMBOL(pch_tx_snap_read); @@ -292,8 +265,9 @@ static void pch_reset(struct pch_dev *chip) */ int pch_set_station_address(u8 *addr, struct pci_dev *pdev) { - s32 i; struct pch_dev *chip = pci_get_drvdata(pdev); + bool valid; + u64 mac; /* Verify the parameter */ if ((chip->regs == NULL) || addr == (u8 *)NULL) { @@ -301,37 +275,15 @@ int pch_set_station_address(u8 *addr, struct pci_dev *pdev) "invalid params returning PCH_INVALIDPARAM\n"); return PCH_INVALIDPARAM; } - /* For all station address bytes */ - for (i = 0; i < PCH_STATION_BYTES; i++) { - u32 val; - s32 tmp; - - tmp = hex_to_bin(addr[i * 3]); - if (tmp < 0) { - dev_err(&pdev->dev, - "invalid params returning PCH_INVALIDPARAM\n"); - return PCH_INVALIDPARAM; - } - val = tmp * 16; - tmp = hex_to_bin(addr[(i * 3) + 1]); - if (tmp < 0) { - dev_err(&pdev->dev, - "invalid params returning PCH_INVALIDPARAM\n"); - return PCH_INVALIDPARAM; - } - val += tmp; - /* Expects ':' separated addresses */ - if ((i < 5) && (addr[(i * 3) + 2] != ':')) { - dev_err(&pdev->dev, - "invalid params returning PCH_INVALIDPARAM\n"); - return PCH_INVALIDPARAM; - } - /* Ideally we should set the address only after validating - entire string */ - dev_dbg(&pdev->dev, "invoking pch_station_set\n"); - iowrite32(val, &chip->regs->ts_st[i]); + valid = mac_pton(addr, (u8 *)&mac); + if (!valid) { + dev_err(&pdev->dev, "invalid params returning PCH_INVALIDPARAM\n"); + return PCH_INVALIDPARAM; } + + dev_dbg(&pdev->dev, "invoking pch_station_set\n"); + iowrite64_lo_hi(mac, &chip->regs->ts_st); return 0; } EXPORT_SYMBOL(pch_set_station_address); @@ -344,19 +296,16 @@ static irqreturn_t isr(int irq, void *priv) struct pch_dev *pch_dev = priv; struct pch_ts_regs __iomem *regs = pch_dev->regs; struct ptp_clock_event event; - u32 ack = 0, lo, hi, val; + u32 ack = 0, val; val = ioread32(®s->event); if (val & PCH_TSE_SNS) { ack |= PCH_TSE_SNS; if (pch_dev->exts0_enabled) { - hi = ioread32(®s->asms_hi); - lo = ioread32(®s->asms_lo); event.type = PTP_CLOCK_EXTTS; event.index = 0; - event.timestamp = ((u64) hi) << 32; - event.timestamp |= lo; + event.timestamp = ioread64_hi_lo(®s->asms_hi); event.timestamp <<= TICKS_NS_SHIFT; ptp_clock_event(pch_dev->ptp_clock, &event); } @@ -365,12 +314,9 @@ static irqreturn_t isr(int irq, void *priv) if (val & PCH_TSE_SNM) { ack |= PCH_TSE_SNM; if (pch_dev->exts1_enabled) { - hi = ioread32(®s->amms_hi); - lo = ioread32(®s->amms_lo); event.type = PTP_CLOCK_EXTTS; event.index = 1; - event.timestamp = ((u64) hi) << 32; - event.timestamp |= lo; + event.timestamp = ioread64_hi_lo(®s->asms_hi); event.timestamp <<= TICKS_NS_SHIFT; ptp_clock_event(pch_dev->ptp_clock, &event); } @@ -501,31 +447,12 @@ static const struct ptp_clock_info ptp_pch_caps = { .enable = ptp_pch_enable, }; -#define pch_suspend NULL -#define pch_resume NULL - static void pch_remove(struct pci_dev *pdev) { struct pch_dev *chip = pci_get_drvdata(pdev); + free_irq(pdev->irq, chip); ptp_clock_unregister(chip->ptp_clock); - /* free the interrupt */ - if (pdev->irq != 0) - free_irq(pdev->irq, chip); - - /* unmap the virtual IO memory space */ - if (chip->regs != NULL) { - iounmap(chip->regs); - chip->regs = NULL; - } - /* release the reserved IO memory space */ - if (chip->mem_base != 0) { - release_mem_region(chip->mem_base, chip->mem_size); - chip->mem_base = 0; - } - pci_disable_device(pdev); - kfree(chip); - dev_info(&pdev->dev, "complete\n"); } static s32 @@ -535,50 +462,29 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) unsigned long flags; struct pch_dev *chip; - chip = kzalloc(sizeof(struct pch_dev), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; /* enable the 1588 pci device */ - ret = pci_enable_device(pdev); + ret = pcim_enable_device(pdev); if (ret != 0) { dev_err(&pdev->dev, "could not enable the pci device\n"); - goto err_pci_en; + return ret; } - chip->mem_base = pci_resource_start(pdev, IO_MEM_BAR); - if (!chip->mem_base) { + ret = pcim_iomap_regions(pdev, BIT(IO_MEM_BAR), "1588_regs"); + if (ret) { dev_err(&pdev->dev, "could not locate IO memory address\n"); - ret = -ENODEV; - goto err_pci_start; - } - - /* retrieve the available length of the IO memory space */ - chip->mem_size = pci_resource_len(pdev, IO_MEM_BAR); - - /* allocate the memory for the device registers */ - if (!request_mem_region(chip->mem_base, chip->mem_size, "1588_regs")) { - dev_err(&pdev->dev, - "could not allocate register memory space\n"); - ret = -EBUSY; - goto err_req_mem_region; + return ret; } /* get the virtual address to the 1588 registers */ - chip->regs = ioremap(chip->mem_base, chip->mem_size); - - if (!chip->regs) { - dev_err(&pdev->dev, "Could not get virtual address\n"); - ret = -ENOMEM; - goto err_ioremap; - } - + chip->regs = pcim_iomap_table(pdev)[IO_MEM_BAR]; chip->caps = ptp_pch_caps; chip->ptp_clock = ptp_clock_register(&chip->caps, &pdev->dev); - if (IS_ERR(chip->ptp_clock)) { - ret = PTR_ERR(chip->ptp_clock); - goto err_ptp_clock_reg; - } + if (IS_ERR(chip->ptp_clock)) + return PTR_ERR(chip->ptp_clock); spin_lock_init(&chip->register_lock); @@ -598,8 +504,7 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) pch_reset(chip); iowrite32(DEFAULT_ADDEND, &chip->regs->addend); - iowrite32(1, &chip->regs->trgt_lo); - iowrite32(0, &chip->regs->trgt_hi); + iowrite64_lo_hi(1, &chip->regs->trgt_lo); iowrite32(PCH_TSE_TTIPEND, &chip->regs->event); pch_eth_enable_set(chip); @@ -617,21 +522,7 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_req_irq: ptp_clock_unregister(chip->ptp_clock); -err_ptp_clock_reg: - iounmap(chip->regs); - chip->regs = NULL; -err_ioremap: - release_mem_region(chip->mem_base, chip->mem_size); - -err_req_mem_region: - chip->mem_base = 0; - -err_pci_start: - pci_disable_device(pdev); - -err_pci_en: - kfree(chip); dev_err(&pdev->dev, "probe failed(ret=0x%x)\n", ret); return ret; @@ -646,33 +537,13 @@ static const struct pci_device_id pch_ieee1588_pcidev_id[] = { }; MODULE_DEVICE_TABLE(pci, pch_ieee1588_pcidev_id); -static SIMPLE_DEV_PM_OPS(pch_pm_ops, pch_suspend, pch_resume); - static struct pci_driver pch_driver = { .name = KBUILD_MODNAME, .id_table = pch_ieee1588_pcidev_id, .probe = pch_probe, .remove = pch_remove, - .driver.pm = &pch_pm_ops, }; - -static void __exit ptp_pch_exit(void) -{ - pci_unregister_driver(&pch_driver); -} - -static s32 __init ptp_pch_init(void) -{ - s32 ret; - - /* register the driver with the pci core */ - ret = pci_register_driver(&pch_driver); - - return ret; -} - -module_init(ptp_pch_init); -module_exit(ptp_pch_exit); +module_pci_driver(pch_driver); module_param_string(station, pch_param.station, sizeof(pch_param.station), 0444); diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c index 41b92dc2f011..9233bfedeb17 100644 --- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -14,7 +14,7 @@ static ssize_t clock_name_show(struct device *dev, struct device_attribute *attr, char *page) { struct ptp_clock *ptp = dev_get_drvdata(dev); - return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name); + return sysfs_emit(page, "%s\n", ptp->info->name); } static DEVICE_ATTR_RO(clock_name); @@ -387,7 +387,7 @@ static ssize_t ptp_pin_show(struct device *dev, struct device_attribute *attr, mutex_unlock(&ptp->pincfg_mux); - return snprintf(page, PAGE_SIZE, "%u %u\n", func, chan); + return sysfs_emit(page, "%u %u\n", func, chan); } static ssize_t ptp_pin_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c index ab1d233173e1..cb179a3ea508 100644 --- a/drivers/ptp/ptp_vclock.c +++ b/drivers/ptp/ptp_vclock.c @@ -57,6 +57,30 @@ static int ptp_vclock_gettime(struct ptp_clock_info *ptp, return 0; } +static int ptp_vclock_gettimex(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct ptp_vclock *vclock = info_to_vclock(ptp); + struct ptp_clock *pptp = vclock->pclock; + struct timespec64 pts; + unsigned long flags; + int err; + u64 ns; + + err = pptp->info->gettimex64(pptp->info, &pts, sts); + if (err) + return err; + + spin_lock_irqsave(&vclock->lock, flags); + ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts)); + spin_unlock_irqrestore(&vclock->lock, flags); + + *ts = ns_to_timespec64(ns); + + return 0; +} + static int ptp_vclock_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { @@ -71,6 +95,28 @@ static int ptp_vclock_settime(struct ptp_clock_info *ptp, return 0; } +static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp, + struct system_device_crosststamp *xtstamp) +{ + struct ptp_vclock *vclock = info_to_vclock(ptp); + struct ptp_clock *pptp = vclock->pclock; + unsigned long flags; + int err; + u64 ns; + + err = pptp->info->getcrosststamp(pptp->info, xtstamp); + if (err) + return err; + + spin_lock_irqsave(&vclock->lock, flags); + ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device)); + spin_unlock_irqrestore(&vclock->lock, flags); + + xtstamp->device = ns_to_ktime(ns); + + return 0; +} + static long ptp_vclock_refresh(struct ptp_clock_info *ptp) { struct ptp_vclock *vclock = info_to_vclock(ptp); @@ -84,11 +130,9 @@ static long ptp_vclock_refresh(struct ptp_clock_info *ptp) static const struct ptp_clock_info ptp_vclock_info = { .owner = THIS_MODULE, .name = "ptp virtual clock", - /* The maximum ppb value that long scaled_ppm can support */ - .max_adj = 32767999, + .max_adj = 500000000, .adjfine = ptp_vclock_adjfine, .adjtime = ptp_vclock_adjtime, - .gettime64 = ptp_vclock_gettime, .settime64 = ptp_vclock_settime, .do_aux_work = ptp_vclock_refresh, }; @@ -124,6 +168,12 @@ struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock) vclock->pclock = pclock; vclock->info = ptp_vclock_info; + if (pclock->info->gettimex64) + vclock->info.gettimex64 = ptp_vclock_gettimex; + else + vclock->info.gettime64 = ptp_vclock_gettime; + if (pclock->info->getcrosststamp) + vclock->info.getcrosststamp = ptp_vclock_getcrosststamp; vclock->cc = ptp_vclock_cc; snprintf(vclock->info.name, PTP_CLOCK_NAME_LEN, "ptp%d_virt", |