Message ID | cover.386a66ec6a89750d4890f63f0d28582a52b838b5.1717696995.git-series.nbd@nbd.name |
---|---|
Headers | show |
Series | cfg80211/mac80211: support defining multiple radios per wiphy | expand |
On Thu, 2024-06-06 at 20:07 +0200, Felix Fietkau wrote: > > @@ -4577,6 +4579,7 @@ struct mgmt_frame_regs { > * > * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames. > * @set_ttlm: set the TID to link mapping. > + * @get_radio_mask: get bitmask of radios in use > */ > struct cfg80211_ops { > int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); > @@ -4938,6 +4941,8 @@ struct cfg80211_ops { > struct cfg80211_set_hw_timestamp *hwts); > int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev, > struct cfg80211_ttlm_params *params); > + int (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev, > + u32 *mask); not sure I see the point of this being a callback rather than being passed in? (Also, if really needed, do you actually expect a device with 32 radios? if not you can use a return value instead of u32 *mask out pointer :) ) > +DEFINE_EVENT(wiphy_netdev_evt, rdev_get_radio_mask, > + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), > + TP_ARGS(wiphy, netdev) > +); and if we do need it that really should trace not just the fact that it happened but also the return value and mask > static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, > u32 *beacon_int_gcd, > - bool *beacon_int_different) > + bool *beacon_int_different, > + const struct wiphy_radio *radio) > { > + struct cfg80211_registered_device *rdev; > struct wireless_dev *wdev; > + int radio_idx = -1; > > *beacon_int_gcd = 0; > *beacon_int_different = false; > + if (radio) > + radio_idx = radio - wiphy->radio; This can go oh so wrong ... and technically even be UB. I'd rather pass the index from the driver, I guess, and validate it against n_radios. > + rdev = wiphy_to_rdev(wiphy); > list_for_each_entry(wdev, &wiphy->wdev_list, list) { > int wdev_bi; > + u32 mask; > > /* this feature isn't supported with MLO */ > if (wdev->valid_links) > continue; Are we expecting this to change? because the premise of this patchset is MLO support, and yet with real MLO we won't get here? Or is that because non-MLO interfaces could be created on this wiphy? > > + if (radio_idx >= 0) { > + if (rdev_get_radio_mask(rdev, wdev->netdev, &mask)) > + continue; here: given that 'radio'/'radio_idx' is passed in, not sure I see why the mask couldn't also be passed in? > + if (!(mask & BIT(radio_idx))) > + continue; that could use a comment > - for (i = 0; i < wiphy->n_iface_combinations; i++) { > - const struct ieee80211_iface_combination *c; > + if (radio) { > + c = radio->iface_combinations; > + n = radio->n_iface_combinations; > + } else { > + c = wiphy->iface_combinations; > + n = wiphy->n_iface_combinations; > + } > + for (i = 0; i < n; i++, c++) { that c++ is a bit too hidden for my taste there, but YMMV and I guess if I wasn't reading the diff it'd be more obvious :) johannes
On Fri, 2024-06-07 at 11:53 +0200, Felix Fietkau wrote: > > struct wiphy_radio *wiphy_get_radio(struct wiphy *wiphy, ... *chandef); > > I didn't add such a helper, in case we get hardware where multiple > radios support the same band. That's why ieee80211_find_available_radio > loops over all radios until it finds one that matches both the freq > range and the ifcomb constraints. Ah, fair. Thinking more about the "whole chandef" thing, I think I want to have a check in cfg80211 somewhere that ensures you don't split up ranges that could be used for a wider channel? Say (for a stupid example) you have a device that (only) supports channels 36-40: * 5180 * 5200 but now you say it has two radios: * radio 1 ranges: 5170-5190 * radio 2 ranges: 5190-5210 Now you can't use 40 MHz... but nothing will actually really prevent it. Obviously this is a totally useless case, so I'd argue we should just check during wiphy registration that you don't split the channel list in this way with multiple radios? Even on the potential Qualcomm 5 GHz low/mid/high split radios you'd have gaps between the channels (e.g. no channel 80, no channel 148), so it feels like you should always be able to split it in a way that the radio range boundaries don't land between two adjacent channels in the channel array. Not sure how to implement such a check best, probably easiest to find all non-adjacent channels first: - go over bands - ensure channels are sorted by increasing frequency (not sure we do that today? but every driver probably does) - find adjacent channels: - while more channels: - start_freq = current channel's freq - 10 - end_freq = current channel's freq + 10 - while current channel's freq == end_freq - 10: - go to next channel - check all radio's ranges cover this full or not at all (neither start nor end of a range falls into the calculated [start_freq, end_freq) interval) or something like that? (Also some docs on this I guess!) johannes
On 07.06.24 11:32, Johannes Berg wrote: > On Thu, 2024-06-06 at 20:07 +0200, Felix Fietkau wrote: >> >> @@ -4577,6 +4579,7 @@ struct mgmt_frame_regs { >> * >> * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames. >> * @set_ttlm: set the TID to link mapping. >> + * @get_radio_mask: get bitmask of radios in use >> */ >> struct cfg80211_ops { >> int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); >> @@ -4938,6 +4941,8 @@ struct cfg80211_ops { >> struct cfg80211_set_hw_timestamp *hwts); >> int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev, >> struct cfg80211_ttlm_params *params); >> + int (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev, >> + u32 *mask); > > > not sure I see the point of this being a callback rather than being > passed in? > > (Also, if really needed, do you actually expect a device with 32 radios? > if not you can use a return value instead of u32 *mask out pointer :) ) I'll update the callback to return u32 >> +DEFINE_EVENT(wiphy_netdev_evt, rdev_get_radio_mask, >> + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), >> + TP_ARGS(wiphy, netdev) >> +); > > and if we do need it that really should trace not just the fact that it > happened but also the return value and mask > >> static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, >> u32 *beacon_int_gcd, >> - bool *beacon_int_different) >> + bool *beacon_int_different, >> + const struct wiphy_radio *radio) >> { >> + struct cfg80211_registered_device *rdev; >> struct wireless_dev *wdev; >> + int radio_idx = -1; >> >> *beacon_int_gcd = 0; >> *beacon_int_different = false; >> + if (radio) >> + radio_idx = radio - wiphy->radio; > > This can go oh so wrong ... and technically even be UB. I'd rather pass > the index from the driver, I guess, and validate it against n_radios. Will pass the index in directly. >> + rdev = wiphy_to_rdev(wiphy); >> list_for_each_entry(wdev, &wiphy->wdev_list, list) { >> int wdev_bi; >> + u32 mask; >> >> /* this feature isn't supported with MLO */ >> if (wdev->valid_links) >> continue; > > Are we expecting this to change? because the premise of this patchset is > MLO support, and yet with real MLO we won't get here? > > Or is that because non-MLO interfaces could be created on this wiphy? Not sure about this. I guess we can revisit it later since it's out of scope for this series. >> >> + if (radio_idx >= 0) { >> + if (rdev_get_radio_mask(rdev, wdev->netdev, &mask)) >> + continue; > > > here: given that 'radio'/'radio_idx' is passed in, not sure I see why > the mask couldn't also be passed in? mask is supposed to be per wdev, which is iterated in a loop here. > >> + if (!(mask & BIT(radio_idx))) >> + continue; > > that could use a comment > >> - for (i = 0; i < wiphy->n_iface_combinations; i++) { >> - const struct ieee80211_iface_combination *c; >> + if (radio) { >> + c = radio->iface_combinations; >> + n = radio->n_iface_combinations; >> + } else { >> + c = wiphy->iface_combinations; >> + n = wiphy->n_iface_combinations; >> + } >> + for (i = 0; i < n; i++, c++) { > > that c++ is a bit too hidden for my taste there, but YMMV and I guess if > I wasn't reading the diff it'd be more obvious :) Will move it into the loop body to make it more obvious. Thanks, - Felix