/*! * @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; }
/*! * @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;