Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ccee4bd authored by Sneh Shah's avatar Sneh Shah Committed by Gerrit - the friendly Code Review server
Browse files

net: stmmac: Add support for smmu enablement



Add smmu enablement and smmu mapping for ethernet.

Change-Id: I4cc2a1834cdeb9adf25a735bf41197be70a29a3b
Signed-off-by: default avatarSneh Shah <snehshah@codeaurora.org>
parent b889587c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -43,10 +43,10 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)

	len = nopaged_len - bmax;

	des2 = dma_map_single(priv->device, skb->data,
	des2 = dma_map_single(GET_MEM_PDEV_DEV, skb->data,
			      bmax, DMA_TO_DEVICE);
	desc->des2 = cpu_to_le32(des2);
	if (dma_mapping_error(priv->device, des2))
	if (dma_mapping_error(GET_MEM_PDEV_DEV, des2))
		return -1;
	tx_q->tx_skbuff_dma[entry].buf = des2;
	tx_q->tx_skbuff_dma[entry].len = bmax;
+136 −5
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/debugfs.h>
#include <asm/dma-iommu.h>
#include <linux/iommu.h>


#include "stmmac.h"
#include "stmmac_platform.h"
@@ -100,6 +103,7 @@
bool phy_intr_en;

struct qcom_ethqos *pethqos;
struct emac_emb_smmu_cb_ctx emac_emb_smmu_ctx = {0};

void *ipc_emac_log_ctxt;

@@ -600,6 +604,12 @@ static void ethqos_pps_irq_config(struct qcom_ethqos *ethqos)
	}
}

static const struct of_device_id qcom_ethqos_match[] = {
	{ .compatible = "qcom,sdxprairie-ethqos", .data = &emac_v2_3_2_por},
	{ .compatible = "qcom,emac-smmu-embedded", },
	{ }
};

static ssize_t read_phy_reg_dump(struct file *file, char __user *user_buf,
				 size_t count, loff_t *ppos)
{
@@ -766,6 +776,114 @@ static int ethqos_create_debugfs(struct qcom_ethqos *ethqos)
	debugfs_remove_recursive(ethqos->debugfs_dir);
	return -ENOMEM;
}

static void emac_emb_smmu_exit(void)
{
	if (emac_emb_smmu_ctx.valid) {
		if (emac_emb_smmu_ctx.smmu_pdev)
			arm_iommu_detach_device
			(&emac_emb_smmu_ctx.smmu_pdev->dev);
		if (emac_emb_smmu_ctx.mapping)
			arm_iommu_release_mapping(emac_emb_smmu_ctx.mapping);
		emac_emb_smmu_ctx.valid = false;
		emac_emb_smmu_ctx.mapping = NULL;
		emac_emb_smmu_ctx.pdev_master = NULL;
		emac_emb_smmu_ctx.smmu_pdev = NULL;
	}
}

