| /* SPDX-License-Identifier: GPL-2.0+ */ | |
| /* | |
| * SSH request transport layer. | |
| * | |
| * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> | |
| */ | |
| #ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H | |
| #define _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H | |
| #include <linux/atomic.h> | |
| #include <linux/ktime.h> | |
| #include <linux/list.h> | |
| #include <linux/spinlock.h> | |
| #include <linux/workqueue.h> | |
| #include <linux/surface_aggregator/serial_hub.h> | |
| #include <linux/surface_aggregator/controller.h> | |
| #include "ssh_packet_layer.h" | |
| /** | |
| * enum ssh_rtl_state_flags - State-flags for &struct ssh_rtl. | |
| * | |
| * @SSH_RTL_SF_SHUTDOWN_BIT: | |
| * Indicates that the request transport layer has been shut down or is | |
| * being shut down and should not accept any new requests. | |
| */ | |
| enum ssh_rtl_state_flags { | |
| SSH_RTL_SF_SHUTDOWN_BIT, | |
| }; | |
| /** | |
| * struct ssh_rtl_ops - Callback operations for request transport layer. | |
| * @handle_event: Function called when a SSH event has been received. The | |
| * specified function takes the request layer, received command | |
| * struct, and corresponding payload as arguments. If the event | |
| * has no payload, the payload span is empty (not %NULL). | |
| */ | |
| struct ssh_rtl_ops { | |
| void (*handle_event)(struct ssh_rtl *rtl, const struct ssh_command *cmd, | |
| const struct ssam_span *data); | |
| }; | |
| /** | |
| * struct ssh_rtl - SSH request transport layer. | |
| * @ptl: Underlying packet transport layer. | |
| * @state: State(-flags) of the transport layer. | |
| * @queue: Request submission queue. | |
| * @queue.lock: Lock for modifying the request submission queue. | |
| * @queue.head: List-head of the request submission queue. | |
| * @pending: Set/list of pending requests. | |
| * @pending.lock: Lock for modifying the request set. | |
| * @pending.head: List-head of the pending set/list. | |
| * @pending.count: Number of currently pending requests. | |
| * @tx: Transmitter subsystem. | |
| * @tx.work: Transmitter work item. | |
| * @rtx_timeout: Retransmission timeout subsystem. | |
| * @rtx_timeout.lock: Lock for modifying the retransmission timeout reaper. | |
| * @rtx_timeout.timeout: Timeout interval for retransmission. | |
| * @rtx_timeout.expires: Time specifying when the reaper work is next scheduled. | |
| * @rtx_timeout.reaper: Work performing timeout checks and subsequent actions. | |
| * @ops: Request layer operations. | |
| */ | |
| struct ssh_rtl { | |
| struct ssh_ptl ptl; | |
| unsigned long state; | |
| struct { | |
| spinlock_t lock; | |
| struct list_head head; | |
| } queue; | |
| struct { | |
| spinlock_t lock; | |
| struct list_head head; | |
| atomic_t count; | |
| } pending; | |
| struct { | |
| struct work_struct work; | |
| } tx; | |
| struct { | |
| spinlock_t lock; | |
| ktime_t timeout; | |
| ktime_t expires; | |
| struct delayed_work reaper; | |
| } rtx_timeout; | |
| struct ssh_rtl_ops ops; | |
| }; | |
| #define rtl_dbg(r, fmt, ...) ptl_dbg(&(r)->ptl, fmt, ##__VA_ARGS__) | |
| #define rtl_info(p, fmt, ...) ptl_info(&(p)->ptl, fmt, ##__VA_ARGS__) | |
| #define rtl_warn(r, fmt, ...) ptl_warn(&(r)->ptl, fmt, ##__VA_ARGS__) | |
| #define rtl_err(r, fmt, ...) ptl_err(&(r)->ptl, fmt, ##__VA_ARGS__) | |
| #define rtl_dbg_cond(r, fmt, ...) __ssam_prcond(rtl_dbg, r, fmt, ##__VA_ARGS__) | |
| #define to_ssh_rtl(ptr, member) \ | |
| container_of(ptr, struct ssh_rtl, member) | |
| /** | |
| * ssh_rtl_get_device() - Get device associated with request transport layer. | |
| * @rtl: The request transport layer. | |
| * | |
| * Return: Returns the device on which the given request transport layer | |
| * builds upon. | |
| */ | |
| static inline struct device *ssh_rtl_get_device(struct ssh_rtl *rtl) | |
| { | |
| return ssh_ptl_get_device(&rtl->ptl); | |
| } | |
| /** | |
| * ssh_request_rtl() - Get request transport layer associated with request. | |
| * @rqst: The request to get the request transport layer reference for. | |
| * | |
| * Return: Returns the &struct ssh_rtl associated with the given SSH request. | |
| */ | |
| static inline struct ssh_rtl *ssh_request_rtl(struct ssh_request *rqst) | |
| { | |
| struct ssh_ptl *ptl; | |
| ptl = READ_ONCE(rqst->packet.ptl); | |
| return likely(ptl) ? to_ssh_rtl(ptl, ptl) : NULL; | |
| } | |
| int ssh_rtl_submit(struct ssh_rtl *rtl, struct ssh_request *rqst); | |
| bool ssh_rtl_cancel(struct ssh_request *rqst, bool pending); | |
| int ssh_rtl_init(struct ssh_rtl *rtl, struct serdev_device *serdev, | |
| const struct ssh_rtl_ops *ops); | |
| int ssh_rtl_start(struct ssh_rtl *rtl); | |
| int ssh_rtl_flush(struct ssh_rtl *rtl, unsigned long timeout); | |
| void ssh_rtl_shutdown(struct ssh_rtl *rtl); | |
| void ssh_rtl_destroy(struct ssh_rtl *rtl); | |
| int ssh_request_init(struct ssh_request *rqst, enum ssam_request_flags flags, | |
| const struct ssh_request_ops *ops); | |
| #endif /* _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H */ |