Commit 40cb5942 authored by Sudeep Dutt's avatar Sudeep Dutt Committed by Greg Kroah-Hartman

misc: mic: SCIF node queue pair setup management

SCIF node queue pair setup creates the SCIF driver kernel
mode private node queue pairs between all the nodes to enable
internal control message communication once SCIF gets probed
by the SCIF hardware bus. Peer to peer communication between
MIC Coprocessor nodes is supported.
Reviewed-by: default avatarNikhil Rao <nikhil.rao@intel.com>
Reviewed-by: default avatarAshutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: default avatarSudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fb4d0e3d
/*
* 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.
*
*/
#include "scif_peer_bus.h"
#include "scif_main.h"
#include "scif_map.h"
void scif_free_qp(struct scif_dev *scifdev)
{
struct scif_qp *qp = scifdev->qpairs;
if (!qp)
return;
scif_free_coherent((void *)qp->inbound_q.rb_base,
qp->local_buf, scifdev, qp->inbound_q.size);
scif_unmap_single(qp->local_qp, scifdev, sizeof(struct scif_qp));
kfree(scifdev->qpairs);
scifdev->qpairs = NULL;
}
static void scif_cleanup_qp(struct scif_dev *dev)
{
struct scif_qp *qp = &dev->qpairs[0];
if (!qp)
return;
scif_iounmap((void *)qp->remote_qp, sizeof(struct scif_qp), dev);
scif_iounmap((void *)qp->outbound_q.rb_base,
sizeof(struct scif_qp), dev);
qp->remote_qp = NULL;
qp->local_write = 0;
qp->inbound_q.current_write_offset = 0;
qp->inbound_q.current_read_offset = 0;
if (scifdev_is_p2p(dev))
scif_free_qp(dev);
}
void scif_send_acks(struct scif_dev *dev)
{
struct scifmsg msg;
if (dev->node_remove_ack_pending) {
msg.uop = SCIF_NODE_REMOVE_ACK;
msg.src.node = scif_info.nodeid;
msg.dst.node = SCIF_MGMT_NODE;
msg.payload[0] = dev->node;
scif_nodeqp_send(&scif_dev[SCIF_MGMT_NODE], &msg);
dev->node_remove_ack_pending = false;
}
if (dev->exit_ack_pending) {
msg.uop = SCIF_EXIT_ACK;
msg.src.node = scif_info.nodeid;
msg.dst.node = dev->node;
scif_nodeqp_send(dev, &msg);
dev->exit_ack_pending = false;
}
}
/*
* scif_cleanup_scifdev
*
* @dev: Remote SCIF device.
* Uninitialize SCIF data structures for remote SCIF device.
*/
void scif_cleanup_scifdev(struct scif_dev *dev)
{
struct scif_hw_dev *sdev = dev->sdev;
if (!dev->sdev)
return;
if (scifdev_is_p2p(dev)) {
if (dev->cookie) {
sdev->hw_ops->free_irq(sdev, dev->cookie, dev);
dev->cookie = NULL;
}
scif_destroy_intr_wq(dev);
}
scif_destroy_p2p(dev);
scif_send_acks(dev);
if (!dev->node && scif_info.card_initiated_exit) {
/*
* Send an SCIF_EXIT message which is the last message from MIC
* to the Host and wait for a SCIF_EXIT_ACK
*/
scif_send_exit(dev);
scif_info.card_initiated_exit = false;
}
scif_cleanup_qp(dev);
}
/*
* scif_remove_node:
*
* @node: Node to remove
*/
void scif_handle_remove_node(int node)
{
struct scif_dev *scifdev = &scif_dev[node];
struct scif_peer_dev *spdev;
rcu_read_lock();
spdev = rcu_dereference(scifdev->spdev);
rcu_read_unlock();
if (spdev)
scif_peer_unregister_device(spdev);
else
scif_send_acks(scifdev);
}
static int scif_send_rmnode_msg(int node, int remove_node)
{
struct scifmsg notif_msg;
struct scif_dev *dev = &scif_dev[node];
notif_msg.uop = SCIF_NODE_REMOVE;
notif_msg.src.node = scif_info.nodeid;
notif_msg.dst.node = node;
notif_msg.payload[0] = remove_node;
return scif_nodeqp_send(dev, &notif_msg);
}
/**
* scif_node_disconnect:
*
* @node_id[in]: source node id.
* @mgmt_initiated: Disconnection initiated from the mgmt node
*
* Disconnect a node from the scif network.
*/
void scif_disconnect_node(u32 node_id, bool mgmt_initiated)
{
int ret;
int msg_cnt = 0;
u32 i = 0;
struct scif_dev *scifdev = &scif_dev[node_id];
if (!node_id)
return;
atomic_set(&scifdev->disconn_rescnt, 0);
/* Destroy p2p network */
for (i = 1; i <= scif_info.maxid; i++) {
if (i == node_id)
continue;
ret = scif_send_rmnode_msg(i, node_id);
if (!ret)
msg_cnt++;
}
/* Wait for the remote nodes to respond with SCIF_NODE_REMOVE_ACK */
ret = wait_event_timeout(scifdev->disconn_wq,
(atomic_read(&scifdev->disconn_rescnt)
== msg_cnt), SCIF_NODE_ALIVE_TIMEOUT);
/* Tell the card to clean up */
if (mgmt_initiated && _scifdev_alive(scifdev))
/*
* Send an SCIF_EXIT message which is the last message from Host
* to the MIC and wait for a SCIF_EXIT_ACK
*/
scif_send_exit(scifdev);
atomic_set(&scifdev->disconn_rescnt, 0);
/* Tell the mgmt node to clean up */
ret = scif_send_rmnode_msg(SCIF_MGMT_NODE, node_id);
if (!ret)
/* Wait for mgmt node to respond with SCIF_NODE_REMOVE_ACK */
wait_event_timeout(scifdev->disconn_wq,
(atomic_read(&scifdev->disconn_rescnt) == 1),
SCIF_NODE_ALIVE_TIMEOUT);
}
This diff is collapsed.
/*
* Intel MIC Platform Software Stack (MPSS)
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License 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.
*
* BSD LICENSE
*
* Copyright(c) 2014 Intel Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Intel SCIF driver.
*
*/
#ifndef SCIF_NODEQP
#define SCIF_NODEQP
#include "scif_rb.h"
#include "scif_peer_bus.h"
#define SCIF_INIT 1 /* First message sent to the peer node for discovery */
#define SCIF_EXIT 2 /* Last message from the peer informing intent to exit */
#define SCIF_EXIT_ACK 3 /* Response to SCIF_EXIT message */
#define SCIF_NODE_ADD 4 /* Tell Online nodes a new node exits */
#define SCIF_NODE_ADD_ACK 5 /* Confirm to mgmt node sequence is finished */
#define SCIF_NODE_ADD_NACK 6 /* SCIF_NODE_ADD failed */
#define SCIF_NODE_REMOVE 7 /* Request to deactivate a SCIF node */
#define SCIF_NODE_REMOVE_ACK 8 /* Response to a SCIF_NODE_REMOVE message */
#define SCIF_MAX_MSG SCIF_NODE_REMOVE_ACK
/*
* struct scifmsg - Node QP message format
*
* @src: Source information
* @dst: Destination information
* @uop: The message opcode
* @payload: Unique payload format for each message
*/
struct scifmsg {
struct scif_port_id src;
struct scif_port_id dst;
u32 uop;
u64 payload[4];
} __packed;
/*
* struct scif_qp - Node Queue Pair
*
* Interesting structure -- a little difficult because we can only
* write across the PCIe, so any r/w pointer we need to read is
* local. We only need to read the read pointer on the inbound_q
* and read the write pointer in the outbound_q
*
* @magic: Magic value to ensure the peer sees the QP correctly
* @outbound_q: The outbound ring buffer for sending messages
* @inbound_q: The inbound ring buffer for receiving messages
* @local_write: Local write index
* @local_read: Local read index
* @remote_qp: The remote queue pair
* @local_buf: DMA address of local ring buffer
* @local_qp: DMA address of the local queue pair data structure
* @remote_buf: DMA address of remote ring buffer
* @qp_state: QP state i.e. online or offline used for P2P
* @send_lock: synchronize access to outbound queue
* @recv_lock: Synchronize access to inbound queue
*/
struct scif_qp {
u64 magic;
#define SCIFEP_MAGIC 0x5c1f000000005c1fULL
struct scif_rb outbound_q;
struct scif_rb inbound_q;
u32 local_write __aligned(64);
u32 local_read __aligned(64);
struct scif_qp *remote_qp;
dma_addr_t local_buf;
dma_addr_t local_qp;
dma_addr_t remote_buf;
u32 qp_state;
#define SCIF_QP_OFFLINE 0xdead
#define SCIF_QP_ONLINE 0xc0de
spinlock_t send_lock;
spinlock_t recv_lock;
};
/*
* struct scif_loopb_msg - An element in the loopback Node QP message list.
*
* @msg - The SCIF node QP message
* @list - link in the list of messages
*/
struct scif_loopb_msg {
struct scifmsg msg;
struct list_head list;
};
int scif_nodeqp_send(struct scif_dev *scifdev, struct scifmsg *msg);
int _scif_nodeqp_send(struct scif_dev *scifdev, struct scifmsg *msg);
void scif_nodeqp_intrhandler(struct scif_dev *scifdev, struct scif_qp *qp);
int scif_loopb_msg_handler(struct scif_dev *scifdev, struct scif_qp *qp);
int scif_setup_qp(struct scif_dev *scifdev);
int scif_qp_response(phys_addr_t phys, struct scif_dev *dev);
int scif_setup_qp_connect(struct scif_qp *qp, dma_addr_t *qp_offset,
int local_size, struct scif_dev *scifdev);
int scif_setup_qp_accept(struct scif_qp *qp, dma_addr_t *qp_offset,
dma_addr_t phys, int local_size,
struct scif_dev *scifdev);
int scif_setup_qp_connect_response(struct scif_dev *scifdev,
struct scif_qp *qp, u64 payload);
int scif_setup_loopback_qp(struct scif_dev *scifdev);
int scif_destroy_loopback_qp(struct scif_dev *scifdev);
void scif_poll_qp_state(struct work_struct *work);
void scif_qp_response_ack(struct work_struct *work);
void scif_destroy_p2p(struct scif_dev *scifdev);
void scif_send_exit(struct scif_dev *scifdev);
static inline struct device *scif_get_peer_dev(struct scif_dev *scifdev)
{
struct scif_peer_dev *spdev;
struct device *spdev_ret;
rcu_read_lock();
spdev = rcu_dereference(scifdev->spdev);
if (spdev)
spdev_ret = get_device(&spdev->dev);
else
spdev_ret = ERR_PTR(-ENODEV);
rcu_read_unlock();
return spdev_ret;
}
static inline void scif_put_peer_dev(struct device *dev)
{
put_device(dev);
}
#endif /* SCIF_NODEQP */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment