Skip to content

Commit

Permalink
ieee802154: add support for setting CCA energy detection levels
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Phoebe Buckheister authored and David S. Miller committed Feb 17, 2014
1 parent ba08fea commit 6ca0019
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 5 deletions.
26 changes: 24 additions & 2 deletions drivers/net/ieee802154/at86rf230.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,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)
Expand Down Expand Up @@ -580,6 +582,8 @@ at86rf230_stop(struct ieee802154_dev *dev)
static int
at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel)
{
lp->rssi_base_val = -91;

return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
}

Expand All @@ -595,10 +599,13 @@ at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
if (rc < 0)
return rc;

if (page == 0)
if (page == 0) {
rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0);
else
lp->rssi_base_val = -100;
} else {
rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1);
lp->rssi_base_val = -98;
}
if (rc < 0)
return rc;

Expand Down Expand Up @@ -802,6 +809,20 @@ at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
}

static int
at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
{
struct at86rf230_local *lp = dev->priv;
int desens_steps;

if (level < lp->rssi_base_val || level > 30)
return -EINVAL;

desens_steps = (level - lp->rssi_base_val) * 100 / 207;

return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps);
}

static struct ieee802154_ops at86rf230_ops = {
.owner = THIS_MODULE,
.xmit = at86rf230_xmit,
Expand All @@ -823,6 +844,7 @@ static struct ieee802154_ops at86rf212_ops = {
.set_txpower = at86rf212_set_txpower,
.set_lbt = at86rf212_set_lbt,
.set_cca_mode = at86rf212_set_cca_mode,
.set_cca_ed_level = at86rf212_set_cca_ed_level,
};

static void at86rf230_irqwork(struct work_struct *work)
Expand Down
1 change: 1 addition & 0 deletions include/linux/nl802154.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ enum {
IEEE802154_ATTR_TXPOWER,
IEEE802154_ATTR_LBT_ENABLED,
IEEE802154_ATTR_CCA_MODE,
IEEE802154_ATTR_CCA_ED_LEVEL,

__IEEE802154_ATTR_MAX,
};
Expand Down
7 changes: 7 additions & 0 deletions include/net/mac802154.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ struct ieee802154_dev {
* set_cca_mode
* Sets the CCA mode used by the device. Called with pib_lock held.
* Returns either zero, or negative errno.
*
* set_cca_ed_level
* Sets the CCA energy detection threshold in dBm. Called with pib_lock
* held.
* Returns either zero, or negative errno.
*/
struct ieee802154_ops {
struct module *owner;
Expand All @@ -145,6 +150,8 @@ struct ieee802154_ops {
int (*set_txpower)(struct ieee802154_dev *dev, int db);
int (*set_lbt)(struct ieee802154_dev *dev, bool 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 */
Expand Down
2 changes: 2 additions & 0 deletions include/net/wpan-phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct wpan_phy {
u8 cca_mode;

bool lbt;
s32 cca_ed_level;

struct device dev;
int idx;
Expand All @@ -59,6 +60,7 @@ struct wpan_phy {
int (*set_txpower)(struct wpan_phy *phy, int db);
int (*set_lbt)(struct wpan_phy *phy, bool 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)));
};
Expand Down
30 changes: 27 additions & 3 deletions net/ieee802154/nl-phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel) ||
nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, phy->transmit_power) ||
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])
Expand Down Expand Up @@ -403,6 +404,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;
Expand All @@ -413,7 +428,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]);
Expand All @@ -426,7 +442,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;

mutex_lock(&phy->pib_lock);
Expand All @@ -449,6 +467,12 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
goto error;
}

if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) {
rc = phy_set_cca_ed_level(phy, info);
if (rc < 0)
goto error;
}

mutex_unlock(&phy->pib_lock);

wpan_phy_put(phy);
Expand Down
1 change: 1 addition & 0 deletions net/ieee802154/nl_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,6 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
[IEEE802154_ATTR_TXPOWER] = { .type = NLA_S8, },
[IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, },
[IEEE802154_ATTR_CCA_MODE] = { .type = NLA_U8, },
[IEEE802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
};

11 changes: 11 additions & 0 deletions net/mac802154/ieee802154_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,16 @@ 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);

if (!priv->ops->set_cca_ed_level)
return -ENOTSUPP;

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)
{
Expand Down Expand Up @@ -275,6 +285,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)
Expand Down

0 comments on commit 6ca0019

Please sign in to comment.