@@ -12,6 +12,8 @@ struct intel_uncore_type **uncore_mmio_uncores = empty_uncore;
static bool pcidrv_registered;
struct pci_driver *uncore_pci_driver;
+struct uncore_platform_driver *uncore_platform_driver;
+
/* pci bus to socket mapping */
DEFINE_RAW_SPINLOCK(pci2phy_map_lock);
struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head);
@@ -1159,6 +1161,42 @@ static void uncore_pci_remove(struct pci_dev *pdev)
uncore_pci_pmu_unregister(pmu, box);
}
+static int uncore_platform_probe(struct platform_device *pdev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent);
+ struct intel_uncore_pmu *pmu;
+ int phys_id, die, ret;
+
+ pmu = uncore_find_pmu_by_pci_dev(pci_dev, uncore_platform_driver->pci_ids);
+ if (!pmu)
+ return -ENODEV;
+
+ ret = uncore_pci_get_die_info(pci_dev, &phys_id, &die);
+ if (ret)
+ return ret;
+
+ ret = uncore_pci_pmu_register(pci_dev, pmu->type, pmu, phys_id, die);
+
+ platform_set_drvdata(pdev, pmu->boxes[die]);
+
+ return ret;
+}
+
+static int uncore_platform_remove(struct platform_device *pdev)
+{
+ struct intel_uncore_box *box;
+
+ box = platform_get_drvdata(pdev);
+ if (!box)
+ return 0;
+
+ uncore_pci_pmu_unregister(box->pmu, box);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
static int __init uncore_pci_init(void)
{
size_t size;
@@ -1183,6 +1221,19 @@ static int __init uncore_pci_init(void)
goto errtype;
pcidrv_registered = true;
+
+ if (uncore_platform_driver) {
+ uncore_platform_driver->driver->probe = uncore_platform_probe;
+ uncore_platform_driver->driver->remove = uncore_platform_remove;
+
+ ret = platform_driver_register(uncore_platform_driver->driver);
+ if (ret) {
+ pr_warn("Failed to register platform driver. "
+ "Disable %s uncore unit.\n",
+ uncore_platform_driver->driver->driver.name);
+ uncore_platform_driver = NULL;
+ }
+ }
return 0;
errtype:
@@ -1197,6 +1248,9 @@ static int __init uncore_pci_init(void)
static void uncore_pci_exit(void)
{
+ if (uncore_platform_driver)
+ platform_driver_unregister(uncore_platform_driver->driver);
+
if (pcidrv_registered) {
pcidrv_registered = false;
pci_unregister_driver(uncore_pci_driver);
@@ -3,6 +3,7 @@
#include <linux/pci.h>
#include <asm/apicdef.h>
#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/platform_device.h>
#include <linux/perf_event.h>
#include "../perf_event.h"
@@ -161,6 +162,24 @@ struct uncore_event_desc {
const char *config;
};
+/*
+ * A platform device created by other drivers for uncore monitoring
+ * @driver: platform_driver for the platform device
+ * @pci_ids: id_table for supported PCI devices
+ * Used to compare with the platform device's parent PCI device
+ *
+ * Other drivers may create a platform device for uncore monitoring,
+ * e.g. pcieport driver on SNR. To match the platform device, the probe
+ * function has to compare the platform device's parent PCI device with
+ * pci_ids.
+ */
+struct uncore_platform_driver {
+ struct platform_driver *driver;
+ const struct pci_device_id *pci_ids;
+};
+
+extern struct uncore_platform_driver *uncore_platform_driver;
+
struct freerunning_counters {
unsigned int counter_base;
unsigned int counter_offset;