From 895ac5a51fe280e9898e212da7803ec9babf137f Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Fri, 21 Oct 2022 02:24:29 +0300 Subject: ptp: ocp: upgrade serial line information Introduce structure to hold serial port line number and the baud rate it supports. Acked-by: Jonathan Lemon Signed-off-by: Jonathan Lemon Signed-off-by: Vadim Fedorenko Signed-off-by: David S. Miller --- drivers/ptp/ptp_ocp.c | 110 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 43 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index a48d9b7d2921..1ce0f2989a85 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -278,6 +278,11 @@ struct ptp_ocp_signal { bool running; }; +struct ptp_ocp_serial_port { + int line; + int baud; +}; + #define OCP_BOARD_ID_LEN 13 #define OCP_SERIAL_LEN 6 @@ -318,10 +323,10 @@ struct ptp_ocp { time64_t gnss_lost; int id; int n_irqs; - int gnss_port; - int gnss2_port; - int mac_port; /* miniature atomic clock */ - int nmea_port; + struct ptp_ocp_serial_port gnss_port; + struct ptp_ocp_serial_port gnss2_port; + struct ptp_ocp_serial_port mac_port; /* miniature atomic clock */ + struct ptp_ocp_serial_port nmea_port; bool fw_loader; u8 fw_tag; u16 fw_version; @@ -596,14 +601,23 @@ static struct ocp_resource ocp_fb_resource[] = { { OCP_SERIAL_RESOURCE(gnss_port), .offset = 0x00160000 + 0x1000, .irq_vec = 3, + .extra = &(struct ptp_ocp_serial_port) { + .baud = 115200, + }, }, { OCP_SERIAL_RESOURCE(gnss2_port), .offset = 0x00170000 + 0x1000, .irq_vec = 4, + .extra = &(struct ptp_ocp_serial_port) { + .baud = 115200, + }, }, { OCP_SERIAL_RESOURCE(mac_port), .offset = 0x00180000 + 0x1000, .irq_vec = 5, + .extra = &(struct ptp_ocp_serial_port) { + .baud = 57600, + }, }, { OCP_SERIAL_RESOURCE(nmea_port), @@ -1872,11 +1886,15 @@ ptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r) static int ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r) { - int port; + struct ptp_ocp_serial_port *p = (struct ptp_ocp_serial_port *)r->extra; + struct ptp_ocp_serial_port port = {}; + + port.line = ptp_ocp_serial_line(bp, r); + if (port.line < 0) + return port.line; - port = ptp_ocp_serial_line(bp, r); - if (port < 0) - return port; + if (p) + port.baud = p->baud; bp_assign_entry(bp, r, port); @@ -3177,14 +3195,16 @@ ptp_ocp_summary_show(struct seq_file *s, void *data) bp = dev_get_drvdata(dev); seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp)); - if (bp->gnss_port != -1) - seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS1", bp->gnss_port); - if (bp->gnss2_port != -1) - seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS2", bp->gnss2_port); - if (bp->mac_port != -1) - seq_printf(s, "%7s: /dev/ttyS%d\n", "MAC", bp->mac_port); - if (bp->nmea_port != -1) - seq_printf(s, "%7s: /dev/ttyS%d\n", "NMEA", bp->nmea_port); + if (bp->gnss_port.line != -1) + seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS1", + bp->gnss_port.line); + if (bp->gnss2_port.line != -1) + seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS2", + bp->gnss2_port.line); + if (bp->mac_port.line != -1) + seq_printf(s, "%7s: /dev/ttyS%d\n", "MAC", bp->mac_port.line); + if (bp->nmea_port.line != -1) + seq_printf(s, "%7s: /dev/ttyS%d\n", "NMEA", bp->nmea_port.line); memset(sma_val, 0xff, sizeof(sma_val)); if (bp->sma_map1) { @@ -3508,10 +3528,10 @@ ptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev) bp->ptp_info = ptp_ocp_clock_info; spin_lock_init(&bp->lock); - bp->gnss_port = -1; - bp->gnss2_port = -1; - bp->mac_port = -1; - bp->nmea_port = -1; + bp->gnss_port.line = -1; + bp->gnss2_port.line = -1; + bp->mac_port.line = -1; + bp->nmea_port.line = -1; bp->pdev = pdev; device_initialize(&bp->dev); @@ -3569,20 +3589,20 @@ ptp_ocp_complete(struct ptp_ocp *bp) struct pps_device *pps; char buf[32]; - if (bp->gnss_port != -1) { - sprintf(buf, "ttyS%d", bp->gnss_port); + if (bp->gnss_port.line != -1) { + sprintf(buf, "ttyS%d", bp->gnss_port.line); ptp_ocp_link_child(bp, buf, "ttyGNSS"); } - if (bp->gnss2_port != -1) { - sprintf(buf, "ttyS%d", bp->gnss2_port); + if (bp->gnss2_port.line != -1) { + sprintf(buf, "ttyS%d", bp->gnss2_port.line); ptp_ocp_link_child(bp, buf, "ttyGNSS2"); } - if (bp->mac_port != -1) { - sprintf(buf, "ttyS%d", bp->mac_port); + if (bp->mac_port.line != -1) { + sprintf(buf, "ttyS%d", bp->mac_port.line); ptp_ocp_link_child(bp, buf, "ttyMAC"); } - if (bp->nmea_port != -1) { - sprintf(buf, "ttyS%d", bp->nmea_port); + if (bp->nmea_port.line != -1) { + sprintf(buf, "ttyS%d", bp->nmea_port.line); ptp_ocp_link_child(bp, buf, "ttyNMEA"); } sprintf(buf, "ptp%d", ptp_clock_index(bp->ptp)); @@ -3638,16 +3658,20 @@ ptp_ocp_info(struct ptp_ocp *bp) ptp_ocp_phc_info(bp); - ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port, 115200); - ptp_ocp_serial_info(dev, "GNSS2", bp->gnss2_port, 115200); - ptp_ocp_serial_info(dev, "MAC", bp->mac_port, 57600); - if (bp->nmea_out && bp->nmea_port != -1) { - int baud = -1; + ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port.line, + bp->gnss_port.baud); + ptp_ocp_serial_info(dev, "GNSS2", bp->gnss2_port.line, + bp->gnss2_port.baud); + ptp_ocp_serial_info(dev, "MAC", bp->mac_port.line, bp->mac_port.baud); + if (bp->nmea_out && bp->nmea_port.line != -1) { + bp->nmea_port.baud = -1; reg = ioread32(&bp->nmea_out->uart_baud); if (reg < ARRAY_SIZE(nmea_baud)) - baud = nmea_baud[reg]; - ptp_ocp_serial_info(dev, "NMEA", bp->nmea_port, baud); + bp->nmea_port.baud = nmea_baud[reg]; + + ptp_ocp_serial_info(dev, "NMEA", bp->nmea_port.line, + bp->nmea_port.baud); } } @@ -3688,14 +3712,14 @@ ptp_ocp_detach(struct ptp_ocp *bp) for (i = 0; i < 4; i++) if (bp->signal_out[i]) ptp_ocp_unregister_ext(bp->signal_out[i]); - if (bp->gnss_port != -1) - serial8250_unregister_port(bp->gnss_port); - if (bp->gnss2_port != -1) - serial8250_unregister_port(bp->gnss2_port); - if (bp->mac_port != -1) - serial8250_unregister_port(bp->mac_port); - if (bp->nmea_port != -1) - serial8250_unregister_port(bp->nmea_port); + if (bp->gnss_port.line != -1) + serial8250_unregister_port(bp->gnss_port.line); + if (bp->gnss2_port.line != -1) + serial8250_unregister_port(bp->gnss2_port.line); + if (bp->mac_port.line != -1) + serial8250_unregister_port(bp->mac_port.line); + if (bp->nmea_port.line != -1) + serial8250_unregister_port(bp->nmea_port.line); platform_device_unregister(bp->spi_flash); platform_device_unregister(bp->i2c_ctrl); if (bp->i2c_clk) -- cgit v1.2.3 From 69dbe1079cd015d0c96ec488289981ab5663b640 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Fri, 21 Oct 2022 02:24:30 +0300 Subject: ptp: ocp: add Orolia timecard support This brings in the Orolia timecard support from the GitHub repository. The card uses different drivers to provide access to i2c EEPROM and firmware SPI flash. And it also has a bit different EEPROM map, but other parts of the code are the same and could be reused. Co-developed-by: Charles Parent Acked-by: Jonathan Lemon Signed-off-by: Jonathan Lemon Signed-off-by: Vadim Fedorenko Signed-off-by: David S. Miller --- drivers/ptp/ptp_ocp.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 1ce0f2989a85..8c1ce630b67f 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -13,9 +13,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -28,6 +30,9 @@ #define PCI_VENDOR_ID_CELESTICA 0x18d4 #define PCI_DEVICE_ID_CELESTICA_TIMECARD 0x1008 +#define PCI_VENDOR_ID_OROLIA 0x1ad7 +#define PCI_DEVICE_ID_OROLIA_ARTCARD 0xa000 + static struct class timecard_class = { .owner = THIS_MODULE, .name = "timecard", @@ -310,6 +315,7 @@ struct ptp_ocp { struct ptp_ocp_ext_src *ts2; struct ptp_ocp_ext_src *ts3; struct ptp_ocp_ext_src *ts4; + struct ocp_art_gpio_reg __iomem *art_sma; struct img_reg __iomem *image; struct ptp_clock *ptp; struct ptp_clock_info ptp_info; @@ -370,8 +376,12 @@ static int ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen, static int ptp_ocp_signal_enable(void *priv, u32 req, bool enable); static int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr); +static int ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r); + static const struct ocp_attr_group fb_timecard_groups[]; +static const struct ocp_attr_group art_timecard_groups[]; + struct ptp_ocp_eeprom_map { u16 off; u16 len; @@ -394,6 +404,12 @@ static struct ptp_ocp_eeprom_map fb_eeprom_map[] = { { } }; +static struct ptp_ocp_eeprom_map art_eeprom_map[] = { + { EEPROM_ENTRY(0x200 + 0x43, board_id) }, + { EEPROM_ENTRY(0x200 + 0x63, serial) }, + { } +}; + #define bp_assign_entry(bp, res, val) ({ \ uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset; \ *(typeof(val) *)addr = val; \ @@ -435,6 +451,13 @@ static struct ptp_ocp_eeprom_map fb_eeprom_map[] = { * 14: Signal Generator 4 * 15: TS3 * 16: TS4 + -- + * 8: Orolia TS1 + * 10: Orolia TS2 + * 11: Orolia TS0 (GNSS) + * 12: Orolia PPS + * 14: Orolia TS3 + * 15: Orolia TS4 */ static struct ocp_resource ocp_fb_resource[] = { @@ -661,9 +684,127 @@ static struct ocp_resource ocp_fb_resource[] = { { } }; +struct ocp_art_gpio_reg { + struct { + u32 gpio; + u32 __pad[3]; + } map[4]; +}; + +static struct ocp_resource ocp_art_resource[] = { + { + OCP_MEM_RESOURCE(reg), + .offset = 0x01000000, .size = 0x10000, + }, + { + OCP_SERIAL_RESOURCE(gnss_port), + .offset = 0x00160000 + 0x1000, .irq_vec = 3, + .extra = &(struct ptp_ocp_serial_port) { + .baud = 115200, + }, + }, + { + OCP_MEM_RESOURCE(art_sma), + .offset = 0x003C0000, .size = 0x1000, + }, + /* Timestamp associated with GNSS1 receiver PPS */ + { + OCP_EXT_RESOURCE(ts0), + .offset = 0x360000, .size = 0x20, .irq_vec = 12, + .extra = &(struct ptp_ocp_ext_info) { + .index = 0, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_EXT_RESOURCE(ts1), + .offset = 0x380000, .size = 0x20, .irq_vec = 8, + .extra = &(struct ptp_ocp_ext_info) { + .index = 1, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_EXT_RESOURCE(ts2), + .offset = 0x390000, .size = 0x20, .irq_vec = 10, + .extra = &(struct ptp_ocp_ext_info) { + .index = 2, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_EXT_RESOURCE(ts3), + .offset = 0x3A0000, .size = 0x20, .irq_vec = 14, + .extra = &(struct ptp_ocp_ext_info) { + .index = 3, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_EXT_RESOURCE(ts4), + .offset = 0x3B0000, .size = 0x20, .irq_vec = 15, + .extra = &(struct ptp_ocp_ext_info) { + .index = 4, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + /* Timestamp associated with Internal PPS of the card */ + { + OCP_EXT_RESOURCE(pps), + .offset = 0x00330000, .size = 0x20, .irq_vec = 11, + .extra = &(struct ptp_ocp_ext_info) { + .index = 5, + .irq_fcn = ptp_ocp_ts_irq, + .enable = ptp_ocp_ts_enable, + }, + }, + { + OCP_SPI_RESOURCE(spi_flash), + .offset = 0x00310000, .size = 0x10000, .irq_vec = 9, + .extra = &(struct ptp_ocp_flash_info) { + .name = "spi_altera", .pci_offset = 0, + .data_size = sizeof(struct altera_spi_platform_data), + .data = &(struct altera_spi_platform_data) { + .num_chipselect = 1, + .num_devices = 1, + .devices = &(struct spi_board_info) { + .modalias = "spi-nor", + }, + }, + }, + }, + { + OCP_I2C_RESOURCE(i2c_ctrl), + .offset = 0x350000, .size = 0x100, .irq_vec = 4, + .extra = &(struct ptp_ocp_i2c_info) { + .name = "ocores-i2c", + .fixed_rate = 400000, + .data_size = sizeof(struct ocores_i2c_platform_data), + .data = &(struct ocores_i2c_platform_data) { + .clock_khz = 125000, + .bus_khz = 400, + .num_devices = 1, + .devices = &(struct i2c_board_info) { + I2C_BOARD_INFO("24c08", 0x50), + }, + }, + }, + }, + { + .setup = ptp_ocp_art_board_init, + }, + { } +}; + static const struct pci_device_id ptp_ocp_pcidev_id[] = { { PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) }, { PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) }, + { PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) }, { } }; MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id); @@ -728,6 +869,19 @@ static const struct ocp_selector ptp_ocp_sma_out[] = { { } }; +static const struct ocp_selector ptp_ocp_art_sma_in[] = { + { .name = "PPS1", .value = 0x0001 }, + { .name = "10Mhz", .value = 0x0008 }, + { } +}; + +static const struct ocp_selector ptp_ocp_art_sma_out[] = { + { .name = "PHC", .value = 0x0002 }, + { .name = "GNSS", .value = 0x0004 }, + { .name = "10Mhz", .value = 0x0010 }, + { } +}; + struct ocp_sma_op { const struct ocp_selector *tbl[2]; void (*init)(struct ptp_ocp *bp); @@ -2275,6 +2429,118 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data) return err; } +static void +ptp_ocp_art_sma_init(struct ptp_ocp *bp) +{ + u32 reg; + int i; + + /* defaults */ + bp->sma[0].mode = SMA_MODE_IN; + bp->sma[1].mode = SMA_MODE_IN; + bp->sma[2].mode = SMA_MODE_OUT; + bp->sma[3].mode = SMA_MODE_OUT; + + bp->sma[0].default_fcn = 0x08; /* IN: 10Mhz */ + bp->sma[1].default_fcn = 0x01; /* IN: PPS1 */ + bp->sma[2].default_fcn = 0x10; /* OUT: 10Mhz */ + bp->sma[3].default_fcn = 0x02; /* OUT: PHC */ + + /* If no SMA map, the pin functions and directions are fixed. */ + if (!bp->art_sma) { + for (i = 0; i < 4; i++) { + bp->sma[i].fixed_fcn = true; + bp->sma[i].fixed_dir = true; + } + return; + } + + for (i = 0; i < 4; i++) { + reg = ioread32(&bp->art_sma->map[i].gpio); + + switch (reg & 0xff) { + case 0: + bp->sma[i].fixed_fcn = true; + bp->sma[i].fixed_dir = true; + break; + case 1: + case 8: + bp->sma[i].mode = SMA_MODE_IN; + break; + default: + bp->sma[i].mode = SMA_MODE_OUT; + break; + } + } +} + +static u32 +ptp_ocp_art_sma_get(struct ptp_ocp *bp, int sma_nr) +{ + if (bp->sma[sma_nr - 1].fixed_fcn) + return bp->sma[sma_nr - 1].default_fcn; + + return ioread32(&bp->art_sma->map[sma_nr - 1].gpio) & 0xff; +} + +/* note: store 0 is considered invalid. */ +static int +ptp_ocp_art_sma_set(struct ptp_ocp *bp, int sma_nr, u32 val) +{ + unsigned long flags; + u32 __iomem *gpio; + int err = 0; + u32 reg; + + val &= SMA_SELECT_MASK; + if (hweight32(val) > 1) + return -EINVAL; + + gpio = &bp->art_sma->map[sma_nr - 1].gpio; + + spin_lock_irqsave(&bp->lock, flags); + reg = ioread32(gpio); + if (((reg >> 16) & val) == 0) { + err = -EOPNOTSUPP; + } else { + reg = (reg & 0xff00) | (val & 0xff); + iowrite32(reg, gpio); + } + spin_unlock_irqrestore(&bp->lock, flags); + + return err; +} + +static const struct ocp_sma_op ocp_art_sma_op = { + .tbl = { ptp_ocp_art_sma_in, ptp_ocp_art_sma_out }, + .init = ptp_ocp_art_sma_init, + .get = ptp_ocp_art_sma_get, + .set_inputs = ptp_ocp_art_sma_set, + .set_output = ptp_ocp_art_sma_set, +}; + +/* ART specific board initializers; last "resource" registered. */ +static int +ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r) +{ + int err; + + bp->flash_start = 0x1000000; + bp->eeprom_map = art_eeprom_map; + bp->fw_cap = OCP_CAP_BASIC; + bp->fw_version = ioread32(&bp->reg->version); + bp->fw_tag = 2; + bp->sma_op = &ocp_art_sma_op; + + ptp_ocp_sma_init(bp); + + err = ptp_ocp_attr_group_add(bp, art_timecard_groups); + if (err) + return err; + + return ptp_ocp_init_clock(bp); +} + static ssize_t ptp_ocp_show_output(const struct ocp_selector *tbl, u32 val, char *buf, int def_val) @@ -3083,6 +3349,30 @@ static const struct ocp_attr_group fb_timecard_groups[] = { { }, }; +static struct attribute *art_timecard_attrs[] = { + &dev_attr_serialnum.attr, + &dev_attr_clock_source.attr, + &dev_attr_available_clock_sources.attr, + &dev_attr_utc_tai_offset.attr, + &dev_attr_ts_window_adjust.attr, + &dev_attr_sma1.attr, + &dev_attr_sma2.attr, + &dev_attr_sma3.attr, + &dev_attr_sma4.attr, + &dev_attr_available_sma_inputs.attr, + &dev_attr_available_sma_outputs.attr, + NULL, +}; + +static const struct attribute_group art_timecard_group = { + .attrs = art_timecard_attrs, +}; + +static const struct ocp_attr_group art_timecard_groups[] = { + { .cap = OCP_CAP_BASIC, .group = &art_timecard_group }, + { }, +}; + static void gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit, const char *def) -- cgit v1.2.3 From 9c44a7ac17fb980f8e297588e75a6158c69a1a8e Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Fri, 21 Oct 2022 02:24:31 +0300 Subject: ptp: ocp: add serial port of mRO50 MAC on ART card ART card provides interface to access to serial port of miniature atomic clock found on the card. Add support for this device and configure it during init phase. Acked-by: Jonathan Lemon Co-developed-by: Charles Parent Signed-off-by: Jonathan Lemon Signed-off-by: Vadim Fedorenko Signed-off-by: David S. Miller --- drivers/ptp/ptp_ocp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 8c1ce630b67f..223980d725fe 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -208,6 +208,11 @@ struct frequency_reg { u32 ctrl; u32 status; }; + +struct board_config_reg { + u32 mro50_serial_activate; +}; + #define FREQ_STATUS_VALID BIT(31) #define FREQ_STATUS_ERROR BIT(30) #define FREQ_STATUS_OVERRUN BIT(29) @@ -299,6 +304,7 @@ struct ptp_ocp { struct tod_reg __iomem *tod; struct pps_reg __iomem *pps_to_ext; struct pps_reg __iomem *pps_to_clk; + struct board_config_reg __iomem *board_config; struct gpio_reg __iomem *pps_select; struct gpio_reg __iomem *sma_map1; struct gpio_reg __iomem *sma_map2; @@ -795,6 +801,17 @@ static struct ocp_resource ocp_art_resource[] = { }, }, }, + { + OCP_SERIAL_RESOURCE(mac_port), + .offset = 0x00190000, .irq_vec = 7, + .extra = &(struct ptp_ocp_serial_port) { + .baud = 9600, + }, + }, + { + OCP_MEM_RESOURCE(board_config), + .offset = 0x210000, .size = 0x1000, + }, { .setup = ptp_ocp_art_board_init, }, @@ -2532,6 +2549,9 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r) bp->fw_tag = 2; bp->sma_op = &ocp_art_sma_op; + /* Enable MAC serial port during initialisation */ + iowrite32(1, &bp->board_config->mro50_serial_activate); + ptp_ocp_sma_init(bp); err = ptp_ocp_attr_group_add(bp, art_timecard_groups); -- cgit v1.2.3 From ee6439aaad3245851bbbcbf6c7534c9a29407ab2 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Fri, 21 Oct 2022 02:24:32 +0300 Subject: ptp: ocp: expose config and temperature for ART card Orolia card has disciplining configuration and temperature table stored in EEPROM. This patch exposes them as binary attributes to have read and write access. Acked-by: Jonathan Lemon Co-developed-by: Charles Parent Signed-off-by: Jonathan Lemon Signed-off-by: Vadim Fedorenko Signed-off-by: David S. Miller --- drivers/ptp/ptp_ocp.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 223980d725fe..d2d486ccd714 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -690,6 +690,9 @@ static struct ocp_resource ocp_fb_resource[] = { { } }; +#define OCP_ART_CONFIG_SIZE 144 +#define OCP_ART_TEMP_TABLE_SIZE 368 + struct ocp_art_gpio_reg { struct { u32 gpio; @@ -3334,6 +3337,130 @@ DEVICE_FREQ_GROUP(freq2, 1); DEVICE_FREQ_GROUP(freq3, 2); DEVICE_FREQ_GROUP(freq4, 3); +static ssize_t +disciplining_config_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); + size_t size = OCP_ART_CONFIG_SIZE; + struct nvmem_device *nvmem; + ssize_t err; + + nvmem = ptp_ocp_nvmem_device_get(bp, NULL); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + if (off > size) { + err = 0; + goto out; + } + + if (off + count > size) + count = size - off; + + // the configuration is in the very beginning of the EEPROM + err = nvmem_device_read(nvmem, off, count, buf); + if (err != count) { + err = -EFAULT; + goto out; + } + +out: + ptp_ocp_nvmem_device_put(&nvmem); + + return err; +} + +static ssize_t +disciplining_config_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); + struct nvmem_device *nvmem; + ssize_t err; + + /* Allow write of the whole area only */ + if (off || count != OCP_ART_CONFIG_SIZE) + return -EFAULT; + + nvmem = ptp_ocp_nvmem_device_get(bp, NULL); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + err = nvmem_device_write(nvmem, 0x00, count, buf); + if (err != count) + err = -EFAULT; + + ptp_ocp_nvmem_device_put(&nvmem); + + return err; +} +static BIN_ATTR_RW(disciplining_config, OCP_ART_CONFIG_SIZE); + +static ssize_t +temperature_table_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); + size_t size = OCP_ART_TEMP_TABLE_SIZE; + struct nvmem_device *nvmem; + ssize_t err; + + nvmem = ptp_ocp_nvmem_device_get(bp, NULL); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + if (off > size) { + err = 0; + goto out; + } + + if (off + count > size) + count = size - off; + + // the configuration is in the very beginning of the EEPROM + err = nvmem_device_read(nvmem, 0x90 + off, count, buf); + if (err != count) { + err = -EFAULT; + goto out; + } + +out: + ptp_ocp_nvmem_device_put(&nvmem); + + return err; +} + +static ssize_t +temperature_table_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); + struct nvmem_device *nvmem; + ssize_t err; + + /* Allow write of the whole area only */ + if (off || count != OCP_ART_TEMP_TABLE_SIZE) + return -EFAULT; + + nvmem = ptp_ocp_nvmem_device_get(bp, NULL); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + err = nvmem_device_write(nvmem, 0x90, count, buf); + if (err != count) + err = -EFAULT; + + ptp_ocp_nvmem_device_put(&nvmem); + + return err; +} +static BIN_ATTR_RW(temperature_table, OCP_ART_TEMP_TABLE_SIZE); + static struct attribute *fb_timecard_attrs[] = { &dev_attr_serialnum.attr, &dev_attr_gnss_sync.attr, @@ -3353,9 +3480,11 @@ static struct attribute *fb_timecard_attrs[] = { &dev_attr_tod_correction.attr, NULL, }; + 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 }, { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal0_group }, @@ -3384,8 +3513,15 @@ static struct attribute *art_timecard_attrs[] = { NULL, }; +static struct bin_attribute *bin_art_timecard_attrs[] = { + &bin_attr_disciplining_config, + &bin_attr_temperature_table, + NULL, +}; + static const struct attribute_group art_timecard_group = { .attrs = art_timecard_attrs, + .bin_attrs = bin_art_timecard_attrs, }; static const struct ocp_attr_group art_timecard_groups[] = { -- cgit v1.2.3 From c1fd463d571a155bf43e04fd23d02aef364c5b0b Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Fri, 21 Oct 2022 02:24:33 +0300 Subject: ptp: ocp: remove flash image header check fallback Previously there was a fallback mode to flash firmware image without proper header. But now we have different supported vendors and flashing wrong image could destroy the hardware. Remove fallback mode and force header check. Both vendors have published firmware images with headers. Acked-by: Jonathan Lemon Signed-off-by: Vadim Fedorenko Signed-off-by: David S. Miller --- drivers/ptp/ptp_ocp.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index d2d486ccd714..154d58cbd9ce 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -1530,11 +1530,9 @@ ptp_ocp_devlink_fw_image(struct devlink *devlink, const struct firmware *fw, hdr = (const struct ptp_ocp_firmware_header *)fw->data; if (memcmp(hdr->magic, OCP_FIRMWARE_MAGIC_HEADER, 4)) { devlink_flash_update_status_notify(devlink, - "No firmware header found, flashing raw image", + "No firmware header found, cancel firmware upgrade", NULL, 0, 0); - offset = 0; - length = fw->size; - goto out; + return -EINVAL; } if (be16_to_cpu(hdr->pci_vendor_id) != bp->pdev->vendor || @@ -1562,7 +1560,6 @@ ptp_ocp_devlink_fw_image(struct devlink *devlink, const struct firmware *fw, return -EINVAL; } -out: *data = &fw->data[offset]; *size = length; -- cgit v1.2.3 From 73aa29a2b119619bbc1db87e8a8103f4b7e5a5db Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 28 Oct 2022 04:04:14 -0700 Subject: drivers: convert unsupported .adjfreq to .adjfine A few PTP drivers implement a .adjfreq handler which indicates the operation is not supported. Convert all of these to .adjfine. Signed-off-by: Jacob Keller Acked-by: Richard Cochran Cc: "K. Y. Srinivasan" Cc: Haiyang Zhang Cc: Stephen Hemminger Cc: Wei Liu Cc: Dexuan Cui Cc: Vivek Thampi Signed-off-by: David S. Miller --- drivers/hv/hv_util.c | 4 ++-- drivers/ptp/ptp_kvm_common.c | 4 ++-- drivers/ptp/ptp_vmw.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 835e6039c186..d776074b49cb 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -706,7 +706,7 @@ static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts) return -EOPNOTSUPP; } -static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta) +static int hv_ptp_adjfine(struct ptp_clock_info *ptp, long delta) { return -EOPNOTSUPP; } @@ -724,7 +724,7 @@ static struct ptp_clock_info ptp_hyperv_info = { .name = "hyperv", .enable = hv_ptp_enable, .adjtime = hv_ptp_adjtime, - .adjfreq = hv_ptp_adjfreq, + .adjfine = hv_ptp_adjfine, .gettime64 = hv_ptp_gettime, .settime64 = hv_ptp_settime, .owner = THIS_MODULE, diff --git a/drivers/ptp/ptp_kvm_common.c b/drivers/ptp/ptp_kvm_common.c index fcae32f56f25..9141162c4237 100644 --- a/drivers/ptp/ptp_kvm_common.c +++ b/drivers/ptp/ptp_kvm_common.c @@ -66,7 +66,7 @@ static int ptp_kvm_getcrosststamp(struct ptp_clock_info *ptp, * PTP clock operations */ -static int ptp_kvm_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int ptp_kvm_adjfine(struct ptp_clock_info *ptp, long delta) { return -EOPNOTSUPP; } @@ -115,7 +115,7 @@ static const struct ptp_clock_info ptp_kvm_caps = { .n_ext_ts = 0, .n_pins = 0, .pps = 0, - .adjfreq = ptp_kvm_adjfreq, + .adjfine = ptp_kvm_adjfine, .adjtime = ptp_kvm_adjtime, .gettime64 = ptp_kvm_gettime, .settime64 = ptp_kvm_settime, diff --git a/drivers/ptp/ptp_vmw.c b/drivers/ptp/ptp_vmw.c index 5dca26e14bdc..d64eec5b1788 100644 --- a/drivers/ptp/ptp_vmw.c +++ b/drivers/ptp/ptp_vmw.c @@ -47,7 +47,7 @@ static int ptp_vmw_adjtime(struct ptp_clock_info *info, s64 delta) return -EOPNOTSUPP; } -static int ptp_vmw_adjfreq(struct ptp_clock_info *info, s32 delta) +static int ptp_vmw_adjfine(struct ptp_clock_info *info, long delta) { return -EOPNOTSUPP; } @@ -79,7 +79,7 @@ static struct ptp_clock_info ptp_vmw_clock_info = { .name = "ptp_vmw", .max_adj = 0, .adjtime = ptp_vmw_adjtime, - .adjfreq = ptp_vmw_adjfreq, + .adjfine = ptp_vmw_adjfine, .gettime64 = ptp_vmw_gettime, .settime64 = ptp_vmw_settime, .enable = ptp_vmw_enable, -- cgit v1.2.3 From 2e77eded8ec34768618f9ab724b9092e09ddcca2 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 9 Nov 2022 15:09:37 -0800 Subject: ptp_phc: convert .adjfreq to .adjfine The ptp_phc implementation of .adjfreq is implemented in terms of a straight forward "base * ppb / 1 billion" calculation. Convert this to the newer .adjfine, updating the driver to use the recently introduced adjust_by_scaled_ppm helper function. Signed-off-by: Jacob Keller Cc: Richard Cochran Signed-off-by: David S. Miller --- drivers/ptp/ptp_pch.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c index 7d4da9e605ef..33355d5eb033 100644 --- a/drivers/ptp/ptp_pch.c +++ b/drivers/ptp/ptp_pch.c @@ -336,24 +336,13 @@ static irqreturn_t isr(int irq, void *priv) * PTP clock operations */ -static int ptp_pch_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int ptp_pch_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { - u64 adj; - u32 diff, addend; - int neg_adj = 0; + u32 addend; struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); struct pch_ts_regs __iomem *regs = pch_dev->regs; - if (ppb < 0) { - neg_adj = 1; - ppb = -ppb; - } - addend = DEFAULT_ADDEND; - adj = addend; - adj *= ppb; - diff = div_u64(adj, 1000000000ULL); - - addend = neg_adj ? addend - diff : addend + diff; + addend = adjust_by_scaled_ppm(DEFAULT_ADDEND, scaled_ppm); iowrite32(addend, ®s->addend); @@ -440,7 +429,7 @@ static const struct ptp_clock_info ptp_pch_caps = { .n_ext_ts = N_EXT_TS, .n_pins = 0, .pps = 0, - .adjfreq = ptp_pch_adjfreq, + .adjfine = ptp_pch_adjfine, .adjtime = ptp_pch_adjtime, .gettime64 = ptp_pch_gettime, .settime64 = ptp_pch_settime, -- cgit v1.2.3 From e2bd9c76c89fbe25df351fc5902cbbcca6a7d372 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 9 Nov 2022 15:09:44 -0800 Subject: ptp: convert remaining drivers to adjfine interface Convert all remaining drivers that still use .adjfreq to the newer .adjfine implementation. These drivers are not straightforward, as they use non-standard methods of programming their hardware. They are all converted to use scaled_ppm_to_ppb to get the parts per billion value that their logic depends on. Signed-off-by: Jacob Keller Cc: Ariel Elior Cc: Sudarsana Kalluru Cc: Manish Chopra Cc: Derek Chickles Cc: Satanand Burla Cc: Felix Manlunas Cc: Raju Rangoju Cc: Joakim Zhang Cc: Edward Cree Cc: Martin Habets Cc: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 9 +++++---- drivers/net/ethernet/cavium/liquidio/lio_main.c | 11 +++++++---- drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c | 13 ++++++++----- drivers/net/ethernet/freescale/fec_ptp.c | 13 ++++++++----- drivers/net/ethernet/qlogic/qede/qede_ptp.c | 13 ++++++++----- drivers/net/ethernet/sfc/ptp.c | 7 ++++--- drivers/net/ethernet/sfc/siena/ptp.c | 7 ++++--- drivers/net/ethernet/ti/am65-cpts.c | 5 +++-- drivers/ptp/ptp_dte.c | 5 +++-- 9 files changed, 50 insertions(+), 33 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 51b1690fd045..5d1e4fe335aa 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -13671,19 +13671,20 @@ static int bnx2x_send_update_drift_ramrod(struct bnx2x *bp, int drift_dir, return bnx2x_func_state_change(bp, &func_params); } -static int bnx2x_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int bnx2x_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info); int rc; int drift_dir = 1; int val, period, period1, period2, dif, dif1, dif2; int best_dif = BNX2X_MAX_PHC_DRIFT, best_period = 0, best_val = 0; + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); - DP(BNX2X_MSG_PTP, "PTP adjfreq called, ppb = %d\n", ppb); + DP(BNX2X_MSG_PTP, "PTP adjfine called, ppb = %d\n", ppb); if (!netif_running(bp->dev)) { DP(BNX2X_MSG_PTP, - "PTP adjfreq called while the interface is down\n"); + "PTP adjfine called while the interface is down\n"); return -ENETDOWN; } @@ -13818,7 +13819,7 @@ void bnx2x_register_phc(struct bnx2x *bp) bp->ptp_clock_info.n_ext_ts = 0; bp->ptp_clock_info.n_per_out = 0; bp->ptp_clock_info.pps = 0; - bp->ptp_clock_info.adjfreq = bnx2x_ptp_adjfreq; + bp->ptp_clock_info.adjfine = bnx2x_ptp_adjfine; bp->ptp_clock_info.adjtime = bnx2x_ptp_adjtime; bp->ptp_clock_info.gettime64 = bnx2x_ptp_gettime; bp->ptp_clock_info.settime64 = bnx2x_ptp_settime; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index d312bd594935..cc88e743d963 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1512,14 +1512,17 @@ static void free_netsgbuf_with_resp(void *buf) } /** - * liquidio_ptp_adjfreq - Adjust ptp frequency + * liquidio_ptp_adjfine - Adjust ptp frequency * @ptp: PTP clock info - * @ppb: how much to adjust by, in parts-per-billion + * @scaled_ppm: how much to adjust by, in scaled parts-per-million + * + * Scaled parts per million is ppm with a 16-bit binary fractional field. */ -static int liquidio_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int liquidio_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct lio *lio = container_of(ptp, struct lio, ptp_info); struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); u64 comp, delta; unsigned long flags; bool neg_adj = false; @@ -1643,7 +1646,7 @@ static void oct_ptp_open(struct net_device *netdev) lio->ptp_info.n_ext_ts = 0; lio->ptp_info.n_per_out = 0; lio->ptp_info.pps = 0; - lio->ptp_info.adjfreq = liquidio_ptp_adjfreq; + lio->ptp_info.adjfine = liquidio_ptp_adjfine; lio->ptp_info.adjtime = liquidio_ptp_adjtime; lio->ptp_info.gettime64 = liquidio_ptp_gettime; lio->ptp_info.settime64 = liquidio_ptp_settime; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c index 5bf117d2179f..cbd06d9b95d4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c @@ -194,17 +194,20 @@ int cxgb4_ptp_redirect_rx_packet(struct adapter *adapter, struct port_info *pi) } /** - * cxgb4_ptp_adjfreq - Adjust frequency of PHC cycle counter + * cxgb4_ptp_adjfine - Adjust frequency of PHC cycle counter * @ptp: ptp clock structure - * @ppb: Desired frequency change in parts per billion + * @scaled_ppm: Desired frequency in scaled parts per billion * - * Adjust the frequency of the PHC cycle counter by the indicated ppb from + * Adjust the frequency of the PHC cycle counter by the indicated amount from * the base frequency. + * + * Scaled parts per million is ppm with a 16-bit binary fractional field. */ -static int cxgb4_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int cxgb4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct adapter *adapter = (struct adapter *)container_of(ptp, struct adapter, ptp_clock_info); + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); struct fw_ptp_cmd c; int err; @@ -404,7 +407,7 @@ static const struct ptp_clock_info cxgb4_ptp_clock_info = { .n_ext_ts = 0, .n_per_out = 0, .pps = 0, - .adjfreq = cxgb4_ptp_adjfreq, + .adjfine = cxgb4_ptp_adjfine, .adjtime = cxgb4_ptp_adjtime, .gettime64 = cxgb4_ptp_gettime, .settime64 = cxgb4_ptp_settime, diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 67aa694a62ec..ab86bb8562ef 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -338,18 +338,21 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev) } /** - * fec_ptp_adjfreq - adjust ptp cycle frequency + * fec_ptp_adjfine - adjust ptp cycle frequency * @ptp: the ptp clock structure - * @ppb: parts per billion adjustment from base + * @scaled_ppm: scaled parts per million adjustment from base * * Adjust the frequency of the ptp cycle counter by the - * indicated ppb from the base frequency. + * indicated amount from the base frequency. + * + * Scaled parts per million is ppm with a 16-bit binary fractional field. * * Because ENET hardware frequency adjust is complex, * using software method to do that. */ -static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int fec_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); unsigned long flags; int neg_adj = 0; u32 i, tmp; @@ -742,7 +745,7 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx) fep->ptp_caps.n_per_out = 1; fep->ptp_caps.n_pins = 0; fep->ptp_caps.pps = 1; - fep->ptp_caps.adjfreq = fec_ptp_adjfreq; + fep->ptp_caps.adjfine = fec_ptp_adjfine; fep->ptp_caps.adjtime = fec_ptp_adjtime; fep->ptp_caps.gettime64 = fec_ptp_gettime; fep->ptp_caps.settime64 = fec_ptp_settime; diff --git a/drivers/net/ethernet/qlogic/qede/qede_ptp.c b/drivers/net/ethernet/qlogic/qede/qede_ptp.c index c9c8225f04d6..747cc5e2bb78 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ptp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ptp.c @@ -28,16 +28,19 @@ struct qede_ptp { }; /** - * qede_ptp_adjfreq() - Adjust the frequency of the PTP cycle counter. + * qede_ptp_adjfine() - Adjust the frequency of the PTP cycle counter. * * @info: The PTP clock info structure. - * @ppb: Parts per billion adjustment from base. + * @scaled_ppm: Scaled parts per million adjustment from base. + * + * Scaled parts per million is ppm with a 16-bit binary fractional field. * * Return: Zero on success, negative errno otherwise. */ -static int qede_ptp_adjfreq(struct ptp_clock_info *info, s32 ppb) +static int qede_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm) { struct qede_ptp *ptp = container_of(info, struct qede_ptp, clock_info); + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); struct qede_dev *edev = ptp->edev; int rc; @@ -47,7 +50,7 @@ static int qede_ptp_adjfreq(struct ptp_clock_info *info, s32 ppb) rc = ptp->ops->adjfreq(edev->cdev, ppb); spin_unlock_bh(&ptp->lock); } else { - DP_ERR(edev, "PTP adjfreq called while interface is down\n"); + DP_ERR(edev, "PTP adjfine called while interface is down\n"); rc = -EFAULT; } __qede_unlock(edev); @@ -462,7 +465,7 @@ int qede_ptp_enable(struct qede_dev *edev) ptp->clock_info.n_ext_ts = 0; ptp->clock_info.n_per_out = 0; ptp->clock_info.pps = 0; - ptp->clock_info.adjfreq = qede_ptp_adjfreq; + ptp->clock_info.adjfine = qede_ptp_adjfine; ptp->clock_info.adjtime = qede_ptp_adjtime; ptp->clock_info.gettime64 = qede_ptp_gettime; ptp->clock_info.settime64 = qede_ptp_settime; diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index eaef4a15008a..9f07e1ba7780 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -351,7 +351,7 @@ struct efx_ptp_data { void (*xmit_skb)(struct efx_nic *efx, struct sk_buff *skb); }; -static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta); +static int efx_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm); static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta); static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts); static int efx_phc_settime(struct ptp_clock_info *ptp, @@ -1508,7 +1508,7 @@ static const struct ptp_clock_info efx_phc_clock_info = { .n_per_out = 0, .n_pins = 0, .pps = 1, - .adjfreq = efx_phc_adjfreq, + .adjfine = efx_phc_adjfine, .adjtime = efx_phc_adjtime, .gettime64 = efx_phc_gettime, .settime64 = efx_phc_settime, @@ -2137,11 +2137,12 @@ void __efx_rx_skb_attach_timestamp(struct efx_channel *channel, ptp->ts_corrections.general_rx); } -static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) +static int efx_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct efx_ptp_data *ptp_data = container_of(ptp, struct efx_ptp_data, phc_clock_info); + s32 delta = scaled_ppm_to_ppb(scaled_ppm); struct efx_nic *efx = ptp_data->efx; MCDI_DECLARE_BUF(inadj, MC_CMD_PTP_IN_ADJUST_LEN); s64 adjustment_ns; diff --git a/drivers/net/ethernet/sfc/siena/ptp.c b/drivers/net/ethernet/sfc/siena/ptp.c index 7c46752e6eae..38e666561bcd 100644 --- a/drivers/net/ethernet/sfc/siena/ptp.c +++ b/drivers/net/ethernet/sfc/siena/ptp.c @@ -347,7 +347,7 @@ struct efx_ptp_data { void (*xmit_skb)(struct efx_nic *efx, struct sk_buff *skb); }; -static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta); +static int efx_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm); static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta); static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts); static int efx_phc_settime(struct ptp_clock_info *ptp, @@ -1429,7 +1429,7 @@ static const struct ptp_clock_info efx_phc_clock_info = { .n_per_out = 0, .n_pins = 0, .pps = 1, - .adjfreq = efx_phc_adjfreq, + .adjfine = efx_phc_adjfine, .adjtime = efx_phc_adjtime, .gettime64 = efx_phc_gettime, .settime64 = efx_phc_settime, @@ -2044,11 +2044,12 @@ void __efx_siena_rx_skb_attach_timestamp(struct efx_channel *channel, ptp->ts_corrections.general_rx); } -static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) +static int efx_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct efx_ptp_data *ptp_data = container_of(ptp, struct efx_ptp_data, phc_clock_info); + s32 delta = scaled_ppm_to_ppb(scaled_ppm); struct efx_nic *efx = ptp_data->efx; MCDI_DECLARE_BUF(inadj, MC_CMD_PTP_IN_ADJUST_LEN); s64 adjustment_ns; diff --git a/drivers/net/ethernet/ti/am65-cpts.c b/drivers/net/ethernet/ti/am65-cpts.c index 7f928c343426..9535396b28cd 100644 --- a/drivers/net/ethernet/ti/am65-cpts.c +++ b/drivers/net/ethernet/ti/am65-cpts.c @@ -391,9 +391,10 @@ static irqreturn_t am65_cpts_interrupt(int irq, void *dev_id) } /* PTP clock operations */ -static int am65_cpts_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info); + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); int neg_adj = 0; u64 adj_period; u32 val; @@ -625,7 +626,7 @@ static long am65_cpts_ts_work(struct ptp_clock_info *ptp); static struct ptp_clock_info am65_ptp_info = { .owner = THIS_MODULE, .name = "CTPS timer", - .adjfreq = am65_cpts_ptp_adjfreq, + .adjfine = am65_cpts_ptp_adjfine, .adjtime = am65_cpts_ptp_adjtime, .gettimex64 = am65_cpts_ptp_gettimex, .settime64 = am65_cpts_ptp_settime, diff --git a/drivers/ptp/ptp_dte.c b/drivers/ptp/ptp_dte.c index 8641fd060491..7cc5a00e625b 100644 --- a/drivers/ptp/ptp_dte.c +++ b/drivers/ptp/ptp_dte.c @@ -134,8 +134,9 @@ static s64 dte_read_nco_with_ovf(struct ptp_dte *ptp_dte) return ns; } -static int ptp_dte_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int ptp_dte_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); u32 nco_incr; unsigned long flags; struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); @@ -219,7 +220,7 @@ static const struct ptp_clock_info ptp_dte_caps = { .n_ext_ts = 0, .n_pins = 0, .pps = 0, - .adjfreq = ptp_dte_adjfreq, + .adjfine = ptp_dte_adjfine, .adjtime = ptp_dte_adjtime, .gettime64 = ptp_dte_gettime, .settime64 = ptp_dte_settime, -- cgit v1.2.3 From 75ab70ec5cefade915a999886e4863fe6a38f8b5 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 9 Nov 2022 15:09:45 -0800 Subject: ptp: remove the .adjfreq interface function Now that all drivers have been converted to .adjfine, we can remove the .adjfreq from the interface structure. Signed-off-by: Jacob Keller Cc: Richard Cochran Signed-off-by: David S. Miller --- drivers/ptp/ptp_clock.c | 5 +---- include/linux/ptp_clock_kernel.h | 7 ------- 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 51cae72bb6db..62d4d29e7c05 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -131,10 +131,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) long ppb = scaled_ppm_to_ppb(tx->freq); if (ppb > ops->max_adj || ppb < -ops->max_adj) return -ERANGE; - if (ops->adjfine) - err = ops->adjfine(ops, tx->freq); - else - err = ops->adjfreq(ops, ppb); + err = ops->adjfine(ops, tx->freq); ptp->dialed_frequency = tx->freq; } else if (tx->modes & ADJ_OFFSET) { if (ops->adjphase) { diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h index f4781c5766d6..fdffa6a98d79 100644 --- a/include/linux/ptp_clock_kernel.h +++ b/include/linux/ptp_clock_kernel.h @@ -77,12 +77,6 @@ struct ptp_system_timestamp { * nominal frequency in parts per million, but with a * 16 bit binary fractional field. * - * @adjfreq: Adjusts the frequency of the hardware clock. - * This method is deprecated. New drivers should implement - * the @adjfine method instead. - * parameter delta: Desired frequency offset from nominal frequency - * in parts per billion - * * @adjphase: Adjusts the phase offset of the hardware clock. * parameter delta: Desired change in nanoseconds. * @@ -174,7 +168,6 @@ struct ptp_clock_info { int pps; struct ptp_pin_desc *pin_config; int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm); - int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta); int (*adjphase)(struct ptp_clock_info *ptp, s32 phase); int (*adjtime)(struct ptp_clock_info *ptp, s64 delta); int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts); -- cgit v1.2.3 From ad3cc7760dc45f30a772b312a01f965d6e74d36b Mon Sep 17 00:00:00 2001 From: Min Li Date: Wed, 23 Nov 2022 14:52:06 -0500 Subject: ptp: idt82p33: Add PTP_CLK_REQ_EXTTS support 82P33 family of chips can trigger TOD read/write by external signal from one of the IN12/13/14 pins, which are set user space programs by calling PTP_PIN_SETFUNC through ptp_ioctl Signed-off-by: Min Li Signed-off-by: David S. Miller --- drivers/ptp/ptp_idt82p33.c | 683 +++++++++++++++++++++++++++++++++++++++++---- drivers/ptp/ptp_idt82p33.h | 20 +- 2 files changed, 640 insertions(+), 63 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_idt82p33.c b/drivers/ptp/ptp_idt82p33.c index 97c1be44e323..aece499c26d4 100644 --- a/drivers/ptp/ptp_idt82p33.c +++ b/drivers/ptp/ptp_idt82p33.c @@ -27,6 +27,8 @@ MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(FW_FILENAME); +#define EXTTS_PERIOD_MS (95) + /* Module Parameters */ static u32 phase_snap_threshold = SNAP_THRESHOLD_NS; module_param(phase_snap_threshold, uint, 0); @@ -36,6 +38,8 @@ MODULE_PARM_DESC(phase_snap_threshold, static char *firmware; module_param(firmware, charp, 0); +static struct ptp_pin_desc pin_config[MAX_PHC_PLL][MAX_TRIG_CLK]; + static inline int idt82p33_read(struct idt82p33 *idt82p33, u16 regaddr, u8 *buf, u16 count) { @@ -121,24 +125,270 @@ static int idt82p33_dpll_set_mode(struct idt82p33_channel *channel, return 0; } -static int _idt82p33_gettime(struct idt82p33_channel *channel, - struct timespec64 *ts) +static int idt82p33_set_tod_trigger(struct idt82p33_channel *channel, + u8 trigger, bool write) +{ + struct idt82p33 *idt82p33 = channel->idt82p33; + int err; + u8 cfg; + + if (trigger > WR_TRIG_SEL_MAX) + return -EINVAL; + + err = idt82p33_read(idt82p33, channel->dpll_tod_trigger, + &cfg, sizeof(cfg)); + + if (err) + return err; + + if (write == true) + trigger = (trigger << WRITE_TRIGGER_SHIFT) | + (cfg & READ_TRIGGER_MASK); + else + trigger = (trigger << READ_TRIGGER_SHIFT) | + (cfg & WRITE_TRIGGER_MASK); + + return idt82p33_write(idt82p33, channel->dpll_tod_trigger, + &trigger, sizeof(trigger)); +} + +static int idt82p33_get_extts(struct idt82p33_channel *channel, + struct timespec64 *ts) +{ + struct idt82p33 *idt82p33 = channel->idt82p33; + u8 buf[TOD_BYTE_COUNT]; + int err; + + err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf)); + + if (err) + return err; + + /* Since trigger is not self clearing itself, we have to poll tod_sts */ + if (memcmp(buf, channel->extts_tod_sts, TOD_BYTE_COUNT) == 0) + return -EAGAIN; + + memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT); + + idt82p33_byte_array_to_timespec(ts, buf); + + if (channel->discard_next_extts) { + channel->discard_next_extts = false; + return -EAGAIN; + } + + return 0; +} + +static int map_ref_to_tod_trig_sel(int ref, u8 *trigger) +{ + int err = 0; + + switch (ref) { + case 0: + *trigger = HW_TOD_TRIG_SEL_IN12; + break; + case 1: + *trigger = HW_TOD_TRIG_SEL_IN13; + break; + case 2: + *trigger = HW_TOD_TRIG_SEL_IN14; + break; + default: + err = -EINVAL; + } + + return err; +} + +static bool is_one_shot(u8 mask) +{ + /* Treat single bit PLL masks as continuous trigger */ + if ((mask == 1) || (mask == 2)) + return false; + else + return true; +} + +static int arm_tod_read_with_trigger(struct idt82p33_channel *channel, u8 trigger) { struct idt82p33 *idt82p33 = channel->idt82p33; u8 buf[TOD_BYTE_COUNT]; + int err; + + /* Remember the current tod_sts before setting the trigger */ + err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf)); + + if (err) + return err; + + memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT); + + err = idt82p33_set_tod_trigger(channel, trigger, false); + + if (err) + dev_err(idt82p33->dev, "%s: err = %d", __func__, err); + + return err; +} + +static int idt82p33_extts_enable(struct idt82p33_channel *channel, + struct ptp_clock_request *rq, int on) +{ + u8 index = rq->extts.index; + struct idt82p33 *idt82p33; + u8 mask = 1 << index; + int err = 0; + u8 old_mask; u8 trigger; + int ref; + + idt82p33 = channel->idt82p33; + old_mask = idt82p33->extts_mask; + + /* Reject requests with unsupported flags */ + if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | + PTP_RISING_EDGE | + PTP_FALLING_EDGE | + PTP_STRICT_FLAGS)) + return -EOPNOTSUPP; + + /* Reject requests to enable time stamping on falling edge */ + if ((rq->extts.flags & PTP_ENABLE_FEATURE) && + (rq->extts.flags & PTP_FALLING_EDGE)) + return -EOPNOTSUPP; + + if (index >= MAX_PHC_PLL) + return -EINVAL; + + if (on) { + /* Return if it was already enabled */ + if (idt82p33->extts_mask & mask) + return 0; + + /* Use the pin configured for the channel */ + ref = ptp_find_pin(channel->ptp_clock, PTP_PF_EXTTS, channel->plln); + + if (ref < 0) { + dev_err(idt82p33->dev, "%s: No valid pin found for Pll%d!\n", + __func__, channel->plln); + return -EBUSY; + } + + err = map_ref_to_tod_trig_sel(ref, &trigger); + + if (err) { + dev_err(idt82p33->dev, + "%s: Unsupported ref %d!\n", __func__, ref); + return err; + } + + err = arm_tod_read_with_trigger(&idt82p33->channel[index], trigger); + + if (err == 0) { + idt82p33->extts_mask |= mask; + idt82p33->channel[index].tod_trigger = trigger; + idt82p33->event_channel[index] = channel; + idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask); + + if (old_mask) + return 0; + + schedule_delayed_work(&idt82p33->extts_work, + msecs_to_jiffies(EXTTS_PERIOD_MS)); + } + } else { + idt82p33->extts_mask &= ~mask; + idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask); + + if (idt82p33->extts_mask == 0) + cancel_delayed_work(&idt82p33->extts_work); + } + + return err; +} + +static int idt82p33_extts_check_channel(struct idt82p33 *idt82p33, u8 todn) +{ + struct idt82p33_channel *event_channel; + struct ptp_clock_event event; + struct timespec64 ts; + int err; + + err = idt82p33_get_extts(&idt82p33->channel[todn], &ts); + if (err == 0) { + event_channel = idt82p33->event_channel[todn]; + event.type = PTP_CLOCK_EXTTS; + event.index = todn; + event.timestamp = timespec64_to_ns(&ts); + ptp_clock_event(event_channel->ptp_clock, + &event); + } + return err; +} + +static u8 idt82p33_extts_enable_mask(struct idt82p33_channel *channel, + u8 extts_mask, bool enable) +{ + struct idt82p33 *idt82p33 = channel->idt82p33; + u8 trigger = channel->tod_trigger; + u8 mask; int err; + int i; + + if (extts_mask == 0) + return 0; + + if (enable == false) + cancel_delayed_work_sync(&idt82p33->extts_work); + + for (i = 0; i < MAX_PHC_PLL; i++) { + mask = 1 << i; + + if ((extts_mask & mask) == 0) + continue; + + if (enable) { + err = arm_tod_read_with_trigger(&idt82p33->channel[i], trigger); + if (err) + dev_err(idt82p33->dev, + "%s: Arm ToD read trigger failed, err = %d", + __func__, err); + } else { + err = idt82p33_extts_check_channel(idt82p33, i); + if (err == 0 && idt82p33->extts_single_shot) + /* trigger happened so we won't re-enable it */ + extts_mask &= ~mask; + } + } - trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG, - HW_TOD_RD_TRIG_SEL_LSB_TOD_STS); + if (enable) + schedule_delayed_work(&idt82p33->extts_work, + msecs_to_jiffies(EXTTS_PERIOD_MS)); + return extts_mask; +} + +static int _idt82p33_gettime(struct idt82p33_channel *channel, + struct timespec64 *ts) +{ + struct idt82p33 *idt82p33 = channel->idt82p33; + u8 old_mask = idt82p33->extts_mask; + u8 buf[TOD_BYTE_COUNT]; + u8 new_mask = 0; + int err; - err = idt82p33_write(idt82p33, channel->dpll_tod_trigger, - &trigger, sizeof(trigger)); + /* Disable extts */ + if (old_mask) + new_mask = idt82p33_extts_enable_mask(channel, old_mask, false); + err = idt82p33_set_tod_trigger(channel, HW_TOD_RD_TRIG_SEL_LSB_TOD_STS, + false); if (err) return err; + channel->discard_next_extts = true; + if (idt82p33->calculate_overhead_flag) idt82p33->start_time = ktime_get_raw(); @@ -147,6 +397,10 @@ static int _idt82p33_gettime(struct idt82p33_channel *channel, if (err) return err; + /* Re-enable extts */ + if (new_mask) + idt82p33_extts_enable_mask(channel, new_mask, true); + idt82p33_byte_array_to_timespec(ts, buf); return 0; @@ -165,19 +419,16 @@ static int _idt82p33_settime(struct idt82p33_channel *channel, struct timespec64 local_ts = *ts; char buf[TOD_BYTE_COUNT]; s64 dynamic_overhead_ns; - unsigned char trigger; int err; u8 i; - trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG, - HW_TOD_RD_TRIG_SEL_LSB_TOD_STS); - - err = idt82p33_write(idt82p33, channel->dpll_tod_trigger, - &trigger, sizeof(trigger)); - + err = idt82p33_set_tod_trigger(channel, HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG, + true); if (err) return err; + channel->discard_next_extts = true; + if (idt82p33->calculate_overhead_flag) { dynamic_overhead_ns = ktime_to_ns(ktime_get_raw()) - ktime_to_ns(idt82p33->start_time); @@ -202,7 +453,8 @@ static int _idt82p33_settime(struct idt82p33_channel *channel, return err; } -static int _idt82p33_adjtime(struct idt82p33_channel *channel, s64 delta_ns) +static int _idt82p33_adjtime_immediate(struct idt82p33_channel *channel, + s64 delta_ns) { struct idt82p33 *idt82p33 = channel->idt82p33; struct timespec64 ts; @@ -226,6 +478,60 @@ static int _idt82p33_adjtime(struct idt82p33_channel *channel, s64 delta_ns) return err; } +static int _idt82p33_adjtime_internal_triggered(struct idt82p33_channel *channel, + s64 delta_ns) +{ + struct idt82p33 *idt82p33 = channel->idt82p33; + char buf[TOD_BYTE_COUNT]; + struct timespec64 ts; + const u8 delay_ns = 32; + s32 remainder; + s64 ns; + int err; + + err = _idt82p33_gettime(channel, &ts); + + if (err) + return err; + + if (ts.tv_nsec > (NSEC_PER_SEC - 5 * NSEC_PER_MSEC)) { + /* Too close to miss next trigger, so skip it */ + mdelay(6); + ns = (ts.tv_sec + 2) * NSEC_PER_SEC + delta_ns + delay_ns; + } else + ns = (ts.tv_sec + 1) * NSEC_PER_SEC + delta_ns + delay_ns; + + ts = ns_to_timespec64(ns); + idt82p33_timespec_to_byte_array(&ts, buf); + + /* + * Store the new time value. + */ + err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg, buf, sizeof(buf)); + if (err) + return err; + + /* Schedule to implement the workaround in one second */ + (void)div_s64_rem(delta_ns, NSEC_PER_SEC, &remainder); + if (remainder != 0) + schedule_delayed_work(&channel->adjtime_work, HZ); + + return idt82p33_set_tod_trigger(channel, HW_TOD_TRIG_SEL_TOD_PPS, true); +} + +static void idt82p33_adjtime_workaround(struct work_struct *work) +{ + struct idt82p33_channel *channel = container_of(work, + struct idt82p33_channel, + adjtime_work.work); + struct idt82p33 *idt82p33 = channel->idt82p33; + + mutex_lock(idt82p33->lock); + /* Workaround for TOD-to-output alignment issue */ + _idt82p33_adjtime_internal_triggered(channel, 0); + mutex_unlock(idt82p33->lock); +} + static int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm) { struct idt82p33 *idt82p33 = channel->idt82p33; @@ -233,25 +539,22 @@ static int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm) int err, i; s64 fcw; - if (scaled_ppm == channel->current_freq_ppb) - return 0; - /* - * Frequency Control Word unit is: 1.68 * 10^-10 ppm + * Frequency Control Word unit is: 1.6861512 * 10^-10 ppm * * adjfreq: - * ppb * 10^9 - * FCW = ---------- - * 168 + * ppb * 10^14 + * FCW = ----------- + * 16861512 * * adjfine: - * scaled_ppm * 5^12 - * FCW = ------------- - * 168 * 2^4 + * scaled_ppm * 5^12 * 10^5 + * FCW = ------------------------ + * 16861512 * 2^4 */ - fcw = scaled_ppm * 244140625ULL; - fcw = div_s64(fcw, 2688); + fcw = scaled_ppm * 762939453125ULL; + fcw = div_s64(fcw, 8430756LL); for (i = 0; i < 5; i++) { buf[i] = fcw & 0xff; @@ -266,26 +569,84 @@ static int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm) err = idt82p33_write(idt82p33, channel->dpll_freq_cnfg, buf, sizeof(buf)); - if (err == 0) - channel->current_freq_ppb = scaled_ppm; - return err; } +/* ppb = scaled_ppm * 125 / 2^13 */ +static s32 idt82p33_ddco_scaled_ppm(long current_ppm, s32 ddco_ppb) +{ + s64 scaled_ppm = div_s64(((s64)ddco_ppb << 13), 125); + s64 max_scaled_ppm = div_s64(((s64)DCO_MAX_PPB << 13), 125); + + current_ppm += scaled_ppm; + + if (current_ppm > max_scaled_ppm) + current_ppm = max_scaled_ppm; + else if (current_ppm < -max_scaled_ppm) + current_ppm = -max_scaled_ppm; + + return (s32)current_ppm; +} + +static int idt82p33_stop_ddco(struct idt82p33_channel *channel) +{ + int err; + + err = _idt82p33_adjfine(channel, channel->current_freq); + if (err) + return err; + + channel->ddco = false; + + return 0; +} + +static int idt82p33_start_ddco(struct idt82p33_channel *channel, s32 delta_ns) +{ + s32 current_ppm = channel->current_freq; + u32 duration_ms = MSEC_PER_SEC; + s32 ppb; + int err; + + /* If the ToD correction is less than 5 nanoseconds, then skip it. + * The error introduced by the ToD adjustment procedure would be bigger + * than the required ToD correction + */ + if (abs(delta_ns) < DDCO_THRESHOLD_NS) + return 0; + + /* For most cases, keep ddco duration 1 second */ + ppb = delta_ns; + while (abs(ppb) > DCO_MAX_PPB) { + duration_ms *= 2; + ppb /= 2; + } + + err = _idt82p33_adjfine(channel, + idt82p33_ddco_scaled_ppm(current_ppm, ppb)); + if (err) + return err; + + /* schedule the worker to cancel ddco */ + ptp_schedule_worker(channel->ptp_clock, + msecs_to_jiffies(duration_ms) - 1); + channel->ddco = true; + + return 0; +} + static int idt82p33_measure_one_byte_write_overhead( struct idt82p33_channel *channel, s64 *overhead_ns) { struct idt82p33 *idt82p33 = channel->idt82p33; ktime_t start, stop; + u8 trigger = 0; s64 total_ns; - u8 trigger; int err; u8 i; total_ns = 0; *overhead_ns = 0; - trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG, - HW_TOD_RD_TRIG_SEL_LSB_TOD_STS); for (i = 0; i < MAX_MEASURMENT_COUNT; i++) { @@ -307,8 +668,41 @@ static int idt82p33_measure_one_byte_write_overhead( return err; } +static int idt82p33_measure_one_byte_read_overhead( + struct idt82p33_channel *channel, s64 *overhead_ns) +{ + struct idt82p33 *idt82p33 = channel->idt82p33; + ktime_t start, stop; + u8 trigger = 0; + s64 total_ns; + int err; + u8 i; + + total_ns = 0; + *overhead_ns = 0; + + for (i = 0; i < MAX_MEASURMENT_COUNT; i++) { + + start = ktime_get_raw(); + + err = idt82p33_read(idt82p33, channel->dpll_tod_trigger, + &trigger, sizeof(trigger)); + + stop = ktime_get_raw(); + + if (err) + return err; + + total_ns += ktime_to_ns(stop) - ktime_to_ns(start); + } + + *overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT); + + return err; +} + static int idt82p33_measure_tod_write_9_byte_overhead( - struct idt82p33_channel *channel) + struct idt82p33_channel *channel) { struct idt82p33 *idt82p33 = channel->idt82p33; u8 buf[TOD_BYTE_COUNT]; @@ -368,7 +762,7 @@ static int idt82p33_measure_settime_gettime_gap_overhead( static int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel) { - s64 trailing_overhead_ns, one_byte_write_ns, gap_ns; + s64 trailing_overhead_ns, one_byte_write_ns, gap_ns, one_byte_read_ns; struct idt82p33 *idt82p33 = channel->idt82p33; int err; @@ -388,12 +782,19 @@ static int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel) if (err) return err; + err = idt82p33_measure_one_byte_read_overhead(channel, + &one_byte_read_ns); + + if (err) + return err; + err = idt82p33_measure_tod_write_9_byte_overhead(channel); if (err) return err; - trailing_overhead_ns = gap_ns - (2 * one_byte_write_ns); + trailing_overhead_ns = gap_ns - 2 * one_byte_write_ns + - one_byte_read_ns; idt82p33->tod_write_overhead_ns -= trailing_overhead_ns; @@ -462,6 +863,20 @@ static int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable) &sync_cnfg, sizeof(sync_cnfg)); } +static long idt82p33_work_handler(struct ptp_clock_info *ptp) +{ + struct idt82p33_channel *channel = + container_of(ptp, struct idt82p33_channel, caps); + struct idt82p33 *idt82p33 = channel->idt82p33; + + mutex_lock(idt82p33->lock); + (void)idt82p33_stop_ddco(channel); + mutex_unlock(idt82p33->lock); + + /* Return a negative value here to not reschedule */ + return -1; +} + static int idt82p33_output_enable(struct idt82p33_channel *channel, bool enable, unsigned int outn) { @@ -524,6 +939,10 @@ static int idt82p33_enable_tod(struct idt82p33_channel *channel) struct timespec64 ts = {0, 0}; int err; + /* STEELAI-366 - Temporary workaround for ts2phc compatibility */ + if (0) + err = idt82p33_output_mask_enable(channel, false); + err = idt82p33_measure_tod_write_overhead(channel); if (err) { @@ -546,14 +965,15 @@ static void idt82p33_ptp_clock_unregister_all(struct idt82p33 *idt82p33) u8 i; for (i = 0; i < MAX_PHC_PLL; i++) { - channel = &idt82p33->channel[i]; - + cancel_delayed_work_sync(&channel->adjtime_work); if (channel->ptp_clock) ptp_clock_unregister(channel->ptp_clock); } } + + static int idt82p33_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { @@ -564,7 +984,8 @@ static int idt82p33_enable(struct ptp_clock_info *ptp, mutex_lock(idt82p33->lock); - if (rq->type == PTP_CLK_REQ_PEROUT) { + switch (rq->type) { + case PTP_CLK_REQ_PEROUT: if (!on) err = idt82p33_perout_enable(channel, false, &rq->perout); @@ -575,6 +996,12 @@ static int idt82p33_enable(struct ptp_clock_info *ptp, else err = idt82p33_perout_enable(channel, true, &rq->perout); + break; + case PTP_CLK_REQ_EXTTS: + err = idt82p33_extts_enable(channel, rq, on); + break; + default: + break; } mutex_unlock(idt82p33->lock); @@ -634,13 +1061,22 @@ static int idt82p33_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) struct idt82p33 *idt82p33 = channel->idt82p33; int err; + if (channel->ddco == true) + return 0; + + if (scaled_ppm == channel->current_freq) + return 0; + mutex_lock(idt82p33->lock); err = _idt82p33_adjfine(channel, scaled_ppm); + + if (err == 0) + channel->current_freq = scaled_ppm; mutex_unlock(idt82p33->lock); + if (err) dev_err(idt82p33->dev, "Failed in %s with err %d!\n", __func__, err); - return err; } @@ -651,14 +1087,21 @@ static int idt82p33_adjtime(struct ptp_clock_info *ptp, s64 delta_ns) struct idt82p33 *idt82p33 = channel->idt82p33; int err; + if (channel->ddco == true) + return -EBUSY; + mutex_lock(idt82p33->lock); if (abs(delta_ns) < phase_snap_threshold) { + err = idt82p33_start_ddco(channel, delta_ns); mutex_unlock(idt82p33->lock); - return 0; + return err; } - err = _idt82p33_adjtime(channel, delta_ns); + /* Use more accurate internal 1pps triggered write first */ + err = _idt82p33_adjtime_internal_triggered(channel, delta_ns); + if (err && delta_ns > IMMEDIATE_SNAP_THRESHOLD_NS) + err = _idt82p33_adjtime_immediate(channel, delta_ns); mutex_unlock(idt82p33->lock); @@ -703,8 +1146,10 @@ static int idt82p33_settime(struct ptp_clock_info *ptp, return err; } -static int idt82p33_channel_init(struct idt82p33_channel *channel, int index) +static int idt82p33_channel_init(struct idt82p33 *idt82p33, u32 index) { + struct idt82p33_channel *channel = &idt82p33->channel[index]; + switch (index) { case 0: channel->dpll_tod_cnfg = DPLL1_TOD_CNFG; @@ -730,22 +1175,60 @@ static int idt82p33_channel_init(struct idt82p33_channel *channel, int index) return -EINVAL; } - channel->current_freq_ppb = 0; + channel->plln = index; + channel->current_freq = 0; + channel->idt82p33 = idt82p33; + INIT_DELAYED_WORK(&channel->adjtime_work, idt82p33_adjtime_workaround); + + return 0; +} +static int idt82p33_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + switch (func) { + case PTP_PF_NONE: + case PTP_PF_EXTTS: + break; + case PTP_PF_PEROUT: + case PTP_PF_PHYSYNC: + return -1; + } return 0; } -static void idt82p33_caps_init(struct ptp_clock_info *caps) +static void idt82p33_caps_init(u32 index, struct ptp_clock_info *caps, + struct ptp_pin_desc *pin_cfg, u8 max_pins) { + struct ptp_pin_desc *ppd; + int i; + caps->owner = THIS_MODULE; caps->max_adj = DCO_MAX_PPB; - caps->n_per_out = 11; - caps->adjphase = idt82p33_adjwritephase; + caps->n_per_out = MAX_PER_OUT; + caps->n_ext_ts = MAX_PHC_PLL, + caps->n_pins = max_pins, + caps->adjphase = idt82p33_adjwritephase, caps->adjfine = idt82p33_adjfine; caps->adjtime = idt82p33_adjtime; caps->gettime64 = idt82p33_gettime; caps->settime64 = idt82p33_settime; caps->enable = idt82p33_enable; + caps->verify = idt82p33_verify_pin; + caps->do_aux_work = idt82p33_work_handler; + + snprintf(caps->name, sizeof(caps->name), "IDT 82P33 PLL%u", index); + + caps->pin_config = pin_cfg; + + for (i = 0; i < max_pins; ++i) { + ppd = &pin_cfg[i]; + + ppd->index = i; + ppd->func = PTP_PF_NONE; + ppd->chan = index; + snprintf(ppd->name, sizeof(ppd->name), "in%d", 12 + i); + } } static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index) @@ -758,7 +1241,7 @@ static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index) channel = &idt82p33->channel[index]; - err = idt82p33_channel_init(channel, index); + err = idt82p33_channel_init(idt82p33, index); if (err) { dev_err(idt82p33->dev, "Channel_init failed in %s with err %d!\n", @@ -766,11 +1249,8 @@ static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index) return err; } - channel->idt82p33 = idt82p33; - - idt82p33_caps_init(&channel->caps); - snprintf(channel->caps.name, sizeof(channel->caps.name), - "IDT 82P33 PLL%u", index); + idt82p33_caps_init(index, &channel->caps, + pin_config[index], MAX_TRIG_CLK); channel->ptp_clock = ptp_clock_register(&channel->caps, NULL); @@ -805,17 +1285,46 @@ static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index) return 0; } +static int idt82p33_reset(struct idt82p33 *idt82p33, bool cold) +{ + int err; + u8 cfg = SOFT_RESET_EN; + + if (cold == true) + goto cold_reset; + + err = idt82p33_read(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg)); + if (err) { + dev_err(idt82p33->dev, + "Soft reset failed with err %d!\n", err); + return err; + } + + cfg |= SOFT_RESET_EN; + +cold_reset: + err = idt82p33_write(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg)); + if (err) + dev_err(idt82p33->dev, + "Cold reset failed with err %d!\n", err); + return err; +} + static int idt82p33_load_firmware(struct idt82p33 *idt82p33) { + char fname[128] = FW_FILENAME; const struct firmware *fw; struct idt82p33_fwrc *rec; u8 loaddr, page, val; int err; s32 len; - dev_dbg(idt82p33->dev, "requesting firmware '%s'\n", FW_FILENAME); + if (firmware) /* module parameter */ + snprintf(fname, sizeof(fname), "%s", firmware); + + dev_info(idt82p33->dev, "requesting firmware '%s'\n", fname); - err = request_firmware(&fw, FW_FILENAME, idt82p33->dev); + err = request_firmware(&fw, fname, idt82p33->dev); if (err) { dev_err(idt82p33->dev, @@ -863,6 +1372,46 @@ out: return err; } +static void idt82p33_extts_check(struct work_struct *work) +{ + struct idt82p33 *idt82p33 = container_of(work, struct idt82p33, + extts_work.work); + struct idt82p33_channel *channel; + int err; + u8 mask; + int i; + + if (idt82p33->extts_mask == 0) + return; + + mutex_lock(idt82p33->lock); + + for (i = 0; i < MAX_PHC_PLL; i++) { + mask = 1 << i; + + if ((idt82p33->extts_mask & mask) == 0) + continue; + + err = idt82p33_extts_check_channel(idt82p33, i); + + if (err == 0) { + /* trigger clears itself, so clear the mask */ + if (idt82p33->extts_single_shot) { + idt82p33->extts_mask &= ~mask; + } else { + /* Re-arm */ + channel = &idt82p33->channel[i]; + arm_tod_read_with_trigger(channel, channel->tod_trigger); + } + } + } + + if (idt82p33->extts_mask) + schedule_delayed_work(&idt82p33->extts_work, + msecs_to_jiffies(EXTTS_PERIOD_MS)); + + mutex_unlock(idt82p33->lock); +} static int idt82p33_probe(struct platform_device *pdev) { @@ -885,25 +1434,33 @@ static int idt82p33_probe(struct platform_device *pdev) idt82p33->pll_mask = DEFAULT_PLL_MASK; idt82p33->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0; idt82p33->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1; + idt82p33->extts_mask = 0; + INIT_DELAYED_WORK(&idt82p33->extts_work, idt82p33_extts_check); mutex_lock(idt82p33->lock); - err = idt82p33_load_firmware(idt82p33); + /* cold reset before loading firmware */ + idt82p33_reset(idt82p33, true); + err = idt82p33_load_firmware(idt82p33); if (err) dev_warn(idt82p33->dev, "loading firmware failed with %d\n", err); + /* soft reset after loading firmware */ + idt82p33_reset(idt82p33, false); + if (idt82p33->pll_mask) { for (i = 0; i < MAX_PHC_PLL; i++) { - if (idt82p33->pll_mask & (1 << i)) { + if (idt82p33->pll_mask & (1 << i)) err = idt82p33_enable_channel(idt82p33, i); - if (err) { - dev_err(idt82p33->dev, - "Failed in %s with err %d!\n", - __func__, err); - break; - } + else + err = idt82p33_channel_init(idt82p33, i); + if (err) { + dev_err(idt82p33->dev, + "Failed in %s with err %d!\n", + __func__, err); + break; } } } else { @@ -928,6 +1485,8 @@ static int idt82p33_remove(struct platform_device *pdev) { struct idt82p33 *idt82p33 = platform_get_drvdata(pdev); + cancel_delayed_work_sync(&idt82p33->extts_work); + idt82p33_ptp_clock_unregister_all(idt82p33); return 0; diff --git a/drivers/ptp/ptp_idt82p33.h b/drivers/ptp/ptp_idt82p33.h index 0ea1c35c0f9f..cddebf05a5b9 100644 --- a/drivers/ptp/ptp_idt82p33.h +++ b/drivers/ptp/ptp_idt82p33.h @@ -13,6 +13,8 @@ #define FW_FILENAME "idt82p33xxx.bin" #define MAX_PHC_PLL (2) +#define MAX_TRIG_CLK (3) +#define MAX_PER_OUT (11) #define TOD_BYTE_COUNT (10) #define DCO_MAX_PPB (92000) #define MAX_MEASURMENT_COUNT (5) @@ -60,8 +62,18 @@ struct idt82p33_channel { struct ptp_clock *ptp_clock; struct idt82p33 *idt82p33; enum pll_mode pll_mode; - s32 current_freq_ppb; + /* Workaround for TOD-to-output alignment issue */ + struct delayed_work adjtime_work; + s32 current_freq; + /* double dco mode */ + bool ddco; u8 output_mask; + /* last input trigger for extts */ + u8 tod_trigger; + bool discard_next_extts; + u8 plln; + /* remember last tod_sts for extts */ + u8 extts_tod_sts[TOD_BYTE_COUNT]; u16 dpll_tod_cnfg; u16 dpll_tod_trigger; u16 dpll_tod_sts; @@ -76,6 +88,12 @@ struct idt82p33 { struct idt82p33_channel channel[MAX_PHC_PLL]; struct device *dev; u8 pll_mask; + /* Polls for external time stamps */ + u8 extts_mask; + bool extts_single_shot; + struct delayed_work extts_work; + /* Remember the ptp channel to report extts */ + struct idt82p33_channel *event_channel[MAX_PHC_PLL]; /* Mutex to protect operations from being interrupted */ struct mutex *lock; struct regmap *regmap; -- cgit v1.2.3 From 46da4aa2560f44eb24d55d931533dc1da45b8e89 Mon Sep 17 00:00:00 2001 From: Min Li Date: Wed, 23 Nov 2022 14:52:07 -0500 Subject: ptp: idt82p33: remove PEROUT_ENABLE_OUTPUT_MASK PEROUT_ENABLE_OUTPUT_MASK was there to allow us to enable/disable all the perout pins. But it is not standard procedure, we will have to discard it. Signed-off-by: Min Li Signed-off-by: David S. Miller --- drivers/ptp/ptp_idt82p33.c | 34 ---------------------------------- drivers/ptp/ptp_idt82p33.h | 1 - 2 files changed, 35 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/ptp/ptp_idt82p33.c b/drivers/ptp/ptp_idt82p33.c index aece499c26d4..afc76c22271a 100644 --- a/drivers/ptp/ptp_idt82p33.c +++ b/drivers/ptp/ptp_idt82p33.c @@ -895,40 +895,10 @@ static int idt82p33_output_enable(struct idt82p33_channel *channel, return idt82p33_write(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val)); } -static int idt82p33_output_mask_enable(struct idt82p33_channel *channel, - bool enable) -{ - u16 mask; - int err; - u8 outn; - - mask = channel->output_mask; - outn = 0; - - while (mask) { - if (mask & 0x1) { - err = idt82p33_output_enable(channel, enable, outn); - if (err) - return err; - } - - mask >>= 0x1; - outn++; - } - - return 0; -} - static int idt82p33_perout_enable(struct idt82p33_channel *channel, bool enable, struct ptp_perout_request *perout) { - unsigned int flags = perout->flags; - - /* Enable/disable output based on output_mask */ - if (flags == PEROUT_ENABLE_OUTPUT_MASK) - return idt82p33_output_mask_enable(channel, enable); - /* Enable/disable individual output instead */ return idt82p33_output_enable(channel, enable, perout->index); } @@ -939,10 +909,6 @@ static int idt82p33_enable_tod(struct idt82p33_channel *channel) struct timespec64 ts = {0, 0}; int err; - /* STEELAI-366 - Temporary workaround for ts2phc compatibility */ - if (0) - err = idt82p33_output_mask_enable(channel, false); - err = idt82p33_measure_tod_write_overhead(channel); if (err) { diff --git a/drivers/ptp/ptp_idt82p33.h b/drivers/ptp/ptp_idt82p33.h index cddebf05a5b9..8fcb0b17d207 100644 --- a/drivers/ptp/ptp_idt82p33.h +++ b/drivers/ptp/ptp_idt82p33.h @@ -22,7 +22,6 @@ #define IMMEDIATE_SNAP_THRESHOLD_NS (50000) #define DDCO_THRESHOLD_NS (5) #define IDT82P33_MAX_WRITE_COUNT (512) -#define PEROUT_ENABLE_OUTPUT_MASK (0xdeadbeef) #define PLLMASK_ADDR_HI 0xFF #define PLLMASK_ADDR_LO 0xA5 -- cgit v1.2.3 From 226bf980550627c88549b112ac6c8fb40873afb4 Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Tue, 29 Nov 2022 18:51:38 +0900 Subject: net: devlink: let the core report the driver name instead of the drivers The driver name is available in device_driver::name. Right now, drivers still have to report this piece of information themselves in their devlink_ops::info_get callback function. In order to factorize code, make devlink_nl_info_fill() add the driver name attribute. Now that the core sets the driver name attribute, drivers are not supposed to call devlink_info_driver_name_put() anymore. Remove devlink_info_driver_name_put() and clean-up all the drivers using this function in their callback. Signed-off-by: Vincent Mailhol Tested-by: Ido Schimmel # mlxsw Reviewed-by: Jacob Keller Reviewed-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- .../crypto/marvell/octeontx2/otx2_cpt_devlink.c | 4 ---- drivers/net/dsa/hirschmann/hellcreek.c | 5 ----- drivers/net/dsa/mv88e6xxx/devlink.c | 5 ----- drivers/net/dsa/sja1105/sja1105_devlink.c | 12 +++------- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 4 ---- .../ethernet/freescale/dpaa2/dpaa2-eth-devlink.c | 11 +-------- .../net/ethernet/fungible/funeth/funeth_devlink.c | 2 +- .../ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c | 5 ----- .../hisilicon/hns3/hns3vf/hclgevf_devlink.c | 5 ----- drivers/net/ethernet/intel/ice/ice_devlink.c | 6 ----- .../ethernet/marvell/octeontx2/af/rvu_devlink.c | 2 +- .../ethernet/marvell/octeontx2/nic/otx2_devlink.c | 9 +------- .../ethernet/marvell/prestera/prestera_devlink.c | 5 ----- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 4 ---- drivers/net/ethernet/mellanox/mlxsw/core.c | 5 ----- drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 4 ---- .../net/ethernet/pensando/ionic/ionic_devlink.c | 4 ---- drivers/net/ethernet/qlogic/qed/qed_devlink.c | 4 ---- drivers/net/netdevsim/dev.c | 3 --- drivers/ptp/ptp_ocp.c | 4 ---- include/net/devlink.h | 2 -- net/core/devlink.c | 26 +++++++++++++++------- 22 files changed, 25 insertions(+), 106 deletions(-) (limited to 'drivers/ptp') diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c b/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c index 7503f6b18ac5..a2aba0b0d68a 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c @@ -76,10 +76,6 @@ static int otx2_cpt_devlink_info_get(struct devlink *dl, struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf; int err; - err = devlink_info_driver_name_put(req, "rvu_cptpf"); - if (err) - return err; - err = otx2_cpt_dl_info_firmware_version_put(req, cptpf->eng_grps.grp, "fw.ae", OTX2_CPT_AE_TYPES); if (err) diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index 951f7935c872..595a548bb0a8 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -1176,11 +1176,6 @@ static int hellcreek_devlink_info_get(struct dsa_switch *ds, struct netlink_ext_ack *extack) { struct hellcreek *hellcreek = ds->priv; - int ret; - - ret = devlink_info_driver_name_put(req, "hellcreek"); - if (ret) - return ret; return devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c index 1266eabee086..a08dab75e0c0 100644 --- a/drivers/net/dsa/mv88e6xxx/devlink.c +++ b/drivers/net/dsa/mv88e6xxx/devlink.c @@ -821,11 +821,6 @@ int mv88e6xxx_devlink_info_get(struct dsa_switch *ds, struct netlink_ext_ack *extack) { struct mv88e6xxx_chip *chip = ds->priv; - int err; - - err = devlink_info_driver_name_put(req, "mv88e6xxx"); - if (err) - return err; return devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, diff --git a/drivers/net/dsa/sja1105/sja1105_devlink.c b/drivers/net/dsa/sja1105/sja1105_devlink.c index 10c6fea1227f..da532614f34a 100644 --- a/drivers/net/dsa/sja1105/sja1105_devlink.c +++ b/drivers/net/dsa/sja1105/sja1105_devlink.c @@ -120,16 +120,10 @@ int sja1105_devlink_info_get(struct dsa_switch *ds, struct netlink_ext_ack *extack) { struct sja1105_private *priv = ds->priv; - int rc; - - rc = devlink_info_driver_name_put(req, "sja1105"); - if (rc) - return rc; - rc = devlink_info_version_fixed_put(req, - DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, - priv->info->name); - return rc; + return devlink_info_version_fixed_put(req, + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, + priv->info->name); } int sja1105_devlink_setup(struct dsa_switch *ds) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 8a6f788f6294..26913dc816d3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -892,10 +892,6 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req, u32 ver = 0; int rc; - rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME); - if (rc) - return rc; - if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) { sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4], diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c index 5c6dd3029e2f..76f808d38066 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c @@ -37,18 +37,9 @@ static int dpaa2_eth_dl_info_get(struct devlink *devlink, struct dpaa2_eth_devlink_priv *dl_priv = devlink_priv(devlink); struct dpaa2_eth_priv *priv = dl_priv->dpaa2_priv; char buf[10]; - int err; - - err = devlink_info_driver_name_put(req, KBUILD_MODNAME); - if (err) - return err; scnprintf(buf, 10, "%d.%d", priv->dpni_ver_major, priv->dpni_ver_minor); - err = devlink_info_version_running_put(req, "dpni", buf); - if (err) - return err; - - return 0; + return devlink_info_version_running_put(req, "dpni", buf); } static struct dpaa2_eth_trap_item * diff --git a/drivers/net/ethernet/fungible/funeth/funeth_devlink.c b/drivers/net/ethernet/fungible/funeth/funeth_devlink.c index d50c222948b4..6668375edff6 100644 --- a/drivers/net/ethernet/fungible/funeth/funeth_devlink.c +++ b/drivers/net/ethernet/fungible/funeth/funeth_devlink.c @@ -6,7 +6,7 @@ static int fun_dl_info_get(struct devlink *dl, struct devlink_info_req *req, struct netlink_ext_ack *extack) { - return devlink_info_driver_name_put(req, KBUILD_MODNAME); + return 0; } static const struct devlink_ops fun_dl_ops = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c index 4c441e6a5082..3d3b69605423 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c @@ -13,11 +13,6 @@ static int hclge_devlink_info_get(struct devlink *devlink, struct hclge_devlink_priv *priv = devlink_priv(devlink); char version_str[HCLGE_DEVLINK_FW_STRING_LEN]; struct hclge_dev *hdev = priv->hdev; - int ret; - - ret = devlink_info_driver_name_put(req, KBUILD_MODNAME); - if (ret) - return ret; snprintf(version_str, sizeof(version_str), "%lu.%lu.%lu.%lu", hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE3_MASK, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c index fdc19868b818..a6c3c5e8f0ab 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c @@ -13,11 +13,6 @@ static int hclgevf_devlink_info_get(struct devlink *devlink, struct hclgevf_devlink_priv *priv = devlink_priv(devlink); char version_str[HCLGEVF_DEVLINK_FW_STRING_LEN]; struct hclgevf_dev *hdev = priv->hdev; - int ret; - - ret = devlink_info_driver_name_put(req, KBUILD_MODNAME); - if (ret) - return ret; snprintf(version_str, sizeof(version_str), "%lu.%lu.%lu.%lu", hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE3_MASK, diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 946d64e577c9..8286e47b4bae 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -311,12 +311,6 @@ static int ice_devlink_info_get(struct devlink *devlink, } } - err = devlink_info_driver_name_put(req, KBUILD_MODNAME); - if (err) { - NL_SET_ERR_MSG_MOD(extack, "Unable to set driver name"); - goto out_free_ctx; - } - ice_info_get_dsn(pf, ctx); err = devlink_info_serial_number_put(req, ctx->buf); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c index 88dee589cb21..f15439d26d21 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c @@ -1550,7 +1550,7 @@ static int rvu_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, static int rvu_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, struct netlink_ext_ack *extack) { - return devlink_info_driver_name_put(req, DRV_NAME); + return 0; } static const struct devlink_ops rvu_devlink_ops = { diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c index 777a27047c8e..5cc6416cf1a6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c @@ -77,18 +77,11 @@ static const struct devlink_param otx2_dl_params[] = { otx2_dl_mcam_count_validate), }; -/* Devlink OPs */ static int otx2_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, struct netlink_ext_ack *extack) { - struct otx2_devlink *otx2_dl = devlink_priv(devlink); - struct otx2_nic *pfvf = otx2_dl->pfvf; - - if (is_otx2_vf(pfvf->pcifunc)) - return devlink_info_driver_name_put(req, "rvu_nicvf"); - - return devlink_info_driver_name_put(req, "rvu_nicpf"); + return 0; } static const struct devlink_ops otx2_devlink_ops = { diff --git a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c index 84ad05c9f12d..2a4c9df4eb79 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c @@ -355,11 +355,6 @@ static int prestera_dl_info_get(struct devlink *dl, { struct prestera_switch *sw = devlink_priv(dl); char buf[16]; - int err; - - err = devlink_info_driver_name_put(req, PRESTERA_DRV_NAME); - if (err) - return err; snprintf(buf, sizeof(buf), "%d.%d.%d", sw->dev->fw_rev.maj, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index cc2ae427dcb0..751bc4a9edcf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -46,10 +46,6 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, u32 running_fw, stored_fw; int err; - err = devlink_info_driver_name_put(req, KBUILD_MODNAME); - if (err) - return err; - err = devlink_info_version_fixed_put(req, "fw.psid", dev->board_id); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index a83f6bc30072..a0a06e2eff82 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1459,11 +1459,6 @@ mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, char buf[32]; int err; - err = devlink_info_driver_name_put(req, - mlxsw_core->bus_info->device_kind); - if (err) - return err; - mlxsw_reg_mgir_pack(mgir_pl); err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgir), mgir_pl); if (err) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index 784f23602a8a..bf6bae557158 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -239,10 +239,6 @@ nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, char *buf = NULL; int err; - err = devlink_info_driver_name_put(req, "nfp"); - if (err) - return err; - vendor = nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor"); part = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno"); sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial"); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c index 567f778433e2..e6ff757895ab 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c @@ -26,10 +26,6 @@ static int ionic_dl_info_get(struct devlink *dl, struct devlink_info_req *req, char buf[16]; int err = 0; - err = devlink_info_driver_name_put(req, IONIC_DRV_NAME); - if (err) - return err; - err = devlink_info_version_running_put(req, DEVLINK_INFO_VERSION_GENERIC_FW, idev->dev_info.fw_version); diff --git a/drivers/net/ethernet/qlogic/qed/qed_devlink.c b/drivers/net/ethernet/qlogic/qed/qed_devlink.c index 6bb4e165b592..922c47797af6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_devlink.c +++ b/drivers/net/ethernet/qlogic/qed/qed_devlink.c @@ -162,10 +162,6 @@ static int qed_devlink_info_get(struct devlink *devlink, dev_info = &cdev->common_dev_info; - err = devlink_info_driver_name_put(req, KBUILD_MODNAME); - if (err) - return err; - memcpy(buf, cdev->hwfns[0].hw_info.part_num, sizeof(cdev->hwfns[0].hw_info.part_num)); buf[sizeof(cdev->hwfns[0].hw_info.part_num)] = 0; diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index e14686594a71..b962fc8e1397 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -994,9 +994,6 @@ static int nsim_dev_info_get(struct devlink *devlink, { int err; - err = devlink_info_driver_name_put(req, DRV_NAME); - if (err) - return err; err = devlink_info_version_stored_put_ext(req, "fw.mgmt", "10.20.30", DEVLINK_INFO_VERSION_TYPE_COMPONENT); if (err) diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 154d58cbd9ce..4bbaccd543ad 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -1647,10 +1647,6 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, char buf[32]; int err; - err = devlink_info_driver_name_put(req, KBUILD_MODNAME); - if (err) - return err; - fw_image = bp->fw_loader ? "loader" : "fw"; sprintf(buf, "%d.%d", bp->fw_tag, bp->fw_version); err = devlink_info_version_running_put(req, fw_image, buf); diff --git a/include/net/devlink.h b/include/net/devlink.h index 02528f736f65..5f6eca5e4a40 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1762,8 +1762,6 @@ int devlink_region_snapshot_create(struct devlink_region *region, u8 *data, u32 snapshot_id); int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn); -int devlink_info_driver_name_put(struct devlink_info_req *req, - const char *name); int devlink_info_board_serial_number_put(struct devlink_info_req *req, const char *bsn); diff --git a/net/core/devlink.c b/net/core/devlink.c index 298041a44aa8..60eb0f46520f 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -6707,14 +6707,6 @@ out_unlock: return err; } -int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name) -{ - if (!req->msg) - return 0; - return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name); -} -EXPORT_SYMBOL_GPL(devlink_info_driver_name_put); - int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn) { if (!req->msg) @@ -6823,11 +6815,25 @@ int devlink_info_version_running_put_ext(struct devlink_info_req *req, } EXPORT_SYMBOL_GPL(devlink_info_version_running_put_ext); +static int devlink_nl_driver_info_get(struct device_driver *drv, + struct devlink_info_req *req) +{ + if (!drv) + return 0; + + if (drv->name[0]) + return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, + drv->name); + + return 0; +} + static int devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink, enum devlink_command cmd, u32 portid, u32 seq, int flags, struct netlink_ext_ack *extack) { + struct device *dev = devlink_to_dev(devlink); struct devlink_info_req req = {}; void *hdr; int err; @@ -6845,6 +6851,10 @@ devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink, if (err) goto err_cancel_msg; + err = devlink_nl_driver_info_get(dev->driver, &req); + if (err) + goto err_cancel_msg; + genlmsg_end(msg, hdr); return 0; -- cgit v1.2.3