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.buckheis...@itwm.fraunhofer.de>
---
 drivers/net/ieee802154/at86rf230.c |   29 ++++++++++++++++++++++++++++-
 include/linux/nl802154.h           |    1 +
 include/net/mac802154.h            |    6 ++++++
 include/net/wpan-phy.h             |    2 ++
 net/ieee802154/nl-phy.c            |   28 +++++++++++++++++++++++++---
 net/ieee802154/nl_policy.c         |    1 +
 net/mac802154/ieee802154_dev.c     |    8 ++++++++
 7 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ieee802154/at86rf230.c 
b/drivers/net/ieee802154/at86rf230.c
index f3f6ecb..a92c3e8 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -53,6 +53,8 @@ struct at86rf230_local {
        spinlock_t lock;
        bool irq_busy;
        bool is_tx;
+
+       int rssi_base_val;
 };
 
 static inline int is_rf212(struct at86rf230_local *local)
@@ -558,7 +560,10 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, 
int channel)
                rc = at86rf230_write_subreg(lp, SR_OQPSK_DATA_RATE, 0);
                if (rc)
                        return rc;
-       }
+
+               lp->rssi_base_val = -98;
+       } else
+               lp->rssi_base_val = -100;
 
        msleep(1); /* Wait for PLL */
        dev->phy->current_channel = channel;
@@ -748,6 +753,25 @@ at86rf230_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
        return rc;
 }
 
+static int
+at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
+{
+       struct at86rf230_local *lp = dev->priv;
+       int rc, desens_steps;
+
+       if (!is_rf212(lp))
+               return -ENOTSUPP;
+
+       if (level < lp->rssi_base_val || level > 30)
+               return -EINVAL;
+
+       desens_steps = (level - lp->rssi_base_val) * 100 / 207;
+
+       rc = at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps);
+
+       return rc;
+}
+
 static struct ieee802154_ops at86rf230_ops = {
        .owner = THIS_MODULE,
        .xmit = at86rf230_xmit,
@@ -759,6 +783,7 @@ static struct ieee802154_ops at86rf230_ops = {
        .set_txpower = at86rf230_set_txpower,
        .set_lbt = at86rf230_set_lbt,
        .set_cca_mode = at86rf230_set_cca_mode,
+       .set_cca_ed_level = at86rf230_set_cca_ed_level,
 };
 
 static void at86rf230_irqwork(struct work_struct *work)
@@ -949,6 +974,8 @@ static int at86rf230_probe(struct spi_device *spi)
 
        lp->spi = spi;
 
+       lp->rssi_base_val = INT_MAX;
+
        dev->parent = &spi->dev;
        dev->extra_tx_headroom = 0;
        dev->flags = IEEE802154_HW_OMIT_CKSUM;
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index 5edefc1..0594a0a 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -73,6 +73,7 @@ enum {
        IEEE802154_ATTR_TXPOWER,
        IEEE802154_ATTR_LBT_ENABLED,
        IEEE802154_ATTR_CCA_MODE,
+       IEEE802154_ATTR_CCA_ED_LEVEL,
 
        __IEEE802154_ATTR_MAX,
 };
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 44b6129..1feabc5 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -125,6 +125,10 @@ struct ieee802154_dev {
  * set_cca_mode
  *       Sets the CCA mode used by the device.
  *       Returns either zero, or negative errno.
+ *
+ * set_cca_ed_level
+ *       Sets the CCA energy detection threshold in dBm.
+ *       Returns either zero, or negative errno.
  */
 struct ieee802154_ops {
        struct module   *owner;
@@ -144,6 +148,8 @@ struct ieee802154_ops {
        int             (*set_txpower)(struct ieee802154_dev *dev, int db);
        int             (*set_lbt)(struct ieee802154_dev *dev, u8 on);
        int             (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
+       int             (*set_cca_ed_level)(struct ieee802154_dev *dev,
+                                           s32 level);
 };
 
 /* Basic interface to register ieee802154 device */
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h
index ffc5f6e..79923c6 100644
--- a/include/net/wpan-phy.h
+++ b/include/net/wpan-phy.h
@@ -48,6 +48,7 @@ struct wpan_phy {
        u8 cca_mode;
 
        u8 lbt:1;
+       s32 cca_ed_level;
 
        struct device dev;
        int idx;
@@ -59,6 +60,7 @@ struct wpan_phy {
        int (*set_txpower)(struct wpan_phy *phy, int txpower);
        int (*set_lbt)(struct wpan_phy *phy, u8 on);
        int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode);
+       int (*set_cca_ed_level)(struct wpan_phy *phy, int level);
 
        char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index b34dfae..24922fe 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -59,7 +59,8 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 
portid,
            nla_put_s32(msg, IEEE802154_ATTR_TXPOWER,
                    ((signed char) (phy->transmit_power << 2)) >> 2) ||
            nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, phy->lbt) ||
-           nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, phy->cca_mode))
+           nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, phy->cca_mode) ||
+           nla_put_s32(msg, IEEE802154_ATTR_CCA_ED_LEVEL, phy->cca_ed_level))
                goto nla_put_failure;
        for (i = 0; i < 32; i++) {
                if (phy->channels_supported[i])
@@ -410,6 +411,20 @@ static int phy_set_cca_mode(struct wpan_phy *phy, struct 
genl_info *info)
        return 0;
 }
 
