diff options
Diffstat (limited to 'drivers/irqchip/irq-gic-v3-its.c')
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 141 |
1 files changed, 73 insertions, 68 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index c5dee300e8a3..23201004fd7a 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -37,7 +37,6 @@ #include <linux/irqchip.h> #include <linux/irqchip/arm-gic-v3.h> -#include <asm/cacheflush.h> #include <asm/cputype.h> #include <asm/exception.h> @@ -162,7 +161,7 @@ struct its_cmd_desc { struct its_device *dev; u32 phys_id; u32 event_id; - } its_mapvi_cmd; + } its_mapti_cmd; struct { struct its_device *dev; @@ -194,58 +193,56 @@ struct its_cmd_block { typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *, struct its_cmd_desc *); +static void its_mask_encode(u64 *raw_cmd, u64 val, int h, int l) +{ + u64 mask = GENMASK_ULL(h, l); + *raw_cmd &= ~mask; + *raw_cmd |= (val << l) & mask; +} + static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr) { - cmd->raw_cmd[0] &= ~0xffUL; - cmd->raw_cmd[0] |= cmd_nr; + its_mask_encode(&cmd->raw_cmd[0], cmd_nr, 7, 0); } static void its_encode_devid(struct its_cmd_block *cmd, u32 devid) { - cmd->raw_cmd[0] &= BIT_ULL(32) - 1; - cmd->raw_cmd[0] |= ((u64)devid) << 32; + its_mask_encode(&cmd->raw_cmd[0], devid, 63, 32); } static void its_encode_event_id(struct its_cmd_block *cmd, u32 id) { - cmd->raw_cmd[1] &= ~0xffffffffUL; - cmd->raw_cmd[1] |= id; + its_mask_encode(&cmd->raw_cmd[1], id, 31, 0); } static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id) { - cmd->raw_cmd[1] &= 0xffffffffUL; - cmd->raw_cmd[1] |= ((u64)phys_id) << 32; + its_mask_encode(&cmd->raw_cmd[1], phys_id, 63, 32); } static void its_encode_size(struct its_cmd_block *cmd, u8 size) { - cmd->raw_cmd[1] &= ~0x1fUL; - cmd->raw_cmd[1] |= size & 0x1f; + its_mask_encode(&cmd->raw_cmd[1], size, 4, 0); } static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr) { - cmd->raw_cmd[2] &= ~0xffffffffffffUL; - cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00UL; + its_mask_encode(&cmd->raw_cmd[2], itt_addr >> 8, 50, 8); } static void its_encode_valid(struct its_cmd_block *cmd, int valid) { - cmd->raw_cmd[2] &= ~(1UL << 63); - cmd->raw_cmd[2] |= ((u64)!!valid) << 63; + its_mask_encode(&cmd->raw_cmd[2], !!valid, 63, 63); } static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr) { - cmd->raw_cmd[2] &= ~(0xffffffffUL << 16); - cmd->raw_cmd[2] |= (target_addr & (0xffffffffUL << 16)); + its_mask_encode(&cmd->raw_cmd[2], target_addr >> 16, 50, 16); } static void its_encode_collection(struct its_cmd_block *cmd, u16 col) { - cmd->raw_cmd[2] &= ~0xffffUL; - cmd->raw_cmd[2] |= col; + its_mask_encode(&cmd->raw_cmd[2], col, 15, 0); } static inline void its_fixup_cmd(struct its_cmd_block *cmd) @@ -290,18 +287,18 @@ static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd, return desc->its_mapc_cmd.col; } -static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd, +static struct its_collection *its_build_mapti_cmd(struct its_cmd_block *cmd, struct its_cmd_desc *desc) { struct its_collection *col; - col = dev_event_to_col(desc->its_mapvi_cmd.dev, - desc->its_mapvi_cmd.event_id); + col = dev_event_to_col(desc->its_mapti_cmd.dev, + desc->its_mapti_cmd.event_id); - its_encode_cmd(cmd, GITS_CMD_MAPVI); - its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id); - its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id); + its_encode_cmd(cmd, GITS_CMD_MAPTI); + its_encode_devid(cmd, desc->its_mapti_cmd.dev->device_id); + its_encode_event_id(cmd, desc->its_mapti_cmd.event_id); + its_encode_phys_id(cmd, desc->its_mapti_cmd.phys_id); its_encode_collection(cmd, col->col_id); its_fixup_cmd(cmd); @@ -414,6 +411,12 @@ static struct its_cmd_block *its_allocate_entry(struct its_node *its) if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES)) its->cmd_write = its->cmd_base; + /* Clear command */ + cmd->raw_cmd[0] = 0; + cmd->raw_cmd[1] = 0; + cmd->raw_cmd[2] = 0; + cmd->raw_cmd[3] = 0; + return cmd; } @@ -433,7 +436,7 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd) * the ITS. */ if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING) - __flush_dcache_area(cmd, sizeof(*cmd)); + gic_flush_dcache_to_poc(cmd, sizeof(*cmd)); else dsb(ishst); } @@ -532,15 +535,15 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col, its_send_single_command(its, its_build_mapc_cmd, &desc); } -static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id) +static void its_send_mapti(struct its_device *dev, u32 irq_id, u32 id) { struct its_cmd_desc desc; - desc.its_mapvi_cmd.dev = dev; - desc.its_mapvi_cmd.phys_id = irq_id; - desc.its_mapvi_cmd.event_id = id; + desc.its_mapti_cmd.dev = dev; + desc.its_mapti_cmd.phys_id = irq_id; + desc.its_mapti_cmd.event_id = id; - its_send_single_command(dev->its, its_build_mapvi_cmd, &desc); + its_send_single_command(dev->its, its_build_mapti_cmd, &desc); } static void its_send_movi(struct its_device *dev, @@ -602,7 +605,7 @@ static void lpi_set_config(struct irq_data *d, bool enable) * Humpf... */ if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING) - __flush_dcache_area(cfg, sizeof(*cfg)); + gic_flush_dcache_to_poc(cfg, sizeof(*cfg)); else dsb(ishst); its_send_inv(its_dev, id); @@ -657,8 +660,8 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) its = its_dev->its; addr = its->phys_base + GITS_TRANSLATER; - msg->address_lo = addr & ((1UL << 32) - 1); - msg->address_hi = addr >> 32; + msg->address_lo = lower_32_bits(addr); + msg->address_hi = upper_32_bits(addr); msg->data = its_get_event_id(d); iommu_dma_map_msi_msg(d->irq, msg); @@ -817,7 +820,7 @@ static int __init its_alloc_lpi_tables(void) LPI_PROPBASE_SZ); /* Make sure the GIC will observe the written configuration */ - __flush_dcache_area(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ); + gic_flush_dcache_to_poc(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ); return 0; } @@ -825,7 +828,7 @@ static int __init its_alloc_lpi_tables(void) static const char *its_base_type_string[] = { [GITS_BASER_TYPE_DEVICE] = "Devices", [GITS_BASER_TYPE_VCPU] = "Virtual CPUs", - [GITS_BASER_TYPE_CPU] = "Physical CPUs", + [GITS_BASER_TYPE_RESERVED3] = "Reserved (3)", [GITS_BASER_TYPE_COLLECTION] = "Interrupt Collections", [GITS_BASER_TYPE_RESERVED5] = "Reserved (5)", [GITS_BASER_TYPE_RESERVED6] = "Reserved (6)", @@ -836,7 +839,7 @@ static u64 its_read_baser(struct its_node *its, struct its_baser *baser) { u32 idx = baser - its->tables; - return readq_relaxed(its->base + GITS_BASER + (idx << 3)); + return gits_read_baser(its->base + GITS_BASER + (idx << 3)); } static void its_write_baser(struct its_node *its, struct its_baser *baser, @@ -844,7 +847,7 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, { u32 idx = baser - its->tables; - writeq_relaxed(val, its->base + GITS_BASER + (idx << 3)); + gits_write_baser(val, its->base + GITS_BASER + (idx << 3)); baser->val = its_read_baser(its, baser); } @@ -910,7 +913,7 @@ retry_baser: shr = tmp & GITS_BASER_SHAREABILITY_MASK; if (!shr) { cache = GITS_BASER_nC; - __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order)); + gic_flush_dcache_to_poc(base, PAGE_ORDER_TO_SIZE(order)); } goto retry_baser; } @@ -935,9 +938,9 @@ retry_baser: } if (val != tmp) { - pr_err("ITS@%pa: %s doesn't stick: %lx %lx\n", + pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n", &its->phys_base, its_base_type_string[type], - (unsigned long) val, (unsigned long) tmp); + val, tmp); free_pages((unsigned long)base, order); return -ENXIO; } @@ -948,7 +951,7 @@ retry_baser: tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; pr_info("ITS@%pa: allocated %d %s @%lx (%s, esz %d, psz %dK, shr %d)\n", - &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / tmp), + &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / (int)tmp), its_base_type_string[type], (unsigned long)virt_to_phys(base), indirect ? "indirect" : "flat", (int)esz, @@ -961,7 +964,7 @@ static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser u32 psz, u32 *order) { u64 esz = GITS_BASER_ENTRY_SIZE(its_read_baser(its, baser)); - u64 val = GITS_BASER_InnerShareable | GITS_BASER_WaWb; + u64 val = GITS_BASER_InnerShareable | GITS_BASER_RaWaWb; u32 ids = its->device_ids; u32 new_order = *order; bool indirect = false; @@ -983,7 +986,7 @@ static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser * which is reported by ITS hardware times lvl1 table * entry size. */ - ids -= ilog2(psz / esz); + ids -= ilog2(psz / (int)esz); esz = GITS_LVL1_ENTRY_SIZE; } } @@ -998,7 +1001,7 @@ static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser new_order = max_t(u32, get_order(esz << ids), new_order); if (new_order >= MAX_ORDER) { new_order = MAX_ORDER - 1; - ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / esz); + ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz); pr_warn("ITS@%pa: Device Table too large, reduce ids %u->%u\n", &its->phys_base, its->device_ids, ids); } @@ -1026,7 +1029,7 @@ static int its_alloc_tables(struct its_node *its) u64 typer = gic_read_typer(its->base + GITS_TYPER); u32 ids = GITS_TYPER_DEVBITS(typer); u64 shr = GITS_BASER_InnerShareable; - u64 cache = GITS_BASER_WaWb; + u64 cache = GITS_BASER_RaWaWb; u32 psz = SZ_64K; int err, i; @@ -1102,7 +1105,7 @@ static void its_cpu_init_lpis(void) } /* Make sure the GIC will observe the zero-ed page */ - __flush_dcache_area(page_address(pend_page), LPI_PENDBASE_SZ); + gic_flush_dcache_to_poc(page_address(pend_page), LPI_PENDBASE_SZ); paddr = page_to_phys(pend_page); pr_info("CPU%d: using LPI pending table @%pa\n", @@ -1123,11 +1126,11 @@ static void its_cpu_init_lpis(void) /* set PROPBASE */ val = (page_to_phys(gic_rdists->prop_page) | GICR_PROPBASER_InnerShareable | - GICR_PROPBASER_WaWb | + GICR_PROPBASER_RaWaWb | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); - writeq_relaxed(val, rbase + GICR_PROPBASER); - tmp = readq_relaxed(rbase + GICR_PROPBASER); + gicr_write_propbaser(val, rbase + GICR_PROPBASER); + tmp = gicr_read_propbaser(rbase + GICR_PROPBASER); if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { @@ -1139,7 +1142,7 @@ static void its_cpu_init_lpis(void) val &= ~(GICR_PROPBASER_SHAREABILITY_MASK | GICR_PROPBASER_CACHEABILITY_MASK); val |= GICR_PROPBASER_nC; - writeq_relaxed(val, rbase + GICR_PROPBASER); + gicr_write_propbaser(val, rbase + GICR_PROPBASER); } pr_info_once("GIC: using cache flushing for LPI property table\n"); gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING; @@ -1148,10 +1151,10 @@ static void its_cpu_init_lpis(void) /* set PENDBASE */ val = (page_to_phys(pend_page) | GICR_PENDBASER_InnerShareable | - GICR_PENDBASER_WaWb); + GICR_PENDBASER_RaWaWb); - writeq_relaxed(val, rbase + GICR_PENDBASER); - tmp = readq_relaxed(rbase + GICR_PENDBASER); + gicr_write_pendbaser(val, rbase + GICR_PENDBASER); + tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { /* @@ -1161,7 +1164,7 @@ static void its_cpu_init_lpis(void) val &= ~(GICR_PENDBASER_SHAREABILITY_MASK | GICR_PENDBASER_CACHEABILITY_MASK); val |= GICR_PENDBASER_nC; - writeq_relaxed(val, rbase + GICR_PENDBASER); + gicr_write_pendbaser(val, rbase + GICR_PENDBASER); } /* Enable LPIs */ @@ -1287,13 +1290,13 @@ static bool its_alloc_device_table(struct its_node *its, u32 dev_id) /* Flush Lvl2 table to PoC if hw doesn't support coherency */ if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) - __flush_dcache_area(page_address(page), baser->psz); + gic_flush_dcache_to_poc(page_address(page), baser->psz); table[idx] = cpu_to_le64(page_to_phys(page) | GITS_BASER_VALID); /* Flush Lvl1 entry to PoC if hw doesn't support coherency */ if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) - __flush_dcache_area(table + idx, GITS_LVL1_ENTRY_SIZE); + gic_flush_dcache_to_poc(table + idx, GITS_LVL1_ENTRY_SIZE); /* Ensure updated table contents are visible to ITS hardware */ dsb(sy); @@ -1340,7 +1343,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, return NULL; } - __flush_dcache_area(itt, sz); + gic_flush_dcache_to_poc(itt, sz); dev->its = its; dev->itt = itt; @@ -1499,7 +1502,7 @@ static void its_irq_domain_activate(struct irq_domain *domain, its_dev->event_map.col_map[event] = cpumask_first(cpu_mask); /* Map the GIC IRQ and event to the device */ - its_send_mapvi(its_dev, d->hwirq, event); + its_send_mapti(its_dev, d->hwirq, event); } static void its_irq_domain_deactivate(struct irq_domain *domain, @@ -1643,6 +1646,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) inner_domain->parent = its_parent; inner_domain->bus_token = DOMAIN_BUS_NEXUS; + inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP; info->ops = &its_msi_domain_ops; info->data = its; inner_domain->host_data = info; @@ -1694,7 +1698,8 @@ static int __init its_probe_one(struct resource *res, its->ite_size = ((gic_read_typer(its_base + GITS_TYPER) >> 4) & 0xf) + 1; its->numa_node = numa_node; - its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); + its->cmd_base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(ITS_CMD_QUEUE_SZ)); if (!its->cmd_base) { err = -ENOMEM; goto out_free_its; @@ -1712,13 +1717,13 @@ static int __init its_probe_one(struct resource *res, goto out_free_tables; baser = (virt_to_phys(its->cmd_base) | - GITS_CBASER_WaWb | + GITS_CBASER_RaWaWb | GITS_CBASER_InnerShareable | (ITS_CMD_QUEUE_SZ / SZ_4K - 1) | GITS_CBASER_VALID); - writeq_relaxed(baser, its->base + GITS_CBASER); - tmp = readq_relaxed(its->base + GITS_CBASER); + gits_write_cbaser(baser, its->base + GITS_CBASER); + tmp = gits_read_cbaser(its->base + GITS_CBASER); if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) { @@ -1730,13 +1735,13 @@ static int __init its_probe_one(struct resource *res, baser &= ~(GITS_CBASER_SHAREABILITY_MASK | GITS_CBASER_CACHEABILITY_MASK); baser |= GITS_CBASER_nC; - writeq_relaxed(baser, its->base + GITS_CBASER); + gits_write_cbaser(baser, its->base + GITS_CBASER); } pr_info("ITS: using cache flushing for cmd queue\n"); its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING; } - writeq_relaxed(0, its->base + GITS_CWRITER); + gits_write_cwriter(0, its->base + GITS_CWRITER); writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); err = its_init_domain(handle, its); @@ -1752,7 +1757,7 @@ static int __init its_probe_one(struct resource *res, out_free_tables: its_free_tables(its); out_free_cmd: - kfree(its->cmd_base); + free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); out_free_its: kfree(its); out_unmap: |