/*!
 * @fn          int CPUMON_Install_Cpuhooks(VOID)
 * @brief       Assign the PMU interrupt to the driver
 *
 * @return      zero if successful, non-zero error value if something failed
 *
 * Install the driver ebs handler onto the PMU interrupt. If perfmon is
 * compiled in then we ask perfmon for the interrupt, otherwise we ask the
 * kernel...
 *
 * <I>Special Notes:</I>
 *
 * @Note This routine is for Itanium(R)-based systems only!
 *
 *      For IA32, the LBRs are not frozen when a PMU interrupt is taken.
 * Since the LBRs capture information on every branch, for the LBR
 * registers to be useful, we need to freeze them as quickly as
 * possible after the interrupt. This means hooking the IDT directly
 * to call a driver specific interrupt handler. That happens in the
 * vtxsys.S file via samp_get_set_idt_entry. The real routine being
 * called first upon PMU interrupt is t_ebs (in vtxsys.S) and that
 * routine calls PMI_Interrupt_Handler()...
 *
 */
extern void
CPUMON_Install_Cpuhooks (
    void
)
{
    int status = -1;

    SEP_PRINT_DEBUG("CPUMON_Install_Cpuhooks: entered... pmv 0x%p \n", SYS_Read_PMV());

#if defined(PERFMON_V1) || defined(PERFMON_V2_ALT)
    /*
     * if Perfmon1 or Perfmon2_alt is set, we can use the perfmon.c
     * interface to steal perfmon.c's interrupt handler for our use
     * perfmon.c has already done register_percpu_irq()
     */

     ebs_irq      = SEP_PERFMON_IRQ;
     desc.handler = &PMI_Interrupt_Handler;
     status       = CPUMON_INSTALL_INTERRUPT(&desc);
     if (status) {
         SEP_PRINT_ERROR("CPUMON_Install_Cpuhooks: CPUMON_INSTALL_INTERRUPT returned %d\n",status);
     }
#elif !defined(PERFMON_V2)
    if (pebs_irqaction) {
        return status;
    }

#ifdef SA_PERCPU_IRQ_SUPPORTED
    ebs_irq        = SEP_PERFMON_IRQ;
    pebs_irqaction = (struct irqaction *) 1;
    status         = request_irq(SEP_PERFMON_IRQ,
                                 PMI_Interrupt_Handler,
                                 SA_INTERRUPT | SA_PERCPU_IRQ,
                                 "SEP Sampling",
                                 NULL);

#else
    {
        pebs_irqaction = kmalloc(sizeof (struct irqaction), GFP_ATOMIC);
        if (pebs_irqaction) {
            memset(pebs_irqaction, 0, sizeof (struct irqaction));
            ebs_irq                 = SEP_PERFMON_IRQ;
            pebs_irqaction->handler = (void *)PMI_Interrupt_Handler;
            pebs_irqaction->flags   = SA_INTERRUPT;
            pebs_irqaction->name    = SEP_DRIVER_NAME;
            pebs_irqaction->dev_id  = NULL;

            register_percpu_irq(ebs_irq, pebs_irqaction);
            status = 0;
        }
        else {
            SEP_PRINT_WARNING("couldn't kmalloc pebs_irqaction (%d bytes)\n",
                              (int)sizeof(struct irqaction));
        }
    }
#endif
#endif
    SEP_PRINT("IRQ vector 0x%x will be used for handling PMU interrupts\n", SEP_PERFMON_IRQ);

    SEP_PRINT_DEBUG("CPUMON_Install_Cpuhooks: exit...... rc=0x%x pmv=0x%p \n",
                    status, SYS_Read_PMV());

    return;
}
Example #2
0
/*!
 * @fn       VOID UTILITY_Configure_CPU
 *
 * @brief    Reads the CPU information from the hardware
 *
 * @param    param   dispatch_id -  The id of the dispatch table.
 *
 * @return   Pointer to the correct dispatch table for the CPU architecture
 *
 * <I>Special Notes:</I>
 *              <NONE>
 */
