/* * Table for matching compatible strings, for device tree * guts node, for QorIQ SOCs. * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4 * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0" * string would be used.
*/ staticconststruct of_device_id guts_device_ids[] = {
{ .compatible = "fsl,qoriq-device-config-1.0", },
{ .compatible = "fsl,qoriq-device-config-2.0", },
{}
};
/* * Table for matching compatible strings, for device tree * L3 cache controller node. * "fsl,t4240-l3-cache-controller" corresponds to T4, * "fsl,b4860-l3-cache-controller" corresponds to B4 & * "fsl,p4080-l3-cache-controller" corresponds to other, * SOCs.
*/ staticconststruct of_device_id l3_device_ids[] = {
{ .compatible = "fsl,t4240-l3-cache-controller", },
{ .compatible = "fsl,b4860-l3-cache-controller", },
{ .compatible = "fsl,p4080-l3-cache-controller", },
{}
};
/* maximum subwindows permitted per liodn */ static u32 max_subwindow_count;
/** * pamu_get_ppaace() - Return the primary PACCE * @liodn: liodn PAACT index for desired PAACE * * Returns the ppace pointer upon success else return * null.
*/ staticstruct paace *pamu_get_ppaace(int liodn)
{ if (!ppaact || liodn >= PAACE_NUMBER_ENTRIES) {
pr_debug("PPAACT doesn't exist\n"); return NULL;
}
return &ppaact[liodn];
}
/** * pamu_enable_liodn() - Set valid bit of PACCE * @liodn: liodn PAACT index for desired PAACE * * Returns 0 upon success else error code < 0 returned
*/ int pamu_enable_liodn(int liodn)
{ struct paace *ppaace;
/* Derive the window size encoding for a particular PAACE entry */ staticunsignedint map_addrspace_size_to_wse(phys_addr_t addrspace_size)
{ /* Bug if not a power of 2 */
BUG_ON(addrspace_size & (addrspace_size - 1));
/* * Set the PAACE type as primary and set the coherency required domain * attribute
*/ staticvoid pamu_init_ppaace(struct paace *ppaace)
{
set_bf(ppaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_PRIMARY);
/* * Function used for updating stash destination for the coressponding * LIODN.
*/ int pamu_update_paace_stash(int liodn, u32 value)
{ struct paace *paace;
/** * pamu_config_ppaace() - Sets up PPAACE entry for specified liodn * * @liodn: Logical IO device number * @omi: Operation mapping index -- if ~omi == 0 then omi not defined * @stashid: cache stash id for associated cpu -- if ~stashid == 0 then * stashid not defined * @prot: window permissions * * Returns 0 upon success else error code < 0 returned
*/ int pamu_config_ppaace(int liodn, u32 omi, u32 stashid, int prot)
{ struct paace *ppaace;
ppaace = pamu_get_ppaace(liodn); if (!ppaace) return -ENOENT;
/** * get_ome_index() - Returns the index in the operation mapping table * for device. * @omi_index: pointer for storing the index value * @dev: target device *
*/ void get_ome_index(u32 *omi_index, struct device *dev)
{ if (of_device_is_compatible(dev->of_node, "fsl,qman-portal"))
*omi_index = OMI_QMAN; if (of_device_is_compatible(dev->of_node, "fsl,qman"))
*omi_index = OMI_QMAN_PRIV;
}
/** * get_stash_id - Returns stash destination id corresponding to a * cache type and vcpu. * @stash_dest_hint: L1, L2 or L3 * @vcpu: vpcu target for a particular cache type. * * Returs stash on success or ~(u32)0 on failure. *
*/
u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
{ const u32 *prop; struct device_node *node;
u32 cache_level; int len, found = 0; int i;
/* Fastpath, exit early if L3/CPC cache is target for stashing */ if (stash_dest_hint == PAMU_ATTR_CACHE_L3) {
node = of_find_matching_node(NULL, l3_device_ids); if (node) {
prop = of_get_property(node, "cache-stash-id", NULL); if (!prop) {
pr_debug("missing cache-stash-id at %pOF\n",
node);
of_node_put(node); return ~(u32)0;
}
of_node_put(node); return be32_to_cpup(prop);
} return ~(u32)0;
}
for_each_of_cpu_node(node) {
prop = of_get_property(node, "reg", &len); for (i = 0; i < len / sizeof(u32); i++) { if (be32_to_cpup(&prop[i]) == vcpu) {
found = 1; goto found_cpu_node;
}
}
}
found_cpu_node:
/* find the hwnode that represents the cache */ for (cache_level = PAMU_ATTR_CACHE_L1; (cache_level < PAMU_ATTR_CACHE_L3) && found; cache_level++) { if (stash_dest_hint == cache_level) {
prop = of_get_property(node, "cache-stash-id", NULL); if (!prop) {
pr_debug("missing cache-stash-id at %pOF\n",
node);
of_node_put(node); return ~(u32)0;
}
of_node_put(node); return be32_to_cpup(prop);
}
prop = of_get_property(node, "next-level-cache", NULL); if (!prop) {
pr_debug("can't find next-level-cache at %pOF\n", node);
of_node_put(node); return ~(u32)0; /* can't traverse any further */
}
of_node_put(node);
/* advance to next node in cache hierarchy */
node = of_find_node_by_phandle(*prop); if (!node) {
pr_debug("Invalid node for cache hierarchy\n"); return ~(u32)0;
}
}
pr_debug("stash dest not found for %d on vcpu %d\n",
stash_dest_hint, vcpu); return ~(u32)0;
}
/* Identify if the PAACT table entry belongs to QMAN, BMAN or QMAN Portal */ #define QMAN_PAACE 1 #define QMAN_PORTAL_PAACE 2 #define BMAN_PAACE 3
/* * Setup operation mapping and stash destinations for QMAN and QMAN portal. * Memory accesses to QMAN and BMAN private memory need not be coherent, so * clear the PAACE entry coherency attribute for them.
*/ staticvoid setup_qbman_paace(struct paace *ppaace, int paace_type)
{ switch (paace_type) { case QMAN_PAACE:
set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
ppaace->op_encode.index_ot.omi = OMI_QMAN_PRIV; /* setup QMAN Private data stashing for the L3 cache */
set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0));
set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
0); break; case QMAN_PORTAL_PAACE:
set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
ppaace->op_encode.index_ot.omi = OMI_QMAN; /* Set DQRR and Frame stashing for the L3 cache */
set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0)); break; case BMAN_PAACE:
set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
0); break;
}
}
/* * Setup the operation mapping table for various devices. This is a static * table where each table index corresponds to a particular device. PAMU uses * this table to translate device transaction to appropriate corenet * transaction.
*/ staticvoid setup_omt(struct ome *omt)
{ struct ome *ome;
/* * Get the maximum number of PAACT table entries * and subwindows supported by PAMU
*/ staticvoid get_pamu_cap_values(unsignedlong pamu_reg_base)
{
u32 pc_val;
pc_val = in_be32((u32 *)(pamu_reg_base + PAMU_PC3)); /* Maximum number of subwindows per liodn */
max_subwindow_count = 1 << (1 + PAMU_PC3_MWCE(pc_val));
}
if (i == 0 || i == num_laws) { /* This should never happen */
ret = -ENOENT; goto error;
}
/* Find a free LAW entry */ while (law[--i].lawar & LAWAR_EN) { if (i == 0) { /* No higher priority LAW slots available */
ret = -ENOENT; goto error;
}
}
/* * Table of SVRs and the corresponding PORT_ID values. Port ID corresponds to a * bit map of snoopers for a given range of memory mapped by a LAW. * * All future CoreNet-enabled SOCs will have this erratum(A-004510) fixed, so this * table should never need to be updated. SVRs are guaranteed to be unique, so * there is no worry that a future SOC will inadvertently have one of these * values.
*/ staticconststruct {
u32 svr;
u32 port_id;
} port_id_map[] = {
{(SVR_P2040 << 8) | 0x10, 0xFF000000}, /* P2040 1.0 */
{(SVR_P2040 << 8) | 0x11, 0xFF000000}, /* P2040 1.1 */
{(SVR_P2041 << 8) | 0x10, 0xFF000000}, /* P2041 1.0 */
{(SVR_P2041 << 8) | 0x11, 0xFF000000}, /* P2041 1.1 */
{(SVR_P3041 << 8) | 0x10, 0xFF000000}, /* P3041 1.0 */
{(SVR_P3041 << 8) | 0x11, 0xFF000000}, /* P3041 1.1 */
{(SVR_P4040 << 8) | 0x20, 0xFFF80000}, /* P4040 2.0 */
{(SVR_P4080 << 8) | 0x20, 0xFFF80000}, /* P4080 2.0 */
{(SVR_P5010 << 8) | 0x10, 0xFC000000}, /* P5010 1.0 */
{(SVR_P5010 << 8) | 0x20, 0xFC000000}, /* P5010 2.0 */
{(SVR_P5020 << 8) | 0x10, 0xFC000000}, /* P5020 1.0 */
{(SVR_P5021 << 8) | 0x10, 0xFF800000}, /* P5021 1.0 */
{(SVR_P5040 << 8) | 0x10, 0xFF800000}, /* P5040 1.0 */
};
#define SVR_SECURITY 0x80000 /* The Security (E) bit */
staticint fsl_pamu_probe(struct platform_device *pdev)
{ struct device *dev = &pdev->dev; void __iomem *pamu_regs = NULL; struct ccsr_guts __iomem *guts_regs = NULL;
u32 pamubypenr, pamu_counter; unsignedlong pamu_reg_off; unsignedlong pamu_reg_base; struct pamu_isr_data *data = NULL; struct device_node *guts_node;
u64 size; struct page *p; int ret = 0; int irq;
phys_addr_t ppaact_phys;
phys_addr_t spaact_phys; struct ome *omt;
phys_addr_t omt_phys;
size_t mem_size = 0; unsignedint order = 0;
u32 csd_port_id = 0; unsigned i; /* * enumerate all PAMUs and allocate and setup PAMU tables * for each of them, * NOTE : All PAMUs share the same LIODN tables.
*/
if (WARN_ON(probed)) return -EBUSY;
pamu_regs = of_iomap(dev->of_node, 0); if (!pamu_regs) {
dev_err(dev, "ioremap of PAMU node failed\n"); return -ENOMEM;
}
of_get_address(dev->of_node, 0, &size, NULL);
irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) {
dev_warn(dev, "no interrupts listed in PAMU node\n"); goto error;
}
data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) {
ret = -ENOMEM; goto error;
}
data->pamu_reg_base = pamu_regs;
data->count = size / PAMU_OFFSET;
/* The ISR needs access to the regs, so we won't iounmap them */
ret = request_irq(irq, pamu_av_isr, 0, "pamu", data); if (ret < 0) {
dev_err(dev, "error %i installing ISR for irq %i\n", ret, irq); goto error;
}
guts_node = of_find_matching_node(NULL, guts_device_ids); if (!guts_node) {
dev_err(dev, "could not find GUTS node %pOF\n", dev->of_node);
ret = -ENODEV; goto error;
}
guts_regs = of_iomap(guts_node, 0);
of_node_put(guts_node); if (!guts_regs) {
dev_err(dev, "ioremap of GUTS node failed\n");
ret = -ENODEV; goto error;
}
/* read in the PAMU capability registers */
get_pamu_cap_values((unsignedlong)pamu_regs); /* * To simplify the allocation of a coherency domain, we allocate the * PAACT and the OMT in the same memory buffer. Unfortunately, this * wastes more memory compared to allocating the buffers separately.
*/ /* Determine how much memory we need */
mem_size = (PAGE_SIZE << get_order(PAACT_SIZE)) +
(PAGE_SIZE << get_order(SPAACT_SIZE)) +
(PAGE_SIZE << get_order(OMT_SIZE));
order = get_order(mem_size);
p = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); if (!p) {
dev_err(dev, "unable to allocate PAACT/SPAACT/OMT block\n");
ret = -ENOMEM; goto error;
}
/* Make sure the memory is naturally aligned */ if (ppaact_phys & ((PAGE_SIZE << order) - 1)) {
dev_err(dev, "PAACT/OMT block is unaligned\n");
ret = -ENOMEM; goto error;
}
/* Check to see if we need to implement the work-around on this SOC */
/* Determine the Port ID for our coherence subdomain */ for (i = 0; i < ARRAY_SIZE(port_id_map); i++) { if (port_id_map[i].svr == (mfspr(SPRN_SVR) & ~SVR_SECURITY)) {
csd_port_id = port_id_map[i].port_id;
dev_dbg(dev, "found matching SVR %08x\n",
port_id_map[i].svr); break;
}
}
if (csd_port_id) {
dev_dbg(dev, "creating coherency subdomain at address %pa, size %zu, port id 0x%08x",
&ppaact_phys, mem_size, csd_port_id);
ret = create_csd(ppaact_phys, mem_size, csd_port_id); if (ret) {
dev_err(dev, "could not create coherence subdomain\n"); goto error;
}
}
static __init int fsl_pamu_init(void)
{ struct platform_device *pdev = NULL; struct device_node *np; int ret;
/* * The normal OF process calls the probe function at some * indeterminate later time, after most drivers have loaded. This is * too late for us, because PAMU clients (like the Qman driver) * depend on PAMU being initialized early. * * So instead, we "manually" call our probe function by creating the * platform devices ourselves.
*/
/* * We assume that there is only one PAMU node in the device tree. A * single PAMU node represents all of the PAMU devices in the SOC * already. Everything else already makes that assumption, and the * binding for the PAMU nodes doesn't allow for any parent-child * relationships anyway. In other words, support for more than one * PAMU node would require significant changes to a lot of code.
*/
np = of_find_compatible_node(NULL, NULL, "fsl,pamu"); if (!np) {
pr_err("could not find a PAMU node\n"); return -ENODEV;
}
ret = platform_driver_register(&fsl_of_pamu_driver); if (ret) {
pr_err("could not register driver (err=%i)\n", ret); goto error_driver_register;
}
pdev = platform_device_alloc("fsl-of-pamu", 0); if (!pdev) {
pr_err("could not allocate device %pOF\n", np);
ret = -ENOMEM; goto error_device_alloc;
}
pdev->dev.of_node = of_node_get(np);
ret = pamu_domain_init(); if (ret) goto error_device_add;
ret = platform_device_add(pdev); if (ret) {
pr_err("could not add device %pOF (err=%i)\n", np, ret); goto error_device_add;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.