summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIwona Winiarska <iwona.winiarska@intel.com>2020-12-04 03:13:12 +0300
committerIwona Winiarska <iwona.winiarska@intel.com>2020-12-17 12:00:34 +0300
commitfca274838c6d6292851f327418cace93616b5ee0 (patch)
tree6a528ba521d3bb325ff708189c76b34701bd7420
parentec06446ae64ec6dc05609ddab456be9c22bf30b0 (diff)
downloadlinux-fca274838c6d6292851f327418cace93616b5ee0.tar.xz
soc: aspeed: mctp: Fix header swapping consistency
Right now, TX ring contains packets with PCIe header already swapped to little endian (byte order expected by HW), while RX ring contains packets with PCIe header already swapped to network order (expected by userspace). Let's keep TX packets in network order and swap before write to HW buffer. To make it more readable, let's extract swapping into a helper function. Change-Id: I6c69ad9b3c9f68b2ef416eaf9259798cf011b8c4 Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
-rw-r--r--drivers/soc/aspeed/aspeed-mctp.c47
1 files changed, 23 insertions, 24 deletions
diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c
index 3fb0c8c8f6f1..2f2e15a5258c 100644
--- a/drivers/soc/aspeed/aspeed-mctp.c
+++ b/drivers/soc/aspeed/aspeed-mctp.c
@@ -244,6 +244,19 @@ static void packet_free(void *packet)
kmem_cache_free(packet_cache, packet);
}
+/*
+ * HW produces and expects VDM header in little endian and payload in network order.
+ * To allow userspace to use network order for the whole packet, PCIe VDM header needs
+ * to be swapped.
+ */
+static void aspeed_mctp_swap_pcie_vdm_hdr(struct mctp_pcie_packet_data *data)
+{
+ int i;
+
+ for (i = 0; i < PCIE_VDM_HDR_SIZE_DW; i++)
+ data->hdr[i] = swab32(data->hdr[i]);
+}
+
static void aspeed_mctp_rx_trigger(struct mctp_channel *rx)
{
struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx);
@@ -290,6 +303,8 @@ static void aspeed_mctp_emit_tx_cmd(struct mctp_channel *tx,
sizeof(packet->data.hdr) / sizeof(u32);
u32 offset = tx->wr_ptr * sizeof(packet->data);
+ aspeed_mctp_swap_pcie_vdm_hdr(&packet->data);
+
memcpy((u8 *)tx->data.vaddr + offset, &packet->data,
sizeof(packet->data));
@@ -459,7 +474,6 @@ static void aspeed_mctp_rx_tasklet(unsigned long data)
struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx);
struct mctp_pcie_packet *rx_packet;
struct mctp_pcie_packet_data *rx_buf;
- int i;
u32 *hdr;
/*
@@ -476,15 +490,10 @@ static void aspeed_mctp_rx_tasklet(unsigned long data)
dev_err(priv->dev, "Failed to allocate RX packet\n");
break;
}
- /*
- * XXX: HW outputs VDM header in little endian, swap to present
- * the whole packet to userspace in network order
- */
- for (i = 0; i < PCIE_VDM_HDR_SIZE_DW; i++)
- rx_packet->data.hdr[i] = swab32(hdr[i]);
- memcpy(&rx_packet->data.payload, hdr + PCIE_VDM_HDR_SIZE_DW,
- sizeof(rx_packet->data) - sizeof(rx_packet->data.hdr));
+ memcpy(&rx_packet->data, hdr, sizeof(rx_packet->data));
+
+ aspeed_mctp_swap_pcie_vdm_hdr(&rx_packet->data);
*hdr = 0;
rx->wr_ptr = (rx->wr_ptr + 1) % RX_PACKET_COUNT;
@@ -621,7 +630,6 @@ static ssize_t aspeed_mctp_read(struct file *file, char __user *buf,
struct mctp_client *client = file->private_data;
struct aspeed_mctp *priv = client->priv;
struct mctp_pcie_packet *rx_packet;
- size_t packet_sz = sizeof(rx_packet->data);
if (count < PCIE_MCTP_MIN_PACKET_SIZE)
return -EINVAL;
@@ -629,8 +637,8 @@ static ssize_t aspeed_mctp_read(struct file *file, char __user *buf,
if (priv->pcie.bdf == 0)
return -EIO;
- if (count > packet_sz)
- count = packet_sz;
+ if (count > sizeof(rx_packet->data))
+ count = sizeof(rx_packet->data);
rx_packet = ptr_ring_consume_bh(&client->rx_queue);
if (!rx_packet)
@@ -652,8 +660,7 @@ static ssize_t aspeed_mctp_write(struct file *file, const char __user *buf,
struct mctp_client *client = file->private_data;
struct aspeed_mctp *priv = client->priv;
struct mctp_pcie_packet *tx_packet;
- u16 bdf = priv->pcie.bdf;
- int ret, i;
+ int ret;
if (count < PCIE_MCTP_MIN_PACKET_SIZE)
return -EINVAL;
@@ -661,7 +668,7 @@ static ssize_t aspeed_mctp_write(struct file *file, const char __user *buf,
if (count > sizeof(tx_packet->data))
return -ENOSPC;
- if (bdf == 0)
+ if (priv->pcie.bdf == 0)
return -EIO;
tx_packet = packet_alloc(GFP_KERNEL);
@@ -677,16 +684,8 @@ static ssize_t aspeed_mctp_write(struct file *file, const char __user *buf,
}
tx_packet->size = count;
- /* Update PCIE header with requester BDF */
be32p_replace_bits(&tx_packet->data.hdr[PCIE_VDM_HDR_REQUESTER_BDF_DW],
- bdf, PCIE_VDM_HDR_REQUESTER_BDF_MASK);
-
- /*
- * XXX: HW expects VDM header in little endian, swap to let
- * userspace use network order for the whole packet
- */
- for (i = 0; i < PCIE_VDM_HDR_SIZE_DW; i++)
- tx_packet->data.hdr[i] = swab32(tx_packet->data.hdr[i]);
+ priv->pcie.bdf, PCIE_VDM_HDR_REQUESTER_BDF_MASK);
ret = ptr_ring_produce_bh(&client->tx_queue, tx_packet);
if (ret)