/*      $NetBSD: ldcvar.h,v 1.2 2025/02/05 20:46:26 palle Exp $ */
/*      $OpenBSD: ldcvar.h,v 1.6 2014/09/29 17:43:29 kettenis Exp $     */
/*
* Copyright (c) 2009 Mark Kettenis
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
* LDC queues.
*/

#include <sys/mutex.h>

struct ldc_queue {
       kmutex_t        lq_mtx;
#if OPENBSD_BUSDMA
       bus_dmamap_t    lq_map;
       bus_dma_segment_t lq_seg;
#endif
       vaddr_t         lq_va;
       int             lq_nentries;
};

#if OPENBSD_BUSDMA
struct ldc_queue *ldc_queue_alloc(bus_dma_tag_t, int);
void    ldc_queue_free(bus_dma_tag_t, struct ldc_queue *);
#else
struct ldc_queue *ldc_queue_alloc(int);
void    ldc_queue_free(struct ldc_queue *);
#endif

/*
* LDC virtual link layer protocol.
*/

#define LDC_VERSION_MAJOR       1
#define LDC_VERSION_MINOR       0

#define LDC_PKT_PAYLOAD         56

struct ldc_pkt {
       uint8_t         type;
       uint8_t         stype;
       uint8_t         ctrl;
       uint8_t         env;
       uint32_t        seqid;

       uint16_t        major;
       uint16_t        minor;
       uint32_t        _reserved[13];
};

/* Packet types. */
#define LDC_CTRL        0x01
#define LDC_DATA        0x02
#define LDC_ERR         0x10

/* Packet subtypes. */
#define LDC_INFO        0x01
#define LDC_ACK         0x02
#define LDC_NACK        0x04

/* Control info values. */
#define LDC_VERS        0x01
#define LDC_RTS         0x02
#define LDC_RTR         0x03
#define LDC_RDX         0x04

/* Packet envelope. */
#define LDC_MODE_RAW            0x00
#define LDC_MODE_UNRELIABLE     0x01
#define LDC_MODE_RELIABLE       0x03

#define LDC_LEN_MASK    0x3f
#define LDC_FRAG_MASK   0xc0
#define LDC_FRAG_START  0x40
#define LDC_FRAG_STOP   0x80

/*
* XXX Get rid of the +8 once we no longer need to store the header of
* the first packet.
*/
#define LDC_MSG_MAX     (128 + 8)

struct ldc_conn {
       uint64_t        lc_id;

       struct ldc_queue *lc_txq;
       struct ldc_queue *lc_rxq;
       uint64_t        lc_tx_state;
       uint64_t        lc_rx_state;

       uint32_t        lc_tx_seqid;
       uint8_t         lc_state;
#define LDC_SND_VERS    1
#define LDC_RCV_VERS    2
#define LDC_SND_RTS     3
#define LDC_SND_RTR     4
#define LDC_SND_RDX     5

       uint64_t        lc_msg[LDC_MSG_MAX / 8];
       size_t          lc_len;

       void            *lc_sc;
       void            (*lc_reset)(struct ldc_conn *);
       void            (*lc_start)(struct ldc_conn *);
       void            (*lc_rx_data)(struct ldc_conn *, struct ldc_pkt *);
};

void    ldc_rx_ctrl(struct ldc_conn *, struct ldc_pkt *);
void    ldc_rx_data(struct ldc_conn *, struct ldc_pkt *);

int     ldc_send_vers(struct ldc_conn *);
int     ldc_send_unreliable(struct ldc_conn *, void *, size_t);

void    ldc_reset(struct ldc_conn *);

/*
* LDC map tables.
*/

struct ldc_map_slot {
       uint64_t        entry;
       uint64_t        cookie;
};

#define LDC_MTE_R       0x0000000000000010ULL
#define LDC_MTE_W       0x0000000000000020ULL
#define LDC_MTE_X       0x0000000000000040ULL
#define LDC_MTE_IOR     0x0000000000000080ULL
#define LDC_MTE_IOW     0x0000000000000100ULL
#define LDC_MTE_CPR     0x0000000000000200ULL
#define LDC_MTE_CPW     0x0000000000000400ULL
#define LDC_MTE_RA_MASK 0x007fffffffffe000ULL

struct ldc_map {
#if OPENBSD_BUSDMA
       bus_dmamap_t            lm_map;
       bus_dma_segment_t       lm_seg;
#endif
       struct ldc_map_slot     *lm_slot;
       int                     lm_nentries;
       int                     lm_next;
       int                     lm_count;
};

#if OPENBSD_BUSDMA
struct ldc_map *ldc_map_alloc(bus_dma_tag_t, int);
void    ldc_map_free(bus_dma_tag_t, struct ldc_map *);
#else
struct ldc_map *ldc_map_alloc(int);
void    ldc_map_free(struct ldc_map *);
#endif

struct ldc_cookie {
       uint64_t        addr;
       uint64_t        size;
};