perf/x86/intel: Add Ivy Bridge-EP uncore IRP box support
[cascardo/linux.git] / arch / x86 / kernel / cpu / perf_event_intel_uncore.c
index 6da3999..29c2487 100644 (file)
@@ -997,6 +997,20 @@ static int snbep_pci2phy_map_init(int devid)
                }
        }
 
+       if (!err) {
+               /*
+                * For PCI bus with no UBOX device, find the next bus
+                * that has UBOX device and use its mapping.
+                */
+               i = -1;
+               for (bus = 255; bus >= 0; bus--) {
+                       if (pcibus_to_physid[bus] >= 0)
+                               i = pcibus_to_physid[bus];
+                       else
+                               pcibus_to_physid[bus] = i;
+               }
+       }
+
        if (ubox_dev)
                pci_dev_put(ubox_dev);
 
@@ -1330,6 +1344,59 @@ static struct intel_uncore_type ivt_uncore_imc = {
        IVT_UNCORE_PCI_COMMON_INIT(),
 };
 
+/* registers in IRP boxes are not properly aligned */
+static unsigned ivt_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4};
+static unsigned ivt_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0};
+
+static void ivt_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx],
+                              hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void ivt_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], hwc->config);
+}
+
+static u64 ivt_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count = 0;
+
+       pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
+       pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
+
+       return count;
+}
+
+static struct intel_uncore_ops ivt_uncore_irp_ops = {
+       .init_box       = ivt_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = ivt_uncore_irp_disable_event,
+       .enable_event   = ivt_uncore_irp_enable_event,
+       .read_counter   = ivt_uncore_irp_read_counter,
+};
+
+static struct intel_uncore_type ivt_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_mask             = IVT_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .ops                    = &ivt_uncore_irp_ops,
+       .format_group           = &ivt_uncore_format_group,
+};
+
 static struct intel_uncore_ops ivt_uncore_qpi_ops = {
        .init_box       = ivt_uncore_pci_init_box,
        .disable_box    = snbep_uncore_pci_disable_box,
@@ -1377,6 +1444,7 @@ static struct intel_uncore_type ivt_uncore_r3qpi = {
 enum {
        IVT_PCI_UNCORE_HA,
        IVT_PCI_UNCORE_IMC,
+       IVT_PCI_UNCORE_IRP,
        IVT_PCI_UNCORE_QPI,
        IVT_PCI_UNCORE_R2PCIE,
        IVT_PCI_UNCORE_R3QPI,
@@ -1385,6 +1453,7 @@ enum {
 static struct intel_uncore_type *ivt_pci_uncores[] = {
        [IVT_PCI_UNCORE_HA]     = &ivt_uncore_ha,
        [IVT_PCI_UNCORE_IMC]    = &ivt_uncore_imc,
+       [IVT_PCI_UNCORE_IRP]    = &ivt_uncore_irp,
        [IVT_PCI_UNCORE_QPI]    = &ivt_uncore_qpi,
        [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie,
        [IVT_PCI_UNCORE_R3QPI]  = &ivt_uncore_r3qpi,
@@ -1432,6 +1501,10 @@ static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
                .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7),
        },
+       { /* IRP */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IRP, 0),
+       },
        { /* QPI0 Port 0 */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
                .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0),