static int emac_emb_smmu_cb_probe(struct platform_device *pdev)
{
	int result;
	u32 iova_ap_mapping[2];
	struct device *dev = &pdev->dev;
	int atomic_ctx = 1;
	int fast = 1;
	int bypass = 1;

	ETHQOSDBG("EMAC EMB SMMU CB probe: smmu pdev=%p\n", pdev);

	result = of_property_read_u32_array(dev->of_node, "qcom,iova-mapping",
					    iova_ap_mapping, 2);
	if (result) {
		ETHQOSERR("Failed to read EMB start/size iova addresses\n");
		return result;
	}
	emac_emb_smmu_ctx.va_start = iova_ap_mapping[0];
	emac_emb_smmu_ctx.va_size = iova_ap_mapping[1];
	emac_emb_smmu_ctx.va_end = emac_emb_smmu_ctx.va_start +
				   emac_emb_smmu_ctx.va_size;

	emac_emb_smmu_ctx.smmu_pdev = pdev;

	if (dma_set_mask(dev, DMA_BIT_MASK(32)) ||
	    dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
		ETHQOSERR("DMA set 32bit mask failed\n");
		return -EOPNOTSUPP;
	}

	emac_emb_smmu_ctx.mapping = arm_iommu_create_mapping
	(dev->bus, emac_emb_smmu_ctx.va_start, emac_emb_smmu_ctx.va_size);
	if (IS_ERR_OR_NULL(emac_emb_smmu_ctx.mapping)) {
		ETHQOSDBG("Fail to create mapping\n");
		/* assume this failure is because iommu driver is not ready */
		return -EPROBE_DEFER;
	}
	ETHQOSDBG("Successfully Created SMMU mapping\n");
	emac_emb_smmu_ctx.valid = true;

	if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass")) {
		if (iommu_domain_set_attr(emac_emb_smmu_ctx.mapping->domain,
					  DOMAIN_ATTR_S1_BYPASS,
					  &bypass)) {
			ETHQOSERR("Couldn't set SMMU S1 bypass\n");
			result = -EIO;
			goto err_smmu_probe;
		}
		ETHQOSDBG("SMMU S1 BYPASS set\n");
	} else {
		if (iommu_domain_set_attr(emac_emb_smmu_ctx.mapping->domain,
					  DOMAIN_ATTR_ATOMIC,
					  &atomic_ctx)) {
			ETHQOSERR("Couldn't set SMMU domain as atomic\n");
			result = -EIO;
			goto err_smmu_probe;
		}
		ETHQOSDBG("SMMU atomic set\n");
		if (iommu_domain_set_attr(emac_emb_smmu_ctx.mapping->domain,
					  DOMAIN_ATTR_FAST,
					  &fast)) {
			ETHQOSERR("Couldn't set FAST SMMU\n");
			result = -EIO;
			goto err_smmu_probe;
		}
		ETHQOSDBG("SMMU fast map set\n");
	}

	result = arm_iommu_attach_device(&emac_emb_smmu_ctx.smmu_pdev->dev,
					 emac_emb_smmu_ctx.mapping);
	if (result) {
		ETHQOSERR("couldn't attach to IOMMU ret=%d\n", result);
		goto err_smmu_probe;
	}

	emac_emb_smmu_ctx.iommu_domain =
		iommu_get_domain_for_dev(&emac_emb_smmu_ctx.smmu_pdev->dev);

	ETHQOSDBG("Successfully attached to IOMMU\n");
	if (emac_emb_smmu_ctx.pdev_master)
		goto smmu_probe_done;

err_smmu_probe:
	if (emac_emb_smmu_ctx.mapping)
		arm_iommu_release_mapping(emac_emb_smmu_ctx.mapping);
	emac_emb_smmu_ctx.valid = false;

smmu_probe_done:
	emac_emb_smmu_ctx.ret = result;
	return result;
}

static int qcom_ethqos_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
@@ -781,6 +899,9 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
		ETHQOSERR("Error creating logging context for emac\n");
	else
		ETHQOSDBG("IPC logging has been enabled for emac\n");
	if (of_device_is_compatible(pdev->dev.of_node,
				    "qcom,emac-smmu-embedded"))
		return emac_emb_smmu_cb_probe(pdev);
	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
	if (ret)
		return ret;
@@ -832,6 +953,20 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
	plat_dat->pmt = 1;
	plat_dat->tso_en = of_property_read_bool(np, "snps,tso");

	if (of_property_read_bool(pdev->dev.of_node, "qcom,arm-smmu")) {
		emac_emb_smmu_ctx.pdev_master = pdev;
		ret = of_platform_populate(pdev->dev.of_node,
					   qcom_ethqos_match, NULL, &pdev->dev);
		if (ret)
			ETHQOSERR("Failed to populate EMAC platform\n");
		if (emac_emb_smmu_ctx.ret) {
			ETHQOSERR("smmu probe failed\n");
			of_platform_depopulate(&pdev->dev);
			ret = emac_emb_smmu_ctx.ret;
			emac_emb_smmu_ctx.ret = 0;
		}
	}

	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
	if (ret)
		goto err_clk;
@@ -885,16 +1020,12 @@ static int qcom_ethqos_remove(struct platform_device *pdev)

	if (phy_intr_en)
		free_irq(ethqos->phy_intr, ethqos);
	emac_emb_smmu_exit();
	ethqos_disable_regulators(ethqos);

	return ret;
}

static const struct of_device_id qcom_ethqos_match[] = {
	{ .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_por},
	{ .compatible = "qcom,sdxprairie-ethqos", .data = &emac_v2_3_2_por},
	{ }
};
MODULE_DEVICE_TABLE(of, qcom_ethqos_match);

