191 lines
5.9 KiB
C
191 lines
5.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* SSH packet transport layer.
|
|
*
|
|
* Copyright (C) 2019-2020 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);
|
|
|
|
int 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 */
|