+static int phy_set_cca_ed_level(struct wpan_phy *phy, struct genl_info *info)
+{
+       s32 level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]);
+       int rc;
+
+       rc = phy->set_cca_ed_level(phy, level);
+       if (rc < 0)
+               return rc;
+
+       phy->cca_ed_level = level;
+
+       return 0;
+}
+
 int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
 {
        struct wpan_phy *phy;
@@ -420,7 +435,8 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct 
genl_info *info)
 
        if (!info->attrs[IEEE802154_ATTR_PHY_NAME] &&
                !info->attrs[IEEE802154_ATTR_LBT_ENABLED] &&
-               !info->attrs[IEEE802154_ATTR_CCA_MODE])
+               !info->attrs[IEEE802154_ATTR_CCA_MODE] &&
+               !info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL])
                return -EINVAL;
 
        name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
@@ -433,7 +449,9 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct 
genl_info *info)
 
        if ((!phy->set_txpower && info->attrs[IEEE802154_ATTR_TXPOWER]) ||
                (!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
-               (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]))
+               (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
+               (!phy->set_cca_ed_level &&
+                       info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]))
                goto out;
 
        if (info->attrs[IEEE802154_ATTR_TXPOWER] &&
@@ -448,6 +466,10 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct 
genl_info *info)
                (rc = phy_set_cca_mode(phy, info)) < 0)
                goto out;
 
+       if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL] &&
+               (rc = phy_set_cca_ed_level(phy, info)) < 0)
+               goto out;
+
        wpan_phy_put(phy);
 
        return 0;
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
index 86e59d0..c8a8687 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] = {
        [IEEE802154_ATTR_TXPOWER] = { .type = NLA_S32, },
        [IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, },
        [IEEE802154_ATTR_CCA_MODE] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
 };
 
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c
index 56d0e71..5f877b7 100644
--- a/net/mac802154/ieee802154_dev.c
+++ b/net/mac802154/ieee802154_dev.c
@@ -186,6 +186,13 @@ static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 
mode)
        return priv->ops->set_cca_mode(&priv->hw, mode);
 }
 
+static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       return priv->ops->set_cca_ed_level(&priv->hw, level);
+}
+
 struct ieee802154_dev *
 ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
 {
@@ -266,6 +273,7 @@ int ieee802154_register_device(struct ieee802154_dev *dev)
        priv->phy->set_txpower = mac802154_set_txpower;
        priv->phy->set_lbt = mac802154_set_lbt;
        priv->phy->set_cca_mode = mac802154_set_cca_mode;
+       priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
 
        rc = wpan_phy_register(priv->phy);
        if (rc < 0)
-- 
1.7.9.5


------------------------------------------------------------------------------
CenturyLink Cloud: The Leader in Enterprise Cloud Services.
Learn Why More Businesses Are Choosing CenturyLink Cloud For
Critical Workloads, Development Environments & Everything In Between.
Get a Quote or Start a Free Trial Today. 
http://pubads.g.doubleclick.net/gampad/clk?id=119420431&iu=/4140/ostg.clktrk
_______________________________________________
Linux-zigbee-devel mailing list
Linux-zigbee-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel

Reply via email to