15c170a4dSMichal Wajdeczko // SPDX-License-Identifier: MIT 25c170a4dSMichal Wajdeczko /* 35c170a4dSMichal Wajdeczko * Copyright © 2025 Intel Corporation 45c170a4dSMichal Wajdeczko */ 55c170a4dSMichal Wajdeczko 65c170a4dSMichal Wajdeczko #include <linux/kobject.h> 75c170a4dSMichal Wajdeczko #include <linux/sysfs.h> 85c170a4dSMichal Wajdeczko 95c170a4dSMichal Wajdeczko #include <drm/drm_managed.h> 105c170a4dSMichal Wajdeczko 115c170a4dSMichal Wajdeczko #include "xe_assert.h" 1217899358SMichal Wajdeczko #include "xe_pci_sriov.h" 13f9091794SMichal Wajdeczko #include "xe_pm.h" 145c170a4dSMichal Wajdeczko #include "xe_sriov.h" 15f9091794SMichal Wajdeczko #include "xe_sriov_pf.h" 16*79e419c9SMichal Wajdeczko #include "xe_sriov_pf_control.h" 175c170a4dSMichal Wajdeczko #include "xe_sriov_pf_helpers.h" 183f984d70SMichal Wajdeczko #include "xe_sriov_pf_provision.h" 195c170a4dSMichal Wajdeczko #include "xe_sriov_pf_sysfs.h" 205c170a4dSMichal Wajdeczko #include "xe_sriov_printk.h" 215c170a4dSMichal Wajdeczko 22b5b297b9SMichal Wajdeczko static int emit_choice(char *buf, int choice, const char * const *array, size_t size) 23b5b297b9SMichal Wajdeczko { 24b5b297b9SMichal Wajdeczko int pos = 0; 25b5b297b9SMichal Wajdeczko int n; 26b5b297b9SMichal Wajdeczko 27b5b297b9SMichal Wajdeczko for (n = 0; n < size; n++) { 28b5b297b9SMichal Wajdeczko pos += sysfs_emit_at(buf, pos, "%s%s%s%s", 29b5b297b9SMichal Wajdeczko n ? " " : "", 30b5b297b9SMichal Wajdeczko n == choice ? "[" : "", 31b5b297b9SMichal Wajdeczko array[n], 32b5b297b9SMichal Wajdeczko n == choice ? "]" : ""); 33b5b297b9SMichal Wajdeczko } 34b5b297b9SMichal Wajdeczko pos += sysfs_emit_at(buf, pos, "\n"); 35b5b297b9SMichal Wajdeczko 36b5b297b9SMichal Wajdeczko return pos; 37b5b297b9SMichal Wajdeczko } 38b5b297b9SMichal Wajdeczko 395c170a4dSMichal Wajdeczko /* 405c170a4dSMichal Wajdeczko * /sys/bus/pci/drivers/xe/BDF/ 415c170a4dSMichal Wajdeczko * : 425c170a4dSMichal Wajdeczko * ├── sriov_admin/ 435c170a4dSMichal Wajdeczko * ├── ... 4471f5933cSMichal Wajdeczko * ├── .bulk_profile 4571f5933cSMichal Wajdeczko * │ ├── exec_quantum_ms 469f64d21dSMichal Wajdeczko * │ ├── preempt_timeout_us 479f64d21dSMichal Wajdeczko * │ └── sched_priority 485c170a4dSMichal Wajdeczko * ├── pf/ 495c170a4dSMichal Wajdeczko * │ ├── ... 5017899358SMichal Wajdeczko * │ ├── device -> ../../../BDF 513f984d70SMichal Wajdeczko * │ └── profile 523f984d70SMichal Wajdeczko * │ ├── exec_quantum_ms 53b5b297b9SMichal Wajdeczko * │ ├── preempt_timeout_us 54b5b297b9SMichal Wajdeczko * │ └── sched_priority 555c170a4dSMichal Wajdeczko * ├── vf1/ 565c170a4dSMichal Wajdeczko * │ ├── ... 5717899358SMichal Wajdeczko * │ ├── device -> ../../../BDF.1 58*79e419c9SMichal Wajdeczko * │ ├── stop 593f984d70SMichal Wajdeczko * │ └── profile 603f984d70SMichal Wajdeczko * │ ├── exec_quantum_ms 61b5b297b9SMichal Wajdeczko * │ ├── preempt_timeout_us 62b5b297b9SMichal Wajdeczko * │ └── sched_priority 635c170a4dSMichal Wajdeczko * ├── vf2/ 645c170a4dSMichal Wajdeczko * : 655c170a4dSMichal Wajdeczko * └── vfN/ 665c170a4dSMichal Wajdeczko */ 675c170a4dSMichal Wajdeczko 685c170a4dSMichal Wajdeczko struct xe_sriov_kobj { 695c170a4dSMichal Wajdeczko struct kobject base; 705c170a4dSMichal Wajdeczko struct xe_device *xe; 715c170a4dSMichal Wajdeczko unsigned int vfid; 725c170a4dSMichal Wajdeczko }; 735c170a4dSMichal Wajdeczko #define to_xe_sriov_kobj(p) container_of_const((p), struct xe_sriov_kobj, base) 745c170a4dSMichal Wajdeczko 755c170a4dSMichal Wajdeczko struct xe_sriov_dev_attr { 765c170a4dSMichal Wajdeczko struct attribute attr; 775c170a4dSMichal Wajdeczko ssize_t (*show)(struct xe_device *xe, char *buf); 785c170a4dSMichal Wajdeczko ssize_t (*store)(struct xe_device *xe, const char *buf, size_t count); 795c170a4dSMichal Wajdeczko }; 805c170a4dSMichal Wajdeczko #define to_xe_sriov_dev_attr(p) container_of_const((p), struct xe_sriov_dev_attr, attr) 815c170a4dSMichal Wajdeczko 825c170a4dSMichal Wajdeczko #define XE_SRIOV_DEV_ATTR(NAME) \ 835c170a4dSMichal Wajdeczko struct xe_sriov_dev_attr xe_sriov_dev_attr_##NAME = \ 845c170a4dSMichal Wajdeczko __ATTR(NAME, 0644, xe_sriov_dev_attr_##NAME##_show, xe_sriov_dev_attr_##NAME##_store) 855c170a4dSMichal Wajdeczko 865c170a4dSMichal Wajdeczko #define XE_SRIOV_DEV_ATTR_RO(NAME) \ 875c170a4dSMichal Wajdeczko struct xe_sriov_dev_attr xe_sriov_dev_attr_##NAME = \ 885c170a4dSMichal Wajdeczko __ATTR(NAME, 0444, xe_sriov_dev_attr_##NAME##_show, NULL) 895c170a4dSMichal Wajdeczko 905c170a4dSMichal Wajdeczko #define XE_SRIOV_DEV_ATTR_WO(NAME) \ 915c170a4dSMichal Wajdeczko struct xe_sriov_dev_attr xe_sriov_dev_attr_##NAME = \ 925c170a4dSMichal Wajdeczko __ATTR(NAME, 0200, NULL, xe_sriov_dev_attr_##NAME##_store) 935c170a4dSMichal Wajdeczko 945c170a4dSMichal Wajdeczko struct xe_sriov_vf_attr { 955c170a4dSMichal Wajdeczko struct attribute attr; 965c170a4dSMichal Wajdeczko ssize_t (*show)(struct xe_device *xe, unsigned int vfid, char *buf); 975c170a4dSMichal Wajdeczko ssize_t (*store)(struct xe_device *xe, unsigned int vfid, const char *buf, size_t count); 985c170a4dSMichal Wajdeczko }; 995c170a4dSMichal Wajdeczko #define to_xe_sriov_vf_attr(p) container_of_const((p), struct xe_sriov_vf_attr, attr) 1005c170a4dSMichal Wajdeczko 1015c170a4dSMichal Wajdeczko #define XE_SRIOV_VF_ATTR(NAME) \ 1025c170a4dSMichal Wajdeczko struct xe_sriov_vf_attr xe_sriov_vf_attr_##NAME = \ 1035c170a4dSMichal Wajdeczko __ATTR(NAME, 0644, xe_sriov_vf_attr_##NAME##_show, xe_sriov_vf_attr_##NAME##_store) 1045c170a4dSMichal Wajdeczko 1055c170a4dSMichal Wajdeczko #define XE_SRIOV_VF_ATTR_RO(NAME) \ 1065c170a4dSMichal Wajdeczko struct xe_sriov_vf_attr xe_sriov_vf_attr_##NAME = \ 1075c170a4dSMichal Wajdeczko __ATTR(NAME, 0444, xe_sriov_vf_attr_##NAME##_show, NULL) 1085c170a4dSMichal Wajdeczko 1095c170a4dSMichal Wajdeczko #define XE_SRIOV_VF_ATTR_WO(NAME) \ 1105c170a4dSMichal Wajdeczko struct xe_sriov_vf_attr xe_sriov_vf_attr_##NAME = \ 1115c170a4dSMichal Wajdeczko __ATTR(NAME, 0200, NULL, xe_sriov_vf_attr_##NAME##_store) 1125c170a4dSMichal Wajdeczko 1135c170a4dSMichal Wajdeczko /* device level attributes go here */ 1145c170a4dSMichal Wajdeczko 11571f5933cSMichal Wajdeczko #define DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(NAME, ITEM, TYPE) \ 11671f5933cSMichal Wajdeczko \ 11771f5933cSMichal Wajdeczko static ssize_t xe_sriov_dev_attr_##NAME##_store(struct xe_device *xe, \ 11871f5933cSMichal Wajdeczko const char *buf, size_t count) \ 11971f5933cSMichal Wajdeczko { \ 12071f5933cSMichal Wajdeczko TYPE value; \ 12171f5933cSMichal Wajdeczko int err; \ 12271f5933cSMichal Wajdeczko \ 12371f5933cSMichal Wajdeczko err = kstrto##TYPE(buf, 0, &value); \ 12471f5933cSMichal Wajdeczko if (err) \ 12571f5933cSMichal Wajdeczko return err; \ 12671f5933cSMichal Wajdeczko \ 12771f5933cSMichal Wajdeczko err = xe_sriov_pf_provision_bulk_apply_##ITEM(xe, value); \ 12871f5933cSMichal Wajdeczko return err ?: count; \ 12971f5933cSMichal Wajdeczko } \ 13071f5933cSMichal Wajdeczko \ 13171f5933cSMichal Wajdeczko static XE_SRIOV_DEV_ATTR_WO(NAME) 13271f5933cSMichal Wajdeczko 13371f5933cSMichal Wajdeczko DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(exec_quantum_ms, eq, u32); 13471f5933cSMichal Wajdeczko DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(preempt_timeout_us, pt, u32); 13571f5933cSMichal Wajdeczko 1369f64d21dSMichal Wajdeczko static const char * const sched_priority_names[] = { 1379f64d21dSMichal Wajdeczko [GUC_SCHED_PRIORITY_LOW] = "low", 1389f64d21dSMichal Wajdeczko [GUC_SCHED_PRIORITY_NORMAL] = "normal", 1399f64d21dSMichal Wajdeczko [GUC_SCHED_PRIORITY_HIGH] = "high", 1409f64d21dSMichal Wajdeczko }; 1419f64d21dSMichal Wajdeczko 142b5b297b9SMichal Wajdeczko static bool sched_priority_change_allowed(unsigned int vfid) 143b5b297b9SMichal Wajdeczko { 144b5b297b9SMichal Wajdeczko /* As of today GuC FW allows to selectively change only the PF priority. */ 145b5b297b9SMichal Wajdeczko return vfid == PFID; 146b5b297b9SMichal Wajdeczko } 147b5b297b9SMichal Wajdeczko 1489f64d21dSMichal Wajdeczko static bool sched_priority_high_allowed(unsigned int vfid) 1499f64d21dSMichal Wajdeczko { 1509f64d21dSMichal Wajdeczko /* As of today GuC FW allows to select 'high' priority only for the PF. */ 1519f64d21dSMichal Wajdeczko return vfid == PFID; 1529f64d21dSMichal Wajdeczko } 1539f64d21dSMichal Wajdeczko 1549f64d21dSMichal Wajdeczko static bool sched_priority_bulk_high_allowed(struct xe_device *xe) 1559f64d21dSMichal Wajdeczko { 1569f64d21dSMichal Wajdeczko /* all VFs are equal - it's sufficient to check VF1 only */ 1579f64d21dSMichal Wajdeczko return sched_priority_high_allowed(VFID(1)); 1589f64d21dSMichal Wajdeczko } 1599f64d21dSMichal Wajdeczko 1609f64d21dSMichal Wajdeczko static ssize_t xe_sriov_dev_attr_sched_priority_store(struct xe_device *xe, 1619f64d21dSMichal Wajdeczko const char *buf, size_t count) 1629f64d21dSMichal Wajdeczko { 1639f64d21dSMichal Wajdeczko size_t num_priorities = ARRAY_SIZE(sched_priority_names); 1649f64d21dSMichal Wajdeczko int match; 1659f64d21dSMichal Wajdeczko int err; 1669f64d21dSMichal Wajdeczko 1679f64d21dSMichal Wajdeczko if (!sched_priority_bulk_high_allowed(xe)) 1689f64d21dSMichal Wajdeczko num_priorities--; 1699f64d21dSMichal Wajdeczko 1709f64d21dSMichal Wajdeczko match = __sysfs_match_string(sched_priority_names, num_priorities, buf); 1719f64d21dSMichal Wajdeczko if (match < 0) 1729f64d21dSMichal Wajdeczko return -EINVAL; 1739f64d21dSMichal Wajdeczko 1749f64d21dSMichal Wajdeczko err = xe_sriov_pf_provision_bulk_apply_priority(xe, match); 1759f64d21dSMichal Wajdeczko return err ?: count; 1769f64d21dSMichal Wajdeczko } 1779f64d21dSMichal Wajdeczko 1789f64d21dSMichal Wajdeczko static XE_SRIOV_DEV_ATTR_WO(sched_priority); 1799f64d21dSMichal Wajdeczko 18071f5933cSMichal Wajdeczko static struct attribute *bulk_profile_dev_attrs[] = { 18171f5933cSMichal Wajdeczko &xe_sriov_dev_attr_exec_quantum_ms.attr, 18271f5933cSMichal Wajdeczko &xe_sriov_dev_attr_preempt_timeout_us.attr, 1839f64d21dSMichal Wajdeczko &xe_sriov_dev_attr_sched_priority.attr, 18471f5933cSMichal Wajdeczko NULL 18571f5933cSMichal Wajdeczko }; 18671f5933cSMichal Wajdeczko 18771f5933cSMichal Wajdeczko static const struct attribute_group bulk_profile_dev_attr_group = { 18871f5933cSMichal Wajdeczko .name = ".bulk_profile", 18971f5933cSMichal Wajdeczko .attrs = bulk_profile_dev_attrs, 19071f5933cSMichal Wajdeczko }; 19171f5933cSMichal Wajdeczko 1925c170a4dSMichal Wajdeczko static const struct attribute_group *xe_sriov_dev_attr_groups[] = { 19371f5933cSMichal Wajdeczko &bulk_profile_dev_attr_group, 1945c170a4dSMichal Wajdeczko NULL 1955c170a4dSMichal Wajdeczko }; 1965c170a4dSMichal Wajdeczko 1975c170a4dSMichal Wajdeczko /* and VF-level attributes go here */ 1985c170a4dSMichal Wajdeczko 1993f984d70SMichal Wajdeczko #define DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(NAME, ITEM, TYPE, FORMAT) \ 2003f984d70SMichal Wajdeczko static ssize_t xe_sriov_vf_attr_##NAME##_show(struct xe_device *xe, unsigned int vfid, \ 2013f984d70SMichal Wajdeczko char *buf) \ 2023f984d70SMichal Wajdeczko { \ 2033f984d70SMichal Wajdeczko TYPE value = 0; \ 2043f984d70SMichal Wajdeczko int err; \ 2053f984d70SMichal Wajdeczko \ 2063f984d70SMichal Wajdeczko err = xe_sriov_pf_provision_query_vf_##ITEM(xe, vfid, &value); \ 2073f984d70SMichal Wajdeczko if (err) \ 2083f984d70SMichal Wajdeczko return err; \ 2093f984d70SMichal Wajdeczko \ 2103f984d70SMichal Wajdeczko return sysfs_emit(buf, FORMAT, value); \ 2113f984d70SMichal Wajdeczko } \ 2123f984d70SMichal Wajdeczko \ 2133f984d70SMichal Wajdeczko static ssize_t xe_sriov_vf_attr_##NAME##_store(struct xe_device *xe, unsigned int vfid, \ 2143f984d70SMichal Wajdeczko const char *buf, size_t count) \ 2153f984d70SMichal Wajdeczko { \ 2163f984d70SMichal Wajdeczko TYPE value; \ 2173f984d70SMichal Wajdeczko int err; \ 2183f984d70SMichal Wajdeczko \ 2193f984d70SMichal Wajdeczko err = kstrto##TYPE(buf, 0, &value); \ 2203f984d70SMichal Wajdeczko if (err) \ 2213f984d70SMichal Wajdeczko return err; \ 2223f984d70SMichal Wajdeczko \ 2233f984d70SMichal Wajdeczko err = xe_sriov_pf_provision_apply_vf_##ITEM(xe, vfid, value); \ 2243f984d70SMichal Wajdeczko return err ?: count; \ 2253f984d70SMichal Wajdeczko } \ 2263f984d70SMichal Wajdeczko \ 2273f984d70SMichal Wajdeczko static XE_SRIOV_VF_ATTR(NAME) 2283f984d70SMichal Wajdeczko 2293f984d70SMichal Wajdeczko DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(exec_quantum_ms, eq, u32, "%u\n"); 2303f984d70SMichal Wajdeczko DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(preempt_timeout_us, pt, u32, "%u\n"); 2313f984d70SMichal Wajdeczko 232b5b297b9SMichal Wajdeczko static ssize_t xe_sriov_vf_attr_sched_priority_show(struct xe_device *xe, unsigned int vfid, 233b5b297b9SMichal Wajdeczko char *buf) 234b5b297b9SMichal Wajdeczko { 235b5b297b9SMichal Wajdeczko size_t num_priorities = ARRAY_SIZE(sched_priority_names); 236b5b297b9SMichal Wajdeczko u32 priority; 237b5b297b9SMichal Wajdeczko int err; 238b5b297b9SMichal Wajdeczko 239b5b297b9SMichal Wajdeczko err = xe_sriov_pf_provision_query_vf_priority(xe, vfid, &priority); 240b5b297b9SMichal Wajdeczko if (err) 241b5b297b9SMichal Wajdeczko return err; 242b5b297b9SMichal Wajdeczko 243b5b297b9SMichal Wajdeczko if (!sched_priority_high_allowed(vfid)) 244b5b297b9SMichal Wajdeczko num_priorities--; 245b5b297b9SMichal Wajdeczko 246b5b297b9SMichal Wajdeczko xe_assert(xe, priority < num_priorities); 247b5b297b9SMichal Wajdeczko return emit_choice(buf, priority, sched_priority_names, num_priorities); 248b5b297b9SMichal Wajdeczko } 249b5b297b9SMichal Wajdeczko 250b5b297b9SMichal Wajdeczko static ssize_t xe_sriov_vf_attr_sched_priority_store(struct xe_device *xe, unsigned int vfid, 251b5b297b9SMichal Wajdeczko const char *buf, size_t count) 252b5b297b9SMichal Wajdeczko { 253b5b297b9SMichal Wajdeczko size_t num_priorities = ARRAY_SIZE(sched_priority_names); 254b5b297b9SMichal Wajdeczko int match; 255b5b297b9SMichal Wajdeczko int err; 256b5b297b9SMichal Wajdeczko 257b5b297b9SMichal Wajdeczko if (!sched_priority_change_allowed(vfid)) 258b5b297b9SMichal Wajdeczko return -EOPNOTSUPP; 259b5b297b9SMichal Wajdeczko 260b5b297b9SMichal Wajdeczko if (!sched_priority_high_allowed(vfid)) 261b5b297b9SMichal Wajdeczko num_priorities--; 262b5b297b9SMichal Wajdeczko 263b5b297b9SMichal Wajdeczko match = __sysfs_match_string(sched_priority_names, num_priorities, buf); 264b5b297b9SMichal Wajdeczko if (match < 0) 265b5b297b9SMichal Wajdeczko return -EINVAL; 266b5b297b9SMichal Wajdeczko 267b5b297b9SMichal Wajdeczko err = xe_sriov_pf_provision_apply_vf_priority(xe, vfid, match); 268b5b297b9SMichal Wajdeczko return err ?: count; 269b5b297b9SMichal Wajdeczko } 270b5b297b9SMichal Wajdeczko 271b5b297b9SMichal Wajdeczko static XE_SRIOV_VF_ATTR(sched_priority); 272b5b297b9SMichal Wajdeczko 2733f984d70SMichal Wajdeczko static struct attribute *profile_vf_attrs[] = { 2743f984d70SMichal Wajdeczko &xe_sriov_vf_attr_exec_quantum_ms.attr, 2753f984d70SMichal Wajdeczko &xe_sriov_vf_attr_preempt_timeout_us.attr, 276b5b297b9SMichal Wajdeczko &xe_sriov_vf_attr_sched_priority.attr, 2773f984d70SMichal Wajdeczko NULL 2783f984d70SMichal Wajdeczko }; 2793f984d70SMichal Wajdeczko 280b5b297b9SMichal Wajdeczko static umode_t profile_vf_attr_is_visible(struct kobject *kobj, 281b5b297b9SMichal Wajdeczko struct attribute *attr, int index) 282b5b297b9SMichal Wajdeczko { 283b5b297b9SMichal Wajdeczko struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 284b5b297b9SMichal Wajdeczko 285b5b297b9SMichal Wajdeczko if (attr == &xe_sriov_vf_attr_sched_priority.attr && 286b5b297b9SMichal Wajdeczko !sched_priority_change_allowed(vkobj->vfid)) 287b5b297b9SMichal Wajdeczko return attr->mode & 0444; 288b5b297b9SMichal Wajdeczko 289b5b297b9SMichal Wajdeczko return attr->mode; 290b5b297b9SMichal Wajdeczko } 291b5b297b9SMichal Wajdeczko 2923f984d70SMichal Wajdeczko static const struct attribute_group profile_vf_attr_group = { 2933f984d70SMichal Wajdeczko .name = "profile", 2943f984d70SMichal Wajdeczko .attrs = profile_vf_attrs, 295b5b297b9SMichal Wajdeczko .is_visible = profile_vf_attr_is_visible, 2963f984d70SMichal Wajdeczko }; 2973f984d70SMichal Wajdeczko 298*79e419c9SMichal Wajdeczko #define DEFINE_SIMPLE_CONTROL_SRIOV_VF_ATTR(NAME) \ 299*79e419c9SMichal Wajdeczko \ 300*79e419c9SMichal Wajdeczko static ssize_t xe_sriov_vf_attr_##NAME##_store(struct xe_device *xe, unsigned int vfid, \ 301*79e419c9SMichal Wajdeczko const char *buf, size_t count) \ 302*79e419c9SMichal Wajdeczko { \ 303*79e419c9SMichal Wajdeczko bool yes; \ 304*79e419c9SMichal Wajdeczko int err; \ 305*79e419c9SMichal Wajdeczko \ 306*79e419c9SMichal Wajdeczko if (!vfid) \ 307*79e419c9SMichal Wajdeczko return -EPERM; \ 308*79e419c9SMichal Wajdeczko \ 309*79e419c9SMichal Wajdeczko err = kstrtobool(buf, &yes); \ 310*79e419c9SMichal Wajdeczko if (err) \ 311*79e419c9SMichal Wajdeczko return err; \ 312*79e419c9SMichal Wajdeczko if (!yes) \ 313*79e419c9SMichal Wajdeczko return count; \ 314*79e419c9SMichal Wajdeczko \ 315*79e419c9SMichal Wajdeczko err = xe_sriov_pf_control_##NAME##_vf(xe, vfid); \ 316*79e419c9SMichal Wajdeczko return err ?: count; \ 317*79e419c9SMichal Wajdeczko } \ 318*79e419c9SMichal Wajdeczko \ 319*79e419c9SMichal Wajdeczko static XE_SRIOV_VF_ATTR_WO(NAME) 320*79e419c9SMichal Wajdeczko 321*79e419c9SMichal Wajdeczko DEFINE_SIMPLE_CONTROL_SRIOV_VF_ATTR(stop); 322*79e419c9SMichal Wajdeczko 323*79e419c9SMichal Wajdeczko static struct attribute *control_vf_attrs[] = { 324*79e419c9SMichal Wajdeczko &xe_sriov_vf_attr_stop.attr, 325*79e419c9SMichal Wajdeczko NULL 326*79e419c9SMichal Wajdeczko }; 327*79e419c9SMichal Wajdeczko 328*79e419c9SMichal Wajdeczko static umode_t control_vf_attr_is_visible(struct kobject *kobj, 329*79e419c9SMichal Wajdeczko struct attribute *attr, int index) 330*79e419c9SMichal Wajdeczko { 331*79e419c9SMichal Wajdeczko struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 332*79e419c9SMichal Wajdeczko 333*79e419c9SMichal Wajdeczko if (vkobj->vfid == PFID) 334*79e419c9SMichal Wajdeczko return 0; 335*79e419c9SMichal Wajdeczko 336*79e419c9SMichal Wajdeczko return attr->mode; 337*79e419c9SMichal Wajdeczko } 338*79e419c9SMichal Wajdeczko 339*79e419c9SMichal Wajdeczko static const struct attribute_group control_vf_attr_group = { 340*79e419c9SMichal Wajdeczko .attrs = control_vf_attrs, 341*79e419c9SMichal Wajdeczko .is_visible = control_vf_attr_is_visible, 342*79e419c9SMichal Wajdeczko }; 343*79e419c9SMichal Wajdeczko 3445c170a4dSMichal Wajdeczko static const struct attribute_group *xe_sriov_vf_attr_groups[] = { 3453f984d70SMichal Wajdeczko &profile_vf_attr_group, 346*79e419c9SMichal Wajdeczko &control_vf_attr_group, 3475c170a4dSMichal Wajdeczko NULL 3485c170a4dSMichal Wajdeczko }; 3495c170a4dSMichal Wajdeczko 3505c170a4dSMichal Wajdeczko /* no user serviceable parts below */ 3515c170a4dSMichal Wajdeczko 3525c170a4dSMichal Wajdeczko static struct kobject *create_xe_sriov_kobj(struct xe_device *xe, unsigned int vfid) 3535c170a4dSMichal Wajdeczko { 3545c170a4dSMichal Wajdeczko struct xe_sriov_kobj *vkobj; 3555c170a4dSMichal Wajdeczko 3565c170a4dSMichal Wajdeczko xe_sriov_pf_assert_vfid(xe, vfid); 3575c170a4dSMichal Wajdeczko 3585c170a4dSMichal Wajdeczko vkobj = kzalloc(sizeof(*vkobj), GFP_KERNEL); 3595c170a4dSMichal Wajdeczko if (!vkobj) 3605c170a4dSMichal Wajdeczko return NULL; 3615c170a4dSMichal Wajdeczko 3625c170a4dSMichal Wajdeczko vkobj->xe = xe; 3635c170a4dSMichal Wajdeczko vkobj->vfid = vfid; 3645c170a4dSMichal Wajdeczko return &vkobj->base; 3655c170a4dSMichal Wajdeczko } 3665c170a4dSMichal Wajdeczko 3675c170a4dSMichal Wajdeczko static void release_xe_sriov_kobj(struct kobject *kobj) 3685c170a4dSMichal Wajdeczko { 3695c170a4dSMichal Wajdeczko struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 3705c170a4dSMichal Wajdeczko 3715c170a4dSMichal Wajdeczko kfree(vkobj); 3725c170a4dSMichal Wajdeczko } 3735c170a4dSMichal Wajdeczko 3745c170a4dSMichal Wajdeczko static ssize_t xe_sriov_dev_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) 3755c170a4dSMichal Wajdeczko { 3765c170a4dSMichal Wajdeczko struct xe_sriov_dev_attr *vattr = to_xe_sriov_dev_attr(attr); 3775c170a4dSMichal Wajdeczko struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 3785c170a4dSMichal Wajdeczko struct xe_device *xe = vkobj->xe; 3795c170a4dSMichal Wajdeczko 3805c170a4dSMichal Wajdeczko if (!vattr->show) 3815c170a4dSMichal Wajdeczko return -EPERM; 3825c170a4dSMichal Wajdeczko 3835c170a4dSMichal Wajdeczko return vattr->show(xe, buf); 3845c170a4dSMichal Wajdeczko } 3855c170a4dSMichal Wajdeczko 3865c170a4dSMichal Wajdeczko static ssize_t xe_sriov_dev_attr_store(struct kobject *kobj, struct attribute *attr, 3875c170a4dSMichal Wajdeczko const char *buf, size_t count) 3885c170a4dSMichal Wajdeczko { 3895c170a4dSMichal Wajdeczko struct xe_sriov_dev_attr *vattr = to_xe_sriov_dev_attr(attr); 3905c170a4dSMichal Wajdeczko struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 3915c170a4dSMichal Wajdeczko struct xe_device *xe = vkobj->xe; 392f9091794SMichal Wajdeczko ssize_t ret; 3935c170a4dSMichal Wajdeczko 3945c170a4dSMichal Wajdeczko if (!vattr->store) 3955c170a4dSMichal Wajdeczko return -EPERM; 3965c170a4dSMichal Wajdeczko 397f9091794SMichal Wajdeczko xe_pm_runtime_get(xe); 398f9091794SMichal Wajdeczko ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, buf, count); 399f9091794SMichal Wajdeczko xe_pm_runtime_put(xe); 400f9091794SMichal Wajdeczko 401f9091794SMichal Wajdeczko return ret; 4025c170a4dSMichal Wajdeczko } 4035c170a4dSMichal Wajdeczko 4045c170a4dSMichal Wajdeczko static ssize_t xe_sriov_vf_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) 4055c170a4dSMichal Wajdeczko { 4065c170a4dSMichal Wajdeczko struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr); 4075c170a4dSMichal Wajdeczko struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 4085c170a4dSMichal Wajdeczko struct xe_device *xe = vkobj->xe; 4095c170a4dSMichal Wajdeczko unsigned int vfid = vkobj->vfid; 4105c170a4dSMichal Wajdeczko 4115c170a4dSMichal Wajdeczko xe_sriov_pf_assert_vfid(xe, vfid); 4125c170a4dSMichal Wajdeczko 4135c170a4dSMichal Wajdeczko if (!vattr->show) 4145c170a4dSMichal Wajdeczko return -EPERM; 4155c170a4dSMichal Wajdeczko 4165c170a4dSMichal Wajdeczko return vattr->show(xe, vfid, buf); 4175c170a4dSMichal Wajdeczko } 4185c170a4dSMichal Wajdeczko 4195c170a4dSMichal Wajdeczko static ssize_t xe_sriov_vf_attr_store(struct kobject *kobj, struct attribute *attr, 4205c170a4dSMichal Wajdeczko const char *buf, size_t count) 4215c170a4dSMichal Wajdeczko { 4225c170a4dSMichal Wajdeczko struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr); 4235c170a4dSMichal Wajdeczko struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 4245c170a4dSMichal Wajdeczko struct xe_device *xe = vkobj->xe; 4255c170a4dSMichal Wajdeczko unsigned int vfid = vkobj->vfid; 426f9091794SMichal Wajdeczko ssize_t ret; 4275c170a4dSMichal Wajdeczko 4285c170a4dSMichal Wajdeczko xe_sriov_pf_assert_vfid(xe, vfid); 4295c170a4dSMichal Wajdeczko 4305c170a4dSMichal Wajdeczko if (!vattr->store) 4315c170a4dSMichal Wajdeczko return -EPERM; 4325c170a4dSMichal Wajdeczko 433f9091794SMichal Wajdeczko xe_pm_runtime_get(xe); 434f9091794SMichal Wajdeczko ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, vfid, buf, count); 435f9091794SMichal Wajdeczko xe_pm_runtime_get(xe); 436f9091794SMichal Wajdeczko 437f9091794SMichal Wajdeczko return ret; 4385c170a4dSMichal Wajdeczko } 4395c170a4dSMichal Wajdeczko 4405c170a4dSMichal Wajdeczko static const struct sysfs_ops xe_sriov_dev_sysfs_ops = { 4415c170a4dSMichal Wajdeczko .show = xe_sriov_dev_attr_show, 4425c170a4dSMichal Wajdeczko .store = xe_sriov_dev_attr_store, 4435c170a4dSMichal Wajdeczko }; 4445c170a4dSMichal Wajdeczko 4455c170a4dSMichal Wajdeczko static const struct sysfs_ops xe_sriov_vf_sysfs_ops = { 4465c170a4dSMichal Wajdeczko .show = xe_sriov_vf_attr_show, 4475c170a4dSMichal Wajdeczko .store = xe_sriov_vf_attr_store, 4485c170a4dSMichal Wajdeczko }; 4495c170a4dSMichal Wajdeczko 4505c170a4dSMichal Wajdeczko static const struct kobj_type xe_sriov_dev_ktype = { 4515c170a4dSMichal Wajdeczko .release = release_xe_sriov_kobj, 4525c170a4dSMichal Wajdeczko .sysfs_ops = &xe_sriov_dev_sysfs_ops, 4535c170a4dSMichal Wajdeczko .default_groups = xe_sriov_dev_attr_groups, 4545c170a4dSMichal Wajdeczko }; 4555c170a4dSMichal Wajdeczko 4565c170a4dSMichal Wajdeczko static const struct kobj_type xe_sriov_vf_ktype = { 4575c170a4dSMichal Wajdeczko .release = release_xe_sriov_kobj, 4585c170a4dSMichal Wajdeczko .sysfs_ops = &xe_sriov_vf_sysfs_ops, 4595c170a4dSMichal Wajdeczko .default_groups = xe_sriov_vf_attr_groups, 4605c170a4dSMichal Wajdeczko }; 4615c170a4dSMichal Wajdeczko 4625c170a4dSMichal Wajdeczko static int pf_sysfs_error(struct xe_device *xe, int err, const char *what) 4635c170a4dSMichal Wajdeczko { 4645c170a4dSMichal Wajdeczko if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) 4655c170a4dSMichal Wajdeczko xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err)); 4665c170a4dSMichal Wajdeczko return err; 4675c170a4dSMichal Wajdeczko } 4685c170a4dSMichal Wajdeczko 46917899358SMichal Wajdeczko static void pf_sysfs_note(struct xe_device *xe, int err, const char *what) 47017899358SMichal Wajdeczko { 47117899358SMichal Wajdeczko xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err)); 47217899358SMichal Wajdeczko } 47317899358SMichal Wajdeczko 4745c170a4dSMichal Wajdeczko static void action_put_kobject(void *arg) 4755c170a4dSMichal Wajdeczko { 4765c170a4dSMichal Wajdeczko struct kobject *kobj = arg; 4775c170a4dSMichal Wajdeczko 4785c170a4dSMichal Wajdeczko kobject_put(kobj); 4795c170a4dSMichal Wajdeczko } 4805c170a4dSMichal Wajdeczko 4815c170a4dSMichal Wajdeczko static int pf_setup_root(struct xe_device *xe) 4825c170a4dSMichal Wajdeczko { 4835c170a4dSMichal Wajdeczko struct kobject *parent = &xe->drm.dev->kobj; 4845c170a4dSMichal Wajdeczko struct kobject *root; 4855c170a4dSMichal Wajdeczko int err; 4865c170a4dSMichal Wajdeczko 4875c170a4dSMichal Wajdeczko root = create_xe_sriov_kobj(xe, PFID); 4885c170a4dSMichal Wajdeczko if (!root) 4895c170a4dSMichal Wajdeczko return pf_sysfs_error(xe, -ENOMEM, "root obj"); 4905c170a4dSMichal Wajdeczko 4915c170a4dSMichal Wajdeczko err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, root); 4925c170a4dSMichal Wajdeczko if (err) 4935c170a4dSMichal Wajdeczko return pf_sysfs_error(xe, err, "root action"); 4945c170a4dSMichal Wajdeczko 4955c170a4dSMichal Wajdeczko err = kobject_init_and_add(root, &xe_sriov_dev_ktype, parent, "sriov_admin"); 4965c170a4dSMichal Wajdeczko if (err) 4975c170a4dSMichal Wajdeczko return pf_sysfs_error(xe, err, "root init"); 4985c170a4dSMichal Wajdeczko 4995c170a4dSMichal Wajdeczko xe_assert(xe, IS_SRIOV_PF(xe)); 5005c170a4dSMichal Wajdeczko xe_assert(xe, !xe->sriov.pf.sysfs.root); 5015c170a4dSMichal Wajdeczko xe->sriov.pf.sysfs.root = root; 5025c170a4dSMichal Wajdeczko return 0; 5035c170a4dSMichal Wajdeczko } 5045c170a4dSMichal Wajdeczko 5055c170a4dSMichal Wajdeczko static int pf_setup_tree(struct xe_device *xe) 5065c170a4dSMichal Wajdeczko { 5075c170a4dSMichal Wajdeczko unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe); 5085c170a4dSMichal Wajdeczko struct kobject *root, *kobj; 5095c170a4dSMichal Wajdeczko unsigned int n; 5105c170a4dSMichal Wajdeczko int err; 5115c170a4dSMichal Wajdeczko 5125c170a4dSMichal Wajdeczko xe_assert(xe, IS_SRIOV_PF(xe)); 5135c170a4dSMichal Wajdeczko root = xe->sriov.pf.sysfs.root; 5145c170a4dSMichal Wajdeczko 5155c170a4dSMichal Wajdeczko for (n = 0; n <= totalvfs; n++) { 5165c170a4dSMichal Wajdeczko kobj = create_xe_sriov_kobj(xe, VFID(n)); 5175c170a4dSMichal Wajdeczko if (!kobj) 5185c170a4dSMichal Wajdeczko return pf_sysfs_error(xe, -ENOMEM, "tree obj"); 5195c170a4dSMichal Wajdeczko 5205c170a4dSMichal Wajdeczko err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, root); 5215c170a4dSMichal Wajdeczko if (err) 5225c170a4dSMichal Wajdeczko return pf_sysfs_error(xe, err, "tree action"); 5235c170a4dSMichal Wajdeczko 5245c170a4dSMichal Wajdeczko if (n) 5255c170a4dSMichal Wajdeczko err = kobject_init_and_add(kobj, &xe_sriov_vf_ktype, 5265c170a4dSMichal Wajdeczko root, "vf%u", n); 5275c170a4dSMichal Wajdeczko else 5285c170a4dSMichal Wajdeczko err = kobject_init_and_add(kobj, &xe_sriov_vf_ktype, 5295c170a4dSMichal Wajdeczko root, "pf"); 5305c170a4dSMichal Wajdeczko if (err) 5315c170a4dSMichal Wajdeczko return pf_sysfs_error(xe, err, "tree init"); 5325c170a4dSMichal Wajdeczko 5335c170a4dSMichal Wajdeczko xe_assert(xe, !xe->sriov.pf.vfs[n].kobj); 5345c170a4dSMichal Wajdeczko xe->sriov.pf.vfs[n].kobj = kobj; 5355c170a4dSMichal Wajdeczko } 5365c170a4dSMichal Wajdeczko 5375c170a4dSMichal Wajdeczko return 0; 5385c170a4dSMichal Wajdeczko } 5395c170a4dSMichal Wajdeczko 54017899358SMichal Wajdeczko static void action_rm_device_link(void *arg) 54117899358SMichal Wajdeczko { 54217899358SMichal Wajdeczko struct kobject *kobj = arg; 54317899358SMichal Wajdeczko 54417899358SMichal Wajdeczko sysfs_remove_link(kobj, "device"); 54517899358SMichal Wajdeczko } 54617899358SMichal Wajdeczko 54717899358SMichal Wajdeczko static int pf_link_pf_device(struct xe_device *xe) 54817899358SMichal Wajdeczko { 54917899358SMichal Wajdeczko struct kobject *kobj = xe->sriov.pf.vfs[PFID].kobj; 55017899358SMichal Wajdeczko int err; 55117899358SMichal Wajdeczko 55217899358SMichal Wajdeczko err = sysfs_create_link(kobj, &xe->drm.dev->kobj, "device"); 55317899358SMichal Wajdeczko if (err) 55417899358SMichal Wajdeczko return pf_sysfs_error(xe, err, "PF device link"); 55517899358SMichal Wajdeczko 55617899358SMichal Wajdeczko err = devm_add_action_or_reset(xe->drm.dev, action_rm_device_link, kobj); 55717899358SMichal Wajdeczko if (err) 55817899358SMichal Wajdeczko return pf_sysfs_error(xe, err, "PF unlink action"); 55917899358SMichal Wajdeczko 56017899358SMichal Wajdeczko return 0; 56117899358SMichal Wajdeczko } 56217899358SMichal Wajdeczko 5635c170a4dSMichal Wajdeczko /** 5645c170a4dSMichal Wajdeczko * xe_sriov_pf_sysfs_init() - Setup PF's SR-IOV sysfs tree. 5655c170a4dSMichal Wajdeczko * @xe: the PF &xe_device to setup sysfs 5665c170a4dSMichal Wajdeczko * 5675c170a4dSMichal Wajdeczko * This function will create additional nodes that will represent PF and VFs 5685c170a4dSMichal Wajdeczko * devices, each populated with SR-IOV Xe specific attributes. 5695c170a4dSMichal Wajdeczko * 5705c170a4dSMichal Wajdeczko * Return: 0 on success or a negative error code on failure. 5715c170a4dSMichal Wajdeczko */ 5725c170a4dSMichal Wajdeczko int xe_sriov_pf_sysfs_init(struct xe_device *xe) 5735c170a4dSMichal Wajdeczko { 5745c170a4dSMichal Wajdeczko int err; 5755c170a4dSMichal Wajdeczko 5765c170a4dSMichal Wajdeczko err = pf_setup_root(xe); 5775c170a4dSMichal Wajdeczko if (err) 5785c170a4dSMichal Wajdeczko return err; 5795c170a4dSMichal Wajdeczko 5805c170a4dSMichal Wajdeczko err = pf_setup_tree(xe); 5815c170a4dSMichal Wajdeczko if (err) 5825c170a4dSMichal Wajdeczko return err; 5835c170a4dSMichal Wajdeczko 58417899358SMichal Wajdeczko err = pf_link_pf_device(xe); 58517899358SMichal Wajdeczko if (err) 58617899358SMichal Wajdeczko return err; 58717899358SMichal Wajdeczko 5885c170a4dSMichal Wajdeczko return 0; 5895c170a4dSMichal Wajdeczko } 59017899358SMichal Wajdeczko 59117899358SMichal Wajdeczko /** 59217899358SMichal Wajdeczko * xe_sriov_pf_sysfs_link_vfs() - Add VF's links in SR-IOV sysfs tree. 59317899358SMichal Wajdeczko * @xe: the &xe_device where to update sysfs 59417899358SMichal Wajdeczko * @num_vfs: number of enabled VFs to link 59517899358SMichal Wajdeczko * 59617899358SMichal Wajdeczko * This function is specific for the PF driver. 59717899358SMichal Wajdeczko * 59817899358SMichal Wajdeczko * This function will add symbolic links between VFs represented in the SR-IOV 59917899358SMichal Wajdeczko * sysfs tree maintained by the PF and enabled VF PCI devices. 60017899358SMichal Wajdeczko * 60117899358SMichal Wajdeczko * The @xe_sriov_pf_sysfs_unlink_vfs() shall be used to remove those links. 60217899358SMichal Wajdeczko */ 60317899358SMichal Wajdeczko void xe_sriov_pf_sysfs_link_vfs(struct xe_device *xe, unsigned int num_vfs) 60417899358SMichal Wajdeczko { 60517899358SMichal Wajdeczko unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe); 60617899358SMichal Wajdeczko struct pci_dev *pf_pdev = to_pci_dev(xe->drm.dev); 60717899358SMichal Wajdeczko struct pci_dev *vf_pdev = NULL; 60817899358SMichal Wajdeczko unsigned int n; 60917899358SMichal Wajdeczko int err; 61017899358SMichal Wajdeczko 61117899358SMichal Wajdeczko xe_assert(xe, IS_SRIOV_PF(xe)); 61217899358SMichal Wajdeczko xe_assert(xe, num_vfs <= totalvfs); 61317899358SMichal Wajdeczko 61417899358SMichal Wajdeczko for (n = 1; n <= num_vfs; n++) { 61517899358SMichal Wajdeczko vf_pdev = xe_pci_sriov_get_vf_pdev(pf_pdev, VFID(n)); 61617899358SMichal Wajdeczko if (!vf_pdev) 61717899358SMichal Wajdeczko return pf_sysfs_note(xe, -ENOENT, "VF link"); 61817899358SMichal Wajdeczko 61917899358SMichal Wajdeczko err = sysfs_create_link(xe->sriov.pf.vfs[VFID(n)].kobj, 62017899358SMichal Wajdeczko &vf_pdev->dev.kobj, "device"); 62117899358SMichal Wajdeczko 62217899358SMichal Wajdeczko /* must balance xe_pci_sriov_get_vf_pdev() */ 62317899358SMichal Wajdeczko pci_dev_put(vf_pdev); 62417899358SMichal Wajdeczko 62517899358SMichal Wajdeczko if (err) 62617899358SMichal Wajdeczko return pf_sysfs_note(xe, err, "VF link"); 62717899358SMichal Wajdeczko } 62817899358SMichal Wajdeczko } 62917899358SMichal Wajdeczko 63017899358SMichal Wajdeczko /** 63117899358SMichal Wajdeczko * xe_sriov_pf_sysfs_unlink_vfs() - Remove VF's links from SR-IOV sysfs tree. 63217899358SMichal Wajdeczko * @xe: the &xe_device where to update sysfs 63317899358SMichal Wajdeczko * @num_vfs: number of VFs to unlink 63417899358SMichal Wajdeczko * 63517899358SMichal Wajdeczko * This function shall be called only on the PF. 63617899358SMichal Wajdeczko * This function will remove "device" links added by @xe_sriov_sysfs_link_vfs(). 63717899358SMichal Wajdeczko */ 63817899358SMichal Wajdeczko void xe_sriov_pf_sysfs_unlink_vfs(struct xe_device *xe, unsigned int num_vfs) 63917899358SMichal Wajdeczko { 64017899358SMichal Wajdeczko unsigned int n; 64117899358SMichal Wajdeczko 64217899358SMichal Wajdeczko xe_assert(xe, IS_SRIOV_PF(xe)); 64317899358SMichal Wajdeczko xe_assert(xe, num_vfs <= xe_sriov_pf_get_totalvfs(xe)); 64417899358SMichal Wajdeczko 64517899358SMichal Wajdeczko for (n = 1; n <= num_vfs; n++) 64617899358SMichal Wajdeczko sysfs_remove_link(xe->sriov.pf.vfs[VFID(n)].kobj, "device"); 64717899358SMichal Wajdeczko } 648