1873e65bcSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 22832a81dSGeoff Levand /* 32832a81dSGeoff Levand * PS3 interrupt routines. 42832a81dSGeoff Levand * 52832a81dSGeoff Levand * Copyright (C) 2006 Sony Computer Entertainment Inc. 62832a81dSGeoff Levand * Copyright 2006 Sony Corp. 72832a81dSGeoff Levand */ 82832a81dSGeoff Levand 92832a81dSGeoff Levand #include <linux/kernel.h> 104b16f8e2SPaul Gortmaker #include <linux/export.h> 112832a81dSGeoff Levand #include <linux/irq.h> 1213a9a5d1SMarc Zyngier #include <linux/irqdomain.h> 132832a81dSGeoff Levand 142832a81dSGeoff Levand #include <asm/machdep.h> 152832a81dSGeoff Levand #include <asm/udbg.h> 162832a81dSGeoff Levand #include <asm/lv1call.h> 1742d284bcSStephen Rothwell #include <asm/smp.h> 182832a81dSGeoff Levand 192832a81dSGeoff Levand #include "platform.h" 202832a81dSGeoff Levand 212832a81dSGeoff Levand #if defined(DEBUG) 2283bb643dSGeert Uytterhoeven #define DBG udbg_printf 2332b9074bSGeoff Levand #define FAIL udbg_printf 242832a81dSGeoff Levand #else 2532b9074bSGeoff Levand #define DBG pr_devel 2632b9074bSGeoff Levand #define FAIL pr_debug 272832a81dSGeoff Levand #endif 282832a81dSGeoff Levand 292832a81dSGeoff Levand /** 30861be32cSGeoff Levand * struct ps3_bmp - a per cpu irq status and mask bitmap structure 31861be32cSGeoff Levand * @status: 256 bit status bitmap indexed by plug 3232b9074bSGeoff Levand * @unused_1: Alignment 33861be32cSGeoff Levand * @mask: 256 bit mask bitmap indexed by plug 3432b9074bSGeoff Levand * @unused_2: Alignment 35861be32cSGeoff Levand * 36b595076aSUwe Kleine-König * The HV maintains per SMT thread mappings of HV outlet to HV plug on 37861be32cSGeoff Levand * behalf of the guest. These mappings are implemented as 256 bit guest 38861be32cSGeoff Levand * supplied bitmaps indexed by plug number. The addresses of the bitmaps 39861be32cSGeoff Levand * are registered with the HV through lv1_configure_irq_state_bitmap(). 4057715765SGeoff Levand * The HV requires that the 512 bits of status + mask not cross a page 4157715765SGeoff Levand * boundary. PS3_BMP_MINALIGN is used to define this minimal 64 byte 4257715765SGeoff Levand * alignment. 43861be32cSGeoff Levand * 44861be32cSGeoff Levand * The HV supports 256 plugs per thread, assigned as {0..255}, for a total 45861be32cSGeoff Levand * of 512 plugs supported on a processor. To simplify the logic this 46861be32cSGeoff Levand * implementation equates HV plug value to Linux virq value, constrains each 47861be32cSGeoff Levand * interrupt to have a system wide unique plug number, and limits the range 48861be32cSGeoff Levand * of the plug values to map into the first dword of the bitmaps. This 49*7c576f4dSMarc Zyngier * gives a usable range of plug values of {NR_IRQS_LEGACY..63}. Note 50861be32cSGeoff Levand * that there is no constraint on how many in this set an individual thread 51861be32cSGeoff Levand * can acquire. 5246ca0d15SStephen Rothwell * 5346ca0d15SStephen Rothwell * The mask is declared as unsigned long so we can use set/clear_bit on it. 54861be32cSGeoff Levand */ 55861be32cSGeoff Levand 5657715765SGeoff Levand #define PS3_BMP_MINALIGN 64 5757715765SGeoff Levand 58861be32cSGeoff Levand struct ps3_bmp { 59861be32cSGeoff Levand struct { 60861be32cSGeoff Levand u64 status; 61861be32cSGeoff Levand u64 unused_1[3]; 6246ca0d15SStephen Rothwell unsigned long mask; 63861be32cSGeoff Levand u64 unused_2[3]; 64861be32cSGeoff Levand }; 65861be32cSGeoff Levand }; 66861be32cSGeoff Levand 67861be32cSGeoff Levand /** 68861be32cSGeoff Levand * struct ps3_private - a per cpu data structure 69861be32cSGeoff Levand * @bmp: ps3_bmp structure 70446957baSAdam Buchbinder * @bmp_lock: Synchronize access to bmp. 7132b9074bSGeoff Levand * @ipi_debug_brk_mask: Mask for debug break IPIs 72aab83500SGeoff Levand * @ppe_id: HV logical_ppe_id 73aab83500SGeoff Levand * @thread_id: HV thread_id 7432b9074bSGeoff Levand * @ipi_mask: Mask of IPI virqs 75861be32cSGeoff Levand */ 76861be32cSGeoff Levand 77861be32cSGeoff Levand struct ps3_private { 7857715765SGeoff Levand struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); 7932b9074bSGeoff Levand spinlock_t bmp_lock; 80aab83500SGeoff Levand u64 ppe_id; 81aab83500SGeoff Levand u64 thread_id; 8232b9074bSGeoff Levand unsigned long ipi_debug_brk_mask; 8372f3bea0SGeoff Levand unsigned long ipi_mask; 84861be32cSGeoff Levand }; 85861be32cSGeoff Levand 86861be32cSGeoff Levand static DEFINE_PER_CPU(struct ps3_private, ps3_private); 87861be32cSGeoff Levand 88dc4f60c2SGeoff Levand /** 89743c1bb0SGeoff Levand * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp. 90743c1bb0SGeoff Levand * @virq: The assigned Linux virq. 91743c1bb0SGeoff Levand * 92743c1bb0SGeoff Levand * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). 93743c1bb0SGeoff Levand */ 94743c1bb0SGeoff Levand 958126708aSLennert Buytenhek static void ps3_chip_mask(struct irq_data *d) 96743c1bb0SGeoff Levand { 978126708aSLennert Buytenhek struct ps3_private *pd = irq_data_get_irq_chip_data(d); 98743c1bb0SGeoff Levand unsigned long flags; 99743c1bb0SGeoff Levand 10032b9074bSGeoff Levand DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, 1018126708aSLennert Buytenhek pd->thread_id, d->irq); 102743c1bb0SGeoff Levand 103743c1bb0SGeoff Levand local_irq_save(flags); 1048126708aSLennert Buytenhek clear_bit(63 - d->irq, &pd->bmp.mask); 105aab83500SGeoff Levand lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); 106743c1bb0SGeoff Levand local_irq_restore(flags); 107743c1bb0SGeoff Levand } 108743c1bb0SGeoff Levand 109743c1bb0SGeoff Levand /** 110743c1bb0SGeoff Levand * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp. 111743c1bb0SGeoff Levand * @virq: The assigned Linux virq. 112743c1bb0SGeoff Levand * 113743c1bb0SGeoff Levand * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). 114743c1bb0SGeoff Levand */ 115743c1bb0SGeoff Levand 1168126708aSLennert Buytenhek static void ps3_chip_unmask(struct irq_data *d) 117743c1bb0SGeoff Levand { 1188126708aSLennert Buytenhek struct ps3_private *pd = irq_data_get_irq_chip_data(d); 119743c1bb0SGeoff Levand unsigned long flags; 120743c1bb0SGeoff Levand 12132b9074bSGeoff Levand DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, 1228126708aSLennert Buytenhek pd->thread_id, d->irq); 123743c1bb0SGeoff Levand 124743c1bb0SGeoff Levand local_irq_save(flags); 1258126708aSLennert Buytenhek set_bit(63 - d->irq, &pd->bmp.mask); 126aab83500SGeoff Levand lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); 127743c1bb0SGeoff Levand local_irq_restore(flags); 128743c1bb0SGeoff Levand } 129743c1bb0SGeoff Levand 130743c1bb0SGeoff Levand /** 131743c1bb0SGeoff Levand * ps3_chip_eoi - HV end-of-interrupt. 132743c1bb0SGeoff Levand * @virq: The assigned Linux virq. 133743c1bb0SGeoff Levand * 134743c1bb0SGeoff Levand * Calls lv1_end_of_interrupt_ext(). 135743c1bb0SGeoff Levand */ 136743c1bb0SGeoff Levand 1378126708aSLennert Buytenhek static void ps3_chip_eoi(struct irq_data *d) 138743c1bb0SGeoff Levand { 1398126708aSLennert Buytenhek const struct ps3_private *pd = irq_data_get_irq_chip_data(d); 14072f3bea0SGeoff Levand 14172f3bea0SGeoff Levand /* non-IPIs are EOIed here. */ 14272f3bea0SGeoff Levand 14372f3bea0SGeoff Levand if (!test_bit(63 - d->irq, &pd->ipi_mask)) 1448126708aSLennert Buytenhek lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq); 145743c1bb0SGeoff Levand } 146743c1bb0SGeoff Levand 147743c1bb0SGeoff Levand /** 148743c1bb0SGeoff Levand * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip. 149743c1bb0SGeoff Levand */ 150743c1bb0SGeoff Levand 151743c1bb0SGeoff Levand static struct irq_chip ps3_irq_chip = { 152b27df672SThomas Gleixner .name = "ps3", 1538126708aSLennert Buytenhek .irq_mask = ps3_chip_mask, 1548126708aSLennert Buytenhek .irq_unmask = ps3_chip_unmask, 1558126708aSLennert Buytenhek .irq_eoi = ps3_chip_eoi, 156743c1bb0SGeoff Levand }; 157743c1bb0SGeoff Levand 158743c1bb0SGeoff Levand /** 159dc4f60c2SGeoff Levand * ps3_virq_setup - virq related setup. 160dc4f60c2SGeoff Levand * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 161dc4f60c2SGeoff Levand * serviced on. 162dc4f60c2SGeoff Levand * @outlet: The HV outlet from the various create outlet routines. 163dc4f60c2SGeoff Levand * @virq: The assigned Linux virq. 164dc4f60c2SGeoff Levand * 165dc4f60c2SGeoff Levand * Calls irq_create_mapping() to get a virq and sets the chip data to 166dc4f60c2SGeoff Levand * ps3_private data. 167dc4f60c2SGeoff Levand */ 168dc4f60c2SGeoff Levand 169fdedb4caSGeert Uytterhoeven static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, 170861be32cSGeoff Levand unsigned int *virq) 171861be32cSGeoff Levand { 172861be32cSGeoff Levand int result; 173861be32cSGeoff Levand struct ps3_private *pd; 174861be32cSGeoff Levand 175861be32cSGeoff Levand /* This defines the default interrupt distribution policy. */ 176861be32cSGeoff Levand 177861be32cSGeoff Levand if (cpu == PS3_BINDING_CPU_ANY) 178861be32cSGeoff Levand cpu = 0; 179861be32cSGeoff Levand 180861be32cSGeoff Levand pd = &per_cpu(ps3_private, cpu); 181861be32cSGeoff Levand 182861be32cSGeoff Levand *virq = irq_create_mapping(NULL, outlet); 183861be32cSGeoff Levand 184ef24ba70SMichael Ellerman if (!*virq) { 18532b9074bSGeoff Levand FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n", 186861be32cSGeoff Levand __func__, __LINE__, outlet); 187861be32cSGeoff Levand result = -ENOMEM; 188861be32cSGeoff Levand goto fail_create; 189861be32cSGeoff Levand } 190861be32cSGeoff Levand 19132b9074bSGeoff Levand DBG("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, 192861be32cSGeoff Levand outlet, cpu, *virq); 193861be32cSGeoff Levand 194ec775d0eSThomas Gleixner result = irq_set_chip_data(*virq, pd); 195861be32cSGeoff Levand 196861be32cSGeoff Levand if (result) { 19732b9074bSGeoff Levand FAIL("%s:%d: irq_set_chip_data failed\n", 198861be32cSGeoff Levand __func__, __LINE__); 199861be32cSGeoff Levand goto fail_set; 200861be32cSGeoff Levand } 201861be32cSGeoff Levand 2028126708aSLennert Buytenhek ps3_chip_mask(irq_get_irq_data(*virq)); 2039263e85aSGeoff Levand 204861be32cSGeoff Levand return result; 205861be32cSGeoff Levand 206861be32cSGeoff Levand fail_set: 207861be32cSGeoff Levand irq_dispose_mapping(*virq); 208861be32cSGeoff Levand fail_create: 209861be32cSGeoff Levand return result; 210861be32cSGeoff Levand } 211861be32cSGeoff Levand 212dc4f60c2SGeoff Levand /** 213dc4f60c2SGeoff Levand * ps3_virq_destroy - virq related teardown. 214dc4f60c2SGeoff Levand * @virq: The assigned Linux virq. 215dc4f60c2SGeoff Levand * 216dc4f60c2SGeoff Levand * Clears chip data and calls irq_dispose_mapping() for the virq. 217dc4f60c2SGeoff Levand */ 218dc4f60c2SGeoff Levand 219fdedb4caSGeert Uytterhoeven static int ps3_virq_destroy(unsigned int virq) 220dc4f60c2SGeoff Levand { 221ec775d0eSThomas Gleixner const struct ps3_private *pd = irq_get_chip_data(virq); 222dc4f60c2SGeoff Levand 22332b9074bSGeoff Levand DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, 224aab83500SGeoff Levand __LINE__, pd->ppe_id, pd->thread_id, virq); 225dc4f60c2SGeoff Levand 226ec775d0eSThomas Gleixner irq_set_chip_data(virq, NULL); 227dc4f60c2SGeoff Levand irq_dispose_mapping(virq); 228dc4f60c2SGeoff Levand 22932b9074bSGeoff Levand DBG("%s:%d <-\n", __func__, __LINE__); 230dc4f60c2SGeoff Levand return 0; 231dc4f60c2SGeoff Levand } 232dc4f60c2SGeoff Levand 233dc4f60c2SGeoff Levand /** 234dc4f60c2SGeoff Levand * ps3_irq_plug_setup - Generic outlet and virq related setup. 235dc4f60c2SGeoff Levand * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 236dc4f60c2SGeoff Levand * serviced on. 237dc4f60c2SGeoff Levand * @outlet: The HV outlet from the various create outlet routines. 238dc4f60c2SGeoff Levand * @virq: The assigned Linux virq. 239dc4f60c2SGeoff Levand * 240dc4f60c2SGeoff Levand * Sets up virq and connects the irq plug. 241dc4f60c2SGeoff Levand */ 242dc4f60c2SGeoff Levand 243dc4f60c2SGeoff Levand int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, 244dc4f60c2SGeoff Levand unsigned int *virq) 245dc4f60c2SGeoff Levand { 246dc4f60c2SGeoff Levand int result; 247dc4f60c2SGeoff Levand struct ps3_private *pd; 248dc4f60c2SGeoff Levand 249dc4f60c2SGeoff Levand result = ps3_virq_setup(cpu, outlet, virq); 250dc4f60c2SGeoff Levand 251dc4f60c2SGeoff Levand if (result) { 25232b9074bSGeoff Levand FAIL("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__); 253dc4f60c2SGeoff Levand goto fail_setup; 254dc4f60c2SGeoff Levand } 255dc4f60c2SGeoff Levand 256ec775d0eSThomas Gleixner pd = irq_get_chip_data(*virq); 257dc4f60c2SGeoff Levand 258dc4f60c2SGeoff Levand /* Binds outlet to cpu + virq. */ 259dc4f60c2SGeoff Levand 260aab83500SGeoff Levand result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq, 261aab83500SGeoff Levand outlet, 0); 262dc4f60c2SGeoff Levand 263dc4f60c2SGeoff Levand if (result) { 26432b9074bSGeoff Levand FAIL("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", 265dc4f60c2SGeoff Levand __func__, __LINE__, ps3_result(result)); 266dc4f60c2SGeoff Levand result = -EPERM; 267dc4f60c2SGeoff Levand goto fail_connect; 268dc4f60c2SGeoff Levand } 269dc4f60c2SGeoff Levand 270dc4f60c2SGeoff Levand return result; 271dc4f60c2SGeoff Levand 272dc4f60c2SGeoff Levand fail_connect: 273dc4f60c2SGeoff Levand ps3_virq_destroy(*virq); 274dc4f60c2SGeoff Levand fail_setup: 275dc4f60c2SGeoff Levand return result; 276dc4f60c2SGeoff Levand } 277dc4f60c2SGeoff Levand EXPORT_SYMBOL_GPL(ps3_irq_plug_setup); 278dc4f60c2SGeoff Levand 279dc4f60c2SGeoff Levand /** 280dc4f60c2SGeoff Levand * ps3_irq_plug_destroy - Generic outlet and virq related teardown. 281dc4f60c2SGeoff Levand * @virq: The assigned Linux virq. 282dc4f60c2SGeoff Levand * 283dc4f60c2SGeoff Levand * Disconnects the irq plug and tears down virq. 284dc4f60c2SGeoff Levand * Do not call for system bus event interrupts setup with 285dc4f60c2SGeoff Levand * ps3_sb_event_receive_port_setup(). 286dc4f60c2SGeoff Levand */ 287dc4f60c2SGeoff Levand 288dc4f60c2SGeoff Levand int ps3_irq_plug_destroy(unsigned int virq) 289861be32cSGeoff Levand { 290861be32cSGeoff Levand int result; 291ec775d0eSThomas Gleixner const struct ps3_private *pd = irq_get_chip_data(virq); 292861be32cSGeoff Levand 29332b9074bSGeoff Levand DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, 294aab83500SGeoff Levand __LINE__, pd->ppe_id, pd->thread_id, virq); 295861be32cSGeoff Levand 2968126708aSLennert Buytenhek ps3_chip_mask(irq_get_irq_data(virq)); 2979263e85aSGeoff Levand 298aab83500SGeoff Levand result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq); 299861be32cSGeoff Levand 300861be32cSGeoff Levand if (result) 30132b9074bSGeoff Levand FAIL("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", 302861be32cSGeoff Levand __func__, __LINE__, ps3_result(result)); 303861be32cSGeoff Levand 304dc4f60c2SGeoff Levand ps3_virq_destroy(virq); 305dc4f60c2SGeoff Levand 306b1eeb38eSGeert Uytterhoeven return result; 307861be32cSGeoff Levand } 308dc4f60c2SGeoff Levand EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy); 309861be32cSGeoff Levand 310861be32cSGeoff Levand /** 311dc4f60c2SGeoff Levand * ps3_event_receive_port_setup - Setup an event receive port. 312861be32cSGeoff Levand * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 313861be32cSGeoff Levand * serviced on. 3142832a81dSGeoff Levand * @virq: The assigned Linux virq. 3152832a81dSGeoff Levand * 3162832a81dSGeoff Levand * The virq can be used with lv1_connect_interrupt_event_receive_port() to 317dc4f60c2SGeoff Levand * arrange to receive interrupts from system-bus devices, or with 318dc4f60c2SGeoff Levand * ps3_send_event_locally() to signal events. 3192832a81dSGeoff Levand */ 3202832a81dSGeoff Levand 321dc4f60c2SGeoff Levand int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq) 3222832a81dSGeoff Levand { 3232832a81dSGeoff Levand int result; 324b17b3df1SStephen Rothwell u64 outlet; 3252832a81dSGeoff Levand 3262832a81dSGeoff Levand result = lv1_construct_event_receive_port(&outlet); 3272832a81dSGeoff Levand 3282832a81dSGeoff Levand if (result) { 32932b9074bSGeoff Levand FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n", 3302832a81dSGeoff Levand __func__, __LINE__, ps3_result(result)); 331ef24ba70SMichael Ellerman *virq = 0; 3322832a81dSGeoff Levand return result; 3332832a81dSGeoff Levand } 3342832a81dSGeoff Levand 335dc4f60c2SGeoff Levand result = ps3_irq_plug_setup(cpu, outlet, virq); 336861be32cSGeoff Levand BUG_ON(result); 3372832a81dSGeoff Levand 338861be32cSGeoff Levand return result; 3392832a81dSGeoff Levand } 340dc4f60c2SGeoff Levand EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup); 3412832a81dSGeoff Levand 342dc4f60c2SGeoff Levand /** 343dc4f60c2SGeoff Levand * ps3_event_receive_port_destroy - Destroy an event receive port. 344dc4f60c2SGeoff Levand * @virq: The assigned Linux virq. 345dc4f60c2SGeoff Levand * 346dc4f60c2SGeoff Levand * Since ps3_event_receive_port_destroy destroys the receive port outlet, 347dc4f60c2SGeoff Levand * SB devices need to call disconnect_interrupt_event_receive_port() before 348dc4f60c2SGeoff Levand * this. 349dc4f60c2SGeoff Levand */ 350dc4f60c2SGeoff Levand 351dc4f60c2SGeoff Levand int ps3_event_receive_port_destroy(unsigned int virq) 3522832a81dSGeoff Levand { 3532832a81dSGeoff Levand int result; 3542832a81dSGeoff Levand 35532b9074bSGeoff Levand DBG(" -> %s:%d virq %u\n", __func__, __LINE__, virq); 3569263e85aSGeoff Levand 3578126708aSLennert Buytenhek ps3_chip_mask(irq_get_irq_data(virq)); 3582832a81dSGeoff Levand 3592832a81dSGeoff Levand result = lv1_destruct_event_receive_port(virq_to_hw(virq)); 3602832a81dSGeoff Levand 3612832a81dSGeoff Levand if (result) 36232b9074bSGeoff Levand FAIL("%s:%d: lv1_destruct_event_receive_port failed: %s\n", 3632832a81dSGeoff Levand __func__, __LINE__, ps3_result(result)); 3642832a81dSGeoff Levand 3659263e85aSGeoff Levand /* 3669263e85aSGeoff Levand * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu() 3679263e85aSGeoff Levand * calls from interrupt context (smp_call_function) when kexecing. 368dc4f60c2SGeoff Levand */ 369dc4f60c2SGeoff Levand 37032b9074bSGeoff Levand DBG(" <- %s:%d\n", __func__, __LINE__); 3712832a81dSGeoff Levand return result; 3722832a81dSGeoff Levand } 3732832a81dSGeoff Levand 3742832a81dSGeoff Levand int ps3_send_event_locally(unsigned int virq) 3752832a81dSGeoff Levand { 3762832a81dSGeoff Levand return lv1_send_event_locally(virq_to_hw(virq)); 3772832a81dSGeoff Levand } 3782832a81dSGeoff Levand 3792832a81dSGeoff Levand /** 380dc4f60c2SGeoff Levand * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. 381861be32cSGeoff Levand * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 382861be32cSGeoff Levand * serviced on. 3836bb5cf10SGeoff Levand * @dev: The system bus device instance. 3842832a81dSGeoff Levand * @virq: The assigned Linux virq. 3852832a81dSGeoff Levand * 3862832a81dSGeoff Levand * An event irq represents a virtual device interrupt. The interrupt_id 3872832a81dSGeoff Levand * coresponds to the software interrupt number. 3882832a81dSGeoff Levand */ 3892832a81dSGeoff Levand 3906bb5cf10SGeoff Levand int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, 3916bb5cf10SGeoff Levand enum ps3_cpu_binding cpu, unsigned int *virq) 3922832a81dSGeoff Levand { 393dc4f60c2SGeoff Levand /* this should go in system-bus.c */ 394dc4f60c2SGeoff Levand 3952832a81dSGeoff Levand int result; 3962832a81dSGeoff Levand 397dc4f60c2SGeoff Levand result = ps3_event_receive_port_setup(cpu, virq); 3982832a81dSGeoff Levand 3992832a81dSGeoff Levand if (result) 4002832a81dSGeoff Levand return result; 4012832a81dSGeoff Levand 4026bb5cf10SGeoff Levand result = lv1_connect_interrupt_event_receive_port(dev->bus_id, 4036bb5cf10SGeoff Levand dev->dev_id, virq_to_hw(*virq), dev->interrupt_id); 4042832a81dSGeoff Levand 4052832a81dSGeoff Levand if (result) { 40632b9074bSGeoff Levand FAIL("%s:%d: lv1_connect_interrupt_event_receive_port" 4072832a81dSGeoff Levand " failed: %s\n", __func__, __LINE__, 4082832a81dSGeoff Levand ps3_result(result)); 409dc4f60c2SGeoff Levand ps3_event_receive_port_destroy(*virq); 410ef24ba70SMichael Ellerman *virq = 0; 4112832a81dSGeoff Levand return result; 4122832a81dSGeoff Levand } 4132832a81dSGeoff Levand 41432b9074bSGeoff Levand DBG("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, 4156bb5cf10SGeoff Levand dev->interrupt_id, *virq); 4162832a81dSGeoff Levand 4172832a81dSGeoff Levand return 0; 4182832a81dSGeoff Levand } 419dc4f60c2SGeoff Levand EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); 4202832a81dSGeoff Levand 4216bb5cf10SGeoff Levand int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, 4226bb5cf10SGeoff Levand unsigned int virq) 4232832a81dSGeoff Levand { 424dc4f60c2SGeoff Levand /* this should go in system-bus.c */ 425dc4f60c2SGeoff Levand 4262832a81dSGeoff Levand int result; 4272832a81dSGeoff Levand 42832b9074bSGeoff Levand DBG(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, 4296bb5cf10SGeoff Levand dev->interrupt_id, virq); 4302832a81dSGeoff Levand 4316bb5cf10SGeoff Levand result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, 4326bb5cf10SGeoff Levand dev->dev_id, virq_to_hw(virq), dev->interrupt_id); 4332832a81dSGeoff Levand 4342832a81dSGeoff Levand if (result) 43532b9074bSGeoff Levand FAIL("%s:%d: lv1_disconnect_interrupt_event_receive_port" 4362832a81dSGeoff Levand " failed: %s\n", __func__, __LINE__, 4372832a81dSGeoff Levand ps3_result(result)); 4382832a81dSGeoff Levand 439dc4f60c2SGeoff Levand result = ps3_event_receive_port_destroy(virq); 440dc4f60c2SGeoff Levand BUG_ON(result); 4412832a81dSGeoff Levand 4429263e85aSGeoff Levand /* 4439263e85aSGeoff Levand * ps3_event_receive_port_destroy() destroys the IRQ plug, 4449263e85aSGeoff Levand * so don't call ps3_irq_plug_destroy() here. 4459263e85aSGeoff Levand */ 4469263e85aSGeoff Levand 4479263e85aSGeoff Levand result = ps3_virq_destroy(virq); 4489263e85aSGeoff Levand BUG_ON(result); 4499263e85aSGeoff Levand 45032b9074bSGeoff Levand DBG(" <- %s:%d\n", __func__, __LINE__); 4512832a81dSGeoff Levand return result; 4522832a81dSGeoff Levand } 453dc4f60c2SGeoff Levand EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy); 4542832a81dSGeoff Levand 4552832a81dSGeoff Levand /** 456dc4f60c2SGeoff Levand * ps3_io_irq_setup - Setup a system bus io irq. 457dc4f60c2SGeoff Levand * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 458dc4f60c2SGeoff Levand * serviced on. 459dc4f60c2SGeoff Levand * @interrupt_id: The device interrupt id read from the system repository. 460dc4f60c2SGeoff Levand * @virq: The assigned Linux virq. 461dc4f60c2SGeoff Levand * 462dc4f60c2SGeoff Levand * An io irq represents a non-virtualized device interrupt. interrupt_id 463dc4f60c2SGeoff Levand * coresponds to the interrupt number of the interrupt controller. 464dc4f60c2SGeoff Levand */ 465dc4f60c2SGeoff Levand 466dc4f60c2SGeoff Levand int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id, 467dc4f60c2SGeoff Levand unsigned int *virq) 468dc4f60c2SGeoff Levand { 469dc4f60c2SGeoff Levand int result; 470b17b3df1SStephen Rothwell u64 outlet; 471dc4f60c2SGeoff Levand 472dc4f60c2SGeoff Levand result = lv1_construct_io_irq_outlet(interrupt_id, &outlet); 473dc4f60c2SGeoff Levand 474dc4f60c2SGeoff Levand if (result) { 47532b9074bSGeoff Levand FAIL("%s:%d: lv1_construct_io_irq_outlet failed: %s\n", 476dc4f60c2SGeoff Levand __func__, __LINE__, ps3_result(result)); 477dc4f60c2SGeoff Levand return result; 478dc4f60c2SGeoff Levand } 479dc4f60c2SGeoff Levand 480dc4f60c2SGeoff Levand result = ps3_irq_plug_setup(cpu, outlet, virq); 481dc4f60c2SGeoff Levand BUG_ON(result); 482dc4f60c2SGeoff Levand 483dc4f60c2SGeoff Levand return result; 484dc4f60c2SGeoff Levand } 485dc4f60c2SGeoff Levand EXPORT_SYMBOL_GPL(ps3_io_irq_setup); 486dc4f60c2SGeoff Levand 487dc4f60c2SGeoff Levand int ps3_io_irq_destroy(unsigned int virq) 488dc4f60c2SGeoff Levand { 489dc4f60c2SGeoff Levand int result; 4909263e85aSGeoff Levand unsigned long outlet = virq_to_hw(virq); 491dc4f60c2SGeoff Levand 4928126708aSLennert Buytenhek ps3_chip_mask(irq_get_irq_data(virq)); 4939263e85aSGeoff Levand 4949263e85aSGeoff Levand /* 4959263e85aSGeoff Levand * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, 4969263e85aSGeoff Levand * so call ps3_irq_plug_destroy() first. 4979263e85aSGeoff Levand */ 4989263e85aSGeoff Levand 4999263e85aSGeoff Levand result = ps3_irq_plug_destroy(virq); 5009263e85aSGeoff Levand BUG_ON(result); 5019263e85aSGeoff Levand 5029263e85aSGeoff Levand result = lv1_destruct_io_irq_outlet(outlet); 503dc4f60c2SGeoff Levand 504dc4f60c2SGeoff Levand if (result) 50532b9074bSGeoff Levand FAIL("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", 506dc4f60c2SGeoff Levand __func__, __LINE__, ps3_result(result)); 507dc4f60c2SGeoff Levand 508dc4f60c2SGeoff Levand return result; 509dc4f60c2SGeoff Levand } 510dc4f60c2SGeoff Levand EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); 511dc4f60c2SGeoff Levand 512dc4f60c2SGeoff Levand /** 513dc4f60c2SGeoff Levand * ps3_vuart_irq_setup - Setup the system virtual uart virq. 514861be32cSGeoff Levand * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 515861be32cSGeoff Levand * serviced on. 5162832a81dSGeoff Levand * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. 5172832a81dSGeoff Levand * @virq: The assigned Linux virq. 5182832a81dSGeoff Levand * 5192832a81dSGeoff Levand * The system supports only a single virtual uart, so multiple calls without 5202832a81dSGeoff Levand * freeing the interrupt will return a wrong state error. 5212832a81dSGeoff Levand */ 5222832a81dSGeoff Levand 523dc4f60c2SGeoff Levand int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, 524861be32cSGeoff Levand unsigned int *virq) 5252832a81dSGeoff Levand { 5262832a81dSGeoff Levand int result; 527b17b3df1SStephen Rothwell u64 outlet; 528861be32cSGeoff Levand u64 lpar_addr; 5292832a81dSGeoff Levand 530861be32cSGeoff Levand BUG_ON(!is_kernel_addr((u64)virt_addr_bmp)); 5312832a81dSGeoff Levand 5322832a81dSGeoff Levand lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); 5332832a81dSGeoff Levand 5342832a81dSGeoff Levand result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet); 5352832a81dSGeoff Levand 5362832a81dSGeoff Levand if (result) { 53732b9074bSGeoff Levand FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", 5382832a81dSGeoff Levand __func__, __LINE__, ps3_result(result)); 5392832a81dSGeoff Levand return result; 5402832a81dSGeoff Levand } 5412832a81dSGeoff Levand 542dc4f60c2SGeoff Levand result = ps3_irq_plug_setup(cpu, outlet, virq); 543861be32cSGeoff Levand BUG_ON(result); 5442832a81dSGeoff Levand 545861be32cSGeoff Levand return result; 5462832a81dSGeoff Levand } 5477626e78dSGeoff Levand EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup); 5482832a81dSGeoff Levand 549dc4f60c2SGeoff Levand int ps3_vuart_irq_destroy(unsigned int virq) 5502832a81dSGeoff Levand { 5512832a81dSGeoff Levand int result; 5522832a81dSGeoff Levand 5538126708aSLennert Buytenhek ps3_chip_mask(irq_get_irq_data(virq)); 5542832a81dSGeoff Levand result = lv1_deconfigure_virtual_uart_irq(); 5552832a81dSGeoff Levand 5562832a81dSGeoff Levand if (result) { 55732b9074bSGeoff Levand FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", 5582832a81dSGeoff Levand __func__, __LINE__, ps3_result(result)); 5592832a81dSGeoff Levand return result; 5602832a81dSGeoff Levand } 5612832a81dSGeoff Levand 562dc4f60c2SGeoff Levand result = ps3_irq_plug_destroy(virq); 563dc4f60c2SGeoff Levand BUG_ON(result); 5642832a81dSGeoff Levand 5652832a81dSGeoff Levand return result; 5662832a81dSGeoff Levand } 5677626e78dSGeoff Levand EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy); 5682832a81dSGeoff Levand 5692832a81dSGeoff Levand /** 570dc4f60c2SGeoff Levand * ps3_spe_irq_setup - Setup an spe virq. 571861be32cSGeoff Levand * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 572861be32cSGeoff Levand * serviced on. 5732832a81dSGeoff Levand * @spe_id: The spe_id returned from lv1_construct_logical_spe(). 5742832a81dSGeoff Levand * @class: The spe interrupt class {0,1,2}. 5752832a81dSGeoff Levand * @virq: The assigned Linux virq. 5762832a81dSGeoff Levand * 5772832a81dSGeoff Levand */ 5782832a81dSGeoff Levand 579dc4f60c2SGeoff Levand int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, 580861be32cSGeoff Levand unsigned int class, unsigned int *virq) 5812832a81dSGeoff Levand { 5822832a81dSGeoff Levand int result; 583b17b3df1SStephen Rothwell u64 outlet; 5842832a81dSGeoff Levand 5852832a81dSGeoff Levand BUG_ON(class > 2); 5862832a81dSGeoff Levand 5872832a81dSGeoff Levand result = lv1_get_spe_irq_outlet(spe_id, class, &outlet); 5882832a81dSGeoff Levand 5892832a81dSGeoff Levand if (result) { 59032b9074bSGeoff Levand FAIL("%s:%d: lv1_get_spe_irq_outlet failed: %s\n", 5912832a81dSGeoff Levand __func__, __LINE__, ps3_result(result)); 5922832a81dSGeoff Levand return result; 5932832a81dSGeoff Levand } 5942832a81dSGeoff Levand 595dc4f60c2SGeoff Levand result = ps3_irq_plug_setup(cpu, outlet, virq); 596861be32cSGeoff Levand BUG_ON(result); 5972832a81dSGeoff Levand 598861be32cSGeoff Levand return result; 5992832a81dSGeoff Levand } 6002832a81dSGeoff Levand 601dc4f60c2SGeoff Levand int ps3_spe_irq_destroy(unsigned int virq) 6022832a81dSGeoff Levand { 6039263e85aSGeoff Levand int result; 6049263e85aSGeoff Levand 6058126708aSLennert Buytenhek ps3_chip_mask(irq_get_irq_data(virq)); 6069263e85aSGeoff Levand 6079263e85aSGeoff Levand result = ps3_irq_plug_destroy(virq); 608dc4f60c2SGeoff Levand BUG_ON(result); 6099263e85aSGeoff Levand 6109263e85aSGeoff Levand return result; 6112832a81dSGeoff Levand } 6122832a81dSGeoff Levand 613b1eeb38eSGeert Uytterhoeven 6142832a81dSGeoff Levand #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) 6152832a81dSGeoff Levand #define PS3_PLUG_MAX 63 6162832a81dSGeoff Levand 6172832a81dSGeoff Levand #if defined(DEBUG) 618861be32cSGeoff Levand static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, 6192832a81dSGeoff Levand const char* func, int line) 6202832a81dSGeoff Levand { 62132b9074bSGeoff Levand pr_debug("%s:%d: %s %u {%04llx_%04llx_%04llx_%04llx}\n", 6222832a81dSGeoff Levand func, line, header, cpu, 6232832a81dSGeoff Levand *p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff, 6242832a81dSGeoff Levand *p & 0xffff); 6252832a81dSGeoff Levand } 6262832a81dSGeoff Levand 627848cfdc5SGeoff Levand static void __maybe_unused _dump_256_bmp(const char *header, 628861be32cSGeoff Levand const u64 *p, unsigned cpu, const char* func, int line) 6292832a81dSGeoff Levand { 63032b9074bSGeoff Levand pr_debug("%s:%d: %s %u {%016llx:%016llx:%016llx:%016llx}\n", 6312832a81dSGeoff Levand func, line, header, cpu, p[0], p[1], p[2], p[3]); 6322832a81dSGeoff Levand } 6332832a81dSGeoff Levand 6342832a81dSGeoff Levand #define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__) 6359633ac8dSGeoff Levand static void _dump_bmp(struct ps3_private* pd, const char* func, int line) 6362832a81dSGeoff Levand { 6372832a81dSGeoff Levand unsigned long flags; 6382832a81dSGeoff Levand 63932b9074bSGeoff Levand spin_lock_irqsave(&pd->bmp_lock, flags); 640aab83500SGeoff Levand _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line); 64132b9074bSGeoff Levand _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); 64232b9074bSGeoff Levand spin_unlock_irqrestore(&pd->bmp_lock, flags); 6432832a81dSGeoff Levand } 6442832a81dSGeoff Levand 6452832a81dSGeoff Levand #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) 646848cfdc5SGeoff Levand static void __maybe_unused _dump_mask(struct ps3_private *pd, 6472832a81dSGeoff Levand const char* func, int line) 6482832a81dSGeoff Levand { 6492832a81dSGeoff Levand unsigned long flags; 6502832a81dSGeoff Levand 65132b9074bSGeoff Levand spin_lock_irqsave(&pd->bmp_lock, flags); 65232b9074bSGeoff Levand _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); 65332b9074bSGeoff Levand spin_unlock_irqrestore(&pd->bmp_lock, flags); 6542832a81dSGeoff Levand } 6552832a81dSGeoff Levand #else 6569633ac8dSGeoff Levand static void dump_bmp(struct ps3_private* pd) {}; 6572832a81dSGeoff Levand #endif /* defined(DEBUG) */ 6582832a81dSGeoff Levand 659bae1d8f1SGrant Likely static int ps3_host_map(struct irq_domain *h, unsigned int virq, 6602832a81dSGeoff Levand irq_hw_number_t hwirq) 6612832a81dSGeoff Levand { 66232b9074bSGeoff Levand DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, 663861be32cSGeoff Levand virq); 6642832a81dSGeoff Levand 665ec775d0eSThomas Gleixner irq_set_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); 6662832a81dSGeoff Levand 667861be32cSGeoff Levand return 0; 6682832a81dSGeoff Levand } 6692832a81dSGeoff Levand 670ad3aedfbSMarc Zyngier static int ps3_host_match(struct irq_domain *h, struct device_node *np, 671ad3aedfbSMarc Zyngier enum irq_domain_bus_token bus_token) 6728528ab84SMichael Ellerman { 6738528ab84SMichael Ellerman /* Match all */ 6748528ab84SMichael Ellerman return 1; 6758528ab84SMichael Ellerman } 6768528ab84SMichael Ellerman 6779f70b8ebSGrant Likely static const struct irq_domain_ops ps3_host_ops = { 6789633ac8dSGeoff Levand .map = ps3_host_map, 6798528ab84SMichael Ellerman .match = ps3_host_match, 6802832a81dSGeoff Levand }; 6812832a81dSGeoff Levand 6822832a81dSGeoff Levand void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) 6832832a81dSGeoff Levand { 6849633ac8dSGeoff Levand struct ps3_private *pd = &per_cpu(ps3_private, cpu); 6852832a81dSGeoff Levand 68632b9074bSGeoff Levand set_bit(63 - virq, &pd->ipi_debug_brk_mask); 6872832a81dSGeoff Levand 68832b9074bSGeoff Levand DBG("%s:%d: cpu %u, virq %u, mask %lxh\n", __func__, __LINE__, 68932b9074bSGeoff Levand cpu, virq, pd->ipi_debug_brk_mask); 6902832a81dSGeoff Levand } 6912832a81dSGeoff Levand 69272f3bea0SGeoff Levand void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq) 69372f3bea0SGeoff Levand { 69472f3bea0SGeoff Levand struct ps3_private *pd = &per_cpu(ps3_private, cpu); 69572f3bea0SGeoff Levand 69672f3bea0SGeoff Levand set_bit(63 - virq, &pd->ipi_mask); 69772f3bea0SGeoff Levand 69872f3bea0SGeoff Levand DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__, 69972f3bea0SGeoff Levand cpu, virq, pd->ipi_mask); 70072f3bea0SGeoff Levand } 70172f3bea0SGeoff Levand 7029263e85aSGeoff Levand static unsigned int ps3_get_irq(void) 7032832a81dSGeoff Levand { 70469111bacSChristoph Lameter struct ps3_private *pd = this_cpu_ptr(&ps3_private); 705861be32cSGeoff Levand u64 x = (pd->bmp.status & pd->bmp.mask); 7069cf9e196SBenjamin Herrenschmidt unsigned int plug; 7072832a81dSGeoff Levand 7082832a81dSGeoff Levand /* check for ipi break first to stop this cpu ASAP */ 7092832a81dSGeoff Levand 71032b9074bSGeoff Levand if (x & pd->ipi_debug_brk_mask) 71132b9074bSGeoff Levand x &= pd->ipi_debug_brk_mask; 7122832a81dSGeoff Levand 7139cf9e196SBenjamin Herrenschmidt asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x)); 7149cf9e196SBenjamin Herrenschmidt plug &= 0x3f; 7152832a81dSGeoff Levand 716ef24ba70SMichael Ellerman if (unlikely(!plug)) { 71732b9074bSGeoff Levand DBG("%s:%d: no plug found: thread_id %llu\n", __func__, 718aab83500SGeoff Levand __LINE__, pd->thread_id); 7199633ac8dSGeoff Levand dump_bmp(&per_cpu(ps3_private, 0)); 7209633ac8dSGeoff Levand dump_bmp(&per_cpu(ps3_private, 1)); 721ef24ba70SMichael Ellerman return 0; 7222832a81dSGeoff Levand } 7232832a81dSGeoff Levand 7242832a81dSGeoff Levand #if defined(DEBUG) 725*7c576f4dSMarc Zyngier if (unlikely(plug < NR_IRQS_LEGACY || plug > PS3_PLUG_MAX)) { 7269633ac8dSGeoff Levand dump_bmp(&per_cpu(ps3_private, 0)); 7279633ac8dSGeoff Levand dump_bmp(&per_cpu(ps3_private, 1)); 7282832a81dSGeoff Levand BUG(); 7292832a81dSGeoff Levand } 7302832a81dSGeoff Levand #endif 73172f3bea0SGeoff Levand 73272f3bea0SGeoff Levand /* IPIs are EOIed here. */ 73372f3bea0SGeoff Levand 73472f3bea0SGeoff Levand if (test_bit(63 - plug, &pd->ipi_mask)) 73572f3bea0SGeoff Levand lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug); 73672f3bea0SGeoff Levand 7372832a81dSGeoff Levand return plug; 7382832a81dSGeoff Levand } 7392832a81dSGeoff Levand 7402832a81dSGeoff Levand void __init ps3_init_IRQ(void) 7412832a81dSGeoff Levand { 7422832a81dSGeoff Levand int result; 7432832a81dSGeoff Levand unsigned cpu; 744bae1d8f1SGrant Likely struct irq_domain *host; 7452832a81dSGeoff Levand 7466fa6c8e2SGrant Likely host = irq_domain_add_nomap(NULL, PS3_PLUG_MAX + 1, &ps3_host_ops, NULL); 7472832a81dSGeoff Levand irq_set_default_host(host); 7482832a81dSGeoff Levand 7492832a81dSGeoff Levand for_each_possible_cpu(cpu) { 7509633ac8dSGeoff Levand struct ps3_private *pd = &per_cpu(ps3_private, cpu); 7512832a81dSGeoff Levand 752aab83500SGeoff Levand lv1_get_logical_ppe_id(&pd->ppe_id); 753aab83500SGeoff Levand pd->thread_id = get_hard_smp_processor_id(cpu); 75432b9074bSGeoff Levand spin_lock_init(&pd->bmp_lock); 7552832a81dSGeoff Levand 75632b9074bSGeoff Levand DBG("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n", 757aab83500SGeoff Levand __func__, __LINE__, pd->ppe_id, pd->thread_id, 758407e24a0SGeoff Levand ps3_mm_phys_to_lpar(__pa(&pd->bmp))); 759407e24a0SGeoff Levand 760aab83500SGeoff Levand result = lv1_configure_irq_state_bitmap(pd->ppe_id, 761aab83500SGeoff Levand pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); 7622832a81dSGeoff Levand 7632832a81dSGeoff Levand if (result) 76432b9074bSGeoff Levand FAIL("%s:%d: lv1_configure_irq_state_bitmap failed:" 7652832a81dSGeoff Levand " %s\n", __func__, __LINE__, 7662832a81dSGeoff Levand ps3_result(result)); 7672832a81dSGeoff Levand } 7682832a81dSGeoff Levand 7692832a81dSGeoff Levand ppc_md.get_irq = ps3_get_irq; 7702832a81dSGeoff Levand } 7719263e85aSGeoff Levand 7729263e85aSGeoff Levand void ps3_shutdown_IRQ(int cpu) 7739263e85aSGeoff Levand { 7749263e85aSGeoff Levand int result; 7759263e85aSGeoff Levand u64 ppe_id; 7769263e85aSGeoff Levand u64 thread_id = get_hard_smp_processor_id(cpu); 7779263e85aSGeoff Levand 7789263e85aSGeoff Levand lv1_get_logical_ppe_id(&ppe_id); 7799263e85aSGeoff Levand result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0); 7809263e85aSGeoff Levand 7815c949070SStephen Rothwell DBG("%s:%d: lv1_configure_irq_state_bitmap (%llu:%llu/%d) %s\n", __func__, 7829263e85aSGeoff Levand __LINE__, ppe_id, thread_id, cpu, ps3_result(result)); 7839263e85aSGeoff Levand } 784