extern  DISPATCH
UTILITY_Configure_CPU (
    U32 dispatch_id
)
{
    DISPATCH     dispatch = NULL;
    switch (dispatch_id) {
#if defined(DRV_IA32) && !defined(DRV_ATOM_ONLY)
        case 0:
            SEP_PRINT_DEBUG("Set up the Core(TM) processor dispatch table\n");
            dispatch = &core_dispatch;
            break;
#endif
#if defined(DRV_IA32) || defined(DRV_EM64T)
        case 1:
            SEP_PRINT_DEBUG("Set up the Core(TM)2 processor dispatch table\n");
            dispatch = &core2_dispatch;
            break;
        case 6:
            SEP_PRINT_DEBUG("Set up the Silvermont dispatch table\n");
            dispatch = &silvermont_dispatch;
            break;

#if !defined(DRV_ATOM_ONLY)
        case 2:
            dispatch = &corei7_dispatch;
            SEP_PRINT_DEBUG("Set up the Core i7(TM) processor dispatch table\n");
            break;
        case 3:
            SEP_PRINT_DEBUG("Set up the Core i7(TM) dispatch table\n");
            dispatch = &corei7_dispatch_htoff_mode;
            break;
        case 4:
            dispatch = &corei7_dispatch_2;
            SEP_PRINT_DEBUG("Set up the Sandybridge processor dispatch table\n");
            break;
        case 5:
            SEP_PRINT_DEBUG("Set up the Sandybridge dispatch table\n");
            dispatch = &corei7_dispatch_htoff_mode_2;
            break;
        case 100:
            SEP_PRINT_DEBUG("Set up the Core i7 uncore dispatch table\n");
            dispatch = &corei7_unc_dispatch;
            break;
        case 200:
            SEP_PRINT_DEBUG("Set up the SNB iMC dispatch table\n");
            dispatch = &snbunc_imc_dispatch;
            break;
        case 201:
            SEP_PRINT_DEBUG("Set up the SNB Cbo dispatch table\n");
            dispatch = &snbunc_cbo_dispatch;
            break;
        case 210:
            SEP_PRINT_DEBUG("Set up the WSM-EX iMC dispatch table\n");
            dispatch = &wsmexunc_imc_dispatch;
            break;
        case 211:
            SEP_PRINT_DEBUG("Set up the WSM-EX QPI dispatch table\n");
            dispatch = &wsmexunc_qpi_dispatch;
            break;
        case 212:
            SEP_PRINT_DEBUG("Set up the WSM-EX WBOX dispatch table\n");
            dispatch = &wsmexunc_wbox_dispatch;
            break;
        case 220:
            SEP_PRINT_DEBUG("Set up the JKT IMC dispatch table\n");
            dispatch = &jktunc_imc_dispatch;
            break;
        case 221:
            SEP_PRINT_DEBUG("Set up the JKT QPILL dispatch table\n");
            dispatch = &jktunc_qpill_dispatch;
            break;
        case 222:
            SEP_PRINT_DEBUG("Set up the Jaketown UBOX dispatch table\n");
            dispatch = &jaketown_ubox_dispatch;
            break;
        case 500:
            SEP_PRINT_DEBUG("Set up the Haswell UNC NCU dispatch table\n");
            dispatch = &haswellunc_ncu_dispatch;
            break;
        case 600:
            SEP_PRINT_DEBUG("Set up the IVT UNC CBO dispatch table\n");
            dispatch = &ivtunc_cbo_dispatch;
            break;
        case 610:
            SEP_PRINT_DEBUG("Set up the IVT UNC IMC dispatch table\n");
            dispatch = &ivtunc_imc_dispatch;
            break;
        case 620:
            SEP_PRINT("Set up the Ivytown UNC PCU dispatch table\n");
            dispatch = &ivytown_pcu_dispatch;
            break;
        case 630:
            SEP_PRINT("Set up the Ivytown UNC PCU dispatch table\n");
            dispatch = &ivytown_ha_dispatch;
            break;
        case 640:
            SEP_PRINT_DEBUG("Set up the Ivytown QPI dispatch table\n");
            dispatch = &ivytown_qpill_dispatch;
            break;
        case 650:
            SEP_PRINT_DEBUG("Set up the Ivytown R3QPI dispatch table\n");
            dispatch = &ivytown_r3qpi_dispatch;
            break;
        case 660:
            SEP_PRINT("Set up the Ivytown UNC UBOX dispatch table\n");
            dispatch = &ivytown_ubox_dispatch;
            break;
        case 670:
            SEP_PRINT("Set up the Ivytown UNC R2PCIe dispatch table\n");
            dispatch = &ivytown_r2pcie_dispatch;
            break;
#endif
#endif
#if defined(DRV_IA64)
        case 4:
            dispatch = &montecito_dispatch;
            SEP_PRINT_DEBUG("Set up the Itanium(TM) Processor dispatch table\n");
            break;
        case 5:
            dispatch = &poulson_dispatch;
            SEP_PRINT_DEBUG("Set up the Itanium(TM) Processor dispatch table\n");
            break;
#endif
        default:
            dispatch = NULL;
            SEP_PRINT_ERROR("Architecture not supported (dispatch_id=%d)\n", dispatch_id);
            break;
    }

    return dispatch;
}
/*!
 * @fn          static VOID snbunc_imc_Write_PMU(VOID*)
 * 
 * @brief       Initial write of PMU registers
 *              Walk through the enties and write the value of the register accordingly.
 *              When current_group = 0, then this is the first time this routine is called,
 *
 * @param       None
 * 
 * @return      None
 *
 * <I>Special Notes:</I>
 */
