This patch adds support for MAC Hardware Accelerator functions such as
Automated Acknowledgement (AACK) and CSMA-CA with Retransmission found on a few
802.15.4 Radio Transceivers.
In order to support such functionality the radio's address filtering needs to
know it's Short, IEEE Address and PAN ID.
This patch makes sure that this information is pushed to the radio in case it
provides a new ieee802154_ops callback function set_hw_addr_filt.
All this is optional, and shouldn't influence drivers without such hardware
support.
Example ieee802154_ops:set_hw_addr_filt callback:
static int trx_set_hw_addr_filt(struct ieee802154_dev *dev,
struct ieee802154_hw_addr_filt *filt, unsigned long changed)
{
struct trx_local *lp = dev->priv;
u8 reg;
might_sleep();
if (changed & IEEE802515_IEEEADDR_CHANGED) {
trx_write_reg(lp, REG_IEEE_ADDR_0, filt->ieee_addr[7]);
trx_write_reg(lp, REG_IEEE_ADDR_1, filt->ieee_addr[6]);
trx_write_reg(lp, REG_IEEE_ADDR_2, filt->ieee_addr[5]);
trx_write_reg(lp, REG_IEEE_ADDR_3, filt->ieee_addr[4]);
trx_write_reg(lp, REG_IEEE_ADDR_4, filt->ieee_addr[3]);
trx_write_reg(lp, REG_IEEE_ADDR_5, filt->ieee_addr[2]);
trx_write_reg(lp, REG_IEEE_ADDR_6, filt->ieee_addr[1]);
trx_write_reg(lp, REG_IEEE_ADDR_7, filt->ieee_addr[0]);
}
if (changed & IEEE802515_SADDR_CHANGED) {
trx_write_reg(lp, REG_SHORT_ADDR_0, filt->short_addr);
trx_write_reg(lp, REG_SHORT_ADDR_1, filt->short_addr >> 8);
}
if (changed & IEEE802515_PANID_CHANGED) {
trx_write_reg(lp, REG_PAN_ID0, filt->pan_id);
trx_write_reg(lp, REG_PAN_ID1, filt->pan_id >> 8);
}
if (changed & IEEE802515_PANC_CHANGED) {
trx_read_reg(lp, REG_AUTO_CFG, ®);
if (filt->pan_coord)
reg |= IS_PANCOORD;
else
reg &= ~IS_PANCOORD;
trx_write_reg(lp, REG_AUTO_CFG, reg);
}
return 0;
}
Version 2 changes:
-Keep wpan-phy a phy-only instance.
-Refractor callback function so it takes as argument a pointer to a structure
containing all addressing fields and a changed mask.
From: Michael Hennerich <[email protected]>
include/net/mac802154.h | 46 ++++++++++++++++++++++++++-
net/mac802154/dev.c | 1 +
net/mac802154/mac_cmd.c | 3 ++
net/mac802154/mib.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++
net/mac802154/mib.h | 2 +
5 files changed, 128 insertions(+), 2 deletions(-)
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 3463996..e3bb579 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -21,6 +21,40 @@
#ifndef NET_MAC802154_H
#define NET_MAC802154_H
+#include <net/af_ieee802154.h>
+
+/**
+ * enum ieee802154_hw_addr_filt_flags - hardware flags
+ *
+ * These flags are used to indicate changed address settings from
+ * the stack to the hardware.
+ *
+ * @IEEE802515_SADDR_CHANGED:
+ * Indicates that the Short Address changed
+ *
+ * @IEEE802515_IEEEADDR_CHANGED:
+ * Indicates that the IEEE Address changed
+ *
+ * @IEEE802515_PANID_CHANGED:
+ * Indicates that the PAN ID changed
+ *
+ * @IEEE802515_PANC_CHANGED:
+ * Indicates that PAN Coordinator status changed
+ */
+enum ieee802154_hw_addr_filt_flags {
+ IEEE802515_SADDR_CHANGED = 1 << 0,
+ IEEE802515_IEEEADDR_CHANGED = 1 << 1,
+ IEEE802515_PANID_CHANGED = 1 << 2,
+ IEEE802515_PANC_CHANGED = 1 << 3,
+};
+
+struct ieee802154_hw_addr_filt {
+ u16 pan_id;
+ u16 short_addr;
+ u8 ieee_addr[IEEE802154_ADDR_LEN];
+ u8 pan_coord;
+};
+
struct ieee802154_dev {
/* filled by the driver */
int extra_tx_headroom; /* headroom to reserve for tx skb */
@@ -28,6 +62,7 @@ struct ieee802154_dev {
struct device *parent;
/* filled by mac802154 core */
+ struct ieee802154_hw_addr_filt hw_filt;
void *priv; /* driver-specific data */
struct wpan_phy *phy;
};
@@ -86,16 +121,23 @@ struct sk_buff;
* Set the device for listening on specified channel.
* Returns either zero, or negative errno.
* Called with pib_lock held.
+ *
+ * @set_hw_addr_filt: Set radio for listening on specific address.
+ * Set the device for listening on specified address.
+ * Returns either zero, or negative errno.
*/
struct ieee802154_ops {
struct module *owner;
int (*start)(struct ieee802154_dev *dev);
void (*stop)(struct ieee802154_dev *dev);
int (*xmit)(struct ieee802154_dev *dev,
- struct sk_buff *skb);
+ struct sk_buff *skb);
int (*ed)(struct ieee802154_dev *dev, u8 *level);
int (*set_channel)(struct ieee802154_dev *dev,
- int channel);
+ int channel);
+ int (*set_hw_addr_filt)(struct ieee802154_dev *dev,
+ struct ieee802154_hw_addr_filt *filt,
+ unsigned long changed);
};
struct ieee802154_dev *ieee802154_alloc_device(size_t priv_size,
diff --git a/net/mac802154/dev.c b/net/mac802154/dev.c
index 7c21252..cdd0f78 100644
--- a/net/mac802154/dev.c
+++ b/net/mac802154/dev.c
@@ -219,6 +219,7 @@ static int ieee802154_slave_mac_addr(struct net_device
*dev, void *p)
return -EBUSY;
/* FIXME: validate addr */
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ ieee802154_dev_set_ieee_addr(dev);
return 0;
}
diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c
index bbad128..5d1c630 100644
--- a/net/mac802154/mac_cmd.c
+++ b/net/mac802154/mac_cmd.c
@@ -250,6 +250,7 @@ static int ieee802154_mlme_assoc_req(struct net_device *dev,
ieee802154_dev_set_pan_id(dev, addr->pan_id);
ieee802154_dev_set_page(dev, page);
ieee802154_dev_set_channel(dev, channel);
+ ieee802154_dev_set_ieee_addr(dev);
buf[pos++] = IEEE802154_CMD_ASSOCIATION_REQ;
buf[pos++] = cap;
@@ -311,6 +312,7 @@ static int ieee802154_mlme_start_req(struct net_device *dev,
ieee802154_dev_set_pan_id(dev, addr->pan_id);
ieee802154_dev_set_short_addr(dev, addr->short_addr);
+ ieee802154_dev_set_ieee_addr(dev);
ieee802154_dev_set_page(dev, page);
ieee802154_dev_set_channel(dev, channel);
@@ -324,6 +326,7 @@ static int ieee802154_mlme_start_req(struct net_device *dev,
else
dev->priv_flags &= ~IFF_IEEE802154_COORD;
+ ieee802154_dev_set_pan_coord(dev);
ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS);
return 0;
diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c
index 94dc0e9..b3dfb08 100644
--- a/net/mac802154/mib.c
+++ b/net/mac802154/mib.c
@@ -33,6 +33,47 @@ struct phy_chan_notify_work {
struct net_device *dev;
};
+struct hw_addr_filt_notify_work {
+ struct work_struct work;
+ struct net_device *dev;
+ unsigned long changed;
+};
+
+static void hw_addr_notify(struct work_struct *work)
+{
+ struct hw_addr_filt_notify_work *nw = container_of(work,
+ struct hw_addr_filt_notify_work, work);
+ struct ieee802154_priv *hw = ieee802154_slave_get_priv(nw->dev);
+ int res;
+
+ res = hw->ops->set_hw_addr_filt(&hw->hw,
+ &hw->hw.hw_filt, nw->changed);
+ if (res)
+ pr_debug("%s: failed changed mask %lx\n",
+ __func__, nw->changed);
+
+ kfree(nw);
+
+ return;
+}
+
+static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
+{
+ struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+ struct hw_addr_filt_notify_work *work;
+
+ work = kzalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return;
+
+ INIT_WORK(&work->work, hw_addr_notify);
+ work->dev = dev;
+ work->changed = changed;
+ queue_work(priv->hw->dev_workqueue, &work->work);
+
+ return;
+}
+
static void phy_chan_notify(struct work_struct *work)
{
struct phy_chan_notify_work *nw = container_of(work,
@@ -87,6 +128,24 @@ void ieee802154_dev_set_pan_id(struct net_device *dev, u16
val)
spin_lock_bh(&priv->mib_lock);
priv->pan_id = val;
spin_unlock_bh(&priv->mib_lock);
+
+ if (priv->hw->ops->set_hw_addr_filt &&
+ (priv->hw->hw.hw_filt.pan_id != priv->pan_id)) {
+ priv->hw->hw.hw_filt.pan_id = priv->pan_id;
+ set_hw_addr_filt(dev, IEEE802515_PANID_CHANGED);
+ }
+}
+
+void ieee802154_dev_set_pan_coord(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+ int pan_coord = !!(dev->priv_flags & IFF_IEEE802154_COORD);
+
+ if (priv->hw->ops->set_hw_addr_filt &&
+ (priv->hw->hw.hw_filt.pan_coord != pan_coord)) {
+ priv->hw->hw.hw_filt.pan_coord = pan_coord;
+ set_hw_addr_filt(dev, IEEE802515_PANC_CHANGED);
+ }
}
void ieee802154_dev_set_short_addr(struct net_device *dev, u16 val)
@@ -98,6 +157,25 @@ void ieee802154_dev_set_short_addr(struct net_device *dev,
u16 val)
spin_lock_bh(&priv->mib_lock);
priv->short_addr = val;
spin_unlock_bh(&priv->mib_lock);
+
+ if (priv->hw->ops->set_hw_addr_filt &&
+ (priv->hw->hw.hw_filt.short_addr != priv->short_addr)) {
+ priv->hw->hw.hw_filt.short_addr = priv->short_addr;
+ set_hw_addr_filt(dev, IEEE802515_SADDR_CHANGED);
+ }
+}
+
+void ieee802154_dev_set_ieee_addr(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *priv = netdev_priv(dev);
+
+ if (priv->hw->ops->set_hw_addr_filt &&
+ memcmp(priv->hw->hw.hw_filt.ieee_addr,
+ dev->dev_addr, IEEE802154_ADDR_LEN)) {
+ memcpy(priv->hw->hw.hw_filt.ieee_addr,
+ dev->dev_addr, IEEE802154_ADDR_LEN);
+ set_hw_addr_filt(dev, IEEE802515_IEEEADDR_CHANGED);
+ }
}
void ieee802154_dev_set_channel(struct net_device *dev, u8 val)
diff --git a/net/mac802154/mib.h b/net/mac802154/mib.h
index 5096c6a..8b66d0d 100644
--- a/net/mac802154/mib.h
+++ b/net/mac802154/mib.h
@@ -25,7 +25,9 @@ u8 ieee802154_dev_get_bsn(const struct net_device *dev);
u16 ieee802154_dev_get_pan_id(const struct net_device *dev);
u16 ieee802154_dev_get_short_addr(const struct net_device *dev);
void ieee802154_dev_set_pan_id(struct net_device *dev, u16 val);
+void ieee802154_dev_set_pan_coord(struct net_device *dev);
void ieee802154_dev_set_short_addr(struct net_device *dev, u16 val);
+void ieee802154_dev_set_ieee_addr(struct net_device *dev);
void ieee802154_dev_set_channel(struct net_device *dev, u8 chan);
void ieee802154_dev_set_page(struct net_device *dev, u8 page);
struct wpan_phy *ieee802154_get_phy(const struct net_device *dev);
------------------------------------------------------------------
********* Analog Devices GmbH Open Platform Solutions
** *****
** ** Wilhelm-Wagenfeld-Strasse 6
** ***** D-80807 Munich
********* Germany
Registergericht München HRB 40368, Geschäftsführer: Thomas Wessel, William A.
Martin, Margaret K. Seif
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Linux-zigbee-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel