};
 
 #define UNCORE_SPR_NUM_UNCORE_TYPES            12
+#define UNCORE_SPR_IIO                         1
 
 static struct intel_uncore_type *spr_uncores[UNCORE_SPR_NUM_UNCORE_TYPES] = {
        &spr_uncore_chabox,
        &spr_uncore_mdf,
 };
 
+enum perf_uncore_spr_iio_freerunning_type_id {
+       SPR_IIO_MSR_IOCLK,
+       SPR_IIO_MSR_BW_IN,
+       SPR_IIO_MSR_BW_OUT,
+
+       SPR_IIO_FREERUNNING_TYPE_MAX,
+};
+
+static struct freerunning_counters spr_iio_freerunning[] = {
+       [SPR_IIO_MSR_IOCLK]     = { 0x340e, 0x1, 0x10, 1, 48 },
+       [SPR_IIO_MSR_BW_IN]     = { 0x3800, 0x1, 0x10, 8, 48 },
+       [SPR_IIO_MSR_BW_OUT]    = { 0x3808, 0x1, 0x10, 8, 48 },
+};
+
+static struct uncore_event_desc spr_uncore_iio_freerunning_events[] = {
+       /* Free-Running IIO CLOCKS Counter */
+       INTEL_UNCORE_EVENT_DESC(ioclk,                  "event=0xff,umask=0x10"),
+       /* Free-Running IIO BANDWIDTH IN Counters */
+       INTEL_UNCORE_EVENT_DESC(bw_in_port0,            "event=0xff,umask=0x20"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port0.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port0.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port1,            "event=0xff,umask=0x21"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port1.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port1.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port2,            "event=0xff,umask=0x22"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port2.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port2.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port3,            "event=0xff,umask=0x23"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port3.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port3.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port4,            "event=0xff,umask=0x24"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port4.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port4.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port5,            "event=0xff,umask=0x25"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port5.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port5.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port6,            "event=0xff,umask=0x26"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port6.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port6.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port7,            "event=0xff,umask=0x27"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port7.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port7.unit,       "MiB"),
+       /* Free-Running IIO BANDWIDTH OUT Counters */
+       INTEL_UNCORE_EVENT_DESC(bw_out_port0,           "event=0xff,umask=0x30"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port0.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port0.unit,      "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port1,           "event=0xff,umask=0x31"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port1.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port1.unit,      "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port2,           "event=0xff,umask=0x32"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port2.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port2.unit,      "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port3,           "event=0xff,umask=0x33"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port3.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port3.unit,      "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port4,           "event=0xff,umask=0x34"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port4.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port4.unit,      "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port5,           "event=0xff,umask=0x35"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port5.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port5.unit,      "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port6,           "event=0xff,umask=0x36"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port6.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port6.unit,      "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port7,           "event=0xff,umask=0x37"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port7.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_out_port7.unit,      "MiB"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type spr_uncore_iio_free_running = {
+       .name                   = "iio_free_running",
+       .num_counters           = 17,
+       .num_freerunning_types  = SPR_IIO_FREERUNNING_TYPE_MAX,
+       .freerunning            = spr_iio_freerunning,
+       .ops                    = &skx_uncore_iio_freerunning_ops,
+       .event_descs            = spr_uncore_iio_freerunning_events,
+       .format_group           = &skx_uncore_iio_freerunning_format_group,
+};
+
+#define UNCORE_SPR_MSR_EXTRA_UNCORES           1
+
+static struct intel_uncore_type *spr_msr_uncores[UNCORE_SPR_MSR_EXTRA_UNCORES] = {
+       &spr_uncore_iio_free_running,
+};
+
 static void uncore_type_customized_copy(struct intel_uncore_type *to_type,
                                        struct intel_uncore_type *from_type)
 {
 }
 
 static struct intel_uncore_type **
-uncore_get_uncores(enum uncore_access_type type_id)
+uncore_get_uncores(enum uncore_access_type type_id, int num_extra,
+                   struct intel_uncore_type **extra)
 {
        struct intel_uncore_type **types, **start_types;
+       int i;
 
-       start_types = types = intel_uncore_generic_init_uncores(type_id);
+       start_types = types = intel_uncore_generic_init_uncores(type_id, num_extra);
 
        /* Only copy the customized features */
        for (; *types; types++) {
                uncore_type_customized_copy(*types, spr_uncores[(*types)->type_id]);
        }
 
+       for (i = 0; i < num_extra; i++, types++)
+               *types = extra[i];
+
        return start_types;
 }
 
+static struct intel_uncore_type *
+uncore_find_type_by_id(struct intel_uncore_type **types, int type_id)
+{
+       for (; *types; types++) {
+               if (type_id == (*types)->type_id)
+                       return *types;
+       }
+
+       return NULL;
+}
+
+static int uncore_type_max_boxes(struct intel_uncore_type **types,
+                                int type_id)
+{
+       struct intel_uncore_type *type;
+       int i, max = 0;
+
+       type = uncore_find_type_by_id(types, type_id);
+       if (!type)
+               return 0;
+
+       for (i = 0; i < type->num_boxes; i++) {
+               if (type->box_ids[i] > max)
+                       max = type->box_ids[i];
+       }
+
+       return max + 1;
+}
+
 void spr_uncore_cpu_init(void)
 {
-       uncore_msr_uncores = uncore_get_uncores(UNCORE_ACCESS_MSR);
+       uncore_msr_uncores = uncore_get_uncores(UNCORE_ACCESS_MSR,
+                                               UNCORE_SPR_MSR_EXTRA_UNCORES,
+                                               spr_msr_uncores);
+
+       spr_uncore_iio_free_running.num_boxes = uncore_type_max_boxes(uncore_msr_uncores, UNCORE_SPR_IIO);
 }
 
 int spr_uncore_pci_init(void)
 {
-       uncore_pci_uncores = uncore_get_uncores(UNCORE_ACCESS_PCI);
+       uncore_pci_uncores = uncore_get_uncores(UNCORE_ACCESS_PCI, 0, NULL);
        return 0;
 }
 
 void spr_uncore_mmio_init(void)
 {
-       uncore_mmio_uncores = uncore_get_uncores(UNCORE_ACCESS_MMIO);
+       uncore_mmio_uncores = uncore_get_uncores(UNCORE_ACCESS_MMIO, 0, NULL);
 }
 
 /* end of SPR uncore support */