/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LDC_IMPL_H #define _LDC_IMPL_H #pragma ident "%Z%%M% %I% %E% SMI" #ifdef __cplusplus extern "C" { #endif #include #include #include #include /* Memory map table entries */ #define LDC_MTBL_ENTRIES 8192 /* 8 K */ /* Define LDC Queue info */ #define LDC_PACKET_SHIFT 6 #define LDC_QUEUE_ENTRIES 512 #define LDC_MTU_MSGS 4 #define LDC_QUEUE_SIZE (LDC_QUEUE_ENTRIES << LDC_PACKET_SHIFT) #define LDC_DEFAULT_MTU (LDC_QUEUE_SIZE / LDC_MTU_MSGS) #define LDC_RXDQ_MULTIPLIER 2 /* * LDC Reliable mode - initial packet seqid * - If peer initiated handshake, RDX should contain init_seqid + 1 * - If this endpoint initiated handshake first data packet should * contain the message init_seqid + 1 */ #define LDC_INIT_SEQID 0x0 /* LDC Message types */ #define LDC_CTRL 0x01 /* Control Pkt */ #define LDC_DATA 0x02 /* Data Pkt */ #define LDC_ERR 0x10 /* Error Pkt */ /* LDC Message Subtypes */ #define LDC_INFO 0x01 /* Control/Data/Error info pkt */ #define LDC_ACK 0x02 /* Control/Data ACK */ #define LDC_NACK 0x04 /* Control/Data NACK */ /* LDC Control Messages */ #define LDC_VER 0x01 /* Version message */ #define LDC_RTS 0x02 /* Request to Send */ #define LDC_RTR 0x03 /* Ready To Receive */ #define LDC_RDX 0x04 /* Ready for data exchange */ #define LDC_CTRL_MASK 0x0f /* Mask to read control bits */ /* LDC Channel Transport State (tstate) */ #define TS_TXQ_RDY 0x01 /* allocated TX queue */ #define TS_RXQ_RDY 0x02 /* allocated RX queue */ #define TS_INIT (TS_TXQ_RDY | TS_RXQ_RDY) #define TS_QCONF_RDY 0x04 /* registered queues with HV */ #define TS_CNEX_RDY 0x08 /* registered channel with cnex */ #define TS_OPEN (TS_INIT | TS_QCONF_RDY | TS_CNEX_RDY) #define TS_LINK_READY 0x10 /* both endpts registered Rx queues */ #define TS_READY (TS_OPEN | TS_LINK_READY) #define TS_VER_DONE 0x20 /* negotiated version */ #define TS_VREADY (TS_READY | TS_VER_DONE) #define TS_HSHAKE_DONE 0x40 /* completed handshake */ #define TS_UP (TS_READY | TS_VER_DONE | TS_HSHAKE_DONE) #define TS_IN_RESET 0x100 /* channel is in reset state */ /* LDC Channel Transport Handshake states */ #define TS_SENT_VER 0x01 /* Sent version */ #define TS_SENT_RTS 0x02 /* Sent RTS */ #define TS_RCVD_RTR 0x04 /* Received RTR */ #define TS_SENT_RDX 0x08 /* Sent RDX */ #define TS_RCVD_VER 0x10 /* Received version */ #define TS_RCVD_RTS 0x20 /* Received RTS */ #define TS_SENT_RTR 0x40 /* Sent RTR */ #define TS_RCVD_RDX 0x80 /* Received RDX */ /* LDC Interrupt State */ #define LDC_INTR_NONE 0x00 /* No interrupts */ #define LDC_INTR_ACTIVE 0x01 /* Interrupt being processed */ #define LDC_INTR_PEND 0x02 /* Interrupt pending */ /* LDC MSG Envelope */ #define LDC_LEN_MASK 0x3F #define LDC_FRAG_MASK 0xC0 #define LDC_FRAG_START 0x40 /* frag_info = 0x01 */ #define LDC_FRAG_STOP 0x80 /* frag_info = 0x02 */ #define LDC_FRAG_CONT 0x00 /* frag_info = 0x00 */ /* * LDC will retry LDC_MAX_RETRIES times when sending or * receiving data or if the HV returns back EWOULDBLOCK. * Between each retry it will wait LDC_DELAY usecs. */ #define LDC_MAX_RETRIES 1000 #define LDC_DELAY 1 /* delay(usec) between channel unregister retries in ldc_close() */ #define LDC_CLOSE_DELAY 1 /* * LDC Version information */ #define LDC_PAYLOAD_VER_OFF 8 /* offset of version in payload */ typedef struct ldc_ver { uint16_t major; uint16_t minor; } ldc_ver_t; /* * Each guest consists of one or more LDC endpoints represented by a ldc_chan * structure. Each ldc_chan structure points to a ldc_mtbl structure that * contains information about the map table associated with this LDC endpoint. * The map table contains the list of pages being shared by this guest over * this endpoint with the guest at the other end of this endpoint. Each LDC * endpoint also points to a list of memory handles used to bind and export * memory segments from this guest. If a memory segment is bound, it points to * a memory segment structure, which inturn consists of an array of ldc_page * structure for all the pages within that segment. Each ldc_page structure * contains information about the shared page and also points to the * corresponding entry in the map table. * * Each LDC endpoint also points to a list of ldc_dring structures that refer * to both imported and exported descriptor rings. If it is a exported * descriptor ring, it then points to memory handle/memseg corresponding to * the region of memory associated with the descriptor ring. * * +----------+ +----------+ +----------+ * | ldc_chan |-->| ldc_chan |-->| ldc_chan |-->.... * +----------+ +----------+ +----------+ * | | | * | | | * | | | +-----------+ +-----------+ * | | +----->| ldc_dring |---->| ldc_dring |---->...... * | | +-----------+ +-----------+ * | | | * | | +----------------------------+ * | | | * | | v * | | +----------+ +----------+ +----------+ * | +----->| ldc_mhdl |---->| ldc_mhdl |---->| ldc_mhdl |---> .... * | +----------+ +----------+ +----------+ * v | | * +----------+ | +------------+ | +------------+ * | ldc_mtbl |--+ +--->| ldc_memseg |-----+ +--->| ldc_memseg | * +----------+ | +------------+ | +------------+ * | | | | | * v v v | v * +--------------+ +----------+ +--------+ | +--------+ * | ldc_mte_slot |<--------| ldc_page | | cookie | | | cookie | * +--------------+ +----------+ +--------+ | +--------+ * | ldc_mte_slot |<--------| ldc_page | | cookie | v * +--------------+ +----------+ +--------+ +----------+ * | ldc_mte_slot |<-----------------------------------| ldc_page | * +--------------+ +----------+ * | ldc_mte_slot | * +--------------+ * | ...... |/ +------------+ * +--------------+ | entry | * | ldc_mte_slot | +------------+ * +--------------+ | inv_cookie | * \ +------------+ * */ /* * Message format of each packet sent over the LDC channel. * Each packet is 64-bytes long. * * Each packet that is sent over LDC can contain either data or acks. * The type will reflect the contents. The len will contain in bytes * the amount of data being sent. In the case of ACKs, the seqid and * data fields will contain the SEQIDs of messages for which ACKs are * being sent. * * Raw pkt format: * * +------------------------------------------------------+ * 0 - 7 | data payload | * +------------------------------------------------------+ * * Unreliable pkt format: * * +------------------------------------------------------+ * 0 | seqid | env | ctrl | stype | type | * +------------------------------------------------------+ * 1 - 7 | data payload | * +------------------------------------------------------+ * * Reliable pkt format: * * +------------------------------------------------------+ * 0 | seqid | env | ctrl | stype | type | * +------------------------------------------------------+ * 1 | ackid | unused | * +------------------------------------------------------+ * 2 - 7 | data payload | * +------------------------------------------------------+ */ typedef struct ldc_msg { union { struct { uint8_t _type; /* Message type */ uint8_t _stype; /* Message subtype */ uint8_t _ctrl; /* Control/Error Message */ uint8_t _env; /* Message Envelope */ uint32_t _seqid; /* Sequence ID */ union { uint8_t _ud[LDC_PAYLOAD_SIZE_UNRELIABLE]; /* Unreliable data payload */ struct { uint32_t _unused; /* unused */ uint32_t _ackid; /* ACK ID */ uint8_t _rd[LDC_PAYLOAD_SIZE_RELIABLE]; /* Reliable data payload */ } _rl; } _data; } _tpkt; uint8_t _raw[LDC_PAYLOAD_SIZE_RAW]; } _pkt; } ldc_msg_t; #define raw _pkt._raw #define type _pkt._tpkt._type #define stype _pkt._tpkt._stype #define ctrl _pkt._tpkt._ctrl #define env _pkt._tpkt._env #define seqid _pkt._tpkt._seqid #define udata _pkt._tpkt._data._ud #define ackid _pkt._tpkt._data._rl._ackid #define rdata _pkt._tpkt._data._rl._rd /* * LDC Map Table Entry (MTE) * * 6 6 1 1 1 * |3 0| psz| 3| 1| 0| 9| 8| 7|6|5|4| 0| * +------+--------------------------+----+----+--+--+--+--+-+-+-+-------+ * | rsvd | PFN | 0 | 0 |CW|CR|IW|IR|X|W|R| pgszc | * +------+--------------------------+----+----+--+--+--+--+-+-+-+-------+ * | hv invalidation cookie | * +---------------------------------------------------------------------+ */ typedef union { struct { uint64_t _rsvd2:8, /* <63:56> reserved */ rpfn:43, /* <55:13> real pfn */ _rsvd1:2, /* <12:11> reserved */ cw:1, /* <10> copy write access */ cr:1, /* <9> copy read perm */ iw:1, /* <8> iommu write perm */ ir:1, /* <7> iommu read perm */ x:1, /* <6> execute perm */ w:1, /* <5> write perm */ r:1, /* <4> read perm */ pgszc:4; /* <3:0> pgsz code */ } mte_bit; uint64_t ll; } ldc_mte_t; #define mte_rpfn mte_bit.rpfn #define mte_cw mte_bit.cw #define mte_cr mte_bit.cr #define mte_iw mte_bit.iw #define mte_ir mte_bit.ir #define mte_x mte_bit.x #define mte_w mte_bit.w #define mte_r mte_bit.r #define mte_pgszc mte_bit.pgszc #define MTE_BSZS_SHIFT(sz) ((sz) * 3) #define MTEBYTES(sz) (MMU_PAGESIZE << MTE_BSZS_SHIFT(sz)) #define MTEPAGES(sz) (1 << MTE_BSZS_SHIFT(sz)) #define MTE_PAGE_SHIFT(sz) (MMU_PAGESHIFT + MTE_BSZS_SHIFT(sz)) #define MTE_PAGE_OFFSET(sz) (MTEBYTES(sz) - 1) #define MTE_PAGEMASK(sz) (~MTE_PAGE_OFFSET(sz)) #define MTE_PFNMASK(sz) (~(MTE_PAGE_OFFSET(sz) >> MMU_PAGESHIFT)) /* * LDC Map Table Slot */ typedef struct ldc_mte_slot { ldc_mte_t entry; uint64_t cookie; } ldc_mte_slot_t; /* * LDC Memory Map Table * * Each LDC has a memory map table it uses to list all the pages * it exporting to its peer over the channel. This structure * contains information about the map table and is pointed to * by the ldc_chan structure. */ typedef struct ldc_mtbl { kmutex_t lock; /* Table lock */ size_t size; /* Table size (in bytes) */ uint64_t next_entry; /* Next entry to use */ uint64_t num_entries; /* Num entries in table */ uint64_t num_avail; /* Num of available entries */ boolean_t contigmem; /* TRUE=Contig mem alloc'd */ ldc_mte_slot_t *table; /* The table itself */ } ldc_mtbl_t; /* * LDC page and memory segment information */ typedef struct ldc_page { uintptr_t raddr; /* Exported page RA */ uint64_t offset; /* Exported page offset */ size_t size; /* Exported page size */ uint64_t index; /* Index in map table */ ldc_mte_slot_t *mte; /* Map table entry */ } ldc_page_t; typedef struct ldc_memseg { caddr_t vaddr; /* Exported segment VA */ uintptr_t raddr; /* Exported segment VA */ size_t size; /* Exported segment size */ uint64_t npages; /* Number of pages */ ldc_page_t *pages; /* Array of exported pages */ uint32_t ncookies; /* Number of cookies */ ldc_mem_cookie_t *cookies; uint64_t next_cookie; /* Index to next cookie */ } ldc_memseg_t; /* * LDC Cookie address format * * 6 6 m+n * |3| 0| | m| 0| * +-+-------+----------+-------------------+-------------------+ * |X| pgszc | rsvd | table_idx | page_offset | * +-+-------+----------+-------------------+-------------------+ */ #define LDC_COOKIE_PGSZC_MASK 0x7 #define LDC_COOKIE_PGSZC_SHIFT 60 /* * LDC Memory handle */ typedef struct ldc_chan ldc_chan_t; typedef struct ldc_mhdl { kmutex_t lock; /* Mutex for memory handle */ ldc_mstatus_t status; /* Memory map status */ uint8_t mtype; /* Type of sharing */ uint8_t perm; /* Access permissions */ boolean_t myshadow; /* TRUE=alloc'd shadow mem */ ldc_chan_t *ldcp; /* Pointer to channel struct */ ldc_memseg_t *memseg; /* Bound memory segment */ struct ldc_mhdl *next; /* Next memory handle */ } ldc_mhdl_t; /* * LDC Descriptor rings */ typedef struct ldc_dring { kmutex_t lock; /* Desc ring lock */ ldc_mstatus_t status; /* Desc ring status */ uint32_t dsize; /* Descriptor size */ uint32_t length; /* Descriptor ring length */ uint64_t size; /* Desc ring size (in bytes) */ caddr_t base; /* Descriptor ring base addr */ ldc_chan_t *ldcp; /* Pointer to bound channel */ ldc_mem_handle_t mhdl; /* Mem handle to desc ring */ struct ldc_dring *ch_next; /* Next dring in channel */ struct ldc_dring *next; /* Next dring overall */ } ldc_dring_t; /* * Channel specific information is kept in a separate * structure. These are then stored on a array indexed * by the channel number. */ struct ldc_chan { ldc_chan_t *next; /* Next channel */ kmutex_t lock; /* Channel lock */ uint64_t id; /* Channel ID */ ldc_status_t status; /* Channel status */ uint32_t tstate; /* Channel transport state */ uint32_t hstate; /* Channel transport handshake state */ ldc_dev_t devclass; /* Associated device class */ uint64_t devinst; /* Associated device instance */ ldc_mode_t mode; /* Channel mode */ uint64_t mtu; /* Max TU size */ ldc_ver_t version; /* Channel version */ uint32_t next_vidx; /* Next version to match */ uint_t (*cb)(uint64_t event, caddr_t arg); caddr_t cb_arg; /* Channel callback and arg */ boolean_t cb_inprogress; /* Channel callback in progress */ boolean_t cb_enabled; /* Channel callbacks are enabled */ uint8_t tx_intr_state; /* Tx interrupt state */ uint8_t rx_intr_state; /* Rx interrupt state */ kmutex_t tx_lock; /* Transmit lock */ uint64_t tx_q_entries; /* Num entries in transmit queue */ uint64_t tx_q_va; /* Virtual addr of transmit queue */ uint64_t tx_q_ra; /* Real addr of transmit queue */ uint64_t tx_head; /* Tx queue head */ uint64_t tx_ackd_head; /* Tx queue ACKd head (Reliable) */ uint64_t tx_tail; /* Tx queue tail */ uint64_t rx_q_entries; /* Num entries in receive queue */ uint64_t rx_q_va; /* Virtual addr of receive queue */ uint64_t rx_q_ra; /* Real addr of receive queue */ uint64_t rx_dq_entries; /* Num entries in the data queue */ uint64_t rx_dq_va; /* Virtual addr of the data queue */ uint64_t rx_dq_head; /* Receive data queue head */ uint64_t rx_dq_tail; /* Receive data queue tail */ uint64_t rx_ack_head; /* Receive data ACK peek head ptr */ uint64_t link_state; /* Underlying HV channel state */ ldc_mtbl_t *mtbl; /* Memory table used by channel */ ldc_mhdl_t *mhdl_list; /* List of memory handles */ kmutex_t mlist_lock; /* Mem handle list lock */ ldc_dring_t *exp_dring_list; /* Exported desc ring list */ kmutex_t exp_dlist_lock; /* Lock for exported desc ring list */ ldc_dring_t *imp_dring_list; /* Imported desc ring list */ kmutex_t imp_dlist_lock; /* Lock for imported desc ring list */ uint8_t pkt_payload; /* Size of packet payload */ uint32_t last_msg_snt; /* Seqid of last packet sent */ uint32_t last_ack_rcd; /* Seqid of last ACK recd */ uint32_t last_msg_rcd; /* Seqid of last packet received */ uint32_t stream_remains; /* Number of bytes in stream */ /* packet buffer */ uint32_t stream_offset; /* Offset into packet buffer for */ /* next read */ uint8_t *stream_bufferp; /* Stream packet buffer */ int (*read_p)(ldc_chan_t *ldcp, caddr_t bufferp, size_t *sizep); int (*write_p)(ldc_chan_t *ldcp, caddr_t bufferp, size_t *sizep); uint64_t (*readq_get_state)(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, uint64_t *link_state); int (*readq_set_head)(ldc_chan_t *ldcp, uint64_t head); }; /* * LDC module soft state structure */ typedef struct ldc_soft_state { kmutex_t lock; /* Protects ldc_soft_state_t */ ldc_cnex_t cinfo; /* channel nexus info */ uint64_t channel_count; /* Number of channels */ uint64_t channels_open; /* Number of open channels */ ldc_chan_t *chan_list; /* List of LDC endpoints */ ldc_dring_t *dring_list; /* Descriptor rings (for export) */ kmem_cache_t *memhdl_cache; /* Memory handle cache */ kmem_cache_t *memseg_cache; /* Memory segment cache */ } ldc_soft_state_t; /* * Debugging Utilities */ #define DBG_ALL_LDCS -1 #ifdef DEBUG #define D1 \ if (ldcdbg & 0x01) \ ldcdebug #define D2 \ if (ldcdbg & 0x02) \ ldcdebug #define DWARN \ if (ldcdbg & 0x04) \ ldcdebug #else #define D1 #define D2 #define DWARN #endif #ifdef __cplusplus } #endif #endif /* _LDC_IMPL_H */