| /* SPDX-License-Identifier: GPL-2.0+ */ |
| /* |
| * SSH packet transport layer. |
| * |
| * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> |
| */ |
| |
| #ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H |
| #define _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H |
| |
| #include <linux/atomic.h> |
| #include <linux/kfifo.h> |
| #include <linux/ktime.h> |
| #include <linux/list.h> |
| #include <linux/serdev.h> |
| #include <linux/spinlock.h> |
| #include <linux/types.h> |
| #include <linux/wait.h> |
| #include <linux/workqueue.h> |
| |
| #include <linux/surface_aggregator/serial_hub.h> |
| #include "ssh_parser.h" |
| |
| /** |
| * enum ssh_ptl_state_flags - State-flags for &struct ssh_ptl. |
| * |
| * @SSH_PTL_SF_SHUTDOWN_BIT: |
| * Indicates that the packet transport layer has been shut down or is |
| * being shut down and should not accept any new packets/data. |
| */ |
| enum ssh_ptl_state_flags { |
| SSH_PTL_SF_SHUTDOWN_BIT, |
| }; |
| |
| /** |
| * struct ssh_ptl_ops - Callback operations for packet transport layer. |
| * @data_received: Function called when a data-packet has been received. Both, |
| * the packet layer on which the packet has been received and |
| * the packet's payload data are provided to this function. |
| */ |
| struct ssh_ptl_ops { |
| void (*data_received)(struct ssh_ptl *p, const struct ssam_span *data); |
| }; |
| |
| /** |
| * struct ssh_ptl - SSH packet transport layer. |
| * @serdev: Serial device providing the underlying data transport. |
| * @state: State(-flags) of the transport layer. |
| * @queue: Packet submission queue. |
| * @queue.lock: Lock for modifying the packet submission queue. |
| * @queue.head: List-head of the packet submission queue. |
| * @pending: Set/list of pending packets. |
| * @pending.lock: Lock for modifying the pending set. |
| * @pending.head: List-head of the pending set/list. |
| * @pending.count: Number of currently pending packets. |
| * @tx: Transmitter subsystem. |
| * @tx.running: Flag indicating (desired) transmitter thread state. |
| * @tx.thread: Transmitter thread. |
| * @tx.thread_cplt_tx: Completion for transmitter thread waiting on transfer. |
| * @tx.thread_cplt_pkt: Completion for transmitter thread waiting on packets. |
| * @tx.packet_wq: Waitqueue-head for packet transmit completion. |
| * @rx: Receiver subsystem. |
| * @rx.thread: Receiver thread. |
| * @rx.wq: Waitqueue-head for receiver thread. |
| * @rx.fifo: Buffer for receiving data/pushing data to receiver thread. |
| * @rx.buf: Buffer for evaluating data on receiver thread. |
| * @rx.blocked: List of recent/blocked sequence IDs to detect retransmission. |
| * @rx.blocked.seqs: Array of blocked sequence IDs. |
| * @rx.blocked.offset: Offset indicating where a new ID should be inserted. |
| * @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: Packet layer operations. |
| */ |
| struct ssh_ptl { |
| struct serdev_device *serdev; |
| 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 { |
| atomic_t running; |
| struct task_struct *thread; |
| struct completion thread_cplt_tx; |
| struct completion thread_cplt_pkt; |
| struct wait_queue_head packet_wq; |
| } tx; |
| |
| struct { |
| struct task_struct *thread; |
| struct wait_queue_head wq; |
| struct kfifo fifo; |
| struct sshp_buf buf; |
| |
| struct { |
| u16 seqs[8]; |
| u16 offset; |
| } blocked; |
| } rx; |
| |
| struct { |
| spinlock_t lock; |
| ktime_t timeout; |
| ktime_t expires; |
| struct delayed_work reaper; |
| } rtx_timeout; |
| |
| struct ssh_ptl_ops ops; |
| }; |
| |
| #define __ssam_prcond(func, p, fmt, ...) \ |
| do { \ |
| typeof(p) __p = (p); \ |
| \ |
| if (__p) \ |
| func(__p, fmt, ##__VA_ARGS__); \ |
| } while (0) |
| |
| #define ptl_dbg(p, fmt, ...) dev_dbg(&(p)->serdev->dev, fmt, ##__VA_ARGS__) |
| #define ptl_info(p, fmt, ...) dev_info(&(p)->serdev->dev, fmt, ##__VA_ARGS__) |
| #define ptl_warn(p, fmt, ...) dev_warn(&(p)->serdev->dev, fmt, ##__VA_ARGS__) |
| #define ptl_err(p, fmt, ...) dev_err(&(p)->serdev->dev, fmt, ##__VA_ARGS__) |
| #define ptl_dbg_cond(p, fmt, ...) __ssam_prcond(ptl_dbg, p, fmt, ##__VA_ARGS__) |
| |
| #define to_ssh_ptl(ptr, member) \ |
| container_of(ptr, struct ssh_ptl, member) |
| |
| int ssh_ptl_init(struct ssh_ptl *ptl, struct serdev_device *serdev, |
| struct ssh_ptl_ops *ops); |
| |
| void ssh_ptl_destroy(struct ssh_ptl *ptl); |
| |
| /** |
| * ssh_ptl_get_device() - Get device associated with packet transport layer. |
| * @ptl: The packet transport layer. |
| * |
| * Return: Returns the device on which the given packet transport layer builds |
| * upon. |
| */ |
| static inline struct device *ssh_ptl_get_device(struct ssh_ptl *ptl) |
| { |
| return ptl->serdev ? &ptl->serdev->dev : NULL; |
| } |
| |
| int ssh_ptl_tx_start(struct ssh_ptl *ptl); |
| int ssh_ptl_tx_stop(struct ssh_ptl *ptl); |
| int ssh_ptl_rx_start(struct ssh_ptl *ptl); |
| int ssh_ptl_rx_stop(struct ssh_ptl *ptl); |
| void ssh_ptl_shutdown(struct ssh_ptl *ptl); |
| |
| int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p); |
| void ssh_ptl_cancel(struct ssh_packet *p); |
| |
| ssize_t ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n); |
| |
| /** |
| * ssh_ptl_tx_wakeup_transfer() - Wake up packet transmitter thread for |
| * transfer. |
| * @ptl: The packet transport layer. |
| * |
| * Wakes up the packet transmitter thread, notifying it that the underlying |
| * transport has more space for data to be transmitted. If the packet |
| * transport layer has been shut down, calls to this function will be ignored. |
| */ |
| static inline void ssh_ptl_tx_wakeup_transfer(struct ssh_ptl *ptl) |
| { |
| if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state)) |
| return; |
| |
| complete(&ptl->tx.thread_cplt_tx); |
| } |
| |
| void ssh_packet_init(struct ssh_packet *packet, unsigned long type, |
| u8 priority, const struct ssh_packet_ops *ops); |
| |
| int ssh_ctrl_packet_cache_init(void); |
| void ssh_ctrl_packet_cache_destroy(void); |
| |
| #endif /* _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H */ |