1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __MAC802154_DRIVER_OPS 3 #define __MAC802154_DRIVER_OPS 4 5 #include <linux/types.h> 6 #include <linux/rtnetlink.h> 7 8 #include <net/mac802154.h> 9 10 #include "ieee802154_i.h" 11 #include "trace.h" 12 13 static inline int 14 drv_xmit_async(struct ieee802154_local *local, struct sk_buff *skb) 15 { 16 return local->ops->xmit_async(&local->hw, skb); 17 } 18 19 static inline int 20 drv_xmit_sync(struct ieee802154_local *local, struct sk_buff *skb) 21 { 22 might_sleep(); 23 24 return local->ops->xmit_sync(&local->hw, skb); 25 } 26 27 static inline int drv_set_pan_id(struct ieee802154_local *local, __le16 pan_id) 28 { 29 struct ieee802154_hw_addr_filt filt; 30 int ret; 31 32 might_sleep(); 33 34 if (!local->ops->set_hw_addr_filt) { 35 WARN_ON(1); 36 return -EOPNOTSUPP; 37 } 38 39 filt.pan_id = pan_id; 40 41 trace_802154_drv_set_pan_id(local, pan_id); 42 ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 43 IEEE802154_AFILT_PANID_CHANGED); 44 trace_802154_drv_return_int(local, ret); 45 return ret; 46 } 47 48 static inline int 49 drv_set_extended_addr(struct ieee802154_local *local, __le64 extended_addr) 50 { 51 struct ieee802154_hw_addr_filt filt; 52 int ret; 53 54 might_sleep(); 55 56 if (!local->ops->set_hw_addr_filt) { 57 WARN_ON(1); 58 return -EOPNOTSUPP; 59 } 60 61 filt.ieee_addr = extended_addr; 62 63 trace_802154_drv_set_extended_addr(local, extended_addr); 64 ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 65 IEEE802154_AFILT_IEEEADDR_CHANGED); 66 trace_802154_drv_return_int(local, ret); 67 return ret; 68 } 69 70 static inline int 71 drv_set_short_addr(struct ieee802154_local *local, __le16 short_addr) 72 { 73 struct ieee802154_hw_addr_filt filt; 74 int ret; 75 76 might_sleep(); 77 78 if (!local->ops->set_hw_addr_filt) { 79 WARN_ON(1); 80 return -EOPNOTSUPP; 81 } 82 83 filt.short_addr = short_addr; 84 85 trace_802154_drv_set_short_addr(local, short_addr); 86 ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 87 IEEE802154_AFILT_SADDR_CHANGED); 88 trace_802154_drv_return_int(local, ret); 89 return ret; 90 } 91 92 static inline int 93 drv_set_pan_coord(struct ieee802154_local *local, bool is_coord) 94 { 95 struct ieee802154_hw_addr_filt filt; 96 int ret; 97 98 might_sleep(); 99 100 if (!local->ops->set_hw_addr_filt) { 101 WARN_ON(1); 102 return -EOPNOTSUPP; 103 } 104 105 filt.pan_coord = is_coord; 106 107 trace_802154_drv_set_pan_coord(local, is_coord); 108 ret = local->ops->set_hw_addr_filt(&local->hw, &filt, 109 IEEE802154_AFILT_PANC_CHANGED); 110 trace_802154_drv_return_int(local, ret); 111 return ret; 112 } 113 114 static inline int 115 drv_set_promiscuous_mode(struct ieee802154_local *local, bool on) 116 { 117 int ret; 118 119 might_sleep(); 120 121 if (!local->ops->set_promiscuous_mode) { 122 WARN_ON(1); 123 return -EOPNOTSUPP; 124 } 125 126 trace_802154_drv_set_promiscuous_mode(local, on); 127 ret = local->ops->set_promiscuous_mode(&local->hw, on); 128 trace_802154_drv_return_int(local, ret); 129 return ret; 130 } 131 132 static inline int drv_start(struct ieee802154_local *local, 133 enum ieee802154_filtering_level level, 134 const struct ieee802154_hw_addr_filt *addr_filt) 135 { 136 int ret; 137 138 might_sleep(); 139 140 /* setup receive mode parameters e.g. address mode */ 141 if (local->hw.flags & IEEE802154_HW_AFILT) { 142 ret = drv_set_pan_id(local, addr_filt->pan_id); 143 if (ret < 0) 144 return ret; 145 146 ret = drv_set_short_addr(local, addr_filt->short_addr); 147 if (ret < 0) 148 return ret; 149 150 ret = drv_set_extended_addr(local, addr_filt->ieee_addr); 151 if (ret < 0) 152 return ret; 153 } 154 155 switch (level) { 156 case IEEE802154_FILTERING_NONE: 157 fallthrough; 158 case IEEE802154_FILTERING_1_FCS: 159 fallthrough; 160 case IEEE802154_FILTERING_2_PROMISCUOUS: 161 /* TODO: Requires a different receive mode setup e.g. 162 * at86rf233 hardware. 163 */ 164 fallthrough; 165 case IEEE802154_FILTERING_3_SCAN: 166 if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { 167 ret = drv_set_promiscuous_mode(local, true); 168 if (ret < 0) 169 return ret; 170 } else { 171 return -EOPNOTSUPP; 172 } 173 174 /* In practice other filtering levels can be requested, but as 175 * for now most hardware/drivers only support 176 * IEEE802154_FILTERING_NONE, we fallback to this actual 177 * filtering level in hardware and make our own additional 178 * filtering in mac802154 receive path. 179 * 180 * TODO: Move this logic to the device drivers as hardware may 181 * support more higher level filters. Hardware may also require 182 * a different order how register are set, which could currently 183 * be buggy, so all received parameters need to be moved to the 184 * start() callback and let the driver go into the mode before 185 * it will turn on receive handling. 186 */ 187 local->phy->filtering = IEEE802154_FILTERING_NONE; 188 break; 189 case IEEE802154_FILTERING_4_FRAME_FIELDS: 190 /* Do not error out if IEEE802154_HW_PROMISCUOUS because we 191 * expect the hardware to operate at the level 192 * IEEE802154_FILTERING_4_FRAME_FIELDS anyway. 193 */ 194 if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { 195 ret = drv_set_promiscuous_mode(local, false); 196 if (ret < 0) 197 return ret; 198 } 199 200 local->phy->filtering = IEEE802154_FILTERING_4_FRAME_FIELDS; 201 break; 202 default: 203 WARN_ON(1); 204 return -EINVAL; 205 } 206 207 trace_802154_drv_start(local); 208 local->started = true; 209 smp_mb(); 210 ret = local->ops->start(&local->hw); 211 trace_802154_drv_return_int(local, ret); 212 return ret; 213 } 214 215 static inline void drv_stop(struct ieee802154_local *local) 216 { 217 might_sleep(); 218 219 trace_802154_drv_stop(local); 220 local->ops->stop(&local->hw); 221 trace_802154_drv_return_void(local); 222 223 /* sync away all work on the tasklet before clearing started */ 224 tasklet_disable(&local->tasklet); 225 tasklet_enable(&local->tasklet); 226 227 barrier(); 228 229 local->started = false; 230 } 231 232 static inline int 233 drv_set_channel(struct ieee802154_local *local, u8 page, u8 channel) 234 { 235 int ret; 236 237 might_sleep(); 238 239 trace_802154_drv_set_channel(local, page, channel); 240 ret = local->ops->set_channel(&local->hw, page, channel); 241 trace_802154_drv_return_int(local, ret); 242 return ret; 243 } 244 245 static inline int drv_set_tx_power(struct ieee802154_local *local, s32 mbm) 246 { 247 int ret; 248 249 might_sleep(); 250 251 if (!local->ops->set_txpower) { 252 WARN_ON(1); 253 return -EOPNOTSUPP; 254 } 255 256 trace_802154_drv_set_tx_power(local, mbm); 257 ret = local->ops->set_txpower(&local->hw, mbm); 258 trace_802154_drv_return_int(local, ret); 259 return ret; 260 } 261 262 static inline int drv_set_cca_mode(struct ieee802154_local *local, 263 const struct wpan_phy_cca *cca) 264 { 265 int ret; 266 267 might_sleep(); 268 269 if (!local->ops->set_cca_mode) { 270 WARN_ON(1); 271 return -EOPNOTSUPP; 272 } 273 274 trace_802154_drv_set_cca_mode(local, cca); 275 ret = local->ops->set_cca_mode(&local->hw, cca); 276 trace_802154_drv_return_int(local, ret); 277 return ret; 278 } 279 280 static inline int drv_set_lbt_mode(struct ieee802154_local *local, bool mode) 281 { 282 int ret; 283 284 might_sleep(); 285 286 if (!local->ops->set_lbt) { 287 WARN_ON(1); 288 return -EOPNOTSUPP; 289 } 290 291 trace_802154_drv_set_lbt_mode(local, mode); 292 ret = local->ops->set_lbt(&local->hw, mode); 293 trace_802154_drv_return_int(local, ret); 294 return ret; 295 } 296 297 static inline int 298 drv_set_cca_ed_level(struct ieee802154_local *local, s32 mbm) 299 { 300 int ret; 301 302 might_sleep(); 303 304 if (!local->ops->set_cca_ed_level) { 305 WARN_ON(1); 306 return -EOPNOTSUPP; 307 } 308 309 trace_802154_drv_set_cca_ed_level(local, mbm); 310 ret = local->ops->set_cca_ed_level(&local->hw, mbm); 311 trace_802154_drv_return_int(local, ret); 312 return ret; 313 } 314 315 static inline int 316 drv_set_csma_params(struct ieee802154_local *local, u8 min_be, u8 max_be, 317 u8 max_csma_backoffs) 318 { 319 int ret; 320 321 might_sleep(); 322 323 if (!local->ops->set_csma_params) { 324 WARN_ON(1); 325 return -EOPNOTSUPP; 326 } 327 328 trace_802154_drv_set_csma_params(local, min_be, max_be, 329 max_csma_backoffs); 330 ret = local->ops->set_csma_params(&local->hw, min_be, max_be, 331 max_csma_backoffs); 332 trace_802154_drv_return_int(local, ret); 333 return ret; 334 } 335 336 static inline int 337 drv_set_max_frame_retries(struct ieee802154_local *local, s8 max_frame_retries) 338 { 339 int ret; 340 341 might_sleep(); 342 343 if (!local->ops->set_frame_retries) { 344 WARN_ON(1); 345 return -EOPNOTSUPP; 346 } 347 348 trace_802154_drv_set_max_frame_retries(local, max_frame_retries); 349 ret = local->ops->set_frame_retries(&local->hw, max_frame_retries); 350 trace_802154_drv_return_int(local, ret); 351 return ret; 352 } 353 354 #endif /* __MAC802154_DRIVER_OPS */ 355