1 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 2 /* 3 * Copyright (C) 2024-2025 Intel Corporation 4 */ 5 #include "iface.h" 6 #include "sta.h" 7 8 #define MLD_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ 9 struct dbgfs_##name##_data { \ 10 argtype *arg; \ 11 bool read_done; \ 12 ssize_t rlen; \ 13 char buf[buflen]; \ 14 }; \ 15 static int _iwl_dbgfs_##name##_open(struct inode *inode, \ 16 struct file *file) \ 17 { \ 18 struct dbgfs_##name##_data *data; \ 19 \ 20 if ((file->f_flags & O_ACCMODE) == O_RDWR) \ 21 return -EOPNOTSUPP; \ 22 \ 23 data = kzalloc(sizeof(*data), GFP_KERNEL); \ 24 if (!data) \ 25 return -ENOMEM; \ 26 \ 27 data->read_done = false; \ 28 data->arg = inode->i_private; \ 29 file->private_data = data; \ 30 \ 31 return 0; \ 32 } 33 34 #define MLD_DEBUGFS_READ_WRAPPER(name) \ 35 static ssize_t _iwl_dbgfs_##name##_read(struct file *file, \ 36 char __user *user_buf, \ 37 size_t count, loff_t *ppos) \ 38 { \ 39 struct dbgfs_##name##_data *data = file->private_data; \ 40 \ 41 if (!data->read_done) { \ 42 data->read_done = true; \ 43 data->rlen = iwl_dbgfs_##name##_read(data->arg, \ 44 sizeof(data->buf),\ 45 data->buf); \ 46 } \ 47 \ 48 if (data->rlen < 0) \ 49 return data->rlen; \ 50 return simple_read_from_buffer(user_buf, count, ppos, \ 51 data->buf, data->rlen); \ 52 } 53 54 static int _iwl_dbgfs_release(struct inode *inode, struct file *file) 55 { 56 kfree(file->private_data); 57 return 0; 58 } 59 60 #define _MLD_DEBUGFS_READ_FILE_OPS(name, buflen, argtype) \ 61 MLD_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ 62 MLD_DEBUGFS_READ_WRAPPER(name) \ 63 static const struct file_operations iwl_dbgfs_##name##_ops = { \ 64 .read = _iwl_dbgfs_##name##_read, \ 65 .open = _iwl_dbgfs_##name##_open, \ 66 .llseek = generic_file_llseek, \ 67 .release = _iwl_dbgfs_release, \ 68 } 69 70 #define WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \ 71 static ssize_t iwl_dbgfs_##name##_write_handler(struct wiphy *wiphy, \ 72 struct file *file, char *buf, \ 73 size_t count, void *data) \ 74 { \ 75 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \ 76 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \ 77 return iwl_dbgfs_##name##_write(mld, buf, count, data); \ 78 } 79 80 static inline struct iwl_mld * 81 iwl_mld_from_link_sta(struct ieee80211_link_sta *link_sta) 82 { 83 struct ieee80211_vif *vif = 84 iwl_mld_sta_from_mac80211(link_sta->sta)->vif; 85 return iwl_mld_vif_from_mac80211(vif)->mld; 86 } 87 88 static inline struct iwl_mld * 89 iwl_mld_from_bss_conf(struct ieee80211_bss_conf *link) 90 { 91 return iwl_mld_vif_from_mac80211(link->vif)->mld; 92 } 93 94 static inline struct iwl_mld *iwl_mld_from_vif(struct ieee80211_vif *vif) 95 { 96 return iwl_mld_vif_from_mac80211(vif)->mld; 97 } 98 99 #define WIPHY_DEBUGFS_WRITE_WRAPPER(name, bufsz, objtype) \ 100 WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \ 101 static ssize_t __iwl_dbgfs_##name##_write(struct file *file, \ 102 const char __user *user_buf, \ 103 size_t count, loff_t *ppos) \ 104 { \ 105 struct ieee80211_##objtype *arg = file->private_data; \ 106 struct iwl_mld *mld = iwl_mld_from_##objtype(arg); \ 107 char buf[bufsz] = {}; \ 108 \ 109 return wiphy_locked_debugfs_write(mld->wiphy, file, \ 110 buf, sizeof(buf), \ 111 user_buf, count, \ 112 iwl_dbgfs_##name##_write_handler, \ 113 arg); \ 114 } 115 116 #define WIPHY_DEBUGFS_WRITE_FILE_OPS(name, bufsz, objtype) \ 117 WIPHY_DEBUGFS_WRITE_WRAPPER(name, bufsz, objtype) \ 118 static const struct file_operations iwl_dbgfs_##name##_ops = { \ 119 .write = __iwl_dbgfs_##name##_write, \ 120 .open = simple_open, \ 121 .llseek = generic_file_llseek, \ 122 } 123 124 #define WIPHY_DEBUGFS_READ_HANDLER_WRAPPER_MLD(name) \ 125 static ssize_t iwl_dbgfs_##name##_read_handler(struct wiphy *wiphy, \ 126 struct file *file, char *buf, \ 127 size_t count, void *data) \ 128 { \ 129 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \ 130 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \ 131 return iwl_dbgfs_##name##_read(mld, buf, count); \ 132 } 133 134 #define WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER_MLD(name) \ 135 static ssize_t iwl_dbgfs_##name##_write_handler(struct wiphy *wiphy, \ 136 struct file *file, char *buf, \ 137 size_t count, void *data) \ 138 { \ 139 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \ 140 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \ 141 return iwl_dbgfs_##name##_write(mld, buf, count); \ 142 } 143 144 #define WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \ 145 WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER_MLD(name) \ 146 static ssize_t __iwl_dbgfs_##name##_write(struct file *file, \ 147 const char __user *user_buf, \ 148 size_t count, loff_t *ppos) \ 149 { \ 150 struct dbgfs_##name##_data *data = file->private_data; \ 151 struct iwl_mld *mld = data->arg; \ 152 \ 153 return wiphy_locked_debugfs_write(mld->wiphy, file, \ 154 data->buf, sizeof(data->buf), \ 155 user_buf, count, \ 156 iwl_dbgfs_##name##_write_handler, \ 157 NULL); \ 158 } 159 160 #define WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \ 161 WIPHY_DEBUGFS_READ_HANDLER_WRAPPER_MLD(name) \ 162 static ssize_t __iwl_dbgfs_##name##_read(struct file *file, \ 163 char __user *user_buf, \ 164 size_t count, loff_t *ppos) \ 165 { \ 166 struct dbgfs_##name##_data *data = file->private_data; \ 167 struct iwl_mld *mld = data->arg; \ 168 \ 169 if (!data->read_done) { \ 170 data->read_done = true; \ 171 data->rlen = wiphy_locked_debugfs_read(mld->wiphy, \ 172 file, data->buf, sizeof(data->buf), \ 173 user_buf, count, ppos, \ 174 iwl_dbgfs_##name##_read_handler, NULL); \ 175 return data->rlen; \ 176 } \ 177 \ 178 if (data->rlen < 0) \ 179 return data->rlen; \ 180 return simple_read_from_buffer(user_buf, count, ppos, \ 181 data->buf, data->rlen); \ 182 } 183 184 #define WIPHY_DEBUGFS_READ_FILE_OPS_MLD(name, bufsz) \ 185 MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \ 186 WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \ 187 static const struct file_operations iwl_dbgfs_##name##_ops = { \ 188 .read = __iwl_dbgfs_##name##_read, \ 189 .open = _iwl_dbgfs_##name##_open, \ 190 .llseek = generic_file_llseek, \ 191 .release = _iwl_dbgfs_release, \ 192 } 193 194 #define WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(name, bufsz) \ 195 MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \ 196 WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \ 197 static const struct file_operations iwl_dbgfs_##name##_ops = { \ 198 .write = __iwl_dbgfs_##name##_write, \ 199 .open = _iwl_dbgfs_##name##_open, \ 200 .llseek = generic_file_llseek, \ 201 .release = _iwl_dbgfs_release, \ 202 } 203 204 #define WIPHY_DEBUGFS_READ_WRITE_FILE_OPS_MLD(name, bufsz) \ 205 MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \ 206 WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \ 207 WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \ 208 static const struct file_operations iwl_dbgfs_##name##_ops = { \ 209 .write = __iwl_dbgfs_##name##_write, \ 210 .read = __iwl_dbgfs_##name##_read, \ 211 .open = _iwl_dbgfs_##name##_open, \ 212 .llseek = generic_file_llseek, \ 213 .release = _iwl_dbgfs_release, \ 214 } 215 216 #define WIPHY_DEBUGFS_WRITE_WRAPPER_IEEE80211(name, bufsz, objtype) \ 217 WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \ 218 static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \ 219 const char __user *user_buf, \ 220 size_t count, loff_t *ppos) \ 221 { \ 222 struct dbgfs_##name##_data *data = file->private_data; \ 223 struct ieee80211_##objtype *arg = data->arg; \ 224 struct iwl_mld *mld = iwl_mld_from_##objtype(arg); \ 225 char buf[bufsz] = {}; \ 226 \ 227 return wiphy_locked_debugfs_write(mld->wiphy, file, \ 228 buf, sizeof(buf), \ 229 user_buf, count, \ 230 iwl_dbgfs_##name##_write_handler, \ 231 arg); \ 232 } 233 234 #define IEEE80211_WIPHY_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, objtype) \ 235 MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct ieee80211_##objtype) \ 236 WIPHY_DEBUGFS_WRITE_WRAPPER_IEEE80211(name, bufsz, objtype) \ 237 MLD_DEBUGFS_READ_WRAPPER(name) \ 238 static const struct file_operations iwl_dbgfs_##name##_ops = { \ 239 .write = _iwl_dbgfs_##name##_write, \ 240 .read = _iwl_dbgfs_##name##_read, \ 241 .open = _iwl_dbgfs_##name##_open, \ 242 .llseek = generic_file_llseek, \ 243 .release = _iwl_dbgfs_release, \ 244 } 245