diff options
Diffstat (limited to 'drivers/net/ethernet')
21 files changed, 1213 insertions, 206 deletions
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 7ca077b65eaa..9c410f93a103 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -717,14 +717,15 @@ #define MACB_CAPS_BD_RD_PREFETCH 0x00000080 #define MACB_CAPS_NEEDS_RSTONUBR 0x00000100 #define MACB_CAPS_MIIONRGMII 0x00000200 +#define MACB_CAPS_NEED_TSUCLK 0x00000400 +#define MACB_CAPS_PCS 0x01000000 +#define MACB_CAPS_HIGH_SPEED 0x02000000 #define MACB_CAPS_CLK_HW_CHG 0x04000000 #define MACB_CAPS_MACB_IS_EMAC 0x08000000 #define MACB_CAPS_FIFO_MODE 0x10000000 #define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 #define MACB_CAPS_SG_DISABLED 0x40000000 #define MACB_CAPS_MACB_IS_GEM 0x80000000 -#define MACB_CAPS_PCS 0x01000000 -#define MACB_CAPS_HIGH_SPEED 0x02000000 /* LSO settings */ #define MACB_LSO_UFO_ENABLE 0x01 diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 7eb7822cd184..4cd4f57ca2aa 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4773,6 +4773,16 @@ static const struct macb_config sama7g5_emac_config = { .usrio = &sama7g5_usrio, }; +static const struct macb_config versal_config = { + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO | + MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH | MACB_CAPS_NEED_TSUCLK, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = init_reset_optional, + .jumbo_max_len = 10240, + .usrio = &macb_default_usrio, +}; + static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,at32ap7000-macb" }, { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config }, @@ -4794,6 +4804,7 @@ static const struct of_device_id macb_dt_ids[] = { { .compatible = "microchip,mpfs-macb", .data = &mpfs_config }, { .compatible = "microchip,sama7g5-gem", .data = &sama7g5_gem_config }, { .compatible = "microchip,sama7g5-emac", .data = &sama7g5_emac_config }, + { .compatible = "cdns,versal-gem", .data = &versal_config}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, macb_dt_ids); @@ -5203,7 +5214,7 @@ static int __maybe_unused macb_runtime_suspend(struct device *dev) if (!(device_may_wakeup(dev))) macb_clks_disable(bp->pclk, bp->hclk, bp->tx_clk, bp->rx_clk, bp->tsu_clk); - else + else if (!(bp->caps & MACB_CAPS_NEED_TSUCLK)) macb_clks_disable(NULL, NULL, NULL, NULL, bp->tsu_clk); return 0; @@ -5219,8 +5230,10 @@ static int __maybe_unused macb_runtime_resume(struct device *dev) clk_prepare_enable(bp->hclk); clk_prepare_enable(bp->tx_clk); clk_prepare_enable(bp->rx_clk); + clk_prepare_enable(bp->tsu_clk); + } else if (!(bp->caps & MACB_CAPS_NEED_TSUCLK)) { + clk_prepare_enable(bp->tsu_clk); } - clk_prepare_enable(bp->tsu_clk); return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index f72c5cc4e035..1a2e54dbc5a1 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -545,8 +545,8 @@ struct ice_pf { u32 msg_enable; struct ice_ptp ptp; struct tty_driver *ice_gnss_tty_driver; - struct tty_port gnss_tty_port; - struct gnss_serial *gnss_serial; + struct tty_port *gnss_tty_port[ICE_GNSS_TTY_MINOR_DEVICES]; + struct gnss_serial *gnss_serial[ICE_GNSS_TTY_MINOR_DEVICES]; u16 num_rdma_msix; /* Total MSIX vectors for RDMA driver */ u16 rdma_base_vector; diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 05cb9dd7035a..9939238573a4 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1395,7 +1395,7 @@ struct ice_aqc_get_link_topo { u8 rsvd[9]; }; -/* Read I2C (direct, 0x06E2) */ +/* Read/Write I2C (direct, 0x06E2/0x06E3) */ struct ice_aqc_i2c { struct ice_aqc_link_topo_addr topo_addr; __le16 i2c_addr; @@ -1405,7 +1405,7 @@ struct ice_aqc_i2c { u8 rsvd; __le16 i2c_bus_addr; - u8 rsvd2[4]; + u8 i2c_data[4]; /* Used only by write command, reserved in read. */ }; /* Read I2C Response (direct, 0x06E2) */ @@ -2124,7 +2124,7 @@ struct ice_aq_desc { struct ice_aqc_get_link_status get_link_status; struct ice_aqc_event_lan_overflow lan_overflow; struct ice_aqc_get_link_topo get_link_topo; - struct ice_aqc_i2c read_i2c; + struct ice_aqc_i2c read_write_i2c; struct ice_aqc_read_i2c_resp read_i2c_resp; } params; }; @@ -2241,6 +2241,7 @@ enum ice_adminq_opc { ice_aqc_opc_set_mac_lb = 0x0620, ice_aqc_opc_get_link_topo = 0x06E0, ice_aqc_opc_read_i2c = 0x06E2, + ice_aqc_opc_write_i2c = 0x06E3, ice_aqc_opc_set_port_id_led = 0x06E9, ice_aqc_opc_set_gpio = 0x06EC, ice_aqc_opc_get_gpio = 0x06ED, diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 9619bdb9e49a..27d0cbbd29da 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -4823,7 +4823,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_read_i2c); - cmd = &desc.params.read_i2c; + cmd = &desc.params.read_write_i2c; if (!data) return -EINVAL; @@ -4851,6 +4851,51 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, } /** + * ice_aq_write_i2c + * @hw: pointer to the hw struct + * @topo_addr: topology address for a device to communicate with + * @bus_addr: 7-bit I2C bus address + * @addr: I2C memory address (I2C offset) with up to 16 bits + * @params: I2C parameters: bit [4] - I2C address type, bits [3:0] - data size to write (0-7 bytes) + * @data: pointer to data (0 to 4 bytes) to be written to the I2C device + * @cd: pointer to command details structure or NULL + * + * Write I2C (0x06E3) + * + * * Return: + * * 0 - Successful write to the i2c device + * * -EINVAL - Data size greater than 4 bytes + * * -EIO - FW error + */ +int +ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, + u16 bus_addr, __le16 addr, u8 params, u8 *data, + struct ice_sq_cd *cd) +{ + struct ice_aq_desc desc = { 0 }; + struct ice_aqc_i2c *cmd; + u8 data_size; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_write_i2c); + cmd = &desc.params.read_write_i2c; + + data_size = FIELD_GET(ICE_AQC_I2C_DATA_SIZE_M, params); + + /* data_size limited to 4 */ + if (data_size > 4) + return -EINVAL; + + cmd->i2c_bus_addr = cpu_to_le16(bus_addr); + cmd->topo_addr = topo_addr; + cmd->i2c_params = params; + cmd->i2c_addr = addr; + + memcpy(cmd->i2c_data, data, data_size); + + return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); +} + +/** * ice_aq_set_driver_param - Set driver parameter to share via firmware * @hw: pointer to the HW struct * @idx: parameter index to set diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 872ea7d2332d..61b7c60db689 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -214,5 +214,9 @@ int ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, u16 bus_addr, __le16 addr, u8 params, u8 *data, struct ice_sq_cd *cd); +int +ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, + u16 bus_addr, __le16 addr, u8 params, u8 *data, + struct ice_sq_cd *cd); bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw); #endif /* _ICE_COMMON_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c index c6d755f707aa..b5a7f246d230 100644 --- a/drivers/net/ethernet/intel/ice/ice_gnss.c +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c @@ -1,11 +1,104 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2018-2021, Intel Corporation. */ +/* Copyright (C) 2021-2022, Intel Corporation. */ #include "ice.h" #include "ice_lib.h" #include <linux/tty_driver.h> /** + * ice_gnss_do_write - Write data to internal GNSS + * @pf: board private structure + * @buf: command buffer + * @size: command buffer size + * + * Write UBX command data to the GNSS receiver + */ +static unsigned int +ice_gnss_do_write(struct ice_pf *pf, unsigned char *buf, unsigned int size) +{ + struct ice_aqc_link_topo_addr link_topo; + struct ice_hw *hw = &pf->hw; + unsigned int offset = 0; + int err = 0; + + memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr)); + link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS; + link_topo.topo_params.node_type_ctx |= + FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, + ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE); + + /* It's not possible to write a single byte to u-blox. + * Write all bytes in a loop until there are 6 or less bytes left. If + * there are exactly 6 bytes left, the last write would be only a byte. + * In this case, do 4+2 bytes writes instead of 5+1. Otherwise, do the + * last 2 to 5 bytes write. + */ + while (size - offset > ICE_GNSS_UBX_WRITE_BYTES + 1) { + err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, + cpu_to_le16(buf[offset]), + ICE_MAX_I2C_WRITE_BYTES, + &buf[offset + 1], NULL); + if (err) + goto err_out; + + offset += ICE_GNSS_UBX_WRITE_BYTES; + } + + /* Single byte would be written. Write 4 bytes instead of 5. */ + if (size - offset == ICE_GNSS_UBX_WRITE_BYTES + 1) { + err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, + cpu_to_le16(buf[offset]), + ICE_MAX_I2C_WRITE_BYTES - 1, + &buf[offset + 1], NULL); + if (err) + goto err_out; + + offset += ICE_GNSS_UBX_WRITE_BYTES - 1; + } + + /* Do the last write, 2 to 5 bytes. */ + err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, + cpu_to_le16(buf[offset]), size - offset - 1, + &buf[offset + 1], NULL); + if (err) + goto err_out; + + return size; + +err_out: + dev_err(ice_pf_to_dev(pf), "GNSS failed to write, offset=%u, size=%u, err=%d\n", + offset, size, err); + + return offset; +} + +/** + * ice_gnss_write_pending - Write all pending data to internal GNSS + * @work: GNSS write work structure + */ +static void ice_gnss_write_pending(struct kthread_work *work) +{ + struct gnss_serial *gnss = container_of(work, struct gnss_serial, + write_work); + struct ice_pf *pf = gnss->back; + + if (!list_empty(&gnss->queue)) { + struct gnss_write_buf *write_buf = NULL; + unsigned int bytes; + + write_buf = list_first_entry(&gnss->queue, + struct gnss_write_buf, queue); + + bytes = ice_gnss_do_write(pf, write_buf->buf, write_buf->size); + dev_dbg(ice_pf_to_dev(pf), "%u bytes written to GNSS\n", bytes); + + list_del(&write_buf->queue); + kfree(write_buf->buf); + kfree(write_buf); + } +} + +/** * ice_gnss_read - Read data from internal GNSS module * @work: GNSS read work structure * @@ -104,8 +197,9 @@ exit: /** * ice_gnss_struct_init - Initialize GNSS structure for the TTY * @pf: Board private structure + * @index: TTY device index */ -static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf) +static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf, int index) { struct device *dev = ice_pf_to_dev(pf); struct kthread_worker *kworker; @@ -118,9 +212,11 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf) mutex_init(&gnss->gnss_mutex); gnss->open_count = 0; gnss->back = pf; - pf->gnss_serial = gnss; + pf->gnss_serial[index] = gnss; kthread_init_delayed_work(&gnss->read_work, ice_gnss_read); + INIT_LIST_HEAD(&gnss->queue); + kthread_init_work(&gnss->write_work, ice_gnss_write_pending); /* Allocate a kworker for handling work required for the GNSS TTY * writes. */ @@ -156,10 +252,10 @@ static int ice_gnss_tty_open(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; /* Get the serial object associated with this tty pointer */ - gnss = pf->gnss_serial; + gnss = pf->gnss_serial[tty->index]; if (!gnss) { /* Initialize GNSS struct on the first device open */ - gnss = ice_gnss_struct_init(pf); + gnss = ice_gnss_struct_init(pf, tty->index); if (!gnss) return -ENOMEM; } @@ -212,25 +308,100 @@ exit: } /** - * ice_gnss_tty_write - Dummy TTY write function to avoid kernel panic + * ice_gnss_tty_write - Write GNSS data * @tty: pointer to the tty_struct * @buf: pointer to the user data - * @cnt: the number of characters that was able to be sent to the hardware (or - * queued to be sent at a later time) + * @count: the number of characters queued to be sent to the HW + * + * The write function call is called by the user when there is data to be sent + * to the hardware. First the tty core receives the call, and then it passes the + * data on to the tty driver's write function. The tty core also tells the tty + * driver the size of the data being sent. + * If any errors happen during the write call, a negative error value should be + * returned instead of the number of characters queued to be written. */ static int -ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int cnt) +ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) { - return 0; + struct gnss_write_buf *write_buf; + struct gnss_serial *gnss; + unsigned char *cmd_buf; + struct ice_pf *pf; + int err = count; + + /* We cannot write a single byte using our I2C implementation. */ + if (count <= 1 || count > ICE_GNSS_TTY_WRITE_BUF) + return -EINVAL; + + gnss = tty->driver_data; + if (!gnss) + return -EFAULT; + + pf = (struct ice_pf *)tty->driver->driver_state; + if (!pf) + return -EFAULT; + + /* Only allow to write on TTY 0 */ + if (gnss != pf->gnss_serial[0]) + return -EIO; + + mutex_lock(&gnss->gnss_mutex); + + if (!gnss->open_count) { + err = -EINVAL; + goto exit; + } + + cmd_buf = kcalloc(count, sizeof(*buf), GFP_KERNEL); + if (!cmd_buf) { + err = -ENOMEM; + goto exit; + } + + memcpy(cmd_buf, buf, count); + + /* Send the data out to a hardware port */ + write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL); + if (!write_buf) { + err = -ENOMEM; + goto exit; + } + + write_buf->buf = cmd_buf; + write_buf->size = count; + INIT_LIST_HEAD(&write_buf->queue); + list_add_tail(&write_buf->queue, &gnss->queue); + kthread_queue_work(gnss->kworker, &gnss->write_work); +exit: + mutex_unlock(&gnss->gnss_mutex); + return err; } /** - * ice_gnss_tty_write_room - Dummy TTY write_room function to avoid kernel panic + * ice_gnss_tty_write_room - Returns the numbers of characters to be written. * @tty: pointer to the tty_struct + * + * This routine returns the numbers of characters the tty driver will accept + * for queuing to be written or 0 if either the TTY is not open or user + * tries to write to the TTY other than the first. */ static unsigned int ice_gnss_tty_write_room(struct tty_struct *tty) { - return 0; + struct gnss_serial *gnss = tty->driver_data; + + /* Only allow to write on TTY 0 */ + if (!gnss || gnss != gnss->back->gnss_serial[0]) + return 0; + + mutex_lock(&gnss->gnss_mutex); + + if (!gnss->open_count) { + mutex_unlock(&gnss->gnss_mutex); + return 0; + } + + mutex_unlock(&gnss->gnss_mutex); + return ICE_GNSS_TTY_WRITE_BUF; } static const struct tty_operations tty_gps_ops = { @@ -250,11 +421,13 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf) const int ICE_TTYDRV_NAME_MAX = 14; struct tty_driver *tty_driver; char *ttydrv_name; + unsigned int i; int err; - tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); + tty_driver = tty_alloc_driver(ICE_GNSS_TTY_MINOR_DEVICES, + TTY_DRIVER_REAL_RAW); if (IS_ERR(tty_driver)) { - dev_err(ice_pf_to_dev(pf), "Failed to allocate memory for GNSS TTY\n"); + dev_err(dev, "Failed to allocate memory for GNSS TTY\n"); return NULL; } @@ -284,23 +457,32 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf) tty_driver->driver_state = pf; tty_set_operations(tty_driver, &tty_gps_ops); - pf->gnss_serial = NULL; + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { + pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]), + GFP_KERNEL); + pf->gnss_serial[i] = NULL; - tty_port_init(&pf->gnss_tty_port); - tty_port_link_device(&pf->gnss_tty_port, tty_driver, 0); + tty_port_init(pf->gnss_tty_port[i]); + tty_port_link_device(pf->gnss_tty_port[i], tty_driver, i); + } err = tty_register_driver(tty_driver); if (err) { - dev_err(ice_pf_to_dev(pf), "Failed to register TTY driver err=%d\n", - err); + dev_err(dev, "Failed to register TTY driver err=%d\n", err); - tty_port_destroy(&pf->gnss_tty_port); + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { + tty_port_destroy(pf->gnss_tty_port[i]); + kfree(pf->gnss_tty_port[i]); + } kfree(ttydrv_name); tty_driver_kref_put(pf->ice_gnss_tty_driver); return NULL; } + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) + dev_info(dev, "%s%d registered\n", ttydrv_name, i); + return tty_driver; } @@ -328,17 +510,25 @@ void ice_gnss_init(struct ice_pf *pf) */ void ice_gnss_exit(struct ice_pf *pf) { + unsigned int i; + if (!test_bit(ICE_FLAG_GNSS, pf->flags) || !pf->ice_gnss_tty_driver) return; - tty_port_destroy(&pf->gnss_tty_port); + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { + if (pf->gnss_tty_port[i]) { + tty_port_destroy(pf->gnss_tty_port[i]); + kfree(pf->gnss_tty_port[i]); + } - if (pf->gnss_serial) { - struct gnss_serial *gnss = pf->gnss_serial; + if (pf->gnss_serial[i]) { + struct gnss_serial *gnss = pf->gnss_serial[i]; - kthread_cancel_delayed_work_sync(&gnss->read_work); - kfree(gnss); - pf->gnss_serial = NULL; + kthread_cancel_work_sync(&gnss->write_work); + kthread_cancel_delayed_work_sync(&gnss->read_work); + kfree(gnss); + pf->gnss_serial[i] = NULL; + } } tty_unregister_driver(pf->ice_gnss_tty_driver); diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.h b/drivers/net/ethernet/intel/ice/ice_gnss.h index 9211adb2372c..f454dd1d9285 100644 --- a/drivers/net/ethernet/intel/ice/ice_gnss.h +++ b/drivers/net/ethernet/intel/ice/ice_gnss.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2018-2021, Intel Corporation. */ +/* Copyright (C) 2021-2022, Intel Corporation. */ #ifndef _ICE_GNSS_H_ #define _ICE_GNSS_H_ @@ -8,14 +8,34 @@ #include <linux/tty_flip.h> #define ICE_E810T_GNSS_I2C_BUS 0x2 +#define ICE_GNSS_TIMER_DELAY_TIME (HZ / 10) /* 0.1 second per message */ +/* Create 2 minor devices, both using the same GNSS module. First one is RW, + * second one RO. + */ +#define ICE_GNSS_TTY_MINOR_DEVICES 2 +#define ICE_GNSS_TTY_WRITE_BUF 250 +#define ICE_MAX_I2C_DATA_SIZE FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M) +#define ICE_MAX_I2C_WRITE_BYTES 4 + +/* u-blox ZED-F9T specific definitions */ #define ICE_GNSS_UBX_I2C_BUS_ADDR 0x42 /* Data length register is big endian */ #define ICE_GNSS_UBX_DATA_LEN_H 0xFD #define ICE_GNSS_UBX_DATA_LEN_WIDTH 2 #define ICE_GNSS_UBX_EMPTY_DATA 0xFF -#define ICE_GNSS_TIMER_DELAY_TIME (HZ / 10) /* 0.1 second per message */ -#define ICE_MAX_I2C_DATA_SIZE FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M) +/* For u-blox writes are performed without address so the first byte to write is + * passed as I2C addr parameter. + */ +#define ICE_GNSS_UBX_WRITE_BYTES (ICE_MAX_I2C_WRITE_BYTES + 1) #define ICE_MAX_UBX_READ_TRIES 255 +#define ICE_MAX_UBX_ACK_READ_TRIES 4095 + +struct gnss_write_buf { + struct list_head queue; + unsigned int size; + unsigned char *buf; +}; + /** * struct gnss_serial - data used to initialize GNSS TTY port @@ -25,6 +45,8 @@ * @gnss_mutex: gnss_mutex used to protect GNSS serial operations * @kworker: kwork thread for handling periodic work * @read_work: read_work function for handling GNSS reads + * @write_work: write_work function for handling GNSS writes + * @queue: write buffers queue */ struct gnss_serial { struct ice_pf *back; @@ -33,6 +55,8 @@ struct gnss_serial { struct mutex gnss_mutex; /* protects GNSS serial structure */ struct kthread_worker *kworker; struct kthread_delayed_work read_work; + struct kthread_work write_work; + struct list_head queue; }; #if IS_ENABLED(CONFIG_TTY) diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig index da4ec235d146..97374fb3ee79 100644 --- a/drivers/net/ethernet/mediatek/Kconfig +++ b/drivers/net/ethernet/mediatek/Kconfig @@ -17,6 +17,8 @@ config NET_MEDIATEK_SOC select PINCTRL select PHYLINK select DIMLIB + select PAGE_POOL + select PAGE_POOL_STATS help This driver supports the gigabit ethernet MACs in the MediaTek SoC family. diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 6beb3d4873a3..c370d6589596 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -34,6 +34,10 @@ MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); #define MTK_ETHTOOL_STAT(x) { #x, \ offsetof(struct mtk_hw_stats, x) / sizeof(u64) } +#define MTK_ETHTOOL_XDP_STAT(x) { #x, \ + offsetof(struct mtk_hw_stats, xdp_stats.x) / \ + sizeof(u64) } + static const struct mtk_reg_map mtk_reg_map = { .tx_irq_mask = 0x1a1c, .tx_irq_status = 0x1a18, @@ -141,6 +145,13 @@ static const struct mtk_ethtool_stats { MTK_ETHTOOL_STAT(rx_long_errors), MTK_ETHTOOL_STAT(rx_checksum_errors), MTK_ETHTOOL_STAT(rx_flow_control_packets), + MTK_ETHTOOL_XDP_STAT(rx_xdp_redirect), + MTK_ETHTOOL_XDP_STAT(rx_xdp_pass), + MTK_ETHTOOL_XDP_STAT(rx_xdp_drop), + MTK_ETHTOOL_XDP_STAT(rx_xdp_tx), + MTK_ETHTOOL_XDP_STAT(rx_xdp_tx_errors), + MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit), + MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit_errors), }; static const char * const mtk_clks_source_name[] = { @@ -1020,15 +1031,26 @@ static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, } } - tx_buf->flags = 0; - if (tx_buf->skb && - (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) { - if (napi) - napi_consume_skb(tx_buf->skb, napi); + if (tx_buf->type == MTK_TYPE_SKB) { + if (tx_buf->data && + tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { + struct sk_buff *skb = tx_buf->data; + + if (napi) + napi_consume_skb(skb, napi); + else + dev_kfree_skb_any(skb); + } + } else if (tx_buf->data) { + struct xdp_frame *xdpf = tx_buf->data; + + if (napi && tx_buf->type == MTK_TYPE_XDP_TX) + xdp_return_frame_rx_napi(xdpf); else - dev_kfree_skb_any(tx_buf->skb); + xdp_return_frame(xdpf); } - tx_buf->skb = NULL; + tx_buf->flags = 0; + tx_buf->data = NULL; } static void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, @@ -1045,7 +1067,7 @@ static void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, dma_unmap_addr_set(tx_buf, dma_addr1, mapped_addr); dma_unmap_len_set(tx_buf, dma_len1, size); } else { - tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; + tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; txd->txd1 = mapped_addr; txd->txd2 = TX_DMA_PLEN0(size); dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); @@ -1221,7 +1243,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, soc->txrx.txd_size); if (new_desc) memset(tx_buf, 0, sizeof(*tx_buf)); - tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; + tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; tx_buf->flags |= MTK_TX_FLAGS_PAGE0; tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; @@ -1235,7 +1257,8 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, } /* store skb to cleanup */ - itx_buf->skb = skb; + itx_buf->type = MTK_TYPE_SKB; + itx_buf->data = skb; if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { if (k & 0x1) @@ -1432,11 +1455,259 @@ static void mtk_update_rx_cpu_idx(struct mtk_eth *eth) } } +static bool mtk_page_pool_enabled(struct mtk_eth *eth) +{ + return !eth->hwlro; +} + +static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, + struct xdp_rxq_info *xdp_q, + int id, int size) +{ + struct page_pool_params pp_params = { + .order = 0, + .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, + .pool_size = size, + .nid = NUMA_NO_NODE, + .dev = eth->dma_dev, + .offset = MTK_PP_HEADROOM, + .max_len = MTK_PP_MAX_BUF_SIZE, + }; + struct page_pool *pp; + int err; + + pp_params.dma_dir = rcu_access_pointer(eth->prog) ? DMA_BIDIRECTIONAL + : DMA_FROM_DEVICE; + pp = page_pool_create(&pp_params); + if (IS_ERR(pp)) + return pp; + + err = __xdp_rxq_info_reg(xdp_q, ð->dummy_dev, eth->rx_napi.napi_id, + id, PAGE_SIZE); + if (err < 0) + goto err_free_pp; + + err = xdp_rxq_info_reg_mem_model(xdp_q, MEM_TYPE_PAGE_POOL, pp); + if (err) + goto err_unregister_rxq; + + return pp; + +err_unregister_rxq: + xdp_rxq_info_unreg(xdp_q); +err_free_pp: + page_pool_destroy(pp); + + return ERR_PTR(err); +} + +static void *mtk_page_pool_get_buff(struct page_pool *pp, dma_addr_t *dma_addr, + gfp_t gfp_mask) +{ + struct page *page; + + page = page_pool_alloc_pages(pp, gfp_mask | __GFP_NOWARN); + if (!page) + return NULL; + + *dma_addr = page_pool_get_dma_addr(page) + MTK_PP_HEADROOM; + return page_address(page); +} + +static void mtk_rx_put_buff(struct mtk_rx_ring *ring, void *data, bool napi) +{ + if (ring->page_pool) + page_pool_put_full_page(ring->page_pool, + virt_to_head_page(data), napi); + else + skb_free_frag(data); +} + +static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + struct net_device *dev, bool dma_map) +{ + const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; + struct mtk_tx_dma_desc_info txd_info = { + .size = xdpf->len, + .first = true, + .last = true, + }; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_tx_dma *txd, *txd_pdma; + int err = 0, index = 0, n_desc = 1; + struct mtk_tx_buf *tx_buf; + + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + return -EBUSY; + + if (unlikely(atomic_read(&ring->free_count) <= 1)) + return -EBUSY; + + spin_lock(ð->page_lock); + + txd = ring->next_free; + if (txd == ring->last_free) { + err = -ENOMEM; + goto out; + } + + tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); + memset(tx_buf, 0, sizeof(*tx_buf)); + + if (dma_map) { /* ndo_xdp_xmit */ + txd_info.addr = dma_map_single(eth->dma_dev, xdpf->data, + txd_info.size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) { + err = -ENOMEM; + goto out; + } + tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + } else { + struct page *page = virt_to_head_page(xdpf->data); + + txd_info.addr = page_pool_get_dma_addr(page) + + sizeof(*xdpf) + xdpf->headroom; + dma_sync_single_for_device(eth->dma_dev, txd_info.addr, + txd_info.size, + DMA_BIDIRECTIONAL); + } + mtk_tx_set_dma_desc(dev, txd, &txd_info); + + tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; + + txd_pdma = qdma_to_pdma(ring, txd); + setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, txd_info.size, + index++); + + /* store xdpf for cleanup */ + tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; + tx_buf->data = xdpf; + + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + if (index & 1) + txd_pdma->txd2 |= TX_DMA_LS0; + else + txd_pdma->txd2 |= TX_DMA_LS1; + } + + ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); + atomic_sub(n_desc, &ring->free_count); + + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + + if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); + } else { + int idx; + + idx = txd_to_idx(ring, txd, soc->txrx.txd_size); + mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), + MT7628_TX_CTX_IDX0); + } +out: + spin_unlock(ð->page_lock); + + return err; +} + +static int mtk_xdp_xmit(struct net_device *dev, int num_frame, + struct xdp_frame **frames, u32 flags) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_hw_stats *hw_stats = mac->hw_stats; + struct mtk_eth *eth = mac->hw; + int i, nxmit = 0; + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; + + for (i = 0; i < num_frame; i++) { + if (mtk_xdp_submit_frame(eth, frames[i], dev, true)) + break; + nxmit++; + } + + u64_stats_update_begin(&hw_stats->syncp); + hw_stats->xdp_stats.tx_xdp_xmit += nxmit; + hw_stats->xdp_stats.tx_xdp_xmit_errors += num_frame - nxmit; + u64_stats_update_end(&hw_stats->syncp); + + return nxmit; +} + +static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, + struct xdp_buff *xdp, struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_hw_stats *hw_stats = mac->hw_stats; + u64 *count = &hw_stats->xdp_stats.rx_xdp_drop; + struct bpf_prog *prog; + u32 act = XDP_PASS; + + rcu_read_lock(); + + prog = rcu_dereference(eth->prog); + if (!prog) + goto out; + + act = bpf_prog_run_xdp(prog, xdp); + switch (act) { + case XDP_PASS: + count = &hw_stats->xdp_stats.rx_xdp_pass; + goto update_stats; + case XDP_REDIRECT: + if (unlikely(xdp_do_redirect(dev, xdp, prog))) { + act = XDP_DROP; + break; + } + + count = &hw_stats->xdp_stats.rx_xdp_redirect; + goto update_stats; + case XDP_TX: { + struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); + + if (mtk_xdp_submit_frame(eth, xdpf, dev, false)) { + count = &hw_stats->xdp_stats.rx_xdp_tx_errors; + act = XDP_DROP; + break; + } + + count = &hw_stats->xdp_stats.rx_xdp_tx; + goto update_stats; + } + default: + bpf_warn_invalid_xdp_action(dev, prog, act); + fallthrough; + case XDP_ABORTED: + trace_xdp_exception(dev, prog, act); + fallthrough; + case XDP_DROP: + break; + } + + page_pool_put_full_page(ring->page_pool, + virt_to_head_page(xdp->data), true); + +update_stats: + u64_stats_update_begin(&hw_stats->syncp); + *count = *count + 1; + u64_stats_update_end(&hw_stats->syncp); +out: + rcu_read_unlock(); + + return act; +} + static int mtk_poll_rx(struct napi_struct *napi, int budget, struct mtk_eth *eth) { struct dim_sample dim_sample = {}; struct mtk_rx_ring *ring; + bool xdp_flush = false; int idx; struct sk_buff *skb; u8 *data, *new_data; @@ -1477,41 +1748,86 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, if (unlikely(test_bit(MTK_RESETTING, ð->state))) goto release_desc; + pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + /* alloc new buffer */ - if (ring->frag_size <= PAGE_SIZE) - new_data = napi_alloc_frag(ring->frag_size); - else - new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); - if (unlikely(!new_data)) { - netdev->stats.rx_dropped++; - goto release_desc; - } - dma_addr = dma_map_single(eth->dma_dev, - new_data + NET_SKB_PAD + - eth->ip_align, - ring->buf_size, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) { - skb_free_frag(new_data); - netdev->stats.rx_dropped++; - goto release_desc; - } + if (ring->page_pool) { + struct page *page = virt_to_head_page(data); + struct xdp_buff xdp; + u32 ret; + + new_data = mtk_page_pool_get_buff(ring->page_pool, + &dma_addr, + GFP_ATOMIC); + if (unlikely(!new_data)) { + netdev->stats.rx_dropped++; + goto release_desc; + } - dma_unmap_single(eth->dma_dev, trxd.rxd1, - ring->buf_size, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(eth->dma_dev, + page_pool_get_dma_addr(page) + MTK_PP_HEADROOM, + pktlen, page_pool_get_dma_dir(ring->page_pool)); - /* receive data */ - skb = build_skb(data, ring->frag_size); - if (unlikely(!skb)) { - skb_free_frag(data); - netdev->stats.rx_dropped++; - goto skip_rx; + xdp_init_buff(&xdp, PAGE_SIZE, &ring->xdp_q); + xdp_prepare_buff(&xdp, data, MTK_PP_HEADROOM, pktlen, + false); + xdp_buff_clear_frags_flag(&xdp); + + ret = mtk_xdp_run(eth, ring, &xdp, netdev); + if (ret == XDP_REDIRECT) + xdp_flush = true; + + if (ret != XDP_PASS) + goto skip_rx; + + skb = build_skb(data, PAGE_SIZE); + if (unlikely(!skb)) { + page_pool_put_full_page(ring->page_pool, + page, true); + netdev->stats.rx_dropped++; + goto skip_rx; + } + + skb_reserve(skb, xdp.data - xdp.data_hard_start); + skb_put(skb, xdp.data_end - xdp.data); + skb_mark_for_recycle(skb); + } else { + if (ring->frag_size <= PAGE_SIZE) + new_data = napi_alloc_frag(ring->frag_size); + else + new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); + + if (unlikely(!new_data)) { + netdev->stats.rx_dropped++; + goto release_desc; + } + + dma_addr = dma_map_single(eth->dma_dev, + new_data + NET_SKB_PAD + eth->ip_align, + ring->buf_size, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, + dma_addr))) { + skb_free_frag(new_data); + netdev->stats.rx_dropped++; + goto release_desc; + } + + dma_unmap_single(eth->dma_dev, trxd.rxd1, + ring->buf_size, DMA_FROM_DEVICE); + + skb = build_skb(data, ring->frag_size); + if (unlikely(!skb)) { + netdev->stats.rx_dropped++; + skb_free_frag(data); + goto skip_rx; + } + + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + skb_put(skb, pktlen); } - skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); - pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); skb->dev = netdev; - skb_put(skb, pktlen); + bytes += skb->len; if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) rxdcsum = &trxd.rxd3; @@ -1523,7 +1839,6 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, else skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); - bytes += pktlen; hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; if (hash != MTK_RXD4_FOE_ENTRY) { @@ -1561,7 +1876,6 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, skip_rx: ring->data[idx] = new_data; rxd->rxd1 = (unsigned int)dma_addr; - release_desc: if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) rxd->rxd2 = RX_DMA_LSO; @@ -1569,7 +1883,6 @@ release_desc: rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); ring->calc_idx = idx; - done++; } @@ -1588,6 +1901,9 @@ rx_done: &dim_sample); net_dim(ð->rx_dim, dim_sample); + if (xdp_flush) + xdp_do_flush_map(); + return done; } @@ -1596,9 +1912,8 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, { const struct mtk_reg_map *reg_map = eth->soc->reg_map; struct mtk_tx_ring *ring = ð->tx_ring; - struct mtk_tx_dma *desc; - struct sk_buff *skb; struct mtk_tx_buf *tx_buf; + struct mtk_tx_dma *desc; u32 cpu, dma; cpu = ring->last_free_ptr; @@ -1619,15 +1934,21 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) mac = 1; - skb = tx_buf->skb; - if (!skb) + if (!tx_buf->data) break; - if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { + if (tx_buf->type == MTK_TYPE_SKB && + tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { + struct sk_buff *skb = tx_buf->data; + bytes[mac] += skb->len; done[mac]++; budget--; + } else if (tx_buf->type == MTK_TYPE_XDP_TX || + tx_buf->type == MTK_TYPE_XDP_NDO) { + budget--; } + mtk_tx_unmap(eth, tx_buf, true); ring->last_free = desc; @@ -1646,9 +1967,8 @@ static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, unsigned int *done, unsigned int *bytes) { struct mtk_tx_ring *ring = ð->tx_ring; - struct mtk_tx_dma *desc; - struct sk_buff *skb; struct mtk_tx_buf *tx_buf; + struct mtk_tx_dma *desc; u32 cpu, dma; cpu = ring->cpu_idx; @@ -1656,14 +1976,18 @@ static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, while ((cpu != dma) && budget) { tx_buf = &ring->buf[cpu]; - skb = tx_buf->skb; - if (!skb) + if (!tx_buf->data) break; - if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { + if (tx_buf->type == MTK_TYPE_SKB && + tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { + struct sk_buff *skb = tx_buf->data; bytes[0] += skb->len; done[0]++; budget--; + } else if (tx_buf->type == MTK_TYPE_XDP_TX || + tx_buf->type == MTK_TYPE_XDP_NDO) { + budget--; } mtk_tx_unmap(eth, tx_buf, true); @@ -1933,13 +2257,15 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) if (!ring->data) return -ENOMEM; - for (i = 0; i < rx_dma_size; i++) { - if (ring->frag_size <= PAGE_SIZE) - ring->data[i] = netdev_alloc_frag(ring->frag_size); - else - ring->data[i] = mtk_max_lro_buf_alloc(GFP_KERNEL); - if (!ring->data[i]) - return -ENOMEM; + if (mtk_page_pool_enabled(eth)) { + struct page_pool *pp; + + pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, + rx_dma_size); + if (IS_ERR(pp)) + return PTR_ERR(pp); + + ring->page_pool = pp; } ring->dma = dma_alloc_coherent(eth->dma_dev, @@ -1950,16 +2276,33 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) for (i = 0; i < rx_dma_size; i++) { struct mtk_rx_dma_v2 *rxd; - - dma_addr_t dma_addr = dma_map_single(eth->dma_dev, - ring->data[i] + NET_SKB_PAD + eth->ip_align, - ring->buf_size, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) - return -ENOMEM; + dma_addr_t dma_addr; + void *data; rxd = ring->dma + i * eth->soc->txrx.rxd_size; + if (ring->page_pool) { + data = mtk_page_pool_get_buff(ring->page_pool, + &dma_addr, GFP_KERNEL); + if (!data) + return -ENOMEM; + } else { + if (ring->frag_size <= PAGE_SIZE) + data = netdev_alloc_frag(ring->frag_size); + else + data = mtk_max_lro_buf_alloc(GFP_KERNEL); + + if (!data) + return -ENOMEM; + + dma_addr = dma_map_single(eth->dma_dev, + data + NET_SKB_PAD + eth->ip_align, + ring->buf_size, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, + dma_addr))) + return -ENOMEM; + } rxd->rxd1 = (unsigned int)dma_addr; + ring->data[i] = data; if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) rxd->rxd2 = RX_DMA_LSO; @@ -1975,6 +2318,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) rxd->rxd8 = 0; } } + ring->dma_size = rx_dma_size; ring->calc_idx_update = false; ring->calc_idx = rx_dma_size - 1; @@ -2026,7 +2370,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring) dma_unmap_single(eth->dma_dev, rxd->rxd1, ring->buf_size, DMA_FROM_DEVICE); - skb_free_frag(ring->data[i]); + mtk_rx_put_buff(ring, ring->data[i], false); } kfree(ring->data); ring->data = NULL; @@ -2038,6 +2382,13 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring) ring->dma, ring->phys); ring->dma = NULL; } + + if (ring->page_pool) { + if (xdp_rxq_info_is_reg(&ring->xdp_q)) + xdp_rxq_info_unreg(&ring->xdp_q); + page_pool_destroy(ring->page_pool); + ring->page_pool = NULL; + } } static int mtk_hwlro_rx_init(struct mtk_eth *eth) @@ -2645,6 +2996,48 @@ static int mtk_stop(struct net_device *dev) return 0; } +static int mtk_xdp_setup(struct net_device *dev, struct bpf_prog *prog, + struct netlink_ext_ack *extack) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct bpf_prog *old_prog; + bool need_update; + + if (eth->hwlro) { + NL_SET_ERR_MSG_MOD(extack, "XDP not supported with HWLRO"); + return -EOPNOTSUPP; + } + + if (dev->mtu > MTK_PP_MAX_BUF_SIZE) { + NL_SET_ERR_MSG_MOD(extack, "MTU too large for XDP"); + return -EOPNOTSUPP; + } + + need_update = !!eth->prog != !!prog; + if (netif_running(dev) && need_update) + mtk_stop(dev); + + old_prog = rcu_replace_pointer(eth->prog, prog, lockdep_rtnl_is_held()); + if (old_prog) + bpf_prog_put(old_prog); + + if (netif_running(dev) && need_update) + return mtk_open(dev); + + return 0; +} + +static int mtk_xdp(struct net_device *dev, struct netdev_bpf *xdp) +{ + switch (xdp->command) { + case XDP_SETUP_PROG: + return mtk_xdp_setup(dev, xdp->prog, xdp->extack); + default: + return -EINVAL; + } +} + static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) { regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, @@ -2940,6 +3333,12 @@ static int mtk_change_mtu(struct net_device *dev, int new_mtu) struct mtk_eth *eth = mac->hw; u32 mcr_cur, mcr_new; + if (rcu_access_pointer(eth->prog) && + length > MTK_PP_MAX_BUF_SIZE) { + netdev_err(dev, "Invalid MTU for XDP mode\n"); + return -EINVAL; + } + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; @@ -3129,11 +3528,18 @@ static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data) int i; switch (stringset) { - case ETH_SS_STATS: + case ETH_SS_STATS: { + struct mtk_mac *mac = netdev_priv(dev); + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) { memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN); data += ETH_GSTRING_LEN; } + if (mtk_page_pool_enabled(mac->hw)) + page_pool_ethtool_stats_get_strings(data); + break; + } + default: break; } } @@ -3141,13 +3547,35 @@ static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data) static int mtk_get_sset_count(struct net_device *dev, int sset) { switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(mtk_ethtool_stats); + case ETH_SS_STATS: { + int count = ARRAY_SIZE(mtk_ethtool_stats); + struct mtk_mac *mac = netdev_priv(dev); + + if (mtk_page_pool_enabled(mac->hw)) + count += page_pool_ethtool_stats_get_count(); + return count; + } default: return -EOPNOTSUPP; } } +static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) +{ + struct page_pool_stats stats = {}; + int i; + + for (i = 0; i < ARRAY_SIZE(eth->rx_ring); i++) { + struct mtk_rx_ring *ring = ð->rx_ring[i]; + + if (!ring->page_pool) + continue; + + page_pool_get_stats(ring->page_pool, &stats); + } + page_pool_ethtool_stats_get(data, &stats); +} + static void mtk_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { @@ -3175,6 +3603,8 @@ static void mtk_get_ethtool_stats(struct net_device *dev, for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); + if (mtk_page_pool_enabled(mac->hw)) + mtk_ethtool_pp_stats(mac->hw, data_dst); } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); } @@ -3267,6 +3697,8 @@ static const struct net_device_ops mtk_netdev_ops = { .ndo_poll_controller = mtk_poll_controller, #endif .ndo_setup_tc = mtk_eth_setup_tc, + .ndo_bpf = mtk_xdp, + .ndo_xdp_xmit = mtk_xdp_xmit, }; static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 0a632896451a..7405c97cda66 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -18,6 +18,8 @@ #include <linux/rhashtable.h> #include <linux/dim.h> #include <linux/bitfield.h> +#include <net/page_pool.h> +#include <linux/bpf_trace.h> #include "mtk_ppe.h" #define MTK_QDMA_PAGE_SIZE 2048 @@ -49,6 +51,11 @@ #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1)) +#define MTK_PP_HEADROOM XDP_PACKET_HEADROOM +#define MTK_PP_PAD (MTK_PP_HEADROOM + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define MTK_PP_MAX_BUF_SIZE (PAGE_SIZE - MTK_PP_PAD) + #define MTK_QRX_OFFSET 0x10 #define MTK_MAX_RX_RING_NUM 4 @@ -563,6 +570,16 @@ struct mtk_tx_dma_v2 { struct mtk_eth; struct mtk_mac; +struct mtk_xdp_stats { + u64 rx_xdp_redirect; + u64 rx_xdp_pass; + u64 rx_xdp_drop; + u64 rx_xdp_tx; + u64 rx_xdp_tx_errors; + u64 tx_xdp_xmit; + u64 tx_xdp_xmit_errors; +}; + /* struct mtk_hw_stats - the structure that holds the traffic statistics. * @stats_lock: make sure that stats operations are atomic * @reg_offset: the status register offset of the SoC @@ -586,6 +603,8 @@ struct mtk_hw_stats { u64 rx_checksum_errors; u64 rx_flow_control_packets; + struct mtk_xdp_stats xdp_stats; + spinlock_t stats_lock; u32 reg_offset; struct u64_stats_sync syncp; @@ -677,6 +696,12 @@ enum mtk_dev_state { MTK_RESETTING }; +enum mtk_tx_buf_type { + MTK_TYPE_SKB, + MTK_TYPE_XDP_TX, + MTK_TYPE_XDP_NDO, +}; + /* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at * by the TX descriptor s * @skb: The SKB pointer of the packet being sent @@ -686,7 +711,9 @@ enum mtk_dev_state { * @dma_len1: The length of the second segment */ struct mtk_tx_buf { - struct sk_buff *skb; + enum mtk_tx_buf_type type; + void *data; + u32 flags; DEFINE_DMA_UNMAP_ADDR(dma_addr0); DEFINE_DMA_UNMAP_LEN(dma_len0); @@ -745,6 +772,9 @@ struct mtk_rx_ring { bool calc_idx_update; u16 calc_idx; u32 crx_idx_reg; + /* page_pool */ + struct page_pool *page_pool; + struct xdp_rxq_info xdp_q; }; enum mkt_eth_capabilities { @@ -1078,6 +1108,8 @@ struct mtk_eth { struct mtk_ppe *ppe; struct rhashtable flow_table; + + struct bpf_prog __rcu *prog; }; /* struct mtk_mac - the structure that holds the info about the MACs of the diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c index 5d457bc9acc1..25dc3c3aa31d 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c @@ -88,32 +88,28 @@ mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth) static int mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info) { - struct net_device_path_ctx ctx = { - .dev = dev, - }; - struct net_device_path path = {}; + struct net_device_path_stack stack; + struct net_device_path *path; + int err; - if (!ctx.dev) + if (!dev) return -ENODEV; - memcpy(ctx.daddr, addr, sizeof(ctx.daddr)); - if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) return -1; - if (!dev->netdev_ops->ndo_fill_forward_path) - return -1; - - if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path)) - return -1; + err = dev_fill_forward_path(dev, addr, &stack); + if (err) + return err; - if (path.type != DEV_PATH_MTK_WDMA) + path = &stack.path[stack.num_paths - 1]; + if (path->type != DEV_PATH_MTK_WDMA) return -1; - info->wdma_idx = path.mtk_wdma.wdma_idx; - info->queue = path.mtk_wdma.queue; - info->bss = path.mtk_wdma.bss; - info->wcid = path.mtk_wdma.wcid; + info->wdma_idx = path->mtk_wdma.wdma_idx; + info->queue = path->mtk_wdma.queue; + info->bss = path->mtk_wdma.bss; + info->wcid = path->mtk_wdma.wcid; return 0; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h index 666d6b6e4dbf..60232fb8ccd7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h +++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h @@ -329,6 +329,32 @@ MLXSW_ITEM64(cmd_mbox, query_fw, free_running_clock_offset, 0x50, 0, 64); */ MLXSW_ITEM32(cmd_mbox, query_fw, fr_rn_clk_bar, 0x58, 30, 2); +/* cmd_mbox_query_fw_utc_sec_offset + * The offset of the UTC_Sec page + */ +MLXSW_ITEM64(cmd_mbox, query_fw, utc_sec_offset, 0x70, 0, 64); + +/* cmd_mbox_query_fw_utc_sec_bar + * PCI base address register (BAR) of the UTC_Sec page + * 0: BAR 0 + * 1: 64 bit BAR + * Reserved on SwitchX/-2, Switch-IB/2, Spectrum-1 + */ +MLXSW_ITEM32(cmd_mbox, query_fw, utc_sec_bar, 0x78, 30, 2); + +/* cmd_mbox_query_fw_utc_nsec_offset + * The offset of the UTC_nSec page + */ +MLXSW_ITEM64(cmd_mbox, query_fw, utc_nsec_offset, 0x80, 0, 64); + +/* cmd_mbox_query_fw_utc_nsec_bar + * PCI base address register (BAR) of the UTC_nSec page + * 0: BAR 0 + * 1: 64 bit BAR + * Reserved on SwitchX/-2, Switch-IB/2, Spectrum-1 + */ +MLXSW_ITEM32(cmd_mbox, query_fw, utc_nsec_bar, 0x88, 30, 2); + /* QUERY_BOARDINFO - Query Board Information * ----------------------------------------- * OpMod == 0 (N/A), INMmod == 0 (N/A) @@ -663,6 +689,12 @@ MLXSW_ITEM32(cmd_mbox, config_profile, set_kvd_hash_double_size, 0x0C, 26, 1); */ MLXSW_ITEM32(cmd_mbox, config_profile, set_cqe_version, 0x08, 0, 1); +/* cmd_mbox_config_set_cqe_time_stamp_type + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_cqe_time_stamp_type, 0x08, 2, 1); + /* cmd_mbox_config_profile_max_vepa_channels * Maximum number of VEPA channels per port (0 through 16) * 0 - multi-channel VEPA is disabled @@ -858,6 +890,26 @@ MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_type, MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_properties, 0x60, 0, 8, 0x08, 0x00, false); +enum mlxsw_cmd_mbox_config_profile_cqe_time_stamp_type { + /* uSec - 1.024uSec (default). Only bits 15:0 are valid. */ + MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_USEC, + /* FRC - Free Running Clock, units of 1nSec. + * Reserved when SwitchX/-2, Switch-IB/2 and Spectrum-1. + */ + MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_FRC, + /* UTC. time_stamp[37:30] = Sec, time_stamp[29:0] = nSec. + * Reserved when SwitchX/2, Switch-IB/2 and Spectrum-1. + */ + MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, +}; + +/* cmd_mbox_config_profile_cqe_time_stamp_type + * CQE time_stamp_type for non-mirror-packets. + * Configured if set_cqe_time_stamp_type is set. + * Reserved when SwitchX/-2, Switch-IB/2 and Spectrum-1. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, cqe_time_stamp_type, 0xB0, 8, 2); + /* cmd_mbox_config_profile_cqe_version * CQE version: * 0: CQE version is 0 diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 61eb96b93889..1b61bc8f59a2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -2296,8 +2296,8 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, devl_resources_unregister(devlink); mlxsw_core->bus->fini(mlxsw_core->bus_priv); if (!reload) { - devlink_free(devlink); devl_unlock(devlink); + devlink_free(devlink); } return; @@ -2305,8 +2305,8 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, reload_fail_deinit: mlxsw_core_params_unregister(mlxsw_core); devl_resources_unregister(devlink); - devlink_free(devlink); devl_unlock(devlink); + devlink_free(devlink); } EXPORT_SYMBOL(mlxsw_core_bus_device_unregister); diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index a3491ef2aa7e..9d2e8a8d3a75 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -296,7 +296,8 @@ struct mlxsw_config_profile { used_ar_sec:1, used_adaptive_routing_group_cap:1, used_ubridge:1, - used_kvd_sizes:1; + used_kvd_sizes:1, + used_cqe_time_stamp_type:1; u8 max_vepa_channels; u16 max_mid; u16 max_pgt; @@ -319,6 +320,7 @@ struct mlxsw_config_profile { u32 kvd_linear_size; u8 kvd_hash_single_parts; u8 kvd_hash_double_parts; + u8 cqe_time_stamp_type; struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT]; }; @@ -485,7 +487,7 @@ struct mlxsw_bus_info { u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; u8 low_frequency:1, - read_frc_capable:1; + read_clock_capable:1; }; struct mlxsw_hwmon; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 41f0f68bc911..83659fb0559a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -505,6 +505,12 @@ static void mlxsw_pci_cq_fini(struct mlxsw_pci *mlxsw_pci, mlxsw_cmd_hw2sw_cq(mlxsw_pci->core, q->num); } +static unsigned int mlxsw_pci_read32_off(struct mlxsw_pci *mlxsw_pci, + ptrdiff_t off) +{ + return ioread32be(mlxsw_pci->hw_addr + off); +} + static void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci, struct mlxsw_pci_queue *q, u16 consumer_counter_limit, @@ -1267,6 +1273,13 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox, mlxsw_cmd_mbox_config_profile_cqe_version_set(mbox, 1); } + if (profile->used_cqe_time_stamp_type) { + mlxsw_cmd_mbox_config_profile_set_cqe_time_stamp_type_set(mbox, + 1); + mlxsw_cmd_mbox_config_profile_cqe_time_stamp_type_set(mbox, + profile->cqe_time_stamp_type); + } + return mlxsw_cmd_config_profile_set(mlxsw_pci->core, mbox); } @@ -1802,19 +1815,19 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, static u32 mlxsw_pci_read_frc_h(void *bus_priv) { struct mlxsw_pci *mlxsw_pci = bus_priv; - u64 frc_offset; + u64 frc_offset_h; - frc_offset = mlxsw_pci->free_running_clock_offset; - return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_H(frc_offset)); + frc_offset_h = mlxsw_pci->free_running_clock_offset; + return mlxsw_pci_read32_off(mlxsw_pci, frc_offset_h); } static u32 mlxsw_pci_read_frc_l(void *bus_priv) { struct mlxsw_pci *mlxsw_pci = bus_priv; - u64 frc_offset; + u64 frc_offset_l; - frc_offset = mlxsw_pci->free_running_clock_offset; - return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_L(frc_offset)); + frc_offset_l = mlxsw_pci->free_running_clock_offset + 4; + return mlxsw_pci_read32_off(mlxsw_pci, frc_offset_l); } static const struct mlxsw_bus mlxsw_pci_bus = { @@ -1916,7 +1929,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mlxsw_pci->bus_info.device_kind = driver_name; mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); mlxsw_pci->bus_info.dev = &pdev->dev; - mlxsw_pci->bus_info.read_frc_capable = true; + mlxsw_pci->bus_info.read_clock_capable = true; mlxsw_pci->id = id; err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 7b531228d6c0..48dbfea0a2a1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -41,9 +41,6 @@ #define MLXSW_PCI_DOORBELL(offset, type_offset, num) \ ((offset) + (type_offset) + (num) * 4) -#define MLXSW_PCI_FREE_RUNNING_CLOCK_H(offset) (offset) -#define MLXSW_PCI_FREE_RUNNING_CLOCK_L(offset) ((offset) + 4) - #define MLXSW_PCI_CQS_MAX 96 #define MLXSW_PCI_EQS_COUNT 2 #define MLXSW_PCI_EQ_ASYNC_NUM 0 @@ -217,6 +214,25 @@ MLXSW_ITEM32(pci, cqe0, dqn, 0x0C, 1, 5); MLXSW_ITEM32(pci, cqe12, dqn, 0x0C, 1, 6); mlxsw_pci_cqe_item_helpers(dqn, 0, 12, 12); +/* pci_cqe_time_stamp_low + * Time stamp of the CQE + * Format according to time_stamp_type: + * 0: uSec - 1.024uSec (default for devices which do not support + * time_stamp_type). Only bits 15:0 are valid + * 1: FRC - Free Running Clock - units of 1nSec + * 2: UTC - time_stamp[37:30] = Sec + * - time_stamp[29:0] = nSec + * 3: Mirror_UTC. UTC time stamp of the original packet that has + * MIRROR_SESSION traps + * - time_stamp[37:30] = Sec + * - time_stamp[29:0] = nSec + * Formats 0..2 are configured by + * CONFIG_PROFILE.cqe_time_stamp_type for PTP traps + * Format 3 is used for MIRROR_SESSION traps + * Note that Spectrum does not reveal FRC, UTC and Mirror_UTC + */ +MLXSW_ITEM32(pci, cqe2, time_stamp_low, 0x0C, 16, 16); + #define MLXSW_PCI_CQE2_MIRROR_TCLASS_INVALID 0x1F /* pci_cqe_mirror_tclass @@ -280,8 +296,67 @@ MLXSW_ITEM32(pci, cqe2, user_def_val_orig_pkt_len, 0x14, 0, 20); */ MLXSW_ITEM32(pci, cqe2, mirror_reason, 0x18, 24, 8); +enum mlxsw_pci_cqe_time_stamp_type { + MLXSW_PCI_CQE_TIME_STAMP_TYPE_USEC, + MLXSW_PCI_CQE_TIME_STAMP_TYPE_FRC, + MLXSW_PCI_CQE_TIME_STAMP_TYPE_UTC, + MLXSW_PCI_CQE_TIME_STAMP_TYPE_MIRROR_UTC, +}; + +/* pci_cqe_time_stamp_type + * Time stamp type: + * 0: uSec - 1.024uSec (default for devices which do not support + * time_stamp_type) + * 1: FRC - Free Running Clock - units of 1nSec + * 2: UTC + * 3: Mirror_UTC. UTC time stamp of the original packet that has + * MIRROR_SESSION traps + */ +MLXSW_ITEM32(pci, cqe2, time_stamp_type, 0x18, 22, 2); + #define MLXSW_PCI_CQE2_MIRROR_LATENCY_INVALID 0xFFFFFF +/* pci_cqe_time_stamp_high + * Time stamp of the CQE + * Format according to time_stamp_type: + * 0: uSec - 1.024uSec (default for devices which do not support + * time_stamp_type). Only bits 15:0 are valid + * 1: FRC - Free Running Clock - units of 1nSec + * 2: UTC - time_stamp[37:30] = Sec + * - time_stamp[29:0] = nSec + * 3: Mirror_UTC. UTC time stamp of the original packet that has + * MIRROR_SESSION traps + * - time_stamp[37:30] = Sec + * - time_stamp[29:0] = nSec + * Formats 0..2 are configured by + * CONFIG_PROFILE.cqe_time_stamp_type for PTP traps + * Format 3 is used for MIRROR_SESSION traps + * Note that Spectrum does not reveal FRC, UTC and Mirror_UTC + */ +MLXSW_ITEM32(pci, cqe2, time_stamp_high, 0x18, 0, 22); + +static inline u64 mlxsw_pci_cqe2_time_stamp_get(const char *cqe) +{ + u64 ts_high = mlxsw_pci_cqe2_time_stamp_high_get(cqe); + u64 ts_low = mlxsw_pci_cqe2_time_stamp_low_get(cqe); + + return ts_high << 16 | ts_low; +} + +static inline u8 mlxsw_pci_cqe2_time_stamp_sec_get(const char *cqe) +{ + u64 full_ts = mlxsw_pci_cqe2_time_stamp_get(cqe); + + return full_ts >> 30 & 0xFF; +} + +static inline u32 mlxsw_pci_cqe2_time_stamp_nsec_get(const char *cqe) +{ + u64 full_ts = mlxsw_pci_cqe2_time_stamp_get(cqe); + + return full_ts & 0x3FFFFFFF; +} + /* pci_cqe_mirror_latency * End-to-end latency of the original packet that does mirroring to the CPU. * Value of 0xFFFFFF means that the latency is invalid. Units are according to diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 17ce28e65464..ddab5476c8b2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -10347,6 +10347,8 @@ MLXSW_REG_DEFINE(mtutc, MLXSW_REG_MTUTC_ID, MLXSW_REG_MTUTC_LEN); enum mlxsw_reg_mtutc_operation { MLXSW_REG_MTUTC_OPERATION_SET_TIME_AT_NEXT_SEC = 0, + MLXSW_REG_MTUTC_OPERATION_SET_TIME_IMMEDIATE = 1, + MLXSW_REG_MTUTC_OPERATION_ADJUST_TIME = 2, MLXSW_REG_MTUTC_OPERATION_ADJUST_FREQ = 3, }; @@ -10359,25 +10361,50 @@ MLXSW_ITEM32(reg, mtutc, operation, 0x00, 0, 4); /* reg_mtutc_freq_adjustment * Frequency adjustment: Every PPS the HW frequency will be * adjusted by this value. Units of HW clock, where HW counts - * 10^9 HW clocks for 1 HW second. + * 10^9 HW clocks for 1 HW second. Range is from -50,000,000 to +50,000,000. + * In Spectrum-2, the field is reversed, positive values mean to decrease the + * frequency. * Access: RW */ MLXSW_ITEM32(reg, mtutc, freq_adjustment, 0x04, 0, 32); +#define MLXSW_REG_MTUTC_MAX_FREQ_ADJ (50 * 1000 * 1000) + /* reg_mtutc_utc_sec * UTC seconds. * Access: WO */ MLXSW_ITEM32(reg, mtutc, utc_sec, 0x10, 0, 32); +/* reg_mtutc_utc_nsec + * UTC nSecs. + * Range 0..(10^9-1) + * Updated when operation is SET_TIME_IMMEDIATE. + * Reserved on Spectrum-1. + * Access: WO + */ +MLXSW_ITEM32(reg, mtutc, utc_nsec, 0x14, 0, 30); + +/* reg_mtutc_time_adjustment + * Time adjustment. + * Units of nSec. + * Range is from -32768 to +32767. + * Updated when operation is ADJUST_TIME. + * Reserved on Spectrum-1. + * Access: WO + */ +MLXSW_ITEM32(reg, mtutc, time_adjustment, 0x18, 0, 32); + static inline void mlxsw_reg_mtutc_pack(char *payload, enum mlxsw_reg_mtutc_operation oper, - u32 freq_adj, u32 utc_sec) + u32 freq_adj, u32 utc_sec, u32 utc_nsec, u32 time_adj) { MLXSW_REG_ZERO(mtutc, payload); mlxsw_reg_mtutc_operation_set(payload, oper); mlxsw_reg_mtutc_freq_adjustment_set(payload, freq_adj); mlxsw_reg_mtutc_utc_sec_set(payload, utc_sec); + mlxsw_reg_mtutc_utc_nsec_set(payload, utc_nsec); + mlxsw_reg_mtutc_time_adjustment_set(payload, time_adj); } /* MCQI - Management Component Query Information @@ -11045,15 +11072,76 @@ MLXSW_ITEM32(reg, mtptpt, trap_id, 0x00, 0, 4); */ MLXSW_ITEM32(reg, mtptpt, message_type, 0x04, 0, 16); -static inline void mlxsw_reg_mtptptp_pack(char *payload, - enum mlxsw_reg_mtptpt_trap_id trap_id, - u16 message_type) +static inline void mlxsw_reg_mtptpt_pack(char *payload, + enum mlxsw_reg_mtptpt_trap_id trap_id, + u16 message_type) { MLXSW_REG_ZERO(mtptpt, payload); mlxsw_reg_mtptpt_trap_id_set(payload, trap_id); mlxsw_reg_mtptpt_message_type_set(payload, message_type); } +/* MTPCPC - Monitoring Time Precision Correction Port Configuration Register + * ------------------------------------------------------------------------- + */ +#define MLXSW_REG_MTPCPC_ID 0x9093 +#define MLXSW_REG_MTPCPC_LEN 0x2C + +MLXSW_REG_DEFINE(mtpcpc, MLXSW_REG_MTPCPC_ID, MLXSW_REG_MTPCPC_LEN); + +/* reg_mtpcpc_pport + * Per port: + * 0: config is global. When reading - the local_port is 1. + * 1: config is per port. + * Access: Index + */ +MLXSW_ITEM32(reg, mtpcpc, pport, 0x00, 31, 1); + +/* reg_mtpcpc_local_port + * Local port number. + * Supported to/from CPU port. + * Reserved when pport = 0. + * Access: Index + */ +MLXSW_ITEM32_LP(reg, mtpcpc, 0x00, 16, 0x00, 12); + +/* reg_mtpcpc_ptp_trap_en + * Enable PTP traps. + * The trap_id is configured by MTPTPT. + * Access: RW + */ +MLXSW_ITEM32(reg, mtpcpc, ptp_trap_en, 0x04, 0, 1); + +/* reg_mtpcpc_ing_correction_message_type + * Bitwise vector of PTP message types to update correction-field at ingress. + * MessageType field as defined by IEEE 1588 Each bit corresponds to a value + * (e.g. Bit0: Sync, Bit1: Delay_Req). Supported also from CPU port. + * Default all 0 + * Access: RW + */ +MLXSW_ITEM32(reg, mtpcpc, ing_correction_message_type, 0x10, 0, 16); + +/* reg_mtpcpc_egr_correction_message_type + * Bitwise vector of PTP message types to update correction-field at egress. + * MessageType field as defined by IEEE 1588 Each bit corresponds to a value + * (e.g. Bit0: Sync, Bit1: Delay_Req). Supported also from CPU port. + * Default all 0 + * Access: RW + */ +MLXSW_ITEM32(reg, mtpcpc, egr_correction_message_type, 0x14, 0, 16); + +static inline void mlxsw_reg_mtpcpc_pack(char *payload, bool pport, + u16 local_port, bool ptp_trap_en, + u16 ing, u16 egr) +{ + MLXSW_REG_ZERO(mtpcpc, payload); + mlxsw_reg_mtpcpc_pport_set(payload, pport); + mlxsw_reg_mtpcpc_local_port_set(payload, pport ? local_port : 0); + mlxsw_reg_mtpcpc_ptp_trap_en_set(payload, ptp_trap_en); + mlxsw_reg_mtpcpc_ing_correction_message_type_set(payload, ing); + mlxsw_reg_mtpcpc_egr_correction_message_type_set(payload, egr); +} + /* MFGD - Monitoring FW General Debug Register * ------------------------------------------- */ @@ -12770,6 +12858,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mtpppc), MLXSW_REG(mtpptr), MLXSW_REG(mtptpt), + MLXSW_REG(mtpcpc), MLXSW_REG(mfgd), MLXSW_REG(mgpir), MLXSW_REG(mbct), diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 826e47fb4586..19ae0d1c74a8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -24,6 +24,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES, MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC, MLXSW_RES_ID_MAX_SYSTEM_PORT, + MLXSW_RES_ID_FID, MLXSW_RES_ID_MAX_LAG, MLXSW_RES_ID_MAX_LAG_MEMBERS, MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER, @@ -83,6 +84,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES] = 0x2443, [MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC] = 0x2449, [MLXSW_RES_ID_MAX_SYSTEM_PORT] = 0x2502, + [MLXSW_RES_ID_FID] = 0x2512, [MLXSW_RES_ID_MAX_LAG] = 0x2520, [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, [MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 209587cf7529..641078060b02 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -166,7 +166,7 @@ MLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16); * set, otherwise calculated based on the packet's VID using VID to FID mapping. * Valid for data packets only. */ -MLXSW_ITEM32(tx, hdr, fid, 0x08, 0, 16); +MLXSW_ITEM32(tx, hdr, fid, 0x08, 16, 16); /* tx_hdr_type * 0 - Data packets @@ -3096,7 +3096,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_router_init; } - if (mlxsw_sp->bus_info->read_frc_capable) { + if (mlxsw_sp->bus_info->read_clock_capable) { /* NULL is a valid return value from clock_init */ mlxsw_sp->clock = mlxsw_sp->ptp_ops->clock_init(mlxsw_sp, @@ -3411,6 +3411,8 @@ static const struct mlxsw_config_profile mlxsw_sp2_config_profile = { .type = MLXSW_PORT_SWID_TYPE_ETH, } }, + .used_cqe_time_stamp_type = 1, + .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, }; static void diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c index 35422e64d89f..5116d7ebe258 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c @@ -29,6 +29,10 @@ struct mlxsw_sp_ptp_state { struct mlxsw_sp *mlxsw_sp; +}; + +struct mlxsw_sp1_ptp_state { + struct mlxsw_sp_ptp_state common; struct rhltable unmatched_ht; spinlock_t unmatched_lock; /* protects the HT */ struct delayed_work ht_gc_dw; @@ -60,20 +64,37 @@ static const struct rhashtable_params mlxsw_sp1_ptp_unmatched_ht_params = { struct mlxsw_sp_ptp_clock { struct mlxsw_core *core; + struct ptp_clock *ptp; + struct ptp_clock_info ptp_info; +}; + +struct mlxsw_sp1_ptp_clock { + struct mlxsw_sp_ptp_clock common; spinlock_t lock; /* protect this structure */ struct cyclecounter cycles; struct timecounter tc; u32 nominal_c_mult; - struct ptp_clock *ptp; - struct ptp_clock_info ptp_info; unsigned long overflow_period; struct delayed_work overflow_work; }; -static u64 __mlxsw_sp1_ptp_read_frc(struct mlxsw_sp_ptp_clock *clock, +static struct mlxsw_sp1_ptp_state * +mlxsw_sp1_ptp_state(struct mlxsw_sp *mlxsw_sp) +{ + return container_of(mlxsw_sp->ptp_state, struct mlxsw_sp1_ptp_state, + common); +} + +static struct mlxsw_sp1_ptp_clock * +mlxsw_sp1_ptp_clock(struct ptp_clock_info *ptp) +{ + return container_of(ptp, struct mlxsw_sp1_ptp_clock, common.ptp_info); +} + +static u64 __mlxsw_sp1_ptp_read_frc(struct mlxsw_sp1_ptp_clock *clock, struct ptp_system_timestamp *sts) { - struct mlxsw_core *mlxsw_core = clock->core; + struct mlxsw_core *mlxsw_core = clock->common.core; u32 frc_h1, frc_h2, frc_l; frc_h1 = mlxsw_core_read_frc_h(mlxsw_core); @@ -94,20 +115,20 @@ static u64 __mlxsw_sp1_ptp_read_frc(struct mlxsw_sp_ptp_clock *clock, static u64 mlxsw_sp1_ptp_read_frc(const struct cyclecounter *cc) { - struct mlxsw_sp_ptp_clock *clock = - container_of(cc, struct mlxsw_sp_ptp_clock, cycles); + struct mlxsw_sp1_ptp_clock *clock = + container_of(cc, struct mlxsw_sp1_ptp_clock, cycles); return __mlxsw_sp1_ptp_read_frc(clock, NULL) & cc->mask; } static int -mlxsw_sp1_ptp_phc_adjfreq(struct mlxsw_sp_ptp_clock *clock, int freq_adj) +mlxsw_sp_ptp_phc_adjfreq(struct mlxsw_sp_ptp_clock *clock, int freq_adj) { struct mlxsw_core *mlxsw_core = clock->core; char mtutc_pl[MLXSW_REG_MTUTC_LEN]; mlxsw_reg_mtutc_pack(mtutc_pl, MLXSW_REG_MTUTC_OPERATION_ADJUST_FREQ, - freq_adj, 0); + freq_adj, 0, 0, 0); return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtutc), mtutc_pl); } @@ -122,9 +143,9 @@ static u64 mlxsw_sp1_ptp_ns2cycles(const struct timecounter *tc, u64 nsec) } static int -mlxsw_sp1_ptp_phc_settime(struct mlxsw_sp_ptp_clock *clock, u64 nsec) +mlxsw_sp1_ptp_phc_settime(struct mlxsw_sp1_ptp_clock *clock, u64 nsec) { - struct mlxsw_core *mlxsw_core = clock->core; + struct mlxsw_core *mlxsw_core = clock->common.core; u64 next_sec, next_sec_in_nsec, cycles; char mtutc_pl[MLXSW_REG_MTUTC_LEN]; char mtpps_pl[MLXSW_REG_MTPPS_LEN]; @@ -144,14 +165,13 @@ mlxsw_sp1_ptp_phc_settime(struct mlxsw_sp_ptp_clock *clock, u64 nsec) mlxsw_reg_mtutc_pack(mtutc_pl, MLXSW_REG_MTUTC_OPERATION_SET_TIME_AT_NEXT_SEC, - 0, next_sec); + 0, next_sec, 0, 0); return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtutc), mtutc_pl); } static int mlxsw_sp1_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { - struct mlxsw_sp_ptp_clock *clock = - container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info); + struct mlxsw_sp1_ptp_clock *clock = mlxsw_sp1_ptp_clock(ptp); int neg_adj = 0; u32 diff; u64 adj; @@ -174,13 +194,12 @@ static int mlxsw_sp1_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) clock->nominal_c_mult + diff; spin_unlock_bh(&clock->lock); - return mlxsw_sp1_ptp_phc_adjfreq(clock, neg_adj ? -ppb : ppb); + return mlxsw_sp_ptp_phc_adjfreq(&clock->common, neg_adj ? -ppb : ppb); } static int mlxsw_sp1_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { - struct mlxsw_sp_ptp_clock *clock = - container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info); + struct mlxsw_sp1_ptp_clock *clock = mlxsw_sp1_ptp_clock(ptp); u64 nsec; spin_lock_bh(&clock->lock); @@ -195,8 +214,7 @@ static int mlxsw_sp1_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *sts) { - struct mlxsw_sp_ptp_clock *clock = - container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info); + struct mlxsw_sp1_ptp_clock *clock = mlxsw_sp1_ptp_clock(ptp); u64 cycles, nsec; spin_lock_bh(&clock->lock); @@ -212,8 +230,7 @@ static int mlxsw_sp1_ptp_gettimex(struct ptp_clock_info *ptp, static int mlxsw_sp1_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { - struct mlxsw_sp_ptp_clock *clock = - container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info); + struct mlxsw_sp1_ptp_clock *clock = mlxsw_sp1_ptp_clock(ptp); u64 nsec = timespec64_to_ns(ts); spin_lock_bh(&clock->lock); @@ -237,9 +254,9 @@ static const struct ptp_clock_info mlxsw_sp1_ptp_clock_info = { static void mlxsw_sp1_ptp_clock_overflow(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct mlxsw_sp_ptp_clock *clock; + struct mlxsw_sp1_ptp_clock *clock; - clock = container_of(dwork, struct mlxsw_sp_ptp_clock, overflow_work); + clock = container_of(dwork, struct mlxsw_sp1_ptp_clock, overflow_work); spin_lock_bh(&clock->lock); timecounter_read(&clock->tc); @@ -251,7 +268,7 @@ struct mlxsw_sp_ptp_clock * mlxsw_sp1_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev) { u64 overflow_cycles, nsec, frac = 0; - struct mlxsw_sp_ptp_clock *clock; + struct mlxsw_sp1_ptp_clock *clock; int err; clock = kzalloc(sizeof(*clock), GFP_KERNEL); @@ -265,10 +282,9 @@ mlxsw_sp1_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev) clock->cycles.shift); clock->nominal_c_mult = clock->cycles.mult; clock->cycles.mask = CLOCKSOURCE_MASK(MLXSW_SP1_PTP_CLOCK_MASK); - clock->core = mlxsw_sp->core; + clock->common.core = mlxsw_sp->core; - timecounter_init(&clock->tc, &clock->cycles, - ktime_to_ns(ktime_get_real())); + timecounter_init(&clock->tc, &clock->cycles, 0); /* Calculate period in seconds to call the overflow watchdog - to make * sure counter is checked at least twice every wrap around. @@ -286,15 +302,15 @@ mlxsw_sp1_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev) INIT_DELAYED_WORK(&clock->overflow_work, mlxsw_sp1_ptp_clock_overflow); mlxsw_core_schedule_dw(&clock->overflow_work, 0); - clock->ptp_info = mlxsw_sp1_ptp_clock_info; - clock->ptp = ptp_clock_register(&clock->ptp_info, dev); - if (IS_ERR(clock->ptp)) { - err = PTR_ERR(clock->ptp); + clock->common.ptp_info = mlxsw_sp1_ptp_clock_info; + clock->common.ptp = ptp_clock_register(&clock->common.ptp_info, dev); + if (IS_ERR(clock->common.ptp)) { + err = PTR_ERR(clock->common.ptp); dev_err(dev, "ptp_clock_register failed %d\n", err); goto err_ptp_clock_register; } - return clock; + return &clock->common; err_ptp_clock_register: cancel_delayed_work_sync(&clock->overflow_work); @@ -302,9 +318,12 @@ err_ptp_clock_register: return ERR_PTR(err); } -void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock) +void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock_common) { - ptp_clock_unregister(clock->ptp); + struct mlxsw_sp1_ptp_clock *clock = + container_of(clock_common, struct mlxsw_sp1_ptp_clock, common); + + ptp_clock_unregister(clock_common->ptp); cancel_delayed_work_sync(&clock->overflow_work); kfree(clock); } @@ -348,7 +367,7 @@ mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp, u64 timestamp) { int cycles = MLXSW_SP1_PTP_HT_GC_TIMEOUT / MLXSW_SP1_PTP_HT_GC_INTERVAL; - struct mlxsw_sp_ptp_state *ptp_state = mlxsw_sp->ptp_state; + struct mlxsw_sp1_ptp_state *ptp_state = mlxsw_sp1_ptp_state(mlxsw_sp); struct mlxsw_sp1_ptp_unmatched *unmatched; int err; @@ -359,7 +378,7 @@ mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp, unmatched->key = key; unmatched->skb = skb; unmatched->timestamp = timestamp; - unmatched->gc_cycle = mlxsw_sp->ptp_state->gc_cycle + cycles; + unmatched->gc_cycle = ptp_state->gc_cycle + cycles; err = rhltable_insert(&ptp_state->unmatched_ht, &unmatched->ht_node, mlxsw_sp1_ptp_unmatched_ht_params); @@ -373,11 +392,12 @@ static struct mlxsw_sp1_ptp_unmatched * mlxsw_sp1_ptp_unmatched_lookup(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp1_ptp_key key, int *p_length) { + struct mlxsw_sp1_ptp_state *ptp_state = mlxsw_sp1_ptp_state(mlxsw_sp); struct mlxsw_sp1_ptp_unmatched *unmatched, *last = NULL; struct rhlist_head *tmp, *list; int length = 0; - list = rhltable_lookup(&mlxsw_sp->ptp_state->unmatched_ht, &key, + list = rhltable_lookup(&ptp_state->unmatched_ht, &key, mlxsw_sp1_ptp_unmatched_ht_params); rhl_for_each_entry_rcu(unmatched, tmp, list, ht_node) { last = unmatched; @@ -392,7 +412,9 @@ static int mlxsw_sp1_ptp_unmatched_remove(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp1_ptp_unmatched *unmatched) { - return rhltable_remove(&mlxsw_sp->ptp_state->unmatched_ht, + struct mlxsw_sp1_ptp_state *ptp_state = mlxsw_sp1_ptp_state(mlxsw_sp); + + return rhltable_remove(&ptp_state->unmatched_ht, &unmatched->ht_node, mlxsw_sp1_ptp_unmatched_ht_params); } @@ -438,12 +460,16 @@ static void mlxsw_sp1_packet_timestamp(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, u64 timestamp) { + struct mlxsw_sp_ptp_clock *clock_common = mlxsw_sp->clock; + struct mlxsw_sp1_ptp_clock *clock = + container_of(clock_common, struct mlxsw_sp1_ptp_clock, common); + struct skb_shared_hwtstamps hwtstamps; u64 nsec; - spin_lock_bh(&mlxsw_sp->clock->lock); - nsec = timecounter_cyc2time(&mlxsw_sp->clock->tc, timestamp); - spin_unlock_bh(&mlxsw_sp->clock->lock); + spin_lock_bh(&clock->lock); + nsec = timecounter_cyc2time(&clock->tc, timestamp); + spin_unlock_bh(&clock->lock); hwtstamps.hwtstamp = ns_to_ktime(nsec); mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb, @@ -481,13 +507,14 @@ static void mlxsw_sp1_ptp_got_piece(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp1_ptp_key key, struct sk_buff *skb, u64 timestamp) { + struct mlxsw_sp1_ptp_state *ptp_state = mlxsw_sp1_ptp_state(mlxsw_sp); struct mlxsw_sp1_ptp_unmatched *unmatched; int length; int err; rcu_read_lock(); - spin_lock(&mlxsw_sp->ptp_state->unmatched_lock); + spin_lock(&ptp_state->unmatched_lock); unmatched = mlxsw_sp1_ptp_unmatched_lookup(mlxsw_sp, key, &length); if (skb && unmatched && unmatched->timestamp) { @@ -515,7 +542,7 @@ static void mlxsw_sp1_ptp_got_piece(struct mlxsw_sp *mlxsw_sp, WARN_ON_ONCE(err); } - spin_unlock(&mlxsw_sp->ptp_state->unmatched_lock); + spin_unlock(&ptp_state->unmatched_lock); if (unmatched) mlxsw_sp1_ptp_unmatched_finish(mlxsw_sp, unmatched); @@ -611,9 +638,10 @@ void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp, } static void -mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp_ptp_state *ptp_state, +mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp1_ptp_state *ptp_state, struct mlxsw_sp1_ptp_unmatched *unmatched) { + struct mlxsw_sp *mlxsw_sp = ptp_state->common.mlxsw_sp; struct mlxsw_sp_ptp_port_dir_stats *stats; struct mlxsw_sp_port *mlxsw_sp_port; int err; @@ -636,7 +664,7 @@ mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp_ptp_state *ptp_state, /* The packet was matched with timestamp during the walk. */ goto out; - mlxsw_sp_port = ptp_state->mlxsw_sp->ports[unmatched->key.local_port]; + mlxsw_sp_port = mlxsw_sp->ports[unmatched->key.local_port]; if (mlxsw_sp_port) { stats = unmatched->key.ingress ? &mlxsw_sp_port->ptp.stats.rx_gcd : @@ -653,7 +681,7 @@ mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp_ptp_state *ptp_state, * netif_receive_skb(), in process context, is seen elsewhere in the * kernel, notably in pktgen. */ - mlxsw_sp1_ptp_unmatched_finish(ptp_state->mlxsw_sp, unmatched); + mlxsw_sp1_ptp_unmatched_finish(mlxsw_sp, unmatched); out: local_bh_enable(); @@ -663,12 +691,12 @@ static void mlxsw_sp1_ptp_ht_gc(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct mlxsw_sp1_ptp_unmatched *unmatched; - struct mlxsw_sp_ptp_state *ptp_state; + struct mlxsw_sp1_ptp_state *ptp_state; struct rhashtable_iter iter; u32 gc_cycle; void *obj; - ptp_state = container_of(dwork, struct mlxsw_sp_ptp_state, ht_gc_dw); + ptp_state = container_of(dwork, struct mlxsw_sp1_ptp_state, ht_gc_dw); gc_cycle = ptp_state->gc_cycle++; rhltable_walk_enter(&ptp_state->unmatched_ht, &iter); @@ -694,7 +722,7 @@ static int mlxsw_sp_ptp_mtptpt_set(struct mlxsw_sp *mlxsw_sp, { char mtptpt_pl[MLXSW_REG_MTPTPT_LEN]; - mlxsw_reg_mtptptp_pack(mtptpt_pl, trap_id, message_type); + mlxsw_reg_mtptpt_pack(mtptpt_pl, trap_id, message_type); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mtptpt), mtptpt_pl); } @@ -809,7 +837,7 @@ static int mlxsw_sp1_ptp_shaper_params_set(struct mlxsw_sp *mlxsw_sp) struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp) { - struct mlxsw_sp_ptp_state *ptp_state; + struct mlxsw_sp1_ptp_state *ptp_state; u16 message_type; int err; @@ -820,7 +848,7 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp) ptp_state = kzalloc(sizeof(*ptp_state), GFP_KERNEL); if (!ptp_state) return ERR_PTR(-ENOMEM); - ptp_state->mlxsw_sp = mlxsw_sp; + ptp_state->common.mlxsw_sp = mlxsw_sp; spin_lock_init(&ptp_state->unmatched_lock); @@ -853,7 +881,7 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp) INIT_DELAYED_WORK(&ptp_state->ht_gc_dw, mlxsw_sp1_ptp_ht_gc); mlxsw_core_schedule_dw(&ptp_state->ht_gc_dw, MLXSW_SP1_PTP_HT_GC_INTERVAL); - return ptp_state; + return &ptp_state->common; err_fifo_clr: mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0); @@ -866,9 +894,12 @@ err_hashtable_init: return ERR_PTR(err); } -void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state) +void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state_common) { - struct mlxsw_sp *mlxsw_sp = ptp_state->mlxsw_sp; + struct mlxsw_sp *mlxsw_sp = ptp_state_common->mlxsw_sp; + struct mlxsw_sp1_ptp_state *ptp_state; + + ptp_state = mlxsw_sp1_ptp_state(mlxsw_sp); cancel_delayed_work_sync(&ptp_state->ht_gc_dw); mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp, 0, 0); @@ -887,9 +918,10 @@ int mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port, return 0; } -static int mlxsw_sp_ptp_get_message_types(const struct hwtstamp_config *config, - u16 *p_ing_types, u16 *p_egr_types, - enum hwtstamp_rx_filters *p_rx_filter) +static int +mlxsw_sp1_ptp_get_message_types(const struct hwtstamp_config *config, + u16 *p_ing_types, u16 *p_egr_types, + enum hwtstamp_rx_filters *p_rx_filter) { enum hwtstamp_rx_filters rx_filter = config->rx_filter; enum hwtstamp_tx_types tx_type = config->tx_type; @@ -1050,8 +1082,8 @@ int mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 egr_types; int err; - err = mlxsw_sp_ptp_get_message_types(config, &ing_types, &egr_types, - &rx_filter); + err = mlxsw_sp1_ptp_get_message_types(config, &ing_types, &egr_types, + &rx_filter); if (err) return err; |