summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/irqchip/irq-gic-v3.c42
-rw-r--r--include/linux/irqchip/arm-gic-v3.h12
2 files changed, 47 insertions, 7 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index f5dbdbf3e98d..d3727e877872 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -104,6 +104,7 @@ static DEFINE_PER_CPU(bool, has_rss);
104enum gic_intid_range { 104enum gic_intid_range {
105 PPI_RANGE, 105 PPI_RANGE,
106 SPI_RANGE, 106 SPI_RANGE,
107 EPPI_RANGE,
107 ESPI_RANGE, 108 ESPI_RANGE,
108 LPI_RANGE, 109 LPI_RANGE,
109 __INVALID_RANGE__ 110 __INVALID_RANGE__
@@ -116,6 +117,8 @@ static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
116 return PPI_RANGE; 117 return PPI_RANGE;
117 case 32 ... 1019: 118 case 32 ... 1019:
118 return SPI_RANGE; 119 return SPI_RANGE;
120 case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63):
121 return EPPI_RANGE;
119 case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023): 122 case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023):
120 return ESPI_RANGE; 123 return ESPI_RANGE;
121 case 8192 ... GENMASK(23, 0): 124 case 8192 ... GENMASK(23, 0):
@@ -137,13 +140,15 @@ static inline unsigned int gic_irq(struct irq_data *d)
137 140
138static inline int gic_irq_in_rdist(struct irq_data *d) 141static inline int gic_irq_in_rdist(struct irq_data *d)
139{ 142{
140 return get_intid_range(d) == PPI_RANGE; 143 enum gic_intid_range range = get_intid_range(d);
144 return range == PPI_RANGE || range == EPPI_RANGE;
141} 145}
142 146
143static inline void __iomem *gic_dist_base(struct irq_data *d) 147static inline void __iomem *gic_dist_base(struct irq_data *d)
144{ 148{
145 switch (get_intid_range(d)) { 149 switch (get_intid_range(d)) {
146 case PPI_RANGE: 150 case PPI_RANGE:
151 case EPPI_RANGE:
147 /* SGI+PPI -> SGI_base for this CPU */ 152 /* SGI+PPI -> SGI_base for this CPU */
148 return gic_data_rdist_sgi_base(); 153 return gic_data_rdist_sgi_base();
149 154
@@ -242,6 +247,14 @@ static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index)
242 case SPI_RANGE: 247 case SPI_RANGE:
243 *index = d->hwirq; 248 *index = d->hwirq;
244 return offset; 249 return offset;
250 case EPPI_RANGE:
251 /*
252 * Contrary to the ESPI range, the EPPI range is contiguous
253 * to the PPI range in the registers, so let's adjust the
254 * displacement accordingly. Consistency is overrated.
255 */
256 *index = d->hwirq - EPPI_BASE_INTID + 32;
257 return offset;
245 case ESPI_RANGE: 258 case ESPI_RANGE:
246 *index = d->hwirq - ESPI_BASE_INTID; 259 *index = d->hwirq - ESPI_BASE_INTID;
247 switch (offset) { 260 switch (offset) {
@@ -414,6 +427,8 @@ static u32 gic_get_ppi_index(struct irq_data *d)
414 switch (get_intid_range(d)) { 427 switch (get_intid_range(d)) {
415 case PPI_RANGE: 428 case PPI_RANGE:
416 return d->hwirq - 16; 429 return d->hwirq - 16;
430 case EPPI_RANGE:
431 return d->hwirq - EPPI_BASE_INTID + 16;
417 default: 432 default:
418 unreachable(); 433 unreachable();
419 } 434 }
@@ -507,6 +522,7 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d)
507 522
508static int gic_set_type(struct irq_data *d, unsigned int type) 523static int gic_set_type(struct irq_data *d, unsigned int type)
509{ 524{
525 enum gic_intid_range range;
510 unsigned int irq = gic_irq(d); 526 unsigned int irq = gic_irq(d);
511 void (*rwp_wait)(void); 527 void (*rwp_wait)(void);
512 void __iomem *base; 528 void __iomem *base;
@@ -517,9 +533,11 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
517 if (irq < 16) 533 if (irq < 16)
518 return -EINVAL; 534 return -EINVAL;
519 535
536 range = get_intid_range(d);
537
520 /* SPIs have restrictions on the supported types */ 538 /* SPIs have restrictions on the supported types */
521 if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH && 539 if ((range == SPI_RANGE || range == ESPI_RANGE) &&
522 type != IRQ_TYPE_EDGE_RISING) 540 type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
523 return -EINVAL; 541 return -EINVAL;
524 542
525 if (gic_irq_in_rdist(d)) { 543 if (gic_irq_in_rdist(d)) {
@@ -533,9 +551,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
533 offset = convert_offset_index(d, GICD_ICFGR, &index); 551 offset = convert_offset_index(d, GICD_ICFGR, &index);
534 552
535 ret = gic_configure_irq(index, type, base + offset, rwp_wait); 553 ret = gic_configure_irq(index, type, base + offset, rwp_wait);
536 if (ret && irq < 32) { 554 if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) {
537 /* Misconfigured PPIs are usually not fatal */ 555 /* Misconfigured PPIs are usually not fatal */
538 pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16); 556 pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq);
539 ret = 0; 557 ret = 0;
540 } 558 }
541 559
@@ -833,7 +851,7 @@ static int __gic_update_rdist_properties(struct redist_region *region,
833 u64 typer = gic_read_typer(ptr + GICR_TYPER); 851 u64 typer = gic_read_typer(ptr + GICR_TYPER);
834 gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS); 852 gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
835 gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS); 853 gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS);
836 gic_data.ppi_nr = 16; 854 gic_data.ppi_nr = min(GICR_TYPER_NR_PPIS(typer), gic_data.ppi_nr);
837 855
838 return 1; 856 return 1;
839} 857}
@@ -1222,6 +1240,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
1222 1240
1223 switch (__get_intid_range(hw)) { 1241 switch (__get_intid_range(hw)) {
1224 case PPI_RANGE: 1242 case PPI_RANGE:
1243 case EPPI_RANGE:
1225 irq_set_percpu_devid(irq); 1244 irq_set_percpu_devid(irq);
1226 irq_domain_set_info(d, irq, hw, chip, d->host_data, 1245 irq_domain_set_info(d, irq, hw, chip, d->host_data,
1227 handle_percpu_devid_irq, NULL, NULL); 1246 handle_percpu_devid_irq, NULL, NULL);
@@ -1266,15 +1285,24 @@ static int gic_irq_domain_translate(struct irq_domain *d,
1266 *hwirq = fwspec->param[1] + 32; 1285 *hwirq = fwspec->param[1] + 32;
1267 break; 1286 break;
1268 case 1: /* PPI */ 1287 case 1: /* PPI */
1269 case GIC_IRQ_TYPE_PARTITION:
1270 *hwirq = fwspec->param[1] + 16; 1288 *hwirq = fwspec->param[1] + 16;
1271 break; 1289 break;
1272 case 2: /* ESPI */ 1290 case 2: /* ESPI */
1273 *hwirq = fwspec->param[1] + ESPI_BASE_INTID; 1291 *hwirq = fwspec->param[1] + ESPI_BASE_INTID;
1274 break; 1292 break;
1293 case 3: /* EPPI */
1294 *hwirq = fwspec->param[1] + EPPI_BASE_INTID;
1295 break;
1275 case GIC_IRQ_TYPE_LPI: /* LPI */ 1296 case GIC_IRQ_TYPE_LPI: /* LPI */
1276 *hwirq = fwspec->param[1]; 1297 *hwirq = fwspec->param[1];
1277 break; 1298 break;
1299 case GIC_IRQ_TYPE_PARTITION:
1300 *hwirq = fwspec->param[1];
1301 if (fwspec->param[1] >= 16)
1302 *hwirq += EPPI_BASE_INTID - 16;
1303 else
1304 *hwirq += 16;
1305 break;
1278 default: 1306 default:
1279 return -EINVAL; 1307 return -EINVAL;
1280 } 1308 }
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index c523bf1faa55..9ec3349dee04 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -124,6 +124,18 @@
124 124
125#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) 125#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff)
126 126
127#define EPPI_BASE_INTID 1056
128
129#define GICR_TYPER_NR_PPIS(r) \
130 ({ \
131 unsigned int __ppinum = ((r) >> 27) & 0x1f; \
132 unsigned int __nr_ppis = 16; \
133 if (__ppinum == 1 || __ppinum == 2) \
134 __nr_ppis += __ppinum * 32; \
135 \
136 __nr_ppis; \
137 })
138
127#define GICR_WAKER_ProcessorSleep (1U << 1) 139#define GICR_WAKER_ProcessorSleep (1U << 1)
128#define GICR_WAKER_ChildrenAsleep (1U << 2) 140#define GICR_WAKER_ChildrenAsleep (1U << 2)
129 141