static struct platform_driver qcom_ethqos_driver = {
+6 −6
Original line number Diff line number Diff line
@@ -47,10 +47,10 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)

	if (nopaged_len > BUF_SIZE_8KiB) {

		des2 = dma_map_single(priv->device, skb->data, bmax,
		des2 = dma_map_single(GET_MEM_PDEV_DEV, skb->data, bmax,
				      DMA_TO_DEVICE);
		desc->des2 = cpu_to_le32(des2);
		if (dma_mapping_error(priv->device, des2))
		if (dma_mapping_error(GET_MEM_PDEV_DEV, des2))
			return -1;

		tx_q->tx_skbuff_dma[entry].buf = des2;
@@ -69,10 +69,10 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
		else
			desc = tx_q->dma_tx + entry;

		des2 = dma_map_single(priv->device, skb->data + bmax, len,
		des2 = dma_map_single(GET_MEM_PDEV_DEV, skb->data + bmax, len,
				      DMA_TO_DEVICE);
		desc->des2 = cpu_to_le32(des2);
		if (dma_mapping_error(priv->device, des2))
		if (dma_mapping_error(GET_MEM_PDEV_DEV, des2))
			return -1;
		tx_q->tx_skbuff_dma[entry].buf = des2;
		tx_q->tx_skbuff_dma[entry].len = len;
@@ -83,10 +83,10 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
						STMMAC_RING_MODE, 1,
						true, skb->len);
	} else {
		des2 = dma_map_single(priv->device, skb->data,
		des2 = dma_map_single(GET_MEM_PDEV_DEV, skb->data,
				      nopaged_len, DMA_TO_DEVICE);
		desc->des2 = cpu_to_le32(des2);
		if (dma_mapping_error(priv->device, des2))
		if (dma_mapping_error(GET_MEM_PDEV_DEV, des2))
			return -1;
		tx_q->tx_skbuff_dma[entry].buf = des2;
		tx_q->tx_skbuff_dma[entry].len = nopaged_len;
+17 −0
Original line number Diff line number Diff line
@@ -149,6 +149,23 @@ struct stmmac_priv {
#endif
};

struct emac_emb_smmu_cb_ctx {
	bool valid;
	struct platform_device *pdev_master;
	struct platform_device *smmu_pdev;
	struct dma_iommu_mapping *mapping;
	struct iommu_domain *iommu_domain;
	u32 va_start;
	u32 va_size;
	u32 va_end;
	int ret;
};

extern struct emac_emb_smmu_cb_ctx emac_emb_smmu_ctx;

#define GET_MEM_PDEV_DEV (emac_emb_smmu_ctx.valid ? \
			&emac_emb_smmu_ctx.smmu_pdev->dev : priv->device)

int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);

extern bool phy_intr_en;
+29 −29
Original line number Diff line number Diff line
@@ -1148,10 +1148,10 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
		return -ENOMEM;
	}
	rx_q->rx_skbuff[i] = skb;
	rx_q->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
	rx_q->rx_skbuff_dma[i] = dma_map_single(GET_MEM_PDEV_DEV, skb->data,
						priv->dma_buf_sz,
						DMA_FROM_DEVICE);
	if (dma_mapping_error(priv->device, rx_q->rx_skbuff_dma[i])) {
	if (dma_mapping_error(GET_MEM_PDEV_DEV, rx_q->rx_skbuff_dma[i])) {
		netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
		dev_kfree_skb_any(skb);
		return -EINVAL;
@@ -1180,7 +1180,7 @@ static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i)
	struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];

	if (rx_q->rx_skbuff[i]) {
		dma_unmap_single(priv->device, rx_q->rx_skbuff_dma[i],
		dma_unmap_single(GET_MEM_PDEV_DEV, rx_q->rx_skbuff_dma[i],
				 priv->dma_buf_sz, DMA_FROM_DEVICE);
		dev_kfree_skb_any(rx_q->rx_skbuff[i]);
	}
@@ -1199,12 +1199,12 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i)

	if (tx_q->tx_skbuff_dma[i].buf) {
		if (tx_q->tx_skbuff_dma[i].map_as_page)
			dma_unmap_page(priv->device,
			dma_unmap_page(GET_MEM_PDEV_DEV,
				       tx_q->tx_skbuff_dma[i].buf,
				       tx_q->tx_skbuff_dma[i].len,
				       DMA_TO_DEVICE);
		else
			dma_unmap_single(priv->device,
			dma_unmap_single(GET_MEM_PDEV_DEV,
					 tx_q->tx_skbuff_dma[i].buf,
					 tx_q->tx_skbuff_dma[i].len,
					 DMA_TO_DEVICE);
@@ -1445,11 +1445,11 @@ static void free_dma_rx_desc_resources(struct stmmac_priv *priv)

		/* Free DMA regions of consistent memory previously allocated */
		if (!priv->extend_desc)
			dma_free_coherent(priv->device,
			dma_free_coherent(GET_MEM_PDEV_DEV,
					  DMA_RX_SIZE * sizeof(struct dma_desc),
					  rx_q->dma_rx, rx_q->dma_rx_phy);
		else
			dma_free_coherent(priv->device, DMA_RX_SIZE *
			dma_free_coherent(GET_MEM_PDEV_DEV, DMA_RX_SIZE *
					  sizeof(struct dma_extended_desc),
					  rx_q->dma_erx, rx_q->dma_rx_phy);

@@ -1476,11 +1476,11 @@ static void free_dma_tx_desc_resources(struct stmmac_priv *priv)

		/* Free DMA regions of consistent memory previously allocated */
		if (!priv->extend_desc)
			dma_free_coherent(priv->device,
			dma_free_coherent(GET_MEM_PDEV_DEV,
					  DMA_TX_SIZE * sizeof(struct dma_desc),
					  tx_q->dma_tx, tx_q->dma_tx_phy);
		else
			dma_free_coherent(priv->device, DMA_TX_SIZE *
			dma_free_coherent(GET_MEM_PDEV_DEV, DMA_TX_SIZE *
					  sizeof(struct dma_extended_desc),
					  tx_q->dma_etx, tx_q->dma_tx_phy);

@@ -1523,7 +1523,7 @@ static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv)
			goto err_dma;

		if (priv->extend_desc) {
			rx_q->dma_erx = dma_zalloc_coherent(priv->device,
			rx_q->dma_erx = dma_zalloc_coherent(GET_MEM_PDEV_DEV,
							    DMA_RX_SIZE *
							    sizeof(struct
							    dma_extended_desc),
@@ -1533,7 +1533,7 @@ static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv)
				goto err_dma;

		} else {
			rx_q->dma_rx = dma_zalloc_coherent(priv->device,
			rx_q->dma_rx = dma_zalloc_coherent(GET_MEM_PDEV_DEV,
							   DMA_RX_SIZE *
							   sizeof(struct
							   dma_desc),
@@ -1586,7 +1586,7 @@ static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv)
			goto err_dma;

		if (priv->extend_desc) {
			tx_q->dma_etx = dma_zalloc_coherent(priv->device,
			tx_q->dma_etx = dma_zalloc_coherent(GET_MEM_PDEV_DEV,
							    DMA_TX_SIZE *
							    sizeof(struct
							    dma_extended_desc),
@@ -1595,7 +1595,7 @@ static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv)
			if (!tx_q->dma_etx)
				goto err_dma;
		} else {
			tx_q->dma_tx = dma_zalloc_coherent(priv->device,
			tx_q->dma_tx = dma_zalloc_coherent(GET_MEM_PDEV_DEV,
							   DMA_TX_SIZE *
							   sizeof(struct
								  dma_desc),
@@ -1867,12 +1867,12 @@ static void stmmac_tx_clean(struct stmmac_priv *priv, u32 queue)

		if (likely(tx_q->tx_skbuff_dma[entry].buf)) {
			if (tx_q->tx_skbuff_dma[entry].map_as_page)
				dma_unmap_page(priv->device,
				dma_unmap_page(GET_MEM_PDEV_DEV,
					       tx_q->tx_skbuff_dma[entry].buf,
					       tx_q->tx_skbuff_dma[entry].len,
					       DMA_TO_DEVICE);
			else
				dma_unmap_single(priv->device,
				dma_unmap_single(GET_MEM_PDEV_DEV,
						 tx_q->tx_skbuff_dma[entry].buf,
						 tx_q->tx_skbuff_dma[entry].len,
						 DMA_TO_DEVICE);
@@ -2853,9 +2853,9 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
	first = desc;

	/* first descriptor: fill Headers on Buf1 */
	des = dma_map_single(priv->device, skb->data, skb_headlen(skb),
	des = dma_map_single(GET_MEM_PDEV_DEV, skb->data, skb_headlen(skb),
			     DMA_TO_DEVICE);
	if (dma_mapping_error(priv->device, des))
	if (dma_mapping_error(GET_MEM_PDEV_DEV, des))
		goto dma_map_err;

	tx_q->tx_skbuff_dma[first_entry].buf = des;
@@ -2876,10 +2876,10 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
	for (i = 0; i < nfrags; i++) {
		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];

		des = skb_frag_dma_map(priv->device, frag, 0,
		des = skb_frag_dma_map(GET_MEM_PDEV_DEV, frag, 0,
				       skb_frag_size(frag),
				       DMA_TO_DEVICE);
		if (dma_mapping_error(priv->device, des))
		if (dma_mapping_error(GET_MEM_PDEV_DEV, des))
			goto dma_map_err;

		stmmac_tso_allocator(priv, des, skb_frag_size(frag),
@@ -3074,9 +3074,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
		else
			desc = tx_q->dma_tx + entry;

		des = skb_frag_dma_map(priv->device, frag, 0, len,
		des = skb_frag_dma_map(GET_MEM_PDEV_DEV, frag, 0, len,
				       DMA_TO_DEVICE);
		if (dma_mapping_error(priv->device, des))
		if (dma_mapping_error(GET_MEM_PDEV_DEV, des))
			goto dma_map_err; /* should reuse desc w/o issues */

		tx_q->tx_skbuff[entry] = NULL;
@@ -3159,9 +3159,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
	if (likely(!is_jumbo)) {
		bool last_segment = (nfrags == 0);

		des = dma_map_single(priv->device, skb->data,
		des = dma_map_single(GET_MEM_PDEV_DEV, skb->data,
				     nopaged_len, DMA_TO_DEVICE);
		if (dma_mapping_error(priv->device, des))
		if (dma_mapping_error(GET_MEM_PDEV_DEV, des))
			goto dma_map_err;

		tx_q->tx_skbuff_dma[first_entry].buf = des;
@@ -3275,9 +3275,9 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)

			rx_q->rx_skbuff[entry] = skb;
			rx_q->rx_skbuff_dma[entry] =
			    dma_map_single(priv->device, skb->data, bfsize,
			    dma_map_single(GET_MEM_PDEV_DEV, skb->data, bfsize,
					   DMA_FROM_DEVICE);
			if (dma_mapping_error(priv->device,
			if (dma_mapping_error(GET_MEM_PDEV_DEV,
					      rx_q->rx_skbuff_dma[entry])) {
				netdev_err(priv->dev, "Rx DMA map failed\n");
				dev_kfree_skb(skb);
@@ -3384,7 +3384,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
				 */
				dev_kfree_skb_any(rx_q->rx_skbuff[entry]);
				rx_q->rx_skbuff[entry] = NULL;
				dma_unmap_single(priv->device,
				dma_unmap_single(GET_MEM_PDEV_DEV,
						 rx_q->rx_skbuff_dma[entry],
						 priv->dma_buf_sz,
						 DMA_FROM_DEVICE);
@@ -3450,7 +3450,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
					break;
				}

				dma_sync_single_for_cpu(priv->device,
				dma_sync_single_for_cpu(GET_MEM_PDEV_DEV,
							rx_q->rx_skbuff_dma
							[entry], frame_len,
							DMA_FROM_DEVICE);
@@ -3460,7 +3460,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
							frame_len);

				skb_put(skb, frame_len);
				dma_sync_single_for_device(priv->device,
				dma_sync_single_for_device(GET_MEM_PDEV_DEV,
							   rx_q->rx_skbuff_dma
							   [entry], frame_len,
							   DMA_FROM_DEVICE);
@@ -3479,7 +3479,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
				rx_q->rx_zeroc_thresh++;

				skb_put(skb, frame_len);
				dma_unmap_single(priv->device,
				dma_unmap_single(GET_MEM_PDEV_DEV,
						 rx_q->rx_skbuff_dma[entry],
						 priv->dma_buf_sz,
						 DMA_FROM_DEVICE);