#define IBS_FETCH_CONFIG_MASK  (IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
 #define IBS_OP_CONFIG_MASK     IBS_OP_MAX_CNT
 
+/* attr.config2 */
+#define IBS_SW_FILTER_MASK     1
 
 /*
  * IBS states:
        if (has_branch_stack(event))
                return -EOPNOTSUPP;
 
+       /* handle exclude_{user,kernel} in the IRQ handler */
+       if (event->attr.exclude_host || event->attr.exclude_guest ||
+           event->attr.exclude_idle)
+               return -EINVAL;
+
+       if (!(event->attr.config2 & IBS_SW_FILTER_MASK) &&
+           (event->attr.exclude_kernel || event->attr.exclude_user ||
+            event->attr.exclude_hv))
+               return -EINVAL;
+
        ret = validate_group(event);
        if (ret)
                return ret;
        NULL,
 };
 
-static struct attribute_group empty_format_group = {
-       .name = "format",
-       .attrs = attrs_empty,
-};
-
 static struct attribute_group empty_caps_group = {
        .name = "caps",
        .attrs = attrs_empty,
 };
 
-static const struct attribute_group *empty_attr_groups[] = {
-       &empty_format_group,
-       &empty_caps_group,
-       NULL,
-};
-
 PMU_FORMAT_ATTR(rand_en,       "config:57");
 PMU_FORMAT_ATTR(cnt_ctl,       "config:19");
+PMU_FORMAT_ATTR(swfilt,                "config2:0");
 PMU_EVENT_ATTR_STRING(l3missonly, fetch_l3missonly, "config:59");
 PMU_EVENT_ATTR_STRING(l3missonly, op_l3missonly, "config:16");
 PMU_EVENT_ATTR_STRING(zen4_ibs_extensions, zen4_ibs_extensions, "1");
        return ibs_caps & IBS_CAPS_ZEN4 ? attr->mode : 0;
 }
 
-static struct attribute *rand_en_attrs[] = {
+static struct attribute *fetch_attrs[] = {
        &format_attr_rand_en.attr,
+       &format_attr_swfilt.attr,
        NULL,
 };
 
        NULL,
 };
 
-static struct attribute_group group_rand_en = {
+static struct attribute_group group_fetch_formats = {
        .name = "format",
-       .attrs = rand_en_attrs,
+       .attrs = fetch_attrs,
 };
 
 static struct attribute_group group_fetch_l3missonly = {
 };
 
 static const struct attribute_group *fetch_attr_groups[] = {
-       &group_rand_en,
+       &group_fetch_formats,
        &empty_caps_group,
        NULL,
 };
        return ibs_caps & IBS_CAPS_OPCNT ? attr->mode : 0;
 }
 
+static struct attribute *op_attrs[] = {
+       &format_attr_swfilt.attr,
+       NULL,
+};
+
 static struct attribute *cnt_ctl_attrs[] = {
        &format_attr_cnt_ctl.attr,
        NULL,
        NULL,
 };
 
+static struct attribute_group group_op_formats = {
+       .name = "format",
+       .attrs = op_attrs,
+};
+
 static struct attribute_group group_cnt_ctl = {
        .name = "format",
        .attrs = cnt_ctl_attrs,
        .is_visible = zen4_ibs_extensions_is_visible,
 };
 
+static const struct attribute_group *op_attr_groups[] = {
+       &group_op_formats,
+       &empty_caps_group,
+       NULL,
+};
+
 static const struct attribute_group *op_attr_update[] = {
        &group_cnt_ctl,
        &group_op_l3missonly,
                .start          = perf_ibs_start,
                .stop           = perf_ibs_stop,
                .read           = perf_ibs_read,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
        },
        .msr                    = MSR_AMD64_IBSFETCHCTL,
        .config_mask            = IBS_FETCH_CONFIG_MASK,
                .start          = perf_ibs_start,
                .stop           = perf_ibs_stop,
                .read           = perf_ibs_read,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
        },
        .msr                    = MSR_AMD64_IBSOPCTL,
        .config_mask            = IBS_OP_CONFIG_MASK,
                regs.flags |= PERF_EFLAGS_EXACT;
        }
 
+       if ((event->attr.config2 & IBS_SW_FILTER_MASK) &&
+           perf_exclude_event(event, ®s)) {
+               throttle = perf_event_account_interrupt(event);
+               goto out;
+       }
+
        if (event->attr.sample_type & PERF_SAMPLE_RAW) {
                raw = (struct perf_raw_record){
                        .frag = {
        if (ibs_caps & IBS_CAPS_ZEN4)
                perf_ibs_op.config_mask |= IBS_OP_L3MISSONLY;
 
-       perf_ibs_op.pmu.attr_groups = empty_attr_groups;
+       perf_ibs_op.pmu.attr_groups = op_attr_groups;
        perf_ibs_op.pmu.attr_update = op_attr_update;
 
        return perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");