diff options
author | Emil Medve <Emilian.Medve@Freescale.com> | 2013-04-09 16:34:41 (GMT) |
---|---|---|
committer | Fleming Andrew-AFLEMING <AFLEMING@freescale.com> | 2013-04-10 20:52:31 (GMT) |
commit | a2fe11000bc73db327736378313c2d6c5a2e9173 (patch) | |
tree | 055637446c3a741b1daf2abebf1ee6536d8b728f | |
parent | 4f1e206f2b70a8795aa27bb291e1fa0019f74aef (diff) | |
download | linux-fsl-qoriq-a2fe11000bc73db327736378313c2d6c5a2e9173.tar.xz |
fsl_qman: Set stashing using the IOMMU API
This is using thew new PAMU driver
This integration uses a *horrible hack* in order to provide the IOMMU/PAMU
driver with a 'struct device'. Making the QMan portal driver nice and
proper is part of the upstreaming effort
Change-Id: I5f03a3b662949162bff7ac8c7b14ad5fbc0394ce
Signed-off-by: Emil Medve <Emilian.Medve@Freescale.com>
Change-Id: Ic66bb3904ffa537e497ba00c67e22d851087b435
Reviewed-on: http://git.am.freescale.net:8181/1173
Reviewed-by: Ladouceur Jeffrey-R11498 <Jeffrey.Ladouceur@freescale.com>
Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
-rw-r--r-- | drivers/staging/fsl_qbman/dpa_sys.h | 2 | ||||
-rw-r--r-- | drivers/staging/fsl_qbman/dpa_uio.c | 2 | ||||
-rw-r--r-- | drivers/staging/fsl_qbman/qman_driver.c | 87 | ||||
-rw-r--r-- | drivers/staging/fsl_qbman/qman_private.h | 3 |
4 files changed, 87 insertions, 7 deletions
diff --git a/drivers/staging/fsl_qbman/dpa_sys.h b/drivers/staging/fsl_qbman/dpa_sys.h index 8837684..4aa61ae 100644 --- a/drivers/staging/fsl_qbman/dpa_sys.h +++ b/drivers/staging/fsl_qbman/dpa_sys.h @@ -88,7 +88,7 @@ struct dpa_uio_vtable { void (*destroy)(const struct list_head *pcfg, struct uio_info *info); /* Called when the portal is opened (Qman uses this for rerouting * stashing to the current cpu) */ - int (*on_open)(const struct list_head *pcfg); + int (*on_open)(struct list_head *pcfg); void (*on_close)(const struct list_head *pcfg); /* Called when an interrupt fires - must disable interrupts */ void (*on_interrupt)(const struct list_head *pcfg); diff --git a/drivers/staging/fsl_qbman/dpa_uio.c b/drivers/staging/fsl_qbman/dpa_uio.c index cdb78db..557be44 100644 --- a/drivers/staging/fsl_qbman/dpa_uio.c +++ b/drivers/staging/fsl_qbman/dpa_uio.c @@ -38,7 +38,7 @@ static LIST_HEAD(dpa_uio_list); struct dpa_uio_info { const struct dpa_uio_vtable *vtable; - const struct list_head *pcfg; + struct list_head *pcfg; atomic_t ref; /* exclusive, only one open() at a time */ struct uio_info uio; struct platform_device *pdev; diff --git a/drivers/staging/fsl_qbman/qman_driver.c b/drivers/staging/fsl_qbman/qman_driver.c index 877bee2..90f85cc 100644 --- a/drivers/staging/fsl_qbman/qman_driver.c +++ b/drivers/staging/fsl_qbman/qman_driver.c @@ -31,6 +31,8 @@ #include "qman_private.h" +#include <linux/iommu.h> + /* Global variable containing revision id (even on non-control plane systems * where CCSR isn't available) */ u16 qman_ip_rev; @@ -348,6 +350,18 @@ static struct qm_portal_config * __init parse_pcfg(struct device_node *node) return NULL; } + /* + * This is a *horrible hack*, but the IOMMU/PAMU driver needs a + * 'struct device' in order to get the PAMU stashing setup and the QMan + * portal [driver] won't function at all without ring stashing + * + * Making the QMan portal driver nice and proper is part of the + * upstreaming effort + */ + pcfg->dev.bus = &platform_bus_type; + pcfg->dev.of_node = node; + pcfg->dev.archdata.iommu_domain = NULL; + ret = of_address_to_resource(node, DPA_PORTAL_CE, &pcfg->addr_phys[DPA_PORTAL_CE]); if (ret) { @@ -390,7 +404,6 @@ static struct qm_portal_config * __init parse_pcfg(struct device_node *node) } pcfg->public_cfg.irq = irq; pcfg->public_cfg.index = *index; - pcfg->node = node; #ifdef CONFIG_FSL_QMAN_CONFIG /* We need the same LIODN offset for all portals */ qman_liodn_fixup(pcfg->public_cfg.channel); @@ -429,17 +442,82 @@ static struct qm_portal_config *get_pcfg(struct list_head *list) return pcfg; } -static void portal_set_cpu(const struct qm_portal_config *pcfg, int cpu) +static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu) { + int ret; + int window_count = 1; + struct iommu_domain_geometry geom_attr; + struct iommu_stash_attribute stash_attr; + + pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type); + if (!pcfg->iommu_domain) { + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_alloc() failed", + __func__); + return; + } + geom_attr.aperture_start = 0; + geom_attr.aperture_end = (1ULL << 36) - 1; + geom_attr.force_aperture = true; + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY, + &geom_attr); + if (ret < 0) { + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", + __func__, ret); + goto _iommu_domain_free; + } + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS, + &window_count); + if (ret < 0) { + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", + __func__, ret); + goto _iommu_domain_free; + } + stash_attr.cpu = cpu; + stash_attr.cache = IOMMU_ATTR_CACHE_L1; + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_PAMU_STASH, + &stash_attr); + if (ret < 0) { + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", + __func__, ret); + goto _iommu_domain_free; + } + ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36, + IOMMU_READ | IOMMU_WRITE); + if (ret < 0) { + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_window_enable() = %d", + __func__, ret); + goto _iommu_domain_free; + } + ret = iommu_attach_device(pcfg->iommu_domain, &pcfg->dev); + if (ret < 0) { + pr_err(KBUILD_MODNAME ":%s(): iommu_device_attach() = %d", + __func__, ret); + goto _iommu_domain_free; + } + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_PAMU_ENABLE, + &window_count); + if (ret < 0) { + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", + __func__, ret); + goto _iommu_detach_device; + } + #ifdef CONFIG_FSL_QMAN_CONFIG if (qman_set_sdest(pcfg->public_cfg.channel, cpu)) #endif pr_warning("Failed to set QMan portal's stash request queue\n"); + + return; + +_iommu_detach_device: + iommu_detach_device(pcfg->iommu_domain, NULL); +_iommu_domain_free: + iommu_domain_free(pcfg->iommu_domain); } /* UIO handling callbacks */ #define QMAN_UIO_PREAMBLE() \ - const struct qm_portal_config *pcfg = \ + struct qm_portal_config *pcfg = \ container_of(__p, struct qm_portal_config, list) static int qman_uio_cb_init(const struct list_head *__p, struct uio_info *info) { @@ -473,7 +551,7 @@ static void qman_uio_cb_destroy(const struct list_head *__p, * Here it's passed back to us for final clean it up, so de-constify. */ destroy_pcfg((struct qm_portal_config *)pcfg); } -static int qman_uio_cb_open(const struct list_head *__p) +static int qman_uio_cb_open(struct list_head *__p) { QMAN_UIO_PREAMBLE(); /* Bind stashing LIODNs to the CPU we are currently executing on, and @@ -608,6 +686,7 @@ static __init int qman_init(void) if (ret) return ret; } + /* Initialise portals. See bman_driver.c for comments */ for_each_compatible_node(dn, NULL, "fsl,qman-portal") { if (!of_device_is_available(dn)) diff --git a/drivers/staging/fsl_qbman/qman_private.h b/drivers/staging/fsl_qbman/qman_private.h index e43a41a..cea96d6 100644 --- a/drivers/staging/fsl_qbman/qman_private.h +++ b/drivers/staging/fsl_qbman/qman_private.h @@ -115,7 +115,8 @@ struct qm_portal_config { * [0]==cache-enabled, [1]==cache-inhibited. */ __iomem void *addr_virt[2]; struct resource addr_phys[2]; - struct device_node *node; + struct device dev; + struct iommu_domain *iommu_domain; /* Allow these to be joined in lists */ struct list_head list; /* User-visible portal configuration settings */ |