static VOID
snbunc_imc_Write_PMU (
    VOID  *param
)
{
    
    DRV_PCI_DEVICE_ENTRY_NODE  dpden;
    U32                        pci_address;
    U32                        bar_lo;
    U64                        next_bar_offset;
    U64                        bar_hi;
    U64                        physical_address;
    U64                        final_bar;
    U32                        dev_idx   = *((U32*)param);
    ECB                        pecb      = LWPMU_DEVICE_PMU_register_data(&devices[(dev_idx)])[0];
    U32                        j;
    U32                        event_id   = 0;
    U32                        offset_delta;
    U32                        tmp_value;
    int                        me      = CONTROL_THIS_CPU();
    
    if (me != invoking_processor_id) {
        return;
    }

    SEP_PRINT_DEBUG("snbunc_imc_Write_PMU Enter\n");
    dpden = ECB_pcidev_entry_node(pecb);
    pci_address = FORM_PCI_ADDR(DRV_PCI_DEVICE_ENTRY_bus_no(&dpden),
                                DRV_PCI_DEVICE_ENTRY_dev_no(&dpden),
                                DRV_PCI_DEVICE_ENTRY_func_no(&dpden),
                                0);

#if defined(MYDEBUG)
    {
    U32 device_id  = PCI_Read_Ulong(pci_address);
    SEP_PRINT("Bus no = 0x%x\n",DRV_PCI_DEVICE_ENTRY_bus_no(&dpden));
    SEP_PRINT("Dev no = 0x%x\n",DRV_PCI_DEVICE_ENTRY_dev_no(&dpden));
    SEP_PRINT("Func no = 0x%x\n",DRV_PCI_DEVICE_ENTRY_func_no(&dpden));
    SEP_PRINT("value for device id = 0x%x\n",device_id);
    }
#endif

    pci_address = FORM_PCI_ADDR(DRV_PCI_DEVICE_ENTRY_bus_no(&dpden),
                                DRV_PCI_DEVICE_ENTRY_dev_no(&dpden),
                                DRV_PCI_DEVICE_ENTRY_func_no(&dpden),
                                DRV_PCI_DEVICE_ENTRY_bar_offset(&dpden));
    bar_lo      = PCI_Read_Ulong(pci_address);
        
    next_bar_offset     = DRV_PCI_DEVICE_ENTRY_bar_offset(&dpden) + NEXT_ADDR_OFFSET;
    pci_address         = FORM_PCI_ADDR(DRV_PCI_DEVICE_ENTRY_bus_no(&dpden),
                                DRV_PCI_DEVICE_ENTRY_dev_no(&dpden),
                                DRV_PCI_DEVICE_ENTRY_func_no(&dpden),
                                next_bar_offset);
    bar_hi              = PCI_Read_Ulong(pci_address);
    final_bar = (bar_hi << SNBUNC_IMC_BAR_ADDR_SHIFT) | bar_lo;
    final_bar &= SNBUNC_IMC_BAR_ADDR_MASK;

    DRV_PCI_DEVICE_ENTRY_bar_address(&ECB_pcidev_entry_node(pecb)) = final_bar;
    physical_address     = DRV_PCI_DEVICE_ENTRY_bar_address(&ECB_pcidev_entry_node(pecb))
                                 + DRV_PCI_DEVICE_ENTRY_base_offset_for_mmio(&ECB_pcidev_entry_node(pecb));
    virtual_address      = ioremap_nocache(physical_address,4096); 
    //Read in the counts into temporary buffer
    FOR_EACH_PCI_DATA_REG(pecb,i,dev_idx,offset_delta) {
            event_id                            = ECB_entries_event_id_index_local(pecb,i);
            tmp_value                           = readl((U32*)((char*)(virtual_address) + offset_delta));
            for ( j = 0; j < (U32)GLOBAL_STATE_num_cpus(driver_state) ; j++) {
                   LWPMU_DEVICE_prev_val_per_thread(&devices[dev_idx])[j][event_id + 1] = tmp_value; // need to account for group id
#if defined(MYDEBUG)
                   SEP_PRINT_DEBUG("initial value for i =%d is 0x%x\n",i,LWPMU_DEVICE_prev_val_per_thread(&devices[dev_idx])[j][i]);

#endif
            }

            // this is needed for overflow detection of the accumulators.
            if (LWPMU_DEVICE_counter_mask(&devices[dev_idx]) == 0) {
                LWPMU_DEVICE_counter_mask(&devices[dev_idx]) = (U64)ECB_entries_max_bits(pecb,i);
            }
    } END_FOR_EACH_PCI_DATA_REG;