summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIwona Winiarska <iwona.winiarska@intel.com>2020-12-04 03:16:27 +0300
committerIwona Winiarska <iwona.winiarska@intel.com>2020-12-17 12:19:12 +0300
commite25f94a28a950297018b3f4caebba41a60a46d61 (patch)
tree23224182b3a80679d87e6ca6a2f4affe0362503f
parentfca274838c6d6292851f327418cace93616b5ee0 (diff)
downloadlinux-e25f94a28a950297018b3f4caebba41a60a46d61.tar.xz
soc: aspeed: mctp: Expose internal kernel API
Some protocols that are already implemented in kernel can be encapsulated in MCTP packets. To allow use aspeed-mctp internally in kernel space, let's allow to use selected functions outside of aspeed-mctp. Change-Id: I543bfce975dfdd7cf8017899a139f69febbaca8d Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
-rw-r--r--drivers/soc/aspeed/aspeed-mctp.c101
-rw-r--r--include/linux/aspeed-mctp.h117
2 files changed, 179 insertions, 39 deletions
diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c
index 2f2e15a5258c..85aed4db13e7 100644
--- a/drivers/soc/aspeed/aspeed-mctp.c
+++ b/drivers/soc/aspeed/aspeed-mctp.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020, Intel Corporation.
+#include <linux/aspeed-mctp.h>
#include <linux/bitfield.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
@@ -142,20 +143,6 @@
#define PCIE_VDM_HDR_REQUESTER_BDF_DW 1
#define PCIE_VDM_HDR_REQUESTER_BDF_MASK GENMASK(31, 16)
-#define PCIE_VDM_HDR_SIZE_DW (ASPEED_MCTP_PCIE_VDM_HDR_SIZE / 4)
-#define PCIE_VDM_DATA_SIZE_DW (ASPEED_MCTP_MTU / 4)
-
-#define PCIE_MCTP_MIN_PACKET_SIZE (ASPEED_MCTP_PCIE_VDM_HDR_SIZE + 4)
-
-struct mctp_pcie_packet_data {
- u32 hdr[PCIE_VDM_HDR_SIZE_DW];
- u32 payload[PCIE_VDM_DATA_SIZE_DW];
-};
-
-struct mctp_pcie_packet {
- struct mctp_pcie_packet_data data;
- u32 size;
-};
struct aspeed_mctp_tx_cmd {
u32 tx_lo;
@@ -234,15 +221,17 @@ struct aspeed_mctp_endpoint {
struct kmem_cache *packet_cache;
-static void *packet_alloc(gfp_t flags)
+void *aspeed_mctp_packet_alloc(gfp_t flags)
{
return kmem_cache_alloc(packet_cache, flags);
}
+EXPORT_SYMBOL_GPL(aspeed_mctp_packet_alloc);
-static void packet_free(void *packet)
+void aspeed_mctp_packet_free(void *packet)
{
kmem_cache_free(packet_cache, packet);
}
+EXPORT_SYMBOL_GPL(aspeed_mctp_packet_free);
/*
* HW produces and expects VDM header in little endian and payload in network order.
@@ -336,8 +325,8 @@ static void aspeed_mctp_client_free(struct kref *ref)
{
struct mctp_client *client = container_of(ref, typeof(*client), ref);
- ptr_ring_cleanup(&client->rx_queue, &packet_free);
- ptr_ring_cleanup(&client->tx_queue, &packet_free);
+ ptr_ring_cleanup(&client->rx_queue, &aspeed_mctp_packet_free);
+ ptr_ring_cleanup(&client->tx_queue, &aspeed_mctp_packet_free);
kfree(client);
}
@@ -416,14 +405,14 @@ static void aspeed_mctp_dispatch_packet(struct aspeed_mctp *priv,
ret = ptr_ring_produce(&client->rx_queue, packet);
if (ret) {
dev_warn(priv->dev, "Failed to produce RX packet\n");
- packet_free(packet);
+ aspeed_mctp_packet_free(packet);
} else {
wake_up_all(&client->wait_queue);
}
aspeed_mctp_client_put(client);
} else {
dev_dbg(priv->dev, "Failed to dispatch RX packet\n");
- packet_free(packet);
+ aspeed_mctp_packet_free(packet);
}
}
@@ -457,7 +446,7 @@ static void aspeed_mctp_tx_tasklet(unsigned long data)
ptr_ring_consume(&client->tx_queue);
aspeed_mctp_emit_tx_cmd(tx, packet);
- packet_free(packet);
+ aspeed_mctp_packet_free(packet);
trigger = true;
}
}
@@ -485,7 +474,7 @@ static void aspeed_mctp_rx_tasklet(unsigned long data)
hdr = (u32 *)&rx_buf[rx->wr_ptr];
while (*hdr != 0) {
- rx_packet = packet_alloc(GFP_ATOMIC);
+ rx_packet = aspeed_mctp_packet_alloc(GFP_ATOMIC);
if (!rx_packet) {
dev_err(priv->dev, "Failed to allocate RX packet\n");
break;
@@ -538,7 +527,7 @@ static void aspeed_mctp_tx_chan_init(struct mctp_channel *tx)
regmap_write(priv->map, ASPEED_MCTP_TX_BUF_WR_PTR, 0);
}
-static struct mctp_client *aspeed_mctp_create_client(struct aspeed_mctp *priv)
+struct mctp_client *aspeed_mctp_create_client(struct aspeed_mctp *priv)
{
struct mctp_client *client;
@@ -564,6 +553,7 @@ static struct mctp_client *aspeed_mctp_create_client(struct aspeed_mctp *priv)
return client;
}
+EXPORT_SYMBOL_GPL(aspeed_mctp_create_client);
static int aspeed_mctp_open(struct inode *inode, struct file *file)
{
@@ -588,7 +578,7 @@ static int aspeed_mctp_open(struct inode *inode, struct file *file)
return 0;
}
-static void aspeed_mctp_delete_client(struct mctp_client *client)
+void aspeed_mctp_delete_client(struct mctp_client *client)
{
struct aspeed_mctp *priv = client->priv;
struct mctp_type_handler *handler, *tmp;
@@ -614,6 +604,7 @@ static void aspeed_mctp_delete_client(struct mctp_client *client)
aspeed_mctp_client_put(client);
local_bh_enable();
}
+EXPORT_SYMBOL_GPL(aspeed_mctp_delete_client);
static int aspeed_mctp_release(struct inode *inode, struct file *file)
{
@@ -624,6 +615,45 @@ static int aspeed_mctp_release(struct inode *inode, struct file *file)
return 0;
}
+int aspeed_mctp_write_packet(struct mctp_client *client,
+ struct mctp_pcie_packet *tx_packet)
+{
+ struct aspeed_mctp *priv = client->priv;
+ int ret;
+
+ if (priv->pcie.bdf == 0)
+ return -EIO;
+
+ be32p_replace_bits(&tx_packet->data.hdr[PCIE_VDM_HDR_REQUESTER_BDF_DW],
+ priv->pcie.bdf, PCIE_VDM_HDR_REQUESTER_BDF_MASK);
+
+ ret = ptr_ring_produce_bh(&client->tx_queue, tx_packet);
+ if (!ret)
+ tasklet_hi_schedule(&priv->tx.tasklet);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aspeed_mctp_write_packet);
+
+struct mctp_pcie_packet *aspeed_mctp_read_packet(struct mctp_client *client,
+ unsigned long timeout)
+{
+ struct aspeed_mctp *priv = client->priv;
+ int ret;
+
+ if (priv->pcie.bdf == 0)
+ return ERR_PTR(-EIO);
+
+ ret = wait_event_interruptible_timeout(client->wait_queue,
+ __ptr_ring_peek(&client->rx_queue),
+ timeout);
+ if (ret == 0)
+ return ERR_PTR(-EAGAIN);
+
+ return ptr_ring_consume_bh(&client->rx_queue);
+}
+EXPORT_SYMBOL_GPL(aspeed_mctp_read_packet);
+
static ssize_t aspeed_mctp_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -649,7 +679,7 @@ static ssize_t aspeed_mctp_read(struct file *file, char __user *buf,
count = -EFAULT;
}
- packet_free(rx_packet);
+ aspeed_mctp_packet_free(rx_packet);
return count;
}
@@ -668,10 +698,7 @@ static ssize_t aspeed_mctp_write(struct file *file, const char __user *buf,
if (count > sizeof(tx_packet->data))
return -ENOSPC;
- if (priv->pcie.bdf == 0)
- return -EIO;
-
- tx_packet = packet_alloc(GFP_KERNEL);
+ tx_packet = aspeed_mctp_packet_alloc(GFP_KERNEL);
if (!tx_packet) {
ret = -ENOMEM;
goto out;
@@ -682,28 +709,23 @@ static ssize_t aspeed_mctp_write(struct file *file, const char __user *buf,
ret = -EFAULT;
goto out_packet;
}
- tx_packet->size = count;
- be32p_replace_bits(&tx_packet->data.hdr[PCIE_VDM_HDR_REQUESTER_BDF_DW],
- priv->pcie.bdf, PCIE_VDM_HDR_REQUESTER_BDF_MASK);
+ tx_packet->size = count;
- ret = ptr_ring_produce_bh(&client->tx_queue, tx_packet);
+ ret = aspeed_mctp_write_packet(client, tx_packet);
if (ret)
goto out_packet;
- tasklet_hi_schedule(&priv->tx.tasklet);
-
return count;
out_packet:
- packet_free(tx_packet);
+ aspeed_mctp_packet_free(tx_packet);
out:
return ret;
}
-int aspeed_mctp_add_type_handler(struct mctp_client *client,
- u8 mctp_type, u16 pci_vendor_id,
- u16 vdm_type, u16 vdm_mask)
+int aspeed_mctp_add_type_handler(struct mctp_client *client, u8 mctp_type,
+ u16 pci_vendor_id, u16 vdm_type, u16 vdm_mask)
{
struct aspeed_mctp *priv = client->priv;
struct mctp_type_handler *handler, *new_handler;
@@ -747,6 +769,7 @@ out_unlock:
return ret;
}
+EXPORT_SYMBOL_GPL(aspeed_mctp_add_type_handler);
int aspeed_mctp_remove_type_handler(struct mctp_client *client,
u8 mctp_type, u16 pci_vendor_id,
diff --git a/include/linux/aspeed-mctp.h b/include/linux/aspeed-mctp.h
new file mode 100644
index 000000000000..3cfa8ca927ca
--- /dev/null
+++ b/include/linux/aspeed-mctp.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2020 Intel Corporation */
+
+#ifndef __LINUX_ASPEED_MCTP_H
+#define __LINUX_ASPEED_MCTP_H
+
+#include <linux/types.h>
+
+struct mctp_client;
+struct aspeed_mctp;
+
+struct pcie_transport_hdr {
+ u8 fmt_type;
+ u8 mbz;
+ u8 mbz_attr_len_hi;
+ u8 len_lo;
+ u16 requester;
+ u8 tag;
+ u8 code;
+ u16 target;
+ u16 vendor;
+} __packed;
+
+struct mctp_protocol_hdr {
+ u8 ver;
+ u8 dest;
+ u8 src;
+ u8 flags_seq_tag;
+} __packed;
+
+#define PCIE_VDM_HDR_SIZE 16
+#define MCTP_BTU_SIZE 64
+#define PCIE_VDM_DATA_SIZE_DW (MCTP_BTU_SIZE / 4)
+#define PCIE_VDM_HDR_SIZE_DW (PCIE_VDM_HDR_SIZE / 4)
+
+#define PCIE_MCTP_MIN_PACKET_SIZE (PCIE_VDM_HDR_SIZE + 4)
+
+struct mctp_pcie_packet_data {
+ u32 hdr[PCIE_VDM_HDR_SIZE_DW];
+ u32 payload[PCIE_VDM_DATA_SIZE_DW];
+};
+
+struct mctp_pcie_packet {
+ struct mctp_pcie_packet_data data;
+ u32 size;
+};
+
+/**
+ * aspeed_mctp_add_type_handler() - register for the given MCTP message type
+ * @client: pointer to the existing mctp_client context
+ * @mctp_type: message type code according to DMTF DSP0239 spec.
+ * @pci_vendor_id: vendor ID (non-zero if msg_type is Vendor Defined PCI,
+ * otherwise it should be set to 0)
+ * @vdm_type: vendor defined message type (it should be set to 0 for non-Vendor
+ * Defined PCI message type)
+ * @vdm_mask: vendor defined message mask (it should be set to 0 for non-Vendor
+ * Defined PCI message type)
+ *
+ * Return:
+ * * 0 - success,
+ * * -EINVAL - arguments passed are incorrect,
+ * * -ENOMEM - cannot alloc a new handler,
+ * * -EBUSY - given message has already registered handler.
+ */
+
+int aspeed_mctp_add_type_handler(struct mctp_client *client, u8 mctp_type,
+ u16 pci_vendor_id, u16 vdm_type, u16 vdm_mask);
+
+/**
+ * aspeed_mctp_create_client() - create mctp_client context
+ * @priv pointer to aspeed-mctp context
+ *
+ * Returns struct mctp_client or NULL.
+ */
+struct mctp_client *aspeed_mctp_create_client(struct aspeed_mctp *priv);
+
+/**
+ * aspeed_mctp_delete_client()- delete mctp_client context
+ * @client: pointer to existing mctp_client context
+ */
+void aspeed_mctp_delete_client(struct mctp_client *client);
+
+/**
+ * aspeed_mctp_write_packet() - send mctp_packet
+ * @client: pointer to existing mctp_client context
+ * @tx_packet: the allocated packet that needs to be send via aspeed-mctp
+ *
+ * After the function returns success, the packet is no longer owned by the
+ * caller, and as such, the caller should not attempt to free it.
+ *
+ * Return:
+ * * 0 - success,
+ * * -ENOSPC - failed to send packet due to lack of available space.
+ */
+int aspeed_mctp_write_packet(struct mctp_client *client,
+ struct mctp_pcie_packet *tx_packet);
+
+/**
+ * aspeed_mctp_read_packet() - receive mctp_packet
+ * @client: pointer to existing mctp_client context
+ * @timeout: timeout, in jiffies
+ *
+ * The function will sleep for up to @timeout if no packet is ready to read.
+ *
+ * After the function returns valid packet, the caller takes its ownership and
+ * is responsible for freeing it.
+ *
+ * Returns struct mctp_pcie_packet from or ERR_PTR in case of error or the
+ * @timeout elapsed.
+ */
+struct mctp_pcie_packet *aspeed_mctp_read_packet(struct mctp_client *client,
+ unsigned long timeout);
+
+void *aspeed_mctp_packet_alloc(gfp_t flags);
+void aspeed_mctp_packet_free(void *packet);
+
+#endif /* __LINUX_ASPEED_MCTP_H */