162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef __MAC802154_DRIVER_OPS 362306a36Sopenharmony_ci#define __MAC802154_DRIVER_OPS 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/rtnetlink.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <net/mac802154.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "ieee802154_i.h" 1162306a36Sopenharmony_ci#include "trace.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic inline int 1462306a36Sopenharmony_cidrv_xmit_async(struct ieee802154_local *local, struct sk_buff *skb) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci return local->ops->xmit_async(&local->hw, skb); 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic inline int 2062306a36Sopenharmony_cidrv_xmit_sync(struct ieee802154_local *local, struct sk_buff *skb) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci might_sleep(); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci return local->ops->xmit_sync(&local->hw, skb); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic inline int drv_set_pan_id(struct ieee802154_local *local, __le16 pan_id) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct ieee802154_hw_addr_filt filt; 3062306a36Sopenharmony_ci int ret; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci might_sleep(); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (!local->ops->set_hw_addr_filt) { 3562306a36Sopenharmony_ci WARN_ON(1); 3662306a36Sopenharmony_ci return -EOPNOTSUPP; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci filt.pan_id = pan_id; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci trace_802154_drv_set_pan_id(local, pan_id); 4262306a36Sopenharmony_ci ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 4362306a36Sopenharmony_ci IEEE802154_AFILT_PANID_CHANGED); 4462306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 4562306a36Sopenharmony_ci return ret; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic inline int 4962306a36Sopenharmony_cidrv_set_extended_addr(struct ieee802154_local *local, __le64 extended_addr) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct ieee802154_hw_addr_filt filt; 5262306a36Sopenharmony_ci int ret; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci might_sleep(); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (!local->ops->set_hw_addr_filt) { 5762306a36Sopenharmony_ci WARN_ON(1); 5862306a36Sopenharmony_ci return -EOPNOTSUPP; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci filt.ieee_addr = extended_addr; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci trace_802154_drv_set_extended_addr(local, extended_addr); 6462306a36Sopenharmony_ci ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 6562306a36Sopenharmony_ci IEEE802154_AFILT_IEEEADDR_CHANGED); 6662306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 6762306a36Sopenharmony_ci return ret; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline int 7162306a36Sopenharmony_cidrv_set_short_addr(struct ieee802154_local *local, __le16 short_addr) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct ieee802154_hw_addr_filt filt; 7462306a36Sopenharmony_ci int ret; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci might_sleep(); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (!local->ops->set_hw_addr_filt) { 7962306a36Sopenharmony_ci WARN_ON(1); 8062306a36Sopenharmony_ci return -EOPNOTSUPP; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci filt.short_addr = short_addr; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci trace_802154_drv_set_short_addr(local, short_addr); 8662306a36Sopenharmony_ci ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 8762306a36Sopenharmony_ci IEEE802154_AFILT_SADDR_CHANGED); 8862306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 8962306a36Sopenharmony_ci return ret; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic inline int 9362306a36Sopenharmony_cidrv_set_pan_coord(struct ieee802154_local *local, bool is_coord) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct ieee802154_hw_addr_filt filt; 9662306a36Sopenharmony_ci int ret; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci might_sleep(); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (!local->ops->set_hw_addr_filt) { 10162306a36Sopenharmony_ci WARN_ON(1); 10262306a36Sopenharmony_ci return -EOPNOTSUPP; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci filt.pan_coord = is_coord; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci trace_802154_drv_set_pan_coord(local, is_coord); 10862306a36Sopenharmony_ci ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 10962306a36Sopenharmony_ci IEEE802154_AFILT_PANC_CHANGED); 11062306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 11162306a36Sopenharmony_ci return ret; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline int 11562306a36Sopenharmony_cidrv_set_promiscuous_mode(struct ieee802154_local *local, bool on) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int ret; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci might_sleep(); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (!local->ops->set_promiscuous_mode) { 12262306a36Sopenharmony_ci WARN_ON(1); 12362306a36Sopenharmony_ci return -EOPNOTSUPP; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci trace_802154_drv_set_promiscuous_mode(local, on); 12762306a36Sopenharmony_ci ret = local->ops->set_promiscuous_mode(&local->hw, on); 12862306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline int drv_start(struct ieee802154_local *local, 13362306a36Sopenharmony_ci enum ieee802154_filtering_level level, 13462306a36Sopenharmony_ci const struct ieee802154_hw_addr_filt *addr_filt) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci int ret; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci might_sleep(); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* setup receive mode parameters e.g. address mode */ 14162306a36Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_AFILT) { 14262306a36Sopenharmony_ci ret = drv_set_pan_id(local, addr_filt->pan_id); 14362306a36Sopenharmony_ci if (ret < 0) 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ret = drv_set_short_addr(local, addr_filt->short_addr); 14762306a36Sopenharmony_ci if (ret < 0) 14862306a36Sopenharmony_ci return ret; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ret = drv_set_extended_addr(local, addr_filt->ieee_addr); 15162306a36Sopenharmony_ci if (ret < 0) 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci switch (level) { 15662306a36Sopenharmony_ci case IEEE802154_FILTERING_NONE: 15762306a36Sopenharmony_ci fallthrough; 15862306a36Sopenharmony_ci case IEEE802154_FILTERING_1_FCS: 15962306a36Sopenharmony_ci fallthrough; 16062306a36Sopenharmony_ci case IEEE802154_FILTERING_2_PROMISCUOUS: 16162306a36Sopenharmony_ci /* TODO: Requires a different receive mode setup e.g. 16262306a36Sopenharmony_ci * at86rf233 hardware. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci fallthrough; 16562306a36Sopenharmony_ci case IEEE802154_FILTERING_3_SCAN: 16662306a36Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { 16762306a36Sopenharmony_ci ret = drv_set_promiscuous_mode(local, true); 16862306a36Sopenharmony_ci if (ret < 0) 16962306a36Sopenharmony_ci return ret; 17062306a36Sopenharmony_ci } else { 17162306a36Sopenharmony_ci return -EOPNOTSUPP; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* In practice other filtering levels can be requested, but as 17562306a36Sopenharmony_ci * for now most hardware/drivers only support 17662306a36Sopenharmony_ci * IEEE802154_FILTERING_NONE, we fallback to this actual 17762306a36Sopenharmony_ci * filtering level in hardware and make our own additional 17862306a36Sopenharmony_ci * filtering in mac802154 receive path. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * TODO: Move this logic to the device drivers as hardware may 18162306a36Sopenharmony_ci * support more higher level filters. Hardware may also require 18262306a36Sopenharmony_ci * a different order how register are set, which could currently 18362306a36Sopenharmony_ci * be buggy, so all received parameters need to be moved to the 18462306a36Sopenharmony_ci * start() callback and let the driver go into the mode before 18562306a36Sopenharmony_ci * it will turn on receive handling. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci local->phy->filtering = IEEE802154_FILTERING_NONE; 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci case IEEE802154_FILTERING_4_FRAME_FIELDS: 19062306a36Sopenharmony_ci /* Do not error out if IEEE802154_HW_PROMISCUOUS because we 19162306a36Sopenharmony_ci * expect the hardware to operate at the level 19262306a36Sopenharmony_ci * IEEE802154_FILTERING_4_FRAME_FIELDS anyway. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { 19562306a36Sopenharmony_ci ret = drv_set_promiscuous_mode(local, false); 19662306a36Sopenharmony_ci if (ret < 0) 19762306a36Sopenharmony_ci return ret; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci local->phy->filtering = IEEE802154_FILTERING_4_FRAME_FIELDS; 20162306a36Sopenharmony_ci break; 20262306a36Sopenharmony_ci default: 20362306a36Sopenharmony_ci WARN_ON(1); 20462306a36Sopenharmony_ci return -EINVAL; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci trace_802154_drv_start(local); 20862306a36Sopenharmony_ci local->started = true; 20962306a36Sopenharmony_ci smp_mb(); 21062306a36Sopenharmony_ci ret = local->ops->start(&local->hw); 21162306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 21262306a36Sopenharmony_ci return ret; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic inline void drv_stop(struct ieee802154_local *local) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci might_sleep(); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci trace_802154_drv_stop(local); 22062306a36Sopenharmony_ci local->ops->stop(&local->hw); 22162306a36Sopenharmony_ci trace_802154_drv_return_void(local); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* sync away all work on the tasklet before clearing started */ 22462306a36Sopenharmony_ci tasklet_disable(&local->tasklet); 22562306a36Sopenharmony_ci tasklet_enable(&local->tasklet); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci barrier(); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci local->started = false; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic inline int 23362306a36Sopenharmony_cidrv_set_channel(struct ieee802154_local *local, u8 page, u8 channel) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci int ret; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci might_sleep(); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci trace_802154_drv_set_channel(local, page, channel); 24062306a36Sopenharmony_ci ret = local->ops->set_channel(&local->hw, page, channel); 24162306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 24262306a36Sopenharmony_ci return ret; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic inline int drv_set_tx_power(struct ieee802154_local *local, s32 mbm) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci int ret; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci might_sleep(); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!local->ops->set_txpower) { 25262306a36Sopenharmony_ci WARN_ON(1); 25362306a36Sopenharmony_ci return -EOPNOTSUPP; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci trace_802154_drv_set_tx_power(local, mbm); 25762306a36Sopenharmony_ci ret = local->ops->set_txpower(&local->hw, mbm); 25862306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 25962306a36Sopenharmony_ci return ret; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic inline int drv_set_cca_mode(struct ieee802154_local *local, 26362306a36Sopenharmony_ci const struct wpan_phy_cca *cca) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci int ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci might_sleep(); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (!local->ops->set_cca_mode) { 27062306a36Sopenharmony_ci WARN_ON(1); 27162306a36Sopenharmony_ci return -EOPNOTSUPP; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci trace_802154_drv_set_cca_mode(local, cca); 27562306a36Sopenharmony_ci ret = local->ops->set_cca_mode(&local->hw, cca); 27662306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic inline int drv_set_lbt_mode(struct ieee802154_local *local, bool mode) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci int ret; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci might_sleep(); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (!local->ops->set_lbt) { 28762306a36Sopenharmony_ci WARN_ON(1); 28862306a36Sopenharmony_ci return -EOPNOTSUPP; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci trace_802154_drv_set_lbt_mode(local, mode); 29262306a36Sopenharmony_ci ret = local->ops->set_lbt(&local->hw, mode); 29362306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic inline int 29862306a36Sopenharmony_cidrv_set_cca_ed_level(struct ieee802154_local *local, s32 mbm) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci might_sleep(); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!local->ops->set_cca_ed_level) { 30562306a36Sopenharmony_ci WARN_ON(1); 30662306a36Sopenharmony_ci return -EOPNOTSUPP; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci trace_802154_drv_set_cca_ed_level(local, mbm); 31062306a36Sopenharmony_ci ret = local->ops->set_cca_ed_level(&local->hw, mbm); 31162306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 31262306a36Sopenharmony_ci return ret; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic inline int 31662306a36Sopenharmony_cidrv_set_csma_params(struct ieee802154_local *local, u8 min_be, u8 max_be, 31762306a36Sopenharmony_ci u8 max_csma_backoffs) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci int ret; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci might_sleep(); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (!local->ops->set_csma_params) { 32462306a36Sopenharmony_ci WARN_ON(1); 32562306a36Sopenharmony_ci return -EOPNOTSUPP; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci trace_802154_drv_set_csma_params(local, min_be, max_be, 32962306a36Sopenharmony_ci max_csma_backoffs); 33062306a36Sopenharmony_ci ret = local->ops->set_csma_params(&local->hw, min_be, max_be, 33162306a36Sopenharmony_ci max_csma_backoffs); 33262306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 33362306a36Sopenharmony_ci return ret; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic inline int 33762306a36Sopenharmony_cidrv_set_max_frame_retries(struct ieee802154_local *local, s8 max_frame_retries) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci int ret; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci might_sleep(); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!local->ops->set_frame_retries) { 34462306a36Sopenharmony_ci WARN_ON(1); 34562306a36Sopenharmony_ci return -EOPNOTSUPP; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci trace_802154_drv_set_max_frame_retries(local, max_frame_retries); 34962306a36Sopenharmony_ci ret = local->ops->set_frame_retries(&local->hw, max_frame_retries); 35062306a36Sopenharmony_ci trace_802154_drv_return_int(local, ret); 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci#endif /* __MAC802154_DRIVER_OPS */ 355