/*
* Remote Processor Framework
*
* Copyright (C) 2011 Texas Instruments, Inc.
* Copyright (C) 2011 Google, Inc.
*
* Ohad Ben-Cohen <ohad@wizery.com>
* Brian Swetland <swetland@google.com>
* Mark Grosen <mgrosen@ti.com>
* Fernando Guzman Lugo <fernando.lugo@ti.com>
* Suman Anna <s-anna@ti.com>
* Robert Tivy <rtivy@ti.com>
* Armando Uribe De Leon <x0095078@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* 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.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/dma-mapping.h>
#include <linux/firmware.h>
#include <linux/string.h>
#include <linux/debugfs.h>
#include <linux/remoteproc.h>
#include <linux/iommu.h>
#include <linux/idr.h>
#include <linux/elf.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_ring.h>
#include <asm/byteorder.h>
#include "remoteproc_internal.h"
typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
struct resource_table *table, int len);
typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail);
/* Unique indices for remoteproc devices */
static DEFINE_IDA(rproc_dev_index);
/*
* This is the IOMMU fault handler we register with the IOMMU API
* (when relevant; not all remote processors access memory through
* an IOMMU).
*
* IOMMU core will invoke this handler whenever the remote processor
* will try to access an unmapped device address.
*
* Currently this is mostly a stub, but it will be later used to trigger
* the recovery of the remote processor.
*/
static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
unsigned long iova, int flags, void *token)
{
dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags);
/*
* Let the iommu core know we're not really handling this fault;
* we just plan to use this as a recovery trigger.
*/
return -ENOSYS;
}
static int rproc_enable_iommu(struct rproc *rproc)
{
struct iommu_domain *domain;
struct device *dev = rproc->dev.parent;
int ret;
/*
* We currently use iommu_present() to decide if an IOMMU
* setup is needed.
*
* This works for simple cases, but will easily fail with
* platforms that do have an IOMMU, but not for this specific
* rproc.
*
* This will be easily solved by introducing hw capabilities
* that will be set by the remoteproc driver.
*/
if (!iommu_present(dev->bus)) {
dev_dbg(dev, "iommu not found\n");
return 0;
}
domain = iommu_domain_alloc(dev->bus);
if (!domain) {
dev_err(dev, "can't alloc iommu domain\n");
return -ENOMEM;
}
iommu_set_fault_handler(domain, rproc_iommu_fault, rproc);
ret = iommu_attach_device(domain, dev);
if (ret) {
dev_err(dev, "can't attach iommu device: %d\n", ret);
goto free_domain;
}
rproc->domain = domain;
return 0;
free_domain:
iommu_domain_free(domain);
return ret;
}
static void rproc_disable_iommu(struct rproc *rproc)
{
struct iommu_domain *domain = rproc->domain;
struct device