Qualcomm ARM Based Driver Updates for v4.15 Part 2

* Add Qualcomm Remote Filesystem Memory driver
 * Add OF linkage for RMTFS
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJZ7G5TAAoJEFKiBbHx2RXVhYgP/23hFR610Nb/00Zdukt8pRAv
 2Q54WO8oWl0CKjY6ohkHhOCwHFIp6Td/DHcg01yw1jTD7gnRJEFZleMX4/SJOWjX
 eIui9+sztCI3MpQbWOqCGmfSVGwlCmivto2fyyJfqQaKUTYfs4CtqSGFw5t01TH2
 /fnvP1z06Qa3mPk38La8vmxGdQCF7O97O0RceWxFNyiOEhksLZUOktkC/DEfupzU
 DjKbcgDIr7GGok7mdP26mRMGLcqtkIV+ZdQsIyx6JTMm7tC7Yq6jNn7e2iwMTDnt
 aYJQ3iecWMoa9XV9+jG4OzR0aMl1IzFy75BewJIsSKOMt6DhlN/wxF7HNpnxnIMZ
 HmtXgrqDM4k8yIyG7Gp5C152N6vK5cNXGuJSfJliw+cMtGC2ikBu/aQkCU9H5+gh
 wa0pcYKxdBdImhJfj+bC5SmoJ3ERUKH3neH90aOTfsUZilGVAwrJ72eGT8zchbB1
 R9oHlez4RIGsM1gx0DyK8stqYdYrrelML43qsBsbC9OiwgCJY9Y5ObykMjO+s3Oa
 zSxn1f7b4LxgdnQnzRgcJIMAKlR6zv/vUI7+TGRWe3lrcMJAEqx2dmxI6k+2yatG
 ijRAyS2SBaK4aVb5Qk1dBUGRD9isEyD6aqyr8TAl1kLLYm5x4XKqLXtmC0NLU1ee
 3Kw/ohbcBRlPlaZzWs9v
 =E/Ae
 -----END PGP SIGNATURE-----

Merge tag 'qcom-drivers-for-4.15-2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/agross/linux into next/drivers

Pull "Qualcomm ARM Based Driver Updates for v4.15 Part 2" from Andy Gross:

* Add Qualcomm Remote Filesystem Memory driver
* Add OF linkage for RMTFS

* tag 'qcom-drivers-for-4.15-2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/agross/linux:
  soc: qcom: Remote filesystem memory driver
  dt-binding: soc: qcom: Add binding for rmtfs memory
  of: reserved_mem: Accessor for acquiring reserved_mem
  of/platform: Generalize /reserved-memory handling
This commit is contained in:
Arnd Bergmann 2017-11-02 16:24:36 +01:00
Родитель 5e9b41ff09 d1de6d6c63
Коммит ae1d77fce7
7 изменённых файлов: 376 добавлений и 8 удалений

Просмотреть файл

@ -0,0 +1,51 @@
Qualcomm Remote File System Memory binding
This binding describes the Qualcomm remote filesystem memory, which serves the
purpose of describing the shared memory region used for remote processors to
access block device data using the Remote Filesystem protocol.
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be:
"qcom,rmtfs-mem"
- reg:
Usage: required for static allocation
Value type: <prop-encoded-array>
Definition: must specify base address and size of the memory region,
as described in reserved-memory.txt
- size:
Usage: required for dynamic allocation
Value type: <prop-encoded-array>
Definition: must specify a size of the memory region, as described in
reserved-memory.txt
- qcom,client-id:
Usage: required
Value type: <u32>
Definition: identifier of the client to use this region for buffers.
- qcom,vmid:
Usage: optional
Value type: <u32>
Definition: vmid of the remote processor, to set up memory protection.
= EXAMPLE
The following example shows the remote filesystem memory setup for APQ8016,
with the rmtfs region for the Hexagon DSP (id #1) located at 0x86700000.
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
rmtfs@86700000 {
compatible = "qcom,rmtfs-mem";
reg = <0x0 0x86700000 0x0 0xe0000>;
no-map;
qcom,client-id = <1>;
};
};

