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

Commit ba53fbd3 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "nvme: smmu support via devicetree"

parents 6f046912 1df24233
Loading
Loading
Loading
Loading
+51 −0
Original line number Diff line number Diff line
NVMe Device Support on chipsets of Qualcomm Technologies, Inc.


Required properties:

- compatible : should be one of "qcom,nvme"

If SMMU is present, also use:

- qcom,smmu : if present, SMMU attach is performed
- qcom,smmu-iova-base : SMMU IOVA start address the device can access
- qcom,smmu-iova-size : SMMU IOVA size the device can access

Optional Properties:

- qcom,smmu-attr-s1-bypass : Bypasses SMMU S1 translation
- qcom,smmu-attr-fastmap : Enables SMMU fastmap
- qcom,smmu-attr-atomic : Enables DMA alloc using GFP_ATOMIC
- qcom,smmu-attr-pt-coherent : Use if DMA coherency is available for SMMU page tables


Example:

&pcie_rc0 {

	nvme_x1: qcom,nvme@pcie_rc0 {
		compatible = "qcom,nvme";

		qcom,smmu;
		qcom,smmu-iova-base = /bits/ 64 <0x0>;
		qcom,smmu-iova-size = /bits/ 64 <0x100000000>;

		qcom,smmu-attr-s1-bypass;
	};
};

&pcie_rc1 {

	nvme_x4: qcom,nvme@pcie_rc1 {
		compatible = "qcom,nvme";

		qcom,smmu;
		qcom,smmu-iova-base = /bits/ 64 <0x0>;
		qcom,smmu-iova-size = /bits/ 64 <0x100000000>;

		qcom,smmu-attr-atomic;
		qcom,smmu-attr-fastmap;
		qcom,smmu-attr-pt-coherent;
	};
};
+7 −0
Original line number Diff line number Diff line
@@ -48,3 +48,10 @@ config NVME_FC
	  from https://github.com/linux-nvme/nvme-cli.

	  If unsure, say N.

config NVME_QCOM
        bool "QTI MSM/MDM target support"
        depends on BLK_DEV_NVME
        depends on ARCH_QCOM
        help
          Enable support for integration with Qualcomm Technologies, Inc. chipsets.
+2 −0
Original line number Diff line number Diff line
@@ -15,3 +15,5 @@ nvme-fabrics-y += fabrics.o
nvme-rdma-y				+= rdma.o

nvme-fc-y				+= fc.o

obj-$(CONFIG_NVME_QCOM)			+= nvme-qcom.o
+146 −0
Original line number Diff line number Diff line
/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only 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.
 */

#include <linux/iommu.h>
#include <asm/dma-iommu.h>
#include <linux/platform_device.h>

#include "nvme-qcom.h"

static const struct of_device_id nvme_matches[] = {
	{ .compatible = "qcom,nvme" },
};

static struct dma_iommu_mapping *mapping;

static int nvme_qcom_parse_smmu_attr(struct device *dev,
				    struct iommu_domain *domain,
				    const char *key,
				    enum iommu_attr attr)
{
	int rc = 0;
	unsigned int data = 1;

	if (of_find_property(dev->of_node, key, NULL)) {
		rc = iommu_domain_set_attr(domain, attr, &data);
		if (!rc)
			dev_dbg(dev, "enabled SMMU attribute %u\n", attr);
		else
			dev_err(dev, "failed to set SMMU attribute %u\n", attr);
	}

	return rc;
}

static int nvme_qcom_parse_smmu_attrs(struct device *dev,
				     struct iommu_domain *domain)
{
	int rc = 0;

	rc |= nvme_qcom_parse_smmu_attr(dev, domain,
		"qcom,smmu-attr-s1-bypass", DOMAIN_ATTR_S1_BYPASS);

	rc |= nvme_qcom_parse_smmu_attr(dev, domain,
		"qcom,smmu-attr-fastmap", DOMAIN_ATTR_FAST);

	rc |= nvme_qcom_parse_smmu_attr(dev, domain,
		"qcom,smmu-attr-atomic", DOMAIN_ATTR_ATOMIC);

	rc |= nvme_qcom_parse_smmu_attr(dev, domain,
		"qcom,smmu-attr-pt-coherent",
		DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT);

	rc |= nvme_qcom_parse_smmu_attr(dev, domain,
		"qcom,smmu-attr-pt-coherent-force",
		DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT);

	return rc;
}

static int nvme_qcom_parse_smmu(struct device *dev)
{
	int rc;
	const char *key;
	u64 val64;
	dma_addr_t iova_base = 0;
	u64 iova_size = 0;

	key = "qcom,smmu-iova-base";
	rc = of_property_read_u64(dev->of_node, key, &val64);
	if (rc) {
		dev_err(dev, "error parsing DT prop %s: %d\n", key, rc);
		return rc;
	}
	iova_base = (dma_addr_t)val64;

	key = "qcom,smmu-iova-size";
	rc = of_property_read_u64(dev->of_node, key, &val64);
	if (rc) {
		dev_err(dev, "error parsing DT prop %s: %d\n", key, rc);
		return rc;
	}
	iova_size = val64;
	dev_dbg(dev, "creating SMMU mapping with base=0x%llx, size=0x%llx\n",
		iova_base, iova_size);

	mapping = arm_iommu_create_mapping(dev->bus, iova_base, iova_size);
	if (IS_ERR(mapping)) {
		dev_err(dev, "failed to create SMMU mapping\n");
		return PTR_ERR(mapping);
	}

	rc = nvme_qcom_parse_smmu_attrs(dev, mapping->domain);
	if (rc) {
		dev_err(dev, "error parsing SMMU DT attributes\n");
		goto err_release_mapping;
	}

	rc = arm_iommu_attach_device(dev, mapping);
	if (rc) {
		dev_err(dev, "failed to attach device to smmu\n");
		goto err_release_mapping;
	}

	return 0;

err_release_mapping:
	arm_iommu_release_mapping(mapping);
	return rc;
}

int nvme_qcom_parse_dt(struct device *dev)
{
	int rc = 0;

	if (!dev->of_node) {
		dev_notice(dev, "device tree node is not present\n");
		return -EINVAL;
	}

	if (!of_match_node(nvme_matches, dev->of_node)) {
		dev_notice(dev, "device tree node is not compatible\n");
		return -EINVAL;
	}

	if (of_find_property(dev->of_node, "qcom,smmu", NULL))
		rc = nvme_qcom_parse_smmu(dev);
	else
		dev_dbg(dev, "SMMU config not present in DT\n");

	return rc;
}

void nvme_qcom_release_mapping(struct device *dev)
{
	arm_iommu_detach_device(dev);
	arm_iommu_release_mapping(mapping);
}
+35 −0
Original line number Diff line number Diff line
/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only 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.
 */

#ifndef _NVME_QCOM_H_
#define _NVME_QCOM_H_

#ifdef CONFIG_NVME_QCOM

int nvme_qcom_parse_dt(struct device *dev);
void nvme_qcom_release_mapping(struct device *dev);

#else

static inline int nvme_qcom_parse_dt(struct device *dev)
{
	return 0;
}

static inline void nvme_qcom_release_mapping(struct device *dev)
{

}

#endif // CONFIG_NVME_QCOM

#endif // _NVME_QCOM_H_
Loading