aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>2014-02-17 05:34:12 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-17 16:42:38 -0500
commit6ca001978dce0d50ebac01a38d6287f241a520c6 (patch)
tree2ed75aadbfb16ca006a2cd94bc30ebf614783ffc
parentba08fea53a43e02b590d89224afdad976dece841 (diff)
ieee802154: add support for setting CCA energy detection levels
Since three of the four clear channel assesment modes make use of energy detection, provide an API to set the energy detection threshold. Driver support for this is available in at86rf230 for the RF212 chips. Since for these chips the minimal energy detection threshold depends on page and channel used, add a field to struct at86rf230_local that stores the minimal threshold. Actual ED thresholds are configured as offsets from this value. For RF212, setting the ED threshold will not work before a channel/page has been set due to the dependency of energy detection in the chip and the actual channel/page selected. Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ieee802154/at86rf230.c26
-rw-r--r--include/linux/nl802154.h1
-rw-r--r--include/net/mac802154.h7
-rw-r--r--include/net/wpan-phy.h2
-rw-r--r--net/ieee802154/nl-phy.c30
-rw-r--r--net/ieee802154/nl_policy.c1
-rw-r--r--net/mac802154/ieee802154_dev.c11
7 files changed, 73 insertions, 5 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index c60871aff333..20596be61028 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -52,6 +52,8 @@ struct at86rf230_local {
52 spinlock_t lock; 52 spinlock_t lock;
53 bool irq_busy; 53 bool irq_busy;
54 bool is_tx; 54 bool is_tx;
55
56 int rssi_base_val;
55}; 57};
56 58
57static inline int is_rf212(struct at86rf230_local *local) 59static inline int is_rf212(struct at86rf230_local *local)
@@ -580,6 +582,8 @@ at86rf230_stop(struct ieee802154_dev *dev)
580static int 582static int
581at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel) 583at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel)
582{ 584{
585 lp->rssi_base_val = -91;
586
583 return at86rf230_write_subreg(lp, SR_CHANNEL, channel); 587 return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
584} 588}
585 589
@@ -595,10 +599,13 @@ at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
595 if (rc < 0) 599 if (rc < 0)
596 return rc; 600 return rc;
597 601
598 if (page == 0) 602 if (page == 0) {
599 rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0); 603 rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0);
600 else 604 lp->rssi_base_val = -100;
605 } else {
601 rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1); 606 rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1);
607 lp->rssi_base_val = -98;
608 }
602 if (rc < 0) 609 if (rc < 0)
603 return rc; 610 return rc;
604 611
@@ -802,6 +809,20 @@ at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
802 return at86rf230_write_subreg(lp, SR_CCA_MODE, mode); 809 return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
803} 810}
804 811
812static int
813at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
814{
815 struct at86rf230_local *lp = dev->priv;
816 int desens_steps;
817
818 if (level < lp->rssi_base_val || level > 30)
819 return -EINVAL;
820
821 desens_steps = (level - lp->rssi_base_val) * 100 / 207;
822
823 return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps);
824}
825
805static struct ieee802154_ops at86rf230_ops = { 826static struct ieee802154_ops at86rf230_ops = {
806 .owner = THIS_MODULE, 827 .owner = THIS_MODULE,
807 .xmit = at86rf230_xmit, 828 .xmit = at86rf230_xmit,
@@ -823,6 +844,7 @@ static struct ieee802154_ops at86rf212_ops = {
823 .set_txpower = at86rf212_set_txpower, 844 .set_txpower = at86rf212_set_txpower,
824 .set_lbt = at86rf212_set_lbt, 845 .set_lbt = at86rf212_set_lbt,
825 .set_cca_mode = at86rf212_set_cca_mode, 846 .set_cca_mode = at86rf212_set_cca_mode,
847 .set_cca_ed_level = at86rf212_set_cca_ed_level,
826}; 848};
827 849
828static void at86rf230_irqwork(struct work_struct *work) 850static void at86rf230_irqwork(struct work_struct *work)
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index 5edefc14bd83..0594a0ae71ba 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -73,6 +73,7 @@ enum {
73 IEEE802154_ATTR_TXPOWER, 73 IEEE802154_ATTR_TXPOWER,
74 IEEE802154_ATTR_LBT_ENABLED, 74 IEEE802154_ATTR_LBT_ENABLED,
75 IEEE802154_ATTR_CCA_MODE, 75 IEEE802154_ATTR_CCA_MODE,
76 IEEE802154_ATTR_CCA_ED_LEVEL,
76 77
77 __IEEE802154_ATTR_MAX, 78 __IEEE802154_ATTR_MAX,
78}; 79};
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 1a98e5014e66..15fe6bca80f0 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -126,6 +126,11 @@ struct ieee802154_dev {
126 * set_cca_mode 126 * set_cca_mode
127 * Sets the CCA mode used by the device. Called with pib_lock held. 127 * Sets the CCA mode used by the device. Called with pib_lock held.
128 * Returns either zero, or negative errno. 128 * Returns either zero, or negative errno.
129 *
130 * set_cca_ed_level
131 * Sets the CCA energy detection threshold in dBm. Called with pib_lock
132 * held.
133 * Returns either zero, or negative errno.
129 */ 134 */
130struct ieee802154_ops { 135struct ieee802154_ops {
131 struct module *owner; 136 struct module *owner;
@@ -145,6 +150,8 @@ struct ieee802154_ops {
145 int (*set_txpower)(struct ieee802154_dev *dev, int db); 150 int (*set_txpower)(struct ieee802154_dev *dev, int db);
146 int (*set_lbt)(struct ieee802154_dev *dev, bool on); 151 int (*set_lbt)(struct ieee802154_dev *dev, bool on);
147 int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode); 152 int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
153 int (*set_cca_ed_level)(struct ieee802154_dev *dev,
154 s32 level);
148}; 155};
149 156
150/* Basic interface to register ieee802154 device */ 157/* Basic interface to register ieee802154 device */
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h
index 03b59051972d..0b570ad5e5fa 100644
--- a/include/net/wpan-phy.h
+++ b/include/net/wpan-phy.h
@@ -48,6 +48,7 @@ struct wpan_phy {
48 u8 cca_mode; 48 u8 cca_mode;
49 49
50 bool lbt; 50 bool lbt;
51 s32 cca_ed_level;
51 52
52 struct device dev; 53 struct device dev;
53 int idx; 54 int idx;
@@ -59,6 +60,7 @@ struct wpan_phy {
59 int (*set_txpower)(struct wpan_phy *phy, int db); 60 int (*set_txpower)(struct wpan_phy *phy, int db);
60 int (*set_lbt)(struct wpan_phy *phy, bool on); 61 int (*set_lbt)(struct wpan_phy *phy, bool on);
61 int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode); 62 int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode);
63 int (*set_cca_ed_level)(struct wpan_phy *phy, int level);
62 64
63 char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); 65 char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
64}; 66};
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index 36f58d633868..0af0d424dee0 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -58,7 +58,8 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
58 nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel) || 58 nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel) ||
59 nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, phy->transmit_power) || 59 nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, phy->transmit_power) ||
60 nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, phy->lbt) || 60 nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, phy->lbt) ||
61 nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, phy->cca_mode)) 61 nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, phy->cca_mode) ||
62 nla_put_s32(msg, IEEE802154_ATTR_CCA_ED_LEVEL, phy->cca_ed_level))
62 goto nla_put_failure; 63 goto nla_put_failure;
63 for (i = 0; i < 32; i++) { 64 for (i = 0; i < 32; i++) {
64 if (phy->channels_supported[i]) 65 if (phy->channels_supported[i])
@@ -403,6 +404,20 @@ static int phy_set_cca_mode(struct wpan_phy *phy, struct genl_info *info)
403 return 0; 404 return 0;
404} 405}
405 406
407static int phy_set_cca_ed_level(struct wpan_phy *phy, struct genl_info *info)
408{
409 s32 level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]);
410 int rc;
411
412 rc = phy->set_cca_ed_level(phy, level);
413 if (rc < 0)
414 return rc;
415
416 phy->cca_ed_level = level;
417
418 return 0;
419}
420
406int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info) 421int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
407{ 422{
408 struct wpan_phy *phy; 423 struct wpan_phy *phy;
@@ -413,7 +428,8 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
413 428
414 if (!info->attrs[IEEE802154_ATTR_PHY_NAME] && 429 if (!info->attrs[IEEE802154_ATTR_PHY_NAME] &&
415 !info->attrs[IEEE802154_ATTR_LBT_ENABLED] && 430 !info->attrs[IEEE802154_ATTR_LBT_ENABLED] &&
416 !info->attrs[IEEE802154_ATTR_CCA_MODE]) 431 !info->attrs[IEEE802154_ATTR_CCA_MODE] &&
432 !info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL])
417 return -EINVAL; 433 return -EINVAL;
418 434
419 name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 435 name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
@@ -426,7 +442,9 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
426 442
427 if ((!phy->set_txpower && info->attrs[IEEE802154_ATTR_TXPOWER]) || 443 if ((!phy->set_txpower && info->attrs[IEEE802154_ATTR_TXPOWER]) ||
428 (!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) || 444 (!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
429 (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE])) 445 (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
446 (!phy->set_cca_ed_level &&
447 info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]))
430 goto out; 448 goto out;
431 449
432 mutex_lock(&phy->pib_lock); 450 mutex_lock(&phy->pib_lock);
@@ -449,6 +467,12 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
449 goto error; 467 goto error;
450 } 468 }
451 469
470 if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) {
471 rc = phy_set_cca_ed_level(phy, info);
472 if (rc < 0)
473 goto error;
474 }
475
452 mutex_unlock(&phy->pib_lock); 476 mutex_unlock(&phy->pib_lock);
453 477
454 wpan_phy_put(phy); 478 wpan_phy_put(phy);
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
index d87c2c904110..55b5616295ff 100644
--- a/net/ieee802154/nl_policy.c
+++ b/net/ieee802154/nl_policy.c
@@ -56,5 +56,6 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
56 [IEEE802154_ATTR_TXPOWER] = { .type = NLA_S8, }, 56 [IEEE802154_ATTR_TXPOWER] = { .type = NLA_S8, },
57 [IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, }, 57 [IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, },
58 [IEEE802154_ATTR_CCA_MODE] = { .type = NLA_U8, }, 58 [IEEE802154_ATTR_CCA_MODE] = { .type = NLA_U8, },
59 [IEEE802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
59}; 60};
60 61
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c
index 4965e4ce6b5b..4707f36546d3 100644
--- a/net/mac802154/ieee802154_dev.c
+++ b/net/mac802154/ieee802154_dev.c
@@ -195,6 +195,16 @@ static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode)
195 return priv->ops->set_cca_mode(&priv->hw, mode); 195 return priv->ops->set_cca_mode(&priv->hw, mode);
196} 196}
197 197
198static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level)
199{
200 struct mac802154_priv *priv = wpan_phy_priv(phy);
201
202 if (!priv->ops->set_cca_ed_level)
203 return -ENOTSUPP;
204
205 return priv->ops->set_cca_ed_level(&priv->hw, level);
206}
207
198struct ieee802154_dev * 208struct ieee802154_dev *
199ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) 209ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
200{ 210{
@@ -275,6 +285,7 @@ int ieee802154_register_device(struct ieee802154_dev *dev)
275 priv->phy->set_txpower = mac802154_set_txpower; 285 priv->phy->set_txpower = mac802154_set_txpower;
276 priv->phy->set_lbt = mac802154_set_lbt; 286 priv->phy->set_lbt = mac802154_set_lbt;
277 priv->phy->set_cca_mode = mac802154_set_cca_mode; 287 priv->phy->set_cca_mode = mac802154_set_cca_mode;
288 priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
278 289
279 rc = wpan_phy_register(priv->phy); 290 rc = wpan_phy_register(priv->phy);
280 if (rc < 0) 291 if (rc < 0)