Просмотреть файл

@ -397,3 +397,29 @@ void of_reserved_mem_device_release(struct device *dev)
rmem->ops->device_release(rmem, dev);
}
EXPORT_SYMBOL_GPL(of_reserved_mem_device_release);
/**
* of_reserved_mem_lookup() - acquire reserved_mem from a device node
* @np: node pointer of the desired reserved-memory region
*
* This function allows drivers to acquire a reference to the reserved_mem
* struct based on a device node handle.
*
* Returns a reserved_mem reference, or NULL on error.
*/
struct reserved_mem *of_reserved_mem_lookup(struct device_node *np)
{
const char *name;
int i;
if (!np->full_name)
return NULL;
name = kbasename(np->full_name);
for (i = 0; i < reserved_mem_count; i++)
if (!strcmp(reserved_mem[i].name, name))
return &reserved_mem[i];
return NULL;
}
EXPORT_SYMBOL_GPL(of_reserved_mem_lookup);

Просмотреть файл

@ -497,6 +497,12 @@ int of_platform_default_populate(struct device_node *root,
EXPORT_SYMBOL_GPL(of_platform_default_populate);
#ifndef CONFIG_PPC
static const struct of_device_id reserved_mem_matches[] = {
{ .compatible = "qcom,rmtfs-mem" },
{ .compatible = "ramoops" },
{}
};
static int __init of_platform_default_populate_init(void)
{
struct device_node *node;
@ -505,15 +511,12 @@ static int __init of_platform_default_populate_init(void)
return -ENODEV;
/*
* Handle ramoops explicitly, since it is inside /reserved-memory,
* which lacks a "compatible" property.
* Handle certain compatibles explicitly, since we don't want to create
* platform_devices for every node in /reserved-memory with a
* "compatible",
*/
node = of_find_node_by_path("/reserved-memory");
if (node) {
node = of_find_compatible_node(node, NULL, "ramoops");
if (node)
of_platform_device_create(node, NULL, NULL);
}
for_each_matching_node(node, reserved_mem_matches)
of_platform_device_create(node, NULL, NULL);
/* Populate everything else. */
of_platform_default_populate(NULL, NULL, NULL);

Просмотреть файл

@ -35,6 +35,17 @@ config QCOM_PM
modes. It interface with various system drivers to put the cores in
low power modes.
config QCOM_RMTFS_MEM
tristate "Qualcomm Remote Filesystem memory driver"
depends on ARCH_QCOM
help
The Qualcomm remote filesystem memory driver is used for allocating
and exposing regions of shared memory with remote processors for the
purpose of exchanging sector-data between the remote filesystem
service and its clients.
Say y here if you intend to boot the modem remoteproc.
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM

Просмотреть файл

@ -2,6 +2,7 @@ obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
obj-$(CONFIG_QCOM_PM) += spm.o
obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
obj-$(CONFIG_QCOM_SMEM) += smem.o
obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o

Просмотреть файл

@ -0,0 +1,271 @@
/*
* Copyright (c) 2017 Linaro Ltd.
*
* 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/kernel.h>
#include <linux/cdev.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_reserved_mem.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/qcom_scm.h>
#define QCOM_RMTFS_MEM_DEV_MAX (MINORMASK + 1)
static dev_t qcom_rmtfs_mem_major;
struct qcom_rmtfs_mem {
struct device dev;
struct cdev cdev;
void *base;
phys_addr_t addr;
phys_addr_t size;
unsigned int client_id;
};
static ssize_t qcom_rmtfs_mem_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static DEVICE_ATTR(phys_addr, 0400, qcom_rmtfs_mem_show, NULL);
static DEVICE_ATTR(size, 0400, qcom_rmtfs_mem_show, NULL);
static DEVICE_ATTR(client_id, 0400, qcom_rmtfs_mem_show, NULL);
static ssize_t qcom_rmtfs_mem_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct qcom_rmtfs_mem *rmtfs_mem = container_of(dev,
struct qcom_rmtfs_mem,
dev);
if (attr == &dev_attr_phys_addr)
return sprintf(buf, "%pa\n", &rmtfs_mem->addr);
if (attr == &dev_attr_size)
return sprintf(buf, "%pa\n", &rmtfs_mem->size);
if (attr == &dev_attr_client_id)
return sprintf(buf, "%d\n", rmtfs_mem->client_id);
return -EINVAL;
}
static struct attribute *qcom_rmtfs_mem_attrs[] = {
&dev_attr_phys_addr.attr,
&dev_attr_size.attr,
&dev_attr_client_id.attr,
NULL
};
ATTRIBUTE_GROUPS(qcom_rmtfs_mem);
static int qcom_rmtfs_mem_open(struct inode *inode, struct file *filp)
{
struct qcom_rmtfs_mem *rmtfs_mem = container_of(inode->i_cdev,
struct qcom_rmtfs_mem,
cdev);
get_device(&rmtfs_mem->dev);
filp->private_data = rmtfs_mem;
return 0;
}
static ssize_t qcom_rmtfs_mem_read(struct file *filp,
char __user *buf, size_t count, loff_t *f_pos)
{
struct qcom_rmtfs_mem *rmtfs_mem = filp->private_data;
if (*f_pos >= rmtfs_mem->size)
return 0;
if (*f_pos + count >= rmtfs_mem->size)
count = rmtfs_mem->size - *f_pos;
if (copy_to_user(buf, rmtfs_mem->base + *f_pos, count))
return -EFAULT;
*f_pos += count;
return count;
}
static ssize_t qcom_rmtfs_mem_write(struct file *filp,
const char __user *buf, size_t count,
loff_t *f_pos)
{
struct qcom_rmtfs_mem *rmtfs_mem = filp->private_data;
if (*f_pos >= rmtfs_mem->size)
return 0;
if (*f_pos + count >= rmtfs_mem->size)
count = rmtfs_mem->size - *f_pos;
if (copy_from_user(rmtfs_mem->base + *f_pos, buf, count))
return -EFAULT;
*f_pos += count;
return count;
}
static int qcom_rmtfs_mem_release(struct inode *inode, struct file *filp)
{
struct qcom_rmtfs_mem *rmtfs_mem = filp->private_data;
put_device(&rmtfs_mem->dev);
return 0;
}
static const struct file_operations qcom_rmtfs_mem_fops = {
.owner = THIS_MODULE,
.open = qcom_rmtfs_mem_open,
.read = qcom_rmtfs_mem_read,
.write = qcom_rmtfs_mem_write,
.release = qcom_rmtfs_mem_release,
.llseek = default_llseek,
};
static void qcom_rmtfs_mem_release_device(struct device *dev)
{
struct qcom_rmtfs_mem *rmtfs_mem = container_of(dev,
struct qcom_rmtfs_mem,
dev);
kfree(rmtfs_mem);
}
static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct reserved_mem *rmem;
struct qcom_rmtfs_mem *rmtfs_mem;
u32 client_id;
int ret;
rmem = of_reserved_mem_lookup(node);
if (!rmem) {
dev_err(&pdev->dev, "failed to acquire memory region\n");
return -EINVAL;
}
ret = of_property_read_u32(node, "qcom,client-id", &client_id);
if (ret) {
dev_err(&pdev->dev, "failed to parse \"qcom,client-id\"\n");
return ret;
}
rmtfs_mem = kzalloc(sizeof(*rmtfs_mem), GFP_KERNEL);
if (!rmtfs_mem)
return -ENOMEM;
rmtfs_mem->addr = rmem->base;
rmtfs_mem->client_id = client_id;
rmtfs_mem->size = rmem->size;
device_initialize(&rmtfs_mem->dev);
rmtfs_mem->dev.parent = &pdev->dev;
rmtfs_mem->dev.groups = qcom_rmtfs_mem_groups;
rmtfs_mem->base = devm_memremap(&rmtfs_mem->dev, rmtfs_mem->addr,
rmtfs_mem->size, MEMREMAP_WC);
if (IS_ERR(rmtfs_mem->base)) {
dev_err(&pdev->dev, "failed to remap rmtfs_mem region\n");
ret = PTR_ERR(rmtfs_mem->base);
goto put_device;
}
cdev_init(&rmtfs_mem->cdev, &qcom_rmtfs_mem_fops);
rmtfs_mem->cdev.owner = THIS_MODULE;
dev_set_name(&rmtfs_mem->dev, "qcom_rmtfs_mem%d", client_id);
rmtfs_mem->dev.id = client_id;
rmtfs_mem->dev.devt = MKDEV(MAJOR(qcom_rmtfs_mem_major), client_id);
ret = cdev_device_add(&rmtfs_mem->cdev, &rmtfs_mem->dev);
if (ret) {
dev_err(&pdev->dev, "failed to add cdev: %d\n", ret);
goto put_device;
}
rmtfs_mem->dev.release = qcom_rmtfs_mem_release_device;
dev_set_drvdata(&pdev->dev, rmtfs_mem);
return 0;
remove_cdev:
cdev_device_del(&rmtfs_mem->cdev, &rmtfs_mem->dev);
put_device:
put_device(&rmtfs_mem->dev);
return ret;
}
static int qcom_rmtfs_mem_remove(struct platform_device *pdev)
{
struct qcom_rmtfs_mem *rmtfs_mem = dev_get_drvdata(&pdev->dev);
cdev_device_del(&rmtfs_mem->cdev, &rmtfs_mem->dev);
put_device(&rmtfs_mem->dev);
return 0;
}
static const struct of_device_id qcom_rmtfs_mem_of_match[] = {
{ .compatible = "qcom,rmtfs-mem" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_rmtfs_mem_of_match);
static struct platform_driver qcom_rmtfs_mem_driver = {
.probe = qcom_rmtfs_mem_probe,
.remove = qcom_rmtfs_mem_remove,
.driver = {
.name = "qcom_rmtfs_mem",
.of_match_table = qcom_rmtfs_mem_of_match,
},
};
static int qcom_rmtfs_mem_init(void)
{
int ret;
ret = alloc_chrdev_region(&qcom_rmtfs_mem_major, 0,
QCOM_RMTFS_MEM_DEV_MAX, "qcom_rmtfs_mem");
if (ret < 0) {
pr_err("qcom_rmtfs_mem: failed to allocate char dev region\n");
return ret;
}
ret = platform_driver_register(&qcom_rmtfs_mem_driver);
if (ret < 0) {
pr_err("qcom_rmtfs_mem: failed to register rmtfs_mem driver\n");
unregister_chrdev_region(qcom_rmtfs_mem_major,
QCOM_RMTFS_MEM_DEV_MAX);
}
return ret;
}
module_init(qcom_rmtfs_mem_init);
static void qcom_rmtfs_mem_exit(void)
{
platform_driver_unregister(&qcom_rmtfs_mem_driver);
unregister_chrdev_region(qcom_rmtfs_mem_major, QCOM_RMTFS_MEM_DEV_MAX);
}
module_exit(qcom_rmtfs_mem_exit);

Просмотреть файл

@ -44,6 +44,7 @@ int early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
void fdt_init_reserved_mem(void);
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size);
struct reserved_mem *of_reserved_mem_lookup(struct device_node *np);
#else
static inline int of_reserved_mem_device_init_by_idx(struct device *dev,
struct device_node *np, int idx)
@ -55,6 +56,10 @@ static inline void of_reserved_mem_device_release(struct device *pdev) { }
static inline void fdt_init_reserved_mem(void) { }
static inline void fdt_reserved_mem_save_node(unsigned long node,
const char *uname, phys_addr_t base, phys_addr_t size) { }
static inline struct reserved_mem *of_reserved_mem_lookup(struct device_node *np)
{
return NULL;
}
#endif
/**