| /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ |
| /* |
| * Copyright (C) 2024-2025 Intel Corporation |
| */ |
| #include "iface.h" |
| #include "sta.h" |
| |
| #define MLD_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ |
| struct dbgfs_##name##_data { \ |
| argtype *arg; \ |
| bool read_done; \ |
| ssize_t rlen; \ |
| char buf[buflen]; \ |
| }; \ |
| static int _iwl_dbgfs_##name##_open(struct inode *inode, \ |
| struct file *file) \ |
| { \ |
| struct dbgfs_##name##_data *data; \ |
| \ |
| if ((file->f_flags & O_ACCMODE) == O_RDWR) \ |
| return -EOPNOTSUPP; \ |
| \ |
| data = kzalloc(sizeof(*data), GFP_KERNEL); \ |
| if (!data) \ |
| return -ENOMEM; \ |
| \ |
| data->read_done = false; \ |
| data->arg = inode->i_private; \ |
| file->private_data = data; \ |
| \ |
| return 0; \ |
| } |
| |
| #define MLD_DEBUGFS_READ_WRAPPER(name) \ |
| static ssize_t _iwl_dbgfs_##name##_read(struct file *file, \ |
| char __user *user_buf, \ |
| size_t count, loff_t *ppos) \ |
| { \ |
| struct dbgfs_##name##_data *data = file->private_data; \ |
| \ |
| if (!data->read_done) { \ |
| data->read_done = true; \ |
| data->rlen = iwl_dbgfs_##name##_read(data->arg, \ |
| sizeof(data->buf),\ |
| data->buf); \ |
| } \ |
| \ |
| if (data->rlen < 0) \ |
| return data->rlen; \ |
| return simple_read_from_buffer(user_buf, count, ppos, \ |
| data->buf, data->rlen); \ |
| } |
| |
| static int _iwl_dbgfs_release(struct inode *inode, struct file *file) |
| { |
| kfree(file->private_data); |
| return 0; |
| } |
| |
| #define _MLD_DEBUGFS_READ_FILE_OPS(name, buflen, argtype) \ |
| MLD_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ |
| MLD_DEBUGFS_READ_WRAPPER(name) \ |
| static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
| .read = _iwl_dbgfs_##name##_read, \ |
| .open = _iwl_dbgfs_##name##_open, \ |
| .llseek = generic_file_llseek, \ |
| .release = _iwl_dbgfs_release, \ |
| } |
| |
| #define WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \ |
| static ssize_t iwl_dbgfs_##name##_write_handler(struct wiphy *wiphy, \ |
| struct file *file, char *buf, \ |
| size_t count, void *data) \ |
| { \ |
| struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \ |
| struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \ |
| return iwl_dbgfs_##name##_write(mld, buf, count, data); \ |
| } |
| |
| static inline struct iwl_mld * |
| iwl_mld_from_link_sta(struct ieee80211_link_sta *link_sta) |
| { |
| struct ieee80211_vif *vif = |
| iwl_mld_sta_from_mac80211(link_sta->sta)->vif; |
| return iwl_mld_vif_from_mac80211(vif)->mld; |
| } |
| |
| static inline struct iwl_mld * |
| iwl_mld_from_bss_conf(struct ieee80211_bss_conf *link) |
| { |
| return iwl_mld_vif_from_mac80211(link->vif)->mld; |
| } |
| |
| static inline struct iwl_mld *iwl_mld_from_vif(struct ieee80211_vif *vif) |
| { |
| return iwl_mld_vif_from_mac80211(vif)->mld; |
| } |
| |
| #define WIPHY_DEBUGFS_WRITE_WRAPPER(name, bufsz, objtype) \ |
| WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \ |
| static ssize_t __iwl_dbgfs_##name##_write(struct file *file, \ |
| const char __user *user_buf, \ |
| size_t count, loff_t *ppos) \ |
| { \ |
| struct ieee80211_##objtype *arg = file->private_data; \ |
| struct iwl_mld *mld = iwl_mld_from_##objtype(arg); \ |
| char buf[bufsz] = {}; \ |
| \ |
| return wiphy_locked_debugfs_write(mld->wiphy, file, \ |
| buf, sizeof(buf), \ |
| user_buf, count, \ |
| iwl_dbgfs_##name##_write_handler, \ |
| arg); \ |
| } |
| |
| #define WIPHY_DEBUGFS_WRITE_FILE_OPS(name, bufsz, objtype) \ |
| WIPHY_DEBUGFS_WRITE_WRAPPER(name, bufsz, objtype) \ |
| static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
| .write = __iwl_dbgfs_##name##_write, \ |
| .open = simple_open, \ |
| .llseek = generic_file_llseek, \ |
| } |
| |
| #define WIPHY_DEBUGFS_READ_HANDLER_WRAPPER_MLD(name) \ |
| static ssize_t iwl_dbgfs_##name##_read_handler(struct wiphy *wiphy, \ |
| struct file *file, char *buf, \ |
| size_t count, void *data) \ |
| { \ |
| struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \ |
| struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \ |
| return iwl_dbgfs_##name##_read(mld, buf, count); \ |
| } |
| |
| #define WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER_MLD(name) \ |
| static ssize_t iwl_dbgfs_##name##_write_handler(struct wiphy *wiphy, \ |
| struct file *file, char *buf, \ |
| size_t count, void *data) \ |
| { \ |
| struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); \ |
| struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); \ |
| return iwl_dbgfs_##name##_write(mld, buf, count); \ |
| } |
| |
| #define WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \ |
| WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER_MLD(name) \ |
| static ssize_t __iwl_dbgfs_##name##_write(struct file *file, \ |
| const char __user *user_buf, \ |
| size_t count, loff_t *ppos) \ |
| { \ |
| struct dbgfs_##name##_data *data = file->private_data; \ |
| struct iwl_mld *mld = data->arg; \ |
| \ |
| return wiphy_locked_debugfs_write(mld->wiphy, file, \ |
| data->buf, sizeof(data->buf), \ |
| user_buf, count, \ |
| iwl_dbgfs_##name##_write_handler, \ |
| NULL); \ |
| } |
| |
| #define WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \ |
| WIPHY_DEBUGFS_READ_HANDLER_WRAPPER_MLD(name) \ |
| static ssize_t __iwl_dbgfs_##name##_read(struct file *file, \ |
| char __user *user_buf, \ |
| size_t count, loff_t *ppos) \ |
| { \ |
| struct dbgfs_##name##_data *data = file->private_data; \ |
| struct iwl_mld *mld = data->arg; \ |
| \ |
| if (!data->read_done) { \ |
| data->read_done = true; \ |
| data->rlen = wiphy_locked_debugfs_read(mld->wiphy, \ |
| file, data->buf, sizeof(data->buf), \ |
| user_buf, count, ppos, \ |
| iwl_dbgfs_##name##_read_handler, NULL); \ |
| return data->rlen; \ |
| } \ |
| \ |
| if (data->rlen < 0) \ |
| return data->rlen; \ |
| return simple_read_from_buffer(user_buf, count, ppos, \ |
| data->buf, data->rlen); \ |
| } |
| |
| #define WIPHY_DEBUGFS_READ_FILE_OPS_MLD(name, bufsz) \ |
| MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \ |
| WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \ |
| static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
| .read = __iwl_dbgfs_##name##_read, \ |
| .open = _iwl_dbgfs_##name##_open, \ |
| .llseek = generic_file_llseek, \ |
| .release = _iwl_dbgfs_release, \ |
| } |
| |
| #define WIPHY_DEBUGFS_WRITE_FILE_OPS_MLD(name, bufsz) \ |
| MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \ |
| WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \ |
| static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
| .write = __iwl_dbgfs_##name##_write, \ |
| .open = _iwl_dbgfs_##name##_open, \ |
| .llseek = generic_file_llseek, \ |
| .release = _iwl_dbgfs_release, \ |
| } |
| |
| #define WIPHY_DEBUGFS_READ_WRITE_FILE_OPS_MLD(name, bufsz) \ |
| MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct iwl_mld) \ |
| WIPHY_DEBUGFS_WRITE_WRAPPER_MLD(name) \ |
| WIPHY_DEBUGFS_READ_WRAPPER_MLD(name) \ |
| static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
| .write = __iwl_dbgfs_##name##_write, \ |
| .read = __iwl_dbgfs_##name##_read, \ |
| .open = _iwl_dbgfs_##name##_open, \ |
| .llseek = generic_file_llseek, \ |
| .release = _iwl_dbgfs_release, \ |
| } |
| |
| #define WIPHY_DEBUGFS_WRITE_WRAPPER_IEEE80211(name, bufsz, objtype) \ |
| WIPHY_DEBUGFS_WRITE_HANDLER_WRAPPER(name) \ |
| static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \ |
| const char __user *user_buf, \ |
| size_t count, loff_t *ppos) \ |
| { \ |
| struct dbgfs_##name##_data *data = file->private_data; \ |
| struct ieee80211_##objtype *arg = data->arg; \ |
| struct iwl_mld *mld = iwl_mld_from_##objtype(arg); \ |
| char buf[bufsz] = {}; \ |
| \ |
| return wiphy_locked_debugfs_write(mld->wiphy, file, \ |
| buf, sizeof(buf), \ |
| user_buf, count, \ |
| iwl_dbgfs_##name##_write_handler, \ |
| arg); \ |
| } |
| |
| #define IEEE80211_WIPHY_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, objtype) \ |
| MLD_DEBUGFS_OPEN_WRAPPER(name, bufsz, struct ieee80211_##objtype) \ |
| WIPHY_DEBUGFS_WRITE_WRAPPER_IEEE80211(name, bufsz, objtype) \ |
| MLD_DEBUGFS_READ_WRAPPER(name) \ |
| static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
| .write = _iwl_dbgfs_##name##_write, \ |
| .read = _iwl_dbgfs_##name##_read, \ |
| .open = _iwl_dbgfs_##name##_open, \ |
| .llseek = generic_file_llseek, \ |
| .release = _iwl_dbgfs_release, \ |
| } |