| /* |
| * Intel MIC Platform Software Stack (MPSS) |
| * |
| * Copyright(c) 2014 Intel Corporation. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License, version 2, as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * Intel SCIF driver. |
| * |
| */ |
| #ifndef SCIF_MAIN_H |
| #define SCIF_MAIN_H |
| |
| #include <linux/sched.h> |
| #include <linux/pci.h> |
| #include <linux/miscdevice.h> |
| #include <linux/dmaengine.h> |
| #include <linux/file.h> |
| #include <linux/scif.h> |
| |
| #include "../common/mic_dev.h" |
| |
| #define SCIF_MGMT_NODE 0 |
| #define SCIF_DEFAULT_WATCHDOG_TO 30 |
| #define SCIF_NODE_ACCEPT_TIMEOUT (3 * HZ) |
| #define SCIF_NODE_ALIVE_TIMEOUT (SCIF_DEFAULT_WATCHDOG_TO * HZ) |
| |
| /* |
| * Generic state used for certain node QP message exchanges |
| * like Unregister, Alloc etc. |
| */ |
| enum scif_msg_state { |
| OP_IDLE = 1, |
| OP_IN_PROGRESS, |
| OP_COMPLETED, |
| OP_FAILED |
| }; |
| |
| /* |
| * struct scif_info - Global SCIF information |
| * |
| * @nodeid: Node ID this node is to others |
| * @maxid: Max known node ID |
| * @total: Total number of SCIF nodes |
| * @nr_zombies: number of zombie endpoints |
| * @eplock: Lock to synchronize listening, zombie endpoint lists |
| * @connlock: Lock to synchronize connected and disconnected lists |
| * @nb_connect_lock: Synchronize non blocking connect operations |
| * @port_lock: Synchronize access to SCIF ports |
| * @uaccept: List of user acceptreq waiting for acceptreg |
| * @listen: List of listening end points |
| * @zombie: List of zombie end points with pending RMA's |
| * @connected: List of end points in connected state |
| * @disconnected: List of end points in disconnected state |
| * @nb_connect_list: List for non blocking connections |
| * @misc_work: miscellaneous SCIF tasks |
| * @conflock: Lock to synchronize SCIF node configuration changes |
| * @en_msg_log: Enable debug message logging |
| * @p2p_enable: Enable P2P SCIF network |
| * @mdev: The MISC device |
| * @conn_work: Work for workqueue handling all connections |
| * @exitwq: Wait queue for waiting for an EXIT node QP message response |
| * @loopb_dev: Dummy SCIF device used for loopback |
| * @loopb_wq: Workqueue used for handling loopback messages |
| * @loopb_wqname[16]: Name of loopback workqueue |
| * @loopb_work: Used for submitting work to loopb_wq |
| * @loopb_recv_q: List of messages received on the loopb_wq |
| * @card_initiated_exit: set when the card has initiated the exit |
| */ |
| struct scif_info { |
| u8 nodeid; |
| u8 maxid; |
| u8 total; |
| u32 nr_zombies; |
| spinlock_t eplock; |
| struct mutex connlock; |
| spinlock_t nb_connect_lock; |
| spinlock_t port_lock; |
| struct list_head uaccept; |
| struct list_head listen; |
| struct list_head zombie; |
| struct list_head connected; |
| struct list_head disconnected; |
| struct list_head nb_connect_list; |
| struct work_struct misc_work; |
| struct mutex conflock; |
| u8 en_msg_log; |
| u8 p2p_enable; |
| struct miscdevice mdev; |
| struct work_struct conn_work; |
| wait_queue_head_t exitwq; |
| struct scif_dev *loopb_dev; |
| struct workqueue_struct *loopb_wq; |
| char loopb_wqname[16]; |
| struct work_struct loopb_work; |
| struct list_head loopb_recv_q; |
| bool card_initiated_exit; |
| }; |
| |
| /* |
| * struct scif_p2p_info - SCIF mapping information used for P2P |
| * |
| * @ppi_peer_id - SCIF peer node id |
| * @ppi_sg - Scatter list for bar information (One for mmio and one for aper) |
| * @sg_nentries - Number of entries in the scatterlist |
| * @ppi_da: DMA address for MMIO and APER bars |
| * @ppi_len: Length of MMIO and APER bars |
| * @ppi_list: Link in list of mapping information |
| */ |
| struct scif_p2p_info { |
| u8 ppi_peer_id; |
| struct scatterlist *ppi_sg[2]; |
| u64 sg_nentries[2]; |
| dma_addr_t ppi_da[2]; |
| u64 ppi_len[2]; |
| #define SCIF_PPI_MMIO 0 |
| #define SCIF_PPI_APER 1 |
| struct list_head ppi_list; |
| }; |
| |
| /* |
| * struct scif_dev - SCIF remote device specific fields |
| * |
| * @node: Node id |
| * @p2p: List of P2P mapping information |
| * @qpairs: The node queue pair for exchanging control messages |
| * @intr_wq: Workqueue for handling Node QP messages |
| * @intr_wqname: Name of node QP workqueue for handling interrupts |
| * @intr_bh: Used for submitting work to intr_wq |
| * @lock: Lock used for synchronizing access to the scif device |
| * @sdev: SCIF hardware device on the SCIF hardware bus |
| * @db: doorbell the peer will trigger to generate an interrupt on self |
| * @rdb: Doorbell to trigger on the peer to generate an interrupt on the peer |
| * @cookie: Cookie received while registering the interrupt handler |
| * init_msg_work: work scheduled for SCIF_INIT message processing |
| * @p2p_dwork: Delayed work to enable polling for P2P state |
| * @qp_dwork: Delayed work for enabling polling for remote QP information |
| * @p2p_retry: Number of times to retry polling of P2P state |
| * @base_addr: P2P aperture bar base address |
| * @mic_mw mmio: The peer MMIO information used for P2P |
| * @spdev: SCIF peer device on the SCIF peer bus |
| * @node_remove_ack_pending: True if a node_remove_ack is pending |
| * @exit_ack_pending: true if an exit_ack is pending |
| * @disconn_wq: Used while waiting for a node remove response |
| * @disconn_rescnt: Keeps track of number of node remove requests sent |
| * @exit: Status of exit message |
| * @qp_dma_addr: Queue pair DMA address passed to the peer |
| */ |
| struct scif_dev { |
| u8 node; |
| struct list_head p2p; |
| struct scif_qp *qpairs; |
| struct workqueue_struct *intr_wq; |
| char intr_wqname[16]; |
| struct work_struct intr_bh; |
| struct mutex lock; |
| struct scif_hw_dev *sdev; |
| int db; |
| int rdb; |
| struct mic_irq *cookie; |
| struct work_struct init_msg_work; |
| struct delayed_work p2p_dwork; |
| struct delayed_work qp_dwork; |
| int p2p_retry; |
| dma_addr_t base_addr; |
| struct mic_mw mmio; |
| struct scif_peer_dev __rcu *spdev; |
| bool node_remove_ack_pending; |
| bool exit_ack_pending; |
| wait_queue_head_t disconn_wq; |
| atomic_t disconn_rescnt; |
| enum scif_msg_state exit; |
| dma_addr_t qp_dma_addr; |
| }; |
| |
| extern struct scif_info scif_info; |
| extern struct idr scif_ports; |
| extern struct scif_dev *scif_dev; |
| extern const struct file_operations scif_fops; |
| |
| /* Size of the RB for the Node QP */ |
| #define SCIF_NODE_QP_SIZE 0x10000 |
| |
| #include "scif_nodeqp.h" |
| |
| /* |
| * scifdev_self: |
| * @dev: The remote SCIF Device |
| * |
| * Returns true if the SCIF Device passed is the self aka Loopback SCIF device. |
| */ |
| static inline int scifdev_self(struct scif_dev *dev) |
| { |
| return dev->node == scif_info.nodeid; |
| } |
| |
| static inline bool scif_is_mgmt_node(void) |
| { |
| return !scif_info.nodeid; |
| } |
| |
| /* |
| * scifdev_is_p2p: |
| * @dev: The remote SCIF Device |
| * |
| * Returns true if the SCIF Device is a MIC Peer to Peer SCIF device. |
| */ |
| static inline bool scifdev_is_p2p(struct scif_dev *dev) |
| { |
| if (scif_is_mgmt_node()) |
| return false; |
| else |
| return dev != &scif_dev[SCIF_MGMT_NODE] && |
| !scifdev_self(dev); |
| } |
| |
| /* |
| * scifdev_alive: |
| * @scifdev: The remote SCIF Device |
| * |
| * Returns true if the remote SCIF Device is running or sleeping for |
| * this endpoint. |
| */ |
| static inline int _scifdev_alive(struct scif_dev *scifdev) |
| { |
| struct scif_peer_dev *spdev; |
| |
| rcu_read_lock(); |
| spdev = rcu_dereference(scifdev->spdev); |
| rcu_read_unlock(); |
| return !!spdev; |
| } |
| |
| #include "scif_epd.h" |
| |
| void __init scif_init_debugfs(void); |
| void scif_exit_debugfs(void); |
| int scif_setup_intr_wq(struct scif_dev *scifdev); |
| void scif_destroy_intr_wq(struct scif_dev *scifdev); |
| void scif_cleanup_scifdev(struct scif_dev *dev); |
| void scif_handle_remove_node(int node); |
| void scif_disconnect_node(u32 node_id, bool mgmt_initiated); |
| void scif_free_qp(struct scif_dev *dev); |
| void scif_misc_handler(struct work_struct *work); |
| void scif_stop(struct scif_dev *scifdev); |
| irqreturn_t scif_intr_handler(int irq, void *data); |
| #endif /* SCIF_MAIN_H */ |