Import of kernel-5.14.0-570.28.1.el9_6
This commit is contained in:
parent
bbc13f3f35
commit
d63051341b
@ -12,7 +12,7 @@ RHEL_MINOR = 6
|
|||||||
#
|
#
|
||||||
# Use this spot to avoid future merge conflicts.
|
# Use this spot to avoid future merge conflicts.
|
||||||
# Do not trim this comment.
|
# Do not trim this comment.
|
||||||
RHEL_RELEASE = 570.26.1
|
RHEL_RELEASE = 570.28.1
|
||||||
|
|
||||||
#
|
#
|
||||||
# ZSTREAM
|
# ZSTREAM
|
||||||
|
|||||||
@ -1397,6 +1397,11 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||||||
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], MSG_END_CONTINUE);
|
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], MSG_END_CONTINUE);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Validate message length before proceeding */
|
||||||
|
if (msgs[i].buf[0] == 0 || msgs[i].buf[0] > I2C_SMBUS_BLOCK_MAX)
|
||||||
|
break;
|
||||||
|
|
||||||
/* Set the msg length from first byte */
|
/* Set the msg length from first byte */
|
||||||
msgs[i].len += msgs[i].buf[0];
|
msgs[i].len += msgs[i].buf[0];
|
||||||
dev_dbg(i2c_dev->dev, "reading %d bytes\n", msgs[i].len);
|
dev_dbg(i2c_dev->dev, "reading %d bytes\n", msgs[i].len);
|
||||||
|
|||||||
@ -1579,6 +1579,40 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
|
|||||||
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
|
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl,
|
||||||
|
struct uvc_fh *new_handle)
|
||||||
|
{
|
||||||
|
lockdep_assert_held(&handle->chain->ctrl_mutex);
|
||||||
|
|
||||||
|
if (new_handle) {
|
||||||
|
if (ctrl->handle)
|
||||||
|
dev_warn_ratelimited(&handle->stream->dev->udev->dev,
|
||||||
|
"UVC non compliance: Setting an async control with a pending operation.");
|
||||||
|
|
||||||
|
if (new_handle == ctrl->handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ctrl->handle) {
|
||||||
|
WARN_ON(!ctrl->handle->pending_async_ctrls);
|
||||||
|
if (ctrl->handle->pending_async_ctrls)
|
||||||
|
ctrl->handle->pending_async_ctrls--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl->handle = new_handle;
|
||||||
|
handle->pending_async_ctrls++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cannot clear the handle for a control not owned by us.*/
|
||||||
|
if (WARN_ON(ctrl->handle != handle))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctrl->handle = NULL;
|
||||||
|
if (WARN_ON(!handle->pending_async_ctrls))
|
||||||
|
return;
|
||||||
|
handle->pending_async_ctrls--;
|
||||||
|
}
|
||||||
|
|
||||||
void uvc_ctrl_status_event(struct uvc_video_chain *chain,
|
void uvc_ctrl_status_event(struct uvc_video_chain *chain,
|
||||||
struct uvc_control *ctrl, const u8 *data)
|
struct uvc_control *ctrl, const u8 *data)
|
||||||
{
|
{
|
||||||
@ -1588,8 +1622,12 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
|
|||||||
|
|
||||||
mutex_lock(&chain->ctrl_mutex);
|
mutex_lock(&chain->ctrl_mutex);
|
||||||
|
|
||||||
|
/* Flush the control cache, the data might have changed. */
|
||||||
|
ctrl->loaded = 0;
|
||||||
|
|
||||||
handle = ctrl->handle;
|
handle = ctrl->handle;
|
||||||
ctrl->handle = NULL;
|
if (handle)
|
||||||
|
uvc_ctrl_set_handle(handle, ctrl, NULL);
|
||||||
|
|
||||||
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
|
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
|
||||||
s32 value = __uvc_ctrl_get_value(mapping, data);
|
s32 value = __uvc_ctrl_get_value(mapping, data);
|
||||||
@ -1640,10 +1678,8 @@ bool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain,
|
|||||||
struct uvc_device *dev = chain->dev;
|
struct uvc_device *dev = chain->dev;
|
||||||
struct uvc_ctrl_work *w = &dev->async_ctrl;
|
struct uvc_ctrl_work *w = &dev->async_ctrl;
|
||||||
|
|
||||||
if (list_empty(&ctrl->info.mappings)) {
|
if (list_empty(&ctrl->info.mappings))
|
||||||
ctrl->handle = NULL;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
w->data = data;
|
w->data = data;
|
||||||
w->urb = urb;
|
w->urb = urb;
|
||||||
@ -1811,7 +1847,10 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
||||||
struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl)
|
struct uvc_fh *handle,
|
||||||
|
struct uvc_entity *entity,
|
||||||
|
int rollback,
|
||||||
|
struct uvc_control **err_ctrl)
|
||||||
{
|
{
|
||||||
struct uvc_control *ctrl;
|
struct uvc_control *ctrl;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@ -1859,6 +1898,10 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
|||||||
*err_ctrl = ctrl;
|
*err_ctrl = ctrl;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!rollback && handle &&
|
||||||
|
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
|
||||||
|
uvc_ctrl_set_handle(handle, ctrl, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1895,8 +1938,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
|
|||||||
|
|
||||||
/* Find the control. */
|
/* Find the control. */
|
||||||
list_for_each_entry(entity, &chain->entities, chain) {
|
list_for_each_entry(entity, &chain->entities, chain) {
|
||||||
ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback,
|
ret = uvc_ctrl_commit_entity(chain->dev, handle, entity,
|
||||||
&err_ctrl);
|
rollback, &err_ctrl);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ctrls)
|
if (ctrls)
|
||||||
ctrls->error_idx =
|
ctrls->error_idx =
|
||||||
@ -1941,6 +1984,8 @@ int uvc_ctrl_set(struct uvc_fh *handle,
|
|||||||
s32 max;
|
s32 max;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
lockdep_assert_held(&chain->ctrl_mutex);
|
||||||
|
|
||||||
if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
|
if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
@ -2046,9 +2091,6 @@ int uvc_ctrl_set(struct uvc_fh *handle,
|
|||||||
mapping->set(mapping, value,
|
mapping->set(mapping, value,
|
||||||
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
|
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
|
||||||
|
|
||||||
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
|
|
||||||
ctrl->handle = handle;
|
|
||||||
|
|
||||||
ctrl->dirty = 1;
|
ctrl->dirty = 1;
|
||||||
ctrl->modified = 1;
|
ctrl->modified = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@ -2377,7 +2419,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
|
|||||||
ctrl->dirty = 1;
|
ctrl->dirty = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL);
|
ret = uvc_ctrl_commit_entity(dev, NULL, entity, 0, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -2770,6 +2812,26 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uvc_ctrl_cleanup_fh(struct uvc_fh *handle)
|
||||||
|
{
|
||||||
|
struct uvc_entity *entity;
|
||||||
|
|
||||||
|
guard(mutex)(&handle->chain->ctrl_mutex);
|
||||||
|
|
||||||
|
if (!handle->pending_async_ctrls)
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry(entity, &handle->chain->dev->entities, list) {
|
||||||
|
for (unsigned int i = 0; i < entity->ncontrols; ++i) {
|
||||||
|
if (entity->controls[i].handle != handle)
|
||||||
|
continue;
|
||||||
|
uvc_ctrl_set_handle(handle, &entity->controls[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN_ON(handle->pending_async_ctrls);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cleanup device controls.
|
* Cleanup device controls.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
unsigned int uvc_clock_param = CLOCK_MONOTONIC;
|
unsigned int uvc_clock_param = CLOCK_MONOTONIC;
|
||||||
unsigned int uvc_hw_timestamps_param;
|
unsigned int uvc_hw_timestamps_param;
|
||||||
unsigned int uvc_no_drop_param;
|
unsigned int uvc_no_drop_param = 1;
|
||||||
static unsigned int uvc_quirks_param = -1;
|
static unsigned int uvc_quirks_param = -1;
|
||||||
unsigned int uvc_dbg_param;
|
unsigned int uvc_dbg_param;
|
||||||
unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
|
unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
|
||||||
@ -1949,7 +1949,7 @@ int uvc_register_video_device(struct uvc_device *dev,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Initialize the video buffers queue. */
|
/* Initialize the video buffers queue. */
|
||||||
ret = uvc_queue_init(queue, type, !uvc_no_drop_param);
|
ret = uvc_queue_init(queue, type);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -2387,8 +2387,25 @@ module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
|
|||||||
MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
|
MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
|
||||||
module_param_named(hwtimestamps, uvc_hw_timestamps_param, uint, 0644);
|
module_param_named(hwtimestamps, uvc_hw_timestamps_param, uint, 0644);
|
||||||
MODULE_PARM_DESC(hwtimestamps, "Use hardware timestamps");
|
MODULE_PARM_DESC(hwtimestamps, "Use hardware timestamps");
|
||||||
module_param_named(nodrop, uvc_no_drop_param, uint, 0644);
|
|
||||||
|
static int param_set_nodrop(const char *val, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
pr_warn_once("uvcvideo: "
|
||||||
|
DEPRECATED
|
||||||
|
"nodrop parameter will be eventually removed.\n");
|
||||||
|
return param_set_bool(val, kp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct kernel_param_ops param_ops_nodrop = {
|
||||||
|
.set = param_set_nodrop,
|
||||||
|
.get = param_get_uint,
|
||||||
|
};
|
||||||
|
|
||||||
|
param_check_uint(nodrop, &uvc_no_drop_param);
|
||||||
|
module_param_cb(nodrop, ¶m_ops_nodrop, &uvc_no_drop_param, 0644);
|
||||||
|
__MODULE_PARM_TYPE(nodrop, "uint");
|
||||||
MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
|
MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
|
||||||
|
|
||||||
module_param_named(quirks, uvc_quirks_param, uint, 0644);
|
module_param_named(quirks, uvc_quirks_param, uint, 0644);
|
||||||
MODULE_PARM_DESC(quirks, "Forced device quirks");
|
MODULE_PARM_DESC(quirks, "Forced device quirks");
|
||||||
module_param_named(trace, uvc_dbg_param, uint, 0644);
|
module_param_named(trace, uvc_dbg_param, uint, 0644);
|
||||||
|
|||||||
@ -212,8 +212,7 @@ static const struct vb2_ops uvc_meta_queue_qops = {
|
|||||||
.stop_streaming = uvc_stop_streaming,
|
.stop_streaming = uvc_stop_streaming,
|
||||||
};
|
};
|
||||||
|
|
||||||
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
|
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
|
||||||
int drop_corrupted)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -243,7 +242,6 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
|
|||||||
mutex_init(&queue->mutex);
|
mutex_init(&queue->mutex);
|
||||||
spin_lock_init(&queue->irqlock);
|
spin_lock_init(&queue->irqlock);
|
||||||
INIT_LIST_HEAD(&queue->irqqueue);
|
INIT_LIST_HEAD(&queue->irqqueue);
|
||||||
queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -476,14 +474,15 @@ static void uvc_queue_buffer_complete(struct kref *ref)
|
|||||||
struct vb2_buffer *vb = &buf->buf.vb2_buf;
|
struct vb2_buffer *vb = &buf->buf.vb2_buf;
|
||||||
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
|
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
|
||||||
|
|
||||||
if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
|
if (buf->error && !uvc_no_drop_param) {
|
||||||
uvc_queue_buffer_requeue(queue, buf);
|
uvc_queue_buffer_requeue(queue, buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
|
buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
|
||||||
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
|
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
|
||||||
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
|
vb2_buffer_done(&buf->buf.vb2_buf, buf->error ? VB2_BUF_STATE_ERROR :
|
||||||
|
VB2_BUF_STATE_DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -659,6 +659,8 @@ static int uvc_v4l2_release(struct file *file)
|
|||||||
|
|
||||||
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
|
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
|
||||||
|
|
||||||
|
uvc_ctrl_cleanup_fh(handle);
|
||||||
|
|
||||||
/* Only free resources if this is a privileged handle. */
|
/* Only free resources if this is a privileged handle. */
|
||||||
if (uvc_has_privileges(handle))
|
if (uvc_has_privileges(handle))
|
||||||
uvc_queue_release(&stream->queue);
|
uvc_queue_release(&stream->queue);
|
||||||
|
|||||||
@ -316,7 +316,6 @@ struct uvc_buffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define UVC_QUEUE_DISCONNECTED (1 << 0)
|
#define UVC_QUEUE_DISCONNECTED (1 << 0)
|
||||||
#define UVC_QUEUE_DROP_CORRUPTED (1 << 1)
|
|
||||||
|
|
||||||
struct uvc_video_queue {
|
struct uvc_video_queue {
|
||||||
struct vb2_queue queue;
|
struct vb2_queue queue;
|
||||||
@ -337,7 +336,11 @@ struct uvc_video_chain {
|
|||||||
struct uvc_entity *processing; /* Processing unit */
|
struct uvc_entity *processing; /* Processing unit */
|
||||||
struct uvc_entity *selector; /* Selector unit */
|
struct uvc_entity *selector; /* Selector unit */
|
||||||
|
|
||||||
struct mutex ctrl_mutex; /* Protects ctrl.info */
|
struct mutex ctrl_mutex; /*
|
||||||
|
* Protects ctrl.info,
|
||||||
|
* ctrl.handle and
|
||||||
|
* uvc_fh.pending_async_ctrls
|
||||||
|
*/
|
||||||
|
|
||||||
struct v4l2_prio_state prio; /* V4L2 priority state */
|
struct v4l2_prio_state prio; /* V4L2 priority state */
|
||||||
u32 caps; /* V4L2 chain-wide caps */
|
u32 caps; /* V4L2 chain-wide caps */
|
||||||
@ -612,6 +615,7 @@ struct uvc_fh {
|
|||||||
struct uvc_video_chain *chain;
|
struct uvc_video_chain *chain;
|
||||||
struct uvc_streaming *stream;
|
struct uvc_streaming *stream;
|
||||||
enum uvc_handle_state state;
|
enum uvc_handle_state state;
|
||||||
|
unsigned int pending_async_ctrls;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uvc_driver {
|
struct uvc_driver {
|
||||||
@ -674,8 +678,7 @@ extern struct uvc_driver uvc_driver;
|
|||||||
struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
|
struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
|
||||||
|
|
||||||
/* Video buffers queue management. */
|
/* Video buffers queue management. */
|
||||||
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
|
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type);
|
||||||
int drop_corrupted);
|
|
||||||
void uvc_queue_release(struct uvc_video_queue *queue);
|
void uvc_queue_release(struct uvc_video_queue *queue);
|
||||||
int uvc_request_buffers(struct uvc_video_queue *queue,
|
int uvc_request_buffers(struct uvc_video_queue *queue,
|
||||||
struct v4l2_requestbuffers *rb);
|
struct v4l2_requestbuffers *rb);
|
||||||
@ -795,6 +798,8 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
|
|||||||
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
|
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
|
||||||
struct uvc_xu_control_query *xqry);
|
struct uvc_xu_control_query *xqry);
|
||||||
|
|
||||||
|
void uvc_ctrl_cleanup_fh(struct uvc_fh *handle);
|
||||||
|
|
||||||
/* Utility functions */
|
/* Utility functions */
|
||||||
struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
|
struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
|
||||||
u8 epaddr);
|
u8 epaddr);
|
||||||
|
|||||||
@ -326,7 +326,7 @@ static int mlx5e_ptp_alloc_txqsq(struct mlx5e_ptp *c, int txq_ix,
|
|||||||
int node;
|
int node;
|
||||||
|
|
||||||
sq->pdev = c->pdev;
|
sq->pdev = c->pdev;
|
||||||
sq->clock = &mdev->clock;
|
sq->clock = mdev->clock;
|
||||||
sq->mkey_be = c->mkey_be;
|
sq->mkey_be = c->mkey_be;
|
||||||
sq->netdev = c->netdev;
|
sq->netdev = c->netdev;
|
||||||
sq->priv = c->priv;
|
sq->priv = c->priv;
|
||||||
@ -696,7 +696,7 @@ static int mlx5e_init_ptp_rq(struct mlx5e_ptp *c, struct mlx5e_params *params,
|
|||||||
rq->pdev = c->pdev;
|
rq->pdev = c->pdev;
|
||||||
rq->netdev = priv->netdev;
|
rq->netdev = priv->netdev;
|
||||||
rq->priv = priv;
|
rq->priv = priv;
|
||||||
rq->clock = &mdev->clock;
|
rq->clock = mdev->clock;
|
||||||
rq->tstamp = &priv->tstamp;
|
rq->tstamp = &priv->tstamp;
|
||||||
rq->mdev = mdev;
|
rq->mdev = mdev;
|
||||||
rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
|
rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
|
||||||
|
|||||||
@ -46,7 +46,7 @@ static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params
|
|||||||
rq->pdev = t->pdev;
|
rq->pdev = t->pdev;
|
||||||
rq->netdev = priv->netdev;
|
rq->netdev = priv->netdev;
|
||||||
rq->priv = priv;
|
rq->priv = priv;
|
||||||
rq->clock = &mdev->clock;
|
rq->clock = mdev->clock;
|
||||||
rq->tstamp = &priv->tstamp;
|
rq->tstamp = &priv->tstamp;
|
||||||
rq->mdev = mdev;
|
rq->mdev = mdev;
|
||||||
rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
|
rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
|
||||||
|
|||||||
@ -231,9 +231,9 @@ static u64 mlx5e_xsk_fill_timestamp(void *_priv)
|
|||||||
ts = get_cqe_ts(priv->cqe);
|
ts = get_cqe_ts(priv->cqe);
|
||||||
|
|
||||||
if (mlx5_is_real_time_rq(priv->cq->mdev) || mlx5_is_real_time_sq(priv->cq->mdev))
|
if (mlx5_is_real_time_rq(priv->cq->mdev) || mlx5_is_real_time_sq(priv->cq->mdev))
|
||||||
return mlx5_real_time_cyc2time(&priv->cq->mdev->clock, ts);
|
return mlx5_real_time_cyc2time(priv->cq->mdev->clock, ts);
|
||||||
|
|
||||||
return mlx5_timecounter_cyc2time(&priv->cq->mdev->clock, ts);
|
return mlx5_timecounter_cyc2time(priv->cq->mdev->clock, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlx5e_xsk_request_checksum(u16 csum_start, u16 csum_offset, void *priv)
|
static void mlx5e_xsk_request_checksum(u16 csum_start, u16 csum_offset, void *priv)
|
||||||
|
|||||||
@ -72,7 +72,7 @@ static int mlx5e_init_xsk_rq(struct mlx5e_channel *c,
|
|||||||
rq->netdev = c->netdev;
|
rq->netdev = c->netdev;
|
||||||
rq->priv = c->priv;
|
rq->priv = c->priv;
|
||||||
rq->tstamp = c->tstamp;
|
rq->tstamp = c->tstamp;
|
||||||
rq->clock = &mdev->clock;
|
rq->clock = mdev->clock;
|
||||||
rq->icosq = &c->icosq;
|
rq->icosq = &c->icosq;
|
||||||
rq->ix = c->ix;
|
rq->ix = c->ix;
|
||||||
rq->channel = c;
|
rq->channel = c;
|
||||||
|
|||||||
@ -742,7 +742,7 @@ static int mlx5e_init_rxq_rq(struct mlx5e_channel *c, struct mlx5e_params *param
|
|||||||
rq->netdev = c->netdev;
|
rq->netdev = c->netdev;
|
||||||
rq->priv = c->priv;
|
rq->priv = c->priv;
|
||||||
rq->tstamp = c->tstamp;
|
rq->tstamp = c->tstamp;
|
||||||
rq->clock = &mdev->clock;
|
rq->clock = mdev->clock;
|
||||||
rq->icosq = &c->icosq;
|
rq->icosq = &c->icosq;
|
||||||
rq->ix = c->ix;
|
rq->ix = c->ix;
|
||||||
rq->channel = c;
|
rq->channel = c;
|
||||||
@ -1621,7 +1621,7 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
sq->pdev = c->pdev;
|
sq->pdev = c->pdev;
|
||||||
sq->clock = &mdev->clock;
|
sq->clock = mdev->clock;
|
||||||
sq->mkey_be = c->mkey_be;
|
sq->mkey_be = c->mkey_be;
|
||||||
sq->netdev = c->netdev;
|
sq->netdev = c->netdev;
|
||||||
sq->mdev = c->mdev;
|
sq->mdev = c->mdev;
|
||||||
|
|||||||
@ -43,6 +43,8 @@
|
|||||||
#include <linux/cpufeature.h>
|
#include <linux/cpufeature.h>
|
||||||
#endif /* CONFIG_X86 */
|
#endif /* CONFIG_X86 */
|
||||||
|
|
||||||
|
#define MLX5_RT_CLOCK_IDENTITY_SIZE MLX5_FLD_SZ_BYTES(mrtcq_reg, rt_clock_identity)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MLX5_PIN_MODE_IN = 0x0,
|
MLX5_PIN_MODE_IN = 0x0,
|
||||||
MLX5_PIN_MODE_OUT = 0x1,
|
MLX5_PIN_MODE_OUT = 0x1,
|
||||||
@ -77,6 +79,56 @@ enum {
|
|||||||
MLX5_MTUTC_OPERATION_ADJUST_TIME_EXTENDED_MAX = 200000,
|
MLX5_MTUTC_OPERATION_ADJUST_TIME_EXTENDED_MAX = 200000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mlx5_clock_dev_state {
|
||||||
|
struct mlx5_core_dev *mdev;
|
||||||
|
struct mlx5_devcom_comp_dev *compdev;
|
||||||
|
struct mlx5_nb pps_nb;
|
||||||
|
struct work_struct out_work;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx5_clock_priv {
|
||||||
|
struct mlx5_clock clock;
|
||||||
|
struct mlx5_core_dev *mdev;
|
||||||
|
struct mutex lock; /* protect mdev and used in PTP callbacks */
|
||||||
|
struct mlx5_core_dev *event_mdev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mlx5_clock_priv *clock_priv(struct mlx5_clock *clock)
|
||||||
|
{
|
||||||
|
return container_of(clock, struct mlx5_clock_priv, clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx5_clock_lockdep_assert(struct mlx5_clock *clock)
|
||||||
|
{
|
||||||
|
if (!clock->shared)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lockdep_assert(lockdep_is_held(&clock_priv(clock)->lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mlx5_core_dev *mlx5_clock_mdev_get(struct mlx5_clock *clock)
|
||||||
|
{
|
||||||
|
mlx5_clock_lockdep_assert(clock);
|
||||||
|
|
||||||
|
return clock_priv(clock)->mdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx5_clock_lock(struct mlx5_clock *clock)
|
||||||
|
{
|
||||||
|
if (!clock->shared)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&clock_priv(clock)->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx5_clock_unlock(struct mlx5_clock *clock)
|
||||||
|
{
|
||||||
|
if (!clock->shared)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_unlock(&clock_priv(clock)->lock);
|
||||||
|
}
|
||||||
|
|
||||||
static bool mlx5_real_time_mode(struct mlx5_core_dev *mdev)
|
static bool mlx5_real_time_mode(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
return (mlx5_is_real_time_rq(mdev) || mlx5_is_real_time_sq(mdev));
|
return (mlx5_is_real_time_rq(mdev) || mlx5_is_real_time_sq(mdev));
|
||||||
@ -94,6 +146,22 @@ static bool mlx5_modify_mtutc_allowed(struct mlx5_core_dev *mdev)
|
|||||||
return MLX5_CAP_MCAM_FEATURE(mdev, ptpcyc2realtime_modify);
|
return MLX5_CAP_MCAM_FEATURE(mdev, ptpcyc2realtime_modify);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mlx5_clock_identity_get(struct mlx5_core_dev *mdev,
|
||||||
|
u8 identify[MLX5_RT_CLOCK_IDENTITY_SIZE])
|
||||||
|
{
|
||||||
|
u32 out[MLX5_ST_SZ_DW(mrtcq_reg)] = {};
|
||||||
|
u32 in[MLX5_ST_SZ_DW(mrtcq_reg)] = {};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = mlx5_core_access_reg(mdev, in, sizeof(in),
|
||||||
|
out, sizeof(out), MLX5_REG_MRTCQ, 0, 0);
|
||||||
|
if (!err)
|
||||||
|
memcpy(identify, MLX5_ADDR_OF(mrtcq_reg, out, rt_clock_identity),
|
||||||
|
MLX5_RT_CLOCK_IDENTITY_SIZE);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static u32 mlx5_ptp_shift_constant(u32 dev_freq_khz)
|
static u32 mlx5_ptp_shift_constant(u32 dev_freq_khz)
|
||||||
{
|
{
|
||||||
/* Optimal shift constant leads to corrections above just 1 scaled ppm.
|
/* Optimal shift constant leads to corrections above just 1 scaled ppm.
|
||||||
@ -119,21 +187,30 @@ static u32 mlx5_ptp_shift_constant(u32 dev_freq_khz)
|
|||||||
ilog2((U32_MAX / NSEC_PER_MSEC) * dev_freq_khz));
|
ilog2((U32_MAX / NSEC_PER_MSEC) * dev_freq_khz));
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 mlx5_ptp_getmaxphase(struct ptp_clock_info *ptp)
|
static s32 mlx5_clock_getmaxphase(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
|
||||||
struct mlx5_core_dev *mdev;
|
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
|
||||||
|
|
||||||
return MLX5_CAP_MCAM_FEATURE(mdev, mtutc_time_adjustment_extended_range) ?
|
return MLX5_CAP_MCAM_FEATURE(mdev, mtutc_time_adjustment_extended_range) ?
|
||||||
MLX5_MTUTC_OPERATION_ADJUST_TIME_EXTENDED_MAX :
|
MLX5_MTUTC_OPERATION_ADJUST_TIME_EXTENDED_MAX :
|
||||||
MLX5_MTUTC_OPERATION_ADJUST_TIME_MAX;
|
MLX5_MTUTC_OPERATION_ADJUST_TIME_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static s32 mlx5_ptp_getmaxphase(struct ptp_clock_info *ptp)
|
||||||
|
{
|
||||||
|
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
||||||
|
struct mlx5_core_dev *mdev;
|
||||||
|
s32 ret;
|
||||||
|
|
||||||
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
ret = mlx5_clock_getmaxphase(mdev);
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static bool mlx5_is_mtutc_time_adj_cap(struct mlx5_core_dev *mdev, s64 delta)
|
static bool mlx5_is_mtutc_time_adj_cap(struct mlx5_core_dev *mdev, s64 delta)
|
||||||
{
|
{
|
||||||
s64 max = mlx5_ptp_getmaxphase(&mdev->clock.ptp_info);
|
s64 max = mlx5_clock_getmaxphase(mdev);
|
||||||
|
|
||||||
if (delta < -max || delta > max)
|
if (delta < -max || delta > max)
|
||||||
return false;
|
return false;
|
||||||
@ -209,7 +286,7 @@ static int mlx5_mtctr_syncdevicetime(ktime_t *device_time,
|
|||||||
if (real_time_mode)
|
if (real_time_mode)
|
||||||
*device_time = ns_to_ktime(REAL_TIME_TO_NS(device >> 32, device & U32_MAX));
|
*device_time = ns_to_ktime(REAL_TIME_TO_NS(device >> 32, device & U32_MAX));
|
||||||
else
|
else
|
||||||
*device_time = mlx5_timecounter_cyc2time(&mdev->clock, device);
|
*device_time = mlx5_timecounter_cyc2time(mdev->clock, device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -220,16 +297,23 @@ static int mlx5_ptp_getcrosststamp(struct ptp_clock_info *ptp,
|
|||||||
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
||||||
struct system_time_snapshot history_begin = {0};
|
struct system_time_snapshot history_begin = {0};
|
||||||
struct mlx5_core_dev *mdev;
|
struct mlx5_core_dev *mdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
|
||||||
if (!mlx5_is_ptm_source_time_available(mdev))
|
if (!mlx5_is_ptm_source_time_available(mdev)) {
|
||||||
return -EBUSY;
|
err = -EBUSY;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
ktime_get_snapshot(&history_begin);
|
ktime_get_snapshot(&history_begin);
|
||||||
|
|
||||||
return get_device_system_crosststamp(mlx5_mtctr_syncdevicetime, mdev,
|
err = get_device_system_crosststamp(mlx5_mtctr_syncdevicetime, mdev,
|
||||||
&history_begin, cts);
|
&history_begin, cts);
|
||||||
|
unlock:
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_X86 */
|
#endif /* CONFIG_X86 */
|
||||||
|
|
||||||
@ -263,8 +347,7 @@ static u64 read_internal_timer(const struct cyclecounter *cc)
|
|||||||
{
|
{
|
||||||
struct mlx5_timer *timer = container_of(cc, struct mlx5_timer, cycles);
|
struct mlx5_timer *timer = container_of(cc, struct mlx5_timer, cycles);
|
||||||
struct mlx5_clock *clock = container_of(timer, struct mlx5_clock, timer);
|
struct mlx5_clock *clock = container_of(timer, struct mlx5_clock, timer);
|
||||||
struct mlx5_core_dev *mdev = container_of(clock, struct mlx5_core_dev,
|
struct mlx5_core_dev *mdev = mlx5_clock_mdev_get(clock);
|
||||||
clock);
|
|
||||||
|
|
||||||
return mlx5_read_time(mdev, NULL, false) & cc->mask;
|
return mlx5_read_time(mdev, NULL, false) & cc->mask;
|
||||||
}
|
}
|
||||||
@ -272,7 +355,7 @@ static u64 read_internal_timer(const struct cyclecounter *cc)
|
|||||||
static void mlx5_update_clock_info_page(struct mlx5_core_dev *mdev)
|
static void mlx5_update_clock_info_page(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_ib_clock_info *clock_info = mdev->clock_info;
|
struct mlx5_ib_clock_info *clock_info = mdev->clock_info;
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
struct mlx5_timer *timer;
|
struct mlx5_timer *timer;
|
||||||
u32 sign;
|
u32 sign;
|
||||||
|
|
||||||
@ -295,12 +378,10 @@ static void mlx5_update_clock_info_page(struct mlx5_core_dev *mdev)
|
|||||||
|
|
||||||
static void mlx5_pps_out(struct work_struct *work)
|
static void mlx5_pps_out(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct mlx5_pps *pps_info = container_of(work, struct mlx5_pps,
|
struct mlx5_clock_dev_state *clock_state = container_of(work, struct mlx5_clock_dev_state,
|
||||||
out_work);
|
out_work);
|
||||||
struct mlx5_clock *clock = container_of(pps_info, struct mlx5_clock,
|
struct mlx5_core_dev *mdev = clock_state->mdev;
|
||||||
pps_info);
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
struct mlx5_core_dev *mdev = container_of(clock, struct mlx5_core_dev,
|
|
||||||
clock);
|
|
||||||
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
@ -322,17 +403,17 @@ static void mlx5_pps_out(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlx5_timestamp_overflow(struct work_struct *work)
|
static long mlx5_timestamp_overflow(struct ptp_clock_info *ptp_info)
|
||||||
{
|
{
|
||||||
struct delayed_work *dwork = to_delayed_work(work);
|
|
||||||
struct mlx5_core_dev *mdev;
|
struct mlx5_core_dev *mdev;
|
||||||
struct mlx5_timer *timer;
|
struct mlx5_timer *timer;
|
||||||
struct mlx5_clock *clock;
|
struct mlx5_clock *clock;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
timer = container_of(dwork, struct mlx5_timer, overflow_work);
|
clock = container_of(ptp_info, struct mlx5_clock, ptp_info);
|
||||||
clock = container_of(timer, struct mlx5_clock, timer);
|
mlx5_clock_lock(clock);
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
timer = &clock->timer;
|
||||||
|
|
||||||
if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
|
if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
|
||||||
goto out;
|
goto out;
|
||||||
@ -343,7 +424,8 @@ static void mlx5_timestamp_overflow(struct work_struct *work)
|
|||||||
write_sequnlock_irqrestore(&clock->lock, flags);
|
write_sequnlock_irqrestore(&clock->lock, flags);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
schedule_delayed_work(&timer->overflow_work, timer->overflow_period);
|
mlx5_clock_unlock(clock);
|
||||||
|
return timer->overflow_period;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx5_ptp_settime_real_time(struct mlx5_core_dev *mdev,
|
static int mlx5_ptp_settime_real_time(struct mlx5_core_dev *mdev,
|
||||||
@ -362,15 +444,12 @@ static int mlx5_ptp_settime_real_time(struct mlx5_core_dev *mdev,
|
|||||||
return mlx5_set_mtutc(mdev, in, sizeof(in));
|
return mlx5_set_mtutc(mdev, in, sizeof(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx5_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts)
|
static int mlx5_clock_settime(struct mlx5_core_dev *mdev, struct mlx5_clock *clock,
|
||||||
|
const struct timespec64 *ts)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
|
||||||
struct mlx5_timer *timer = &clock->timer;
|
struct mlx5_timer *timer = &clock->timer;
|
||||||
struct mlx5_core_dev *mdev;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
|
||||||
|
|
||||||
if (mlx5_modify_mtutc_allowed(mdev)) {
|
if (mlx5_modify_mtutc_allowed(mdev)) {
|
||||||
int err = mlx5_ptp_settime_real_time(mdev, ts);
|
int err = mlx5_ptp_settime_real_time(mdev, ts);
|
||||||
|
|
||||||
@ -386,6 +465,20 @@ static int mlx5_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mlx5_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts)
|
||||||
|
{
|
||||||
|
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
||||||
|
struct mlx5_core_dev *mdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
err = mlx5_clock_settime(mdev, clock, ts);
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
struct timespec64 mlx5_ptp_gettimex_real_time(struct mlx5_core_dev *mdev,
|
struct timespec64 mlx5_ptp_gettimex_real_time(struct mlx5_core_dev *mdev,
|
||||||
struct ptp_system_timestamp *sts)
|
struct ptp_system_timestamp *sts)
|
||||||
@ -402,23 +495,21 @@ static int mlx5_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts,
|
|||||||
struct ptp_system_timestamp *sts)
|
struct ptp_system_timestamp *sts)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
||||||
struct mlx5_timer *timer = &clock->timer;
|
|
||||||
struct mlx5_core_dev *mdev;
|
struct mlx5_core_dev *mdev;
|
||||||
unsigned long flags;
|
|
||||||
u64 cycles, ns;
|
u64 cycles, ns;
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
if (mlx5_real_time_mode(mdev)) {
|
if (mlx5_real_time_mode(mdev)) {
|
||||||
*ts = mlx5_ptp_gettimex_real_time(mdev, sts);
|
*ts = mlx5_ptp_gettimex_real_time(mdev, sts);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_seqlock_irqsave(&clock->lock, flags);
|
|
||||||
cycles = mlx5_read_time(mdev, sts, false);
|
cycles = mlx5_read_time(mdev, sts, false);
|
||||||
ns = timecounter_cyc2time(&timer->tc, cycles);
|
ns = mlx5_timecounter_cyc2time(clock, cycles);
|
||||||
write_sequnlock_irqrestore(&clock->lock, flags);
|
|
||||||
*ts = ns_to_timespec64(ns);
|
*ts = ns_to_timespec64(ns);
|
||||||
out:
|
out:
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,14 +540,16 @@ static int mlx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|||||||
struct mlx5_timer *timer = &clock->timer;
|
struct mlx5_timer *timer = &clock->timer;
|
||||||
struct mlx5_core_dev *mdev;
|
struct mlx5_core_dev *mdev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
|
||||||
if (mlx5_modify_mtutc_allowed(mdev)) {
|
if (mlx5_modify_mtutc_allowed(mdev)) {
|
||||||
int err = mlx5_ptp_adjtime_real_time(mdev, delta);
|
err = mlx5_ptp_adjtime_real_time(mdev, delta);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_seqlock_irqsave(&clock->lock, flags);
|
write_seqlock_irqsave(&clock->lock, flags);
|
||||||
@ -464,17 +557,23 @@ static int mlx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|||||||
mlx5_update_clock_info_page(mdev);
|
mlx5_update_clock_info_page(mdev);
|
||||||
write_sequnlock_irqrestore(&clock->lock, flags);
|
write_sequnlock_irqrestore(&clock->lock, flags);
|
||||||
|
|
||||||
return 0;
|
unlock:
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx5_ptp_adjphase(struct ptp_clock_info *ptp, s32 delta)
|
static int mlx5_ptp_adjphase(struct ptp_clock_info *ptp, s32 delta)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
|
||||||
struct mlx5_core_dev *mdev;
|
struct mlx5_core_dev *mdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
err = mlx5_ptp_adjtime_real_time(mdev, delta);
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
|
||||||
return mlx5_ptp_adjtime_real_time(mdev, delta);
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx5_ptp_freq_adj_real_time(struct mlx5_core_dev *mdev, long scaled_ppm)
|
static int mlx5_ptp_freq_adj_real_time(struct mlx5_core_dev *mdev, long scaled_ppm)
|
||||||
@ -503,15 +602,17 @@ static int mlx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|||||||
struct mlx5_timer *timer = &clock->timer;
|
struct mlx5_timer *timer = &clock->timer;
|
||||||
struct mlx5_core_dev *mdev;
|
struct mlx5_core_dev *mdev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int err = 0;
|
||||||
u32 mult;
|
u32 mult;
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
|
||||||
if (mlx5_modify_mtutc_allowed(mdev)) {
|
if (mlx5_modify_mtutc_allowed(mdev)) {
|
||||||
int err = mlx5_ptp_freq_adj_real_time(mdev, scaled_ppm);
|
err = mlx5_ptp_freq_adj_real_time(mdev, scaled_ppm);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
mult = (u32)adjust_by_scaled_ppm(timer->nominal_c_mult, scaled_ppm);
|
mult = (u32)adjust_by_scaled_ppm(timer->nominal_c_mult, scaled_ppm);
|
||||||
@ -521,8 +622,11 @@ static int mlx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|||||||
timer->cycles.mult = mult;
|
timer->cycles.mult = mult;
|
||||||
mlx5_update_clock_info_page(mdev);
|
mlx5_update_clock_info_page(mdev);
|
||||||
write_sequnlock_irqrestore(&clock->lock, flags);
|
write_sequnlock_irqrestore(&clock->lock, flags);
|
||||||
|
ptp_schedule_worker(clock->ptp, timer->overflow_period);
|
||||||
|
|
||||||
return 0;
|
unlock:
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx5_extts_configure(struct ptp_clock_info *ptp,
|
static int mlx5_extts_configure(struct ptp_clock_info *ptp,
|
||||||
@ -531,18 +635,14 @@ static int mlx5_extts_configure(struct ptp_clock_info *ptp,
|
|||||||
{
|
{
|
||||||
struct mlx5_clock *clock =
|
struct mlx5_clock *clock =
|
||||||
container_of(ptp, struct mlx5_clock, ptp_info);
|
container_of(ptp, struct mlx5_clock, ptp_info);
|
||||||
struct mlx5_core_dev *mdev =
|
|
||||||
container_of(clock, struct mlx5_core_dev, clock);
|
|
||||||
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
||||||
|
struct mlx5_core_dev *mdev;
|
||||||
u32 field_select = 0;
|
u32 field_select = 0;
|
||||||
u8 pin_mode = 0;
|
u8 pin_mode = 0;
|
||||||
u8 pattern = 0;
|
u8 pattern = 0;
|
||||||
int pin = -1;
|
int pin = -1;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (!MLX5_PPS_CAP(mdev))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
/* Reject requests with unsupported flags */
|
/* Reject requests with unsupported flags */
|
||||||
if (rq->extts.flags & ~(PTP_ENABLE_FEATURE |
|
if (rq->extts.flags & ~(PTP_ENABLE_FEATURE |
|
||||||
PTP_RISING_EDGE |
|
PTP_RISING_EDGE |
|
||||||
@ -573,6 +673,14 @@ static int mlx5_extts_configure(struct ptp_clock_info *ptp,
|
|||||||
field_select = MLX5_MTPPS_FS_ENABLE;
|
field_select = MLX5_MTPPS_FS_ENABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mlx5_clock_lock(clock);
|
||||||
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
|
||||||
|
if (!MLX5_PPS_CAP(mdev)) {
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
MLX5_SET(mtpps_reg, in, pin, pin);
|
MLX5_SET(mtpps_reg, in, pin, pin);
|
||||||
MLX5_SET(mtpps_reg, in, pin_mode, pin_mode);
|
MLX5_SET(mtpps_reg, in, pin_mode, pin_mode);
|
||||||
MLX5_SET(mtpps_reg, in, pattern, pattern);
|
MLX5_SET(mtpps_reg, in, pattern, pattern);
|
||||||
@ -581,15 +689,23 @@ static int mlx5_extts_configure(struct ptp_clock_info *ptp,
|
|||||||
|
|
||||||
err = mlx5_set_mtpps(mdev, in, sizeof(in));
|
err = mlx5_set_mtpps(mdev, in, sizeof(in));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto unlock;
|
||||||
|
|
||||||
return mlx5_set_mtppse(mdev, pin, 0,
|
err = mlx5_set_mtppse(mdev, pin, 0, MLX5_EVENT_MODE_REPETETIVE & on);
|
||||||
MLX5_EVENT_MODE_REPETETIVE & on);
|
if (err)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
clock->pps_info.pin_armed[pin] = on;
|
||||||
|
clock_priv(clock)->event_mdev = mdev;
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 find_target_cycles(struct mlx5_core_dev *mdev, s64 target_ns)
|
static u64 find_target_cycles(struct mlx5_core_dev *mdev, s64 target_ns)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
u64 cycles_now, cycles_delta;
|
u64 cycles_now, cycles_delta;
|
||||||
u64 nsec_now, nsec_delta;
|
u64 nsec_now, nsec_delta;
|
||||||
struct mlx5_timer *timer;
|
struct mlx5_timer *timer;
|
||||||
@ -648,7 +764,7 @@ static int mlx5_perout_conf_out_pulse_duration(struct mlx5_core_dev *mdev,
|
|||||||
struct ptp_clock_request *rq,
|
struct ptp_clock_request *rq,
|
||||||
u32 *out_pulse_duration_ns)
|
u32 *out_pulse_duration_ns)
|
||||||
{
|
{
|
||||||
struct mlx5_pps *pps_info = &mdev->clock.pps_info;
|
struct mlx5_pps *pps_info = &mdev->clock->pps_info;
|
||||||
u32 out_pulse_duration;
|
u32 out_pulse_duration;
|
||||||
struct timespec64 ts;
|
struct timespec64 ts;
|
||||||
|
|
||||||
@ -681,7 +797,7 @@ static int perout_conf_npps_real_time(struct mlx5_core_dev *mdev, struct ptp_clo
|
|||||||
u32 *field_select, u32 *out_pulse_duration_ns,
|
u32 *field_select, u32 *out_pulse_duration_ns,
|
||||||
u64 *period, u64 *time_stamp)
|
u64 *period, u64 *time_stamp)
|
||||||
{
|
{
|
||||||
struct mlx5_pps *pps_info = &mdev->clock.pps_info;
|
struct mlx5_pps *pps_info = &mdev->clock->pps_info;
|
||||||
struct ptp_clock_time *time = &rq->perout.start;
|
struct ptp_clock_time *time = &rq->perout.start;
|
||||||
struct timespec64 ts;
|
struct timespec64 ts;
|
||||||
|
|
||||||
@ -716,26 +832,18 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
|
|||||||
{
|
{
|
||||||
struct mlx5_clock *clock =
|
struct mlx5_clock *clock =
|
||||||
container_of(ptp, struct mlx5_clock, ptp_info);
|
container_of(ptp, struct mlx5_clock, ptp_info);
|
||||||
struct mlx5_core_dev *mdev =
|
|
||||||
container_of(clock, struct mlx5_core_dev, clock);
|
|
||||||
bool rt_mode = mlx5_real_time_mode(mdev);
|
|
||||||
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
||||||
u32 out_pulse_duration_ns = 0;
|
u32 out_pulse_duration_ns = 0;
|
||||||
|
struct mlx5_core_dev *mdev;
|
||||||
u32 field_select = 0;
|
u32 field_select = 0;
|
||||||
u64 npps_period = 0;
|
u64 npps_period = 0;
|
||||||
u64 time_stamp = 0;
|
u64 time_stamp = 0;
|
||||||
u8 pin_mode = 0;
|
u8 pin_mode = 0;
|
||||||
u8 pattern = 0;
|
u8 pattern = 0;
|
||||||
|
bool rt_mode;
|
||||||
int pin = -1;
|
int pin = -1;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (!MLX5_PPS_CAP(mdev))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
/* Reject requests with unsupported flags */
|
|
||||||
if (mlx5_perout_verify_flags(mdev, rq->perout.flags))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
if (rq->perout.index >= clock->ptp_info.n_pins)
|
if (rq->perout.index >= clock->ptp_info.n_pins)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -744,14 +852,29 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
|
|||||||
if (pin < 0)
|
if (pin < 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
if (on) {
|
mlx5_clock_lock(clock);
|
||||||
bool rt_mode = mlx5_real_time_mode(mdev);
|
mdev = mlx5_clock_mdev_get(clock);
|
||||||
|
rt_mode = mlx5_real_time_mode(mdev);
|
||||||
|
|
||||||
|
if (!MLX5_PPS_CAP(mdev)) {
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reject requests with unsupported flags */
|
||||||
|
if (mlx5_perout_verify_flags(mdev, rq->perout.flags)) {
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on) {
|
||||||
pin_mode = MLX5_PIN_MODE_OUT;
|
pin_mode = MLX5_PIN_MODE_OUT;
|
||||||
pattern = MLX5_OUT_PATTERN_PERIODIC;
|
pattern = MLX5_OUT_PATTERN_PERIODIC;
|
||||||
|
|
||||||
if (rt_mode && rq->perout.start.sec > U32_MAX)
|
if (rt_mode && rq->perout.start.sec > U32_MAX) {
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
field_select |= MLX5_MTPPS_FS_PIN_MODE |
|
field_select |= MLX5_MTPPS_FS_PIN_MODE |
|
||||||
MLX5_MTPPS_FS_PATTERN |
|
MLX5_MTPPS_FS_PATTERN |
|
||||||
@ -764,7 +887,7 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
|
|||||||
else
|
else
|
||||||
err = perout_conf_1pps(mdev, rq, &time_stamp, rt_mode);
|
err = perout_conf_1pps(mdev, rq, &time_stamp, rt_mode);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
MLX5_SET(mtpps_reg, in, pin, pin);
|
MLX5_SET(mtpps_reg, in, pin, pin);
|
||||||
@ -777,13 +900,16 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
|
|||||||
MLX5_SET(mtpps_reg, in, out_pulse_duration_ns, out_pulse_duration_ns);
|
MLX5_SET(mtpps_reg, in, out_pulse_duration_ns, out_pulse_duration_ns);
|
||||||
err = mlx5_set_mtpps(mdev, in, sizeof(in));
|
err = mlx5_set_mtpps(mdev, in, sizeof(in));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto unlock;
|
||||||
|
|
||||||
if (rt_mode)
|
if (rt_mode)
|
||||||
return 0;
|
goto unlock;
|
||||||
|
|
||||||
return mlx5_set_mtppse(mdev, pin, 0,
|
err = mlx5_set_mtppse(mdev, pin, 0, MLX5_EVENT_MODE_REPETETIVE & on);
|
||||||
MLX5_EVENT_MODE_REPETETIVE & on);
|
|
||||||
|
unlock:
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx5_pps_configure(struct ptp_clock_info *ptp,
|
static int mlx5_pps_configure(struct ptp_clock_info *ptp,
|
||||||
@ -856,6 +982,7 @@ static const struct ptp_clock_info mlx5_ptp_clock_info = {
|
|||||||
.settime64 = mlx5_ptp_settime,
|
.settime64 = mlx5_ptp_settime,
|
||||||
.enable = NULL,
|
.enable = NULL,
|
||||||
.verify = NULL,
|
.verify = NULL,
|
||||||
|
.do_aux_work = mlx5_timestamp_overflow,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mlx5_query_mtpps_pin_mode(struct mlx5_core_dev *mdev, u8 pin,
|
static int mlx5_query_mtpps_pin_mode(struct mlx5_core_dev *mdev, u8 pin,
|
||||||
@ -869,10 +996,8 @@ static int mlx5_query_mtpps_pin_mode(struct mlx5_core_dev *mdev, u8 pin,
|
|||||||
mtpps_size, MLX5_REG_MTPPS, 0, 0);
|
mtpps_size, MLX5_REG_MTPPS, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx5_get_pps_pin_mode(struct mlx5_clock *clock, u8 pin)
|
static int mlx5_get_pps_pin_mode(struct mlx5_core_dev *mdev, u8 pin)
|
||||||
{
|
{
|
||||||
struct mlx5_core_dev *mdev = container_of(clock, struct mlx5_core_dev, clock);
|
|
||||||
|
|
||||||
u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {};
|
u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {};
|
||||||
u8 mode;
|
u8 mode;
|
||||||
int err;
|
int err;
|
||||||
@ -891,8 +1016,9 @@ static int mlx5_get_pps_pin_mode(struct mlx5_clock *clock, u8 pin)
|
|||||||
return PTP_PF_NONE;
|
return PTP_PF_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlx5_init_pin_config(struct mlx5_clock *clock)
|
static void mlx5_init_pin_config(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!clock->ptp_info.n_pins)
|
if (!clock->ptp_info.n_pins)
|
||||||
@ -913,15 +1039,15 @@ static void mlx5_init_pin_config(struct mlx5_clock *clock)
|
|||||||
sizeof(clock->ptp_info.pin_config[i].name),
|
sizeof(clock->ptp_info.pin_config[i].name),
|
||||||
"mlx5_pps%d", i);
|
"mlx5_pps%d", i);
|
||||||
clock->ptp_info.pin_config[i].index = i;
|
clock->ptp_info.pin_config[i].index = i;
|
||||||
clock->ptp_info.pin_config[i].func = mlx5_get_pps_pin_mode(clock, i);
|
clock->ptp_info.pin_config[i].func = mlx5_get_pps_pin_mode(mdev, i);
|
||||||
clock->ptp_info.pin_config[i].chan = 0;
|
clock->ptp_info.pin_config[i].chan = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlx5_get_pps_caps(struct mlx5_core_dev *mdev)
|
static void mlx5_get_pps_caps(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
|
||||||
u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
|
||||||
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
|
|
||||||
mlx5_query_mtpps(mdev, out, sizeof(out));
|
mlx5_query_mtpps(mdev, out, sizeof(out));
|
||||||
|
|
||||||
@ -971,16 +1097,16 @@ static u64 perout_conf_next_event_timer(struct mlx5_core_dev *mdev,
|
|||||||
static int mlx5_pps_event(struct notifier_block *nb,
|
static int mlx5_pps_event(struct notifier_block *nb,
|
||||||
unsigned long type, void *data)
|
unsigned long type, void *data)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = mlx5_nb_cof(nb, struct mlx5_clock, pps_nb);
|
struct mlx5_clock_dev_state *clock_state = mlx5_nb_cof(nb, struct mlx5_clock_dev_state,
|
||||||
|
pps_nb);
|
||||||
|
struct mlx5_core_dev *mdev = clock_state->mdev;
|
||||||
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
struct ptp_clock_event ptp_event;
|
struct ptp_clock_event ptp_event;
|
||||||
struct mlx5_eqe *eqe = data;
|
struct mlx5_eqe *eqe = data;
|
||||||
int pin = eqe->data.pps.pin;
|
int pin = eqe->data.pps.pin;
|
||||||
struct mlx5_core_dev *mdev;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u64 ns;
|
u64 ns;
|
||||||
|
|
||||||
mdev = container_of(clock, struct mlx5_core_dev, clock);
|
|
||||||
|
|
||||||
switch (clock->ptp_info.pin_config[pin].func) {
|
switch (clock->ptp_info.pin_config[pin].func) {
|
||||||
case PTP_PF_EXTTS:
|
case PTP_PF_EXTTS:
|
||||||
ptp_event.index = pin;
|
ptp_event.index = pin;
|
||||||
@ -1000,11 +1126,15 @@ static int mlx5_pps_event(struct notifier_block *nb,
|
|||||||
ptp_clock_event(clock->ptp, &ptp_event);
|
ptp_clock_event(clock->ptp, &ptp_event);
|
||||||
break;
|
break;
|
||||||
case PTP_PF_PEROUT:
|
case PTP_PF_PEROUT:
|
||||||
|
if (clock->shared) {
|
||||||
|
mlx5_core_warn(mdev, " Received unexpected PPS out event\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
ns = perout_conf_next_event_timer(mdev, clock);
|
ns = perout_conf_next_event_timer(mdev, clock);
|
||||||
write_seqlock_irqsave(&clock->lock, flags);
|
write_seqlock_irqsave(&clock->lock, flags);
|
||||||
clock->pps_info.start[pin] = ns;
|
clock->pps_info.start[pin] = ns;
|
||||||
write_sequnlock_irqrestore(&clock->lock, flags);
|
write_sequnlock_irqrestore(&clock->lock, flags);
|
||||||
schedule_work(&clock->pps_info.out_work);
|
schedule_work(&clock_state->out_work);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mlx5_core_err(mdev, " Unhandled clock PPS event, func %d\n",
|
mlx5_core_err(mdev, " Unhandled clock PPS event, func %d\n",
|
||||||
@ -1016,7 +1146,7 @@ static int mlx5_pps_event(struct notifier_block *nb,
|
|||||||
|
|
||||||
static void mlx5_timecounter_init(struct mlx5_core_dev *mdev)
|
static void mlx5_timecounter_init(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
struct mlx5_timer *timer = &clock->timer;
|
struct mlx5_timer *timer = &clock->timer;
|
||||||
u32 dev_freq;
|
u32 dev_freq;
|
||||||
|
|
||||||
@ -1032,10 +1162,10 @@ static void mlx5_timecounter_init(struct mlx5_core_dev *mdev)
|
|||||||
ktime_to_ns(ktime_get_real()));
|
ktime_to_ns(ktime_get_real()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlx5_init_overflow_period(struct mlx5_clock *clock)
|
static void mlx5_init_overflow_period(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_core_dev *mdev = container_of(clock, struct mlx5_core_dev, clock);
|
|
||||||
struct mlx5_ib_clock_info *clock_info = mdev->clock_info;
|
struct mlx5_ib_clock_info *clock_info = mdev->clock_info;
|
||||||
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
struct mlx5_timer *timer = &clock->timer;
|
struct mlx5_timer *timer = &clock->timer;
|
||||||
u64 overflow_cycles;
|
u64 overflow_cycles;
|
||||||
u64 frac = 0;
|
u64 frac = 0;
|
||||||
@ -1056,12 +1186,11 @@ static void mlx5_init_overflow_period(struct mlx5_clock *clock)
|
|||||||
do_div(ns, NSEC_PER_SEC / HZ);
|
do_div(ns, NSEC_PER_SEC / HZ);
|
||||||
timer->overflow_period = ns;
|
timer->overflow_period = ns;
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&timer->overflow_work, mlx5_timestamp_overflow);
|
if (!timer->overflow_period) {
|
||||||
if (timer->overflow_period)
|
timer->overflow_period = HZ;
|
||||||
schedule_delayed_work(&timer->overflow_work, 0);
|
|
||||||
else
|
|
||||||
mlx5_core_warn(mdev,
|
mlx5_core_warn(mdev,
|
||||||
"invalid overflow period, overflow_work is not scheduled\n");
|
"invalid overflow period, overflow_work is scheduled once per second\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (clock_info)
|
if (clock_info)
|
||||||
clock_info->overflow_period = timer->overflow_period;
|
clock_info->overflow_period = timer->overflow_period;
|
||||||
@ -1069,7 +1198,7 @@ static void mlx5_init_overflow_period(struct mlx5_clock *clock)
|
|||||||
|
|
||||||
static void mlx5_init_clock_info(struct mlx5_core_dev *mdev)
|
static void mlx5_init_clock_info(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
struct mlx5_ib_clock_info *info;
|
struct mlx5_ib_clock_info *info;
|
||||||
struct mlx5_timer *timer;
|
struct mlx5_timer *timer;
|
||||||
|
|
||||||
@ -1092,7 +1221,7 @@ static void mlx5_init_clock_info(struct mlx5_core_dev *mdev)
|
|||||||
|
|
||||||
static void mlx5_init_timer_max_freq_adjustment(struct mlx5_core_dev *mdev)
|
static void mlx5_init_timer_max_freq_adjustment(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
u32 out[MLX5_ST_SZ_DW(mtutc_reg)] = {};
|
u32 out[MLX5_ST_SZ_DW(mtutc_reg)] = {};
|
||||||
u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {};
|
u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {};
|
||||||
u8 log_max_freq_adjustment = 0;
|
u8 log_max_freq_adjustment = 0;
|
||||||
@ -1111,7 +1240,7 @@ static void mlx5_init_timer_max_freq_adjustment(struct mlx5_core_dev *mdev)
|
|||||||
|
|
||||||
static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev)
|
static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
|
|
||||||
/* Configure the PHC */
|
/* Configure the PHC */
|
||||||
clock->ptp_info = mlx5_ptp_clock_info;
|
clock->ptp_info = mlx5_ptp_clock_info;
|
||||||
@ -1127,38 +1256,30 @@ static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev)
|
|||||||
|
|
||||||
mlx5_timecounter_init(mdev);
|
mlx5_timecounter_init(mdev);
|
||||||
mlx5_init_clock_info(mdev);
|
mlx5_init_clock_info(mdev);
|
||||||
mlx5_init_overflow_period(clock);
|
mlx5_init_overflow_period(mdev);
|
||||||
|
|
||||||
if (mlx5_real_time_mode(mdev)) {
|
if (mlx5_real_time_mode(mdev)) {
|
||||||
struct timespec64 ts;
|
struct timespec64 ts;
|
||||||
|
|
||||||
ktime_get_real_ts64(&ts);
|
ktime_get_real_ts64(&ts);
|
||||||
mlx5_ptp_settime(&clock->ptp_info, &ts);
|
mlx5_clock_settime(mdev, clock, &ts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlx5_init_pps(struct mlx5_core_dev *mdev)
|
static void mlx5_init_pps(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
|
||||||
|
|
||||||
if (!MLX5_PPS_CAP(mdev))
|
if (!MLX5_PPS_CAP(mdev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mlx5_get_pps_caps(mdev);
|
mlx5_get_pps_caps(mdev);
|
||||||
mlx5_init_pin_config(clock);
|
mlx5_init_pin_config(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mlx5_init_clock(struct mlx5_core_dev *mdev)
|
static void mlx5_init_clock_dev(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
|
|
||||||
if (!MLX5_CAP_GEN(mdev, device_frequency_khz)) {
|
|
||||||
mlx5_core_warn(mdev, "invalid device_frequency_khz, aborting HW clock init\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
seqlock_init(&clock->lock);
|
seqlock_init(&clock->lock);
|
||||||
INIT_WORK(&clock->pps_info.out_work, mlx5_pps_out);
|
|
||||||
|
|
||||||
/* Initialize the device clock */
|
/* Initialize the device clock */
|
||||||
mlx5_init_timer_clock(mdev);
|
mlx5_init_timer_clock(mdev);
|
||||||
@ -1167,33 +1288,27 @@ void mlx5_init_clock(struct mlx5_core_dev *mdev)
|
|||||||
mlx5_init_pps(mdev);
|
mlx5_init_pps(mdev);
|
||||||
|
|
||||||
clock->ptp = ptp_clock_register(&clock->ptp_info,
|
clock->ptp = ptp_clock_register(&clock->ptp_info,
|
||||||
&mdev->pdev->dev);
|
clock->shared ? NULL : &mdev->pdev->dev);
|
||||||
if (IS_ERR(clock->ptp)) {
|
if (IS_ERR(clock->ptp)) {
|
||||||
mlx5_core_warn(mdev, "ptp_clock_register failed %ld\n",
|
mlx5_core_warn(mdev, "%sptp_clock_register failed %ld\n",
|
||||||
|
clock->shared ? "shared clock " : "",
|
||||||
PTR_ERR(clock->ptp));
|
PTR_ERR(clock->ptp));
|
||||||
clock->ptp = NULL;
|
clock->ptp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MLX5_NB_INIT(&clock->pps_nb, mlx5_pps_event, PPS_EVENT);
|
if (clock->ptp)
|
||||||
mlx5_eq_notifier_register(mdev, &clock->pps_nb);
|
ptp_schedule_worker(clock->ptp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mlx5_cleanup_clock(struct mlx5_core_dev *mdev)
|
static void mlx5_destroy_clock_dev(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
struct mlx5_clock *clock = &mdev->clock;
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
|
|
||||||
if (!MLX5_CAP_GEN(mdev, device_frequency_khz))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mlx5_eq_notifier_unregister(mdev, &clock->pps_nb);
|
|
||||||
if (clock->ptp) {
|
if (clock->ptp) {
|
||||||
ptp_clock_unregister(clock->ptp);
|
ptp_clock_unregister(clock->ptp);
|
||||||
clock->ptp = NULL;
|
clock->ptp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel_work_sync(&clock->pps_info.out_work);
|
|
||||||
cancel_delayed_work_sync(&clock->timer.overflow_work);
|
|
||||||
|
|
||||||
if (mdev->clock_info) {
|
if (mdev->clock_info) {
|
||||||
free_page((unsigned long)mdev->clock_info);
|
free_page((unsigned long)mdev->clock_info);
|
||||||
mdev->clock_info = NULL;
|
mdev->clock_info = NULL;
|
||||||
@ -1201,3 +1316,248 @@ void mlx5_cleanup_clock(struct mlx5_core_dev *mdev)
|
|||||||
|
|
||||||
kfree(clock->ptp_info.pin_config);
|
kfree(clock->ptp_info.pin_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mlx5_clock_free(struct mlx5_core_dev *mdev)
|
||||||
|
{
|
||||||
|
struct mlx5_clock_priv *cpriv = clock_priv(mdev->clock);
|
||||||
|
|
||||||
|
mlx5_destroy_clock_dev(mdev);
|
||||||
|
mutex_destroy(&cpriv->lock);
|
||||||
|
kfree(cpriv);
|
||||||
|
mdev->clock = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlx5_clock_alloc(struct mlx5_core_dev *mdev, bool shared)
|
||||||
|
{
|
||||||
|
struct mlx5_clock_priv *cpriv;
|
||||||
|
struct mlx5_clock *clock;
|
||||||
|
|
||||||
|
cpriv = kzalloc(sizeof(*cpriv), GFP_KERNEL);
|
||||||
|
if (!cpriv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mutex_init(&cpriv->lock);
|
||||||
|
cpriv->mdev = mdev;
|
||||||
|
clock = &cpriv->clock;
|
||||||
|
clock->shared = shared;
|
||||||
|
mdev->clock = clock;
|
||||||
|
mlx5_clock_lock(clock);
|
||||||
|
mlx5_init_clock_dev(mdev);
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
|
||||||
|
if (!clock->shared)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!clock->ptp) {
|
||||||
|
mlx5_core_warn(mdev, "failed to create ptp dev shared by multiple functions");
|
||||||
|
mlx5_clock_free(mdev);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx5_shared_clock_register(struct mlx5_core_dev *mdev, u64 key)
|
||||||
|
{
|
||||||
|
struct mlx5_core_dev *peer_dev, *next = NULL;
|
||||||
|
struct mlx5_devcom_comp_dev *pos;
|
||||||
|
|
||||||
|
mdev->clock_state->compdev = mlx5_devcom_register_component(mdev->priv.devc,
|
||||||
|
MLX5_DEVCOM_SHARED_CLOCK,
|
||||||
|
key, NULL, mdev);
|
||||||
|
if (IS_ERR(mdev->clock_state->compdev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mlx5_devcom_comp_lock(mdev->clock_state->compdev);
|
||||||
|
mlx5_devcom_for_each_peer_entry(mdev->clock_state->compdev, peer_dev, pos) {
|
||||||
|
if (peer_dev->clock) {
|
||||||
|
next = peer_dev;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
mdev->clock = next->clock;
|
||||||
|
/* clock info is shared among all the functions using the same clock */
|
||||||
|
mdev->clock_info = next->clock_info;
|
||||||
|
} else {
|
||||||
|
mlx5_clock_alloc(mdev, true);
|
||||||
|
}
|
||||||
|
mlx5_devcom_comp_unlock(mdev->clock_state->compdev);
|
||||||
|
|
||||||
|
if (!mdev->clock) {
|
||||||
|
mlx5_devcom_unregister_component(mdev->clock_state->compdev);
|
||||||
|
mdev->clock_state->compdev = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx5_shared_clock_unregister(struct mlx5_core_dev *mdev)
|
||||||
|
{
|
||||||
|
struct mlx5_core_dev *peer_dev, *next = NULL;
|
||||||
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
|
struct mlx5_devcom_comp_dev *pos;
|
||||||
|
|
||||||
|
mlx5_devcom_comp_lock(mdev->clock_state->compdev);
|
||||||
|
mlx5_devcom_for_each_peer_entry(mdev->clock_state->compdev, peer_dev, pos) {
|
||||||
|
if (peer_dev->clock && peer_dev != mdev) {
|
||||||
|
next = peer_dev;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
struct mlx5_clock_priv *cpriv = clock_priv(clock);
|
||||||
|
|
||||||
|
mlx5_clock_lock(clock);
|
||||||
|
if (mdev == cpriv->mdev)
|
||||||
|
cpriv->mdev = next;
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
} else {
|
||||||
|
mlx5_clock_free(mdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
mdev->clock = NULL;
|
||||||
|
mdev->clock_info = NULL;
|
||||||
|
mlx5_devcom_comp_unlock(mdev->clock_state->compdev);
|
||||||
|
|
||||||
|
mlx5_devcom_unregister_component(mdev->clock_state->compdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlx5_clock_arm_pps_in_event(struct mlx5_clock *clock,
|
||||||
|
struct mlx5_core_dev *new_mdev,
|
||||||
|
struct mlx5_core_dev *old_mdev)
|
||||||
|
{
|
||||||
|
struct ptp_clock_info *ptp_info = &clock->ptp_info;
|
||||||
|
struct mlx5_clock_priv *cpriv = clock_priv(clock);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ptp_info->n_pins; i++) {
|
||||||
|
if (ptp_info->pin_config[i].func != PTP_PF_EXTTS ||
|
||||||
|
!clock->pps_info.pin_armed[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (new_mdev) {
|
||||||
|
mlx5_set_mtppse(new_mdev, i, 0, MLX5_EVENT_MODE_REPETETIVE);
|
||||||
|
cpriv->event_mdev = new_mdev;
|
||||||
|
} else {
|
||||||
|
cpriv->event_mdev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_mdev)
|
||||||
|
mlx5_set_mtppse(old_mdev, i, 0, MLX5_EVENT_MODE_DISABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mlx5_clock_load(struct mlx5_core_dev *mdev)
|
||||||
|
{
|
||||||
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
|
struct mlx5_clock_priv *cpriv;
|
||||||
|
|
||||||
|
if (!MLX5_CAP_GEN(mdev, device_frequency_khz))
|
||||||
|
return;
|
||||||
|
|
||||||
|
INIT_WORK(&mdev->clock_state->out_work, mlx5_pps_out);
|
||||||
|
MLX5_NB_INIT(&mdev->clock_state->pps_nb, mlx5_pps_event, PPS_EVENT);
|
||||||
|
mlx5_eq_notifier_register(mdev, &mdev->clock_state->pps_nb);
|
||||||
|
|
||||||
|
if (!clock->shared) {
|
||||||
|
mlx5_clock_arm_pps_in_event(clock, mdev, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpriv = clock_priv(clock);
|
||||||
|
mlx5_devcom_comp_lock(mdev->clock_state->compdev);
|
||||||
|
mlx5_clock_lock(clock);
|
||||||
|
if (mdev == cpriv->mdev && mdev != cpriv->event_mdev)
|
||||||
|
mlx5_clock_arm_pps_in_event(clock, mdev, cpriv->event_mdev);
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
mlx5_devcom_comp_unlock(mdev->clock_state->compdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mlx5_clock_unload(struct mlx5_core_dev *mdev)
|
||||||
|
{
|
||||||
|
struct mlx5_core_dev *peer_dev, *next = NULL;
|
||||||
|
struct mlx5_clock *clock = mdev->clock;
|
||||||
|
struct mlx5_devcom_comp_dev *pos;
|
||||||
|
|
||||||
|
if (!MLX5_CAP_GEN(mdev, device_frequency_khz))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!clock->shared) {
|
||||||
|
mlx5_clock_arm_pps_in_event(clock, NULL, mdev);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlx5_devcom_comp_lock(mdev->clock_state->compdev);
|
||||||
|
mlx5_devcom_for_each_peer_entry(mdev->clock_state->compdev, peer_dev, pos) {
|
||||||
|
if (peer_dev->clock && peer_dev != mdev) {
|
||||||
|
next = peer_dev;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mlx5_clock_lock(clock);
|
||||||
|
if (mdev == clock_priv(clock)->event_mdev)
|
||||||
|
mlx5_clock_arm_pps_in_event(clock, next, mdev);
|
||||||
|
mlx5_clock_unlock(clock);
|
||||||
|
mlx5_devcom_comp_unlock(mdev->clock_state->compdev);
|
||||||
|
|
||||||
|
out:
|
||||||
|
mlx5_eq_notifier_unregister(mdev, &mdev->clock_state->pps_nb);
|
||||||
|
cancel_work_sync(&mdev->clock_state->out_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mlx5_clock null_clock;
|
||||||
|
|
||||||
|
int mlx5_init_clock(struct mlx5_core_dev *mdev)
|
||||||
|
{
|
||||||
|
u8 identity[MLX5_RT_CLOCK_IDENTITY_SIZE];
|
||||||
|
struct mlx5_clock_dev_state *clock_state;
|
||||||
|
u64 key;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!MLX5_CAP_GEN(mdev, device_frequency_khz)) {
|
||||||
|
mdev->clock = &null_clock;
|
||||||
|
mlx5_core_warn(mdev, "invalid device_frequency_khz, aborting HW clock init\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
clock_state = kzalloc(sizeof(*clock_state), GFP_KERNEL);
|
||||||
|
if (!clock_state)
|
||||||
|
return -ENOMEM;
|
||||||
|
clock_state->mdev = mdev;
|
||||||
|
mdev->clock_state = clock_state;
|
||||||
|
|
||||||
|
if (MLX5_CAP_MCAM_REG3(mdev, mrtcq) && mlx5_real_time_mode(mdev)) {
|
||||||
|
if (mlx5_clock_identity_get(mdev, identity)) {
|
||||||
|
mlx5_core_warn(mdev, "failed to get rt clock identity, create ptp dev per function\n");
|
||||||
|
} else {
|
||||||
|
memcpy(&key, &identity, sizeof(key));
|
||||||
|
mlx5_shared_clock_register(mdev, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mdev->clock) {
|
||||||
|
err = mlx5_clock_alloc(mdev, false);
|
||||||
|
if (err) {
|
||||||
|
kfree(clock_state);
|
||||||
|
mdev->clock_state = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mlx5_cleanup_clock(struct mlx5_core_dev *mdev)
|
||||||
|
{
|
||||||
|
if (!MLX5_CAP_GEN(mdev, device_frequency_khz))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mdev->clock->shared)
|
||||||
|
mlx5_shared_clock_unregister(mdev);
|
||||||
|
else
|
||||||
|
mlx5_clock_free(mdev);
|
||||||
|
kfree(mdev->clock_state);
|
||||||
|
mdev->clock_state = NULL;
|
||||||
|
}
|
||||||
|
|||||||
@ -33,6 +33,38 @@
|
|||||||
#ifndef __LIB_CLOCK_H__
|
#ifndef __LIB_CLOCK_H__
|
||||||
#define __LIB_CLOCK_H__
|
#define __LIB_CLOCK_H__
|
||||||
|
|
||||||
|
#include <linux/ptp_clock_kernel.h>
|
||||||
|
|
||||||
|
/* KABI checker sees the old definitions in include/linux/mlx5/driver.h */
|
||||||
|
#ifndef __GENKSYMS__
|
||||||
|
#define MAX_PIN_NUM 8
|
||||||
|
struct mlx5_pps {
|
||||||
|
u8 pin_caps[MAX_PIN_NUM];
|
||||||
|
u64 start[MAX_PIN_NUM];
|
||||||
|
u8 enabled;
|
||||||
|
u64 min_npps_period;
|
||||||
|
u64 min_out_pulse_duration_ns;
|
||||||
|
bool pin_armed[MAX_PIN_NUM];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx5_timer {
|
||||||
|
struct cyclecounter cycles;
|
||||||
|
struct timecounter tc;
|
||||||
|
u32 nominal_c_mult;
|
||||||
|
unsigned long overflow_period;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlx5_clock {
|
||||||
|
seqlock_t lock;
|
||||||
|
struct hwtstamp_config hwtstamp_config;
|
||||||
|
struct ptp_clock *ptp;
|
||||||
|
struct ptp_clock_info ptp_info;
|
||||||
|
struct mlx5_pps pps_info;
|
||||||
|
struct mlx5_timer timer;
|
||||||
|
bool shared;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline bool mlx5_is_real_time_rq(struct mlx5_core_dev *mdev)
|
static inline bool mlx5_is_real_time_rq(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
u8 rq_ts_format_cap = MLX5_CAP_GEN(mdev, rq_ts_format);
|
u8 rq_ts_format_cap = MLX5_CAP_GEN(mdev, rq_ts_format);
|
||||||
@ -54,12 +86,14 @@ static inline bool mlx5_is_real_time_sq(struct mlx5_core_dev *mdev)
|
|||||||
typedef ktime_t (*cqe_ts_to_ns)(struct mlx5_clock *, u64);
|
typedef ktime_t (*cqe_ts_to_ns)(struct mlx5_clock *, u64);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
|
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
|
||||||
void mlx5_init_clock(struct mlx5_core_dev *mdev);
|
int mlx5_init_clock(struct mlx5_core_dev *mdev);
|
||||||
void mlx5_cleanup_clock(struct mlx5_core_dev *mdev);
|
void mlx5_cleanup_clock(struct mlx5_core_dev *mdev);
|
||||||
|
void mlx5_clock_load(struct mlx5_core_dev *mdev);
|
||||||
|
void mlx5_clock_unload(struct mlx5_core_dev *mdev);
|
||||||
|
|
||||||
static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev)
|
static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
return mdev->clock.ptp ? ptp_clock_index(mdev->clock.ptp) : -1;
|
return mdev->clock->ptp ? ptp_clock_index(mdev->clock->ptp) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ktime_t mlx5_timecounter_cyc2time(struct mlx5_clock *clock,
|
static inline ktime_t mlx5_timecounter_cyc2time(struct mlx5_clock *clock,
|
||||||
@ -87,8 +121,10 @@ static inline ktime_t mlx5_real_time_cyc2time(struct mlx5_clock *clock,
|
|||||||
return ns_to_ktime(time);
|
return ns_to_ktime(time);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline void mlx5_init_clock(struct mlx5_core_dev *mdev) {}
|
static inline int mlx5_init_clock(struct mlx5_core_dev *mdev) { return 0; }
|
||||||
static inline void mlx5_cleanup_clock(struct mlx5_core_dev *mdev) {}
|
static inline void mlx5_cleanup_clock(struct mlx5_core_dev *mdev) {}
|
||||||
|
static inline void mlx5_clock_load(struct mlx5_core_dev *mdev) {}
|
||||||
|
static inline void mlx5_clock_unload(struct mlx5_core_dev *mdev) {}
|
||||||
static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev)
|
static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ enum mlx5_devcom_component {
|
|||||||
MLX5_DEVCOM_MPV,
|
MLX5_DEVCOM_MPV,
|
||||||
MLX5_DEVCOM_HCA_PORTS,
|
MLX5_DEVCOM_HCA_PORTS,
|
||||||
MLX5_DEVCOM_SD_GROUP,
|
MLX5_DEVCOM_SD_GROUP,
|
||||||
|
MLX5_DEVCOM_SHARED_CLOCK,
|
||||||
MLX5_DEVCOM_NUM_COMPONENTS,
|
MLX5_DEVCOM_NUM_COMPONENTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1032,7 +1032,11 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
|
|||||||
|
|
||||||
mlx5_init_reserved_gids(dev);
|
mlx5_init_reserved_gids(dev);
|
||||||
|
|
||||||
mlx5_init_clock(dev);
|
err = mlx5_init_clock(dev);
|
||||||
|
if (err) {
|
||||||
|
mlx5_core_err(dev, "failed to initialize hardware clock\n");
|
||||||
|
goto err_tables_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
dev->vxlan = mlx5_vxlan_create(dev);
|
dev->vxlan = mlx5_vxlan_create(dev);
|
||||||
dev->geneve = mlx5_geneve_create(dev);
|
dev->geneve = mlx5_geneve_create(dev);
|
||||||
@ -1040,7 +1044,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
|
|||||||
err = mlx5_init_rl_table(dev);
|
err = mlx5_init_rl_table(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
mlx5_core_err(dev, "Failed to init rate limiting\n");
|
mlx5_core_err(dev, "Failed to init rate limiting\n");
|
||||||
goto err_tables_cleanup;
|
goto err_clock_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mlx5_mpfs_init(dev);
|
err = mlx5_mpfs_init(dev);
|
||||||
@ -1117,10 +1121,11 @@ err_mpfs_cleanup:
|
|||||||
mlx5_mpfs_cleanup(dev);
|
mlx5_mpfs_cleanup(dev);
|
||||||
err_rl_cleanup:
|
err_rl_cleanup:
|
||||||
mlx5_cleanup_rl_table(dev);
|
mlx5_cleanup_rl_table(dev);
|
||||||
err_tables_cleanup:
|
err_clock_cleanup:
|
||||||
mlx5_geneve_destroy(dev->geneve);
|
mlx5_geneve_destroy(dev->geneve);
|
||||||
mlx5_vxlan_destroy(dev->vxlan);
|
mlx5_vxlan_destroy(dev->vxlan);
|
||||||
mlx5_cleanup_clock(dev);
|
mlx5_cleanup_clock(dev);
|
||||||
|
err_tables_cleanup:
|
||||||
mlx5_cleanup_reserved_gids(dev);
|
mlx5_cleanup_reserved_gids(dev);
|
||||||
mlx5_cq_debugfs_cleanup(dev);
|
mlx5_cq_debugfs_cleanup(dev);
|
||||||
mlx5_fw_reset_cleanup(dev);
|
mlx5_fw_reset_cleanup(dev);
|
||||||
@ -1353,6 +1358,8 @@ static int mlx5_load(struct mlx5_core_dev *dev)
|
|||||||
goto err_eq_table;
|
goto err_eq_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mlx5_clock_load(dev);
|
||||||
|
|
||||||
err = mlx5_fw_tracer_init(dev->tracer);
|
err = mlx5_fw_tracer_init(dev->tracer);
|
||||||
if (err) {
|
if (err) {
|
||||||
mlx5_core_err(dev, "Failed to init FW tracer %d\n", err);
|
mlx5_core_err(dev, "Failed to init FW tracer %d\n", err);
|
||||||
@ -1436,6 +1443,7 @@ err_fpga_start:
|
|||||||
mlx5_hv_vhca_cleanup(dev->hv_vhca);
|
mlx5_hv_vhca_cleanup(dev->hv_vhca);
|
||||||
mlx5_fw_reset_events_stop(dev);
|
mlx5_fw_reset_events_stop(dev);
|
||||||
mlx5_fw_tracer_cleanup(dev->tracer);
|
mlx5_fw_tracer_cleanup(dev->tracer);
|
||||||
|
mlx5_clock_unload(dev);
|
||||||
mlx5_eq_table_destroy(dev);
|
mlx5_eq_table_destroy(dev);
|
||||||
err_eq_table:
|
err_eq_table:
|
||||||
mlx5_irq_table_destroy(dev);
|
mlx5_irq_table_destroy(dev);
|
||||||
@ -1462,6 +1470,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
|
|||||||
mlx5_hv_vhca_cleanup(dev->hv_vhca);
|
mlx5_hv_vhca_cleanup(dev->hv_vhca);
|
||||||
mlx5_fw_reset_events_stop(dev);
|
mlx5_fw_reset_events_stop(dev);
|
||||||
mlx5_fw_tracer_cleanup(dev->tracer);
|
mlx5_fw_tracer_cleanup(dev->tracer);
|
||||||
|
mlx5_clock_unload(dev);
|
||||||
mlx5_eq_table_destroy(dev);
|
mlx5_eq_table_destroy(dev);
|
||||||
mlx5_irq_table_destroy(dev);
|
mlx5_irq_table_destroy(dev);
|
||||||
mlx5_pagealloc_stop(dev);
|
mlx5_pagealloc_stop(dev);
|
||||||
|
|||||||
@ -161,6 +161,7 @@ enum {
|
|||||||
MLX5_REG_MIRC = 0x9162,
|
MLX5_REG_MIRC = 0x9162,
|
||||||
MLX5_REG_MTPTM = 0x9180,
|
MLX5_REG_MTPTM = 0x9180,
|
||||||
MLX5_REG_MTCTR = 0x9181,
|
MLX5_REG_MTCTR = 0x9181,
|
||||||
|
MLX5_REG_MRTCQ = 0x9182,
|
||||||
MLX5_REG_SBCAM = 0xB01F,
|
MLX5_REG_SBCAM = 0xB01F,
|
||||||
MLX5_REG_RESOURCE_DUMP = 0xC000,
|
MLX5_REG_RESOURCE_DUMP = 0xC000,
|
||||||
MLX5_REG_DTOR = 0xC00E,
|
MLX5_REG_DTOR = 0xC00E,
|
||||||
@ -706,17 +707,38 @@ struct mlx5_rsvd_gids {
|
|||||||
struct ida ida;
|
struct ida ida;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_PIN_NUM 8
|
/* RHEL 9.6 GA had an embedded struct mlx5_clock in struct mlx5_core_dev.
|
||||||
struct mlx5_pps {
|
* For PTP clock support with BF-3 (RHEL-87775), it needs to change to
|
||||||
u8 pin_caps[MAX_PIN_NUM];
|
* a pointer. However, changes to struct mlx5_core_dev break KABI symbols:
|
||||||
|
* mlx5_blocking_notifier_register
|
||||||
|
* mlx5_blocking_notifier_unregister
|
||||||
|
* mlx5_core_access_reg
|
||||||
|
* mlx5_core_uplink_netdev_event_replay
|
||||||
|
*
|
||||||
|
* We assume that:
|
||||||
|
* - The functions are exported to serve the in-tree drivers (mlx5_ib,
|
||||||
|
* mlx5_dpll).
|
||||||
|
* - Mixing the in-tree mlx5_core with an external mlx5_* aux binary
|
||||||
|
* driver is unlikely.
|
||||||
|
* - Even if the mixing occurs, the external driver is unlikely to touch
|
||||||
|
* the "clock" member anyway.
|
||||||
|
*
|
||||||
|
* To preserve the maximum of the KABI, we keep a dummy struct mlx5_clock where
|
||||||
|
* it was originally. To any external module accessing it, it will appear as if
|
||||||
|
* mlx5_init_clock() had aborted the HW clock init and left the struct cleared.
|
||||||
|
* To make this work, we keep the original struct layout definitions here.
|
||||||
|
*/
|
||||||
|
#define RHEL96_KABI_MAX_PIN_NUM 8
|
||||||
|
struct RH_KABI_RENAME(mlx5_pps, rhel96_kabi_mlx5_pps) {
|
||||||
|
u8 pin_caps[RHEL96_KABI_MAX_PIN_NUM];
|
||||||
struct work_struct out_work;
|
struct work_struct out_work;
|
||||||
u64 start[MAX_PIN_NUM];
|
u64 start[RHEL96_KABI_MAX_PIN_NUM];
|
||||||
u8 enabled;
|
u8 enabled;
|
||||||
u64 min_npps_period;
|
u64 min_npps_period;
|
||||||
u64 min_out_pulse_duration_ns;
|
u64 min_out_pulse_duration_ns;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx5_timer {
|
struct RH_KABI_RENAME(mlx5_timer, rhel96_kabi_mlx5_timer) {
|
||||||
struct cyclecounter cycles;
|
struct cyclecounter cycles;
|
||||||
struct timecounter tc;
|
struct timecounter tc;
|
||||||
u32 nominal_c_mult;
|
u32 nominal_c_mult;
|
||||||
@ -724,16 +746,18 @@ struct mlx5_timer {
|
|||||||
struct delayed_work overflow_work;
|
struct delayed_work overflow_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx5_clock {
|
struct RH_KABI_RENAME(mlx5_clock, rhel96_kabi_mlx5_clock) {
|
||||||
struct mlx5_nb pps_nb;
|
struct mlx5_nb pps_nb;
|
||||||
seqlock_t lock;
|
seqlock_t lock;
|
||||||
struct hwtstamp_config hwtstamp_config;
|
struct hwtstamp_config hwtstamp_config;
|
||||||
struct ptp_clock *ptp;
|
struct ptp_clock *ptp;
|
||||||
struct ptp_clock_info ptp_info;
|
struct ptp_clock_info ptp_info;
|
||||||
struct mlx5_pps pps_info;
|
struct RH_KABI_RENAME(mlx5_pps, rhel96_kabi_mlx5_pps) pps_info;
|
||||||
struct mlx5_timer timer;
|
struct RH_KABI_RENAME(mlx5_timer, rhel96_kabi_mlx5_timer) timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mlx5_clock;
|
||||||
|
struct mlx5_clock_dev_state;
|
||||||
struct mlx5_dm;
|
struct mlx5_dm;
|
||||||
struct mlx5_fw_tracer;
|
struct mlx5_fw_tracer;
|
||||||
struct mlx5_vxlan;
|
struct mlx5_vxlan;
|
||||||
@ -818,7 +842,8 @@ struct mlx5_core_dev {
|
|||||||
#ifdef CONFIG_MLX5_FPGA
|
#ifdef CONFIG_MLX5_FPGA
|
||||||
struct mlx5_fpga_device *fpga;
|
struct mlx5_fpga_device *fpga;
|
||||||
#endif
|
#endif
|
||||||
struct mlx5_clock clock;
|
struct RH_KABI_RENAME(mlx5_clock, rhel96_kabi_mlx5_clock)
|
||||||
|
RH_KABI_RENAME(clock, rhel96_kabi_dummy_clock);
|
||||||
struct mlx5_ib_clock_info *clock_info;
|
struct mlx5_ib_clock_info *clock_info;
|
||||||
struct mlx5_fw_tracer *tracer;
|
struct mlx5_fw_tracer *tracer;
|
||||||
struct mlx5_rsc_dump *rsc_dump;
|
struct mlx5_rsc_dump *rsc_dump;
|
||||||
@ -837,6 +862,8 @@ struct mlx5_core_dev {
|
|||||||
enum mlx5_wc_state wc_state;
|
enum mlx5_wc_state wc_state;
|
||||||
/* sync write combining state */
|
/* sync write combining state */
|
||||||
struct mutex wc_state_lock;
|
struct mutex wc_state_lock;
|
||||||
|
RH_KABI_EXTEND(struct mlx5_clock *clock)
|
||||||
|
RH_KABI_EXTEND(struct mlx5_clock_dev_state *clock_state)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx5_db {
|
struct mlx5_db {
|
||||||
|
|||||||
@ -10626,7 +10626,8 @@ struct mlx5_ifc_mcam_access_reg_bits3 {
|
|||||||
|
|
||||||
u8 regs_63_to_32[0x20];
|
u8 regs_63_to_32[0x20];
|
||||||
|
|
||||||
u8 regs_31_to_2[0x1e];
|
u8 regs_31_to_3[0x1d];
|
||||||
|
u8 mrtcq[0x1];
|
||||||
u8 mtctr[0x1];
|
u8 mtctr[0x1];
|
||||||
u8 mtptm[0x1];
|
u8 mtptm[0x1];
|
||||||
};
|
};
|
||||||
@ -13117,4 +13118,12 @@ struct mlx5_ifc_msees_reg_bits {
|
|||||||
u8 reserved_at_80[0x180];
|
u8 reserved_at_80[0x180];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mlx5_ifc_mrtcq_reg_bits {
|
||||||
|
u8 reserved_at_0[0x40];
|
||||||
|
|
||||||
|
u8 rt_clock_identity[0x40];
|
||||||
|
|
||||||
|
u8 reserved_at_80[0x180];
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* MLX5_IFC_H */
|
#endif /* MLX5_IFC_H */
|
||||||
|
|||||||
@ -1370,7 +1370,8 @@ svc_process_common(struct svc_rqst *rqstp)
|
|||||||
case SVC_OK:
|
case SVC_OK:
|
||||||
break;
|
break;
|
||||||
case SVC_GARBAGE:
|
case SVC_GARBAGE:
|
||||||
goto err_garbage_args;
|
rqstp->rq_auth_stat = rpc_autherr_badcred;
|
||||||
|
goto err_bad_auth;
|
||||||
case SVC_SYSERR:
|
case SVC_SYSERR:
|
||||||
goto err_system_err;
|
goto err_system_err;
|
||||||
case SVC_DENIED:
|
case SVC_DENIED:
|
||||||
@ -1511,14 +1512,6 @@ err_bad_proc:
|
|||||||
*rqstp->rq_accept_statp = rpc_proc_unavail;
|
*rqstp->rq_accept_statp = rpc_proc_unavail;
|
||||||
goto sendit;
|
goto sendit;
|
||||||
|
|
||||||
err_garbage_args:
|
|
||||||
svc_printk(rqstp, "failed to decode RPC header\n");
|
|
||||||
|
|
||||||
if (serv->sv_stats)
|
|
||||||
serv->sv_stats->rpcbadfmt++;
|
|
||||||
*rqstp->rq_accept_statp = rpc_garbage_args;
|
|
||||||
goto sendit;
|
|
||||||
|
|
||||||
err_system_err:
|
err_system_err:
|
||||||
if (serv->sv_stats)
|
if (serv->sv_stats)
|
||||||
serv->sv_stats->rpcbadfmt++;
|
serv->sv_stats->rpcbadfmt++;
|
||||||
|
|||||||
@ -1,3 +1,32 @@
|
|||||||
|
* Tue Jul 15 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-570.28.1.el9_6]
|
||||||
|
- sunrpc: handle SVC_GARBAGE during svc auth processing as auth error (CKI Backport Bot) [RHEL-101327] {CVE-2025-38089}
|
||||||
|
Resolves: RHEL-101327
|
||||||
|
|
||||||
|
* Sat Jul 12 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-570.27.1.el9_6]
|
||||||
|
- i2c: tegra: check msg length in SMBUS block read (Steve Dunnagan) [RHEL-100516]
|
||||||
|
- net/mlx5: Generate PPS IN event on new function for shared clock (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: Support one PTP device per hardware clock (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: Move PPS notifier and out_work to clock_state (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: Add devcom component for the clock shared by functions (Michal Schmidt) [RHEL-87775]
|
||||||
|
- net/mlx5: Change clock in mlx5_core_dev to mlx5_clock pointer (Michal Schmidt) [RHEL-87775]
|
||||||
|
- net/mlx5: Add API to get mlx5_core_dev from mlx5_clock (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: Add init and destruction functions for a single HW clock (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: Change parameters for PTP internal functions (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: Add helper functions for PTP callbacks (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: Add support for MRTCQ register (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- net/mlx5: use do_aux_work for PHC overflow checks (Michal Schmidt) [RHEL-87775]
|
||||||
|
- mlx5_en: use read sequence for gettimex64 (Benjamin Poirier) [RHEL-87775]
|
||||||
|
- media: uvcvideo: Announce the user our deprecation intentions (Desnes Nunes) [RHEL-98772]
|
||||||
|
- media: uvcvideo: Allow changing noparam on the fly (Desnes Nunes) [RHEL-98772]
|
||||||
|
- media: uvcvideo: Invert default value for nodrop module param (Desnes Nunes) [RHEL-98772]
|
||||||
|
- media: uvcvideo: Propagate buf->error to userspace (Desnes Nunes) [RHEL-98772]
|
||||||
|
- media: uvcvideo: Flush the control cache when we get an event (Desnes Nunes) [RHEL-98772]
|
||||||
|
- media: uvcvideo: Annotate lock requirements for uvc_ctrl_set (Desnes Nunes) [RHEL-98772]
|
||||||
|
- media: uvcvideo: Remove dangling pointers (Desnes Nunes) [RHEL-98772] {CVE-2024-58002}
|
||||||
|
- media: uvcvideo: Remove redundant NULL assignment (Desnes Nunes) [RHEL-98772]
|
||||||
|
- media: uvcvideo: Only save async fh if success (Desnes Nunes) [RHEL-98772]
|
||||||
|
Resolves: RHEL-100516, RHEL-87775, RHEL-98772
|
||||||
|
|
||||||
* Sat Jul 05 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-570.26.1.el9_6]
|
* Sat Jul 05 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-570.26.1.el9_6]
|
||||||
- x86/microcode/AMD: Fix out-of-bounds on systems with CPU-less NUMA nodes (CKI Backport Bot) [RHEL-98996] {CVE-2025-21991}
|
- x86/microcode/AMD: Fix out-of-bounds on systems with CPU-less NUMA nodes (CKI Backport Bot) [RHEL-98996] {CVE-2025-21991}
|
||||||
- cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode (David Arcari) [RHEL-90212]
|
- cpufreq: intel_pstate: Unchecked MSR aceess in legacy mode (David Arcari) [RHEL-90212]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user